#!/usr/bin/python

# rmmail 0.0.1 (21 Feb 2002)
# Copyright (c) 2002 Hans-Georg Eer <h.g.esser@gmx.de>
#
# 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

import sys
from string import split
from re import match
import readline
from os import mkdir,environ
from os.path import isdir
# import ConfigParser
from gtk import *
from gnome.ui import *
from GDK import *
from libglade import *


# BEGIN flags
deb_flag=0
verbose_flag=0
# END flags


# BEGIN init
def init():
    global fname, homedir
    try: homedir=environ["HOME"]
    except: homedir="/tmp"
    try: localmail=environ["MAIL"]
    except: localmail=""
    if len(sys.argv) > 2: print ("rmmail: Call with one or no argument."); sys.exit(1)
    if len(sys.argv) == 2:
        fname = sys.argv[1]
        if fname in ["-h","-H","--help"]:
            print """Syntax: rmmail [mailfolder]
Remove mails quickly.
If called without any arguments, rmmail tries to open the
users' incoming mail folder as set in $MAIL. rmmail knows
no arguments."""; sys.exit()            
    else:
        fname = localmail
# END init

# BGEIN debug
def debug(mesg):
    if deb_flag: print "debug:",mesg
# END debug


# BEGIN analyze
def analyze(filename):
    global lines, nummails, numberformat
    try: mbox=open(filename)
    except: print "rmmail: Could not open "+filename; sys.exit(1)
    
    lines=mbox.readlines()
    numlines=len(lines)
    mails=[]
    mail=-1
    i=0
    while i<=numlines:
        if i<numlines:
            line=lines[i]
        else:
            line=-1
        if line == -1 or line[:5] == "From ":
            mail=mail+1
            if i>0:
                end=i-1
                if verbose_flag:
                    print "MailNr: ", mail
                    print "Anfang: ", start
                    print "Ende:   ", end
                    print "From:   ", frm
                    print "To:     ", to
                    print "Subject:", sub
                    print
                mails.append([mail,1,start,end,frm,to,sub])
                
            start=i
            # search this message
            to_seek,from_seek,sub_seek=1,1,1
            while (to_seek or from_seek or sub_seek) and i<numlines-1:
                i=i+1
                if i >= numlines: debug("end of file")
                line=lines[i]
                if line[:5] == "From:":
                    frm=line[6:-1]
                    from_seek=0
                    debug("From found")
                if line[:3] == "To:":
                    to=line[4:-1]
                    to_seek=0
                    debug("To found")
                if line[:8] == "Subject:":
                    sub=line[9:-1]
                    sub_seek=0
                    debug("subject found")
                # handle possible "header missing" problem
                if line[:5] == "From ":
                    debug("Not complete")
                    if from_seek: frm="<No Sender>"; from_seek=0
                    if to_seek:   to ="<No Recipient>"; to_seek=0
                    if sub_seek:  sub="<No Subject>"; sub_seek=0
                    i=i-1
            # all headers read; now skip to end
            debug("2nd stage")
        i=i+1    
    mbox.close()
    nummails=mail
    if   nummails<10: numberformat="%1d"
    elif nummails>=10   and nummails<100:   numberformat="%2d"
    elif nummails>=100  and nummails<1000:  numberformat="%3d"
    elif nummails>=1000 and nummails<10000: numberformat="%4d"
    if verbose_flag: print "# Mails:", nummails
    return mails
# END analyze


# BEGIN simple_output
def simple_output(mail):
    clist = wTree.get_widget("clist")
    if mail[1]: xTag="x"
    else: xTag=""
    numstr=str(mail[0])
    clist.append([numstr,xTag,mail[4],mail[5],mail[6]])

    #print numberformat % (mail[0]),
    #if mail[1]: print "[x] ",
    #else: print "[ ] ",
    #print "%-20s -> %-15s : %-30s" % (mail[4][:20],mail[4][:15],mail[6][:30])
# END simple_output


# BEGIN list
def list():
    global clist
    clist = wTree.get_widget("clist")
    clist.clear()
    for m in mails:
        simple_output(m)
    if len(mails) == 0: print "No mail."
# END list


