#!/usr/bin/python
# vim: set fileencoding=utf-8 : sts=4 : et : sw=4
#    This is a component of mailpie, a full-text search for email
#
#    Copyright © 2008 Jeff Epler <jepler@unpythonic.net>
#    This program 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 2 of the License, or
#    (at your option) any later version.
#
#    This program 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 this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import errno
import getopt
import mailpie.swishfilter
import mailpie.log
import os
import sha
import sys
import tempfile
import time

def usage(result=0):
    print """mailpie-add: Add messages to a mailpie storage area
Usage: %s [-B dir] [-i|-n] [file ...]
    -B dir, --base=dir  Choose base location of the mailpie storage.
                        Default: $HOME/.mailpie

    -i, --index         Add messages to the index (default)
    -n, --no-index      Do not add messages to the index 

    file:               Unix mailbox file(s) to add.
                        Default: index mailbox on standard input
""" % os.path.basename(sys.argv[0])
    raise SystemExit, result


def Open(f):
    if not isinstance(f, str): return f
    if f == "-": return sys.stdin
    return open(f)

def split(mbox):
    mbox = Open(mbox)
    result = []
    for line in mbox:
        if line.startswith("From "):
            if result:
                yield result
            result = []
        result.append(line)
    if result:
        yield result    

def make_dir_once(dir, made=set()):
    if dir in made: return
    try:
        os.makedirs(dir)
    except os.error, detail:
        if detail.errno != errno.EEXIST: raise os.error, detail
    made.add(dir)

def store(base, content):
    sys.stderr.write("."); sys.stderr.flush()
    hash = sha.new(content).hexdigest()
    dir = os.path.join(base, hash[:2])
    file = os.path.join(base, hash[:2], hash[2:])
    if os.path.exists(file):
        mailpie.log.log("Duplicate message with hash", hash)
        return file, hash
    make_dir_once(dir)
    fd, temp = tempfile.mkstemp(dir=dir)
    os.write(fd, content)
    os.close(fd)
    try:
        os.rename(temp, file)
    except os.error, detail:
        try:
            os.unlink(temp)
        except os.error:
            mailpie.log.log("Failed to unlink temporary", temp)
        if detail.errno != errno.EEXIST:
            raise os.error, detail
    return file, hash

def add(base, mailbox, swish):
    count = 0
    for message in split(mailbox):
        count += 1
        message = "".join(message)
        filename, key = store(base, message)
        if swish:
            swish.do_one(filename, key, message)
    return count

def format_time(s):
    if s < 60: return "%.1fs" % s
    if s < 3600: return "%d:%04.1f" % (int(s/60), s%60)
    return "%d:%02d:%04.1f" % (int(s/3600), int(s/60)%60, s%60)

def main(args):
    try:
        opts, args = getopt.getopt(args, "Bin:h?", ["help", "base=", "index", "no-index"])
    except getopt.GetoptError, detail:
        usage(detail)

    base = os.path.expanduser("~/.mailpie")
    swish = True

    for k, v in opts:
        if k in ("-?", "-h", "--help"): usage(0)
        if k in ("-B", "--base"): base = v
        if k in ("-n", "--no-index"): swish = False
        if k in ("-i", "--index"): swish = True

    if swish: swish = mailpie.swishfilter.Swish(base, True)

    args = args or ["-"]
    count = 0
    start = time.time()
    try:
        for filename in args:
            sys.stderr.write(filename)
            count += add(base, filename, swish)
            sys.stderr.write("\n")
    finally:
        if swish:
            swish.close()
    end = time.time()
    mailpie.log.progress("Added %d messages in %s (%.1f messages/second)\n",
                        count, format_time(end - start), count / (end-start))
if __name__ == '__main__':
    main(sys.argv[1:])
