#!/usr/local/bin/python2.7
# -*- coding: utf-8; indent-tabs-mode: nil -*-

import os
import sys
import locale
import MAPI
from MAPI.Util import *
from MAPI.Time import *
from MAPI.Struct import *
import inetmapi

# @todo add ignore empty recipients
sopt = inetmapi.sending_options()
sopt.no_recipients_workaround = True
sopt.add_received_date = True
dopt = inetmapi.delivery_options()
verbose = False

class emptyCompany: pass

def CheckUser(store, abook):
    abeid = store.GetProps([PR_MAILBOX_OWNER_ENTRYID], 0)
    user = abook.OpenEntry(abeid[0].Value, None, 0)
    enabled = user.GetProps([PR_EC_ENABLED_FEATURES], 0)
    return enabled[0].Value.index('imap')

def OpenUser(session, store, username):
    admin = store.QueryInterface(IID_IExchangeManageStore)
    userEntryID = admin.CreateStoreEntryID('', username, 0)
    return session.OpenMsgStore(0, userEntryID, None, MDB_WRITE | MDB_NO_DIALOG)

def GetCompanyList(store):
    service = store.QueryInterface(IID_IECServiceAdmin)
    try:
        return service.GetCompanyList(0)
    except:
        company = emptyCompany()
        company.Companyname = 'Default'
        company.CompanyID = None
        return [company]

def GetUserList(store, company):
    service = store.QueryInterface(IID_IECServiceAdmin)
    try:
        return service.GetUserList(company, 0)
    except:
        return []

def ProcessMessage(session, envPropTag, message):
    rfc822 = inetmapi.IMToINet(session, None, message, sopt)
    (envelope, body, bodystructure) = inetmapi.createIMAPProperties(rfc822)
    message.SetProps([SPropValue(PR_EC_IMAP_EMAIL, rfc822), SPropValue(PR_EC_IMAP_EMAIL_SIZE, len(rfc822)),
                      SPropValue(PR_EC_IMAP_BODY, body), SPropValue(PR_EC_IMAP_BODYSTRUCTURE, bodystructure),
                      SPropValue(envPropTag, envelope)])
    message.SaveChanges(0)

def ProcessFolder(session, envPropTag, folder):
    content = folder.GetContentsTable(0)
    content.SetColumns([PR_ENTRYID, PR_SUBJECT], MAPI_DEFERRED_ERRORS)
    content.Restrict(SNotRestriction(SExistRestriction(PR_EC_IMAP_EMAIL_SIZE)), MAPI_DEFERRED_ERRORS)
    while True:
        try:
            rows = content.QueryRows(100, 0)
        except MAPIError, err:
            break
        if rows == []:
            break
        for row in rows:
            if verbose: print '      Processing \'%s\'' % row[1].Value
            try:
                message = folder.OpenEntry(row[0].Value, None, MAPI_MODIFY)
            except MAPIError, err:
                if verbose: print '        Unable to open message \'%s\', error 0x%08X' % (row[1].Value, err.hr)
                continue
            try:
                ProcessMessage(session, envPropTag, message)
            except MAPIError, err:
                if verbose: print '        Error in message: 0x%08X' % err.hr
                if err.hr == MAPI_E_STORE_FULL:
                    raise err

def ProcessStore(session, store):
    try:
        subtreeEID = store.GetProps([PR_IPM_SUBTREE_ENTRYID], 0)
        if PROP_TYPE(subtreeEID[0].ulPropTag) == PT_ERROR:
            raise Exception('not found')
    except:
        if verbose: print '    No IPM SUBTREE'
        return
    subtree = store.OpenEntry(subtreeEID[0].Value, None, 0)

    # prop 1: dispidIMAPEnvelope
    prop = store.GetIDsFromNames([MAPINAMEID(PS_EC_IMAP, MNID_ID, 1)], MAPI_CREATE)
    prop[0] = CHANGE_PROP_TYPE(prop[0], PT_STRING8)
    
    table = subtree.GetHierarchyTable(CONVENIENT_DEPTH)
    # not exists PR_CONTAINER_CLASS or PR_CONTAINER_CLASS 'IPF.Note'
    restriction = SOrRestriction([
        SNotRestriction(SExistRestriction(PR_CONTAINER_CLASS)),
        SPropertyRestriction(RELOP_EQ, PR_CONTAINER_CLASS, SPropValue(PR_CONTAINER_CLASS, 'IPF.Note'))
        ])
    table.Restrict(restriction, MAPI_DEFERRED_ERRORS)
    table.SetColumns([PR_ENTRYID, PR_DISPLAY_NAME], MAPI_DEFERRED_ERRORS)
    rows = table.QueryRows(-1, 0)
    for row in rows:
        if verbose: print '    Processing folder %s' % (row[1].Value)
        try:
            folder = store.OpenEntry(row[0].Value, None, MAPI_MODIFY)
            ProcessFolder(session, prop[0], folder)
        except MAPIError, err:
            if verbose: print '    Error in folder: 0x%08X' % err.hr
            if err.hr == MAPI_E_STORE_FULL:
                raise err


# main()
try:
    if sys.argv[1] == '-v':
        verbose = True
except: pass

locale.setlocale(locale.LC_CTYPE, '')
session = OpenECSession('SYSTEM', '', os.getenv('ZARAFA_SOCKET', 'file:///var/run/zarafa'))
admin = GetDefaultStore(session)
abook = session.OpenAddressBook(0, None, MAPI_UNICODE)

companies = GetCompanyList(admin)
for company in companies:
    print 'Processing ' + company.Companyname
    users = GetUserList(admin, company.CompanyID)
    for user in users:
        if user.Username == 'SYSTEM':
            continue
        print '  Processing ' + user.Username
        try:
            ustore = OpenUser(session, admin, user.Username)
        except MAPIError, err:
            print '    Failed to open store: 0x%08X' % err.hr
            continue
        try:
            CheckUser(ustore, abook)
        except Exception:
            print '    IMAP feature disabled, skipping'
            continue
        try:
            ProcessStore(session, ustore)
        except MAPIError, err:
            if err.hr == MAPI_E_STORE_FULL:
                print '    Store Quota reached, unable to continue'
            else:
                print '    Error while processing: 0x%08X' % err.hr
            continue
