gmail migration python script
sync.py
#!/usr/bin/env python import cPickle as pickle import imaplib import sys from sexp import scan_sexp def savetemp(name, value): f = open(name, 'w') pickle.dump(value, f) f.close() def loadtemp(name): try: f = open(name, 'r') value = pickle.load(f) f.close() return value except: return {} HOST = 'imap.gmail.com' PORT = 993 SOURCE_USER = 'XXX@gmail.com' SOURCE_PASS = 'XXX' DEST_USER = 'XXX@gmail.com' DEST_PASS = 'XXX' TEMPFILE = 'temp' print 'connecting...' source = imaplib.IMAP4_SSL(HOST, PORT) print 'logging in...' source.login(SOURCE_USER, SOURCE_PASS) print 'connecting...' dest = imaplib.IMAP4_SSL(HOST, PORT) print 'logging in...' dest.login(DEST_USER, DEST_PASS) labels = { '[Gmail]/All Mail': '[Gmail]/All Mail', } temp = loadtemp(TEMPFILE) for slabel, dlabel in labels.items(): # creating temp for slabel if not temp.has_key(slabel): temp[slabel] = {'dest_uids': {}, 'dest_info': {}, 'source_uids': {}} # printing temp info for slabel print 'loaded for %s: "dest_uids": %d, "dest_info": %d, "source_uids": %d' % (slabel, len(temp[slabel]['dest_uids']), len(temp[slabel]['dest_info']), len(temp[slabel]['source_uids'])) print 'selecting source folder %s...' % slabel if source.select(slabel)[0] == 'NO': print 'error: select failed' continue else: print 'selecting dest folder %s...' % dlabel if dest.select(dlabel)[0] == 'NO': print 'dest folder not found; creating...' if dest.create(dlabel)[0]=='NO' or dest.select(dlabel)[0]=='NO': print 'error: could not create folder' continue print 'analyzing existing messages...' uids = dest.search(None, 'ALL')[1][0].split() if uids: i = 1 length = len(uids) for uid in uids: # progress sys.stdout.write('\r%d/%d' % (i, length)) sys.stdout.flush() i += 1 if not temp[slabel]['dest_uids'].has_key(uid): try: msg_id = scan_sexp(dest.fetch(uid, 'ENVELOPE')[1][0])[1][1][-1] temp[slabel]['dest_uids'][uid] = True temp[slabel]['dest_info'][msg_id] = True except: pass print '\nwriting dest_uids and dest_info temp...' savetemp(TEMPFILE, temp) print 'migrating...' uids = source.search(None, 'ALL')[1][0].split() if uids: i = 1 length = len(uids) for uid in uids: # progress sys.stdout.write('\r%d/%d' % (i, length)) sys.stdout.flush() i += 1 if not temp[slabel]['source_uids'].has_key(uid): try: msg_id = scan_sexp(source.fetch(uid, 'ENVELOPE')[1][0])[1][1][-1] if not temp[slabel]['dest_info'].has_key(msg_id): msg = source.fetch(uid, '(RFC822 FLAGS INTERNALDATE)') dest.append(dlabel, \ imaplib.ParseFlags(msg[1][1][:-1]), \ imaplib.Internaldate2tuple(msg[1][1][:-1]), \ msg[1][0][1]) temp[slabel]['source_uids'][uid] = True else: temp[slabel]['source_uids'][uid] = True except: pass print '\nwriting dest_uids and dest_info temp...' savetemp(TEMPFILE, temp) try: source.close() dest.close() except: pass print '\ndone'
sexp.py
# -*- coding: utf-8 -*- # imaplib2 python module, meant to be a replacement to the python default # imaplib module # Copyright (C) 2008 Helder Guerreiro ## This file is part of imaplib2. ## ## imaplib2 is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## imaplib2 is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with hlimap. If not, see <http://www.gnu.org/licenses/>. # # Helder Guerreiro <helder@paxjulia.com> # # $LastChangedDate: 2008-04-22 22:45:55 +0100 (Tue, 22 Apr 2008) $ # $LastChangedRevision: 327 $ # $LastChangedBy: helder $ # # Global imports import re, string # Regexp literal_re = re.compile(r'^{(\d+)}\r\n') simple_re = re.compile(r'^([^ ()]+)') quoted_re = re.compile(r'^"((?:[^"\\]|\\")*?)"') # Errors class SError(Exception): pass def scan_sexp(text): '''S-Expression scanner. This is a non-recursive version. It uses the lists property of assigning only by reference to assemble the s-exp. @param text: text to be scanned. @type text: s-exp string @return result: s-exp in a python list. ''' # Initialization pos = 0 lenght = len(text) current = '' result = [] cur_result = result level = [ cur_result ] # Scanner while pos < lenght: # Quoted literal: if text[pos] == '"': quoted = quoted_re.match(text[pos:]) if quoted: cur_result.append( quoted.groups()[0] ) pos += quoted.end() - 1 # Numbered literal: elif text[pos] == '{': lit = literal_re.match(text[pos:]) if lit: start = pos+lit.end() end = pos+lit.end()+int(lit.groups()[0]) pos = end - 1 cur_result.append( text[ start:end ] ) # Simple literal elif text[pos] not in '() ': simple = simple_re.match(text[pos:]) if simple: tmp = simple.groups()[0] if tmp.isdigit(): tmp = int(tmp) elif tmp == 'NIL': tmp = None cur_result.append( tmp ) pos += simple.end() - 1 # Level handling, if we find a '(' we must add another list, if we # find a ')' we must return to the previous list. elif text[pos] == '(': cur_result.append([]) cur_result = cur_result[-1] level.append(cur_result) elif text[pos] == ')': try: cur_result = level[-2] del level[-1] except IndexError: raise SError('Unexpected parenthesis at pos %d' % pos) pos += 1 return result if __name__ == '__main__': from time import time count = 1000 text = '(A NIL {5}\r\n12345 (D E))(F G)' text = '266 FETCH (FLAGS (\Seen) UID 31608 INTERNALDATE "30-Jan-2008 02:48:01 +0000" RFC822.SIZE 4509 ENVELOPE ("Tue, 29 Jan 2008 14:00:24 +0000" "Aprenda as tXcnicas e os truques da cozinha mais doce..." (("Ediclube" NIL "ediclube" "sigmathis.info")) (("Ediclube" NIL "ediclube" "sigmathis.info")) ((NIL NIL "ediclube" "sigmathis.info")) ((NIL NIL "helder" "example.com")) NIL NIL NIL "<64360f85d83238281a27b921fd3e7eb3@localhost.localdomain>"))' #text = 'AA 12341 NIL (A NIL "asdasd fffff\\"sdasd" {%d}\r\n%s (D E))(F G)' % ( count, '#' * count) #text = 'A B (C NIL (D E))(F G)' itx = 300 rit = xrange(itx) print 'Test to the s-exp parser:' print print 'Non Recursive (%d times):' % itx a = time() for i in rit: scan_sexp(text) b = time() print 1000 * (b-a) / itx, 'ms/iter' print itx, ' --> ', 1000 * (b-a) , 'ms' print print scan_sexp(text)
