# HG changeset patch # User Paul Boddie # Date 1384450990 -3600 # Node ID 85e8ce50de99be177569f034ce2378a874206229 # Parent 1783e36ab941fae07fefd58401eeb8016236103b Introduced initial routing for messages having a "To" header, consulting the main recipients dictionary and directing messages to appropriate message stores. diff -r 1783e36ab941 -r 85e8ce50de99 MoinMessageSupport.py --- a/MoinMessageSupport.py Thu Nov 14 18:40:34 2013 +0100 +++ b/MoinMessageSupport.py Thu Nov 14 18:43:10 2013 +0100 @@ -10,7 +10,8 @@ from MoinMoin.log import getLogger from MoinMoin.user import User from MoinMoin import wikiutil -from MoinSupport import getHeader, getMetadata, getWikiDict, writeHeaders +from MoinSupport import getHeader, getMetadata, getWikiDict, writeHeaders, \ + parseDictEntry from ItemSupport import ItemStore from MoinMessage import GPG, Message, MoinMessageError, \ MoinMessageMissingPart, MoinMessageBadContent, \ @@ -39,6 +40,9 @@ self.pagename = pagename self.request = request self.page = Page(request, pagename) + self.init_store() + + def init_store(self): self.store = ItemStore(self.page, "messages", "message-locks") def do_action(self): @@ -53,7 +57,29 @@ "Handle the given 'message_text'." + request = self.request message = Parser().parse(StringIO(message_text)) + + # Detect any indicated recipient and change the target page, if + # appropriate. + + if message.has_key("To"): + try: + parameters = get_recipient_details(request, message["To"], main=True) + except MoinMessageRecipientError, exc: + writeHeaders(request, "text/plain", getMetadata(self.page), "403 Forbidden") + request.write("The recipient indicated in the message is not known to this site. " + "Details: %s" % exc.message) + return + else: + if parameters["type"] == "page": + self.page = Page(request, parameters["location"]) + self.init_store() + + # NOTE: Support "url". + + # Handle the parsed message. + self.handle_message(message) def handle_message(self, message): @@ -200,6 +226,18 @@ return homedir +class MoinMessageRecipientError(MoinMessageError): + pass + +class MoinMessageNoRecipients(MoinMessageRecipientError): + pass + +class MoinMessageUnknownRecipient(MoinMessageRecipientError): + pass + +class MoinMessageBadRecipient(MoinMessageRecipientError): + pass + def get_homedir(request): "Locate the GPG home directory." @@ -222,27 +260,32 @@ getattr(request.cfg, "moinmessage_gpg_relays_page", "MoinMessageRelayDict"), request) -def get_recipients(request): +def get_recipients(request, main=False): """ Return the recipients dictionary by first obtaining the page in which it is stored. This page may either be a subpage of the user's home page, if stored on this wiki, or it may be relative to the site root. + When 'main' is specified and set to a true value, only a dictionary under + the site root is consulted. + The name of the subpage is defined by the configuration setting 'moinmessage_gpg_recipients_page', which if absent is set to "MoinMessageRecipientsDict". """ subpage = getattr(request.cfg, "moinmessage_gpg_recipients_page", "MoinMessageRecipientsDict") - homedetails = wikiutil.getInterwikiHomePage(request) + + if not main: + homedetails = wikiutil.getInterwikiHomePage(request) - if homedetails: - homewiki, homepage = homedetails - if homewiki == "Self": - recipients = getWikiDict("%s/%s" % (homepage, subpage), request) - if recipients: - return recipients + if homedetails: + homewiki, homepage = homedetails + if homewiki == "Self": + recipients = getWikiDict("%s/%s" % (homepage, subpage), request) + if recipients: + return recipients return getWikiDict(subpage, request) @@ -267,4 +310,38 @@ else: return None +def get_recipient_details(request, recipient, main=False): + + """ + Using the 'request', return a dictionary of details for the specified + 'recipient'. If no details exist, raise a MoinMessageRecipientError + exception. + + When 'main' is specified and set to a true value, only the recipients + dictionary under the site root is consulted. + """ + + _ = request.getText + + recipients = get_recipients(request, main) + if not recipients: + raise MoinMessageNoRecipients, _("No recipients page is defined for MoinMessage.") + + recipient_details = recipients.get(recipient) + if not recipient_details: + raise MoinMessageUnknownRecipient, _("The specified recipient is not present in the list of known contacts.") + + parameters = parseDictEntry(recipient_details, ("type", "location", "fingerprint",)) + + if not parameters.has_key("type"): + raise MoinMessageBadRecipient, _("The recipient details are missing a destination type.") + + if not parameters.has_key("location"): + raise MoinMessageBadRecipient, _("The recipient details are missing a location for sent messages.") + + if parameters["type"] in ("url", "relay") and not parameters.has_key("fingerprint"): + raise MoinMessageBadRecipient, _("The recipient details are missing a fingerprint for sending messages.") + + return parameters + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 1783e36ab941 -r 85e8ce50de99 README.txt --- a/README.txt Thu Nov 14 18:40:34 2013 +0100 +++ b/README.txt Thu Nov 14 18:43:10 2013 +0100 @@ -282,6 +282,13 @@ http://localhost/wiki/ShareTest \ collection update 'An update to the wiki.' 'Another update.' +Explicit recipient information can be provided for routing purposes: + +python tests/test_send.py 1C1AAF83 0891463A --to PaulBoddie \ + --forward 1C1AAF83 \ + http://localhost/wiki/ShareTest \ + collection update 'An update to the wiki.' 'Another update.' + Below, the mechanisms employed are illustrated through the use of the other test programs. diff -r 1783e36ab941 -r 85e8ce50de99 actions/SendMessage.py --- a/actions/SendMessage.py Thu Nov 14 18:40:34 2013 +0100 +++ b/actions/SendMessage.py Thu Nov 14 18:43:10 2013 +0100 @@ -12,7 +12,8 @@ from MoinMoin.Page import Page from MoinMoin import config from MoinMessage import GPG, MoinMessageError, Message, sendMessage, timestamp -from MoinMessageSupport import get_signing_users, get_recipients, get_relays +from MoinMessageSupport import get_signing_users, get_recipients, get_relays, \ + get_recipient_details, MoinMessageRecipientError from MoinSupport import * from ItemSupport import ItemStore from MoinMoin.wikiutil import escape, MimeType, parseQueryString, \ @@ -274,24 +275,10 @@ # Get the recipient details. - recipients = get_recipients(request) - if not recipients: - return 0, _("No recipients page is defined for MoinMessage.") - - recipient_details = recipients.get(recipient) - if not recipient_details: - return 0, _("The specified recipient is not present in the list of known contacts.") - - parameters = parseDictEntry(recipient_details, ("type", "location", "fingerprint",)) - - if not parameters.has_key("type"): - return 0, _("The recipient details are missing a destination type.") - - if not parameters.has_key("location"): - return 0, _("The recipient details are missing a location for sent messages.") - - if parameters["type"] in ("url", "relay") and not parameters.has_key("fingerprint"): - return 0, _("The recipient details are missing a fingerprint for sending messages.") + try: + parameters = get_recipient_details(request, recipient) + except MoinMessageRecipientError, exc: + return 0, exc.message type = parameters["type"] location = parameters["location"] diff -r 1783e36ab941 -r 85e8ce50de99 tests/test_add_recipient.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_add_recipient.py Thu Nov 14 18:43:10 2013 +0100 @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +from email import message_from_string +import sys + +if __name__ == "__main__": + to = sys.argv[1] + text = sys.stdin.read() + + message = message_from_string(text) + message["To"] = to + + # Show the resulting message text. + + text = message.as_string() + print text + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 1783e36ab941 -r 85e8ce50de99 tests/test_send.py --- a/tests/test_send.py Thu Nov 14 18:40:34 2013 +0100 +++ b/tests/test_send.py Thu Nov 14 18:43:10 2013 +0100 @@ -8,12 +8,17 @@ try: signer = sys.argv[1] recipient = sys.argv[2] - if sys.argv[3] == "--forward": - forwarder = sys.argv[4] - i = 5 + i = 3 + if sys.argv[i] == "--to": + to = sys.argv[i+1] + i += 2 + else: + to = None + if sys.argv[i] == "--forward": + forwarder = sys.argv[i+1] + i += 2 else: forwarder = None - i = 3 url = sys.argv[i] + "?action=PostMessage" type = sys.argv[i+1] action = sys.argv[i+2] @@ -60,6 +65,11 @@ message_to_send["Update-Action"] = "store" message_to_send = gpg.signMessage(message_to_send, forwarder) + # An explicit recipient can also be added. + + if to: + message_to_send["To"] = to + resp = sendMessage(message_to_send, url) print resp