/offlineimap/head: changeset 278
Moved password promting into imapserver.py. Passwords are now asked for on-demand and typos will no longer crash the program (the user will be re-prompted). Closes: #162672.
This commit is contained in:
parent
d64138c228
commit
4527b82221
@ -1,3 +1,11 @@
|
||||
offlineimap (3.99.3) unstable; urgency=low
|
||||
|
||||
* Moved password promting into imapserver.py. Passwords are now asked
|
||||
for on-demand and typos will no longer crash the program (the user
|
||||
will be re-prompted). Closes: #162672.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Mon, 4 Nov 2002 11:15:11 -0600
|
||||
|
||||
offlineimap (3.99.2) unstable; urgency=low
|
||||
|
||||
* Further attempts to fix imapsplit problems.
|
||||
|
@ -48,11 +48,15 @@ class UsefulIMAP4_SSL(UsefulIMAPMixIn, imaplib.IMAP4_SSL): pass
|
||||
class UsefulIMAP4_Tunnel(UsefulIMAPMixIn, imaplib.IMAP4_Tunnel): pass
|
||||
|
||||
class IMAPServer:
|
||||
def __init__(self, username = None, password = None, hostname = None,
|
||||
def __init__(self, config, accountname,
|
||||
username = None, password = None, hostname = None,
|
||||
port = None, ssl = 1, maxconnections = 1, tunnel = None,
|
||||
reference = '""'):
|
||||
self.account = accountname
|
||||
self.config = config
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.passworderror = None
|
||||
self.hostname = hostname
|
||||
self.tunnel = tunnel
|
||||
self.port = port
|
||||
@ -72,6 +76,16 @@ class IMAPServer:
|
||||
self.connectionlock = Lock()
|
||||
self.reference = reference
|
||||
|
||||
def getpassword(self):
|
||||
if self.password != None and self.passworderror == None:
|
||||
return self.password
|
||||
|
||||
self.password = UIBase.getglobalui().getpass(self.account, self.config,
|
||||
self.passworderror)
|
||||
self.passworderror = None
|
||||
|
||||
return self.password
|
||||
|
||||
def getdelim(self):
|
||||
"""Returns this server's folder delimiter. Can only be called
|
||||
after one or more calls to acquireconnection."""
|
||||
@ -92,7 +106,7 @@ class IMAPServer:
|
||||
|
||||
def md5handler(self, response):
|
||||
challenge = response.strip()
|
||||
msg = self.password
|
||||
msg = self.getpassword()
|
||||
while len(msg) < 64:
|
||||
msg += "\0"
|
||||
|
||||
@ -135,6 +149,8 @@ class IMAPServer:
|
||||
|
||||
UIBase.getglobalui().connecting(self.hostname, self.port)
|
||||
|
||||
success = 0
|
||||
while not success:
|
||||
# Generate a new connection.
|
||||
if self.tunnel:
|
||||
imapobj = UsefulIMAP4_Tunnel(self.tunnel)
|
||||
@ -144,6 +160,7 @@ class IMAPServer:
|
||||
imapobj = UsefulIMAP4(self.hostname, self.port)
|
||||
|
||||
if not self.tunnel:
|
||||
try:
|
||||
if 'AUTH=CRAM-MD5' in imapobj.capabilities:
|
||||
UIBase.getglobalui().debug('imap',
|
||||
'Attempting CRAM-MD5 authentication')
|
||||
@ -151,7 +168,12 @@ class IMAPServer:
|
||||
else:
|
||||
UIBase.getglobalui().debug('imap',
|
||||
'Attempting plain authentication')
|
||||
imapobj.login(self.username, self.password)
|
||||
imapobj.login(self.username, self.getpassword())
|
||||
# Would bail by here if there was a failure.
|
||||
success = 1
|
||||
except imapobj.error, val:
|
||||
self.passworderror = str(val)
|
||||
self.password = None
|
||||
|
||||
if self.delim == None:
|
||||
listres = imapobj.list(self.reference, '""')[1]
|
||||
@ -249,13 +271,19 @@ class ConfigedIMAPServer(IMAPServer):
|
||||
|
||||
# Connect to the remote server.
|
||||
if usetunnel:
|
||||
IMAPServer.__init__(self,
|
||||
IMAPServer.__init__(self, config, accountname,
|
||||
tunnel = config.get(accountname, "preauthtunnel"),
|
||||
reference = reference,
|
||||
maxconnections = config.getint(accountname, "maxconnections"))
|
||||
else:
|
||||
if not password:
|
||||
if config.has_option(accountname, 'remotepass'):
|
||||
password = config.get(accountname, 'remotepass')
|
||||
IMAPServer.__init__(self, user, password, host, port, ssl,
|
||||
elif config.has_option(accountname, 'remotepassfile'):
|
||||
passfile = open(os.path.expanduser(config.get(accountname, "remotepassfile")))
|
||||
password = passfile.readline().strip()
|
||||
passfile.close()
|
||||
IMAPServer.__init__(self, config, accountname,
|
||||
user, password, host, port, ssl,
|
||||
config.getint(accountname, "maxconnections"),
|
||||
reference = reference)
|
||||
|
@ -90,8 +90,6 @@ def startup(versionno):
|
||||
server = None
|
||||
remoterepos = None
|
||||
localrepos = None
|
||||
passwords = {}
|
||||
tunnels = {}
|
||||
|
||||
if '-1' in options:
|
||||
threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
|
||||
@ -99,23 +97,7 @@ def startup(versionno):
|
||||
threadutil.initInstanceLimit("ACCOUNTLIMIT",
|
||||
config.getint("general", "maxsyncaccounts"))
|
||||
|
||||
# We have to gather passwords here -- don't want to have two threads
|
||||
# asking for passwords simultaneously.
|
||||
|
||||
for account in accounts:
|
||||
#if '.' in account:
|
||||
# raise ValueError, "Account '%s' contains a dot; dots are not " \
|
||||
# "allowed in account names." % account
|
||||
if config.has_option(account, "preauthtunnel"):
|
||||
tunnels[account] = config.get(account, "preauthtunnel")
|
||||
elif config.has_option(account, "remotepass"):
|
||||
passwords[account] = config.get(account, "remotepass")
|
||||
elif config.has_option(account, "remotepassfile"):
|
||||
passfile = open(os.path.expanduser(config.get(account, "remotepassfile")))
|
||||
passwords[account] = passfile.readline().strip()
|
||||
passfile.close()
|
||||
else:
|
||||
passwords[account] = ui.getpass(account, config)
|
||||
for instancename in ["FOLDER_" + account, "MSGCOPY_" + account]:
|
||||
if '-1' in options:
|
||||
threadutil.initInstanceLimit(instancename, 1)
|
||||
@ -133,7 +115,6 @@ def startup(versionno):
|
||||
'metadatadir': metadatadir,
|
||||
'servers': servers,
|
||||
'config': config,
|
||||
'passwords': passwords,
|
||||
'localeval': localeval})
|
||||
t.setDaemon(1)
|
||||
t.start()
|
||||
|
@ -23,7 +23,7 @@ import re, os, os.path, offlineimap, sys
|
||||
from ConfigParser import ConfigParser
|
||||
from threading import *
|
||||
|
||||
def syncaccount(accountname, metadatadir, servers, config, passwords,
|
||||
def syncaccount(accountname, metadatadir, servers, config,
|
||||
localeval, *args):
|
||||
ui = UIBase.getglobalui()
|
||||
# We don't need an account lock because syncitall() goes through
|
||||
@ -38,7 +38,7 @@ def syncaccount(accountname, metadatadir, servers, config, passwords,
|
||||
if accountname in servers:
|
||||
server = servers[accountname]
|
||||
else:
|
||||
server = imapserver.ConfigedIMAPServer(config, accountname, passwords)
|
||||
server = imapserver.ConfigedIMAPServer(config, accountname)
|
||||
servers[accountname] = server
|
||||
|
||||
remoterepos = repository.IMAP.IMAPRepository(config, localeval, accountname, server)
|
||||
@ -147,7 +147,7 @@ def syncfolder(accountname, remoterepos, remotefolder, localrepos,
|
||||
|
||||
|
||||
|
||||
def syncitall(accounts, metadatadir, servers, config, passwords, localeval):
|
||||
def syncitall(accounts, metadatadir, servers, config, localeval):
|
||||
ui = UIBase.getglobalui()
|
||||
global mailboxes
|
||||
mailboxes = [] # Reset.
|
||||
@ -157,7 +157,7 @@ def syncitall(accounts, metadatadir, servers, config, passwords, localeval):
|
||||
target = syncaccount,
|
||||
name = "Account sync %s" % accountname,
|
||||
args = (accountname, metadatadir,
|
||||
servers, config, passwords,
|
||||
servers, config,
|
||||
localeval))
|
||||
thread.setDaemon(1)
|
||||
thread.start()
|
||||
@ -166,11 +166,11 @@ def syncitall(accounts, metadatadir, servers, config, passwords, localeval):
|
||||
threadutil.threadsreset(threads)
|
||||
mbnames.genmbnames(config, localeval, mailboxes)
|
||||
|
||||
def sync_with_timer(accounts, metadatadir, servers, config, passwords,
|
||||
def sync_with_timer(accounts, metadatadir, servers, config,
|
||||
localeval):
|
||||
ui = UIBase.getglobalui()
|
||||
currentThread().setExitMessage('SYNC_WITH_TIMER_TERMINATE')
|
||||
syncitall(accounts, metadatadir, servers, config, passwords, localeval)
|
||||
syncitall(accounts, metadatadir, servers, config, localeval)
|
||||
if config.has_option('general', 'autorefresh'):
|
||||
refreshperiod = config.getint('general', 'autorefresh') * 60
|
||||
while 1:
|
||||
@ -200,5 +200,5 @@ def sync_with_timer(accounts, metadatadir, servers, config, passwords,
|
||||
event.set()
|
||||
for thread in kathreads.values():
|
||||
thread.join()
|
||||
syncitall(accounts, metadatadir, servers, config, passwords,
|
||||
syncitall(accounts, metadatadir, servers, config,
|
||||
localeval)
|
||||
|
@ -25,21 +25,32 @@ class TTYUI(UIBase):
|
||||
def __init__(s, config, verbose = 0):
|
||||
UIBase.__init__(s, config, verbose)
|
||||
s.iswaiting = 0
|
||||
s.outputlock = Lock()
|
||||
|
||||
def isusable(s):
|
||||
return sys.stdout.isatty() and sys.stdin.isatty()
|
||||
|
||||
def _msg(s, msg):
|
||||
s.outputlock.acquire()
|
||||
try:
|
||||
if (currentThread().getName() == 'MainThread'):
|
||||
print msg
|
||||
else:
|
||||
print "%s:\n %s" % (currentThread().getName(), msg)
|
||||
sys.stdout.flush()
|
||||
finally:
|
||||
s.outputlock.release()
|
||||
|
||||
def getpass(s, accountname, config):
|
||||
def getpass(s, accountname, config, errmsg = None):
|
||||
if errmsg:
|
||||
s._msg("%s: %s" % (accountname, errmsg))
|
||||
s.outputlock.acquire()
|
||||
try:
|
||||
return getpass("%s: Enter password for %s on %s: " %
|
||||
(accountname, config.get(accountname, "remoteuser"),
|
||||
config.get(accountname, "remotehost")))
|
||||
finally:
|
||||
s.outputlock.release()
|
||||
|
||||
def sleep(s, sleepsecs):
|
||||
s.iswaiting = 1
|
||||
|
@ -27,13 +27,16 @@ from Queue import Queue
|
||||
from UIBase import UIBase
|
||||
|
||||
class PasswordDialog:
|
||||
def __init__(self, accountname, config, master=None):
|
||||
def __init__(self, accountname, config, master=None, errmsg = None):
|
||||
self.top = Toplevel(master)
|
||||
self.top.title(version.productname + " Password Entry")
|
||||
self.label = Label(self.top,
|
||||
text = "%s: Enter password for %s on %s: " % \
|
||||
text = ''
|
||||
if errmsg:
|
||||
text = '%s: %s\n' % (accountname, errmsg)
|
||||
text += "%s: Enter password for %s on %s: " % \
|
||||
(accountname, config.get(accountname, "remoteuser"),
|
||||
config.get(accountname, "remotehost")))
|
||||
config.get(accountname, "remotehost"))
|
||||
self.label = Label(self.top, text = text)
|
||||
self.label.pack()
|
||||
|
||||
self.entry = Entry(self.top, show='*')
|
||||
@ -171,8 +174,8 @@ class VerboseUI(UIBase):
|
||||
s.top.mainloop()
|
||||
s.notdeleted = 0
|
||||
|
||||
def getpass(s, accountname, config):
|
||||
pd = PasswordDialog(accountname, config)
|
||||
def getpass(s, accountname, config, errmsg = None):
|
||||
pd = PasswordDialog(accountname, config, errmsg = errmsg)
|
||||
return pd.getpassword()
|
||||
|
||||
def gettf(s, newtype=ThreadFrame, master = None):
|
||||
|
@ -92,7 +92,7 @@ class UIBase:
|
||||
|
||||
################################################## INPUT
|
||||
|
||||
def getpass(s, accountname, config):
|
||||
def getpass(s, accountname, config, errmsg = None):
|
||||
raise NotImplementedError
|
||||
|
||||
def folderlist(s, list):
|
||||
|
Loading…
Reference in New Issue
Block a user