]> code.delx.au - offlineimap/blob - offlineimap/init.py
Merge branch 'master' of ssh://jpgarch@complete.org/~jpgarch/git/offlineimap
[offlineimap] / offlineimap / init.py
1 # OfflineIMAP initialization code
2 # Copyright (C) 2002-2007 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 import imaplib
20 from offlineimap import imapserver, repository, folder, mbnames, threadutil, version, syncmaster, accounts
21 from offlineimap.localeval import LocalEval
22 from offlineimap.threadutil import InstanceLimitedThread, ExitNotifyThread
23 from offlineimap.ui import UIBase
24 import re, os, os.path, offlineimap, sys
25 from offlineimap.CustomConfig import CustomConfigParser
26 from threading import *
27 import threading, socket
28 from getopt import getopt
29
30 try:
31 import fcntl
32 hasfcntl = 1
33 except:
34 hasfcntl = 0
35
36 lockfd = None
37
38 def lock(config, ui):
39 global lockfd, hasfcntl
40 if not hasfcntl:
41 return
42 lockfd = open(config.getmetadatadir() + "/lock", "w")
43 try:
44 fcntl.flock(lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB)
45 except IOError:
46 ui.locked()
47 ui.terminate(1)
48
49 def startup(versionno):
50 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)
51 options = {}
52 if '--help' in sys.argv[1:]:
53 sys.stdout.write(version.getcmdhelp() + "\n")
54 sys.exit(0)
55
56 for optlist in getopt(sys.argv[1:], 'P:1oqa:c:d:l:u:hk:f:')[0]:
57 options[optlist[0]] = optlist[1]
58
59 if options.has_key('-h'):
60 sys.stdout.write(version.getcmdhelp())
61 sys.stdout.write("\n")
62 sys.exit(0)
63 configfilename = os.path.expanduser("~/.offlineimaprc")
64 if options.has_key('-c'):
65 configfilename = options['-c']
66 if options.has_key('-P'):
67 if not options.has_key('-1'):
68 sys.stderr.write("FATAL: profile mode REQUIRES -1\n")
69 sys.exit(100)
70 profiledir = options['-P']
71 os.mkdir(profiledir)
72 threadutil.setprofiledir(profiledir)
73 sys.stderr.write("WARNING: profile mode engaged;\nPotentially large data will be created in " + profiledir + "\n")
74
75 config = CustomConfigParser()
76 if not os.path.exists(configfilename):
77 sys.stderr.write(" *** Config file %s does not exist; aborting!\n" % configfilename)
78 sys.exit(1)
79
80 config.read(configfilename)
81
82 # override config values with option '-k'
83 for option in options.keys():
84 if option == '-k':
85 (key, value) = options['-k'].split('=', 1)
86 if ':' in key:
87 (secname, key) = key.split(':', 1)
88 section = secname.replace("_", " ")
89 else:
90 section = "general"
91 config.set(section, key, value)
92
93 ui = offlineimap.ui.detector.findUI(config, options.get('-u'))
94 UIBase.setglobalui(ui)
95
96 if options.has_key('-l'):
97 ui.setlogfd(open(options['-l'], 'wt'))
98
99 ui.init_banner()
100
101 if options.has_key('-d'):
102 for debugtype in options['-d'].split(','):
103 ui.add_debug(debugtype.strip())
104 if debugtype == 'imap':
105 imaplib.Debug = 5
106 if debugtype == 'thread':
107 threading._VERBOSE = 1
108
109 if options.has_key('-o'):
110 # FIXME: maybe need a better
111 for section in accounts.getaccountlist(config):
112 config.remove_option('Account ' + section, "autorefresh")
113
114 if options.has_key('-q'):
115 for section in accounts.getaccountlist(config):
116 config.set('Account ' + section, "quick", '-1')
117
118 if options.has_key('-f'):
119 foldernames = options['-f'].replace(" ", "").split(",")
120 folderfilter = "lambda f: f in %s" % foldernames
121 folderincludes = "[]"
122 for accountname in accounts.getaccountlist(config):
123 account_section = 'Account ' + accountname
124 remote_repo_section = 'Repository ' + \
125 config.get(account_section, 'remoterepository')
126 local_repo_section = 'Repository ' + \
127 config.get(account_section, 'localrepository')
128 for section in [remote_repo_section, local_repo_section]:
129 config.set(section, "folderfilter", folderfilter)
130 config.set(section, "folderincludes", folderincludes)
131
132 lock(config, ui)
133
134 try:
135 pidfd = open(config.getmetadatadir() + "/pid", "w")
136 pidfd.write(str(os.getpid()) + "\n")
137 pidfd.close()
138 except:
139 pass
140
141 try:
142 if options.has_key('-l'):
143 sys.stderr = ui.logfile
144
145 socktimeout = config.getdefaultint("general", "socktimeout", 0)
146 if socktimeout > 0:
147 socket.setdefaulttimeout(socktimeout)
148
149 activeaccounts = config.get("general", "accounts")
150 if options.has_key('-a'):
151 activeaccounts = options['-a']
152 activeaccounts = activeaccounts.replace(" ", "")
153 activeaccounts = activeaccounts.split(",")
154 allaccounts = accounts.AccountHashGenerator(config)
155
156 syncaccounts = {}
157 for account in activeaccounts:
158 if account not in allaccounts:
159 if len(allaccounts) == 0:
160 errormsg = 'The account "%s" does not exist because no accounts are defined!'%account
161 else:
162 errormsg = 'The account "%s" does not exist. Valid accounts are:'%account
163 for name in allaccounts.keys():
164 errormsg += '\n%s'%name
165 ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
166 syncaccounts[account] = allaccounts[account]
167
168 server = None
169 remoterepos = None
170 localrepos = None
171
172 if options.has_key('-1'):
173 threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
174 else:
175 threadutil.initInstanceLimit("ACCOUNTLIMIT",
176 config.getdefaultint("general", "maxsyncaccounts", 1))
177
178 for reposname in config.getsectionlist('Repository'):
179 for instancename in ["FOLDER_" + reposname,
180 "MSGCOPY_" + reposname]:
181 if options.has_key('-1'):
182 threadutil.initInstanceLimit(instancename, 1)
183 else:
184 threadutil.initInstanceLimit(instancename,
185 config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
186
187 threadutil.initexitnotify()
188 t = ExitNotifyThread(target=syncmaster.syncitall,
189 name='Sync Runner',
190 kwargs = {'accounts': syncaccounts,
191 'config': config})
192 t.setDaemon(1)
193 t.start()
194 except:
195 ui.mainException()
196
197 try:
198 threadutil.exitnotifymonitorloop(threadutil.threadexited)
199 except SystemExit:
200 raise
201 except:
202 ui.mainException() # Also expected to terminate.
203
204