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.
517 lines
12 KiB
517 lines
12 KiB
/*
|
|
* X L O C K . C P P
|
|
*
|
|
* XML push model parsing for LOCK requests
|
|
*
|
|
* Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
|
|
*/
|
|
|
|
#include "_xml.h"
|
|
|
|
#include <xlock.h>
|
|
#include <statetok.h>
|
|
|
|
// Here are our LOCK XML elements
|
|
//
|
|
const WCHAR gc_wszLockActive[] = L"DAV:activelock";
|
|
const WCHAR gc_wszLockDepth[] = L"DAV:depth";
|
|
const WCHAR gc_wszLockDiscovery[] = L"DAV:lockdiscovery";
|
|
const WCHAR gc_wszLockEntry[] = L"DAV:lockentry";
|
|
const WCHAR gc_wszLockInfo[] = L"DAV:lockinfo";
|
|
const WCHAR gc_wszLockOwner[] = L"DAV:owner";
|
|
const WCHAR gc_wszLockScope[] = L"DAV:lockscope";
|
|
const WCHAR gc_wszLockScopeExclusive[] = L"DAV:exclusive";
|
|
const WCHAR gc_wszLockScopeShared[] = L"DAV:shared";
|
|
const WCHAR gc_wszLockSupportedlock[] = L"DAV:supportedlock";
|
|
const WCHAR gc_wszLockTimeout[] = L"DAV:timeout";
|
|
const WCHAR gc_wszLockToken[] = L"DAV:locktoken";
|
|
const WCHAR gc_wszLockType[] = L"DAV:locktype";
|
|
const WCHAR gc_wszLockTypeWrite[] = L"DAV:write";
|
|
const WCHAR gc_wszLockTypeCheckout[] = L"DAV:checkout";
|
|
const WCHAR gc_wszLockTypeTransaction[] = L"DAV:transaction";
|
|
const WCHAR gc_wszLockTypeTransactionGOP[] = L"DAV:groupoperation";
|
|
const WCHAR gc_wszLockScopeLocal[] = L"DAV:local";
|
|
|
|
// And one item from the rollback draft.
|
|
//
|
|
const WCHAR gc_wszLockRollback[] = L"http://www.iana.org/experimental/msrollback/rollback";
|
|
|
|
// UNLOCK xml elememts
|
|
//
|
|
const WCHAR gc_wszUnlockInfo[] = L"DAV:unlockinfo";
|
|
const WCHAR gc_wszCancelCheckout[] = L"DAV:cancelcheckout";
|
|
const WCHAR gc_wszComment[] = L"DAV:comment";
|
|
const WCHAR gc_wszTransactionInfo[] = L"DAV:transactioninfo";
|
|
const WCHAR gc_wszTransactionStatus[] = L"DAV:transactionstatus";
|
|
const WCHAR gc_wszCommit[] = L"DAV:commit";
|
|
const WCHAR gc_wszAbort[] = L"DAV:abort";
|
|
|
|
// class CNFLock -------------------------------------------------------------
|
|
//
|
|
SCODE
|
|
CNFLock::ScCompleteAttribute (void)
|
|
{
|
|
// When we have gotten here, we have started processing
|
|
// owner node attributes and all cached namespaces have
|
|
// been added.
|
|
//
|
|
if (m_state == ST_OWNER)
|
|
return m_xo.ScCompleteChildren ( FALSE, XML_ATTRIBUTE, L"", 0 );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
SCODE
|
|
CNFLock::ScCompleteChildren (
|
|
/* [in] */ BOOL fEmptyNode,
|
|
/* [in] */ DWORD dwType,
|
|
/* [in] */ const WCHAR __RPC_FAR *pwcText,
|
|
/* [in] */ ULONG ulLen)
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
// Handle owner processing first....
|
|
//
|
|
if (ST_OWNER == m_state)
|
|
{
|
|
sc = m_xo.ScCompleteChildren (fEmptyNode,
|
|
dwType,
|
|
pwcText,
|
|
ulLen);
|
|
if (FAILED (sc))
|
|
goto ret;
|
|
}
|
|
|
|
// Handle the rest...
|
|
//
|
|
switch (dwType)
|
|
{
|
|
case XML_ELEMENT:
|
|
|
|
switch (m_state)
|
|
{
|
|
case ST_LOCKINFO:
|
|
|
|
m_state = ST_NODOC;
|
|
break;
|
|
|
|
case ST_OWNER:
|
|
|
|
if (0 == m_xo.LDepth())
|
|
{
|
|
// Complete the owner comment buffer
|
|
//
|
|
m_state = ST_LOCKINFO;
|
|
m_sbOwner.Append (sizeof(WCHAR), L"\0");
|
|
XmlTrace ("Xml: Lock: owner XML body:\n%ws\n",
|
|
m_sbOwner.PContents());
|
|
}
|
|
break;
|
|
|
|
case ST_TYPE:
|
|
|
|
m_state = ST_LOCKINFO;
|
|
break;
|
|
|
|
case ST_INTYPE:
|
|
|
|
m_state = ST_TYPE;
|
|
break;
|
|
|
|
case ST_INTYPE_TRANS:
|
|
|
|
m_state = ST_INTYPE;
|
|
break;
|
|
|
|
case ST_SCOPE:
|
|
|
|
m_state = ST_LOCKINFO;
|
|
break;
|
|
|
|
case ST_INSCOPE:
|
|
|
|
m_state = ST_SCOPE;
|
|
break;
|
|
|
|
case ST_ROLLBACK:
|
|
|
|
m_state = ST_LOCKINFO;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ret:
|
|
return sc;
|
|
}
|
|
|
|
SCODE
|
|
CNFLock::ScHandleNode (
|
|
/* [in] */ DWORD dwType,
|
|
/* [in] */ DWORD dwSubType,
|
|
/* [in] */ BOOL fTerminal,
|
|
/* [in] */ const WCHAR __RPC_FAR *pwcText,
|
|
/* [in] */ ULONG ulLen,
|
|
/* [in] */ ULONG ulNamespaceLen,
|
|
/* [in] */ const WCHAR __RPC_FAR *pwcNamespace,
|
|
/* [in] */ const ULONG ulNsPrefixLen)
|
|
{
|
|
CStackBuffer<WCHAR> wsz;
|
|
LPCWSTR pwszTag = NULL;
|
|
SCODE sc = S_FALSE;
|
|
UINT cch;
|
|
|
|
switch (dwType)
|
|
{
|
|
case XML_ELEMENT:
|
|
|
|
// Construct the full name of the node
|
|
//
|
|
cch = ulNamespaceLen + ulLen;
|
|
pwszTag = wsz.resize(CbSizeWsz(cch));
|
|
if (NULL == pwszTag)
|
|
{
|
|
sc = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
wcsncpy (wsz.get(), pwcNamespace, ulNamespaceLen);
|
|
wcsncpy (wsz.get() + ulNamespaceLen, pwcText, ulLen);
|
|
*(wsz.get() + cch) = 0;
|
|
|
|
switch (m_state)
|
|
{
|
|
case ST_NODOC:
|
|
|
|
// If this is the topmost node in a propfind request,
|
|
// transition to the next state. Since there is no parent
|
|
// node to provide scoping, FIsTag() cannot be used here!
|
|
//
|
|
if (!wcscmp (pwszTag, gc_wszLockInfo))
|
|
{
|
|
m_state = ST_LOCKINFO;
|
|
sc = S_OK;
|
|
}
|
|
break;
|
|
|
|
case ST_LOCKINFO:
|
|
|
|
// Look for our well know node types
|
|
//
|
|
if (FIsTag (pwszTag, gc_wszLockOwner))
|
|
{
|
|
CEmitNmspc cen(m_xo);
|
|
|
|
// Make the state transition and start recording
|
|
//
|
|
m_sbOwner.Reset();
|
|
m_state = ST_OWNER;
|
|
sc = m_xo.ScHandleNode (dwType,
|
|
dwSubType,
|
|
fTerminal,
|
|
pwcText,
|
|
ulLen,
|
|
ulNamespaceLen,
|
|
pwcNamespace,
|
|
ulNsPrefixLen);
|
|
|
|
// Spit out the namespaces.
|
|
//
|
|
// Note that this will spit out any namespaces
|
|
// decl'd in the DAV:owner node itself. So we
|
|
// do not really want to emit these out to the
|
|
// owners comments until ScCompleteAttribute()
|
|
// is called.
|
|
//
|
|
Assert (!m_xo.FAddNamespaceDecl());
|
|
m_cache.ForEach(cen);
|
|
sc = S_OK;
|
|
}
|
|
else if (FIsTag (pwszTag, gc_wszLockRollback))
|
|
{
|
|
m_dwRollback = DAV_LOCKTYPE_ROLLBACK;
|
|
m_state = ST_ROLLBACK;
|
|
sc = S_OK;
|
|
}
|
|
else if (FIsTag (pwszTag, gc_wszLockType))
|
|
{
|
|
m_state = ST_TYPE;
|
|
sc = S_OK;
|
|
}
|
|
else if (FIsTag (pwszTag, gc_wszLockScope))
|
|
{
|
|
m_state = ST_SCOPE;
|
|
sc = S_OK;
|
|
}
|
|
break;
|
|
|
|
case ST_TYPE:
|
|
|
|
if (FIsTag (pwszTag, gc_wszLockTypeWrite))
|
|
{
|
|
XmlTrace ("Xml: Lock: request is for a WRITE lock\n");
|
|
m_dwLockType |= GENERIC_WRITE;
|
|
m_state = ST_INTYPE;
|
|
sc = S_OK;
|
|
}
|
|
else if (FIsTag (pwszTag, gc_wszLockTypeCheckout))
|
|
{
|
|
XmlTrace ("Xml: Lock: request is for a CHECKOUT lock\n");
|
|
m_dwLockType |= DAV_LOCKTYPE_CHECKOUT;
|
|
m_state = ST_INTYPE;
|
|
sc = S_OK;
|
|
}
|
|
else if (FIsTag (pwszTag, gc_wszLockTypeTransaction))
|
|
{
|
|
XmlTrace ("Xml: Lock: request is for a TRANSACTION lock\n");
|
|
m_state = ST_INTYPE_TRANS;
|
|
sc = S_OK;
|
|
}
|
|
#ifdef DBG
|
|
if (!_wcsicmp (pwszTag, L"read"))
|
|
{
|
|
XmlTrace ("Xml: Lock: request is for a READ lock\n");
|
|
m_dwLockType |= GENERIC_READ;
|
|
m_state = ST_INTYPE;
|
|
sc = S_OK;
|
|
}
|
|
#endif // DBG
|
|
break;
|
|
|
|
case ST_SCOPE:
|
|
|
|
if (FIsTag (pwszTag, gc_wszLockScopeExclusive))
|
|
{
|
|
XmlTrace ("Xml: Lock: request is for an EXCLUSE lock\n");
|
|
m_dwScope = DAV_EXCLUSIVE_LOCK;
|
|
m_state = ST_INSCOPE;
|
|
sc = S_OK;
|
|
}
|
|
else if (FIsTag (pwszTag, gc_wszLockScopeShared))
|
|
{
|
|
XmlTrace ("Xml: Lock: request is for a SHARED lock\n");
|
|
m_dwScope = DAV_SHARED_LOCK;
|
|
m_state = ST_INSCOPE;
|
|
sc = S_OK;
|
|
}
|
|
else if (FIsTag (pwszTag, gc_wszLockScopeLocal))
|
|
{
|
|
XmlTrace ("Xml: Lock: request is for a LOCAL scope lock\n");
|
|
m_dwScope = DAV_LOCKSCOPE_LOCAL;
|
|
m_state = ST_INSCOPE;
|
|
sc = S_OK;
|
|
}
|
|
break;
|
|
case ST_OWNER:
|
|
|
|
sc = m_xo.ScHandleNode (dwType,
|
|
dwSubType,
|
|
fTerminal,
|
|
pwcText,
|
|
ulLen,
|
|
ulNamespaceLen,
|
|
pwcNamespace,
|
|
ulNsPrefixLen);
|
|
break;
|
|
|
|
case ST_INTYPE_TRANS:
|
|
|
|
if (FIsTag (pwszTag, gc_wszLockTypeTransactionGOP))
|
|
{
|
|
XmlTrace ("Xml: Lock: request is for a TRANSACTION GOP lock\n");
|
|
m_dwLockType |= DAV_LOCKTYPE_TRANSACTION_GOP;
|
|
m_state = ST_INTYPE_TRANS;
|
|
sc = S_OK;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
// If we are processing the owner, continue
|
|
// to do so...
|
|
//
|
|
if (ST_OWNER == m_state)
|
|
{
|
|
sc = m_xo.ScHandleNode (dwType,
|
|
dwSubType,
|
|
fTerminal,
|
|
pwcText,
|
|
ulLen,
|
|
ulNamespaceLen,
|
|
pwcNamespace,
|
|
ulNsPrefixLen);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
SCODE
|
|
CNFLock::ScCompleteCreateNode (
|
|
/* [in] */ DWORD dwType)
|
|
{
|
|
if (ST_OWNER == m_state)
|
|
m_xo.CompleteCreateNode (dwType);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// class CNFUnlock -------------------------------------------------------------
|
|
//
|
|
SCODE
|
|
CNFUnlock::ScCompleteAttribute (void)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
SCODE
|
|
CNFUnlock::ScCompleteChildren (
|
|
/* [in] */ BOOL fEmptyNode,
|
|
/* [in] */ DWORD dwType,
|
|
/* [in] */ const WCHAR __RPC_FAR *pwcText,
|
|
/* [in] */ ULONG ulLen)
|
|
{
|
|
// Handle the rest...
|
|
//
|
|
switch (m_state)
|
|
{
|
|
case ST_UNLOCKINFO:
|
|
|
|
m_state = ST_NODOC;
|
|
break;
|
|
|
|
case ST_COMMENT:
|
|
case ST_CANCELCHECKOUT:
|
|
|
|
m_state = ST_UNLOCKINFO;
|
|
break;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
SCODE
|
|
CNFUnlock::ScHandleNode (
|
|
/* [in] */ DWORD dwType,
|
|
/* [in] */ DWORD dwSubType,
|
|
/* [in] */ BOOL fTerminal,
|
|
/* [in] */ const WCHAR __RPC_FAR *pwcText,
|
|
/* [in] */ ULONG ulLen,
|
|
/* [in] */ ULONG ulNamespaceLen,
|
|
/* [in] */ const WCHAR __RPC_FAR *pwcNamespace,
|
|
/* [in] */ const ULONG ulNsPrefixLen)
|
|
{
|
|
CStackBuffer<WCHAR> wsz;
|
|
LPCWSTR pwszTag = NULL;
|
|
SCODE sc = S_FALSE;
|
|
UINT cch;
|
|
|
|
switch (dwType)
|
|
{
|
|
case XML_ELEMENT:
|
|
|
|
// Construct the full name of the node
|
|
//
|
|
cch = ulNamespaceLen + ulLen;
|
|
pwszTag = wsz.resize(CbSizeWsz(cch));
|
|
if (NULL == pwszTag)
|
|
{
|
|
sc = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
wcsncpy (wsz.get(), pwcNamespace, ulNamespaceLen);
|
|
wcsncpy (wsz.get() + ulNamespaceLen, pwcText, ulLen);
|
|
*(wsz.get() + cch) = 0;
|
|
|
|
switch (m_state)
|
|
{
|
|
case ST_NODOC:
|
|
|
|
// If this is the topmost node in a propfind request,
|
|
// transition to the next state. Since there is no parent
|
|
// node to provide scoping, FIsTag() cannot be used here!
|
|
//
|
|
if (!wcscmp (pwszTag, gc_wszUnlockInfo))
|
|
{
|
|
m_state = ST_UNLOCKINFO;
|
|
sc = S_OK;
|
|
}
|
|
else if (FIsTag (pwszTag, gc_wszTransactionInfo))
|
|
{
|
|
m_state = ST_TRANSACTIONINFO;
|
|
sc = S_OK;
|
|
}
|
|
break;
|
|
|
|
case ST_UNLOCKINFO:
|
|
|
|
// Look for our well know node types
|
|
//
|
|
if (FIsTag (pwszTag, gc_wszComment))
|
|
{
|
|
m_state = ST_COMMENT;
|
|
sc = S_OK;
|
|
}
|
|
else if (FIsTag (pwszTag, gc_wszCancelCheckout))
|
|
{
|
|
m_fCancelCheckout = TRUE;
|
|
m_state = ST_CANCELCHECKOUT;
|
|
sc = S_OK;
|
|
}
|
|
break;
|
|
case ST_TRANSACTIONINFO:
|
|
// Look for our well know node types
|
|
//
|
|
if (FIsTag (pwszTag, gc_wszTransactionStatus))
|
|
{
|
|
m_state = ST_TRANSACTIONSTATUS;
|
|
sc = S_OK;
|
|
}
|
|
break;
|
|
case ST_TRANSACTIONSTATUS:
|
|
// Look for our well know node types
|
|
//
|
|
if (FIsTag (pwszTag, gc_wszCommit))
|
|
{
|
|
m_fCommitTransaction = TRUE;
|
|
m_state = ST_TRANSACTIONSTATUS_COMMIT;
|
|
sc = S_OK;
|
|
}
|
|
else if (FIsTag (pwszTag, gc_wszAbort))
|
|
{
|
|
m_fAbortTransaction = TRUE;
|
|
m_state = ST_TRANSACTIONSTATUS_ABORT;
|
|
sc = S_OK;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case XML_PCDATA:
|
|
|
|
// get unlock comment
|
|
//
|
|
if (m_state == ST_COMMENT)
|
|
{
|
|
// Keep the comment
|
|
// It's a syntax error to have more than one comment
|
|
//
|
|
if (!m_wszComment.get())
|
|
{
|
|
m_wszComment = reinterpret_cast<LPWSTR>(ExAlloc((ulLen + 1) * sizeof(WCHAR)));
|
|
Assert (m_wszComment.get());
|
|
|
|
wcsncpy (m_wszComment.get(), pwcText, ulLen);
|
|
m_wszComment[ulLen] = L'\0';
|
|
|
|
sc = S_OK;
|
|
}
|
|
// else it's an error
|
|
else
|
|
sc = E_DAV_XML_PARSE_ERROR;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return sc;
|
|
}
|