Compare commits

...

3 Commits

Author SHA1 Message Date
inpos 8f88a79980 Перелал счётчики 2016-06-11 09:51:16 +03:00
inpos 0a34f252d4 промежуточный 2016-06-10 21:32:15 +03:00
inpos 966ce51781 промежуточный 2016-06-10 19:59:55 +03:00
4 changed files with 65 additions and 58 deletions

View File

@ -20,19 +20,18 @@ class IMAPUserAccount(object):
if not os.path.exists(mdir): if not os.path.exists(mdir):
os.makedirs(mdir) os.makedirs(mdir)
self.dir = mdir self.dir = mdir
if self.dir in IMAP_MBOX_REG.keys(): if self.dir in IMAP_MBOX_REG.iterkeys():
IMAP_MBOX_REG[self.dir][IMAP_ACC_CONN_NUM] += 1 IMAP_MBOX_REG[self.dir][IMAP_ACC_CONN_NUM] += 1
else: else:
IMAP_MBOX_REG[self.dir] = {} IMAP_MBOX_REG[self.dir] = {}
IMAP_MBOX_REG[self.dir][IMAP_ACC_CONN_NUM] = 0 IMAP_MBOX_REG[self.dir][IMAP_ACC_CONN_NUM] = 1
for m in conf.imap_auto_mbox.keys(): for m in conf.imap_auto_mbox.keys():
name = m name = m
if isinstance(m, unicode): if isinstance(m, unicode):
m = m.encode('imap4-utf-7') m = m.encode('imap4-utf-7')
if m not in IMAP_MBOX_REG[self.dir].keys(): if m not in IMAP_MBOX_REG[self.dir].iterkeys():
IMAP_MBOX_REG[self.dir][m] = self.create(m) IMAP_MBOX_REG[self.dir][m] = self.create(m)
IMAP_MBOX_REG[self.dir][m].setSpecial(conf.imap_auto_mbox[name]) IMAP_MBOX_REG[self.dir][m].setSpecial(conf.imap_auto_mbox[name])
IMAP_MBOX_REG[self.dir][m]._start_monitor()
self.subscribe(m) self.subscribe(m)
def _getMailbox(self, path): def _getMailbox(self, path):
@ -66,11 +65,11 @@ class IMAPUserAccount(object):
def create(self, pathspec): def create(self, pathspec):
if isinstance(pathspec, unicode): if isinstance(pathspec, unicode):
pathspec = pathspec.encode('imap4-utf-7') pathspec = pathspec.encode('imap4-utf-7')
if pathspec not in IMAP_MBOX_REG[self.dir].keys(): if pathspec not in IMAP_MBOX_REG[self.dir].iterkeys():
paths = filter(None, pathspec.split(IMAP_HDELIM)) paths = filter(None, pathspec.split(IMAP_HDELIM))
for accum in range(1, len(paths)): for accum in range(1, len(paths)):
subpath = IMAP_HDELIM.join(paths[:accum]) subpath = IMAP_HDELIM.join(paths[:accum])
if subpath not in IMAP_MBOX_REG[self.dir].keys(): if subpath not in IMAP_MBOX_REG[self.dir].iterkeys():
try: try:
IMAP_MBOX_REG[self.dir][subpath] = self._getMailbox(IMAP_HDELIM.join(paths[:accum])) IMAP_MBOX_REG[self.dir][subpath] = self._getMailbox(IMAP_HDELIM.join(paths[:accum]))
IMAP_MBOX_REG[self.dir][subpath].subscribe() IMAP_MBOX_REG[self.dir][subpath].subscribe()
@ -189,16 +188,26 @@ class IMAPServerProtocol(imap4.IMAP4Server):
def connectionLost(self, reason): def connectionLost(self, reason):
self.setTimeout(None) self.setTimeout(None)
if self.account and self.account.dir in IMAP_MBOX_REG.keys(): self.transport.loseConnection()
if self.account and self.account.dir in IMAP_MBOX_REG.iterkeys():
IMAP_MBOX_REG[self.account.dir][IMAP_ACC_CONN_NUM] -= 1 IMAP_MBOX_REG[self.account.dir][IMAP_ACC_CONN_NUM] -= 1
if IMAP_MBOX_REG[self.account.dir][IMAP_ACC_CONN_NUM] <= 0: if IMAP_MBOX_REG[self.account.dir][IMAP_ACC_CONN_NUM] <= 0:
for m in IMAP_MBOX_REG[self.account.dir].keys(): for m in IMAP_MBOX_REG[self.account.dir].keys():
if m == IMAP_ACC_CONN_NUM: if m == IMAP_ACC_CONN_NUM:
continue continue
for l in IMAP_MBOX_REG[self.account.dir][m].listeners:
l.transport.loseConnection()
IMAP_MBOX_REG[self.account.dir][m].removeListener(l)
IMAP_MBOX_REG[self.account.dir][m].close() IMAP_MBOX_REG[self.account.dir][m].close()
del IMAP_MBOX_REG[self.account.dir][m] if IMAP_MBOX_REG[self.account.dir][m].closed:
del IMAP_MBOX_REG[self.account.dir] del IMAP_MBOX_REG[self.account.dir][m]
if IMAP_MBOX_REG[self.account.dir].keys() == []:
del IMAP_MBOX_REG[self.account.dir]
self.account = None self.account = None
def timeoutConnection(self):
self.sendLine('* BYE Autologout; connection idle too long')
self.connectionLost('timeout')
self.state = 'timeout'
def _parseMbox(self, name): def _parseMbox(self, name):
if isinstance(name, unicode): if isinstance(name, unicode):

