MSP.H

/* 
* M S P . H
*
* Definitions for the MAPI Sample Message Store Provider.
*
* Copyright 1992-1995 Microsoft Corporation. All Rights Reserved.
*/

#ifdef _WIN32
#define _INC_OLE
#define INC_OLE2 /* Get the OLE2 stuff */
#define INC_RPC /* harmless on NT 3.5; Win95 needs it */
#endif

#include <windows.h>
#include <ole2.h>

#include <mapispi.h>
#include <mapidbg.h>
#include <mapiwin.h>
#include <mapiutil.h>
#include <mapival.h>
#include <smpms.h>

#include <mapidefs.h>
#include <mapicode.h>
#include <mapitags.h>
#include <mapiguid.h>

#include <imessage.h>

#include <limits.h>
#include <memory.h>

#if defined(_WIN32)
#define OLE_CHAR WCHAR
#else
#define OLE_CHAR char
#endif

#define VALIDATE

#ifdef VALIDATE
#define OBJ_ValidateParameters(pobj, intf, method, cbObj, _lpVtbl, arglist) \
{ \
Validate##_##intf##_##method arglist; \
if (IsBadWritePtr(pobj, cbObj) || (pobj)->lpVtbl != _lpVtbl) \
return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); }

#define OBJ_CheckParameters(pobj, intf, method, cbObj, _lpVtbl, arglist) \
{ \
CheckParameters##_##intf##_##method arglist; \
AssertSz(!IsBadWritePtr(pobj, cbObj) && (pobj)->lpVtbl == _lpVtbl, \
"Bad object pointer"); }
#else
#define OBJ_ValidateParameters(pobj, intf, method, cbObj, _lpVtbl, arglist)
#define OBJ_CheckParameters(pobj, intf, method, cbObj, _lpVtbl, arglist)
#endif /* VALIDATE */

typedef LPVOID *PPV;

#define NUM_RETRIES 6 /* number of times to retry opening a file */

/* Per-instance data. */
typedef struct
{
UINT cRef;
LPMALLOC lpmalloc;
} INST, *PINST;

/* Linked Memory Routines */
typedef struct _lmr
{
LPALLOCATEBUFFER lpAllocBuf;
LPALLOCATEMORE lpAllocMore;
LPFREEBUFFER lpFreeBuf;
} LMR, *PLMR;

#define LMAlloc(plmr, lcb, ppv) ((plmr)->lpAllocBuf(lcb, ppv))
#define LMAllocMore(plmr, lcb, pvLink, ppv) ((plmr)->lpAllocMore(lcb, pvLink, ppv))
#define LMFree(plmr, pv) ((plmr)->lpFreeBuf(pv))

