1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/actions/FetchMessages.py Mon Jun 03 23:28:37 2013 +0200
1.3 @@ -0,0 +1,136 @@
1.4 +# -*- coding: iso-8859-1 -*-
1.5 +"""
1.6 + MoinMoin - FetchMessages Action
1.7 +
1.8 + @copyright: 2012, 2013 by Paul Boddie <paul@boddie.org.uk>
1.9 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
1.10 +"""
1.11 +
1.12 +from MoinSupport import getMetadata, writeHeaders
1.13 +from MoinMessage import Message
1.14 +from MoinMessageSupport import MoinMessageAction
1.15 +from email.mime.text import MIMEText
1.16 +from email.parser import Parser
1.17 +from itertools import islice
1.18 +
1.19 +try:
1.20 + from cStringIO import StringIO
1.21 +except ImportError:
1.22 + from StringIO import StringIO
1.23 +
1.24 +Dependencies = ['pages']
1.25 +
1.26 +class FetchMessages(MoinMessageAction):
1.27 +
1.28 + "A handler for requests accessing messages."
1.29 +
1.30 + def handle_message_content(self, content):
1.31 +
1.32 + "Handle the given message 'content'."
1.33 +
1.34 + request = self.request
1.35 +
1.36 + # NOTE: Could employ a more accurate content type.
1.37 +
1.38 + if not content.get_content_type() == "text/plain":
1.39 + writeHeaders(request, "text/plain", getMetadata(self.page), "403 Forbidden")
1.40 + request.write("The content does not appear to be a request for messages.")
1.41 + return
1.42 +
1.43 + # Obtain commands from the payload, returning a collection of messages.
1.44 +
1.45 + commands = content.get_payload()
1.46 +
1.47 + # Build a container for the responses.
1.48 +
1.49 + message = Message()
1.50 +
1.51 + # Process each command, using RFC 1939 (POP3) as inspiration.
1.52 +
1.53 + for command in commands.split("\n"):
1.54 + command = command.strip()
1.55 +
1.56 + # Get the command and arguments.
1.57 +
1.58 + command_parts = command.split(None, 1)
1.59 + cmd = command_parts[0]
1.60 +
1.61 + # A request to count the messages is returned in a part.
1.62 +
1.63 + if cmd == "STAT":
1.64 + result = str(len(self.store))
1.65 + part = MIMEText(result, "plain")
1.66 + part["Request-Type"] = "STAT"
1.67 + part["Request-Status"] = "OK"
1.68 + message.add_update(part)
1.69 +
1.70 + # A request for specific messages returns each message in its own
1.71 + # part.
1.72 +
1.73 + elif cmd in ("RETR", "DELE"):
1.74 +
1.75 + try:
1.76 + # Either select all.
1.77 +
1.78 + if len(command_parts) == 1:
1.79 + count = None
1.80 +
1.81 + # Or select a particular number.
1.82 +
1.83 + else:
1.84 + count = int(parameters[1])
1.85 +
1.86 + except ValueError:
1.87 + part = MIMEText(command, "plain")
1.88 + part["Request-Type"] = cmd
1.89 + part["Request-Status"] = "ERR"
1.90 + message.add_update(part)
1.91 +
1.92 + else:
1.93 + # A request for specific messages returns each message
1.94 + # in its own part within a collection part.
1.95 +
1.96 + if cmd == "RETR":
1.97 + container = Message()
1.98 +
1.99 + for message_text in islice(iter(self.store), count):
1.100 + message_item = Parser().parse(StringIO(message_text))
1.101 + container.add_update(message_item)
1.102 +
1.103 + # Convert the container to a proper multipart section.
1.104 +
1.105 + message.add_update(container.get_payload())
1.106 +
1.107 + # A request to delete messages is performed immediately.
1.108 +
1.109 + elif cmd == "DELE":
1.110 + keys = self.store.keys()[:count]
1.111 + keys.sort()
1.112 +
1.113 + for key in keys:
1.114 + del self.store[key]
1.115 +
1.116 + part = MIMEText(result, "plain")
1.117 + part["Request-Type"] = cmd
1.118 + part["Request-Status"] = "OK"
1.119 + message.add_update(part)
1.120 +
1.121 + # Handle invalid commands.
1.122 +
1.123 + elif cmd:
1.124 + part = MIMEText(result, "plain")
1.125 + part["Request-Type"] = cmd
1.126 + part["Request-Status"] = "ERR"
1.127 + message.add_update(part)
1.128 +
1.129 + # Write the response.
1.130 +
1.131 + request.write(message.get_payload().as_string())
1.132 + return 1, None
1.133 +
1.134 +# Action function.
1.135 +
1.136 +def execute(pagename, request):
1.137 + FetchMessages(pagename, request).do_action() # instead of render
1.138 +
1.139 +# vim: tabstop=4 expandtab shiftwidth=4
2.1 --- a/actions/SendMessage.py Sun Jun 02 16:17:37 2013 +0200
2.2 +++ b/actions/SendMessage.py Mon Jun 03 23:28:37 2013 +0200
2.3 @@ -244,7 +244,7 @@
2.4 outbox = ItemStore(request.page, "outgoing-messages", "outgoing-message-locks")
2.5 outbox.append(message.as_string())
2.6
2.7 - return 1, None
2.8 + return 1, _("Message sent!")
2.9
2.10 def get_homedir(self):
2.11
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/tests/test_fetch.py Mon Jun 03 23:28:37 2013 +0200
3.3 @@ -0,0 +1,36 @@
3.4 +#!/usr/bin/env python
3.5 +
3.6 +from MoinMessage import *
3.7 +from email.mime.text import MIMEText
3.8 +import sys
3.9 +
3.10 +if __name__ == "__main__":
3.11 + try:
3.12 + signer = sys.argv[1]
3.13 + recipient = sys.argv[2]
3.14 + url = sys.argv[3] + "?action=FetchMessages"
3.15 + args = sys.argv[4:]
3.16 + except IndexError:
3.17 + args = None
3.18 +
3.19 + if not args:
3.20 + print >>sys.stderr, "Need a signer, recipient, URL and some commands as arguments to this program."
3.21 + sys.exit(1)
3.22 +
3.23 + message = Message()
3.24 + parts = []
3.25 +
3.26 + part = MIMEText("\n".join(args), "plain", sys.stdin.encoding)
3.27 + message.add_update(part)
3.28 +
3.29 + email_message = message.get_payload()
3.30 + gpg = GPG()
3.31 +
3.32 + try:
3.33 + signed_message = gpg.signMessage(email_message, signer)
3.34 + encrypted_message = gpg.encryptMessage(signed_message, recipient)
3.35 + print sendMessage(encrypted_message, url)
3.36 + except MoinMessageError, exc:
3.37 + print exc
3.38 +
3.39 +# vim: tabstop=4 expandtab shiftwidth=4