[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[minion-cvs] First cut at implementing headers (server-side)
Update of /home/minion/cvsroot/src/minion/lib/mixminion/server
In directory moria.mit.edu:/tmp/cvs-serv30719/lib/mixminion/server
Modified Files:
Modules.py PacketHandler.py ServerMain.py
Log Message:
First cut at implementing headers (server-side)
Index: Modules.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/server/Modules.py,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -d -r1.45 -r1.46
--- Modules.py 25 Jun 2003 17:03:15 -0000 1.45
+++ Modules.py 30 Jun 2003 17:33:33 -0000 1.46
@@ -765,12 +765,40 @@
return "SMTP"
def getExitTypes(self):
return [ mixminion.Packet.SMTP_TYPE ]
+ def _formatSMTPMessage(self, address, packet):
+ """DOCDOC"""
+ #DOCDOC implied fields
+
+ headers = packet.getHeaders()
+ subject = headers.get("SUBJECT", self.subject)
+ fromAddr = headers.get("FROM")
+ if fromAddr:
+ fromAddr = '"%s %s" <%s>' % (self.fromTag, fromAddr,
+ self.returnAddress)
+ else:
+ fromAddr = self.returnAddress
+
+ morelines = []
+ if headers.has_key("IN-REPLY-TO"):
+ morelines.append("In-Reply-To: %s\n" % headers['IN-REPLY-TO'])
+ if headers.has_key("REFERENCES"):
+ morelines.append("References: %s\n" % headers['REFERENCES'])
+
+ # Decode and escape the message, and get ready to send it.
+ msg = _escapeMessageForEmail(packet)
+ msg = "To: %s\nFrom: %s\nSubject: %s\n%s%s\n\n%s"%(
+ address, fromAddr, subject, "".join(morelines), self.header, msg)
+
+ return msg
class DirectSMTPModule(SMTPModule):
"""Module that delivers SMTP messages via a local MTA."""
## Fields
# server -- Name of the MTA server.
- # header -- The string, minus "To:"-line, that gets prepended to all
+ # subject: The default subject line we use for outgoing messages
+ # fromPattern: A printf format string with a field for user-supplied
+ # from addresses.
+ # header -- A string, minus "To:"-line, that gets prepended to all
# outgoing messages.
# returnAddress -- The address to use in the "From:" line.
# blacklist -- An EmailAddressSet of addresses to which we refuse
@@ -792,6 +820,7 @@
'SMTPServer' : ('ALLOW', None, 'localhost'),
'Message' : ('ALLOW', None, ""),
'ReturnAddress': ('ALLOW', None, None), #Required on e
+ 'FromTag' : ('ALLOW', None, "[Anon]"),
'SubjectLine' : ('ALLOW', None,
'Type III Anonymous Message'),
@@ -827,11 +856,13 @@
else:
self.blacklist = None
message = "\n".join(textwrap.wrap(sec.get('Message',""))).strip()
- subject = sec['SubjectLine']
+ self.subject = sec['SubjectLine']
self.returnAddress = sec['ReturnAddress']
-
- self.header = "From: %s\nSubject: %s\nX-Anonymous: yes\n\n%s" %(
- self.returnAddress, subject, message)
+ self.fromTag = sec.get('FromTag', "[Anon]")
+ if message:
+ self.header = "X-Anonymous: yes\n\n%s" %(message)
+ else:
+ self.header = "X-Anonymous: yes"
manager.enableModule(self)
@@ -851,10 +882,7 @@
LOG.warn("Dropping message to blacklisted address %r", address)
return DELIVER_FAIL_NORETRY
- # Decode and escape the message, and get ready to send it.
- msg = _escapeMessageForEmail(packet)
- msg = "To: %s\n%s\n\n%s"%(address, self.header, msg)
-
+ msg = self._formatSMTPMessage(address, packet)
# Send the message.
return sendSMTPMessage(self.server, [address], self.returnAddress, msg)
@@ -868,7 +896,9 @@
## Fields:
# server: The path (usually a single server) to use for outgoing messages.
# Multiple servers should be separated by commas.
- # subject: The subject line we use for outgoing messages
+ # subject: The default subject line we use for outgoing messages
+ # fromPattern: A printf format string with a field for user-supplied
+ # from addresses.
# command: The Mixmaster binary.
# options: Options to pass to the Mixmaster binary when queueing messages
# tmpQueue: An auxiliary Queue used to hold files so we can pass them to
@@ -887,6 +917,7 @@
"7 hours for 6 days"),
'MixCommand' : ('REQUIRE', _parseCommand, None),
'Server' : ('REQUIRE', None, None),
+ 'FromTag' : ('ALLOW', None, "[Anon]"),
'SubjectLine' : ('ALLOW', None,
'Type III Anonymous Message'),
}
@@ -908,9 +939,11 @@
self.server = sec['Server']
self.subject = sec['SubjectLine']
self.retrySchedule = sec['Retry']
+ self.fromTag = sec.get('FromTag', "[Anon]")
self.command = cmd[0]
- self.options = tuple(cmd[1]) + ("-l", self.server,
- "-s", self.subject)
+ self.options = tuple(cmd[1]) + ("-l", self.server)
+ self.returnAddress = "nobody"
+ self.header = "X-Anonymous: yes"
manager.enableModule(self)
def getName(self):
@@ -934,12 +967,11 @@
packet.getAddress())
return DELIVER_FAIL_NORETRY
- msg = _escapeMessageForEmail(packet)
+ msg = self._formatSMTPMessage(info.email, packet)
handle = self.tmpQueue.queueMessage(msg)
cmd = self.command
- opts = self.options + ("-t", info.email,
- self.tmpQueue.getMessagePath(handle))
+ opts = self.options + (self.tmpQueue.getMessagePath(handle),)
code = os.spawnl(os.P_WAIT, cmd, cmd, *opts)
LOG.debug("Queued Mixmaster message: exit code %s", code)
self.tmpQueue.removeMessage(handle)
@@ -962,6 +994,20 @@
#----------------------------------------------------------------------
+MAIL_HEADERS = ["SUBJECT", "FROM", "IN-REPLY-TO", "REFERENCES"]
+def checkMailHeaders(headers):
+ """DOCDOC"""
+ for k in headers.keys():
+ if k not in MAIL_HEADERS:
+ #XXXX this should raise parse error instead.
+ LOG.warn("Skipping unrecognized mail header %s"%k)
+
+ fromAddr = headers['FROM']
+ if re.search(r'[\[\]:"]', fromAddr):
+ raise ParseError("Invalid FROM address: %r", fromAddr)
+
+#----------------------------------------------------------------------
+
def sendSMTPMessage(server, toList, fromAddr, message):
"""Send a single SMTP message. The message will be delivered to
toList, and seem to originate from fromAddr. We use 'server' as an
@@ -991,6 +1037,7 @@
"""Helper function: Given a message and tag, escape the message if
it is not plaintext ascii, and wrap it in some standard
boilerplate. Add a disclaimer if the message is not ascii.
+ Extracts headers if possible. Returns a 2-tuple of message/headers.
packet -- an instance of DeliveryPacket
Index: PacketHandler.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/server/PacketHandler.py,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- PacketHandler.py 6 Jun 2003 06:04:58 -0000 1.17
+++ PacketHandler.py 30 Jun 2003 17:33:33 -0000 1.18
@@ -4,10 +4,11 @@
"""mixminion.PacketHandler: Code to process mixminion packets on a server"""
import binascii
+import re
import threading
import types
-from mixminion.Common import encodeBase64, formatBase64
+from mixminion.Common import encodeBase64, formatBase64, LOG
import mixminion.Crypto as Crypto
import mixminion.Packet as Packet
import mixminion.Common as Common
@@ -276,6 +277,7 @@
self.payload = payload
self.contents = None
self.type = None
+ self.headers = None#DOCDOC
def isDelivery(self):
"""Return true iff this packet is a delivery (non-relay) packet."""
@@ -333,17 +335,20 @@
# encrypted message
self.type = 'enc'
self.contents = message
+ self.headers = {}
else:
# forward message
self.type = 'plain'
- # self.contents is right
+ self.contents, self.headers = \
+ Packet.parseMessageAndHeaders(self.contents)
except Packet.CompressedDataTooLong, _:
- self.contents = (mixminion.Packet.parsePayload(message)
- .getContents())
+ self.contents = Packet.parsePayload(message).getContents()
self.type = 'long'
+ self.headers = {}
except MixError:
self.contents = message
self.type = 'err'
+ self.headers = {}
self.payload = None
@@ -358,6 +363,13 @@
else:
return encodeBase64(self.contents)
+ def getHeaders(self):
+ """DOCDOC"""
+ if self.type is None:
+ self.decode()
+ assert self.headers is not None
+ return self.headers
+
def getAsciiTag(self):
"""Return a base64-representation of this message's decoding handle."""
return formatBase64(self.tag)
@@ -378,3 +390,4 @@
tp = 'BIN'
return Packet.TextEncodedMessage(self.contents, tp, tag)
+
Index: ServerMain.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/server/ServerMain.py,v
retrieving revision 1.82
retrieving revision 1.83
diff -u -d -r1.82 -r1.83
--- ServerMain.py 26 Jun 2003 17:52:09 -0000 1.82
+++ ServerMain.py 30 Jun 2003 17:33:33 -0000 1.83
@@ -643,7 +643,12 @@
raise UIError("The server homedir contains keys for an "
"unrecognized version of the server.")
else:
- raise
+ raise UIError("""\
+For some reason, your generated server descriptors cannot be parsed. You
+may want to delete all your keysets with server-DELKEYS and have the server
+generate new ones. [Messages sent to the old keys will be lost].\n
+The original error message was '%s'."""%e)
+
self.keyring.createKeysAsNeeded()
self.keyring.checkDescriptorConsistency()