]> code.delx.au - offlineimap/blob - offlineimap/init.py
Add option '-k' for overriding config options
[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:')[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 lock(config, ui)
119
120 try:
121 pidfd = open(config.getmetadatadir() + "/pid", "w")
122 pidfd.write(os.getpid())
123 pidfd.close()
124 except:
125 pass
126
127 try:
128 if options.has_key('-l'):
129 sys.stderr = ui.logfile
130
131 socktimeout = config.getdefaultint("general", "socktimeout", 0)
132 if socktimeout > 0:
133 socket.setdefaulttimeout(socktimeout)
134
135 activeaccounts = config.get("general", "accounts")
136 if options.has_key('-a'):
137 activeaccounts = options['-a']
138 activeaccounts = activeaccounts.replace(" ", "")
139 activeaccounts = activeaccounts.split(",")
140 allaccounts = accounts.AccountHashGenerator(config)
141
142 syncaccounts = {}
143 for account in activeaccounts:
144 if account not in allaccounts:
145 if len(allaccounts) == 0:
146 errormsg = 'The account "%s" does not exist because no accounts are defined!'%account
147 else:
148 errormsg = 'The account "%s" does not exist. Valid accounts are:'%account
149 for name in allaccounts.keys():
150 errormsg += '\n%s'%name
151 ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
152 syncaccounts[account] = allaccounts[account]
153
154 server = None
155 remoterepos = None
156 localrepos = None
157
158 if options.has_key('-1'):
159 threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
160 else:
161 threadutil.initInstanceLimit("ACCOUNTLIMIT",
162 config.getdefaultint("general", "maxsyncaccounts", 1))
163
164 for reposname in config.getsectionlist('Repository'):
165 for instancename in ["FOLDER_" + reposname,
166 "MSGCOPY_" + reposname]:
167 if options.has_key('-1'):
168 threadutil.initInstanceLimit(instancename, 1)
169 else:
170 threadutil.initInstanceLimit(instancename,
171 config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
172
173 threadutil.initexitnotify()
174 t = ExitNotifyThread(target=syncmaster.syncitall,
175 name='Sync Runner',
176 kwargs = {'accounts': syncaccounts,
177 'config': config})
178 t.setDaemon(1)
179 t.start()
180 except:
181 ui.mainException()
182
183 try:
184 threadutil.exitnotifymonitorloop(threadutil.threadexited)
185 except SystemExit:
186 raise
187 except:
188 ui.mainException() # Also expected to terminate.
189
190