diff options
Diffstat (limited to 'Mailman/GatewayManager.py')
| -rw-r--r-- | Mailman/GatewayManager.py | 267 |
1 files changed, 149 insertions, 118 deletions
diff --git a/Mailman/GatewayManager.py b/Mailman/GatewayManager.py index 911b89df1..bdebc8f21 100644 --- a/Mailman/GatewayManager.py +++ b/Mailman/GatewayManager.py @@ -16,131 +16,162 @@ '''Mixin class for gatewaying mail to news, and news to mail.''' +# All these things should already be imported, so might as well do them here +# at the top level +import os +import string +import time +import mm_cfg # XXX: This should be integrated with the Errors module ImproperNNTPConfigError = "ImproperNNTPConfigError" - +# XXX: Bogus, but might as we do it `legally' +QuickEscape = 'QuickEscape' class GatewayManager: - def InitVars(self): - # Configurable - self.nntp_host = '' - self.linked_newsgroup = '' - self.gateway_to_news = 0 - self.gateway_to_mail = 0 - - def GetConfigInfo(self): - import mm_cfg - return [ - 'Mail to news and news to mail gateway services.', - ('nntp_host', mm_cfg.String, 50, 0, - 'The internet address of the machine your news server is running on.', + def InitVars(self): + # Configurable + self.nntp_host = '' + self.linked_newsgroup = '' + self.gateway_to_news = 0 + self.gateway_to_mail = 0 - 'The news server is not part of Mailman proper. You have to already' - ' have access to a nntp server, and that nntp server has to recognize' - ' the machine this mailing list runs on as a machine capable of' - ' reading and posting news.'), - ('linked_newsgroup', mm_cfg.String, 50, 0, - 'The name of the usenet group to gateway to and/or from.'), - ('gateway_to_news', mm_cfg.Toggle, ('No', 'Yes'), 0, - 'Should posts to the mailing list be resent to the newsgroup?'), - ('gateway_to_mail', mm_cfg.Toggle, ('No', 'Yes'), 0, - 'Should newsgroup posts not sent from the list be resent to the' - ' list?') - ] + def GetConfigInfo(self): + return [ + 'Mail-to-News and News-to-Mail gateway services.', + ('nntp_host', mm_cfg.String, 50, 0, + 'The Internet address of the machine your News server ' + 'is running on.', + 'The News server is not part of Mailman proper. You have to ' + 'already have access to a NNTP server, and that NNTP server ' + 'has to recognize the machine this mailing list runs on as ' + 'a machine capable of reading and posting news.'), + ('linked_newsgroup', mm_cfg.String, 50, 0, + 'The name of the Usenet group to gateway to and/or from.'), + ('gateway_to_news', mm_cfg.Toggle, ('No', 'Yes'), 0, + 'Should posts to the mailing list be resent to the ' + 'newsgroup?'), + ('gateway_to_mail', mm_cfg.Toggle, ('No', 'Yes'), 0, + 'Should newsgroup posts not sent from the list be resent ' + 'to the list?') + ] - # Watermarks are kept externally to avoid locking problems. - def PollNewsGroup(self, watermark): - if (not self.gateway_to_mail or not self.nntp_host or - not self.linked_newsgroup): - return 0 - import nntplib, os, string, mm_cfg - con = nntplib.NNTP(self.nntp_host) - r,c,f,l,n = con.group(self.linked_newsgroup) - # NEWNEWS is not portable and has synchronization issues... - # Use a watermark system instead. - if watermark == 0: - return eval(l) - for num in range(max(watermark+1, eval(f)), eval(l)+1): - try: - headers = con.head(`num`)[3] - found_to = 0 - for header in headers: - i = string.find(header, ':') - if i > 0 and string.lower(header[:i]) == 'to': - found_to = 1 - if header[:i] <> 'X-BeenThere': - continue - if header[i:] == ': %s' % self.GetListEmail(): - raise "QuickEscape" - body = con.body(`num`)[3] - file = os.popen("%s %s nonews" % - (os.path.join(mm_cfg.SCRIPTS_DIR, - "post"), self._internal_name), "w") - file.write(string.join(headers,'\n')) - # If there wasn't already a TO: header, add one. - if not found_to: - file.write("\nTo: %s" % self.GetListEmail()) - file.write('\n\n') - file.write(string.join(body,'\n')) - file.write('\n') - file.close() - except nntplib.error_temp: - pass # Probably canceled, etc... - except "QuickEscape": - pass # We gated this TO news, don't repost it! - return eval(l) - - def SendMailToNewsGroup(self, mail_msg): - import Message - import os - #if self.gateway_to_news == 0: - # return - if self.linked_newsgroup == '' or self.nntp_host == '': - raise ImproperNNTPConfigError - try: - if self.tmp_prevent_gate: - return + # Watermarks are kept externally to avoid locking problems. + def PollNewsGroup(self, watermark): + if (not self.gateway_to_mail or not self.nntp_host or + not self.linked_newsgroup): + return 0 + import nntplib + con = nntplib.NNTP(self.nntp_host) + r,c,f,l,n = con.group(self.linked_newsgroup) + # the (estimated)count, first, and last are numbers returned as + # string. We use them as numbers throughout + c = int(c) + f = int(f) + l = int(l) + # NEWNEWS is not portable and has synchronization issues... + # Use a watermark system instead. + if watermark == 0: + return l + for num in range(max(watermark+1, f, l+1)): + try: + headers = con.head(`num`)[3] + found_to = 0 + for header in headers: + i = string.find(header, ':') + if i > 0 and string.lower(header[:i]) == 'to': + found_to = 1 + if header[:i] <> 'X-BeenThere': + continue + if header[i:] == ': %s' % self.GetListEmail(): + raise QuickEscape + body = con.body(`num`)[3] + # Create the pipe to the Mail posting script. Note that it is + # not installed executable, so we'll tack on the path to + # Python we discovered when we configured Mailman + cmd = '%s %s %s nonews' % ( + mm_cfg.PYTHON, + os.path.join(mm_cfg.SCRIPTS_DIR, 'post'), + self._internal_name) + file = os.popen(cmd, 'w') + file.write(string.join(headers,'\n')) + # If there wasn't already a TO: header, add one. + if not found_to: + file.write("\nTo: %s" % self.GetListEmail()) + file.write('\n\n') + file.write(string.join(body,'\n')) + file.write('\n') + file.close() + except nntplib.error_temp: + pass # Probably canceled, etc... + except "QuickEscape": + pass # We gated this TO news, don't repost it! + return l + + def SendMailToNewsGroup(self, mail_msg): + import Message + #if self.gateway_to_news == 0: + # return + if self.linked_newsgroup == '' or self.nntp_host == '': + raise ImproperNNTPConfigError + try: + if self.tmp_prevent_gate: + return except AttributeError: - pass # Wasn't remailed by the news gater then. Let it through. - # Fork in case the nntp connection hangs. - x = os.fork() - if not x: - # Now make the news message... - msg = Message.NewsMessage(mail_msg) - - import nntplib,string - - # Ok, munge headers, etc. - subj = msg.getheader('subject') - if not subj: - msg.SetHeader('Subject', '%s(no subject)' % prefix) - if self.reply_goes_to_list: - del msg['reply-to'] - msg.headers.append('Reply-To: %s\n' % self.GetListEmail()) - msg.headers.append('Sender: %s\n' % self.GetAdminEmail()) - msg.headers.append('Errors-To: %s\n' % self.GetAdminEmail()) - msg.headers.append('X-BeenThere: %s\n' % self.GetListEmail()) - msg.headers.append('Newsgroups: %s\n' % self.linked_newsgroup) - # Note: Need to be sure 2 messages aren't ever sent to the same - # list in the same process, since message ID's need to be unique. - # could make the ID be mm.listname.postnum instead if that happens - if msg.getheader('Message-ID') == None: - import time - msg.headers.append('Message-ID: <mm.%s.%s@%s>\n' % - (time.time(), os.getpid(), self.host_name)) - if msg.getheader('Lines') == None: - msg.headers.append('Lines: %s\n' % + pass # Wasn't remailed by the news gater then. Let it through. + # Fork in case the nntp connection hangs. + x = os.fork() + if not x: + import nntplib + # Now make the news message... + msg = Message.NewsMessage(mail_msg) + # Ok, munge headers, etc. + subj = msg.getheader('subject') + if not subj: + msg.SetHeader('Subject', '%s(no subject)' % prefix) + if self.reply_goes_to_list: + del msg['reply-to'] + msg.headers.append('Reply-To: %s\n' % self.GetListEmail()) + # if we already have a sender header, don't add another one; use + # the header that's already there. + if not msg.getheader('sender'): + msg.headers.append('Sender: %s\n' % self.GetAdminEmail()) + msg.headers.append('Errors-To: %s\n' % self.GetAdminEmail()) + msg.headers.append('X-BeenThere: %s\n' % self.GetListEmail()) + ngheader = msg.getheader('newsgroups') + if ngheader is not None: + # see if the Newsgroups: header already contains our + # linked_newsgroup. If so, don't add it again. If not, + # append our linked_newsgroup to the end of the header list + ngroups = map(string.strip, string.split(ngheader, ',')) + if self.linked_newsgroup not in ngroups: + ngroups.append(self.linked_newsgroup) + ngheader = string.join(ngroups, ',') + # subtitute our new header for the old one. XXX Message + # class should have a __setitem__() + del msg['newsgroups'] + msg.headers.append('Newsgroups: %s\n' % ngroups) + else: + # Newsgroups: isn't in the message + msg.headers.append('Newsgroups: %s\n' % self.linked_newsgroup) + # Note: Need to be sure 2 messages aren't ever sent to the same + # list in the same process, since message ID's need to be unique. + # Could make the ID be mm.listname.postnum instead if that happens + if msg.getheader('Message-ID') is None: + msg.headers.append('Message-ID: <mm.%s.%s@%s>\n' % + (time.time(), os.getpid(), self.host_name)) + if msg.getheader('Lines') is None: + msg.headers.append('Lines: %s\n' % len(string.split(msg.body,"\n"))) - del msg['received'] + del msg['received'] - # NNTP is strict about spaces after the colon in headers. - for n in range(len(msg.headers)): - line = msg.headers[n] - i = string.find(line,":") - if i <> -1 and line[i+1] <> ' ': - msg.headers[n] = line[:i+1] + ' ' + line[i+1:] - con = nntplib.NNTP(self.nntp_host) - con.post(msg) - con.quit() - os._exit(0) + # NNTP is strict about spaces after the colon in headers. + for n in range(len(msg.headers)): + line = msg.headers[n] + i = string.find(line,":") + if i <> -1 and line[i+1] <> ' ': + msg.headers[n] = line[:i+1] + ' ' + line[i+1:] + con = nntplib.NNTP(self.nntp_host) + con.post(msg) + con.quit() + os._exit(0) |
