1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
#!/usr/bin/env python3
import string, buglist, smtplib, time, hashlib
import email.mime.multipart, email.mime.text
def send(contact, msg):
"Send a message."
try:
server = smtplib.SMTP('localhost')
#server.set_debuglevel(1)
server.sendmail("esr@thyrsus.com", [contact], msg)
server.quit()
print contact, "OK"
except smtplib.SMTPServerDisconnected:
print "*** Disconnected while mailing", contacr
except smtplib.SMTPSenderRefused:
print "*** Host refused sender for", contact
except smtplib.SMTPRecipientsRefused:
print "*** Recipient address refused for", contact
except smtplib.SMTPDataError:
print "*** Message data refused for", contact
except smtplib.SMTPConnectError:
print "*** Connection refused for", contact
except smtplib.SMTPHeloError:
print "*** HELO refused for", contact
def hashkey(patch):
body = "\n".join(patch.split('\n')[2:]) # Trim off the header lines
m = hashlib.md5()
m.update(body)
return m.digest()
def mailall(filter, hook):
duplicates = {}
for contact in bugs.maildict:
if not contact or contact.startswith("http"):
continue
template = '''\
This is automatically generated email about markup problems in a man
page for which you appear to be responsible. If you are not the right
person or list, please tell me so I can correct my database.
See http://catb.org/~esr/doclifter/bugs.html for details on how and
why these patches were generated. Feel free to email me with any
questions. Note: These patches do not change the modification date of
any manual page. You may wish to do that by hand.
I apologize if this message seems spammy or impersonal. The volume of
markup bugs I am tracking is over five hundred - there is no real
alternative to generating bugmail from a database and template.
'''
reminder = '''
My records indicate that you have accepted this patch, so this is just
a reminder.
'''
unique = {}
pagelist = []
page_to_problems = {}
for (status, pages, problems) in bugs.maildict[contact]:
if 'y' in status or 'r' in status or 'b' in status or 's' in status:
continue
if filter(status, pages, problems, contact):
# Setup
for page in pages.split(","):
pagelist.append(page)
duplicates[page] = []
page_to_problems[page] = problems
# Enable duplicate detection
for page in pagelist:
patch = buglist.pagetofile(page.strip())
if patch is None:
# Meant to generate a unique cookie
body = str(time.time())
else:
d = hashkey(patch)
if d in unique:
if not d in duplicates:
duplicates[d] = []
duplicates[d].append(page)
else:
unique[d] = page
# Now generate explanations
explanations = []
for page in unique.values():
patch = buglist.pagetofile(page.strip())
d = hashkey(patch)
explanation = "Problems with " + page + ":\n"
if d in duplicates:
explanation += "\n(Identical patches should apply to: %s)\n" \
% (" ".join(duplicates[d],))
if 'p' in status:
explanation += reminder
if page.endswith("pm"):
explanation += "\n(May reflect bugs in POD).\n"
explanation += "\n"
patch = buglist.pagetofile(page.strip())
for letter in page_to_problems[page]:
if letter.isalnum():
explanation += "%s\n" % (bugs.codes[letter])
elif letter != '*':
sys.stderr.write("Problem with %s\n" % page)
d = hashkey(patch)
if patch:
this = explanation + patch
else:
this += explanation + "(No patch.)\n"
explanations.append(this)
if explanations:
pagelist = ", ".join(pagelist)
if len(pagelist) > 100:
pagelist = "several man pages you maintain"
body = template \
+ "\n--\n Eric S. Raymond\n"
msg = email.mime.multipart.MIMEMultipart()
msg["To"] = contact
msg["Subject"] = "Problems in " + pagelist
msg.attach(email.mime.text.MIMEText(body))
for x in explanations:
msg.attach(email.mime.text.MIMEText(x))
apply(hook, (contact, str(msg) + "\n"))
if __name__ == '__main__':
import getopt, re, sys
bugs = buglist.Buglist()
selector = None
pagefilter = None
codefilter = None
addressfilter = None
hook = lambda contact, msg: sys.stdout.write(msg)
(options, arguments) = getopt.getopt(sys.argv[1:], "a:c:mp:s:")
for (switch, val) in options:
if switch == '-s': # Select on given status code
selector = val
elif switch == '-p': # Filter on given regexp matching pages
pagefilter = val
elif switch == '-a': # Filter on given regexp matching addressees
addressfilter = val
elif switch == '-c': # Filter on given regexp matching problems
codefilter = val
elif switch == '-m': # Actually send mail
hook = send
if selector:
selector = re.compile(selector)
if pagefilter:
pagefilter = re.compile(pagefilter)
if addressfilter:
addressfilter = re.compile(addressfilter)
if codefilter:
codefilter = re.compile(codefilter)
def filter(status, pages, problems, contact):
if selector and not selector.search(status):
return False
if pagefilter and not pagefilter.search(pages):
return False
if addressfilter and not addressfilter.search(contact):
return False
if codefilter and not codefilter.search(contact):
return False
return True
mailall(filter, hook)
|