Re: 2.5.1-1 error

Marco Paganini <[email protected]> Wed, 27 Apr 2005 12:18:13 -0400
Newsgroups gmane.mail.spam.active-spam-killer.general
Message-ID <[email protected]>
Hi Stephen et al,

The problem you see was caused by some last minute mixup with CVS.  Somehow,
I overwrote the correct version of askconfig.py with an older version. :(

I will release ASK 2.5.2 soon. In the meantime, please overwrite your
askconfig.py file in the ASK distribution with the attached file and tell me
if it runs OK.

Regards
Paga

On Sat, Apr 23, 2005 at 06:44:19PM -0500, Stephen Stocker wrote:
>   Hi,
> 
>   I haven't updated ASK since 2.4.1, and tried the beta version. It's 
> giving me this error, using procmail 3.22 (or for that matter, when 
> invoked from the command line). I'm using Python 2.2.3, if that helps.
> 
>   I've looked through .askrc and tried a completely new setup, with the 
> same results. Any ideas? Thanks, and please keep up the great work on this 
> system, it's been a life-saver! :)
> 
> 	Steve
> 
> 
> 
> -------------------------------------
> Hope, Despair and the Triumph of Life
>          http://www.hdtl.org
>   Abuse Prevention/Survivor Support
> 
> 
> -------------------------------------------------------
> SF email is sponsored by - The IT Product Guide
> Read honest & candid reviews on hundreds of IT Products from real users.
> Discover which products truly live up to the hype. Start reading now.
> http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
> _______________________________________________
> A-S-K-users mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/a-s-k-users
> 

-- 
Marco Paganini          | UNIX / Linux / Networking
[email protected]   | PGP: http://www.paganini.net/pgp/
http://www.paganini.net | Magnus Frater te spectat...
askconfig.py (text/plain, 12.9 KB)
#------------------------------------------------------------------------------
#	askconfig.py - configuration related functions
#
#	(C) 2001-2002 by Marco Paganini ([email protected])
#
#   This file is part of ASK - Active Spam Killer
#
#   ASK 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.
#
#   ASK 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 ASK; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#	$Id: askconfig.py,v 1.57 2005/04/27 01:59:52 paganini Exp $
#------------------------------------------------------------------------------

import os
import sys
import string
import rfc822
import md5
import re
import time
import struct, fcntl
import tempfile
import getopt
import ConfigParser
import askversion

#------------------------------------------------------------------------------

class AskConfig:
	"""
	Manages the configuration related information for ASK.

	Attributes:

	- cfg:  				 ConfigParser object
	- home:					 home directory (from $HOME)
	- rc_*: 				 Reflect values set in the configuration file.
	- RET_PROCMAIL_CONTINUE: Signals procmail to continue delivery
	- RET_PROCMAIL_STOP:	 Signals procmail to stop delivery
	"""

	#------------------------------------------------------------------------------
	def __init__(self, argv):
		"""
		Initializes the AskConfig class. 'argv' is used to parse the command
		line options.
		"""
	
		self.procmail_mode = 0
		self.filter_mode   = 0
		self.loglevel      = 0
		self.logfile       = ""
		self.home          = ""
		self.rcfile		   = ""

		self.__cmdline(argv)

		## If self.home is already set, we passed it through command line

		if (self.home == ""):
			self.home = os.getenv("HOME")

		if not self.home:
			sys.stderr.write("ASK ERROR: Cannot find HOME directory! Aborting...\n")
			sys.exit(1)

		## Acquire python's version number and warn if unsupported.

		try:
			self.python_major_version, \
			self.python_minor_version, \
			self.python_micro_version, \
			self.python_releaselevel,  \
			tmp = sys.version_info
		except:
			## Older versions of python do not define sys.version_info
			self.python_major_version = 0
			self.python_minor_version = 0
			self.python_micro_version = 0
			self.python_releaselevel  = ""

		if not self.rcfile:
			self.rcfile = self.home + "/.askrc"
			
		self.__read_config(self.rcfile)

			
	#------------------------------------------------------------------------------
	def __read_config(self, configfile):
		"""
		Reads config file pointed to by 'configfile' and process the options 
		accordingly. Note that this function will expand lists and environment
		variables found inside the options.
		"""

		if (os.access(configfile, os.R_OK) == 0):
			sys.stderr.write("ERROR: %s does not exist or is unreadable. Exiting...\n" % configfile)
			sys.exit(self.RET_PROCMAIL_CONTINUE)

		self.cfg = ConfigParser.ConfigParser()

		try:
			self.cfg.read(configfile)
		except ConfigParser.MissingSectionHeaderError:
			sys.stderr.write("ERROR: Config file has no headers. Exiting...\n")
			sys.exit(self.RET_PROCMAIL_CONTINUE)
		
		## We now load each of value in turn

		self.rc_mymails     = self.__expand("rc_mymails", listmode = 1)
		self.rc_myfullname  = self.__expand("rc_myfullname", mandatory = 0)
		self.rc_mymailbox   = self.__expand("rc_mymailbox")
		self.rc_junkmailbox = self.__expand("rc_junkmailbox",mandatory = 0)
		self.rc_bulkmailbox = self.__expand("rc_bulkmailbox",mandatory = 0)
		self.rc_mailkey     = self.__expand("rc_mailkey")
		self.rc_md5_key	    = self.__expand("rc_md5_key")
 
 		self.rc_askdir      = self.__expand("rc_askdir")

		## If msgdir ends in "/" we assume messages will be queued in a
		## Maildir compatible format. In that case we add the "cur/" directory
		## to the path, as it will be the "real" directory where the files reside.
		## The delivery routines are smart enough to remove the "cur/new/tmp" part.

		self.rc_msgdir      = self.__expand("rc_msgdir")
		if (self.rc_msgdir[len(self.rc_msgdir) - 1] == "/"):
			
			## Create dirs
			if not os.path.exists(self.rc_msgdir):	os.mkdir(self.rc_msgdir)

			if not os.path.exists(self.rc_msgdir + "cur"): os.mkdir(self.rc_msgdir + "cur")
			if not os.path.exists(self.rc_msgdir + "new"): os.mkdir(self.rc_msgdir + "new")
			if not os.path.exists(self.rc_msgdir + "tmp"): os.mkdir(self.rc_msgdir + "tmp")

			self.rc_msgdir = self.rc_msgdir + "/new/"
			self.queue_is_maildir = 1
		else:
			self.queue_is_maildir = 0

		self.rc_tmpdir      = self.__expand("rc_tmpdir")

		self.rc_lockfile    = self.__expand("rc_lockfile", mandatory = 0)

		self.rc_confirm_mailbody   = self.__expand("rc_confirm_mailbody",   mandatory = 0)

		self.rc_confirm_dirs    = self.__expand("rc_confirm_dirs",   listmode = 1, mandatory = 0)
		self.rc_confirm_langs   = self.__expand("rc_confirm_langs",  listmode = 1, mandatory = 0)

		self.rc_whitelist  = self.__expand("rc_whitelist",  listmode = 1)
		self.rc_ignorelist = self.__expand("rc_ignorelist", listmode = 1)

		# This is kept here for backwards compatibility.
		# The blacklist is now a synonym for ignorelist
		self.rc_blacklist  = self.__expand("rc_blacklist",  listmode = 1, mandatory = 0)

		self.rc_basic_headers = self.__expand("rc_basic_headers", listmode = 1, mandatory = 0)
		self.rc_mta_command   = self.__expand("rc_mta_command")

		self.rc_junk_unknown_recipients = self.__expand("rc_junk_unknown_recipients", mandatory = 0, boolean = 1)

 		self.rc_whitelist_on_mailkey = self.__expand("rc_whitelist_on_mailkey", mandatory = 0, boolean = 0)

 		self.rc_remote_cmd_enabled  = self.__expand("rc_remote_cmd_enabled",     mandatory = 0, boolean = 1)
 		self.rc_remote_cmd_htmlmail = self.__expand("rc_remote_cmd_htmlmail",    mandatory = 0, boolean = 1)

 		self.rc_smtp_validate = self.__expand("rc_smtp_validate", mandatory = 0, boolean = 1)

		## Queued messages older than this will have "Delete" suggested as the default action
 		self.rc_remote_cmd_max_age  = self.__expand_int("rc_remote_cmd_max_age", mandatory = 0, default = 10)

		self.rc_max_attach_lines = self.__expand_int("rc_max_attach_lines", default = 50)

		## Set the max number of confirmations we can have in the list
		## before we stop sending them to that address
		self.rc_max_confirmations = self.__expand_int("rc_max_confirmations", default = 5)

		## Set the Minimum list size for who we have recently sent
		## Confirmation messages to
		self.rc_min_confirmation_list = self.__expand_int("rc_min_confirmation_list", default = 20)

		if self.rc_min_confirmation_list < 2:
			self.rc_min_confirmation_list = 2

		## Set the Maximum list size for who we have recently sent
		## Confirmation messages to
		self.rc_max_confirmation_list = self.__expand_int("rc_max_confirmation_list", default = self.rc_min_confirmation_list * 2)

		if self.rc_max_confirmation_list < self.rc_min_confirmation_list:
			self.rc_max_confirmation_list = self.rc_min_confirmation_list * 2

		## Blacklist will always be treated as ignorelist.
		if self.rc_blacklist:
			self.rc_ignorelist.extend(self.rc_blacklist)

		## We must have either rc_confirm_dirs (in which case we'll use the
		## new rc_confirm_langs) or the old style rc_confirm_mailbody. 

		if (self.rc_confirm_dirs != []):

			## Assume English if no language specified
			if (self.rc_confirm_langs == ""):
				self.rc_confirm_langs = ["en"];

			## Fill in with the filenames

			self.rc_confirm_filenames = []

			for dirname in self.rc_confirm_dirs:
				for lang in self.rc_confirm_langs:
					
					fname = os.path.join(dirname, "confirm_%s.txt" % lang)

					if os.path.isfile(fname):
						self.rc_confirm_filenames.append(fname)
		else:
			if (self.rc_confirm_mailbody != ""):
				self.rc_confirm_filenames = [ self.rc_confirm_mailbody ]
			else:
				sys.stderr.write("ERROR: No confirm_dirs or confirm_body in rcfile. Exiting...\n")
				sys.exit(self.RET_PROCMAIL_CONTINUE)
				
		## Verify if we got something...

		if self.rc_confirm_filenames == []:
			sys.stderr.write("ERROR: No confirmation templates found! Exiting...\n")
			sys.exit(self.RET_PROCMAIL_CONTINUE)

		## Pipe delivery is only supported for Python 2
		if (self.rc_mymailbox[0] == "|" and self.python_major_version < 2):
			sys.stderr.write("ERROR: You need Python 2 to use pipe delivery. Exiting...\n")
			sys.exit(self.RET_PROCMAIL_CONTINUE)

		## If we are in procmail or filter mode, set rc_mymailbox to "-"
		## to indicate stdout delivery. rc_my_original_mailbox always 
		## points to what was chosen by the user in the config file.
		##
		## Note: If the mailbox starts with a "|" (pipe symbol), we assume
		## "pipe to this program for delivery" (usually sendmail).

		self.rc_my_original_mailbox = self.rc_mymailbox

		if self.procmail_mode or self.filter_mode:
			self.rc_mymailbox = "-"

	#------------------------------------------------------------------------------

	def __expand_int(self, option, listmode = 0, mandatory = 1, boolean = 0, default = None):
		"""
		Returns same results as __expand, converted to int.
		Returns 'None' on exception.
		"""
		
		value = self.__expand(option, listmode, mandatory, boolean, default)
		try:
			value = int(value)
		except:
			value = None

		return value
	#------------------------------------------------------------------------------
	def __expand(self, option, listmode = 0, mandatory = 1, boolean = 0, default = None):
		"""
		Returns option 'option' within section 'Ask'. Some mangling will be
		done in the input field:

		- ${VARIABLE} will be expanded.

		If 'listmode' is set, the input will be split into a list (commas will
		be used as the separator).

		If 'mandatory' is set (the default), an error will occur if the variable
		is not found. If mandatory == 0 and the variable does not exist in the
		config file, it will be set to '' (or [] if listmode == 1).

		The 'boolean' argument will cause the interpretation of on/off/true/false/1/0.
		Anything else will cause the parameter to be set to false.

		"""

		try:
			buf = self.cfg.get("ask",option)

		except ConfigParser.NoSectionError, str:
			print "Config file error: %s" % str
			sys.exit(self.RET_PROCMAIL_CONTINUE)

		except ConfigParser.NoOptionError, str:
			if not default == None:
				return default
			if not mandatory:
				if listmode:
					return([])
				else:
					return('')
			print "Config file error: %s" % str
			sys.exit(self.RET_PROCMAIL_CONTINUE)

		except ValueError, str:
			print "Config file error: %s" % str
			sys.exit(self.RET_PROCMAIL_CONTINUE)

		## Remove leading and trailing backspaces
		buf = string.strip(buf)

		## Expand Environment vars

		while 1:
			res = re.search("(\$\{[a-z0-9]*\})", buf, re.IGNORECASE)

			if (res == None):
				break

			env = res.group(1)
			env = env[2:-1]						## Remove ${ and }

			## Expand environment variable, treating $HOME as a special case
			## Non-existent environment variables yield an empty string.

			if env == "HOME":
				result = self.home
			else:
				result = os.getenv(env,"")

			buf = string.replace(buf, res.group(1), result)

		## List?

		if listmode:
			listbuf = string.split(buf, ",")
			return map(lambda str: string.strip(str), listbuf)

		## If boolean, interpret true/false/on/off/1/0

		if boolean:
			if string.lower(buf) in ("true","on","1","yes"):
				return 1
			else:
				return 0

		## Normal case
		return(buf)

	#------------------------------------------------------------------------------
	def	__cmdline(self, cmd):
		"""
		Parses the command line and set the self.rc_* variables accordingly.
		Also sets the return codes for procmail.
		"""
		try:
			(opts, args) = getopt.getopt(cmd[1:], "", ["loglevel=", "logfile=","procmail","filter","home=","rcfile="])
		except getopt.error:
			sys.stderr.write("Use: askfilter [--loglevel=x --logfile=file] [--procmail|--filter] [--home=your_homedir]\n")
			sys.exit(1)

		for o, a in opts:
			if (o == "--loglevel"):
				try:
					self.loglevel = int(a)
				except ValueError:
					sys.stderr.write("Error: --loglevel takes a numeric argument\n")
			if (o == "--logfile"):
				self.logfile = a
			if (o == "--procmail"):
				self.procmail_mode = 1
				self.filter_mode = 0
			if (o == "--filter"):
				self.procmail_mode = 0
				self.filter_mode = 1
			if (o == "--home"):
				self.home = a
			if (o == "--rcfile"):
				self.rcfile = a
		
		## Set procmail return codes accordingly.
		## filter_mode always returns "continue" so procmail or another 
		## generic mail filter process knows when to discard the message

		if self.procmail_mode:
			self.RET_PROCMAIL_CONTINUE = 0
			self.RET_PROCMAIL_STOP     = 1
		else:
			self.RET_PROCMAIL_CONTINUE = 0
			self.RET_PROCMAIL_STOP     = 0

#--------------------------------------------------------------------------------------