[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
[0202]
[0203]
[0204]
[0205]
[0206]
[0207]
[0208]
[0209]
[0210]
[0211]
[0212]
[0213]
[0214]
[0215]
[0216]
[0217]
[0218]
[0219]
[0220]
[0221]
[0222]
[0223]
[0224]
[0225]
[0226]
[0227]
[0228]
[0229]
[0230]
[0231]
[0232]
[0233]
[0234]
[0235]
[0236]
[0237]
[0238]
[0239]
[0240]
[0241]
[0242]
[0243]
[0244]
[0245]
[0246]
[0247]
[0248]
[0249]
[0250]
[0251]
[0252]
[0253]
[0254]
[0255]
[0256]
[0257]
[0258]
[0259]
[0260]
[0261]
[0262]
[0263]
[0264]
[0265]
[0266]
[0267]
[0268]
[0269]
[0270]
[0271]
[0272]
[0273]
[0274]
[0275]
[0276]
[0277]
[0278]
[0279]
[0280]
[0281]
[0282]
[0283]
[0284]
[0285]
[0286]
[0287]
[0288]
[0289]
[0290]
[0291]
[0292]
[0293]
[0294]
[0295]
[0296]
[0297]
[0298]
[0299]
[0300]
[0301]
[0302]
[0303]
[0304]
[0305]
[0306]
[0307]
[0308]
[0309]
[0310]
[0311]
[0312]
[0313]
[0314]
[0315]
[0316]
[0317]
[0318]
[0319]
[0320]
[0321]
[0322]
[0323]
[0324]
[0325]
[0326]
[0327]
[0328]
[0329]
[0330]
[0331]
[0332]
[0333]
[0334]
[0335]
[0336]
[0337]
[0338]
[0339]
[0340]
[0341]
[0342]
[0343]
[0344]
[0345]
[0346]
[0347]
[0348]
[0349]
[0350]
[0351]
[0352]
[0353]
[0354]
[0355]
[0356]
[0357]
[0358]
[0359]
[0360]
[0361]
[0362]
[0363]
[0364]
[0365]
[0366]
[0367]
[0368]
[0369]
[0370]
[0371]
[0372]
[0373]
[0374]
[0375]
[0376]
[0377]
[0378]
[0379]
[0380]
[0381]
[0382]
[0383]
[0384]
[0385]
[0386]
[0387]
[0388]
[0389]
[0390]
[0391]
[0392]
[0393]
[0394]
[0395]
[0396]
[0397]
[0398]
[0399]
[0400]
[0401]
[0402]
[0403]
[0404]
[0405]
[0406]
[0407]
[0408]
[0409]
[0410]
[0411]
[0412]
[0413]
[0414]
[0415]
[0416]
[0417]
[0418]
[0419]
[0420]
[0421]
[0422]
[0423]
[0424]
[0425]
[0426]
[0427]
[0428]
[0429]
[0430]
[0431]
[0432]
[0433]
[0434]
[0435]
[0436]
[0437]
[0438]
[0439]
[0440]
[0441]
[0442]
[0443]
[0444]
[0445]
[0446]
[0447]
[0448]
[0449]
[0450]
[0451]
[0452]
[0453]
[0454]
[0455]
[0456]
[0457]
[0458]
[0459]
[0460]
[0461]
[0462]
[0463]
[0464]
[0465]
[0466]
[0467]
[0468]
[0469]
[0470]
[0471]
[0472]
[0473]
[0474]
[0475]
[0476]
[0477]
[0478]
[0479]
[0480]
[0481]
[0482]
[0483]
[0484]
[0485]
[0486]
[0487]
[0488]
[0489]
[0490]
[0491]
[0492]
[0493]
[0494]
[0495]
[0496]
[0497]
[0498]
[0499]
[0500]
[0501]
[0502]
[0503]
[0504]
[0505]
[0506]
[0507]
[0508]
[0509]
[0510]
[0511]
[0512]
[0513]
[0514]
[0515]
[0516]
[0517]
[0518]
[0519]
[0520]
[0521]
[0522]
[0523]
[0524]
[0525]
[0526]
[0527]
[0528]
[0529]
[0530]
[0531]
[0532]
[0533]
[0534]
[0535]
[0536]
[0537]
[0538]
[0539]
[0540]
[0541]
[0542]
[0543]
[0544]
[0545]
[0546]
[0547]
[0548]
[0549]
[0550]
[0551]
[0552]
[0553]
[0554]
[0555]
[0556]
[0557]
[0558]
[0559]
[0560]
[0561]
[0562]
[0563]
[0564]
[0565]
[0566]
[0567]
[0568]
[0569]
[0570]
[0571]
[0572]
[0573]
[0574]
[0575]
[0576]
[0577]
[0578]
[0579]
[0580]
[0581]
[0582]
[0583]
[0584]
[0585]
[0586]
[0587]
[0588]
[0589]
[0590]
[0591]
[0592]
[0593]
[0594]
[0595]
[0596]
[0597]
[0598]
[0599]
[0600]
[0601]
[0602]
[0603]
[0604]
[0605]
[0606]
[0607]
[0608]
[0609]
[0610]
[0611]
[0612]
[0613]
[0614]
[0615]
[0616]
[0617]
[0618]
[0619]
[0620]
[0621]
[0622]
[0623]
[0624]
[0625]
[0626]
[0627]
[0628]
[0629]
[0630]
[0631]
[0632]
[0633]
[0634]
[0635]
[0636]
[0637]
[0638]
[0639]
[0640]
[0641]
[0642]
[0643]
[0644]
[0645]
[0646]
[0647]
[0648]
[0649]
[0650]
[0651]
[0652]
[0653]
[0654]
[0655]
[0656]
[0657]
[0658]
[0659]
[0660]
[0661]
[0662]
[0663]
[0664]
[0665]
[0666]
[0667]
[0668]
[0669]
[0670]
[0671]
[0672]
[0673]
[0674]
[0675]
[0676]
[0677]
[0678]
[0679]
[0680]
[0681]
[0682]
[0683]
[0684]
[0685]
[0686]
[0687]
[0688]
[0689]
[0690]
[0691]
[0692]
[0693]
[0694]
[0695]
[0696]
[0697]
[0698]
[0699]
[0700]
[0701]
[0702]
[0703]
[0704]
[0705]
[0706]
[0707]
[0708]
[0709]
[0710]
[0711]
[0712]
[0713]
[0714]
[0715]
[0716]
[0717]
[0718]
[0719]
[0720]
[0721]
[0722]
[0723]
[0724]
[0725]
[0726]
[0727]
[0728]
[0729]
[0730]
[0731]
[0732]
[0733]
[0734]
[0735]
[0736]
[0737]
[0738]
[0739]
[0740]
[0741]
[0742]
[0743]
[0744]
[0745]
[0746]
[0747]
[0748]
[0749]
[0750]
[0751]
[0752]
[0753]
[0754]
[0755]
[0756]
[0757]
[0758]
[0759]
[0760]
[0761]
[0762]
[0763]
[0764]
[0765]
[0766]
[0767]
[0768]
[0769]
[0770]
[0771]
[0772]
[0773]
[0774]
[0775]
[0776]
[0777]
[0778]
[0779]
[0780]
[0781]
[0782]
[0783]
[0784]
[0785]
[0786]
[0787]
[0788]
[0789]
[0790]
[0791]
[0792]
[0793]
[0794]
[0795]
[0796]
[0797]
[0798]
[0799]
[0800]
[0801]
[0802]
[0803]
[0804]
[0805]
[0806]
[0807]
[0808]
[0809]
[0810]
[0811]
[0812]
[0813]
[0814]
[0815]
[0816]
[0817]
[0818]
[0819]
[0820]
[0821]
[0822]
[0823]
[0824]
[0825]
[0826]
[0827]
[0828]
[0829]
[0830]
[0831]
[0832]
[0833]
[0834]
[0835]
[0836]
[0837]
[0838]
[0839]
[0840]
[0841]
[0842]
[0843]
[0844]
[0845]
[0846]
[0847]
[0848]
[0849]
[0850]
[0851]
[0852]
[0853]
[0854]
[0855]
[0856]
[0857]
[0858]
[0859]
[0860]
[0861]
[0862]
[0863]
[0864]
[0865]
[0866]
[0867]
[0868]
[0869]
[0870]
[0871]
[0872]
[0873]
[0874]
[0875]
[0876]
[0877]
[0878]
[0879]
[0880]
[0881]
[0882]
[0883]
[0884]
[0885]
[0886]
[0887]
[0888]
[0889]
[0890]
[0891]
[0892]
[0893]
[0894]
[0895]
[0896]
[0897]
[0898]
[0899]
[0900]
[0901]
[0902]
[0903]
[0904]
[0905]
[0906]
[0907]
[0908]
[0909]
[0910]
[0911]
[0912]
[0913]
[0914]
[0915]
[0916]
[0917]
[0918]
[0919]
[0920]
[0921]
[0922]
[0923]
[0924]
[0925]
[0926]
[0927]
[0928]
[0929]
[0930]
[0931]
[0932]
[0933]
[0934]
[0935]
[0936]
[0937]
[0938]
[0939]
[0940]
[0941]
[0942]
[0943]
[0944]
[0945]
[0946]
[0947]
[0948]
[0949]
[0950]
[0951]
[0952]
[0953]
[0954]
[0955]
[0956]
[0957]
[0958]
[0959]
[0960]
[0961]
[0962]
[0963]
[0964]
[0965]
[0966]
[0967]
[0968]
[0969]
[0970]
[0971]
[0972]
[0973]
[0974]
[0975]
[0976]
[0977]
[0978]
[0979]
[0980]
[0981]
[0982]
[0983]
[0984]
[0985]
[0986]
[0987]
[0988]
[0989]
[0990]
[0991]
[0992]
[0993]
[0994]
[0995]
[0996]
[0997]
[0998]
[0999]
[1000]
[1001]
[1002]
[1003]
[1004]
[1005]
[1006]
[1007]
[1008]
[1009]
[1010]
[1011]
[1012]
[1013]
[1014]
[1015]
[1016]
[1017]
[1018]
[1019]
[1020]
[1021]
[1022]
[1023]
[1024]
[1025]
[1026]
[1027]
[1028]
[1029]
[1030]
[1031]
[1032]
[1033]
[1034]
[1035]
[1036]
[1037]
[1038]
[1039]
[1040]
[1041]
[1042]
[1043]
[1044]
[1045]
[1046]
[1047]
[1048]
[1049]
[1050]
[1051]
[1052]
[1053]
[1054]
[1055]
[1056]
[1057]
[1058]
[1059]
[1060]
[1061]
[1062]
[1063]
[1064]
[1065]
[1066]
[1067]
[1068]
[1069]
[1070]
[1071]
[1072]
[1073]
[1074]
[1075]
[1076]
[1077]
[1078]
[1079]
[1080]
[1081]
[1082]
[1083]
[1084]
[1085]
[1086]
[1087]
[1088]
[1089]
[1090]
[1091]
[1092]
[1093]
[1094]
[1095]
[1096]
[1097]
[1098]
[1099]
[1100]
[1101]
[1102]
[1103]
[1104]
[1105]
[1106]
[1107]
[1108]
[1109]
[1110]
[1111]
[1112]
/*****************************************************************************/
/*
                                 DAVxml.c

Uses the EXPAT XML parser to parse the request body.


REFERENCES
----------
Using Expat by Clark Cooper
http://en.wikipedia.org/wiki/Expat_(XML)
https://libexpat.github.io
http://www.xml.com/pub/a/1999/09/expat/index.html
http://www.xml.com/lpt/a/47


VERSION HISTORY
---------------
09-MAY-2018  MGD  DavXmlMemoryError() detect out-of-memory
                  DavXmlParseText() detect out-of-memory
19-NOV-2017  MGD  always DavWebEnd() not RequestEnd()
23-APR-2015  MGD  bugfix; DavXmlStartElement() PROPFIND accumulate list of
                    dead properties subsequently searched for in the metadata
20-AUG-2009  MGD  DavXmlStartElement() begin parsing lock own immediately
31-DEC-2006  MGD  initial
*/
/*****************************************************************************/

#ifdef WASD_VMS_V7
#undef _VMS__V6__SOURCE
#define _VMS__V6__SOURCE
#undef __VMS_VER
#define __VMS_VER 70000000
#undef __CRTL_VER
#define __CRTL_VER 70000000
#endif

#define DAVXML_MEMORY 1
#ifndef DAVXML_MEMORY
#define DAVXML_MEMORY 1
#endif

#include <ctype.h>
#include <errno.h>
#include <stdio.h>

#include <libdef.h>

#include "wasd.h"
#include "davweb.h"

#define WASD_MODULE "DAVXML"

/* just reduce the amount of XML parse noise when WATCHing */
#define WATCH_XML 1

/******************/
/* global storage */
/******************/

static XML_Memory_Handling_Suite  DavXmlMemorySuite;

/********************/
/* external storage */
/********************/

extern int  HttpdTickSecond;

extern char  ErrorSanityCheck[];

extern ACCOUNTING_STRUCT  *AccountingPtr;
extern CONFIG_STRUCT  Config;
extern WATCH_STRUCT  Watch;

/*****************************************************************************/
/*
Initialise ememory management for when parsing XML.
*/

void DavXmlInit ()

{
   if (VmExpatInit ())
   {
      /* initialise the EXPAT memory mnagement suite */
      DavXmlMemorySuite.free_fcn = VmExpatFree;
      DavXmlMemorySuite.malloc_fcn = VmExpatMalloc;
      DavXmlMemorySuite.realloc_fcn = VmExpatRealloc;
   }
}

/*****************************************************************************/
/*
Wrap XML_ParserCreateNS() to allow memory management and monitoring.
Note that the request pointer is currently unused.
*/

XML_Parser* DavXmlParserCreate (REQUEST_STRUCT *rqptr)

{
   static char  nssep[] = " ",
                nsenc[] = "UTF-8";

   /*********/
   /* begin */
   /*********/

   if (WATCH_XML && WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavXmlParserCreate()");

   if (DavXmlMemorySuite.free_fcn)
      return (XML_ParserCreate_MM (nsenc, &DavXmlMemorySuite, nssep));
   else
      return (XML_ParserCreate_MM (nsenc, NULL, nssep));
}

/*****************************************************************************/
/*
*/

int DavXmlParseText
(
REQUEST_STRUCT *rqptr,
STR_DSC *sdptr
)
{
   int  cnt, column, line, status, xmlsts;
   char  *cptr, *eptr, *sptr;
   WEBDAV_LOCK  *lckptr;
   WEBDAV_TASK  *tkptr;
   WEBDAV_XML  *xmlptr;

   /*********/
   /* begin */
   /*********/

   if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavXmlParseText()");

   /* shouldn't be calling this without content to parse! */
   if (!(STR_DSC_SANITY(sdptr) && STR_DSC_LEN(sdptr))) return (SS$_BUGCHECK);

   status = SS$_NORMAL;

   tkptr = rqptr->WebDavTaskPtr;
   lckptr = &tkptr->LockData;
   xmlptr = &tkptr->XmlData;

   InstanceGblSecIncrLong (&AccountingPtr->WebDavXmlParseCount);

   xmlptr->ParserPtr = DavXmlParserCreate (rqptr);

   if (!xmlptr->ParserPtr)
   {
      status = vaxc$errno;
      rqptr->rqResponse.HttpStatus = 500;
      ErrorVmsStatus (rqptr, status, FI_LI);
      return (status);
   }

   xmlptr->ParseLockInfo = xmlptr->ParseLockOwner =
      xmlptr->ParseLockScope = xmlptr->ParseLockType =
      xmlptr->ParseProp = xmlptr->ParsePropertyBehavior =
      xmlptr->ParsePropertyUpdate = xmlptr->ParsePropFind =
      xmlptr->ParseRemove = xmlptr->ParseSet = WEBDAV_STATE_NOT_PARSING;

   lckptr->Type = lckptr->Scope = xmlptr->ElementDepth = 0;

   /* properties will be in a descriptor collection */
   StrDscColIfNotBegin (rqptr, &xmlptr->PropFindDsc, 256);
   StrDscColIfNotBegin (rqptr, &xmlptr->PropRemoveDsc, 256);
   StrDscColIfNotBegin (rqptr, &xmlptr->PropSetDsc, 256);

   XML_SetUserData (xmlptr->ParserPtr, rqptr);

   XML_SetElementHandler (xmlptr->ParserPtr, DavXmlStartElement,
                                             DavXmlEndElement);

   XML_SetCharacterDataHandler (xmlptr->ParserPtr, DavXmlCharData);

   xmlsts = XML_Parse (xmlptr->ParserPtr, STR_DSC_PTR(sdptr),
                                          STR_DSC_LEN(sdptr), 1);

   if (xmlsts == XML_STATUS_ERROR)
   {
      DavXmlParseError (rqptr, xmlptr->ParserPtr,
                        sdptr, &xmlptr->ParseErrorDsc);
      if (DavXmlMemoryError (rqptr, tkptr->XmlData.ParserPtr))
         status = LIB$_INSVIRMEM;
      else
         status = SS$_ABORT;
   }

   if (xmlptr->ParserPtr) XML_ParserFree (xmlptr->ParserPtr);

   if (xmlsts == XML_STATUS_ERROR)
   {
      DavWebResponse (rqptr, 400, 0, "XML_STATUS_ERROR", FI_LI);
      return (status);
   }

   if (WATCHING (rqptr, WATCH_WEBDAV))
   {
      if (STR_DSC_LEN(&xmlptr->PropRemoveDsc))
         WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "REMOVE");
      STR_DSC_ITERATE (sdptr, &xmlptr->PropRemoveDsc)
         if (STR_DSC_LEN(sdptr))
            WatchDataFormatted ("!AZ\n", STR_DSC_PTR(sdptr));

      if (STR_DSC_LEN(&xmlptr->PropSetDsc))
         WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "SET");
      STR_DSC_ITERATE (sdptr, &xmlptr->PropSetDsc)
         if (STR_DSC_LEN(sdptr))
            WatchDataFormatted ("!AZ\n", STR_DSC_PTR(sdptr));
   }

   if (WATCHING (rqptr, WATCH_WEBDAV)) DavXmlWatchProp (rqptr);

   return (status);
}

