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