#!/usr/local/bin/python2.7

import os
import locale
import sys
import getopt
import datetime
import time
import json

try:
    import MAPI
    from MAPI.Util import *
    from MAPI.Time import *
    from MAPI.Struct import *
except ImportError, e:
    print "Not all modules can be loaded. The following modules are required:"
    print "- MAPI (Zarafa)"
    print ""
    print e
    sys.exit(1) 

PR_EC_OUTOFOFFICE                   = PROP_TAG(PT_BOOLEAN,    PR_EC_BASE+0x60)
PR_EC_OUTOFOFFICE_MSG               = PROP_TAG(PT_TSTRING,    PR_EC_BASE+0x61)
PR_EC_OUTOFOFFICE_SUBJECT           = PROP_TAG(PT_TSTRING,    PR_EC_BASE+0x62)
PR_EC_OUTOFOFFICE_FROM              = PROP_TAG(PT_SYSTIME,    PR_EC_BASE+0x63)
PR_EC_OUTOFOFFICE_UNTIL             = PROP_TAG(PT_SYSTIME,    PR_EC_BASE+0x64)

MODE_ENABLE = 1
MODE_DISABLE = 2
MODE_UPDATE_ONLY = 3

def print_help():
    print "Usage: %s -u [username of mailbox]" % sys.argv[0]
    print ""
    print "Manage out of office messages of users"
    print ""
    print "Required arguments:"
    print "   -u, --user          user to set out of office message for"
    print "   -m, --mode          0 to disable out of office (default), 1 to enable"
    print ""
    print "optional arguments:"
    print "   --from              specify the date/time when oof should become active"
    print "   --until             specify the date/time when oof should become inactive again"
    print "   -t, --subject       specify the subject to be set in oof message"
    print "   -n, --message       text file containing body of out of office message"
    print "   -h, --host          Host to connect with. Default: file:///var/run/zarafad/server.sock"
    print "   -s, --sslkey-file   SSL key file to authenticate as admin."
    print "   -p, --sslkey-pass   Password for the SSL key file."
    print "   --dump-json         Dumps the current status as JSON."
    print "   --help              Show this help message and exit."
    print ""
    print ""
    print "Example:"
    print " Enable out of office message of mailbox user1 with subject 'test' and body from file /tmp/oof-message"
    print "  $ %s --user user1 --mode 1 --subject 'test' --message /tmp/oof-message" % sys.argv[0]
    print ""
    print " Enable out of office message of mailbox user1 with subject 'test' and body from file /tmp/oof-message in a multi-server-environment"
    print "  $ %s --user user1 --mode 1 --subject 'test' --message /tmp/oof-message --host https://127.0.0.1:237/zarafa --sslkey-file /etc/zarafa/ssl/client.pem --sslkey-pass password" % sys.argv[0]
    print ""
    print " Disable out of office message of mailbox user1 in a multi-server-environment"
    print "  $ %s --user user1 --mode 0 --sslkey-file /etc/zarafa/ssl/client.pem --host https://127.0.0.1:237/zarafa --sslkey-pass password" % sys.argv[0]

def PrintSubject(subject):
    if subject.ulPropTag == PR_EC_OUTOFOFFICE_SUBJECT:
        print "Current subject: '%s'" % subject.Value
    else:
        print "Current subject: No subject set"
    