/*****************************************************************************/
/*
Return true if error was "out of memory", false if not.
*/

BOOL DavXmlMemoryError
(
REQUEST_STRUCT *rqptr,
XML_Parser *XmlParserPtr
)
{
   /*********/
   /* begin */
   /*********/

   if (WATCH_XML && WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavXmlMemoryError()");

   return (XML_GetErrorCode(XmlParserPtr) == XML_ERROR_NO_MEMORY);
}

/*****************************************************************************/
/*
The ExPat XML parser has returned an error code.
Generate a WATCH item and textual report describing that error.
*/

DavXmlParseError
(
REQUEST_STRUCT *rqptr,
XML_Parser *XmlParserPtr,
STR_DSC *xdptr,
STR_DSC *sdptr
)
{
   int  cnt, column, line, status, xmlsts;
   char  *cptr, *eptr, *sptr;
   WEBDAV_TASK  *tkptr;
   WEBDAV_XML  *xmlptr;

   /*********/
   /* begin */
   /*********/

   if (WATCH_XML && WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavXmlParseError()");

   tkptr = rqptr->WebDavTaskPtr;
   xmlptr = &tkptr->XmlData;

   line = cnt = XML_GetCurrentLineNumber(XmlParserPtr);
   column = XML_GetCurrentColumnNumber(XmlParserPtr);
   eptr = (char*)XML_ErrorString(XML_GetErrorCode(XmlParserPtr));

   /* delimit the problematic line */
   if (cnt) cnt--;
   for (cptr = STR_DSC_PTR(xdptr); *cptr && cnt; cptr++)
      if (*cptr == '\n') cnt--;
   for (sptr = cptr; *sptr && *sptr != '\n'; sptr++);

   if (WATCHING (rqptr, WATCH_WEBDAV))
   {
      WatchThis (WATCHITM(rqptr), WATCH_WEBDAV,
                 "XML parse ERROR line:!UL column:!UL !AZ\n!#AZ\n!#*-^",
                 line, column, eptr, sptr-cptr, cptr, column);
      WatchDataDump (cptr, sptr-cptr);
   }

   /* create an error report that is also available for interrogation */
   StrDscBegin (rqptr, sdptr, -1);
   FaoToBuffer (sdptr, -1, NULL,
                "XML parse ERROR line:!UL column:!UL !AZ:\n!#AZ\n!#*-^",
                line, column, eptr, sptr-cptr, cptr, column);
}

/*****************************************************************************/
/*
This function and DavXmlEndElement() set various flags to indicate the state of
the current XML element.  From that various flags indicating properties to be
manipulated are set.

This pretty-much assumes that the parsing library is ensuring document
well-formedness, so the checks on element nesting are very elementary.
*/

void XMLCALL DavXmlStartElement
(
REQUEST_STRUCT *rqptr,
char *ElementPtr,
char **AttrPtr
)
{
   int  idx;
   char  *cptr, *sptr;
   STR_DSC  *sdptr;
   STR_DSC_AUTO (ScratchDsc);
   WEBDAV_LOCK  *lckptr;
   WEBDAV_PROP  *proptr;
   WEBDAV_TASK  *tkptr;
   WEBDAV_XML  *xmlptr;

   /*********/
   /* begin */
   /*********/

   if (WATCH_XML && WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV,
                 "DavXmlStartElement() !UL",
                 rqptr->WebDavTaskPtr->XmlData.ElementDepth+1);

   tkptr = rqptr->WebDavTaskPtr;
   lckptr = &tkptr->LockData;
   proptr = &tkptr->PropData;
   xmlptr = &tkptr->XmlData;

   xmlptr->ElementDepth++;

   if (WATCH_XML && WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
   {
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "ELEMENT !AZ", ElementPtr);
      for (idx = 0; AttrPtr[idx]; idx += 2)
         WatchDataFormatted ("!AZ=\"!AZ\"\n", AttrPtr[idx], AttrPtr[idx+1]);
   }

   sdptr = NULL;
   if (WEBDAV_IS_PARSING(xmlptr->ParseSet) &&
       WEBDAV_IS_PARSING(xmlptr->ParseProp))
      sdptr = &xmlptr->PropSetDsc;
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParseRemove) &&
       WEBDAV_IS_PARSING(xmlptr->ParseProp))
      sdptr = &xmlptr->PropRemoveDsc;
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParseLockOwner))
      sdptr = &lckptr->OwnerDsc;

   if (WEBDAV_IS_PARSING(xmlptr->ParseLockInfo))
   {
      /************/
      /* lockinfo */
      /************/

      StrDscColIfNotBegin (rqptr, &lckptr->OwnerDsc, 256);
      /* initialise the descriptor to reallocate expanded storage */
      STR_DSC_REALLOC(&lckptr->OwnerDsc, 256);

      if (WEBDAV_IS_PARSING(xmlptr->ParseLockType))
      {
         if (WEBDAV_IS_DAVEL(ElementPtr, "write"))
            lckptr->Type = WEBDAV_LOCK_TYPE_WRITE;
      }
      else
      if (WEBDAV_IS_PARSING(xmlptr->ParseLockScope))
      {
         if (WEBDAV_IS_DAVEL(ElementPtr, "exclusive"))
            lckptr->Scope = WEBDAV_LOCK_SCOPE_EXCLUSIVE;
         else
         if (WEBDAV_IS_DAVEL(ElementPtr, "shared"))
            lckptr->Scope = WEBDAV_LOCK_SCOPE_SHARED;
      }
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "locktype"))
         WEBDAV_PARSING(xmlptr->ParseLockType);
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "lockscope"))
         WEBDAV_PARSING(xmlptr->ParseLockScope);
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "owner"))
      {
         WEBDAV_PARSING(xmlptr->ParseLockOwner);
         WEBDAV_PARSING(xmlptr->ParseCharData);
      }
   }
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParsePropFind))
   {
      /************/
      /* propfind */
      /************/

      if (WEBDAV_IS_DAVEL(ElementPtr, "allprop"))
         proptr->AllProp = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "creationdate"))
         proptr->CreationDate = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "displayname"))
         proptr->DisplayName = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "resourcetype"))
         proptr->ResourceType = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "getcontenttype"))
         proptr->GetContentType = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "getcontentlength"))
         proptr->GetContentLength = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "getetag"))
         proptr->GetEtag = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "getlastmodified"))
         proptr->GetLastModified = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "lockdiscovery"))
         proptr->LockDiscovery = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "propname"))
         proptr->PropName = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "supportedlock"))
         proptr->SupportedLock = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "quota-available-bytes"))
         proptr->QuotaAvailableBytes = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "quota-used-bytes"))
         proptr->QuotaUsedBytes = true;
      else
      if (!WEBDAV_IS_DAVEL(ElementPtr, "prop"))
      {
         /* stored and searched for in the dead properties */
         sdptr = &xmlptr->PropFindDsc;
         proptr->FindProp = true;
         WEBDAV_PARSING(xmlptr->ParseFind);
      }

      if (WATCHING (rqptr, WATCH_WEBDAV)) DavXmlWatchProp (rqptr);
   }
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParsePropertyBehavior))
   {
      /********************/
      /* propertybehavior */
      /********************/

      if (WEBDAV_IS_DAVEL(ElementPtr, "keepalive"))
         proptr->PropertyBehaviorKeepalive = true;
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "omit"))
         proptr->PropertyBehaviorOmit = true;
   }
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParsePropertyUpdate))
   {
      /******************/
      /* propertyupdate */
      /******************/

      if (WEBDAV_IS_PARSING(xmlptr->ParseSet) ||
          WEBDAV_IS_PARSING(xmlptr->ParseRemove))
      {
         if (WEBDAV_IS_DAVEL(ElementPtr, "prop"))
            WEBDAV_PARSING(xmlptr->ParseProp);
      }
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "set"))
         WEBDAV_PARSING(xmlptr->ParseSet);
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "remove"))
         WEBDAV_PARSING(xmlptr->ParseRemove);
   }
   else
   if (WEBDAV_IS_DAVEL(ElementPtr, "lockinfo"))
      WEBDAV_PARSING(xmlptr->ParseLockInfo);
   else
   if (WEBDAV_IS_DAVEL(ElementPtr, "propfind"))
      WEBDAV_PARSING(xmlptr->ParsePropFind);
   else
   if (WEBDAV_IS_DAVEL(ElementPtr, "propertybehavior"))
      WEBDAV_PARSING(xmlptr->ParsePropertyBehavior);
   else
   if (WEBDAV_IS_DAVEL(ElementPtr, "propertyupdate"))
      WEBDAV_PARSING(xmlptr->ParsePropertyUpdate);

   if (sdptr)
   {
      for (cptr = ElementPtr; *cptr && *cptr != ' '; cptr++);
      sdptr = StrDscBuild (sdptr, NULL, "<NS:");
      StrDscBuild (sdptr, NULL, cptr+1);
      for (idx = 0; AttrPtr[idx]; idx += 2)
      {
         StrDscBuild (sdptr, NULL, " ");
         StrDscBuild (sdptr, NULL, AttrPtr[idx]);
         StrDscBuild (sdptr, NULL, "=\"");
         StrDscBuild (sdptr, NULL, AttrPtr[idx+1]);
         StrDscBuild (sdptr, NULL, "\"");
      }
      StrDscBuild (sdptr, NULL, " xmlns:NS=\"");
      StrDscThis (NULL, &ScratchDsc, ElementPtr, cptr - ElementPtr);
      StrDscBuild (sdptr, &ScratchDsc, NULL);
      StrDscBuild (sdptr, NULL, "\">");

      if (WEBDAV_IS_PARSING(xmlptr->ParsePropFind))
         STR_DSC_SET_FROZEN (sdptr)

      WEBDAV_PARSING(xmlptr->ParseCharData);
   }
}

