#!/usr/bin/env python
# -*- mode: python -*-
import userdir_gpg, userdir_ldap, sys, traceback, time, ldap, os, getopt;
import pwd
import email, email.parser
from userdir_gpg import *;
from userdir_ldap import *;

EX_TEMPFAIL = 75;
EX_PERMFAIL = 65;      # EX_DATAERR
Debug = None;

# Try to extract a key fingerprint from a PGP siged message
def TryGPG(mail):
   # Try to get a pgp text
   try:
      Msg = GetClearSig(mail, lax_multipart=True);
   except:
      # Log an exception.. but continue. This is to deal with 'sort of' 
      # PGP-MIME things
      S = "%s: %s -> %s\n" %(Now,MsgID,ErrMsg);
      S = S + " %s: %s\n" %(sys.exc_type,sys.exc_value);
      ErrLog.write(S);
      return None;

   if Msg[0].find("-----BEGIN PGP SIGNED MESSAGE-----") == -1:
      return None;

   pgp = GPGCheckSig2(Msg[0]);

   # Failed to find a matching sig
   if not pgp.ok:
      S = "%s: %s -> PGP Checking failed '%s': %s %s\n" %(Now,MsgID,mail["From"],str(pgp.why),str(pgp.key_info));
      ErrLog.write(S);
      return None;
      
   # Search for the matching key fingerprint
   Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyFingerPrint=" + pgp.key_fpr);
   if len(Attrs) == 0:
      return None;
   if len(Attrs) != 1:
      raise Error, "Oddly your key fingerprint is assigned to more than one account.."
   
   return (Attrs[0][1]["uid"][0],"PGP",FormatPGPKey(pgp.key_fpr));

# Try to guess the name from the email address
def TryMatcher(mail):
   Sender = mail["From"];
   if Sender == None:
      return None;
      
   # Split up the address and invoke the matcher routine
   UID = GetUID(l,SplitEmail(Sender));
   
   if UID[0] == None:
      if UID[1] == None or len(UID[1]) == 0:
         return None;

      # Print out an error message
      S = "%s: %s -> Address matching failed '%s'\n" %(Now,MsgID,Sender);
      for x in UID[1]:
         S = S + " " + x + "\n";
      ErrLog.write(S);
      return None;
    
   return (UID[0],"FROM",Sender);

# Process options
(options, arguments) = getopt.getopt(sys.argv[1:], "dr")
for (switch, val) in options:
   if (switch == '-d'):
      Debug = "";
   
# Open the log files
if Debug == None:
   MainLog = open(Ech_MainLog,"a+",0);
   ErrLog = open(Ech_ErrorLog,"a+",0);
else:
   MainLog = open("/dev/stdout","a+",0);
   ErrLog = open("/dev/stdout","a+",0);
   
# Start of main program
ErrMsg = "Indeterminate Error";
ErrType = EX_TEMPFAIL;
Now = time.strftime("%a, %d %b %Y %H:%M:%S",time.gmtime(time.time()));
MsgID = None;
try:
   # Get the email 
   ErrType = EX_PERMFAIL;
   ErrMsg = "Failed to understand the email or find a signature:";
   mail = email.parser.Parser().parse(sys.stdin);
   MsgID = mail["Message-ID"]

   # Connect to the ldap server
   ErrType = EX_TEMPFAIL;
   ErrMsg = "An error occured while performing the LDAP lookup";
   global l;
   l = connectLDAP()
   if Debug == None:
      F = open(PassDir+"/pass-"+pwd.getpwuid(os.getuid())[0],"r");
      AccessPass = F.readline().strip().split(" ")
      l.simple_bind_s("uid="+AccessPass[0]+","+BaseDn,AccessPass[1]);
      F.close();
   else:
      l.simple_bind_s("","");

   # Try to decode
   ErrType = EX_TEMPFAIL;
   ErrMsg = "An error occured while trying GPG decoding";
   User = TryGPG(mail);
   if User == None:
      ErrMsg = "An error occured while trying Matcher decoding";
      User = TryMatcher(mail);

   # Get any mailing list information   
   List = mail['X-Mailing-List']
   if not List: List = "-";

   # Tada, write a log message
   if User != None:
      Msg = "[%s] \"%s\" \"%s\" \"%s\""%(Now,User[2],List,MsgID);
      MainLog.write("%s %s %s\n"%(User[0],User[1],Msg));
      Dn = "uid=" + User[0] + "," + BaseDn;
      Rec = [(ldap.MOD_REPLACE,"activity-%s"%(User[1]),Msg)];
      if Debug == None:
         l.modify_s(Dn,Rec);
      else:
         print Rec;
   else:
      User = ("-","UKN",mail["From"]);
      Msg = "[%s] \"%s\" \"%s\" \"%s\""%(Now,User[2],List,MsgID);
      MainLog.write("%s %s %s\n"%(User[0],User[1],Msg));

except:
   # Log an exception..
   S = "%s: %s -> %s\n" %(Now,MsgID,ErrMsg);
   S = S + "==> %s: %s\n" %(sys.exc_type,sys.exc_value);
   List = traceback.extract_tb(sys.exc_traceback);
   if len(List) > 1:
      for x in List:
         S = S + "   %s %s:%u: %s\n" %(x[2],x[0],x[1],x[3]);
   ErrLog.write(S);
   sys.exit(ErrType);
   
sys.exit(0);
