diff options
| -rw-r--r-- | Mailman/Defaults.py.in | 8 | ||||
| -rw-r--r-- | Mailman/Digester.py | 22 | ||||
| -rw-r--r-- | Mailman/mm_cfg.py.dist.in | 15 | ||||
| -rw-r--r-- | Mailman/smtplib.py | 104 | ||||
| -rw-r--r-- | modules/mm_cfg.py.in | 15 | ||||
| -rw-r--r-- | modules/mm_defaults.py | 8 | ||||
| -rw-r--r-- | modules/mm_defaults.py.in | 8 | ||||
| -rw-r--r-- | modules/mm_digest.py | 22 | ||||
| -rw-r--r-- | modules/smtplib.py | 104 |
9 files changed, 277 insertions, 29 deletions
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in index 31f470f7e..f5c82d242 100644 --- a/Mailman/Defaults.py.in +++ b/Mailman/Defaults.py.in @@ -9,7 +9,7 @@ this file, to override the distributed defaults with site-specific ones. import os VERSION = '1.0b1.2' -__version__ = "$Revision: 423 $" +__version__ = "$Revision: 445 $" # Many site-specific settings # @@ -21,8 +21,10 @@ DEFAULT_URL = 'http://www.OVERRIDE.WITH.YOUR.HOST/mailman/' PUBLIC_ARCHIVE_URL = 'http://www.OVERRIDE.WITH.YOUR.PUBLIC.ARCHIVE.URL/' PRIVATE_ARCHIVE_URL = 'http://www.OVERRIDE.WITH.YOUR.PRIVATE.ARCHIVE.URL/' # Once we know our home directory we can figure out the rest. -HOME_DIR = '/home/mailman' # Override if you change -MAILMAN_DIR = '/home/mailman/mailman' # Override if you change +# BUT, if you override these in mm_cfg.py, you have to override the dependants +# as well. +HOME_DIR = '/home/mailman' +MAILMAN_DIR = '/home/mailman/mailman' LIST_DATA_DIR = os.path.join(MAILMAN_DIR, 'lists') HTML_DIR = os.path.join(HOME_DIR, 'public_html') CGI_DIR = os.path.join(HOME_DIR, 'cgi-bin') diff --git a/Mailman/Digester.py b/Mailman/Digester.py index 5ff7fe4b8..8413ae2a3 100644 --- a/Mailman/Digester.py +++ b/Mailman/Digester.py @@ -1,6 +1,6 @@ """Mixin class with list-digest handling methods and settings.""" -__version__ = "$Revision: 396 $" +__version__ = "$Revision: 445 $" import mm_utils, mm_err, mm_message, mm_cfg import time, os, string @@ -185,10 +185,26 @@ From: %s Subject: Contents of %s digest, Volume %d #%d Date: %s +When replying, please edit your Subject line so it is more specific than +"Re: Contents of %s digest..." + +Send %s maillist submissions to + %s +To subscribe or unsubscribe via the web, visit + %s +or send email to %s + Topics for this digest: %s -''' % (self._mime_separator, msg.GetSender(), self.real_name, self.volume, - self.next_digest_number, time.ctime(time.time()), topics_text) +''' % (self._mime_separator, + msg.GetSender(), + self.real_name, self.volume, self.next_digest_number, + time.ctime(time.time()), + self.real_name, self.GetListEmail(), + self.real_name, + self.GetScriptURL('listinfo'), + self.GetRequestEmail(), + topics_text) if self.digest_header: digest_header = digest_header + (self.digest_header diff --git a/Mailman/mm_cfg.py.dist.in b/Mailman/mm_cfg.py.dist.in index 24847cd8c..99865588a 100644 --- a/Mailman/mm_cfg.py.dist.in +++ b/Mailman/mm_cfg.py.dist.in @@ -1,13 +1,14 @@ -"""This is the module which take your site-specific settings. +"""This is the module which takes your site-specific settings. -From a raw distribution it should be moved to be named mm_cfg.py. If you -already have an mm_cfg.py, be careful to add in only the new settings you -want. The complete set of distributed defaults are in ./mm_defaults. In -mm_cfg, override only those you want to change, after the +From a raw distribution it should be copied to mm_cfg.py. If you +already have an mm_cfg.py, be careful to add in only the new settings +you want. The complete set of distributed defaults, with annotation, +are in ./mm_defaults. In mm_cfg, override only those you want to +change, after the from mm_defaults import * -line, below. +line (see below). Note that these are just default settings - many can be overridden via the admin and user interfaces on a per-list or per-user basis. @@ -17,7 +18,7 @@ setting by using the value as a format string against the list-instance-object's dictionary - see the distributed value of DEFAULT_MSG_FOOTER for an example.""" -__version__ = "$Revision: 428 $" +__version__ = "$Revision: 445 $" ####################################################### # Here's where we get the distributed defaults. # diff --git a/Mailman/smtplib.py b/Mailman/smtplib.py new file mode 100644 index 000000000..db6e3e254 --- /dev/null +++ b/Mailman/smtplib.py @@ -0,0 +1,104 @@ +# A quick hack. Talk to the SMTP port. +# Right now this isn't very functional. +# A lot of functionality was borrowed directly from ftplib... +# John Viega (viega@list.org) + +# >>> from smtplib import * +# >>> s = SmtpConnection('list.org') +# >>> s.helo('adder.cs.virginia.edu') +# >>> s.send(to='viega@list.org', frm='jtv2j@cs.virginia.edu', text='hello, world!') +# >>> s.quit() + +from socket import * +import string + +SMTP_PORT = 25 + +CRLF = '\r\n' + +# Exception raised when an error or invalid response is received +error_reply = 'smtplib.error_reply' # unexpected [123]xx reply +error_temp = 'smtplib.error_temp' # 4xx errors +error_perm = 'smtplib.error_perm' # 5xx errors +error_proto = 'smtplib.error_proto' # response does not begin with [1-5] + +class SmtpConnection: + def __init__(self, host=''): + self.host = host + self._file = None + self.connect() + + def connect(self): + self._sock = socket(AF_INET, SOCK_STREAM) + self._sock.connect(self.host, SMTP_PORT) + self._file = self._sock.makefile('r') + self.getresp() + + def helo(self, host): + self._sock.send('HELO %s\r\n' % host) + self.getresp() + + def quit(self): + self._sock.send('QUIT\r\n') + self.getresp() + + # text should be \n at eol, we'll add the \r. + def send(self, to, frm, text, headers=None): + if headers: + hlines = string.split(headers, '\n') + lines = string.split(text, '\n') + self._sock.send('MAIL FROM: %s\r\n' % frm) + self.getresp() + self._sock.send('RCPT TO: %s\r\n' % to) + self.getresp() + self._sock.send('DATA\r\n') + self.getresp() + if headers: + for line in hlines: + self._sock.send(line + '\r\n') + self._sock.send('\r\n') + for line in lines: + if line == '.': line = '..' + self._sock.send(line + '\r\n') + self._sock.send('.\r\n') + self.getresp() + +# Private crap from here down. + def getline(self): + line = self._file.readline() + if not line: raise EOFError + if line[-2:] == CRLF: line = line[:-2] + elif line[-1:] in CRLF: line = line[:-1] + return line + + # Internal: get a response from the server, which may possibly + # consist of multiple lines. Return a single string with no + # trailing CRLF. If the response consists of multiple lines, + # these are separated by '\n' characters in the string + def getmultiline(self): + line = self.getline() + if line[3:4] == '-': + code = line[:3] + while 1: + nextline = self.getline() + line = line + ('\n' + nextline) + if nextline[:3] == code and \ + nextline[3:4] <> '-': + break + return line + + def getresp(self): + resp = self.getmultiline() + self.lastresp = resp[:3] + c = resp[:1] + if c == '4': + raise error_temp, resp + if c == '5': + raise error_perm, resp + if c not in '123': + raise error_proto, resp + return resp + + + + diff --git a/modules/mm_cfg.py.in b/modules/mm_cfg.py.in index 24847cd8c..99865588a 100644 --- a/modules/mm_cfg.py.in +++ b/modules/mm_cfg.py.in @@ -1,13 +1,14 @@ -"""This is the module which take your site-specific settings. +"""This is the module which takes your site-specific settings. -From a raw distribution it should be moved to be named mm_cfg.py. If you -already have an mm_cfg.py, be careful to add in only the new settings you -want. The complete set of distributed defaults are in ./mm_defaults. In -mm_cfg, override only those you want to change, after the +From a raw distribution it should be copied to mm_cfg.py. If you +already have an mm_cfg.py, be careful to add in only the new settings +you want. The complete set of distributed defaults, with annotation, +are in ./mm_defaults. In mm_cfg, override only those you want to +change, after the from mm_defaults import * -line, below. +line (see below). Note that these are just default settings - many can be overridden via the admin and user interfaces on a per-list or per-user basis. @@ -17,7 +18,7 @@ setting by using the value as a format string against the list-instance-object's dictionary - see the distributed value of DEFAULT_MSG_FOOTER for an example.""" -__version__ = "$Revision: 428 $" +__version__ = "$Revision: 445 $" ####################################################### # Here's where we get the distributed defaults. # diff --git a/modules/mm_defaults.py b/modules/mm_defaults.py index 31f470f7e..f5c82d242 100644 --- a/modules/mm_defaults.py +++ b/modules/mm_defaults.py @@ -9,7 +9,7 @@ this file, to override the distributed defaults with site-specific ones. import os VERSION = '1.0b1.2' -__version__ = "$Revision: 423 $" +__version__ = "$Revision: 445 $" # Many site-specific settings # @@ -21,8 +21,10 @@ DEFAULT_URL = 'http://www.OVERRIDE.WITH.YOUR.HOST/mailman/' PUBLIC_ARCHIVE_URL = 'http://www.OVERRIDE.WITH.YOUR.PUBLIC.ARCHIVE.URL/' PRIVATE_ARCHIVE_URL = 'http://www.OVERRIDE.WITH.YOUR.PRIVATE.ARCHIVE.URL/' # Once we know our home directory we can figure out the rest. -HOME_DIR = '/home/mailman' # Override if you change -MAILMAN_DIR = '/home/mailman/mailman' # Override if you change +# BUT, if you override these in mm_cfg.py, you have to override the dependants +# as well. +HOME_DIR = '/home/mailman' +MAILMAN_DIR = '/home/mailman/mailman' LIST_DATA_DIR = os.path.join(MAILMAN_DIR, 'lists') HTML_DIR = os.path.join(HOME_DIR, 'public_html') CGI_DIR = os.path.join(HOME_DIR, 'cgi-bin') diff --git a/modules/mm_defaults.py.in b/modules/mm_defaults.py.in index 31f470f7e..f5c82d242 100644 --- a/modules/mm_defaults.py.in +++ b/modules/mm_defaults.py.in @@ -9,7 +9,7 @@ this file, to override the distributed defaults with site-specific ones. import os VERSION = '1.0b1.2' -__version__ = "$Revision: 423 $" +__version__ = "$Revision: 445 $" # Many site-specific settings # @@ -21,8 +21,10 @@ DEFAULT_URL = 'http://www.OVERRIDE.WITH.YOUR.HOST/mailman/' PUBLIC_ARCHIVE_URL = 'http://www.OVERRIDE.WITH.YOUR.PUBLIC.ARCHIVE.URL/' PRIVATE_ARCHIVE_URL = 'http://www.OVERRIDE.WITH.YOUR.PRIVATE.ARCHIVE.URL/' # Once we know our home directory we can figure out the rest. -HOME_DIR = '/home/mailman' # Override if you change -MAILMAN_DIR = '/home/mailman/mailman' # Override if you change +# BUT, if you override these in mm_cfg.py, you have to override the dependants +# as well. +HOME_DIR = '/home/mailman' +MAILMAN_DIR = '/home/mailman/mailman' LIST_DATA_DIR = os.path.join(MAILMAN_DIR, 'lists') HTML_DIR = os.path.join(HOME_DIR, 'public_html') CGI_DIR = os.path.join(HOME_DIR, 'cgi-bin') diff --git a/modules/mm_digest.py b/modules/mm_digest.py index 5ff7fe4b8..8413ae2a3 100644 --- a/modules/mm_digest.py +++ b/modules/mm_digest.py @@ -1,6 +1,6 @@ """Mixin class with list-digest handling methods and settings.""" -__version__ = "$Revision: 396 $" +__version__ = "$Revision: 445 $" import mm_utils, mm_err, mm_message, mm_cfg import time, os, string @@ -185,10 +185,26 @@ From: %s Subject: Contents of %s digest, Volume %d #%d Date: %s +When replying, please edit your Subject line so it is more specific than +"Re: Contents of %s digest..." + +Send %s maillist submissions to + %s +To subscribe or unsubscribe via the web, visit + %s +or send email to %s + Topics for this digest: %s -''' % (self._mime_separator, msg.GetSender(), self.real_name, self.volume, - self.next_digest_number, time.ctime(time.time()), topics_text) +''' % (self._mime_separator, + msg.GetSender(), + self.real_name, self.volume, self.next_digest_number, + time.ctime(time.time()), + self.real_name, self.GetListEmail(), + self.real_name, + self.GetScriptURL('listinfo'), + self.GetRequestEmail(), + topics_text) if self.digest_header: digest_header = digest_header + (self.digest_header diff --git a/modules/smtplib.py b/modules/smtplib.py new file mode 100644 index 000000000..db6e3e254 --- /dev/null +++ b/modules/smtplib.py @@ -0,0 +1,104 @@ +# A quick hack. Talk to the SMTP port. +# Right now this isn't very functional. +# A lot of functionality was borrowed directly from ftplib... +# John Viega (viega@list.org) + +# >>> from smtplib import * +# >>> s = SmtpConnection('list.org') +# >>> s.helo('adder.cs.virginia.edu') +# >>> s.send(to='viega@list.org', frm='jtv2j@cs.virginia.edu', text='hello, world!') +# >>> s.quit() + +from socket import * +import string + +SMTP_PORT = 25 + +CRLF = '\r\n' + +# Exception raised when an error or invalid response is received +error_reply = 'smtplib.error_reply' # unexpected [123]xx reply +error_temp = 'smtplib.error_temp' # 4xx errors +error_perm = 'smtplib.error_perm' # 5xx errors +error_proto = 'smtplib.error_proto' # response does not begin with [1-5] + +class SmtpConnection: + def __init__(self, host=''): + self.host = host + self._file = None + self.connect() + + def connect(self): + self._sock = socket(AF_INET, SOCK_STREAM) + self._sock.connect(self.host, SMTP_PORT) + self._file = self._sock.makefile('r') + self.getresp() + + def helo(self, host): + self._sock.send('HELO %s\r\n' % host) + self.getresp() + + def quit(self): + self._sock.send('QUIT\r\n') + self.getresp() + + # text should be \n at eol, we'll add the \r. + def send(self, to, frm, text, headers=None): + if headers: + hlines = string.split(headers, '\n') + lines = string.split(text, '\n') + self._sock.send('MAIL FROM: %s\r\n' % frm) + self.getresp() + self._sock.send('RCPT TO: %s\r\n' % to) + self.getresp() + self._sock.send('DATA\r\n') + self.getresp() + if headers: + for line in hlines: + self._sock.send(line + '\r\n') + self._sock.send('\r\n') + for line in lines: + if line == '.': line = '..' + self._sock.send(line + '\r\n') + self._sock.send('.\r\n') + self.getresp() + +# Private crap from here down. + def getline(self): + line = self._file.readline() + if not line: raise EOFError + if line[-2:] == CRLF: line = line[:-2] + elif line[-1:] in CRLF: line = line[:-1] + return line + + # Internal: get a response from the server, which may possibly + # consist of multiple lines. Return a single string with no + # trailing CRLF. If the response consists of multiple lines, + # these are separated by '\n' characters in the string + def getmultiline(self): + line = self.getline() + if line[3:4] == '-': + code = line[:3] + while 1: + nextline = self.getline() + line = line + ('\n' + nextline) + if nextline[:3] == code and \ + nextline[3:4] <> '-': + break + return line + + def getresp(self): + resp = self.getmultiline() + self.lastresp = resp[:3] + c = resp[:1] + if c == '4': + raise error_temp, resp + if c == '5': + raise error_perm, resp + if c not in '123': + raise error_proto, resp + return resp + + + + |