/*****************************************************************************/
/*
*/

void XMLCALL DavXmlEndElement
(
REQUEST_STRUCT *rqptr,
char *ElementPtr
)
{
   char  *cptr, *sptr;
   STR_DSC  *sdptr;
   STR_DSC_AUTO (ScratchDsc);
   WEBDAV_LOCK  *lckptr;
   WEBDAV_TASK  *tkptr;
   WEBDAV_XML  *xmlptr;

   /*********/
   /* begin */
   /*********/

   if (WATCH_XML && WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV,
                 "DavXmlEndElement() !UL !AZ",
                 rqptr->WebDavTaskPtr->XmlData.ElementDepth, ElementPtr);

   tkptr = rqptr->WebDavTaskPtr;
   lckptr = &tkptr->LockData;
   xmlptr = &tkptr->XmlData;

   if (WEBDAV_IS_PARSING(xmlptr->ParseLockInfo))
   {
      if (WEBDAV_IS_PARSING(xmlptr->ParseLockScope) &&
          WEBDAV_IS_DAVEL(ElementPtr, "lockscope"))
         WEBDAV_PARSED(xmlptr->ParseLockScope);
      else
      if (WEBDAV_IS_PARSING(xmlptr->ParseLockType) &&
          WEBDAV_IS_DAVEL(ElementPtr, "locktype"))
         WEBDAV_PARSED(xmlptr->ParseLockType);
      else
      if (WEBDAV_IS_PARSING(xmlptr->ParseLockOwner) &&
          WEBDAV_IS_DAVEL(ElementPtr, "owner"))
      {
         WEBDAV_PARSED(xmlptr->ParseLockOwner);
         DavXmlTrimElement (&lckptr->OwnerDsc);
         if (WATCH_XML && WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
            WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV,
                       "!&Z", STR_DSC_PTR(&lckptr->OwnerDsc));
      }
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "lockinfo"))
         WEBDAV_PARSED(xmlptr->ParseLockInfo);
   }
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParsePropFind))
   {
      if (WEBDAV_IS_DAVEL(ElementPtr, "propfind"))
         WEBDAV_PARSED(xmlptr->ParsePropFind);
      else
         WEBDAV_PARSED(xmlptr->ParseFind);
   }
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParsePropertyBehavior))
   {
      if (WEBDAV_IS_DAVEL(ElementPtr, "propertybehavior"))
         WEBDAV_PARSED(xmlptr->ParsePropertyBehavior);
   }
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParsePropertyUpdate))
   {
      if (WEBDAV_IS_PARSING(xmlptr->ParseSet))
      {
         if (WEBDAV_IS_PARSING(xmlptr->ParseProp))
         {
            if (WEBDAV_IS_DAVEL(ElementPtr, "prop"))
               WEBDAV_PARSED(xmlptr->ParseProp);
         }
         else
         if (WEBDAV_IS_DAVEL(ElementPtr, "set"))
            WEBDAV_PARSED(xmlptr->ParseSet);
      }
      else
      if (WEBDAV_IS_PARSING(xmlptr->ParseRemove))
      {
         if (WEBDAV_IS_PARSING(xmlptr->ParseProp))
         {
            if (WEBDAV_IS_DAVEL(ElementPtr, "prop"))
               WEBDAV_PARSED(xmlptr->ParseProp);
         }
         else
         if (WEBDAV_IS_DAVEL(ElementPtr, "remove"))
            WEBDAV_PARSED(xmlptr->ParseRemove);
      }
      else
      if (WEBDAV_IS_DAVEL(ElementPtr, "propertyupdate"))
         WEBDAV_PARSED(xmlptr->ParsePropertyUpdate);
   }

   sdptr = NULL;
   if (WEBDAV_IS_PARSING(xmlptr->ParseSet) &&
       WEBDAV_IS_PARSING(xmlptr->ParseProp))
      sdptr = &xmlptr->PropSetDsc;
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParseRemove) &&
       WEBDAV_IS_PARSING(xmlptr->ParseProp))
      sdptr = &xmlptr->PropRemoveDsc;
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParseLockOwner))
      sdptr = &lckptr->OwnerDsc;

   if (sdptr)
   {
      for (cptr = ElementPtr; *cptr && *cptr != ' '; cptr++);
      sdptr = StrDscBuild (sdptr, NULL, "</NS:");
      StrDscBuild (sdptr, NULL, cptr+1);
      StrDscBuild (sdptr, NULL, ">");

      if (WEBDAV_IS_PARSING(xmlptr->ParseProp) &&
          xmlptr->ElementDepth == 4)
      {
         /* end of this property, freeze current content */ 
         STR_DSC_SET_FROZEN (sdptr)
         WEBDAV_NOT_PARSING(xmlptr->ParseCharData);
      }
      else
         WEBDAV_PARSING(xmlptr->ParseCharData);
   }
   else
      WEBDAV_NOT_PARSING(xmlptr->ParseCharData);

   if (xmlptr->ElementDepth) xmlptr->ElementDepth--;
}

