1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import os
23 from twisted.python import log
24 from twisted.application import service, internet
25 from twisted.internet import reactor
26 dnotify = None
27 try:
28 import dnotify
29 except:
30
31 log.msg("unable to import dnotify, so Maildir will use polling instead")
32
35
37 """I watch a maildir for new messages. I should be placed as the service
38 child of some MultiService instance. When running, I use the linux
39 dirwatcher API (if available) or poll for new files in the 'new'
40 subdirectory of my maildir path. When I discover a new message, I invoke
41 my .messageReceived() method with the short filename of the new message,
42 so the full name of the new file can be obtained with
43 os.path.join(maildir, 'new', filename). messageReceived() should be
44 overridden by a subclass to do something useful. I will not move or
45 delete the file on my own: the subclass's messageReceived() should
46 probably do that.
47 """
48 pollinterval = 10
49
51 """Create the Maildir watcher. BASEDIR is the maildir directory (the
52 one which contains new/ and tmp/)
53 """
54 service.MultiService.__init__(self)
55 self.basedir = basedir
56 self.files = []
57 self.dnotify = None
58
65
67 service.MultiService.startService(self)
68 self.newdir = os.path.join(self.basedir, "new")
69 if not os.path.isdir(self.basedir) or not os.path.isdir(self.newdir):
70 raise NoSuchMaildir("invalid maildir '%s'" % self.basedir)
71 try:
72 if dnotify:
73
74
75 self.dnotify = dnotify.DNotify(self.newdir,
76 self.dnotify_callback,
77 [dnotify.DNotify.DN_CREATE])
78 except (IOError, OverflowError):
79
80
81
82 log.msg("DNotify failed, falling back to polling")
83 if not self.dnotify:
84 t = internet.TimerService(self.pollinterval, self.poll)
85 t.setServiceParent(self)
86 self.poll()
87
89 log.msg("dnotify noticed something, now polling")
90
91
92
93
94
95
96
97
98
99
100 reactor.callLater(0.1, self.poll)
101
102
104 if self.dnotify:
105 self.dnotify.remove()
106 self.dnotify = None
107 return service.MultiService.stopService(self)
108
110 assert self.basedir
111
112 for f in self.files:
113 if not os.path.isfile(os.path.join(self.newdir, f)):
114 self.files.remove(f)
115 newfiles = []
116 for f in os.listdir(self.newdir):
117 if not f in self.files:
118 newfiles.append(f)
119 self.files.extend(newfiles)
120
121
122 for n in newfiles:
123
124 self.messageReceived(n)
125
127 """Called when a new file is noticed. Will call
128 self.parent.messageReceived() with a path relative to maildir/new.
129 Should probably be overridden in subclasses."""
130 self.parent.messageReceived(filename)
131