[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[Patch] More headers



Hi,

next patch:

* mixminion client now supports --followup-to=news.group (loosely
  checked for syntactic validity) and --x-no-archive (boolean).
* delivery modules now support "FromTag" and "SubjectTag", each
  prepended to (if user-specified) from name resp. subject line.
* mixminion server now rejects out-of-order headers (found this
  one in the end-to-end spec).

===== Beginn =====

Index: Common.py
===================================================================
--- Common.py   (revision 6)
+++ Common.py   (working copy)
@@ -1533,8 +1533,8 @@
 
 #----------------------------------------------------------------------
 
-# A single newsgroup is a sequence of dot-separated atoms.
-_SINGLE_NEWSGROUP_PAT = r"(?:%s)(?:\.(?:%s))*" % (_ATOM_PAT, _ATOM_PAT)
+# A single newsgroup is a sequence of at least two dot-separated atoms.
+_SINGLE_NEWSGROUP_PAT = r"(?:%s)(?:\.(?:%s))+" % (_ATOM_PAT, _ATOM_PAT)
 # A list of newsgroups is a sequence of comma-separated newsgroups.
 _NEWSGROUPS_PAT = r"\A%s(,%s)*\Z" % (_SINGLE_NEWSGROUP_PAT, _SINGLE_NEWSGROUP_PAT)
 NEWSGROUPS_RE = re.compile(_NEWSGROUPS_PAT)
Index: Packet.py
===================================================================
--- Packet.py   (revision 6)
+++ Packet.py   (working copy)
@@ -869,7 +869,7 @@
 MAX_HEADER_LEN = 900
 
 def encodeMailHeaders(subject=None, fromAddr=None, inReplyTo=None,
-                      references=None):
+                      references=None, followupTo=None, xNoArchive=0):
     """Given (optionally) any of the headers permissible for email
        messages, return a string to be prepended to a message before
        encoding.  Raise MixError on failure."""
@@ -886,6 +886,12 @@
         headers['IN-REPLY-TO'] = inReplyTo
     if references:
         headers['REFERENCES'] = references
+    if followupTo:
+        if not isNewsgroups(followupTo):
+            raise MixError("Invalid followup-to %r " % followupTo)
+        headers['FOLLOWUP-TO'] = followupTo
+    if xNoArchive:
+        headers['X-NO-ARCHIVE'] = 'yes'
     return encodeMessageHeaders(headers)
 
 def encodeMessageHeaders(headers):