/*****************************************************************************/
/*
*/

void XMLCALL DavXmlCharData
(
REQUEST_STRUCT *rqptr,
XML_Char *DataPtr,
int DataLength
)
{
   STR_DSC  *sdptr;
   STR_DSC_AUTO (CharDataDsc);
   WEBDAV_LOCK  *lckptr;
   WEBDAV_TASK  *tkptr;
   WEBDAV_XML  *xmlptr;

   /*********/
   /* begin */
   /*********/

   if (WATCH_XML && WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV,
                 "DavXmlCharData() !&B !UL |!#AZ",
                 rqptr->WebDavTaskPtr->XmlData.ParseCharData,
                 DataLength, DataLength, DataPtr);

   tkptr = rqptr->WebDavTaskPtr;
   lckptr = &tkptr->LockData;
   xmlptr = &tkptr->XmlData;

   if (!WEBDAV_IS_PARSING(xmlptr->ParseCharData)) return;

   if (WEBDAV_IS_PARSING(xmlptr->ParseSet) &&
       WEBDAV_IS_PARSING(xmlptr->ParseProp))
      sdptr = &xmlptr->PropSetDsc;
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParseRemove) &&
       WEBDAV_IS_PARSING(xmlptr->ParseProp))
      sdptr = &xmlptr->PropRemoveDsc;
   else
   if (WEBDAV_IS_PARSING(xmlptr->ParseLockOwner))
      sdptr = &lckptr->OwnerDsc;
   else
      sdptr = NULL;

   if (sdptr)
   {
      StrDscThis (NULL, &CharDataDsc, DataPtr, DataLength);
      StrDscBuild (sdptr, &CharDataDsc, NULL);
   }
}

