#!/usr/bin/python

import MAPI
from MAPI.Util import *
from MAPI.Tags import *
from MAPI.Util.Generators import *

import sys, os, getopt
import zarafa_msr.config as config

CORRECT = False

def GetEidList(folder):
    t = folder.GetContentsTable(0)
    t.SetColumns([PR_ENTRYID], 0)
    eids = {}
    while True:
        rows = t.QueryRows(200, 0)
        if len(rows) == 0:
            break
        for row in rows:
            eids[row[0].Value] = 1
            
    return eids

def Verify(src, dst):
    srcEids = GetEidList(src)
    dstEids = GetEidList(dst)
    
    inSrc = []
    inDst = []
    
    for eid in dstEids.keys():
        if not srcEids.has_key(eid):
            inDst.append(eid)
            
    for eid in srcEids.keys():
        if not dstEids.has_key(eid):
            inSrc.append(eid)
            
    print 'Not in src: %d, not in dst: %d' % (len(inDst), len(inSrc))
    
    return (inDst, inSrc)
    

def print_help(out):
        print "Usage: %s [OPTIONS] config" % os.path.basename(sys.argv[0])
        print "OPTIONS:"
        print "  --correct\tAttempt to correct mismatches."
        print "  --help   \tShow this help message."
        print ""    

    

try:    
    opts, args = getopt.gnu_getopt(sys.argv[1:], '', ['correct', 'help'])
except getopt.GetoptError, err:
    print str(err)
    sys.exit(1)


for o, a in opts:
    if o == '--correct':
        CORRECT = True
    elif o == '--help':
        print_help(sys.stdout)
        sys.exit(0)
    else:
        assert False, 'Unhandled option'
        
if len(args) != 1:
    print >> sys.stderr, 'Exactly one configuration file must be provided.'
    print_help(sys.stderr)
    sys.exit(1)


try:
    cfg = config.Config(args[0])
except config.ConfigException, ce:
    print >> sys.stderr, str(ce)
    sys.exit(1)
    


try:
    srcSession = OpenECSession("SYSTEM", "", cfg.connection.get('serverpath', 'file:///var/run/zarafa'), **cfg.connection)
    srcAdminStore = GetDefaultStore(srcSession)
except MAPIError, err:
    print >> sys.stderr, 'Unable to open source admin store, please verify your configuration. hr=0x%08x' % err.hr
    sys.exit(1)

for user, server in ((x[0], x[1] % cfg.servers) for x in cfg.mapping):
    print '%s: Verifying...' % user
    
    try:
        dstSession = OpenECSession("SYSTEM", "", server, **cfg.connection)
        dstAdminStore = GetDefaultStore(dstSession)
    except MAPIError, err:
        print >> sys.stderr, 'Unable to open destination admin store, please verify your settings. hr=0x%08x' % err.hr
        sys.exit(1)     # This is bad enough to just abort

    iemsSrc = srcAdminStore.QueryInterface(IID_IExchangeManageStore)
    iemsDst = dstAdminStore.QueryInterface(IID_IExchangeManageStore)

    try:
        eidSrc = iemsSrc.CreateStoreEntryID(None, user, 0x10)
        srcStore = srcSession.OpenMsgStore(0, eidSrc, None, 0)
    except MAPIError, err:
        print >> sys.stderr, 'Unable to open source store for user \'%s\'. hr=0x%08x' % (user, err.hr)
        continue

    try:
        eidDst = iemsDst.CreateStoreEntryID(None, user, 0x10)
        dstStore = dstSession.OpenMsgStore(0, eidDst, None, MDB_WRITE)
    except MAPIError, err:
        print >> sys.stderr, 'Unable to open destination store for user \'%s\'. hr=0x%08x' % (user, err.hr)
        continue


    verified = True
    warning = False
    for (folder, depth) in GetFolders(srcStore):
        props = folder.GetProps([PR_DISPLAY_NAME, PR_ENTRYID, PR_FOLDER_TYPE], 0)
        if props[2].Value != FOLDER_GENERIC:
            continue
        try:
            dstFolder = dstStore.OpenEntry(props[1].Value, None, MAPI_MODIFY)
        except MAPIError, e:
            print "Destination folder '%s' not found" % props[0].Value
            verified = False
            continue
            
        (inDst, inSrc) = Verify(folder, dstFolder)
        if inDst or inSrc:
            print "Folder name %s" % props[0].Value
            if inSrc:
                print "%d messages in src that are not in dst for folder eid %s" % (len(inSrc), props[1].Value.encode('hex'))
                verified = False
            if inDst:
                print "%d messages in dst that are not in src for folder eid %s" % (len(inDst), props[1].Value.encode('hex'))
                if CORRECT:
                    print "Correcting %d dst messages .. " % (len(inDst))
                    dstFolder.DeleteMessages(inDst, 0, None, 0)
                else:
                    warning = True

    if verified:
        if warning:
            vstring = 'WARNING'
        else:
            vstring = 'OK'
    else:
        vstring = 'FAIL'
        
    print '%s: Verified: %s' % (user, vstring)
