WebDav.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include <utility>
  19. #include "WebDav.h"
  20. #include <kopano/stringutil.h>
  21. #include <kopano/CommonUtil.h>
  22. #include <libical/ical.h>
  23. using namespace std;
  24. /**
  25. * @param[in] lpRequest Pointer to http Request object
  26. * @param[in] lpSession Pointer to mapi session of the user
  27. */
  28. WebDav::WebDav(Http *lpRequest, IMAPISession *lpSession,
  29. const std::string &strSrvTz, const std::string &strCharset) :
  30. ProtocolBase(lpRequest, lpSession, strSrvTz, strCharset)
  31. {
  32. }
  33. WebDav::~WebDav()
  34. {
  35. if (m_lpXmlDoc)
  36. xmlFreeDoc(m_lpXmlDoc);
  37. }
  38. /**
  39. * Parse the xml request body
  40. * @return HRESULT
  41. * @retval MAPI_E_INVALID_PARAMETER Unable to parse the xml data
  42. */
  43. HRESULT WebDav::HrParseXml()
  44. {
  45. HRESULT hr = hrSuccess;
  46. std::string strBody;
  47. assert(m_lpXmlDoc == NULL);
  48. if (m_lpXmlDoc != NULL)
  49. return hr;
  50. m_lpRequest->HrGetBody(&strBody);
  51. m_lpXmlDoc = xmlReadMemory((char *)strBody.c_str(),(int)strBody.length(), "PROVIDE_BASE.xml", NULL, XML_PARSE_NOBLANKS);
  52. if (m_lpXmlDoc == NULL)
  53. hr = MAPI_E_INVALID_PARAMETER;
  54. strBody.clear();
  55. return hr;
  56. }
  57. /**
  58. * Parse the PROPFIND request
  59. *
  60. * Example of PROPFIND request
  61. *
  62. * <D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
  63. * <D:prop>
  64. * <D:resourcetype/>
  65. * <D:owner/>
  66. * <CS:getctag/>
  67. * </D:prop>
  68. * </D:propfind>
  69. *
  70. * @return HRESULT
  71. * @retval MAPI_E_CORRUPT_DATA Invalid xml data
  72. * @retval MAPI_E_NOT_FOUND Folder requested in url not found
  73. *
  74. */
  75. HRESULT WebDav::HrPropfind()
  76. {
  77. HRESULT hr = hrSuccess;
  78. WEBDAVPROPSTAT sPropStat;
  79. WEBDAVRESPONSE sDavResp;
  80. WEBDAVMULTISTATUS sDavMStatus;
  81. WEBDAVREQSTPROPS sDavReqsProps;
  82. WEBDAVPROP sDavPropRet;
  83. std::string strFldPath;
  84. std::string strXml;
  85. xmlNode * lpXmlNode = NULL;
  86. // libxml parser parses the xml data and returns the DomTree pointer.
  87. hr = HrParseXml();
  88. if (hr != hrSuccess)
  89. goto exit;
  90. lpXmlNode = xmlDocGetRootElement(m_lpXmlDoc);
  91. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"propfind"))
  92. {
  93. hr = MAPI_E_CORRUPT_DATA;
  94. goto exit;
  95. }
  96. lpXmlNode = lpXmlNode->children;
  97. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"prop"))
  98. {
  99. hr = MAPI_E_CORRUPT_DATA;
  100. goto exit;
  101. }
  102. HrSetDavPropName(&(sDavPropRet.sPropName),lpXmlNode);
  103. lpXmlNode = lpXmlNode->children;
  104. while (lpXmlNode)
  105. {
  106. WEBDAVPROPERTY sProperty;
  107. HrSetDavPropName(&(sProperty.sPropName),lpXmlNode);
  108. sDavPropRet.lstProps.push_back(std::move(sProperty));
  109. lpXmlNode = lpXmlNode->next;
  110. }
  111. /*
  112. * Call to CALDAV::HrHandlePropfind
  113. * This function Retrieves data from server and adds it to the structure.
  114. */
  115. sDavReqsProps.sProp = sDavPropRet;
  116. hr = HrHandlePropfind(&sDavReqsProps, &sDavMStatus);
  117. if (hr != hrSuccess)
  118. goto exit;
  119. // Convert WEBMULTISTATUS structure to xml data.
  120. hr = RespStructToXml(&sDavMStatus, &strXml);
  121. if (hr != hrSuccess)
  122. {
  123. ec_log_debug("Unable to convert response to xml: 0x%08X", hr);
  124. goto exit;
  125. }
  126. exit:
  127. if(hr == hrSuccess)
  128. {
  129. m_lpRequest->HrResponseHeader(207, "Multi-Status");
  130. m_lpRequest->HrResponseHeader("Content-Type", "application/xml; charset=\"utf-8\"");
  131. m_lpRequest->HrResponseBody(strXml);
  132. }
  133. else if (hr == MAPI_E_NOT_FOUND)
  134. m_lpRequest->HrResponseHeader(404, "Not Found");
  135. else if (hr == MAPI_E_NO_ACCESS)
  136. m_lpRequest->HrResponseHeader(403, "Access Denied");
  137. else
  138. m_lpRequest->HrResponseHeader(500, "Internal Server Error");
  139. return hr;
  140. }
  141. /**
  142. * Converts WEBDAVMULTISTATUS response structure to xml data
  143. * @param[in] sDavMStatus Pointer to WEBDAVMULTISTATUS structure
  144. * @param[out] strXml Return string for xml data
  145. *
  146. * @return HRESULT
  147. * @retval MAPI_E_NOT_ENOUGH_MEMORY Error alocating memory
  148. * @retval MAPI_E_CALL_FAILED Error initializing xml writer
  149. * @retval MAPI_E_CALL_FAILED Error writing xml data
  150. */
  151. HRESULT WebDav::RespStructToXml(WEBDAVMULTISTATUS *sDavMStatus, std::string *strXml)
  152. {
  153. HRESULT hr = hrSuccess;
  154. int ulRet;
  155. std::string strNsPrefix;
  156. xmlTextWriter *xmlWriter = NULL;
  157. xmlBuffer *xmlBuff = NULL;
  158. std::string strNs;
  159. strNsPrefix = "C";
  160. xmlBuff = xmlBufferCreate();
  161. if (xmlBuff == NULL)
  162. {
  163. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  164. ec_log_err("Error allocating memory to xmlBuffer");
  165. goto exit;
  166. }
  167. //Initialize Xml-Writer
  168. xmlWriter = xmlNewTextWriterMemory(xmlBuff, 0);
  169. if (xmlWriter == NULL)
  170. {
  171. hr = MAPI_E_CALL_FAILED;
  172. ec_log_err("Error Initializing xmlWriter");
  173. goto exit;
  174. }
  175. // let xml use enters and spaces to make it somewhat readable
  176. // if indedentaion is not present, iCal.app does not show suggestionlist.
  177. ulRet = xmlTextWriterSetIndent(xmlWriter, 1);
  178. if (ulRet < 0)
  179. goto xmlfail;
  180. //start xml-data i.e <xml version="1.0" encoding="utf-8"?>
  181. ulRet = xmlTextWriterStartDocument(xmlWriter, NULL, "UTF-8", NULL);
  182. if (ulRet < 0)
  183. goto xmlfail;
  184. // @todo move this default to sDavMStatus constructor, never different.
  185. if(sDavMStatus->sPropName.strNS.empty())
  186. sDavMStatus->sPropName.strNS = "DAV:";
  187. if (sDavMStatus->sPropName.strPropname.empty())
  188. sDavMStatus->sPropName.strPropname = "multistatus";
  189. strNsPrefix = "C";
  190. m_mapNs[sDavMStatus->sPropName.strNS.c_str()] = "C";
  191. //<multistatus>
  192. ulRet = xmlTextWriterStartElementNS(xmlWriter,
  193. (const xmlChar *)strNsPrefix.c_str(),
  194. (const xmlChar *)sDavMStatus->sPropName.strPropname.c_str(),
  195. (const xmlChar *)sDavMStatus->sPropName.strNS.c_str());
  196. if (ulRet < 0)
  197. goto xmlfail;
  198. //write all xmlname spaces in main tag.
  199. for (const auto &ns : m_mapNs) {
  200. std::string strprefix;
  201. strNs = ns.first;
  202. if(sDavMStatus->sPropName.strNS == strNs || strNs.empty())
  203. continue;
  204. RegisterNs(strNs, &strNsPrefix);
  205. strprefix = "xmlns:" + strNsPrefix;
  206. ulRet = xmlTextWriterWriteAttribute(xmlWriter,
  207. reinterpret_cast<const xmlChar *>(strprefix.c_str()),
  208. reinterpret_cast<const xmlChar *>(strNs.c_str()));
  209. if (ulRet < 0)
  210. goto xmlfail;
  211. }
  212. // <response>
  213. for (const auto &resp : sDavMStatus->lstResp) {
  214. hr = HrWriteSResponse(xmlWriter, &strNsPrefix, resp);
  215. if(hr != hrSuccess)
  216. goto exit;
  217. }
  218. //</multistatus>
  219. ulRet = xmlTextWriterEndElement(xmlWriter);
  220. if (ulRet < 0)
  221. goto xmlfail;
  222. //EOF
  223. ulRet = xmlTextWriterEndDocument(xmlWriter);
  224. if (ulRet < 0)
  225. goto xmlfail;
  226. // force write to buffer
  227. ulRet = xmlTextWriterFlush(xmlWriter);
  228. if (ulRet < 0)
  229. goto xmlfail;
  230. strXml->assign((char *)xmlBuff->content, xmlBuff->use);
  231. exit:
  232. if (xmlWriter)
  233. xmlFreeTextWriter(xmlWriter);
  234. if (xmlBuff)
  235. xmlBufferFree(xmlBuff);
  236. return hr;
  237. xmlfail:
  238. hr = MAPI_E_CALL_FAILED;
  239. ec_log_err("Error writing xml data");
  240. goto exit;
  241. }
  242. /**
  243. * Parse the REPORT request, identify the type of report request
  244. *
  245. * @return HRESULT
  246. * @retval MAPI_E_CORRUPT_DATA Invalid xml request
  247. *
  248. */
  249. HRESULT WebDav::HrReport()
  250. {
  251. HRESULT hr;
  252. xmlNode *lpXmlNode;
  253. hr = HrParseXml();
  254. if (hr != hrSuccess)
  255. return hr;
  256. lpXmlNode = xmlDocGetRootElement(m_lpXmlDoc);
  257. if (!lpXmlNode)
  258. return MAPI_E_CORRUPT_DATA;
  259. if (lpXmlNode->name && !xmlStrcmp(lpXmlNode->name, (const xmlChar *)"calendar-query") )
  260. //CALENDAR-QUERY
  261. //Retrieves the list of GUIDs
  262. return HrHandleRptCalQry();
  263. else if (lpXmlNode->name && !xmlStrcmp(lpXmlNode->name, (const xmlChar *)"calendar-multiget") )
  264. //MULTIGET
  265. //Retrieves Ical data for each GUID that client requests
  266. return HrHandleRptMulGet();
  267. else if (lpXmlNode->name && !xmlStrcmp(lpXmlNode->name, (const xmlChar *)"principal-property-search"))
  268. // suggestion list while adding attendees on mac iCal.
  269. return HrPropertySearch();
  270. else if (lpXmlNode->name && !xmlStrcmp(lpXmlNode->name, (const xmlChar *)"principal-search-property-set"))
  271. // which all properties to be searched while searching for attendees.
  272. return HrPropertySearchSet();
  273. else if (lpXmlNode->name && !xmlStrcmp(lpXmlNode->name, (const xmlChar *)"expand-property"))
  274. // ignore expand-property
  275. m_lpRequest->HrResponseHeader(200, "OK");
  276. else
  277. m_lpRequest->HrResponseHeader(500, "Internal Server Error");
  278. return hrSuccess;
  279. }
  280. /**
  281. * Parses the calendar-query REPORT request.
  282. *
  283. * The request is for retrieving list of calendar entries in folder
  284. * Example of the request
  285. *
  286. * <calendar-query xmlns:D="DAV:" xmlns="urn:ietf:params:xml:ns:caldav">
  287. * <D:prop>
  288. * <D:getetag/>
  289. * </D:prop>
  290. * <filter>
  291. * <comp-filter name="VCALENDAR">
  292. * <comp-filter name="VEVENT"/>
  293. * </comp-filter>
  294. * </filter>
  295. * </calendar-query>
  296. *
  297. * @return HRESULT
  298. * @retval MAPI_E_CORRUPT_DATA Invalid xml data
  299. */
  300. // @todo, do not return MAPI_E_CORRUPT_DATA, but make a clean error report for the client.
  301. // only return MAPI_E_CORRUPT_DATA when xml is invalid (which normal working clients won't send)
  302. HRESULT WebDav::HrHandleRptCalQry()
  303. {
  304. HRESULT hr = hrSuccess;
  305. xmlNode * lpXmlNode = NULL;
  306. xmlNode * lpXmlChildNode = NULL;
  307. xmlAttr * lpXmlAttr = NULL;
  308. xmlNode * lpXmlChildAttr = NULL;
  309. WEBDAVREQSTPROPS sReptQuery;
  310. WEBDAVMULTISTATUS sWebMStatus;
  311. std::string strXml;
  312. lpXmlNode = xmlDocGetRootElement(m_lpXmlDoc);
  313. if (!lpXmlNode)
  314. {
  315. hr = MAPI_E_CORRUPT_DATA;
  316. goto exit;
  317. }
  318. // REPORT calendar-query
  319. sReptQuery.sPropName.strPropname.assign((const char*) lpXmlNode->name);
  320. sReptQuery.sFilter.tStart = 0;
  321. //HrSetDavPropName(&(sReptQuery.sPropName),lpXmlNode);
  322. lpXmlNode = lpXmlNode->children;
  323. while (lpXmlNode) {
  324. if (xmlStrcmp(lpXmlNode->name, (const xmlChar *)"filter") == 0)
  325. {
  326. // @todo convert xml filter to mapi restriction
  327. // "old" code
  328. if (!lpXmlNode->children) {
  329. hr = MAPI_E_CORRUPT_DATA;
  330. goto exit;
  331. }
  332. HrSetDavPropName(&(sReptQuery.sFilter.sPropName),lpXmlNode);
  333. lpXmlChildNode = lpXmlNode->children;
  334. lpXmlAttr = lpXmlChildNode->properties;
  335. if (lpXmlAttr && lpXmlAttr->children)
  336. lpXmlChildAttr = lpXmlAttr->children;
  337. else
  338. {
  339. hr = MAPI_E_CORRUPT_DATA;
  340. goto exit;
  341. }
  342. if (!lpXmlChildAttr || !lpXmlChildAttr->content || xmlStrcmp(lpXmlChildAttr->content, (const xmlChar *)"VCALENDAR"))
  343. {
  344. hr = E_FAIL;
  345. goto exit;
  346. }
  347. sReptQuery.sFilter.lstFilters.push_back((char *)lpXmlChildAttr->content);
  348. lpXmlChildNode = lpXmlChildNode->children;
  349. if (lpXmlChildNode->properties == nullptr || lpXmlChildNode->properties->children == nullptr) {
  350. hr = MAPI_E_CORRUPT_DATA;
  351. goto exit;
  352. }
  353. lpXmlAttr = lpXmlChildNode->properties;
  354. lpXmlChildAttr = lpXmlAttr->children;
  355. if (lpXmlChildAttr == NULL || lpXmlChildAttr->content == NULL) {
  356. hr = MAPI_E_CORRUPT_DATA;
  357. goto exit;
  358. }
  359. if (xmlStrcmp(lpXmlChildAttr->content, (const xmlChar *)"VTODO") != 0 &&
  360. xmlStrcmp(lpXmlChildAttr->content, (const xmlChar *)"VEVENT") != 0) {
  361. hr = MAPI_E_CORRUPT_DATA;
  362. goto exit;
  363. }
  364. sReptQuery.sFilter.lstFilters.push_back((char *)lpXmlChildAttr->content);
  365. // filter not done here.., time-range in lpXmlChildNode->children.
  366. if (lpXmlChildNode->children) {
  367. for (lpXmlChildNode = lpXmlChildNode->children; lpXmlChildNode != NULL; lpXmlChildNode = lpXmlChildNode->next) {
  368. if (xmlStrcmp(lpXmlChildNode->name, (const xmlChar *)"time-range") != 0)
  369. continue;
  370. if (lpXmlChildNode->properties == NULL || lpXmlChildNode->properties->children == NULL)
  371. continue;
  372. lpXmlChildAttr = lpXmlChildNode->properties->children;
  373. if (xmlStrcmp(lpXmlChildAttr->name, (const xmlChar *)"start") != 0)
  374. // other lpXmlChildAttr->name .. like "end" maybe?
  375. continue;
  376. // timestamp from ical
  377. icaltimetype iTime = icaltime_from_string((const char *)lpXmlChildAttr->content);
  378. sReptQuery.sFilter.tStart = icaltime_as_timet(iTime);
  379. // @note this is still being ignored in CalDavProto::HrListCalEntries
  380. }
  381. }
  382. }
  383. else if (xmlStrcmp(lpXmlNode->name, (const xmlChar *)"prop") == 0)
  384. {
  385. if (lpXmlNode->ns && lpXmlNode->ns->href)
  386. sReptQuery.sPropName.strNS.assign((const char*) lpXmlNode->ns->href);
  387. else
  388. sReptQuery.sPropName.strNS.assign(WEBDAVNS);
  389. HrSetDavPropName(&(sReptQuery.sProp.sPropName),lpXmlNode);
  390. lpXmlChildNode = lpXmlNode->children;
  391. while (lpXmlChildNode)
  392. {
  393. //properties requested by client.
  394. WEBDAVPROPERTY sWebProperty;
  395. HrSetDavPropName(&(sWebProperty.sPropName),lpXmlChildNode);
  396. sReptQuery.sProp.lstProps.push_back(std::move(sWebProperty));
  397. lpXmlChildNode = lpXmlChildNode->next;
  398. }
  399. } else {
  400. ec_log_debug("Skipping unknown XML element: %s", lpXmlNode->name);
  401. }
  402. lpXmlNode = lpXmlNode->next;
  403. }
  404. // @todo, load depth 0 ? .. see propfind version.
  405. //Retrieve Data from the server & return WEBMULTISTATUS structure.
  406. hr = HrListCalEntries(&sReptQuery, &sWebMStatus);
  407. if (hr != hrSuccess)
  408. goto exit;
  409. //Convert WEBMULTISTATUS structure to xml data.
  410. hr = RespStructToXml(&sWebMStatus, &strXml);
  411. if (hr != hrSuccess)
  412. goto exit;
  413. //Respond to the client with xml data.
  414. m_lpRequest->HrResponseHeader(207, "Multi-Status");
  415. m_lpRequest->HrResponseHeader("Content-Type", "application/xml; charset=\"utf-8\"");
  416. m_lpRequest->HrResponseBody(strXml);
  417. exit:
  418. if (hr != hrSuccess)
  419. {
  420. ec_log_debug("Unable to process report calendar query: 0x%08X", hr);
  421. m_lpRequest->HrResponseHeader(500, "Internal Server Error");
  422. }
  423. return hr;
  424. }
  425. /**
  426. * Parses the calendar-multiget REPORT request
  427. *
  428. * The request contains the list of guid and the response should have the
  429. * ical data
  430. * Example of the request
  431. * <calendar-multiget xmlns:D="DAV:" xmlns="urn:ietf:params:xml:ns:caldav">
  432. * <D:prop>
  433. * <D:getetag/>
  434. * <calendar-data/>
  435. * </D:prop>
  436. * <D:href>/caldav/user/path-to-calendar/d8516650-b6fc-11dd-92a5-a494cf95cb3a.ics</D:href>
  437. * </calendar-multiget>
  438. *
  439. * @return HRESULT
  440. * @retval MAPI_E_CORRUPT_DATA Invalid xml data in request
  441. */
  442. HRESULT WebDav::HrHandleRptMulGet()
  443. {
  444. HRESULT hr = hrSuccess;
  445. WEBDAVRPTMGET sRptMGet;
  446. WEBDAVMULTISTATUS sWebMStatus;
  447. xmlNode * lpXmlNode = NULL;
  448. xmlNode * lpXmlChildNode = NULL;
  449. xmlNode * lpXmlContentNode = NULL;
  450. std::string strXml;
  451. lpXmlNode = xmlDocGetRootElement(m_lpXmlDoc);
  452. if (!lpXmlNode)
  453. {
  454. hr = MAPI_E_CORRUPT_DATA;
  455. goto exit;
  456. }
  457. //REPORT Multiget Request.
  458. // xml data to structures
  459. HrSetDavPropName(&(sRptMGet.sPropName),lpXmlNode);
  460. lpXmlNode = lpXmlNode->children;
  461. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"prop"))
  462. {
  463. hr = MAPI_E_CORRUPT_DATA;
  464. goto exit;
  465. }
  466. HrSetDavPropName(&(sRptMGet.sProp.sPropName),lpXmlNode);
  467. lpXmlChildNode = lpXmlNode->children;
  468. while (lpXmlChildNode)
  469. {
  470. //Reqeuested properties of the client.
  471. WEBDAVPROPERTY sWebProperty;
  472. HrSetDavPropName(&(sWebProperty.sPropName),lpXmlChildNode);
  473. sRptMGet.sProp.lstProps.push_back(std::move(sWebProperty));
  474. lpXmlChildNode = lpXmlChildNode->next;
  475. }
  476. if (lpXmlNode->next)
  477. lpXmlChildNode = lpXmlNode->next;
  478. else
  479. {
  480. hr = MAPI_E_CORRUPT_DATA;
  481. goto exit;
  482. }
  483. while (lpXmlChildNode)
  484. {
  485. //List of ALL GUIDs whose ical data is requested.
  486. WEBDAVVALUE sWebVal;
  487. std::string strGuid;
  488. size_t found = 0;
  489. lpXmlContentNode = lpXmlChildNode->children;
  490. HrSetDavPropName(&(sWebVal.sPropName),lpXmlChildNode);
  491. strGuid.assign((const char *) lpXmlContentNode->content);
  492. found = strGuid.rfind("/");
  493. if(found == string::npos || (found+1) == strGuid.length()) {
  494. lpXmlChildNode = lpXmlChildNode->next;
  495. continue;
  496. }
  497. ++found;
  498. // strip url and .ics from guid, and convert %hex to real data
  499. strGuid.erase(0, found);
  500. strGuid.erase(strGuid.length() - 4);
  501. strGuid = urlDecode(strGuid);
  502. sWebVal.strValue = strGuid;
  503. sRptMGet.lstWebVal.push_back(std::move(sWebVal));
  504. lpXmlChildNode = lpXmlChildNode->next;
  505. }
  506. //Retrieve Data from the Server and return WEBMULTISTATUS structure.
  507. hr = HrHandleReport(&sRptMGet, &sWebMStatus);
  508. if (hr != hrSuccess)
  509. goto exit;
  510. //Convert WEBMULTISTATUS structure to xml data
  511. hr = RespStructToXml(&sWebMStatus, &strXml);
  512. if (hr != hrSuccess)
  513. goto exit;
  514. m_lpRequest->HrResponseHeader(207, "Multi-Status");
  515. m_lpRequest->HrResponseHeader("Content-Type", "application/xml; charset=\"utf-8\"");
  516. m_lpRequest->HrResponseBody(strXml);
  517. exit:
  518. if(hr != hrSuccess)
  519. {
  520. ec_log_debug("Unable to process report multi-get: 0x%08X", hr);
  521. m_lpRequest->HrResponseHeader(500, "Internal Server Error");
  522. }
  523. return hr;
  524. }
  525. /**
  526. * Parses the property-search request and generates xml response
  527. *
  528. * The response contains list of users matching the request
  529. * for the attendeee suggestion list in mac
  530. *
  531. * @return HRESULT
  532. */
  533. HRESULT WebDav::HrPropertySearch()
  534. {
  535. HRESULT hr = hrSuccess;
  536. WEBDAVRPTMGET sRptMGet;
  537. WEBDAVMULTISTATUS sWebMStatus;
  538. WEBDAVPROPERTY sWebProperty;
  539. WEBDAVVALUE sWebVal;
  540. xmlNode *lpXmlNode = NULL;
  541. xmlNode *lpXmlChildNode = NULL;
  542. xmlNode *lpXmlSubChildNode = NULL;
  543. std::string strXml;
  544. lpXmlNode = xmlDocGetRootElement(m_lpXmlDoc);
  545. if (!lpXmlNode)
  546. {
  547. hr = MAPI_E_CORRUPT_DATA;
  548. goto exit;
  549. }
  550. lpXmlNode = lpXmlNode->children;
  551. // <principal-property-search>
  552. HrSetDavPropName(&(sRptMGet.sPropName),lpXmlNode);
  553. //REPORT Multiget Request.
  554. // xml data to structures
  555. while (lpXmlNode) {
  556. // <property-search>
  557. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"property-search"))
  558. {
  559. hr = hrSuccess;
  560. break;
  561. }
  562. // <prop>
  563. lpXmlChildNode = lpXmlNode->children;
  564. if (!lpXmlChildNode || !lpXmlChildNode->name || xmlStrcmp(lpXmlChildNode->name, (const xmlChar *)"prop"))
  565. {
  566. hr = MAPI_E_CORRUPT_DATA;
  567. goto exit;;
  568. }
  569. HrSetDavPropName(&(sRptMGet.sProp.sPropName),lpXmlChildNode);
  570. // eg <diplayname>
  571. lpXmlSubChildNode = lpXmlChildNode->children;
  572. HrSetDavPropName(&(sWebVal.sPropName),lpXmlSubChildNode);
  573. // <match>
  574. if (!lpXmlChildNode->next) {
  575. hr = MAPI_E_CORRUPT_DATA;
  576. goto exit;
  577. }
  578. lpXmlChildNode = lpXmlChildNode->next;
  579. if(lpXmlChildNode->children->content)
  580. sWebVal.strValue.assign((char*)lpXmlChildNode->children->content);
  581. sRptMGet.lstWebVal.push_back(sWebVal);
  582. if(lpXmlNode->next)
  583. lpXmlNode = lpXmlNode->next;
  584. }
  585. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"prop"))
  586. {
  587. hr = MAPI_E_CORRUPT_DATA;
  588. goto exit;
  589. }
  590. lpXmlChildNode = lpXmlNode->children;
  591. while (lpXmlChildNode)
  592. {
  593. HrSetDavPropName(&(sWebProperty.sPropName),lpXmlChildNode);
  594. sRptMGet.sProp.lstProps.push_back(sWebProperty);
  595. lpXmlChildNode = lpXmlChildNode->next;
  596. }
  597. //Retrieve Data from the Server and return WEBMULTISTATUS structure.
  598. hr = HrHandlePropertySearch(&sRptMGet, &sWebMStatus);
  599. if (hr != hrSuccess)
  600. goto exit;
  601. //Convert WEBMULTISTATUS structure to xml data
  602. hr = RespStructToXml(&sWebMStatus, &strXml);
  603. if (hr != hrSuccess)
  604. goto exit;
  605. m_lpRequest->HrResponseHeader(207 , "Multi-Status");
  606. m_lpRequest->HrResponseHeader("Content-Type", "application/xml; charset=\"utf-8\"");
  607. m_lpRequest->HrResponseBody(strXml);
  608. exit:
  609. if(hr != hrSuccess)
  610. {
  611. ec_log_debug("Unable to process report multi-get: 0x%08X", hr);
  612. m_lpRequest->HrResponseHeader(500, "Internal Server Error");
  613. }
  614. return hr;
  615. }
  616. /**
  617. * Handles the property-search-set request
  618. *
  619. * The response contains list of property that the client can request while
  620. * requesting attendees in suggestion list
  621. *
  622. * @return HRESULT
  623. */
  624. HRESULT WebDav::HrPropertySearchSet()
  625. {
  626. HRESULT hr;
  627. WEBDAVMULTISTATUS sDavMStatus;
  628. std::string strXml;
  629. hr = HrHandlePropertySearchSet(&sDavMStatus);
  630. if (hr != hrSuccess)
  631. return hr;
  632. hr = RespStructToXml(&sDavMStatus, &strXml);
  633. if (hr != hrSuccess)
  634. return hr;
  635. m_lpRequest->HrResponseHeader(200, "OK");
  636. m_lpRequest->HrResponseHeader("Content-Type", "application/xml; charset=\"utf-8\"");
  637. m_lpRequest->HrResponseBody(strXml);
  638. return hrSuccess;
  639. }
  640. /**
  641. * Generates xml response for POST request to view freebusy information
  642. *
  643. * @param[in] lpsWebFbInfo WEBDAVFBINFO structure, contains all freebusy information
  644. * @return HRESULT
  645. */
  646. HRESULT WebDav::HrPostFreeBusy(WEBDAVFBINFO *lpsWebFbInfo)
  647. {
  648. HRESULT hr = hrSuccess;
  649. WEBDAVMULTISTATUS sWebMStatus;
  650. std::string strXml;
  651. HrSetDavPropName(&sWebMStatus.sPropName,"schedule-response", CALDAVNS);
  652. for (const auto &ui : lpsWebFbInfo->lstFbUserInfo) {
  653. WEBDAVPROPERTY sWebProperty;
  654. WEBDAVVALUE sWebVal;
  655. WEBDAVRESPONSE sWebResPonse;
  656. HrSetDavPropName(&sWebResPonse.sPropName,"response", CALDAVNS);
  657. HrSetDavPropName(&sWebProperty.sPropName,"recipient", CALDAVNS);
  658. HrSetDavPropName(&sWebVal.sPropName,"href", WEBDAVNS);
  659. sWebVal.strValue = "mailto:" + ui.strUser;
  660. sWebProperty.lstValues.push_back(sWebVal);
  661. sWebResPonse.lstProps.push_back(sWebProperty);
  662. sWebProperty.lstValues.clear();
  663. HrSetDavPropName(&sWebProperty.sPropName,"request-status", CALDAVNS);
  664. sWebProperty.strValue = ui.strIcal.empty() ? "3.8;No authority" : "2.0;Success";
  665. sWebResPonse.lstProps.push_back(sWebProperty);
  666. if (!ui.strIcal.empty()) {
  667. HrSetDavPropName(&sWebProperty.sPropName,"calendar-data", CALDAVNS);
  668. sWebProperty.strValue = ui.strIcal;
  669. sWebResPonse.lstProps.push_back(sWebProperty);
  670. }
  671. sWebMStatus.lstResp.push_back(std::move(sWebResPonse));
  672. }
  673. hr = RespStructToXml(&sWebMStatus, &strXml);
  674. if (hr != hrSuccess)
  675. goto exit;
  676. exit:
  677. if (hr == hrSuccess) {
  678. m_lpRequest->HrResponseHeader(200, "OK");
  679. m_lpRequest->HrResponseHeader("Content-Type", "application/xml; charset=\"utf-8\"");
  680. m_lpRequest->HrResponseBody(strXml);
  681. } else {
  682. m_lpRequest->HrResponseHeader(404, "Not found");
  683. }
  684. return hr;
  685. }
  686. /**
  687. * Converts WEBDAVVALUE structure to xml data
  688. * @param[in] xmlWriter xml writer to write xml data
  689. * @param[in] sWebVal WEBDAVVALUE structure to be converted to xml
  690. * @param[in] szNsPrefix Current Namespace prefix
  691. * @return HRESULT
  692. * @retval MAPI_E_CALL_FAILED Unable to write xml data
  693. */
  694. HRESULT WebDav::WriteData(xmlTextWriter *xmlWriter, const WEBDAVVALUE &sWebVal,
  695. std::string *szNsPrefix)
  696. {
  697. std::string strNs;
  698. int ulRet;
  699. convert_context converter;
  700. HRESULT hr;
  701. strNs = sWebVal.sPropName.strNS;
  702. if(strNs.empty())
  703. {
  704. ulRet = xmlTextWriterWriteElement(xmlWriter,
  705. (const xmlChar *)sWebVal.sPropName.strPropname.c_str(),
  706. (const xmlChar *)sWebVal.strValue.c_str());
  707. if (ulRet < 0)
  708. return MAPI_E_CALL_FAILED;
  709. return hrSuccess;
  710. }
  711. // Retrieve the namespace prefix if present in map.
  712. hr = GetNs(szNsPrefix, &strNs);
  713. // if namespace is not present in the map then insert it into map.
  714. if (hr != hrSuccess)
  715. RegisterNs(strNs, szNsPrefix);
  716. /*Write xml none of the form
  717. * <D:href>/caldav/user/calendar/entryGUID.ics</D:href>
  718. */
  719. ulRet = xmlTextWriterWriteElementNS(xmlWriter,
  720. (const xmlChar *)szNsPrefix->c_str(),
  721. (const xmlChar *)sWebVal.sPropName.strPropname.c_str(),
  722. (const xmlChar *)(strNs.empty() ? NULL : strNs.c_str()),
  723. (const xmlChar *)sWebVal.strValue.c_str());
  724. if (ulRet < 0)
  725. return MAPI_E_CALL_FAILED;
  726. return hrSuccess;
  727. }
  728. /**
  729. * Converts WEBDAVPROPNAME to xml data
  730. * @param[in] xmlWriter xml writer to write xml data
  731. * @param[in] sWebPropName sWebPropName structure to be written into xml
  732. * @param[in] lpstrNsPrefix current namespace prefix
  733. * @return HRESULT
  734. */
  735. HRESULT WebDav::WriteNode(xmlTextWriter *xmlWriter,
  736. const WEBDAVPROPNAME &sWebPropName, std::string *lpstrNsPrefix)
  737. {
  738. std::string strNs;
  739. int ulRet;
  740. HRESULT hr;
  741. strNs = sWebPropName.strNS;
  742. if(strNs.empty())
  743. {
  744. ulRet = xmlTextWriterStartElement(xmlWriter,
  745. (const xmlChar *)sWebPropName.strPropname.c_str());
  746. if (ulRet < 0)
  747. return MAPI_E_CALL_FAILED;
  748. return hrSuccess;
  749. }
  750. hr = GetNs(lpstrNsPrefix, &strNs);
  751. if (hr != hrSuccess)
  752. RegisterNs(strNs, lpstrNsPrefix);
  753. /*Write Xml data of the form
  754. * <D:propstat>
  755. * the end tag </D:propstat> is written by "xmlTextWriterEndElement(xmlWriter)"
  756. */
  757. ulRet = xmlTextWriterStartElementNS (xmlWriter,
  758. (const xmlChar *)lpstrNsPrefix->c_str(),
  759. (const xmlChar *)sWebPropName.strPropname.c_str(),
  760. (const xmlChar *)(strNs.empty() ? NULL : strNs.c_str()));
  761. if (ulRet < 0)
  762. return MAPI_E_CALL_FAILED;
  763. if (!sWebPropName.strPropAttribName.empty()) {
  764. ulRet = xmlTextWriterWriteAttribute(xmlWriter, (const xmlChar *)sWebPropName.strPropAttribName.c_str(), (const xmlChar *) sWebPropName.strPropAttribValue.c_str());
  765. if (ulRet < 0)
  766. return MAPI_E_CALL_FAILED;
  767. }
  768. return hrSuccess;
  769. }
  770. /**
  771. * Adds namespace prefix into map of namespaces
  772. * @param[in] strNs Namespace name
  773. * @param[in] lpstrNsPrefix Namespace prefix
  774. * @return HRESULT Always returns hrSuccess
  775. */
  776. void WebDav::RegisterNs(const std::string &strNs, std::string *lpstrNsPrefix)
  777. {
  778. (*lpstrNsPrefix)[0]++;
  779. m_mapNs[strNs] = *lpstrNsPrefix;
  780. }
  781. /**
  782. * Returns the namespace prefix for the corresponding namespace name
  783. * @param[in,out] lpstrPrefx Return string for namespace prefix
  784. * @param[in,out] lpstrNs Namespace name, is set to empty string if namespace prefix found
  785. * @return HRESULT
  786. * @retval MAPI_E_NOT_FOUND Namespace prefix not found
  787. */
  788. HRESULT WebDav::GetNs(std::string * lpstrPrefx, std::string *lpstrNs)
  789. {
  790. HRESULT hr = hrSuccess;
  791. auto itMpNs = m_mapNs.find(*lpstrNs);
  792. if (itMpNs != m_mapNs.cend()) {
  793. lpstrPrefx->assign(itMpNs->second);
  794. lpstrNs->clear();
  795. }
  796. else
  797. hr = MAPI_E_NOT_FOUND;
  798. return hr;
  799. }
  800. /**
  801. * Converts WEBDAVRESPONSE structure to xml data
  802. *
  803. * @param[in] xmlWriter xml writer to write xml data
  804. * @param[in] lpstrNsPrefix Pointer to string containing the current namespace prefix
  805. * @param[in] sResponse WEBDAVRESPONSE structure to be converted to xml data
  806. * @return HRESULT
  807. */
  808. HRESULT WebDav::HrWriteSResponse(xmlTextWriter *xmlWriter,
  809. std::string *lpstrNsPrefix, const WEBDAVRESPONSE &sResponse)
  810. {
  811. HRESULT hr;
  812. WEBDAVRESPONSE sWebResp;
  813. int ulRet;
  814. sWebResp = sResponse;
  815. // <response>
  816. hr = WriteNode(xmlWriter, sWebResp.sPropName, lpstrNsPrefix);
  817. if (hr != hrSuccess)
  818. return hr;
  819. // <href>xxxxxxxxxxxxxxxx</href>
  820. if (!sWebResp.sHRef.sPropName.strPropname.empty()) {
  821. hr = WriteData(xmlWriter, sWebResp.sHRef, lpstrNsPrefix);
  822. if (hr != hrSuccess)
  823. return hr;
  824. }
  825. // Only set for broken calendar entries
  826. // <D:status>HTTP/1.1 404 Not Found</D:status>
  827. if (!sWebResp.sStatus.sPropName.strPropname.empty()) {
  828. hr = WriteData(xmlWriter,sWebResp.sStatus , lpstrNsPrefix);
  829. if (hr != hrSuccess)
  830. return hr;
  831. }
  832. for (const auto &stat : sWebResp.lstsPropStat) {
  833. hr = HrWriteSPropStat(xmlWriter, lpstrNsPrefix, stat);
  834. if (hr != hrSuccess)
  835. return hr;
  836. }
  837. if (!sWebResp.lstProps.empty())
  838. {
  839. hr = HrWriteResponseProps(xmlWriter, lpstrNsPrefix, &(sWebResp.lstProps));
  840. if (hr != hrSuccess)
  841. return hr;
  842. }
  843. //</response>
  844. ulRet = xmlTextWriterEndElement(xmlWriter);
  845. if (ulRet < 0)
  846. return MAPI_E_CALL_FAILED;
  847. return hrSuccess;
  848. }
  849. /**
  850. * Converts WEBDAVPROPERTY list to xml data
  851. *
  852. * @param[in] xmlWriter xml writer to write xml data
  853. * @param[in] lpstrNsPrefix Pointer to string containing the current namespace prefix
  854. * @param[in] lplstProps WEBDAVPROPERTY list to be converted to xml data
  855. * @return HRESULT
  856. */
  857. HRESULT WebDav::HrWriteResponseProps(xmlTextWriter *xmlWriter,
  858. std::string *lpstrNsPrefix, std::list<WEBDAVPROPERTY> *lplstProps)
  859. {
  860. HRESULT hr;
  861. int ulRet;
  862. for (const auto &iterProp : *lplstProps) {
  863. auto sWebProperty = iterProp;
  864. if (!sWebProperty.strValue.empty())
  865. {
  866. WEBDAVVALUE sWebVal;
  867. sWebVal.sPropName = sWebProperty.sPropName;
  868. sWebVal.strValue = sWebProperty.strValue;
  869. //<getctag xmlns="xxxxxxxxxxx">xxxxxxxxxxxxxxxxx</getctag>
  870. hr = WriteData(xmlWriter,sWebVal,lpstrNsPrefix);
  871. }
  872. else
  873. { //<resourcetype>
  874. hr = WriteNode(xmlWriter, sWebProperty.sPropName,lpstrNsPrefix);
  875. }
  876. if (hr != hrSuccess)
  877. return hr;
  878. //loop for sub properties
  879. for (int k = 0; !sWebProperty.lstValues.empty(); ++k) {
  880. WEBDAVVALUE sWebVal;
  881. sWebVal = sWebProperty.lstValues.front();
  882. //<collection/>
  883. if (!sWebVal.strValue.empty()) {
  884. hr = WriteData(xmlWriter, sWebVal, lpstrNsPrefix);
  885. if (hr != hrSuccess)
  886. return hr;
  887. } else {
  888. hr = WriteNode(xmlWriter, sWebVal.sPropName, lpstrNsPrefix);
  889. if (hr != hrSuccess)
  890. return hr;
  891. ulRet = xmlTextWriterEndElement(xmlWriter);
  892. if (ulRet < 0)
  893. return MAPI_E_CALL_FAILED;
  894. }
  895. sWebProperty.lstValues.pop_front();
  896. }
  897. if (sWebProperty.strValue.empty()) {
  898. ulRet = xmlTextWriterEndElement(xmlWriter);
  899. if (ulRet < 0)
  900. return MAPI_E_CALL_FAILED;
  901. }
  902. }
  903. return hrSuccess;
  904. }
  905. /**
  906. * Converts WEBDAVPROPSTAT structure to xml data
  907. *
  908. * @param[in] xmlWriter xml writer to write xml data
  909. * @param[in] lpstrNsPrefix Pointer to string containing the current namespace prefix
  910. * @param[in] lpsPropStat WEBDAVPROPSTAT structure to be converted to xml data
  911. * @return HRESULT
  912. */
  913. HRESULT WebDav::HrWriteSPropStat(xmlTextWriter *xmlWriter,
  914. std::string *lpstrNsPrefix, const WEBDAVPROPSTAT &lpsPropStat)
  915. {
  916. HRESULT hr;
  917. WEBDAVPROPSTAT sWebPropStat;
  918. WEBDAVPROP sWebProp;
  919. int ulRet;
  920. sWebPropStat = lpsPropStat;
  921. //<propstat>
  922. hr = WriteNode(xmlWriter, sWebPropStat.sPropName,lpstrNsPrefix);
  923. if (hr != hrSuccess)
  924. return hr;
  925. sWebProp = sWebPropStat.sProp;
  926. //<prop>
  927. hr = WriteNode(xmlWriter, sWebProp.sPropName,lpstrNsPrefix);
  928. if (hr != hrSuccess)
  929. return hr;
  930. //loop for properties list
  931. for (const auto &iterProp : sWebProp.lstProps) {
  932. auto sWebProperty = iterProp;
  933. if (!sWebProperty.strValue.empty())
  934. {
  935. WEBDAVVALUE sWebVal;
  936. sWebVal.sPropName = sWebProperty.sPropName;
  937. sWebVal.strValue = sWebProperty.strValue;
  938. //<getctag xmlns="xxxxxxxxxxx">xxxxxxxxxxxxxxxxx</getctag>
  939. hr = WriteData(xmlWriter,sWebVal,lpstrNsPrefix);
  940. }
  941. else
  942. { //<resourcetype>
  943. hr = WriteNode(xmlWriter, sWebProperty.sPropName,lpstrNsPrefix);
  944. }
  945. if (hr != hrSuccess)
  946. return hr;
  947. if (!sWebProperty.lstItems.empty()) {
  948. hr = HrWriteItems(xmlWriter, lpstrNsPrefix, &sWebProperty);
  949. if (hr != hrSuccess)
  950. return hr;
  951. }
  952. //loop for sub properties
  953. for (int k = 0; !sWebProperty.lstValues.empty(); ++k)
  954. {
  955. WEBDAVVALUE sWebVal;
  956. sWebVal = sWebProperty.lstValues.front();
  957. //<collection/>
  958. if (!sWebVal.strValue.empty()) {
  959. hr = WriteData(xmlWriter,sWebVal,lpstrNsPrefix);
  960. if (hr != hrSuccess)
  961. return hr;
  962. } else {
  963. hr = WriteNode(xmlWriter, sWebVal.sPropName, lpstrNsPrefix);
  964. if (hr != hrSuccess)
  965. return hr;
  966. ulRet = xmlTextWriterEndElement(xmlWriter);
  967. if (ulRet < 0)
  968. return MAPI_E_CALL_FAILED;
  969. }
  970. sWebProperty.lstValues.pop_front();
  971. }
  972. //end tag if started
  973. //</resourcetype>
  974. if (sWebProperty.strValue.empty()) {
  975. ulRet = xmlTextWriterEndElement(xmlWriter);
  976. if (ulRet < 0)
  977. return MAPI_E_CALL_FAILED;
  978. }
  979. }
  980. //</prop>
  981. ulRet = xmlTextWriterEndElement(xmlWriter);
  982. if (ulRet < 0)
  983. return MAPI_E_CALL_FAILED;
  984. //<status xmlns="xxxxxxx">HTTP/1.1 200 OK</status>
  985. hr = WriteData(xmlWriter,sWebPropStat.sStatus,lpstrNsPrefix);
  986. // ending the function here on !hrSuccess breaks several tests.
  987. //</propstat>
  988. ulRet = xmlTextWriterEndElement(xmlWriter);
  989. if (ulRet < 0)
  990. return MAPI_E_CALL_FAILED;
  991. return hrSuccess;
  992. }
  993. /**
  994. * Converts Items List to xml data
  995. *
  996. * @param[in] xmlWriter xml writer to write xml data
  997. * @param[in] lpstrNsPrefix Pointer to string containing the current namespace prefix
  998. * @param[in] lpsWebProperty WEBDAVPROPERTY structure containing the list of items
  999. * @return HRESULT Always returns hrSuccess
  1000. */
  1001. HRESULT WebDav::HrWriteItems(xmlTextWriter *xmlWriter,
  1002. std::string *lpstrNsPrefix, WEBDAVPROPERTY *lpsWebProperty)
  1003. {
  1004. HRESULT hr;
  1005. WEBDAVITEM sDavItem;
  1006. ULONG ulDepthPrev = 0;
  1007. ULONG ulDepthCur = 0;
  1008. bool blFirst = true;
  1009. ulDepthPrev = lpsWebProperty->lstItems.front().ulDepth;
  1010. while(!lpsWebProperty->lstItems.empty())
  1011. {
  1012. sDavItem = lpsWebProperty->lstItems.front();
  1013. ulDepthCur = sDavItem.ulDepth;
  1014. if(ulDepthCur >= ulDepthPrev)
  1015. {
  1016. if(ulDepthCur == ulDepthPrev && !blFirst && sDavItem.sDavValue.sPropName.strPropname != "ace")
  1017. if (xmlTextWriterEndElement(xmlWriter) < 0)
  1018. return MAPI_E_CALL_FAILED;
  1019. blFirst = false;
  1020. if (!sDavItem.sDavValue.strValue.empty())
  1021. {
  1022. hr = WriteData(xmlWriter, sDavItem.sDavValue, lpstrNsPrefix);
  1023. sDavItem.ulDepth = sDavItem.ulDepth - 1;
  1024. }
  1025. else
  1026. {
  1027. //<resourcetype>
  1028. hr = WriteNode(xmlWriter, sDavItem.sDavValue.sPropName, lpstrNsPrefix);
  1029. }
  1030. if (hr != hrSuccess)
  1031. return MAPI_E_CALL_FAILED;
  1032. }
  1033. else
  1034. {
  1035. for (ULONG i = ulDepthCur; i <= ulDepthPrev; ++i)
  1036. if (xmlTextWriterEndElement(xmlWriter) < 0)
  1037. return MAPI_E_CALL_FAILED;
  1038. if (!sDavItem.sDavValue.strValue.empty())
  1039. {
  1040. hr = WriteData(xmlWriter, sDavItem.sDavValue, lpstrNsPrefix);
  1041. sDavItem.ulDepth = sDavItem.ulDepth - 1;
  1042. }
  1043. else
  1044. {
  1045. //<resourcetype>
  1046. hr = WriteNode(xmlWriter, sDavItem.sDavValue.sPropName, lpstrNsPrefix);
  1047. }
  1048. if (hr != hrSuccess)
  1049. return hr;
  1050. }
  1051. ulDepthPrev = sDavItem.ulDepth;
  1052. lpsWebProperty->lstItems.pop_front();
  1053. }
  1054. for (ULONG i = 0; i <= ulDepthPrev; ++i)
  1055. if (xmlTextWriterEndElement(xmlWriter) < 0)
  1056. return MAPI_E_CALL_FAILED;
  1057. return hrSuccess;
  1058. }
  1059. /**
  1060. * Set Name and namespace to WEBDAVPROPNAME structure from xmlNode
  1061. *
  1062. * The structure contains information about a xml element
  1063. *
  1064. * @param[in] lpsDavPropName Strutcture to which all the values are set
  1065. * @param[in] lpXmlNode Pointer to xmlNode object, it contains name and namespace
  1066. *
  1067. * @return HRESULT Always returns hrsuccess
  1068. */
  1069. void WebDav::HrSetDavPropName(WEBDAVPROPNAME *lpsDavPropName, xmlNode *lpXmlNode)
  1070. {
  1071. lpsDavPropName->strPropname.assign((const char*)lpXmlNode->name);
  1072. if (lpXmlNode->ns != NULL && lpXmlNode->ns->href != NULL)
  1073. lpsDavPropName->strNS.assign(reinterpret_cast<const char *>(lpXmlNode->ns->href));
  1074. else
  1075. lpsDavPropName->strNS.clear();
  1076. if(!lpsDavPropName->strNS.empty())
  1077. m_mapNs[lpsDavPropName->strNS] = "";
  1078. lpsDavPropName->strPropAttribName = "";
  1079. lpsDavPropName->strPropAttribValue = "";
  1080. }
  1081. /**
  1082. * Set Name and namespace to WEBDAVPROPNAME structure
  1083. *
  1084. * The structure contains information about a xml element
  1085. *
  1086. * @param[in] lpsDavPropName Strutcture to which all the values are set
  1087. * @param[in] strPropName Name of the element
  1088. * @param[in] strNs Namespace of the element
  1089. *
  1090. * @return HRESULT Always returns hrsuccess
  1091. */
  1092. void WebDav::HrSetDavPropName(WEBDAVPROPNAME *lpsDavPropName,
  1093. const std::string &strPropName, const std::string &strNs)
  1094. {
  1095. lpsDavPropName->strPropname.assign(strPropName);
  1096. lpsDavPropName->strNS.assign(strNs);
  1097. if (!lpsDavPropName->strNS.empty())
  1098. m_mapNs[lpsDavPropName->strNS].clear();
  1099. lpsDavPropName->strPropAttribName.clear();
  1100. lpsDavPropName->strPropAttribValue.clear();
  1101. }
  1102. /**
  1103. * Set Name, attribute and namespace to WEBDAVPROPNAME structure
  1104. *
  1105. * The structure contains information about a xml element
  1106. *
  1107. * @param[in] lpsDavPropName Strutcture to which all the values are set
  1108. * @param[in] strPropName Name of the element
  1109. * @param[in] strPropAttribName Attribute's name to be set in the element
  1110. * @param[in] strPropAttribValue Attribute's value to be set in the element
  1111. * @param[in] strNs Namespace of the element
  1112. *
  1113. * @return HRESULT Always returns hrsuccess
  1114. */
  1115. void WebDav::HrSetDavPropName(WEBDAVPROPNAME *lpsDavPropName,
  1116. const std::string &strPropName, const std::string &strPropAttribName,
  1117. const std::string &strPropAttribValue, const std::string &strNs)
  1118. {
  1119. lpsDavPropName->strPropname.assign(strPropName);
  1120. lpsDavPropName->strNS.assign(strNs);
  1121. lpsDavPropName->strPropAttribName = strPropAttribName;
  1122. lpsDavPropName->strPropAttribValue = strPropAttribValue;
  1123. if (!lpsDavPropName->strNS.empty())
  1124. m_mapNs[lpsDavPropName->strNS] = "";
  1125. }
  1126. /**
  1127. * Parse the PROPPATCH xml request
  1128. *
  1129. * @return HRESULT
  1130. * @retval MAPI_E_CORRUPT_DATA Invalid xml data in request
  1131. * @retval MAPI_E_NO_ACCESS Not enough permissions to edit folder names or comments
  1132. * @retval MAPI_E_COLLISION A folder with same name already exists
  1133. */
  1134. HRESULT WebDav::HrPropPatch()
  1135. {
  1136. HRESULT hr = hrSuccess;
  1137. WEBDAVPROP sDavProp;
  1138. WEBDAVMULTISTATUS sDavMStatus;
  1139. std::string strFldPath;
  1140. std::string strXml;
  1141. xmlNode * lpXmlNode = NULL;
  1142. //libxml parser parses the xml data and returns the DomTree pointer.
  1143. hr = HrParseXml();
  1144. if (hr != hrSuccess)
  1145. goto exit;
  1146. lpXmlNode = xmlDocGetRootElement(m_lpXmlDoc);
  1147. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"propertyupdate"))
  1148. {
  1149. hr = MAPI_E_CORRUPT_DATA;
  1150. goto exit;
  1151. }
  1152. lpXmlNode = lpXmlNode->children;
  1153. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"set"))
  1154. {
  1155. hr = MAPI_E_CORRUPT_DATA;
  1156. goto exit;
  1157. }
  1158. lpXmlNode = lpXmlNode->children;
  1159. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"prop"))
  1160. {
  1161. hr = MAPI_E_CORRUPT_DATA;
  1162. goto exit;
  1163. }
  1164. if(lpXmlNode->ns && lpXmlNode->ns->href)
  1165. HrSetDavPropName(&(sDavProp.sPropName),"prop",(char *)lpXmlNode->ns->href);
  1166. else
  1167. HrSetDavPropName(&(sDavProp.sPropName),"prop", WEBDAVNS);
  1168. lpXmlNode = lpXmlNode->children;
  1169. while(lpXmlNode)
  1170. {
  1171. WEBDAVPROPERTY sProperty;
  1172. if(lpXmlNode->ns && lpXmlNode->ns->href)
  1173. HrSetDavPropName(&(sProperty.sPropName),(char *)lpXmlNode->name,(char*)lpXmlNode->ns->href);
  1174. else
  1175. HrSetDavPropName(&(sProperty.sPropName),(char *)lpXmlNode->name, WEBDAVNS);
  1176. if (lpXmlNode->children != nullptr &&
  1177. lpXmlNode->children->content != nullptr)
  1178. sProperty.strValue = (char *)lpXmlNode->children->content;
  1179. sDavProp.lstProps.push_back(std::move(sProperty));
  1180. lpXmlNode = lpXmlNode->next;
  1181. }
  1182. hr = HrHandlePropPatch(&sDavProp, &sDavMStatus);
  1183. if (hr != hrSuccess)
  1184. goto exit;
  1185. // Convert WEBMULTISTATUS structure to xml data.
  1186. hr = RespStructToXml(&sDavMStatus, &strXml);
  1187. if (hr != hrSuccess)
  1188. {
  1189. ec_log_debug("Unable to convert response to xml: 0x%08X", hr);
  1190. goto exit;
  1191. }
  1192. exit:
  1193. if (hr != hrSuccess) {
  1194. // this is important for renaming your calendar folder
  1195. if (hr == MAPI_E_COLLISION)
  1196. m_lpRequest->HrResponseHeader(409, "Conflict");
  1197. else
  1198. m_lpRequest->HrResponseHeader(403, "Forbidden");
  1199. } else {
  1200. m_lpRequest->HrResponseHeader(207 , "Multi-Status");
  1201. m_lpRequest->HrResponseHeader("Content-Type", "application/xml; charset=\"utf-8\"");
  1202. m_lpRequest->HrResponseBody(strXml);
  1203. }
  1204. return hr;
  1205. }
  1206. /**
  1207. * Handle xml parsing for MKCALENDAR request
  1208. *
  1209. * @return HRESULT
  1210. * @retval MAPI_E_CORRUPT_DATA Invalid xml request
  1211. * @retval MAPI_E_COLLISION Folder with same name exists
  1212. * @retval MAPI_E_NO_ACCESS Not enough permissions to create a folder
  1213. */
  1214. // input url: /caldav/username/7F2A8EB0-5E2C-4EB7-8B46-6ECBFE91BA3F/
  1215. /* input xml:
  1216. <x0:mkcalendar xmlns:x1="DAV:" xmlns:x2="http://apple.com/ns/ical/" xmlns:x0="urn:ietf:params:xml:ns:caldav">
  1217. <x1:set>
  1218. <x1:prop>
  1219. <x1:displayname>Untitled</x1:displayname>
  1220. <x2:calendar-color>#492BA1FF</x2:calendar-color>
  1221. <x2:calendar-order>9</x2:calendar-order>
  1222. <x0:calendar-free-busy-set><YES/></x0:calendar-free-busy-set>
  1223. <x0:calendar-timezone> ... ical timezone data snipped ... </x0:calendar-timezone>
  1224. </x1:prop>
  1225. </x1:set>
  1226. </x0:mkcalendar>
  1227. */
  1228. HRESULT WebDav::HrMkCalendar()
  1229. {
  1230. HRESULT hr = hrSuccess;
  1231. xmlNode * lpXmlNode = NULL;
  1232. WEBDAVPROP sDavProp;
  1233. hr = HrParseXml();
  1234. if(hr != hrSuccess)
  1235. {
  1236. ec_log_err("Parsing Error For MKCALENDAR");
  1237. goto exit;
  1238. }
  1239. lpXmlNode = xmlDocGetRootElement(m_lpXmlDoc);
  1240. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"mkcalendar"))
  1241. {
  1242. hr = MAPI_E_CORRUPT_DATA;
  1243. goto exit;
  1244. }
  1245. lpXmlNode = lpXmlNode->children;
  1246. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"set"))
  1247. {
  1248. hr = MAPI_E_CORRUPT_DATA;
  1249. goto exit;
  1250. }
  1251. lpXmlNode = lpXmlNode->children;
  1252. if (!lpXmlNode || !lpXmlNode->name || xmlStrcmp(lpXmlNode->name, (const xmlChar *)"prop"))
  1253. {
  1254. hr = MAPI_E_CORRUPT_DATA;
  1255. goto exit;
  1256. }
  1257. if(lpXmlNode->ns && lpXmlNode->ns->href)
  1258. HrSetDavPropName(&(sDavProp.sPropName),(char*)lpXmlNode->name,(char*)lpXmlNode->ns->href);
  1259. else
  1260. HrSetDavPropName(&(sDavProp.sPropName),(char*)lpXmlNode->name,WEBDAVNS);
  1261. lpXmlNode = lpXmlNode->children;
  1262. while(lpXmlNode)
  1263. {
  1264. WEBDAVPROPERTY sProperty;
  1265. if (lpXmlNode->ns && lpXmlNode->ns->href)
  1266. HrSetDavPropName(&(sProperty.sPropName),(char*)lpXmlNode->name,(char*)lpXmlNode->ns->href);
  1267. else
  1268. HrSetDavPropName(&(sProperty.sPropName),(char*)lpXmlNode->name,WEBDAVNS);
  1269. if (lpXmlNode->children && lpXmlNode->children->content)
  1270. sProperty.strValue = (char*)lpXmlNode->children->content;
  1271. // @todo we should have a generic xml to structs converter, this is *way* too hackish
  1272. if (sProperty.sPropName.strPropname.compare("supported-calendar-component-set") == 0) {
  1273. xmlNode *lpXmlChild = lpXmlNode->children;
  1274. while (lpXmlChild) {
  1275. if (lpXmlChild->type == XML_ELEMENT_NODE &&
  1276. xmlStrcmp(lpXmlChild->name, reinterpret_cast<const xmlChar *>("comp")) == 0 &&
  1277. lpXmlChild->properties != nullptr &&
  1278. lpXmlChild->properties->children != nullptr &&
  1279. lpXmlChild->properties->children->content != nullptr)
  1280. sProperty.strValue = reinterpret_cast<char *>(lpXmlChild->properties->children->content);
  1281. lpXmlChild = lpXmlChild->next;
  1282. }
  1283. }
  1284. sDavProp.lstProps.push_back(std::move(sProperty));
  1285. lpXmlNode = lpXmlNode->next;
  1286. }
  1287. hr = HrHandleMkCal(&sDavProp);
  1288. exit:
  1289. if(hr == MAPI_E_COLLISION)
  1290. {
  1291. m_lpRequest->HrResponseHeader(409,"CONFLICT");
  1292. m_lpRequest->HrResponseBody("Folder with same name already exists");
  1293. }
  1294. else if(hr == MAPI_E_NO_ACCESS)
  1295. m_lpRequest->HrResponseHeader(403 ,"Forbidden");
  1296. else if(hr == hrSuccess)
  1297. m_lpRequest->HrResponseHeader(201,"Created");
  1298. else
  1299. m_lpRequest->HrResponseHeader(500,"Bad Request");
  1300. return hr;
  1301. }