Mercurial > p > roundup > code
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 |
