[Mailman-Developers] post messages from the web

Steven Hazel cherub@azrael.dyn.cheapnet.net
Wed, 25 Aug 1999 03:07:29 -0500 (CDT)


Well, my previous mailing inquiring about how to best submit code got
no reponse, so I'm submitting as I see fit: namely, via attached files
and generous context diffs.  Attached are
mailman/Mailman/Cgi/postmsg.py, a basic web interface for posting
messages, and Message.diff, a 30-line context diff of some minor
changes to IncomingMessage which allow postmsg.py to work properly.
This is still all very early code, so your beautifcations and
suggestions are appriciated.  Patches to make the postmsg script
accessable via a replacement tag are pending.  User accounts are in
progress, but further off.

-S

===File ~/projects/mailman/Mailman/Cgi/postmsg.py===========
#! /usr/bin/env python
#
# Copyright (C) 1999 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.

"""Allows user to log in, setting authentication cookies
"""

# No lock needed in this script, because we don't change data.

from Mailman import auth
import Cookie
import sys
import os, string, cgi
from regsub import gsub
from Mailman import Utils, MailList, Message, Errors
from Mailman import mm_cfg
from Mailman.htmlformat import *

def main():
    global user
    try:
        path = os.environ['PATH_INFO']
    except KeyError:
        path = ""

    list_info = Utils.GetPathPieces(path)


    list_name = string.lower(list_info[0])

    try:
        list = MailList.MailList(list_name, lock=0)
    except:
        list = None

    if not (list and list._ready):
        FormatPostmsgStatus(error="List <em>%s</em> not found." % list_name)
        return

    if len(list_info) == 0:
        FormatPostmsgStatus()
        return

    global cgi_data
    cgi_data = cgi.FieldStorage()
    message = None
    if cgi_data.has_key('message'):
	imsg = Message.IncomingMessage('');
        fromaddr = cgi_data['from'].value
        is_auth = 0
        try:
            # admin uses cookies with -admin name suffix
            is_auth = list.WebAuthenticate(user=fromaddr,
                                           password=
                                           cgi_data['password'].value)
        except Errors.MMNotAMemberError:
            errormsg = 'Incorrect user name or password.'
        except Errors.MMBadPasswordError:
            errormsg = 'Incorrect user name or password.'
        except Errors.MMExpiredCookieError:
            errormsg = 'Your cookie has gone stale, ' \
                       'enter password to get a new one.',
        except Errors.MMInvalidCookieError:
            errormsg = 'Error decoding authorization cookie.'
        except Errors.MMAuthenticationError:
            errormsg = 'Authentication error.'
            if (is_auth):
                imsg.SetHeader('from', fromaddr)
            else:
                FormatPostmsgStatus(errormsg)
                return
        imsg.SetHeader('subject', cgi_data['subject'].value)
        imsg.SetHeader('to', list.GetListEmail())
        message = cgi_data['message'].value
        if message[len(message)-1]!='\n':
            message = "%s\n" % message
        imsg.SetBody(message)
	list.Post(imsg)
        FormatPostmsgStatus('Message Posted')

    else:
	doc = Document()
	doc.SetTitle('Post Message')

        doc.AddItem('Fill out the form below to post a message to the ')
        doc.AddItem(list_name)
        doc.AddItem(' mailing list.<br><br>')

	form = Form(list.GetRelativeScriptURL('postmsg'))
	doc.AddItem(form)

        form.AddItem('Email Address: ')
        form.AddItem(TextBox(name='from', size=30))
        form.AddItem('<br>Password: ')
        form.AddItem(PasswordBox(name='password'))
        form.AddItem('<br>')

        form.AddItem('<br><br>Subject: ')
        form.AddItem(TextBox(name='subject', size=30))
        form.AddItem('<br><br>Post<br>')
	form.AddItem(TextArea(name='message', rows=24, cols=80, wrap='soft'))
        form.AddItem('<br>')
	form.AddItem(SubmitButton('Post','Post Message'))
	print doc.Format()


def FormatPostmsgStatus(error=None):
    "Simple message posting overview"

    # XXX We need a portable way to determine the host by which we are being 
    #     visited!  An absolute URL would do...
    http_host = os.environ.get('HTTP_HOST') or\
                os.environ.get('SERVER_NAME')
    port = os.environ.get('SERVER_PORT')
    # strip off the port if there is one
    if port and http_host[-len(port)-1:] == ':'+port:
        http_host = http_host[:-len(port)-1]
    if mm_cfg.VIRTUAL_HOST_OVERVIEW and http_host:
	host_name = http_host
    else:
	host_name = mm_cfg.DEFAULT_HOST_NAME

    doc = Document()
    doc.SetTitle(error)

    table = Table(border=0, width="100%")
    table.AddRow([Center(Header(2, error))])
    table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
                      colspan=2, bgcolor="#99ccff")

    advertised = []
    names = Utils.list_names()
    names.sort()

    for n in names:
	l = MailList.MailList(n, lock = 0)
	if l.advertised:
	    if (mm_cfg.VIRTUAL_HOST_OVERVIEW
                and http_host
		and (string.find(http_host, l.web_page_url) == -1
		     and string.find(l.web_page_url, http_host) == -1)):
		# List is for different identity of this host - skip it.
		continue
	    else:
		advertised.append(l)

    doc.AddItem(table)
    doc.AddItem('<hr>')
    doc.AddItem(MailmanLogo())
    print doc.Format(bgcolor="#ffffff")


if __name__ == "__main__":
    main()
============================================================

===File ~/Message.diff======================================
Index: Message.py
===================================================================
RCS file: /home/cherub/cvs/mailman/Mailman/Message.py,v
retrieving revision 1.1
retrieving revision 1.4
diff -c -3 -0 -r1.1 -r1.4
*** Message.py	1999/07/28 20:42:33	1.1
--- Message.py	1999/08/25 07:58:32	1.4
***************
*** 76,135 ****
--- 76,141 ----
  
  # 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'
  
+     def SetBody(self, body):
+ 	self.body = body
+ 
+     def AppendToBody(self, text):
+ 	self.body = self.body + text
+ 
      def GetSender(self):
  	# Look for a Sender field.
  	sender = self.getheader('sender')
  	if sender:
  	    realname, mail_address = self.getaddr('sender')
  	else:
  	    try:
  		realname, mail_address = self.getaddr('from')
  	    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)
============================================================