# BEGIN preparse
def preparse(args):
    removelist=[]
    for arg in args:
        try:
            arg_int=int(arg)
            if arg_int<1 or arg_int>nummails: print "Non-existent Mail:",arg; removelist.append(arg)
        except:
            if match("[0-9]+-[0-9]+",arg):
                [num1,num2]=split(arg,"-")
                num1=int(num1); num2=int(num2)
                if num1>num2:
                    print "Wrong order in range",num1,"-",num2
                    removelist.append(arg)
                else:
                    for i in range(num1,num2+1):
                        if i in range(1,nummails+1): args.append(i)
                    removelist.append(arg)
            else: print "Wrong syntax."
    for arg in removelist:
        args.remove(arg)
    return
# ENDE preparse


# BEGIN delete_one
def delete_one(number):
    try:
        mails[number-1][1]=0
        clist = wTree.get_widget("clist")
        clist.set_text(number-1,1,"")
        clist.show()
    except: print "Wrong Mail number",number-1
# END delete_one

# BEGIN delete
def delete(args):
    preparse(args)
    for arg in args:
        if verbose_flag: print "deleting", int(arg)
        delete_one(int(arg))
# END delete


# BEGIN undelete_one
def undelete_one(number):
    mails[number-1][1]=1
# END undelete_one

# BEGIN undelete
def undelete(args):
    preparse(args)
    for arg in args:
        print "undeleting", int(arg)
        undelete_one(int(arg))
# END undelete


# BEGIN write
def write():
    global mails
    out=open(fname,"w")
    if not isdir(homedir+"/.rmmail"): mkdir(homedir+"/.rmmail")
    deleted=open(homedir+"/.rmmail/deleted.mails","a")
    delno=0; saveno=0
    for mail in mails:
        if mail[1]:
            saveno=saveno+1
            for i in range(mail[2],mail[3]+1):
                out.write(lines[i]),
        else:
            delno=delno+1
            for i in range(mail[2],mail[3]+1):
                deleted.write(lines[i]),
    out.close()
    deleted.close()
    print delno,"Mails deleted; saved in "+homedir+"/.rmmail/deleted.mails"
    print saveno,"Mails saved in "+fname
    mails=analyze(fname)
    print fname+" reopened"
# END write


# BEGIN info
def info():
    print "Mail file: "+fname+" ("+str(nummails)+")"

# END info


# BEGIN interact
def interact():
    cmd=""
    while cmd <> "q":
        cmd_input = raw_input ("rmmail["+fname+"/"+str(nummails)+"]: ")
        cmdsplit = split(cmd_input, " ")
        cmd = cmdsplit[0]
        args = cmdsplit[1:]
        # selection of command
        if   cmd == "l": list()
        elif cmd == "i": info()
        elif cmd in ["h","H","?","help"]: print """rmmail help:
  l  list mails
  i  information
  o  open new mail folder
  d  delete mail(s)
  u  undelete mail(s)
  w  write (save changes)
  q  quit (ignore changes)
  h  show this help
Checked files [x] remain intact; unchecked files [ ] will
be deleted when a write command is issued."""
        elif cmd == "d": delete(args)
        elif cmd == "u": undelete(args)
        elif cmd == "o": print "open", args[0]; analyze(args[0])
        elif cmd == "w": write()
        elif cmd == "q": print "Exiting."
        elif cmd == "":  cmd=""
        else: print "Unknown command",cmd,"- try h for help."
# END interact


# BEGIN main
#try:
#    init()
#    mails=analyze(fname)
#    list()
#    if len(mails) == 0: sys.exit()
#    interact()
#except KeyboardInterrupt:
#    # Catch Ctrl-C and terminate properly
#    print "\nrmmail terminates (ctrl-c). No changes made since last 'write'."
# END main

def set_status(msg):
    status=wTree.get_widget("status")
    status.set_text(" "+msg)

def on_open1_activate(x):
    print "File/Open"
    clist = wTree.get_widget("clist")
    clist.append(["H","I","J","K","L"])
 
def on_save_changes1_activate(x):
    print "File/Save"
    write()
    list()

def delete_them(x):
    clist = wTree.get_widget("clist")
    sel = clist.selection
    # print "delete!!!"
    for i in sel:
        clist.set_text(i,1,"")
        mails[i][1]=0
    clist.show()

def undelete_them(x):
    clist = wTree.get_widget("clist")
    sel = clist.selection
    # print "undelete!!!"
    for i in sel:
        clist.set_text(i,1,"x")
        mails[i][1]=1
    clist.show()

def on_key_pressed(a,event):
    clist = wTree.get_widget("clist")
    sel = clist.selection
    # print sel
    key=event.keyval
    if key == 100:                 # "d" pressed; delete
        delete_them(0)
    elif key == 117:               # "u" pressed; undelete
        undelete_them(0)
    # else: print "Key", key