def main(argv = None):
    if argv is None:
        argv = sys.argv

    try:
        opts, args = getopt.gnu_getopt(argv, "h:s:p:u:m:t:n:he", ['from=', 'until=', 'host=', 'sslkey-file=', 'sslkey-pass=', 'user=', 'mode=', 'subject=', 'message=', 'dump-json', 'help', ])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err)
        print ""
        print_help()
        return 1

    # defaults
    host = os.getenv("ZARAFA_SOCKET", "default:")
    sslkey_file = None
    sslkey_pass = None
    mode = MODE_UPDATE_ONLY
    date_from = None
    date_until = None
    username = None 
    subject = None
    message = None

    dump_json = False
    
    for o, a in opts:
        if o in ('-h', '--host'):
            host = a
        elif o in ('-s', '--sslkey-file'):
            sslkey_file = a
        elif o in ('-p', '--sslkey-pass'):
            sslkey_pass = a
        elif o in ('-u', '--user'):
            username = a
        elif o in ('-m', '--mode'):
            if a == '-':
                mode = MODE_UPDATE_ONLY
            elif a == '1':
                enabled = True
                mode = MODE_ENABLE
            else:
                enabled = False
                mode = MODE_DISABLE
        elif o == "--from":
            date_from = datetime.datetime.strptime(a, "%Y-%m-%d %H:%M")
        elif o == "--until":
            date_until = datetime.datetime.strptime(a, "%Y-%m-%d %H:%M")
        elif o in ('-t', '--subject'):
            subject = a
        elif o in ('-n', '--message'):
            message = a
        elif o == '--dump-json':
            dump_json = True
        elif o == '--help':
            print_help()
            return 0
        else:
            assert False, ("unhandled option '%s'" % o)

    if not username:
        print "No username specified."
        print ""
        print_help()
        sys.exit(1)

    try:
        session = OpenECSession(username, '', host, sslkey_file = sslkey_file, sslkey_pass = sslkey_pass)
    except MAPIError, err:
        if err.hr == MAPI_E_LOGON_FAILED:
            print "Failed to logon. Make sure your SSL certificate is correct."
        elif err.hr == MAPI_E_NETWORK_ERROR:
            print "Unable to connect to server. Make sure you specified the correct server."
        else:
            print "Unexpected error occurred. hr=0x%08x" % err.hr
        sys.exit(1)

    try:
        st = GetDefaultStore(session)
    except:
        print "Unable to open store for user '%s'" % username

    try:
        oldstatus = st.GetProps([PR_EC_OUTOFOFFICE], 0)[0].Value
        if oldstatus == MAPI_E_NOT_FOUND:
            oldstatus = False
    except Exception:
        print "Unable to read out of office status of user '%s'" % username

    try:
        oldsubject = st.GetProps([PR_EC_OUTOFOFFICE_SUBJECT], 0)[0].Value
        if oldsubject == MAPI_E_NOT_FOUND:
            oldsubject = None

    except Exception:
        print "Unable to read out of office subject of user '%s'" % username

    try:
        oldmsg = st.GetProps([PR_EC_OUTOFOFFICE_MSG], 0)[0].Value
        if oldmsg == MAPI_E_NOT_FOUND:
            oldmsg = None
    except Exception:
        print "Unable to read out of office message of user '%s'" % username

    if dump_json:
        result = json.dumps({'set': bool(oldstatus), 'subject': oldsubject, 'message': oldmsg})
        print(result)
        sys.exit(0)

    if mode != MODE_UPDATE_ONLY:
        try:
            if oldstatus == enabled and not enabled:
                print "Out of office for user '%s' already disabled, skipping." % username
            elif enabled:
                st.SetProps([SPropValue(PR_EC_OUTOFOFFICE, enabled)])
                if date_from and date_until:
                    t1 = MAPI.Time.FileTime(0)
                    t1.unixtime = time.mktime(date_from.timetuple())
                    t2 = MAPI.Time.FileTime(0)
                    t2.unixtime = time.mktime(date_until.timetuple())
                    p1 = SPropValue(PR_EC_OUTOFOFFICE_FROM, t1)
                    p2 = SPropValue(PR_EC_OUTOFOFFICE_UNTIL, t2)
                    st.SetProps([p1, p2])
                else:
                    st.DeleteProps([PR_EC_OUTOFOFFICE_FROM, PR_EC_OUTOFOFFICE_UNTIL])
                print "Out of office enabled for user '%s'" % username
            else:
                st.SetProps([SPropValue(PR_EC_OUTOFOFFICE, enabled)])
                print "Out of office disabled for user '%s'" % username
        except:
            print "Unable to set out of office for user '%s'" % username
            raise

    if mode != MODE_DISABLE:
        if date_from and date_until:
            try:
                t1 = MAPI.Time.FileTime(0)
                t1.unixtime = time.mktime(date_from.timetuple())
                t2 = MAPI.Time.FileTime(0)
                t2.unixtime = time.mktime(date_until.timetuple())
                p1 = SPropValue(PR_EC_OUTOFOFFICE_FROM, t1)
                p2 = SPropValue(PR_EC_OUTOFOFFICE_UNTIL, t2)
                st.SetProps([p1, p2])
            except:
                print "Unable to update OOF date restriction for user '%s'" % username
                raise

        if subject:
            try:
                if oldsubject == subject:
                    print "Not changing subject for user '%s' as it was not updated" % username
                else:
                    print "Setting new subject '%s' for user '%s'" % (subject, username)
                    st.SetProps([SPropValue(PR_EC_OUTOFOFFICE_SUBJECT, subject)])
            except:
                print "Unable to set out of office subject for user '%s'" % username

            newsubject = st.GetProps([PR_EC_OUTOFOFFICE_SUBJECT], 0)
            PrintSubject(newsubject[0])

        if message:
            try:
                f = open(message, 'rt')
            except IOError:
                print "The specified file '%s' does not exist - Please specify a valid message file." % message
                sys.exit(1)

            msg = f.read()
            f.close()
            try:
                if oldmsg == msg:
                    print "Not updating message, already matching with input file."
                else:
                    print "Setting new out of office message for user '%s'" % username
                    st.SetProps([SPropValue(PR_EC_OUTOFOFFICE_MSG, msg)])
            except:
                print "Unable to set out of office message."


if __name__ == '__main__':
    locale.setlocale(locale.LC_ALL, '')
    sys.exit(main())
