]>
code.delx.au - offlineimap/blob - offlineimap/init.py
1 # OfflineIMAP initialization code
2 # Copyright (C) 2002-2007 John Goerzen
3 # <jgoerzen@complete.org>
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.
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.
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
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
40 global lockfd
, hasfcntl
43 lockfd
= open ( config
. getmetadatadir () + "/lock" , "w" )
45 fcntl
. flock ( lockfd
, fcntl
. LOCK_EX | fcntl
. LOCK_NB
)
50 def startup ( versionno
):
51 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
)
53 if '--help' in sys
. argv
[ 1 :]:
54 sys
. stdout
. write ( version
. getcmdhelp () + " \n " )
57 for optlist
in getopt ( sys
. argv
[ 1 :], 'P:1oqa:c:d:l:u:hk:f:' )[ 0 ]:
58 options
[ optlist
[ 0 ]] = optlist
[ 1 ]
60 if options
. has_key ( '-h' ):
61 sys
. stdout
. write ( version
. getcmdhelp ())
62 sys
. stdout
. write ( " \n " )
64 configfilename
= os
. path
. expanduser ( "~/.offlineimaprc" )
65 if options
. has_key ( '-c' ):
66 configfilename
= options
[ '-c' ]
67 if options
. has_key ( '-P' ):
68 if not options
. has_key ( '-1' ):
69 sys
. stderr
. write ( "FATAL: profile mode REQUIRES -1 \n " )
71 profiledir
= options
[ '-P' ]
73 threadutil
. setprofiledir ( profiledir
)
74 sys
. stderr
. write ( "WARNING: profile mode engaged; \n Potentially large data will be created in " + profiledir
+ " \n " )
76 config
= CustomConfigParser ()
77 if not os
. path
. exists ( configfilename
):
78 sys
. stderr
. write ( " *** Config file %s does not exist; aborting! \n " % configfilename
)
81 config
. read ( configfilename
)
83 # override config values with option '-k'
84 for option
in options
. keys ():
86 ( key
, value
) = options
[ '-k' ]. split ( '=' , 1 )
88 ( secname
, key
) = key
. split ( ':' , 1 )
89 section
= secname
. replace ( "_" , " " )
92 config
. set ( section
, key
, value
)
94 ui
= offlineimap
. ui
. detector
. findUI ( config
, options
. get ( '-u' ))
95 UIBase
. setglobalui ( ui
)
97 if options
. has_key ( '-l' ):
98 ui
. setlogfd ( open ( options
[ '-l' ], 'wt' ))
102 if options
. has_key ( '-d' ):
103 for debugtype
in options
[ '-d' ]. split ( ',' ):
104 ui
. add_debug ( debugtype
. strip ())
105 if debugtype
== 'imap' :
107 if debugtype
== 'thread' :
108 threading
._ VERBOSE
= 1
110 if options
. has_key ( '-o' ):
111 # FIXME: maybe need a better
112 for section
in accounts
. getaccountlist ( config
):
113 config
. remove_option ( 'Account ' + section
, "autorefresh" )
115 if options
. has_key ( '-q' ):
116 for section
in accounts
. getaccountlist ( config
):
117 config
. set ( 'Account ' + section
, "quick" , '-1' )
119 if options
. has_key ( '-f' ):
120 foldernames
= options
[ '-f' ]. replace ( " " , "" ). split ( "," )
121 folderfilter
= "lambda f: f in %s " % foldernames
122 folderincludes
= "[]"
123 for accountname
in accounts
. getaccountlist ( config
):
124 account_section
= 'Account ' + accountname
125 remote_repo_section
= 'Repository ' + \
126 config
. get ( account_section
, 'remoterepository' )
127 local_repo_section
= 'Repository ' + \
128 config
. get ( account_section
, 'localrepository' )
129 for section
in [ remote_repo_section
, local_repo_section
]:
130 config
. set ( section
, "folderfilter" , folderfilter
)
131 config
. set ( section
, "folderincludes" , folderincludes
)
135 def sigterm_handler ( signum
, frame
):
137 ui
. terminate ( errormsg
= "terminating..." )
138 signal
. signal ( signal
. SIGTERM
, sigterm_handler
)
141 pidfd
= open ( config
. getmetadatadir () + "/pid" , "w" )
142 pidfd
. write ( str ( os
. getpid ()) + " \n " )
148 if options
. has_key ( '-l' ):
149 sys
. stderr
= ui
. logfile
151 socktimeout
= config
. getdefaultint ( "general" , "socktimeout" , 0 )
153 socket
. setdefaulttimeout ( socktimeout
)
155 activeaccounts
= config
. get ( "general" , "accounts" )
156 if options
. has_key ( '-a' ):
157 activeaccounts
= options
[ '-a' ]
158 activeaccounts
= activeaccounts
. replace ( " " , "" )
159 activeaccounts
= activeaccounts
. split ( "," )
160 allaccounts
= accounts
. AccountHashGenerator ( config
)
163 for account
in activeaccounts
:
164 if account
not in allaccounts
:
165 if len ( allaccounts
) == 0 :
166 errormsg
= 'The account " %s " does not exist because no accounts are defined!' % account
168 errormsg
= 'The account " %s " does not exist. Valid accounts are:' % account
169 for name
in allaccounts
. keys ():
170 errormsg
+= ' \n %s ' % name
171 ui
. terminate ( 1 , errortitle
= 'Unknown Account " %s "' % account
, errormsg
= errormsg
)
172 syncaccounts
[ account
] = allaccounts
[ account
]
178 if options
. has_key ( '-1' ):
179 threadutil
. initInstanceLimit ( "ACCOUNTLIMIT" , 1 )
181 threadutil
. initInstanceLimit ( "ACCOUNTLIMIT" ,
182 config
. getdefaultint ( "general" , "maxsyncaccounts" , 1 ))
184 for reposname
in config
. getsectionlist ( 'Repository' ):
185 for instancename
in [ "FOLDER_" + reposname
,
186 "MSGCOPY_" + reposname
]:
187 if options
. has_key ( '-1' ):
188 threadutil
. initInstanceLimit ( instancename
, 1 )
190 threadutil
. initInstanceLimit ( instancename
,
191 config
. getdefaultint ( 'Repository ' + reposname
, "maxconnections" , 1 ))
193 def sig_handler ( signum
, frame
):
194 if signum
== signal
. SIGUSR1
:
195 # tell each account to do a full sync asap
197 elif signum
== signal
. SIGHUP
:
198 # tell each account to die asap
200 elif signum
== signal
. SIGUSR2
:
201 # tell each account to do a full sync asap, then die
203 # one listener per account thread (up to maxsyncaccounts)
204 for listener
in siglisteners
:
206 listener
. put_nowait ( sig
)
207 signal
. signal ( signal
. SIGHUP
, sig_handler
)
208 signal
. signal ( signal
. SIGUSR1
, sig_handler
)
209 signal
. signal ( signal
. SIGUSR2
, sig_handler
)
211 threadutil
. initexitnotify ()
212 t
= ExitNotifyThread ( target
= syncmaster
. syncitall
,
214 kwargs
= { 'accounts' : syncaccounts
,
216 'siglisteners' : siglisteners
})
223 threadutil
. exitnotifymonitorloop ( threadutil
. threadexited
)
227 ui
. mainException () # Also expected to terminate.