]> code.delx.au - offlineimap/blob - offlineimap/init.py
TAG RELEASE_offlineimap_5.99.3
[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:h')[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 ui = offlineimap.ui.detector.findUI(config, options.get('-u'))
83 UIBase.setglobalui(ui)
84
85 if options.has_key('-l'):
86 ui.setlogfd(open(options['-l'], 'wt'))
87
88 ui.init_banner()
89
90 if options.has_key('-d'):
91 for debugtype in options['-d'].split(','):
92 ui.add_debug(debugtype.strip())
93 if debugtype == 'imap':
94 imaplib.Debug = 5
95 if debugtype == 'thread':
96 threading._VERBOSE = 1
97
98 if options.has_key('-o'):
99 # FIXME: maybe need a better
100 for section in accounts.getaccountlist(config):
101 config.remove_option('Account ' + section, "autorefresh")
102
103 if options.has_key('-q'):
104 for section in accounts.getaccountlist(config):
105 config.set('Account ' + section, "quick", '-1')
106
107 lock(config, ui)
108
109 try:
110 pidfd = open(config.getmetadatadir() + "/pid", "w")
111 pidfd.write(os.getpid())
112 pidfd.close()
113 except:
114 pass
115
116 try:
117 if options.has_key('-l'):
118 sys.stderr = ui.logfile
119
120 socktimeout = config.getdefaultint("general", "socktimeout", 0)
121 if socktimeout > 0:
122 socket.setdefaulttimeout(socktimeout)
123
124 activeaccounts = config.get("general", "accounts")
125 if options.has_key('-a'):
126 activeaccounts = options['-a']
127 activeaccounts = activeaccounts.replace(" ", "")
128 activeaccounts = activeaccounts.split(",")
129 allaccounts = accounts.AccountHashGenerator(config)
130
131 syncaccounts = {}
132 for account in activeaccounts:
133 if account not in allaccounts:
134 if len(allaccounts) == 0:
135 errormsg = 'The account "%s" does not exist because no accounts are defined!'%account
136 else:
137 errormsg = 'The account "%s" does not exist. Valid accounts are:'%account
138 for name in allaccounts.keys():
139 errormsg += '\n%s'%name
140 ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
141 syncaccounts[account] = allaccounts[account]
142
143 server = None
144 remoterepos = None
145 localrepos = None
146
147 if options.has_key('-1'):
148 threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
149 else:
150 threadutil.initInstanceLimit("ACCOUNTLIMIT",
151 config.getdefaultint("general", "maxsyncaccounts", 1))
152
153 for reposname in config.getsectionlist('Repository'):
154 for instancename in ["FOLDER_" + reposname,
155 "MSGCOPY_" + reposname]:
156 if options.has_key('-1'):
157 threadutil.initInstanceLimit(instancename, 1)
158 else:
159 threadutil.initInstanceLimit(instancename,
160 config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
161
162 threadutil.initexitnotify()
163 t = ExitNotifyThread(target=syncmaster.syncitall,
164 name='Sync Runner',
165 kwargs = {'accounts': syncaccounts,
166 'config': config})
167 t.setDaemon(1)
168 t.start()
169 except:
170 ui.mainException()
171
172 try:
173 threadutil.exitnotifymonitorloop(threadutil.threadexited)
174 except SystemExit:
175 raise
176 except:
177 ui.mainException() # Also expected to terminate.
178
179