diff options
-rw-r--r-- | CHANGELOG | 3 | ||||
-rwxr-xr-x | archivemail.py | 52 |
2 files changed, 43 insertions, 12 deletions
@@ -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.""" |