shutil.copy2(path, topath)
except (IOError, os.error), msg:
tofolder._copysequences(self, refiled.items())
self.removefromallsequences(refiled.keys())
raise os.error, errors[0]
raise os.error, ('multiple errors:', errors)
def _copysequences(self, fromfolder, refileditems):
"""Helper for refilemessages() to copy sequences."""
fromsequences = fromfolder.getsequences()
tosequences = self.getsequences()
for name, seq in fromsequences.items():
toseq = tosequences[name]
for fromn, ton in refileditems:
tosequences[name] = toseq
self.putsequences(tosequences)
def movemessage(self, n, tofolder, ton):
"""Move one message over a specific destination message,
which may or may not already exist."""
path = self.getmessagefilename(n)
# Open it to check that it exists
topath = tofolder.getmessagefilename(ton)
backuptopath = tofolder.getmessagefilename(',%d' % ton)
os.rename(topath, backuptopath)
shutil.copy2(path, topath)
self.removefromallsequences([n])
def copymessage(self, n, tofolder, ton):
"""Copy one message over a specific destination message,
which may or may not already exist."""
path = self.getmessagefilename(n)
# Open it to check that it exists
topath = tofolder.getmessagefilename(ton)
backuptopath = tofolder.getmessagefilename(',%d' % ton)
os.rename(topath, backuptopath)
shutil.copy2(path, topath)
def createmessage(self, n, txt):
"""Create a message, with text from the open file txt."""
path = self.getmessagefilename(n)
backuppath = self.getmessagefilename(',%d' % n)
os.rename(path, backuppath)
def removefromallsequences(self, list):
"""Remove one or more messages from all sequences (including last)
-- but not from 'cur'!!!"""
if hasattr(self, 'last') and self.last in list:
sequences = self.getsequences()
for name, seq in sequences.items():
self.putsequences(sequences)
"""Return the last message number."""
if not hasattr(self, 'last'):
self.listmessages() # Set self.last
"""Set the last message number."""
if hasattr(self, 'last'):
class Message(mimetools.Message):
def __init__(self, f, n, fp = None):
path = f.getmessagefilename(n)
mimetools.Message.__init__(self, fp)
"""String representation."""
return 'Message(%s, %s)' % (repr(self.folder), self.number)
def getheadertext(self, pred = None):
"""Return the message's header text as a string. If an
argument is specified, it is used as a filter predicate to
decide which headers to return (its argument is the header
name converted to lower case)."""
return ''.join(self.headers)
for line in self.headers:
if not line[0].isspace():
hit = pred(line[:i].lower())
if hit: headers.append(line)
def getbodytext(self, decode = 1):
"""Return the message's body text as string. This undoes a
Content-Transfer-Encoding, but does not interpret other MIME
features (e.g. multipart messages). To suppress decoding,
pass 0 as an argument."""
self.fp.seek(self.startofbody)
encoding = self.getencoding()
if not decode or encoding in ('', '7bit', '8bit', 'binary'):
from cStringIO import StringIO
from StringIO import StringIO
mimetools.decode(self.fp, output, encoding)
"""Only for multipart messages: return the message's body as a
list of SubMessage objects. Each submessage object behaves
(almost) as a Message object."""
if self.getmaintype() != 'multipart':
raise Error, 'Content-Type is not multipart/*'
bdry = self.getparam('boundary')
raise Error, 'multipart/* without boundary param'
self.fp.seek(self.startofbody)
mf = multifile.MultiFile(self.fp)
n = "%s.%r" % (self.number, 1 + len(parts))
part = SubMessage(self.folder, n, mf)
"""Return body, either a string or a list of messages."""
if self.getmaintype() == 'multipart':
return self.getbodyparts()
return self.getbodytext()
class SubMessage(Message):
def __init__(self, f, n, fp):
Message.__init__(self, f, n, fp)
if self.getmaintype() == 'multipart':
self.body = Message.getbodyparts(self)
self.body = Message.getbodytext(self)
self.bodyencoded = Message.getbodytext(self, decode=0)
# XXX If this is big, should remember file pointers
"""String representation."""
f, n, fp = self.folder, self.number, self.fp
return 'SubMessage(%s, %s, %s)' % (f, n, fp)
def getbodytext(self, decode = 1):
if type(self.body) == type(''):
if type(self.body) == type([]):
"""Class implementing sets of integers.
This is an efficient representation for sets consisting of several
continuous ranges, e.g. 1-100,200-400,402-1000 is represented
internally as a list of three pairs: [(1,100), (200,400),
(402,1000)]. The internal representation is always kept normalized.
The constructor has up to three arguments:
- the string used to initialize the set (default ''),
- the separator between ranges (default ',')
- the separator between begin and end of a range (default '-')
The separators must be strings (not regexprs) and should be different.
The tostring() function yields a string that can be passed to another
IntSet constructor; __repr__() is a valid IntSet constructor itself.
# XXX The default begin/end separator means that negative numbers are
# not supported very well.
# XXX There are currently no operations to remove set elements.
def __init__(self, data = None, sep = ',', rng = '-'):
if data: self.fromstring(data)
def __cmp__(self, other):
return cmp(self.pairs, other.pairs)
return 'IntSet(%r, %r, %r)' % (self.tostring(), self.sep, self.rng)
while i < len(self.pairs):
alo, ahi = self.pairs[i-1]
self.pairs[i-1:i+1] = [(alo, max(ahi, bhi))]
for lo, hi in self.pairs:
if lo == hi: t = repr(lo)
else: t = repr(lo) + self.rng + repr(hi)
if s: s = s + (self.sep + t)
for lo, hi in self.pairs:
def fromlist(self, list):
new.pairs = self.pairs[:]
return self.pairs[-1][-1]
for lo, hi in self.pairs:
if lo <= x <= hi: return True
for i in range(len(self.pairs)):
if x < lo: # Need to insert before
self.pairs.insert(i, (x, x))
if i > 0 and x-1 == self.pairs[i-1][1]:
if x <= hi: # Already in set
self.pairs.append((x, x))
def addpair(self, xlo, xhi):
self.pairs.append((xlo, xhi))
def fromstring(self, data):
for part in data.split(self.sep):
for subp in part.split(self.rng):
new.append((list[0], list[0]))
elif len(list) == 2 and list[0] <= list[1]:
new.append((list[0], list[1]))
raise ValueError, 'bad data passed to IntSet'
self.pairs = self.pairs + new
# Subroutines to read/write entries in .mh_profile and .mh_sequences
def pickline(file, key, casefold = 1):
pat = re.escape(key) + ':'
prog = re.compile(pat, casefold and re.IGNORECASE)
if not line or not line[0].isspace():
def updateline(file, key, value, casefold = 1):
pat = re.escape(key) + ':(.*)\n'
prog = re.compile(pat, casefold and re.IGNORECASE)
newline = '%s: %s\n' % (key, value)
for i in range(len(lines)):
os.rename(tempfile, file)
os.system('rm -rf $HOME/Mail/@test')
def do(s): print s; print eval(s)
do('mh.listallfolders()')
testfolders = ['@test', '@test/test1', '@test/test2',
'@test/test1/test11', '@test/test1/test12',
'@test/test1/test11/test111']
for t in testfolders: do('mh.makefolder(%r)' % (t,))
do('mh.listsubfolders(\'@test\')')
do('mh.listallsubfolders(\'@test\')')
f = mh.openfolder('@test')
do('f.listallsubfolders()')
seqs['foo'] = IntSet('1-10 12-20', ' ').tolist()
for t in reversed(testfolders): do('mh.deletefolder(%r)' % (t,))
context = mh.getcontext()
f = mh.openfolder(context)
for seq in ('first', 'last', 'cur', '.', 'prev', 'next',
'first:3', 'last:3', 'cur:3', 'cur:-3',
'1:3', '1:-3', '100:3', '100:-3', '10000:3', '10000:-3',
do('f.parsesequence(%r)' % (seq,))
stuff = os.popen("pick %r 2>/dev/null" % (seq,)).read()
list = map(int, stuff.split())