/*****************************************************************************/
/*
Trim leading and trailing white-space from a string containing an XML element.
*/

DavXmlTrimElement (STR_DSC *sdptr)

{
   char  *cptr, *sptr;

   /*********/
   /* begin */
   /*********/

   if (!STR_DSC_PTR(sdptr) || !STR_DSC_LEN(sdptr)) return;

   for (cptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
        cptr > STR_DSC_PTR(sdptr) && *cptr != '>';
        cptr--);
   if (cptr > STR_DSC_PTR(sdptr))
   {
      *++cptr = '\0';
      STR_DSC_LEN(sdptr) = cptr - STR_DSC_PTR(sdptr);
   }
   for (cptr = STR_DSC_PTR(sdptr); *cptr && *cptr != '<'; cptr++);
   if (cptr > STR_DSC_PTR(sdptr) &&
       cptr < STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr))
   {
      for (sptr = STR_DSC_PTR(sdptr); *cptr; *sptr++ = *cptr++);
      *sptr = '\0';
      STR_DSC_LEN(sdptr) = sptr - STR_DSC_PTR(sdptr);
   }
}

/*****************************************************************************/
/*
Report on the XML.
*/ 

DavXmlReport (REQUEST_STRUCT *rqptr)

{
   static char  ReportFormFao [] =
"<form action=\"" ADMIN_REPORT_WEBDAV_XML "\" METHOD=\"POST\" \
ENCtype=\"application/x-www-form-urlencoded\">\n\
<p><table cellpadding=\"1\" cellspacing=\"0\" border=\"0\">\n\
<tr><td>\
<textarea name=\"XMLtext\" id=\"XMLtext\" \
rows=\"24\" cols=\"80\" nowrap></textarea>\n\
</td></tr>\n\
</table>\n\
<p><input type=\"submit\" name=\"submit\" value=\"Parse XML\">\
&nbsp;&nbsp;<input type=\"submit\" name=\"submit\" value=\"Display XML\">\
&nbsp;&nbsp;<input type=\"submit\" name=\"submit\" value=\"Display Plain\">\
&nbsp;&nbsp;&nbsp;<input type=\"reset\" value=\"Clear\">\n\
</form>\n\
</body>\n\
</html>\n";

   static char  ReportPage1Fao [] =
"<p><table cellpadding=\"5\" cellspacing=\"0\" border=\"1\">\n\
<tr><td>";

   static char  ReportPage2Fao [] =
"</td></tr>\n\
</table>\n\
</tr></td>\n\
</body>\n\
</html>\n";

   BOOL  DisplayPlain,
         DisplayXML,
         ParseXML;
   int  qlen, status,
        FieldValueSize,
        XmlTextLength;
   unsigned long  FaoVector [16];
   unsigned long  *vecptr;
   char  *qptr,
         *FieldValuePtr,
         *XmlTextPtr;
   char  FieldName [256],
         FieldValue [256];
   BODY_PROCESS  *prptr;
   STR_DSC_AUTO (XmlTextDsc);
   WEBDAV_TASK  *tkptr;
   WEBDAV_XML  *xmlptr;

   /*********/
   /* begin */
   /*********/

   if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavXmlReport()");

   if (rqptr->rqHeader.ContentLength64)
   {
      if (!rqptr->rqBody.DataPtr)
      {
         /* read all of request body and then AST back to this function */
         BodyReadBegin (rqptr, &DavXmlReport, &BodyProcessReadAll);
         return;
      }
      if (rqptr->rqBody.DataStatus != SS$_ENDOFFILE)
      {
         DavWebEnd (rqptr);
         return;
      }
      if (!(prptr = rqptr->rqBody.ProcessPtr))
      {
         ErrorNoticed (rqptr, SS$_BUGCHECK, ErrorSanityCheck, FI_LI);
         rqptr->rqResponse.ErrorTextPtr = ErrorSanityCheck;
         ErrorVmsStatus (rqptr, SS$_BUGCHECK, FI_LI);
         DavWebEnd (rqptr);
         return;
      }
      FieldValueSize = prptr->BlockBufferCount;
   }
   else
      FieldValueSize = 256;

   FieldValuePtr = (char*)VmGetHeap (rqptr, FieldValueSize);

   DisplayPlain = DisplayXML = ParseXML = false;
   XmlTextPtr = "";

   if (rqptr->rqHeader.Method == HTTP_METHOD_POST)
   {
      if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
         WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "!UL bytes",
                    prptr->BlockBufferCount);
      qptr = prptr->BlockBufferPtr;
      qlen = prptr->BlockBufferCount;
   }
   else
   if (rqptr->rqHeader.QueryStringLength)
   {
      qptr = rqptr->rqHeader.QueryStringPtr;
      qlen = rqptr->rqHeader.QueryStringLength;
   }
   else
   {
      qptr = "";
      qlen = 0;
   }

   while (*qptr)
   {
      status = StringParseQuery (&qptr, FieldName, sizeof(FieldName),
                                        FieldValuePtr, FieldValueSize);
      if (VMSnok (status))
      {
         /* error occured */
         if (status == SS$_IVCHAR) rqptr->rqResponse.HttpStatus = 400;
         rqptr->rqResponse.ErrorTextPtr = "parsing query string";
         ErrorVmsStatus (rqptr, status, FI_LI);
         DavWebEnd (rqptr);
         return;
      }
      if (strsame (FieldName, "XMLtext", -1))
      {
         XmlTextPtr = FieldValuePtr;
         /* subsequent fields into fixed storage */
         FieldValuePtr = FieldValue;
         FieldValueSize = sizeof(FieldValue);
      }
      if (strsame (FieldName, "submit", -1))
      {
         if (strsame (FieldValue, "Display XML", -1))
            DisplayXML = true;
         else
         if (strsame (FieldValue, "Display Plain", -1))
            DisplayPlain = true;
         else
         if (strsame (FieldValue, "Parse XML", -1))
            ParseXML = true;
      }
   }

   if (DisplayXML)
   {
      StrDscBegin (rqptr, &rqptr->NetWriteBufferDsc,
                   rqptr->rqHeader.ContentLength64);
      StrDscBuild (&rqptr->NetWriteBufferDsc, NULL, XmlTextPtr);
      XmlTextLength = StrDscLength (&rqptr->NetWriteBufferDsc);
      ResponseHeader (rqptr, 200, "text/xml; charset=\"utf-8\"",
                      XmlTextLength, NULL, NULL);
      DavWebEnd (rqptr);
      return;
   }

   if (DisplayPlain)
   {
      StrDscBegin (rqptr, &rqptr->NetWriteBufferDsc,
                   rqptr->rqHeader.ContentLength64);
      StrDscBuild (&rqptr->NetWriteBufferDsc, NULL, XmlTextPtr);
      XmlTextLength = StrDscLength (&rqptr->NetWriteBufferDsc);
      ResponseHeader (rqptr, 200, "text/plain", XmlTextLength, NULL, NULL);
      DavWebEnd (rqptr);
      return;
   }

   StrDscThis (NULL, &XmlTextDsc, XmlTextPtr, strlen(XmlTextPtr));

   AdminPageTitle (rqptr, "WebDAV XML Parse Test Tool");

   if (rqptr->rqHeader.Method == HTTP_METHOD_POST)
   {
      /* set up the task structure for the duration of the parse */
      tkptr = rqptr->WebDavTaskPtr = VmGetHeap (rqptr, sizeof(WEBDAV_TASK));
      xmlptr = &tkptr->XmlData;

      DavXmlParseText (rqptr, &XmlTextDsc);

      NetWriteBuffered (rqptr, NULL, ReportPage1Fao, sizeof(ReportPage1Fao)-1);

      if (STR_DSC_PTR(&xmlptr->ParseErrorDsc))
         FaoToNet (rqptr, "<pre>!&;AZ</pre>",
                   STR_DSC_PTR(&xmlptr->ParseErrorDsc));
      else
         DavXmlReportOnParse (rqptr);

      NetWriteBuffered (rqptr, NULL, ReportPage2Fao, sizeof(ReportPage2Fao)-1);
      rqptr->rqResponse.PreExpired = PRE_EXPIRE_ADMIN;

      VmFreeFromHeap (rqptr, rqptr->WebDavTaskPtr, FI_LI);
      rqptr->WebDavTaskPtr = NULL;
   }
   else
   {
      FaolToNet (rqptr, ReportFormFao, &FaoVector);
      rqptr->rqResponse.PreExpired = 0;
   }

   ResponseHeader200 (rqptr, "text/html", &rqptr->NetWriteBufferDsc);

   AdminEnd (rqptr);
}

