Hi! While making a Debian package for Papercut, I made a few changes in Papercut that you may be interested in. Attached is a patch that does the following: * Remove she-bang from module source files Theses Python files are not meant to be run alone, adding she-bangs makes lintian barf, and darcs setting +x where it should not. * Use os.path.join more extensively os.path.join was already used in the Maildir storage. This function is now used more extensively to avoid errors related to trailing slashes. * Add support to run in background Following Python Cookbook reciepe 6.7. A pid file is created on startup and removed on exit. * Add support for command-line options Using the optparse Python module. It allows the daemon to run in foreground mode using [-f | --foreground]. * Fix a bug in article receiving Line separators were not stripped from articles during reading, but added later when joining them in do_POST. * Add automatic hostname detection If nntp_hostname is set to None, the hostname is automatically detected using socket.gethostname. A fallback to 127.0.0.1 is triggered on exceptions. This hostname is then resolved via socket.gethostbyname to give NNTPServer the correct IP address. Also, please note that most of your your copyrights are outdated. Thank you for this software, it's exactly what I have been looking for. Regards, -- Jérémy
--- papercut-0.9.13.orig/auth/__init__.py +++ papercut-0.9.13/auth/__init__.py @@ -1,3 +1,2 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: __init__.py,v 1.1 2002/04/04 23:10:20 jpm Exp $ --- papercut-0.9.13.orig/auth/mysql.py +++ papercut-0.9.13/auth/mysql.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: mysql.py,v 1.3 2003/04/26 00:24:55 jpm Exp $ import MySQLdb --- papercut-0.9.13.orig/auth/postnuke_phpbb_mysql_users.py +++ papercut-0.9.13/auth/postnuke_phpbb_mysql_users.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: postnuke_phpbb_mysql_users.py,v 1.1 2004/08/01 01:51:48 jpm Exp $ import MySQLdb --- papercut-0.9.13.orig/auth/phpnuke_phpbb_mysql_users.py +++ papercut-0.9.13/auth/phpnuke_phpbb_mysql_users.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. import MySQLdb import settings --- papercut-0.9.13.orig/auth/phpbb_mysql_users.py +++ papercut-0.9.13/auth/phpbb_mysql_users.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: phpbb_mysql_users.py,v 1.4 2003/09/19 03:11:51 jpm Exp $ import MySQLdb --- papercut-0.9.13.orig/auth/phorum_pgsql_users.py +++ papercut-0.9.13/auth/phorum_pgsql_users.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: phorum_pgsql_users.py,v 1.3 2004/01/14 22:26:40 jpm Exp $ from pyPgSQL import PgSQL --- papercut-0.9.13.orig/auth/phorum_mysql_users.py +++ papercut-0.9.13/auth/phorum_mysql_users.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: phorum_mysql_users.py,v 1.5 2004/01/14 22:26:40 jpm Exp $ import MySQLdb --- papercut-0.9.13.orig/storage/phorum_pgsql.py +++ papercut-0.9.13/storage/phorum_pgsql.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: phorum_pgsql.py,v 1.13 2004/08/01 01:51:48 jpm Exp $ from pyPgSQL import PgSQL @@ -10,6 +9,7 @@ import strutil import smtplib import md5 +import os.path # patch by Andreas Wegmann <Andreas.Wegmann@VSA.de> to fix the handling of unusual encodings of messages q_quote_multiline = re.compile("=\?(.*?)\?[qQ]\?(.*?)\?=.*?=\?\\1\?[qQ]\?(.*?)\?=", re.M | re.S) @@ -132,7 +132,8 @@ def get_notification_emails(self, forum_id): # open the configuration file - fp = open("%s%s.php" % (settings.phorum_settings_path, forum_id), "r") + fp = open("%s.php" % os.path.join(settings.phorum_settings_path, + forum_id), "r") content = fp.read() fp.close() # get the value of the configuration variable @@ -186,7 +187,8 @@ forum_id, forum_name = self.cursor.fetchone() forum_name.strip() # open the main configuration file - fp = open("%sforums.php" % (settings.phorum_settings_path), "r") + fp = open("%s.php" % os.path.join(settings.phorum_settings_path, + 'forums'), "r") content = fp.read() fp.close() # regexps to get the content from the phorum configuration files --- papercut-0.9.13.orig/storage/__init__.py +++ papercut-0.9.13/storage/__init__.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: __init__.py,v 1.4 2002/03/26 22:55:00 jpm Exp $ --- papercut-0.9.13.orig/storage/strutil.py +++ papercut-0.9.13/storage/strutil.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: strutil.py,v 1.3 2003/02/22 00:46:18 jpm Exp $ import time --- papercut-0.9.13.orig/storage/p2p.py +++ papercut-0.9.13/storage/p2p.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: p2p.py,v 1.2 2002/04/03 23:07:22 jpm Exp $ import settings --- papercut-0.9.13.orig/storage/mysql.py +++ papercut-0.9.13/storage/mysql.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: mysql.py,v 1.44 2004/08/01 01:51:48 jpm Exp $ import MySQLdb --- papercut-0.9.13.orig/storage/phpbb_mysql.py +++ papercut-0.9.13/storage/phpbb_mysql.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002, 2003, 2004 Joao Prado Maia. See the LICENSE file for more information. # $Id: phpbb_mysql.py,v 1.20 2004/08/01 01:51:48 jpm Exp $ import MySQLdb --- papercut-0.9.13.orig/storage/phpnuke_phpbb_mysql.py +++ papercut-0.9.13/storage/phpnuke_phpbb_mysql.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002, 2003, 2004 Joao Prado Maia. See the LICENSE file for more information. import MySQLdb import time --- papercut-0.9.13.orig/storage/phorum_mysql.py +++ papercut-0.9.13/storage/phorum_mysql.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: phorum_mysql.py,v 1.47 2004/08/01 01:51:48 jpm Exp $ import MySQLdb @@ -10,6 +9,7 @@ import strutil import smtplib import md5 +import os.path # patch by Andreas Wegmann <Andreas.Wegmann@VSA.de> to fix the handling of unusual encodings of messages q_quote_multiline = re.compile("=\?(.*?)\?[qQ]\?(.*?)\?=.*?=\?\\1\?[qQ]\?(.*?)\?=", re.M | re.S) @@ -126,7 +126,8 @@ def get_notification_emails(self, forum_id): # open the configuration file - fp = open("%s%s.php" % (settings.phorum_settings_path, forum_id), "r") + fp = open("%s.php" % os.path.join(settings.phorum_settings_path, + forum_id), "r") content = fp.read() fp.close() # get the value of the configuration variable @@ -179,7 +180,8 @@ self.cursor.execute(stmt) forum_id, forum_name = self.cursor.fetchone() # open the main configuration file - fp = open("%sforums.php" % (settings.phorum_settings_path), "r") + fp = open("%s.php" % os.path.join(settings.phorum_settings_path, + 'forums'), "r") content = fp.read() fp.close() # regexps to get the content from the phorum configuration files --- papercut-0.9.13.orig/storage/mime.py +++ papercut-0.9.13/storage/mime.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: mime.py,v 1.1 2002/02/03 06:15:25 jpm Exp $ import re --- papercut-0.9.13.orig/storage/mbox.py +++ papercut-0.9.13/storage/mbox.py @@ -1,8 +1,8 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: mbox.py,v 1.7 2004/08/01 01:51:48 jpm Exp $ import os +import os.path import mailbox import settings import strutil @@ -19,7 +19,7 @@ self.mbox_dir = settings.mbox_path def get_mailbox(self, filename): - return mailbox.PortableUnixMailbox(open(self.mbox_dir + filename)) + return mailbox.PortableUnixMailbox(open(os.path.join(self.mbox_dir, filename))) def get_file_list(self): return os.listdir(self.mbox_dir) --- papercut-0.9.13.orig/storage/maildir.py +++ papercut-0.9.13/storage/maildir.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2004 Scott Parish, Joao Prado Maia # See the LICENSE file for more information. # $Id: maildir.py,v 1.2 2004/08/01 01:51:48 jpm Exp $ --- papercut-0.9.13.orig/storage/forwarding_proxy.py +++ papercut-0.9.13/storage/forwarding_proxy.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python import nntplib import re import time --- papercut-0.9.13.orig/papercut.py +++ papercut-0.9.13/papercut.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: papercut.py,v 1.93 2005/03/05 04:06:54 jpm Exp $ +import atexit +import socket import SocketServer import sys import os @@ -9,6 +11,7 @@ import re import traceback import StringIO +from optparse import OptionParser # papercut based modules import settings @@ -772,7 +775,7 @@ 440 posting not allowed 441 posting failed """ - lines = "\r\n".join(self.article_lines) + lines = "".join(self.article_lines) # check the 'Newsgroups' header group_name = newsgroups_regexp.search(lines, 0).groups()[0].strip() if not backend.group_exists(group_name): @@ -870,6 +873,24 @@ time.sleep(1) sys.exit(0) + def exit_cleanup(): + os.remove(settings.pid_file) + + parser = OptionParser(version="%%prog %s" % __VERSION__) + parser.add_option("-f", "--foreground", action="store_false", + dest="background", default=True, + help="don't run in background") + (options, args) = parser.parse_args() + + if len(args) > 0: + parser.print_help() + sys.exit(1) + + # check for another papercut running + if os.path.exists(settings.pid_file): + print >>sys.stderr, "papercut seems already running." + sys.exit(1) + # dynamic loading of the appropriate storage backend module temp = __import__('storage.%s' % (settings.storage_backend), globals(), locals(), ['Papercut_Storage']) if settings.nntp_cache == 'yes': @@ -879,10 +900,83 @@ # now for the authentication module, if needed if settings.nntp_auth == 'yes': + # check for the appropriate configuration + if auth_backend == '': + sys.exit("Please configure the 'nntp_auth' and 'auth_backend' " + + "options correctly and restart Papercut.") temp = __import__('auth.%s' % (settings.auth_backend), globals(), locals(), ['Papercut_Auth']) auth = temp.Papercut_Auth() + if not settings.nntp_hostname: + try: + settings.nntp_hostname = socket.gethostname() + except: + print >>sys.stderr, ( + "Unable to determine hostname. Using 127.0.0.1 as a " + + "fallback. Please set nntp_hostname in " + + "/etc/papercut/settings.py.") + settings.nntp_hostname = "127.0.0.1" + + try: + ip_address = socket.gethostbyname(settings.nntp_hostname) + except: + print >>sys.stderr, ( + "Unable to lookup %s. Using 127.0.0.1 as a " + + "fallback. Please check nntp_hostname in " + + "/etc/papercut/settings.py." % settings.nntp_hostname) + ip_address = "127.0.0.1" + + if options.background: + # first fork + try: + pid = os.fork() + if pid > 0: + # Exit first parent + sys.exit(0) + except OSError, e: + print >>sys.stderr, "fork #1 failed: %d (%s)" % ( + e.errno, e.strerror) + sys.exit(1) + + # unlink parent environment + fp = open('/dev/null', 'rw') + sys.stdin = sys.__stdin__ = fp + #sys.stdout = sys.__stdout__ = fp + #sys.stderr = sys.__stderr__ = fp + del fp + os.chdir('/') + os.setsid() + os.umask(0) + + # second fork + try: + pid = os.fork() + if pid > 0: + # write pid file and exit parent process + fp = open(settings.pid_file, 'w') + fp.write("%d\n" % pid) + fp.close() + sys.exit(0) + except OSError, e: + print >>sys.stderr, "fork #2 failed: %d (%s)" % ( + e.errno, e.strerror) + sys.exit(1) + else: # foreground + fp = open(settings.pid_file, 'w') + fp.write("%d\n" % os.getpid()) + fp.close() + + settings.logEvent( + 'Papercut %s (%s storage module) - starting up (PID: %d)' + % (__VERSION__, settings.storage_backend, os.getpid())) + + # register signal handler + signal.signal(signal.SIGTERM, sighandler) signal.signal(signal.SIGINT, sighandler) - print 'Papercut %s (%s storage module) - starting up' % (__VERSION__, settings.storage_backend) - server = NNTPServer((settings.nntp_hostname, settings.nntp_port), NNTPRequestHandler) + signal.signal(signal.SIGQUIT, sighandler) + # register cleanup function + atexit.register(exit_cleanup) + + server = NNTPServer((ip_address, settings.nntp_port), + NNTPRequestHandler) server.serve_forever() --- papercut-0.9.13.orig/TODO +++ papercut-0.9.13/TODO @@ -4,6 +4,4 @@ - Set the self.commands and self.extensions on the storage extensions, as some storages do not support all commands - MODE STREAM (it means several commands at the same time without waiting for responses) - Check more the patterns of searching (wildmat) -> backend.format_wildcards() -> Work in progress -- Fork the server to the background automatically (using fork()?) -- Make a command line option to make the server actually run on the foreground (-f option?) - Add a --verbose flag to replace the current __DEBUG__ flag \ No newline at end of file --- papercut-0.9.13.orig/portable_locker.py +++ papercut-0.9.13/portable_locker.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # $Id: portable_locker.py,v 1.2 2002/10/03 01:05:24 jpm Exp $ # Note: this was originally from Python Cookbook, which was --- papercut-0.9.13.orig/papercut_cache.py +++ papercut-0.9.13/papercut_cache.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information. # $Id: papercut_cache.py,v 1.7 2002/10/04 03:14:38 jpm Exp $ @@ -6,6 +5,7 @@ import md5 import time import os +import os.path import cPickle import portable_locker # papercut settings file @@ -72,7 +72,8 @@ def _get_filename(self, *args, **kwds): arguments = '%s%s%s' % (self.name, args, kwds) - return '%s%s' % (settings.nntp_cache_path, binascii.hexlify(md5.new(arguments).digest())) + return os.path.join(settings.nntp_cache_path, + binascii.hexlify(md5.new(arguments).digest())) class Cache:
Attachment:
pgpp7ro1u6Fhe.pgp
Description: PGP signature