Home | Trees | Indices | Help |
|
---|
|
1 2 # This is a class which watches a maildir for new messages. It uses the 3 # linux dirwatcher API (if available) to look for new files. The 4 # .messageReceived method is invoked with the filename of the new message, 5 # relative to the top of the maildir (so it will look like "new/blahblah"). 6 7 import os 8 from twisted.python import log 9 from twisted.application import service, internet 10 from twisted.internet import reactor 11 dnotify = None 12 try: 13 import dnotify 14 except: 15 # I'm not actually sure this log message gets recorded 16 log.msg("unable to import dnotify, so Maildir will use polling instead") 17 2022 """I watch a maildir for new messages. I should be placed as the service 23 child of some MultiService instance. When running, I use the linux 24 dirwatcher API (if available) or poll for new files in the 'new' 25 subdirectory of my maildir path. When I discover a new message, I invoke 26 my .messageReceived() method with the short filename of the new message, 27 so the full name of the new file can be obtained with 28 os.path.join(maildir, 'new', filename). messageReceived() should be 29 overridden by a subclass to do something useful. I will not move or 30 delete the file on my own: the subclass's messageReceived() should 31 probably do that. 32 """ 33 pollinterval = 10 # only used if we don't have DNotify 3411636 """Create the Maildir watcher. BASEDIR is the maildir directory (the 37 one which contains new/ and tmp/) 38 """ 39 service.MultiService.__init__(self) 40 self.basedir = basedir 41 self.files = [] 42 self.dnotify = None4345 # some users of MaildirService (scheduler.Try_Jobdir, in particular) 46 # don't know their basedir until setServiceParent, since it is 47 # relative to the buildmaster's basedir. So let them set it late. We 48 # don't actually need it until our own startService. 49 self.basedir = basedir5052 service.MultiService.startService(self) 53 self.newdir = os.path.join(self.basedir, "new") 54 if not os.path.isdir(self.basedir) or not os.path.isdir(self.newdir): 55 raise NoSuchMaildir("invalid maildir '%s'" % self.basedir) 56 try: 57 if dnotify: 58 # we must hold an fd open on the directory, so we can get 59 # notified when it changes. 60 self.dnotify = dnotify.DNotify(self.newdir, 61 self.dnotify_callback, 62 [dnotify.DNotify.DN_CREATE]) 63 except (IOError, OverflowError): 64 # IOError is probably linux<2.4.19, which doesn't support 65 # dnotify. OverflowError will occur on some 64-bit machines 66 # because of a python bug 67 log.msg("DNotify failed, falling back to polling") 68 if not self.dnotify: 69 t = internet.TimerService(self.pollinterval, self.poll) 70 t.setServiceParent(self) 71 self.poll()7274 log.msg("dnotify noticed something, now polling") 75 76 # give it a moment. I found that qmail had problems when the message 77 # was removed from the maildir instantly. It shouldn't, that's what 78 # maildirs are made for. I wasn't able to eyeball any reason for the 79 # problem, and safecat didn't behave the same way, but qmail reports 80 # "Temporary_error_on_maildir_delivery" (qmail-local.c:165, 81 # maildir_child() process exited with rc not in 0,2,3,4). Not sure 82 # why, and I'd have to hack qmail to investigate further, so it's 83 # easier to just wait a second before yanking the message out of new/ 84 85 reactor.callLater(0.1, self.poll)86 8789 if self.dnotify: 90 self.dnotify.remove() 91 self.dnotify = None 92 return service.MultiService.stopService(self)9395 assert self.basedir 96 # see what's new 97 for f in self.files: 98 if not os.path.isfile(os.path.join(self.newdir, f)): 99 self.files.remove(f) 100 newfiles = [] 101 for f in os.listdir(self.newdir): 102 if not f in self.files: 103 newfiles.append(f) 104 self.files.extend(newfiles) 105 # TODO: sort by ctime, then filename, since safecat uses a rather 106 # fine-grained timestamp in the filename 107 for n in newfiles: 108 # TODO: consider catching exceptions in messageReceived 109 self.messageReceived(n)110112 """Called when a new file is noticed. Will call 113 self.parent.messageReceived() with a path relative to maildir/new. 114 Should probably be overridden in subclasses.""" 115 self.parent.messageReceived(filename)
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Thu Jan 21 21:26:32 2010 | http://epydoc.sourceforge.net |