@@ -915,16 +921,20 @@
        Skips improperly formatted headers."""
     headers = {}
     msg = message
+    previous = None
     while 1:
         if msg[0] == '\n':
             return msg[1:], headers
         m = HEADER_RE.match(msg)
         if m:
             k,v = m.groups()
-            if len(v) > MAX_HEADER_LEN:
+            if previous and k < previous:
+                LOG.warn("Rejecting out-of-order exit header %r:%r...",k,v[:30])
+            elif len(v) > MAX_HEADER_LEN:
                 LOG.warn("Rejecting overlong exit header %r:%r...",k,v[:30])
             else:
                 headers[k] = v
+                previous = k
             msg = msg[m.end():]
         else:
             LOG.warn("Could not parse headers on message; not using them.")
Index: server/Modules.py
===================================================================
--- server/Modules.py   (revision 6)
+++ server/Modules.py   (working copy)
@@ -962,6 +962,7 @@
     # subject: Default subject to use for outgoing mail, if none is given
     #    in the message.
     # fromTag: String to prepend to from name.
+    # subjectTag: String to prepend to subject.
     # returnAddress: Return address for mail; should be an rfc822-style
     #    mailbox.
     # header: Text that should be appended after the headers and before
@@ -983,6 +984,7 @@
         'MessageHeader' : ('ALLOW', None, None),
         'MessageFooter' : ('ALLOW', None, None),
         'FromTag' : ('ALLOW', None, "[Anon]"),
+        'SubjectTag' : ('ALLOW', None, None),
         'ReturnAddress' : ('ALLOW', None, None),
         }
 
@@ -998,7 +1000,13 @@
             return None
 
         headers = packet.getHeaders()
-        subject = headers.get("SUBJECT", self.subject)
+        if headers.has_key("SUBJECT"):
+            if self.subjectTag:
+                subject = "%s %s" % (self.subjectTag, headers.get("SUBJECT"))
+            else:
+                subject = headers.get("SUBJECT")
+        else:
+            subject = self.subject
         fromAddr = headers.get("FROM")
         if fromAddr and self.allowFromAddr:
             fromAddr = '"%s %s" <%s>' % (self.fromTag, fromAddr,
@@ -1008,14 +1016,25 @@
 
         morelines = []
         if mixminion.Packet.NEWS_TYPE in self.getExitTypes():
-            newsgroups = packet.getAddress()
-            if isNewsgroups(newsgroups):
-                 if newsgroups.count(',') > MAX_NEWSGROUPS-1:
-                      LOG.warn("Dropping excessive crossposting: %s" % newsgroups)
-                      return None
-                 morelines.append("Newsgroups: %s\n" % newsgroups)
+            newsgroups = packet.getAddress().lower()
+            if not isNewsgroups(newsgroups):
+                LOG.warn("Invalid newsgroups: %s" % newsgroups)
+                return None
             else:
-                 LOG.warn("Invalid newsgroups: %s" % newsgroups)
+                if newsgroups.count(',') > MAX_NEWSGROUPS-1:
+                    LOG.warn("Dropping excessive crossposting: %s" % newsgroups)
+                    return None
+                morelines.append("Newsgroups: %s\n" % newsgroups)
+
+            if headers.has_key("FOLLOWUP-TO"):
+                followupto = headers['FOLLOWUP-TO'].lower()
+                if not isNewsgroups(followupto):
+                    LOG.warn("Invalid followup-to: %s" % followupto)
+                else:
+                    morelines.append("Followup-To: %s\n" % followupto)
+            if headers.has_key("X-NO-ARCHIVE"):
+                morelines.append("X-No-Archive: yes\n")
+            
         if headers.has_key("IN-REPLY-TO"):
             morelines.append("In-Reply-To: %s\n" % headers['IN-REPLY-TO'])
         if headers.has_key("REFERENCES"):
@@ -1141,7 +1160,8 @@
 
         # These fields are needed by MailBase
         self.initializeHeaders(sec)
-        self.fromTag = "[Anon]"
+        self.fromTag = sec.get('FromTag', "[Anon]")
+        self.subjectTag = sec.get('SubjectTag', "")
 
         # Enable module
         moduleManager.enableModule(self)
@@ -1268,7 +1288,8 @@
 
         # These fields are needed by MailBase
         self.initializeHeaders(sec)
-        self.fromTag = "[Anon]"
+        self.fromTag = sec.get('FromTag', "[Anon]")
+        self.subjectTag = sec.get('SubjectTag', "")
 
         # Parse the address file.
         self.addresses = {}
@@ -1420,6 +1441,7 @@
             self.blacklist = None
         self.returnAddress = sec['ReturnAddress']
         self.fromTag = sec.get('FromTag', "[Anon]")
+        self.subjectTag = sec.get('SubjectTag', "")
         self.allowFromAddr = sec['AllowFromAddress']
         self.armorPlaintext = sec['ArmorPlaintext']
 
@@ -1504,6 +1526,7 @@
         self.server = sec['Server']
         self.retrySchedule = sec['Retry']
         self.fromTag = sec.get('FromTag', "[Anon]")
+        self.subjectTag = sec.get('SubjectTag', "")
         self.allowFromAddr = sec['AllowFromAddress']
         self.armorPlaintext = sec['ArmorPlaintext']
         self.command = cmd[0]
Index: ClientMain.py
===================================================================
--- ClientMain.py       (revision 6)
+++ ClientMain.py       (working copy)
@@ -1079,7 +1079,7 @@
         shortOpts += "P:H:"
         longOpts += ["path=","hops="]
     if headers:
-        longOpts += ["subject=", "from=", "in-reply-to=", "references="]
+        longOpts += ["subject=", "from=", "in-reply-to=", "references=", "followup-to=", "x-no-archive"]
     if dest:
         shortOpts += "t:"
         longOpts += ["to="]
@@ -1115,6 +1115,8 @@
                              or '-' for a reply block read from stdin.
   --subject=<str>, --from=<str>, --in-reply-to=<str>, --references=<str>
                              Specify an email header for the exiting message.
+  --followup-to=<str>, --x-no-archive
+                             Specify a news header for the exiting message.
   --deliver-fragments        If the message is too long to fit in a single
                              packet, then deliver multiple fragmented packets
                              to the recipient instead of having the server
@@ -1194,7 +1196,8 @@
         sendUsageAndExit(cmd)
 
     inFile = '-'
-    h_subject = h_from = h_irt = h_references = None
+    h_subject = h_from = h_irt = h_references = h_fut = None
+    h_xna = 0
     no_ss_fragment = 0
     for opt,val in options:
         if opt in ('-i', '--input'):
@@ -1207,6 +1210,10 @@
             h_irt = val
         elif opt == '--references':
             h_references = val
+        elif opt == '--followup-to':
+            h_fut = val
+        elif opt == '--x-no-archive':
+            h_xna = 1
         elif opt == '--deliver-fragments':
             no_ss_fragment = 1
 
@@ -1226,7 +1233,8 @@
     # they won't work.
     try:
         headerStr = encodeMailHeaders(subject=h_subject, fromAddr=h_from,
-                                      inReplyTo=h_irt, references=h_references)
+                                      inReplyTo=h_irt, references=h_references,
+                                      followupTo=h_fut, xNoArchive=h_xna)
     except MixError, e:
         raise UIError("Invalid headers: %s"%e)
     if no_ss_fragment:
@@ -1311,6 +1319,8 @@
   -i <file>, --input=<file>  Read the message from <file>. (Defaults to stdin.)
   --subject=<str>, --from=<str>, --in-reply-to=<str>, --references=<str>
                              Specify an email header for the exiting message.
+  --followup-to=<str>, --x-no-archive
+                             Specify a news header for the exiting message.
   --deliver-fragments        If the message is too long to fit in a single
                              packet, then deliver multiple fragmented packets
                              to the recipient instead of having the server
@@ -1323,7 +1333,8 @@
                                input=1, headers=1)
 
     inFile = '-'
-    h_subject = h_from = h_irt = h_references = None
+    h_subject = h_from = h_irt = h_references = h_fut = None
+    h_xna = 0
     no_ss_fragment = 0
     reply = 0
     for opt,val in options:
@@ -1337,6 +1348,10 @@
             h_irt = val
         elif opt == '--references':
             h_references = val
+        elif opt == '--followup-to':
+            h_fut = val
+        elif opt == '--x-no-archive':
+            h_xna = 1
         elif opt == '--deliver-fragments':
             no_ss_fragment = 1
         elif opt in ('-R', '--reply'):
@@ -1353,7 +1368,8 @@
     # they won't work.
     try:
         headerStr = encodeMailHeaders(subject=h_subject, fromAddr=h_from,
-                                      inReplyTo=h_irt, references=h_references)
+                                      inReplyTo=h_irt, references=h_references,
+                                      followupTo=h_fut, xNoArchive=h_xna)
     except MixError, e:
         raise UIError("Invalid headers: %s"%e)
     if no_ss_fragment:

===== Ende =====

Ciao

Tobias
-- 
mbox:admin@tainaron

Attachment: pgplnbFRIP3nH.pgp
Description: PGP signature