Mercurial > libervia-backend
diff src/plugins/plugin_misc_imap.py @ 257:012c38b56cdd
plugin IMAP, plugin Maildir: profile management
- IMAP Login/pass is now checked against profile name/jabber pass
- Mailboxes are now per-profile
- flags are now checked without case sensitiveness
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 18 Jan 2011 00:57:26 +0100 |
parents | 55b750017b71 |
children | c8406fe5e81e |
line wrap: on
line diff
--- a/src/plugins/plugin_misc_imap.py Tue Jan 18 00:51:47 2011 +0100 +++ b/src/plugins/plugin_misc_imap.py Tue Jan 18 00:57:26 2011 +0100 @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """ -SAT plugin for managing imap server +SàT plugin for managing imap server Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org) This program is free software: you can redistribute it and/or modify @@ -21,9 +21,10 @@ from logging import debug, info, error import warnings -from twisted.internet import protocol +from twisted.internet import protocol,defer from twisted.words.protocols.jabber import error as jab_error -from twisted.cred import portal,checkers +from twisted.cred import portal,checkers,credentials +from twisted.cred import error as cred_error from twisted.mail import imap4 from email.parser import Parser import email.message @@ -86,7 +87,6 @@ """Retrieve the unique identifier associated with this message. """ debug('getUID (message)') - debug ('===>%i', self.uid) return self.uid def getFlags(self): @@ -152,14 +152,13 @@ class SatMailbox: implements(imap4.IMailbox) - def __init__(self,host,name): + def __init__(self,host,name,profile): self.host = host self.listeners=set() debug ('Mailbox init (%s)', name) if name!="INBOX": raise imap4.MailboxException("Only INBOX is managed for the moment") - self.name=name - self.mailbox=self.host.plugins["Maildir"].accessMessageBox("INBOX",self.newMessage) + self.mailbox=self.host.plugins["Maildir"].accessMessageBox(name,self.newMessage, profile) def newMessage(self): """Called when a new message is in the mailbox""" @@ -207,7 +206,7 @@ """Return the number of messages with the 'Unseen' flag. """ debug('getUnseenCount') - return self.getMessageCount()-len(self.mailbox.getMessageIdsWithFlag('\\Seen')) + return self.getMessageCount()-len(self.mailbox.getMessageIdsWithFlag('\\SEEN')) def isWriteable(self): """Get the read/write status of the mailbox. @@ -271,7 +270,7 @@ invoked otherwise. """ debug('addMessage') - raise NotImplementedError + raise imap4.MailboxException("Client message addition not implemented yet") def expunge(self): """Remove all messages flagged \\Deleted. @@ -323,6 +322,8 @@ """ debug('store') + flags=[flag.upper() for flag in flags] + def updateFlags(getF,setF): ret = {} for mess_id in messages: @@ -335,16 +336,27 @@ _flags.update(set(flags)) new_flags=list(_flags) setF(mess_id, new_flags) - ret[mess_id] = new_flags + ret[mess_id] = tuple(new_flags) return ret if uid: messages.last = self.mailbox.getMaxUid() messages.getnext = self.mailbox.getNextExistingUid - return updateFlags(self.mailbox.getFlagsUid,self.mailbox.setFlagsUid) + ret = updateFlags(self.mailbox.getFlagsUid,self.mailbox.setFlagsUid) + for listener in self.listeners: + listener.flagsChanged(ret) + return ret + else: messages.last = self.getMessageCount() - return updateFlags(self.mailbox.getFlags,self.mailbox.setFlags) + ret = updateFlags(self.mailbox.getFlags,self.mailbox.setFlags) + newFlags={} + for idx in ret: + #we have to convert idx to uid for the listeners + newFlags[self.mailbox.getUid(idx)] = ret[idx] + for listener in self.listeners: + listener.flagsChanged(newFlags) + return ret def getFlags(self): """Return the flags defined in this mailbox @@ -352,7 +364,7 @@ @return: A list of the flags that can be set on messages in this mailbox. """ debug('getFlags') - return ['\Seen','\Answered','\Flagged','\Deleted','\Draft'] #TODO: add '\Recent' + return ['\\SEEN','\\ANSWERED','\\FLAGGED','\\DELETED','\\DRAFT'] #TODO: add '\\RECENT' def getHierarchicalDelimiter(self): """Get the character which delimits namespaces for in this mailbox. @@ -360,21 +372,19 @@ debug('getHierarchicalDelimiter') return '.' - - -class ImapAccount(imap4.MemoryAccount): +class ImapSatAccount(imap4.MemoryAccount): #implements(imap4.IAccount) - # Actually implement the interface here - def __init__(self, host, name): + def __init__(self, host, profile): debug("ImapAccount init") self.host=host - imap4.MemoryAccount.__init__(self,name) + self.profile=profile + imap4.MemoryAccount.__init__(self,profile) self.addMailbox("Inbox") #We only manage Inbox for the moment debug ('INBOX added') def _emptyMailbox(self, name, id): - return SatMailbox(self.host,name) + return SatMailbox(self.host,name,self.profile) class ImapRealm: @@ -385,9 +395,40 @@ def requestAvatar(self, avatarID, mind, *interfaces): debug('requestAvatar') + profile=avatarID.decode('utf-8') if imap4.IAccount not in interfaces: raise NotImplementedError - return imap4.IAccount, ImapAccount(self.host,avatarID), lambda:None + return imap4.IAccount, ImapSatAccount(self.host,profile), lambda:None + +class SatProfileCredentialChecker: + """ + This credential checker check against SàT's profile and associated jabber's password + Check if the profile exists, and if the password is OK + Return the profile as avatarId + """ + implements(checkers.ICredentialsChecker) + credentialInterfaces = (credentials.IUsernamePassword, + credentials.IUsernameHashedPassword) + + + def __init__(self, host): + self.host = host + + def _cbPasswordMatch(self, matched, profile): + if matched: + return profile.encode('utf-8') + else: + return failure.Failure(cred_error.UnauthorizedLogin()) + + def requestAvatarId(self, credentials): + profiles = self.host.memory.getProfilesList() + if not credentials.username in profiles: + return defer.fail(cred_error.UnauthorizedLogin()) + password = self.host.memory.getParamA("Password", "Connection", profile_key=credentials.username) + return defer.maybeDeferred( + credentials.checkPassword, + password).addCallback( + self._cbPasswordMatch, credentials.username) class ImapServerFactory(protocol.ServerFactory): protocol = imap4.IMAP4Server @@ -405,5 +446,5 @@ debug ("Building protocole") prot = protocol.ServerFactory.buildProtocol(self, addr) prot.portal = portal.Portal(ImapRealm(self.host)) - prot.portal.registerChecker(checkers.InMemoryUsernamePasswordDatabaseDontUse(goffi="toto")) + prot.portal.registerChecker(SatProfileCredentialChecker(self.host)) return prot