aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatěj Cepl <mcepl@cepl.eu>2023-05-25 10:15:47 +0200
committerMatěj Cepl <mcepl@cepl.eu>2023-05-25 11:01:18 +0200
commitec4b49d843e67b31b33ac81bef55346353f1d04c (patch)
tree5f60ffae4d6ebe180c5ee4d51d468bf154535251
parent8006d981ce26fe8c1140e33b9476c08470d59f30 (diff)
downloadpygn-ec4b49d843e67b31b33ac81bef55346353f1d04c.tar.gz
refactor: rearrange the project to the src/ layout.0.10.3
Fix also pyproject.toml to generate what seems right. Add the explicit dependency on nntplib for Python >= 3.12 (gh#python/cpython!104894). Fixes: https://todo.sr.ht/~mcepl/pygn/7
-rw-r--r--.gitignore2
-rw-r--r--MANIFEST.in4
-rw-r--r--docs/HOWTO.md33
-rw-r--r--docs/pygm2n.168
-rw-r--r--docs/pygn2m.179
-rw-r--r--pyproject.toml22
-rw-r--r--setup.py43
-rw-r--r--src/mail2news.py (renamed from mail2news.py)4
-rw-r--r--src/news2mail.py (renamed from news2mail.py)0
-rwxr-xr-xsrc/pygm2n99
-rwxr-xr-xsrc/pygn2m126
-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.py4
-rw-r--r--test/whitelist-pygn2m3
16 files changed, 427 insertions, 60 deletions
diff --git a/.gitignore b/.gitignore
index 277d95c..166ec5f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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.py b/src/wlp.py
index e3bcddd..e3bcddd 100644
--- a/wlp.py
+++ b/src/wlp.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'
+}