~mhall119/+junk/click-store-stats

« back to all changes in this revision

Viewing changes to ubuntustats/mail.py

  • Committer: mhall119
  • Date: 2013-10-29 19:15:53 UTC
  • Revision ID: mhall119@ubuntu.com-20131029191553-fk065fquxynwlfh4
initial graph scripts

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from mailbox import PortableUnixMailbox
 
2
from email import message_from_file
 
3
from email.errors import MessageParseError
 
4
from email.utils import parseaddr, parsedate
 
5
from calendar import timegm
 
6
from datetime import datetime
 
7
import string
 
8
import os
 
9
import re
 
10
 
 
11
from paths import mbox_dir, stamp_dir
 
12
 
 
13
MESSAGE_NOT_PARSEABLE = object()
 
14
 
 
15
class MailResult(object):
 
16
    email = None
 
17
    name = None
 
18
    timestamp = None
 
19
    package = None
 
20
    version = None
 
21
    signer_email = None
 
22
    signer_name = None
 
23
    msg_id = None
 
24
    version = None
 
25
 
 
26
    def __init__(self, msg_id, package=None, version=None):
 
27
        self.msg_id = msg_id
 
28
        if package:
 
29
            self.package = package
 
30
        if version:
 
31
            self.version = version
 
32
 
 
33
def last_msg_id(mbox):
 
34
    stamp_file = os.path.join(stamp_dir, mbox+".stamp")
 
35
    if not os.path.exists(stamp_file):
 
36
        return ""
 
37
    return open(stamp_file).read().strip()
 
38
 
 
39
def write_last_msg_id(mbox, msg_id):
 
40
    if not os.path.exists(stamp_dir):
 
41
        os.makedirs(stamp_dir)
 
42
    stamp_file = os.path.join(stamp_dir, mbox+".stamp")
 
43
    if os.path.exists(stamp_file):
 
44
        os.remove(stamp_file)
 
45
    f = open(stamp_file, "w")
 
46
    f.write(msg_id)
 
47
    f.close()
 
48
 
 
49
def download_archive(mbox):
 
50
    if not os.path.exists(mbox_dir):
 
51
        os.makedirs(mbox_dir)
 
52
    url =  "http://daniel.holba.ch/lists/%s.mbox" % (mbox)
 
53
    filename = os.path.join(mbox_dir, os.path.basename(url))
 
54
    pwd = os.getcwd()
 
55
    args = "-q "
 
56
    if os.path.exists(filename):
 
57
        args += "-c"
 
58
    os.system("cd %s; wget %s %s; cd %s" % (mbox_dir, args, url, pwd))
 
59
    return (os.path.join(mbox_dir, os.path.basename(url)), last_msg_id(mbox))
 
60
 
 
61
def message_factory(fp):
 
62
    try:
 
63
        return message_from_file(fp)
 
64
    except MessageParseError:
 
65
        # Don't return None since that will stop the mailbox iterator.
 
66
        print "error in ", fp
 
67
        return MESSAGE_NOT_PARSEABLE
 
68
 
 
69
def get_persons_from_payload(pl):
 
70
    changed_by = ""
 
71
    signed_by = ""
 
72
    res = re.findall(r"Changed-By: (.*?) <(.*?)>", pl, re.DOTALL)
 
73
    if res:
 
74
        changed_by = res[0]
 
75
    else:
 
76
        fallback_regexes = [ r"Changed-By: <(.*?)>", r"Changed-By: (.*?)" ]
 
77
        for regex in fallback_regexes:
 
78
            if not res:
 
79
                res = re.findall(regex, pl, re.DOTALL)
 
80
                if res:
 
81
                    changed_by = ["", res[0]]
 
82
    res = re.findall(r"Signed-By: (.*?) <(.*?)>", pl, re.DOTALL)
 
83
    if res:
 
84
        signed_by = res[0]
 
85
    else:
 
86
        fallback_regex = [ r"Signed-By: <(.*?)>", r"Signed-By: (.*?)" ]
 
87
        for regex in fallback_regex:
 
88
            if not res:
 
89
                res = re.findall(regex, pl, re.DOTALL)
 
90
                if res:
 
91
                    signed_by = [ "", res[0]]
 
92
    return (changed_by, signed_by)
 
93
 
 
94
def find_in_subject(subject):
 
95
    regexes = [ r"\[ubuntu\/.*?\]\s+(.*)\s+(.+?)\s+\(Accepted\)",
 
96
                r"Accepted\:\s+(.*?)\s+(.*)\s+\(source\)",
 
97
                r"Accepted\s+(.*?)\s+(.*)\s+\(source\)",
 
98
              ]
 
99
    for regex in regexes:
 
100
        ret = re.findall(regex, subject, re.DOTALL)
 
101
        if ret:
 
102
            return map(lambda a: string.strip(a, u"\n\t ,"), ret[0])
 
103
    return (None, None)
 
104
 
 
105
def extract_from_subject(subject):
 
106
    for blacklist_item in [ "(raw-ddtp-tarball)" ]:
 
107
        if blacklist_item in subject:
 
108
            return (None, None)
 
109
    (pkg, version) = find_in_subject(subject)
 
110
    if not pkg and not version:
 
111
        return (None, None)
 
112
    if "_" in pkg:
 
113
        pkg = string.strip(pkg.split("_")[0], u"\n\t ,")
 
114
    return (pkg, version)
 
115
 
 
116
def scan(messages, last_msg_id, uploads=True):
 
117
    data = []
 
118
    for count, message in enumerate(messages):
 
119
        # Skip broken messages.
 
120
        if message is MESSAGE_NOT_PARSEABLE:
 
121
            continue
 
122
 
 
123
        msg_id = message.get('Message-Id')
 
124
        # if we checked this mbox before we only need to start reading
 
125
        # from last_msg_id
 
126
        if last_msg_id and not data and msg_id != last_msg_id:
 
127
            continue
 
128
 
 
129
        if uploads:
 
130
            package, version = extract_from_subject(message.get("subject").strip())
 
131
            if not package:
 
132
                continue
 
133
 
 
134
            mail = MailResult(msg_id, package, version)
 
135
        else:
 
136
            mail = MailResult(msg_id)
 
137
        
 
138
        sent_date = parsedate(message.get('date'))
 
139
        mail.timestamp = datetime.utcfromtimestamp(timegm(sent_date))
 
140
        if uploads:
 
141
            pl = message.get_payload()
 
142
            if type(pl) == list:
 
143
                pl = pl[0].get_payload()
 
144
            (changed_by, signed_by) = get_persons_from_payload(pl)
 
145
            if not changed_by or not signed_by:
 
146
                mail.name, mail.email = parseaddr(message.get('from'))
 
147
            else:
 
148
                mail.name, mail.email = changed_by
 
149
                mail.signer_name, mail.signer_email = signed_by
 
150
        data += [ mail ]
 
151
    return (data, mail.msg_id)
 
152
 
 
153
def scan_archive(mailbox_file, last_msg_id, uploads=True):
 
154
    mbox = PortableUnixMailbox(open(mailbox_file, 'rb'), message_factory)
 
155
    return scan(mbox, last_msg_id, uploads)