/*
 * Copyright 2005 - 2009  Zarafa B.V.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3, 
 * as published by the Free Software Foundation with the following additional 
 * term according to sec. 7:
 *  
 * According to sec. 7 of the GNU Affero General Public License, version
 * 3, the terms of the AGPL are supplemented with the following terms:
 * 
 * "Zarafa" is a registered trademark of Zarafa B.V. The licensing of
 * the Program under the AGPL does not imply a trademark license.
 * Therefore any rights, title and interest in our trademarks remain
 * entirely with us.
 * 
 * However, if you propagate an unmodified version of the Program you are
 * allowed to use the term "Zarafa" to indicate that you distribute the
 * Program. Furthermore you may use our trademarks where it is necessary
 * to indicate the intended purpose of a product or service provided you
 * use it in accordance with honest practices in industrial or commercial
 * matters.  If you want to propagate modified versions of the Program
 * under the name "Zarafa" or "Zarafa Server", you may only do so if you
 * have a written permission by Zarafa B.V. (to acquire a permission
 * please contact Zarafa at trademark@zarafa.com).
 * 
 * The interactive user interface of the software displays an attribution
 * notice containing the term "Zarafa" and/or the logo of Zarafa.
 * Interactive user interfaces of unmodified and modified versions must
 * display Appropriate Legal Notices according to sec. 5 of the GNU
 * Affero General Public License, version 3, when you propagate
 * unmodified or modified versions of the Program. In accordance with
 * sec. 7 b) of the GNU Affero General Public License, version 3, these
 * Appropriate Legal Notices must retain the logo of Zarafa or display
 * the words "Initial Development by Zarafa" if the display of the logo
 * is not reasonably feasible for technical reasons."
 * 
 * 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 Affero General Public License for more details.
 *  
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

#ifndef COMMONUTIL_H
#define COMMONUTIL_H

#include <mapidefs.h>
#include <mapix.h>
#include <string>
#include "ECLogger.h"
#include "ECTags.h"


// Newmail Notify columns
const static SizedSPropTagArray(4, sPropNewMailColumns) =
{
	4,
	{
		PR_ENTRYID,
		PR_PARENT_ENTRYID,
		PR_MESSAGE_CLASS,
		PR_MESSAGE_FLAGS
	}
};

// Indexes of the sPropNewMailColumns property array
enum
{
	NEWMAIL_ENTRYID,		// Array Indexes
	NEWMAIL_PARENT_ENTRYID,
	NEWMAIL_MESSAGE_CLASS,
	NEWMAIL_MESSAGE_FLAGS,
	NUM_NEWMAIL_PROPS		// Array size
};

// Version of GetClientVersion
#define CLIENT_VERSION_OLK2000			9
#define CLIENT_VERSION_OLK2002			10
#define CLIENT_VERSION_OLK2003			11
#define CLIENT_VERSION_OLK2007			12

// The ucs2string type
// WARNING, this is different from wstring !
typedef std::basic_string<WCHAR> ucs2string;

// char_traits<WCHAR> is already present in win32
namespace std {

template<>
    struct char_traits<WCHAR>
    {
      typedef WCHAR	        char_type;
      typedef wint_t            int_type;
      typedef streamoff         off_type;
      typedef wstreampos        pos_type;
      typedef mbstate_t         state_type;

      static void
      assign(char_type& __c1, const char_type& __c2)
      { __c1 = __c2; }

      static bool
      eq(const char_type& __c1, const char_type& __c2)
      { return __c1 == __c2; }

      static bool
      lt(const char_type& __c1, const char_type& __c2)
      { return __c1 < __c2; }

      static int
      compare(const char_type* __s1, const char_type* __s2, size_t __n)
      { while(*__s1 != 0 && *__s2 != 0) { 
		if(*__s1 != *__s2) return *__s1 - *__s2;
		__s1++; __s2++;
	}
	if(*__s1 == 0 && *__s2 == 0) return 0;
	if(*__s1 != 0) return -1;
	return 1;
      }

      static size_t
      length(const char_type* __s)
      { int l = 0;
	while(*__s != 0) { l++; __s++; }
	return l; 
      }

      static const char_type* 
      find(const char_type* __s, size_t __n, const char_type& __a)
      { while(*__s != 0 && __n > 0) { 
	  if(*__s == __a) return __s; 
	__s++; __n--; 
	}
	return NULL;
      }

      static char_type* 
      move(char_type* __s1, const char_type* __s2, int_type __n)
      { return (WCHAR *)memmove((void *)__s1, (void *)__s2, __n*sizeof(WCHAR)); }

      static char_type* 
      copy(char_type* __s1, const char_type* __s2, size_t __n)
      { return (WCHAR *)memcpy((void *)__s1, (void *)__s2, __n*sizeof(WCHAR)); }

      static char_type* 
      assign(char_type* __s, size_t __n, char_type __a)
      { char_type *__o = __s;
	while(__n>0) {*__s = __a; __n--; __s++; }
	return  __o;
      }

      static char_type 
      to_char_type(const int_type& __c) { return char_type(__c); }

      static int_type 
      to_int_type(const char_type& __c) { return int_type(__c); }

      static bool 
      eq_int_type(const int_type& __c1, const int_type& __c2)
      { return __c1 == __c2; }

      static int_type 
      eof() { return static_cast<int_type>(WEOF); }

      static int_type 
      not_eof(const int_type& __c)
      { return eq_int_type(__c, eof()) ? 0 : __c; }
  };
}

/* darn, no sane place because of depend include on mapidefs.h */
bool operator ==(SBinary a, SBinary b);

