2002-06-19 07:22:21 +02:00
|
|
|
# IMAP folder support
|
2004-08-02 04:49:16 +02:00
|
|
|
# Copyright (C) 2002-2004 John Goerzen
|
2002-06-19 07:22:21 +02:00
|
|
|
# <jgoerzen@complete.org>
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
2003-04-16 21:23:45 +02:00
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
2002-06-19 07:22:21 +02:00
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
from Base import BaseFolder
|
2002-06-21 12:01:10 +02:00
|
|
|
from offlineimap import imaputil, imaplib
|
2002-10-07 22:59:02 +02:00
|
|
|
from offlineimap.ui import UIBase
|
2004-07-26 22:37:45 +02:00
|
|
|
from offlineimap.version import versionstr
|
2003-04-18 09:06:04 +02:00
|
|
|
import rfc822, time, string, random, binascii, re
|
2002-06-21 03:22:40 +02:00
|
|
|
from StringIO import StringIO
|
2002-07-12 01:35:51 +02:00
|
|
|
from copy import copy
|
2002-06-19 07:22:21 +02:00
|
|
|
|
2002-07-18 02:51:03 +02:00
|
|
|
|
2002-06-19 07:22:21 +02:00
|
|
|
class IMAPFolder(BaseFolder):
|
2002-08-20 22:54:02 +02:00
|
|
|
def __init__(self, imapserver, name, visiblename, accountname, repository):
|
2002-11-12 22:36:34 +01:00
|
|
|
self.config = imapserver.config
|
2003-04-18 04:18:34 +02:00
|
|
|
self.expunge = repository.getexpunge()
|
2002-06-19 07:22:21 +02:00
|
|
|
self.name = imaputil.dequote(name)
|
2002-07-20 09:03:21 +02:00
|
|
|
self.root = None # imapserver.root
|
2002-06-19 07:22:21 +02:00
|
|
|
self.sep = imapserver.delim
|
|
|
|
self.imapserver = imapserver
|
2002-06-20 08:26:28 +02:00
|
|
|
self.messagelist = None
|
2002-06-21 08:51:21 +02:00
|
|
|
self.visiblename = visiblename
|
2002-07-04 05:59:19 +02:00
|
|
|
self.accountname = accountname
|
2002-08-20 22:54:02 +02:00
|
|
|
self.repository = repository
|
2003-04-18 04:18:34 +02:00
|
|
|
self.randomgenerator = random.Random()
|
|
|
|
BaseFolder.__init__(self)
|
2002-06-21 08:51:21 +02:00
|
|
|
|
2003-01-06 00:07:58 +01:00
|
|
|
def getaccountname(self):
|
|
|
|
return self.accountname
|
|
|
|
|
2002-07-04 03:35:05 +02:00
|
|
|
def suggeststhreads(self):
|
|
|
|
return 1
|
|
|
|
|
|
|
|
def waitforthread(self):
|
|
|
|
self.imapserver.connectionwait()
|
|
|
|
|
2002-07-04 05:59:19 +02:00
|
|
|
def getcopyinstancelimit(self):
|
2003-04-18 04:18:34 +02:00
|
|
|
return 'MSGCOPY_' + self.repository.getname()
|
2002-07-04 05:59:19 +02:00
|
|
|
|
2002-06-21 08:51:21 +02:00
|
|
|
def getvisiblename(self):
|
|
|
|
return self.visiblename
|
2002-06-20 08:26:28 +02:00
|
|
|
|
|
|
|
def getuidvalidity(self):
|
2002-07-04 03:35:05 +02:00
|
|
|
imapobj = self.imapserver.acquireconnection()
|
|
|
|
try:
|
2002-07-11 05:31:39 +02:00
|
|
|
# Primes untagged_responses
|
|
|
|
imapobj.select(self.getfullname(), readonly = 1)
|
|
|
|
return long(imapobj.untagged_responses['UIDVALIDITY'][0])
|
2002-07-04 03:35:05 +02:00
|
|
|
finally:
|
|
|
|
self.imapserver.releaseconnection(imapobj)
|
2002-06-20 08:26:28 +02:00
|
|
|
|
|
|
|
def cachemessagelist(self):
|
2002-07-04 03:35:05 +02:00
|
|
|
imapobj = self.imapserver.acquireconnection()
|
2002-07-11 05:31:39 +02:00
|
|
|
self.messagelist = {}
|
|
|
|
|
2002-07-04 03:35:05 +02:00
|
|
|
try:
|
2002-07-11 05:31:39 +02:00
|
|
|
# Primes untagged_responses
|
2003-06-02 23:17:29 +02:00
|
|
|
imapobj.select(self.getfullname(), readonly = 1, force = 1)
|
2003-04-18 04:18:34 +02:00
|
|
|
try:
|
|
|
|
# Some mail servers do not return an EXISTS response if
|
|
|
|
# the folder is empty.
|
|
|
|
maxmsgid = long(imapobj.untagged_responses['EXISTS'][0])
|
|
|
|
except KeyError:
|
|
|
|
return
|
2002-07-11 05:31:39 +02:00
|
|
|
if maxmsgid < 1:
|
|
|
|
# No messages; return
|
2002-07-04 03:35:05 +02:00
|
|
|
return
|
|
|
|
|
|
|
|
# Now, get the flags and UIDs for these.
|
2002-07-16 03:46:21 +02:00
|
|
|
# We could conceivably get rid of maxmsgid and just say
|
|
|
|
# '1:*' here.
|
2002-07-04 03:35:05 +02:00
|
|
|
response = imapobj.fetch('1:%d' % maxmsgid, '(FLAGS UID)')[1]
|
|
|
|
finally:
|
|
|
|
self.imapserver.releaseconnection(imapobj)
|
2002-06-20 08:26:28 +02:00
|
|
|
for messagestr in response:
|
|
|
|
# Discard the message number.
|
2002-07-24 01:36:44 +02:00
|
|
|
messagestr = string.split(messagestr, maxsplit = 1)[1]
|
2002-06-20 08:26:28 +02:00
|
|
|
options = imaputil.flags2hash(messagestr)
|
2002-10-30 05:26:49 +01:00
|
|
|
if not options.has_key('UID'):
|
|
|
|
UIBase.getglobalui().warn('No UID in message with options %s' %\
|
|
|
|
str(options),
|
|
|
|
minor = 1)
|
|
|
|
else:
|
|
|
|
uid = long(options['UID'])
|
|
|
|
flags = imaputil.flagsimap2maildir(options['FLAGS'])
|
2002-11-12 22:40:40 +01:00
|
|
|
self.messagelist[uid] = {'uid': uid, 'flags': flags}
|
2002-06-20 09:40:29 +02:00
|
|
|
|
|
|
|
def getmessagelist(self):
|
|
|
|
return self.messagelist
|
|
|
|
|
2002-06-20 13:39:27 +02:00
|
|
|
def getmessage(self, uid):
|
2004-08-02 05:42:57 +02:00
|
|
|
ui = UIBase.getglobalui()
|
2002-07-04 03:35:05 +02:00
|
|
|
imapobj = self.imapserver.acquireconnection()
|
|
|
|
try:
|
2002-07-10 06:13:33 +02:00
|
|
|
imapobj.select(self.getfullname(), readonly = 1)
|
2004-08-02 04:49:16 +02:00
|
|
|
initialresult = imapobj.uid('fetch', '%d' % uid, '(BODY.PEEK[])')
|
|
|
|
ui.debug('imap', 'Returned object from fetching %d: %s' % \
|
|
|
|
(uid, str(initialresult)))
|
|
|
|
return initialresult[1][0][1].replace("\r\n", "\n")
|
|
|
|
|
2002-07-04 03:35:05 +02:00
|
|
|
finally:
|
|
|
|
self.imapserver.releaseconnection(imapobj)
|
2002-06-20 13:39:27 +02:00
|
|
|
|
|
|
|
def getmessageflags(self, uid):
|
2002-07-04 03:35:05 +02:00
|
|
|
return self.messagelist[uid]['flags']
|
2003-04-18 04:18:34 +02:00
|
|
|
|
|
|
|
def savemessage_getnewheader(self, content):
|
|
|
|
headername = 'X-OfflineIMAP-%s-' % str(binascii.crc32(content)).replace('-', 'x')
|
|
|
|
headername += binascii.hexlify(self.repository.getname()) + '-'
|
|
|
|
headername += binascii.hexlify(self.getname())
|
|
|
|
headervalue= '%d-' % long(time.time())
|
|
|
|
headervalue += str(self.randomgenerator.random()).replace('.', '')
|
2004-07-26 22:37:45 +02:00
|
|
|
headervalue += '-v' + versionstr
|
2003-04-18 04:18:34 +02:00
|
|
|
return (headername, headervalue)
|
|
|
|
|
|
|
|
def savemessage_addheader(self, content, headername, headervalue):
|
2003-05-06 20:41:13 +02:00
|
|
|
ui = UIBase.getglobalui()
|
|
|
|
ui.debug('imap',
|
|
|
|
'savemessage_addheader: called to add %s: %s' % (headername,
|
|
|
|
headervalue))
|
2003-04-18 04:18:34 +02:00
|
|
|
insertionpoint = content.find("\r\n")
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.debug('imap', 'savemessage_addheader: insertionpoint = %d' % insertionpoint)
|
2004-06-15 16:43:14 +02:00
|
|
|
leader = content[0:insertionpoint]
|
|
|
|
ui.debug('imap', 'savemessage_addheader: leader = %s' % repr(leader))
|
|
|
|
if insertionpoint == 0 or insertionpoint == -1:
|
|
|
|
newline = ''
|
|
|
|
insertionpoint = 0
|
2003-05-06 20:41:13 +02:00
|
|
|
else:
|
2004-06-15 16:43:14 +02:00
|
|
|
newline = "\r\n"
|
|
|
|
newline += "%s: %s" % (headername, headervalue)
|
|
|
|
ui.debug('imap', 'savemessage_addheader: newline = ' + repr(newline))
|
|
|
|
trailer = content[insertionpoint:]
|
|
|
|
ui.debug('imap', 'savemessage_addheader: trailer = ' + repr(trailer))
|
|
|
|
return leader + newline + trailer
|
2003-04-18 04:18:34 +02:00
|
|
|
|
|
|
|
def savemessage_searchforheader(self, imapobj, headername, headervalue):
|
2003-06-27 01:28:54 +02:00
|
|
|
if imapobj.untagged_responses.has_key('APPENDUID'):
|
2004-10-18 21:00:29 +02:00
|
|
|
return long(imapobj.untagged_responses['APPENDUID'][-1].split(' ')[1])
|
2003-06-27 01:28:54 +02:00
|
|
|
|
2003-05-06 20:41:13 +02:00
|
|
|
ui = UIBase.getglobalui()
|
|
|
|
ui.debug('imap', 'savemessage_searchforheader called for %s: %s' % \
|
|
|
|
(headername, headervalue))
|
2003-04-18 04:18:34 +02:00
|
|
|
# Now find the UID it got.
|
|
|
|
headervalue = imapobj._quote(headervalue)
|
|
|
|
try:
|
|
|
|
matchinguids = imapobj.uid('search', None,
|
|
|
|
'(HEADER %s %s)' % (headername, headervalue))[1][0]
|
|
|
|
except imapobj.error:
|
|
|
|
# IMAP server doesn't implement search or had a problem.
|
|
|
|
return 0
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.debug('imap', 'savemessage_searchforheader got initial matchinguids: ' + repr(matchinguids))
|
|
|
|
|
2003-04-18 04:18:34 +02:00
|
|
|
matchinguids = matchinguids.split(' ')
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.debug('imap', 'savemessage_searchforheader: matchinguids now ' + \
|
|
|
|
repr(matchinguids))
|
2003-04-18 04:18:34 +02:00
|
|
|
if len(matchinguids) != 1 or matchinguids[0] == None:
|
|
|
|
raise ValueError, "While attempting to find UID for message with header %s, got wrong-sized matchinguids of %s" % (headername, str(matchinguids))
|
|
|
|
matchinguids.sort()
|
|
|
|
return long(matchinguids[0])
|
|
|
|
|
2002-06-21 03:22:40 +02:00
|
|
|
def savemessage(self, uid, content, flags):
|
2002-07-04 03:35:05 +02:00
|
|
|
imapobj = self.imapserver.acquireconnection()
|
2003-05-06 20:41:13 +02:00
|
|
|
ui = UIBase.getglobalui()
|
|
|
|
ui.debug('imap', 'savemessage: called')
|
2002-07-04 03:35:05 +02:00
|
|
|
try:
|
2002-08-08 03:57:17 +02:00
|
|
|
try:
|
|
|
|
imapobj.select(self.getfullname()) # Needed for search
|
|
|
|
except imapobj.readonly:
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.msgtoreadonly(self, uid, content, flags)
|
2002-08-08 03:57:17 +02:00
|
|
|
# Return indicating message taken, but no UID assigned.
|
|
|
|
# Fudge it.
|
|
|
|
return 0
|
2002-07-11 05:31:39 +02:00
|
|
|
|
2002-07-04 03:35:05 +02:00
|
|
|
# This backend always assigns a new uid, so the uid arg is ignored.
|
|
|
|
# In order to get the new uid, we need to save off the message ID.
|
|
|
|
|
|
|
|
message = rfc822.Message(StringIO(content))
|
2002-07-18 23:50:50 +02:00
|
|
|
datetuple = rfc822.parsedate(message.getheader('Date'))
|
2002-07-19 00:59:56 +02:00
|
|
|
# Will be None if missing or not in a valid format.
|
2002-07-18 23:50:50 +02:00
|
|
|
if datetuple == None:
|
|
|
|
datetuple = time.localtime()
|
2002-07-19 00:59:56 +02:00
|
|
|
try:
|
2002-08-10 02:29:29 +02:00
|
|
|
if datetuple[0] < 1981:
|
|
|
|
raise ValueError
|
|
|
|
# This could raise a value error if it's not a valid format.
|
|
|
|
date = imaplib.Time2Internaldate(datetuple)
|
2002-07-19 00:59:56 +02:00
|
|
|
except ValueError:
|
|
|
|
# Argh, sometimes it's a valid format but year is 0102
|
2002-08-10 02:29:29 +02:00
|
|
|
# or something. Argh. It seems that Time2Internaldate
|
|
|
|
# will rause a ValueError if the year is 0102 but not 1902,
|
|
|
|
# but some IMAP servers nonetheless choke on 1902.
|
2002-07-19 00:59:56 +02:00
|
|
|
date = imaplib.Time2Internaldate(time.localtime())
|
2002-07-04 03:35:05 +02:00
|
|
|
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.debug('imap', 'savemessage: using date ' + str(date))
|
2003-04-19 03:44:10 +02:00
|
|
|
content = re.sub("(?<!\r)\n", "\r\n", content)
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.debug('imap', 'savemessage: initial content is: ' + repr(content))
|
2002-07-04 03:35:05 +02:00
|
|
|
|
2003-04-18 04:18:34 +02:00
|
|
|
(headername, headervalue) = self.savemessage_getnewheader(content)
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.debug('imap', 'savemessage: new headers are: %s: %s' % \
|
|
|
|
(headername, headervalue))
|
2003-04-18 04:18:34 +02:00
|
|
|
content = self.savemessage_addheader(content, headername,
|
|
|
|
headervalue)
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.debug('imap', 'savemessage: new content is: ' + repr(content))
|
|
|
|
ui.debug('imap', 'savemessage: new content length is ' + \
|
|
|
|
str(len(content)))
|
2003-04-18 04:18:34 +02:00
|
|
|
|
2002-07-04 03:35:05 +02:00
|
|
|
assert(imapobj.append(self.getfullname(),
|
|
|
|
imaputil.flagsmaildir2imap(flags),
|
|
|
|
date, content)[0] == 'OK')
|
2003-04-18 04:18:34 +02:00
|
|
|
|
2002-07-04 03:35:05 +02:00
|
|
|
# Checkpoint. Let it write out the messages, etc.
|
|
|
|
assert(imapobj.check()[0] == 'OK')
|
2003-04-18 04:18:34 +02:00
|
|
|
|
|
|
|
# Keep trying until we get the UID.
|
2002-07-18 02:51:03 +02:00
|
|
|
try:
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.debug('imap', 'savemessage: first attempt to get new UID')
|
2003-04-18 04:18:34 +02:00
|
|
|
uid = self.savemessage_searchforheader(imapobj, headername,
|
|
|
|
headervalue)
|
2002-07-18 02:51:03 +02:00
|
|
|
except ValueError:
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.debug('imap', 'savemessage: first attempt to get new UID failed. Going to run a NOOP and try again.')
|
2003-04-18 04:18:34 +02:00
|
|
|
assert(imapobj.noop()[0] == 'OK')
|
|
|
|
uid = self.savemessage_searchforheader(imapobj, headername,
|
|
|
|
headervalue)
|
2002-07-04 03:35:05 +02:00
|
|
|
finally:
|
|
|
|
self.imapserver.releaseconnection(imapobj)
|
2002-06-21 03:22:40 +02:00
|
|
|
|
2003-04-18 04:18:34 +02:00
|
|
|
self.messagelist[uid] = {'uid': uid, 'flags': flags}
|
2003-05-06 20:41:13 +02:00
|
|
|
ui.debug('imap', 'savemessage: returning %d' % uid)
|
2003-04-18 04:18:34 +02:00
|
|
|
return uid
|
|
|
|
|
2002-06-21 03:55:06 +02:00
|
|
|
def savemessageflags(self, uid, flags):
|
2002-07-04 05:59:19 +02:00
|
|
|
imapobj = self.imapserver.acquireconnection()
|
2002-07-04 03:35:05 +02:00
|
|
|
try:
|
2002-08-08 03:57:17 +02:00
|
|
|
try:
|
|
|
|
imapobj.select(self.getfullname())
|
|
|
|
except imapobj.readonly:
|
2002-10-07 22:59:02 +02:00
|
|
|
UIBase.getglobalui().flagstoreadonly(self, [uid], flags)
|
2002-08-08 03:57:17 +02:00
|
|
|
return
|
2002-07-04 03:35:05 +02:00
|
|
|
result = imapobj.uid('store', '%d' % uid, 'FLAGS',
|
2002-07-12 15:20:09 +02:00
|
|
|
imaputil.flagsmaildir2imap(flags))
|
|
|
|
assert result[0] == 'OK', 'Error with store: ' + r[1]
|
2002-07-04 03:35:05 +02:00
|
|
|
finally:
|
|
|
|
self.imapserver.releaseconnection(imapobj)
|
2002-07-12 15:20:09 +02:00
|
|
|
result = result[1][0]
|
|
|
|
if not result:
|
|
|
|
self.messagelist[uid]['flags'] = flags
|
|
|
|
else:
|
|
|
|
flags = imaputil.flags2hash(imaputil.imapsplit(result)[1])['FLAGS']
|
|
|
|
self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags)
|
|
|
|
|
|
|
|
def addmessageflags(self, uid, flags):
|
|
|
|
self.addmessagesflags([uid], flags)
|
2002-06-21 03:55:06 +02:00
|
|
|
|
2003-04-18 04:18:34 +02:00
|
|
|
def addmessagesflags_noconvert(self, uidlist, flags):
|
2003-01-09 03:16:07 +01:00
|
|
|
self.processmessagesflags('+', uidlist, flags)
|
|
|
|
|
2003-04-18 04:18:34 +02:00
|
|
|
def addmessagesflags(self, uidlist, flags):
|
|
|
|
"""This is here for the sake of UIDMaps.py -- deletemessages must
|
|
|
|
add flags and get a converted UID, and if we don't have noconvert,
|
|
|
|
then UIDMaps will try to convert it twice."""
|
|
|
|
self.addmessagesflags_noconvert(uidlist, flags)
|
|
|
|
|
2003-01-09 03:16:07 +01:00
|
|
|
def deletemessageflags(self, uid, flags):
|
|
|
|
self.deletemessagesflags([uid], flags)
|
|
|
|
|
|
|
|
def deletemessagesflags(self, uidlist, flags):
|
|
|
|
self.processmessagesflags('-', uidlist, flags)
|
|
|
|
|
|
|
|
def processmessagesflags(self, operation, uidlist, flags):
|
2004-11-16 23:41:09 +01:00
|
|
|
if len(uidlist) > 101:
|
|
|
|
# Hack for those IMAP ervers with a limited line length
|
|
|
|
self.processmessagesflags(operation, uidlist[:100], flags)
|
|
|
|
self.processmessagesflags(operation, uidlist[100:], flags)
|
|
|
|
return
|
|
|
|
|
2002-07-04 04:14:07 +02:00
|
|
|
imapobj = self.imapserver.acquireconnection()
|
2002-07-04 03:35:05 +02:00
|
|
|
try:
|
2002-08-08 03:57:17 +02:00
|
|
|
try:
|
|
|
|
imapobj.select(self.getfullname())
|
|
|
|
except imapobj.readonly:
|
2002-10-07 22:59:02 +02:00
|
|
|
UIBase.getglobalui().flagstoreadonly(self, uidlist, flags)
|
2002-08-08 03:57:17 +02:00
|
|
|
return
|
2002-07-04 03:35:05 +02:00
|
|
|
r = imapobj.uid('store',
|
2002-07-16 03:46:21 +02:00
|
|
|
imaputil.listjoin(uidlist),
|
2003-01-09 03:16:07 +01:00
|
|
|
operation + 'FLAGS',
|
2002-07-12 01:35:51 +02:00
|
|
|
imaputil.flagsmaildir2imap(flags))
|
|
|
|
assert r[0] == 'OK', 'Error with store: ' + r[1]
|
|
|
|
r = r[1]
|
2002-07-04 03:35:05 +02:00
|
|
|
finally:
|
|
|
|
self.imapserver.releaseconnection(imapobj)
|
2002-07-12 01:35:51 +02:00
|
|
|
# Some IMAP servers do not always return a result. Therefore,
|
|
|
|
# only update the ones that it talks about, and manually fix
|
|
|
|
# the others.
|
|
|
|
needupdate = copy(uidlist)
|
2002-07-03 07:05:49 +02:00
|
|
|
for result in r:
|
2002-07-12 01:35:51 +02:00
|
|
|
if result == None:
|
2002-07-12 04:04:04 +02:00
|
|
|
# Compensate for servers that don't return anything from
|
|
|
|
# STORE.
|
2002-07-12 01:35:51 +02:00
|
|
|
continue
|
2002-07-12 04:04:04 +02:00
|
|
|
attributehash = imaputil.flags2hash(imaputil.imapsplit(result)[1])
|
|
|
|
if not ('UID' in attributehash and 'FLAGS' in attributehash):
|
|
|
|
# Compensate for servers that don't return a UID attribute.
|
|
|
|
continue
|
|
|
|
flags = attributehash['FLAGS']
|
|
|
|
uid = long(attributehash['UID'])
|
2002-07-03 07:05:49 +02:00
|
|
|
self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags)
|
2002-07-12 01:35:51 +02:00
|
|
|
try:
|
|
|
|
needupdate.remove(uid)
|
|
|
|
except ValueError: # Let it slide if it's not in the list
|
|
|
|
pass
|
|
|
|
for uid in needupdate:
|
2003-01-09 03:16:07 +01:00
|
|
|
if operation == '+':
|
|
|
|
for flag in flags:
|
|
|
|
if not flag in self.messagelist[uid]['flags']:
|
|
|
|
self.messagelist[uid]['flags'].append(flag)
|
|
|
|
self.messagelist[uid]['flags'].sort()
|
|
|
|
elif operation == '-':
|
|
|
|
for flag in flags:
|
|
|
|
if flag in self.messagelist[uid]['flags']:
|
|
|
|
self.messagelist[uid]['flags'].remove(flag)
|
2002-07-03 07:05:49 +02:00
|
|
|
|
2002-06-21 03:55:06 +02:00
|
|
|
def deletemessage(self, uid):
|
2003-04-18 04:18:34 +02:00
|
|
|
self.deletemessages_noconvert([uid])
|
2002-07-03 07:05:49 +02:00
|
|
|
|
2002-07-03 07:16:56 +02:00
|
|
|
def deletemessages(self, uidlist):
|
2003-04-18 04:18:34 +02:00
|
|
|
self.deletemessages_noconvert(uidlist)
|
|
|
|
|
|
|
|
def deletemessages_noconvert(self, uidlist):
|
2002-07-03 07:05:49 +02:00
|
|
|
# Weed out ones not in self.messagelist
|
|
|
|
uidlist = [uid for uid in uidlist if uid in self.messagelist]
|
|
|
|
if not len(uidlist):
|
|
|
|
return
|
2002-07-04 03:35:05 +02:00
|
|
|
|
2003-04-18 04:18:34 +02:00
|
|
|
self.addmessagesflags_noconvert(uidlist, ['T'])
|
2002-07-04 03:35:05 +02:00
|
|
|
imapobj = self.imapserver.acquireconnection()
|
|
|
|
try:
|
2002-08-08 03:57:17 +02:00
|
|
|
try:
|
|
|
|
imapobj.select(self.getfullname())
|
|
|
|
except imapobj.readonly:
|
2002-10-07 22:59:02 +02:00
|
|
|
UIBase.getglobalui().deletereadonly(self, uidlist)
|
2002-08-08 03:57:17 +02:00
|
|
|
return
|
2002-11-12 22:36:34 +01:00
|
|
|
if self.expunge:
|
|
|
|
assert(imapobj.expunge()[0] == 'OK')
|
2002-07-04 03:35:05 +02:00
|
|
|
finally:
|
|
|
|
self.imapserver.releaseconnection(imapobj)
|
2002-07-03 07:05:49 +02:00
|
|
|
for uid in uidlist:
|
2002-07-12 01:35:51 +02:00
|
|
|
del self.messagelist[uid]
|
2002-06-21 03:55:06 +02:00
|
|
|
|
2002-06-21 03:22:40 +02:00
|
|
|
|