2025-04-27 07:49:33 -04:00

686 lines
22 KiB
C++

#include <objbase.h>
#include <assert.h>
#include "davstore.h"
#include "davstorn.h"
#include "davinet.clsid.h"
#include "davbagmn.clsid.h"
#include "httpstrm.clsid.h"
#include "davstore.clsid.h"
#include "idavinet.h"
#include "ihttpstrm.h"
#include "strconv.h"
#include "strutil.h"
#include "mischlpr.h"
#include <stdio.h>
//#define TRACE(a) (fprintf(stderr,"%d %s\n",GetTickCount(),a))
#define TRACE(a)
///////////////////////////////////////
CDavStorageImpl::CDavStorageImpl (): _pDavTransport(NULL), _grfStateBits(0), _fInit(FALSE), _pwszURL(NULL), _pwszUserName(NULL), _pwszPassword(NULL)
{
TRACE("CDavStorage::CDavStorage");
}
///////////////////////////////////////
CDavStorageImpl::~CDavStorageImpl ()
{
TRACE("CDavStorage::~CDavStorage");
if (_pDavTransport != NULL)
{
_pDavTransport->Release();
}
if (_pwszURL != NULL)
{
free(_pwszURL);
}
if (_pwszUserName != NULL)
{
free(_pwszUserName);
}
if (_pwszPassword != NULL)
{
free(_pwszPassword);
}
}
///////////////////////////////////////
LPWSTR __stdcall CDavStorageImpl::_ResolveURL(LPWSTR pwszRootURL, LPWSTR pwszRelativeURL)
{
LPWSTR pwszURL = NULL;
ULONG cchRootURL;
TRACE("CDavStorage::_ResolveURL");
assert(pwszRootURL != NULL);
assert(pwszRelativeURL != NULL);
cchRootURL = lstrlen(pwszRootURL);
if (pwszRootURL[cchRootURL-1] == '/')
{
// don't need to add an extra /
pwszURL = AllocateStringW (cchRootURL + lstrlen(pwszRelativeURL)); // AllocateString auto-does the +1 for the NULL
if (pwszURL != NULL)
{
lstrcpy(pwszURL, pwszRootURL);
lstrcpy(pwszURL + cchRootURL, pwszRelativeURL);
}
}
else
{
// we DO need to add an extra /
pwszURL = AllocateStringW (cchRootURL + lstrlen(pwszRelativeURL) + 1); // +1 for the extra slash
if (pwszURL != NULL)
{
lstrcpy(pwszURL, pwszRootURL);
pwszURL[cchRootURL] = '/';
lstrcpy(pwszURL + cchRootURL + 1, pwszRelativeURL);
}
}
return pwszURL;
}
///////////////////////////////////////
STDMETHODIMP CDavStorageImpl::Init(LPWSTR pwszURL,
IDavTransport* pDavTransport)
{
HRESULT hr = S_OK;
TRACE("CDavStorage::Init");
if (pwszURL == NULL || pDavTransport == NULL)
{
hr = E_INVALIDARG;
}
else
{
if (_fInit == TRUE)
{
hr = E_FAIL;
}
else
{
// hr = pDavTransport->CommandHEAD(pwszURL, NULL, 0); // check if this is a URL to a valid place // DEBUG: replace check in the future
if (SUCCEEDED(hr))
{
_pwszURL = DuplicateStringW(pwszURL);
if (_pwszURL == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
_pDavTransport = pDavTransport;
_pDavTransport->AddRef();
_fInit = TRUE;
}
}
}
}
return hr;
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::SetAuth(LPWSTR pwszUserName,
LPWSTR pwszPassword)
{
HRESULT hr = S_OK;
TRACE("CDavStorage::SetAuth");
if (_pwszUserName != NULL)
{
free(_pwszUserName);
_pwszUserName = NULL;
}
if (_pwszPassword != NULL)
{
free(_pwszPassword);
_pwszPassword = NULL;
}
if (pwszUserName != NULL)
{
_pwszUserName = DuplicateStringW(pwszUserName);
if (_pwszUserName == NULL)
{
hr = E_OUTOFMEMORY;
}
}
if (SUCCEEDED(hr))
{
if (pwszPassword != NULL)
{
_pwszPassword = DuplicateStringW(pwszPassword);
if (_pwszPassword == NULL)
{
hr = E_OUTOFMEMORY;
}
}
}
return hr;
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::_GetStream(const WCHAR * pwcsName, //Points to the name of the new stream
DWORD grfMode, //Access mode for the new stream
IStream ** ppstm, //Points to new stream object
BOOL fCreate)
{
HRESULT hr;
LPWSTR pwszURL;
BOOL fTransacted;
BOOL fDeleteOnRelease;
TRACE("CDavStorage::_GetStream");
// code
assert(fInit);
// open a HTTPStrm to that location, passing in _pDavTransport so that it can do the right thing
CoInitialize(NULL);
hr = ::CoCreateInstance(CLSID_HttpStrm,
NULL,
CLSCTX_INPROC_SERVER,
IID_IHttpStrm,
(LPVOID*)ppstm);
if (SUCCEEDED(hr))
{
hr = ((IHttpStrm*)*ppstm)->SetAuth(_pwszUserName, _pwszPassword);
if (SUCCEEDED(hr))
{
if (SUCCEEDED(hr))
{
pwszURL = this->_ResolveURL(_pwszURL, (LPWSTR)pwcsName);
if (pwszURL == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
// parse the grfMode
// BUGBUG: only things we can deal with are transacted and deleteonrelease
if (grfMode & STGM_TRANSACTED)
{
fTransacted = TRUE;
}
else
{
fTransacted = FALSE;
}
if (grfMode & STGM_DELETEONRELEASE)
{
fDeleteOnRelease = TRUE;
}
else
{
fDeleteOnRelease = FALSE;
}
hr = ((IHttpStrm*)*ppstm)->Open(pwszURL,
!fTransacted, // direct mode?
fDeleteOnRelease, // delete when finished?
fCreate);
}
}
}
}
return hr;
}
///////////////////////////////////
STDMETHODIMP CDavStorageImpl::CreateStream(const WCHAR * pwcsName, //Points to the name of the new stream
DWORD grfMode, //Access mode for the new stream
DWORD reserved1, //Reserved; must be zero
DWORD reserved2, //Reserved; must be zero
IStream ** ppstm) //Points to new stream object
{
HRESULT hr = S_OK;
TRACE("CDavStorage::CreateStream");
if (_fInit != TRUE)
{
hr = E_FAIL;
}
else
{
// check params
if (pwcsName == NULL || reserved1 != 0 || reserved2 != 0)
{
hr = E_INVALIDARG;
}
else
{
hr = this->_GetStream(pwcsName, grfMode, ppstm, TRUE);
}
}
return hr;
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::OpenStream(const WCHAR * pwcsName, //Points to name of stream to open
void * reserved1, //Reserved; must be NULL
DWORD grfMode, //Access mode for the new stream
DWORD reserved2, //Reserved; must be zero
IStream ** ppstm) //Address of output variable
// that receives the IStream interface pointer
{
HRESULT hr = S_OK;
TRACE("CDavStorage::OpenStream");
if (_fInit != TRUE)
{
hr = E_FAIL;
}
else
{
// check params
if (pwcsName == NULL || reserved1 != NULL || reserved2 != 0)
{
hr = E_INVALIDARG;
}
else
{
// code
// open a HTTPStrm to that location, passing in _pDavTransport so that it can do the right thing
hr = this->_GetStream(pwcsName, grfMode, ppstm, FALSE);
}
}
return hr;
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::_OpenStorage(LPWSTR pwszURL, //Points to the URL of the new storage object
IStorage ** ppstg) //Points to new storage object
{
HRESULT hr;
hr = ::CoCreateInstance(CLSID_CDavStorage,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDavStorage,
(LPVOID*)ppstg);
if (SUCCEEDED(hr))
{
hr = ((IDavStorage*)*ppstg)->Init(pwszURL, _pDavTransport);
if (SUCCEEDED(hr))
{
hr = ((IDavStorage*)*ppstg)->SetAuth(_pwszUserName, _pwszPassword);
}
}
return hr;
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::CreateStorage(const WCHAR * pwcsName, //Points to the name of the new storage object
DWORD UNREF_PARAM(grfMode), //Access mode for the new storage object
DWORD reserved1, //Reserved; must be zero
DWORD reserved2, //Reserved; must be zero
IStorage ** ppstg) //Points to new storage object
{
HRESULT hr = S_OK;
LPWSTR pwszURL = NULL;
TRACE("CDavStorage::CreateStorage");
if (_fInit != TRUE)
{
hr = E_FAIL;
}
else if (pwcsName == NULL || ppstg == NULL || reserved1 != NULL || reserved2 != 0)
{
hr = E_INVALIDARG;
}
else
{
// code
pwszURL = this->_ResolveURL(_pwszURL, (LPWSTR)pwcsName);
if (pwszURL == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = _pDavTransport->CommandMKCOL(pwszURL, NULL, 0);
if (SUCCEEDED(hr))
{
hr = this->_OpenStorage(pwszURL, ppstg);
}
}
}
return hr;
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::OpenStorage(const WCHAR * pwcsName, //Points to the name of the
// storage object to open
IStorage * pstgPriority, //Must be NULL.
DWORD UNREF_PARAM(grfMode), //Access mode for the new storage object
SNB snbExclude, //Must be NULL.
DWORD reserved, //Reserved; must be zero
IStorage ** ppstg) //Points to opened storage object
{
HRESULT hr = S_OK;
LPWSTR pwszURL = NULL;
TRACE("CDavStorage::OpenStorage");
if (_fInit != TRUE)
{
hr = E_FAIL;
}
else if (pwcsName == NULL || ppstg == NULL || pstgPriority != NULL || snbExclude != NULL || reserved != 0)
{
hr = E_INVALIDARG;
}
else
{
pwszURL = this->_ResolveURL(_pwszURL, (LPWSTR)pwcsName);
if (pwszURL == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = this->_OpenStorage(pwszURL, ppstg);
}
}
return hr;
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::CopyTo(DWORD ciidExclude, //Number of elements in rgiidExclude
IID const * rgiidExclude, //Array of interface identifiers (IIDs)
SNB snbExclude, //Points to a block of stream
// names in the storage object
IStorage * pstgDest) //Points to destination storage object
{
HRESULT hr = S_OK;
TRACE("CDavStorage::CopyTo");
if (_fInit != TRUE)
{
hr = E_FAIL;
}
else
{
if (ciidExclude > 0 || rgiidExclude != NULL || snbExclude != NULL || pstgDest == NULL)
{
hr = E_INVALIDARG; // BUGBUG: we don't support exclusion right now
}
else
{
hr = _pDavTransport->SetAuthentication(_pwszUserName, _pwszPassword);
if (SUCCEEDED(hr))
{
hr = _pDavTransport->CommandCOPY(_pwszURL, ((CDavStorageImpl*)pstgDest)->_pwszURL, DEPTH_INFINITY, TRUE, NULL, 0); // synchronous (no callback)
}
}
}
return S_OK;
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::MoveElementTo(const WCHAR * pwcsName, //Name of the element to be moved
IStorage * pstgDest, //Points to destination storage object
const WCHAR* pwcsNewName, //Points to new name of element in destination
DWORD UNREF_PARAM(grfFlags)) //Specifies a copy or a move
{
HRESULT hr = S_OK;
LPWSTR pwszSource = NULL;
LPWSTR pwszDest = NULL;
TRACE("CDavStorage::MoveElementTo");
if (_fInit != TRUE)
{
hr = E_FAIL;
}
else
{
if (pwcsName == NULL || pstgDest != NULL || pwcsNewName != NULL)
{
hr = E_INVALIDARG;
}
else
{
pwszSource = this->_ResolveURL(_pwszURL, (LPWSTR)pwcsName);
if (pwszSource == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
pwszDest = this->_ResolveURL(((CDavStorageImpl*)pstgDest)->_pwszURL, (LPWSTR)pwcsNewName);
if (pwszDest == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = _pDavTransport->SetAuthentication(_pwszUserName, _pwszPassword);
if (SUCCEEDED(hr))
{
hr = _pDavTransport->CommandMOVE(pwszSource, pwszDest, TRUE, NULL, 0); // synchronous (no callback)
}
}
}
}
}
return S_OK;
}
/////////////////////////////////////
// IStorage::EnumElements
STDMETHODIMP CDavStorageImpl::EnumElements(DWORD reserved1, //Reserved; must be zero
void * reserved2, //Reserved; must be NULL
DWORD reserved3, //Reserved; must be zero
IEnumSTATSTG ** ppenum) //Address of output variable that
// receives the IEnumSTATSTG interface pointer
{
HRESULT hr = S_OK;
IEnumSTATSTG* pEnumObj = NULL;
TRACE("CDavStorage::EnumElements");
if (_fInit != TRUE)
{
hr = E_FAIL;
}
else
{
// check params
if (reserved1 != 0 || reserved2 != NULL || reserved3 != 0 || ppenum == NULL)
{
hr = E_INVALIDARG;
}
else
{
// do some magic of issuing a PROPFIND, collecting all the responses, and packaging them into an IEnumSTATSTG
hr = ::CoCreateInstance(CLSID_CDavStorageEnum,
NULL,
CLSCTX_INPROC_SERVER,
IID_IEnumSTATSTG,
(LPVOID*)&pEnumObj);
if (SUCCEEDED(hr))
{
hr = ((CDavStorageEnum*)pEnumObj)->Init(_pwszURL, _pDavTransport);
if (SUCCEEDED(hr))
{
*ppenum = pEnumObj;
}
else
{
pEnumObj->Release();
}
}
}
}
return hr;
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::DestroyElement(const WCHAR* pwcsName) //Points to the name of the element to be removed
{
HRESULT hr = S_OK;
LPWSTR pwszURL = NULL;
LPWSTR pwszDest = NULL;
TRACE("CDavStorage::DestroyElement");
if (_fInit != TRUE)
{
hr = E_FAIL;
}
else
{
if (pwcsName == NULL)
{
hr = E_INVALIDARG;
}
else
{
pwszURL = this->_ResolveURL(_pwszURL, (LPWSTR)pwcsName);
if (pwszURL == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = _pDavTransport->SetAuthentication(_pwszUserName, _pwszPassword);
if (SUCCEEDED(hr))
{
hr = _pDavTransport->CommandDELETE(pwszURL, NULL, 0);
}
}
}
}
return S_OK;
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::RenameElement(const WCHAR * pwcsOldName, //Points to the name of the
// element to be changed
const WCHAR * pwcsNewName) //Points to the new name for
// the specified element
{
TRACE("CDavStorage::RenameElement");
return this->MoveElementTo(pwcsOldName, this, (LPWSTR)pwcsNewName, 0); // BUGBUG: what should last param be?
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::SetStateBits(DWORD grfStateBits, //Specifies new values of bits
DWORD grfMask) //Specifies mask that indicates which
// bits are significant
{
TRACE("CDavStorage::SetStateBits");
_grfStateBits = _grfStateBits & !grfMask; // clear the elements of the mask
_grfStateBits = _grfStateBits | (grfStateBits & grfMask); // elements of the mask in the grfStateBits copied to _grfStateBits
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDavStorageImpl::Commit(DWORD UNREF_PARAM(grfCommitFlags)) //Specifies how changes are to be committed
{
return E_NOTIMPL; // first pass, we do everything synchronously to the server
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::Revert(void)
{
return E_NOTIMPL; // first pass, we do everything synchronously to the server
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::SetElementTimes(const WCHAR * UNREF_PARAM(pwcsName), //Points to name of element to be changed
FILETIME const * UNREF_PARAM(pctime), //New creation time for element, or NULL
FILETIME const * UNREF_PARAM(patime), //New access time for element, or NULL
FILETIME const * UNREF_PARAM(pmtime)) //New modification time for element, or NULL
{
return E_NOTIMPL; // not the first time around
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::SetClass(REFCLSID UNREF_PARAM(clsid)) //Class identifier to be assigned to the storage object
{
return E_NOTIMPL; // not the first pass
}
/////////////////////////////////////
STDMETHODIMP CDavStorageImpl::Stat(STATSTG* UNREF_PARAM(pstatstg), //Location for STATSTG structure
DWORD UNREF_PARAM(grfStatFlag)) //Values taken from the STATFLAG enumeration
{
return E_NOTIMPL; // not the first pass
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IPropertySetStorage
STDMETHODIMP CDavStorageImpl::Create(REFFMTID UNREF_PARAM(fmtid),
const CLSID * UNREF_PARAM(pclsid),
DWORD UNREF_PARAM(grfFlags),
DWORD UNREF_PARAM(grfMode),
IPropertyStorage** UNREF_PARAM(ppPropStg))
{
return E_NOTIMPL;
}
STDMETHODIMP CDavStorageImpl::Open(REFFMTID UNREF_PARAM(fmtid),
DWORD UNREF_PARAM(grfMode),
IPropertyStorage** UNREF_PARAM(ppPropStg))
{
return E_NOTIMPL;
}
STDMETHODIMP CDavStorageImpl::Delete(REFFMTID UNREF_PARAM(fmtid))
{
return E_NOTIMPL;
}
STDMETHODIMP CDavStorageImpl::Enum(IEnumSTATPROPSETSTG** UNREF_PARAM(ppenum))
{
return E_NOTIMPL;
}