#define IsBadIfacePtr(param, iface) \
(IsBadReadPtr((param), sizeof(iface)) \
|| IsBadReadPtr((param)->lpVtbl, sizeof(iface##Vtbl)))

#define SMPMS_VERSION (0x03) /* For MAPI 1.0 */

typedef struct _EID /* Sample Message Store EntryID */
{
BYTE abFlags[4];
MAPIUID uidResource;
BYTE bVersion;
BYTE bVerPad[3];
TCHAR szPath[1];
} EID, *PEID;

#define CbNewEID(_cbPath) \
(offsetof(EID,szPath) + (_cbPath)*sizeof(CHAR))

/* This includes the NULL terminator */
#define CbEID(_peid) \
(offsetof(EID,szPath) + \
(((UINT)(lstrlen((_peid)->szPath)))*sizeof(CHAR)) + sizeof(CHAR))

/* This includes the NULL */
#define CbEIDPath(peid) (CbEID(peid)-CbNewEID(0))

#define PR_FILENAME_SEQUENCE_NUMBER PROP_TAG(PT_LONG, 0x6600)
#define PR_SMS_CONTENTS_SORT_ORDER PROP_TAG(PT_MV_LONG, 0x6601)

#if defined(_WIN32)
#define CRITICAL_SECTION_MEMBERS CRITICAL_SECTION cs;
#define CRITICAL_SECTION_MEMBERS_P CRITICAL_SECTION *pcs;
#else
#define CRITICAL_SECTION_MEMBERS
#define CRITICAL_SECTION_MEMBERS_P
#endif

/* Object typedefs ------------------------------------------------------- */

typedef struct _OBJ OBJ, * POBJ, ** PPOBJ;
typedef struct _MSP MSP, * PMSP, ** PPMSP;
typedef struct _MSL MSL, * PMSL, ** PPMSL;
typedef struct _IMS IMS, * PIMS, ** PPIMS;
typedef struct _IFLD IFLD, * PIFLD, ** PPIFLD;
typedef struct _IMSG IMSG, * PIMSG, ** PPIMSG;
typedef struct _IATCH IATCH, * PIATCH, ** PPIATCH;
typedef struct _STM STM, * PSTM, ** PPSTM;
typedef struct _STG STG, * PSTG, ** PPSTG;

/* Standard Object --------------------------------------------------------- */

#undef INTERFACE
#define INTERFACE struct _OBJ

#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, OBJ_)
MAPI_IUNKNOWN_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) STDMETHOD_(type, method)

DECLARE_MAPI_INTERFACE(OBJ_)
{
MAPI_IUNKNOWN_METHODS(IMPL)
};

#define STANDARD_OBJECT_MEMBERS \
LONG cRef; \
WORD wType; \
WORD wFlags; \
POBJ pobjParent; \
POBJ pobjNext; \
POBJ pobjHead; \
PIMS pims; \
CRITICAL_SECTION_MEMBERS_P \

/* NOTE: If you modify this enumeration, you must also update various */
/* structures in mspobj.c which use the type as an index into lookup tables */
enum {
OT_MSPROVIDER,
OT_MSLOGON,
OT_MSGSTORE,
OT_FOLDER,
OT_MESSAGE,
OT_ATTACH,
OT_STREAM,
OT_TABLE,
OT_MAX
};

#define OBJF_MODIFY ((WORD)0x0001)

struct _OBJ
{
OBJ_Vtbl * lpVtbl;
STANDARD_OBJECT_MEMBERS
};

typedef void (*LPFNNEUTER)(POBJ);
extern LPFNNEUTER rgfnNeuter[];

#define OBJ_SetFlag(pobj, f) ((pobj)->wFlags |= (f))
#define OBJ_ClearFlag(pobj, f) ((pobj)->wFlags &= ~(f))
#define OBJ_TestFlag(pobj, f) ((pobj)->wFlags & (f))

#ifdef _WIN32
#define OBJ_Initialize(pobj, _vtbl, _wType, _pims, _pcs) \
(pobj)->lpVtbl = _vtbl; \
(pobj)->cRef = 1; \
(pobj)->wType = _wType; \
(pobj)->pims = _pims; \
(pobj)->pcs = _pcs;
#else
#define OBJ_Initialize(pobj, _vtbl, _wType, _pims, _pcs) \
(pobj)->lpVtbl = _vtbl; \
(pobj)->cRef = 1; \
(pobj)->wType = _wType; \
(pobj)->pims = _pims;
#endif

#define OBJ_EnterCriticalSection(pobj) EnterCriticalSection((pobj)->pcs)
#define OBJ_LeaveCriticalSection(pobj) LeaveCriticalSection((pobj)->pcs)
#define MSP_EnterCriticalSection(pmsp) OBJ_EnterCriticalSection((POBJ)pmsp)
#define MSP_LeaveCriticalSection(pmsp) OBJ_LeaveCriticalSection((POBJ)pmsp)
#define IMS_EnterCriticalSection(pims) OBJ_EnterCriticalSection((POBJ)pims)
#define IMS_LeaveCriticalSection(pims) OBJ_LeaveCriticalSection((POBJ)pims)

/*
* MSPOBJ.C
*/

BOOL FQueryInterface(int wType, REFIID riid);

void OBJ_Enqueue(POBJ pobj, POBJ pobjParent);
void OBJ_Dequeue(POBJ pobj);
void OBJ_Destroy(POBJ pobj);

extern CHAR szFolderTemplate[]; /* "*.fld" */
extern CHAR szMessageTemplate[]; /* "*.msg" */
extern CHAR szPropertyFileName[]; /* "folder.prp" */
extern CHAR szHierarchyFileName[]; /* "hierarch.tbl" */
extern CHAR szContentsFileName[]; /* "contents.tbl" */
extern CHAR szOutgoingFileName[]; /* "outgoing.tbl" */

/*
* MSPRFS.C
*/

/* Manifest constants */

#define RFS_CREATE ((ULONG) 0x00000001)

/* Typedefs */

typedef struct _RFS /* Receive Folder Storage */
{
LPTSTR szFile; /* Name of docfile containing RecFldr settings */
} RFS, * PRFS;

typedef struct _RFN /* A single RFS Node */
{
LPTSTR szClass; /* Name of the message class */
LPTSTR szName; /* Relative path name of receive folder, i.e. */
/* EntryID minus the GUID */
} RFN, * PRFN;

/* Exported functions */

BOOL FIsValidMessageClass(LPTSTR szMessageClass);
HRESULT OpenRFS (LPTSTR szStoreRoot, LPTSTR szFile, ULONG ulFlags,
PRFS * lpprfs);
HRESULT GetRFN (PRFS prfs, LPTSTR szClassName, PRFN * pprfn);
VOID FreeRFN (PRFN prfn);
HRESULT DeleteRFN (PRFS prfs, LPTSTR szClassName);
HRESULT AddRFN (PRFS, PRFN prfn);
HRESULT CloseRFS (PRFS prfs);

/*
* MSPMS.C
*/

/* Manifest constants */

#define IMS_CREATE ((WORD) 0x0002)
#define IMS_INVALID ((WORD) 0x0004)

/* Typedefs */

#undef INTERFACE
#define INTERFACE struct _IMS

#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, IMS_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IMSGSTORE_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_TYPEDEF(type, method, IMS_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IMSGSTORE_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) STDMETHOD_(type, method)

DECLARE_MAPI_INTERFACE(IMS_)
{
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IMSGSTORE_METHODS(IMPL)
};

struct _IMS /* Implementation of IMsgStore */
{
IMS_Vtbl * lpVtbl; /* -> vtblIMS */
STANDARD_OBJECT_MEMBERS
LPTSTR szStorePath; /* Full path to the store root */
MAPIUID uidResource; /* Message Store unique identifier */
LPTSTR szProps; /* Full path to property docfile */
PMSL pmsl; /* Logon object (MAPI session stuff) */
PMSP pmsp; /* Provider object (global stuff) */
LMR lmr; /* Linked memory routines */
PRFS prfs; /* Struct handling access to receive folder */
LPMAPISUP psup; /* MAPI Support object */
SBinary eidStore; /* PR_STORE_ENTRYID */
LPTABLEDATA lptblOutgoing; /* outgoing queue for this store */
HANDLE hOGQueueMutex; /* Mutex for reading/writing the OG Queue */
FILETIME ftOGQueue; /* The time of the OQ file when we read it */
ULONG cOutgoingViews; /* number of views open on the outgoing queue */
ULONG ulOQConn; /* Connection for OQ unadvise */
HANDLE hContTblMutex; /* Mutex for reading/writing ALL cont tbls */
ULONG ulTblConn; /* Connection for Tbl unadvise */
LPMSGSESS pmsgsess; /* IMSG Session to create all messages within */
ULONG ulFlagsSLT; /* Flags for StoreLogoffTransports */
};

#define MSF_SPOOLER ((WORD)0x8000)
#define MSF_BEINGDESTROYED ((WORD)0x4000)

#define SMS_SUPPORTMASK (STORE_ENTRYID_UNIQUE | \
STORE_ATTACH_OK | \
STORE_OLE_OK | \
STORE_NOTIFY_OK | \
STORE_MV_PROPS_OK | \
STORE_RESTRICTION_OK | \
STORE_SORT_OK | \
STORE_MODIFY_OK | \
STORE_CREATE_OK | \
STORE_SUBMIT_OK)

/* Outgoing Queue Notification Block (ONB) */
/* This is the format of our extended cross-process notification for the */
/* outgoing queue table. We use this to update the table data in other */
/* processes after we change it in the originating process. The changes */
/* that we pass across are either deleting a row (for example, when the */
/* spooler calls FinishedMsg), or adding a row (for example, when the */
/* client submits a message). */

typedef struct _ONB
{
FILETIME ftBeforeUpdate; /* time of the file before updating */
FILETIME ftAfterUpdate; /* time of the file after applying the update */
LPVOID pvRef; /* memory offset from originating process */
ULONG cbNtf; /* # of bytes in abNtf (the flat notif below) */
BYTE abNtf[1]; /* the update to apply to the table */
} ONB, * PONB;

#define CbNewONB(_cb) (offsetof(ONB,abNtf) + (_cb))
#define CbONB(_ponb) \
(offsetof(ONB,abNtf) + (UINT)((_ponb)->cbNtf))


/* Table Notification Block (TNB) */
/* This is the format of our extended cross-process notification for */
/* Contents and Hierarchy Tables. We use this notification to update a */
/* table in other processes after we change it in the originating process. */
/* The notification consists of an object notification containing the */
/* entryids we need. The fnev tells the event type. We only use two of */
/* the entryids in the object notification. The ParentID fields refer to */
/* the parent folder of the table we need to update. The EntryID fields */
/* refer to the object that changed within the folder. The ulObjType field */
/* will be either MAPI_MESSAGE (for contents table changes) or MAPI_FOLDER */
/* (for hierarchy table changes). All other fields in the structure are */
/* unused and should be set to 0. */

typedef struct _TNB
{
ULONG ulTableEvent; /* TABLE_ROW_ (ADDED, DELETED, MODIFIED) */
LPVOID pvRef; /* memory offset from originating process */
ULONG cbNtf; /* # of bytes in abNtf (the flat notif below) */
BYTE abNtf[1]; /* an object notification */
} TNB, * PTNB;

#define CbNewTNB(_cb) (offsetof(TNB,abNtf) + (_cb))
#define CbTNB(_ptnb) \
(offsetof(TNB,abNtf) + (UINT)((_ptnb)->cbNtf))


/* Exported functions */
HRESULT HrOpenIMSPropsFileRetry(LPMSGSESS pmsgsess, LPTSTR szFile, PLMR plmr,
LPMAPISUP psup, BOOL fModify, LPMESSAGE * lppmsg);
BOOL IMS_IsInvalid(PIMS pims);

/* Constructors */

HRESULT HrNewIMS(LPTSTR szStorePath, LPTSTR szStoreProps, PMSP pmsp,
PMSL pmsl, PRFS prfs, LPPROFSECT pps, LPMAPISUP psup, BOOL fCreate,
PIMS *ppims);

/* Non-virtual public methods */

void IMS_Neuter(PIMS pims);
HRESULT HrInitIMSProps (PIMS pims, LPTSTR szPswd);
VOID GetResourceUID (PIMS pims, LPMAPIUID lpuid);
HRESULT HrUniqueFileName (PIMS pims, ULONG * lpulSeqNumber, LPTSTR *
lppszNewName);
BOOL FIsInvalidEID (ULONG, PEID, PIMS);
/* Others */

STDAPI_(void) MsgReleaseStg (ULONG ulCallerData, LPMESSAGE lpMessage);
long STDAPICALLTYPE LSMSNotifCallback (LPVOID lpvContext,
ULONG cNotif, LPNOTIFICATION lpNotifs);

/* column properties for outgoing queue */
#define OUTGOING_COLUMNS 13 /* number of columns in outgoing queue */
static const SizedSPropTagArray(OUTGOING_COLUMNS, sptaOutgoing) =
{
OUTGOING_COLUMNS,
{
PR_ENTRYID,
PR_SUBMIT_FLAGS,
PR_INSTANCE_KEY, /* the index column */
PR_DISPLAY_TO,
PR_DISPLAY_CC,
PR_DISPLAY_BCC,
PR_SENDER_NAME,
PR_SUBJECT,
PR_CLIENT_SUBMIT_TIME,
PR_PRIORITY,
PR_MESSAGE_FLAGS,
PR_MESSAGE_SIZE,
PR_SPOOLER_STATUS
}
};


/*
* MSPFLD.C
*/

#define FAILED_SEARCH (INVALID_HANDLE_VALUE)

#define MODIFY_INDEX 1 /* index of LAST_MODIFICATION_TIME in tables */

/* column properties for contents tables */
#define CONTENTS_COLUMNS 22 /* number of columns in a table of messages */
static const SizedSPropTagArray(CONTENTS_COLUMNS, sPropTagsContents) =
{
CONTENTS_COLUMNS,
{
PR_ENTRYID,
PR_LAST_MODIFICATION_TIME, /* must be in position MODIFY_INDEX */
PR_INSTANCE_KEY, /* the index column */
PR_HASATTACH,
PR_SUBJECT,
PR_SENDER_NAME,
PR_DISPLAY_TO,
PR_DISPLAY_CC,
PR_CLIENT_SUBMIT_TIME,
PR_MESSAGE_DELIVERY_TIME,
PR_MESSAGE_FLAGS,
PR_PRIORITY,
PR_CONVERSATION_KEY,
PR_SEARCH_KEY,
PR_ICON,
PR_MINI_ICON,
PR_SENSITIVITY,
PR_MESSAGE_CLASS,
PR_RECORD_KEY,
PR_SPOOLER_STATUS,
PR_SENT_REPRESENTING_NAME,
PR_MSG_STATUS
}
};

/* column properties for hierarchy tables */
#define HIERARCHY_COLUMNS 12
static const SizedSPropTagArray(HIERARCHY_COLUMNS, sPropTagsHierarchy) =
{
HIERARCHY_COLUMNS,
{
PR_ENTRYID,
PR_LAST_MODIFICATION_TIME, /* must be in postion MODIFY_INDEX */
PR_DISPLAY_NAME, /* the folder name */
PR_INSTANCE_KEY, /* the index column */
PR_OBJECT_TYPE,
PR_COMMENT,
PR_CONTENT_COUNT,
PR_CONTENT_UNREAD,
PR_STATUS,
PR_SUBFOLDERS,
PR_FOLDER_TYPE,
PR_DEPTH /* depth in hierarchy, must be last */
}
} ;

#undef INTERFACE
#define INTERFACE struct _IFLD

#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, IFLD_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IMAPICONTAINER_METHODS(IMPL)
MAPI_IMAPIFOLDER_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_TYPEDEF(type, method, IFLD_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IMAPICONTAINER_METHODS(IMPL)
MAPI_IMAPIFOLDER_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) STDMETHOD_(type, method)

DECLARE_MAPI_INTERFACE(IFLD_)
{
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IMAPICONTAINER_METHODS(IMPL)
MAPI_IMAPIFOLDER_METHODS(IMPL)
};

extern IFLD_Vtbl vtblIFLD;

/* we store PR_ENTRYID, PR_PARENT_ENTRYID and PR_INSTANCE_KEY internally */
#define cpropIFLDInternal 3

/* Folder's instance data */
struct _IFLD
{
IFLD_Vtbl * lpVtbl; /* -> vtblIFLD */
STANDARD_OBJECT_MEMBERS
PEID peid; /* EntryID of this folder */
ULONG cval; /* # of internal props */
LPSPropValue pval; /* internal prop values */
LPTABLEDATA lptblContents; /* contents table for this folder */
ULONG cContentsViews; /* number of views open on contents table*/
LPTABLEDATA lptblHierarchy; /* hierarchy table for this folder */
ULONG cHierarchyViews; /* number of views open on hierarchy table */
};

HRESULT HrNewIFLD(PEID peid, PIMS pims, BOOL fModify, PIFLD * ppifld);
HRESULT HrCreateFolderStorage(PIFLD pifld, ULONG ulFolderType,
LPSTR szFolderName, LPSTR szFolderComment, BOOL fCreateDir,
PIMS pims, PEID *ppeid);
HRESULT HrNewEID (PIFLD, PIMS, LPTSTR, ULONG *, PEID *);
HRESULT HrIncrementOneROProp(PIFLD pifld, LONG lDelta, ULONG ulPT);
HRESULT HrIsParent(PEID peidParent, PEID peidChild, BOOL *pfIsParent);
HRESULT HrGetFileModTime(LPTSTR szStorePath, LPTSTR szFileName,
FILETIME *pft);
HRESULT HrFullPathName (LPSTR, LPSTR, LPSTR, LPSTR *);
HRESULT HrFullToRelative(LPTSTR, PIMS, LPTSTR *);
HRESULT HrOpenPropertyMessageRetry(PEID peid, PIMS pims,
BOOL fModifyExclusive, LPMESSAGE *lppmsg);
HRESULT HrFindFirstID( PIFLD, LPTSTR, ULONG *, LPTSTR *, HANDLE *,
WIN32_FIND_DATA *, PEID *);
HRESULT HrFindNextID( PIFLD, ULONG, LPTSTR, HANDLE, WIN32_FIND_DATA *, PEID *);
void CloseIDSearch( HANDLE *, LPTSTR *);
HRESULT HrFullToRelative( LPTSTR, PIMS, LPTSTR *);
HRESULT HrUpdateRow(PIMS pims, LPTABLEDATA lptbl, PEID peid,
LPSPropTagArray pPTA, FILETIME *pft, ULONG ulObjType);
void IFLD_Neuter (PIFLD);
void ChangeTable(PIMS pims, PEID peidTable, PEID peidObject,
ULONG ulObjType, ULONG ulTableEvent, BOOL fSendNotif);
HRESULT HrRemoveRow( LPTABLEDATA lptbl, PEID peid);

/*
* MSPMSG.C
*/

#undef INTERFACE
#define INTERFACE struct _IMSG

#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, IMSG_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IMESSAGE_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_TYPEDEF(type, method, IMSG_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IMESSAGE_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) STDMETHOD_(type, method)

DECLARE_MAPI_INTERFACE(IMSG_)
{
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IMESSAGE_METHODS(IMPL)
};

extern IMSG_Vtbl vtblIMSG;

struct _IMSG /* Implementation of IMessage */
{
IMSG_Vtbl * lpVtbl; /* -> vtblIMSG */
STANDARD_OBJECT_MEMBERS
LPMESSAGE lpmsg;
PEID peid;
ULONG cval;
LPSPropValue pval;
};

#define MSGF_NEWLYCREATED ((WORD)0x4000)
#define MSGF_MSGINMSG ((WORD)0x2000)
#define MSGF_FRESH ((WORD)0x1000)
#define MSGF_CREATEDSTORAGE ((WORD)0x0800)

#define SET 1
#define UNSET 2
#define DONT_SAVE 4

/* Exported functions */

HRESULT HrNewIMSG(PEID peid, PIMS pims, BOOL fCreate, BOOL fModify,
ULONG ulSeqNum, LPSTR *pszFull, PIMSG *ppimsg);
HRESULT HrSetFlags(PIMSG, ULONG, ULONG, ULONG);
HRESULT NewIMSGInIATCH (LPMESSAGE lpmsg, POBJ pobj, ULONG ulFlags, PIMSG * ppimsg);
HRESULT InitIMSGProps(PIMSG pimsg);
void IMSG_Neuter (PIMSG);
HRESULT HrSetInternalProps(PLMR plmr, ULONG cprop, LPSPropValue *ppval,
ULONG *pcval, PEID peid, PEID peidParent, ULONG ulSeqNum);

/*
* MSPATCH.C
*/

#undef INTERFACE
#define INTERFACE struct _IATCH

#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, IATCH_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IATTACH_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_TYPEDEF(type, method, IATCH_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IATTACH_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) STDMETHOD_(type, method)

DECLARE_MAPI_INTERFACE(IATCH_)
{
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMAPIPROP_METHODS(IMPL)
MAPI_IATTACH_METHODS(IMPL)
};

extern IATCH_Vtbl vtblIATCH;

struct _IATCH /* Implementation of IAttach */
{
IATCH_Vtbl * lpVtbl; /* -> vtblIATCH */
STANDARD_OBJECT_MEMBERS
LPATTACH lpattach;
};

/* Exported functions */

HRESULT HrNewIATCH(LPATTACH lpattach, PIMSG pimsg, BOOL fModify,
PIATCH * ppiatch);
void IATCH_Neuter (PIATCH piatch);

/*
* MSPGLE.C
*/

HRESULT MapScodeSz (SCODE scArg, PIMS pims, LPTSTR * lppszError);

/*
* MSPMISC.C
*/

/* length in chars of file extension including . (no NULL) */
#define CCH_EXT 4

/* length in chars of the base portion of a local name (no NULL) */
#define CCH_BASE 8

/* length in chars of a local name of a message or folder, including NULL */
#define CCH_NAME (CCH_BASE + CCH_EXT + 1)

#define FOLDER_EXT TEXT( ".fld" ) /* extension for folder directory names */
#define MESSAGE_EXT TEXT( ".msg" ) /* File name extension for messages */
#define TEMP_EXT TEXT( ".tmp" ) /* File name extension for messages */

/* Filename extension for read-receipt messages */
#define READRECEIPT_EXT TEXT( ".rrt" )

SCODE ScAlloc(ULONG lcb, LPVOID *ppv);
SCODE ScAllocZ(ULONG lcb, LPVOID *ppv);
SCODE ScRealloc(ULONG lcb, LPVOID pvOrig, LPVOID * ppv);
void FreeNull(LPVOID pv);
SCODE LMAllocZ(PLMR plmr, ULONG lcb, LPVOID *ppv);
SCODE ScInitMSInstance(LPMALLOC lpmalloc);
void DeinitMSInstance(void);

#define HrAlloc(a,b) ResultFromScode(ScAlloc((a), (b)))
#define HrAllocZ(a,b) ResultFromScode(ScAllocZ((a), (b)))
#define HrRealloc(a,b,c) ResultFromScode(ScRealloc((a), (b), (c)))

LPTSTR SzBaseName (PEID);

BOOL FCheckEIDType(PEID peid, LPSTR szExt);
BOOL FIsRoot (PEID peid);
BOOL FIsFolder (PEID peid);
BOOL FIsUnsavedMsg (PIMSG pimsg);
#define FIsMessage(_peid) FCheckEIDType((_peid), MESSAGE_EXT)
#define FIsUnsavedEID(_peid) FCheckEIDType((_peid), TEMP_EXT)

HRESULT HrDeconstructEID (PEID peid, LPMAPIUID * lppuid,
LPTSTR * lppszPath, LPTSTR * lppszFile);
HRESULT HrAppendPath (LPTSTR szBase, LPTSTR szAppend, LPTSTR *
lppszFullPath);
BOOL FAppendPathNoMem (LPTSTR szBase, LPTSTR szAppend,
ULONG cchFullPath, LPTSTR szFullPath);
void ReplaceExt(LPTSTR szFile, LPTSTR szExt);
HRESULT HrConstructEID(LPMAPIUID lpuidStore, PLMR plmr, LPSTR szNewName,
PEID *ppeidNew);
HRESULT HrGetParentEID (PLMR, PEID, PEID *);
HRESULT HrOpenParent(PIMS pims, PEID peid, ULONG ulFlags, PIFLD *ppifld);

void FreePropArrays (LPSPropValue *,
LPSPropTagArray *, LPSPropAttrArray *);
HRESULT HrAllocPropArrays (ULONG, LPSPropValue *,
LPSPropTagArray *, LPSPropAttrArray *);

HRESULT HrWrap_GetProps(HRESULT hr, PIMS pims, ULONG cvalInt,
LPSPropValue pvalInt, ULONG * lpcValues, LPSPropValue * ppval,
BOOL fStore, BOOL fTagsSpecified, POBJ pobj);

BOOL FIsSubmittedMessage(PIMS pims, PEID peid);

HRESULT HrOpenIMsgSession(LPMSGSESS *ppmsgsess);
HRESULT HrOpenIMsg(LPMSGSESS pmsgsess, LPSTR szFile, PLMR plmr, LPMAPISUP psup,
BOOL fCreate, BOOL fModify, BOOL fExclusive, LPMESSAGE *lppmsg);

HRESULT HrSetOneROProp(LPMESSAGE lpmsg, PLMR plmr, ULONG ulPT, LPVOID pv);
HRESULT HrGetSingleProp(LPMAPIPROP pmprop, PLMR plmr, ULONG ulPT, LPVOID pv);
HRESULT HrSetSingleProp(LPMAPIPROP pmprop, PLMR plmr, ULONG ulPT, LPVOID pv);

BOOL FContainsProp(ULONG ulPropTag, LPSPropTagArray ptaga);


/*
* MSPROVIDER object.
* Returned by MSProviderInit() routine.
* One is created for each Session logged
* into this store provider on this process.
*/

#undef INTERFACE
#define INTERFACE struct _MSP

#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, MSP_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMSPROVIDER_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_TYPEDEF(type, method, MSP_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMSPROVIDER_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) STDMETHOD_(type, method)

DECLARE_MAPI_INTERFACE(MSP_)
{
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMSPROVIDER_METHODS(IMPL)
};

extern MSP_Vtbl vtblMSP;

struct _MSP
{
MSP_Vtbl * lpVtbl; /* -> vtblMSP */
STANDARD_OBJECT_MEMBERS
CRITICAL_SECTION_MEMBERS /* Critical section (_WIN32 only) */
HINSTANCE hInst; /* Instance handle */
LMR lmr; /* Linked memory routines */
IFDBG(BOOL fInvalid;) /* TRUE if invalid (DEBUG only) */
};

/*
* LOGON object.
* Returned from MSP_Logon().
* Called by MAPI.DLL. Equivalent to the IMSGSTORE object
* returned on the same call but is used by MAPI instead of the client.
*/

#undef INTERFACE
#define INTERFACE struct _MSL

#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, MSL_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMSLOGON_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_TYPEDEF(type, method, MSL_)
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMSLOGON_METHODS(IMPL)
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) STDMETHOD_(type, method)