#define CLIENT_ADMIN_SOCKET "file:///var/run/zarafa"
char* GetServerUnixSocket(char* szPreferred = NULL);

HRESULT HrOpenECAdminSession(IMAPISession **lppSession, char *szPath = NULL, ULONG ulProfileFlags = 0, char *sslkey_file = NULL, char *sslkey_password = NULL);
HRESULT HrOpenECSession(IMAPISession **lppSession, char *szUsername, char *szPassword, char *szPath = NULL, ULONG ulProfileFlags = 0, char *sslkey_file = NULL, char *sslkey_password = NULL, char *profname = NULL);
HRESULT HrSearchECStoreEntryId(IMAPISession *lpMAPISession, BOOL bPublic, ULONG *lpcbEntryID, LPENTRYID *lppEntryID);
HRESULT HrOpenDefaultStore(IMAPISession *lpMAPISession, IMsgStore **lppMsgStore);
HRESULT HrOpenDefaultStore(IMAPISession *lpMAPISession, ULONG ulFlags, IMsgStore **lppMsgStore);
HRESULT HrOpenECPublicStore(IMAPISession *lpMAPISession, IMsgStore **lppMsgStore);
HRESULT HrOpenECPublicStore(IMAPISession *lpMAPISession, ULONG ulFlags, IMsgStore **lppMsgStore);

HRESULT HrOpenDefaultStoreOffline(IMAPISession *lpMAPISession, IMsgStore **lppMsgStore);
HRESULT HrOpenDefaultStoreOnline(IMAPISession *lpMAPISession, IMsgStore **lppMsgStore);
HRESULT HrOpenStoreOnline(IMAPISession *lpMAPISession, ULONG cbEntryID, LPENTRYID lpEntryID, IMsgStore **lppMsgStore);
HRESULT HrOpenECPublicStoreOnline(IMAPISession *lpMAPISession, IMsgStore **lppMsgStore);

HRESULT GetProxyStoreObject(IMsgStore *lpMsgStore, IMsgStore **lppMsgStore);

HRESULT HrAddECMailBox(LPMAPISESSION lpSession, char *lpszUserName);
HRESULT HrAddECMailBox(LPPROVIDERADMIN lpProviderAdmin, char * lpszUserName);

HRESULT HrRemoveECMailBox(LPMAPISESSION lpSession, LPMAPIUID lpsProviderUID);
HRESULT HrRemoveECMailBox(LPPROVIDERADMIN lpProviderAdmin, LPMAPIUID lpsProviderUID);

HRESULT ECCreateOneOff(char* lpszName, char* lpszAdrType, char* lpszAddress, ULONG ulFlags, ULONG* lpcbEntryID, LPENTRYID* lppEntryID);
HRESULT ECParseOneOff(LPENTRYID lpEntryID, ULONG cbEntryID, std::string &strName, std::string &strType, std::string &strEmailAddress);

HRESULT HrGetAddress(IMAPISession *lpSession, LPSPropValue lpProps, ULONG cValues, ULONG ulPropTagEntryID, ULONG ulPropTagName, ULONG ulPropTagType, ULONG ulPropTagEmailAddress, std::string &strName, std::string &strType, std::string &strEmailAddress);
HRESULT HrGetAddress(IMAPISession *lpSession, IMessage *lpMessage, ULONG ulPropTagEntryID, ULONG ulPropTagName, ULONG ulPropTagType, ULONG ulPropTagEmailAddress, std::string &strName, std::string &strType, std::string &strEmailAddress);
HRESULT HrGetAddress(LPADRBOOK lpAdrBook, IMessage *lpMessage, ULONG ulPropTagEntryID, ULONG ulPropTagName, ULONG ulPropTagType, ULONG ulPropTagEmailAddress, std::string &strName, std::string &strType, std::string &strEmailAddress);
HRESULT HrGetAddress(LPADRBOOK lpAdrBook, LPSPropValue lpProps, ULONG cValues, ULONG ulPropTagEntryID, ULONG ulPropTagName, ULONG ulPropTagType, ULONG ulPropTagEmailAddress, std::string &strName, std::string &strType, std::string &strEmailAddress);
HRESULT HrGetAddress(LPADRBOOK lpAdrBook, LPENTRYID lpEntryID, ULONG cbEntryID, std::string &strName, std::string &strType, std::string &strEmailAddress);

