|
16 | 16 | # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, |
17 | 17 | # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
18 | 18 | # |
19 | | -# $Id: roundup-mailgw,v 1.11 2001-11-07 05:32:58 richard Exp $ |
| 19 | +# $Id: roundup-mailgw,v 1.12 2001-11-08 05:16:55 richard Exp $ |
20 | 20 |
|
21 | | -import sys |
| 21 | +import sys, os, re |
22 | 22 | if int(sys.version[0]) < 2: |
23 | 23 | print "Roundup requires Python 2.0 or newer." |
24 | 24 | sys.exit(1) |
25 | 25 |
|
26 | | -# figure the instance home |
27 | | -import os |
28 | | -if len(sys.argv) > 1: |
29 | | - instance_home = sys.argv[1] |
30 | | -else: |
31 | | - instance_home = os.environ.get('ROUNDUP_INSTANCE', '') |
32 | | -if not instance_home: |
33 | | - print 'Usage: %s <instance home> [mail spool file]'%sys.argv[0] |
| 26 | +from mimetools import Message |
| 27 | + |
| 28 | +def do_pipe(handler): |
| 29 | + '''Read a message from standard input and pass it to the mail handler. |
| 30 | + ''' |
| 31 | + handler.main(sys.stdin) |
| 32 | + return 0 |
| 33 | + |
| 34 | +def do_mailbox(handler, filename): |
| 35 | + '''Read a series of messages from the specified unix mailbox file and |
| 36 | + pass each to the mail handler. |
| 37 | + ''' |
| 38 | + # open the spool file and lock it |
| 39 | + import fcntl, FCNTL |
| 40 | + f = open(filename, 'r+') |
| 41 | + fcntl.flock(f.fileno(), FCNTL.LOCK_EX) |
| 42 | + |
| 43 | + # handle and clear the mailbox |
| 44 | + try: |
| 45 | + from mailbox import UnixMailbox |
| 46 | + mailbox = UnixMailbox(f, factory=Message) |
| 47 | + # grab one message |
| 48 | + message = mailbox.next() |
| 49 | + while message: |
| 50 | + # call the instance mail handler |
| 51 | + handler.handle_Message(message) |
| 52 | + message = mailbox.next() |
| 53 | + # nuke the file contents |
| 54 | + os.ftruncate(f.fileno(), 0) |
| 55 | + except: |
| 56 | + import traceback |
| 57 | + traceback.print_exc() |
| 58 | + return 1 |
| 59 | + fcntl.flock(f.fileno(), FCNTL.LOCK_UN) |
| 60 | + return 0 |
| 61 | + |
| 62 | +def do_pop(handler, server, user='', password=''): |
| 63 | + '''Read a series of messages from the specified POP server. |
| 64 | + ''' |
| 65 | + import getpass, poplib |
| 66 | + if not user: |
| 67 | + user = raw_input('User: ') |
| 68 | + if not password: |
| 69 | + password = getpass.getpass() |
| 70 | + |
| 71 | + # open a connection to the server and retrieve all messages |
| 72 | + server = poplib.POP3(server) |
| 73 | + server.user(user) |
| 74 | + server.pass_(password) |
| 75 | + numMessages = len(server.list()[1]) |
| 76 | + for i in range(numMessages): |
| 77 | + for j in server.retr(i+1)[1]: |
| 78 | + s = cStringIO.StringIO('\n'.join(j)) |
| 79 | + s.seek(0) |
| 80 | + handler.handle_Message(Message(s)) |
| 81 | + return 0 |
| 82 | + |
| 83 | +def usage(args, message=None): |
| 84 | + if message is not None: |
| 85 | + print message |
| 86 | + print 'Usage: %s <instance home> [source spec]'%args[0] |
34 | 87 | print ''' |
35 | 88 | The roundup mail gateway may be called in one of two ways: |
36 | | - . with an instance home as the only argument, or |
37 | | - . with both an instance home and a mail spool file. |
| 89 | + . with an instance home as the only argument, |
| 90 | + . with both an instance home and a mail spool file, or |
| 91 | + . with both an instance home and a pop server account. |
38 | 92 |
|
39 | | -In the first case, the mail gateway reads a single message from the |
40 | | -standard input and submits the message to the roundup.mailgw module. |
| 93 | +PIPE: |
| 94 | + In the first case, the mail gateway reads a single message from the |
| 95 | + standard input and submits the message to the roundup.mailgw module. |
41 | 96 |
|
42 | | -In the second case, the gateway reads all messages from the mail spool |
43 | | -file and submits each in turn to the roundup.mailgw module. The file is |
44 | | -emptied once all messages have been successfully handled. |
| 97 | +UNIX mailbox: |
| 98 | + In the second case, the gateway reads all messages from the mail spool |
| 99 | + file and submits each in turn to the roundup.mailgw module. The file is |
| 100 | + emptied once all messages have been successfully handled. The file is |
| 101 | + specified as: |
| 102 | + mailbox /path/to/mailbox |
| 103 | +
|
| 104 | +POP: |
| 105 | + In the third case, the gateway reads all messages from the POP server |
| 106 | + specified and submits each in turn to the roundup.mailgw module. The |
| 107 | + server is specified as: |
| 108 | + pop username:password@server |
| 109 | + The username and password may be omitted: |
| 110 | + pop username@server |
| 111 | + pop server |
| 112 | + are both valid. The username and/or password will be prompted for if |
| 113 | + not supplied on the command-line. |
45 | 114 | ''' |
46 | | - sys.exit(1) |
| 115 | + return 1 |
47 | 116 |
|
48 | | -# get the instance |
49 | | -import roundup.instance |
50 | | -instance = roundup.instance.open(instance_home) |
| 117 | +def main(args): |
| 118 | + '''Handle the arguments to the program and initialise environment. |
| 119 | + ''' |
| 120 | + # figure the instance home |
| 121 | + if len(args) > 1: |
| 122 | + instance_home = args[1] |
| 123 | + else: |
| 124 | + instance_home = os.environ.get('ROUNDUP_INSTANCE', '') |
| 125 | + if not instance_home: |
| 126 | + return usage(args) |
51 | 127 |
|
52 | | -# invoke the mail handler |
53 | | -db = instance.open('admin') |
54 | | -handler = instance.MailGW(db) |
| 128 | + # get the instance |
| 129 | + import roundup.instance |
| 130 | + instance = roundup.instance.open(instance_home) |
55 | 131 |
|
56 | | -# if there's no more arguments, read a single message from stdin |
57 | | -if len(sys.argv) < 2: |
58 | | - handler.main(sys.stdin) |
| 132 | + # get a mail handler |
| 133 | + db = instance.open('admin') |
| 134 | + handler = instance.MailGW(db) |
59 | 135 |
|
60 | | -# otherwise, there's a spool file to read from |
61 | | -import fcntl, FCNTL |
62 | | -spool_file = sys.argv[2] |
63 | | - |
64 | | -# open the spool file and lock it |
65 | | -f = open(spool_file, 'r+') |
66 | | -fcntl.flock(f.fileno(), FCNTL.LOCK_EX) |
67 | | - |
68 | | -# handle and clear the mailbox |
69 | | -try: |
70 | | - from mailbox import UnixMailbox |
71 | | - import mimetools |
72 | | - mailbox = UnixMailbox(f, factory=mimetools.Message) |
73 | | - # grab one message |
74 | | - message = mailbox.next() |
75 | | - while message: |
76 | | - # call the instance mail handler |
77 | | - handler.handle_Message(message) |
78 | | - message = mailbox.next() |
79 | | - # nuke the file contents |
80 | | - os.ftruncate(f.fileno(), 0) |
81 | | -except: |
82 | | - import traceback |
83 | | - traceback.print_exc() |
84 | | -fcntl.flock(f.fileno(), FCNTL.LOCK_UN) |
| 136 | + # if there's no more arguments, read a single message from stdin |
| 137 | + if len(args) == 2: |
| 138 | + return do_pipe(handler) |
| 139 | + |
| 140 | + # otherwise, figure what sort of mail source to handle |
| 141 | + if len(args) < 4: |
| 142 | + return usage(args, 'Error: not enough source specification information') |
| 143 | + source, specification = args[2:] |
| 144 | + if source == 'mailbox': |
| 145 | + return do_mailbox(handler, specification) |
| 146 | + elif source == 'pop': |
| 147 | + m = re.match(r'((?P<user>[^:]+)(:(?P<pass>.+))?@)?(?P<server>.+)', |
| 148 | + specification) |
| 149 | + if m: |
| 150 | + return do_pop(handler, m.group('server'), m.group('user'), |
| 151 | + m.group('pass')) |
| 152 | + return usage(args, 'Error: pop specification not valid') |
| 153 | + |
| 154 | + return usage(args, 'Error: The source must be either "mailbox" or "pop"') |
| 155 | + |
| 156 | +# call main |
| 157 | +if __name__ == '__main__': |
| 158 | + sys.exit(main(sys.argv)) |
85 | 159 |
|
86 | 160 | # |
87 | 161 | # $Log: not supported by cvs2svn $ |
| 162 | +# Revision 1.11 2001/11/07 05:32:58 richard |
| 163 | +# More roundup-mailgw usage help. |
| 164 | +# |
88 | 165 | # Revision 1.10 2001/11/07 05:30:11 richard |
89 | 166 | # Nicer usage message. |
90 | 167 | # |
|
0 commit comments