#!/usr/bin/python
# -*- coding: ISO-8859-15 -*-

# Maildir archive utility.

# Copyright (c) 2003 Santeri Hernejärvi
# Copyright (c) 2004 Philippe Normand

# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:

# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from os import chdir,listdir,system,rename,environ
from os.path import exists,isdir,split,splitext
from time import strftime, localtime,mktime,asctime,ctime
import re
from getopt import getopt, GetoptError
import sys
from email import Utils
import email

verbose = 1
doit = 1
maildir = environ['HOME'] + "/Maildir/"
stats = {}

def usage():
    """Display usage information"""
    print "Usage: %s [-v] [-q] [-d] [-a AGE] [-p FOLDER] FOLDER" % sys.argv[0]
    print " -v         Increase verbosity."
    print " -q         Be quiet."
    print " -d         dry run, don't actually do anything."
    print " -a AGE     Archive messages older than AGE days. Default: 31."
    print " -m         Use Mail dates instead of IMAP ones"
    print " -p FOLDER  Archive to this maildir folder. Default: nothing"
    print " FOLDER     The maildir forlder to archive"
    print ""
    print "For example: "
    print "%% %s -a 100 -p InboxArchive List" % sys.argv[0]
    print ""
    print "This archives mails in $HOME/Maildir/.List older than 100 days to"
    print "Maildir/.List.InboxArchive.[year].[month]  folders"
    print ""
    
cond = re.compile("(\d+)\.")
def getMaildirTime(file):
    """Return the timestamp portion of a maildir mail"""
    m = cond.search(file)
    if m: return float(m.group(1))
    else: raise "getMaildirTime: No Match: ", file

def getMailDate(file):        
    f = open(file,'r')
    msg = email.message_from_file(f)
    f.close()
    date = msg.get('Date',None)
    if date:
	d = Utils.parsedate(date)
	d = mktime(d)
	return d
    else:
	raise "getMailDate: No Match: ", file
    
def isOld(file,folder,age,useDate):
    """True if the mail file in folder is older that age seconds."""
    f = '%s/%s' % (folder,file)
    if useDate:
	date = getMailDate(f)
    else:
	date = getMaildirTime(f)
    #print ctime(date),date,'|',age, ctime(age)
    if (date < age):
	return (1, date)
    return (0,None)

def archive(date,file, folder, prefix,directory,useDate):
    """archives a single mail file from folder in prefix"""
    global verbose, doit

    # ym is in format '2003-10'
    ym     = '%4d-%02d' % localtime(date)[:2] 
    
    # target is in format 'Maildir/.Archive.Foo.2003-10'
    if prefix:
	target = '%s%s.%s.%s'  % (maildir,folder, prefix, ym)
    else:
	target = '%s%s.%s' % (maildir,folder,ym)
	
    try:
	stats[ym] = stats[ym] + 1
    except KeyError:
	stats[ym] = 1

    if (not exists(target)):
	if verbose > 1 and stats[ym] == 1:
	    print "Will create target: " + target
	if (doit and system("maildirmake " + target) != 0):
	    raise "archive: failed to create target " + target

    if verbose > 2:
	print '%s%s/%s/%s -> %s/%s/%s' % (maildir,folder,file, directory,target,directory,file)
    if doit:
	if (not isdir(target)):
	    raise "Target '%s' not a directory!" % target
	rename("%s%s/%s/%s" % (maildir,folder, directory,file), '%s/%s/%s' % (target, directory,file))

def main():
    global verbose
    global doit
    
    try:
	opts, args = getopt(sys.argv[1:], "Vvqhda:f:p:m")
    except GetoptError:
	usage();
	sys.exit(2)
	

    prefix = None
    start  = mktime(localtime())
    age    = start  - 60*60*24 * 31 # 31 days
    useDate = 0
    
    for o,a in opts:
	if (o == "-h"):	usage(); sys.exit()
	if (o == "-v"): verbose = verbose + 1
	if (o == "-q"):	verbose = 0
	if (o == "-d"):	doit    = 0
	if (o == "-a"):	age     = start - 60*60*24 * int(a) 
	if (o == "-p"):	prefix  = a 
	if (o == '-m'): useDate = 1
	if (o == "-V"):
	    print "$Id: mdirarchive.py,v 1.8 2003/10/05 20:01:59 gray Exp $"
	    sys.exit()

    try:
	folder = args[0]
    except IndexError:
	usage();
	print "No folder specified!"
	sys.exit(2)

    folder = '.' + folder
	
    realFolder = maildir + folder

    if verbose:
	if not doit: print "-- DRY RUN --"
	print "Local time: ", ctime(start)
	print "Will archive messages older than ", ctime(age)
	print "Archiving folder " + folder
	if prefix:
	    print "To " + prefix

    for dire in ('new','cur'):
	curFolder = realFolder + '/%s/' % dire
	for file in listdir(curFolder):
	    old,date = isOld(file, curFolder, age,useDate)
	    if old:
		archive(date,file,folder,prefix,dire,useDate)
	    
    if verbose:
	print "Done archiving folder " + folder
	print "It took %d seconds" % (mktime(localtime()) - start) 
	print "Stats:"
	
	list = stats.items()
	list.sort()
	for key,value in list:
	    print key, ": ", value

if __name__ == "__main__":
    main()
