352
385
if (mailboxstore == true) {
353
386
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
354
LDB_SCOPE_SUBTREE, attrs, "(PidTagFolderId=0x%.16"PRIx64")", fid);
356
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_root_basedn(ldb_ctx),
357
LDB_SCOPE_SUBTREE, attrs, "(PidTagFolderId=0x%.16"PRIx64")", fid);
360
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
362
*mapistoreURL = talloc_strdup(parent_ctx, ldb_msg_find_attr_as_string(res->msgs[0], "mapistore_uri", NULL));
364
talloc_free(mem_ctx);
366
return MAPI_E_SUCCESS;
387
LDB_SCOPE_SUBTREE, attrs, "(PidTagFolderId=%"PRIu64")", fid);
389
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_root_basedn(ldb_ctx),
390
LDB_SCOPE_SUBTREE, attrs, "(PidTagFolderId=%"PRIu64")", fid);
393
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
395
*mapistoreURL = talloc_strdup(parent_ctx, ldb_msg_find_attr_as_string(res->msgs[0], "MAPIStoreURI", NULL));
397
talloc_free(mem_ctx);
399
return MAPI_E_SUCCESS;
403
\details Retrieve the parent fid associated to a mailbox system
406
\param ldb_ctx pointer to the openchange LDB context
407
\param fid the Folder identifier to search for
408
\param parent_fidp pointer to the parent_fid the function returns
409
\param mailboxstore boolean value which defines whether the record
410
has to be searched within Public folders hierarchy or not
412
\return MAPI_E_SUCCESS on success, otherwise MAPI_E_NOT_FOUND
414
_PUBLIC_ enum MAPISTATUS openchangedb_get_parent_fid(struct ldb_context *ldb_ctx,
416
uint64_t *parent_fidp,
420
struct ldb_result *res = NULL;
421
const char * const attrs[] = { "*", NULL };
424
mem_ctx = talloc_named(NULL, 0, "get_parent_fid");
426
if (mailboxstore == true) {
427
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
428
LDB_SCOPE_SUBTREE, attrs, "(PidTagFolderId=%"PRIu64")", fid);
430
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_root_basedn(ldb_ctx),
431
LDB_SCOPE_SUBTREE, attrs, "(PidTagFolderId=%"PRIu64")", fid);
433
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
434
*parent_fidp = ldb_msg_find_attr_as_uint64(res->msgs[0], "PidTagParentFolderId", 0x0);
436
talloc_free(mem_ctx);
438
return MAPI_E_SUCCESS;
442
\details Retrieve the fid associated with a mapistore URI.
444
\param ldb_ctx pointer to the openchange LDB context
445
\param fid the Folder identifier to search for
446
\param mapistoreURL pointer on pointer to the mapistore URI the
448
\param mailboxstore boolean value which defines whether the record
449
has to be searched within Public folders hierarchy or not
451
\return MAPI_E_SUCCESS on success, otherwise MAPI_E_NOT_FOUND
453
_PUBLIC_ enum MAPISTATUS openchangedb_get_fid(struct ldb_context *ldb_ctx, const char *mapistoreURL, uint64_t *fidp)
456
struct ldb_result *res = NULL;
457
const char * const attrs[] = { "*", NULL };
462
mem_ctx = talloc_named(NULL, 0, "openchangedb_get_fid");
464
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
465
LDB_SCOPE_SUBTREE, attrs, "(MAPIStoreURI=%s)", mapistoreURL);
466
if (ret != LDB_SUCCESS || !res->count) {
467
len = strlen(mapistoreURL);
468
if (mapistoreURL[len-1] == '/') {
469
slashLessURL = talloc_strdup(mem_ctx, mapistoreURL);
470
slashLessURL[len-1] = 0;
471
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), LDB_SCOPE_SUBTREE, attrs, "(MAPIStoreURI=%s)", slashLessURL);
473
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
475
*fidp = ldb_msg_find_attr_as_uint64(res->msgs[0], "PidTagFolderId", 0x0);
477
talloc_free(mem_ctx);
479
return MAPI_E_SUCCESS;
483
\details Retrieve a list of mapistore URI in use for a certain user
485
\param ldb_ctx pointer to the openchange LDB context
486
\param fid the Folder identifier to search for
487
\param mapistoreURL pointer on pointer to the mapistore URI the
489
\param mailboxstore boolean value which defines whether the record
490
has to be searched within Public folders hierarchy or not
492
\return MAPI_E_SUCCESS on success, otherwise MAPI_E_NOT_FOUND
494
_PUBLIC_ enum MAPISTATUS openchangedb_get_MAPIStoreURIs(struct ldb_context *ldb_ctx, const char *username, TALLOC_CTX *mem_ctx, struct StringArrayW_r **urisP)
496
TALLOC_CTX *local_mem_ctx;
497
struct ldb_result *res = NULL;
499
const char * const attrs[] = { "*", NULL };
501
int i, elements, ret;
502
struct StringArrayW_r *uris;
504
local_mem_ctx = talloc_named(NULL, 0, "openchangedb_get_fid");
506
/* fetch mailbox DN */
507
ret = ldb_search(ldb_ctx, local_mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
508
LDB_SCOPE_SUBTREE, attrs, "(&(cn=%s)(MailboxGUID=*))", username);
509
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, local_mem_ctx);
511
dnstr = talloc_strdup(local_mem_ctx, ldb_msg_find_attr_as_string(res->msgs[0], "distinguishedName", NULL));
512
OPENCHANGE_RETVAL_IF(!dnstr, MAPI_E_NOT_FOUND, local_mem_ctx);
513
dn = ldb_dn_new(local_mem_ctx, ldb_ctx, dnstr);
515
uris = talloc_zero(mem_ctx, struct StringArrayW_r);
516
uris->lppszW = talloc_zero(uris, const char *);
521
/* search subfolders which have a non-null mapistore uri */
522
ret = ldb_search(ldb_ctx, local_mem_ctx, &res, dn, LDB_SCOPE_SUBTREE, attrs, "(MAPIStoreURI=*)");
523
if (ret == LDB_SUCCESS) {
524
for (i = 0; i < res->count; i++) {
525
if ((uris->cValues + 1) > elements) {
526
elements = uris->cValues + 16;
527
uris->lppszW = talloc_realloc(uris, uris->lppszW, const char *, elements);
529
uris->lppszW[uris->cValues] = talloc_strdup(uris, ldb_msg_find_attr_as_string(res->msgs[i], "MAPIStoreURI", NULL));
534
talloc_free(local_mem_ctx);
536
return MAPI_E_SUCCESS;
371
540
\details Retrieve the Explicit message class and Folder identifier
372
541
associated to the MessageClass search pattern.
374
543
\param parent_ctx pointer to the memory context
375
\param _ldb_ctx pointer to the openchange LDB context
544
\param ldb_ctx pointer to the openchange LDB context
376
545
\param recipient pointer to the mailbox's username
377
546
\param MessageClass substring to search for
378
547
\param fid pointer to the folder identifier the function returns
468
632
OPENCHANGE_RETVAL_IF(!*ExplicitMessageClass, MAPI_E_NOT_FOUND, mem_ctx);
469
DEBUG(5, ("openchangedb_get_ReceiveFolder, fid: 0x%016"PRIx64"\n", *fid));
471
talloc_free(mem_ctx);
473
return MAPI_E_SUCCESS;
633
DEBUG(5, ("openchangedb_get_ReceiveFolder, fid: %.16"PRIx64"\n", *fid));
635
talloc_free(mem_ctx);
637
return MAPI_E_SUCCESS;
642
\details Retrieve the Transport Folder FolderID for given recipient from openchange dispatcher database
644
\param ldb_ctx pointer to the OpenChange LDB context
645
\param recipient the mailbox username
646
\param FolderId pointer to the folder identifier the function returns
648
\return MAPI_E_SUCCESS on success, otherwise MAPI error
650
_PUBLIC_ enum MAPISTATUS openchangedb_get_TransportFolder(struct ldb_context *ldb_ctx, const char *recipient, uint64_t *FolderId)
653
struct ldb_result *res = NULL;
654
const char * const attrs[] = { "*", NULL };
657
struct ldb_dn *ldb_dn = NULL;
660
OPENCHANGE_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
661
OPENCHANGE_RETVAL_IF(!recipient, MAPI_E_INVALID_PARAMETER, NULL);
662
OPENCHANGE_RETVAL_IF(!FolderId, MAPI_E_INVALID_PARAMETER, NULL);
664
mem_ctx = talloc_named(NULL, 0, "get_TransportFolder");
666
/* Step 1. Find mailbox DN for the recipient */
667
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
668
LDB_SCOPE_SUBTREE, attrs, "CN=%s", recipient);
669
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
671
dnstr = talloc_strdup(mem_ctx, ldb_msg_find_attr_as_string(res->msgs[0], "distinguishedName", NULL));
672
OPENCHANGE_RETVAL_IF(!dnstr, MAPI_E_NOT_FOUND, mem_ctx);
676
/* Step 2. Find "Outbox" in user mailbox */
677
ldb_dn = ldb_dn_new(mem_ctx, ldb_ctx, dnstr);
680
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_dn, LDB_SCOPE_SUBTREE, attrs, "(PidTagDisplayName=%s)", "Outbox");
681
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
683
/* Step 2. If Mailbox root folder, check for FolderID within current record */
684
*FolderId = ldb_msg_find_attr_as_uint64(res->msgs[0], "PidTagFolderId", 0);
685
OPENCHANGE_RETVAL_IF(!*FolderId, MAPI_E_CORRUPT_STORE, mem_ctx);
687
talloc_free(mem_ctx);
689
return MAPI_E_SUCCESS;
478
693
\details Retrieve the number of sub folders for a given fid
480
\param _ldb_ctx pointer to the openchange LDB context
695
\param ldb_ctx pointer to the openchange LDB context
481
696
\param fid the folder identifier to use for the search
482
697
\param RowCount pointer to the returned number of results
484
699
\return MAPI_E_SUCCESS on success, otherwise MAPI_E_NOT_FOUND
486
_PUBLIC_ enum MAPISTATUS openchangedb_get_folder_count(void *_ldb_ctx,
701
_PUBLIC_ enum MAPISTATUS openchangedb_get_folder_count(struct ldb_context *ldb_ctx, uint64_t fid, uint32_t *RowCount)
490
703
TALLOC_CTX *mem_ctx;
491
struct ldb_context *ldb_ctx = (struct ldb_context *)_ldb_ctx;
492
704
struct ldb_result *res;
493
705
const char * const attrs[] = { "*", NULL };
709
OPENCHANGE_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
710
OPENCHANGE_RETVAL_IF(!RowCount, MAPI_E_INVALID_PARAMETER, NULL);
496
712
mem_ctx = talloc_named(NULL, 0, "get_folder_count");
499
715
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
500
716
LDB_SCOPE_SUBTREE, attrs,
501
"(PidTagParentFolderId=0x%.16"PRIx64")(PidTagFolderId=*)", fid);
717
"(PidTagParentFolderId=%"PRIu64")(PidTagFolderId=*)", fid);
503
718
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, mem_ctx);
505
720
*RowCount = res->count;
619
895
\return valid data pointer on success, otherwise NULL
621
static void *openchangedb_get_folder_property_data(TALLOC_CTX *mem_ctx,
622
struct ldb_result *res,
625
const char *PidTagAttr)
897
void *openchangedb_get_property_data(TALLOC_CTX *mem_ctx,
898
struct ldb_result *res,
901
const char *PidTagAttr)
903
return openchangedb_get_property_data_message(mem_ctx, res->msgs[pos],
904
proptag, PidTagAttr);
908
\details Retrieve a MAPI property from an OpenChange LDB message
910
\param mem_ctx pointer to the memory context
911
\param msg pointer to the LDB message
912
\param proptag the MAPI property tag to lookup
913
\param PidTagAttr the mapped MAPI property name
915
\return valid data pointer on success, otherwise NULL
917
void *openchangedb_get_property_data_message(TALLOC_CTX *mem_ctx,
918
struct ldb_message *msg,
920
const char *PidTagAttr)
928
struct Binary_r *bin;
929
struct BinaryArray_r *bin_array;
930
struct LongArray_r *long_array;
932
TALLOC_CTX *local_mem_ctx;
633
934
switch (proptag & 0xFFFF) {
635
936
b = talloc_zero(mem_ctx, int);
636
*b = ldb_msg_find_attr_as_bool(res->msgs[pos], PidTagAttr, 0x0);
937
*b = ldb_msg_find_attr_as_bool(msg, PidTagAttr, 0x0);
637
938
data = (void *)b;
640
941
l = talloc_zero(mem_ctx, uint32_t);
641
*l = ldb_msg_find_attr_as_int(res->msgs[pos], PidTagAttr, 0x0);
942
*l = ldb_msg_find_attr_as_uint(msg, PidTagAttr, 0x0);
642
943
data = (void *)l;
645
str = ldb_msg_find_attr_as_string(res->msgs[pos], PidTagAttr, 0x0);
646
d = talloc_zero(mem_ctx, uint64_t);
647
*d = strtoull(str, NULL, 16);
946
ll = talloc_zero(mem_ctx, uint64_t);
947
*ll = ldb_msg_find_attr_as_uint64(msg, PidTagAttr, 0x0);
652
str = ldb_msg_find_attr_as_string(res->msgs[pos], PidTagAttr, NULL);
653
data = (char *) talloc_strdup(mem_ctx, str);
952
str = ldb_msg_find_attr_as_string(msg, PidTagAttr, NULL);
953
local_mem_ctx = talloc_zero(NULL, TALLOC_CTX);
954
val = ldb_binary_decode(local_mem_ctx, str);
955
data = (char *) talloc_strndup(mem_ctx, (char *) val.data, val.length);
956
talloc_free(local_mem_ctx);
959
ft = talloc_zero(mem_ctx, struct FILETIME);
960
ll = talloc_zero(mem_ctx, uint64_t);
961
*ll = ldb_msg_find_attr_as_uint64(msg, PidTagAttr, 0x0);
962
ft->dwLowDateTime = (*ll & 0xffffffff);
963
ft->dwHighDateTime = *ll >> 32;
968
str = ldb_msg_find_attr_as_string(msg, PidTagAttr, 0x0);
969
bin = talloc_zero(mem_ctx, struct Binary_r);
970
bin->lpb = (uint8_t *) talloc_strdup(mem_ctx, str);
971
bin->cb = ldb_base64_decode((char *) bin->lpb);
975
str = ldb_msg_find_attr_as_string(msg, PidTagAttr, NULL);
976
bin_array = decode_mv_binary(mem_ctx, str);
977
data = (void *)bin_array;
980
str = ldb_msg_find_attr_as_string(msg, PidTagAttr, NULL);
981
long_array = decode_mv_long(mem_ctx, str);
982
data = (void *)long_array;
656
talloc_free(mem_ctx);
657
985
DEBUG(0, ("[%s:%d] Property Type 0x%.4x not supported\n", __FUNCTION__, __LINE__, (proptag & 0xFFFF)));
666
\details Return the next available FolderID
668
\param _ldb_ctx pointer to the openchange LDB context
669
\param fid pointer to the fid value the function returns
671
\return MAPI_E_SUCCESS on success, otherwise MAPI error
673
_PUBLIC_ enum MAPISTATUS openchangedb_get_new_folderID(void *_ldb_ctx,
678
struct ldb_context *ldb_ctx = (struct ldb_context *)_ldb_ctx;
679
struct ldb_result *res = NULL;
680
struct ldb_message *msg;
681
const char * const attrs[] = { "*", NULL };
685
mem_ctx = talloc_named(NULL, 0, "get_new_folderID");
994
\details Build a MAPI property suitable for a OpenChange LDB message
996
\param mem_ctx pointer to the memory context
997
\param value the MAPI property
999
\return valid string pointer on success, otherwise NULL
1001
_PUBLIC_ char *openchangedb_set_folder_property_data(TALLOC_CTX *mem_ctx,
1002
struct SPropValue *value)
1004
char *data, *subdata;
1005
struct SPropValue *subvalue;
1008
size_t data_len, subdata_len;
1009
struct BinaryArray_r *bin_array;
1011
switch (value->ulPropTag & 0xFFFF) {
1013
data = talloc_strdup(mem_ctx, value->value.b ? "TRUE" : "FALSE");
1016
data = talloc_asprintf(mem_ctx, "%d", value->value.l);
1019
data = talloc_asprintf(mem_ctx, "%"PRIu64, value->value.d);
1022
data = talloc_strdup(mem_ctx, value->value.lpszA);
1025
data = talloc_strdup(mem_ctx, value->value.lpszW);
1028
nt_time = ((uint64_t) value->value.ft.dwHighDateTime << 32) | value->value.ft.dwLowDateTime;
1029
data = talloc_asprintf(mem_ctx, "%"PRIu64, nt_time);
1032
data = ldb_base64_encode(mem_ctx, (char *) value->value.bin.lpb, value->value.bin.cb);
1035
bin_array = &value->value.MVbin;
1036
data = talloc_asprintf(mem_ctx, "0x%.8x", bin_array->cValues);
1037
data_len = strlen(data);
1038
for (i = 0; i < bin_array->cValues; i++) {
1039
subvalue = talloc_zero(NULL, struct SPropValue);
1040
subvalue->ulPropTag = (value->ulPropTag & 0xffff0fff);
1041
subvalue->value.bin = bin_array->lpbin[i];
1042
subdata = openchangedb_set_folder_property_data(subvalue, subvalue);
1043
subdata_len = strlen(subdata);
1044
data = talloc_realloc(mem_ctx, data, char, data_len + subdata_len + 2);
1045
*(data + data_len) = ';';
1046
memcpy(data + data_len + 1, subdata, subdata_len);
1047
data_len += subdata_len + 1;
1048
talloc_free(subvalue);
1050
*(data + data_len) = 0;
1053
DEBUG(0, ("[%s:%d] Property Type 0x%.4x not supported\n", __FUNCTION__, __LINE__, (value->ulPropTag & 0xFFFF)));
1061
\details Allocates a new FolderID and returns it
1063
\param ldb_ctx pointer to the openchange LDB context
1064
\param fid pointer to the fid value the function returns
1066
\return MAPI_E_SUCCESS on success, otherwise MAPI error
1068
_PUBLIC_ enum MAPISTATUS openchangedb_get_new_folderID(struct ldb_context *ldb_ctx, uint64_t *fid)
1070
TALLOC_CTX *mem_ctx;
1072
struct ldb_result *res;
1073
struct ldb_message *msg;
1074
const char * const attrs[] = { "*", NULL };
1076
/* Get the current GlobalCount */
1077
mem_ctx = talloc_named(NULL, 0, "get_next_folderID");
1078
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_root_basedn(ldb_ctx),
1079
LDB_SCOPE_SUBTREE, attrs, "(objectClass=server)");
1080
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
1082
*fid = ldb_msg_find_attr_as_uint64(res->msgs[0], "GlobalCount", 0);
1084
/* Update GlobalCount value */
1085
msg = ldb_msg_new(mem_ctx);
1086
msg->dn = ldb_dn_copy(msg, ldb_msg_find_attr_as_dn(ldb_ctx, mem_ctx, res->msgs[0], "distinguishedName"));
1087
ldb_msg_add_fmt(msg, "GlobalCount", "%"PRIu64, ((*fid) + 1));
1088
msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
1089
ret = ldb_modify(ldb_ctx, msg);
1090
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
1092
talloc_free(mem_ctx);
1094
*fid = (exchange_globcnt(*fid) << 16) | 0x0001;
1096
return MAPI_E_SUCCESS;
1100
\details Allocates a new change number and returns it
1102
\param ldb_ctx pointer to the openchange LDB context
1103
\param cn pointer to the cn value the function returns
1105
\return MAPI_E_SUCCESS on success, otherwise MAPI error
1107
_PUBLIC_ enum MAPISTATUS openchangedb_get_new_changeNumber(struct ldb_context *ldb_ctx, uint64_t *cn)
1109
TALLOC_CTX *mem_ctx;
1111
struct ldb_result *res;
1112
struct ldb_message *msg;
1113
const char * const attrs[] = { "*", NULL };
1115
/* Get the current GlobalCount */
1116
mem_ctx = talloc_named(NULL, 0, "get_next_changeNumber");
1117
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_root_basedn(ldb_ctx),
1118
LDB_SCOPE_SUBTREE, attrs, "(objectClass=server)");
1119
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
1121
*cn = ldb_msg_find_attr_as_uint64(res->msgs[0], "ChangeNumber", 1);
1123
/* Update GlobalCount value */
1124
msg = ldb_msg_new(mem_ctx);
1125
msg->dn = ldb_dn_copy(msg, ldb_msg_find_attr_as_dn(ldb_ctx, mem_ctx, res->msgs[0], "distinguishedName"));
1126
ldb_msg_add_fmt(msg, "ChangeNumber", "%"PRIu64, ((*cn) + 1));
1127
msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
1128
ret = ldb_modify(ldb_ctx, msg);
1129
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
1131
talloc_free(mem_ctx);
1133
*cn = (exchange_globcnt(*cn) << 16) | 0x0001;
1135
return MAPI_E_SUCCESS;
1139
\details Reserve a range of FMID
1141
\param ldb_ctx pointer to the openchange LDB context
1142
\param fid pointer to the fid value the function returns
1144
\return MAPI_E_SUCCESS on success, otherwise MAPI error
1146
_PUBLIC_ enum MAPISTATUS openchangedb_reserve_fmid_range(struct ldb_context *ldb_ctx,
1148
uint64_t *first_fmidp)
1150
TALLOC_CTX *mem_ctx;
1152
struct ldb_result *res;
1153
struct ldb_message *msg;
1155
const char * const attrs[] = { "*", NULL };
687
1157
/* Step 1. Get the current GlobalCount */
1158
mem_ctx = talloc_named(NULL, 0, "get_next_folderID");
688
1159
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_root_basedn(ldb_ctx),
689
1160
LDB_SCOPE_SUBTREE, attrs, "(objectClass=server)");
690
1161
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
692
*fid = ldb_msg_find_attr_as_uint64(res->msgs[0], "GlobalCount", 0);
1163
fmid = ldb_msg_find_attr_as_uint64(res->msgs[0], "GlobalCount", 0);
694
1165
/* Step 2. Update GlobalCount value */
1166
mem_ctx = talloc_zero(NULL, void);
695
1168
msg = ldb_msg_new(mem_ctx);
696
1169
msg->dn = ldb_dn_copy(msg, ldb_msg_find_attr_as_dn(ldb_ctx, mem_ctx, res->msgs[0], "distinguishedName"));
697
ldb_msg_add_fmt(msg, "GlobalCount", "0x%"PRIx64, ((*fid) + 1));
1170
ldb_msg_add_fmt(msg, "GlobalCount", "%"PRIu64, (fmid + range_len));
698
1171
msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
699
1172
ret = ldb_modify(ldb_ctx, msg);
700
1173
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
702
1175
talloc_free(mem_ctx);
704
*fid = (*fid << 16) + 1;
1177
*first_fmidp = (exchange_globcnt(fmid) << 16) | 0x0001;
706
1179
return MAPI_E_SUCCESS;
711
1183
\details Retrieve a MAPI property value from a folder record
713
1185
\param parent_ctx pointer to the memory context
714
\param _ldb_ctx pointer to the openchange LDB context
715
\param recipient the mailbox username
1186
\param ldb_ctx pointer to the openchange LDB context
716
1187
\param proptag the MAPI property tag to retrieve value for
717
1188
\param fid the record folder identifier
718
1189
\param data pointer on pointer to the data the function returns
760
1229
return MAPI_E_NOT_FOUND;
1232
_PUBLIC_ enum MAPISTATUS openchangedb_set_folder_properties(struct ldb_context *ldb_ctx, uint64_t fid, struct SRow *row)
1234
TALLOC_CTX *mem_ctx;
1235
struct ldb_result *res = NULL;
1236
char *PidTagAttr = NULL;
1237
struct SPropValue *value;
1238
const char * const attrs[] = { "*", NULL };
1239
struct ldb_message *msg;
1246
unix_time = time(NULL);
1248
mem_ctx = talloc_named(NULL, 0, "set_folder_property");
1250
/* Step 1. Find PidTagFolderId record */
1251
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
1252
LDB_SCOPE_SUBTREE, attrs, "(PidTagFolderId=%"PRIu64")", fid);
1253
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
1255
/* Step 2. Update GlobalCount value */
1256
msg = ldb_msg_new(mem_ctx);
1257
msg->dn = ldb_dn_copy(msg, ldb_msg_find_attr_as_dn(ldb_ctx, mem_ctx, res->msgs[0], "distinguishedName"));
1259
for (i = 0; i < row->cValues; i++) {
1260
value = row->lpProps + i;
1262
switch (value->ulPropTag) {
1265
case PR_PARENT_SOURCE_KEY:
1267
case PR_CREATION_TIME:
1268
case PR_LAST_MODIFICATION_TIME:
1269
DEBUG(5, ("Ignored attempt to set handled property %.8x\n", value->ulPropTag));
1272
/* Step 2. Convert proptag into PidTag attribute */
1273
PidTagAttr = (char *) openchangedb_property_get_attribute(value->ulPropTag);
1275
PidTagAttr = talloc_asprintf(mem_ctx, "%.8x", value->ulPropTag);
1278
str_value = openchangedb_set_folder_property_data(mem_ctx, value);
1280
DEBUG(5, ("Ignored property of unhandled type %.4x\n", (value->ulPropTag & 0xffff)));
1284
ldb_msg_add_string(msg, PidTagAttr, str_value);
1285
msg->elements[msg->num_elements-1].flags = LDB_FLAG_MOD_REPLACE;
1289
/* We set the last modification time */
1290
value = talloc_zero(NULL, struct SPropValue);
1292
value->ulPropTag = PR_LAST_MODIFICATION_TIME;
1293
unix_to_nt_time(&nt_time, unix_time);
1294
value->value.ft.dwLowDateTime = nt_time & 0xffffffff;
1295
value->value.ft.dwHighDateTime = nt_time >> 32;
1296
str_value = openchangedb_set_folder_property_data(mem_ctx, value);
1297
ldb_msg_add_string(msg, "PidTagLastModificationTime", str_value);
1298
msg->elements[msg->num_elements-1].flags = LDB_FLAG_MOD_REPLACE;
1300
value->ulPropTag = PidTagChangeNumber;
1301
openchangedb_get_new_changeNumber(ldb_ctx, (uint64_t *) &value->value.d);
1302
str_value = openchangedb_set_folder_property_data(mem_ctx, value);
1303
ldb_msg_add_string(msg, "PidTagChangeNumber", str_value);
1304
msg->elements[msg->num_elements-1].flags = LDB_FLAG_MOD_REPLACE;
1308
ret = ldb_modify(ldb_ctx, msg);
1309
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
1311
talloc_free(mem_ctx);
1313
return MAPI_E_SUCCESS;
765
1318
\details Retrieve a MAPI property from a table (ldb search results)
767
1320
\param parent_ctx pointer to the memory context
768
\param _ldb_ctx pointer to the openchange LDB context
769
\param recipient the mailbox username
1321
\param ldb_ctx pointer to the openchange LDB context
770
1322
\param ldb_filter the ldb search string
771
1323
\param proptag the MAPI property tag to retrieve value for
772
1324
\param pos the record position in search results
1418
\details Retrieve the message ID associated with a given subject (normalized)
1420
\param ldb_ctx pointer to the openchange LDB context
1421
\param parent_fid the folder ID of the parent folder
1422
\param subject the normalized subject to look up
1423
\param mid the message ID for the message (0 if not found)
1425
\return MAPI_E_SUCCESS on success, otherwise MAPI_E_NOT_FOUND
1427
_PUBLIC_ enum MAPISTATUS openchangedb_get_mid_by_subject(struct ldb_context *ldb_ctx, uint64_t parent_fid, const char *subject, bool mailboxstore, uint64_t *mid)
1429
TALLOC_CTX *mem_ctx;
1430
struct ldb_result *res;
1431
struct ldb_dn *base_dn;
1432
const char * const attrs[] = { "*", NULL };
1435
mem_ctx = talloc_named(NULL, 0, "get_mid_by_subject");
1438
base_dn = ldb_get_default_basedn(ldb_ctx);
1440
base_dn = ldb_get_root_basedn(ldb_ctx);
1443
ret = ldb_search(ldb_ctx, mem_ctx, &res, base_dn,
1444
LDB_SCOPE_SUBTREE, attrs,
1445
"(&(PidTagParentFolderId=%"PRIu64")(PidTagNormalizedSubject=%s))",
1446
parent_fid, subject);
1448
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, mem_ctx);
1450
/* We should only ever get 0 records or 1 record, but there is always a chance
1451
that things got confused at some point, so just return one of the records */
1452
OPENCHANGE_RETVAL_IF(res->count < 1, MAPI_E_NOT_FOUND, mem_ctx);
1454
*mid = ldb_msg_find_attr_as_uint64(res->msgs[0], "PidTagMessageId", 0);
1456
talloc_free(mem_ctx);
1458
return MAPI_E_SUCCESS;
1461
_PUBLIC_ enum MAPISTATUS openchangedb_delete_folder(struct ldb_context *ldb_ctx, uint64_t fid)
1463
TALLOC_CTX *mem_ctx;
1467
enum MAPISTATUS ret;
1469
mem_ctx = talloc_zero(NULL, TALLOC_CTX);
1471
ret = openchangedb_get_distinguishedName(mem_ctx, ldb_ctx, fid, &dnstr);
1472
if (ret != MAPI_E_SUCCESS) {
1476
dn = ldb_dn_new(mem_ctx, ldb_ctx, dnstr);
1477
retval = ldb_delete(ldb_ctx, dn);
1478
if (retval == LDB_SUCCESS) {
1479
ret = MAPI_E_SUCCESS;
1482
ret = MAPI_E_CORRUPT_STORE;
1486
talloc_free(mem_ctx);
870
1492
\details Set the receive folder for a specific message class.
872
1494
\param parent_ctx pointer to the memory context
873
\param _ldb_ctx pointer to the openchange LDB context
1495
\param ldb_ctx pointer to the openchange LDB context
874
1496
\param recipient pointer to the mailbox's username
875
1497
\param MessageClass message class (e.g. IPM.whatever) to set
876
1498
\param fid folder identifier for the recipient folder for the message class
878
1500
\return MAPI_E_SUCCESS on success, otherwise MAPI_E_NOT_FOUND
880
_PUBLIC_ enum MAPISTATUS openchangedb_set_ReceiveFolder(TALLOC_CTX *parent_ctx,
882
const char *recipient,
883
const char *MessageClass,
1502
_PUBLIC_ enum MAPISTATUS openchangedb_set_ReceiveFolder(struct ldb_context *ldb_ctx, const char *recipient, const char *MessageClass, uint64_t fid)
886
1504
TALLOC_CTX *mem_ctx;
887
struct ldb_context *ldb_ctx = (struct ldb_context *)_ldb_ctx;
888
1505
struct ldb_result *res = NULL;
889
1506
struct ldb_dn *dn;
979
1594
return MAPI_E_SUCCESS;
1598
_PUBLIC_ enum MAPISTATUS openchangedb_get_fid_from_partial_uri(struct ldb_context *ldb_ctx,
1599
const char *partialURI,
1602
TALLOC_CTX *mem_ctx;
1603
struct ldb_result *res = NULL;
1604
const char * const attrs[] = { "*", NULL };
1607
mem_ctx = talloc_named(NULL, 0, "get_fid_from_partial_uri");
1609
/* Search mapistoreURI given partial URI */
1610
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
1611
LDB_SCOPE_SUBTREE, attrs, "(MAPIStoreURI=%s)", partialURI);
1613
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
1614
OPENCHANGE_RETVAL_IF(res->count > 1, MAPI_E_COLLISION, mem_ctx);
1616
*fid = ldb_msg_find_attr_as_uint64(res->msgs[0], "PidTagFolderId", 0);
1617
talloc_free(mem_ctx);
1619
return MAPI_E_SUCCESS;
1623
_PUBLIC_ enum MAPISTATUS openchangedb_get_users_from_partial_uri(TALLOC_CTX *parent_ctx,
1624
struct ldb_context *ldb_ctx,
1625
const char *partialURI,
1627
char ***MAPIStoreURI,
1630
TALLOC_CTX *mem_ctx;
1631
struct ldb_result *res = NULL;
1632
struct ldb_result *mres = NULL;
1633
const char *mailboxDN;
1635
const char * const attrs[] = { "*", NULL };
1641
OPENCHANGE_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1642
OPENCHANGE_RETVAL_IF(!partialURI, MAPI_E_INVALID_PARAMETER, NULL);
1643
OPENCHANGE_RETVAL_IF(!count, MAPI_E_INVALID_PARAMETER, NULL);
1644
OPENCHANGE_RETVAL_IF(!MAPIStoreURI, MAPI_E_INVALID_PARAMETER, NULL);
1645
OPENCHANGE_RETVAL_IF(!users, MAPI_E_INVALID_PARAMETER, NULL);
1647
mem_ctx = talloc_named(NULL, 0, "get_users_from_partial_uri");
1649
/* Search mapistoreURI given partial URI */
1650
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
1651
LDB_SCOPE_SUBTREE, attrs, "(MAPIStoreURI=%s)", partialURI);
1652
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
1654
*count = res->count;
1655
*MAPIStoreURI = talloc_array(parent_ctx, char *, *count);
1656
*users = talloc_array(parent_ctx, char *, *count);
1658
for (i = 0; i != *count; i++) {
1659
tmp = ldb_msg_find_attr_as_string(res->msgs[i], "MAPIStoreURI", NULL);
1660
*MAPIStoreURI[i] = talloc_strdup((TALLOC_CTX *)*MAPIStoreURI, tmp);
1662
/* Retrieve the system user name */
1663
mailboxDN = ldb_msg_find_attr_as_string(res->msgs[i], "mailboxDN", NULL);
1664
dn = ldb_dn_new(mem_ctx, ldb_ctx, mailboxDN);
1665
ret = ldb_search(ldb_ctx, mem_ctx, &mres, dn, LDB_SCOPE_SUBTREE, attrs, "(distinguishedName=%s)", mailboxDN);
1666
/* This should NEVER happen */
1667
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
1668
tmp = ldb_msg_find_attr_as_string(mres->msgs[0], "cn", NULL);
1669
*users[i] = talloc_strdup((TALLOC_CTX *)*users, tmp);
1673
talloc_free(mem_ctx);
1675
return MAPI_E_SUCCESS;
1680
\details Create a folder in openchangedb
1682
\param ldb_ctx pointer to the openchangedb LDB context
1683
\param username the owner of the mailbox
1684
\param systemIdx the id of the mailbox
1685
\param fidp a pointer to the fid of the mailbox
1687
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
1689
_PUBLIC_ enum MAPISTATUS openchangedb_create_mailbox(struct ldb_context *ldb_ctx, const char *username, int systemIdx, uint64_t *fidp)
1691
enum MAPISTATUS retval;
1692
TALLOC_CTX *mem_ctx;
1693
struct ldb_dn *mailboxdn;
1694
struct ldb_message *msg;
1696
uint64_t fid, changeNum;
1700
MAPI_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1701
MAPI_RETVAL_IF(!username, MAPI_E_NOT_INITIALIZED, NULL);
1703
unix_to_nt_time(&now, time(NULL));
1705
mem_ctx = talloc_named(NULL, 0, "openchangedb_create_mailbox");
1707
openchangedb_get_new_folderID(ldb_ctx, &fid);
1708
openchangedb_get_new_changeNumber(ldb_ctx, &changeNum);
1710
/* Retrieve distinguesName for parent folder */
1712
mailboxdn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(ldb_ctx));
1713
MAPI_RETVAL_IF(!mailboxdn, MAPI_E_NOT_ENOUGH_MEMORY, mem_ctx);
1715
ldb_dn_add_child_fmt(mailboxdn, "CN=%s", username);
1716
MAPI_RETVAL_IF(!ldb_dn_validate(mailboxdn), MAPI_E_BAD_VALUE, mem_ctx);
1718
msg = ldb_msg_new(mem_ctx);
1719
MAPI_RETVAL_IF(!msg, MAPI_E_NOT_ENOUGH_MEMORY, mem_ctx);
1721
msg->dn = mailboxdn;
1722
ldb_msg_add_string(msg, "objectClass", "systemfolder");
1723
ldb_msg_add_string(msg, "objectClass", "container");
1724
ldb_msg_add_string(msg, "ReplicaID", "1");
1725
guid = GUID_random();
1726
ldb_msg_add_fmt(msg, "ReplicaGUID", "%s", GUID_string(mem_ctx, &guid));
1727
guid = GUID_random();
1728
ldb_msg_add_fmt(msg, "MailboxGUID", "%s", GUID_string(mem_ctx, &guid));
1729
ldb_msg_add_string(msg, "cn", username);
1730
ldb_msg_add_string(msg, "PidTagAccess", "63");
1731
ldb_msg_add_string(msg, "PidTagRights", "2043");
1732
ldb_msg_add_fmt(msg, "PidTagDisplayName", "OpenChange Mailbox: %s", username);
1733
ldb_msg_add_fmt(msg, "PidTagCreationTime", "%"PRId64, now);
1734
ldb_msg_add_fmt(msg, "PidTagLastModificationTime", "%"PRId64, now);
1735
ldb_msg_add_string(msg, "PidTagSubFolders", "TRUE");
1736
ldb_msg_add_fmt(msg, "PidTagFolderId", "%"PRIu64, fid);
1737
ldb_msg_add_fmt(msg, "PidTagChangeNumber", "%"PRIu64, changeNum);
1738
ldb_msg_add_fmt(msg, "PidTagFolderType", "1");
1739
if (systemIdx > -1) {
1740
ldb_msg_add_fmt(msg, "SystemIdx", "%d", systemIdx);
1742
ldb_msg_add_fmt(msg, "distinguishedName", "%s", ldb_dn_get_linearized(msg->dn));
1744
msg->elements[0].flags = LDB_FLAG_MOD_ADD;
1746
if (ldb_add(ldb_ctx, msg) != LDB_SUCCESS) {
1747
retval = MAPI_E_CALL_FAILED;
1754
retval = MAPI_E_SUCCESS;
1757
talloc_free(mem_ctx);
1763
\details Create a folder in openchangedb
1765
\param ldb_ctx pointer to the openchangedb LDB context
1766
\param parentFolderID the FID of the parent folder
1767
\param fid the FID of the folder to create
1768
\param MAPIStoreURI the mapistore URI to associate to this folder
1769
\param nt_time the creation time of the folder
1770
\param changeNumber the change number
1772
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
1774
_PUBLIC_ enum MAPISTATUS openchangedb_create_folder(struct ldb_context *ldb_ctx, uint64_t parentFolderID, uint64_t fid, uint64_t changeNumber, const char *MAPIStoreURI, int systemIdx)
1776
enum MAPISTATUS retval;
1777
TALLOC_CTX *mem_ctx;
1781
struct ldb_dn *basedn;
1782
struct ldb_message *msg;
1786
MAPI_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1787
MAPI_RETVAL_IF(!parentFolderID, MAPI_E_NOT_INITIALIZED, NULL);
1788
MAPI_RETVAL_IF(!fid, MAPI_E_NOT_INITIALIZED, NULL);
1789
MAPI_RETVAL_IF(!changeNumber, MAPI_E_NOT_INITIALIZED, NULL);
1791
unix_to_nt_time(&now, time(NULL));
1793
mem_ctx = talloc_named(NULL, 0, "openchangedb_create_folder");
1795
/* Retrieve distinguesName for parent folder */
1796
retval = openchangedb_get_distinguishedName(mem_ctx, ldb_ctx, parentFolderID, &parentDN);
1797
MAPI_RETVAL_IF(retval, retval, mem_ctx);
1799
retval = openchangedb_get_mailboxDN(mem_ctx, ldb_ctx, parentFolderID, &mailboxDN);
1800
MAPI_RETVAL_IF(retval, retval, mem_ctx);
1802
dn = talloc_asprintf(mem_ctx, "CN=%"PRIu64",%s", fid, parentDN);
1803
MAPI_RETVAL_IF(!dn, MAPI_E_NOT_ENOUGH_MEMORY, mem_ctx);
1804
basedn = ldb_dn_new(mem_ctx, ldb_ctx, dn);
1807
MAPI_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
1809
msg = ldb_msg_new(mem_ctx);
1810
MAPI_RETVAL_IF(!msg, MAPI_E_NOT_ENOUGH_MEMORY, mem_ctx);
1812
msg->dn = ldb_dn_copy(mem_ctx, basedn);
1813
ldb_msg_add_string(msg, "objectClass", "systemfolder");
1814
ldb_msg_add_fmt(msg, "cn", "%"PRIu64, fid);
1815
ldb_msg_add_string(msg, "FolderType", "1");
1816
ldb_msg_add_string(msg, "PidTagContentUnreadCount", "0");
1817
ldb_msg_add_string(msg, "PidTagContentCount", "0");
1818
ldb_msg_add_string(msg, "PidTagAttributeHidden", "0");
1819
ldb_msg_add_string(msg, "PidTagAttributeSystem", "0");
1820
ldb_msg_add_string(msg, "PidTagAttributeReadOnly", "0");
1821
ldb_msg_add_string(msg, "PidTagAccess", "63");
1822
ldb_msg_add_string(msg, "PidTagRights", "2043");
1823
ldb_msg_add_fmt(msg, "PidTagFolderType", "1");
1824
ldb_msg_add_fmt(msg, "PidTagCreationTime", "%"PRIu64, now);
1825
ldb_msg_add_fmt(msg, "PidTagNTSDModificationTime", "%"PRIu64, now);
1827
ldb_msg_add_string(msg, "mailboxDN", mailboxDN);
1829
if (parentFolderID) {
1830
ldb_msg_add_fmt(msg, "PidTagParentFolderId", "%"PRIu64, parentFolderID);
1832
ldb_msg_add_fmt(msg, "PidTagFolderId", "%"PRIu64, fid);
1833
ldb_msg_add_fmt(msg, "PidTagChangeNumber", "%"PRIu64, changeNumber);
1835
ldb_msg_add_string(msg, "MAPIStoreURI", MAPIStoreURI);
1837
if (systemIdx > -1) {
1838
ldb_msg_add_fmt(msg, "SystemIdx", "%d", systemIdx);
1840
ldb_msg_add_fmt(msg, "distinguishedName", "%s", ldb_dn_get_linearized(msg->dn));
1842
msg->elements[0].flags = LDB_FLAG_MOD_ADD;
1844
if (ldb_add(ldb_ctx, msg) != LDB_SUCCESS) {
1845
retval = MAPI_E_CALL_FAILED;
1848
retval = MAPI_E_SUCCESS;
1851
talloc_free(mem_ctx);
1857
\details Retrieve the number of messages within the specified folder
1859
\param ldb_ctx pointer to the openchange LDB context
1860
\param fid the folder identifier to use for the search
1861
\param RowCount pointer to the returned number of results
1863
\return MAPI_E_SUCCESS on success, otherwise MAPI_E_NOT_FOUND
1865
_PUBLIC_ enum MAPISTATUS openchangedb_get_message_count(struct ldb_context *ldb_ctx, uint64_t fid, uint32_t *RowCount, bool fai)
1867
TALLOC_CTX *mem_ctx;
1868
struct ldb_result *res;
1869
const char * const attrs[] = { "*", NULL };
1870
const char *objectClass;
1874
OPENCHANGE_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1875
OPENCHANGE_RETVAL_IF(!RowCount, MAPI_E_INVALID_PARAMETER, NULL);
1877
mem_ctx = talloc_named(NULL, 0, "get_message_count");
1880
objectClass = (fai ? "faiMessage" : "systemMessage");
1881
ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
1882
LDB_SCOPE_SUBTREE, attrs,
1883
"(&(objectClass=%s)(PidTagParentFolderId=%"PRIu64"))", objectClass, fid);
1884
printf("ldb error: %s\n", ldb_errstring(ldb_ctx));
1885
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, mem_ctx);
1887
*RowCount = res->count;
1889
talloc_free(mem_ctx);
1891
return MAPI_E_SUCCESS;