diff options
Diffstat (limited to 'news2mail.py')
-rw-r--r-- | news2mail.py | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/news2mail.py b/news2mail.py new file mode 100644 index 0000000..73808b3 --- /dev/null +++ b/news2mail.py @@ -0,0 +1,299 @@ +"""News to mail gateway script. Copyright 2000 Cosimo Alfarano + +Author: Cosimo Alfarano +Date: June 11 2000 + +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. + +normal (what pygs does) operations flow is: +1) reads from stdin NNTP article (readfile) +2) divide headers and body (parsearticle) +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. + +""" + +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) + + + + |