aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mail2news.py178
-rwxr-xr-xpygm2n251
2 files changed, 175 insertions, 254 deletions
diff --git a/mail2news.py b/mail2news.py
index d340432..3011a4e 100644
--- a/mail2news.py
+++ b/mail2news.py
@@ -3,7 +3,7 @@
Author: Cosimo Alfarano
Date: September 16 2000
-mail2news.py - Copyright 2000 by Cosimo Alfarano <Alfarano@Students.CS.UniBo.It>
+mail2news.py - (C) 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.
@@ -16,19 +16,17 @@ class mail2news is hopefully conform to rfc850.
"""
import sys
-from os import unlink, getpid
+from os import 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
@@ -42,20 +40,25 @@ class mail2news:
heads_dict, smtpheads, nntpheads = {}, {}, {}
email, headers, body = [], [], []
-
- def readfile(self):
+ def readfile(self, opt):
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():
+ for line in open(file, 'r').readlines():
self.email.append(line)
-
- return 1
+ # introduce nntpheads
+ if opt.newsgroup != '':
+ # TODO put it directly to self.message when we have it
+ self.nntpheads['Newsgroups:'] = opt.newsgroup + '\n'
+ if opt.approver != '':
+ self.nntpheads['Approved:'] = opt.approver + '\n'
+
+ return 1
def parseemail(self):
"""get news email from file or stdin and separate heads from body
@@ -66,7 +69,7 @@ class mail2news:
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
@@ -74,7 +77,7 @@ class mail2news:
if not body:
try:
# if it is a multi-line header like Received:
- if not line[0] in [' ','\t']:
+ if line[0] not in [' ', '\t']:
try:
head, value = string.split(line, ' ', 1)
except string.index_error:
@@ -84,17 +87,18 @@ class mail2news:
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
+ 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):
@@ -102,7 +106,7 @@ class mail2news:
Appends key of dict to list, deleting it from dict.
"""
- if dict.has_key(key):
+ if key in dict:
list.append(key + ' ' + dict.get(key))
del dict[key]
else:
@@ -110,39 +114,42 @@ class mail2news:
return 1
def sortheads(self):
- """make list sorted by heads: From: To: Subject: first, others, X-*, X-Resent-* last"""
+ """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
+ # put at top
+ set = ('Newsgroups:', 'From:', 'To:', 'X-To:', 'Cc:', 'Subject:',
+ 'Date:', 'Approved:', 'References:', 'Message-Id:')
for k in set:
- self.puthead(self.heads_dict,self.headers,k)
+ 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)
+ 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)
-
+ 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)
-
+ self.puthead(self.heads_dict, self.headers, k)
+
return self.headers
-
-
+
def mergeheads(self):
- """make a unique headers dictionary from NNTP and SMTP
+ """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
+ 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
+
+ # and replace them w/ nntp new heads
+ for header in self.nntpheads.keys():
self.heads_dict[header] = self.nntpheads[header]
except KeyError, message:
@@ -151,7 +158,7 @@ class mail2news:
return self.heads_dict
def addheads(self):
- """add new header like X-Gateway:
+ """add new header like X-Gateway:
"""
info = pyginfo.pygsinfo()
@@ -163,10 +170,10 @@ class mail2news:
# 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
@@ -180,45 +187,46 @@ class mail2news:
"""
try:
-### test
-# if(post):
-# if(self.heads_dict.has_key(post)):
-# self.heads_dict['X-Original-' + post] = self.heads_dict[post]
+### test
+# if(post):
+# if(post in self.heads_dict):
+# 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])
+# self.heads_dict[post] = self.heads_dict[pre]
+# del(self.heads_dict[pre])
+#
+# else:
+# if(pre[0:2] == 'X-' and pre in self.heads_dict):
+# self.heads_dict['X-Original-' + pre] = self.heads_dict[pre]
+# elif(not pre[0:2] == 'X-' and 'X-' + pre in self.heads_dict):
+# 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]
+ if ('X-' + key) in self.heads_dict:
+ 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:')):
+ if ('References:' not in self.heads_dict) and \
+ ('In-Reply-To:' in self.heads_dict):
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:'])
+ 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['References:'] = '%s\n' % ref[0]
+
+# if('To:' in self.heads_dict):
# self.heads_dict['X-To:'] = self.heads_dict['To:']
# del self.heads_dict['To:']
@@ -227,48 +235,46 @@ class mail2news:
return self.heads_dict
-
- def removeheads(self, heads = None):
+ 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:']
+ 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):
+ if head in self.heads_dict:
del self.heads_dict[head]
-
-# if self.heads_dict.has_key('From'): # neither 'From ' nor 'From:'
+
+# if 'From' in self.heads_dict: # neither 'From ' nor 'From:'
# del self.heads_dict['From']
-# if self.heads_dict.has_key('NNTP-Posting-Host:'): # neither 'From ' nor 'From:'
+# # neither 'From ' nor 'From:'
+# if 'NNTP-Posting-Host:' in self.heads_dict:
# del self.heads_dict['']
-
-# if self.heads_dict.has_key('Lines:'):
+# if 'Lines:' in self.heads_dict:
# del self.heads_dict['Lines:']
# it is usually set by INN, if ng is moderated...
-# if self.heads_dict.has_key('Sender:'):
+# if 'Sender:' in self.heads_dict:
# del self.heads_dict['Sender:']
-
- if self.heads_dict.has_key('Message-id:'):
+ if 'Message-id:' in self.heads_dict:
self.heads_dict['Message-Id:'] = self.heads_dict['Message-id:']
del(self.heads_dict['Message-id:'])
-
- if self.heads_dict.has_key('Message-ID:'):
+
+ if 'Message-ID:' in self.heads_dict:
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:'):
+ if 'Message-Id:' not in self.heads_dict:
msgid = '<pyg.%d@tuchailepuppapera.org>\n' % (getpid())
self.heads_dict['Message-Id:'] = msgid
@@ -280,19 +286,18 @@ class mail2news:
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)
+ 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':
+ # sett RFC977 2.4.2
+ if resp[0] != '3':
raise n.error_reply, str(resp)
for line in self.headers:
@@ -316,5 +321,6 @@ class mail2news:
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)
+ except (nntplib.error_reply, nntplib.error_temp, nntplib.error_perm,
+ nntplib.error_proto, nntplib.error_data), message:
+ return 'NNTP: ' + str(message)
diff --git a/pygm2n b/pygm2n
index cf677f2..ba98908 100755
--- a/pygm2n
+++ b/pygm2n
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-
"""News to mail gateway script. Copyright 2000 Cosimo Alfarano
Author: Cosimo Alfarano
@@ -13,200 +12,116 @@ Thanks to md for this useful formula. Beer is beer.
Gets news article and sends it via SMTP.
"""
+from __future__ import print_function
+import logging
+import sys
-import sys, os
-import getopt
-from string import split
-
-sys.path.append('/usr/lib/pyg')
+import argparse
+import mail2news
import pyginfo
-import mail2news
-
-def parse_cmdline(gw):
- """Parses cmdline with getopt. and returns a dictionary with
- smtp new header
- """
- opt, arg = None, None
- test, verbose = 0, 0
-# retnull = (None, None)
- retnull = None
-
- retval = { 'test': 0,
- 'verbose': 0 }
-
- try:
- opt, arg = getopt.getopt(sys.argv[1:],"a:s:n:u:p:P:hvVTM")
- except (getopt.error), message:
- print '%s: %s\n' % (sys.argv[0], message)
- sys.exit(1)
-
- if len(sys.argv) == 1 or opt == []:
- gw.smtpheads = None
- return retnull
-
- for i in range(len(opt)):
- if opt[i][0] == '-h':
- gw.nntpheads = None
- return retnull
- elif opt[i][0] == '-v':
- gw.nntpheads = None
- return retnull
- elif opt[i][0] == '-n':
- gw.nntpheads['Newsgroups:'] = opt[i][1] + '\n'
- elif opt[i][0] == '-a':
- gw.nntpheads['Approved:'] = opt[i][1] + '\n'
- elif opt[i][0] == '-s':
- gw.newsserver = opt[i][1]
- elif opt[i][0] == '-P':
- gw.port = int(opt[i][1])
-# elif opt[i][0] == '-d':
-# gw.debug = 1
- elif opt[i][0] == '-u':
- gw.user = opt[i][1]
- elif opt[i][0] == '-p':
- gw.password = opt[i][1]
- elif opt[i][0] == '-T':
- retval['test'] = 1
- elif opt[i][0] == '-V':
- retval['verbose'] = 1
- elif opt[i][0] == '-M':
- gw.reader = 1
-
- if not gw.nntpheads.has_key('Newsgroups:'):
- print 'Error: Missing Newsgroups\n'
- return retnull
-
-
-# By rfc822 [Resent-]Sender: should be ever set, unless == From:
-# (not this case). Should be a human, while [Resent-]From: may be a program.
-
-# if gw.rcpt == '' or gw.sender == '':
-# print 'missing command line option'
-# gw.smtpheads = None
-# return retnull
-
-# if gw.envelope == '' and gw.sender != '':
-# gw.smtpheads['Resent-From:'] = gw.sender + '\n'
-# gw.envelope = gw.sender
-# elif gw.envelope == -1:
-# gw.smtpheads = None
-# return retnull
-
- sys.argv[1:] = arg
-
-# return (test, verbose)
- return retval
-
-
-def usage():
- i = pyginfo.pygsinfo()
-
- print '%s version %s - Copyright 2000 Cosimo Alfarano' % (i.PROGNAME, i.VERSION)
- print i.PROGDESC + ' - Mail to News'
- print
- print 'usage: %s -n newsgroup [-h] [-a approver] [-n newsgroup] [-T] [-V]' % split(sys.argv[0],'/')[-1]
- print '-n newsgroup[s] (specified as comma separated without spaces list)'
- print '-u user | -p passwword (for auth to newsserver)'
- print '-a address of moderator/approver'
- print '-s servername'
-# print '-d for debug'
- print '-h or -v for this info'
- print '-T for test mode (not send article via NNTP)'
- print '-V for verbose output (usefull with -T option for debugging)'
+logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s',
+ level=logging.DEBUG)
-"""main is structured in 4 phases:
- 1) check and set pyg's internal variables
- 2) check whitelist for users' permission
- 3) format rfc 822 headers from input article
- 4) open smtp connection and send e-mail
-"""
+sys.path.append('/usr/lib/pyg')
-try:
+def parse_cmdline():
+ i = pyginfo.pygsinfo()
+ parser = argparse.ArgumentParser(
+ description='%s version %s - Copyright 2000 Cosimo Alfarano\n%s' %
+ (i.PROGNAME, i.VERSION, i.__doc__))
+
+ parser.add_argument('-s', '--newsserver', default='')
+ parser.add_argument('-a', '--approver', default='',
+ help="address of moderator/approver")
+ parser.add_argument('-n', '--newsgroup', default='',
+ help='newsgroup[s] (specified as comma separated ' +
+ 'without spaces list)', required=True)
+ parser.add_argument('-u', '--user', default='')
+ parser.add_argument('-p', '--password', default='',
+ help='password (for auth to newsserver)')
+ parser.add_argument('-P', '--port', default='')
+ parser.add_argument('-M', '--reader', default='')
- """phase 1:
- check and set pyg's internal variables
- """
+ parser.add_argument('-e', '--envellope', default='')
+ parser.add_argument('-t', '--to', dest='rcpt')
+ parser.add_argument('-w', '--wlfile')
+ parser.add_argument('-l', '--logfile')
- m2n = mail2news.mail2news()
- owner = None
+ parser.add_argument('-T', '--test', action='store_true',
+ help='test mode (not send article via NNTP)')
+ parser.add_argument('-d', '--debug', action='store_true')
+ parser.add_argument('-V', '--verbose', action='store_true',
+ help='verbose output ' +
+ '(usefull with -T option for debugging)')
- opt = parse_cmdline(m2n)
- if(opt == None):
- usage()
- sys.exit(0)
+ args = parser.parse_args()
+ if not args.newsgroup:
+ raise argparse.ArgumentError('Error: Missing Newsgroups\n')
- # check if m2n has some file prefercences set on commandline
-# if(m2n.wlfile == None):
-# wl = os.environ['HOME'] + '/pyg.whitelist'
-# else:
-# wl = m2n.wlfile
-#
-# if(m2n.logfile == None):
-# log = os.environ['HOME'] + '/pyg.log'
-# else:
-# log = m2n.logfile
+ logging.debug('args = %s', args)
+ return args
-# wl = whitelist.whitelist(wl,log)
- # reads stdin and parses article separating head from body
- m2n.readfile()
- m2n.parseemail()
+"""main is structured in 4 phases:
+ 1) check and set pyg's internal variables
+ 2) check whitelist for users' permission
+ 3) format rfc 822 headers from input article
+ 4) open smtp connection and send e-mail
+"""
+try:
-# for line in m2n.email:
-# print line[:-1]
+ """phase 1:
+ check and set pyg's internal variables
+ """
-# for line in m2n.smtpheads.keys():
-# print line
-# print m2n.smtpheads[line][:-1]
+ m2n = mail2news.mail2news()
+ owner = None
- """phase 2:
- check whitelist for user's permission
- """
+ opt = parse_cmdline()
- # make a first check of From: address
-# owner = wl.checkfrom(m2n.nntpheads['From:'])
-# if(owner == None):
-# if(sys.stdin.isatty()==1 or test or verbose):
-# print ('"%s" is not in whitelist!' % (m2n.nntpheads['From:'][:-1]))
-# else:
-# wl.logmsg(m2n.nntpheads,wl.DENY)
-# sys.exit(1)
+ # reads stdin and parses article separating head from body
+ m2n.readfile(opt)
+ m2n.parseemail()
- """phase 3:
- format rfc 822 headers from input article
- """
+ """phase 2:
+ check whitelist for user's permission
+ """
- m2n.mergeheads() # make unique dict from NNTP and SMTP dicts
-
- m2n.addheads() # add some important heads
- m2n.renameheads() # rename useless heads
- m2n.removeheads() # remove other heads
+ """phase 3:
+ format rfc 822 headers from input article
+ """
+
+ m2n.mergeheads() # make unique dict from NNTP and SMTP dicts
- m2n.sortheads() # sort remaining heads :)
+ m2n.addheads() # add some important heads
+ m2n.renameheads() # rename useless heads
+ m2n.removeheads() # remove other heads
- if(opt['verbose']):
- for line in m2n.headers:
- print line[:-1]
+ m2n.sortheads() # sort remaining heads :)
- """phase 4:
- open smtp connection and send e-mail
- """
+ if opt.verbose:
+ for line in m2n.headers:
+ print(line[:-1])
+
+ """phase 4:
+ open smtp connection and send e-mail
+ """
- if(len(m2n.headers) > 0 and len(m2n.body) > 0):
-# wl.logmsg(m2n.heads_dict,wl.ACCEPT,owner)
- if(not opt['test']):
- resp = m2n.sendemail()
- if resp:
- print resp
+ if len(m2n.headers) > 0 and len(m2n.body) > 0:
+# wl.logmsg(m2n.heads_dict,wl.ACCEPT,owner)
+ if not opt.test:
+ resp = m2n.sendemail()
+ if resp:
+ print(resp)
except KeyboardInterrupt:
- print 'Keyboard Interrupt'
- sys.exit(0)
+ print('Keyboard Interrupt')
+ sys.exit(0)