Compare commits
3 Commits
master
...
sqlitedict
Author | SHA1 | Date |
---|---|---|
inpos | 8f88a79980 | |
inpos | 0a34f252d4 | |
inpos | 966ce51781 |
27
mech_imap.py
27
mech_imap.py
|
@ -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):
|
||||||
|
|
|
@ -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'
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue