diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | MANIFEST.in | 4 | ||||
-rw-r--r-- | docs/HOWTO.md | 33 | ||||
-rw-r--r-- | docs/pygm2n.1 | 68 | ||||
-rw-r--r-- | docs/pygn2m.1 | 79 | ||||
-rw-r--r-- | pyproject.toml | 22 | ||||
-rw-r--r-- | setup.py | 43 | ||||
-rw-r--r-- | src/mail2news.py (renamed from mail2news.py) | 4 | ||||
-rw-r--r-- | src/news2mail.py (renamed from news2mail.py) | 0 | ||||
-rwxr-xr-x | src/pygm2n | 99 | ||||
-rwxr-xr-x | src/pygn2m | 126 | ||||
-rw-r--r-- | src/whitelist.py (renamed from whitelist.py) | 0 | ||||
-rw-r--r-- | src/wlp.py (renamed from wlp.py) | 0 | ||||
-rw-r--r-- | src/wlp_parser.py (renamed from wlp_parser.py) | 0 | ||||
-rw-r--r-- | test/test_pyg.py | 4 | ||||
-rw-r--r-- | test/whitelist-pygn2m | 3 |
16 files changed, 427 insertions, 60 deletions
@@ -1,6 +1,6 @@ build/ *.pyc -pygn.egg-info/ +pygn.*-info/ dist/ pyg.log *.suo diff --git a/MANIFEST.in b/MANIFEST.in index e8c25b7..9726a32 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,3 @@ -include examples/* +recursive-include examples * +recursive-include test * +global-exclude *.py[cod] diff --git a/docs/HOWTO.md b/docs/HOWTO.md new file mode 100644 index 0000000..e39c123 --- /dev/null +++ b/docs/HOWTO.md @@ -0,0 +1,33 @@ +MUST BE FINISHED! + + +It is a (very) small HOWTO to make pyg working properly. + +pygm2n: + +Pre: a fully working MTA (ie postfix) where you can run procmail or any other MDA. +A news server (local or remote) where you can create groups (admin +privileges). + +Create a user, ie mailgate, set its procmail as: + +:0 bhc: +| pygm2n -n local.test + +or its maildrop (thanks to Joy): + +dotlock pygm2n.`echo $$`.lock { + `pygm2n -n local.test` +} + +you can use -a your@address and -s nntphost if local.test is moderated, +or nntphost isn't localhost + +[NOTE: if you've configuration for any other MDA, please file a wishlist +bug against pyg] + +Create local.test (if it doen't exist). + +Now any mail you will write to mailgate user, will be sent to the +server. Read local.test on localhost (or nntphost), you will see +message. diff --git a/docs/pygm2n.1 b/docs/pygm2n.1 new file mode 100644 index 0000000..63f2e09 --- /dev/null +++ b/docs/pygm2n.1 @@ -0,0 +1,68 @@ +.\" wing requests are required for all man pages. +.TH pygm2n 1 "Sun Sep 12 18:10:00 CEST 2000" "" "Python Gateway mail to news" +.SH NAME +pygm2n - Python Gateway mail to news +.SH SYNOPSIS +.B pygm2n +.BR -n +.IR newsgroups +[ +.BR -s +.IR newsserver +] +[ +.BR -h +] + +.SH DESCRIPTION +.B IMPORTANT: +this man page is to be continued. The Whole pyg gateway is in +.B devel.\ state. +try -h option for more detailed option. + +pygm2n reads from stdin an email, sending it to newsgroups, a comma separated list without spaces of newsgroup names (at least one), rfc799 compliant. + +If pygm2n reads from stdin a sigle line starting with /, it is +considered an absolute path to a single-email mailbox, +so pygm2n will open and read it. + +.B Note +that now pyg can't read a real mailbox, with many emails. If you +give it in input, pyg will post the whole mailbox as a single email. + +\" The following requests should be uncommented and +.\" used where appropriate. This next request is +.\" for sections 2 and 3 function return values only. +.\" .Sh RETURN VALUES +.\" This next request is for sections 1, 6, 7 & 8 only +.\" .Sh ENVIRONMENT +.\" .Sh FILES +.SH EXAMPLES +There is some documetation in /urs/share/doc/pyg + +I created mailgate user (moderator of local.moderated ng). +Subscribe to a list with this user (or simply email one message to). +Every email posted to this user will send to newsgroups, +in its .procmailrc I've put something like: + +:0 bh +* ^From *mailinglist-request@lists.debian.org +| $HOME/pygm2n -n local.debian.mailinglist + + +.\" This next request is for sections 1, 6, 7 & 8 only +.\" (command return values (to shell) and +.\" fprintf/stderr type diagnostics) +.\" .Sh DIAGNOSTICS +.\" The next request is for sections 2 and 3 error +.\" and signal handling only. +.\" .Sh ERRORS +.\" .Sh SEE ALSO +.\" .Sh STANDARDS +.\" .Sh HISTORY +.SH AUTHORS +Cosimo Alfarano <alfarano@students.cs.unibo.it> + +.SH BUGS +Boh. send any bug, advice or opinion to the author, please. + diff --git a/docs/pygn2m.1 b/docs/pygn2m.1 new file mode 100644 index 0000000..5b2750e --- /dev/null +++ b/docs/pygn2m.1 @@ -0,0 +1,79 @@ +.\" wing requests are required for all man pages. +.TH pygn2m 1 "Sun Sep 12 22:40:00 CEST 2000" "" "Python Gateway news to mail" +.SH NAME +pygn2m - Python Gateway news to mail +.SH SYNOPSIS +.B pygs +.BR -t +.IR recipient@domain1 +.BR -s +.IR sender@domain2 +[ +.BR -e +.IR envelope@domain3 +] +[ +.BR -h +] + +.SH DESCRIPTION +.B IMPORTANT: +this man page is to be continued. The Whole pyg gateway is in +.B devel.\ state. +try -h option for more detailed option. + +pygn2m reads from stdin a nntp article, sending it to recipient@domain1 +a rfc822 compliant email setting Resent-Sender: sender@domain2 +and envelope envelope@domain3 if exists, else sender@domain2. + +If pygn2m reads from stdin a sigle line starting with /, it is +considered an absolute path to an article (ie in a spool), +so pygn2m will open and read it. + +\" The following requests should be uncommented and +.\" used where appropriate. This next request is +.\" for sections 2 and 3 function return values only. +.\" .Sh RETURN VALUES +.\" This next request is for sections 1, 6, 7 & 8 only +.\" .Sh ENVIRONMENT +.\" .Sh FILES +.SH EXAMPLES +There is some documetation in /urs/share/doc/pyg + +I created mailgate user (moderator of local.moderated ng). +Every article posted in local.moderated is sent to mailgate, +in its .procmailrc I've put: + +:0 bhc +* ^To: *local-moderated +| $HOME/pygs -t kalfa@localhost -e mailgate@students.cs.unibo.it -s 'cosimo@students.cs.unibo.it' + + +where kalfa@localhost is the recipient (usually a mailing list) + +Here is an header extract from kalfa@localhost mbox: + +From mailgate@students.cs.unibo.it +From: whosentnntparticle@domain4 +To: kalfa@localhost +Resent-Sender: cosimo@students.cs.unibo.it + +note that sender and envelope are different. rfc822 says that Sender: have to be a human user (not a program or similia). envelope can mailgate user. + + +.\" This next request is for sections 1, 6, 7 & 8 only +.\" (command return values (to shell) and +.\" fprintf/stderr type diagnostics) +.\" .Sh DIAGNOSTICS +.\" The next request is for sections 2 and 3 error +.\" and signal handling only. +.\" .Sh ERRORS +.\" .Sh SEE ALSO +.\" .Sh STANDARDS +.\" .Sh HISTORY +.SH AUTHOR +Cosimo Alfarano <alfarano@students.cs.unibo.it> + +.SH BUGS +Boh. send any bug to the author, please. + diff --git a/pyproject.toml b/pyproject.toml index 35a7abf..1cbc27c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools"] +requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" [project] @@ -8,8 +8,8 @@ authors = [ {name = "Cosimo Alfarano", email = "kalfa@debian.org"}, {name = "Matěj Cepl", email = "mcepl@cepl.eu"}, ] +description = 'The Python Gateway Script: news2mail mail2news gateway' keywords=["nntp", "email", "gateway"] -readme = "README.md" requires-python = ">=3.6" license = {text = "GPL-3.0"} classifiers = [ @@ -23,9 +23,15 @@ classifiers = [ 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)' ] dependencies = [ - "rply", + 'rply', + 'nntplib; python_version>="3.12"' ] -dynamic = ["version", "description"] +dynamic = ["version", "readme"] + +[project.urls] +Homepage = "https://sr.ht/~mcepl/pygn/" +"Bug Tracker" = "https://todo.sr.ht/~mcepl/pygn" +Repository = "https://git.sr.ht/~mcepl/pygn" [project.scripts] pygm2n = "mail2news:main" @@ -33,10 +39,4 @@ pygn2m = "news2mail:main" [tool.setuptools.dynamic] version = {attr = "mail2news.__version__"} -description = {attr = "mail2news.__description__"} - -[tool.setuptools.packages.find] -where = ["."] -include = ["*.py"] -exclude = ["setup.py"] -namespaces = false +readme = {file = "README.md"} diff --git a/setup.py b/setup.py deleted file mode 100644 index e763429..0000000 --- a/setup.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - - -from __future__ import absolute_import -from mail2news import VERSION, DESC -import os.path -from setuptools import setup - - -def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read() - - -setup(name='pygn', - version=VERSION, # the current Debian version is 0.9.8 - author="Cosimo Alfarano, Matej Cepl", - author_email="kalfa@debian.org, mcepl@cepl.eu", - description=DESC, - long_description=read('README'), - url='https://gitlab.com/mcepl/pyg', - py_modules=['mail2news', 'news2mail', 'whitelist', 'wlp', - 'wlp_parser'], - test_suite="test", - scripts=['pygm2n', 'pygn2m'], - requires=['rply'], - license="GPLv3", - keywords=["nntp", "email", "gateway"], - classifiers=[ - 'Development Status :: 3 - Alpha', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Intended Audience :: System Administrators', - 'Topic :: Utilities', - 'Topic :: Communications :: Usenet News', - 'Environment :: Console', - 'Operating System :: OS Independent', - 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)' - ] - ) diff --git a/mail2news.py b/src/mail2news.py index 2f64f6c..6e8fe53 100644 --- a/mail2news.py +++ b/src/mail2news.py @@ -31,8 +31,8 @@ import tempfile # This is the single source of Truth # Yes, it is awkward to have it assymetrically here # and not in news2mail as well. -VERSION = '0.10.2' -DESC = "The Python Gateway Script: news2mail mail2news gateway" +__version__ = '0.10.3' +__description__ = 'The Python Gateway Script: news2mail mail2news gateway' class mail2news(object): diff --git a/news2mail.py b/src/news2mail.py index 33d2590..33d2590 100644 --- a/news2mail.py +++ b/src/news2mail.py diff --git a/src/pygm2n b/src/pygm2n new file mode 100755 index 0000000..3629857 --- /dev/null +++ b/src/pygm2n @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""News to mail gateway script. Copyright 2000 Cosimo Alfarano + +Author: Cosimo Alfarano +Date: June 11 2000 + +pygs - 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. +""" +from __future__ import print_function + +import argparse +import logging +import mail2news +import nntplib +import sys + +# logging.basicConfig(level=logging.DEBUG) + +def parse_cmdline(): + parser = argparse.ArgumentParser( + description='%s version %s - Copyright 2000 Cosimo Alfarano\n%s' % + ('pyg', mail2news.VERSION, mail2news.DESC)) + + 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='', + help='NNTP server user (for authentication)') + parser.add_argument('-p', '--password', default='', + help='NNTP server password (for authentication)') + parser.add_argument('-P', '--port', default='') + parser.add_argument('-e', '--envellope', default='') + parser.add_argument('-l', '--logfile') + + parser.add_argument('-T', '--test', action='store_true', + help='test mode (not send article via NNTP)') + parser.add_argument('-v', '--verbose', action='store_true', + help='verbose output ' + + '(usefull with -T option for debugging)') + + args = parser.parse_args() + + if not args.newsgroup: + raise argparse.ArgumentError('Error: Missing Newsgroups\n') + + return args + + +"""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: + + """phase 1: + check and set pyg's internal variables + """ + opt = parse_cmdline() + + m2n = mail2news.mail2news(opt) + owner = None + + """phase 3: + format rfc 822 headers from input article + """ + m2n.renameheads() # rename useless heads + m2n.removeheads() # remove other heads + + m2n.sortheads() # sort remaining heads :) + + if opt.verbose: + print(m2n.message.as_string()) + + logging.debug('m2n.payload = len %d', len(m2n.message.get_payload())) + if len(m2n.message.get_payload()) > 0: +# wl.logmsg(m2n.heads_dict,wl.ACCEPT,owner) + if not opt.test: + try: + resp = m2n.sendemail() + except nntplib.NNTPError as ex: + print(ex) + +except KeyboardInterrupt: + print('Keyboard Interrupt') + sys.exit(0) diff --git a/src/pygn2m b/src/pygn2m new file mode 100755 index 0000000..a2c07cb --- /dev/null +++ b/src/pygn2m @@ -0,0 +1,126 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""News to mail gateway script. Copyright 2000 Cosimo Alfarano + +Author: Cosimo Alfarano +Date: June 11 2000 + +pygs - 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 from stdin and sends it via SMTP. +""" +from __future__ import print_function + +import argparse +from mail2news import VERSION, DESC +import news2mail +import os +import sys +import whitelist + + +def parse_cmdline(): + """ + set a dictionary with smtp new header in gw parameter (gw.smtpheads) + return (test,verbose) boolean tuple + """ + parser = argparse.ArgumentParser( + description='pyg version %s - Copyright 2000 Cosimo Alfarano\n%s' % + (VERSION, DESC)) + + parser.add_argument('-H', '--smtpserver', default='') + parser.add_argument('-s', '--sender', required=True, default='') + parser.add_argument('-e', '--envelope', default='') + parser.add_argument('-t', '--to', dest='rcpt', required=True) + parser.add_argument('-w', '--wlfile') + parser.add_argument('-l', '--logfile') + + parser.add_argument('-T', '--test', + help='test mode (not send article via SMTP)', + action='store_true') + parser.add_argument('-v', '--verbose', help='verbose output', + action='store_true') + + opts = parser.parse_args() + +# 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 opts.rcpt == '' or opts.sender == '': + raise argparse.ArgumentError('missing command line option') + + if opts.envelope == '' and opts.sender != '': + opts.envelope = opts.sender + + return opts + + +"""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 +""" + +"""phase 1: +check and set pyg's internal variables +""" + +# it returns only test, other parms are set directly in the actual +# parameter +args = parse_cmdline() + +n2m = news2mail.news2mail(verbose=args.verbose) +owner = None + +# check if n2m has some file prefercences set on commandline +if args.wlfile is None: + wl = os.path.expanduser(os.path.join(os.path.dirname(__file__), 'pyg.whitelist')) +else: + wl = args.wlfile + +if args.logfile is None: + log = os.path.expanduser(os.path.join(os.path.dirname(__file__), 'pyg.log')) +else: + log = args.logfile + +wl = whitelist.whitelist(wl, log) + +"""phase 2: +check whitelist for user's permission +""" + +# make a first check of From: address +owner = wl.checkfrom(n2m.message['From']) +if owner is None: + if sys.stdin.isatty() == 1 or args.test: + print ('"%s" is not in whitelist!' % (n2m.message['From'][:-1])) + else: + wl.logmsg(n2m.nntpheads, wl.DENY) + + # if verbose, I want to print out headers, so I can't + # exit now. + if not args.verbose: + sys.exit(1) + +# Reformat the message +n2m.process_message() + +# prints formatted email message only (without send) if user wants +if args.verbose: + print(n2m.message.as_string()) + +if owner is None: + sys.exit(1) + +"""phase 4: +open smtp connection and send e-mail +""" + +wl.logmsg(n2m.heads_dict, wl.ACCEPT, owner) +if not args.test: + n2m.sendarticle() diff --git a/whitelist.py b/src/whitelist.py index 4e02f0e..4e02f0e 100644 --- a/whitelist.py +++ b/src/whitelist.py diff --git a/wlp_parser.py b/src/wlp_parser.py index e2e0d19..e2e0d19 100644 --- a/wlp_parser.py +++ b/src/wlp_parser.py diff --git a/test/test_pyg.py b/test/test_pyg.py index 7a4e48a..6044520 100644 --- a/test/test_pyg.py +++ b/test/test_pyg.py @@ -30,7 +30,7 @@ one line test def test_m2n(self): with open('examples/mail') as in_mail: - pid = subprocess.Popen(['python', 'pygm2n', '-Tv', '-n', 'pyg.test'], + pid = subprocess.Popen([sys.executable, 'src/mail2news.py', '-Tv', '-n', 'pyg.test'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True) @@ -61,7 +61,7 @@ Resent-Sender: sender@example.com def test_n2m(self): with open('examples/articletest.accepted') as in_mail: - pid = subprocess.Popen(['python', 'pygn2m', '-Tvt', 'test@example.com', + pid = subprocess.Popen([sys.executable, 'src/news2mail.py', '-Tvt', 'test@example.com', '-s', 'sender@example.com', '-w', 'examples/whitelist.example'], stdin=subprocess.PIPE, diff --git a/test/whitelist-pygn2m b/test/whitelist-pygn2m new file mode 100644 index 0000000..33044bc --- /dev/null +++ b/test/whitelist-pygn2m @@ -0,0 +1,3 @@ +<ceplm@seznam.cz> { + From: = 'ceplm@seznam.cz' +} |