]> code.delx.au - offlineimap/blob - offlineimap/init.py
Configurable thread status character for ui.Curses.Blinkenlights
[offlineimap] / offlineimap / init.py
1 # OfflineIMAP initialization code
2 # Copyright (C) 2002, 2003 John Goerzen
3 # <jgoerzen@complete.org>
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 from offlineimap import imaplib, imapserver, repository, folder, mbnames, threadutil, version, syncmaster, accounts
20 from offlineimap.localeval import LocalEval
21 from offlineimap.threadutil import InstanceLimitedThread, ExitNotifyThread
22 from offlineimap.ui import UIBase
23 import re, os, os.path, offlineimap, sys
24 from offlineimap.CustomConfig import CustomConfigParser
25 from threading import *
26 import threading
27 from getopt import getopt
28
29 try:
30 import fcntl
31 hasfcntl = 1
32 except:
33 hasfcntl = 0
34
35 lockfd = None
36
37 def lock(config, ui):
38 global lockfd, hasfcntl
39 if not hasfcntl:
40 return
41 lockfd = open(config.getmetadatadir() + "/lock", "w")
42 try:
43 fcntl.flock(lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB)
44 except IOError:
45 ui.locked()
46 ui.terminate(1)
47
48 def startup(versionno):
49 assert versionno == version.versionstr, "Revision of main program (%s) does not match that of library (%s). Please double-check your PYTHONPATH and installation locations." % (versionno, version.versionstr)
50 options = {}
51 if '--help' in sys.argv[1:]:
52 sys.stdout.write(version.cmdhelp + "\n")
53 sys.exit(0)
54
55 for optlist in getopt(sys.argv[1:], 'P:1oa:c:d:l:u:h')[0]:
56 options[optlist[0]] = optlist[1]
57
58 if options.has_key('-h'):
59 sys.stdout.write(version.cmdhelp)
60 sys.stdout.write("\n")
61 sys.exit(0)
62 configfilename = os.path.expanduser("~/.offlineimaprc")
63 if options.has_key('-c'):
64 configfilename = options['-c']
65 if options.has_key('-P'):
66 if not options.has_key('-1'):
67 sys.stderr.write("FATAL: profile mode REQUIRES -1\n")
68 sys.exit(100)
69 profiledir = options['-P']
70 os.mkdir(profiledir)
71 threadutil.setprofiledir(profiledir)
72 sys.stderr.write("WARNING: profile mode engaged;\nPotentially large data will be created in " + profiledir + "\n")
73
74 config = CustomConfigParser()
75 if not os.path.exists(configfilename):
76 sys.stderr.write(" *** Config file %s does not exist; aborting!\n" % configfilename)
77 sys.exit(1)
78
79 config.read(configfilename)
80
81 ui = offlineimap.ui.detector.findUI(config, options.get('-u'))
82 UIBase.setglobalui(ui)
83
84 if options.has_key('-l'):
85 ui.setlogfd(open(options['-l'], 'wt'))
86
87 ui.init_banner()
88
89 if options.has_key('-d'):
90 for debugtype in options['-d'].split(','):
91 ui.add_debug(debugtype.strip())
92 if debugtype == 'imap':
93 imaplib.Debug = 5
94 if debugtype == 'thread':
95 threading._VERBOSE = 1
96
97 if options.has_key('-o'):
98 # FIXME: maybe need a better
99 for section in accounts.getaccountlist(config):
100 config.remove_option('Account ' + section, "autorefresh")
101
102 lock(config, ui)
103
104 try:
105 if options.has_key('-l'):
106 sys.stderr = ui.logfile
107
108 activeaccounts = config.get("general", "accounts")
109 if options.has_key('-a'):
110 activeaccounts = options['-a']
111 activeaccounts = activeaccounts.replace(" ", "")
112 activeaccounts = activeaccounts.split(",")
113 allaccounts = accounts.AccountHashGenerator(config)
114
115 syncaccounts = {}
116 for account in activeaccounts:
117 if account not in allaccounts:
118 if len(allaccounts) == 0:
119 errormsg = 'The account "%s" does not exist because no accounts are defined!'%account
120 else:
121 errormsg = 'The account "%s" does not exist. Valid accounts are:'%account
122 for name in allaccounts.keys():
123 errormsg += '\n%s'%name
124 ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
125 syncaccounts[account] = allaccounts[account]
126
127 server = None
128 remoterepos = None
129 localrepos = None
130
131 if options.has_key('-1'):
132 threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
133 else:
134 threadutil.initInstanceLimit("ACCOUNTLIMIT",
135 config.getdefaultint("general", "maxsyncaccounts", 1))
136
137 for reposname in config.getsectionlist('Repository'):
138 for instancename in ["FOLDER_" + reposname,
139 "MSGCOPY_" + reposname]:
140 if options.has_key('-1'):
141 threadutil.initInstanceLimit(instancename, 1)
142 else:
143 threadutil.initInstanceLimit(instancename,
144 config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
145
146 threadutil.initexitnotify()
147 t = ExitNotifyThread(target=syncmaster.syncitall,
148 name='Sync Runner',
149 kwargs = {'accounts': syncaccounts,
150 'config': config})
151 t.setDaemon(1)
152 t.start()
153 except:
154 ui.mainException()
155
156 try:
157 threadutil.exitnotifymonitorloop(threadutil.threadexited)
158 except SystemExit:
159 raise
160 except:
161 ui.mainException() # Also expected to terminate.
162
163