You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6569 lines
206 KiB
6569 lines
206 KiB
// --------------------------------------------------------------------------------
|
|
// 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;
|
|
}
|