Windows2003-3790/inetcore/outlookexpress/inetcomm/imnxport/ixphttpm.cpp
2020-09-30 16:53:55 +02:00

6570 lines
206 KiB
C++

// --------------------------------------------------------------------------------
// Ixphttpm.cpp
// Copyright (c)1998 Microsoft Corporation, All Rights Reserved
// Greg Friedman
// --------------------------------------------------------------------------------
#include "pch.hxx"
#include "dllmain.h"
#include "ixphttpm.h"
#include "wininet.h"
#include "ocidl.h"
#include "Vstream.h"
#include "shlwapi.h"
#include "htmlstr.h"
#include "strconst.h"
#include "propfind.h"
#include "davparse.h"
#include "davstrs.h"
#include <ntverp.h>
#include <process.h>
#include "oleutil.h"
#include "ixputil.h"
#include <demand.h>
extern HRESULT HrGetLastError(void);
typedef struct tagHTTPERROR
{
DWORD dwHttpError;
HRESULT ixpResult;
} HTTPERROR, *LPHTTPERROR;
static const HTTPERROR c_rgHttpErrorMap[] =
{
{ HTTP_STATUS_USE_PROXY, IXP_E_HTTP_USE_PROXY },
{ HTTP_STATUS_BAD_REQUEST, IXP_E_HTTP_BAD_REQUEST },
{ HTTP_STATUS_DENIED, IXP_E_HTTP_UNAUTHORIZED },
{ HTTP_STATUS_FORBIDDEN, IXP_E_HTTP_FORBIDDEN },
{ HTTP_STATUS_NOT_FOUND, IXP_E_HTTP_NOT_FOUND },
{ HTTP_STATUS_BAD_METHOD, IXP_E_HTTP_METHOD_NOT_ALLOW },
{ HTTP_STATUS_NONE_ACCEPTABLE, IXP_E_HTTP_NOT_ACCEPTABLE },
{ HTTP_STATUS_PROXY_AUTH_REQ, IXP_E_HTTP_PROXY_AUTH_REQ },
{ HTTP_STATUS_REQUEST_TIMEOUT, IXP_E_HTTP_REQUEST_TIMEOUT },
{ HTTP_STATUS_CONFLICT, IXP_E_HTTP_CONFLICT },
{ HTTP_STATUS_GONE, IXP_E_HTTP_GONE },
{ HTTP_STATUS_LENGTH_REQUIRED, IXP_E_HTTP_LENGTH_REQUIRED },
{ HTTP_STATUS_PRECOND_FAILED, IXP_E_HTTP_PRECOND_FAILED },
{ HTTP_STATUS_SERVER_ERROR, IXP_E_HTTP_INTERNAL_ERROR },
{ HTTP_STATUS_NOT_SUPPORTED, IXP_E_HTTP_NOT_IMPLEMENTED },
{ HTTP_STATUS_BAD_GATEWAY, IXP_E_HTTP_BAD_GATEWAY },
{ HTTP_STATUS_SERVICE_UNAVAIL, IXP_E_HTTP_SERVICE_UNAVAIL },
{ HTTP_STATUS_GATEWAY_TIMEOUT, IXP_E_HTTP_GATEWAY_TIMEOUT },
{ HTTP_STATUS_VERSION_NOT_SUP, IXP_E_HTTP_VERS_NOT_SUP },
{ 425, IXP_E_HTTP_INSUFFICIENT_STORAGE }, // obsolete out of storage error
{ 507, IXP_E_HTTP_INSUFFICIENT_STORAGE }, // preferred out of storage error
{ ERROR_INTERNET_OUT_OF_HANDLES, E_OUTOFMEMORY },
{ ERROR_INTERNET_TIMEOUT, IXP_E_TIMEOUT },
{ ERROR_INTERNET_NAME_NOT_RESOLVED, IXP_E_CANT_FIND_HOST },
{ ERROR_INTERNET_CANNOT_CONNECT, IXP_E_FAILED_TO_CONNECT },
{ HTTP_STATUS_NOT_MODIFIED, IXP_E_HTTP_NOT_MODIFIED},
};
#define FAIL_ABORT \
if (WasAborted()) \
{ \
hr = TrapError(IXP_E_USER_CANCEL); \
goto exit; \
} \
else
#define FAIL_EXIT_STREAM_WRITE(stream, psz) \
if (FAILED(hr = stream.Write(psz, lstrlen(psz), NULL))) \
goto exit; \
else
#define FAIL_EXIT(hr) \
if (FAILED(hr)) \
goto exit; \
else
#define FAIL_CREATEWND \
if (!m_hwnd && !CreateWnd()) \
{ \
hr = TrapError(E_OUTOFMEMORY); \
goto exit; \
} \
else
// these arrays describe element stack states, and are used to asses
// the current state of the element stack
static const HMELE c_rgPropFindPropStatStack[] =
{
HMELE_DAV_MULTISTATUS,
HMELE_DAV_RESPONSE,
HMELE_DAV_PROPSTAT
};
static const HMELE c_rgPropFindPropValueStack[] =
{
HMELE_DAV_MULTISTATUS,
HMELE_DAV_RESPONSE,
HMELE_DAV_PROPSTAT,
HMELE_DAV_PROP,
HMELE_UNKNOWN // wildcard
};
static const HMELE c_rgPropFindResponseStack[] =
{
HMELE_DAV_MULTISTATUS,
HMELE_DAV_RESPONSE
};
static const HMELE c_rgMultiStatusResponseChildStack[] =
{
HMELE_DAV_MULTISTATUS,
HMELE_DAV_RESPONSE,
HMELE_UNKNOWN
};
static const HMELE c_rgPropFindStatusStack[] =
{
HMELE_DAV_MULTISTATUS,
HMELE_DAV_RESPONSE,
HMELE_DAV_PROPSTAT,
HMELE_DAV_STATUS
};
// GET command
static const PFNHTTPMAILOPFUNC c_rgpfGet[] =
{
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessGetResponse,
&CHTTPMailTransport::FinalizeRequest
};
// DELETE command
static const PFNHTTPMAILOPFUNC c_rgpfDelete[] =
{
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::FinalizeRequest
};
// PROPPATCH command
static const PFNHTTPMAILOPFUNC c_rgpfnPropPatch[] =
{
&CHTTPMailTransport::GeneratePropPatchXML,
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::FinalizeRequest
};
// MKCOL command
static const PFNHTTPMAILOPFUNC c_rgpfnMkCol[] =
{
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddCharsetLine,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessCreatedResponse,
&CHTTPMailTransport::ProcessLocationResponse,
&CHTTPMailTransport::FinalizeRequest
};
// COPY command
static const PFNHTTPMAILOPFUNC c_rgpfnCopy[] =
{
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddDestinationHeader,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessCreatedResponse,
&CHTTPMailTransport::ProcessLocationResponse,
&CHTTPMailTransport::FinalizeRequest
};
// MOVE command
static const PFNHTTPMAILOPFUNC c_rgpfnMove[] =
{
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddDestinationHeader,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessCreatedResponse,
&CHTTPMailTransport::ProcessLocationResponse,
&CHTTPMailTransport::FinalizeRequest
};
// BMOVE command (data applies to bcopy and bmove)
#define BCOPYMOVE_MAXRESPONSES 10
XP_BEGIN_SCHEMA(HTTPMAILBCOPYMOVE)
XP_SCHEMA_COL(HMELE_DAV_HREF, XPCF_MSVALIDMSRESPONSECHILD, XPCDT_STRA, HTTPMAILBCOPYMOVE, pszHref)
XP_SCHEMA_COL(HMELE_DAV_LOCATION, XPCF_MSVALIDMSRESPONSECHILD, XPCDT_STRA, HTTPMAILBCOPYMOVE, pszLocation)
XP_SCHEMA_COL(HMELE_DAV_STATUS, XPCF_MSVALIDMSRESPONSECHILD, XPCDT_IXPHRESULT, HTTPMAILBCOPYMOVE, hrResult)
XP_END_SCHEMA
static const PFNHTTPMAILOPFUNC c_rgpfnBMove[] =
{
&CHTTPMailTransport::InitBCopyMove,
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddDestinationHeader,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessXMLResponse,
&CHTTPMailTransport::FinalizeRequest
};
static const XMLPARSEFUNCS c_rgpfnBCopyMoveParse[] =
{
&CHTTPMailTransport::CreateElement,
&CHTTPMailTransport::BCopyMove_HandleText,
&CHTTPMailTransport::BCopyMove_EndChildren
};
// MemberInfo Data. There are four schemas associated with this command.
// The first three are used to build up the propfind request, and are
// not used to parse responses. The fourth is the combined schema that
// is used for parsing.
//
// THE FOURTH SCHEMA MUST BE KEPT IN SYNC WITH THE FIRST THREE TO
// GUARANTEE THAT RESPONSES WILL BE PARSED CORRECTLY.
#define MEMBERINFO_MAXRESPONSES 10
// common property schema - used only for building the request
XP_BEGIN_SCHEMA(HTTPMEMBERINFO_COMMON)
// common properties
XP_SCHEMA_COL(HMELE_DAV_HREF, XPCF_PROPFINDHREF, XPCDT_STRA, HTTPMEMBERINFO, pszHref)
XP_SCHEMA_COL(HMELE_DAV_ISFOLDER, XPFC_PROPFINDPROP, XPCDT_BOOL, HTTPMEMBERINFO, fIsFolder)
XP_END_SCHEMA
// folder property schema - used only for building the request
XP_BEGIN_SCHEMA(HTTPMEMBERINFO_FOLDER)
XP_SCHEMA_COL(HMELE_DAV_DISPLAYNAME, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPMEMBERINFO, pszDisplayName)
XP_SCHEMA_COL(HMELE_HTTPMAIL_SPECIAL, XPFC_PROPFINDPROP, XPCDT_HTTPSPECIALFOLDER, HTTPMEMBERINFO, tySpecial)
XP_SCHEMA_COL(HMELE_DAV_HASSUBS, XPFC_PROPFINDPROP, XPCDT_BOOL, HTTPMEMBERINFO, fHasSubs)
XP_SCHEMA_COL(HMELE_DAV_NOSUBS, XPFC_PROPFINDPROP, XPCDT_BOOL, HTTPMEMBERINFO, fNoSubs)
XP_SCHEMA_COL(HMELE_HTTPMAIL_UNREADCOUNT, XPFC_PROPFINDPROP, XPCDT_DWORD, HTTPMEMBERINFO, dwUnreadCount)
XP_SCHEMA_COL(HMELE_DAV_VISIBLECOUNT, XPFC_PROPFINDPROP, XPCDT_DWORD, HTTPMEMBERINFO, dwVisibleCount)
XP_SCHEMA_COL(HMELE_HTTPMAIL_SPECIAL, XPFC_PROPFINDPROP, XPCDT_HTTPSPECIALFOLDER, HTTPMEMBERINFO, tySpecial)
XP_END_SCHEMA
// message property schema - used only for building the request
XP_BEGIN_SCHEMA(HTTPMEMBERINFO_MESSAGE)
XP_SCHEMA_COL(HMELE_HTTPMAIL_READ, XPFC_PROPFINDPROP, XPCDT_BOOL, HTTPMEMBERINFO, fRead)
XP_SCHEMA_COL(HMELE_MAIL_HASATTACHMENT, XPFC_PROPFINDPROP, XPCDT_BOOL, HTTPMEMBERINFO, fHasAttachment)
XP_SCHEMA_COL(HMELE_MAIL_TO, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPMEMBERINFO, pszTo)
XP_SCHEMA_COL(HMELE_MAIL_FROM, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPMEMBERINFO, pszFrom)
XP_SCHEMA_COL(HMELE_MAIL_SUBJECT, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPMEMBERINFO, pszSubject)
XP_SCHEMA_COL(HMELE_MAIL_DATE, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPMEMBERINFO, pszDate)
XP_SCHEMA_COL(HMELE_DAV_GETCONTENTLENGTH, XPFC_PROPFINDPROP, XPCDT_DWORD, HTTPMEMBERINFO, dwContentLength)
XP_END_SCHEMA
// combined schema - used for parsing responses
XP_BEGIN_SCHEMA(HTTPMEMBERINFO)
// common properties
XP_SCHEMA_COL(HMELE_DAV_HREF, XPCF_PROPFINDHREF, XPCDT_STRA, HTTPMEMBERINFO, pszHref)
XP_SCHEMA_COL(HMELE_DAV_ISFOLDER, XPFC_PROPFINDPROP, XPCDT_BOOL, HTTPMEMBERINFO, fIsFolder)
// folder properties
XP_SCHEMA_COL(HMELE_DAV_DISPLAYNAME, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPMEMBERINFO, pszDisplayName)
XP_SCHEMA_COL(HMELE_HTTPMAIL_SPECIAL, XPFC_PROPFINDPROP, XPCDT_HTTPSPECIALFOLDER, HTTPMEMBERINFO, tySpecial)
XP_SCHEMA_COL(HMELE_DAV_HASSUBS, XPFC_PROPFINDPROP, XPCDT_BOOL, HTTPMEMBERINFO, fHasSubs)
XP_SCHEMA_COL(HMELE_DAV_NOSUBS, XPFC_PROPFINDPROP, XPCDT_BOOL, HTTPMEMBERINFO, fNoSubs)
XP_SCHEMA_COL(HMELE_HTTPMAIL_UNREADCOUNT, XPFC_PROPFINDPROP, XPCDT_DWORD, HTTPMEMBERINFO, dwUnreadCount)
XP_SCHEMA_COL(HMELE_DAV_VISIBLECOUNT, XPFC_PROPFINDPROP, XPCDT_DWORD, HTTPMEMBERINFO, dwVisibleCount)
XP_SCHEMA_COL(HMELE_HTTPMAIL_SPECIAL, XPFC_PROPFINDPROP, XPCDT_HTTPSPECIALFOLDER, HTTPMEMBERINFO, tySpecial)
// message properties
XP_SCHEMA_COL(HMELE_HTTPMAIL_READ, XPFC_PROPFINDPROP, XPCDT_BOOL, HTTPMEMBERINFO, fRead)
XP_SCHEMA_COL(HMELE_MAIL_HASATTACHMENT, XPFC_PROPFINDPROP, XPCDT_BOOL, HTTPMEMBERINFO, fHasAttachment)
XP_SCHEMA_COL(HMELE_MAIL_TO, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPMEMBERINFO, pszTo)
XP_SCHEMA_COL(HMELE_MAIL_FROM, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPMEMBERINFO, pszFrom)
XP_SCHEMA_COL(HMELE_MAIL_SUBJECT, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPMEMBERINFO, pszSubject)
XP_SCHEMA_COL(HMELE_MAIL_DATE, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPMEMBERINFO, pszDate)
XP_SCHEMA_COL(HMELE_DAV_GETCONTENTLENGTH, XPFC_PROPFINDPROP, XPCDT_DWORD, HTTPMEMBERINFO, dwContentLength)
XP_END_SCHEMA
static const XMLPARSEFUNCS c_rgpfnMemberInfoParse[] =
{
&CHTTPMailTransport::CreateElement,
&CHTTPMailTransport::MemberInfo_HandleText,
&CHTTPMailTransport::MemberInfo_EndChildren
};
static const PFNHTTPMAILOPFUNC c_rgpfnMemberInfo[] =
{
&CHTTPMailTransport::InitMemberInfo,
&CHTTPMailTransport::GeneratePropFindXML,
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddDepthHeader,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessXMLResponse,
&CHTTPMailTransport::RequireMultiStatus,
&CHTTPMailTransport::FinalizeRequest
};
// Operations which share MemberError-based responses (MarkRead, BDELETE)
#define MEMBERERROR_MAXRESPONSES 10
XP_BEGIN_SCHEMA(HTTPMEMBERERROR)
XP_SCHEMA_COL(HMELE_DAV_HREF, XPCF_PROPFINDHREF, XPCDT_STRA, HTTPMEMBERERROR, pszHref)
XP_SCHEMA_COL(HMELE_DAV_STATUS, XPCF_MSVALIDMSRESPONSECHILD, XPCDT_IXPHRESULT, HTTPMEMBERERROR, hrResult)
XP_END_SCHEMA
static const XMLPARSEFUNCS c_rgpfnMemberErrorParse[] =
{
&CHTTPMailTransport::CreateElement,
&CHTTPMailTransport::MemberError_HandleText,
&CHTTPMailTransport::MemberError_EndChildren
};
static const PFNHTTPMAILOPFUNC c_rgpfnMarkRead[] =
{
&CHTTPMailTransport::InitMemberError,
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessXMLResponse,
&CHTTPMailTransport::FinalizeRequest
};
// SendMessage
static const PFNHTTPMAILOPFUNC c_rgpfnSendMessage[] =
{
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddContentTypeHeader,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendPostRequest,
&CHTTPMailTransport::ProcessPostResponse,
&CHTTPMailTransport::FinalizeRequest
};
// RootProps
XP_BEGIN_SCHEMA(ROOTPROPS)
XP_SCHEMA_COL(HMELE_HOTMAIL_ADBAR, XPFC_PROPFINDPROP, XPCDT_STRA, ROOTPROPS, pszAdbar)
XP_SCHEMA_COL(HMELE_HTTPMAIL_CONTACTS, XPFC_PROPFINDPROP, XPCDT_STRA, ROOTPROPS, pszContacts)
XP_SCHEMA_COL(HMELE_HTTPMAIL_INBOX, XPFC_PROPFINDPROP, XPCDT_STRA, ROOTPROPS, pszInbox)
XP_SCHEMA_COL(HMELE_HTTPMAIL_OUTBOX, XPFC_PROPFINDPROP, XPCDT_STRA, ROOTPROPS, pszOutbox)
XP_SCHEMA_COL(HMELE_HTTPMAIL_SENDMSG, XPFC_PROPFINDPROP, XPCDT_STRA, ROOTPROPS, pszSendMsg)
XP_SCHEMA_COL(HMELE_HTTPMAIL_SENTITEMS, XPFC_PROPFINDPROP, XPCDT_STRA, ROOTPROPS, pszSentItems)
XP_SCHEMA_COL(HMELE_HTTPMAIL_DELETEDITEMS, XPFC_PROPFINDPROP, XPCDT_STRA, ROOTPROPS, pszDeletedItems)
XP_SCHEMA_COL(HMELE_HTTPMAIL_DRAFTS, XPFC_PROPFINDPROP, XPCDT_STRA, ROOTPROPS, pszDrafts)
XP_SCHEMA_COL(HMELE_HTTPMAIL_MSGFOLDERROOT, XPFC_PROPFINDPROP, XPCDT_STRA, ROOTPROPS, pszMsgFolderRoot)
XP_SCHEMA_COL(HMELE_HOTMAIL_MAXPOLLINGINTERVAL, XPFC_PROPFINDPROP, XPCDT_DWORD, ROOTPROPS, dwMaxPollingInterval)
XP_SCHEMA_COL(HMELE_HOTMAIL_SIG, XPFC_PROPFINDPROP, XPCDT_STRA, ROOTPROPS, pszSig)
XP_END_SCHEMA
static const XMLPARSEFUNCS c_rgpfnRootPropsParse[] =
{
&CHTTPMailTransport::CreateElement,
&CHTTPMailTransport::RootProps_HandleText,
&CHTTPMailTransport::RootProps_EndChildren
};
static const PFNHTTPMAILOPFUNC c_rgpfnRootProps[] =
{
&CHTTPMailTransport::InitRootProps,
&CHTTPMailTransport::GeneratePropFindXML,
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddDepthHeader,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessXMLResponse,
&CHTTPMailTransport::FinalizeRootProps
};
static const PFNHTTPMAILOPFUNC c_rgpfnPost[] =
{
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddContentTypeHeader,
&CHTTPMailTransport::AddCharsetLine,
&CHTTPMailTransport::SendPostRequest,
//&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessPostResponse,
&CHTTPMailTransport::FinalizeRequest
};
static const PFNHTTPMAILOPFUNC c_rgpfnPut[] =
{
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddCharsetLine,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessPostResponse,
&CHTTPMailTransport::FinalizeRequest
};
// ListContacts Data
#define LISTCONTACTS_MAXRESPONSES 10
XP_BEGIN_SCHEMA(HTTPCONTACTID)
XP_SCHEMA_COL(HMELE_DAV_HREF, XPCF_PROPFINDHREF, XPCDT_STRA, HTTPCONTACTID, pszHref)
XP_SCHEMA_COL(HMELE_DAV_ID, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTID, pszId)
XP_SCHEMA_COL(HMELE_CONTACTS_GROUP, XPFC_PROPFINDPROP, XPCDT_HTTPCONTACTTYPE, HTTPCONTACTID, tyContact)
XP_SCHEMA_COL(HMELE_HOTMAIL_MODIFIED, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTID, pszModified)
XP_END_SCHEMA
static const PFNHTTPMAILOPFUNC c_rgpfnListContacts[] =
{
&CHTTPMailTransport::InitListContacts,
&CHTTPMailTransport::GeneratePropFindXML,
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddDepthHeader,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessXMLResponse,
&CHTTPMailTransport::RequireMultiStatus,
&CHTTPMailTransport::FinalizeRequest
};
static const XMLPARSEFUNCS c_rgpfnListContactsParse[] =
{
&CHTTPMailTransport::CreateElement,
&CHTTPMailTransport::ListContacts_HandleText,
&CHTTPMailTransport::ListContacts_EndChildren
};
// ContactInfo Data
#define CONTACTINFO_MAXRESPONSES 10
XP_BEGIN_SCHEMA(HTTPCONTACTINFO)
XP_SCHEMA_COL(HMELE_DAV_HREF, XPCF_PROPFINDHREF, XPCDT_STRA, HTTPCONTACTINFO, pszHref)
XP_SCHEMA_COL(HMELE_DAV_ID, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszId)
XP_SCHEMA_COL(HMELE_CONTACTS_GROUP, XPFC_PROPFINDPROP, XPCDT_HTTPCONTACTTYPE, HTTPCONTACTINFO, tyContact)
XP_SCHEMA_COL(HMELE_HOTMAIL_MODIFIED, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszModified)
XP_SCHEMA_COL(HMELE_CONTACTS_CN, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszDisplayName)
XP_SCHEMA_COL(HMELE_CONTACTS_GIVENNAME, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszGivenName)
XP_SCHEMA_COL(HMELE_CONTACTS_SN, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszSurname)
XP_SCHEMA_COL(HMELE_CONTACTS_NICKNAME, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszNickname)
XP_SCHEMA_COL(HMELE_CONTACTS_MAIL, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszEmail)
XP_SCHEMA_COL(HMELE_CONTACTS_HOMESTREET, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszHomeStreet)
XP_SCHEMA_COL(HMELE_CONTACTS_HOMECITY, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszHomeCity)
XP_SCHEMA_COL(HMELE_CONTACTS_HOMESTATE, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszHomeState)
XP_SCHEMA_COL(HMELE_CONTACTS_HOMEPOSTALCODE, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszHomePostalCode)
XP_SCHEMA_COL(HMELE_CONTACTS_HOMECOUNTRY, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszHomeCountry)
XP_SCHEMA_COL(HMELE_CONTACTS_O, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszCompany)
XP_SCHEMA_COL(HMELE_CONTACTS_STREET, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszWorkStreet)
XP_SCHEMA_COL(HMELE_CONTACTS_L, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszWorkCity)
XP_SCHEMA_COL(HMELE_CONTACTS_ST, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszWorkState)
XP_SCHEMA_COL(HMELE_CONTACTS_POSTALCODE, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszWorkPostalCode)
XP_SCHEMA_COL(HMELE_CONTACTS_FRIENDLYCOUNTRYNAME, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszWorkCountry)
XP_SCHEMA_COL(HMELE_CONTACTS_HOMEPHONE, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszHomePhone)
XP_SCHEMA_COL(HMELE_CONTACTS_HOMEFAX, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszHomeFax)
XP_SCHEMA_COL(HMELE_CONTACTS_TELEPHONENUMBER, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszWorkPhone)
XP_SCHEMA_COL(HMELE_CONTACTS_FACSIMILETELEPHONENUMBER, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszWorkFax)
XP_SCHEMA_COL(HMELE_CONTACTS_MOBILE, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszMobilePhone)
XP_SCHEMA_COL(HMELE_CONTACTS_OTHERTELEPHONE, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszOtherPhone)
XP_SCHEMA_COL(HMELE_CONTACTS_BDAY, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszBday)
XP_SCHEMA_COL(HMELE_CONTACTS_PAGER, XPFC_PROPFINDPROP, XPCDT_STRA, HTTPCONTACTINFO, pszPager)
XP_END_SCHEMA
static const XMLPARSEFUNCS c_rgpfnContactInfoParse[] =
{
&CHTTPMailTransport::CreateElement,
&CHTTPMailTransport::ContactInfo_HandleText,
&CHTTPMailTransport::ContactInfo_EndChildren
};
static const PFNHTTPMAILOPFUNC c_rgpfnContactInfo[] =
{
&CHTTPMailTransport::InitContactInfo,
&CHTTPMailTransport::GeneratePropFindXML,
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddDepthHeader,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessXMLResponse,
&CHTTPMailTransport::FinalizeRequest
};
// PostContact Data
static const PFNHTTPMAILOPFUNC c_rgpfnPostContact[] =
{
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessPostContactResponse,
&CHTTPMailTransport::InitListContacts,
&CHTTPMailTransport::GeneratePropFindXML,
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddDepthHeader,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessXMLResponse,
&CHTTPMailTransport::FinalizeRequest
};
static const XMLPARSEFUNCS c_rgpfnPostOrPatchContactParse[] =
{
&CHTTPMailTransport::CreateElement,
&CHTTPMailTransport::PostOrPatchContact_HandleText,
&CHTTPMailTransport::PostOrPatchContact_EndChildren
};
// PatchContact data
static const PFNHTTPMAILOPFUNC c_rgpfnPatchContact[] =
{
&CHTTPMailTransport::GeneratePropPatchXML,
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessPatchContactResponse,
&CHTTPMailTransport::InitListContacts,
&CHTTPMailTransport::GeneratePropFindXML,
&CHTTPMailTransport::OpenRequest,
&CHTTPMailTransport::AddDepthHeader,
&CHTTPMailTransport::AddCommonHeaders,
&CHTTPMailTransport::SendRequest,
&CHTTPMailTransport::ProcessXMLResponse,
&CHTTPMailTransport::FinalizeRequest
};
// special folders
typedef struct tagHTTPSPECIALFOLDER
{
const WCHAR *pwcName;
ULONG ulLen;
HTTPMAILSPECIALFOLDER tyFolder;
} HTTPSPECIALFOLDER, *LPHTTPSPECIALFOLDER;
static const HTTPSPECIALFOLDER c_rgpfnSpecialFolder[] =
{
{ DAV_STR_LEN(InboxSpecialFolder), HTTPMAIL_SF_INBOX },
{ DAV_STR_LEN(DeletedItemsSpecialFolder), HTTPMAIL_SF_DELETEDITEMS },
{ DAV_STR_LEN(DraftsSpecialFolder), HTTPMAIL_SF_DRAFTS },
{ DAV_STR_LEN(OutboxSpecialFolder), HTTPMAIL_SF_OUTBOX },
{ DAV_STR_LEN(SentItemsSpecialFolder), HTTPMAIL_SF_SENTITEMS },
{ DAV_STR_LEN(ContactsSpecialFolder), HTTPMAIL_SF_CONTACTS },
{ DAV_STR_LEN(CalendarSpecialFolder), HTTPMAIL_SF_CALENDAR },
{ DAV_STR_LEN(MsnPromoSpecialFolder), HTTPMAIL_SF_MSNPROMO },
{ DAV_STR_LEN(BulkMailSpecialFolder), HTTPMAIL_SF_BULKMAIL },
};
#define VALIDSTACK(rg) ValidStack(rg, ARRAYSIZE(rg))
static const char s_szHTTPMailWndClass[] = "HTTPMailWndClass";
// Notification messages used to communicate between the async thread
// and the window proc
#define SPM_HTTPMAIL_STATECHANGED (WM_USER + 1)
#define SPM_HTTPMAIL_SENDRESPONSE (WM_USER + 2)
#define SPM_HTTPMAIL_LOGONPROMPT (WM_USER + 3)
#define SPM_HTTPMAIL_GETPARENTWINDOW (WM_USER + 4)
// --------------------------------------------------------------------------------
// static functions
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_HrCrackUrl
// --------------------------------------------------------------------------------
HRESULT HrCrackUrl(
LPSTR pszUrl,
LPSTR *ppszHost,
LPSTR *ppszPath,
INTERNET_PORT *pPort)
{
URL_COMPONENTS uc;
char szHost[INTERNET_MAX_HOST_NAME_LENGTH];
char szPath[INTERNET_MAX_PATH_LENGTH];
if (NULL == pszUrl)
return E_INVALIDARG;
if (ppszHost)
*ppszHost = NULL;
if (ppszPath)
*ppszPath = NULL;
if (pPort)
*pPort = INTERNET_INVALID_PORT_NUMBER;
ZeroMemory(&uc, sizeof(URL_COMPONENTS));
uc.dwStructSize = sizeof(URL_COMPONENTS);
uc.lpszHostName = szHost;
uc.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
uc.lpszUrlPath = szPath;
uc.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
if (!InternetCrackUrl(pszUrl, NULL, 0, &uc))
return E_INVALIDARG;
// validate the protocol
if (INTERNET_SCHEME_HTTP != uc.nScheme && INTERNET_SCHEME_HTTPS != uc.nScheme)
return E_INVALIDARG;
// copy the response data
if (ppszHost)
{
*ppszHost = PszDupA(uc.lpszHostName);
if (!*ppszHost)
return E_OUTOFMEMORY;
}
if (ppszPath)
{
*ppszPath = PszDupA(uc.lpszUrlPath);
if (!*ppszPath)
{
SafeMemFree(*ppszHost);
return E_OUTOFMEMORY;
}
}
if (pPort)
*pPort = uc.nPort;
return S_OK;
}
// --------------------------------------------------------------------------------
// Utility functions
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// HttpErrorToIxpResult
// --------------------------------------------------------------------------------
HRESULT HttpErrorToIxpResult(DWORD dwHttpError)
{
for (DWORD dw = 0; dw < ARRAYSIZE(c_rgHttpErrorMap); dw++)
{
if (c_rgHttpErrorMap[dw].dwHttpError == dwHttpError)
return c_rgHttpErrorMap[dw].ixpResult;
}
return E_FAIL;
}
// --------------------------------------------------------------------------------
// HrParseHTTPStatus
// --------------------------------------------------------------------------------
HRESULT HrParseHTTPStatus(LPSTR pszStatusStr, DWORD *pdwStatus)
{
LPSTR psz;
LPSTR pszEnd;
char chSaved;
if (!pszStatusStr || !pdwStatus)
return E_INVALIDARG;
*pdwStatus = 0;
// status is of the form "HTTP/1.1 200 OK"
psz = PszSkipWhiteA(pszStatusStr);
if ('\0' == *psz)
return E_INVALIDARG;
psz = PszScanToWhiteA(psz);
if ('\0' == *psz)
return E_INVALIDARG;
psz = PszSkipWhiteA(psz);
if ('\0' == *psz)
return E_INVALIDARG;
// psz now points at the numeric component
pszEnd = PszScanToWhiteA(psz);
if ('\0' == *psz)
return E_INVALIDARG;
// temporarily modify the string in place
chSaved = *pszEnd;
*pszEnd = '\0';
*pdwStatus = StrToInt(psz);
*pszEnd = chSaved;
return S_OK;
}
// --------------------------------------------------------------------------------
// HrGetStreamSize
// --------------------------------------------------------------------------------
static HRESULT HrGetStreamSize(LPSTREAM pstm, ULONG *pcb)
{
// Locals
HRESULT hr=S_OK;
ULARGE_INTEGER uliPos = {0,0};
LARGE_INTEGER liOrigin = {0,0};
// Seek
hr = pstm->Seek(liOrigin, STREAM_SEEK_END, &uliPos);
if (FAILED(hr))
goto error;
// set size
*pcb = uliPos.LowPart;
error:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// HrAddPropFindProps
// --------------------------------------------------------------------------------
HRESULT HrAddPropFindProps(IPropFindRequest *pRequest, const HMELE *rgEle, DWORD cEle)
{
HRESULT hr;
HMELE ele;
for (DWORD i = 0; i < cEle; ++i)
{
ele = rgEle[i];
hr = pRequest->AddProperty(
rgHTTPMailDictionary[ele].dwNamespaceID,
const_cast<char *>(rgHTTPMailDictionary[ele].pszName));
if (FAILED(hr))
goto exit;
}
exit:
return hr;
}
// --------------------------------------------------------------------------------
// HrAddPropFindSchemaProps
// --------------------------------------------------------------------------------
HRESULT HrAddPropFindSchemaProps(
IPropFindRequest *pRequest,
const XPCOLUMN *prgCols,
DWORD cCols)
{
HRESULT hr = S_OK;
HMELE ele;
for (DWORD i = 0; i < cCols; i++)
{
if (!!(prgCols[i].dwFlags & XPCF_PFREQUEST))
{
hr = pRequest->AddProperty(
rgHTTPMailDictionary[prgCols[i].ele].dwNamespaceID,
rgHTTPMailDictionary[prgCols[i].ele].pszName);
if (FAILED(hr))
goto exit;
}
}
exit:
return hr;
}
// --------------------------------------------------------------------------------
// _HrGenerateRfc821Stream
// --------------------------------------------------------------------------------
HRESULT _HrGenerateRfc821Stream(LPCSTR pszFrom,
LPHTTPTARGETLIST pTargets,
IStream **ppRfc821Stream)
{
HRESULT hr = S_OK;
IStream *pStream = NULL;
DWORD dw;
DWORD cbCloseTerm;
DWORD cbRcptTo;
IxpAssert(pszFrom);
IxpAssert(pTargets);
IxpAssert(ppRfc821Stream);
*ppRfc821Stream = NULL;
cbCloseTerm = lstrlen(c_szXMLCloseElementCRLF);
cbRcptTo = lstrlen(c_szRcptTo);
pStream = new CVirtualStream();
if (NULL == pStream)
{
hr = TraceResult(E_OUTOFMEMORY);
goto exit;
}
// write out 'mail from'
FAIL_EXIT_STREAM_WRITE((*pStream), c_szMailFrom);
FAIL_EXIT_STREAM_WRITE((*pStream), pszFrom);
FAIL_EXIT(hr = pStream->Write(c_szXMLCloseElementCRLF, cbCloseTerm, NULL));
// write out the 'rcpt to' lines
for (dw = 0; dw < pTargets->cTarget; ++dw)
{
FAIL_EXIT(hr = pStream->Write(c_szRcptTo, cbRcptTo, NULL));
FAIL_EXIT_STREAM_WRITE((*pStream), pTargets->prgTarget[dw]);
FAIL_EXIT(hr = pStream->Write(c_szXMLCloseElementCRLF, cbCloseTerm, NULL));
}
// append an extra crlf to the end of the stream
FAIL_EXIT_STREAM_WRITE((*pStream), c_szCRLF);
*ppRfc821Stream = pStream;
pStream = NULL;
exit:
SafeRelease(pStream);
return hr;
}
// --------------------------------------------------------------------------------
// _EscapeString
// --------------------------------------------------------------------------------
LPSTR _EscapeString(LPSTR pszIn)
{
CByteStream stream;
DWORD dwLen;
LPSTR pszLastNonEsc, pszNext, pszOut;
HRESULT hr;
if (NULL == pszIn)
return NULL;
pszLastNonEsc = pszIn;
pszNext = pszIn;
while (*pszNext)
{
switch (*pszNext)
{
case '<':
case '>':
case '&':
if (FAILED(hr = stream.Write(pszLastNonEsc, (ULONG) (pszNext - pszLastNonEsc), NULL)))
goto exit;
if (*pszNext == '<')
{
if (FAILED(hr = stream.Write(c_szEscLessThan, lstrlen(c_szEscLessThan), NULL)))
goto exit;
}
else if (*pszNext == '>')
{
if (FAILED(hr = stream.Write(c_szEscGreaterThan, lstrlen(c_szEscGreaterThan), NULL)))
goto exit;
}
else
{
if (FAILED(hr = stream.Write(c_szEscAmp, lstrlen(c_szEscAmp), NULL)))
goto exit;
}
pszLastNonEsc = CharNextExA(CP_ACP, pszNext, 0);
break;
}
pszNext = CharNextExA(CP_ACP, pszNext, 0);
}
if (FAILED(hr = stream.Write(pszLastNonEsc, (ULONG) (pszNext - pszLastNonEsc), NULL)))
goto exit;
FAIL_EXIT(hr = stream.HrAcquireStringA(&dwLen, (LPSTR *)&pszOut, ACQ_DISPLACE));
return pszOut;
exit:
return NULL;
}
const HMELE g_rgContactEle[] = {
HMELE_UNKNOWN,
HMELE_UNKNOWN,
HMELE_UNKNOWN,
HMELE_UNKNOWN,
HMELE_UNKNOWN,
HMELE_CONTACTS_GIVENNAME,
HMELE_CONTACTS_SN,
HMELE_CONTACTS_NICKNAME,
HMELE_CONTACTS_MAIL,
HMELE_CONTACTS_HOMESTREET,
HMELE_CONTACTS_HOMECITY,
HMELE_CONTACTS_HOMESTATE,
HMELE_CONTACTS_HOMEPOSTALCODE,
HMELE_CONTACTS_HOMECOUNTRY,
HMELE_CONTACTS_O,
HMELE_CONTACTS_STREET,
HMELE_CONTACTS_L,
HMELE_CONTACTS_ST,
HMELE_CONTACTS_POSTALCODE,
HMELE_CONTACTS_FRIENDLYCOUNTRYNAME,
HMELE_CONTACTS_HOMEPHONE,
HMELE_CONTACTS_HOMEFAX,
HMELE_CONTACTS_TELEPHONENUMBER,
HMELE_CONTACTS_FACSIMILETELEPHONENUMBER,
HMELE_CONTACTS_MOBILE,
HMELE_CONTACTS_OTHERTELEPHONE,
HMELE_CONTACTS_BDAY,
HMELE_CONTACTS_PAGER
};
#define CCHMAX_TAGBUFFER 128
HRESULT HrGeneratePostContactXML(LPHTTPCONTACTINFO pciInfo, LPVOID *ppvXML, DWORD *pdwLen)
{
HRESULT hr = S_OK;
CByteStream stream;
CDAVNamespaceArbiterImp dna;
DWORD dwIndex, dwSize = ARRAYSIZE(g_rgContactEle);
DWORD iBufferSize;
TCHAR szTagBuffer[CCHMAX_TAGBUFFER+1];
LPSTR *prgsz = (LPSTR*)pciInfo, pszEsc;
LPCSTR pszPropName;
*ppvXML = NULL;
*pdwLen = 0;
if (NULL == ppvXML)
return E_INVALIDARG;
// write the DAV header. we ALWAYS post using the windows-1252 code
// page for this release.
if (FAILED(hr = stream.Write(c_szXML1252Head, lstrlen(c_szXML1252Head), NULL)))
goto exit;
dna.m_rgbNsUsed[DAVNAMESPACE_CONTACTS] = TRUE;
dna.m_rgbNsUsed[DAVNAMESPACE_DAV] = TRUE;
// write out the contacts header
if (FAILED(hr = stream.Write(c_szContactHead, lstrlen(c_szContactHead), NULL)))
goto exit;
if (FAILED(hr = dna.WriteNamespaces(&stream)))
goto exit;
if (FAILED(hr = stream.Write(c_szXMLCloseElement, lstrlen(c_szXMLCloseElement), NULL)))
goto exit;
// [PaulHi] 3/11/99 Implementing WAB/HM group contact syncing
// Include the xml group tag if this is a group contact item
if (pciInfo->tyContact == HTTPMAIL_CT_GROUP)
{
if (FAILED(hr = stream.Write(c_szCRLFTab, lstrlen(c_szCRLFTab), NULL)))
goto exit;
if (FAILED(hr = stream.Write(c_szGroupSwitch, lstrlen(c_szGroupSwitch), NULL)))
goto exit;
}
for (dwIndex = 0; dwIndex < dwSize; dwIndex ++)
{
if (prgsz[dwIndex] && g_rgContactEle[dwIndex] != HMELE_UNKNOWN)
{
pszPropName = rgHTTPMailDictionary[g_rgContactEle[dwIndex]].pszName;
if (FAILED(hr = stream.Write(c_szOpenContactNamespace, lstrlen(c_szOpenContactNamespace), NULL)))
goto exit;
if (FAILED(hr = stream.Write(pszPropName, lstrlen(pszPropName), NULL)))
goto exit;
if (FAILED(hr = stream.Write(c_szXMLCloseElement, lstrlen(c_szXMLCloseElement), NULL)))
goto exit;
pszEsc = _EscapeString(prgsz[dwIndex]);
if (!pszEsc)
goto exit;
hr = stream.Write(pszEsc, lstrlen(pszEsc), NULL);
SafeMemFree(pszEsc);
if (FAILED(hr))
goto exit;
if (FAILED(hr = stream.Write(c_szCloseContactNamespace, lstrlen(c_szCloseContactNamespace), NULL)))
goto exit;
if (FAILED(hr = stream.Write(pszPropName, lstrlen(pszPropName), NULL)))
goto exit;
if (FAILED(hr = stream.Write(c_szXMLCloseElement, lstrlen(c_szXMLCloseElement), NULL)))
goto exit;
}
}
if (FAILED(hr = stream.Write(c_szContactTail, lstrlen(c_szContactTail), NULL)))
goto exit;
FAIL_EXIT(hr = stream.HrAcquireStringA(pdwLen, (LPSTR *)ppvXML, ACQ_DISPLACE));
exit:
return hr;
}
HRESULT HrCreatePatchContactRequest(LPHTTPCONTACTINFO pciInfo, IPropPatchRequest **ppRequest)
{
HRESULT hr = S_OK;
LPSTR *prgsz = (LPSTR*)pciInfo, pszEsc;
DWORD dwIndex, dwSize = ARRAYSIZE(g_rgContactEle);
CPropPatchRequest *pRequest = NULL;
*ppRequest = NULL;
pRequest = new CPropPatchRequest();
if (NULL == pRequest)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// always specify windows-1252 encoding for this release
pRequest->SpecifyWindows1252Encoding(TRUE);
for (dwIndex = 0; dwIndex < dwSize; dwIndex ++)
{
if (g_rgContactEle[dwIndex] != HMELE_UNKNOWN)
{
if (prgsz[dwIndex])
{
// values with content are added. Empty strings are deleted. Null values are ignored.
if (*(prgsz[dwIndex]))
{
pszEsc = _EscapeString(prgsz[dwIndex]);
if (!pszEsc)
goto exit;
hr = pRequest->SetProperty(DAVNAMESPACE_CONTACTS, const_cast<char *>(rgHTTPMailDictionary[g_rgContactEle[dwIndex]].pszName), pszEsc);
SafeMemFree(pszEsc);
if (FAILED(hr))
goto exit;
}
else
{
if (FAILED(hr = pRequest->RemoveProperty(DAVNAMESPACE_CONTACTS, const_cast<char *>(rgHTTPMailDictionary[g_rgContactEle[dwIndex]].pszName))))
goto exit;
}
}
}
}
exit:
if (FAILED(hr))
SafeRelease(pRequest);
else
*ppRequest = pRequest;
return hr;
}
HRESULT HrGenerateSimpleBatchXML(
LPCSTR pszRootName,
LPHTTPTARGETLIST pTargets,
LPVOID *ppvXML,
DWORD *pdwLen)
{
HRESULT hr = S_OK;
CByteStream stream;
DWORD dwIndex;
DWORD dwHrefHeadLen, dwHrefTailLen;
IxpAssert(NULL != pszRootName);
IxpAssert(NULL != pTargets);
IxpAssert(pTargets->cTarget >= 1);
IxpAssert(NULL != pTargets->prgTarget);
IxpAssert(NULL != ppvXML);
IxpAssert(NULL != pdwLen);
dwHrefHeadLen = lstrlen(c_szHrefHead);
dwHrefTailLen = lstrlen(c_szHrefTail);
// write the DAV header
FAIL_EXIT_STREAM_WRITE(stream, c_szXMLHead);
FAIL_EXIT_STREAM_WRITE(stream, c_szBatchHead1);
FAIL_EXIT_STREAM_WRITE(stream, pszRootName);
FAIL_EXIT_STREAM_WRITE(stream, c_szBatchHead2);
FAIL_EXIT_STREAM_WRITE(stream, c_szTargetHead);
// write out the targets
for (dwIndex = 0; dwIndex < pTargets->cTarget; dwIndex++)
{
if (FAILED(hr = stream.Write(c_szHrefHead, dwHrefHeadLen, NULL)))
goto exit;
FAIL_EXIT_STREAM_WRITE(stream, pTargets->prgTarget[dwIndex]);
if (FAILED(hr = stream.Write(c_szHrefTail, dwHrefTailLen, NULL)))
goto exit;
}
FAIL_EXIT_STREAM_WRITE(stream, c_szTargetTail);
FAIL_EXIT_STREAM_WRITE(stream, c_szBatchTail);
FAIL_EXIT_STREAM_WRITE(stream, pszRootName);
FAIL_EXIT_STREAM_WRITE(stream, c_szXMLCloseElement);
// take ownership of the bytestream
FAIL_EXIT(hr = stream.HrAcquireStringA(pdwLen, (LPSTR *)ppvXML, ACQ_DISPLACE));
exit:
return hr;
}
HRESULT HrGenerateMultiDestBatchXML(
LPCSTR pszRootName,
LPHTTPTARGETLIST pTargets,
LPHTTPTARGETLIST pDestinations,
LPVOID *ppvXML,
DWORD *pdwLen)
{
HRESULT hr = S_OK;
CByteStream stream;
DWORD dwIndex;
IxpAssert(NULL != pszRootName);
IxpAssert(NULL != pTargets);
IxpAssert(NULL != pDestinations);
IxpAssert(NULL != ppvXML);
IxpAssert(NULL != pdwLen);
// source and destination must have same count
if (pTargets->cTarget != pDestinations->cTarget)
return E_INVALIDARG;
*ppvXML = NULL;
*pdwLen = 0;
// write the DAV header
FAIL_EXIT_STREAM_WRITE(stream, c_szXMLHead);
// write the command header
FAIL_EXIT_STREAM_WRITE(stream, c_szBatchHead1);
FAIL_EXIT_STREAM_WRITE(stream, pszRootName);
FAIL_EXIT_STREAM_WRITE(stream, c_szBatchHead2);
// write out the targets
for (dwIndex = 0; dwIndex < pTargets->cTarget; dwIndex++)
{
IxpAssert(NULL != pTargets->prgTarget[dwIndex]);
if (NULL != pTargets->prgTarget[dwIndex])
{
FAIL_EXIT_STREAM_WRITE(stream, c_szTargetHead);
FAIL_EXIT_STREAM_WRITE(stream, c_szHrefHead);
FAIL_EXIT_STREAM_WRITE(stream, pTargets->prgTarget[dwIndex]);
FAIL_EXIT_STREAM_WRITE(stream, c_szHrefTail);
if (NULL != pDestinations->prgTarget[dwIndex])
{
FAIL_EXIT_STREAM_WRITE(stream, c_szDestHead);
FAIL_EXIT_STREAM_WRITE(stream, pDestinations->prgTarget[dwIndex]);
FAIL_EXIT_STREAM_WRITE(stream, c_szDestTail);
}
FAIL_EXIT_STREAM_WRITE(stream, c_szTargetTail);
}
}
FAIL_EXIT_STREAM_WRITE(stream, c_szBatchTail);
FAIL_EXIT_STREAM_WRITE(stream, pszRootName);
FAIL_EXIT_STREAM_WRITE(stream, c_szXMLCloseElement);
// take ownership of the byte stream
hr = stream.HrAcquireStringA(pdwLen, (LPSTR *)ppvXML, ACQ_DISPLACE);
exit:
return hr;
}
HRESULT HrCopyStringList(LPCSTR *rgszInList, LPCSTR **prgszOutList)
{
DWORD cStrings = 0;
HRESULT hr = S_OK;
LPCSTR pszCur;
DWORD i = 0;
IxpAssert(NULL != rgszInList);
IxpAssert(NULL != prgszOutList);
*prgszOutList = NULL;
// count the strings in the list
while (NULL != rgszInList[i++])
++cStrings;
// allocate the new list
if (!MemAlloc((void **)prgszOutList, (cStrings + 1) * sizeof(LPCSTR)))
{
hr = E_OUTOFMEMORY;
goto exit;
}
// copy the strings over. if an allocation fails,
// stay in the loop and null out all of the slots
// that haven't been filled
for (i = 0; i <= cStrings; i++)
{
if (SUCCEEDED(hr) && NULL != rgszInList[i])
{
(*prgszOutList)[i] = PszDupA(rgszInList[i]);
if (NULL == (*prgszOutList)[i])
hr = E_OUTOFMEMORY;
}
else
(*prgszOutList)[i] = NULL;
}
if (FAILED(hr))
{
FreeStringList(*prgszOutList);
*prgszOutList = NULL;
}
exit:
return hr;
}
void FreeStringList(LPCSTR *rgszList)
{
DWORD i = 0;
IxpAssert(NULL != rgszList);
if (rgszList)
{
while (NULL != rgszList[i])
MemFree((void *)rgszList[i++]);
MemFree(rgszList);
}
}
// --------------------------------------------------------------------------------
// class CHTTPMailTransport
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CHTTPMailTransport
// --------------------------------------------------------------------------------
CHTTPMailTransport::CHTTPMailTransport(void) :
m_cRef(1),
m_fHasServer(FALSE),
m_fHasRootProps(FALSE),
m_fTerminating(FALSE),
m_status(IXP_DISCONNECTED),
m_hInternet(NULL),
m_hConnection(NULL),
m_pszUserAgent(NULL),
m_pLogFile(NULL),
m_pCallback(NULL),
m_pParser(NULL),
m_hwnd(NULL),
m_hevPendingCommand(NULL),
m_opPendingHead(NULL),
m_opPendingTail(NULL),
m_pszCurrentHost(NULL),
m_nCurrentPort(INTERNET_INVALID_PORT_NUMBER)
{
DWORD dwTempID;
HANDLE hThread = NULL;
InitializeCriticalSection(&m_cs);
ZeroMemory(&m_rServer, sizeof(INETSERVER));
ZeroMemory(&m_op, sizeof(HTTPMAILOPERATION));
ZeroMemory(&m_rootProps, sizeof(ROOTPROPS));
m_op.rResponse.command = HTTPMAIL_NONE;
m_hevPendingCommand = CreateEvent(NULL, TRUE, FALSE, NULL);
// Create the IO thread
hThread = CreateThread(NULL, 0, IOThreadFuncProxy, (LPVOID)this, 0, &dwTempID);
// We do not need to manipulate the IO Thread through its handle, so close it
// This will NOT terminate the thread
if (NULL != hThread)
{
CloseHandle(hThread);
}
DllAddRef();
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::~CHTTPMailTransport
// --------------------------------------------------------------------------------
CHTTPMailTransport::~CHTTPMailTransport(void)
{
IxpAssert(0 == m_cRef);
// Shouldn't be pending commands
IxpAssert(HTTPMAIL_NONE == m_op.rResponse.command);
IxpAssert(!m_opPendingHead);
IxpAssert(!m_opPendingTail);
IxpAssert(m_fTerminating);
// Destroy the critical sections
DeleteCriticalSection(&m_cs);
// Close the window
if ((NULL != m_hwnd) && (FALSE != IsWindow(m_hwnd)))
::SendMessage(m_hwnd, WM_CLOSE, 0, 0);
SafeMemFree(m_pszUserAgent);
CloseHandle(m_hevPendingCommand);
SafeMemFree(m_rootProps.pszAdbar);
SafeMemFree(m_rootProps.pszContacts);
SafeMemFree(m_rootProps.pszInbox);
SafeMemFree(m_rootProps.pszOutbox);
SafeMemFree(m_rootProps.pszSendMsg);
SafeMemFree(m_rootProps.pszSentItems);
SafeMemFree(m_rootProps.pszDeletedItems);
SafeMemFree(m_rootProps.pszDrafts);
SafeMemFree(m_rootProps.pszMsgFolderRoot);
SafeMemFree(m_rootProps.pszSig);
SafeMemFree(m_pszCurrentHost);
SafeRelease(m_pLogFile);
SafeRelease(m_pCallback);
SafeRelease(m_pParser);
SafeInternetCloseHandle(m_hInternet);
// BUGBUG: clean up window, thread and event, release buffers, etc
DllRelease();
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::HrConnectToHost
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::HrConnectToHost(
LPSTR pszHostName,
INTERNET_PORT nPort,
LPSTR pszUserName,
LPSTR pszPassword)
{
IxpAssert(m_hInternet);
// if a connection exists, determine if it is to the same host/port
// that the caller is specifying.
if (NULL != m_hConnection)
{
// if we are already connected to the correct host, return immediately
if (m_nCurrentPort == nPort && m_pszCurrentHost && (lstrcmp(pszHostName, m_pszCurrentHost) == 0))
return S_OK;
// if we are connected to the wrong server, close the existing connection
SafeInternetCloseHandle(m_hConnection);
SafeMemFree(m_pszCurrentHost);
m_nCurrentPort = INTERNET_INVALID_PORT_NUMBER;
}
// establish a connection to the specified server
m_hConnection = InternetConnect(
m_hInternet,
pszHostName,
nPort,
NULL, // user name
NULL, // password
INTERNET_SERVICE_HTTP, // service
0, // flags
reinterpret_cast<DWORD_PTR>(this)); // context
// what can cause this?
if (NULL == m_hConnection)
return E_OUTOFMEMORY;
// save the host name. don't bother checking for failure...we just won't reuse
// the connection next time through.
m_pszCurrentHost = PszDupA(pszHostName);
m_nCurrentPort = nPort;
return S_OK;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::DoLogonPrompt
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::DoLogonPrompt(void)
{
HRESULT hr = S_OK;
IHTTPMailCallback *pCallback = NULL;
EnterCriticalSection(&m_cs);
if (m_pCallback)
{
pCallback = m_pCallback;
pCallback->AddRef();
}
else
hr = E_FAIL;
LeaveCriticalSection(&m_cs);
if (pCallback)
{
hr = pCallback->OnLogonPrompt(&m_rServer, this);
pCallback->Release();
}
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::DoGetParentWindow
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::DoGetParentWindow(HWND *phwndParent)
{
HRESULT hr = S_OK;
IHTTPMailCallback *pCallback = NULL;
EnterCriticalSection(&m_cs);
if (m_pCallback)
{
pCallback = m_pCallback;
pCallback->AddRef();
}
else
hr = E_FAIL;
LeaveCriticalSection(&m_cs);
if (pCallback)
{
hr = pCallback->GetParentWindow(phwndParent);
pCallback->Release();
}
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CreateWnd
// --------------------------------------------------------------------------------
BOOL CHTTPMailTransport::CreateWnd()
{
WNDCLASS wc;
IxpAssert(!m_hwnd);
if (m_hwnd)
return TRUE;
if (!GetClassInfo(g_hLocRes, s_szHTTPMailWndClass, &wc))
{
wc.style = 0;
wc.lpfnWndProc = CHTTPMailTransport::WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hLocRes;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = s_szHTTPMailWndClass;
RegisterClass(&wc);
}
m_hwnd = CreateWindowEx(0,
s_szHTTPMailWndClass,
s_szHTTPMailWndClass,
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
g_hLocRes,
(LPVOID)this);
return (NULL != m_hwnd);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::DequeueNextOperation
// --------------------------------------------------------------------------------
BOOL CHTTPMailTransport::DequeueNextOperation(void)
{
if (NULL == m_opPendingHead)
return FALSE;
IxpAssert(HTTPMAIL_NONE == m_op.rResponse.command);
IxpAssert(HTTPMAIL_NONE != m_opPendingHead->command);
m_op.rResponse.command = m_opPendingHead->command;
m_op.pfnState = m_opPendingHead->pfnState;
m_op.cState = m_opPendingHead->cState;
m_op.pszUrl = m_opPendingHead->pszUrl;
m_op.pszDestination = m_opPendingHead->pszDestination;
m_op.pszContentType = m_opPendingHead->pszContentType;
m_op.pvData = m_opPendingHead->pvData;
m_op.cbDataLen = m_opPendingHead->cbDataLen;
m_op.dwContext = m_opPendingHead->dwContext;
m_op.dwDepth = m_opPendingHead->dwDepth;
m_op.dwRHFlags = m_opPendingHead->dwRHFlags;
m_op.dwMIFlags = m_opPendingHead->dwMIFlags;
m_op.tyProp = m_opPendingHead->tyProp;
m_op.fBatch = m_opPendingHead->fBatch;
m_op.rgszAcceptTypes = m_opPendingHead->rgszAcceptTypes;
m_op.pPropFindRequest = m_opPendingHead->pPropFindRequest;
m_op.pPropPatchRequest = m_opPendingHead->pPropPatchRequest;
m_op.pParseFuncs = m_opPendingHead->pParseFuncs;
m_op.pHeaderStream = m_opPendingHead->pHeaderStream;
m_op.pBodyStream = m_opPendingHead->pBodyStream;
m_op.pszFolderTimeStamp = m_opPendingHead->pszFolderTimeStamp;
m_op.pszRootTimeStamp = m_opPendingHead->pszRootTimeStamp;
//m_op.pszFolderName = m_opPendingHead->pszFolderName;
LPHTTPQUEUEDOP pDelete = m_opPendingHead;
m_opPendingHead = m_opPendingHead->pNext;
if (NULL == m_opPendingHead)
m_opPendingTail = NULL;
MemFree(pDelete);
return TRUE;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FlushQueue
// --------------------------------------------------------------------------------
void CHTTPMailTransport::FlushQueue(void)
{
// destroy any commands that are pending.
// REVIEW: these commands need to notify their callers
LPHTTPQUEUEDOP pOp = m_opPendingHead;
LPHTTPQUEUEDOP pNext;
while (pOp)
{
pNext = pOp->pNext;
SafeMemFree(pOp->pszUrl);
SafeMemFree(pOp->pszDestination);
if (pOp->pszContentType)
MemFree((void *)pOp->pszContentType);
SafeMemFree(pOp->pvData);
if (pOp->rgszAcceptTypes)
FreeStringList(pOp->rgszAcceptTypes);
SafeRelease(pOp->pPropFindRequest);
SafeRelease(pOp->pPropPatchRequest);
MemFree(pOp);
pOp = pNext;
}
m_opPendingHead = m_opPendingTail = NULL;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::TerminateIOThread
// --------------------------------------------------------------------------------
void CHTTPMailTransport::TerminateIOThread(void)
{
EnterCriticalSection(&m_cs);
// acquire a reference to the transport that will be owned
// by the io thread. the reference will be release when the
// io thread exits. this reference is not acquired when the
// thread is created, because it would prevent the transport
// from going away.
AddRef();
m_fTerminating = TRUE;
FlushQueue();
// signal the io thread to wake it.
SetEvent(m_hevPendingCommand);
LeaveCriticalSection(&m_cs);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::IOThreadFunc
// --------------------------------------------------------------------------------
DWORD CALLBACK CHTTPMailTransport::IOThreadFuncProxy(PVOID pv)
{
CHTTPMailTransport *pHTTPMail = (CHTTPMailTransport*)pv;
DWORD dwResult = S_OK;
IxpAssert(pHTTPMail);
// Initialize COM
if(S_OK == (dwResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
dwResult = pHTTPMail->IOThreadFunc();
//Bug #101165 -- MSXML needs notification to clean up per thread data.
CoUninitialize();
}
return dwResult;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::IOThreadFunc
// Called by IOThreadProxy to transition into an object method
// --------------------------------------------------------------------------------
DWORD CHTTPMailTransport::IOThreadFunc()
{
LPSTR pszVerb = NULL;
BOOL bQueueEmpty = FALSE;
// block until a command is pending.
while (WAIT_OBJECT_0 == WaitForSingleObject(m_hevPendingCommand, INFINITE))
{
if (IsTerminating())
break;
// Reset the event
ResetEvent(m_hevPendingCommand);
// unhook commands from the queue one at a time, and process them until
// the queue is empty
while (TRUE)
{
// dequeue the next operation
EnterCriticalSection(&m_cs);
IxpAssert(HTTPMAIL_NONE == m_op.rResponse.command);
bQueueEmpty = !DequeueNextOperation();
// if no commands left, break out of the loop and block
LeaveCriticalSection(&m_cs);
if (bQueueEmpty)
break;
DoOperation();
}
if (IsTerminating())
break;
}
IxpAssert(IsTerminating());
// TerminateIOThread acquired a reference that gets released here
Release();
return S_OK;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::WndProc
// --------------------------------------------------------------------------------
LRESULT CALLBACK CHTTPMailTransport::WndProc(HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
CHTTPMailTransport *pThis = (CHTTPMailTransport*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
LRESULT lr = 0;
switch (msg)
{
case WM_NCCREATE:
IxpAssert(!pThis);
pThis = (CHTTPMailTransport*)((LPCREATESTRUCT)lParam)->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pThis);
lr = DefWindowProc(hwnd, msg, wParam, lParam);
break;
case SPM_HTTPMAIL_SENDRESPONSE:
IxpAssert(pThis);
pThis->InvokeResponseCallback();
break;
case SPM_HTTPMAIL_LOGONPROMPT:
IxpAssert(pThis);
lr = pThis->DoLogonPrompt();
break;
case SPM_HTTPMAIL_GETPARENTWINDOW:
IxpAssert(pThis);
lr = pThis->DoGetParentWindow((HWND *)wParam);
break;
default:
lr = DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
return lr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::Reset
// --------------------------------------------------------------------------------
void CHTTPMailTransport::Reset(void)
{
// REVIEW: this is incomplete. Should we be aborting the current command?
EnterCriticalSection(&m_cs);
SafeRelease(m_pLogFile);
SafeInternetCloseHandle(m_hConnection);
SafeInternetCloseHandle(m_hInternet);
SafeMemFree(m_pszUserAgent);
SafeRelease(m_pCallback);
m_status = IXP_DISCONNECTED;
m_fHasServer = FALSE;
ZeroMemory(&m_rServer, sizeof(INETSERVER));
LeaveCriticalSection(&m_cs);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::QueryInterface
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::QueryInterface(REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr = S_OK;
// Validate params
if (NULL == ppv)
{
hr = TrapError(E_INVALIDARG);
goto exit;
}
// Initialize params
*ppv = NULL;
// IID_IUnknown
if (IID_IUnknown == riid)
*ppv = ((IUnknown *)(IHTTPMailTransport *)this);
// IID_IInternetTransport
else if (IID_IInternetTransport == riid)
*ppv = (IInternetTransport *)this;
// IID_IHTTPMailTransport
else if (IID_IHTTPMailTransport == riid)
*ppv = (IHTTPMailTransport *)this;
// IID_IXMLNodeFactory
else if (IID_IXMLNodeFactory == riid)
*ppv = (IXMLNodeFactory *)this;
else if (IID_IHTTPMailTransport2 == riid)
*ppv = (IHTTPMailTransport2 *)this;
// if not NULL, acquire a reference and return
if (NULL != *ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
goto exit;
}
hr = TrapError(E_NOINTERFACE);
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::AddRef
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CHTTPMailTransport::AddRef(void)
{
return ++m_cRef;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::Release
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CHTTPMailTransport::Release(void)
{
if (0 != --m_cRef)
return m_cRef;
// our refcount dropped to zero, and we aren't terminating,
// begin terminating
if (!IsTerminating())
{
TerminateIOThread();
return 1;
}
// if we were terminating, and our refCount dropped to zero,
// then the iothread has been unwound and we can safely exit.
delete this;
return 0;
}
// ----------------------------------------------------------------------------
// IInternetTransport methods
// ----------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// CHTTPMailTransport::Connect
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::Connect(LPINETSERVER pInetServer,
boolean fAuthenticate,
boolean fCommandLogging)
{
HRESULT hr = S_OK;
if (NULL == pInetServer || FIsEmptyA(pInetServer->szServerName))
return TrapError(E_INVALIDARG);
// Thread safety
EnterCriticalSection(&m_cs);
// not init
if (NULL == m_hInternet || NULL == m_pCallback)
{
hr = TrapError(IXP_E_NOT_INIT);
goto exit;
}
FAIL_CREATEWND;
// busy
if (IXP_DISCONNECTED != m_status || m_fHasServer)
{
hr = TrapError(IXP_E_ALREADY_CONNECTED);
goto exit;
}
// copy the server struct
CopyMemory(&m_rServer, pInetServer, sizeof(INETSERVER));
m_fHasServer = TRUE;
m_fHasRootProps = FALSE;
exit:
// ThreadSafety
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::DropConnection
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::DropConnection(void)
{
// this function is called to stop any current and pending i/o
// Locals
HRESULT hr = S_OK;
BOOL fSendResponse;
EnterCriticalSection(&m_cs);
// flush any pending i/o from the queue
FlushQueue();
// if a command is being processed, mark it aborted and
// send a response if necessary. stay in the critical
// section to prevent the io thread from sending any
// notifications at the same time.
if (m_op.rResponse.command != HTTPMAIL_NONE)
{
m_op.fAborted = TRUE;
m_op.rResponse.fDone = TRUE;
}
Disconnect();
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::Disconnect
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::Disconnect(void)
{
// Locals
HRESULT hr = S_OK;
// Thread safety
EnterCriticalSection(&m_cs);
if (NULL == m_hConnection)
{
hr = TrapError(IXP_E_NOT_INIT);
goto exit;
}
// Disconnecting
if (m_pCallback)
m_pCallback->OnStatus(IXP_DISCONNECTING, this);
SafeInternetCloseHandle(m_hConnection);
m_status = IXP_DISCONNECTED;
ZeroMemory(&m_rServer, sizeof(INETSERVER));
if (m_pCallback)
m_pCallback->OnStatus(IXP_DISCONNECTED, this);
// Close the window
if ((NULL != m_hwnd) && (FALSE != IsWindow(m_hwnd)))
::SendMessage(m_hwnd, WM_CLOSE, 0, 0);
m_hwnd = NULL;
m_fHasServer = FALSE;
exit:
// Thread safety
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::IsState
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::IsState(IXPISSTATE isstate)
{
// Locals
HRESULT hr = S_OK;
// Thread safety
EnterCriticalSection(&m_cs);
switch(isstate)
{
// are we connected?
case IXP_IS_CONNECTED:
hr = (NULL == m_hConnection) ? S_FALSE : S_OK;
break;
// are we busy?
case IXP_IS_BUSY:
hr = (HTTPMAIL_NONE != m_op.rResponse.command) ? S_OK : S_FALSE;
break;
// are we ready
case IXP_IS_READY:
hr = (HTTPMAIL_NONE == m_op.rResponse.command) ? S_OK : S_FALSE;
break;
case IXP_IS_AUTHENTICATED:
// REVIEW
hr = S_OK;
break;
default:
IxpAssert(FALSE);
break;
}
// Thread safety
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::GetServerInfo
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::GetServerInfo(LPINETSERVER pInetServer)
{
// check params
if (NULL == pInetServer)
return TrapError(E_INVALIDARG);
// Thread safety
EnterCriticalSection(&m_cs);
// Copy server info
CopyMemory(pInetServer, &m_rServer, sizeof(INETSERVER));
// Thread safety
LeaveCriticalSection(&m_cs);
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::GetIXPType
// --------------------------------------------------------------------------------
STDMETHODIMP_(IXPTYPE) CHTTPMailTransport::GetIXPType(void)
{
return IXP_HTTPMail;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::InetServerFromAccount
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::InetServerFromAccount(IImnAccount *pAccount, LPINETSERVER pInetServer)
{
HRESULT hr = S_OK;
DWORD fAlwaysPromptPassword = FALSE;
// check params
if (NULL == pAccount || NULL == pInetServer)
return TrapError(E_INVALIDARG);
// ZeroInit
ZeroMemory(pInetServer, sizeof(INETSERVER));
// Get the account name
if (FAILED(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, pInetServer->szAccount, ARRAYSIZE(pInetServer->szAccount))))
{
hr = TrapError(IXP_E_INVALID_ACCOUNT);
goto exit;
}
// Get the RAS connectoid
if (FAILED(pAccount->GetPropSz(AP_RAS_CONNECTOID, pInetServer->szConnectoid, ARRAYSIZE(pInetServer->szConnectoid))))
*pInetServer->szConnectoid = '\0';
// Connection Type
Assert(sizeof(pInetServer->rasconntype) == sizeof(DWORD));
if (FAILED(pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, (DWORD *)&pInetServer->rasconntype)))
pInetServer->rasconntype = RAS_CONNECT_LAN;
// Get Server Name
hr = pAccount->GetPropSz(AP_HTTPMAIL_SERVER, pInetServer->szServerName, sizeof(pInetServer->szServerName));
if (FAILED(hr))
{
hr = TrapError(IXP_E_INVALID_ACCOUNT);
goto exit;
}
// Password
if (FAILED(pAccount->GetPropDw(AP_HTTPMAIL_PROMPT_PASSWORD, &fAlwaysPromptPassword)) || FALSE == fAlwaysPromptPassword)
pAccount->GetPropSz(AP_HTTPMAIL_PASSWORD, pInetServer->szPassword, sizeof(pInetServer->szPassword));
if (fAlwaysPromptPassword)
pInetServer->dwFlags |= ISF_ALWAYSPROMPTFORPASSWORD;
// Sicily
Assert(sizeof(pInetServer->fTrySicily) == sizeof(DWORD));
pAccount->GetPropDw(AP_HTTPMAIL_USE_SICILY, (DWORD *)&pInetServer->fTrySicily);
// User Name
pAccount->GetPropSz(AP_HTTPMAIL_USERNAME, pInetServer->szUserName, sizeof(pInetServer->szUserName));
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::HandsOffCallback
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::HandsOffCallback(void)
{
// Locals
HRESULT hr = S_OK;
// Thread safety
EnterCriticalSection(&m_cs);
// No current callback
if (NULL == m_pCallback)
{
hr = TrapError(S_FALSE);
goto exit;
}
// Release it
SafeRelease(m_pCallback);
exit:
// Thread safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::GetStatus
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::GetStatus(IXPSTATUS *pCurrentStatus)
{
if (NULL == pCurrentStatus)
return TrapError(E_INVALIDARG);
*pCurrentStatus = m_status;
return S_OK;
}
// ----------------------------------------------------------------------------
// IHTTPMailTransport methods
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// CHTTPMailTransport::GetProperty
// ----------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::GetProperty(
HTTPMAILPROPTYPE type,
LPSTR *ppszProp)
{
HRESULT hr = S_OK;
if (type <= HTTPMAIL_PROP_INVALID || type >= HTTPMAIL_PROP_LAST)
return E_INVALIDARG;
if (ppszProp)
*ppszProp = NULL;
if (!m_fHasRootProps || NULL == ppszProp)
{
IF_FAILEXIT(hr = QueueGetPropOperation(type));
}
switch (type)
{
case HTTPMAIL_PROP_ADBAR:
*ppszProp = PszDupA(m_rootProps.pszAdbar);
break;
case HTTPMAIL_PROP_CONTACTS:
*ppszProp = PszDupA(m_rootProps.pszContacts);
break;
case HTTPMAIL_PROP_INBOX:
*ppszProp = PszDupA(m_rootProps.pszInbox);
break;
case HTTPMAIL_PROP_OUTBOX:
*ppszProp = PszDupA(m_rootProps.pszOutbox);
break;
case HTTPMAIL_PROP_SENDMSG:
*ppszProp = PszDupA(m_rootProps.pszSendMsg);
break;
case HTTPMAIL_PROP_SENTITEMS:
*ppszProp = PszDupA(m_rootProps.pszSentItems);
break;
case HTTPMAIL_PROP_DELETEDITEMS:
*ppszProp = PszDupA(m_rootProps.pszDeletedItems);
break;
case HTTPMAIL_PROP_DRAFTS:
*ppszProp = PszDupA(m_rootProps.pszDrafts);
break;
case HTTPMAIL_PROP_MSGFOLDERROOT:
*ppszProp = PszDupA(m_rootProps.pszMsgFolderRoot);
break;
case HTTPMAIL_PROP_SIG:
*ppszProp = PszDupA(m_rootProps.pszSig);
break;
default:
hr = TrapError(E_INVALIDARG);
break;
}
if (SUCCEEDED(hr) && !*ppszProp)
hr = IXP_E_HTTP_ROOT_PROP_NOT_FOUND;
exit:
return hr;
}
HRESULT CHTTPMailTransport::QueueGetPropOperation(HTTPMAILPROPTYPE type)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp;
if (!m_fHasServer || NULL == m_rServer.szServerName)
{
hr = E_FAIL;
goto exit;
}
FAIL_CREATEWND;
// queue the getprop operation
if (FAILED(hr = AllocQueuedOperation(m_rServer.szServerName, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_GETPROP;
pOp->tyProp = type;
pOp->pfnState = c_rgpfnRootProps;
pOp->cState = ARRAYSIZE(c_rgpfnRootProps);
pOp->pParseFuncs = c_rgpfnRootPropsParse;
pOp->dwRHFlags = (RH_XMLCONTENTTYPE | RH_BRIEF);
QueueOperation(pOp);
hr = E_PENDING;
exit:
return hr;
}
// ----------------------------------------------------------------------------
// CHTTPMailTransport::GetPropertyDw
// ----------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::GetPropertyDw(
HTTPMAILPROPTYPE type,
LPDWORD lpdwProp)
{
HRESULT hr = S_OK;
if (type <= HTTPMAIL_PROP_INVALID || type >= HTTPMAIL_PROP_LAST)
IF_FAILEXIT(hr = E_INVALIDARG);
if (lpdwProp)
*lpdwProp = 0;
if (!m_fHasRootProps || NULL == lpdwProp)
{
IF_FAILEXIT(hr = QueueGetPropOperation(type));
}
switch (type)
{
case HTTPMAIL_PROP_MAXPOLLINGINTERVAL:
*lpdwProp = m_rootProps.dwMaxPollingInterval;
break;
default:
hr = TrapError(E_INVALIDARG);
break;
}
exit:
return hr;
}
// ----------------------------------------------------------------------------
// CHTTPMailTransport::CommandGET
// ----------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandGET(LPCSTR pszUrl,
LPCSTR *rgszAcceptTypes,
BOOL fTranslate,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
LPCSTR *rgszAcceptTypesCopy = NULL;
if (NULL == pszUrl)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (NULL != rgszAcceptTypes)
{
hr = HrCopyStringList(rgszAcceptTypes, &rgszAcceptTypesCopy);
if (FAILED(hr))
goto exit;
}
if (FAILED(hr = AllocQueuedOperation(pszUrl, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_GET;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfGet;
pOp->cState = ARRAYSIZE(c_rgpfGet);
pOp->rgszAcceptTypes = rgszAcceptTypesCopy;
if (!fTranslate)
pOp->dwRHFlags = RH_TRANSLATEFALSE;
rgszAcceptTypesCopy = NULL;
QueueOperation(pOp);
exit:
if (NULL != rgszAcceptTypesCopy)
FreeStringList(rgszAcceptTypesCopy);
return hr;
}
// ----------------------------------------------------------------------------
// CHTTPMailTransport::CommandPUT
// ----------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandPUT(
LPCSTR pszPath,
LPVOID lpvData,
ULONG cbSize,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
LPCSTR pszLocalContentType = NULL;
LPVOID lpvCopy = NULL;
if (NULL == pszPath || NULL == lpvData || 0 == cbSize)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (!MemAlloc(&lpvCopy, cbSize))
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
CopyMemory(lpvCopy, lpvData, cbSize);
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_PUT;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnPut;
pOp->cState = ARRAYSIZE(c_rgpfnPut);
pOp->pvData = lpvCopy;
lpvCopy = NULL;
pOp->cbDataLen = cbSize;
QueueOperation(pOp);
exit:
SafeMemFree(lpvCopy);
return hr;
}
// ----------------------------------------------------------------------------
// CHTTPMailTransport::CommandPOST
// ----------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandPOST(
LPCSTR pszPath,
IStream *pStream,
LPCSTR pszContentType,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
LPCSTR pszLocalContentType = NULL;
if (NULL == pszPath || NULL == pStream)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (pszContentType)
{
pszLocalContentType = PszDupA(pszContentType);
if (NULL == pszLocalContentType)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
}
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_POST;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnPost;
pOp->cState = ARRAYSIZE(c_rgpfnPost);
pOp->pBodyStream = pStream;
pOp->pBodyStream->AddRef();
pOp->pszContentType = pszLocalContentType;
pszLocalContentType = NULL;
QueueOperation(pOp);
exit:
if (pszLocalContentType)
MemFree((void *)pszLocalContentType);
return hr;
}
// ----------------------------------------------------------------------------
// CHTTPMailTransport::CommandDELETE
// ----------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandDELETE(
LPCSTR pszPath,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
if (NULL == pszPath)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_DELETE;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfDelete;
pOp->cState = ARRAYSIZE(c_rgpfDelete);
QueueOperation(pOp);
exit:
return hr;
}
// ----------------------------------------------------------------------------
// CHTTPMailTransport::CommandBDELETE
// ----------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandBDELETE(
LPCSTR pszPath,
LPHTTPTARGETLIST pBatchTargets,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
LPVOID pvXML = NULL;
DWORD dwXMLLen = 0;
if (NULL == pszPath || NULL == pBatchTargets)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (FAILED(hr = HrGenerateSimpleBatchXML(c_szDelete, pBatchTargets, &pvXML, &dwXMLLen)))
goto exit;
if (FAILED(hr = AllocQueuedOperation(pszPath, pvXML, dwXMLLen, &pOp, TRUE)))
goto exit;
pvXML = NULL;
pOp->command = HTTPMAIL_BDELETE;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfDelete;
pOp->cState = ARRAYSIZE(c_rgpfDelete);
pOp->dwRHFlags = RH_XMLCONTENTTYPE;
QueueOperation(pOp);
exit:
SafeMemFree(pvXML);
return hr;
}
// ----------------------------------------------------------------------------
// CHTTPMailTransport::CommandPROPFIND
// ----------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandPROPFIND(
LPCSTR pszPath,
IPropFindRequest *pRequest,
DWORD dwDepth,
DWORD dwContext)
{
if (NULL == pszPath || NULL == pRequest)
return TrapError(E_INVALIDARG);
return E_NOTIMPL;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CommandPROPPATCH
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandPROPPATCH(
LPCSTR pszUrl,
IPropPatchRequest *pRequest,
DWORD dwContext)
{
if (NULL == pszUrl || NULL == pRequest)
return TrapError(E_INVALIDARG);
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
FAIL_CREATEWND;
if (FAILED(hr = AllocQueuedOperation(pszUrl, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_PROPPATCH;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnPropPatch;
pOp->cState = ARRAYSIZE(c_rgpfnPropPatch);
pOp->pPropPatchRequest = pRequest;
pRequest->AddRef();
pOp->dwRHFlags = RH_XMLCONTENTTYPE;
QueueOperation(pOp);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CommandMKCOL
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::CommandMKCOL(LPCSTR pszUrl, DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
if (NULL == pszUrl)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (FAILED(hr = AllocQueuedOperation(pszUrl, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_MKCOL;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnMkCol;
pOp->cState = ARRAYSIZE(c_rgpfnMkCol);
QueueOperation(pOp);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CommandCOPY
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandCOPY(
LPCSTR pszPath,
LPCSTR pszDestination,
BOOL fAllowRename,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp;
LPSTR pszDupDestination = NULL;
if (NULL == pszPath || NULL == pszDestination)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
pszDupDestination = PszDupA(pszDestination);
if (NULL == pszDupDestination)
return TrapError(E_OUTOFMEMORY);
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_COPY;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnCopy;
pOp->cState = ARRAYSIZE(c_rgpfnCopy);
pOp->pszDestination = pszDupDestination;
pszDupDestination = NULL;
if (fAllowRename)
pOp->dwRHFlags = RH_ALLOWRENAME;
QueueOperation(pOp);
exit:
SafeMemFree(pszDupDestination);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CommandBCOPY
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandBCOPY(
LPCSTR pszSourceCollection,
LPHTTPTARGETLIST pTargets,
LPCSTR pszDestCollection,
LPHTTPTARGETLIST pDestinations,
BOOL fAllowRename,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
LPVOID pvXML = NULL;
DWORD dwXMLLen = 0;
LPSTR pszDupDestination = NULL;
if (NULL == pszSourceCollection || NULL == pTargets || NULL == pszDestCollection)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
pszDupDestination = PszDupA(pszDestCollection);
if (NULL == pszDupDestination)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
if (NULL == pDestinations)
hr = HrGenerateSimpleBatchXML(c_szCopy, pTargets, &pvXML, &dwXMLLen);
else
hr = HrGenerateMultiDestBatchXML(c_szCopy, pTargets, pDestinations, &pvXML, &dwXMLLen);
if (FAILED(hr))
goto exit;
if (FAILED(hr = AllocQueuedOperation(pszSourceCollection, pvXML, dwXMLLen, &pOp, TRUE)))
goto exit;
pvXML = NULL;
pOp->command = HTTPMAIL_BCOPY;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnBMove;
pOp->cState = ARRAYSIZE(c_rgpfnBMove);
pOp->pParseFuncs = c_rgpfnBCopyMoveParse;
pOp->pszDestination = pszDupDestination;
pszDupDestination = NULL;
pOp->dwRHFlags = RH_XMLCONTENTTYPE;
if (fAllowRename)
pOp->dwRHFlags |= RH_ALLOWRENAME;
QueueOperation(pOp);
exit:
SafeMemFree(pvXML);
SafeMemFree(pszDupDestination);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CommandMOVE
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandMOVE(
LPCSTR pszPath,
LPCSTR pszDestination,
BOOL fAllowRename,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp;
LPSTR pszDupDestination = NULL;
if (NULL == pszPath || NULL == pszDestination)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
pszDupDestination = PszDupA(pszDestination);
if (NULL == pszDupDestination)
return TrapError(E_OUTOFMEMORY);
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_MOVE;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnMove;
pOp->cState = ARRAYSIZE(c_rgpfnMove);
pOp->pszDestination = pszDupDestination;
pszDupDestination = NULL;
if (fAllowRename)
pOp->dwRHFlags = RH_ALLOWRENAME;
QueueOperation(pOp);
exit:
SafeMemFree(pszDupDestination);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CommandBMOVE
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CommandBMOVE(
LPCSTR pszSourceCollection,
LPHTTPTARGETLIST pTargets,
LPCSTR pszDestCollection,
LPHTTPTARGETLIST pDestinations,
BOOL fAllowRename,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
LPVOID pvXML = NULL;
DWORD dwXMLLen = 0;
LPSTR pszDupDestination = NULL;
if (NULL == pszSourceCollection || NULL == pTargets || NULL == pszDestCollection)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
pszDupDestination = PszDupA(pszDestCollection);
if (NULL == pszDupDestination)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
if (NULL == pDestinations)
hr = HrGenerateSimpleBatchXML(c_szMove, pTargets, &pvXML, &dwXMLLen);
else
hr = HrGenerateMultiDestBatchXML(c_szMove, pTargets, pDestinations, &pvXML, &dwXMLLen);
if (FAILED(hr))
goto exit;
if (FAILED(hr = AllocQueuedOperation(pszSourceCollection, pvXML, dwXMLLen, &pOp, TRUE)))
goto exit;
pvXML = NULL;
pOp->command = HTTPMAIL_BMOVE;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnBMove;
pOp->cState = ARRAYSIZE(c_rgpfnBMove);
pOp->pParseFuncs = c_rgpfnBCopyMoveParse;
pOp->pszDestination = pszDupDestination;
pszDupDestination = NULL;
pOp->dwRHFlags = RH_XMLCONTENTTYPE;
if (fAllowRename)
pOp->dwRHFlags |= RH_ALLOWRENAME;
QueueOperation(pOp);
exit:
SafeMemFree(pvXML);
SafeMemFree(pszDupDestination);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::MemberInfo
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::MemberInfo(
LPCSTR pszPath,
MEMBERINFOFLAGS flags,
DWORD dwDepth,
BOOL fIncludeRoot,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
if (NULL == pszPath)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_MEMBERINFO;
pOp->dwMIFlags = flags;
pOp->dwDepth = dwDepth;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnMemberInfo;
pOp->cState = ARRAYSIZE(c_rgpfnMemberInfo);
pOp->pParseFuncs = c_rgpfnMemberInfoParse;
pOp->dwRHFlags = (RH_BRIEF | RH_XMLCONTENTTYPE);
if (!fIncludeRoot)
pOp->dwRHFlags |= RH_NOROOT;
QueueOperation(pOp);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FindFolders
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::FindFolders(LPCSTR pszPath, DWORD dwContext)
{
return E_NOTIMPL;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::MarkRead
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::MarkRead(
LPCSTR pszPath,
LPHTTPTARGETLIST pTargets,
BOOL fMarkRead,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
CPropPatchRequest *pRequest = NULL;
LPSTR pszXML = NULL;
if (NULL == pszPath)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
pRequest = new CPropPatchRequest();
if (NULL == pRequest)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
if (fMarkRead)
FAIL_EXIT(hr = pRequest->SetProperty(DAVNAMESPACE_HTTPMAIL, "read", "1"));
else
FAIL_EXIT(hr = pRequest->SetProperty(DAVNAMESPACE_HTTPMAIL, "read", "0"));
FAIL_EXIT(hr = pRequest->GenerateXML(pTargets, &pszXML));
FAIL_EXIT(hr = AllocQueuedOperation(pszPath, pszXML, lstrlen(pszXML), &pOp, TRUE));
pszXML = NULL;
pOp->command = HTTPMAIL_MARKREAD;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnMarkRead;
pOp->cState = ARRAYSIZE(c_rgpfnMarkRead);
pOp->pParseFuncs = c_rgpfnMemberErrorParse;
pOp->dwRHFlags = (RH_BRIEF | RH_XMLCONTENTTYPE);
if (pTargets && pTargets->cTarget > 0)
pOp->fBatch = TRUE;
QueueOperation(pOp);
exit:
SafeRelease(pRequest);
SafeMemFree(pszXML);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::SendMessage
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::SendMessage(LPCSTR pszPath,
LPCSTR pszFrom,
LPHTTPTARGETLIST pTargets,
BOOL fSaveInSent,
IStream *pMessageStream,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
IStream *pRfc821Stream = NULL;
if (NULL == pszPath ||
NULL == pszFrom ||
NULL == pTargets || pTargets->cTarget < 1 ||
NULL == pMessageStream)
return E_INVALIDARG;
FAIL_CREATEWND;
// build the rfc821 stream that will precede the mime message
FAIL_EXIT(hr = _HrGenerateRfc821Stream(pszFrom, pTargets, &pRfc821Stream));
FAIL_EXIT(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp));
pOp->command = HTTPMAIL_SENDMESSAGE;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnSendMessage;
pOp->cState = ARRAYSIZE(c_rgpfnSendMessage);
pOp->pHeaderStream = pRfc821Stream;
pRfc821Stream = NULL;
pOp->pBodyStream = pMessageStream;
if (NULL != pOp->pBodyStream)
pOp->pBodyStream->AddRef();
pOp->dwRHFlags = (RH_TRANSLATETRUE | RH_SMTPMESSAGECONTENTTYPE);
pOp->dwRHFlags |= (fSaveInSent ? RH_SAVEINSENTTRUE : RH_SAVEINSENTFALSE);
QueueOperation(pOp);
exit:
SafeRelease(pRfc821Stream);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ListContacts
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ListContacts(LPCSTR pszPath, DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
if (NULL == pszPath)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_LISTCONTACTS;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnListContacts;
pOp->cState = ARRAYSIZE(c_rgpfnListContacts);
pOp->pParseFuncs = c_rgpfnListContactsParse;
pOp->dwDepth = 1;
pOp->dwRHFlags = (RH_NOROOT | RH_XMLCONTENTTYPE);
QueueOperation(pOp);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ListContactInfos
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ListContactInfos(LPCSTR pszCollectionPath, DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
if (NULL == pszCollectionPath)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (FAILED(hr = AllocQueuedOperation(pszCollectionPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_CONTACTINFO;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnContactInfo;
pOp->cState = ARRAYSIZE(c_rgpfnContactInfo);
pOp->pParseFuncs = c_rgpfnContactInfoParse;
pOp->dwDepth = 1;
pOp->dwRHFlags = (RH_NOROOT | RH_XMLCONTENTTYPE);
QueueOperation(pOp);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ContactInfo
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ContactInfo(LPCSTR pszPath, DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
if (NULL == pszPath)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_CONTACTINFO;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnContactInfo;
pOp->cState = ARRAYSIZE(c_rgpfnContactInfo);
pOp->pParseFuncs = c_rgpfnContactInfoParse;
pOp->dwDepth = 0;
pOp->dwRHFlags = RH_XMLCONTENTTYPE;
QueueOperation(pOp);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::PostContact
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::PostContact(LPCSTR pszPath,
LPHTTPCONTACTINFO pciInfo,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
LPVOID pvXML = NULL;
DWORD cb;
if (NULL == pciInfo)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (FAILED(hr = HrGeneratePostContactXML(pciInfo, &pvXML, &cb)))
goto exit;
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->pvData = pvXML;
pOp->cbDataLen = cb;
pvXML = NULL;
pOp->command = HTTPMAIL_POSTCONTACT;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnPostContact;
pOp->cState = ARRAYSIZE(c_rgpfnPostContact);
pOp->dwDepth = 0;
pOp->dwRHFlags = (RH_XMLCONTENTTYPE | RH_TRANSLATEFALSE);
QueueOperation(pOp);
exit:
SafeMemFree(pvXML);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::PatchContact
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::PatchContact(LPCSTR pszPath,
LPHTTPCONTACTINFO pciInfo,
DWORD dwContext)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
IPropPatchRequest *pRequest = NULL;
if (NULL == pciInfo)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
if (FAILED(hr = HrCreatePatchContactRequest(pciInfo, &pRequest)))
goto exit;
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_PATCHCONTACT;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnPatchContact;
pOp->cState = ARRAYSIZE(c_rgpfnPatchContact);
pOp->pPropPatchRequest = pRequest;
pRequest = NULL;
pOp->dwRHFlags = RH_XMLCONTENTTYPE;
QueueOperation(pOp);
exit:
SafeRelease(pRequest);
return hr;
}
// --------------------------------------------------------------------------------
// INodeFactory Methods
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// CHTTPMailTransport::NotifyEvent
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::NotifyEvent(IXMLNodeSource* pSource,
XML_NODEFACTORY_EVENT iEvt)
{
return S_OK;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::BeginChildren
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::BeginChildren(IXMLNodeSource* pSource, XML_NODE_INFO *pNodeInfo)
{
if (m_op.dwStackDepth <= ELE_STACK_CAPACITY)
m_op.rgEleStack[m_op.dwStackDepth - 1].fBeganChildren = TRUE;
return S_OK;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::EndChildren
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::EndChildren(
IXMLNodeSource* pSource,
BOOL fEmpty,
XML_NODE_INFO *pNodeInfo)
{
HRESULT hr = S_OK;
IxpAssert(HTTPMAIL_NONE != m_op.rResponse.command);
IxpAssert(NULL != m_op.pParseFuncs);
if (HTTPMAIL_NONE == m_op.rResponse.command || NULL == m_op.pParseFuncs)
{
hr = E_FAIL;
goto exit;
}
if (XML_ELEMENT == pNodeInfo->dwType)
hr = (this->*(m_op.pParseFuncs->pfnEndChildren))();
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::Error
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::Error(IXMLNodeSource* pSource,
HRESULT hrErrorCode,
USHORT cNumRecs,
XML_NODE_INFO** apNodeInfo)
{
BSTR bstr = NULL;
if (NULL == m_op.rResponse.rIxpResult.pszResponse)
{
if (FAILED(pSource->GetErrorInfo(&bstr)))
goto exit;
HrBSTRToLPSZ(CP_ACP, bstr, &m_op.rResponse.rIxpResult.pszResponse);
}
exit:
if (NULL != bstr)
SysFreeString(bstr);
return S_OK;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CreateNode
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::CreateNode(
IXMLNodeSource* pSource,
PVOID pNodeParent,
USHORT cNumRecs,
XML_NODE_INFO** apNodeInfo)
{
HRESULT hr = S_OK;
LPPCDATABUFFER pTextBuffer = NULL;
CXMLNamespace *pBaseNamespace = m_op.pTopNamespace;
XML_NODE_INFO *pNodeInfo;
IxpAssert(HTTPMAIL_NONE != m_op.rResponse.command);
IxpAssert(NULL != m_op.pParseFuncs);
if (HTTPMAIL_NONE == m_op.rResponse.command || NULL == m_op.pParseFuncs)
{
hr = E_FAIL;
goto exit;
}
if (NULL == apNodeInfo || 0 == cNumRecs)
{
hr = E_INVALIDARG;
goto exit;
}
pNodeInfo = apNodeInfo[0];
switch (pNodeInfo->dwType)
{
case XML_ELEMENT:
if (cNumRecs > 1 && FAILED(hr = PushNamespaces(apNodeInfo, cNumRecs)))
goto exit;
hr = (this->*(m_op.pParseFuncs->pfnCreateElement))(pBaseNamespace, pNodeInfo->pwcText, pNodeInfo->ulLen, pNodeInfo->ulNsPrefixLen, pNodeInfo->fTerminal);
break;
case XML_PCDATA:
// we only parse element content...we don't care about attributes
if (InValidElementChildren())
{
// get the buffer
pTextBuffer = m_op.rgEleStack[m_op.dwStackDepth - 1].pTextBuffer;
// request one if we don't already have one
if (NULL == pTextBuffer)
{
if (FAILED(hr = _GetTextBuffer(&pTextBuffer)))
goto exit;
m_op.rgEleStack[m_op.dwStackDepth - 1].pTextBuffer = pTextBuffer;
}
hr = _AppendTextToBuffer(pTextBuffer, pNodeInfo->pwcText, pNodeInfo->ulLen);
goto exit;
}
break;
default:
break;
}
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_HrThunkConnectionError
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_HrThunkConnectionError(void)
{
return _HrThunkConnectionError(m_op.dwHttpStatus);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_HrThunkConnectionError
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_HrThunkConnectionError(DWORD dwStatus)
{
IxpAssert(NULL == m_op.rResponse.rIxpResult.pszResponse);
IxpAssert(NULL == m_op.rResponse.rIxpResult.pszProblem);
if (m_pLogFile && !m_op.fLoggedResponse)
_LogResponse(NULL, 0);
m_op.rResponse.rIxpResult.hrResult = HttpErrorToIxpResult(dwStatus);
_GetRequestHeader(&m_op.rResponse.rIxpResult.pszResponse, HTTP_QUERY_STATUS_TEXT);
m_op.rResponse.rIxpResult.dwSocketError = GetLastError();
return _HrThunkResponse(TRUE);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_HrThunkResponse
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_HrThunkResponse(BOOL fDone)
{
HRESULT hr = S_OK;
BOOL fSendResponse;
// Thread safety
EnterCriticalSection(&m_cs);
IxpAssert(HTTPMAIL_NONE != m_op.rResponse.command);
if (m_op.rResponse.fDone)
{
fSendResponse = FALSE;
}
else
{
fSendResponse = TRUE;
if (!fDone && WasAborted())
{
m_op.rResponse.rIxpResult.hrResult = IXP_E_USER_CANCEL;
m_op.rResponse.fDone = TRUE;
}
else
m_op.rResponse.fDone = fDone;
}
LeaveCriticalSection(&m_cs);
if (fSendResponse)
hr = (HRESULT) ::SendMessage(m_hwnd, SPM_HTTPMAIL_SENDRESPONSE, 0, NULL);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::InvokeResponseCallback
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::InvokeResponseCallback(void)
{
HRESULT hr = S_OK;
IHTTPMailCallback *pCallback = NULL;
EnterCriticalSection(&m_cs);
if (m_pCallback)
{
pCallback = m_pCallback;
pCallback->AddRef();
}
LeaveCriticalSection(&m_cs);
if (pCallback)
{
hr = pCallback->OnResponse(&m_op.rResponse);
pCallback->Release();
}
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::InitNew
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::InitNew(
LPCSTR pszUserAgent,
LPCSTR pszLogFilePath,
IHTTPMailCallback *pCallback)
{
HRESULT hr = S_OK;
if (NULL == pszUserAgent || NULL == pCallback)
return TrapError(E_INVALIDARG);
IxpAssert(NULL == m_hInternet);
// Thread Safety
EnterCriticalSection(&m_cs);
if (IXP_DISCONNECTED != m_status)
{
hr = TrapError(IXP_E_ALREADY_CONNECTED);
goto exit;
}
Reset();
m_pszUserAgent = PszDupA(pszUserAgent);
if (NULL == m_pszUserAgent)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// open log file
if (pszLogFilePath)
CreateLogFile(g_hInst, pszLogFilePath, "HTTPMAIL", DONT_TRUNCATE, &m_pLogFile,
FILE_SHARE_READ | FILE_SHARE_WRITE);
m_pCallback = pCallback;
m_pCallback->AddRef();
m_hInternet = InternetOpen(m_pszUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (NULL == m_hInternet)
{
hr = TrapError(IXP_E_SOCKET_INIT_ERROR);
goto exit;
}
// Install the callback ptr for the internet handle and all of its derived handles
//InternetSetStatusCallbackA(m_hInternet, StatusCallbackProxy);
exit:
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::OnStatusCallback
// --------------------------------------------------------------------------------
void CHTTPMailTransport::OnStatusCallback(
HINTERNET hInternet,
DWORD dwInternetStatus,
LPVOID pvStatusInformation,
DWORD dwStatusInformationLength)
{
#if 0
// Locals
IXPSTATUS ixps;
EnterCriticalSection(&m_cs);
// if the status message is one of the defined IXPSTATUS messages,
// notify the callback.
if ((NULL != m_pCallback) && TranslateWinInetMsg(dwInternetStatus, &ixps))
m_pCallback->OnStatus(ixps, (IHTTPMailTransport *)this);
// for now, we just handle the request_complete message
if (INTERNET_STATUS_REQUEST_COMPLETE == dwInternetStatus)
HrCommandCompleted();
LeaveCriticalSection(&m_cs);
#endif
}
// ----------------------------------------------------------------------------
// CHTTPMailTransport::AllocQueuedOperation
// ----------------------------------------------------------------------------
HRESULT CHTTPMailTransport::AllocQueuedOperation(
LPCSTR pszUrl,
LPVOID pvData,
ULONG cbDataLen,
LPHTTPQUEUEDOP *ppOp,
BOOL fAdoptData)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pTempOp = NULL;
if (!MemAlloc((void **)&pTempOp , sizeof(HTTPQUEUEDOP)))
{
hr = E_OUTOFMEMORY;
goto exit;
}
ZeroMemory(pTempOp, sizeof(HTTPQUEUEDOP));
if (NULL != pszUrl)
{
pTempOp->pszUrl = PszDupA(pszUrl);
if (NULL == pTempOp->pszUrl)
{
hr = E_OUTOFMEMORY;
goto exit;
}
}
// can't have a length if data ptr is null
IxpAssert(!pvData || cbDataLen);
if (pvData)
{
if (!fAdoptData)
{
if (!MemAlloc((LPVOID*)&pTempOp->pvData, cbDataLen + 1))
{
hr = E_OUTOFMEMORY;
goto exit;
}
CopyMemory(pTempOp->pvData, pvData, cbDataLen);
((char *)pTempOp->pvData)[cbDataLen] = '\0';
}
else
pTempOp->pvData = pvData;
pTempOp->cbDataLen = cbDataLen;
}
*ppOp = pTempOp;
pTempOp = NULL;
exit:
if (pTempOp)
{
SafeMemFree(pTempOp->pszUrl);
if (!fAdoptData)
SafeMemFree(pTempOp->pvData);
MemFree(pTempOp);
}
return hr;
}
// ----------------------------------------------------------------------------
// CHTTPMailTransport::QueueOperation
// ----------------------------------------------------------------------------
void CHTTPMailTransport::QueueOperation(LPHTTPQUEUEDOP pOp)
{
// Thread safety
EnterCriticalSection(&m_cs);
if (m_opPendingTail)
m_opPendingTail->pNext = pOp;
else
{
// if there is no tail, there shouldn't be a head
IxpAssert(!m_opPendingHead);
m_opPendingHead = m_opPendingTail = pOp;
}
// signal the io thread
SetEvent(m_hevPendingCommand);
// Thread Safety
LeaveCriticalSection(&m_cs);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::StatusCallbackProxy
// --------------------------------------------------------------------------------
void CHTTPMailTransport::StatusCallbackProxy(
HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID pvStatusInformation,
DWORD dwStatusInformationLength)
{
// Locals
CHTTPMailTransport *pHTTPMail = reinterpret_cast<CHTTPMailTransport *>(IntToPtr(dwContext));
IxpAssert(NULL != pHTTPMail);
if (NULL != pHTTPMail)
pHTTPMail->OnStatusCallback(hInternet, dwInternetStatus, pvStatusInformation, dwStatusInformationLength);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::DoOperation
// --------------------------------------------------------------------------------
void CHTTPMailTransport::DoOperation(void)
{
HRESULT hr = S_OK;
while (m_op.iState < m_op.cState)
{
hr = (this->*(m_op.pfnState[m_op.iState]))();
if (FAILED(hr))
break;
m_op.iState++;
}
if (!m_op.rResponse.fDone && FAILED(hr))
{
m_op.rResponse.rIxpResult.hrResult = hr;
_HrThunkResponse(TRUE);
}
FreeOperation();
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FreeOperation
// --------------------------------------------------------------------------------
void CHTTPMailTransport::FreeOperation(void)
{
// Thread Safety
EnterCriticalSection(&m_cs);
SafeMemFree(m_op.pszUrl);
SafeMemFree(m_op.pszDestination);
if (m_op.pszContentType)
{
MemFree((void *)m_op.pszContentType);
m_op.pszContentType = NULL;
}
SafeMemFree(m_op.pvData);
SafeInternetCloseHandle(m_op.hRequest);
SafeRelease(m_op.pPropFindRequest);
SafeRelease(m_op.pPropPatchRequest);
if (NULL != m_op.rgszAcceptTypes)
FreeStringList(m_op.rgszAcceptTypes);
SafeRelease(m_op.pHeaderStream);
SafeRelease(m_op.pBodyStream);
if (m_op.pTextBuffer)
_FreeTextBuffer(m_op.pTextBuffer);
// Free the response
SafeMemFree(m_op.rResponse.rIxpResult.pszResponse);
SafeMemFree(m_op.rResponse.rIxpResult.pszProblem);
PopNamespaces(NULL);
// in the case of an error, the element stack can
// contain text buffers that need to be freed
for (DWORD i = 0; i < m_op.dwStackDepth; ++i)
{
if (NULL != m_op.rgEleStack[i].pTextBuffer)
_FreeTextBuffer(m_op.rgEleStack[i].pTextBuffer);
}
SafeMemFree(m_op.rResponse.rIxpResult.pszResponse);
switch (m_op.rResponse.command)
{
case HTTPMAIL_GET:
SafeMemFree(m_op.rResponse.rGetInfo.pvBody);
SafeMemFree(m_op.rResponse.rGetInfo.pszContentType);
break;
case HTTPMAIL_POST:
case HTTPMAIL_SENDMESSAGE:
SafeMemFree(m_op.rResponse.rPostInfo.pszLocation);
break;
case HTTPMAIL_COPY:
case HTTPMAIL_MOVE:
case HTTPMAIL_MKCOL:
SafeMemFree(m_op.rResponse.rCopyMoveInfo.pszLocation);
break;
case HTTPMAIL_BCOPY:
case HTTPMAIL_BMOVE:
SafeMemFree(m_op.rResponse.rBCopyMoveList.prgBCopyMove);
break;
case HTTPMAIL_MEMBERINFO:
FreeMemberInfoList();
SafeMemFree(m_op.rResponse.rMemberInfoList.prgMemberInfo);
SafeMemFree(m_op.pszRootTimeStamp);
SafeMemFree(m_op.pszFolderTimeStamp);
SafeMemFree(m_op.rResponse.rMemberInfoList.pszRootTimeStamp);
SafeMemFree(m_op.rResponse.rMemberInfoList.pszFolderTimeStamp);
break;
case HTTPMAIL_MARKREAD:
FreeMemberErrorList();
SafeMemFree(m_op.rResponse.rMemberErrorList.prgMemberError);
break;
case HTTPMAIL_LISTCONTACTS:
FreeContactIdList();
SafeMemFree(m_op.rResponse.rContactIdList.prgContactId);
break;
case HTTPMAIL_CONTACTINFO:
FreeContactInfoList();
SafeMemFree(m_op.rResponse.rContactInfoList.prgContactInfo);
break;
case HTTPMAIL_POSTCONTACT:
XP_FREE_STRUCT(HTTPCONTACTID, &m_op.rResponse.rPostContactInfo, NULL);
break;
case HTTPMAIL_PATCHCONTACT:
XP_FREE_STRUCT(HTTPCONTACTID, &m_op.rResponse.rPatchContactInfo, NULL);
break;
default:
break;
}
ZeroMemory(&m_op, sizeof(HTTPMAILOPERATION));
m_op.rResponse.command = HTTPMAIL_NONE;
// Thread Safety
LeaveCriticalSection(&m_cs);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_BindToStruct
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_BindToStruct(const WCHAR *pwcText,
ULONG ulLen,
const XPCOLUMN *prgCols,
DWORD cCols,
LPVOID pTarget,
BOOL *pfWasBound)
{
HRESULT hr = S_OK;
DWORD dwColIndex;
DWORD dwColFlags;
LPSTR *ppsz;
DWORD *pdw;
BOOL *pb;
HTTPMAILSPECIALFOLDER *ptySpecial;
HTTPMAILCONTACTTYPE *ptyContact;
HMELE ele;
HRESULT *phr;
if (pfWasBound)
*pfWasBound = FALSE;
// if the stack is overflowed, we definitely won't do anything with the text
if (m_op.dwStackDepth >= ELE_STACK_CAPACITY)
goto exit;
ele = m_op.rgEleStack[m_op.dwStackDepth - 1].ele;
for (dwColIndex = 0; dwColIndex < cCols; dwColIndex++)
{
if (ele == prgCols[dwColIndex].ele)
break;
}
if (dwColIndex >= cCols)
goto exit;
dwColFlags = prgCols[dwColIndex].dwFlags;
// the column may require validation of the element stack
if (!!(dwColFlags & XPCF_MSVALIDPROP))
{
if (!VALIDSTACK(c_rgPropFindPropValueStack))
goto exit;
}
else if (!!(dwColFlags & XPCF_MSVALIDMSRESPONSECHILD))
{
if (!VALIDSTACK(c_rgMultiStatusResponseChildStack))
goto exit;
}
if (dwColIndex < cCols)
{
switch (prgCols[dwColIndex].cdt)
{
case XPCDT_STRA:
ppsz = (LPSTR *)(((char *)pTarget) + prgCols[dwColIndex].offset);
SafeMemFree(*ppsz);
hr = AllocStrFromStrNW(pwcText, ulLen, ppsz);
break;
case XPCDT_DWORD:
pdw = (DWORD *)(((char *)pTarget) + prgCols[dwColIndex].offset);
*pdw = 0;
hr = StrNToDwordW(pwcText, ulLen, pdw);
break;
case XPCDT_BOOL:
pb = (BOOL *)(((char *)pTarget) + prgCols[dwColIndex].offset);
*pb = FALSE;
hr = StrNToBoolW(pwcText, ulLen, pb);
break;
case XPCDT_IXPHRESULT:
phr = (HRESULT *)(((char *)pTarget) + prgCols[dwColIndex].offset);
*phr = S_OK;
hr = StatusStrNToIxpHr(pwcText, ulLen, phr);
break;
case XPCDT_HTTPSPECIALFOLDER:
ptySpecial = (HTTPMAILSPECIALFOLDER *)(((char *)pTarget) + prgCols[dwColIndex].offset);
*ptySpecial = HTTPMAIL_SF_NONE;
hr = StrNToSpecialFolderW(pwcText, ulLen, ptySpecial);
break;
case XPCDT_HTTPCONTACTTYPE:
ptyContact = (HTTPMAILCONTACTTYPE *)(((char *)pTarget) + prgCols[dwColIndex].offset);
*ptyContact = HTTPMAIL_CT_CONTACT;
hr = StrNToContactTypeW(pwcText, ulLen, ptyContact);
break;
default:
IxpAssert(FALSE);
break;
}
if (FAILED(hr))
goto exit;
// set the bit in the flag word to indicate that this field
// has been set.
if (!(dwColFlags & XPCF_DONTSETFLAG))
m_op.dwPropFlags |= (1 << dwColIndex);
if (pfWasBound)
*pfWasBound = TRUE;
}
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_FreeStruct
// --------------------------------------------------------------------------------
void CHTTPMailTransport::_FreeStruct(const XPCOLUMN *prgCols,
DWORD cCols,
LPVOID pTarget,
DWORD *pdwFlags)
{
DWORD dwFlags;
DWORD dwIndex = 0;
LPSTR *ppsz;
DWORD *pdw;
BOOL *pb;
HTTPMAILSPECIALFOLDER *ptySpecial;
HTTPMAILCONTACTTYPE *ptyContact;
HRESULT *phr;
if (NULL != pdwFlags)
{
dwFlags = *pdwFlags;
*pdwFlags = NOFLAGS;
}
else
dwFlags = 0xFFFFFFFF;
while (0 != dwFlags && dwIndex < cCols)
{
// test the low bit
if (!!(dwFlags & 0x00000001))
{
switch (prgCols[dwIndex].cdt)
{
case XPCDT_STRA:
ppsz = (LPSTR *)(((char *)pTarget) + prgCols[dwIndex].offset);
SafeMemFree(*ppsz);
break;
case XPCDT_DWORD:
pdw = (DWORD *)(((char *)pTarget) + prgCols[dwIndex].offset);
*pdw = 0;
break;
case XPCDT_BOOL:
pb = (BOOL *)(((char *)pTarget) + prgCols[dwIndex].offset);
*pb = FALSE;
break;
case XPCDT_IXPHRESULT:
phr = (HRESULT *)(((char *)pTarget) + prgCols[dwIndex].offset);
*phr = S_OK;
break;
case XPCDT_HTTPSPECIALFOLDER:
ptySpecial = (HTTPMAILSPECIALFOLDER *)(((char *)pTarget) + prgCols[dwIndex].offset);
*ptySpecial = HTTPMAIL_SF_NONE;
break;
case XPCDT_HTTPCONTACTTYPE:
ptyContact = (HTTPMAILCONTACTTYPE *)(((char *)pTarget) + prgCols[dwIndex].offset);
*ptyContact = HTTPMAIL_CT_CONTACT;
break;
default:
IxpAssert(FALSE);
break;
}
}
dwFlags >>= 1;
dwIndex++;
}
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_AppendTextToBuffer
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_AppendTextToBuffer(LPPCDATABUFFER pTextBuffer,
const WCHAR *pwcText,
ULONG ulLen)
{
HRESULT hr = S_OK;
ULONG ulNewCapacity = pTextBuffer->ulLen + ulLen;
IxpAssert(ulLen > 0);
// grow the buffer if necessary, and append the text
if (pTextBuffer->ulCapacity < ulNewCapacity)
{
if (!MemRealloc((void **)&(pTextBuffer->pwcText), sizeof(WCHAR) * ulNewCapacity))
{
hr = E_OUTOFMEMORY;
goto exit;
}
pTextBuffer->ulCapacity = ulNewCapacity;
}
// copy the new text over. special case the one-byte case to avoid
// calls to CopyMemory when we see one character entities
if (1 == ulLen)
{
pTextBuffer->pwcText[pTextBuffer->ulLen++] = *pwcText;
}
else
{
CopyMemory(&pTextBuffer->pwcText[pTextBuffer->ulLen], pwcText, sizeof(WCHAR) * ulLen);
pTextBuffer->ulLen += ulLen;
}
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_AllocTextBuffer
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_AllocTextBuffer(LPPCDATABUFFER *ppTextBuffer)
{
HRESULT hr = S_OK;
IxpAssert(NULL != ppTextBuffer);
*ppTextBuffer = NULL;
if (!MemAlloc((void **)ppTextBuffer, sizeof(PCDATABUFFER)))
{
hr = E_OUTOFMEMORY;
goto exit;
}
// allocate the buffer
if (!MemAlloc((void **)(&((*ppTextBuffer)->pwcText)), PCDATA_BUFSIZE * sizeof(WCHAR)))
{
MemFree(*ppTextBuffer);
*ppTextBuffer = NULL;
hr = E_OUTOFMEMORY;
goto exit;
}
(*ppTextBuffer)->ulLen = 0;
(*ppTextBuffer)->ulCapacity = PCDATA_BUFSIZE ;
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FreeTextBuffer
// --------------------------------------------------------------------------------
void CHTTPMailTransport::_FreeTextBuffer(LPPCDATABUFFER pTextBuffer)
{
if (pTextBuffer)
{
if (pTextBuffer->pwcText)
MemFree(pTextBuffer->pwcText);
MemFree(pTextBuffer);
}
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FreeMemberInfoList
// --------------------------------------------------------------------------------
void CHTTPMailTransport::FreeMemberInfoList(void)
{
DWORD cInfo = m_op.rResponse.rMemberInfoList.cMemberInfo;
LPHTTPMEMBERINFO rgInfo = m_op.rResponse.rMemberInfoList.prgMemberInfo;
// free the completed infos
for (DWORD i = 0; i < cInfo; i++)
XP_FREE_STRUCT(HTTPMEMBERINFO, &rgInfo[i], NULL);
// free the partial info
if (m_op.dwPropFlags)
{
IxpAssert(cInfo < MEMBERINFO_MAXRESPONSES);
XP_FREE_STRUCT(HTTPMEMBERINFO, &rgInfo[cInfo], &m_op.dwPropFlags);
}
m_op.rResponse.rMemberInfoList.cMemberInfo= 0;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FreeMemberErrorList
// --------------------------------------------------------------------------------
void CHTTPMailTransport::FreeMemberErrorList(void)
{
DWORD cInfo = m_op.rResponse.rMemberErrorList.cMemberError;
LPHTTPMEMBERERROR rgInfo = m_op.rResponse.rMemberErrorList.prgMemberError;
// free the completed infos
for (DWORD i = 0; i < cInfo; i++)
XP_FREE_STRUCT(HTTPMEMBERERROR, &rgInfo[i], NULL);
// free the partial info
if (m_op.dwPropFlags)
{
IxpAssert(cInfo < MEMBERERROR_MAXRESPONSES);
XP_FREE_STRUCT(HTTPMEMBERERROR, &rgInfo[cInfo], &m_op.dwPropFlags);
}
m_op.rResponse.rMemberErrorList.cMemberError = 0;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FreeContactIdList
// --------------------------------------------------------------------------------
void CHTTPMailTransport::FreeContactIdList(void)
{
DWORD cId = m_op.rResponse.rContactIdList.cContactId;
LPHTTPCONTACTID rgId = m_op.rResponse.rContactIdList.prgContactId;
// free the completed ids
for (DWORD i = 0; i < cId; ++i)
XP_FREE_STRUCT(HTTPCONTACTID, &rgId[i], NULL);
// free the partial id
if (m_op.dwPropFlags)
{
IxpAssert(cId < LISTCONTACTS_MAXRESPONSES);
XP_FREE_STRUCT(HTTPCONTACTID, &rgId[cId], &m_op.dwPropFlags);
m_op.dwPropFlags = NOFLAGS;
}
m_op.rResponse.rContactIdList.cContactId = 0;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FreeContactInfoList
// --------------------------------------------------------------------------------
void CHTTPMailTransport::FreeContactInfoList(void)
{
DWORD cInfo = m_op.rResponse.rContactInfoList.cContactInfo;
LPHTTPCONTACTINFO rgInfo = m_op.rResponse.rContactInfoList.prgContactInfo;
// free the completed ids
for (DWORD i = 0; i < cInfo; ++i)
XP_FREE_STRUCT(HTTPCONTACTINFO, &rgInfo[i], NULL);
// free the partial info
if (m_op.dwPropFlags)
{
IxpAssert(cInfo < CONTACTINFO_MAXRESPONSES);
XP_FREE_STRUCT(HTTPCONTACTINFO, &rgInfo[cInfo], &m_op.dwPropFlags);
}
m_op.rResponse.rContactInfoList.cContactInfo = 0;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FreeBCopyMoveList
// --------------------------------------------------------------------------------
void CHTTPMailTransport::FreeBCopyMoveList(void)
{
DWORD cInfo = m_op.rResponse.rBCopyMoveList.cBCopyMove;
LPHTTPMAILBCOPYMOVE rgInfo = m_op.rResponse.rBCopyMoveList.prgBCopyMove;
// free the completed records
for (DWORD i = 0; i < cInfo; ++i)
XP_FREE_STRUCT(HTTPMAILBCOPYMOVE, &rgInfo[i], NULL);
// free the partial info
if (m_op.dwPropFlags)
{
IxpAssert(cInfo < BCOPYMOVE_MAXRESPONSES);
XP_FREE_STRUCT(HTTPMAILBCOPYMOVE, &rgInfo[cInfo], &m_op.dwPropFlags);
}
m_op.rResponse.rBCopyMoveList.cBCopyMove = 0;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ValidStack
// --------------------------------------------------------------------------------
BOOL CHTTPMailTransport::ValidStack(const HMELE *prgEle, DWORD cEle)
{
BOOL bResult = TRUE;
DWORD dw;
if (cEle != m_op.dwStackDepth)
{
bResult = FALSE;
goto exit;
}
IxpAssert(cEle <= ELE_STACK_CAPACITY);
for (dw = 0; dw < cEle; ++dw)
{
if (prgEle[dw] != HMELE_UNKNOWN && prgEle[dw] != m_op.rgEleStack[dw].ele)
{
bResult = FALSE;
goto exit;
}
}
exit:
return bResult;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::PopNamespaces
// --------------------------------------------------------------------------------
void CHTTPMailTransport::PopNamespaces(CXMLNamespace *pBaseNamespace)
{
CXMLNamespace *pTemp;
while (pBaseNamespace != m_op.pTopNamespace)
{
IxpAssert(m_op.pTopNamespace);
pTemp = m_op.pTopNamespace->GetParent();
m_op.pTopNamespace->Release();
m_op.pTopNamespace = pTemp;
}
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::PushNamespaces
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::PushNamespaces(XML_NODE_INFO** apNodeInfo, USHORT cNumRecs)
{
HRESULT hr = S_OK;
CXMLNamespace *pNamespace = NULL;
for (USHORT i = 0; i < cNumRecs; ++i)
{
if (apNodeInfo[i]->dwType == XML_ATTRIBUTE && apNodeInfo[i]->dwSubType == XML_NS)
{
// better have at least one more record
IxpAssert(i < (cNumRecs - 1));
if (i < (cNumRecs - 1) && apNodeInfo[i + 1]->dwType == XML_PCDATA)
{
pNamespace = new CXMLNamespace();
if (!pNamespace)
{
hr = E_OUTOFMEMORY;
goto exit;
}
if (apNodeInfo[i]->ulLen != apNodeInfo[i]->ulNsPrefixLen)
{
if (FAILED(hr = pNamespace->SetPrefix(
&apNodeInfo[i]->pwcText[apNodeInfo[i]->ulNsPrefixLen + 1],
apNodeInfo[i]->ulLen - (apNodeInfo[i]->ulNsPrefixLen + 1))))
goto exit;
}
if (FAILED(hr = pNamespace->SetNamespace(apNodeInfo[i + 1]->pwcText, apNodeInfo[i + 1]->ulLen)))
goto exit;
pNamespace->SetParent(m_op.pTopNamespace);
if (m_op.pTopNamespace)
m_op.pTopNamespace->Release();
m_op.pTopNamespace = pNamespace;
pNamespace = NULL;
}
}
}
exit:
SafeRelease(pNamespace);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::AllocStrFromStrW
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::AllocStrFromStrNW(
const WCHAR *pwcText,
ULONG ulLen,
LPSTR *ppszAlloc)
{
HRESULT hr = S_OK;
DWORD iBufferSize;
DWORD iConvertedChars;
IxpAssert(NULL != ppszAlloc);
if (NULL == ppszAlloc)
return E_INVALIDARG;
*ppszAlloc = NULL;
// if pwcText is NULL, the result is null, but not an error
if (NULL == pwcText)
goto exit;
iBufferSize = WideCharToMultiByte(CP_ACP, 0, pwcText, ulLen, NULL, 0, NULL, NULL);
if (0 == iBufferSize)
{
m_op.rResponse.rIxpResult.uiServerError = GetLastError();
hr = TrapError(E_FAIL);
goto exit;
}
// allocate the buffer (add 1 to the size to allow for eos)
if (!MemAlloc((void **)ppszAlloc, iBufferSize + 1))
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// convert the string
iConvertedChars = WideCharToMultiByte(CP_ACP, 0, pwcText, ulLen, *ppszAlloc, iBufferSize, NULL, NULL);
if (0 == iConvertedChars)
{
m_op.rResponse.rIxpResult.uiServerError = GetLastError();
hr = TrapError(E_FAIL);
goto exit;
}
IxpAssert(iConvertedChars == iBufferSize);
// terminate the new string
(*ppszAlloc)[iConvertedChars] = 0;
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::StrNToDwordW
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::StrNToDwordW(const WCHAR *pwcText, ULONG ulLen, DWORD *pdw)
{
HRESULT hr = S_OK;
int i;
WCHAR wcBuf[32];
WCHAR *pwcUseBuf;
BOOL fFreeBuf = FALSE;
IxpAssert(NULL != pdw);
if (NULL == pdw)
return E_INVALIDARG;
*pdw = 0;
if (NULL == pwcText)
goto exit;
// decide whether to use a local buffer or an allocated buffer
if (ulLen < 32)
pwcUseBuf = wcBuf;
else
{
if (!MemAlloc((void **)&pwcUseBuf, (ulLen + 1) * sizeof(WCHAR)))
{
hr = E_OUTOFMEMORY;
goto exit;
}
fFreeBuf = TRUE;
}
// copy the string over
CopyMemory(pwcUseBuf, pwcText, ulLen * sizeof(WCHAR));
pwcUseBuf[ulLen] = 0;
*pdw = StrToIntW(pwcUseBuf);
exit:
if (fFreeBuf)
MemFree(pwcUseBuf);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::StrNToSpecialFolderW
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::StrNToSpecialFolderW(const WCHAR *pwcText,
ULONG ulLen,
HTTPMAILSPECIALFOLDER *ptySpecial)
{
HRESULT hr = S_OK;
if (NULL == ptySpecial)
return E_INVALIDARG;
*ptySpecial = HTTPMAIL_SF_UNRECOGNIZED;
if (NULL != pwcText && ulLen > 0)
{
for (DWORD dw = 0; dw < ARRAYSIZE(c_rgpfnSpecialFolder); dw++)
{
if (ulLen == c_rgpfnSpecialFolder[dw].ulLen)
{
if (0 == StrCmpNW(c_rgpfnSpecialFolder[dw].pwcName, pwcText, ulLen))
{
*ptySpecial = c_rgpfnSpecialFolder[dw].tyFolder;
break;
}
}
}
}
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::StrNToContactTypeW
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::StrNToContactTypeW(const WCHAR *pwcText,
ULONG ulLen,
HTTPMAILCONTACTTYPE *ptyContact)
{
HRESULT hr = S_OK;
BOOL fGroup = FALSE;
IxpAssert(NULL != ptyContact);
if (NULL == ptyContact)
return E_INVALIDARG;
// for now, we treat the presence of the <group> element as an indication that
// the contact is a group
*ptyContact = HTTPMAIL_CT_GROUP;
#if 0
// for now, we treat the value as an integer-based bool
hr = StrNToBoolW(pwcText, ulLen, &fGroup);
// default is contact
*ptyContact = fGroup ? HTTPMAIL_CT_GROUP : HTTPMAIL_CT_CONTACT;
#endif
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::StrNToBoolW
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::StrNToBoolW(const WCHAR *pwcText, DWORD ulLen, BOOL *pb)
{
HRESULT hr = S_OK;
DWORD dw;
IxpAssert(NULL != pb);
if (NULL == pb)
return E_INVALIDARG;
*pb = FALSE;
if (NULL == pwcText)
goto exit;
if (FAILED(hr = StrNToDwordW(pwcText, ulLen, &dw)))
goto exit;
if (dw != 0)
*pb = TRUE;
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::StatusStrNToIxpHr
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::StatusStrNToIxpHr(const WCHAR *pwcText, DWORD ulLen, HRESULT *phr)
{
HRESULT hr = S_OK;
DWORD dw;
LPSTR pszStatus = NULL;
DWORD dwStatus = 0;
IxpAssert(NULL != phr);
if (NULL == phr)
return E_INVALIDARG;
*phr = S_OK;
if (NULL == pwcText)
goto exit;
if (FAILED(hr = AllocStrFromStrNW(pwcText, ulLen, &pszStatus)) || NULL == pszStatus)
goto exit;
HrParseHTTPStatus(pszStatus, &dwStatus);
if (dwStatus < 200 || dwStatus > 299)
*phr = HttpErrorToIxpResult(dwStatus);
exit:
SafeMemFree(pszStatus);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CommandToVerb
// --------------------------------------------------------------------------------
LPSTR CHTTPMailTransport::CommandToVerb(HTTPMAILCOMMAND command)
{
LPSTR pszVerb = NULL;
// convert the command to a string
switch (command)
{
case HTTPMAIL_GET:
pszVerb = "GET";
break;
case HTTPMAIL_POST:
case HTTPMAIL_SENDMESSAGE:
pszVerb = "POST";
break;
case HTTPMAIL_PUT:
pszVerb = "PUT";
break;
case HTTPMAIL_GETPROP:
case HTTPMAIL_PROPFIND:
case HTTPMAIL_MEMBERINFO:
case HTTPMAIL_LISTCONTACTS:
case HTTPMAIL_CONTACTINFO:
pszVerb = "PROPFIND";
break;
case HTTPMAIL_MARKREAD:
if (m_op.fBatch)
pszVerb = "BPROPPATCH";
else
pszVerb = "PROPPATCH";
break;
case HTTPMAIL_MKCOL:
pszVerb = "MKCOL";
break;
case HTTPMAIL_COPY:
pszVerb = "COPY";
break;
case HTTPMAIL_BCOPY:
pszVerb = "BCOPY";
break;
case HTTPMAIL_MOVE:
pszVerb = "MOVE";
break;
case HTTPMAIL_BMOVE:
pszVerb = "BMOVE";
break;
case HTTPMAIL_PROPPATCH:
pszVerb = "PROPPATCH";
break;
case HTTPMAIL_DELETE:
pszVerb = "DELETE";
break;
case HTTPMAIL_BDELETE:
pszVerb = "BDELETE";
break;
case HTTPMAIL_POSTCONTACT:
// first post the contact, then do a propfind
if (NULL == m_op.rResponse.rPostContactInfo.pszHref)
pszVerb = "POST";
else
pszVerb = "PROPFIND";
break;
case HTTPMAIL_PATCHCONTACT:
// first patch the contact, then do a propfind
if (NULL == m_op.rResponse.rPatchContactInfo.pszHref)
pszVerb = "PROPPATCH";
else
pszVerb = "PROPFIND";
break;
default:
pszVerb = "";
IxpAssert(FALSE);
break;
}
return pszVerb;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::UpdateLogonInfo
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::UpdateLogonInfo(void)
{
// send the message synchronously
return (HRESULT) (::SendMessage(m_hwnd, SPM_HTTPMAIL_LOGONPROMPT, NULL, NULL));
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::GetParentWindow
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::GetParentWindow(HWND *phwndParent)
{
// send the message synchronously
return (HRESULT) (::SendMessage(m_hwnd, SPM_HTTPMAIL_GETPARENTWINDOW, (WPARAM)phwndParent, NULL));
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ReadBytes
// --------------------------------------------------------------------------------
BOOL CHTTPMailTransport::ReadBytes(LPSTR pszBuffer, DWORD cbBufferSize, DWORD *pcbBytesRead)
{
return InternetReadFile(m_op.hRequest, pszBuffer, cbBufferSize, pcbBytesRead);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_GetStatusCode
// --------------------------------------------------------------------------------
BOOL CHTTPMailTransport::_GetStatusCode(DWORD *pdw)
{
IxpAssert(NULL != pdw);
DWORD dwStatusSize = sizeof(DWORD);
*pdw = 0;
return HttpQueryInfo(m_op.hRequest, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE, pdw, &dwStatusSize, NULL);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_GetContentLength
// --------------------------------------------------------------------------------
BOOL CHTTPMailTransport::_GetContentLength(DWORD *pdw)
{
IxpAssert(NULL != pdw);
DWORD dwLengthSize = sizeof(DWORD);
*pdw = 0;
return HttpQueryInfo(m_op.hRequest, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_CONTENT_LENGTH, pdw, &dwLengthSize, NULL);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_GetRequestHeader
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_GetRequestHeader(LPSTR *ppszHeader, DWORD dwHeader)
{
HRESULT hr = S_OK;
DWORD dwSize = MAX_PATH;
LPSTR pszHeader = NULL;
Assert(NULL != ppszHeader);
*ppszHeader = NULL;
retry:
pszHeader = (LPSTR)ZeroAllocate(dwSize);
if (!pszHeader)
{
hr = E_OUTOFMEMORY;
goto exit;
}
if (!HttpQueryInfo(m_op.hRequest, dwHeader, pszHeader, &dwSize, NULL))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
goto exit;
SafeMemFree(pszHeader);
goto retry;
}
*ppszHeader = pszHeader;
pszHeader = NULL;
exit:
SafeMemFree(pszHeader);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_AddRequestHeader
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_AddRequestHeader(LPCSTR pszHeader)
{
HRESULT hr = S_OK;
if (!HttpAddRequestHeaders(m_op.hRequest, pszHeader, lstrlen(pszHeader), HTTP_ADDREQ_FLAG_ADD))
hr = HrGetLastError();
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_AuthCurrentRequest
// --------------------------------------------------------------------------------
BOOL CHTTPMailTransport::_AuthCurrentRequest(DWORD dwStatus, BOOL fRetryAuth)
{
BOOL fResult = FALSE;
HRESULT hr;
// unused code to let wininet do the ui
#if 0
if (HTTP_STATUS_PROXY_AUTH_REQ == dwStatus || HTTP_STATUS_DENIED == dwStatus)
{
if (!fRequestedParent)
{
GetParentWindow(&hwndParent);
fRequestedParent = TRUE;
}
hr = InternetErrorDlg(hwndParent, m_op.hRequest, hr,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS |
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA,
NULL);
if (ERROR_INTERNET_FORCE_RETRY == hr)
goto resend;
}
#endif
// TODO: should probably let wininet handle proxy auth errors
#if 0
case HTTP_STATUS_PROXY_AUTH_REQ: //Proxy Authentication Required
InternetSetOption(m_op.hRequest, INTERNET_OPTION_PROXY_USERNAME,
GetUserName(), strlen(GetUserName())+1);
InternetSetOption(m_op.hRequest, INTERNET_OPTION_PROXY_PASSWORD,
GetPassword(), strlen(GetPassword())+1);
break;
#endif
if (HTTP_STATUS_DENIED == dwStatus) //Server Authentication Required
{
if (fRetryAuth || (SUCCEEDED(hr = UpdateLogonInfo()) && S_FALSE != hr))
{
InternetSetOption(m_op.hRequest, INTERNET_OPTION_USERNAME,
GetUserName(), strlen(GetUserName())+1);
InternetSetOption(m_op.hRequest, INTERNET_OPTION_PASSWORD,
GetPassword(), strlen(GetPassword())+1);
fResult = TRUE;
}
}
return fResult;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_LogRequest
// --------------------------------------------------------------------------------
void CHTTPMailTransport::_LogRequest(LPVOID pvData, DWORD cbData)
{
HRESULT hr = S_OK;
CByteStream bs;
LPSTR pszCommand = CommandToVerb(m_op.rResponse.command);
LPSTR pszLogData = NULL;
Assert(NULL != m_pLogFile);
if (NULL == m_pLogFile)
return;
FAIL_EXIT_STREAM_WRITE(bs, c_szCRLF);
FAIL_EXIT_STREAM_WRITE(bs, pszCommand);
FAIL_EXIT_STREAM_WRITE(bs, c_szSpace);
FAIL_EXIT_STREAM_WRITE(bs, m_op.pszUrl);
if (pvData && cbData)
{
FAIL_EXIT_STREAM_WRITE(bs, c_szCRLF);
if (FAILED(hr = bs.Write(pvData, cbData, NULL)))
goto exit;
}
FAIL_EXIT_STREAM_WRITE(bs, c_szCRLF);
FAIL_EXIT_STREAM_WRITE(bs, c_szCRLF);
FAIL_EXIT(hr = bs.HrAcquireStringA(NULL, &pszLogData, ACQ_DISPLACE));
m_pLogFile->WriteLog(LOGFILE_TX, pszLogData);
exit:
SafeMemFree(pszLogData);
return;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_LogResponse
// --------------------------------------------------------------------------------
void CHTTPMailTransport::_LogResponse(LPVOID pvData, DWORD cbData)
{
HRESULT hr = S_OK;
CByteStream bs;
LPSTR pszHeaders = NULL;
LPSTR pszLogData = NULL;
Assert(NULL != m_pLogFile);
if (NULL == m_pLogFile || m_op.fLoggedResponse)
return;
FAIL_EXIT(_GetRequestHeader(&pszHeaders, HTTP_QUERY_RAW_HEADERS_CRLF));
if (pszHeaders)
{
// prefix with a CRLF
if ('\r' != pszHeaders[0])
FAIL_EXIT_STREAM_WRITE(bs, c_szCRLF);
FAIL_EXIT_STREAM_WRITE(bs, pszHeaders);
}
if (pvData && cbData)
{
if (FAILED(hr = bs.Write(pvData, cbData, NULL)))
goto exit;
}
FAIL_EXIT_STREAM_WRITE(bs, c_szCRLF);
FAIL_EXIT_STREAM_WRITE(bs, c_szCRLF);
FAIL_EXIT(hr = bs.HrAcquireStringA(NULL, &pszLogData, ACQ_DISPLACE));
m_pLogFile->WriteLog(LOGFILE_RX, pszLogData);
exit:
m_op.fLoggedResponse = TRUE;
SafeMemFree(pszHeaders);
SafeMemFree(pszLogData);
return;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::TranslateWinInetMsg
// --------------------------------------------------------------------------------
BOOL CHTTPMailTransport::TranslateWinInetMsg(
DWORD dwInternetStatus,
IXPSTATUS *pIxpStatus)
{
IxpAssert(NULL != pIxpStatus);
switch (dwInternetStatus)
{
case INTERNET_STATUS_RESOLVING_NAME:
*pIxpStatus = IXP_FINDINGHOST;
break;
case INTERNET_STATUS_CONNECTING_TO_SERVER:
*pIxpStatus = IXP_CONNECTING;
break;
case INTERNET_STATUS_CONNECTED_TO_SERVER:
*pIxpStatus = IXP_CONNECTED;
break;
case INTERNET_STATUS_CLOSING_CONNECTION:
*pIxpStatus = IXP_DISCONNECTING;
break;
case INTERNET_STATUS_CONNECTION_CLOSED:
*pIxpStatus = IXP_DISCONNECTED;
break;
case INTERNET_STATUS_REQUEST_COMPLETE:
*pIxpStatus = IXP_LAST;
break;
default:
// status codes that are not translated:
// INTERNET_STATUS_NAME_RESOLVED
// INTERNET_STATUS_SENDING_REQUEST
// INTERNET_STATUS_ REQUEST_SENT
// INTERNET_STATUS_RECEIVING_RESPONSE
// INTERNET_STATUS_RESPONSE_RECEIVED
// INTERNET_STATUS_REDIRECT
// INTERNET_STATUS_HANDLE_CREATED
// INTERNET_STATUS_HANDLE_CLOSING
return FALSE;
}
return TRUE;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_CreateXMLParser
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_CreateXMLParser()
{
HRESULT hr = S_OK;
if (NULL == m_pParser)
{
// instantiate the xml document
hr = ::CoCreateInstance(CLSID_XMLParser,
NULL,
CLSCTX_INPROC_SERVER,
IID_IXMLParser,
reinterpret_cast<void **>(&m_pParser));
if (FAILED(hr))
goto exit;
if (FAILED(hr = m_pParser->SetFlags(XMLFLAG_FLOATINGAMP)))
goto exit;
}
hr = m_pParser->SetFactory(this);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::OpenRequest
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::OpenRequest(void)
{
LPSTR pszVerb = NULL;
HRESULT hr = S_OK;
LPSTR pszHostName = NULL;
LPSTR pszUrlPath = NULL;
INTERNET_PORT nPort;
LPSTR pszUserName = GetUserName();
LPSTR pszPassword = GetPassword();
if (NULL == pszUserName)
pszUserName = "";
if (NULL == pszPassword)
pszPassword = "";
// crack the url into component parts
if (FAILED(hr = HrCrackUrl(m_op.pszUrl, &pszHostName, &pszUrlPath, &nPort)))
{
TrapError(hr);
goto exit;
}
if (FAILED(hr = HrConnectToHost(pszHostName, nPort, pszUserName, NULL)))
{
TrapError(hr);
goto exit;
}
// We have to set the password and username on every connection. If we don't,
// and and incorrect password or username forces us to prompt the user, the
// newly entered data won't get used on subsequent requests
InternetSetOption(GetConnection(), INTERNET_OPTION_USERNAME, pszUserName, lstrlen(pszUserName) + 1);
InternetSetOption(GetConnection(), INTERNET_OPTION_PASSWORD, pszPassword, lstrlen(pszPassword) + 1);
FAIL_ABORT;
// convert the command to a verb string
pszVerb = CommandToVerb(m_op.rResponse.command);
// Open the HTTP request
m_op.hRequest = HttpOpenRequest(
GetConnection(),
pszVerb,
pszUrlPath,
NULL,
NULL,
m_op.rgszAcceptTypes,
INTERNET_FLAG_EXISTING_CONNECT |
INTERNET_FLAG_RELOAD |
INTERNET_FLAG_KEEP_CONNECTION,
0);
if (NULL == m_op.hRequest)
{
DWORD dwErr = GetLastError();
hr = E_FAIL;
}
exit:
SafeMemFree(pszHostName);
SafeMemFree(pszUrlPath);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::SendPostRequest
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::SendPostRequest(void)
{
HRESULT hr = S_OK;
INTERNET_BUFFERS buffers;
DWORD cbData;
ULONG cbRead;
ULONG cbWritten;
BOOL fResult;
CHAR localBuffer[HTTPMAIL_BUFSIZE];
LARGE_INTEGER liOrigin = {0,0};
DWORD dwBufferLength;
BOOL fSentData = FALSE;
BOOL fWillSend;
DWORD dwWinInetErr = 0;
BOOL fRetryAuth = FALSE;
// log the request, but don't log the request body
if (m_pLogFile)
_LogRequest(NULL, 0);
if (m_op.pHeaderStream)
{
if (FAILED(hr = HrGetStreamSize(m_op.pHeaderStream, &m_op.rResponse.rPostInfo.cbTotal)))
goto exit;
}
if (m_op.pBodyStream)
{
if (FAILED(hr = HrGetStreamSize(m_op.pBodyStream, &cbData)))
goto exit;
m_op.rResponse.rPostInfo.cbTotal += cbData;
}
buffers.dwStructSize = sizeof(INTERNET_BUFFERSA);
buffers.Next = NULL;
buffers.lpcszHeader = NULL;
buffers.dwHeadersLength = 0;
buffers.dwHeadersTotal = 0;
buffers.lpvBuffer = NULL;
buffers.dwBufferLength = 0;
buffers.dwBufferTotal = m_op.rResponse.rPostInfo.cbTotal;
buffers.dwOffsetLow = 0;
buffers.dwOffsetHigh = 0;
resend:
if (fSentData)
{
m_op.rResponse.rPostInfo.fResend = TRUE;
m_op.rResponse.rPostInfo.cbCurrent = 0;
_HrThunkResponse(FALSE);
m_op.rResponse.rPostInfo.fResend = FALSE;
FAIL_ABORT;
}
fResult = HttpSendRequestEx(m_op.hRequest, &buffers, NULL, 0, 0);
if (!fResult)
{
dwWinInetErr = GetLastError();
if (ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION == dwWinInetErr)
{
fRetryAuth = TRUE;
goto resend;
}
_HrThunkConnectionError(dwWinInetErr);
hr = E_FAIL;
goto exit;
}
// with some auth methods (e.g., NTLM), wininet will send a post request
// with a content length of 0, and will ignore calls to InternetWriteFile
// until the server sends a 100 (continue) response. wininet will then
// return ERROR_INTERNET_FORCE_RETRY to force a resend. we detect this
// case here so that we don't send a bunch of OnResponse progress notifications
// when no data is actually going out over the wire
// this constant isn't in the wininet headers as of 10/6/98!!
#ifndef INTERNET_OPTION_DETECT_POST_SEND
#define INTERNET_OPTION_DETECT_POST_SEND 71
#endif
dwBufferLength = sizeof(fWillSend);
if (!InternetQueryOption(m_op.hRequest, INTERNET_OPTION_DETECT_POST_SEND, &fWillSend, &dwBufferLength))
fWillSend = TRUE;
else
{
Assert(dwBufferLength == sizeof(BOOL));
}
if (fWillSend)
{
fSentData = TRUE;
if (m_op.pHeaderStream)
{
// rewind the stream
if (FAILED(hr = m_op.pHeaderStream->Seek(liOrigin, STREAM_SEEK_SET, NULL)))
goto exit;
while (TRUE)
{
if (FAILED(hr = m_op.pHeaderStream->Read(localBuffer, sizeof(localBuffer), &cbRead)))
goto exit;
if (0 == cbRead)
break;
fResult = InternetWriteFile(m_op.hRequest, localBuffer, cbRead, &cbWritten);
IxpAssert(!fResult || (cbRead == cbWritten));
if (!fResult)
{
_HrThunkConnectionError(GetLastError());
hr = E_FAIL;
goto exit;
}
m_op.rResponse.rPostInfo.cbIncrement = cbWritten;
m_op.rResponse.rPostInfo.cbCurrent += cbWritten;
_HrThunkResponse(FALSE);
m_op.rResponse.rPostInfo.cbIncrement = 0;
FAIL_ABORT;
}
}
if (m_op.pBodyStream)
{
// rewind the stream
if (FAILED(hr = m_op.pBodyStream->Seek(liOrigin, STREAM_SEEK_SET, NULL)))
goto exit;
while (TRUE)
{
if (FAILED(hr = m_op.pBodyStream->Read(localBuffer, sizeof(localBuffer), &cbRead)))
goto exit;
if (0 == cbRead)
break;
fResult = InternetWriteFile(m_op.hRequest, localBuffer, cbRead, &cbWritten);
IxpAssert(!fResult || (cbRead == cbWritten));
if (!fResult)
{
_HrThunkConnectionError(GetLastError());
hr = E_FAIL;
goto exit;
}
m_op.rResponse.rPostInfo.cbIncrement = cbWritten;
m_op.rResponse.rPostInfo.cbCurrent += cbWritten;
_HrThunkResponse(FALSE);
m_op.rResponse.rPostInfo.cbIncrement = 0;
FAIL_ABORT;
}
}
}
fResult = HttpEndRequest(m_op.hRequest, NULL, 0, 0);
if (!fResult)
{
if (ERROR_INTERNET_FORCE_RETRY == GetLastError())
goto resend;
_HrThunkConnectionError(GetLastError());
}
if (!_GetStatusCode(&m_op.dwHttpStatus))
{
_HrThunkConnectionError(GetLastError());
hr = E_FAIL;
goto exit;
}
if (_AuthCurrentRequest(m_op.dwHttpStatus, fRetryAuth))
{
fRetryAuth = FALSE;
goto resend;
}
if (!fResult)
{
_HrThunkConnectionError();
hr = E_FAIL;
goto exit;
}
// status codes not in the 200-299 range indicate an error
if (200 > m_op.dwHttpStatus || 299 < m_op.dwHttpStatus)
{
_HrThunkConnectionError();
hr = E_FAIL;
}
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::SendRequest
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::SendRequest(void)
{
HRESULT hr = S_OK;
DWORD dwError;
BOOL bResult;
HWND hwndParent = NULL;
BOOL fRequestedParent = FALSE;
DWORD dwWinInetErr = 0;
BOOL fRetryAuth = FALSE;
// log the request, including the requets body
if (m_pLogFile)
_LogRequest(m_op.pvData, m_op.cbDataLen);
resend:
hr = S_OK;
bResult = HttpSendRequest(m_op.hRequest, NULL, 0L, m_op.pvData, m_op.cbDataLen);
if (!bResult)
{
dwWinInetErr = GetLastError();
if (ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION == dwWinInetErr)
{
fRetryAuth = TRUE;
goto resend;
}
_HrThunkConnectionError(dwWinInetErr);
hr = E_FAIL;
goto exit;
}
if (!_GetStatusCode(&m_op.dwHttpStatus))
{
_HrThunkConnectionError(GetLastError());
hr = E_FAIL;
goto exit;
}
if (_AuthCurrentRequest(m_op.dwHttpStatus, fRetryAuth))
{
fRetryAuth = FALSE;
goto resend;
}
// status codes not in the 200-299 range indicate an error
if (200 > m_op.dwHttpStatus|| 299 < m_op.dwHttpStatus)
{
_HrThunkConnectionError();
hr = E_FAIL;
goto exit;
}
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::RequireMultiStatus
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::RequireMultiStatus(void)
{
HRESULT hr = S_OK;
if (207 != m_op.dwHttpStatus)
{
_HrThunkConnectionError(ERROR_INTERNET_CANNOT_CONNECT);
hr = E_FAIL;
}
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FinalizeRequest
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::FinalizeRequest(void)
{
HRESULT hr = S_OK;
LPSTR pszTimestampHeader = NULL;
// log the response if it hasn't already been logged
if (m_pLogFile && !m_op.fLoggedResponse)
_LogResponse(NULL, 0);
if (HTTPMAIL_MEMBERINFO == m_op.rResponse.command)
{
// Get the headers and copy them. If we don't get timestamp header, its not a big deal. We don't report an error.
hr = _HrGetTimestampHeader(&pszTimestampHeader);
if (SUCCEEDED(hr))
{
// Get the Active timestamp
FAIL_EXIT(hr = _HrParseAndCopy(c_szActive, &m_op.rResponse.rMemberInfoList.pszFolderTimeStamp, pszTimestampHeader));
// Get RootTimeStamp which for some strange reason comes as Folders TimeStamp
// This call might fail for legitimate reasons. For Inbox list headers we do not get a RootTimeStamp.
// Hence we do not exit if we can't get root time stamp.
_HrParseAndCopy(c_szFolders, &m_op.rResponse.rMemberInfoList.pszRootTimeStamp, pszTimestampHeader);
SafeMemFree(pszTimestampHeader);
}
}
hr = _HrThunkResponse(TRUE);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ProcessGetResponse
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ProcessGetResponse(void)
{
HRESULT hr = S_OK;
BOOL bRead;
DWORD cbReadBytes = 0;
// log the respnse, but don't log the response body
if (m_pLogFile && !m_op.fLoggedResponse)
_LogResponse(NULL, 0);
Assert(NULL == m_op.rResponse.rGetInfo.pszContentType);
// extract the content type header
FAIL_EXIT(hr = _GetRequestHeader(&m_op.rResponse.rGetInfo.pszContentType, HTTP_QUERY_CONTENT_TYPE));
// try to get the content length
m_op.rResponse.rGetInfo.fTotalKnown = _GetContentLength(&m_op.rResponse.rGetInfo.cbTotal);
do
{
// The buffer is owned by this object, but the client
// has the option of taking ownership of the buffer
// whenever a read completes. We reallocate the buffer
// here if necessary
FAIL_ABORT;
if (!m_op.rResponse.rGetInfo.pvBody && !MemAlloc((void**)&m_op.rResponse.rGetInfo.pvBody, HTTPMAIL_BUFSIZE + 1))
{
hr = E_OUTOFMEMORY;
break;
}
bRead = ReadBytes((char *)m_op.rResponse.rGetInfo.pvBody, HTTPMAIL_BUFSIZE, &cbReadBytes);
m_op.rResponse.rGetInfo.cbIncrement = cbReadBytes;
m_op.rResponse.rGetInfo.cbCurrent += cbReadBytes;
// we guarantee space for the terminating null by allocating
// a buffer one larger than bufsize
static_cast<char *>(m_op.rResponse.rGetInfo.pvBody)[cbReadBytes] = '\0';
// Send a message to the window that lives in the client's thread
_HrThunkResponse(0 == cbReadBytes);
} while (0 < cbReadBytes);
exit:
SafeMemFree(m_op.rResponse.rGetInfo.pvBody);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ProcessPostResponse
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ProcessPostResponse(void)
{
HRESULT hr = S_OK;
// log the response
if (m_pLogFile && !m_op.fLoggedResponse)
_LogResponse(NULL, 0);
if (m_op.dwHttpStatus < 200 || m_op.dwHttpStatus > 299)
{
_HrThunkConnectionError();
hr = E_FAIL;
goto exit;
}
hr = _GetRequestHeader(&m_op.rResponse.rPostInfo.pszLocation, HTTP_QUERY_LOCATION);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ProcessXMLResponse
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ProcessXMLResponse(void)
{
HRESULT hr = S_OK;
BOOL bRead;
LPSTR pszBody = NULL;
DWORD cbLength = 0;
CByteStream *pLogStream = NULL;
BOOL fFoundBytes = FALSE;
if (m_pLogFile && !m_op.fLoggedResponse)
pLogStream = new CByteStream();
// we only parse xml if the response is a 207 (multistatus)
if (m_op.dwHttpStatus != 207)
goto exit;
// create the xml parser
if (FAILED(hr = _CreateXMLParser()))
goto exit;
if (!MemAlloc((void **)&pszBody, HTTPMAIL_BUFSIZE))
{
hr = E_OUTOFMEMORY;
goto exit;
}
do
{
FAIL_ABORT;
bRead = ReadBytes(pszBody, HTTPMAIL_BUFSIZE, &cbLength);
if (0 == cbLength)
{
if (fFoundBytes)
{
// parse any remaining bytes in the parser's buffer
if (FAILED(hr = m_pParser->PushData(NULL, 0, TRUE)))
goto exit;
if (FAILED(hr = m_pParser->Run(-1)))
goto exit;
}
break;
}
fFoundBytes = TRUE;
// if logging, write the block into the log stream
if (pLogStream)
pLogStream->Write(pszBody, cbLength, NULL);
if (FAILED(hr = m_pParser->PushData(pszBody, cbLength, FALSE)))
goto exit;
if (FAILED(hr = m_pParser->Run(-1)))
{
if (hr == E_PENDING)
hr = S_OK;
else
goto exit;
}
} while (TRUE);
exit:
SafeMemFree(pszBody);
if (pLogStream)
{
LPSTR pszLog = NULL;
DWORD dwLog = 0;
pLogStream->HrAcquireStringA(&dwLog, &pszLog, ACQ_DISPLACE);
_LogResponse(pszLog, dwLog);
SafeMemFree(pszLog);
delete pLogStream;
}
if (m_pParser)
m_pParser->Reset();
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::GeneratePropFindXML
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::GeneratePropFindXML(void)
{
HRESULT hr = S_OK;
LPSTR pszXML = NULL;
IxpAssert(NULL == m_op.pvData && 0 == m_op.cbDataLen);
IxpAssert(NULL != m_op.pPropFindRequest);
if (FAILED(hr = m_op.pPropFindRequest->GenerateXML(&pszXML)))
goto exit;
m_op.pvData = pszXML;
m_op.cbDataLen = lstrlen(pszXML);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::AddDepthHeader
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::AddDepthHeader(void)
{
HRESULT hr = S_OK;
char szDepthHeader[64];
if (0 != m_op.dwDepth && !!(m_op.dwRHFlags & RH_NOROOT))
{
if (DEPTH_INFINITY == m_op.dwDepth)
StrCpyN(szDepthHeader, c_szDepthInfinityNoRootHeader, ARRAYSIZE(szDepthHeader));
else
wnsprintf(szDepthHeader, ARRAYSIZE(szDepthHeader), c_szDepthNoRootHeader, m_op.dwDepth);
}
else
{
if (DEPTH_INFINITY == m_op.dwDepth)
StrCpyN(szDepthHeader, c_szDepthInfinityHeader, ARRAYSIZE(szDepthHeader));
else
wnsprintf(szDepthHeader, ARRAYSIZE(szDepthHeader), c_szDepthHeader, m_op.dwDepth);
}
if (!HttpAddRequestHeaders(m_op.hRequest, szDepthHeader, lstrlen(szDepthHeader), HTTP_ADDREQ_FLAG_ADD))
{
_HrThunkConnectionError();
hr = E_FAIL;
}
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::GeneratePropPatchXML
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::GeneratePropPatchXML(void)
{
HRESULT hr = S_OK;
LPSTR pszXML = NULL;
IxpAssert(NULL == m_op.pvData && 0 == m_op.cbDataLen);
IxpAssert(NULL != m_op.pPropPatchRequest);
if (FAILED(hr = m_op.pPropPatchRequest->GenerateXML(&pszXML)))
goto exit;
m_op.pvData = pszXML;
m_op.cbDataLen = lstrlen(pszXML);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ProcessCreatedResponse
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ProcessCreatedResponse(void)
{
HRESULT hr = S_OK;
if (m_pLogFile && !m_op.fLoggedResponse)
_LogResponse(NULL, 0);
if (HTTP_STATUS_CREATED != m_op.dwHttpStatus)
{
_HrThunkConnectionError();
hr = E_FAIL;
}
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::AddCommonHeaders
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::AddCommonHeaders(void)
{
HRESULT hr = S_OK;
CHAR szHeader[CCHMAX_RES];
if (!!(RH_ALLOWRENAME & m_op.dwRHFlags))
{
if (FAILED(hr = _AddRequestHeader(c_szAllowRenameHeader)))
goto exit;
}
if (!!(RH_TRANSLATEFALSE & m_op.dwRHFlags))
{
if (FAILED(hr = _AddRequestHeader(c_szTranslateFalseHeader)))
goto exit;
}
if (!!(RH_TRANSLATETRUE & m_op.dwRHFlags))
{
if (FAILED(hr = _AddRequestHeader(c_szTranslateTrueHeader)))
goto exit;
}
if (!!(RH_XMLCONTENTTYPE & m_op.dwRHFlags))
{
IxpAssert(NULL == m_op.pszContentType);
m_op.pszContentType = PszDupA(c_szXmlContentType);
if (NULL == m_op.pszContentType)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
if (FAILED(hr = AddContentTypeHeader()))
goto exit;
}
if (!!(RH_MESSAGECONTENTTYPE & m_op.dwRHFlags))
{
IxpAssert(NULL == m_op.pszContentType);
m_op.pszContentType = PszDupA(c_szMailContentType);
if (NULL == m_op.pszContentType)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
if (FAILED(hr = AddContentTypeHeader()))
goto exit;
}
if (!!(RH_SMTPMESSAGECONTENTTYPE & m_op.dwRHFlags))
{
IxpAssert(NULL == m_op.pszContentType);
m_op.pszContentType = PszDupA(c_szSmtpMessageContentType);
if (NULL == m_op.pszContentType)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
if (FAILED(hr = AddContentTypeHeader()))
goto exit;
}
if (!!(RH_BRIEF & m_op.dwRHFlags))
{
if (FAILED(hr = _AddRequestHeader(c_szBriefHeader)))
goto exit;
}
if (!!(RH_SAVEINSENTTRUE & m_op.dwRHFlags))
{
FAIL_EXIT(hr = _AddRequestHeader(c_szSaveInSentTrue));
}
if (!!(RH_SAVEINSENTFALSE & m_op.dwRHFlags))
{
FAIL_EXIT(hr = _AddRequestHeader(c_szSaveInSentFalse));
}
if (!!(RH_ROOTTIMESTAMP & m_op.dwRHFlags))
{
wnsprintf(szHeader, ARRAYSIZE(szHeader), c_szRootTimeStampHeader, m_op.pszRootTimeStamp, m_op.pszFolderTimeStamp);
FAIL_EXIT(hr = _AddRequestHeader(szHeader));
}
if (!!(RH_FOLDERTIMESTAMP & m_op.dwRHFlags))
{
wnsprintf(szHeader, ARRAYSIZE(szHeader), c_szFolderTimeStampHeader, m_op.pszFolderTimeStamp);
FAIL_EXIT(hr = _AddRequestHeader(szHeader));
}
// Fix for 88820
if (!!(RH_ADDCHARSET & m_op.dwRHFlags))
{
CODEPAGEINFO CodePageInfo;
MimeOleGetCodePageInfo(CP_ACP, &CodePageInfo);
*szHeader = 0;
wnsprintf(szHeader, ARRAYSIZE(szHeader), c_szAcceptCharset, CodePageInfo.szWebCset);
FAIL_EXIT(hr = _AddRequestHeader(szHeader));
}
// end of fix
exit:
return hr;
}
// CHTTPMailTransport::AddCharsetLine
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::AddCharsetLine(void)
{
HRESULT hr = S_OK;
CHAR szHeader[CCHMAX_RES];
CODEPAGEINFO CodePageInfo;
MimeOleGetCodePageInfo(CP_ACP, &CodePageInfo);
*szHeader = 0;
wnsprintf(szHeader, ARRAYSIZE(szHeader), c_szAcceptCharset, CodePageInfo.szWebCset);
hr = _AddRequestHeader(szHeader);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::AddDestinationHeader
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::AddDestinationHeader(void)
{
HRESULT hr = S_OK;
ULONG cchSize = (lstrlen(c_szDestinationHeader) + lstrlen(m_op.pszDestination) + 1);
LPSTR pszDestHeader = NULL;
if (!MemAlloc((void **)&pszDestHeader, cchSize * sizeof(pszDestHeader[0])))
{
hr = E_OUTOFMEMORY;
goto exit;
}
wnsprintf(pszDestHeader, cchSize, "%s%s", c_szDestinationHeader, m_op.pszDestination);
hr = _AddRequestHeader(pszDestHeader);
exit:
SafeMemFree(pszDestHeader);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::AddContentTypeHeader
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::AddContentTypeHeader(void)
{
HRESULT hr = S_OK;
ULONG cchSize;
LPSTR pszContentTypeHeader = NULL;
if (NULL == m_op.pszContentType)
goto exit;
cchSize = lstrlen(c_szContentTypeHeader) + lstrlen(m_op.pszContentType) + 1;
if (!MemAlloc((void **)&pszContentTypeHeader, cchSize * sizeof(pszContentTypeHeader[0])))
{
hr = E_OUTOFMEMORY;
goto exit;
}
wnsprintf(pszContentTypeHeader, cchSize, "%s%s", c_szContentTypeHeader, m_op.pszContentType);
hr = _AddRequestHeader(pszContentTypeHeader);
exit:
SafeMemFree(pszContentTypeHeader);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ProcessLocationResponse
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ProcessLocationResponse(void)
{
_GetRequestHeader(&m_op.rResponse.rCopyMoveInfo.pszLocation, HTTP_QUERY_LOCATION);
return S_OK;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::InitBCopyMove
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::InitBCopyMove(void)
{
HRESULT hr = S_OK;
// allocate a buffer to contain the response list
if (!MemAlloc((void **)&m_op.rResponse.rBCopyMoveList.prgBCopyMove,
BCOPYMOVE_MAXRESPONSES * sizeof(HTTPMAILBCOPYMOVE)))
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
ZeroMemory(m_op.rResponse.rBCopyMoveList.prgBCopyMove, BCOPYMOVE_MAXRESPONSES * sizeof(HTTPMAILBCOPYMOVE));
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::InitRootProps
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::InitRootProps(void)
{
HRESULT hr = S_OK;
// it is possible to end up here, and have the root props
// if the caller either forced the request to go async,
// or queued up multiple requests for root props.
if (GetHasRootProps())
{
// finalize the root props, and return an error.
// this will generate the response to the caller,
// and fall out of the fsm.
FinalizeRootProps();
hr = E_FAIL;
}
else
{
IxpAssert(NULL == m_op.pPropFindRequest);
m_op.pPropFindRequest = new CPropFindRequest();
if (NULL == m_op.pPropFindRequest)
{
hr = E_OUTOFMEMORY;
goto exit;
}
hr = XP_CREATE_PROPFIND_REQUEST(ROOTPROPS, m_op.pPropFindRequest);
}
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FinalizeRootProps
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::FinalizeRootProps(void)
{
HRESULT hr = S_OK;
m_fHasRootProps = TRUE;
m_op.rResponse.rGetPropInfo.type = m_op.tyProp;
if (m_op.tyProp != HTTPMAIL_PROP_MAXPOLLINGINTERVAL)
{
m_op.rResponse.rIxpResult.hrResult = GetProperty(m_op.tyProp, &m_op.rResponse.rGetPropInfo.pszProp);
}
else
{
m_op.rResponse.rIxpResult.hrResult = GetPropertyDw(m_op.tyProp, &m_op.rResponse.rGetPropInfo.dwProp);
}
hr = _HrThunkResponse(TRUE);
SafeMemFree(m_op.rResponse.rGetPropInfo.pszProp);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::InitMemberInfo
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::InitMemberInfo(void)
{
HRESULT hr = S_OK;
IxpAssert(NULL == m_op.pPropFindRequest);
// create the propfind request
m_op.pPropFindRequest = new CPropFindRequest();
if (NULL == m_op.pPropFindRequest)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// always add the common properties
FAIL_EXIT(hr = XP_CREATE_PROPFIND_REQUEST(HTTPMEMBERINFO_COMMON, m_op.pPropFindRequest));
// if the client requested folder props, add that schema
if (!!(m_op.dwMIFlags & HTTP_MEMBERINFO_FOLDERPROPS))
FAIL_EXIT(hr = XP_CREATE_PROPFIND_REQUEST(HTTPMEMBERINFO_FOLDER, m_op.pPropFindRequest));
// if the client requested message props, add that schema
if (!!(m_op.dwMIFlags & HTTP_MEMBERINFO_MESSAGEPROPS))
FAIL_EXIT(hr = XP_CREATE_PROPFIND_REQUEST(HTTPMEMBERINFO_MESSAGE, m_op.pPropFindRequest));
// allocate a buffer to contain the response list
if (!MemAlloc((void **)&m_op.rResponse.rMemberInfoList.prgMemberInfo,
MEMBERINFO_MAXRESPONSES * sizeof(HTTPMEMBERINFO)))
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
ZeroMemory(m_op.rResponse.rMemberInfoList.prgMemberInfo, MEMBERINFO_MAXRESPONSES * sizeof(HTTPMEMBERINFO));
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::InitMemberError
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::InitMemberError(void)
{
HRESULT hr = S_OK;
// allocate a buffer to contain the response list
if (!MemAlloc((void **)&m_op.rResponse.rMemberErrorList.prgMemberError,
MEMBERERROR_MAXRESPONSES * sizeof(HTTPMEMBERERROR)))
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
ZeroMemory(m_op.rResponse.rMemberErrorList.prgMemberError, MEMBERERROR_MAXRESPONSES * sizeof(HTTPMEMBERERROR));
exit:
return hr;
}
// --------------------------------------------------------------------------------
// InitListContacts
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::InitListContacts(void)
{
HRESULT hr = S_OK;
IxpAssert(NULL == m_op.pPropFindRequest);
m_op.pPropFindRequest = new CPropFindRequest();
if (NULL == m_op.pPropFindRequest)
{
hr = E_OUTOFMEMORY;
goto exit;
}
hr = XP_CREATE_PROPFIND_REQUEST(HTTPCONTACTID, m_op.pPropFindRequest);
if (FAILED(hr))
goto exit;
// allocate a buffer to contain the response list
if (!MemAlloc((void **)&m_op.rResponse.rContactIdList.prgContactId,
LISTCONTACTS_MAXRESPONSES * sizeof(HTTPCONTACTID)))
{
hr = E_OUTOFMEMORY;
goto exit;
}
ZeroMemory(m_op.rResponse.rContactIdList.prgContactId, LISTCONTACTS_MAXRESPONSES * sizeof(HTTPCONTACTID));
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::InitContactInfo
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::InitContactInfo(void)
{
HRESULT hr = S_OK;
IxpAssert(NULL == m_op.pPropFindRequest);
m_op.pPropFindRequest = new CPropFindRequest();
if (NULL == m_op.pPropFindRequest)
{
hr = E_OUTOFMEMORY;
goto exit;
}
hr = XP_CREATE_PROPFIND_REQUEST(HTTPCONTACTINFO, m_op.pPropFindRequest);
if (FAILED(hr))
goto exit;
// allocate a buffer to contain the response list
if (!MemAlloc((void **)&m_op.rResponse.rContactInfoList.prgContactInfo,
CONTACTINFO_MAXRESPONSES * sizeof(HTTPCONTACTINFO)))
{
hr = E_OUTOFMEMORY;
goto exit;
}
ZeroMemory(m_op.rResponse.rContactInfoList.prgContactInfo, CONTACTINFO_MAXRESPONSES * sizeof(HTTPCONTACTINFO));
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ProcessPostContactResponse
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ProcessPostContactResponse(void)
{
HRESULT hr = S_OK;
DWORD dwSize = MAX_PATH;
LPSTR pszLocation = NULL;
DWORD dwContext;
int iState;
if (m_pLogFile && !m_op.fLoggedResponse)
_LogResponse(NULL, 0);
if (HTTP_STATUS_CREATED != m_op.dwHttpStatus)
{
_HrThunkConnectionError();
hr = E_FAIL;
goto exit;
}
if (FAILED(hr = _GetRequestHeader(&pszLocation, HTTP_QUERY_LOCATION)))
goto exit;
// Prepare for the next phase
// save the context and the state
dwContext = m_op.dwContext;
iState = m_op.iState;
FreeOperation();
// restore context, state, parsing funcs, etc.
m_op.rResponse.command = HTTPMAIL_POSTCONTACT;
m_op.pszUrl = pszLocation;
pszLocation = NULL;
m_op.dwContext = dwContext;
m_op.pfnState = c_rgpfnPostContact;
m_op.cState = ARRAYSIZE(c_rgpfnPostContact);
m_op.iState = iState;
m_op.pParseFuncs = c_rgpfnPostOrPatchContactParse;
m_op.dwDepth = 0;
m_op.dwRHFlags = (RH_XMLCONTENTTYPE | RH_BRIEF);
m_op.rResponse.rPostContactInfo.pszHref = PszDupA(m_op.pszUrl);
if (NULL == m_op.rResponse.rPostContactInfo.pszHref)
hr = E_OUTOFMEMORY;
exit:
SafeMemFree(pszLocation);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ProcessPatchContactResponse
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ProcessPatchContactResponse(void)
{
HRESULT hr = S_OK;
LPSTR pszUrl = NULL;
DWORD dwContext;
int iState;
IHTTPMailCallback *pCallback = NULL;
// REVIEW: we should be handling multistatus responses
if (200 > m_op.dwHttpStatus || 300 < m_op.dwHttpStatus)
{
_HrThunkConnectionError();
hr = E_FAIL;
goto exit;
}
// prepare for the next phase
// save the context and the state
pszUrl = m_op.pszUrl;
m_op.pszUrl = NULL;
dwContext = m_op.dwContext;
iState = m_op.iState;
FreeOperation();
// restore context, etc.
m_op.rResponse.command = HTTPMAIL_PATCHCONTACT;
m_op.pszUrl = pszUrl;
m_op.dwContext = dwContext;
m_op.pfnState = c_rgpfnPatchContact;
m_op.cState = ARRAYSIZE(c_rgpfnPatchContact);
m_op.iState = iState;
m_op.pParseFuncs = c_rgpfnPostOrPatchContactParse; // share the post contact parse funcs
m_op.dwDepth = 0;
m_op.rResponse.rPatchContactInfo.pszHref = PszDupA(m_op.pszUrl);
m_op.dwRHFlags = (RH_BRIEF | RH_XMLCONTENTTYPE);
pszUrl = NULL;
exit:
return hr;
}
// --------------------------------------------------------------------------------
// XML Parsing Callbacks
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// CHTTPMailTransport::CreateElement
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::CreateElement(
CXMLNamespace *pBaseNamespace,
const WCHAR *pwcText,
ULONG ulLen,
ULONG ulNamespaceLen,
BOOL fTerminal)
{
// increment the stack pointer and, if there is room on the stack,
// push the element type
if (!fTerminal)
{
if (m_op.dwStackDepth < ELE_STACK_CAPACITY)
{
m_op.rgEleStack[m_op.dwStackDepth].ele = XMLElementToID(pwcText, ulLen, ulNamespaceLen, m_op.pTopNamespace);
m_op.rgEleStack[m_op.dwStackDepth].pBaseNamespace = pBaseNamespace;
m_op.rgEleStack[m_op.dwStackDepth].fBeganChildren = FALSE;
m_op.rgEleStack[m_op.dwStackDepth].pTextBuffer = NULL;
}
++m_op.dwStackDepth;
}
return S_OK;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::EndChildren
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::EndChildren(void)
{
HRESULT hr = S_OK;
// decrement the stack pointer
if (m_op.dwStackDepth <= ELE_STACK_CAPACITY)
{
LPPCDATABUFFER pTextBuffer = m_op.rgEleStack[m_op.dwStackDepth - 1].pTextBuffer;
if (pTextBuffer)
{
hr = (this->*(m_op.pParseFuncs->pfnHandleText))(pTextBuffer->pwcText, pTextBuffer->ulLen);
_ReleaseTextBuffer(pTextBuffer);
}
else
hr = (this->*(m_op.pParseFuncs->pfnHandleText))(NULL, 0);
// unroll the namespace
PopNamespaces(m_op.rgEleStack[m_op.dwStackDepth - 1].pBaseNamespace);
}
--m_op.dwStackDepth;
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::BCopyMove_HandleText
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::BCopyMove_HandleText(const WCHAR *pwcText, ULONG ulLen)
{
HRESULT hr = S_OK;
LPHTTPMAILBCOPYMOVE pInfo = &m_op.rResponse.rBCopyMoveList.prgBCopyMove[m_op.rResponse.rBCopyMoveList.cBCopyMove];
return XP_BIND_TO_STRUCT(HTTPMAILBCOPYMOVE, pwcText, ulLen, pInfo, NULL);
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::BCopyMove_EndChildren
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::BCopyMove_EndChildren(void)
{
HRESULT hr = S_OK;
if (StackTop(HMELE_DAV_RESPONSE) && VALIDSTACK(c_rgPropFindResponseStack))
{
// clear the prop flags, since we are about to increment the count
m_op.dwPropFlags = NOFLAGS;
// increment the list count and, if we've hit the max, send the notification
if (BCOPYMOVE_MAXRESPONSES == ++m_op.rResponse.rBCopyMoveList.cBCopyMove)
{
if (FAILED(hr = _HrThunkResponse(FALSE)))
goto exit;
FreeBCopyMoveList();
}
}
hr = EndChildren();
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::PropFind_HandleText
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::PropFind_HandleText(const WCHAR *pwcText, ULONG ulLen)
{
HRESULT hr = S_OK;
LPSTR pszStatus = NULL;
// the only element that is handled here is <status>
if (StackTop(HMELE_DAV_STATUS) && VALIDSTACK(c_rgPropFindStatusStack))
{
m_op.fFoundStatus = TRUE;
m_op.dwStatus = 0;
if (SUCCEEDED(hr = AllocStrFromStrNW(pwcText, ulLen, &pszStatus)) && NULL != pszStatus)
{
// ignore errors parsing the status...we treat malformed status
// as status 0, which is an error
HrParseHTTPStatus(pszStatus, &m_op.dwStatus);
}
}
SafeMemFree(pszStatus);
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::RootProps_HandleText
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::RootProps_HandleText(const WCHAR *pwcText, ULONG ulLen)
{
HRESULT hr = S_OK;
BOOL fWasBound = FALSE;
hr = XP_BIND_TO_STRUCT(ROOTPROPS, pwcText, ulLen, &m_rootProps, &fWasBound);
if (FAILED(hr))
goto exit;
if (!fWasBound)
hr = PropFind_HandleText(pwcText, ulLen);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::RootProps_EndChildren
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::RootProps_EndChildren(void)
{
// if we are popping a prop node with a bad status code,
// free any data associated with the node
if (StackTop(HMELE_DAV_PROPSTAT) && VALIDSTACK(c_rgPropFindPropStatStack))
{
if (!m_op.fFoundStatus || m_op.dwStatus != 200)
XP_FREE_STRUCT(ROOTPROPS, &m_rootProps, &m_op.dwPropFlags);
m_op.fFoundStatus = FALSE;
m_op.dwPropFlags = NOFLAGS;
}
return EndChildren();
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::MemberInfo_HandleText
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::MemberInfo_HandleText(const WCHAR *pwcText, ULONG ulLen)
{
HRESULT hr = S_OK;
LPHTTPMEMBERINFO pInfo = &m_op.rResponse.rMemberInfoList.prgMemberInfo[m_op.rResponse.rMemberInfoList.cMemberInfo];
BOOL fWasBound = FALSE;
FAIL_EXIT(hr = XP_BIND_TO_STRUCT(HTTPMEMBERINFO, pwcText, ulLen, pInfo, &fWasBound));
if (!fWasBound)
hr = PropFind_HandleText(pwcText, ulLen);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::MemberInfo_EndChildren
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::MemberInfo_EndChildren(void)
{
HRESULT hr = S_OK;
// if we are popping a propstat node with a bad status code,
// free any data associated with the node
if (StackTop(HMELE_DAV_PROPSTAT) && VALIDSTACK(c_rgPropFindPropStatStack))
{
// grab a pointer to the folder info we are accumulating
LPHTTPMEMBERINFO pInfo =
&m_op.rResponse.rMemberInfoList.prgMemberInfo[m_op.rResponse.rMemberInfoList.cMemberInfo];
if (!m_op.fFoundStatus || m_op.dwStatus != 200)
XP_FREE_STRUCT(HTTPMEMBERINFO, pInfo, &m_op.dwPropFlags);
m_op.fFoundStatus = FALSE;
m_op.dwPropFlags = NOFLAGS;
}
else if (StackTop(HMELE_DAV_RESPONSE) && VALIDSTACK(c_rgPropFindResponseStack))
{
// increment the list count and, if we've hit the max, send the notification
if (MEMBERINFO_MAXRESPONSES == ++m_op.rResponse.rMemberInfoList.cMemberInfo)
{
if (FAILED(hr = _HrThunkResponse(FALSE)))
goto exit;
FreeMemberInfoList();
}
}
hr = EndChildren();
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::MemberError_HandleText
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::MemberError_HandleText(const WCHAR *pwcText, ULONG ulLen)
{
HRESULT hr = S_OK;
LPHTTPMEMBERERROR pInfo = &m_op.rResponse.rMemberErrorList.prgMemberError[m_op.rResponse.rMemberErrorList.cMemberError];
BOOL fWasBound = FALSE;
FAIL_EXIT(hr = XP_BIND_TO_STRUCT(HTTPMEMBERERROR, pwcText, ulLen, pInfo, &fWasBound));
if (!fWasBound)
hr = PropFind_HandleText(pwcText, ulLen);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::MemberError_EndChildren
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::MemberError_EndChildren(void)
{
HRESULT hr = S_OK;
// if we are popping a propstat node with a bad status code,
// free any data associated with the node
if (StackTop(HMELE_DAV_PROPSTAT) && VALIDSTACK(c_rgPropFindPropStatStack))
{
// grab a pointer to the folder info we are accumulating
LPHTTPMEMBERERROR pInfo =
&m_op.rResponse.rMemberErrorList.prgMemberError[m_op.rResponse.rMemberErrorList.cMemberError];
if (!m_op.fFoundStatus || m_op.dwStatus != 200)
XP_FREE_STRUCT(HTTPMEMBERERROR, pInfo, &m_op.dwPropFlags);
m_op.fFoundStatus = FALSE;
m_op.dwPropFlags = NOFLAGS;
}
else if (StackTop(HMELE_DAV_RESPONSE) && VALIDSTACK(c_rgPropFindResponseStack))
{
// increment the list count and, if we've hit the max, send the notification
if (MEMBERERROR_MAXRESPONSES == ++m_op.rResponse.rMemberErrorList.cMemberError)
{
if (FAILED(hr = _HrThunkResponse(FALSE)))
goto exit;
FreeMemberErrorList();
}
}
hr = EndChildren();
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ListContacts_HandleText
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ListContacts_HandleText(const WCHAR *pwcText, ULONG ulLen)
{
HRESULT hr = S_OK;
LPHTTPCONTACTID pId = &m_op.rResponse.rContactIdList.prgContactId[m_op.rResponse.rContactIdList.cContactId];
BOOL fWasBound = FALSE;
hr = XP_BIND_TO_STRUCT(HTTPCONTACTID, pwcText, ulLen, pId, &fWasBound);
if (FAILED(hr))
goto exit;
if (!fWasBound)
hr = PropFind_HandleText(pwcText, ulLen);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ListContacts_EndChildren
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ListContacts_EndChildren(void)
{
HRESULT hr = S_OK;
// if we are popping a propstat node with a bad status code,
// free any data associated with the node
if (StackTop(HMELE_DAV_PROPSTAT) && VALIDSTACK(c_rgPropFindPropStatStack))
{
// grab a pointer to the contact id we are accumulating
LPHTTPCONTACTID pId = &m_op.rResponse.rContactIdList.prgContactId[m_op.rResponse.rContactIdList.cContactId];
if (!m_op.fFoundStatus || m_op.dwStatus != 200)
XP_FREE_STRUCT(HTTPCONTACTID, pId, &m_op.dwPropFlags);
m_op.fFoundStatus = FALSE;
m_op.dwPropFlags = NOFLAGS;
}
else if (StackTop(HMELE_DAV_RESPONSE) && VALIDSTACK(c_rgPropFindResponseStack))
{
// increment the list count and, if we've hit the max, send the notification
if (LISTCONTACTS_MAXRESPONSES == ++m_op.rResponse.rContactIdList.cContactId)
{
if (FAILED(hr = _HrThunkResponse(FALSE)))
goto exit;
FreeContactIdList();
}
}
hr = EndChildren();
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ContactInfo_HandleText
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ContactInfo_HandleText(const WCHAR *pwcText, ULONG ulLen)
{
HRESULT hr = S_OK;
LPHTTPCONTACTINFO pInfo = &m_op.rResponse.rContactInfoList.prgContactInfo[m_op.rResponse.rContactInfoList.cContactInfo];
BOOL fWasBound = FALSE;
hr = XP_BIND_TO_STRUCT(HTTPCONTACTINFO, pwcText, ulLen, pInfo, &fWasBound);
if (FAILED(hr))
goto exit;
if (!fWasBound)
hr = PropFind_HandleText(pwcText, ulLen);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::ContactInfo_EndChildren
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::ContactInfo_EndChildren()
{
HRESULT hr = S_OK;
// if we are popping a propstat node with a bad status code,
// free any data associated with the node
if (StackTop(HMELE_DAV_PROPSTAT) && VALIDSTACK(c_rgPropFindPropStatStack))
{
// grab a pointer to the contact id we are accumulating
LPHTTPCONTACTINFO pInfo = &m_op.rResponse.rContactInfoList.prgContactInfo[m_op.rResponse.rContactInfoList.cContactInfo];
if (!m_op.fFoundStatus || m_op.dwStatus != 200)
XP_FREE_STRUCT(HTTPCONTACTINFO, pInfo, &m_op.dwPropFlags);
m_op.fFoundStatus = FALSE;
m_op.dwPropFlags = NOFLAGS;
}
else if (StackTop(HMELE_DAV_RESPONSE) && VALIDSTACK(c_rgPropFindResponseStack))
{
// increment the list count and, if we've hit the max, send the notification
if (CONTACTINFO_MAXRESPONSES == ++m_op.rResponse.rContactInfoList.cContactInfo)
{
if (FAILED(hr = _HrThunkResponse(FALSE)))
goto exit;
FreeContactInfoList();
}
}
hr = EndChildren();
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::PostOrPatchContact_HandleText
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::PostOrPatchContact_HandleText(const WCHAR *pwcText, ULONG ulLen)
{
HRESULT hr = S_OK;
LPHTTPCONTACTID pId = NULL;
BOOL fWasBound = FALSE;
if (HTTPMAIL_POSTCONTACT == m_op.rResponse.command)
pId = &m_op.rResponse.rPostContactInfo;
else if (HTTPMAIL_PATCHCONTACT == m_op.rResponse.command)
pId = &m_op.rResponse.rPatchContactInfo;
IxpAssert(pId);
hr = XP_BIND_TO_STRUCT(HTTPCONTACTID, pwcText, ulLen, pId, &fWasBound);
if (FAILED(hr))
goto exit;
if (!fWasBound)
hr = PropFind_HandleText(pwcText, ulLen);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::PostOrPatchContact_EndChildren
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::PostOrPatchContact_EndChildren(void)
{
HRESULT hr = S_OK;
// if we are popping a propstat node with a bad status code,
// free any data associated with the node
if (StackTop(HMELE_DAV_PROPSTAT) && VALIDSTACK(c_rgPropFindPropStatStack))
{
// grab a pointer to the contact id we are accumulating
LPHTTPCONTACTID pId = NULL;
if (HTTPMAIL_POSTCONTACT == m_op.rResponse.command)
pId = &m_op.rResponse.rPostContactInfo;
else if (HTTPMAIL_PATCHCONTACT == m_op.rResponse.command)
pId = &m_op.rResponse.rPatchContactInfo;
IxpAssert(pId);
if (!m_op.fFoundStatus || m_op.dwStatus != 200)
XP_FREE_STRUCT(HTTPCONTACTID, pId, &m_op.dwPropFlags);
m_op.fFoundStatus = FALSE;
m_op.dwPropFlags = NOFLAGS;
}
hr = EndChildren();
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_MemberInfo2
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_MemberInfo2(LPCSTR pszPath,
MEMBERINFOFLAGS flags,
DWORD dwDepth,
BOOL fIncludeRoot,
DWORD dwContext,
LPHTTPQUEUEDOP *ppOp)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp = NULL;
if (!ppOp)
{
IF_FAILEXIT(hr = E_INVALIDARG);
}
if (NULL == pszPath)
return TrapError(E_INVALIDARG);
FAIL_CREATEWND;
#pragma prefast(suppress:11, "noise")
*ppOp = NULL;
if (FAILED(hr = AllocQueuedOperation(pszPath, NULL, 0, &pOp)))
goto exit;
pOp->command = HTTPMAIL_MEMBERINFO;
pOp->dwMIFlags = flags;
pOp->dwDepth = dwDepth;
pOp->dwContext = dwContext;
pOp->pfnState = c_rgpfnMemberInfo;
pOp->cState = ARRAYSIZE(c_rgpfnMemberInfo);
pOp->pParseFuncs = c_rgpfnMemberInfoParse;
pOp->dwRHFlags = (RH_BRIEF | RH_XMLCONTENTTYPE);
if (!fIncludeRoot)
pOp->dwRHFlags |= RH_NOROOT;
exit:
if (SUCCEEDED(hr))
{
#pragma prefast(suppress:11, "noise")
*ppOp = pOp;
}
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::RootMemberInfo
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::RootMemberInfo(LPCSTR pszPath,
MEMBERINFOFLAGS flags,
DWORD dwDepth,
BOOL fIncludeRoot,
DWORD dwContext,
LPSTR pszRootTimeStamp,
LPSTR pszInboxTimeStamp)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp;
IF_FAILEXIT(hr = _MemberInfo2(pszPath, flags, dwDepth, fIncludeRoot, dwContext, &pOp));
pOp->dwRHFlags |= RH_ROOTTIMESTAMP | RH_ADDCHARSET;
pOp->pszRootTimeStamp = PszDupA(pszRootTimeStamp);
pOp->pszFolderTimeStamp = PszDupA(pszInboxTimeStamp);
QueueOperation(pOp);
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::FolderMemberInfo
// --------------------------------------------------------------------------------
STDMETHODIMP CHTTPMailTransport::FolderMemberInfo(LPCSTR pszPath,
MEMBERINFOFLAGS flags,
DWORD dwDepth,
BOOL fIncludeRoot,
DWORD dwContext,
LPSTR pszFolderTimeStamp,
LPSTR pszFolderName)
{
HRESULT hr = S_OK;
LPHTTPQUEUEDOP pOp;
IF_FAILEXIT(hr = _MemberInfo2(pszPath, flags, dwDepth, fIncludeRoot, dwContext, &pOp));
pOp->dwRHFlags |= RH_FOLDERTIMESTAMP | RH_ADDCHARSET;
pOp->pszFolderTimeStamp = PszDupA(pszFolderTimeStamp);
// To be used when we do timestamping on every folder. Right now the default is inbox
//pOp->pszFolderName = PszDupA(pszFolderName);
QueueOperation(pOp);
exit:
return hr;
}
HRESULT CHTTPMailTransport::_HrParseAndCopy(LPCSTR pszToken, LPSTR *ppszDest, LPSTR lpszSrc)
{
LPSTR lpszBeginning = lpszSrc;
LPSTR lpszEnd;
DWORD dwCount = 0;
HRESULT hr = E_FAIL;
int cchSize;
lpszBeginning = StrStr(lpszSrc, pszToken);
if (!lpszBeginning)
goto exit;
lpszBeginning = StrChr(lpszBeginning, '=');
if (!lpszBeginning)
goto exit;
// Skip the equal sign
++lpszBeginning;
SkipWhitespace(lpszBeginning, &dwCount);
lpszBeginning += dwCount;
lpszEnd = StrChr(lpszBeginning, ',');
if (!lpszEnd)
{
//Its possible that this token is at the end. So use the remaining string.
//Lets take a look at the length and make sure that it doesn't fall off the deep end.
lpszEnd = lpszBeginning + strlen(lpszBeginning);
}
AssertSz(((lpszEnd - lpszBeginning + 1) < 20), "This number looks awfully long, please make sure that this is correct")
cchSize = (int)(lpszEnd - lpszBeginning + 2);
if (!MemAlloc((void**)ppszDest, cchSize))
goto exit;
cchSize = (int)(lpszEnd - lpszBeginning + 1);
StrCpyN(*ppszDest, lpszBeginning, cchSize);
// Null terminate it
*(*ppszDest + (lpszEnd - lpszBeginning + 1)) = 0;
hr = S_OK;
exit:
return hr;
}
// --------------------------------------------------------------------------------
// CHTTPMailTransport::_GetTimestampHeader
// --------------------------------------------------------------------------------
HRESULT CHTTPMailTransport::_HrGetTimestampHeader(LPSTR *ppszHeader)
{
HRESULT hr = S_OK;
DWORD dwSize = MAX_PATH;
LPSTR pszHeader = NULL;
Assert(NULL != ppszHeader);
*ppszHeader = NULL;
retry:
if (!MemAlloc((void **)&pszHeader, dwSize))
{
hr = E_OUTOFMEMORY;
goto exit;
}
StrCpyN(pszHeader, c_szXTimestamp, dwSize);
if (!HttpQueryInfo(m_op.hRequest, HTTP_QUERY_RAW_HEADERS | HTTP_QUERY_CUSTOM, pszHeader, &dwSize, NULL))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
hr = E_FAIL;
goto exit;
}
SafeMemFree(pszHeader);
goto retry;
}
*ppszHeader = pszHeader;
pszHeader = NULL;
exit:
SafeMemFree(pszHeader);
return hr;
}