NNTP to IMAP duplicator

Annotation For nntpdup.py
anonymous

Annotation For nntpdup.py

Origin for each line in nntpdup.py from check-in 973a1d241e:

3205f8a9ae 2015-10-12 arcade@b1t.na: #!/usr/bin/env python3.4
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: import configparser, email.utils, getpass, imaplib, nntplib, re, sqlite3, sys
3205f8a9ae 2015-10-12 arcade@b1t.na: imaplib._MAXLINE = 1024 * 1024
3205f8a9ae 2015-10-12 arcade@b1t.na: nntplib._MAXLINE = 1024 * 1024
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: config = configparser.ConfigParser(allow_no_value = True)
3205f8a9ae 2015-10-12 arcade@b1t.na: config.read('nntpdup.conf')
3205f8a9ae 2015-10-12 arcade@b1t.na: 
973a1d241e 2015-10-13 arcade@b1t.na: try:
973a1d241e 2015-10-13 arcade@b1t.na: 	server = nntplib.NNTP_SSL(config['connection']['newsserver'])
973a1d241e 2015-10-13 arcade@b1t.na: except nntplib.NNTPTemporaryError as err:
973a1d241e 2015-10-13 arcade@b1t.na: 	if err.response.startswith('400 load at '):
973a1d241e 2015-10-13 arcade@b1t.na: 		print(err.response)
973a1d241e 2015-10-13 arcade@b1t.na: 		exit(0)
973a1d241e 2015-10-13 arcade@b1t.na: 	else:
973a1d241e 2015-10-13 arcade@b1t.na: 		raise(err)
3205f8a9ae 2015-10-12 arcade@b1t.na: mserver = imaplib.IMAP4_SSL(config['connection']['mailserver'])
3205f8a9ae 2015-10-12 arcade@b1t.na: reMessageId = re.compile('(<[-\][a-zA-Z0-9@.%/=_\$+!&~#\?}]+>)"?\)\)(\d+ \(FLAGS\(\)\))?$')
3205f8a9ae 2015-10-12 arcade@b1t.na: mserver.login(config['connection']['mail_user'], config['connection']['mail_password'])
3205f8a9ae 2015-10-12 arcade@b1t.na: if 'mail_limit' in config['connection']:
3205f8a9ae 2015-10-12 arcade@b1t.na: 	mailLimit = int(config['connection']['mail_limit'])
3205f8a9ae 2015-10-12 arcade@b1t.na: else:
3205f8a9ae 2015-10-12 arcade@b1t.na: 	mailLimit = 100
3205f8a9ae 2015-10-12 arcade@b1t.na: if 'header_limit' in config['connection']:
3205f8a9ae 2015-10-12 arcade@b1t.na: 	headerLimit = int(config['connection']['header_limit'])
3205f8a9ae 2015-10-12 arcade@b1t.na: else:
3205f8a9ae 2015-10-12 arcade@b1t.na: 	headerLimit = 1000
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: tables = {
3205f8a9ae 2015-10-12 arcade@b1t.na: 	'list': ["create table list (id integer primary key, name text, last integer default 0);"],
3205f8a9ae 2015-10-12 arcade@b1t.na: 	'ids': ["create table ids (id integer, name text, mask integer, date integer);", "create unique index ids__id_name on ids(id, name);"],
3205f8a9ae 2015-10-12 arcade@b1t.na: }
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: class Folder:
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def __init__(this, filename):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.db = sqlite3.connect(filename)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.id = None
3205f8a9ae 2015-10-12 arcade@b1t.na: 		found = set()
3205f8a9ae 2015-10-12 arcade@b1t.na: 		for row in this.db.execute("select name from sqlite_master where type = 'table';"):
3205f8a9ae 2015-10-12 arcade@b1t.na: 			found.add(row[0])
3205f8a9ae 2015-10-12 arcade@b1t.na: 		for absent in set(tables.keys()).difference(found):
3205f8a9ae 2015-10-12 arcade@b1t.na: 			for query in tables[absent]:
3205f8a9ae 2015-10-12 arcade@b1t.na: 				this.db.execute(query)
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def select(this, folderName):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.name = folderName
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.id = None
3205f8a9ae 2015-10-12 arcade@b1t.na: 		while True:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			present = False
3205f8a9ae 2015-10-12 arcade@b1t.na: 			for row in this.db.execute("select id, last from list where name = ?;", [folderName]):
3205f8a9ae 2015-10-12 arcade@b1t.na: 				present = True
3205f8a9ae 2015-10-12 arcade@b1t.na: 				this.id = row[0]
3205f8a9ae 2015-10-12 arcade@b1t.na: 				this.last = row[1]
3205f8a9ae 2015-10-12 arcade@b1t.na: 			if present:
3205f8a9ae 2015-10-12 arcade@b1t.na: 				break
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.db.execute("insert into list(name) values (?);", [folderName])
3205f8a9ae 2015-10-12 arcade@b1t.na: 		if this.id == None:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			print('Id not found.')
3205f8a9ae 2015-10-12 arcade@b1t.na: 			exit(1)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.mask = {}
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.get_count()
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def get_count(this):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.count = 0
3205f8a9ae 2015-10-12 arcade@b1t.na: 		for row in this.db.execute("select count(*) from ids where id = ? and mask in (3, 1);", [this.id]):
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.count = row[0]
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def get_record_count(this, mask):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		for row in this.db.execute("select count(*) from ids where id = ? and mask = ?;", [this.id, mask]):
3205f8a9ae 2015-10-12 arcade@b1t.na: 			return(row[0])
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def check(this, name):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		if name in this.mask:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			return(this.mask[name])
3205f8a9ae 2015-10-12 arcade@b1t.na: 		for row in this.db.execute("select mask from ids where id = ? and name = ?;", [this.id, name]):
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.mask[name] = row[0]
3205f8a9ae 2015-10-12 arcade@b1t.na: 			return(row[0])
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def addlast(this, count):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.last += count
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.db.execute("update list set last = ? where id = ?;", [this.last, this.id])
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def droplast(this):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.last = 0
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.db.execute("update list set last = ? where id = ?;", [this.last, this.id])
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def addmail(this, mid):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		mask = this.check(mid)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		if mask in (3, 2):
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.db.execute("update ids set mask = 3 where id = ? and name = ?;", [this.id, mid])
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.mask[mid] = 3
3205f8a9ae 2015-10-12 arcade@b1t.na: 		else:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.db.execute("insert into ids(id, name, mask) values(?, ?, ?);", [this.id, mid, 1])
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.count += 1
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.mask[mid] = 1
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def addnews(this, mid, date = None):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		mask = this.check(mid)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		if mask in (1, 3):
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.db.execute("update ids set mask = 3, date = ? where id = ? and name = ?;", [date, this.id, mid])
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.mask[mid] = 3
3205f8a9ae 2015-10-12 arcade@b1t.na: 		else:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.db.execute("insert into ids(id, name, mask, date) values(?, ?, ?, ?);", [this.id, mid, 2, date])
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.count += 1
3205f8a9ae 2015-10-12 arcade@b1t.na: 			this.mask[mid] = 2
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def zeromail(this):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.mask = {}
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.db.execute("update ids set mask = 2 where id = ? and mask = 3;", [this.id])
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.db.execute("delete from ids where id = ? and mask = 1;", [this.id])
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.sync()
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.get_count()
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def zeronews(this):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.mask = {}
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.db.execute("update ids set mask = 1 where id = ? and mask = 3;", [this.id])
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.db.execute("delete from ids where id = ? and mask = 2;", [this.id])
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.droplast()
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.sync()
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def sync(this):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.db.commit()
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def get_unfetched(this):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		return(this.db.execute("select name, date from ids where id = ? and mask = 2 order by date desc;", [this.id]))
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	def forget(this, mid):
3205f8a9ae 2015-10-12 arcade@b1t.na: 		this.db.execute("delete from ids where id = ? and name = ?;", [this.id, mid])
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: def check_folder(mserver, folder, folderName):
3205f8a9ae 2015-10-12 arcade@b1t.na: 	folder.zeromail()
3205f8a9ae 2015-10-12 arcade@b1t.na: 	deleted = 0
3205f8a9ae 2015-10-12 arcade@b1t.na: 	mserver.select(folderName)
3205f8a9ae 2015-10-12 arcade@b1t.na: 	typ, data = mserver.search(None, 'NOT DELETED')
3205f8a9ae 2015-10-12 arcade@b1t.na: 	count = 0
3205f8a9ae 2015-10-12 arcade@b1t.na: 	print(' - building imap index', folderName, '[', end='')
3205f8a9ae 2015-10-12 arcade@b1t.na: 	for num in data[0].split():
3205f8a9ae 2015-10-12 arcade@b1t.na: 		found = False
3205f8a9ae 2015-10-12 arcade@b1t.na: 		typ, data = mserver.fetch(num, '(ENVELOPE)')
3205f8a9ae 2015-10-12 arcade@b1t.na: 		field = 0
3205f8a9ae 2015-10-12 arcade@b1t.na: 		for rec in data:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			if type(rec) == tuple:
3205f8a9ae 2015-10-12 arcade@b1t.na: 				data[field] = ''.join(i.decode('utf-8', 'ignore') for i in rec)
3205f8a9ae 2015-10-12 arcade@b1t.na: 			else:
3205f8a9ae 2015-10-12 arcade@b1t.na: 				data[field] = rec.decode('utf-8', 'ignore')
3205f8a9ae 2015-10-12 arcade@b1t.na: 			field += 1
3205f8a9ae 2015-10-12 arcade@b1t.na: 		data = ''.join(data)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		isMid = reMessageId.search(data)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		if isMid:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			mid = isMid.group(1)
3205f8a9ae 2015-10-12 arcade@b1t.na: 			mask = folder.check(mid)
3205f8a9ae 2015-10-12 arcade@b1t.na: 			if not mask in (1, 3):
3205f8a9ae 2015-10-12 arcade@b1t.na: 				folder.addmail(mid)
3205f8a9ae 2015-10-12 arcade@b1t.na: 				count += 1
3205f8a9ae 2015-10-12 arcade@b1t.na: 			else:
3205f8a9ae 2015-10-12 arcade@b1t.na: 				mserver.store(num, '+FLAGS', '\\Deleted')
3205f8a9ae 2015-10-12 arcade@b1t.na: 				deleted += 1
3205f8a9ae 2015-10-12 arcade@b1t.na: 				sys.stdout.write('x')
3205f8a9ae 2015-10-12 arcade@b1t.na: 				sys.stdout.flush()
3205f8a9ae 2015-10-12 arcade@b1t.na: 		else:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			print('Message id not found.')
3205f8a9ae 2015-10-12 arcade@b1t.na: 			print(repr(data))
3205f8a9ae 2015-10-12 arcade@b1t.na: 			exit(1)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		if (count % 1000) == 0:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			sys.stdout.write('.')
3205f8a9ae 2015-10-12 arcade@b1t.na: 			sys.stdout.flush()
3205f8a9ae 2015-10-12 arcade@b1t.na: 	print('], deleted:', deleted, end = '')
3205f8a9ae 2015-10-12 arcade@b1t.na: 	folder.sync()
3205f8a9ae 2015-10-12 arcade@b1t.na: 	mserver.expunge()
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: folder = Folder('nntpdup.sqlite')
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: limits = [0, 0]
3205f8a9ae 2015-10-12 arcade@b1t.na: limitSteps = [headerLimit / len(config['groups']), mailLimit / len(config['groups'])]
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: maxlength = 0
3205f8a9ae 2015-10-12 arcade@b1t.na: for folderName in (config['groups'].keys()):
3205f8a9ae 2015-10-12 arcade@b1t.na: 	maxlength = max(maxlength, len(folderName))
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: skew = 1 + int(maxlength / 8)
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: for folderName in (set(config['groups'].keys())):
3205f8a9ae 2015-10-12 arcade@b1t.na: 	stats = [0, 0]
3205f8a9ae 2015-10-12 arcade@b1t.na: 	folder.select(folderName)
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	resp = mserver.select(folderName)
3205f8a9ae 2015-10-12 arcade@b1t.na: 	if resp[0] != 'OK':
3205f8a9ae 2015-10-12 arcade@b1t.na: 		print("Can't open folder.")
3205f8a9ae 2015-10-12 arcade@b1t.na: 		exit(1)
3205f8a9ae 2015-10-12 arcade@b1t.na: 	if int(resp[1][0]) != folder.count:
3205f8a9ae 2015-10-12 arcade@b1t.na: 		check_folder(mserver, folder, folderName)
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	_, count, first, last, _ = server.group(folderName)
3205f8a9ae 2015-10-12 arcade@b1t.na: 	limits[0] += limitSteps[0]
3205f8a9ae 2015-10-12 arcade@b1t.na: 	if last > folder.last:
3205f8a9ae 2015-10-12 arcade@b1t.na: 		count = 0
3205f8a9ae 2015-10-12 arcade@b1t.na: 		# we need to fetch new ids
3205f8a9ae 2015-10-12 arcade@b1t.na: 		request = min(last, folder.last + limits[0])
3205f8a9ae 2015-10-12 arcade@b1t.na: 		try:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			for record in server.over((int(folder.last) + 1, int(request)))[1]:
3205f8a9ae 2015-10-12 arcade@b1t.na: 				mid = record[1]['message-id']
3205f8a9ae 2015-10-12 arcade@b1t.na: 				if len(record[1]['message-id']) > 0:
3205f8a9ae 2015-10-12 arcade@b1t.na: 					try:
3205f8a9ae 2015-10-12 arcade@b1t.na: 						folder.addnews(record[1]['message-id'], email.utils.parsedate_to_datetime(record[1]['date']).timestamp())
3205f8a9ae 2015-10-12 arcade@b1t.na: 					except OverflowError as err:
3205f8a9ae 2015-10-12 arcade@b1t.na: 						folder.addnews(record[1]['message-id'])
3205f8a9ae 2015-10-12 arcade@b1t.na: 					except TypeError as err:
3205f8a9ae 2015-10-12 arcade@b1t.na: 						folder.addnews(record[1]['message-id'])
3205f8a9ae 2015-10-12 arcade@b1t.na: 				count += 1
3205f8a9ae 2015-10-12 arcade@b1t.na: 		except nntplib.NNTPTemporaryError as err:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			if err.response.startswith('423 '):
3205f8a9ae 2015-10-12 arcade@b1t.na: 				pass
3205f8a9ae 2015-10-12 arcade@b1t.na: 			else:
3205f8a9ae 2015-10-12 arcade@b1t.na: 				raise(err)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		except nntplib.NNTPPermanentError as err:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			print(folder.last, request)
3205f8a9ae 2015-10-12 arcade@b1t.na: 			raise(err)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		except sqlite3.IntegrityError as err:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			print(repr(record))
3205f8a9ae 2015-10-12 arcade@b1t.na: 			print([x for x in map(repr, folder.db.execute("select * from ids where id = ? and name = ?;", [folder.id, record[1]['message-id']]))])
3205f8a9ae 2015-10-12 arcade@b1t.na: 			raise(err)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		stats[0] = count
3205f8a9ae 2015-10-12 arcade@b1t.na: 		limits[0] -= count
3205f8a9ae 2015-10-12 arcade@b1t.na: 		folder.addlast(request - folder.last)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		folder.sync()
3205f8a9ae 2015-10-12 arcade@b1t.na: 	elif folder.get_record_count(1) > 0:
3205f8a9ae 2015-10-12 arcade@b1t.na: 		folder.droplast()
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	limits[1] += limitSteps[1]
3205f8a9ae 2015-10-12 arcade@b1t.na: 	if folder.get_record_count(2) > 0:
3205f8a9ae 2015-10-12 arcade@b1t.na: 		count = 0
3205f8a9ae 2015-10-12 arcade@b1t.na: 		# there are extra articles
3205f8a9ae 2015-10-12 arcade@b1t.na: 		raw_date = []
3205f8a9ae 2015-10-12 arcade@b1t.na: 		unfetched = []
3205f8a9ae 2015-10-12 arcade@b1t.na: 		for item, env_date in folder.get_unfetched():
3205f8a9ae 2015-10-12 arcade@b1t.na: 			mask = folder.check(item)
3205f8a9ae 2015-10-12 arcade@b1t.na: 			if mask == 2:
3205f8a9ae 2015-10-12 arcade@b1t.na: 				unfetched += (item, env_date),
3205f8a9ae 2015-10-12 arcade@b1t.na: 		for item, env_date in unfetched:
3205f8a9ae 2015-10-12 arcade@b1t.na: 			try:
3205f8a9ae 2015-10-12 arcade@b1t.na: 				_, info = server.article(item)
3205f8a9ae 2015-10-12 arcade@b1t.na: 				if env_date == None or env_date < 0:
3205f8a9ae 2015-10-12 arcade@b1t.na: 					date = None
3205f8a9ae 2015-10-12 arcade@b1t.na: 					backup_date = None
3205f8a9ae 2015-10-12 arcade@b1t.na: 					out = []
3205f8a9ae 2015-10-12 arcade@b1t.na: 					for line in info.lines:
3205f8a9ae 2015-10-12 arcade@b1t.na: 						if len(line) == 0:
3205f8a9ae 2015-10-12 arcade@b1t.na: 							mesg = email.message_from_string('\n'.join(out))
3205f8a9ae 2015-10-12 arcade@b1t.na: 							for header in mesg._headers:
3205f8a9ae 2015-10-12 arcade@b1t.na: 								if header[0] == 'Date':
3205f8a9ae 2015-10-12 arcade@b1t.na: 									raw_date += header[1],
3205f8a9ae 2015-10-12 arcade@b1t.na: 									date = email.utils.parsedate(header[1])
3205f8a9ae 2015-10-12 arcade@b1t.na: 								elif header[0] == 'Original-Received':
3205f8a9ae 2015-10-12 arcade@b1t.na: 									raw_date += header[1],
3205f8a9ae 2015-10-12 arcade@b1t.na: 									tmp_date = email.utils.parsedate(header[1].split(';')[-1])
3205f8a9ae 2015-10-12 arcade@b1t.na: 									if tmp_date != None and tmp_date[0] >= 1970:
3205f8a9ae 2015-10-12 arcade@b1t.na: 										backup_date = tmp_date
3205f8a9ae 2015-10-12 arcade@b1t.na: 							if date == None and backup_date == None:
3205f8a9ae 2015-10-12 arcade@b1t.na: 								print('Date missed.')
3205f8a9ae 2015-10-12 arcade@b1t.na: 								print(repr(out))
3205f8a9ae 2015-10-12 arcade@b1t.na: 								exit(1)
3205f8a9ae 2015-10-12 arcade@b1t.na: 							elif date == None:
3205f8a9ae 2015-10-12 arcade@b1t.na: 								date = backup_date
3205f8a9ae 2015-10-12 arcade@b1t.na: 							break
3205f8a9ae 2015-10-12 arcade@b1t.na: 						try:
3205f8a9ae 2015-10-12 arcade@b1t.na: 							out.append(line.decode('ascii', 'ignore'))
3205f8a9ae 2015-10-12 arcade@b1t.na: 						except UnicodeDecodeError:
3205f8a9ae 2015-10-12 arcade@b1t.na: 							print(repr(line))
3205f8a9ae 2015-10-12 arcade@b1t.na: 							exit(1)
3205f8a9ae 2015-10-12 arcade@b1t.na: 					out.append('\n')
3205f8a9ae 2015-10-12 arcade@b1t.na: 					try:
3205f8a9ae 2015-10-12 arcade@b1t.na: 						#print('*', item, date, type(date))
3205f8a9ae 2015-10-12 arcade@b1t.na: 						mserver.append(folderName, None, date, b'\n'.join(info.lines))
3205f8a9ae 2015-10-12 arcade@b1t.na: 					except AttributeError as err:
3205f8a9ae 2015-10-12 arcade@b1t.na: 						#print('*', item, raw_date, repr(date))
3205f8a9ae 2015-10-12 arcade@b1t.na: 						#raise(err)
3205f8a9ae 2015-10-12 arcade@b1t.na: 						mserver.append(folderName, None, backup_date, b'\n'.join(info.lines))
3205f8a9ae 2015-10-12 arcade@b1t.na: 					except OverflowError as err:
3205f8a9ae 2015-10-12 arcade@b1t.na: 						#print('*', item, raw_date, repr(date))
3205f8a9ae 2015-10-12 arcade@b1t.na: 						#raise(err)
3205f8a9ae 2015-10-12 arcade@b1t.na: 						mserver.append(folderName, None, backup_date, b'\n'.join(info.lines))
3205f8a9ae 2015-10-12 arcade@b1t.na: 				else:
3205f8a9ae 2015-10-12 arcade@b1t.na: 					#print('*', item, env_date, type(env_date))
3205f8a9ae 2015-10-12 arcade@b1t.na: 					mserver.append(folderName, None, env_date, b'\n'.join(info.lines))
3205f8a9ae 2015-10-12 arcade@b1t.na: 				folder.addmail(item)
3205f8a9ae 2015-10-12 arcade@b1t.na: 				folder.sync()
3205f8a9ae 2015-10-12 arcade@b1t.na: 				count += 1
3205f8a9ae 2015-10-12 arcade@b1t.na: 				if count >= limits[1]:
3205f8a9ae 2015-10-12 arcade@b1t.na: 					break
3205f8a9ae 2015-10-12 arcade@b1t.na: 			except nntplib.NNTPTemporaryError as err:
3205f8a9ae 2015-10-12 arcade@b1t.na: 				if err.response.startswith('430 No such article'):
3205f8a9ae 2015-10-12 arcade@b1t.na: 					folder.forget(item)
3205f8a9ae 2015-10-12 arcade@b1t.na: 				else:
3205f8a9ae 2015-10-12 arcade@b1t.na: 					print(err.response, item, env_date)
3205f8a9ae 2015-10-12 arcade@b1t.na: 					raise(err)
3205f8a9ae 2015-10-12 arcade@b1t.na: 		stats[1] = count
3205f8a9ae 2015-10-12 arcade@b1t.na: 		limits[1] -= count
3205f8a9ae 2015-10-12 arcade@b1t.na: 
3205f8a9ae 2015-10-12 arcade@b1t.na: 	if stats[0] != 0 or stats[1] != 0:
3205f8a9ae 2015-10-12 arcade@b1t.na: 		print('# ', folderName, '\t'*(skew - int((len(folderName) + 2) / 8)), '\t'.join(map(str, stats)), sep = '')
3205f8a9ae 2015-10-12 arcade@b1t.na: 	folder.sync()