"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "spambayes-1.0.4/windows/autoconfigure.py" of archive spambayes-1.0.4.zip:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 #!/usr/bin/env python
2
3 """Automatically set up the user's mail client and SpamBayes.
4
5 Example usage:
6 >>> configure("mailer name")
7 Where "mailer name" is any of the names below.
8
9 Currently works with:
10 o Eudora (POP3/SMTP only)
11 o Mozilla Mail (POP3/SMTP only)
12 o M2 (Opera Mail) (POP3/SMTP only)
13 o Outlook Express (POP3/SMTP only)
14 o PocoMail (POP3/SMTP only)
15
16 To do:
17 o Establish which mail client(s) are installed in a more clever way.
18 o This will create some unnecessary proxies in some cases. For example,
19 if I have my client set up to get mail from pop.example.com for the
20 user 'tmeyer' and the user 'tonym', two proxies will be created, but
21 only one is necessary. We should check the existing proxies before
22 adding a new one.
23 o Other mail clients? Other platforms?
24 o This won't work all that well if multiple mail clients are used (they
25 will end up trying to use the same ports). In such a case, we really
26 need to keep track of if the server is being proxied already, and
27 reuse ports, but this is complicated.
28 o We currently don't make any moves to protect the original file, so if
29 something does wrong, it's corrupted. We also write into the file,
30 rather than a temporary one and then copy across. This should all be
31 fixed. Richie's suggestion is for the script to create a clone of an
32 existing account with the new settings. Then people could test the
33 cloned account, and if they're happy with it they can either delete
34 their old account or delete the new one and run the script again in
35 "modify" rather than "clone" mode. This sounds like a good idea,
36 although a lot of work...
37 o Suggestions?
38 """
39
40 # This module is part of the spambayes project, which is Copyright 2002-3
41 # The Python Software Foundation and is covered by the Python Software
42 # Foundation license.
43
44 __author__ = "Tony Meyer <ta-meyer@ihug.co.nz>"
45 __credits__ = "All the Spambayes folk."
46
47 try:
48 True, False
49 except NameError:
50 # Maintain compatibility with Python 2.2
51 True, False = 1, 0
52
53 ## Tested with:
54 ## o Eudora 5.2 on Windows XP
55 ## o Mozilla 1.3 on Windows XP
56 ## o Opera 7.11 on Windows XP
57 ## o Outlook Express 6 on Windows XP
58
59 import re
60 import os
61 import sys
62 import types
63 import socket
64 import shutil
65 import StringIO
66 import ConfigParser
67
68 try:
69 import win32gui
70 import win32api
71 import win32con
72 import pywintypes
73 from win32com.shell import shell, shellcon
74 except ImportError:
75 # The ImportError is delayed until these are needed - if we
76 # did it here, the functions that don't need these would still
77 # fail. (And having "import win32api" in lots of functions
78 # didn't seem to make much sense).
79 win32api = win32con = shell = shellcon = win32gui = pywintypes = None
80
81 from spambayes import oe_mailbox
82 from spambayes import OptionsClass
83 from spambayes.Options import options, optionsPathname
84
85 def move_to_next_free_port(port):
86 # Increment port until we get to one that isn't taken.
87 # I doubt this will work if there is a firewall that prevents
88 # localhost connecting to particular ports, but I'm not sure
89 # how else we can do this - Richie says that bind() doesn't
90 # necessarily fail if the port is already bound.
91 while True:
92 try:
93 port += 1
94 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
95 s.connect(("127.0.0.1", port))
96 s.close()
97 except socket.error:
98 portStr = str(port)
99 if portStr in options["pop3proxy", "listen_ports"] or \
100 portStr in options["smtpproxy", "listen_ports"]:
101 continue
102 else:
103 return port
104
105 # Let's be safe and use high ports, starting at 1110 and 1025, and going up
106 # as required.
107 pop_proxy_port = move_to_next_free_port(1109)
108 smtp_proxy_port = move_to_next_free_port(1024)
109
110 def configure_eudora(config_location):
111 """Configure Eudora to use the SpamBayes POP3 and SMTP proxies, and
112 configure SpamBayes to proxy the servers that Eudora was connecting to.
113 """
114 ini_filename = "%s%seudora.ini" % (config_location, os.sep)
115 c = ConfigParser.ConfigParser()
116 c.read(ini_filename)
117
118 translate = {("PopServer", "POPPort") : "pop3proxy",
119 ("SMTPServer", "SMTPPort") : "smtpproxy",
120 }
121
122 pop_proxy = pop_proxy_port
123 smtp_proxy = smtp_proxy_port
124
125 results = []
126 for sect in c.sections():
127 if sect.startswith("Persona-") or sect == "Settings":
128 if c.get(sect, "UsesIMAP") == "0":
129 # Eudora stores the POP3 server name in two places.
130 # Why? Who cares. We do the popaccount one
131 # separately, because it also has the username.
132 p = c.get(sect, "popaccount")
133 c.set(sect, "popaccount", "%s@localhost" % \
134 (p[:p.index('@')],))
135 for (eud_name, eud_port), us_name in translate.items():
136 try:
137 port = c.get(sect, eud_port)
138 except ConfigParser.NoOptionError:
139 port = None
140
141 if us_name.lower()[:4] == "pop3":
142 if port is None:
143 port = 110
144 pop_proxy = move_to_next_free_port(pop_proxy)
145 proxy_port = pop_proxy
146 else:
147 if port is None:
148 port = 25
149 smtp_proxy = move_to_next_free_port(smtp_proxy)
150 proxy_port = smtp_proxy
151 server = "%s:%s" % (c.get(sect, eud_name), port)
152 options[us_name, "remote_servers"] += (server,)
153 options[us_name, "listen_ports"] += (proxy_port,)
154 results.append("[%s] Proxy %s on localhost:%s" % \
155 (sect, server, proxy_port))
156 c.set(sect, eud_name, "localhost")
157 c.set(sect, eud_port, proxy_port)
158 else:
159 # Setup imapfilter instead
160 pass
161
162 out = file(ini_filename, "w")
163 c.write(out)
164 out.close()
165 options.update_file(optionsPathname)
166
167 # Setup filtering rule
168 # This assumes that the spam and unsure folders already exist!
169 # (Creating them shouldn't be that difficult - it's just a mbox file,
170 # and I think the .toc file is automatically created). Left for
171 # another day, however.
172 filter_filename = "%s%sFilters.pce" % (config_location, os.sep)
173 spam_folder_name = "Junk"
174 unsure_folder_name = "Possible Junk"
175 header_name = options["Headers", "classification_header_name"]
176 spam_tag = options["Headers", "header_spam_string"]
177 unsure_tag = options["Headers", "header_unsure_string"]
178 # We are assuming that a rules file already exists, otherwise there
179 # is a bit more to go at the top.
180 filter_rules = "rule SpamBayes-Spam\n" \
181 "transfer %s.mbx\n" \
182 "incoming\n" \
183 "header %s\n" \
184 "verb contains\n" \
185 "value %s\n" \
186 "conjunction ignore\n" \
187 "header \n" \
188 "verb contains\n" \
189 "value \n" \
190 "rule SpamBayes-Unsure\n" \
191 "transfer %s.mbx\n" \
192 "incoming\n" \
193 "header %s\n" \
194 "verb contains\n" \
195 "value %s\n" \
196 "conjunction ignore\n" \
197 "header \n" \
198 "verb contains\n" \
199 "value \n" % (spam_folder_name, header_name, spam_tag,
200 unsure_folder_name, header_name, unsure_tag)
201 filter_file = file(filter_filename, "a")
202 filter_file.write(filter_rules)
203 filter_file.close()
204 return results
205
206 def configure_mozilla(config_location):
207 """Configure Mozilla to use the SpamBayes POP3 and SMTP proxies, and
208 configure SpamBayes to proxy the servers that Mozilla was connecting
209 to."""
210 prefs_file = file("%s%sprefs.js" % (config_location, os.sep), "r")
211 prefs = prefs_file.read()
212 prefs_file.close()
213 save_prefs = prefs
214 pop_accounts = {}
215 smtp_accounts = {}
216
217 r = re.compile(r"user_pref\(\"mail.server.server(\d+).(real)?hostname\", \"([^\"]*)\"\);")
218 current_pos = 0
219 results = []
220 while True:
221 m = r.search(prefs[current_pos:])
222 if not m:
223 break
224 server_num = m.group(1)
225 real = m.group(2) or ''
226 server = m.group(3)
227 current_pos += m.end()
228 old_pref = 'user_pref("mail.server.server%s.%shostname", "%s");' % \
229 (server_num, real, server)
230
231 # Find the port, if there is one
232 port_string = 'user_pref("mail.server.server%s.port", ' % \
233 (server_num,)
234 port_loc = prefs.find(port_string)
235 if port_loc == -1:
236 port = "110"
237 old_port = None
238 else:
239 loc_plus_len = port_loc + len(port_string)
240 end_of_number = loc_plus_len + prefs[loc_plus_len:].index(')')
241 port = prefs[loc_plus_len : end_of_number]
242 old_port = "%s%s);" % (port_string, port)
243
244 # Find the type of connection
245 type_string = 'user_pref("mail.server.server%s.type", "' % \
246 (server_num,)
247 type_loc = prefs.find(type_string)
248 if type_loc == -1:
249 # no type, so ignore this one
250 continue
251 type_loc += len(type_string)
252 account_type = prefs[type_loc : \
253 type_loc + prefs[type_loc:].index('"')]
254
255 if account_type == "pop3":
256 new_pref = 'user_pref("mail.server.server%s.%shostname", ' \
257 '"127.0.0.1");' % (server_num, real)
258 if not pop_accounts.has_key(server_num) or real:
259 pop_accounts[server_num] = (new_pref, old_pref,
260 old_port, server, port)
261 elif account_type == "imap":
262 # Setup imapfilter instead
263 pass
264
265 proxy_port = pop_proxy_port
266 for num, (pref, old_pref, old_port, server, port) in pop_accounts.items():
267 server = "%s:%s" % (server, port)
268 proxy_port = move_to_next_free_port(proxy_port)
269 port_pref = 'user_pref("mail.server.server%s.port", %s);' % \
270 (num, proxy_port)
271 options["pop3proxy", "remote_servers"] += (server,)
272 options["pop3proxy", "listen_ports"] += (proxy_port,)
273 if old_port is None:
274 pref = "%s\n%s" % (pref, port_pref)
275 else:
276 save_prefs = save_prefs.replace(old_port, port_pref)
277 save_prefs = save_prefs.replace(old_pref, pref)
278 results.append("[%s] Proxy %s on localhost:%s" % \
279 (num, server, proxy_port))
280
281 # Do the SMTP server.
282 # Mozilla recommends that only advanced users setup more than one,
283 # so we'll just set that one up. Advanced users can setup SpamBayes
284 # themselves <wink>.
285 prefs = save_prefs
286 r = re.compile(r"user_pref\(\"mail.smtpserver.smtp(\d+).hostname\", \"([^\"]*)\"\);")
287 current_pos = 0
288 while True:
289 m = r.search(prefs[current_pos:])
290 if not m:
291 break
292 current_pos = m.end()
293 server_num = m.group(1)
294 server = m.group(2)
295 old_pref = 'user_pref("mail.smtpserver.smtp%s.hostname", ' \
296 '"%s");' % (server_num, server)
297 new_pref = 'user_pref("mail.smtpserver.smtp%s.hostname", ' \
298 '"127.0.0.1");' % (server_num,)
299
300 # Find the port
301 port_string = 'user_pref("mail.smtpserver.smtp1.port", '
302 port_loc = prefs.find(port_string)
303 if port_loc == -1:
304 port = "25"
305 old_port = None
306 else:
307 loc_plus_len = port_loc + len(port_string)
308 end_of_number = loc_plus_len + prefs[loc_plus_len:].index(')')
309 port = prefs[loc_plus_len : end_of_number]
310 old_port = 'user_pref("mail.smtpserver.smtp%s.port", %s);' % \
311 (server_num, port)
312 smtp_accounts[server_num] = (new_pref, old_pref, old_port,
313 server, port)
314
315 proxy_port = smtp_proxy_port
316 for num, (pref, old_pref, old_port, server, port) in smtp_accounts.items():
317 server = "%s:%s" % (server, port)
318 proxy_port = move_to_next_free_port(proxy_port)
319 port_pref = 'user_pref("mail.smtpserver.smtp%s.port", %s);' % \
320 (num, proxy_port)
321 options["smtpproxy", "remote_servers"] += (server,)
322 options["smtpproxy", "listen_ports"] += (proxy_port,)
323 if old_port is None:
324 pref = "%s\n%s" % (pref, port_pref)
325 else:
326 save_prefs = save_prefs.replace(old_port, port_pref)
327 save_prefs = save_prefs.replace(old_pref, pref)
328 results.append("[%s] Proxy %s on localhost:%s" % \
329 (num, server, proxy_port))
330
331 prefs_file = file("%s%sprefs.js" % (config_location, os.sep), "w")
332 prefs_file.write(save_prefs)
333 prefs_file.close()
334 options.update_file(optionsPathname)
335
336 # Setup filtering rules.
337 # Assumes that the folders already exist! I don't know how difficult
338 # it would be to create new Mozilla mail folders.
339 filter_filename = "%s%smsgFilterRules.dat" % (config_location, os.sep)
340 store_name = "" # how do we get this?
341 spam_folder_url = "mailbox:////%s//Junk%20Mail" % (store_name,)
342 unsure_folder_url = "mailbox:////%s//Possible%20Junk" % (store_name,)
343 header_name = options["Headers", "classification_header_name"]
344 spam_tag = options["Headers", "header_spam_string"]
345 unsure_tag = options["Headers", "header_unsure_string"]
346 rule = 'name="SpamBayes-Spam"\n' \
347 'enabled="yes"\n' \
348 'type="1"\n' \
349 'action="Move to folder"\n' \
350 'actionValue="%s"\n' \
351 'condition="OR (\"%s\",contains,%s)"\n' \
352 'name="SpamBayes-Unsure"\n' \
353 'enabled="yes"\n' \
354 'type="1"\n' \
355 'action="Move to folder"\n' \
356 'actionValue="%s"\n' \
357 'condition="OR (\"%s\",contains,%s)"\n' % \
358 (spam_folder_url, header_name, spam_tag,
359 unsure_folder_url, header_name, unsure_tag)
360 # This should now be written to the file, but I'm not sure how we
361 # determine which subdirectory it goes into - does it have to go
362 # into them all?
363 # We are assuming that a rules file already exists, otherwise there
364 # is a bit more to go at the top.
365 return results
366
367 def configure_m2(config_location):
368 """Configure M2 (Opera's mailer) to use the SpamBayes POP3 and SMTP
369 proxies, and configure SpamBayes to proxy the servers that M2 was
370 connecting to."""
371 ini_filename = os.path.join(config_location, "Mail", "accounts.ini")
372 ini_file = file(ini_filename, "r")
373 faked_up = StringIO.StringIO()
374 faked_up.write(";") # Missing at the start
375 faked_up.write(ini_file.read())
376 faked_up.seek(0)
377 ini_file.close()
378 c = ConfigParser.ConfigParser()
379 c.readfp(faked_up)
380
381 translate = {("Incoming Servername", "Incoming Port") : "pop3proxy",
382 ("Outgoing Servername", "Outgoing Port") : "smtpproxy",
383 }
384
385 pop_proxy = pop_proxy_port
386 smtp_proxy = smtp_proxy_port
387
388 results = []
389 for sect in c.sections():
390 if sect.startswith("Account") and sect != "Accounts":
391 if c.get(sect, "Incoming Protocol") == "POP":
392 for (m2_name, m2_port), us_name in translate.items():
393 try:
394 port = c.get(sect, m2_port)
395 except ConfigParser.NoOptionError:
396 port = None
397
398 if us_name.lower()[:4] == "pop3":
399 if port is None:
400 port = 110
401 pop_proxy = move_to_next_free_port(pop_proxy)
402 proxy_port = pop_proxy
403 else:
404 if port is None:
405 port = 25
406 smtp_proxy = move_to_next_free_port(smtp_proxy)
407 proxy_port = smtp_proxy
408 server = "%s:%s" % (c.get(sect, m2_name), port)
409 options[us_name, "remote_servers"] += (server,)
410 options[us_name, "listen_ports"] += (proxy_port,)
411 results.append("[%s] Proxy %s on localhost:%s" % \
412 (sect, server, proxy_port))
413 c.set(sect, m2_name, "localhost")
414 c.set(sect, m2_port, proxy_port)
415 elif c.get(sect, "Incoming Protocol") == "IMAP":
416 # Setup imapfilter instead
417 pass
418
419 out = file(ini_filename, "w")
420 c.write(out)
421 out.close()
422 options.update_file(optionsPathname)
423
424 # Setting up a filter in M2 is very simple, but I'm not sure what the
425 # right rule is - M2 doesn't move mail, it just displays a subset.
426 # If someone can describe the best all-purpose rule, I'll pop it in
427 # here.
428 return results
429
430 def configure_outlook_express(unused):
431 """Configure OE to use the SpamBayes POP3 and SMTP proxies, and
432 configure SpamBayes to proxy the servers that OE was connecting to."""
433 # Requires win32all to be available (or for someone to write a
434 # Mac version <wink>)
435 if win32api is None:
436 raise ImportError("win32 extensions required")
437
438 accounts = oe_mailbox.OEAccountKeys()
439
440 translate = {("POP3 Server", "POP3 Port") : "pop3proxy",
441 ("SMTP Server", "SMTP Port") : "smtpproxy",
442 }
443
444 pop_proxy = pop_proxy_port
445 smtp_proxy = smtp_proxy_port
446
447 results = []
448 for proto, subkey, account in accounts:
449 if proto == "POP3":
450 for (server_key, port_key), sect in translate.items():
451 server = "%s:%s" % (account[server_key][0],
452 account[port_key][0])
453 if sect[:4] == "pop3":
454 pop_proxy = move_to_next_free_port(pop_proxy)
455 proxy = pop_proxy
456 else:
457 smtp_proxy = move_to_next_free_port(smtp_proxy)
458 proxy = smtp_proxy
459 options[sect, "remote_servers"] += (server,)
460 options[sect, "listen_ports"] += (proxy,)
461 win32api.RegSetValueEx(subkey, server_key, 0,
462 win32con.REG_SZ, "127.0.0.1")
463 win32api.RegSetValueEx(subkey, port_key, 0,
464 win32con.REG_SZ, str(proxy))
465 results.append("[%s] Proxy %s on localhost:%s" % \
466 (account["Account Name"][0], server, proxy))
467 elif proto == "IMAP4":
468 # Setup imapfilter instead.
469 pass
470
471 options.update_file(optionsPathname)
472
473 # Outlook Express rules are done in much the same way. Should one
474 # be set up to work with notate_to or notate_subject? (and set that
475 # option, obviously)
476 return results
477
478 def configure_pegasus_mail(config_location):
479 """Configure Pegasus Mail to use the SpamBayes POP3 and SMTP proxies,
480 and configure SpamBayes to proxy the servers that Pegasus Mail was
481 connecting to."""
482
483 # We can't use ConfigParser here, as we want 'surgical' editing,
484 # so we want to use out OptionsClass. There is the additional trouble
485 # that the Pegasus Mail config file doesn't have a section header.
486
487 pop_proxy = pop_proxy_port
488 smtp_proxy = smtp_proxy_port
489
490 results = []
491 for filename in os.listdir(config_location):
492 if filename.lower().startswith("pop") or filename.lower().startswith("smt"):
493 full_filename = os.path.join(config_location, filename)
494 working_filename = "%s.tmp" % (filename, )
495 shutil.copyfile(filename, working_filename)
496 c = OptionsClass.OptionsClass()
497 c.merge_file(working_filename)
498 server = "%s:%s" % (c.get("all", "host"), c.get("all", "port"))
499 if filename[:3] == "pop":
500 pop_proxy = move_to_next_free_port(pop_proxy)
501 proxy = pop_proxy
502 sect = "pop3proxy"
503 else:
504 smtp_proxy = move_to_next_free_port(smtp_proxy)
505 proxy = smtp_proxy
506 sect = "smtpproxy"
507 options[sect, "remote_servers"] += (server,)
508 options[sect, "listen_ports"] += (proxy,)
509 # Write in the new options!!
510 c.set("all", "host", "127.0.0.1")
511 c.set("all", "port", proxy)
512 c.update_file(working_filename)
513 results.append("[%s] Proxy %s on localhost:%s" % \
514 (c.get("all", "title"), server, proxy))
515 elif filename.lower() == "IMAP.PM":
516 # Setup imapfilter instead.
517 pass
518
519 # Pegasus Mail has a 'weight' system for determining junk mail.
520 # The best plan would probably be to just add to this. Something like:
521 rules_filename = os.path.join(config_location, "spambust.dat")
522 header_name = options["Headers", "classification_header_name"]
523 spam_tag = options["Headers", "header_spam_string"]
524 unsure_tag = options["Headers", "header_unsure_string"]
525 ham_tag = options["Headers", "header_ham_string"]
526 spam_weight = 500
527 ham_weight = -500
528 unsure_weight = -50 # leave judgement up to the rest of the rules
529 rule = '# SpamBayes adjustments\n' \
530 'if header "%s" contains "%s" weight %s\n' \
531 'if header "%s" contains "%s" weight %s\n' \
532 'if header "%s" contains "%s" wieght %s\n\n' % \
533 (header_name, spam_tag, spam_weight,
534 header_name, unsure_tag, unsure_weight,
535 header_name, ham_tag, ham_weight)
536 rules_file = file(rules_filename, "a")
537 rules_file.write(rule)
538 rules_file.close()
539 return results
540
541 def pocomail_accounts_filename():
542 if win32api is None:
543 # If we don't have win32, then we don't know.
544 return ""
545 key = "Software\\Poco Systems Inc"
546
547 pop_proxy = pop_proxy_port
548 smtp_proxy = smtp_proxy_port
549
550 try:
551 reg = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, key)
552 except pywintypes.error:
553 # It seems that we don't have PocoMail
554 return ""
555 else:
556 subkey_name = "%s\\%s" % (key, win32api.RegEnumKey(reg, 0))
557 reg = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER,
558 subkey_name)
559 pocomail_path = win32api.RegQueryValueEx(reg, "Path")[0]
560
561 return os.path.join(pocomail_path, "accounts.ini")
562
563 def configure_pocomail(pocomail_accounts_file):
564 if os.path.exists(pocomail_accounts_file):
565 f = open(pocomail_accounts_file, "r")
566
567 accountName = ""
568 pocomail_accounts = { }
569
570 # Builds the dictionary with all the existing accounts.
571 for line in f.readlines():
572 line = line.rstrip('\n\r')
573 if line == '':
574 continue
575
576 if line[0] == '[' and line[-1] == ']':
577 accountName = line[1:-1]
578 pocomail_accounts[accountName] = { }
579 else:
580 separator = line.find('=')
581 optionName = line[:separator]
582 optionValue = line[separator + 1:]
583
584 if optionName == "POPServer":
585 pop3 = optionValue.split(':')
586 if len(pop3) == 1:
587 pop3.append(110)
588 server = "%s:%s" % tuple(pop3)
589
590 proxy = pop_proxy
591 pop_proxy = move_to_next_free_port(pop_proxy)
592
593 if not server in options["pop3proxy", "remote_servers"]:
594 options["pop3proxy", "remote_servers"] += (server,)
595 options["pop3proxy", "listen_ports"] += (proxy,)
596 else:
597 serverIndex = 0
598 for remoteServer in options["pop3proxy",
599 "remote_servers"]:
600 if remoteServer == server:
601 break
602 serverIndex += 1
603 proxy = options["pop3proxy", "listen_ports"][serverIndex]
604
605 optionValue = "%s:%s" % ('localhost', proxy)
606
607 pocomail_accounts[accountName][optionName] = optionValue
608
609 f.close()
610 f = open(pocomail_accounts_file, "w")
611 for accountName in pocomail_accounts.keys():
612 f.write('[' + accountName + ']\n')
613 for optionName, optionValue in pocomail_accounts[accountName].items():
614 f.write("%s=%s\n" % (optionName, optionValue))
615 f.write('\n')
616 f.close()
617
618 options.update_file(optionsPathname)
619
620 # Add a filter to pocomail
621 pocomail_filters_file = os.path.join(pocomail_path, "filters.ini")
622
623 if os.path.exists(pocomail_filters_file):
624 f = open(pocomail_filters_file, "r")
625
626 pocomail_filters = { }
627 filterName = ""
628
629 for line in f.readlines():
630 line = line.rstrip('\n\r')
631 if line == '': continue
632
633 if line[0] == '[' and line[-1] == ']':
634 filterName = line[1:-1]
635 pocomail_filters[filterName] = []
636 elif line[0] != '{':
637 pocomail_filters[filterName].append(line)
638 f.close()
639
640 spamBayesFilter = 'spam,X-Spambayes-Classification,move,' \
641 '"Junk Mail",0,0,,,0,,,move,In,0,0,,0,,,' \
642 'move,In,0,0,,0,,,move,In,0,0,,0,,,move,' \
643 'In,0,0,,0,,,move,In,0,0,1,0'
644 if pocomail_filters.has_key("Incoming") and \
645 spamBayesFilter not in pocomail_filters["Incoming"]:
646 pocomail_filters["Incoming"].append(spamBayesFilter)
647
648 f = open(pocomail_filters_file, "w")
649 f.write('{ Filter list generated by PocoMail 3.01 (1661)' \
650 '- Licensed Version}\n')
651 for filterName in pocomail_filters.keys():
652 f.write('\n[' + filterName + ']\n')
653 for filter in pocomail_filters[filterName]:
654 f.write(filter + '\n')
655 f.close()
656 return []
657
658
659 def find_config_location(mailer):
660 """Attempt to find the location of the config file for
661 the given mailer, to pass to the configure_* scripts
662 above."""
663 # Requires win32all to be available, until someone
664 # fixes the function to look in the right places for *nix/Mac.
665 if win32api is None:
666 raise ImportError("win32 extensions required")
667 if mailer in ["Outlook Express", ]:
668 # Outlook Express can be configured without a
669 # config location, because it's all in the registry.
670 return ""
671 windowsUserDirectory = shell.SHGetFolderPath(0,shellcon.CSIDL_APPDATA,0,0)
672 potential_locations = \
673 {"Eudora" : ("%(wud)s%(sep)sQualcomm%(sep)sEudora",),
674 "Mozilla" : \
675 ("%(wud)s%(sep)sMozilla%(sep)sProfiles%(sep)s%(user)s",
676 "%(wud)s%(sep)sMozilla%(sep)sProfiles%(sep)sdefault",),
677 "M2" : ("%(wud)s%(sep)sOpera%(sep)sOpera7",),
678 "PocoMail" : (pocomail_accounts_filename(),),
679 }
680 # We try with the username that the user uses
681 # for Windows, even though that might not be the same as their profile
682 # names for mailers. We can get smarter later.
683 username = win32api.GetUserName()
684 loc_dict = {"sep" : os.sep,
685 "wud" : windowsUserDirectory,
686 "user" : username}
687 for loc in potential_locations[mailer]:
688 loc = loc % loc_dict
689 if os.path.exists(loc):
690 return loc
691 return None
692
693 def configure(mailer):
694 """Automatically configure the specified mailer and SpamBayes."""
695 loc = find_config_location(mailer)
696 if loc is None:
697 # Can't set it up, so do nothing.
698 return
699 funcs = {"Eudora" : configure_eudora,
700 "Mozilla" : configure_mozilla,
701 "M2" : configure_m2,
702 "Outlook Express" : configure_outlook_express,
703 "PocoMail" : configure_pocomail,
704 }
705 return funcs[mailer](loc)
706
707 def is_installed(mailer):
708 """Return True if we believe that the mailer is installed."""
709 # For the simpler mailers, we believe it is installed if the
710 # configuration path can be found and exists.
711 config_location = find_config_location(mailer)
712 if config_location:
713 if os.path.exists(config_location):
714 return True
715 return False
716 # For the ones based in the registry, we have different
717 # techniques.
718 if mailer == "Outlook Express":
719 if oe_mailbox.OEIsInstalled():
720 return True
721 return False
722
723 # If we don't know, guess that it isn't.
724 return False
725
726 def offer_to_configure(mailer):
727 """If the mailer appears to be installed, offer to set it up for
728 SpamBayes (and SpamBayes for it)."""
729 # At the moment, the test we use to check if the mailer is installed
730 # is whether a valid path to the configuration file can be found.
731 # This is ok, except for those that are setup in the registry - there
732 # will always be a valid path, whether they are installed or not.
733 if find_config_location(mailer) is not None:
734 confirm_text = "Would you like %s setup for SpamBayes, and " \
735 "SpamBayes setup with your %s settings?\n" \
736 "(This is alpha software! We recommend that you " \
737 "only do this if you know how to re-setup %s " \
738 "if necessary.)" % (mailer, mailer, mailer)
739 ans = MessageBox(confirm_text, "Configure?",
740 win32con.MB_YESNO | win32con.MB_ICONQUESTION)
741 if ans == win32con.IDYES:
742 results = configure(mailer)
743 if results is None:
744 MessageBox("Configuration unsuccessful.", "Error",
745 win32con.MB_OK | win32con.MB_ICONERROR)
746 else:
747 text = "Configuration complete.\n\n" + "\n".join(results)
748 MessageBox(text, "Complete", win32con.MB_OK)
749
750 def GetConsoleHwnd():
751 """Returns the window handle of the console window in which this script is
752 running, or 0 if not running in a console window. This function is taken
753 directly from Pythonwin\dllmain.cpp in the win32all source, ported to
754 Python."""
755
756 # fetch current window title
757 try:
758 oldWindowTitle = win32api.GetConsoleTitle()
759 except:
760 return 0
761
762 # format a "unique" NewWindowTitle
763 newWindowTitle = "%d/%d" % (win32api.GetTickCount(),
764 win32api.GetCurrentProcessId())
765
766 # change current window title
767 win32api.SetConsoleTitle(newWindowTitle)
768
769 # ensure window title has been updated
770 import time
771 time.sleep(0.040)
772
773 # look for NewWindowTitle
774 hwndFound = win32gui.FindWindow(0, newWindowTitle)
775
776 # restore original window title
777 win32api.SetConsoleTitle(oldWindowTitle)
778
779 return hwndFound
780
781 hwndOwner = GetConsoleHwnd()
782 def MessageBox(message, title=None, style=win32con.MB_OK):
783 return win32gui.MessageBox(hwndOwner, message, title, style)
784
785
786 if __name__ == "__main__":
787 pmail_ini_dir = "C:\\Program Files\\PMAIL\\MAIL\\ADMIN"
788 for mailer in