DECLARE_MAPI_INTERFACE(MSL_)
{
MAPI_IUNKNOWN_METHODS(IMPL)
MAPI_IMSLOGON_METHODS(IMPL)
};

extern MSL_Vtbl vtblMSL;
extern MAPIUID uidProvider;

struct _MSL
{
MSL_Vtbl * lpVtbl; /* -> vtblMSL */
STANDARD_OBJECT_MEMBERS
CRITICAL_SECTION_MEMBERS /* Critical section (_WIN32) */
LMR lmr; /* Linked memory routines */
IFDBG(BOOL fInvalid;) /* TRUE if invalid (DEBUG only) */
};


/*
* MSPTBL.C
*/

HRESULT HrGetTableName(POBJ, LPSTR, LPSTR, LPSTR *);
HRESULT HrSyncOutgoingTable(LPTABLEDATA lptbl, PIMS pims);
HRESULT HrSyncContentsTable(PIFLD pifld, BOOL fWriteTable);
HRESULT HrReadTableFromDisk(LPTABLEDATA, POBJ, LPSTR, ULONG, LPSTR);
HRESULT HrWriteTableOnDisk(LPTABLEDATA, POBJ, LPSTR, LPSTR);

/*
* MSPNTFY.C
*/

HRESULT HrUpdateOutgoingQueue(PIMS pims, PIMSG pimsg, PEID peid,
ULONG ulTableEvent);
HRESULT HrSetupPrivateNotifications(PIMS pims);
HRESULT HrNewOutgoingTableData(PIMS pims);
HRESULT HrCreateOGQueueMutex(HANDLE *phQMutex);

HRESULT HrSendNotif(PIMS pims, PEID peidParent, PEID peidObject,
ULONG ulTableEvent, ULONG ulObjType);