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