Netscape fix
Art Wagner
awagner@uswest.net
Sun, 11 Jun 2000 16:36:52 -0700
This is a multi-part message in MIME format.
--------------5924F90C7260D3B6966054A5
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
"der.hans" wrote:
>
> moin, moin,
>
> can we get this up on the web site, so we can point people at it?
>
> Maybe under a FAQ. We could include questions and answers about joining
> the mailing list and meetings and why everyone thinks Cindy has the PLUG
> website URL tatooed on her butt :).
>
> ciao,
>
> der.hans
> --
> # der.hans@LuftHans.com home.pages.de/~lufthans/ www.Opnix.com
> # Motorraeder toeten nicht. Motorraeder werden getoetet.
>
> _______________________________________________
> Plug-discuss mailing list - Plug-discuss@lists.PLUG.phoenix.az.us
> http://lists.PLUG.phoenix.az.us/mailman/listinfo/plug-discuss
I would hope we can fix the "Mail Hanging" problem with the
attached
patched version of "Message.py" from;
"mailman-1.1/Mailman/Messages.py"
Please note my added comments at line 35.
Arthur Wagner
--------------5924F90C7260D3B6966054A5
Content-Type: text/plain; charset=us-ascii;
name="Message.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="Message.py"
# Message.py from Mailman-1.1
# Copyright (C) 1998 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""Embody incoming and outgoing messages as objects."""
import sys
import string
import time
# Python 1.5's version of rfc822.py is buggy and lacks features we
# depend on -- so we always use the up-to-date version distributed
# with Mailman.
from Mailman.pythonlib import rfc822
# Utility functions 2 of these classes use:
def AddBackNewline(str):
return str + '\n'
def RemoveNewline(str):
return str[:-1]
# XXX klm - use the standard lib StringIO module instead of FakeFile.
# If we're trying to create a message object from text, we need to pass
# a file object to rfc822.Message to get it to do its magic. Well,
# to avoid writing text out to a file, and having it read back in,
# here we define a class that will fool rfc822 into thinking it's a
# non-seekable message.
# The only method rfc822.Message ever calls on a non-seekable file is
# readline. It doesn't use the optional arg to readline, either.
# In my subclasses, I use the read() method, and might just use readlines()
# someday.
#
# It might be useful to expand this into a full blown fully functional class.
class FakeFile:
def __init__(self, text):
self.lines = map(AddBackNewline, string.split(text, '\n'))
self.curline = 0
self.lastline = len(self.lines) - 1
def readline(self):
if self.curline > self.lastline:
return ''
self.curline = self.curline + 1
return self.lines[self.curline - 1]
def read(self):
startline = self.curline
self.curline = self.lastline + 1
return string.join(self.lines[startline:], '')
def readlines(self):
startline = self.curline
self.curline = self.lastline + 1
return self.lines[startline:]
def seek(self, pos):
if pos <> 0:
raise ValueError, "FakeFiles can only seek to the beginning."
self.curline = 0
# We know the message is gonna come in on stdin or from text for our purposes.
class IncomingMessage(rfc822.Message):
def __init__(self, text=None):
if not text:
rfc822.Message.__init__(self, sys.stdin, 0)
self.body = self.fp.read()
else:
rfc822.Message.__init__(self, FakeFile(text), 0)
self.body = self.fp.read()
self.file_count = None
def readlines(self):
if self.file_count <> None:
x = self.file_count
self.file_count = len(self.file_data)
return self.file_data[x:]
return map(RemoveNewline, self.headers) + [''] + \
string.split(self.body,'\n')
def readline(self):
if self.file_count == None:
self.file_count = 0
self.file_data = map(RemoveNewline, self.headers) + [''] + \
string.split(self.body,'\n')
if self.file_count >= len(self.file_data):
return ''
self.file_count = self.file_count + 1
return self.file_data[self.file_count-1] + '\n'
# In lines 54 and 57 Reversed "sender" and "from" This fixes the problem
# with Netscape 4.6 through 4.73 postings hanging for Admin. Arthur L. Wagner
def GetSender(self):
# Look for a Sender field.
sender = self.getheader('from')
if sender:
realname, mail_address = self.getaddr('from')
else:
try:
realname, mail_address = self.getaddr('sender')
except:
real_name = mail_address = None
# We can't trust that any of the headers really contained an address
if mail_address and type(mail_address) == type(""):
return string.lower(mail_address)
else:
# The unix from line is all we have left...
if self.unixfrom:
return string.lower(string.split(self.unixfrom)[1])
def GetEnvelopeSender(self):
#
# look for unix from line and attain address
# from it, return None if there is no unix from line
# this function is used to get the envelope sender
# when mail is sent to a <listname>-admin address
#
if not self.unixfrom:
return None
# XXX assumes no whitespace in address
parts = string.split(self.unixfrom)
for part in parts:
#
# perform minimal check for the address
#
if string.find(part, '@') > -1:
user, host = string.split(part, '@', 1)
if not user:
continue
if string.count(host, ".") < 1: # doesn't look qualified
continue
return part
return None
def GetSenderName(self):
real_name, mail_addr = self.getaddr('from')
if not real_name:
return self.GetSender()
return real_name
def SetHeader(self, name, value, crush_duplicates=1):
if crush_duplicates:
self[name] = value
else:
# Only bother with the dict
self.dict[string.lower(name)] = value
# This is a simplistic class. It could do multi-line headers etc...
# But it doesn't because I don't need that for this app.
class OutgoingMessage:
def __init__(self, headers=None, body='', sender=None):
self.cached_headers = {}
if headers:
self.SetHeaders(headers)
else:
self.headers = []
self.body = body
self.sender = sender
def readlines(self):
if self.file_count <> None:
x = self.file_count
self.file_count = len(self.file_data)
return self.file_data[x:]
return map(RemoveNewline, self.headers) + [''] + \
string.split(self.body,'\n')
def readline(self):
if self.file_count == None:
self.file_count = 0
self.file_data = map(RemoveNewline, self.headers) + [''] + \
string.split(self.body,'\n')
if self.file_count >= len(self.file_data):
return ''
self.file_count = self.file_count + 1
return self.file_data[self.file_count-1] + '\n'
def SetHeaders(self, headers):
self.headers = map(AddBackNewline, string.split(headers, '\n'))
self.CacheHeaders()
def CacheHeaders(self):
for header in self.headers:
i = string.find(header, ':')
self.cached_headers[string.lower(string.strip(header[:i]))
] = header[i+2:]
def SetHeader(self, header, value, crush_duplicates=1):
if value[-1] <> '\n':
value = value + '\n'
if crush_duplicates:
# Run through the list and make sure header isn't already there.
remove_these = []
for item in self.headers:
f = string.find(item, ':')
if string.lower(item[:f]) == string.lower(header):
remove_these.append(item)
for item in remove_these:
self.headers.remove(item)
del remove_these
self.headers.append('%s%s: %s' % (string.upper(header[0]),
string.lower(header[1:]),
value))
self.cached_headers[string.lower(header)] = value
def SetBody(self, body):
self.body = body
def AppendToBody(self, text):
self.body = self.body + text
def SetSender(self, sender, set_from=1):
self.sender = sender
if not self.getheader('from') and set_from:
self.SetHeader('from', sender)
def GetSender(self):
return self.sender
# Lower case the name to give it the same UI as IncomingMessage
# inherits from rfc822
def getheader(self, str):
str = string.lower(str)
if not self.cached_headers.has_key(str):
return None
return self.cached_headers[str]
def __delitem__(self, name):
if not self.getheader(name):
# XXX this should raise an exception
return None
newheaders = []
name = string.lower(name)
nlen = len(name)
for h in self.headers:
if (len(h) > (nlen+1)
and h[nlen] == ":"
and string.lower(h[:nlen]) == name):
continue
newheaders.append(h)
self.headers = newheaders
self.CacheHeaders()
# XXX should have a __setitem__
class NewsMessage(IncomingMessage):
def __init__(self, mail_msg):
self.fp = mail_msg.fp
self.fp.seek(0)
rfc822.Message.__init__(self, self.fp, 0)
self.body = self.fp.read()
self.file_count = None
--------------5924F90C7260D3B6966054A5--