"""Attempt to post an article""" # meoWWW # Copyright 1999 G.J. Andruk # # 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. import config, os, sys, string, cgi, time, msgid, smtplib, rfc822, re from cStringIO import StringIO def trimrefs(refstring): """Clean up a References line and shorten it for transport safety. References will only be kept if they are in the regex form '<\S+>'. Pessimism be here: we don't try to wrap and the maximum line length is assumed to be 510. (Ref. NNTP truncates lines >512 chars, and INN 2.1-2-2 won't take refs longer than that. We use 510 to leave room for a CRLF). NOTE: Some servers allow spaces in message IDs but we don't. Those servers are broken (see RFC 1036 section 2.1.5). """ reflist = [] for ref in string.split(refstring): if len(ref) > 2 and ref[0] == '<' and ref[-1] == '>': reflist.append(ref) refstring = string.join(reflist) while len(refstring) > 497 and len(reflist): try: del reflist[1] refstring = string.join(reflist) except: refstring = '' return refstring def killme(errmsg): """raise an exception with extra text.""" raise ValueError, (errmsg + " Press your browser's back button to " 'correct any problems and try again.') CR = '\015' LF = '\012' NL = CR + LF OF = StringIO() IF = sys.stdin cfg = config.config() knownheaders = ('Newsgroups', 'From', 'Subject', 'To', 'Followup-To', 'References', 'Organization') # Gotta hardcode this because we don't want it internationalized. months = (None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') header = {} try: header['X-Proxy-Path'] = '%s!%s!%s %d' % (os.environ['SERVER_NAME'], os.environ['REMOTE_ADDR'], os.environ['REMOTE_USER'], time.time()) except: killme('%s is undefined, cannot proceed (%s)' % (sys.exc_info()[1], sys.exc_info()[0])) try: query = string.split(os.environ['QUERY_STRING']) except: query = [] formraw = IF.readline() formval = cgi.parse_qs(formraw) for hkey in formval.keys(): if hkey in knownheaders: if len(formval[hkey]) > 1: killme('multiple %s headers found.') if hkey == 'References': formval[hkey][0] = trimrefs(formval[hkey][0]) if hkey != 'body': formval[hkey][0] = string.replace(formval[hkey][0], NL, '') if not formval.has_key('From'): killme('You must supply a From: header.') fromlist = rfc822.AddressList(formval['From'][0]) if len(fromlist.addresslist) > 1: killme("Multiple addresses are not allowed in From: header.") fromcheck = string.split(fromlist.addresslist[0][1], '@', 1) if len(fromcheck) < 2 or '.' not in fromcheck[1]: killme('Your From: header is not an Internet style address.') for formvalcheck in ('From', 'Subject'): if ((not formval.has_key(formvalcheck)) or string.strip(formval[formvalcheck][0]) == ''): killme('%s: header must be present and not blank.' % formvalcheck) if not (formval.has_key('To') or formval.has_key('Newsgroups')): killme('You must supply at least one of To: or Newsgroups:.') if (not formval.has_key('body')) or string.strip(formval['body'][0]) == '': killme('The message body cannot be empty.') origcount = 0 quotecount = 0 for line in string.split(formval['body'][0], NL): if line and line[0] != '>': origcount = origcount + 1 else: quotecount = quotecount + 1 del line if quotecount and origcount < 2: killme('The message appears to contain all quoted text.') formval['body'][0] = string.replace(formval['body'][0], NL, '\n') midctx = msgid.Msgid(os.environ['SERVER_NAME']) datetab = string.split(time.strftime('%d %m %Y %H:%M:%S +0000', time.gmtime(time.time()))) datetab[1] = months[int(datetab[1])] header['Date'] = string.join(datetab) header['Message-ID'] = midctx.makeid() header['Received'] = ('(from %s@%s) by %s (%s/%s)\n\tid %s; %s' % (os.environ['REMOTE_USER'], os.environ['REMOTE_ADDR'], os.environ['SERVER_NAME'], config.name, config.version, string.split(header['Message-ID'][1:], '@')[0], header['Date'])) header['Path'] = string.split(header['X-Proxy-Path'], None, 1)[0] header['User-Agent'] = '%s/%s' % (config.name, config.version) header['X-Meow'] = 'Meow' for hkey in knownheaders: if formval.has_key(hkey) and string.strip(formval[hkey][0]): header[hkey] = formval[hkey][0] # unwrap just in case header[hkey] = string.replace(header[hkey], CR, '') header[hkey] = string.replace(header[hkey], LF, '') if header['Newsgroups']: header['Newsgroups'] = string.join(string.split(header['Newsgroups']), '') while string.find(header['Newsgroups'], ',,') != -1: header['Newsgroups'] = string.replace(header['Newsgroups'], ',,', ',') if header['Newsgroups'][0] == ',': header['Newsgroups'] = header['Newsgroups'][1:] if header['Newsgroups'][-1] == ',': header['Newsgroups'] = header['Newsgroups'][:-1] if (not header['Newsgroups']): killme('No valid-looking newsgroups found.') OF.write('content-type: text/html' + NL + NL) OF.write('