typeconversion.cpp 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182
  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 "phpconfig.h"
  18. #include <kopano/platform.h>
  19. #include <cmath>
  20. #include <mapiutil.h>
  21. extern "C" {
  22. // Remove these defines to remove warnings
  23. #undef PACKAGE_VERSION
  24. #undef PACKAGE_TARNAME
  25. #undef PACKAGE_NAME
  26. #undef PACKAGE_STRING
  27. #undef PACKAGE_BUGREPORT
  28. #include "php.h"
  29. #include "php_globals.h"
  30. #include "ext/standard/info.h"
  31. #include "ext/standard/php_string.h"
  32. #ifdef ZTS
  33. void*** tsrm_ls;
  34. #endif
  35. }
  36. #undef inline
  37. #include <mapi.h>
  38. #include <mapix.h>
  39. #include <mapidefs.h>
  40. #include <mapitags.h>
  41. #include <mapicode.h>
  42. #include <edkmdb.h>
  43. #include "typeconversion.h"
  44. #include <kopano/charset/convert.h>
  45. // Calls MAPIAllocateMore or MAPIAllocateBuffer according to whether an lpBase was passed or not
  46. #define MAPI_ALLOC(n, lpBase, lpp) (lpBase ? MAPIAllocateMore(n, lpBase, lpp) : MAPIAllocateBuffer(n, lpp))
  47. // Frees the buffer with MAPIFreeBuffer if lpBase is NOT set, we can't directly free data allocated with MAPIAllocateMore ..
  48. #define MAPI_FREE(lpbase, lpp) { if(!lpBase) MAPIFreeBuffer(lpp); }
  49. ZEND_EXTERN_MODULE_GLOBALS(mapi)
  50. static LONG PropTagToPHPTag(ULONG ulPropTag) {
  51. LONG PHPTag = 0;
  52. if (PROP_TYPE(ulPropTag) == PT_UNICODE)
  53. PHPTag = (LONG)CHANGE_PROP_TYPE(ulPropTag, PT_STRING8);
  54. else if (PROP_TYPE(ulPropTag) == PT_MV_UNICODE)
  55. PHPTag = (LONG)CHANGE_PROP_TYPE(ulPropTag, PT_MV_STRING8);
  56. else
  57. PHPTag = (LONG)ulPropTag;
  58. return PHPTag;
  59. }
  60. /*
  61. * Converts a PHP Array into a SBinaryArray. This is the same as an ENTRYLIST which
  62. * is used with DeleteMessages();
  63. *
  64. */
  65. HRESULT PHPArraytoSBinaryArray(zval * entryid_array , void *lpBase, SBinaryArray *lpBinaryArray TSRMLS_DC)
  66. {
  67. // local
  68. HashTable *target_hash = NULL;
  69. int count;
  70. zval **ppentry = NULL;
  71. zval *pentry = NULL;
  72. int i, n = 0;
  73. MAPI_G(hr) = hrSuccess;
  74. target_hash = HASH_OF(entryid_array);
  75. if (!target_hash) {
  76. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No target_hash in PHPArraytoSBinaryArray");
  77. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  78. return MAPI_G(hr);
  79. }
  80. count = zend_hash_num_elements(Z_ARRVAL_P(entryid_array));
  81. if (count == 0) {
  82. lpBinaryArray->lpbin = NULL;
  83. lpBinaryArray->cValues = 0;
  84. return MAPI_G(hr);
  85. }
  86. MAPI_G(hr) = MAPIAllocateMore(sizeof(SBinary) * count, lpBase, (void **) &lpBinaryArray->lpbin);
  87. if(MAPI_G(hr) != hrSuccess)
  88. return MAPI_G(hr);
  89. // Reset php pointer
  90. zend_hash_internal_pointer_reset(target_hash);
  91. for (i = 0; i < count; ++i) {
  92. zend_hash_get_current_data(target_hash, (void **) &ppentry);
  93. pentry = *ppentry;
  94. convert_to_string_ex(&pentry);
  95. MAPI_G(hr) = MAPIAllocateMore(pentry->value.str.len, lpBase, (void **) &lpBinaryArray->lpbin[n].lpb);
  96. if(MAPI_G(hr) != hrSuccess)
  97. return MAPI_G(hr);
  98. memcpy(lpBinaryArray->lpbin[n].lpb, pentry->value.str.val, pentry->value.str.len);
  99. lpBinaryArray->lpbin[n++].cb = pentry->value.str.len;
  100. zend_hash_move_forward(target_hash);
  101. }
  102. lpBinaryArray->cValues = n;
  103. return MAPI_G(hr);
  104. }
  105. HRESULT PHPArraytoSBinaryArray(zval * entryid_array , void *lpBase, SBinaryArray **lppBinaryArray TSRMLS_DC)
  106. {
  107. SBinaryArray *lpBinaryArray = NULL;
  108. MAPI_G(hr) = MAPI_ALLOC(sizeof(SBinaryArray), lpBase, (void **)&lpBinaryArray);
  109. if(MAPI_G(hr) != hrSuccess)
  110. return MAPI_G(hr);
  111. MAPI_G(hr) = PHPArraytoSBinaryArray(entryid_array, lpBase ? lpBase : lpBinaryArray, lpBinaryArray TSRMLS_CC);
  112. if(MAPI_G(hr) != hrSuccess) {
  113. MAPI_FREE(lpBase, lpBinaryArray);
  114. return MAPI_G(hr);
  115. }
  116. *lppBinaryArray = lpBinaryArray;
  117. return MAPI_G(hr);
  118. }
  119. HRESULT SBinaryArraytoPHPArray(SBinaryArray *lpBinaryArray, zval **ppvalRet TSRMLS_DC)
  120. {
  121. unsigned int i = 0;
  122. MAPI_G(hr) = hrSuccess;
  123. zval *pvalRet;
  124. MAKE_STD_ZVAL(pvalRet);
  125. array_init(pvalRet);
  126. for (i = 0; i < lpBinaryArray->cValues; ++i)
  127. add_next_index_stringl(pvalRet, (char *)lpBinaryArray->lpbin[i].lpb, lpBinaryArray->lpbin[i].cb, 1);
  128. *ppvalRet = pvalRet;
  129. return MAPI_G(hr);
  130. }
  131. /*
  132. * Converts a PHP Array into a SortOrderSet. This SortOrderSet is used to sort a table
  133. * when a call to IMAPITable->QueryRows is made.
  134. * The zval array will look like this:
  135. * array() {
  136. * PR_SUBJECT => TABLE_SORT_ASCEND,
  137. * etc..
  138. * }
  139. *
  140. * The key is the property and the value is the sorting method for that property
  141. *
  142. * NOTE: The TABLE_SORT_COMBINE is not (yet) implemented, it should work but is not tested
  143. */
  144. HRESULT PHPArraytoSortOrderSet(zval * sortorder_array, void *lpBase, LPSSortOrderSet *lppSortOrderSet TSRMLS_DC)
  145. {
  146. // local
  147. LPSSortOrderSet lpSortOrderSet = NULL;
  148. int count;
  149. HashTable *target_hash = NULL;
  150. zval **entry = NULL;
  151. MAPI_G(hr) = hrSuccess;
  152. target_hash = HASH_OF(sortorder_array);
  153. if (!target_hash) {
  154. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No target_hash in PHPArraytoSortOrderSet");
  155. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  156. }
  157. // get the number of items in the array
  158. count = zend_hash_num_elements(Z_ARRVAL_P(sortorder_array));
  159. MAPI_G(hr) = MAPI_ALLOC(CbNewSSortOrderSet(count), lpBase, (void **) &lpSortOrderSet);
  160. if(MAPI_G(hr) != hrSuccess)
  161. return MAPI_G(hr);
  162. lpSortOrderSet->cSorts = count;
  163. lpSortOrderSet->cCategories = 0;
  164. lpSortOrderSet->cExpanded = 0;
  165. // first reset the hash, so the pointer points to the first element.
  166. zend_hash_internal_pointer_reset(target_hash);
  167. for (int i = 0; i < count; ++i) {
  168. //todo: check on FAILURE
  169. char *key = NULL;
  170. ulong ind = 0;
  171. zend_hash_get_current_data(target_hash, (void **) &entry);
  172. // when the key is a char &key is set else ind is set
  173. zend_hash_get_current_key(target_hash, &key, &ind, 0);
  174. if (key != NULL)
  175. lpSortOrderSet->aSort[i].ulPropTag = atoi(key);
  176. else
  177. lpSortOrderSet->aSort[i].ulPropTag = ind;
  178. convert_to_long_ex(&entry[0]);
  179. lpSortOrderSet->aSort[i].ulOrder = (ULONG) entry[0]->value.lval;
  180. // get next hash pointer
  181. zend_hash_move_forward(target_hash);
  182. }
  183. *lppSortOrderSet = lpSortOrderSet;
  184. return MAPI_G(hr);
  185. }
  186. /**
  187. * Converts a php array to a PropTagArray.
  188. * The caller is responsible to free the memory using MAPIFreeBuffer
  189. */
  190. HRESULT PHPArraytoPropTagArray(zval * prop_value_array, void *lpBase, LPSPropTagArray *lppPropTagArray TSRMLS_DC)
  191. {
  192. // return value
  193. LPSPropTagArray lpPropTagArray = NULL;
  194. // local
  195. int count;
  196. HashTable *target_hash = NULL;
  197. zval ** entry = NULL;
  198. MAPI_G(hr) = hrSuccess;
  199. target_hash = HASH_OF(prop_value_array);
  200. if (!target_hash) {
  201. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No target_hash in PHPArraytoPropTagArray");
  202. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  203. }
  204. // get the number of items in the array
  205. count = zend_hash_num_elements(target_hash);
  206. // allocate memory to use
  207. MAPI_G(hr) = MAPI_ALLOC(CbNewSPropTagArray(count), lpBase, (void **)&lpPropTagArray);
  208. if (MAPI_G(hr) != hrSuccess)
  209. return MAPI_G(hr);
  210. lpPropTagArray->cValues = count;
  211. // first reset the hash, so the pointer points to the first element.
  212. zend_hash_internal_pointer_reset(target_hash);
  213. for (int i = 0; i < count; ++i) {
  214. // Gets the element that exist at the current pointer.
  215. zend_hash_get_current_data(target_hash, (void **) &entry);
  216. convert_to_long_ex(entry);
  217. lpPropTagArray->aulPropTag[i] = entry[0]->value.lval;
  218. // move the pointer to the next entry
  219. zend_hash_move_forward(target_hash);
  220. }
  221. *lppPropTagArray = lpPropTagArray;
  222. return MAPI_G(hr);
  223. }
  224. /*
  225. * Converts a PHP property value array to a MAPI property value structure
  226. */
  227. HRESULT PHPArraytoPropValueArray(zval* phpArray, void *lpBase, ULONG *lpcValues, LPSPropValue *lppPropValArray TSRMLS_DC)
  228. {
  229. // return value
  230. LPSPropValue lpPropValue = NULL;
  231. ULONG cvalues = 0;
  232. // local
  233. int count;
  234. HashTable *target_hash = NULL;
  235. HashTable *dataHash = NULL;
  236. char *keyIndex;
  237. ulong numIndex = 0;
  238. zval **entry = NULL;
  239. ULONG countarray = 0;
  240. zval **dataEntry = NULL;
  241. HashTable *actionHash = NULL;
  242. ULONG j, h;
  243. ACTIONS *lpActions = NULL;
  244. LPSRestriction lpRestriction = NULL;
  245. ULONG ulCountTmp = 0; // temp value
  246. LPSPropValue lpPropTmp = NULL;
  247. if (!phpArray) {
  248. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No phpArray in PHPArraytoPropValueArray");
  249. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  250. }
  251. target_hash = HASH_OF(phpArray);
  252. if (!target_hash) {
  253. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No target_hash in PHPArraytoPropValueArray");
  254. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  255. }
  256. // Get the number of items in the array, also the number of item to use for the LPSPropValue array
  257. count = zend_hash_num_elements(target_hash);
  258. if (count == 0) {
  259. *lppPropValArray = NULL;
  260. *lpcValues = 0;
  261. }
  262. zend_hash_internal_pointer_reset(target_hash);
  263. MAPI_G(hr) = MAPI_ALLOC(sizeof(SPropValue) * count, lpBase, (void**)&lpPropValue);
  264. for (int i = 0; i < count; ++i) {
  265. // Gets the element that exist at the current pointer.
  266. zend_hash_get_current_data(target_hash, (void **) &entry);
  267. zend_hash_get_current_key(target_hash, &keyIndex, &numIndex, 0);
  268. // assume a numeric index
  269. lpPropValue[cvalues].ulPropTag = numIndex;
  270. switch(PROP_TYPE(numIndex)) {
  271. case PT_SHORT:
  272. convert_to_long_ex(entry);
  273. lpPropValue[cvalues++].Value.i = (short)entry[0]->value.lval;
  274. break;
  275. case PT_LONG:
  276. convert_to_long_ex(entry);
  277. lpPropValue[cvalues++].Value.l = entry[0]->value.lval;
  278. break;
  279. case PT_FLOAT:
  280. convert_to_double_ex(entry);
  281. lpPropValue[cvalues++].Value.flt = (float)entry[0]->value.dval;
  282. break;
  283. case PT_DOUBLE:
  284. convert_to_double_ex(entry);
  285. lpPropValue[cvalues++].Value.dbl = entry[0]->value.dval;
  286. break;
  287. case PT_LONGLONG:
  288. convert_to_double_ex(entry);
  289. lpPropValue[cvalues++].Value.li.QuadPart = (LONGLONG)entry[0]->value.dval;
  290. break;
  291. case PT_BOOLEAN:
  292. convert_to_boolean_ex(entry);
  293. // lval will be 1 or 0 for true or false
  294. lpPropValue[cvalues++].Value.b = (unsigned short)entry[0]->value.lval;
  295. break;
  296. case PT_SYSTIME:
  297. convert_to_long_ex(entry);
  298. // convert timestamp to windows FileTime
  299. UnixTimeToFileTime(entry[0]->value.lval, &lpPropValue[cvalues++].Value.ft);
  300. break;
  301. case PT_BINARY:
  302. convert_to_string_ex(entry);
  303. // Allocate and copy data
  304. MAPI_G(hr) = MAPIAllocateMore(entry[0]->value.str.len, lpBase ? lpBase : lpPropValue, (void **)&lpPropValue[cvalues].Value.bin.lpb);
  305. if (MAPI_G(hr) != hrSuccess)
  306. return MAPI_G(hr);
  307. memcpy(lpPropValue[cvalues].Value.bin.lpb, entry[0]->value.str.val, entry[0]->value.str.len);
  308. lpPropValue[cvalues++].Value.bin.cb = entry[0]->value.str.len;
  309. break;
  310. case PT_STRING8:
  311. convert_to_string_ex(entry);
  312. // Allocate and copy data
  313. MAPI_G(hr) = MAPIAllocateMore(entry[0]->value.str.len+1, lpBase ? lpBase : lpPropValue, (void **)&lpPropValue[cvalues].Value.lpszA);
  314. if (MAPI_G(hr) != hrSuccess)
  315. return MAPI_G(hr);
  316. strncpy(lpPropValue[cvalues++].Value.lpszA, entry[0]->value.str.val, entry[0]->value.str.len + 1);
  317. break;
  318. case PT_APPTIME:
  319. convert_to_double_ex(entry);
  320. lpPropValue[cvalues++].Value.at = entry[0]->value.dval;
  321. break;
  322. case PT_CLSID:
  323. convert_to_string_ex(entry);
  324. if (entry[0]->value.str.len != sizeof(GUID)) {
  325. php_error_docref(NULL TSRMLS_CC, E_WARNING, "GUID must be 16 bytes");
  326. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  327. }
  328. MAPI_G(hr) = MAPIAllocateMore(sizeof(GUID), lpBase ? lpBase : lpPropValue, (void **)&lpPropValue[cvalues].Value.lpguid);
  329. if (MAPI_G(hr) != hrSuccess)
  330. return MAPI_G(hr);
  331. memcpy(lpPropValue[cvalues++].Value.lpguid, entry[0]->value.str.val, sizeof(GUID));
  332. break;
  333. #define GET_MV_HASH() \
  334. { \
  335. dataHash = HASH_OF(entry[0]); \
  336. if (!dataHash) { \
  337. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No MV dataHash"); \
  338. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER; \
  339. } \
  340. }
  341. #define CHECK_EMPTY_MV_ARRAY(mapimvmember, mapilpmember) \
  342. { \
  343. countarray = zend_hash_num_elements(dataHash); \
  344. if (countarray == 0) { \
  345. lpPropValue[cvalues].Value.mapimvmember.cValues = 0; \
  346. lpPropValue[cvalues].Value.mapimvmember.mapilpmember = NULL; \
  347. break; \
  348. } \
  349. zend_hash_internal_pointer_reset(dataHash); \
  350. }
  351. #define COPY_MV_PROPS(type, mapimvmember, mapilpmember, phpmember) \
  352. GET_MV_HASH() \
  353. CHECK_EMPTY_MV_ARRAY(mapimvmember, mapilpmember) \
  354. lpPropValue[cvalues].Value.mapimvmember.cValues = countarray; \
  355. MAPI_G(hr) = MAPIAllocateMore(sizeof(lpPropValue[cvalues].Value.mapimvmember.mapilpmember[0]) * countarray, lpBase ? lpBase : lpPropValue, (void**)&lpPropValue[cvalues].Value.mapimvmember.mapilpmember); \
  356. for (j = 0; j < countarray; ++j) { \
  357. zend_hash_get_current_data(dataHash, (void **) &dataEntry); \
  358. convert_to_##type##_ex(dataEntry); \
  359. lpPropValue[cvalues].Value.mapimvmember.mapilpmember[j] = dataEntry[0]->value.phpmember; \
  360. zend_hash_move_forward(dataHash); \
  361. }
  362. case PT_MV_I2:
  363. COPY_MV_PROPS(long, MVi, lpi, lval);
  364. ++cvalues;
  365. break;
  366. case PT_MV_LONG:
  367. COPY_MV_PROPS(long, MVl, lpl, lval);
  368. ++cvalues;
  369. break;
  370. case PT_MV_R4:
  371. COPY_MV_PROPS(double, MVflt, lpflt, dval);
  372. ++cvalues;
  373. break;
  374. case PT_MV_DOUBLE:
  375. COPY_MV_PROPS(double, MVdbl, lpdbl, dval);
  376. ++cvalues;
  377. break;
  378. case PT_MV_APPTIME:
  379. COPY_MV_PROPS(double, MVat, lpat, dval);
  380. ++cvalues;
  381. break;
  382. case PT_MV_SYSTIME:
  383. GET_MV_HASH();
  384. CHECK_EMPTY_MV_ARRAY(MVft, lpft);
  385. lpPropValue[cvalues].Value.MVft.cValues = countarray;
  386. if ((MAPI_G(hr) = MAPIAllocateMore(sizeof(FILETIME) * countarray, lpBase ? lpBase : lpPropValue, (void **)&lpPropValue[cvalues].Value.MVft.lpft)) != hrSuccess)
  387. return MAPI_G(hr);
  388. for (j = 0; j < countarray; ++j) {
  389. zend_hash_get_current_data(dataHash, (void **)&dataEntry);
  390. convert_to_long_ex(dataEntry);
  391. UnixTimeToFileTime(dataEntry[0]->value.lval, &lpPropValue[cvalues].Value.MVft.lpft[j]);
  392. zend_hash_move_forward(dataHash);
  393. }
  394. ++cvalues;
  395. break;
  396. case PT_MV_UNICODE: // PT_MV_UNICODE is binary-compatible with PT_MV_BINARY in this case ..
  397. case PT_MV_BINARY:
  398. GET_MV_HASH();
  399. CHECK_EMPTY_MV_ARRAY(MVbin, lpbin);
  400. if ((MAPI_G(hr) = MAPIAllocateMore(sizeof(SBinary) * countarray, lpBase ? lpBase : lpPropValue, (void **)&lpPropValue[cvalues].Value.MVbin.lpbin)) != hrSuccess)
  401. return MAPI_G(hr);
  402. for (h = 0, j = 0; j < countarray; ++j) {
  403. zend_hash_get_current_data(dataHash, (void **)&dataEntry);
  404. convert_to_string_ex(dataEntry);
  405. lpPropValue[cvalues].Value.MVbin.lpbin[h].cb = dataEntry[0]->value.str.len;
  406. MAPI_G(hr) = MAPIAllocateMore(dataEntry[0]->value.str.len, lpBase ? lpBase : lpPropValue, (void **)&lpPropValue[cvalues].Value.MVbin.lpbin[h].lpb);
  407. if (MAPI_G(hr) != hrSuccess)
  408. return MAPI_G(hr);
  409. memcpy(lpPropValue[cvalues].Value.MVbin.lpbin[h++].lpb, dataEntry[0]->value.str.val, dataEntry[0]->value.str.len);
  410. zend_hash_move_forward(dataHash);
  411. }
  412. lpPropValue[cvalues++].Value.MVbin.cValues = h;
  413. break;
  414. case PT_MV_STRING8:
  415. GET_MV_HASH();
  416. CHECK_EMPTY_MV_ARRAY(MVszA, lppszA);
  417. if ((MAPI_G(hr) = MAPIAllocateMore(sizeof(char*) * countarray, lpBase ? lpBase : lpPropValue, (void **)&lpPropValue[cvalues].Value.MVszA.lppszA)) != hrSuccess)
  418. return MAPI_G(hr);
  419. for (h = 0, j = 0; j < countarray; ++j) {
  420. zend_hash_get_current_data(dataHash, (void **)&dataEntry);
  421. convert_to_string_ex(dataEntry);
  422. MAPI_G(hr) = MAPIAllocateMore(dataEntry[0]->value.str.len+1, lpBase ? lpBase : lpPropValue, (void **)&lpPropValue[cvalues].Value.MVszA.lppszA[h]);
  423. if (MAPI_G(hr) != hrSuccess)
  424. return MAPI_G(hr);
  425. strncpy(lpPropValue[cvalues].Value.MVszA.lppszA[h++], dataEntry[0]->value.str.val, dataEntry[0]->value.str.len + 1);
  426. zend_hash_move_forward(dataHash);
  427. }
  428. lpPropValue[cvalues++].Value.MVszA.cValues = h;
  429. break;
  430. case PT_MV_CLSID:
  431. GET_MV_HASH();
  432. CHECK_EMPTY_MV_ARRAY(MVguid, lpguid);
  433. if ((MAPI_G(hr) = MAPIAllocateMore(sizeof(GUID) * countarray, lpBase ? lpBase : lpPropValue, (void **)&lpPropValue[cvalues].Value.MVguid.lpguid)) != hrSuccess)
  434. return MAPI_G(hr);
  435. for (h = 0, j = 0; j < countarray; ++j) {
  436. zend_hash_get_current_data(dataHash, (void **)&dataEntry);
  437. convert_to_string_ex(dataEntry);
  438. if (dataEntry[0]->value.str.len != sizeof(GUID))
  439. php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid value for PT_MV_CLSID property in proptag 0x%08X, position %d,%d", lpPropValue[cvalues].ulPropTag, i, j);
  440. else
  441. memcpy(&lpPropValue[cvalues].Value.MVguid.lpguid[h++], dataEntry[0]->value.str.val, sizeof(GUID));
  442. zend_hash_move_forward(dataHash);
  443. }
  444. lpPropValue[cvalues++].Value.MVguid.cValues = h;
  445. break;
  446. case PT_MV_I8:
  447. php_error_docref(NULL TSRMLS_CC, E_WARNING, "PT_MV_I8 not supported");
  448. return MAPI_G(hr) = MAPI_E_NO_SUPPORT;
  449. case PT_MV_CURRENCY:
  450. php_error_docref(NULL TSRMLS_CC, E_WARNING, "PT_MV_CURRENCY not supported");
  451. return MAPI_G(hr) = MAPI_E_NO_SUPPORT;
  452. case PT_ACTIONS:
  453. dataHash = HASH_OF(entry[0]);
  454. if (!dataHash)
  455. break;
  456. zend_hash_internal_pointer_reset(dataHash);
  457. countarray = zend_hash_num_elements(dataHash); // # of actions
  458. if (countarray == 0) {
  459. php_error_docref(NULL TSRMLS_CC, E_WARNING, "PT_ACTIONS is empty");
  460. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  461. }
  462. if ((MAPI_G(hr) = MAPIAllocateMore(sizeof(ACTIONS), lpBase ? lpBase : lpPropValue, (void **)&lpPropValue[cvalues].Value.lpszA)) != hrSuccess)
  463. return MAPI_G(hr);
  464. lpActions = (ACTIONS*)lpPropValue[cvalues].Value.lpszA;
  465. lpActions->ulVersion = EDK_RULES_VERSION;
  466. lpActions->cActions = countarray;
  467. if ((MAPI_G(hr) = MAPIAllocateMore(sizeof(ACTION) * lpActions->cActions, lpBase ? lpBase : lpPropValue, (void**)&lpActions->lpAction)) != hrSuccess)
  468. return MAPI_G(hr);
  469. memset(lpActions->lpAction, 0, sizeof(ACTION) * lpActions->cActions);
  470. for (j = 0; j < countarray; ++j) {
  471. zend_hash_get_current_data(dataHash, (void **)&entry);
  472. actionHash = HASH_OF(entry[0]);
  473. if (!actionHash) {
  474. php_error_docref(NULL TSRMLS_CC, E_WARNING, "ACTIONS structure has a wrong ACTION");
  475. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  476. }
  477. if (zend_hash_find(actionHash, "action", sizeof("action"), (void **)&dataEntry) != SUCCESS) {
  478. php_error_docref(NULL TSRMLS_CC, E_WARNING, "PT_ACTIONS type has no action type in array");
  479. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  480. }
  481. convert_to_long_ex(dataEntry);
  482. lpActions->lpAction[j].acttype = (ACTTYPE)Z_LVAL_PP(dataEntry);
  483. // Option field user defined flags, default 0
  484. if (zend_hash_find(actionHash, "flags", sizeof("flags"), (void **)&dataEntry) == SUCCESS) {
  485. convert_to_long_ex(dataEntry);
  486. lpActions->lpAction[j].ulFlags = Z_LVAL_PP(dataEntry);
  487. }
  488. // Option field used with OP_REPLAY and OP_FORWARD, default 0
  489. if (zend_hash_find(actionHash, "flavor", sizeof("flavor"), (void **)&dataEntry) == SUCCESS) {
  490. convert_to_long_ex(dataEntry);
  491. lpActions->lpAction[j].ulActionFlavor = Z_LVAL_PP(dataEntry);
  492. }
  493. switch (lpActions->lpAction[j].acttype) {
  494. case OP_MOVE:
  495. case OP_COPY:
  496. if (zend_hash_find(actionHash, "storeentryid", sizeof("storeentryid"), (void **)&dataEntry) != SUCCESS) {
  497. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_COPY/OP_MOVE but no storeentryid entry");
  498. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  499. }
  500. convert_to_string_ex(dataEntry);
  501. lpActions->lpAction[j].actMoveCopy.cbStoreEntryId = dataEntry[0]->value.str.len;
  502. MAPI_G(hr) = MAPIAllocateMore(dataEntry[0]->value.str.len, lpBase ? lpBase : lpPropValue, (void **)&lpActions->lpAction[j].actMoveCopy.lpStoreEntryId);
  503. if (MAPI_G(hr) != hrSuccess)
  504. return MAPI_G(hr);
  505. memcpy(lpActions->lpAction[j].actMoveCopy.lpStoreEntryId, dataEntry[0]->value.str.val, dataEntry[0]->value.str.len);
  506. if (zend_hash_find(actionHash, "folderentryid", sizeof("folderentryid"), (void **)&dataEntry) != SUCCESS) {
  507. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_COPY/OP_MOVE but no folderentryid entry");
  508. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  509. }
  510. convert_to_string_ex(dataEntry);
  511. lpActions->lpAction[j].actMoveCopy.cbFldEntryId = dataEntry[0]->value.str.len;
  512. MAPI_G(hr) = MAPIAllocateMore(dataEntry[0]->value.str.len, lpBase ? lpBase : lpPropValue, (void **)&lpActions->lpAction[j].actMoveCopy.lpFldEntryId);
  513. if (MAPI_G(hr) != hrSuccess)
  514. return MAPI_G(hr);
  515. memcpy(lpActions->lpAction[j].actMoveCopy.lpFldEntryId, dataEntry[0]->value.str.val, dataEntry[0]->value.str.len);
  516. break;
  517. case OP_REPLY:
  518. case OP_OOF_REPLY:
  519. if (zend_hash_find(actionHash, "replyentryid", sizeof("replyentryid"), (void **)&dataEntry) != SUCCESS) {
  520. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_REPLY but no replyentryid entry");
  521. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  522. }
  523. convert_to_string_ex(dataEntry);
  524. lpActions->lpAction[j].actReply.cbEntryId = dataEntry[0]->value.str.len;
  525. MAPI_G(hr) = MAPIAllocateMore(dataEntry[0]->value.str.len, lpBase ? lpBase : lpPropValue, (void **)&lpActions->lpAction[j].actReply.lpEntryId);
  526. if (MAPI_G(hr) != hrSuccess)
  527. return MAPI_G(hr);
  528. memcpy(lpActions->lpAction[j].actReply.lpEntryId, dataEntry[0]->value.str.val, dataEntry[0]->value.str.len);
  529. // optional field
  530. if (zend_hash_find(actionHash, "replyguid", sizeof("replyguid"), (void **)&dataEntry) == SUCCESS) {
  531. convert_to_string_ex(dataEntry);
  532. if (dataEntry[0]->value.str.len != sizeof(GUID)) {
  533. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_REPLY replyguid not sizeof(GUID)");
  534. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  535. }
  536. memcpy(&lpActions->lpAction[j].actReply.guidReplyTemplate, dataEntry[0]->value.str.val, sizeof(GUID));
  537. }
  538. break;
  539. case OP_DEFER_ACTION:
  540. if (zend_hash_find(actionHash, "dam", sizeof("dam"), (void **)&dataEntry) != SUCCESS) {
  541. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_DEFER_ACTION but no dam entry");
  542. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  543. }
  544. convert_to_string_ex(dataEntry);
  545. lpActions->lpAction[j].actDeferAction.cbData = dataEntry[0]->value.str.len;
  546. MAPI_G(hr) = MAPIAllocateMore(dataEntry[0]->value.str.len, lpBase ? lpBase : lpPropValue, (void **)&lpActions->lpAction[j].actDeferAction.pbData);
  547. if (MAPI_G(hr) != hrSuccess)
  548. return MAPI_G(hr);
  549. memcpy(lpActions->lpAction[j].actDeferAction.pbData, dataEntry[0]->value.str.val, dataEntry[0]->value.str.len);
  550. break;
  551. case OP_BOUNCE:
  552. if (zend_hash_find(actionHash, "code", sizeof("code"), (void **)&dataEntry) != SUCCESS) {
  553. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_BOUNCE but no code entry");
  554. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  555. }
  556. convert_to_long_ex(dataEntry);
  557. lpActions->lpAction[j].scBounceCode = Z_LVAL_PP(dataEntry);
  558. break;
  559. case OP_FORWARD:
  560. case OP_DELEGATE:
  561. if (zend_hash_find(actionHash, "adrlist", sizeof("adrlist"), (void **)&dataEntry) != SUCCESS) {
  562. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_FORWARD/OP_DELEGATE but no adrlist entry");
  563. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  564. }
  565. if (dataEntry[0]->type != IS_ARRAY) {
  566. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_FORWARD/OP_DELEGATE adrlist entry must be an array");
  567. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  568. }
  569. MAPI_G(hr) = PHPArraytoAdrList(dataEntry[0], lpBase ? lpBase : lpPropValue, &lpActions->lpAction[j].lpadrlist TSRMLS_CC);
  570. if (MAPI_G(hr) != hrSuccess)
  571. return MAPI_G(hr);
  572. if (MAPI_G(hr) != hrSuccess){
  573. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_DELEGATE/OP_FORWARD wrong data in adrlist entry");
  574. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  575. }
  576. break;
  577. case OP_TAG:
  578. if (zend_hash_find(actionHash, "proptag", sizeof("proptag"), (void **)&dataEntry) != SUCCESS) {
  579. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_TAG but no proptag entry");
  580. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  581. }
  582. MAPI_G(hr) = PHPArraytoPropValueArray(dataEntry[0], lpBase ? lpBase : lpPropValue, &ulCountTmp, &lpPropTmp TSRMLS_CC);
  583. if (MAPI_G(hr) != hrSuccess)
  584. return MAPI_G(hr);
  585. if (ulCountTmp > 1)
  586. php_error_docref(NULL TSRMLS_CC, E_WARNING, "OP_TAG has 'proptag' member which contains more than one property. Using the first in the array.");
  587. lpActions->lpAction[j].propTag = *lpPropTmp;
  588. break;
  589. case OP_DELETE:
  590. case OP_MARK_AS_READ:
  591. // Nothing to do
  592. break;
  593. };
  594. zend_hash_move_forward(dataHash);
  595. }
  596. ++cvalues;
  597. break;
  598. case PT_SRESTRICTION:
  599. MAPI_G(hr) = PHPArraytoSRestriction(entry[0], lpBase ? lpBase : lpPropValue, &lpRestriction TSRMLS_CC);
  600. if (MAPI_G(hr) != hrSuccess) {
  601. php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHPArray to SRestriction failed");
  602. return MAPI_G(hr);
  603. }
  604. lpPropValue[cvalues++].Value.lpszA = (char *)lpRestriction;
  605. break;
  606. case PT_ERROR:
  607. convert_to_long_ex(entry);
  608. lpPropValue[cvalues].Value.err = entry[0]->value.lval;
  609. break;
  610. default:
  611. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown property type %08X", PROP_TYPE(numIndex));
  612. return MAPI_G(hr) = MAPI_E_INVALID_TYPE;
  613. }
  614. // move the pointer to the next entry
  615. zend_hash_move_forward(target_hash);
  616. }
  617. *lpcValues = cvalues;
  618. *lppPropValArray = lpPropValue;
  619. return MAPI_G(hr);
  620. }
  621. HRESULT PHPArraytoAdrList(zval *phpArray, void *lpBase, LPADRLIST *lppAdrList TSRMLS_DC)
  622. {
  623. HashTable *target_hash = NULL;
  624. ULONG countProperties = 0; // number of properties
  625. ULONG count = 0; // number of elements in the array
  626. ULONG countRecipients = 0; // number of actual recipients
  627. LPADRLIST lpAdrList = NULL;
  628. zval **entry = NULL;
  629. LPSPropValue pPropValue = NULL;
  630. MAPI_G(hr) = hrSuccess;
  631. if (!phpArray) {
  632. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No phpArray in PHPArraytoAdrList");
  633. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  634. goto exit;
  635. }
  636. target_hash = HASH_OF(phpArray);
  637. if (!target_hash) {
  638. php_error_docref(NULL TSRMLS_CC, E_WARNING, "phparraytoadrlist wrong data, unknown error");
  639. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  640. goto exit;
  641. }
  642. if(phpArray->type != IS_ARRAY) {
  643. php_error_docref(NULL TSRMLS_CC, E_WARNING, "phparray to adrlist must include an array");
  644. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  645. goto exit;
  646. }
  647. count = zend_hash_num_elements(target_hash);
  648. // We allow allocing a 0 count addresslist, since we need this the OP_DELEGATE rule
  649. MAPI_G(hr) = MAPI_ALLOC(CbNewADRLIST(count), lpBase, (void **)&lpAdrList);
  650. if(MAPI_G(hr) != hrSuccess)
  651. goto exit;
  652. zend_hash_internal_pointer_reset(target_hash);
  653. // FIXME: It is possible that the memory allocated is more than actually needed. We should first
  654. // count the number of elements needed then allocate memory and then fill the memory.
  655. // but since this waste is probably very minimal, we could not care less about this.
  656. for (unsigned int i = 0; i < count; ++i) {
  657. zend_hash_get_current_data(target_hash, (void **) &entry);
  658. if(entry[0]->type != IS_ARRAY) {
  659. php_error_docref(NULL TSRMLS_CC, E_WARNING, "phparraytoadrlist array must include an array with array of propvalues");
  660. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  661. goto exit;
  662. }
  663. MAPI_G(hr) = PHPArraytoPropValueArray(entry[0], lpBase, &countProperties, &pPropValue TSRMLS_CC);
  664. if(MAPI_G(hr) != hrSuccess)
  665. goto exit;
  666. lpAdrList->aEntries[countRecipients].ulReserved1 = 0;
  667. lpAdrList->aEntries[countRecipients].rgPropVals = pPropValue;
  668. lpAdrList->aEntries[countRecipients].cValues = countProperties;
  669. // move the pointer to the next entry
  670. zend_hash_move_forward(target_hash);
  671. ++countRecipients;
  672. }
  673. lpAdrList->cEntries = countRecipients;
  674. *lppAdrList = lpAdrList;
  675. exit:
  676. if(MAPI_G(hr) != hrSuccess && lpBase == NULL && lpAdrList != NULL)
  677. FreePadrlist(lpAdrList);
  678. return MAPI_G(hr);
  679. }
  680. HRESULT PHPArraytoRowList(zval *phpArray, void *lpBase, LPROWLIST *lppRowList TSRMLS_DC) {
  681. HashTable *target_hash = NULL;
  682. ULONG countProperties = 0; // number of properties
  683. ULONG count = 0; // number of elements in the array
  684. ULONG countRows = 0; // number of actual recipients
  685. LPROWLIST lpRowList = NULL;
  686. zval **entry = NULL;
  687. zval **data = NULL;
  688. LPSPropValue pPropValue = NULL;
  689. MAPI_G(hr) = hrSuccess;
  690. if (!phpArray || phpArray->type != IS_ARRAY) {
  691. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No phpArray in PHPArraytoRowList");
  692. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  693. goto exit;
  694. }
  695. target_hash = HASH_OF(phpArray);
  696. if (!target_hash) {
  697. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No target_hash in PHPArraytoRowList");
  698. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  699. goto exit;
  700. }
  701. count = zend_hash_num_elements(target_hash);
  702. // allocate memory to store the array of pointers
  703. MAPI_G(hr) = MAPIAllocateBuffer(CbNewROWLIST(count),
  704. reinterpret_cast<void **>(&lpRowList));
  705. if (MAPI_G(hr) != hrSuccess)
  706. goto exit;
  707. zend_hash_internal_pointer_reset(target_hash);
  708. // FIXME: It is possible that the memory allocated is more than actually needed. We should first
  709. // count the number of elements needed then allocate memory and then fill the memory.
  710. // but since this waste is probably very minimal, we could not care less about this.
  711. for (unsigned int i = 0; i < count; ++i) {
  712. zend_hash_get_current_data(target_hash, (void **) &entry);
  713. if (Z_TYPE_PP(entry) != IS_ARRAY) {
  714. php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHPArraytoRowList, Row not wrapped in array");
  715. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  716. goto exit;
  717. }
  718. if (zend_hash_find(HASH_OF(entry[0]), "properties", sizeof("properties"), (void**)&data) == SUCCESS){
  719. MAPI_G(hr) = PHPArraytoPropValueArray(data[0], NULL, &countProperties, &pPropValue TSRMLS_CC);
  720. if(MAPI_G(hr) != hrSuccess)
  721. goto exit;
  722. }else {
  723. php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHPArraytoRowList, Missing field properties");
  724. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  725. goto exit;
  726. }
  727. if (pPropValue) {
  728. if (zend_hash_find(HASH_OF(entry[0]), "rowflags", sizeof("rowflags"), (void**)&data) == SUCCESS) {
  729. lpRowList->aEntries[countRows].ulRowFlags = Z_LVAL_PP(data);
  730. } else {
  731. php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHPArraytoRowList, Missing field rowflags");
  732. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  733. goto exit;
  734. }
  735. lpRowList->aEntries[countRows].rgPropVals = pPropValue;
  736. lpRowList->aEntries[countRows++].cValues = countProperties;
  737. }else {
  738. php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHPArraytoRowList, critical error");
  739. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  740. goto exit;
  741. }
  742. // move the pointer to the next entry
  743. zend_hash_move_forward(target_hash);
  744. }
  745. lpRowList->cEntries = countRows;
  746. *lppRowList = lpRowList;
  747. exit:
  748. if (MAPI_G(hr) != hrSuccess)
  749. MAPIFreeBuffer(lpRowList);
  750. return MAPI_G(hr);
  751. }
  752. /**
  753. Function to convert a PHP array to a SRestriction structure.
  754. The SRectriction structure is a structure with multiple level which defines a sort of
  755. tree with restrictions for a table view. It is used with de setSearchCriteria, findRow and other
  756. functions to select rows for a specified criteria.
  757. The PHP array should be in the following form:
  758. array(RES_AND,
  759. array(
  760. array(RES_OR,
  761. array(
  762. array(RES_PROPERTY,
  763. array(
  764. RELOP => RELOP_LE,
  765. ULPROPTAG => PR_BODY,
  766. VALUE => "test"
  767. ),
  768. ),
  769. array(RES_PROPERTY,
  770. array(
  771. RELOP => RELOP_RE,
  772. ULPROPTAG => PR_DISPLAY_NAME,
  773. VALUE => "leon"
  774. ),
  775. ),
  776. ), // OR array
  777. ),
  778. array(RES_EXIST,
  779. array(
  780. ULPROPTAG => PR_HASATTACH
  781. ),
  782. ),
  783. ), // AND array
  784. )
  785. This will mean the following in some pseudocode:
  786. (((PROPERTY PR_BODY = "test") or (PROPERTY PR_DISPLAY_NAME like "leon")) and (PROPERTY TAG EXIST PR_ATTACH))
  787. To fix the collision problem, an array is added. This gives the following assumption:
  788. An entry always consists of:
  789. array(RES_xxxx, array(values))
  790. values = array(RES_xxxx, array(values)) || array(restriction data)
  791. when we read the php array, we use this assumption.
  792. */
  793. // see include/mapi/mapidefs.php restriction array index values
  794. #define VALUE 0
  795. #define RELOP 1
  796. #define FUZZYLEVEL 2
  797. #define CB 3
  798. #define ULTYPE 4
  799. #define ULMASK 5
  800. #define ULPROPTAG 6
  801. #define ULPROPTAG1 7
  802. #define ULPROPTAG2 8
  803. #define PROPS 9
  804. #define RESTRICTION 10
  805. /*
  806. * A lpRes pointer should be given here, the idea is that every time this
  807. * function is run the SRestriction struct will become bigger, using lpBase as base pointer for MAPIAllocateMore().
  808. * TODO: combine code from here and from PHPArraytoPropValueArray in a pval/zval to Proptag function (?)
  809. */
  810. HRESULT PHPArraytoSRestriction(zval *phpVal, void* lpBase, LPSRestriction lpRes TSRMLS_DC)
  811. {
  812. HashTable *resHash = NULL;
  813. HashTable *dataHash = NULL;
  814. zval **typeEntry = NULL;
  815. zval **valueEntry = NULL;
  816. ULONG cValues = 0;
  817. int count;
  818. int i;
  819. if (!phpVal || lpRes == NULL) {
  820. php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error");
  821. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  822. }
  823. resHash = HASH_OF(phpVal);
  824. if (!resHash || zend_hash_num_elements(resHash) != 2) { // should always be array(RES_ , array(values))
  825. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong array should be array(RES_, array(values))");
  826. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  827. }
  828. zend_hash_internal_pointer_reset(resHash);
  829. // structure assumption: add more checks that valueEntry becomes php array pointer?
  830. zend_hash_get_current_data(resHash, (void **) &typeEntry); // 0=type, 1=array
  831. zend_hash_move_forward(resHash);
  832. zend_hash_get_current_data(resHash, (void **) &valueEntry);
  833. lpRes->rt = typeEntry[0]->value.lval; // set restriction type (RES_AND, RES_OR, ...)
  834. dataHash = HASH_OF(valueEntry[0]); // from resHash
  835. if (!dataHash) {
  836. php_error_docref(NULL TSRMLS_CC, E_WARNING, "critical error, wrong array");
  837. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  838. }
  839. count = zend_hash_num_elements(dataHash);
  840. zend_hash_internal_pointer_reset(dataHash);
  841. switch(lpRes->rt) {
  842. /*
  843. * type restrictions
  844. */
  845. case RES_AND:
  846. // Recursively add all AND-ed restrictions
  847. lpRes->res.resAnd.cRes = count;
  848. MAPI_G(hr) = MAPIAllocateMore(sizeof(SRestriction) * count, lpBase, (void **) &lpRes->res.resAnd.lpRes);
  849. if (MAPI_G(hr) != hrSuccess)
  850. return MAPI_G(hr);
  851. for (i = 0; i < count; ++i) {
  852. zend_hash_get_current_data(dataHash, (void **) &valueEntry);
  853. MAPI_G(hr) = PHPArraytoSRestriction(valueEntry[0], lpBase, &lpRes->res.resAnd.lpRes[i] TSRMLS_CC);
  854. if (MAPI_G(hr) != hrSuccess)
  855. return MAPI_G(hr);
  856. zend_hash_move_forward(dataHash);
  857. }
  858. break;
  859. case RES_OR:
  860. // Recursively add all OR-ed restrictions
  861. lpRes->res.resOr.cRes = count;
  862. MAPI_G(hr) = MAPIAllocateMore(sizeof(SRestriction) * count, lpBase, (void **) &lpRes->res.resOr.lpRes);
  863. if (MAPI_G(hr) != hrSuccess)
  864. return MAPI_G(hr);
  865. for (i = 0; i < count; ++i) {
  866. zend_hash_get_current_data(dataHash, (void **) &valueEntry);
  867. MAPI_G(hr) = PHPArraytoSRestriction(valueEntry[0], lpBase, &lpRes->res.resOr.lpRes[i] TSRMLS_CC);
  868. if (MAPI_G(hr) != hrSuccess)
  869. return MAPI_G(hr);
  870. zend_hash_move_forward(dataHash);
  871. }
  872. break;
  873. case RES_NOT:
  874. // NOT has only one restriction
  875. MAPI_G(hr) = MAPIAllocateMore(sizeof(SRestriction), lpBase, (void **) &lpRes->res.resNot.lpRes);
  876. if (MAPI_G(hr) != hrSuccess)
  877. return MAPI_G(hr);
  878. zend_hash_get_current_data(dataHash, (void **) &valueEntry);
  879. MAPI_G(hr) = PHPArraytoSRestriction(valueEntry[0], lpBase, lpRes->res.resNot.lpRes TSRMLS_CC);
  880. if (MAPI_G(hr) != hrSuccess)
  881. return MAPI_G(hr);
  882. break;
  883. case RES_SUBRESTRICTION:
  884. if (zend_hash_index_find(dataHash, RESTRICTION, (void **)&valueEntry) == FAILURE) {
  885. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_SUBRESTRICTION, Missing field RESTRICTION");
  886. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  887. }
  888. MAPI_G(hr) = PHPArraytoSRestriction(valueEntry[0], lpBase, &lpRes->res.resSub.lpRes TSRMLS_CC);
  889. if (MAPI_G(hr) != hrSuccess)
  890. return MAPI_G(hr);
  891. // ULPROPTAG as resSubObject
  892. if (zend_hash_index_find(dataHash, ULPROPTAG, (void **)&valueEntry) == FAILURE) {
  893. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_SUBRESTRICTION, Missing field ULPROPTAG");
  894. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  895. }
  896. lpRes->res.resSub.ulSubObject = valueEntry[0]->value.lval;
  897. break;
  898. case RES_COMMENT:
  899. if (zend_hash_index_find(dataHash, RESTRICTION, (void **)&valueEntry) == FAILURE) {
  900. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_COMMENT, Missing field RESTRICTION");
  901. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  902. }
  903. MAPI_G(hr) = PHPArraytoSRestriction(valueEntry[0], lpBase, &lpRes->res.resComment.lpRes TSRMLS_CC);
  904. if (MAPI_G(hr) != hrSuccess) {
  905. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_COMMENT, Wrong data in field RESTRICTION");
  906. return MAPI_G(hr);
  907. }
  908. if (zend_hash_index_find(dataHash, PROPS, (void **)&valueEntry) == FAILURE) {
  909. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_COMMENT, Missing field PROPS");
  910. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  911. }
  912. MAPI_G(hr) = PHPArraytoPropValueArray(valueEntry[0], lpBase, &lpRes->res.resComment.cValues, &lpRes->res.resComment.lpProp TSRMLS_CC);
  913. if(MAPI_G(hr) != hrSuccess) {
  914. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_COMMENT, Wrong data in field PROPS");
  915. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  916. }
  917. break;
  918. /*
  919. * content restrictions
  920. */
  921. case RES_CONTENT:
  922. case RES_PROPERTY:
  923. {
  924. LPSPropValue lpProp;
  925. if (lpRes->rt == RES_PROPERTY) {
  926. // ULPROPTAG
  927. if (zend_hash_index_find(dataHash, ULPROPTAG, (void **)&valueEntry) == FAILURE) {
  928. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_PROPERTY, Missing field ULPROPTAG");
  929. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  930. }
  931. convert_to_long_ex(valueEntry);
  932. lpRes->res.resProperty.ulPropTag = valueEntry[0]->value.lval;
  933. // RELOP
  934. if (zend_hash_index_find(dataHash, RELOP, (void **)&valueEntry) == FAILURE) {
  935. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_PROPERTY, Missing field RELOP");
  936. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  937. }
  938. convert_to_long_ex(valueEntry);
  939. lpRes->res.resProperty.relop = valueEntry[0]->value.lval;
  940. } else {
  941. // ULPROPTAG
  942. if (zend_hash_index_find(dataHash, ULPROPTAG, (void **)&valueEntry) == FAILURE) {
  943. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_CONTENT, Missing field ULPROPTAG");
  944. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  945. }
  946. convert_to_long_ex(valueEntry);
  947. lpRes->res.resContent.ulPropTag = valueEntry[0]->value.lval;
  948. // possible FUZZYLEVEL
  949. switch (PROP_TYPE(lpRes->res.resContent.ulPropTag)) {
  950. case PT_STRING8:
  951. case PT_UNICODE:
  952. case PT_BINARY:
  953. case PT_MV_BINARY:
  954. case PT_MV_STRING8:
  955. if (zend_hash_index_find(dataHash, FUZZYLEVEL, (void **)&valueEntry) == FAILURE) {
  956. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_CONTENT, Missing field FUZZYLEVEL");
  957. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  958. }
  959. convert_to_long_ex(valueEntry);
  960. lpRes->res.resContent.ulFuzzyLevel = valueEntry[0]->value.lval;
  961. break;
  962. default:
  963. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_CONTENT, Not supported property type");
  964. return MAPI_G(hr) = MAPI_E_TOO_COMPLEX;
  965. };
  966. }
  967. // VALUE
  968. if (zend_hash_index_find(dataHash, VALUE, (void **)&valueEntry) == FAILURE) {
  969. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_PROPERTY or RES_CONTENT, Missing field VALUE");
  970. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  971. }
  972. if(valueEntry[0]->type == IS_ARRAY) {
  973. MAPI_G(hr) = PHPArraytoPropValueArray(valueEntry[0], lpBase, &cValues, &lpProp TSRMLS_CC);
  974. if(MAPI_G(hr) != hrSuccess) {
  975. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_PROPERTY or RES_CONTENT, Wrong data in field VALUE ");
  976. return MAPI_G(hr);
  977. }
  978. }else{
  979. // backward compatibility code <= 5.20
  980. MAPI_G(hr) = MAPIAllocateMore(sizeof(SPropValue), lpBase, (void **)&lpProp);
  981. if (MAPI_G(hr) != hrSuccess)
  982. return MAPI_G(hr);
  983. lpProp->dwAlignPad = 0;
  984. if (lpRes->rt == RES_PROPERTY)
  985. lpProp->ulPropTag = lpRes->res.resProperty.ulPropTag;
  986. else
  987. lpProp->ulPropTag = lpRes->res.resContent.ulPropTag;
  988. switch (PROP_TYPE(lpProp->ulPropTag)) { // sets in either resContent or resProperty
  989. case PT_STRING8:
  990. convert_to_string_ex(valueEntry);
  991. MAPI_G(hr) = MAPIAllocateMore(valueEntry[0]->value.str.len+1, lpBase, (void **)&lpProp->Value.lpszA);
  992. if(MAPI_G(hr) != hrSuccess)
  993. return MAPI_G(hr);
  994. strncpy(lpProp->Value.lpszA, valueEntry[0]->value.str.val, valueEntry[0]->value.str.len+1);
  995. break;
  996. case PT_UNICODE:
  997. return MAPI_G(hr) = MAPI_E_NO_SUPPORT;
  998. break;
  999. case PT_LONG:
  1000. convert_to_long_ex(valueEntry);
  1001. lpProp->Value.l = valueEntry[0]->value.lval;
  1002. break;
  1003. case PT_LONGLONG:
  1004. convert_to_double_ex(valueEntry);
  1005. lpProp->Value.li.QuadPart = (LONGLONG)valueEntry[0]->value.dval;
  1006. break;
  1007. case PT_SHORT:
  1008. convert_to_long_ex(valueEntry);
  1009. lpProp->Value.i = (short) valueEntry[0]->value.lval;
  1010. break;
  1011. case PT_DOUBLE:
  1012. convert_to_double_ex(valueEntry);
  1013. lpProp->Value.dbl = valueEntry[0]->value.dval;
  1014. break;
  1015. case PT_FLOAT:
  1016. convert_to_double_ex(valueEntry);
  1017. lpProp->Value.flt = (float) valueEntry[0]->value.dval;
  1018. break;
  1019. case PT_BOOLEAN:
  1020. convert_to_boolean_ex(valueEntry);
  1021. lpProp->Value.b = (unsigned short) valueEntry[0]->value.lval;
  1022. break;
  1023. case PT_SYSTIME:
  1024. convert_to_long_ex(valueEntry);
  1025. UnixTimeToFileTime(valueEntry[0]->value.lval, &lpProp->Value.ft);
  1026. break;
  1027. case PT_BINARY:
  1028. convert_to_string_ex(valueEntry);
  1029. lpProp->Value.bin.cb = valueEntry[0]->value.str.len;
  1030. MAPI_G(hr) = MAPIAllocateMore(valueEntry[0]->value.str.len, lpBase, (void **) &lpProp->Value.bin.lpb);
  1031. if(MAPI_G(hr) != hrSuccess)
  1032. return MAPI_G(hr);
  1033. memcpy(lpProp->Value.bin.lpb, valueEntry[0]->value.str.val, valueEntry[0]->value.str.len);
  1034. break;
  1035. case PT_APPTIME:
  1036. convert_to_double_ex(valueEntry);
  1037. lpProp->Value.at = valueEntry[0]->value.dval;
  1038. break;
  1039. case PT_CLSID:
  1040. convert_to_string_ex(valueEntry);
  1041. if (valueEntry[0]->value.str.len != sizeof(GUID)) {
  1042. php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid value for PT_CLSID property in proptag 0x%08X", lpProp->ulPropTag);
  1043. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1044. }
  1045. MAPI_G(hr) = MAPIAllocateMore(sizeof(GUID), lpBase, (void **)&lpProp->Value.lpguid);
  1046. memcpy(lpProp->Value.lpguid, valueEntry[0]->value.str.val, sizeof(GUID));
  1047. break;
  1048. default:
  1049. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_PROPERTY or RES_CONTENT, field VALUE no backward compatibility support");
  1050. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1051. }
  1052. }
  1053. if (lpRes->rt == RES_PROPERTY)
  1054. lpRes->res.resProperty.lpProp = lpProp;
  1055. else
  1056. lpRes->res.resContent.lpProp = lpProp;
  1057. }
  1058. break;
  1059. case RES_COMPAREPROPS:
  1060. // RELOP
  1061. if (zend_hash_index_find(dataHash, RELOP, (void **)&valueEntry) == FAILURE) {
  1062. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_COMPAREPROPS, Missing field RELOP");
  1063. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1064. }
  1065. convert_to_long_ex(valueEntry);
  1066. lpRes->res.resCompareProps.relop = valueEntry[0]->value.lval;
  1067. // ULPROPTAG1
  1068. if (zend_hash_index_find(dataHash, ULPROPTAG1, (void **)&valueEntry) == FAILURE) {
  1069. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_COMPAREPROPS, Missing field ULPROPTAG1");
  1070. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1071. }
  1072. convert_to_long_ex(valueEntry);
  1073. lpRes->res.resCompareProps.ulPropTag1 = valueEntry[0]->value.lval;
  1074. // ULPROPTAG2
  1075. if (zend_hash_index_find(dataHash, ULPROPTAG2, (void **)&valueEntry) == FAILURE) {
  1076. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_COMPAREPROPS, Missing field ULPROPTAG2");
  1077. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1078. }
  1079. convert_to_long_ex(valueEntry);
  1080. lpRes->res.resCompareProps.ulPropTag2 = valueEntry[0]->value.lval;
  1081. break;
  1082. case RES_BITMASK:
  1083. // ULTYPE
  1084. if (zend_hash_index_find(dataHash, ULTYPE, (void **)&valueEntry) == FAILURE) {
  1085. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_BITMASK, Missing field ULTYPE");
  1086. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1087. }
  1088. convert_to_long_ex(valueEntry);
  1089. lpRes->res.resBitMask.relBMR = valueEntry[0]->value.lval;
  1090. // ULMASK
  1091. if (zend_hash_index_find(dataHash, ULMASK, (void **)&valueEntry) == FAILURE) {
  1092. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_BITMASK, Missing field ULMASK");
  1093. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1094. }
  1095. convert_to_long_ex(valueEntry);
  1096. lpRes->res.resBitMask.ulMask = valueEntry[0]->value.lval;
  1097. // ULPROPTAG
  1098. if (zend_hash_index_find(dataHash, ULPROPTAG, (void **)&valueEntry) == FAILURE) {
  1099. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_BITMASK, Missing field ULPROPTAG");
  1100. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1101. }
  1102. convert_to_long_ex(valueEntry);
  1103. lpRes->res.resBitMask.ulPropTag = valueEntry[0]->value.lval;
  1104. break;
  1105. case RES_SIZE:
  1106. // CB
  1107. if (zend_hash_index_find(dataHash, CB, (void **)&valueEntry) == FAILURE) {
  1108. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_SIZE, Missing field CB");
  1109. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1110. }
  1111. convert_to_long_ex(valueEntry);
  1112. lpRes->res.resSize.cb = valueEntry[0]->value.lval;
  1113. // RELOP
  1114. if (zend_hash_index_find(dataHash, RELOP, (void **)&valueEntry) == FAILURE) {
  1115. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_SIZE, Missing field RELOP");
  1116. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1117. }
  1118. convert_to_long_ex(valueEntry);
  1119. lpRes->res.resSize.relop = valueEntry[0]->value.lval;
  1120. // ULPROPTAG
  1121. if (zend_hash_index_find(dataHash, ULPROPTAG, (void **)&valueEntry) == FAILURE) {
  1122. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_SIZE, Missing field ULPROPTAG");
  1123. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1124. }
  1125. convert_to_long_ex(valueEntry);
  1126. lpRes->res.resSize.ulPropTag = valueEntry[0]->value.lval;
  1127. break;
  1128. case RES_EXIST:
  1129. // ULPROPTAG
  1130. if (zend_hash_index_find(dataHash, ULPROPTAG, (void **)&valueEntry) == FAILURE) {
  1131. php_error_docref(NULL TSRMLS_CC, E_WARNING, "RES_EXIST, Missing field ULPROPTAG");
  1132. return MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1133. }
  1134. convert_to_long_ex(valueEntry);
  1135. lpRes->res.resExist.ulPropTag = valueEntry[0]->value.lval;
  1136. break;
  1137. default:
  1138. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown restriction type");
  1139. break;
  1140. }
  1141. return MAPI_G(hr);
  1142. }
  1143. HRESULT PHPArraytoSRestriction(zval *phpVal, void* lpBase, LPSRestriction *lppRes TSRMLS_DC) {
  1144. LPSRestriction lpRes = NULL;
  1145. MAPI_G(hr) = MAPI_ALLOC(sizeof(SRestriction), lpBase, (void **)&lpRes);
  1146. if(MAPI_G(hr) != hrSuccess)
  1147. goto exit;
  1148. MAPI_G(hr) = PHPArraytoSRestriction(phpVal, lpBase ? lpBase : lpRes, lpRes TSRMLS_CC);
  1149. if(MAPI_G(hr) != hrSuccess)
  1150. goto exit;
  1151. *lppRes = lpRes;
  1152. exit:
  1153. if (MAPI_G(hr) != hrSuccess && lpBase == NULL)
  1154. MAPIFreeBuffer(lpRes);
  1155. return MAPI_G(hr);
  1156. }
  1157. HRESULT SRestrictiontoPHPArray(LPSRestriction lpRes, int level, zval **pret TSRMLS_DC) {
  1158. zval *entry = NULL;
  1159. char key[16];
  1160. zval *array = NULL;
  1161. zval *props = NULL;
  1162. zval *restriction = NULL;
  1163. zval *ret;
  1164. if (!lpRes) {
  1165. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No restriction in SRestrictiontoPHPArray");
  1166. return MAPI_E_INVALID_PARAMETER;
  1167. }
  1168. // use define depth
  1169. if (level > 16)
  1170. return MAPI_G(hr) = MAPI_E_TOO_COMPLEX;
  1171. MAKE_STD_ZVAL(ret);
  1172. array_init(ret);
  1173. switch (lpRes->rt) {
  1174. case RES_AND:
  1175. MAKE_STD_ZVAL(array);
  1176. array_init(array);
  1177. for (ULONG c = 0; c < lpRes->res.resAnd.cRes; ++c) {
  1178. entry = NULL;
  1179. sprintf(key, "%i", c);
  1180. MAPI_G(hr) = SRestrictiontoPHPArray(&lpRes->res.resAnd.lpRes[c], level+1, &entry TSRMLS_CC);
  1181. if (MAPI_G(hr) != hrSuccess)
  1182. return MAPI_G(hr);
  1183. add_assoc_zval(array, key, entry);
  1184. }
  1185. add_assoc_long(ret, "0", RES_AND);
  1186. add_assoc_zval(ret, "1", array);
  1187. break;
  1188. case RES_OR:
  1189. MAKE_STD_ZVAL(array);
  1190. array_init(array);
  1191. for (ULONG c = 0; c < lpRes->res.resOr.cRes; ++c) {
  1192. entry = NULL;
  1193. sprintf(key, "%i", c);
  1194. MAPI_G(hr) = SRestrictiontoPHPArray(&lpRes->res.resOr.lpRes[c], level+1, &entry TSRMLS_CC);
  1195. if (MAPI_G(hr) != hrSuccess)
  1196. return MAPI_G(hr);
  1197. add_assoc_zval(array, key, entry);
  1198. }
  1199. add_assoc_long(ret, "0", RES_OR);
  1200. add_assoc_zval(ret, "1", array);
  1201. break;
  1202. case RES_NOT:
  1203. // although it's only one value, it still is wrapped in an array.
  1204. MAKE_STD_ZVAL(array);
  1205. array_init(array);
  1206. MAPI_G(hr) = SRestrictiontoPHPArray(lpRes->res.resNot.lpRes, level+1, &entry TSRMLS_CC);
  1207. if (MAPI_G(hr) != hrSuccess)
  1208. return MAPI_G(hr);
  1209. add_assoc_zval(array, "0", entry);
  1210. add_assoc_long(ret, "0", RES_NOT);
  1211. add_assoc_zval(ret, "1", array);
  1212. break;
  1213. case RES_CONTENT:
  1214. MAPI_G(hr) = PropValueArraytoPHPArray(1, lpRes->res.resContent.lpProp, &props TSRMLS_CC);
  1215. if (MAPI_G(hr) != hrSuccess)
  1216. return MAPI_G(hr);
  1217. MAKE_STD_ZVAL(array);
  1218. array_init(array);
  1219. sprintf(key, "%i", VALUE);
  1220. add_assoc_zval(array, key, props);
  1221. sprintf(key, "%i", ULPROPTAG);
  1222. add_assoc_long(array, key, PropTagToPHPTag(lpRes->res.resContent.ulPropTag));
  1223. sprintf(key, "%i", FUZZYLEVEL);
  1224. add_assoc_long(array, key, (LONG)lpRes->res.resContent.ulFuzzyLevel);
  1225. add_assoc_long(ret, "0", RES_CONTENT);
  1226. add_assoc_zval(ret, "1", array);
  1227. break;
  1228. case RES_PROPERTY:
  1229. MAPI_G(hr) = PropValueArraytoPHPArray(1, lpRes->res.resProperty.lpProp, &props TSRMLS_CC);
  1230. if (MAPI_G(hr) != hrSuccess)
  1231. return MAPI_G(hr);
  1232. MAKE_STD_ZVAL(array);
  1233. array_init(array);
  1234. sprintf(key, "%i", RELOP);
  1235. add_assoc_long(array, key, (LONG)lpRes->res.resProperty.relop);
  1236. sprintf(key, "%i", ULPROPTAG);
  1237. add_assoc_long(array, key, PropTagToPHPTag(lpRes->res.resProperty.ulPropTag));
  1238. sprintf(key, "%i", VALUE);
  1239. add_assoc_zval(array, key, props);
  1240. add_assoc_long(ret, "0", RES_PROPERTY);
  1241. add_assoc_zval(ret, "1", array);
  1242. break;
  1243. case RES_COMPAREPROPS:
  1244. MAKE_STD_ZVAL(array);
  1245. array_init(array);
  1246. sprintf(key, "%i", RELOP);
  1247. add_assoc_long(array, key, (LONG)lpRes->res.resCompareProps.relop);
  1248. sprintf(key, "%i", ULPROPTAG1);
  1249. add_assoc_long(array, key, PropTagToPHPTag(lpRes->res.resCompareProps.ulPropTag1));
  1250. sprintf(key, "%i", ULPROPTAG2);
  1251. add_assoc_long(array, key, PropTagToPHPTag(lpRes->res.resCompareProps.ulPropTag2));
  1252. add_assoc_long(ret, "0", RES_COMPAREPROPS);
  1253. add_assoc_zval(ret, "1", array);
  1254. break;
  1255. case RES_BITMASK:
  1256. MAKE_STD_ZVAL(array);
  1257. array_init(array);
  1258. sprintf(key, "%i", ULTYPE);
  1259. add_assoc_long(array, key, (LONG)lpRes->res.resBitMask.relBMR);
  1260. sprintf(key, "%i", ULPROPTAG);
  1261. add_assoc_long(array, key, PropTagToPHPTag(lpRes->res.resBitMask.ulPropTag));
  1262. sprintf(key, "%i", ULMASK);
  1263. add_assoc_long(array, key, (LONG)lpRes->res.resBitMask.ulMask);
  1264. add_assoc_long(ret, "0", RES_BITMASK);
  1265. add_assoc_zval(ret, "1", array);
  1266. break;
  1267. case RES_SIZE:
  1268. MAKE_STD_ZVAL(array);
  1269. array_init(array);
  1270. sprintf(key, "%i", RELOP);
  1271. add_assoc_long(array, key, (LONG)lpRes->res.resSize.relop);
  1272. sprintf(key, "%i", ULPROPTAG);
  1273. add_assoc_long(array, key, PropTagToPHPTag(lpRes->res.resSize.ulPropTag));
  1274. sprintf(key, "%i", CB);
  1275. add_assoc_long(array, key, (LONG)lpRes->res.resSize.cb);
  1276. add_assoc_long(ret, "0", RES_SIZE);
  1277. add_assoc_zval(ret, "1", array);
  1278. break;
  1279. case RES_EXIST:
  1280. MAKE_STD_ZVAL(array);
  1281. array_init(array);
  1282. sprintf(key, "%i", ULPROPTAG);
  1283. add_assoc_long(array, key, PropTagToPHPTag(lpRes->res.resExist.ulPropTag));
  1284. add_assoc_long(ret, "0", RES_EXIST);
  1285. add_assoc_zval(ret, "1", array);
  1286. break;
  1287. case RES_SUBRESTRICTION:
  1288. restriction = NULL;
  1289. MAPI_G(hr) = SRestrictiontoPHPArray(lpRes->res.resSub.lpRes, level+1, &restriction TSRMLS_CC);
  1290. if (!restriction)
  1291. return MAPI_G(hr);
  1292. MAKE_STD_ZVAL(array);
  1293. array_init(array);
  1294. sprintf(key, "%i", ULPROPTAG);
  1295. add_assoc_long(array, key, PropTagToPHPTag(lpRes->res.resSub.ulSubObject));
  1296. sprintf(key, "%i", RESTRICTION);
  1297. add_assoc_zval(array, key, restriction);
  1298. add_assoc_long(ret, "0", RES_SUBRESTRICTION);
  1299. add_assoc_zval(ret, "1", array);
  1300. break;
  1301. case RES_COMMENT:
  1302. MAPI_G(hr) = PropValueArraytoPHPArray(lpRes->res.resComment.cValues, lpRes->res.resComment.lpProp, &props TSRMLS_CC);
  1303. if (MAPI_G(hr) != hrSuccess)
  1304. return MAPI_G(hr);
  1305. restriction = NULL;
  1306. MAPI_G(hr) = SRestrictiontoPHPArray(lpRes->res.resComment.lpRes, level+1, &restriction TSRMLS_CC);
  1307. if (!restriction)
  1308. return MAPI_G(hr);
  1309. MAKE_STD_ZVAL(array);
  1310. array_init(array);
  1311. sprintf(key, "%i", PROPS);
  1312. add_assoc_zval(array, key, props);
  1313. sprintf(key, "%i", RESTRICTION);
  1314. add_assoc_zval(array, key, restriction);
  1315. add_assoc_long(ret, "0", RES_COMMENT);
  1316. add_assoc_zval(ret, "1", array);
  1317. break;
  1318. };
  1319. *pret = ret;
  1320. return MAPI_G(hr);
  1321. }
  1322. /**
  1323. * Function to conver a PropTagArray to a PHP Array
  1324. *
  1325. */
  1326. HRESULT PropTagArraytoPHPArray(ULONG cValues, LPSPropTagArray lpPropTagArray, zval **pret TSRMLS_DC)
  1327. {
  1328. zval *zvalRet = NULL;
  1329. unsigned int i = 0;
  1330. MAPI_G(hr) = hrSuccess;
  1331. MAKE_STD_ZVAL(zvalRet);
  1332. array_init(zvalRet);
  1333. for (i = 0; i < cValues; ++i)
  1334. add_next_index_long(zvalRet, PropTagToPHPTag(lpPropTagArray->aulPropTag[i]));
  1335. *pret = zvalRet;
  1336. return MAPI_G(hr);
  1337. }
  1338. /**
  1339. * Function to convert a PropValueArray to a PHP Array
  1340. *
  1341. *
  1342. */
  1343. HRESULT PropValueArraytoPHPArray(ULONG cValues, LPSPropValue pPropValueArray, zval **pret TSRMLS_DC)
  1344. {
  1345. // return value
  1346. zval * zval_prop_value;
  1347. // local
  1348. zval * zval_mvprop_value; // mvprops converts
  1349. zval * zval_action_array; // action converts
  1350. zval * zval_action_value; // action converts
  1351. zval * zval_alist_value; // adrlist in action convert
  1352. LPSPropValue pPropValue;
  1353. ULONG col, j;
  1354. char ulKey[16];
  1355. ACTIONS *lpActions = NULL;
  1356. LPSRestriction lpRestriction = NULL;
  1357. convert_context converter;
  1358. MAPI_G(hr) = hrSuccess;
  1359. MAKE_STD_ZVAL(zval_prop_value);
  1360. array_init(zval_prop_value);
  1361. for (col = 0; col < cValues; ++col) {
  1362. char pulproptag[16];
  1363. pPropValue = &pPropValueArray[col];
  1364. /*
  1365. * PHP wants a string as array key. PHP will transform this to zval integer when possible.
  1366. * Because MAPI works with ULONGS, some properties (namedproperties) are bigger than LONG_MAX
  1367. * and they will be stored as a zval string.
  1368. * To prevent this we cast the ULONG to a signed long. The number will look a bit weird but it
  1369. * will work.
  1370. */
  1371. sprintf(pulproptag, "%i",PropTagToPHPTag(pPropValue->ulPropTag));
  1372. switch(PROP_TYPE(pPropValue->ulPropTag)) {
  1373. case PT_NULL:
  1374. add_assoc_null(zval_prop_value, pulproptag);
  1375. break;
  1376. case PT_LONG:
  1377. add_assoc_long(zval_prop_value, pulproptag, pPropValue->Value.l);
  1378. break;
  1379. case PT_SHORT:
  1380. add_assoc_long(zval_prop_value, pulproptag, pPropValue->Value.i);
  1381. break;
  1382. case PT_DOUBLE:
  1383. add_assoc_double(zval_prop_value, pulproptag, pPropValue->Value.dbl);
  1384. break;
  1385. case PT_LONGLONG:
  1386. add_assoc_double(zval_prop_value, pulproptag, pPropValue->Value.li.QuadPart);
  1387. break;
  1388. case PT_FLOAT:
  1389. add_assoc_double(zval_prop_value, pulproptag, pPropValue->Value.flt);
  1390. break;
  1391. case PT_BOOLEAN:
  1392. add_assoc_bool(zval_prop_value, pulproptag, pPropValue->Value.b);
  1393. break;
  1394. case PT_STRING8:
  1395. add_assoc_string(zval_prop_value, pulproptag, pPropValue->Value.lpszA, 1);
  1396. break;
  1397. case PT_UNICODE:
  1398. add_assoc_string(zval_prop_value, pulproptag, converter.convert_to<char*>(pPropValue->Value.lpszW), 1);
  1399. break;
  1400. case PT_BINARY:
  1401. add_assoc_stringl(zval_prop_value, pulproptag, (char *)pPropValue->Value.bin.lpb,pPropValue->Value.bin.cb,1);
  1402. break;
  1403. case PT_CURRENCY:
  1404. // to implement
  1405. break;
  1406. case PT_ERROR:
  1407. add_assoc_long(zval_prop_value, pulproptag, (LONG)pPropValue->Value.err);
  1408. break;
  1409. case PT_APPTIME:
  1410. add_assoc_double(zval_prop_value, pulproptag, pPropValue->Value.at);
  1411. break;
  1412. case PT_SYSTIME:
  1413. // convert time to Unix timestamp
  1414. add_assoc_long(zval_prop_value, pulproptag,
  1415. FileTimeToUnixTime(pPropValue->Value.ft.dwHighDateTime,pPropValue->Value.ft.dwLowDateTime));
  1416. break;
  1417. case PT_CLSID:
  1418. add_assoc_stringl(zval_prop_value, pulproptag, (char *)pPropValue->Value.lpguid, sizeof(GUID),1);
  1419. break;
  1420. case PT_MV_I2:
  1421. MAKE_STD_ZVAL(zval_mvprop_value);
  1422. array_init(zval_mvprop_value);
  1423. for (j = 0; j < pPropValue->Value.MVi.cValues; ++j) {
  1424. sprintf(ulKey, "%i", j);
  1425. add_assoc_long(zval_mvprop_value, ulKey, pPropValue->Value.MVi.lpi[j]);
  1426. }
  1427. add_assoc_zval(zval_prop_value, pulproptag, zval_mvprop_value);
  1428. break;
  1429. case PT_MV_LONG:
  1430. MAKE_STD_ZVAL(zval_mvprop_value);
  1431. array_init(zval_mvprop_value);
  1432. for (j = 0; j < pPropValue->Value.MVl.cValues; ++j) {
  1433. sprintf(ulKey, "%i", j);
  1434. add_assoc_long(zval_mvprop_value, ulKey, pPropValue->Value.MVl.lpl[j]);
  1435. }
  1436. add_assoc_zval(zval_prop_value, pulproptag, zval_mvprop_value);
  1437. break;
  1438. case PT_MV_R4:
  1439. MAKE_STD_ZVAL(zval_mvprop_value);
  1440. array_init(zval_mvprop_value);
  1441. for (j = 0; j < pPropValue->Value.MVflt.cValues; ++j) {
  1442. sprintf(ulKey, "%i", j);
  1443. add_assoc_double(zval_mvprop_value, ulKey, pPropValue->Value.MVflt.lpflt[j]);
  1444. }
  1445. add_assoc_zval(zval_prop_value, pulproptag, zval_mvprop_value);
  1446. break;
  1447. case PT_MV_DOUBLE:
  1448. MAKE_STD_ZVAL(zval_mvprop_value);
  1449. array_init(zval_mvprop_value);
  1450. for (j = 0; j < pPropValue->Value.MVdbl.cValues; ++j) {
  1451. sprintf(ulKey, "%i", j);
  1452. add_assoc_double(zval_mvprop_value, ulKey, pPropValue->Value.MVdbl.lpdbl[j]);
  1453. }
  1454. add_assoc_zval(zval_prop_value, pulproptag, zval_mvprop_value);
  1455. break;
  1456. case PT_MV_APPTIME:
  1457. MAKE_STD_ZVAL(zval_mvprop_value);
  1458. array_init(zval_mvprop_value);
  1459. for (j = 0; j < pPropValue->Value.MVat.cValues; ++j) {
  1460. sprintf(ulKey, "%i", j);
  1461. add_assoc_double(zval_mvprop_value, ulKey, pPropValue->Value.MVat.lpat[j]);
  1462. }
  1463. add_assoc_zval(zval_prop_value, pulproptag, zval_mvprop_value);
  1464. break;
  1465. case PT_MV_SYSTIME:
  1466. MAKE_STD_ZVAL(zval_mvprop_value);
  1467. array_init(zval_mvprop_value);
  1468. for (j = 0; j < pPropValue->Value.MVft.cValues; ++j) {
  1469. sprintf(ulKey, "%i", j);
  1470. add_assoc_long(zval_mvprop_value, ulKey,
  1471. FileTimeToUnixTime(pPropValue->Value.MVft.lpft[j].dwHighDateTime,
  1472. pPropValue->Value.MVft.lpft[j].dwLowDateTime));
  1473. }
  1474. add_assoc_zval(zval_prop_value, pulproptag, zval_mvprop_value);
  1475. break;
  1476. case PT_MV_BINARY:
  1477. MAKE_STD_ZVAL(zval_mvprop_value);
  1478. array_init(zval_mvprop_value);
  1479. for (j = 0; j < pPropValue->Value.MVbin.cValues; ++j) {
  1480. sprintf(ulKey, "%i", j);
  1481. add_assoc_stringl(zval_mvprop_value, ulKey,
  1482. (char*)pPropValue->Value.MVbin.lpbin[j].lpb, pPropValue->Value.MVbin.lpbin[j].cb, 1);
  1483. }
  1484. add_assoc_zval(zval_prop_value, pulproptag, zval_mvprop_value);
  1485. break;
  1486. case PT_MV_STRING8:
  1487. MAKE_STD_ZVAL(zval_mvprop_value);
  1488. array_init(zval_mvprop_value);
  1489. for (j = 0; j < pPropValue->Value.MVszA.cValues; ++j) {
  1490. sprintf(ulKey, "%i", j);
  1491. add_assoc_string(zval_mvprop_value, ulKey, pPropValue->Value.MVszA.lppszA[j], 1);
  1492. }
  1493. add_assoc_zval(zval_prop_value, pulproptag, zval_mvprop_value);
  1494. break;
  1495. case PT_MV_UNICODE:
  1496. MAKE_STD_ZVAL(zval_mvprop_value);
  1497. array_init(zval_mvprop_value);
  1498. for (j = 0; j < pPropValue->Value.MVszW.cValues; ++j) {
  1499. sprintf(ulKey, "%i", j);
  1500. add_assoc_string(zval_mvprop_value, ulKey, converter.convert_to<char*>(pPropValue->Value.MVszW.lppszW[j]), 1);
  1501. }
  1502. add_assoc_zval(zval_prop_value, pulproptag, zval_mvprop_value);
  1503. break;
  1504. case PT_MV_CLSID:
  1505. MAKE_STD_ZVAL(zval_mvprop_value);
  1506. array_init(zval_mvprop_value);
  1507. for (j = 0; j < pPropValue->Value.MVguid.cValues; ++j) {
  1508. sprintf(ulKey, "%i", j);
  1509. add_assoc_stringl(zval_mvprop_value, pulproptag, (char *)&pPropValue->Value.MVguid.lpguid[j], sizeof(GUID), 1);
  1510. }
  1511. add_assoc_zval(zval_prop_value, pulproptag, zval_mvprop_value);
  1512. break;
  1513. //case PT_MV_CURRENCY:
  1514. //case PT_MV_I8:
  1515. // rules table properties
  1516. case PT_ACTIONS:
  1517. lpActions = (ACTIONS*)pPropValue->Value.lpszA;
  1518. MAKE_STD_ZVAL(zval_action_array);
  1519. array_init(zval_action_array);
  1520. for (j = 0; j < lpActions->cActions; ++j) {
  1521. MAKE_STD_ZVAL(zval_action_value);
  1522. array_init(zval_action_value);
  1523. add_assoc_long(zval_action_value, "action", lpActions->lpAction[j].acttype);
  1524. add_assoc_long(zval_action_value, "flags", lpActions->lpAction[j].ulFlags);
  1525. add_assoc_long(zval_action_value, "flavor", lpActions->lpAction[j].ulActionFlavor);
  1526. switch (lpActions->lpAction[j].acttype) {
  1527. case OP_MOVE:
  1528. case OP_COPY:
  1529. add_assoc_stringl(zval_action_value, "storeentryid",
  1530. (char*)lpActions->lpAction[j].actMoveCopy.lpStoreEntryId,
  1531. lpActions->lpAction[j].actMoveCopy.cbStoreEntryId, 1);
  1532. add_assoc_stringl(zval_action_value, "folderentryid",
  1533. (char*)lpActions->lpAction[j].actMoveCopy.lpFldEntryId,
  1534. lpActions->lpAction[j].actMoveCopy.cbFldEntryId, 1);
  1535. break;
  1536. case OP_REPLY:
  1537. case OP_OOF_REPLY:
  1538. add_assoc_stringl(zval_action_value, "replyentryid",
  1539. (char*)lpActions->lpAction[j].actReply.lpEntryId,
  1540. lpActions->lpAction[j].actReply.cbEntryId, 1);
  1541. add_assoc_stringl(zval_action_value, "replyguid", (char*)&lpActions->lpAction[j].actReply.guidReplyTemplate, sizeof(GUID), 1);
  1542. break;
  1543. case OP_DEFER_ACTION:
  1544. add_assoc_stringl(zval_action_value, "dam",
  1545. (char*)lpActions->lpAction[j].actDeferAction.pbData,
  1546. lpActions->lpAction[j].actDeferAction.cbData, 1);
  1547. break;
  1548. case OP_BOUNCE:
  1549. add_assoc_long(zval_action_value, "code", lpActions->lpAction[j].scBounceCode);
  1550. break;
  1551. case OP_FORWARD:
  1552. case OP_DELEGATE:
  1553. MAPI_G(hr) = RowSettoPHPArray((LPSRowSet)lpActions->lpAction[j].lpadrlist, &zval_alist_value TSRMLS_CC); // binary compatible
  1554. if(MAPI_G(hr) != hrSuccess)
  1555. return MAPI_G(hr);
  1556. add_assoc_zval(zval_action_value, "adrlist", zval_alist_value);
  1557. break;
  1558. case OP_TAG:
  1559. MAPI_G(hr) = PropValueArraytoPHPArray(1, &lpActions->lpAction[j].propTag, &zval_alist_value TSRMLS_CC);
  1560. if(MAPI_G(hr) != hrSuccess)
  1561. return MAPI_G(hr);
  1562. add_assoc_zval(zval_action_value, "proptag", zval_alist_value);
  1563. break;
  1564. case OP_DELETE:
  1565. case OP_MARK_AS_READ:
  1566. // nothing to add
  1567. break;
  1568. };
  1569. sprintf(ulKey, "%i", j);
  1570. add_assoc_zval(zval_action_array, ulKey, zval_action_value);
  1571. }
  1572. add_assoc_zval(zval_prop_value, pulproptag, zval_action_array);
  1573. break;
  1574. case PT_SRESTRICTION:
  1575. lpRestriction = (LPSRestriction)pPropValue->Value.lpszA;
  1576. zval_action_value = NULL;
  1577. MAPI_G(hr) = SRestrictiontoPHPArray(lpRestriction, 0, &zval_action_value TSRMLS_CC);
  1578. if (MAPI_G(hr) != hrSuccess)
  1579. continue;
  1580. add_assoc_zval(zval_prop_value, pulproptag, zval_action_value);
  1581. break;
  1582. }
  1583. }
  1584. *pret = zval_prop_value;
  1585. return MAPI_G(hr);
  1586. }
  1587. HRESULT RowSettoPHPArray(LPSRowSet lpRowSet, zval **pret TSRMLS_DC) {
  1588. zval *zval_prop_value = NULL;
  1589. ULONG crow = 0;
  1590. zval *ret;
  1591. MAPI_G(hr) = hrSuccess;
  1592. MAKE_STD_ZVAL(ret);
  1593. array_init(ret);
  1594. // make a PHP-array from the rowset resource.
  1595. for (crow = 0; crow < lpRowSet->cRows; ++crow) {
  1596. PropValueArraytoPHPArray(lpRowSet->aRow[crow].cValues, lpRowSet->aRow[crow].lpProps, &zval_prop_value TSRMLS_CC);
  1597. zend_hash_next_index_insert(HASH_OF(ret), &zval_prop_value, sizeof(zval *), NULL);
  1598. }
  1599. *pret = ret;
  1600. return MAPI_G(hr);
  1601. }
  1602. /*
  1603. * Convert from READSTATE array to PHP. Returns a list of arrays, each containing "sourcekey" and "flags" per entry
  1604. */
  1605. HRESULT ReadStateArraytoPHPArray(ULONG cValues, LPREADSTATE lpReadStates, zval **ppvalRet TSRMLS_DC)
  1606. {
  1607. zval *pvalRet;
  1608. unsigned int i=0;
  1609. MAPI_G(hr) = hrSuccess;
  1610. MAKE_STD_ZVAL(pvalRet);
  1611. array_init(pvalRet);
  1612. for (i = 0; i < cValues; ++i) {
  1613. zval *pvalEntry;
  1614. MAKE_STD_ZVAL(pvalEntry);
  1615. array_init(pvalEntry);
  1616. add_assoc_stringl(pvalEntry, "sourcekey", (char *)lpReadStates[i].pbSourceKey, lpReadStates[i].cbSourceKey, 1);
  1617. add_assoc_long(pvalEntry, "flags", lpReadStates[i].ulFlags);
  1618. add_next_index_zval(pvalRet, pvalEntry);
  1619. }
  1620. *ppvalRet = pvalRet;
  1621. return MAPI_G(hr);
  1622. }
  1623. /*
  1624. * Convert from PHP to READSTATE array.
  1625. */
  1626. HRESULT PHPArraytoReadStateArray(zval *zvalReadStates, void *lpBase, ULONG *lpcValues, LPREADSTATE *lppReadStates TSRMLS_DC)
  1627. {
  1628. LPREADSTATE lpReadStates = NULL;
  1629. HashTable *target_hash = NULL;
  1630. int count;
  1631. zval **ppentry = NULL;
  1632. zval *pentry = NULL;
  1633. zval **valueEntry = NULL;
  1634. int n = 0, i = 0;
  1635. MAPI_G(hr) = hrSuccess;
  1636. target_hash = HASH_OF(zvalReadStates);
  1637. if (!target_hash) {
  1638. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No target_hash in PHPArraytoReadStateArray");
  1639. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1640. goto exit;
  1641. }
  1642. count = zend_hash_num_elements(Z_ARRVAL_P(zvalReadStates));
  1643. MAPI_G(hr) = MAPI_ALLOC(sizeof(READSTATE) * count, lpBase, (void **) &lpReadStates);
  1644. if(MAPI_G(hr) != hrSuccess)
  1645. goto exit;
  1646. // Reset php pointer
  1647. zend_hash_internal_pointer_reset(target_hash);
  1648. for (i = 0; i < count; ++i) {
  1649. zend_hash_get_current_data(target_hash, (void **) &ppentry);
  1650. pentry = *ppentry;
  1651. if(zend_hash_find(HASH_OF(pentry), "sourcekey", sizeof("sourcekey"), (void **)&valueEntry) == FAILURE) {
  1652. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No 'sourcekey' entry for one of the entries in the readstate list");
  1653. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1654. goto exit;
  1655. }
  1656. convert_to_string_ex(valueEntry);
  1657. MAPI_G(hr) = MAPIAllocateMore(valueEntry[0]->value.str.len, lpBase ? lpBase : lpReadStates, (void **) &lpReadStates[n].pbSourceKey);
  1658. if(MAPI_G(hr) != hrSuccess)
  1659. goto exit;
  1660. memcpy(lpReadStates[n].pbSourceKey, valueEntry[0]->value.str.val, valueEntry[0]->value.str.len);
  1661. lpReadStates[n].cbSourceKey = valueEntry[0]->value.str.len;
  1662. if(zend_hash_find(HASH_OF(pentry), "flags", sizeof("flags"), (void **)&valueEntry) == FAILURE) {
  1663. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No 'flags' entry for one of the entries in the readstate list");
  1664. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1665. goto exit;
  1666. }
  1667. convert_to_long_ex(valueEntry);
  1668. lpReadStates[n++].ulFlags = valueEntry[0]->value.lval;
  1669. }
  1670. *lppReadStates = lpReadStates;
  1671. *lpcValues = n;
  1672. exit:
  1673. if (MAPI_G(hr) != hrSuccess && lpBase == NULL)
  1674. MAPIFreeBuffer(lpReadStates);
  1675. return MAPI_G(hr);
  1676. }
  1677. HRESULT PHPArraytoGUIDArray(zval *phpVal, void *lpBase, ULONG *lpcValues, LPGUID *lppGUIDs TSRMLS_DC)
  1678. {
  1679. HashTable *target_hash = NULL;
  1680. LPGUID lpGUIDs = NULL;
  1681. int count = 0;
  1682. int n = 0;
  1683. int i = 0;
  1684. zval **ppentry = NULL;
  1685. zval *pentry = NULL;
  1686. MAPI_G(hr) = hrSuccess;
  1687. target_hash = HASH_OF(phpVal);
  1688. if (!target_hash) {
  1689. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No target_hash in PHPArraytoGUIDArray");
  1690. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1691. goto exit;
  1692. }
  1693. count = zend_hash_num_elements(Z_ARRVAL_P(phpVal));
  1694. if (count == 0) {
  1695. *lppGUIDs = NULL;
  1696. *lpcValues = 0;
  1697. goto exit;
  1698. }
  1699. MAPI_G(hr) = MAPI_ALLOC(sizeof(GUID) * count, lpBase, (void **) &lpGUIDs);
  1700. if(MAPI_G(hr) != hrSuccess)
  1701. goto exit;
  1702. zend_hash_internal_pointer_reset(target_hash);
  1703. for (i = 0; i < count; ++i) {
  1704. zend_hash_get_current_data(target_hash, (void **) &ppentry);
  1705. pentry = *ppentry;
  1706. convert_to_string_ex(&pentry);
  1707. if(pentry->value.str.len != sizeof(GUID)){
  1708. php_error_docref(NULL TSRMLS_CC, E_WARNING, "GUID must be 16 bytes");
  1709. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1710. goto exit;
  1711. }
  1712. memcpy(&lpGUIDs[n++], pentry->value.str.val, sizeof(GUID));
  1713. zend_hash_move_forward(target_hash);
  1714. }
  1715. *lppGUIDs = lpGUIDs;
  1716. *lpcValues = n;
  1717. exit:
  1718. if (MAPI_G(hr) != hrSuccess && lpBase == NULL)
  1719. MAPIFreeBuffer(lpGUIDs);
  1720. return MAPI_G(hr);
  1721. }
  1722. HRESULT NotificationstoPHPArray(ULONG cNotifs, LPNOTIFICATION lpNotifs, zval **pret TSRMLS_DC)
  1723. {
  1724. zval *zvalRet = NULL;
  1725. zval *zvalProps = NULL;
  1726. unsigned int i = 0;
  1727. MAPI_G(hr) = hrSuccess;
  1728. MAKE_STD_ZVAL(zvalRet);
  1729. array_init(zvalRet);
  1730. for (i = 0; i < cNotifs; ++i) {
  1731. zval *zvalNotif = NULL;
  1732. MAKE_STD_ZVAL(zvalNotif);
  1733. array_init(zvalNotif);
  1734. add_assoc_long(zvalNotif, "eventtype", lpNotifs[i].ulEventType);
  1735. switch(lpNotifs[i].ulEventType) {
  1736. case fnevNewMail:
  1737. add_assoc_stringl(zvalNotif, "entryid", (char *)lpNotifs[i].info.newmail.lpEntryID, lpNotifs[i].info.newmail.cbEntryID, 1);
  1738. add_assoc_stringl(zvalNotif, "parentid", (char *)lpNotifs[i].info.newmail.lpParentID, lpNotifs[i].info.newmail.cbParentID, 1);
  1739. add_assoc_long(zvalNotif, "flags", lpNotifs[i].info.newmail.ulFlags);
  1740. add_assoc_string(zvalNotif, "messageclass", (char *)lpNotifs[i].info.newmail.lpszMessageClass, 1);
  1741. add_assoc_long(zvalNotif, "messageflags", lpNotifs[i].info.newmail.ulMessageFlags);
  1742. break;
  1743. case fnevObjectCreated:
  1744. case fnevObjectDeleted:
  1745. case fnevObjectModified:
  1746. case fnevObjectMoved:
  1747. case fnevObjectCopied:
  1748. case fnevSearchComplete:
  1749. if (lpNotifs[i].info.obj.lpEntryID)
  1750. add_assoc_stringl(zvalNotif, "entryid", (char *)lpNotifs[i].info.obj.lpEntryID, lpNotifs[i].info.obj.cbEntryID, 1);
  1751. add_assoc_long(zvalNotif, "objtype", lpNotifs[i].info.obj.ulObjType);
  1752. if (lpNotifs[i].info.obj.lpParentID)
  1753. add_assoc_stringl(zvalNotif, "parentid", (char *)lpNotifs[i].info.obj.lpParentID, lpNotifs[i].info.obj.cbParentID, 1);
  1754. if (lpNotifs[i].info.obj.lpOldID)
  1755. add_assoc_stringl(zvalNotif, "oldid", (char *)lpNotifs[i].info.obj.lpOldID, lpNotifs[i].info.obj.cbOldID, 1);
  1756. if (lpNotifs[i].info.obj.lpOldParentID)
  1757. add_assoc_stringl(zvalNotif, "oldparentid", (char *)lpNotifs[i].info.obj.lpOldParentID, lpNotifs[i].info.obj.cbOldParentID, 1);
  1758. if (lpNotifs[i].info.obj.lpPropTagArray) {
  1759. MAPI_G(hr) = PropTagArraytoPHPArray(lpNotifs[i].info.obj.lpPropTagArray->cValues, lpNotifs[i].info.obj.lpPropTagArray, &zvalProps TSRMLS_CC);
  1760. if (MAPI_G(hr) != hrSuccess)
  1761. return MAPI_G(hr);
  1762. add_assoc_zval(zvalNotif, "proptagarray", zvalProps);
  1763. }
  1764. break;
  1765. default:
  1766. break;
  1767. }
  1768. add_next_index_zval(zvalRet, zvalNotif);
  1769. }
  1770. *pret = zvalRet;
  1771. return MAPI_G(hr);
  1772. }
  1773. HRESULT PHPArraytoSendingOptions(zval *phpArray, sending_options *lpSOPT)
  1774. {
  1775. HRESULT hr = hrSuccess;
  1776. // local
  1777. int count;
  1778. HashTable *target_hash = NULL;
  1779. zval **entry = NULL;
  1780. char *keyIndex;
  1781. ulong numIndex = 0;
  1782. if (!phpArray) {
  1783. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No phpArray in PHPArraytoSendingOptions");
  1784. // not an error
  1785. return hr;
  1786. }
  1787. target_hash = HASH_OF(phpArray);
  1788. if (!target_hash) {
  1789. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No target_hash in PHPArraytoSendingOptions");
  1790. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1791. return hr;
  1792. }
  1793. count = zend_hash_num_elements(target_hash);
  1794. zend_hash_internal_pointer_reset(target_hash);
  1795. for (int i = 0; i < count; ++i) {
  1796. // Gets the element that exist at the current pointer.
  1797. zend_hash_get_current_data(target_hash, (void **) &entry);
  1798. zend_hash_get_current_key(target_hash, &keyIndex, &numIndex, 0);
  1799. if (strcmp(keyIndex, "alternate_boundary") == 0) {
  1800. convert_to_string_ex(entry);
  1801. lpSOPT->alternate_boundary = Z_STRVAL_PP(entry);
  1802. } else if (strcmp(keyIndex, "no_recipients_workaround") == 0) {
  1803. convert_to_boolean_ex(entry);
  1804. lpSOPT->no_recipients_workaround = Z_BVAL_PP(entry);
  1805. } else if (strcmp(keyIndex, "headers_only") == 0) {
  1806. convert_to_boolean_ex(entry);
  1807. lpSOPT->headers_only = Z_BVAL_PP(entry);
  1808. } else if (strcmp(keyIndex, "add_received_date") == 0) {
  1809. convert_to_boolean_ex(entry);
  1810. lpSOPT->add_received_date = Z_BVAL_PP(entry);
  1811. } else if (strcmp(keyIndex, "use_tnef") == 0) {
  1812. convert_to_long_ex(entry);
  1813. lpSOPT->use_tnef = Z_LVAL_PP(entry);
  1814. } else if (strcmp(keyIndex, "force_utf8") == 0) {
  1815. convert_to_boolean_ex(entry);
  1816. lpSOPT->force_utf8 = Z_BVAL_PP(entry);
  1817. } else if (strcmp(keyIndex, "charset_upgrade") == 0) {
  1818. convert_to_string_ex(entry);
  1819. lpSOPT->charset_upgrade = Z_STRVAL_PP(entry);
  1820. } else if (strcmp(keyIndex, "allow_send_to_everyone") == 0) {
  1821. convert_to_boolean_ex(entry);
  1822. lpSOPT->force_utf8 = Z_BVAL_PP(entry);
  1823. } else {
  1824. // msg_in_msg and enable_dsn not allowed, others unknown
  1825. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or disallowed sending option %s", keyIndex);
  1826. }
  1827. zend_hash_move_forward(target_hash);
  1828. }
  1829. return hr;
  1830. }
  1831. HRESULT PHPArraytoDeliveryOptions(zval *phpArray, delivery_options *lpDOPT)
  1832. {
  1833. HRESULT hr = hrSuccess;
  1834. // local
  1835. int count;
  1836. HashTable *target_hash = NULL;
  1837. zval **entry = NULL;
  1838. char *keyIndex;
  1839. ulong numIndex = 0;
  1840. if (!phpArray) {
  1841. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No phpArray in PHPArraytoDeliveryOptions");
  1842. // not an error
  1843. return hr;
  1844. }
  1845. target_hash = HASH_OF(phpArray);
  1846. if (!target_hash) {
  1847. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No target_hash in PHPArraytoDeliveryOptions");
  1848. MAPI_G(hr) = MAPI_E_INVALID_PARAMETER;
  1849. return hr;
  1850. }
  1851. count = zend_hash_num_elements(target_hash);
  1852. zend_hash_internal_pointer_reset(target_hash);
  1853. for (int i = 0; i < count; ++i) {
  1854. // Gets the element that exist at the current pointer.
  1855. zend_hash_get_current_data(target_hash, (void **) &entry);
  1856. zend_hash_get_current_key(target_hash, &keyIndex, &numIndex, 0);
  1857. if (strcmp(keyIndex, "use_received_date") == 0) {
  1858. convert_to_boolean_ex(entry);
  1859. lpDOPT->use_received_date = Z_BVAL_PP(entry);
  1860. } else if (strcmp(keyIndex, "mark_as_read") == 0) {
  1861. convert_to_boolean_ex(entry);
  1862. lpDOPT->mark_as_read = Z_BVAL_PP(entry);
  1863. } else if (strcmp(keyIndex, "add_imap_date") == 0) {
  1864. convert_to_boolean_ex(entry);
  1865. lpDOPT->add_imap_data = Z_BVAL_PP(entry);
  1866. } else if (strcmp(keyIndex, "parse_smime_signed") == 0) {
  1867. convert_to_boolean_ex(entry);
  1868. lpDOPT->parse_smime_signed = Z_BVAL_PP(entry);
  1869. } else if (strcmp(keyIndex, "default_charset") == 0) {
  1870. convert_to_string_ex(entry);
  1871. lpDOPT->ascii_upgrade = Z_STRVAL_PP(entry);
  1872. } else {
  1873. // user_entryid not supported, others unknown
  1874. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or disallowed delivery option %s", keyIndex);
  1875. }
  1876. zend_hash_move_forward(target_hash);
  1877. }
  1878. return hr;
  1879. }