Skip to content

Commit

Permalink
sync
Browse files Browse the repository at this point in the history
  • Loading branch information
ahknight committed Dec 13, 2015
1 parent 8ad62d0 commit 0ff75bc
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 137 deletions.
125 changes: 2 additions & 123 deletions emlx/__init__.py
Original file line number Diff line number Diff line change
@@ -1,123 +1,2 @@
#!/usr/bin/env python

import plistlib, email, mailbox

class EmlxMessage(object):
msg = None
plist = None

def __init__(self, message=None):
if isinstance(message, bytes):
start = end = 0
end = message.find(b'\n')
if end is -1:
return
msg_size = int(message[start:end])

start = end + 1
end = start + msg_size
if start > 0 and end > 0:
self.msg = email.message_from_bytes(message[start:end])
if start > 0 and end > 0:
xml = message[end:]
if xml:
self.plist = plistlib.loads(xml)

@property
def flags(self):
attrs = {}

if 'flags' in self.plist:
flags = int(self.plist['flags'])
attrs['read'] = (flags & 1 << 0) > 0
attrs['deleted'] = (flags & 1 << 1) > 0
attrs['answered'] = (flags & 1 << 2) > 0
attrs['encrypted'] = (flags & 1 << 3) > 0
attrs['flagged'] = (flags & 1 << 4) > 0
attrs['recent'] = (flags & 1 << 5) > 0
attrs['draft'] = (flags & 1 << 6) > 0
attrs['initial'] = (flags & 1 << 7) > 0
attrs['forwarded'] = (flags & 1 << 8) > 0
attrs['redirected'] = (flags & 1 << 9) > 0
attrs['attachments'] = (flags & 3 << 10) >> 10 # (6 bits)
attrs['priority'] = (flags & 7 << 16) >> 16 # (7 bits)
attrs['signed'] = (flags & 1 << 23) > 0
attrs['junk'] = (flags & 1 << 24) > 0
attrs['not junk'] = (flags & 1 << 25) > 0
attrs['font size delta'] = (flags & 7 << 26) >> 7 # (3 bits)
attrs['junk set'] = (flags & 1 << 29) > 0
attrs['highlight text in toc'] = (flags & 1 << 30) > 0
attrs['(unused)'] = (flags & 1 << 31) > 0

return attrs

@property
def date_sent(self):
date = None
if 'date-sent' in self.plist and self.plist['date-sent'] is not 0:
date = self.plist['date-sent']
return date

@property
def date_received(self):
date = None
if 'date-received' in self.plist and self.plist['date-received'] is not 0:
date = self.plist['date-received']
return date

@property
def date_last_viewed(self):
date = None
if 'date-last-viewed' in self.plist and self.plist['date-last-viewed'] is not 0:
date = self.plist['date-last-viewed']
return date

def __bytes__(self):
msg = bytes(self.msg)
msg_size = bytes(str(len(msg)).encode("utf8"))
meta = plistlib.dumps(self.plist)
return (msg_size + b"\n" + msg + meta)

def __str__(self):
if not self.msg:
return ""
return str(self.msg)

def __unicode__(self):
if not self.msg:
return ""
return unicode(self.msg)

def get_maildir_message(self):
m = mailbox.MaildirMessage(self.msg)
m.set_subdir("new")

flags_dict = self.flags
if flags_dict['draft']:
m.add_flag('D')
if flags_dict['flagged']:
m.add_flag('F')
if flags_dict['forwarded'] or flags_dict['redirected']:
m.add_flag('P')
if flags_dict['answered']:
m.add_flag('R')
if flags_dict['read']:
m.add_flag('S')
if flags_dict['deleted']:
m.add_flag('T')
if self.date_received is not None:
m.set_date(self.date_received)

return m

if __name__ == "__main__":
import sys
f = open(sys.argv[1], "rb")
original = f.read()
f.close()
m = EmlxMessage(original)

generated = bytes(m)
print(original)
print()
print(generated)
# import .message
# import .mailbox
67 changes: 53 additions & 14 deletions emlx/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,46 @@
import os
import sys
import time
from mailbox import Maildir
from maildir_lite import Maildir

from emlx.message import EmlxMessage
from emlx.progress import Progress


def find_mailboxes(path):
if os.path.isdir(path) is False:
return []

paths = []
for root, dirs, files in os.walk(path):
if root.endswith(".mbox") and "Info.plist" in files:
paths.append(root)

for a_dir in dirs:
paths.extend(find_mailboxes(a_dir))

return paths


def import_mailbox(path, destination):
pass

import emlx
from .progress import Progress

def import_message(path, mailbox):
"""
Reads a single message at :arg:path and adds it to the Maildir :arg:mailbox.
"""
f = open(path, "rb")
data = f.read()
f.close()
msg = emlx.EmlxMessage(data)
mailbox.add(msg.get_maildir_message())
msg = EmlxMessage(data)
mailbox.add_message(msg.get_maildir_message())


def enumerate_messages(path):
"""
Walks :arg:path and returns a list of all files ending with ``.emlx``.
"""
if os.path.isdir(path) is False:
return [path]

Expand All @@ -25,7 +52,20 @@ def enumerate_messages(path):
paths.extend([os.path.join(root, name) for name in files if name.endswith(".emlx")])
return paths

from multiprocessing import Pool
# from multiprocessing.dummy import Pool

