comparison scripts/imapServer.py @ 3203:eddcfee2cc19

reformat
author Alexander Smishlajev <a1s@users.sourceforge.net>
date Fri, 18 Feb 2005 12:31:47 +0000
parents 18ad9d702a5b
children f2fda3e6fc8b
comparison
equal deleted inserted replaced
3200:d2b1a946fdf4 3203:eddcfee2cc19
1 #!/usr/bin/env python2.3 1 #!/usr/bin/env python
2 # arch-tag: f2d1fd6e-df72-4188-a3b4-a9dbbb0807b9
3 # vim: filetype=python ts=4 sw=4 noexpandtab si
4 """\ 2 """\
5 This script is a wrapper around the mailgw.py script that exists in roundup. 3 This script is a wrapper around the mailgw.py script that exists in roundup.
6 It runs as service instead of running as a one-time shot. 4 It runs as service instead of running as a one-time shot.
7 It also connects to a secure IMAP server. The main reasons for this script are: 5 It also connects to a secure IMAP server. The main reasons for this script are:
8 6
9 1) The roundup-mailgw script isn't designed to run as a server. It expects that you 7 1) The roundup-mailgw script isn't designed to run as a server. It
10 either run it by hand, and enter the password each time, or you supply the 8 expects that you either run it by hand, and enter the password each
11 password on the command line. I prefer to run a server that I initialize with 9 time, or you supply the password on the command line. I prefer to
12 the password, and then it just runs. I don't want to have to pass it on the 10 run a server that I initialize with the password, and then it just
13 command line, so running through crontab isn't a possibility. (This wouldn't 11 runs. I don't want to have to pass it on the command line, so
14 be a problem on a local machine running through a mailspool.) 12 running through crontab isn't a possibility. (This wouldn't be a
15 2) mailgw.py somehow screws up SSL support so IMAP4_SSL doesn't work. So hopefully 13 problem on a local machine running through a mailspool.)
16 running that work outside of the mailgw will allow it to work. 14 2) mailgw.py somehow screws up SSL support so IMAP4_SSL doesn't work. So
17 3) I wanted to be able to check multiple projects at the same time. roundup-mailgw is 15 hopefully running that work outside of the mailgw will allow it to work.
18 only for 1 mailbox and 1 project. 16 3) I wanted to be able to check multiple projects at the same time.
17 roundup-mailgw is only for 1 mailbox and 1 project.
19 18
20 19
21 *TODO*: 20 *TODO*:
22 For the first round, the program spawns a new roundup-mailgw for each imap message 21 For the first round, the program spawns a new roundup-mailgw for
23 that it finds and pipes the result in. In the future it might be more practical to 22 each imap message that it finds and pipes the result in. In the
24 actually include the roundup files and run the appropriate commands using python. 23 future it might be more practical to actually include the roundup
24 files and run the appropriate commands using python.
25 25
26 *TODO*: 26 *TODO*:
27 Look into supporting a logfile instead of using 2>/logfile 27 Look into supporting a logfile instead of using 2>/logfile
28 28
29 *TODO*: 29 *TODO*:
30 Add an option for changing the uid/gid of the running process. 30 Add an option for changing the uid/gid of the running process.
31 """ 31 """
32 32
33 import getpass
33 import logging 34 import logging
35 import imaplib
36 import optparse
37 import os
38 import re
39 import time
40
34 logging.basicConfig() 41 logging.basicConfig()
35 log = logging.getLogger('IMAPServer') 42 log = logging.getLogger('IMAPServer')
36 43
37 version = '0.1.2' 44 version = '0.1.2'
38 45
39 class RoundupMailbox: 46 class RoundupMailbox:
40 """This contains all the info about each mailbox. 47 """This contains all the info about each mailbox.
41 Username, Password, server, security, roundup database 48 Username, Password, server, security, roundup database
42 """ 49 """
43 def __init__(self, dbhome='', username=None, password=None, mailbox=None 50 def __init__(self, dbhome='', username=None, password=None, mailbox=None
44 , server=None, protocol='imaps'): 51 , server=None, protocol='imaps'):
45 self.username = username 52 self.username = username
46 self.password = password 53 self.password = password
47 self.mailbox = mailbox 54 self.mailbox = mailbox
48 self.server = server 55 self.server = server
49 self.protocol = protocol 56 self.protocol = protocol
50 self.dbhome = dbhome 57 self.dbhome = dbhome
51 58
52 try: 59 try:
53 if not self.dbhome: 60 if not self.dbhome:
54 import os 61 self.dbhome = raw_input('Tracker home: ')
55 self.dbhome = raw_input('Tracker home: ') 62 if not os.path.exists(self.dbhome):
56 if not os.path.exists(self.dbhome): 63 raise ValueError, 'Invalid home address: ' \
57 raise ValueError, 'Invalid home address directory does not exist. %s' % self.dbhome 64 'directory "%s" does not exist.' % self.dbhome
58 65
59 if not self.server: 66 if not self.server:
60 self.server = raw_input('Server: ') 67 self.server = raw_input('Server: ')
61 if not self.server: 68 if not self.server:
62 raise ValueError, 'No Servername supplied' 69 raise ValueError, 'No Servername supplied'
63 protocol = raw_input('protocol [imaps]? ') 70 protocol = raw_input('protocol [imaps]? ')
64 self.protocol = protocol 71 self.protocol = protocol
65 72
66 if not self.username: 73 if not self.username:
67 self.username = raw_input('Username: ') 74 self.username = raw_input('Username: ')
68 if not self.username: 75 if not self.username:
69 raise ValueError, 'Invalid Username' 76 raise ValueError, 'Invalid Username'
70 77
71 if not self.password: 78 if not self.password:
72 import getpass 79 print 'For server %s, user %s' % (self.server, self.username)
73 print 'For server %s, user %s' % (self.server, self.username) 80 self.password = getpass.getpass()
74 self.password = getpass.getpass() 81 # password can be empty because it could be superceeded
75 # password can be empty because it could be superceeded by a later 82 # by a later entry
76 # entry 83
77 84 #if self.mailbox is None:
78 #if self.mailbox is None: 85 # self.mailbox = raw_input('Mailbox [INBOX]: ')
79 # self.mailbox = raw_input('Mailbox [INBOX]: ') 86 # # We allow an empty mailbox because that will
80 # # We allow an empty mailbox because that will 87 # # select the INBOX, whatever it is called
81 # # select the INBOX, whatever it is called 88
82 89 except (KeyboardInterrupt, EOFError):
83 except (KeyboardInterrupt, EOFError): 90 raise ValueError, 'Canceled by User'
84 raise ValueError, 'Canceled by User' 91
85 92 def __str__(self):
86 def __str__(self): 93 return 'Mailbox{ server:%(server)s, protocol:%(protocol)s, ' \
87 return """Mailbox{ server:%(server)s, protocol:%(protocol)s, username:%(username)s, mailbox:%(mailbox)s, dbhome:%(dbhome)s }""" % self.__dict__ 94 'username:%(username)s, mailbox:%(mailbox)s, ' \
88 95 'dbhome:%(dbhome)s }' % self.__dict__
89 96
90 97
98 # [als] class name is misleading. this is imap client, not imap server
91 class IMAPServer: 99 class IMAPServer:
92 """This class runs as a server process. It is configured with a list of 100
93 mailboxes to connect to, along with the roundup database directories that correspond 101 """IMAP mail gatherer.
94 with each email address. 102
95 It then connects to each mailbox at a specified interval, and if there are new messages 103 This class runs as a server process. It is configured with a list of
96 it reads them, and sends the result to the roundup.mailgw. 104 mailboxes to connect to, along with the roundup database directories
97 105 that correspond with each email address. It then connects to each
98 *TODO*: 106 mailbox at a specified interval, and if there are new messages it
99 Try to be smart about how you access the mailboxes so that you can connect once, and 107 reads them, and sends the result to the roundup.mailgw.
100 access multiple mailboxes and possibly multiple usernames. 108
101 109 *TODO*:
102 *NOTE*: 110 Try to be smart about how you access the mailboxes so that you can
103 This assumes that if you are using the same user on the same server, you are using 111 connect once, and access multiple mailboxes and possibly multiple
104 the same password. (the last one supplied is used.) Empty passwords are ignored. 112 usernames.
105 Only the last protocol supplied is used. 113
106 """ 114 *NOTE*:
107 115 This assumes that if you are using the same user on the same
108 def __init__(self, pidfile=None, delay=5, daemon=False): 116 server, you are using the same password. (the last one supplied is
109 #This is sorted by servername, then username, then mailboxes 117 used.) Empty passwords are ignored. Only the last protocol
110 self.mailboxes = {} 118 supplied is used.
111 self.delay = float(delay) 119 """
112 self.pidfile = pidfile 120
113 self.daemon = daemon 121 def __init__(self, pidfile=None, delay=5, daemon=False):
114 122 #This is sorted by servername, then username, then mailboxes
115 def setDelay(self, delay): 123 self.mailboxes = {}
116 self.delay = delay 124 self.delay = float(delay)
117 125 self.pidfile = pidfile
118 def addMailbox(self, mailbox): 126 self.daemon = daemon
119 """ The linkage is as follows: 127
120 servers -- users - mailbox:dbhome 128 def setDelay(self, delay):
121 So there can be multiple servers, each with multiple users. 129 self.delay = delay
122 Each username can be associated with multiple mailboxes. 130
123 each mailbox is associated with 1 database home 131 def addMailbox(self, mailbox):
124 """ 132 """ The linkage is as follows:
125 log.info('Adding mailbox %s', mailbox) 133 servers -- users - mailbox:dbhome
126 if not self.mailboxes.has_key(mailbox.server): 134 So there can be multiple servers, each with multiple users.
127 self.mailboxes[mailbox.server] = {'protocol':'imaps', 'users':{}} 135 Each username can be associated with multiple mailboxes.
128 server = self.mailboxes[mailbox.server] 136 each mailbox is associated with 1 database home
129 if mailbox.protocol: 137 """
130 server['protocol'] = mailbox.protocol 138 log.info('Adding mailbox %s', mailbox)
131 139 if not self.mailboxes.has_key(mailbox.server):
132 if not server['users'].has_key(mailbox.username): 140 self.mailboxes[mailbox.server] = {'protocol':'imaps', 'users':{}}
133 server['users'][mailbox.username] = {'password':'', 'mailboxes':{}} 141 server = self.mailboxes[mailbox.server]
134 user = server['users'][mailbox.username] 142 if mailbox.protocol:
135 if mailbox.password: 143 server['protocol'] = mailbox.protocol
136 user['password'] = mailbox.password 144
137 145 if not server['users'].has_key(mailbox.username):
138 if user['mailboxes'].has_key(mailbox.mailbox): 146 server['users'][mailbox.username] = {'password':'', 'mailboxes':{}}
139 raise ValueError, 'Mailbox is already defined' 147 user = server['users'][mailbox.username]
140 148 if mailbox.password:
141 user['mailboxes'][mailbox.mailbox] = mailbox.dbhome 149 user['password'] = mailbox.password
142 150
143 def _process(self, message, dbhome): 151 if user['mailboxes'].has_key(mailbox.mailbox):
144 """Actually process one of the email messages""" 152 raise ValueError, 'Mailbox is already defined'
145 import os, sys 153
146 child = os.popen('roundup-mailgw %s' % dbhome, 'wb') 154 user['mailboxes'][mailbox.mailbox] = mailbox.dbhome
147 child.write(message) 155
148 child.close() 156 def _process(self, message, dbhome):
149 #print message 157 """Actually process one of the email messages"""
150 158 child = os.popen('roundup-mailgw %s' % dbhome, 'wb')
151 def _getMessages(self, serv, count, dbhome): 159 child.write(message)
152 """This assumes that you currently have a mailbox open, and want to 160 child.close()
153 process all messages that are inside. 161 #print message
154 """ 162
155 for n in range(1, count+1): 163 def _getMessages(self, serv, count, dbhome):
156 (t, data) = serv.fetch(n, '(RFC822)') 164 """This assumes that you currently have a mailbox open, and want to
157 if t == 'OK': 165 process all messages that are inside.
158 self._process(data[0][1], dbhome) 166 """
159 serv.store(n, '+FLAGS', r'(\Deleted)') 167 for n in range(1, count+1):
160 168 (t, data) = serv.fetch(n, '(RFC822)')
161 def checkBoxes(self): 169 if t == 'OK':
162 """This actually goes out and does all the checking. 170 self._process(data[0][1], dbhome)
163 Returns False if there were any errors, otherwise returns true. 171 serv.store(n, '+FLAGS', r'(\Deleted)')
164 """ 172
165 import imaplib 173 def checkBoxes(self):
166 noErrors = True 174 """This actually goes out and does all the checking.
167 for server in self.mailboxes: 175 Returns False if there were any errors, otherwise returns true.
168 log.info('Connecting to server: %s', server) 176 """
169 s_vals = self.mailboxes[server] 177 noErrors = True
170 178 for server in self.mailboxes:
171 try: 179 log.info('Connecting to server: %s', server)
172 for user in s_vals['users']: 180 s_vals = self.mailboxes[server]
173 u_vals = s_vals['users'][user] 181
174 # TODO: As near as I can tell, you can only 182 try:
175 # login with 1 username for each connection to a server. 183 for user in s_vals['users']:
176 protocol = s_vals['protocol'].lower() 184 u_vals = s_vals['users'][user]
177 if protocol == 'imaps': 185 # TODO: As near as I can tell, you can only
178 serv = imaplib.IMAP4_SSL(server) 186 # login with 1 username for each connection to a server.
179 elif protocol == 'imap': 187 protocol = s_vals['protocol'].lower()
180 serv = imaplib.IMAP4(server) 188 if protocol == 'imaps':
181 else: 189 serv = imaplib.IMAP4_SSL(server)
182 raise ValueError, 'Unknown protocol %s' % protocol 190 elif protocol == 'imap':
183 191 serv = imaplib.IMAP4(server)
184 password = u_vals['password'] 192 else:
185 193 raise ValueError, 'Unknown protocol %s' % protocol
186 try: 194
187 log.info('Connecting as user: %s', user) 195 password = u_vals['password']
188 serv.login(user, password) 196
189 197 try:
190 for mbox in u_vals['mailboxes']: 198 log.info('Connecting as user: %s', user)
191 dbhome = u_vals['mailboxes'][mbox] 199 serv.login(user, password)
192 log.info('Using mailbox: %s, home: %s', mbox, dbhome) 200
193 #access a specific mailbox 201 for mbox in u_vals['mailboxes']:
194 if mbox: 202 dbhome = u_vals['mailboxes'][mbox]
195 (t, data) = serv.select(mbox) 203 log.info('Using mailbox: %s, home: %s',
196 else: 204 mbox, dbhome)
197 # Select the default mailbox (INBOX) 205 #access a specific mailbox
198 (t, data) = serv.select() 206 if mbox:
199 try: 207 (t, data) = serv.select(mbox)
200 nMessages = int(data[0]) 208 else:
201 except ValueError: 209 # Select the default mailbox (INBOX)
202 nMessages = 0 210 (t, data) = serv.select()
203 211 try:
204 log.info('Found %s messages', nMessages) 212 nMessages = int(data[0])
205 213 except ValueError:
206 if nMessages: 214 nMessages = 0
207 self._getMessages(serv, nMessages, dbhome) 215
208 serv.expunge() 216 log.info('Found %s messages', nMessages)
209 217
210 # We are done with this mailbox 218 if nMessages:
211 serv.close() 219 self._getMessages(serv, nMessages, dbhome)
212 except: 220 serv.expunge()
213 log.exception('Exception with server %s user %s', server, user) 221
214 noErrors = False 222 # We are done with this mailbox
215 223 serv.close()
216 serv.logout() 224 except:
217 serv.shutdown() 225 log.exception('Exception with server %s user %s',
218 del serv 226 server, user)
219 except: 227 noErrors = False
220 log.exception('Exception while connecting to %s', server) 228
221 noErrors = False 229 serv.logout()
222 return noErrors 230 serv.shutdown()
223 231 del serv
224 232 except:
225 def makeDaemon(self): 233 log.exception('Exception while connecting to %s', server)
226 """This forks a couple of times, and otherwise makes this run as a daemon.""" 234 noErrors = False
227 ''' Turn this process into a daemon. 235 return noErrors
228 - make our parent PID 1 236
229 237
230 Write our new PID to the pidfile. 238 def makeDaemon(self):
231 239 """Turn this process into a daemon.
232 From A.M. Kuuchling (possibly originally Greg Ward) with 240
233 modification from Oren Tirosh, and finally a small mod from me. 241 - make our parent PID 1
234 Originally taken from roundup.scripts.roundup_server.py 242
235 ''' 243 Write our new PID to the pidfile.
236 log.info('Running as Daemon') 244
237 import os 245 From A.M. Kuuchling (possibly originally Greg Ward) with
238 # Fork once 246 modification from Oren Tirosh, and finally a small mod from me.
239 if os.fork() != 0: 247 Originally taken from roundup.scripts.roundup_server.py
240 os._exit(0) 248 """
241 249 log.info('Running as Daemon')
242 # Create new session 250 # Fork once
243 os.setsid() 251 if os.fork() != 0:
244 252 os._exit(0)
245 # Second fork to force PPID=1 253
246 pid = os.fork() 254 # Create new session
247 if pid: 255 os.setsid()
248 if self.pidfile: 256
249 pidfile = open(self.pidfile, 'w') 257 # Second fork to force PPID=1
250 pidfile.write(str(pid)) 258 pid = os.fork()
251 pidfile.close() 259 if pid:
252 os._exit(0) 260 if self.pidfile:
253 261 pidfile = open(self.pidfile, 'w')
254 #os.chdir("/") 262 pidfile.write(str(pid))
255 #os.umask(0) 263 pidfile.close()
256 264 os._exit(0)
257 def run(self): 265
258 """This spawns itself as a daemon, and then runs continually, just sleeping inbetween checks. 266 #os.chdir("/")
259 It is recommended that you run checkBoxes once first before you select run. That way you can 267 #os.umask(0)
260 know if there were any failures. 268
261 """ 269 def run(self):
262 import time 270 """Run email gathering daemon.
263 if self.daemon: 271
264 self.makeDaemon() 272 This spawns itself as a daemon, and then runs continually, just
265 while True: 273 sleeping inbetween checks. It is recommended that you run
266 274 checkBoxes once first before you select run. That way you can
267 time.sleep(self.delay * 60.0) 275 know if there were any failures.
268 log.info('Time: %s', time.strftime('%Y-%m-%d %H:%M:%S')) 276 """
269 self.checkBoxes() 277 if self.daemon:
278 self.makeDaemon()
279 while True:
280
281 time.sleep(self.delay * 60.0)
282 log.info('Time: %s', time.strftime('%Y-%m-%d %H:%M:%S'))
283 self.checkBoxes()
270 284
271 def getItems(s): 285 def getItems(s):
272 """Parse a string looking for userame@server""" 286 """Parse a string looking for userame@server"""
273 import re 287 myRE = re.compile(
274 myRE = re.compile( 288 r'((?P<protocol>[^:]+)://)?'#You can supply a protocol if you like
275 r'((?P<proto>[^:]+)://)?'#You can supply a protocol if you like 289 r'(' #The username part is optional
276 r'(' #The username part is optional 290 r'(?P<username>[^:]+)' #You can supply the password as
277 r'(?P<user>[^:]+)' #You can supply the password as 291 r'(:(?P<password>.+))?' #username:password@server
278 r'(:(?P<pass>.+))?' #username:password@server 292 r'@)?'
279 r'@)?' 293 r'(?P<server>[^/]+)'
280 r'(?P<server>[^/]+)' 294 r'(/(?P<mailbox>.+))?$'
281 r'(/(?P<mailbox>.+))?$' 295 )
282 ) 296 m = myRE.match(s)
283 m = myRE.match(s) 297 if m:
284 if m: 298 return m.groupdict()
285 return {'username':m.group('user'), 'password':m.group('pass') 299 else:
286 , 'server':m.group('server'), 'protocol':m.group('proto') 300 return None
287 , 'mailbox':m.group('mailbox')
288 }
289 301
290 def main(): 302 def main():
291 """This is what is called if run at the prompt""" 303 """This is what is called if run at the prompt"""
292 import optparse, os 304 parser = optparse.OptionParser(
293 parser = optparse.OptionParser( 305 version=('%prog ' + version),
294 version=('%prog ' + version) 306 usage="""usage: %prog [options] (home server)...
295 , usage="""usage: %prog [options] (home server)... 307
296 So each entry has a home, and then the server configuration. home is just a path to the 308 So each entry has a home, and then the server configuration. Home is just
297 roundup issue tracker. The server is something of the form: 309 a path to the roundup issue tracker. The server is something of the form:
298 imaps://user:password@server/mailbox 310
299 If you don't supply the protocol, imaps is assumed. Without user or password, you will be 311 imaps://user:password@server/mailbox
300 prompted for them. The server must be supplied. Without mailbox the INBOX is used. 312
313 If you don't supply the protocol, imaps is assumed. Without user or
314 password, you will be prompted for them. The server must be supplied.
315 Without mailbox the INBOX is used.
301 316
302 Examples: 317 Examples:
303 %prog /home/roundup/trackers/test imaps://test@imap.example.com/test 318 %prog /home/roundup/trackers/test imaps://test@imap.example.com/test
304 %prog /home/roundup/trackers/test imap.example.com /home/roundup/trackers/test2 imap.example.com/test2 319 %prog /home/roundup/trackers/test imap.example.com \
320 /home/roundup/trackers/test2 imap.example.com/test2
305 """ 321 """
306 ) 322 )
307 parser.add_option('-d', '--delay', dest='delay', type='float', metavar='<sec>' 323 parser.add_option('-d', '--delay', dest='delay', type='float',
308 , default=5 324 metavar='<sec>', default=5,
309 , help="Set the delay between checks in minutes. (default 5)" 325 help="Set the delay between checks in minutes. (default 5)"
310 ) 326 )
311 parser.add_option('-p', '--pid-file', dest='pidfile', metavar='<file>' 327 parser.add_option('-p', '--pid-file', dest='pidfile',
312 , default=None 328 metavar='<file>', default=None,
313 , help="The pid of the server process will be written to <file>" 329 help="The pid of the server process will be written to <file>"
314 ) 330 )
315 parser.add_option('-n', '--no-daemon', dest='daemon', action='store_false' 331 parser.add_option('-n', '--no-daemon', dest='daemon',
316 , default=True 332 action='store_false', default=True,
317 , help="Do not fork into the background after running the first check." 333 help="Do not fork into the background after running the first check."
318 ) 334 )
319 parser.add_option('-v', '--verbose', dest='verbose', action='store_const' 335 parser.add_option('-v', '--verbose', dest='verbose',
320 , const=logging.INFO 336 action='store_const', const=logging.INFO,
321 , help="Be more verbose in letting you know what is going on." 337 help="Be more verbose in letting you know what is going on."
322 " Enables informational messages." 338 " Enables informational messages."
323 ) 339 )
324 parser.add_option('-V', '--very-verbose', dest='verbose', action='store_const' 340 parser.add_option('-V', '--very-verbose', dest='verbose',
325 , const=logging.DEBUG 341 action='store_const', const=logging.DEBUG,
326 , help="Be very verbose in letting you know what is going on." 342 help="Be very verbose in letting you know what is going on."
327 " Enables debugging messages." 343 " Enables debugging messages."
328 ) 344 )
329 parser.add_option('-q', '--quiet', dest='verbose', action='store_const' 345 parser.add_option('-q', '--quiet', dest='verbose',
330 , const=logging.ERROR 346 action='store_const', const=logging.ERROR,
331 , help="Be less verbose. Ignores warnings, only prints errors." 347 help="Be less verbose. Ignores warnings, only prints errors."
332 ) 348 )
333 parser.add_option('-Q', '--very-quiet', dest='verbose', action='store_const' 349 parser.add_option('-Q', '--very-quiet', dest='verbose',
334 , const=logging.CRITICAL 350 action='store_const', const=logging.CRITICAL,
335 , help="Be much less verbose. Ignores warnings and errors." 351 help="Be much less verbose. Ignores warnings and errors."
336 " Only print CRITICAL messages." 352 " Only print CRITICAL messages."
337 ) 353 )
338 354
339 (opts, args) = parser.parse_args() 355 (opts, args) = parser.parse_args()
340 if (len(args) == 0) or (len(args) % 2 == 1): 356 if (len(args) == 0) or (len(args) % 2 == 1):
341 parser.error('Invalid number of arguments. Each site needs a home and a server.') 357 parser.error('Invalid number of arguments. '
342 358 'Each site needs a home and a server.')
343 log.setLevel(opts.verbose) 359
344 myServer = IMAPServer(delay=opts.delay, pidfile=opts.pidfile, daemon=opts.daemon) 360 log.setLevel(opts.verbose)
345 for i in range(0,len(args),2): 361 myServer = IMAPServer(delay=opts.delay, pidfile=opts.pidfile,
346 home = args[i] 362 daemon=opts.daemon)
347 server = args[i+1] 363 for i in range(0,len(args),2):
348 if not os.path.exists(home): 364 home = args[i]
349 parser.error('Home: "%s" does not exist' % home) 365 server = args[i+1]
350 366 if not os.path.exists(home):
351 info = getItems(server) 367 parser.error('Home: "%s" does not exist' % home)
352 if not info: 368
353 parser.error('Invalid server string: "%s"' % server) 369 info = getItems(server)
354 370 if not info:
355 myServer.addMailbox( 371 parser.error('Invalid server string: "%s"' % server)
356 RoundupMailbox(dbhome=home, mailbox=info['mailbox'] 372
357 , username=info['username'], password=info['password'] 373 myServer.addMailbox(
358 , server=info['server'], protocol=info['protocol'] 374 RoundupMailbox(dbhome=home, mailbox=info['mailbox']
359 ) 375 , username=info['username'], password=info['password']
360 ) 376 , server=info['server'], protocol=info['protocol']
361 377 )
362 if myServer.checkBoxes(): 378 )
363 myServer.run() 379
380 if myServer.checkBoxes():
381 myServer.run()
364 382
365 if __name__ == '__main__': 383 if __name__ == '__main__':
366 main() 384 main()
367 385
386 # vim: et ft=python si sts=4 sw=4

Roundup Issue Tracker: http://roundup-tracker.org/