/*****************************************************************************/
/*
Report on the XML elements.
*/ 
 
DavXmlReportOnParse (REQUEST_STRUCT *rqptr)

{
   STR_DSC  *sdptr;
   WEBDAV_LOCK  *lckptr;
   WEBDAV_PROP  *proptr;
   WEBDAV_TASK  *tkptr;
   WEBDAV_XML  *xmlptr;

   /*********/
   /* begin */
   /*********/

   if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavXmlReportOnParse()");

   tkptr = rqptr->WebDavTaskPtr;
   lckptr = &tkptr->LockData;
   proptr = &tkptr->PropData;
   xmlptr = &tkptr->XmlData;

   FaoToNet (rqptr, "<ul>\n");

   if (WEBDAV_IS_PARSED(xmlptr->ParseLockInfo))
   {
      FaoToNet (rqptr, "<p><li><b>lockinfo</b>\n<ul>\n");
      if (lckptr->Type == WEBDAV_LOCK_TYPE_WRITE)
         FaoToNet (rqptr, "<li>write\n");
      if (lckptr->Scope == WEBDAV_LOCK_SCOPE_EXCLUSIVE)
         FaoToNet (rqptr, "<li>exclusive\n");
      else
      if (lckptr->Scope == WEBDAV_LOCK_SCOPE_SHARED)
         FaoToNet (rqptr, "<li>shared\n");
      if (STR_DSC_PTR(&lckptr->OwnerDsc))
         FaoToNet (rqptr, "<li>owner:<pre>!&;AZ</pre>\n",
                   STR_DSC_PTR(&lckptr->OwnerDsc));
      FaoToNet (rqptr, "</ul>\n");
   }

   if (WEBDAV_IS_PARSED(xmlptr->ParsePropFind))
   {
      FaoToNet (rqptr, "<p><li><b>propfind</b>\n<ul>\n");
      if (proptr->AllProp) FaoToNet (rqptr, "<li>allprop\n");
      if (proptr->CreationDate) FaoToNet (rqptr, "<li>creationdate\n");
      if (proptr->DisplayName) FaoToNet (rqptr, "<li>displayname\n");
      if (proptr->ResourceType) FaoToNet (rqptr, "<li>resourcetype\n");
      if (proptr->GetContentType) FaoToNet (rqptr, "<li>getcontenttype\n");
      if (proptr->GetContentLength) FaoToNet (rqptr, "<li>getcontentlength\n");
      if (proptr->GetEtag) FaoToNet (rqptr, "<li>getetag\n");
      if (proptr->GetLastModified) FaoToNet (rqptr, "<li>getlastmodified\n");
      if (proptr->LockDiscovery) FaoToNet (rqptr, "<li>lockdiscovery\n");
      if (proptr->PropName) FaoToNet (rqptr, "<li>propname\n");
      if (proptr->SupportedLock) FaoToNet (rqptr, "<li>supportedlock\n");
      if (proptr->QuotaAvailableBytes) FaoToNet (rqptr, "<li>quota-available-bytes\n");
      if (proptr->QuotaUsedBytes) FaoToNet (rqptr, "<li>quota-used-bytes\n");
      FaoToNet (rqptr, "</ul>\n");
   }

   if (WEBDAV_IS_PARSED(xmlptr->ParsePropertyBehavior))
   {
      FaoToNet (rqptr, "<p><li><b>propertybehaviour</b>\n<ul>\n");
      if (proptr->PropertyBehaviorKeepalive) FaoToNet (rqptr, "<li>keepalive\n");
      if (proptr->PropertyBehaviorOmit) FaoToNet (rqptr, "<li>omit\n");
      FaoToNet (rqptr, "</ul>\n");
   }

   STR_DSC_ITERATE (sdptr, &xmlptr->PropSetDsc)
      if (STR_DSC_LEN(sdptr))
         FaoToNet (rqptr, "<p><li><b>set&nbsp;prop</b><pre>!&;AZ</pre>\n",
                   STR_DSC_PTR(sdptr));

   STR_DSC_ITERATE (sdptr, &xmlptr->PropRemoveDsc)
      if (STR_DSC_LEN(sdptr))
         FaoToNet (rqptr, "<p><li><b>remove&nbsp;prop</b><pre>!&;AZ</pre>\n",
                   STR_DSC_PTR(sdptr));

   FaoToNet (rqptr, "</ul><p>\n");
}