HRESULT HrConvertToWString(const std::string &strInput, const std::string &strCharset, ucs2string &wstrOutput);
HRESULT HrConvertFromWString(const ucs2string &wstrInput, const std::string &strCharset, std::string &strOutput);
HRESULT HrEscapeHTML(ucs2string &wstrInput, std::string &strOutput);
HRESULT HrToQuotedPrintable1252(std::string &input, std::string *output, bool header = true);

HRESULT HrNewMailNotification(IMsgStore* lpMDB, IMessage* lpMessage, ECLogger* lpLogger = NULL);
HRESULT HrCreateEmailSearchKey(char* lpszEmailType, char* lpszEmail, ULONG* cb, LPBYTE* lppByte);

HRESULT DoSentMail(IMAPISession *lpSession, ULONG ulMessage, IMessage *lpMessage);

HRESULT TestRestriction(LPSRestriction lpCondition, ULONG cValues, LPSPropValue lpPropVals, ULONG ulLevel = 0);
HRESULT TestRestriction(LPSRestriction lpCondition, IMAPIProp *lpMessage, ULONG ulLevel = 0);

HRESULT GetClientVersion(unsigned int* ulVersion);

HRESULT CreateProfileTemp(char *username, char *password, char *path, char* szProfName, ULONG ulProfileFlags,
						  char *sslkey_file, char *sslkey_password);
HRESULT DeleteProfileTemp(char *szProfName);
HRESULT OpenSubFolder(LPMDB lpMDB, char *folder, char psep, ECLogger *lpLogger, bool blIsPublic, bool bCreateFolder, LPMAPIFOLDER *lppSubFolder);
HRESULT FindFolder(LPMAPITABLE lpTable, const char *folder, LPSPropValue *lppFolderProp);


HRESULT HrGetPropTags(char **names, IMAPIProp *lpProp, LPSPropTagArray *lppPropTagArray);

/**
 * NAMED PROPERTY utilities
 *
 * HOW TO USE
 * Make sure you have an IMAPIProp interface to pass to PROPMAP_INIT
 * All properties are allocated an ULONG with name PROP_XXXXX (XXXXX passed in first param of PROPMAP_NAMED_ID
 *
 * EXAMPLE
 *
 * PROPMAP_START
 *  PROPMAP_NAMED_ID(RECURRING, PT_BOOLEAN, PSETID_Appointment, dispidRecurring)
 *  PROPMAP_NAMED_ID(START, 	PT_SYSTIME, PSETID_Appointment, dispidStart)
 * PROPMAP_INIT(lpMessage)
 *
 * printf("%X %X\n", PROP_RECURRING, PROP_START);
 *
 */
class ECPropMapEntry  {
public:
    ECPropMapEntry(GUID guid, ULONG ulId);
    ECPropMapEntry(GUID guid, char *strName);
    ECPropMapEntry(const ECPropMapEntry &other);
    ~ECPropMapEntry();
    
    MAPINAMEID* GetMAPINameId();
private:
    MAPINAMEID m_sMAPINameId;
    GUID m_sGuid;
};

class ECPropMap {
public:
    ECPropMap();
    void AddProp(ULONG *lpId, ULONG ulType, ECPropMapEntry entry);
    HRESULT Resolve(IMAPIProp *lpMAPIProp);
private:
    std::list<ECPropMapEntry> lstNames;
    std::list<ULONG *> lstVars;
    std::list<ULONG> lstTypes;
};

#define PROPMAP_START ECPropMap __propmap;
#define PROPMAP_NAMED_ID(name,type,guid,id) ULONG PROP_##name; __propmap.AddProp(&PROP_##name, type, ECPropMapEntry(guid, id));
#define PROPMAP_INIT(lpObject) hr = __propmap.Resolve(lpObject); if(hr != hrSuccess) goto exit;


// Determine the size of an array
template <typename T, unsigned N>
inline unsigned  arraySize(T (&)[N])   { return N; }

#endif // COMMONUTIL_H