def on_clist_selection_get(a,b):
    print "click"

def on_select_all_activate(x):
    clist = wTree.get_widget("clist")
    clist.select_all()
    print "select all"

def on_reverse1_activate(x):
    clist = wTree.get_widget("clist")
    sel = clist.selection
    for i in range(0,len(mails)):
        if i in sel:
            clist.unselect_row(i,0)
        else:
            clist.select_row(i,1)
    print "select reverse"

def on_command_return(x):
    commandline = wTree.get_widget("commandline")
    cmd_input = commandline.get_text()
    commandline.set_text("")
    print "send clicked, cmd:", cmd_input
    cmdsplit = split(cmd_input, " ")
    cmd = cmdsplit[0]
    args = cmdsplit[1:]
    # selection of command
    if   cmd == "l": list(); set_status("OK")
    elif cmd == "i": info(); set_status("OK")
    elif cmd in ["h","H","?","help"]:
        cmdline = wTree.get_widget("cmdhelp")
        cmdline.show()
        set_status("OK")
        print """rmmail help:
  l  list mails
  i  information
  o  open new mail folder
  d  delete mail(s)
  u  undelete mail(s)
  w  write (save changes)
  q  quit (ignore changes)
  h  show this help
Checked files [x] remain intact; unchecked files [ ] will
be deleted when a write command is issued."""
        
    elif cmd == "d": delete(args); set_status("OK")
    elif cmd == "u": undelete(args); set_status("OK")
    elif cmd == "o": print "open", args[0]; analyze(args[0]); set_status("OK")
    elif cmd == "w": write(); set_status("OK")
    elif cmd == "q": print "Exiting."; set_status("OK")
    elif cmd == "":  cmd=""; set_status("OK")
    else:
        print "Unknown command",cmd,"- try h for help."
        set_status ("No such command: "+cmd)

def on_cmdline_ok_button_clicked(x):
    cmdline = wTree.get_widget("cmdhelp")
    cmdline.hide()

def on_use_commandline1_activate(x):
    commandline=wTree.get_widget("commandline")
    commandline.focus()

def on_fileopen_activate(x):
    #fileselection = wTree.get_widget("fileselection")

    def on_ok_button1_clicked(x):
        fname = fileselection.get_filename()
        print "Open:", fname
        analyze (fname)
        list()
        wTree.get_widget("rmmailApp").set_title ("rmmail: "+fname)
        fileselection.destroy()
        
    def on_cancel_button1_clicked(x):
        fileselection.destroy()

    global fileselection
    fs = GladeXML ("rmmail.glade", "fileselection")
    fileselection = fs.get_widget("fileselection")
    fileselection.set_filename(homedir+"/")
    fileselection.hide_fileop_buttons()
    # fileselection.cwd("/home")
    fileselection.show()
    fs.signal_autoconnect({
        "on_ok_button1_clicked": on_ok_button1_clicked,
        "on_cancel_button1_clicked": on_cancel_button1_clicked,
        "gtk_widget_destroy": on_cancel_button1_clicked})
    
def initRmmail ():
    global rootGroup, wTree
    wTree = GladeXML ("rmmail.glade") #,
#                     "rmmailApp")
    dic = {"on_open1_activate": on_open1_activate,
           "on_quit1_activate": mainquit,
           "on_command_return": on_command_return,
           "on_key_pressed": on_key_pressed,
           "on_clist_selection_get": on_clist_selection_get,
           "on_select_all_activate": on_select_all_activate,
           "on_reverse1_activate": on_reverse1_activate,
           "on_use_commandline1_activate": on_use_commandline1_activate,
           "on_Send_clicked": on_command_return,
           # "on_cmdline_ok_button_clicked": on_cmdline_ok_button_clicked,
           "on_delete_them1_activate": delete_them,
           "on_undelete_them1_activate": undelete_them,
           "on_fileopen_activate": on_fileopen_activate,
           "on_save_changes1_activate": on_save_changes1_activate}
    wTree.signal_autoconnect (dic)
    #canvas = wTree.get_widget ("rmmailApp")
    #rootGroup = canvas.root ()

initRmmail ()
try:
    init ()
    mails=analyze(fname)
    list()
except KeyboardInterrupt:
    # Catch Ctrl-C and terminate properly
    print "\nrmmail terminates (ctrl-c). No changes made since last 'write'."

mainloop ()
