[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[minion-cvs] Debug modules in response to tests; refactor.



Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.seul.org:/tmp/cvs-serv9004/lib/mixminion

Modified Files:
	Modules.py 
Log Message:
Debug modules in response to tests; refactor.

	- Change semantics of addresses and tags to centralize decoding
	  in ModuleManager
	- Debug MBOXModule: address handling, message generation
	- Debug MixmasterSMTPModule: handle options sensibly; enable module
	  as needed.
	- Refactor isPrintable from _escapeMessage	
	- Clarify XXXX comments
        - Rename 'deliverMessages' to '_deliverMessages'
	- Rename 'DeliveryQueue.queueMessages' in 'queueDeliverMessages' to
	  avoid confusion with Queue.queueMessages, which it doesn't really
	  override.

Index: Modules.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Modules.py,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- Modules.py	22 Nov 2002 21:12:05 -0000	1.17
+++ Modules.py	2 Dec 2002 03:24:23 -0000	1.18
@@ -11,6 +11,7 @@
 	    'SMTP_TYPE', 'MBOX_TYPE' ]
 
 import os
+import re
 import sys
 import smtplib
 import socket
@@ -88,12 +89,19 @@
 	"""Return a DeliveryQueue object suitable for delivering messages
 	   via this module.  The default implementation returns a
 	   SimpleModuleDeliveryQueue,  which (though adequate) doesn't
-	   batch messages intended for the same destination."""
+	   batch messages intended for the same destination.
+
+	   For the 'address' component of the delivery queue, modules must
+	   accept a tuple of: (exitType, address, tag).  If 'tag' is None,
+	   the message has been decrypted; if 'tag' is 'err', the message is
+	   corrupt.  Otherwise, the message is either a reply or an encrypted
+	   forward message
+	   """
         return SimpleModuleDeliveryQueue(self, queueDir)
 
     def processMessage(self, message, tag, exitType, exitInfo):
 	"""Given a message with a given exitType and exitInfo, try to deliver
-           it.  Return one of:
+           it.  'tag' is as decribed in createDeliveryQueue. Return one of:
             DELIVER_OK (if the message was successfully delivered),
 	    DELIVER_FAIL_RETRY (if the message wasn't delivered, but might be
               deliverable later), or
@@ -108,9 +116,9 @@
     def __init__(self, module):
 	self.module = module
 
-    def queueMessage(self, (exitType, address, tag), message):
+    def queueDeliveryMessage(self, (exitType, address, tag), message):
 	try:
-	    res = self.module.processMessage(message, exitType, tag, address)
+	    res = self.module.processMessage(message, tag, exitType, address)
 	    if res == DELIVER_OK:
 		return
 	    elif res == DELIVER_FAIL_RETRY:
@@ -132,7 +140,7 @@
 	mixminion.Queue.DeliveryQueue.__init__(self, directory)
 	self.module = module
 
-    def deliverMessages(self, msgList):
+    def _deliverMessages(self, msgList):
 	for handle, addr, message, n_retries in msgList:	
 	    try:
 		exitType, address, tag = addr
@@ -284,7 +292,17 @@
                            exitType)
 	    return
 	queue = self.queues[mod.getName()]
-	queue.queueMessage((exitType, address, tag), message)
+	try:
+	    payload = mixminion.BuildMessage.decodePayload(message, tag)
+	except MixError, _:
+	    queue.queueDeliveryMessage((exitType, address, 'err'), message)
+	    return
+	if payload is None:
+	    # enrypted message
+	    queue.queueDeliveryMessage((exitType, address, tag), message)
+	else:
+	    # forward message
+	    queue.queueDeliveryMessage((exitType, address, tag), payload)
 
     def sendReadyMessages(self):
 	for name, queue in self.queues.items():
@@ -358,19 +376,25 @@
             self.nickname = socket.gethostname()
         self.addr = config['Server'].get('IP', "<Unknown host>")
 
+	self.addresses = {}
         f = open(self.addressFile)
-        addresses = f.read()
-        f.close()
-
-        addresses = mixminion.Config._readConfigFile(addresses)
-        assert len(addresses) > 1
-        assert not addresses.has_key('Addresses')
-
-        self.addresses = {}
-        for k, v, line in addresses[0][1]:
-            if self.addresses.has_key(k):
-                raise ConfigError("Duplicate MBOX user %s"%k)
-            self.addresses[k] = v
+	address_line_re = re.compile(r'\s*([^\s:=]+)\s*[:=]\s*(\S+)')
+	try:
+	    lineno = 0
+	    for line in f.xreadlines():
+		line = line.strip()
+		lineno += 1
+		if line == '' or line[0] == '#':
+		    continue
+		m = address_line_re.match(line)
+		if not m:
+		    raise ConfigError("Bad address on line %s of %s"%(
+			lineno,self.addressFile))
+		self.addresses[m.group(1)] = m.group(2)
+		getLog().trace("Mapping MBOX address %s -> %s", m.group(1),
+			       m.group(2))
+	finally:
+	    f.close()
 
 	moduleManager.enableModule(self)
 
@@ -393,7 +417,8 @@
 	try:
 	    address = self.addresses[info.user]
 	except KeyError, _:
-            getLog.warn("Unknown MBOX user %r", info.user)
+            getLog().error("Unknown MBOX user %r", info.user)
+	    return DELIVER_FAIL_NORETRY
 
         msg = _escapeMessageForEmail(message, tag)
 
