aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG3
-rwxr-xr-xarchivemail.py52
2 files changed, 43 insertions, 12 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 9ddecda..7c5f1cb 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,9 @@ Version 0.7.1 - UNRELEASED
* Fixed incompatibility with Python 2.5 which broke Maildir handling.
Closes: #1670422
+ * Username and password in IMAP URLs can now be double-quoted, so it should be
+ no longer a problem if they contain delimiters like the '@' character.
+ Closes: #1640878
Version 0.7.0 - 2 November 2006
* Fixed long options --filter-append and --pwfile to accept their arguments.
diff --git a/archivemail.py b/archivemail.py
index 8c0ebed..b3f6a00 100755
--- a/archivemail.py
+++ b/archivemail.py
@@ -1312,18 +1312,12 @@ def _archive_imap(mailbox_name, final_archive_name):
imap_str = mailbox_name[mailbox_name.find('://') + 3:]
imap_filter = build_imap_filter()
vprint("imap filter: '%s'" % imap_filter)
- try:
- imap_username, imap_str = imap_str.split('@', 1)
- imap_server, imap_folder = imap_str.split('/', 1)
- except ValueError:
- unexpected_error("you must provide a properly formatted "
- "IMAP connection string")
- if options.pwfile:
- imap_password = open(options.pwfile).read().rstrip()
- else:
- try:
- imap_username, imap_password = imap_username.split(':', 1)
- except ValueError:
+ imap_username, imap_password, imap_server, imap_folder = \
+ parse_imap_url(imap_str)
+ if not imap_password:
+ if options.pwfile:
+ imap_password = open(options.pwfile).read().rstrip()
+ else:
if (not os.isatty(sys.stdin.fileno())) or options.quiet:
unexpected_error("No imap password specified")
imap_password = getpass.getpass('IMAP password: ')
@@ -1477,6 +1471,40 @@ def nice_size_str(size):
if kb >= 1.0: return str(round(kb)) + 'kB'
return str(size) + 'B'
+def parse_imap_url(url):
+ """Parse IMAP URL and return username, password (if appliciable), servername
+ and foldername."""
+
+ def split_qstr(string, delim):
+ """Split string once at delim, keeping quoted substring intact.
+ Strip and unescape quotes where necessary."""
+ rm = re.match(r'"(.+?(?<!\\))"(.)(.*)', string)
+ if rm:
+ a, d, b = rm.groups()
+ if not d == delim:
+ raise ValueError
+ a = a.replace('\\"', '"')
+ else:
+ a, b = string.split(delim, 1)
+ return a, b
+
+ password = None
+ try:
+ if options.pwfile:
+ username, url = split_qstr(url, '@')
+ else:
+ try:
+ username, url = split_qstr(url, ':')
+ except ValueError:
+ # request password interactively later
+ username, url = split_qstr(url, '@')
+ else:
+ password, url = split_qstr(url, '@')
+ server, folder = url.split('/', 1)
+ except ValueError:
+ unexpected_error("Invalid IMAP connection string")
+ return username, password, server, folder
+
def get_filename(msg):
"""If the given rfc822.Message can be identified with a file (no mbox),
return the filename, otherwise raise AttributeError."""