diff options
Diffstat (limited to 'news2mail.py')
-rw-r--r-- | news2mail.py | 412 |
1 files changed, 271 insertions, 141 deletions
diff --git a/news2mail.py b/news2mail.py index 78d0ae4..73808b3 100644 --- a/news2mail.py +++ b/news2mail.py @@ -3,12 +3,13 @@ Author: Cosimo Alfarano Date: June 11 2000 -news2mail.py - (C) 2000 by Cosimo Alfarano <Alfarano@Students.CS.UniBo.It> +news2mail.py - Copyright 2000 by Cosimo Alfarano <Alfarano@Students.CS.UniBo.It> You can use this software under the terms of the GPL. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return. Thanks to md for this useful formula. Beer is beer. + Gets news article and sends it via SMTP. class news2mail is hopefully conform to rfc822. @@ -19,151 +20,280 @@ normal (what pygs does) operations flow is: 3) merges NNTP and SMTP heads into a unique heads 4) adds, renames and removes some heads 5) sorts remaining headers starting at top with Received: From: To: Subject: - Date:, normal headers ending with X-* and Resent-* headers. + Date:, normal headers ending with X-* and Resent-* headers. """ -from collections import OrderedDict -import email -from mail2news import VERSION, DESC -import smtplib -from socket import gethostbyaddr, gethostname + import sys +import smtplib +import string +from re import compile +#import getopt import time +#import rfc822 +from socket import gethostbyaddr, gethostname +import tempfile +import pyginfo + +class news2mail: + """news to mail gateway class""" + + TMPFILE = tempfile.mktemp() + wlfile = None + logfile = None + + sender = '' + rcpt = '' + envelope = '' + + smtpserver = 'localhost' + + hostname = gethostbyaddr(gethostname())[0] + + heads_dict, smtpheads, nntpheads = {}, {}, {} + article, headers, body = [], [], [] + + debug = 1 + + def readfile(self): + + for line in sys.stdin.readlines(): + self.article.append(line) + + if (len(self.article) == 1 and self.article[0][0] == '/'): + file = self.article[0][:-1] + del self.article[0] + for line in open(file,'r').readlines(): + self.article.append(line) + + + def parsearticle(self): + """get news article from file or stdin and separate heads from body + + REMEBER: headers value has '\n' as last char. + Use string[:-1] to ignore newline. + """ + + try: + body = 0 # are we in body or in headers? + +# voidline = compile('^$') # I need '\n', ^$ matches anything +# spaceending = compile('\s*\n$') + + for line in self.article: + if not body and len(line) == 1: + body = 1 # starts article body section + + if not body: + try: + head, value = string.split(line, ' ', 1) + self.nntpheads[head] = value + except (string.index_error), message: + print 'string error: %s' % message + print '(probably missing couple "Header: value" in %s)' % line + sys.exit(1) + + elif len(line) > 0 and body: + self.body.append(line) + + return self.nntpheads, self.body + +# except (re.error, string.index_error), message: + except (string.index_error), message: + print message + sys.exit(1) + + + def puthead(self, dict, list, key): + """private, x-form dict entries in list entries""" + + if dict.has_key(key): + list.append(key + ' ' + dict.get(key)) + else: + return 0 + return 1 + + def sortheads(self): + """make list sorting heads, Received: From: To: Subject: first, others, X-*, Resent-* last""" + + set = ('Received:','From:','To:','Subject:','Date:') # put at top + + for k in set: + self.puthead(self.heads_dict,self.headers,k) + + for k in self.heads_dict.keys(): + if k[:2] != 'X-' and k[:7] != 'Resent-' and k not in set: + self.puthead(self.heads_dict,self.headers,k) + + for k in self.heads_dict.keys(): + if k[:2] == 'X-': + self.puthead(self.heads_dict,self.headers,k) + + for k in self.heads_dict.keys(): + if k[:7] == 'Resent-': + self.puthead(self.heads_dict,self.headers,k) + + return self.headers + + + def mergeheads(self): + """make a unique headers dictionary from NNTP and SMTP + single headers dictionaries.""" + + self.heads_dict = {} + + + try: + for header in self.nntpheads.keys(): # fill it w/ nntp old heads + self.heads_dict[header] = self.nntpheads[header] + + for header in self.smtpheads.keys(): # and replace them w/ smtp new heads + self.heads_dict[header] = self.smtpheads[header] + + except KeyError, message: + print message + + return self.heads_dict + + def addheads(self): + """add new header like X-Gateway: Received: + """ + + info = pyginfo.pygsinfo() + + try: + self.heads_dict['X-Gateway:'] = info.PROGNAME + ' ' + \ + info.__doc__ + '\n' + + ##self.heads_dict['X-Gateway:'] = '%s %s\n' % (info.PROGNAME, info.__doc__) + + # to make Received: header + t = time.ctime(time.time()) + + if time.daylight: + tzone = time.tzname[1] + else: + tzone = time.tzname[0] + + # An exemple from debian-italian: + # Received: from murphy.debian.org (murphy.debian.org [216.234.231.6]) + # by smv04.iname.net (8.9.3/8.9.1SMV2) with SMTP id JAA26407 + # for <kame.primo@innocent.com> sent by + # <debian-italian-request@lists.debian.org + + tmp = 'from GATEWAY by ' + self.hostname + \ + ' with ' + info.PROGNAME + \ + '\n\tfor <' + self.rcpt + '> ; ' + \ + t + ' (' + tzone +')\n' + + self.heads_dict['Received:'] = tmp + except KeyError, message: + print message + + return self.heads_dict + + def renameheads(self): + """rename headers such as Newsgroups: to X-Newsgroups: + + headers renamed are useless or not rfc 822 copliant + """ + try: + if self.heads_dict.has_key('Newsgroups:'): + self.heads_dict['X-Newsgroups:'] = self.heads_dict['Newsgroups:'] + del self.heads_dict['Newsgroups:'] + + if self.heads_dict.has_key('NNTP-Posting-Host:'): + self.heads_dict['X-NNTP-Posting-Host:'] = self.heads_dict['NNTP-Posting-Host:'] + del self.heads_dict['NNTP-Posting-Host:'] + except KeyError, message: + print message + + return self.heads_dict + + + def removeheads(self): + """remove headers like Xref: Path: Lines: + """ + + try: + # removing some others useless headers .... + + if self.heads_dict.has_key('Approved:'): + del self.heads_dict['Approved:'] + + if self.heads_dict.has_key('From'): # neither 'From ' nor 'From:' + del self.heads_dict['From'] + + if self.heads_dict.has_key('Xref:'): + del self.heads_dict['Xref:'] + + if self.heads_dict.has_key('Path:'): + del self.heads_dict['Path:'] + + if self.heads_dict.has_key('Lines:'): + del self.heads_dict['Lines:'] + + # it is usually set by INN, if ng is moderated... + if self.heads_dict.has_key('Sender:'): + del self.heads_dict['Sender:'] + + + if self.heads_dict.has_key('Message-id:'): + self.heads_dict['Message-Id:'] = self.heads_dict['Message-id'] + del(self.heads_dict['Message-id']) + + if self.heads_dict.has_key('Message-ID:'): + self.heads_dict['Message-Id:'] = self.heads_dict['Message-ID'] + del(self.heads_dict['Message-ID']) + + # If message-id is not present, I generate it + if not self.heads_dict.has_key('Message-Id:'): + # It should put a real user@domain + msgid = 'pyg@puppapera.org' + + except KeyError, message: + print message + + return self.heads_dict + + def sendarticle(self): + """Talk to SMTP server and try to send email.""" + try: + msglist = [] + + s = smtplib.SMTP(self.smtpserver) + + # put real locahost domain name. + s.helo(self.hostname) + if s.helo_resp is None and s.ehlo_resp is None: + print 'No helo resp' + sys.exit(1) + + resp = s.mail(self.envelope) + if resp[0] != 250: + print 'SMTP error during MAIL cmd: %s %s' % (resp[0], resp[1]) + print 'envelope %s gave problem?' % self.envelope + sys.exit(1) + resp = s.rcpt(self.rcpt) + if resp[0] != 250: + print 'SMTP error during MAIL cmd: %s %s' % (resp[0], resp[1]) + sys.exit(1) + + + msglist.append(string.join(self.headers,'')) + + msglist.append(string.join(self.body,'')) + msg = string.join(msglist,'') + + s.data(msg) + s.quit() + + return 1 + + except (smtplib.SMTPException), messaggio: + print messaggio + sys.exit(1) -# logging.basicConfig(level=logging.DEBUG) -class news2mail(object): - """news to mail gateway class""" - - def __init__(self, verbose=False): - self.wlfile = None - self.logfile = None - self.verbose = verbose - - self.sender = '' - self.rcpt = '' - self.envelope = '' - - self.smtpserver = 'localhost' - - self.hostname = gethostbyaddr(gethostname())[0] - self.heads_dict = {} - self.article, self.headers, self.body = [], [], [] - self.message = self.__addheads(email.message_from_file(sys.stdin)) - def __addheads(self, msg): - """add new header like X-Gateway: Received: - """ - - msg['X-Gateway'] = 'pyg {0} {1}'.format(VERSION, DESC) - - # to make Received: header - t = time.ctime(time.time()) - - if time.daylight: - tzone = time.tzname[1] - else: - tzone = time.tzname[0] - - # An example from debian-italian: - # Received: from murphy.debian.org (murphy.debian.org [216.234.231.6]) - # by smv04.iname.net (8.9.3/8.9.1SMV2) with SMTP id JAA26407 - # for <kame.primo@innocent.com> sent by - # <debian-italian-request@lists.debian.org - - tmp = 'from GATEWAY by ' + self.hostname + \ - ' with pyg' + \ - '\n\tfor <' + self.rcpt + '> ; ' + \ - t + ' (' + tzone + ')\n' - - msg['Received'] = tmp - - return msg - - def __renameheads(self): - """remove headers like Xref: Path: Lines: - rename headers such as Newsgroups: to X-Newsgroups: - - headers renamed are useless or not rfc 822 copliant - """ - try: - if 'Newsgroups' in self.message: - self.message['X-Newsgroups'] = \ - self.message['Newsgroups'] - del self.message['Newsgroups'] - - if 'NNTP-Posting-Host' in self.message: - self.message['X-NNTP-Posting-Host'] = \ - self.message['NNTP-Posting-Host'] - del self.message['NNTP-Posting-Host'] - except KeyError as ex: - print(ex) - - try: - # removing some others useless headers .... - # that includes BOTH 'From ' and 'From' - # 'Sender is usually set by INN, if ng is moderated... - for key in ('Approved', 'From', 'Xref', 'Path', 'Lines', 'Sender'): - if key in self.message: - del self.message[key] - - if 'Message-id' in self.message: - msgid = self.message['Message-id'] - del self.message['Message-id'] - self.message['Message-Id'] = msgid - else: - # It should put a real user@domain - self.heads_dict['Message-Id'] = 'pyg@puppapera.org' - - if 'References' in self.message and \ - 'In-Reply-To' not in self.message: - refs = self.message['References'].split() - self.message['In-Reply-To'] = refs[-1] - - except KeyError, message: - print message - - def __sortheads(self): - """make list sorting heads, Received: From: To: Subject: first, - others, X-*, Resent-* last""" - - # put at top - header_set = ('Received', 'From', 'To', 'Subject', 'Date') - - heads_dict = OrderedDict(self.message) - for hdr in self.message.keys(): - del self.message[hdr] - - for k in header_set: - if k in heads_dict: - self.message[k] = heads_dict[k] - - for k in heads_dict: - if not k.startswith('X-') and not k.startswith('Resent-') \ - and k not in header_set: - self.message[k] = heads_dict[k] - - for k in heads_dict: - if k.startswith('X-'): - self.message[k] = heads_dict[k] - - for k in heads_dict: - if k.startswith('Resent-'): - self.message[k] = heads_dict[k] - - def process_message(self): - """phase 3: - format rfc 822 headers from input article - """ - self.__renameheads() # remove other heads - self.__sortheads() - - def sendarticle(self): - """Talk to SMTP server and try to send email.""" - s = smtplib.SMTP(self.smtpserver) - s.set_debuglevel(self.verbose) - - s.sendmail(self.envelope, self.rcpt, self.message.as_string()) - - s.quit() |