View File

@ -32,8 +32,6 @@ conf.imap_TRASH = 'Trash'
conf.imap_JUNK = 'Junk' conf.imap_JUNK = 'Junk'
conf.imap_ARCHIVE = 'Archive' conf.imap_ARCHIVE = 'Archive'
conf.imap_DRAFTS = 'Drafts' conf.imap_DRAFTS = 'Drafts'
conf.imap_msg_info = 'msg_info.db'
conf.imap_mbox_info = 'mbox_info.db'
conf.imap_auto_mbox = {'INBOX': '\\INBOX', conf.imap_auto_mbox = {'INBOX': '\\INBOX',
conf.imap_SENT: '\\Sent', conf.imap_SENT: '\\Sent',
conf.imap_TRASH: '\\Trash', conf.imap_TRASH: '\\Trash',
@ -43,3 +41,6 @@ conf.imap_auto_mbox = {'INBOX': '\\INBOX',
} }
conf.imap_expunge_on_close = True conf.imap_expunge_on_close = True
conf.imap_check_new_interval = 10.0 # Период проверки новых сообщений в ящике conf.imap_check_new_interval = 10.0 # Период проверки новых сообщений в ящике
conf.imap_msg_flags = 'msg_flags.db'
conf.imap_msg_uids = 'msg_uids.db'
conf.imap_mbox_info = 'mbox_info.db'

View File

@ -69,7 +69,8 @@ class MailDirStore(object):
inbox = os.path.join(mdir, 'INBOX') inbox = os.path.join(mdir, 'INBOX')
mailbox = self.mbox.IMAPMailbox(inbox) mailbox = self.mbox.IMAPMailbox(inbox)
try: try:
mailbox.addMessage(message, [IMAP_FLAGS['RECENT']]) #mailbox.addMessage(message, [IMAP_FLAGS['RECENT']])
mailbox.addMessage(message, [])
return True return True
except: except:
raise raise

View File

@ -66,6 +66,7 @@ class IMAPMailbox(ExtendedMaildir):
def __init__(self, path): def __init__(self, path):
maildir.initializeMaildir(path) maildir.initializeMaildir(path)
self.closed = False
self.listeners = [] self.listeners = []
self.path = path self.path = path
self.open_flags() self.open_flags()
@ -73,8 +74,9 @@ class IMAPMailbox(ExtendedMaildir):
self.__check_flags_() self.__check_flags_()
def open_flags(self): def open_flags(self):
self.msg_info = SqliteDict(os.path.join(self.path, conf.imap_msg_info)) self.msg_flags = SqliteDict(os.path.join(self.path, conf.imap_msg_flags), autocommit = True)
self.mbox_info = SqliteDict(os.path.join(self.path, conf.imap_mbox_info)) self.msg_uids = SqliteDict(os.path.join(self.path, conf.imap_msg_uids), autocommit = True)
self.mbox_info = SqliteDict(os.path.join(self.path, conf.imap_mbox_info), autocommit = True)
def _start_monitor(self): def _start_monitor(self):
self.notifier = inotify.INotify() self.notifier = inotify.INotify()
@ -90,8 +92,10 @@ class IMAPMailbox(ExtendedMaildir):
def _new_files(self, wo, path, code): def _new_files(self, wo, path, code):
if code == inotify.IN_MOVED_TO or code == inotify.IN_DELETE: if code == inotify.IN_MOVED_TO or code == inotify.IN_DELETE:
c = self.getMessageCount()
r = self.getRecentCount()
for l in self.listeners: for l in self.listeners:
l.newMessages(self.getMessageCount(), self.getRecentCount()) l.newMessages(c, r)
def __check_flags_(self): def __check_flags_(self):
if 'subscribed' not in self.mbox_info.keys(): self.mbox_info['subscribed'] = False if 'subscribed' not in self.mbox_info.keys(): self.mbox_info['subscribed'] = False
@ -99,17 +103,17 @@ class IMAPMailbox(ExtendedMaildir):
if 'special' not in self.mbox_info.keys(): self.mbox_info['special'] = '' if 'special' not in self.mbox_info.keys(): self.mbox_info['special'] = ''
if 'uidvalidity' not in self.mbox_info.keys(): self.mbox_info['uidvalidity'] = random.randint(0, 2**32) if 'uidvalidity' not in self.mbox_info.keys(): self.mbox_info['uidvalidity'] = random.randint(0, 2**32)
if 'uidnext' not in self.mbox_info.keys(): self.mbox_info['uidnext'] = 1 if 'uidnext' not in self.mbox_info.keys(): self.mbox_info['uidnext'] = 1
if 'recent' not in self.mbox_info.keys(): self.mbox_info['recent'] = []
#self.mbox_info.commit(blocking=False) # XXX #self.mbox_info.commit(blocking=False) # XXX
l = [l for l in self.__msg_list_()] l = [l for l in self.__msg_list_()]
for i in l: for i in l:
fn = i.split('/')[-1] fn = i.split('/')[-1]
if fn not in self.msg_info.keys(): if fn not in self.msg_uids.iterkeys():
val1 = {'uid': self.getUIDNext()} self.msg_uids[fn] = self.getUIDNext()
if i.split('/')[-2] == 'new': if i.split('/')[-2] == 'new':
val1['flags'] = [] self.msg_flags[fn] = []
else: else:
val1['flags'] = [misc.IMAP_FLAGS['SEEN']] self.msg_flags[fn] = [misc.IMAP_FLAGS['SEEN']]
self.msg_info[fn] = val1
#self.msg_info.commit(blocking=False) # XXX #self.msg_info.commit(blocking=False) # XXX
def subscribe(self): def subscribe(self):
@ -124,8 +128,7 @@ class IMAPMailbox(ExtendedMaildir):
return self.mbox_info['subscribed'] return self.mbox_info['subscribed']
def __count_flagged_msgs_(self, flag): def __count_flagged_msgs_(self, flag):
val1 = [0 for fn in self.msg_info.keys() if flag in self.msg_info[fn]['flags']] return sum(1 for flags in self.msg_flags.itervalues() if flag in flags)
return len(val1)
def getHierarchicalDelimiter(self): def getHierarchicalDelimiter(self):
return misc.IMAP_HDELIM return misc.IMAP_HDELIM
@ -164,22 +167,22 @@ class IMAPMailbox(ExtendedMaildir):
self.removeFlag(misc.MBOX_FLAGS['HASCHILDREN']) self.removeFlag(misc.MBOX_FLAGS['HASCHILDREN'])
def getMessageCount(self): def getMessageCount(self):
val1 = [0 for fn in self.msg_info.keys() if misc.IMAP_FLAGS['DELETED'] not in self.msg_info[fn]['flags']] return sum(1 for flags in self.msg_flags.itervalues() if misc.IMAP_FLAGS['DELETED'] not in flags)
return len(val1)
def getRecentCount(self): def getRecentCount(self):
c = 0 #c = 0
for fn in self.msg_info.keys(): #for m_items in self.msg_flags.iteritems():
if misc.IMAP_FLAGS['RECENT'] in self.msg_info[fn]['flags']: # if misc.IMAP_FLAGS['RECENT'] in m_items[1]:
c += 1 # c += 1
info = self.msg_info[fn] # self.msg_flags[m_items[0]] = list(set(m_items[1]).difference(set([misc.IMAP_FLAGS['RECENT']])))
info['flags'] = set(info['flags']).difference(set([misc.IMAP_FLAGS['RECENT']])) ##self.msg_info.commit(blocking=False) # XXX
self.msg_info[fn] = info c = len(self.mbox_info['recent'])
#self.msg_info.commit(blocking=False) # XXX if c > 0:
self.mbox_info['recent'] = []
return c return c
def getUnseenCount(self): def getUnseenCount(self):
return self.getMessageCount() - self.__count_flagged_msgs_(misc.IMAP_FLAGS['SEEN']) return sum(1 for flags in self.msg_flags.itervalues() if misc.IMAP_FLAGS['SEEN'] not in flags)
def isWriteable(self): def isWriteable(self):
return True return True
@ -203,11 +206,13 @@ class IMAPMailbox(ExtendedMaildir):
path = self.lastadded path = self.lastadded
self.lastadded = None self.lastadded = None
fn = path.split('/')[-1] fn = path.split('/')[-1]
self.msg_info[fn] = {'uid': self.getUIDNext(), 'flags': flags} self.msg_uids[fn] = self.getUIDNext()
self.msg_flags[fn] = flags
#self.msg_info.commit(blocking=False) # XXX #self.msg_info.commit(blocking=False) # XXX
if misc.IMAP_FLAGS['SEEN'] in flags and path.split('/')[-2] != 'cur': if misc.IMAP_FLAGS['SEEN'] in flags and path.split('/')[-2] != 'cur':
new_path = os.path.join(self.path, 'cur', fn) new_path = os.path.join(self.path, 'cur', fn)
os.rename(path, new_path) os.rename(path, new_path)
self.mbox_info['recent'] = list(set(self.mbox_info['recent']).union(set([fn])))
def __msg_list_(self): def __msg_list_(self):
a = [] a = []
@ -231,7 +236,7 @@ class IMAPMailbox(ExtendedMaildir):
def fetch(self, messages, uid): def fetch(self, messages, uid):
return [[seq, MaildirMessage(seq, return [[seq, MaildirMessage(seq,
file(filename, 'rb').read(), file(filename, 'rb').read(),
self.msg_info[filename.split('/')[-1]]['flags'], self.msg_flags[filename.split('/')[-1]],
rfc822date())] rfc822date())]
for seq, filename in self.__fetch_(messages, uid).iteritems()] for seq, filename in self.__fetch_(messages, uid).iteritems()]
def __fetch_(self, messages, uid): def __fetch_(self, messages, uid):
@ -239,7 +244,7 @@ class IMAPMailbox(ExtendedMaildir):
messagesToFetch = {} messagesToFetch = {}
if not messages.last: if not messages.last:
messages.last = self.mbox_info['uidnext'] messages.last = self.mbox_info['uidnext']
fn_uid = dict((fn, self.msg_info[fn]['uid']) for fn in self.msg_info.keys()) fn_uid = dict((fn, self.msg_uids[fn]) for fn in self.msg_uids.iterkeys())
for uid in messages: for uid in messages:
if uid in fn_uid.values(): if uid in fn_uid.values():
for name, _id in fn_uid.iteritems(): for name, _id in fn_uid.iteritems():
@ -256,24 +261,18 @@ class IMAPMailbox(ExtendedMaildir):
for _id, path in self.__fetch_(messages, uid).iteritems(): for _id, path in self.__fetch_(messages, uid).iteritems():
filename = path.split('/')[-1] filename = path.split('/')[-1]
if mode < 0: if mode < 0:
old_f = self.msg_info[filename] self.msg_flags[filename] = list(set(self.msg_flags[filename]).difference(set(flags)))
old_f['flags'] = list(set(old_f['flags']).difference(set(flags)))
self.msg_info[filename] = old_f
if misc.IMAP_FLAGS['SEEN'] in flags and path.split('/')[-2] != 'new': if misc.IMAP_FLAGS['SEEN'] in flags and path.split('/')[-2] != 'new':
new_path = os.path.join(self.path, 'new', filename) new_path = os.path.join(self.path, 'new', filename)
os.rename(path, new_path) os.rename(path, new_path)
elif mode == 0: elif mode == 0:
old_f = self.msg_info[filename] self.msg_flags[filename] = flags
old_f['flags'] = flags
self.msg_info[filename] = old_f
elif mode > 0: elif mode > 0:
old_f = self.msg_info[filename] self.msg_flags[filename] = list(set(self.msg_flags[filename]).union(set(flags)))
old_f['flags'] = list(set(old_f['flags']).union(set(flags)))
self.msg_info[filename] = old_f
if misc.IMAP_FLAGS['SEEN'] in flags and path.split('/')[-2] != 'cur': if misc.IMAP_FLAGS['SEEN'] in flags and path.split('/')[-2] != 'cur':
new_path = os.path.join(self.path, 'cur', filename) new_path = os.path.join(self.path, 'cur', filename)
os.rename(path, new_path) os.rename(path, new_path)
d[_id] = self.msg_info[filename]['flags'] d[_id] = self.msg_flags[filename]
#self.msg_info.commit(blocking=False) # XXX #self.msg_info.commit(blocking=False) # XXX
return d return d
@ -281,12 +280,13 @@ class IMAPMailbox(ExtendedMaildir):
uids = [] uids = []
for path in self.__msg_list_(): for path in self.__msg_list_():
fn = path.split('/')[-1] fn = path.split('/')[-1]
if fn not in self.msg_info.keys(): if fn not in self.msg_uids.iterkeys():
continue continue
uid = self.msg_info[fn]['uid'] uid = self.msg_uids[fn]
if misc.IMAP_FLAGS['DELETED'] in self.msg_info[fn]['flags']: if misc.IMAP_FLAGS['DELETED'] in self.msg_flags[fn]:
os.remove(path) os.remove(path)
del self.msg_info[fn] del self.msg_flags[fn]
del self.msg_uids[fn]
uids.append(uid) uids.append(uid)
#self.msg_info.commit(blocking=False) # XXX #self.msg_info.commit(blocking=False) # XXX
return uids return uids
@ -306,15 +306,11 @@ class IMAPMailbox(ExtendedMaildir):
pass pass
def close(self): def close(self):
print('!!! %s - %d !!!' % (self.path, len(self.listeners)))
if len(self.listeners) == 0: if len(self.listeners) == 0:
self._stop_monitor() self._stop_monitor()
if conf.imap_expunge_on_close: if conf.imap_expunge_on_close:
self.expunge() self.expunge()
self.msg_info.commit(blocking=False) self.closed = True
self.mbox_info.commit(blocking = False)
self.msg_info.close()
self.mbox_info.close()
class MaildirMessagePart(object): class MaildirMessagePart(object):
implements(imap4.IMessagePart) implements(imap4.IMessagePart)