From c50ce75f2e06b6b8abe49e34775d343b74f7e8cd Mon Sep 17 00:00:00 2001 From: Matej Cepl Date: Tue, 26 Feb 2008 17:27:08 +0100 Subject: The original upstream from Debian orig.tar.gz tarball. --- mail2news.py | 320 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 mail2news.py (limited to 'mail2news.py') diff --git a/mail2news.py b/mail2news.py new file mode 100644 index 0000000..d340432 --- /dev/null +++ b/mail2news.py @@ -0,0 +1,320 @@ +"""Mail to news gateway script. Copyright 2000 Cosimo Alfarano + +Author: Cosimo Alfarano +Date: September 16 2000 + +mail2news.py - Copyright 2000 by Cosimo Alfarano +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 email and sends it via SMTP. + +class mail2news is hopefully conform to rfc850. + +""" + +import sys +from os import unlink, getpid +from socket import gethostbyaddr, gethostname +import string +from re import findall +import time +import nntplib +import pyginfo +import tempfile + +class mail2news: + """news to mail gateway class""" + + + reader = None # mode reader +# newsgroups = None # Newsgroups: local.test,local.moderated... +# approved = None # Approved: kame@aragorn.lorien.org + newsserver = 'localhost' # no comment :) + port = 119 + user = None + password = None + + hostname = gethostbyaddr(gethostname())[0] + + heads_dict, smtpheads, nntpheads = {}, {}, {} + email, headers, body = [], [], [] + + + def readfile(self): + + for line in sys.stdin.readlines(): + self.email.append(line) + + if(len(self.email) == 1 and self.email[0][0] == '/'): + file = self.email[0][:-1] + del self.email[0] + for line in open(file,'r').readlines(): + self.email.append(line) + + return 1 + + + def parseemail(self): + """get news email 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? + + for line in self.email: + if not body and len(line) == 1: + body = 1 # starts email body section + + if not body: + try: + # if it is a multi-line header like Received: + if not line[0] in [' ','\t']: + try: + head, value = string.split(line, ' ', 1) + except string.index_error: + value = '' + self.smtpheads[head] = value + else: + self.smtpheads[head] = '%s%s' % \ + (self.smtpheads[head], line) + except (string.index_error), message: + print 'line: %s' % line + print '(probably missing couple "Header: value" in %s)' % line + sys.exit(1) + + elif len(line) > 0 and body: + self.body.append(line) + + except (string.index_error), message: + print message + sys.exit(1) + + return self.smtpheads, self.body + + def puthead(self, dict, list, key): + """private, transform dict entries in list entries + Appends key of dict to list, deleting it from dict. + """ + + if dict.has_key(key): + list.append(key + ' ' + dict.get(key)) + del dict[key] + else: + return 0 + return 1 + + def sortheads(self): + """make list sorted by heads: From: To: Subject: first, others, X-*, X-Resent-* last""" + + set = ('Newsgroups:','From:','To:','X-To:','Cc:','Subject:','Date:','Approved:','References:','Message-Id:') # 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[:9] != 'X-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[:9] == 'X-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.smtpheads.keys(): # fill it w/ smtp old heads + self.heads_dict[header] = self.smtpheads[header] + + for header in self.nntpheads.keys(): # and replace them w/ nntp new heads + self.heads_dict[header] = self.nntpheads[header] + + except KeyError, message: + print message + + return self.heads_dict + + def addheads(self): + """add new header like X-Gateway: + """ + + info = pyginfo.pygsinfo() + + try: + self.heads_dict['X-Gateway:'] = info.PROGNAME + ' ' + \ + info.PROGDESC + ' - Mail to News\n' + +# it is nntpheads stuff +# if(self.newsgroups): +# self.heads_dict['Newsgroups:'] = self.newsgroups + +# if(self.approved): +# self.heads_dict['Approved:'] = self.approved + + except KeyError, message: + print message + + return self.heads_dict + + def renameheads(self): + """rename headers such as Resent-*: to X-Resent-*: + + headers renamed are useless or not rfc 977/850 copliant + handles References/In-Reply-To headers + """ + try: + +### test +# if(post): +# if(self.heads_dict.has_key(post)): +# self.heads_dict['X-Original-' + post] = self.heads_dict[post] +# +# self.heads_dict[post] = self.heads_dict[pre] +# del(self.heads_dict[pre]) +# +# else: +# if(pre[0:2] == 'X-' and self.heads_dict.has_key(pre)): +# self.heads_dict['X-Original-' + pre] = self.heads_dict[pre] +# elif(not pre[0:2] == 'X-' and self.heads_dict.has_key('X-' + pre)): +# self.heads_dict['X-' + pre] = self.heads_dict[pre] +# del(self.heads_dict[pre]) +### end test + + for key in self.heads_dict.keys(): + if(key[:7] in ['Resent-']): + if(self.heads_dict.has_key('X-' + key)): + self.heads_dict[ 'X-Original-' + key ] = self.heads_dict['X-' + key] + self.heads_dict[ 'X-' + key ] = self.heads_dict[key] + del self.heads_dict[key] + + + # In rfc822 References: is considered, but many MUA doen't put it. + if(not self.heads_dict.has_key('References:') and self.heads_dict.has_key('In-Reply-To:')): + print self.heads_dict['In-Reply-To:'] + + # some MUA uses msgid without '<' '>' +# ref = findall('([^\s<>\']+@[^\s<>;:\']+)', \ + # but I prefer use RFC standards + ref = findall('(<[^<>]+@[^<>]+>)', \ + self.heads_dict['In-Reply-To:']) + + # if found, keep first element that seems a Msg-ID. + if(ref and len(ref)): + self.heads_dict['References:'] = '%s\n' % ref[0] + +# if(self.heads_dict.has_key('To:')): +# self.heads_dict['X-To:'] = self.heads_dict['To:'] +# del self.heads_dict['To:'] + + except KeyError, message: + print message + + return self.heads_dict + + + def removeheads(self, heads = None): + """remove headers like Xref: Path: Lines: + """ + + try: + # removing some others useless headers .... (From is not From:) + + rmheads = ['Received:', 'From', 'NNTP-Posting-Host:', \ + 'X-Trace:', 'X-Compliants-To:', 'NNTP-Posting-Date:'] + if(heads): + rmheads.append(heads) + + for head in rmheads: + if self.heads_dict.has_key(head): + del self.heads_dict[head] + +# if self.heads_dict.has_key('From'): # neither 'From ' nor 'From:' +# del self.heads_dict['From'] + +# if self.heads_dict.has_key('NNTP-Posting-Host:'): # neither 'From ' nor 'From:' +# del self.heads_dict[''] + + +# 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:'): + msgid = '\n' % (getpid()) + self.heads_dict['Message-Id:'] = msgid + + except KeyError, message: + print message + + return self.heads_dict + + def sendemail(self): + """Talk to NNTP server and try to send email.""" + try: + msglist = [] + + n = nntplib.NNTP(self.newsserver, self.port, self.user, self.password) + + if(self.reader): + n.putline('mode reader') + resp = n.getline() + print resp + + resp = n.shortcmd('POST') + + # sett RFC977 2.4.2 + if resp[0] <> '3': + raise n.error_reply, str(resp) + + for line in self.headers: + if not line: + break + if line[-1] == '\n': + line = line[:-1] + if line[:1] == '.': + line = '.' + line + n.putline(line) + + for line in self.body: + if not line: + break + if line[-1] == '\n': + line = line[:-1] + if line[:1] == '.': + line = '.' + line + n.putline(line) + + n.putline('.') + n.quit() + return None + except (nntplib.error_reply, nntplib.error_temp, nntplib.error_perm, nntplib.error_proto, nntplib.error_data), message: + return 'NNTP: ' + str(message) -- cgit