def import_msg(path):
global maildir, p, last
import_message(path, maildir)
p.increment()
if time.time() > (last + 0.5):
last = time.time()
p.print_status_line("converting")

def main():
global maildir, p, last

if len(sys.argv) == 1:
print("usage: emlx-to-maildir.py path [path ...] maildir")
print(" Paths can be a mix of emlx files and directories to be searched for emlx files.")
Expand All @@ -38,18 +78,17 @@ def main():
output_path = sys.argv[-1:][0]

maildir = Maildir(output_path, create=True)
maildir.lazy = True

p = Progress(len(input_paths), unit="m")
p = Progress(len(input_paths)/4, unit="m")
last = time.time()

for path in input_paths:
import_message(path, maildir)
p.increment()
if time.time() > (last + 0.5):
last = time.time()
print("[%02d%%] %-8s %-5s" % (p.percentage(), p.overall_rate_str(), p.time_remaining_str()), end="\r")

print("[%02d%%] %-8s %-5s" % (100, p.overall_rate_str(), p.time_elapsed_str()))
pool = Pool(4)
pool.map(import_msg, input_paths)
pool.close()
pool.join()
p.print_status_line()


if __name__ == "__main__":
main()
Empty file added emlx/mailbox.py
Empty file.
134 changes: 134 additions & 0 deletions emlx/message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env python

import plistlib # 3.4+
from maildir_lite import MaildirMessage


class EmlxMessage(object):
content = b""
content_size = 0
plist = {}

def __init__(self, message=None):
if isinstance(message, bytes):
# The size of the message is the first line of the file.
start = end = 0
end = message.find(b'\n')
if end is -1:
return
self.content_size = int(message[start:end])

# Read in the message portion.
start = end + 1
end = start + self.content_size
if start > 0 and end > 0:
self.content = message[start:end]

# Read in the plist metadata at the end.
if start > 0 and end > 0:
meta = message[end:]
if meta:
self.plist = plistlib.loads(meta)

def __str__(self):
if not self.content:
return ""
return str(self.content)

def __bytes__(self):
content_size = str(self.content_size).encode("utf8")
meta = plistlib.dumps(self.plist)
return (content_size + b"\n" + self.content + meta)

def as_string(self, *args, **kwargs):
return str(self)

def as_bytes(self, *args, **kwargs):
return bytes(self)

@property
def flags(self):
attrs = {}

if 'flags' in self.plist:
flags = int(self.plist['flags'])
attrs['read'] = (flags & 1 << 0) > 0
attrs['deleted'] = (flags & 1 << 1) > 0
attrs['answered'] = (flags & 1 << 2) > 0
attrs['encrypted'] = (flags & 1 << 3) > 0
attrs['flagged'] = (flags & 1 << 4) > 0
attrs['recent'] = (flags & 1 << 5) > 0
attrs['draft'] = (flags & 1 << 6) > 0
attrs['initial'] = (flags & 1 << 7) > 0
attrs['forwarded'] = (flags & 1 << 8) > 0
attrs['redirected'] = (flags & 1 << 9) > 0
attrs['attachments'] = (flags & 3 << 10) >> 10 # (6 bits)
attrs['priority'] = (flags & 7 << 16) >> 16 # (7 bits)
attrs['signed'] = (flags & 1 << 23) > 0
attrs['junk'] = (flags & 1 << 24) > 0
attrs['not junk'] = (flags & 1 << 25) > 0
attrs['font size delta'] = (flags & 7 << 26) >> 7 # (3 bits)
attrs['junk set'] = (flags & 1 << 29) > 0
attrs['highlight text in toc'] = (flags & 1 << 30) > 0
attrs['(unused)'] = (flags & 1 << 31) > 0

return attrs

@property
def date_sent(self):
date = None
DATE_SENT = 'date-sent'
if DATE_SENT in self.plist and self.plist[DATE_SENT] is not 0:
date = self.plist[DATE_SENT]
return date

@property
def date_received(self):
date = None
DATE_RECEIVED = 'date-received'
if DATE_RECEIVED in self.plist and self.plist[DATE_RECEIVED] is not 0:
date = self.plist[DATE_RECEIVED]
return date

@property
def date_last_viewed(self):
date = None
DATE_LAST_VIEWED = 'date-last-viewed'
if DATE_LAST_VIEWED in self.plist and self.plist[DATE_LAST_VIEWED] is not 0:
date = self.plist[DATE_LAST_VIEWED]
return date

def get_maildir_message(self):
m = MaildirMessage(self.content)
m.set_subdir("new")

if self.date_received is not None:
m.set_date(self.date_received)

flags_dict = self.flags
if flags_dict['draft']:
m.add_flag('D')
if flags_dict['flagged']:
m.add_flag('F')
if flags_dict['forwarded'] or flags_dict['redirected']:
m.add_flag('P')
if flags_dict['answered']:
m.add_flag('R')
if flags_dict['read']:
m.add_flag('S')
if flags_dict['deleted']:
m.add_flag('T')

return m

if __name__ == "__main__":
import sys
f = open(sys.argv[1], "rb")
original = f.read()
f.close()
m = EmlxMessage(original)

generated = bytes(m)
print(original)
print()
print(generated)
2 changes: 2 additions & 0 deletions setup.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/usr/bin/env python3

from setuptools import setup, find_packages

setup(
Expand Down

0 comments on commit 0ff75bc

Please sign in to comment.