/*****************************************************************************/
/*
WATCH the XML elements.
*/ 
 
DavXmlWatchProp (REQUEST_STRUCT *rqptr)

{
   char  buf [1024];
   STR_DSC  *sdptr;
   WEBDAV_LOCK  *lckptr;
   WEBDAV_PROP  *proptr;
   WEBDAV_TASK  *tkptr;
   WEBDAV_XML  *xmlptr;

   /*********/
   /* begin */
   /*********/

   if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavXmlWatchProp()");

   tkptr = rqptr->WebDavTaskPtr;
   lckptr = &tkptr->LockData;
   proptr = &tkptr->PropData;
   xmlptr = &tkptr->XmlData;

   if (WEBDAV_IS_PARSED(xmlptr->ParseLockInfo))
   {
      buf[0] = '\0';
      if (STR_DSC_LEN(&lckptr->OwnerDsc))
         FaoToBuffer (buf, sizeof(buf)/2, NULL, " owner:\"!AZ\"",
                      STR_DSC_PTR(&lckptr->OwnerDsc));
      if (lckptr->Type == WEBDAV_LOCK_TYPE_WRITE) strcat (buf, " write");
      if (lckptr->Scope == WEBDAV_LOCK_SCOPE_EXCLUSIVE)
         strcat (buf, " exclusive");
      else
      if (lckptr->Scope == WEBDAV_LOCK_SCOPE_SHARED) strcat (buf, " shared");
      WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "LOCKINFO!AZ", buf);
   }

   if (WEBDAV_IS_PARSED(xmlptr->ParsePropFind))
   {
      buf[0] = '\0';
      if (proptr->AllProp) strcat (buf, " allprop");
      if (proptr->CreationDate) strcat (buf, " creationdate");
      if (proptr->DisplayName) strcat (buf, " displayname");
      if (proptr->ResourceType) strcat (buf, " resourcetype");
      if (proptr->GetContentType) strcat (buf, " getcontenttype");
      if (proptr->GetContentLength) strcat (buf, " getcontentlength");
      if (proptr->GetEtag) strcat (buf, " getetag");
      if (proptr->GetLastModified) strcat (buf, " getlastmodified");
      if (proptr->LockDiscovery) strcat (buf, " lockdiscovery");
      if (proptr->PropName) strcat (buf, " propname");
      if (proptr->SupportedLock) strcat (buf, " supportedlock");
      if (proptr->QuotaAvailableBytes) strcat (buf, " quota-available-bytes");
      if (proptr->QuotaUsedBytes) strcat (buf, "quota-used-bytes ");
      WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "PROPFIND!AZ", buf);
   }

   if (WEBDAV_IS_PARSED(xmlptr->ParsePropertyBehavior))
   {
      buf[0] = '\0';
      if (proptr->PropertyBehaviorKeepalive) strcat (buf, " keepalive");
      if (proptr->PropertyBehaviorOmit) strcat (buf, " omit");
      WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "PROPERTYBEHAVIOUR!AZ", buf);
   }

   STR_DSC_ITERATE (sdptr, &xmlptr->PropSetDsc)
      if (STR_DSC_LEN(sdptr))
         WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "SET !AZ",
                    STR_DSC_PTR(sdptr));

   STR_DSC_ITERATE (sdptr, &xmlptr->PropRemoveDsc)
      if (STR_DSC_LEN(sdptr))
         WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "REMOVE !AZ",
                    STR_DSC_PTR(sdptr));
}

/*****************************************************************************/