@@ -403,25 +428,24 @@
                    'addr': self.addr,
                    'contact': self.contact,
                    'msg': msg }
-        msg = """
+        msg = """\
 To: %(user)s
 From: %(return)s
 Subject: Anonymous Mixminion message
 
 THIS IS AN ANONYMOUS MESSAGE.  The mixminion server '%(nickname)s' at
-%(addr)s has been configured to deliver messages to your address.  If you
-do not want to receive messages in the future, contact %(contact)s and you
-will be removed.
+%(addr)s has been configured to deliver messages to your address.  
+If you do not want to receive messages in the future, contact %(contact)s 
+and you will be removed.
 
-%(msg)s
-""" % fields
+%(msg)s""" % fields
 
         return sendSMTPMessage(self.server, [address], self.returnAddress, msg)
 
 #----------------------------------------------------------------------
 class SMTPModule(DeliveryModule):
     """Placeholder for real exit node implementation.
-        DOCDOC XXXXX document me."""
+        DOCDOC document me."""
     def __init__(self):
         DeliveryModule.__init__(self)
         self.enabled = 0
@@ -469,13 +493,14 @@
         self.server = sec['Server']
         self.subject = sec['Subject']
         self.command = cmd[0]
-        self.options = cmd[1] + ("-l", self.server,
-                                 "-s", self.subject)
-        
+        self.options = tuple(cmd[1]) + ("-l", self.server,
+					"-s", self.subject)
+        manager.enableModule(self)
+
     def getName(self): 
         return "SMTP_MIX2" 
     def createDeliveryQueue(self, queueDir):
-        self.tmpQueue = mixminion.Queue.queue(queueDir+"_tmp", 1, 1)
+        self.tmpQueue = mixminion.Queue.Queue(queueDir+"_tmp", 1, 1)
         self.tmpQueue.removeAll()
         return _MixmasterSMTPModuleDeliveryQueue(self, queueDir)
     def processMessage(self, message, tag, exitType, smtpAddress):
@@ -495,18 +520,18 @@
         return DELIVER_OK
                          
     def flushMixmasterPool(self):
-        "XXXX"
+        "DOCDOC"
         cmd = self.command
         getLog().debug("Flushing Mixmaster pool")
         os.spawnl(os.P_NOWAIT, cmd, cmd, "-S")
 
 class _MixmasterSMTPModuleDeliveryQueue(SimpleModuleDeliveryQueue):
-    "XXXX"
+    "DOCDOC"
     def __init__(self, module, directory):
         SimpleModuleDeliveryQueue.__init__(self, module, directory)
-    def deliverMessages(self, msgList):
-        SimpleModuleDeliveryQueue.deliverMessages(self, msgList)
-        self.module.flushMixmaterPool()
+    def _deliverMessages(self, msgList):
+        SimpleModuleDeliveryQueue._deliverMessages(self, msgList)
+        self.module.flushMixmasterPool()
         
 #----------------------------------------------------------------------
 def sendSMTPMessage(server, toList, fromAddr, message):
@@ -525,14 +550,20 @@
 
 #----------------------------------------------------------------------
 
-#XXXX DOCDOC
+# DOCDOC
 _allChars = "".join(map(chr, range(256)))
-# XXXX Are there any nonprinting chars >= 0x7f to worry about now?
+# DOCDOC
+# ???? Are there any nonprinting chars >= 0x7f to worry about now?
 _nonprinting = "".join(map(chr, range(0x00, 0x07)+range(0x0E, 0x20)))
+def isPrintable(s):
+    """Return true iff s consists only of printable characters."""
+    printable = s.translate(_allChars, _nonprinting)
+    return len(printable) == len(s)
+
 def _escapeMessageForEmail(msg, tag):
-    """XXXX DOCDOC
+    """DOCDOC
          -> None | str """
-    m = _decodeAndEscapeMessage(msg, tag, text=1)
+    m = _escapeMessage(msg, tag, text=1)
     if m is None:
 	return None
     code, msg, tag = m
@@ -553,24 +584,18 @@
 %s============ ANONYMOUS MESSAGE BEGINS
 %s%s============ ANONYMOUS MESSAGE ENDS\n""" %(junk_msg, tag, msg)
 
-def _decodeAndEscapeMessage(payload, tag, text=0):
-    """XXXX DOCDOC
-	  -> ("TXT"|"BIN"|"ENC", message, tag|None) or None
+def _escapeMessage(message, tag, text=0):
+    """DOCDOC
+	 (message,tag|None,output-as-text?) 
+                -> ("TXT"|"BIN"|"ENC", message, tag|None) or None
     """
-    if not tag:
-	raise ContentError("Missing tag from message")
-    try:
-	message = mixminion.BuildMessage.decodePayload(payload, tag)
-    except MixError, _:
+    if tag == 'err':
 	return None
-
-    if message is None:
+    elif tag is not None:
 	code = "ENC"
-	message = payload
     else:
 	tag = None
-	printable = message.translate(_allChars, _nonprinting)
-	if len(printable) == len(message):
+	if isPrintable(message):
 	    code = "TXT"
 	else:
 	    code = "BIN"
@@ -578,7 +603,6 @@
     if text and (code != "TXT") :
 	message = base64.encodestring(message)
     if text and tag:
-	tag = base64.encodestring(tag)
-	if tag[-1] == '\n': tag = tag[:-1]
+	tag = base64.encodestring(tag).strip()
 
     return code, message, tag