2 OpenChange Server implementation
4 EMSMDBP: EMSMDB Provider implementation
6 Copyright (C) Julien Kerihuel 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 \file emsmdbp_object.c
25 \brief Server-side specific objects init/release routines
31 #include "mapiproxy/dcesrv_mapiproxy.h"
32 #include "mapiproxy/libmapiproxy/libmapiproxy.h"
33 #include "mapiproxy/libmapiserver/libmapiserver.h"
34 #include "mapiproxy/libmapistore/mapistore_nameid.h"
35 #include "libmapi/property_tags.h"
36 #include "libmapi/property_altnames.h"
38 #include "dcesrv_exchange_emsmdb.h"
40 static const int max_mins_per_month = 31 * 24 * 60;
42 const char *emsmdbp_getstr_type(struct emsmdbp_object *object)
44 switch (object->type) {
45 case EMSMDBP_OBJECT_UNDEF:
47 case EMSMDBP_OBJECT_MAILBOX:
49 case EMSMDBP_OBJECT_FOLDER:
51 case EMSMDBP_OBJECT_MESSAGE:
53 case EMSMDBP_OBJECT_TABLE:
55 case EMSMDBP_OBJECT_STREAM:
57 case EMSMDBP_OBJECT_ATTACHMENT:
59 case EMSMDBP_OBJECT_SUBSCRIPTION:
60 return "subscription";
61 case EMSMDBP_OBJECT_SYNCCONTEXT:
63 case EMSMDBP_OBJECT_FTCONTEXT:
71 \details Convenient function to determine whether specified
72 object is using mapistore or not
74 \param object pointer to the emsmdp object
76 \return true if parent is using mapistore, otherwise false
78 bool emsmdbp_is_mapistore(struct emsmdbp_object *object)
80 /* Sanity checks - probably pointless */
85 switch (object->type) {
86 case EMSMDBP_OBJECT_MAILBOX:
88 case EMSMDBP_OBJECT_FOLDER:
89 if (object->object.folder->mapistore_root) {
93 if (object->parent_object) {
94 return emsmdbp_is_mapistore(object->parent_object);
101 static struct emsmdbp_object *emsmdbp_get_mailbox(struct emsmdbp_object *object)
103 if (object->type == EMSMDBP_OBJECT_MAILBOX) {
107 return emsmdbp_get_mailbox(object->parent_object);
111 \details Convenient function to determine whether specified
112 mapi_handles refers to object within mailbox or public folders
115 \param object pointer to the emsmdp object
117 \return true if parent is within mailbox store, otherwise false
119 bool emsmdbp_is_mailboxstore(struct emsmdbp_object *object)
121 struct emsmdbp_object *mailbox = emsmdbp_get_mailbox(object);
123 return mailbox->object.mailbox->mailboxstore;
127 \details Convenience function to determine the owner of an object
129 \param object pointer to the emsmdp object
131 \return true if parent is within mailbox store, otherwise false
133 char *emsmdbp_get_owner(struct emsmdbp_object *object)
135 struct emsmdbp_object *mailbox;
137 mailbox = emsmdbp_get_mailbox(object);
139 return mailbox->object.mailbox->owner_username;
144 \details Return the contextID associated to a handle
146 \param object pointer to the emsmdp object
148 \return contextID value on success, otherwise -1
150 _PUBLIC_ uint32_t emsmdbp_get_contextID(struct emsmdbp_object *object)
152 switch (object->type) {
153 case EMSMDBP_OBJECT_MAILBOX:
155 case EMSMDBP_OBJECT_FOLDER:
156 if (object->object.folder->mapistore_root) {
157 return object->object.folder->contextID;
160 if (object->parent_object) {
161 return emsmdbp_get_contextID(object->parent_object);
168 _PUBLIC_ enum mapistore_error emsmdbp_object_get_fid_by_name(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *parent_folder, const char *name, uint64_t *fidp)
172 if (!emsmdbp_ctx) return MAPISTORE_ERROR;
173 if (!parent_folder) return MAPISTORE_ERROR;
174 if (!name) return MAPISTORE_ERROR;
175 if (!fidp) return MAPISTORE_ERROR;
177 if (parent_folder->type == EMSMDBP_OBJECT_FOLDER) {
178 folderID = parent_folder->object.folder->folderID;
180 else if (parent_folder->type == EMSMDBP_OBJECT_MAILBOX) {
181 folderID = parent_folder->object.mailbox->folderID;
184 return MAPISTORE_ERROR;
187 if (emsmdbp_is_mapistore(parent_folder)) {
188 if (mapistore_folder_get_child_fid_by_name(emsmdbp_ctx->mstore_ctx, emsmdbp_get_contextID(parent_folder), parent_folder->backend_object, name, fidp)) {
189 return MAPISTORE_ERR_NOT_FOUND;
192 return MAPISTORE_SUCCESS;
195 return openchangedb_get_fid_by_name(emsmdbp_ctx->oc_ctx, folderID, name, fidp);
199 static enum mapistore_context_role emsmdbp_container_class_to_role(const char *container_class)
201 enum mapistore_context_role i, role = MAPISTORE_FALLBACK_ROLE;
202 static const char **container_classes = NULL;
205 if (!container_classes) {
206 container_classes = talloc_array(NULL, const char *, MAPISTORE_MAX_ROLES);
207 for (i = MAPISTORE_MAIL_ROLE; i < MAPISTORE_MAX_ROLES; i++) {
208 container_classes[i] = "IPF.Note";
210 container_classes[MAPISTORE_CALENDAR_ROLE] = "IPF.Appointment";
211 container_classes[MAPISTORE_CONTACTS_ROLE] = "IPF.Contact";
212 container_classes[MAPISTORE_TASKS_ROLE] = "IPF.Task";
213 container_classes[MAPISTORE_NOTES_ROLE] = "IPF.StickyNote";
214 container_classes[MAPISTORE_JOURNAL_ROLE] = "IPF.Journal";
215 container_classes[MAPISTORE_FALLBACK_ROLE] = "";
218 if (container_class) {
219 for (i = 0; !found && i < MAPISTORE_MAX_ROLES; i++) {
220 if (strcmp(container_class, container_classes[i]) == 0) {
230 static enum mapistore_error emsmdbp_object_folder_commit_creation(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *new_folder, bool force_container_class)
232 enum mapistore_error ret = MAPISTORE_SUCCESS;
233 enum MAPISTATUS retval;
234 struct SPropValue *value;
235 char *mapistore_uri, *owner;
236 enum mapistore_context_role role;
238 uint64_t parent_fid, fid;
241 if (!new_folder->object.folder->postponed_props) {
245 mem_ctx = talloc_zero(NULL, TALLOC_CTX);
247 value = get_SPropValue_SRow(new_folder->object.folder->postponed_props, PR_CONTAINER_CLASS_UNICODE);
249 /* Sometimes Outlook does pass non-unicode values. */
250 value = get_SPropValue_SRow(new_folder->object.folder->postponed_props, PR_CONTAINER_CLASS);
253 role = emsmdbp_container_class_to_role(value->value.lpszW);
255 else if (force_container_class) {
256 DEBUG(5, (__location__": forcing folder backend role to 'fallback'\n"));
257 role = MAPISTORE_FALLBACK_ROLE;
260 DEBUG(5, (__location__": container class not set yet\n"));
264 value = get_SPropValue_SRow(new_folder->object.folder->postponed_props, PR_DISPLAY_NAME_UNICODE);
266 DEBUG(5, (__location__": display name not set yet\n"));
270 fid = new_folder->object.folder->folderID;
271 owner = emsmdbp_get_owner(new_folder);
273 ret = mapistore_create_root_folder(owner, role, fid, value->value.lpszW, mem_ctx, &mapistore_uri);
274 if (ret != MAPISTORE_SUCCESS) {
278 ret = mapistore_add_context(emsmdbp_ctx->mstore_ctx, owner, mapistore_uri, fid, &context_id, &new_folder->backend_object);
279 if (ret != MAPISTORE_SUCCESS) {
283 new_folder->object.folder->contextID = context_id;
285 if (new_folder->parent_object->type == EMSMDBP_OBJECT_MAILBOX) {
286 parent_fid = new_folder->parent_object->object.mailbox->folderID;
288 else { /* EMSMDBP_OBJECT_FOLDER */
289 parent_fid = new_folder->parent_object->object.folder->folderID;
292 value = get_SPropValue_SRow(new_folder->object.folder->postponed_props, PidTagChangeNumber);
293 retval = openchangedb_create_folder(emsmdbp_ctx->oc_ctx, parent_fid, fid, value->value.d, mapistore_uri, -1);
294 if (retval != MAPI_E_SUCCESS) {
295 ret = MAPISTORE_ERR_NOT_FOUND;
296 DEBUG(0, (__location__": openchangedb folder creation failed: 0x%.8x\n", retval));
300 mapistore_indexing_record_add_fid(emsmdbp_ctx->mstore_ctx, context_id, owner, fid);
301 new_folder->object.folder->contextID = context_id;
303 openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, fid, new_folder->object.folder->postponed_props);
304 mapistore_properties_set_properties(emsmdbp_ctx->mstore_ctx, context_id, new_folder->backend_object, new_folder->object.folder->postponed_props);
306 talloc_unlink(new_folder, new_folder->object.folder->postponed_props);
307 new_folder->object.folder->postponed_props = NULL;
309 DEBUG(5, ("new mapistore context created at uri: %s\n", mapistore_uri));
312 talloc_free(mem_ctx);
317 _PUBLIC_ enum MAPISTATUS emsmdbp_object_create_folder(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *parent_folder, TALLOC_CTX *mem_ctx, uint64_t fid, struct SRow *rowp, struct emsmdbp_object **new_folderp)
319 uint64_t parentFolderID, testFolderID;
320 struct SPropValue *value;
322 struct emsmdbp_object *new_folder;
323 struct SRow *postponed_props;
326 if (!emsmdbp_ctx) return MAPISTORE_ERROR;
327 if (!parent_folder) return MAPISTORE_ERROR;
328 if (!rowp) return MAPISTORE_ERROR;
330 new_folder = emsmdbp_object_folder_init(mem_ctx, emsmdbp_ctx, fid, parent_folder);
331 if (emsmdbp_is_mapistore(parent_folder)) {
332 retval = mapistore_folder_create_folder(emsmdbp_ctx->mstore_ctx, emsmdbp_get_contextID(parent_folder), parent_folder->backend_object, new_folder, fid, rowp, &new_folder->backend_object);
333 if (retval != MAPISTORE_SUCCESS) {
334 talloc_free(new_folder);
335 if (retval == MAPISTORE_ERR_EXIST) {
336 /* folder with this name already exists */
337 DEBUG(5, (__location__": folder already exists\n"));
338 return MAPI_E_COLLISION;
340 else if (retval == MAPISTORE_ERR_DENIED) {
341 DEBUG(5, (__location__": folder creation denied\n"));
342 return MAPI_E_NO_ACCESS;
345 return MAPI_E_NOT_FOUND;
350 parentFolderID = parent_folder->object.folder->folderID;
351 value = get_SPropValue_SRow(rowp, PR_DISPLAY_NAME_UNICODE);
353 value = get_SPropValue_SRow(rowp, PR_DISPLAY_NAME);
356 talloc_free(new_folder);
357 return MAPI_E_INVALID_PARAMETER;
359 if (openchangedb_get_fid_by_name(emsmdbp_ctx->oc_ctx, parentFolderID,
360 value->value.lpszW, &testFolderID) == MAPI_E_SUCCESS) {
361 /* this folder already exists */
362 DEBUG(4, ("emsmdbp_object: CreateFolder Duplicate Folder error\n"));
363 talloc_free(new_folder);
364 return MAPI_E_COLLISION;
367 value = get_SPropValue_SRow(rowp, PidTagChangeNumber);
369 postponed_props = talloc_zero(new_folder, struct SRow);
370 postponed_props->cValues = rowp->cValues;
371 postponed_props->lpProps = talloc_array(postponed_props, struct SPropValue, rowp->cValues);
372 mapi_copy_spropvalues(postponed_props->lpProps, rowp->lpProps, postponed_props->lpProps, rowp->cValues);
373 new_folder->object.folder->postponed_props = postponed_props;
374 new_folder->object.folder->mapistore_root = true;
376 emsmdbp_object_folder_commit_creation(emsmdbp_ctx, new_folder, false);
379 DEBUG(0, (__location__": PidTagChangeNumber *must* be present\n"));
383 *new_folderp = new_folder;
385 return MAPI_E_SUCCESS;
388 _PUBLIC_ enum mapistore_error emsmdbp_object_open_folder(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *parent, uint64_t fid, struct emsmdbp_object **folder_object_p)
390 struct emsmdbp_object *folder_object, *mailbox_object;
391 enum mapistore_error retval;
396 uint64_t parent_fid, oc_parent_fid;
399 folder_object = emsmdbp_object_folder_init(mem_ctx, emsmdbp_ctx, fid, parent);
400 if (emsmdbp_is_mapistore(parent)) {
401 DEBUG(0, ("%s: opening child mapistore folder\n", __FUNCTION__));
402 retval = mapistore_folder_open_folder(emsmdbp_ctx->mstore_ctx, emsmdbp_get_contextID(parent), parent->backend_object, folder_object, fid, &folder_object->backend_object);
403 if (retval != MAPISTORE_SUCCESS) {
404 talloc_free(folder_object);
409 local_ctx = talloc_zero(NULL, void);
411 retval = openchangedb_get_mapistoreURI(local_ctx, emsmdbp_ctx->oc_ctx, fid, &path, true);
412 if (retval == MAPISTORE_SUCCESS && path) {
413 folder_object->object.folder->mapistore_root = true;
414 /* system/special folder */
415 DEBUG(0, ("%s: opening base mapistore folder\n", __FUNCTION__));
417 retval = mapistore_search_context_by_uri(emsmdbp_ctx->mstore_ctx, path, &contextID, &folder_object->backend_object);
418 if (retval == MAPISTORE_SUCCESS) {
419 retval = mapistore_add_context_ref_count(emsmdbp_ctx->mstore_ctx, contextID);
421 owner = emsmdbp_get_owner(folder_object);
422 retval = mapistore_add_context(emsmdbp_ctx->mstore_ctx, owner, path, folder_object->object.folder->folderID, &contextID, &folder_object->backend_object);
423 if (retval != MAPISTORE_SUCCESS) {
424 talloc_free(local_ctx);
425 talloc_free(folder_object);
428 mapistore_indexing_record_add_fid(emsmdbp_ctx->mstore_ctx, contextID, owner, fid);
430 folder_object->object.folder->contextID = contextID;
431 /* (void) talloc_reference(folder_object, folder_object->backend_object); */
434 switch (parent->type) {
435 case EMSMDBP_OBJECT_MAILBOX:
436 parent_fid = parent->object.mailbox->folderID;
438 case EMSMDBP_OBJECT_FOLDER:
439 parent_fid = parent->object.folder->folderID;
442 DEBUG(5, ("you should never get here\n"));
445 mailbox_object = emsmdbp_get_mailbox(parent);
446 ret = openchangedb_get_parent_fid(emsmdbp_ctx->oc_ctx, fid, &oc_parent_fid, mailbox_object->object.mailbox->mailboxstore);
447 if (ret != MAPI_E_SUCCESS) {
448 DEBUG(0, ("folder %.16"PRIx64" or %.16"PRIx64" does not exist\n", parent_fid, fid));
449 talloc_free(local_ctx);
450 talloc_free(folder_object);
451 return MAPISTORE_ERR_NOT_FOUND;
453 if (oc_parent_fid != parent_fid) {
454 DEBUG(0, ("parent folder mismatch: expected %.16"PRIx64" but got %.16"PRIx64"\n", parent_fid, oc_parent_fid));
455 talloc_free(local_ctx);
456 talloc_free(folder_object);
457 return MAPISTORE_ERR_NOT_FOUND;
459 DEBUG(0, ("%s: opening openchangedb folder\n", __FUNCTION__));
461 talloc_free(local_ctx);
464 *folder_object_p = folder_object;
466 return MAPISTORE_SUCCESS;
469 _PUBLIC_ int emsmdbp_get_uri_from_fid(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, uint64_t fid, char **urip)
471 enum MAPISTATUS retval;
474 retval = openchangedb_get_mapistoreURI(mem_ctx, emsmdbp_ctx->oc_ctx, fid, urip, true); /* FIXME: always mailboxstore */
475 if (retval == MAPI_E_SUCCESS) {
476 return MAPISTORE_SUCCESS;
478 return mapistore_indexing_record_get_uri(emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->username, mem_ctx, fid, urip, &soft_deleted);
481 _PUBLIC_ int emsmdbp_get_fid_from_uri(struct emsmdbp_context *emsmdbp_ctx, const char *uri, uint64_t *fidp)
486 ret = openchangedb_get_fid(emsmdbp_ctx->oc_ctx, uri, fidp);
487 if (ret != MAPI_E_SUCCESS) {
488 ret = mapistore_indexing_record_get_fmid(emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->username, uri, false, fidp, &soft_deleted);
494 static char *emsmdbp_compute_parent_uri(TALLOC_CTX *mem_ctx, char *uri)
496 char *parent_uri, *slash, *lastchar;
499 if (!uri) return NULL;
501 parent_uri = talloc_strdup(mem_ctx, uri);
502 len = strlen(parent_uri);
503 lastchar = parent_uri + len - 1;
504 if (*lastchar == '/') {
507 slash = strrchr(parent_uri, '/');
512 talloc_free(parent_uri);
519 static int emsmdbp_get_parent_fid(struct emsmdbp_context *emsmdbp_ctx, uint64_t fid, uint64_t *parent_fidp)
522 int retval = MAPISTORE_SUCCESS;
524 char *uri, *parent_uri;
526 mem_ctx = talloc_zero(NULL, void);
527 retval = openchangedb_get_parent_fid(emsmdbp_ctx->oc_ctx, fid, parent_fidp, true);
528 if (retval == MAPISTORE_SUCCESS) {
531 retval = openchangedb_get_parent_fid(emsmdbp_ctx->oc_ctx, fid, parent_fidp, false);
532 if (retval == MAPISTORE_SUCCESS) {
536 retval = mapistore_indexing_record_get_uri(emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->username, mem_ctx, fid, &uri, &soft_deleted);
537 if (retval == MAPISTORE_SUCCESS) {
538 parent_uri = emsmdbp_compute_parent_uri(mem_ctx, uri);
540 retval = emsmdbp_get_fid_from_uri(emsmdbp_ctx, parent_uri, parent_fidp);
543 retval = MAPISTORE_ERR_NOT_FOUND;
548 talloc_free(mem_ctx);
554 \details Return the folder object associated to specified folder identified
556 \param mem_ctx pointer to the memory context
557 \param emsmdbp_ctx pointer to the emsmdbp context
558 \param context_object pointer to current context object
559 \param fid pointer to the Folder Identifier to lookup
561 \return Valid emsmdbp object structure on success, otherwise NULL
563 _PUBLIC_ enum mapistore_error emsmdbp_object_open_folder_by_fid(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *context_object, uint64_t fid, struct emsmdbp_object **folder_object_p)
567 struct emsmdbp_object *parent_object;
569 if ((context_object->type == EMSMDBP_OBJECT_MAILBOX
570 && fid == context_object->object.mailbox->folderID)
571 || (context_object->type == EMSMDBP_OBJECT_FOLDER
572 && fid == context_object->object.folder->folderID)) {
573 *folder_object_p = context_object;
574 return MAPISTORE_SUCCESS;
577 parent_object = emsmdbp_get_mailbox(context_object);
578 if (fid == parent_object->object.mailbox->folderID) {
579 *folder_object_p = parent_object;
580 return MAPISTORE_SUCCESS;
584 retval = emsmdbp_get_parent_fid(emsmdbp_ctx, fid, &parent_fid);
585 if (retval == MAPISTORE_SUCCESS) {
587 retval = emsmdbp_object_open_folder_by_fid(mem_ctx, emsmdbp_ctx, context_object, parent_fid, &parent_object);
588 if (retval != MAPISTORE_SUCCESS) {
591 return emsmdbp_object_open_folder(mem_ctx, emsmdbp_ctx, parent_object, fid, folder_object_p);
594 *folder_object_p = emsmdbp_object_folder_init(mem_ctx, emsmdbp_ctx, fid, NULL);
595 return MAPISTORE_SUCCESS;
599 return MAPISTORE_ERROR;
602 _PUBLIC_ int emsmdbp_object_stream_commit(struct emsmdbp_object *stream_object)
605 struct emsmdbp_object_stream *stream;
607 uint8_t *utf8_buffer;
608 struct Binary_r *binary_data;
610 size_t converted_size;
613 if (!stream_object || stream_object->type != EMSMDBP_OBJECT_STREAM) return MAPISTORE_ERROR;
615 stream = stream_object->object.stream;
617 rc = MAPISTORE_SUCCESS;
618 if (stream->needs_commit) {
619 stream->needs_commit = false;
621 aRow.lpProps = talloc_zero(NULL, struct SPropValue);
623 propType = stream->property & 0xffff;
624 if (propType == PT_BINARY) {
625 binary_data = talloc(aRow.lpProps, struct Binary_r);
626 binary_data->cb = stream->stream.buffer.length;
627 binary_data->lpb = stream->stream.buffer.data;
628 stream_data = binary_data;
630 else if (propType == PT_STRING8) {
631 stream_data = stream->stream.buffer.data;
635 utf8_buffer = talloc_array(aRow.lpProps, uint8_t, stream->stream.buffer.length + 2);
636 convert_string(CH_UTF16LE, CH_UTF8,
637 stream->stream.buffer.data, stream->stream.buffer.length,
638 utf8_buffer, stream->stream.buffer.length, &converted_size);
639 utf8_buffer[converted_size] = 0;
640 stream_data = utf8_buffer;
642 set_SPropValue_proptag(aRow.lpProps, stream->property, stream_data);
644 emsmdbp_object_set_properties(stream_object->emsmdbp_ctx, stream_object->parent_object, &aRow);
645 talloc_free(aRow.lpProps);
652 \details talloc destructor for emsmdbp_objects
654 \param data generic pointer on data
656 \return 0 on success, otherwise -1
658 static int emsmdbp_object_destructor(void *data)
660 struct emsmdbp_object *object = (struct emsmdbp_object *) data;
661 int ret = MAPISTORE_SUCCESS;
664 if (!data) return -1;
665 if (!emsmdbp_is_mapistore(object)) goto nomapistore;
667 DEBUG(4, ("[%s:%d]: emsmdbp %s object released\n", __FUNCTION__, __LINE__,
668 emsmdbp_getstr_type(object)));
670 contextID = emsmdbp_get_contextID(object);
671 switch (object->type) {
672 case EMSMDBP_OBJECT_FOLDER:
673 if (object->object.folder->mapistore_root) {
674 ret = mapistore_del_context(object->emsmdbp_ctx->mstore_ctx, contextID);
676 DEBUG(4, ("[%s:%d] mapistore folder context retval = %d\n", __FUNCTION__, __LINE__, ret));
678 case EMSMDBP_OBJECT_TABLE:
679 if (emsmdbp_is_mapistore(object) && object->backend_object && object->object.table->handle > 0) {
680 mapistore_table_handle_destructor(object->emsmdbp_ctx->mstore_ctx, emsmdbp_get_contextID(object), object->backend_object, object->object.table->handle);
682 if (object->object.table->subscription_list) {
683 DLIST_REMOVE(object->emsmdbp_ctx->mstore_ctx->subscriptions, object->object.table->subscription_list);
684 talloc_free(object->object.table->subscription_list);
685 /* talloc_unlink(object->emsmdbp_ctx, object->object.table->subscription_list); */
688 case EMSMDBP_OBJECT_STREAM:
689 emsmdbp_object_stream_commit(object);
691 case EMSMDBP_OBJECT_SUBSCRIPTION:
692 if (object->object.subscription->subscription_list) {
693 DLIST_REMOVE(object->emsmdbp_ctx->mstore_ctx->subscriptions, object->object.subscription->subscription_list);
694 talloc_free(object->object.subscription->subscription_list);
697 case EMSMDBP_OBJECT_UNDEF:
698 case EMSMDBP_OBJECT_MAILBOX:
699 case EMSMDBP_OBJECT_MESSAGE:
700 case EMSMDBP_OBJECT_ATTACHMENT:
701 case EMSMDBP_OBJECT_FTCONTEXT:
702 case EMSMDBP_OBJECT_SYNCCONTEXT:
707 talloc_unlink(object, object->parent_object);
713 \details Initialize an emsmdbp_object
715 \param mem_ctx pointer to the memory context
716 \param emsmdbp_ctx pointer to the emsmdb provider context
718 \return Allocated emsmdbp object on success, otherwise NULL
720 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_init(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *parent_object)
722 struct emsmdbp_object *object = NULL;
724 object = talloc_zero(mem_ctx, struct emsmdbp_object);
725 if (!object) return NULL;
727 talloc_set_destructor((void *)object, (int (*)(void *))emsmdbp_object_destructor);
729 object->type = EMSMDBP_OBJECT_UNDEF;
730 object->emsmdbp_ctx = emsmdbp_ctx;
731 object->object.mailbox = NULL;
732 object->object.folder = NULL;
733 object->object.message = NULL;
734 object->object.stream = NULL;
735 object->backend_object = NULL;
736 object->parent_object = parent_object;
737 (void) talloc_reference(object, parent_object);
739 object->stream_data = NULL;
744 static int emsmdbp_copy_properties(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *source_object, struct emsmdbp_object *dest_object, struct SPropTagArray *excluded_tags)
747 bool *properties_exclusion;
748 struct SPropTagArray *properties, *needed_properties;
749 void **data_pointers;
750 enum MAPISTATUS *retvals = NULL;
752 struct SPropValue newValue;
755 mem_ctx = talloc_zero(NULL, TALLOC_CTX);
756 if (emsmdbp_object_get_available_properties(mem_ctx, emsmdbp_ctx, source_object, &properties) == MAPISTORE_ERROR) {
757 DEBUG(0, ("["__location__"] - mapistore support not implemented yet - shouldn't occur\n"));
758 talloc_free(mem_ctx);
759 return MAPI_E_NO_SUPPORT;
763 properties_exclusion = talloc_array(mem_ctx, bool, 65536);
764 memset(properties_exclusion, 0, 65536 * sizeof(bool));
766 /* 1a. Explicit exclusions */
767 properties_exclusion[(uint16_t) (PR_ROW_TYPE >> 16)] = true;
768 properties_exclusion[(uint16_t) (PR_INSTANCE_KEY >> 16)] = true;
769 properties_exclusion[(uint16_t) (PR_INSTANCE_NUM >> 16)] = true;
770 properties_exclusion[(uint16_t) (PR_INST_ID >> 16)] = true;
771 properties_exclusion[(uint16_t) (PR_FID >> 16)] = true;
772 properties_exclusion[(uint16_t) (PR_MID >> 16)] = true;
773 properties_exclusion[(uint16_t) (PR_SOURCE_KEY >> 16)] = true;
774 properties_exclusion[(uint16_t) (PR_PARENT_SOURCE_KEY >> 16)] = true;
775 properties_exclusion[(uint16_t) (PR_PARENT_FID >> 16)] = true;
777 /* 1b. Request exclusions */
778 if (excluded_tags != NULL) {
779 for (i = 0; i < excluded_tags->cValues; i++) {
780 properties_exclusion[(uint16_t) (excluded_tags->aulPropTag[i] >> 16)] = true;
784 needed_properties = talloc_zero(mem_ctx, struct SPropTagArray);
785 needed_properties->aulPropTag = talloc_zero(needed_properties, void);
786 for (i = 0; i < properties->cValues; i++) {
787 if (!properties_exclusion[(uint16_t) (properties->aulPropTag[i] >> 16)]) {
788 SPropTagArray_add(mem_ctx, needed_properties, properties->aulPropTag[i]);
792 data_pointers = emsmdbp_object_get_properties(mem_ctx, emsmdbp_ctx, source_object, needed_properties, &retvals);
794 aRow = talloc_zero(mem_ctx, struct SRow);
795 for (i = 0; i < needed_properties->cValues; i++) {
796 if (retvals[i] == MAPI_E_SUCCESS) {
797 /* _PUBLIC_ enum MAPISTATUS SRow_addprop(struct SRow *aRow, struct SPropValue spropvalue) */
798 set_SPropValue_proptag(&newValue, needed_properties->aulPropTag[i], data_pointers[i]);
799 SRow_addprop(aRow, newValue);
802 if (emsmdbp_object_set_properties(emsmdbp_ctx, dest_object, aRow) != MAPISTORE_SUCCESS) {
803 talloc_free(mem_ctx);
804 return MAPI_E_NO_SUPPORT;
808 talloc_free(mem_ctx);
809 return MAPI_E_NO_SUPPORT;
812 talloc_free(mem_ctx);
814 return MAPI_E_SUCCESS;
817 /* FIXME: this function is already present in oxcmsg... */
818 struct emsmdbp_prop_index {
819 uint32_t display_name; /* PR_DISPLAY_NAME_UNICODE or PR_7BIT_DISPLAY_NAME_UNICODE or PR_RECIPIENT_DISPLAY_NAME_UNICODE */
820 uint32_t email_address; /* PR_EMAIL_ADDRESS_UNICODE or PR_SMTP_ADDRESS_UNICODE */
823 static inline void emsmdbp_fill_prop_index(struct emsmdbp_prop_index *prop_index, struct SPropTagArray *properties)
825 if (SPropTagArray_find(*properties, PR_DISPLAY_NAME_UNICODE, &prop_index->display_name) == MAPI_E_NOT_FOUND
826 && SPropTagArray_find(*properties, PR_7BIT_DISPLAY_NAME_UNICODE, &prop_index->display_name) == MAPI_E_NOT_FOUND
827 && SPropTagArray_find(*properties, PR_RECIPIENT_DISPLAY_NAME_UNICODE, &prop_index->display_name) == MAPI_E_NOT_FOUND) {
828 prop_index->display_name = (uint32_t) -1;
830 if (SPropTagArray_find(*properties, PR_EMAIL_ADDRESS_UNICODE, &prop_index->email_address) == MAPI_E_NOT_FOUND
831 && SPropTagArray_find(*properties, PR_SMTP_ADDRESS_UNICODE, &prop_index->email_address) == MAPI_E_NOT_FOUND) {
832 prop_index->email_address = (uint32_t) -1;
836 static inline int emsmdbp_copy_message_recipients_mapistore(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *source_object, struct emsmdbp_object *dest_object)
839 struct mapistore_message *msg_data;
840 uint32_t contextID, i;
841 struct emsmdbp_prop_index prop_index;
842 struct SPropTagArray *new_columns;
845 if (!emsmdbp_is_mapistore(source_object) || !emsmdbp_is_mapistore(dest_object)) {
846 /* we silently fail for non-mapistore messages */
847 return MAPI_E_SUCCESS;
850 /* Fetch data from source message */
851 mem_ctx = talloc_zero(NULL, TALLOC_CTX);
852 contextID = emsmdbp_get_contextID(source_object);
853 mapistore_message_get_message_data(emsmdbp_ctx->mstore_ctx, contextID, source_object->backend_object, mem_ctx, &msg_data);
855 /* By convention, we pass PR_DISPLAY_NAME_UNICODE and PR_EMAIL_ADDRESS_UNICODE to the backend, so we prepend them to each values array */
856 if (msg_data->recipients_count > 0
857 && (msg_data->columns->cValues < 2 || msg_data->columns->aulPropTag[0] != PR_DISPLAY_NAME_UNICODE || msg_data->columns->aulPropTag[1] != PR_EMAIL_ADDRESS_UNICODE)) {
858 emsmdbp_fill_prop_index(&prop_index, msg_data->columns);
860 new_columns = talloc_zero(mem_ctx, struct SPropTagArray);
861 new_columns->cValues = msg_data->columns->cValues + 2;
862 new_columns->aulPropTag = talloc_array(new_columns, enum MAPITAGS, new_columns->cValues);
863 memcpy(new_columns->aulPropTag + 2, msg_data->columns->aulPropTag, sizeof(enum MAPITAGS) * msg_data->columns->cValues);
864 new_columns->aulPropTag[0] = PR_DISPLAY_NAME_UNICODE;
865 new_columns->aulPropTag[1] = PR_EMAIL_ADDRESS_UNICODE;
867 for (i = 0; i < msg_data->recipients_count; i++) {
868 new_data = talloc_array(mem_ctx, void *, new_columns->cValues);
869 memcpy(new_data + 2, msg_data->recipients[i].data, sizeof(void *) * msg_data->columns->cValues);
870 if (prop_index.display_name != (uint32_t) -1) {
871 new_data[0] = msg_data->recipients[i].data[prop_index.display_name];
876 if (prop_index.email_address != (uint32_t) -1) {
877 new_data[1] = msg_data->recipients[i].data[prop_index.email_address];
882 msg_data->recipients[i].data = new_data;
884 msg_data->columns = new_columns;
886 /* Copy data into dest message */
887 mapistore_message_modify_recipients(emsmdbp_ctx->mstore_ctx, contextID, dest_object->backend_object, msg_data->columns, msg_data->recipients_count, msg_data->recipients);
890 talloc_free(mem_ctx);
892 return MAPI_E_SUCCESS;
895 static inline int emsmdbp_copy_message_attachments_mapistore(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *source_object, struct emsmdbp_object *dest_object)
898 uint32_t i, count, contextID, dest_num;
899 void **data_pointers;
900 enum MAPISTATUS *retvals;
901 uint32_t *attach_nums;
902 struct emsmdbp_object *table_object, *source_attach, *dest_attach;
903 enum MAPITAGS column;
906 if (!emsmdbp_is_mapistore(source_object) || !emsmdbp_is_mapistore(dest_object)) {
907 /* we silently fail for non-mapistore messages */
908 return MAPI_E_SUCCESS;
911 mem_ctx = talloc_zero(NULL, TALLOC_CTX);
913 /* we fetch the attachment nums */
914 table_object = emsmdbp_object_message_open_attachment_table(mem_ctx, emsmdbp_ctx, source_object);
916 talloc_free(mem_ctx);
917 return MAPI_E_NOT_FOUND;
920 column = PR_ATTACH_NUM;
921 table_object->object.table->prop_count = 1;
922 table_object->object.table->properties = &column;
924 contextID = emsmdbp_get_contextID(table_object);
925 mapistore_table_set_columns(emsmdbp_ctx->mstore_ctx, contextID, table_object->backend_object, 1, &column);
927 count = table_object->object.table->denominator;
928 attach_nums = talloc_array(mem_ctx, uint32_t, count);
929 for (i = 0; i < table_object->object.table->denominator; i++) {
930 data_pointers = emsmdbp_object_table_get_row_props(mem_ctx, emsmdbp_ctx, table_object, i, MAPISTORE_PREFILTERED_QUERY, &retvals);
931 if (!data_pointers) {
932 talloc_free(mem_ctx);
933 return MAPISTORE_ERROR;
935 if (retvals[0] != MAPI_E_SUCCESS) {
936 talloc_free(mem_ctx);
937 DEBUG(5, ("cannot copy attachments without PR_ATTACH_NUM\n"));
938 return MAPISTORE_ERROR;
940 attach_nums[i] = *(uint32_t *) data_pointers[0];
943 /* we open each attachment manually and copy their props to created dest attachments */
944 for (i = 0; i < count; i++) {
945 source_attach = emsmdbp_object_attachment_init(mem_ctx, emsmdbp_ctx, source_object->object.message->messageID, source_object);
947 || mapistore_message_open_attachment(emsmdbp_ctx->mstore_ctx, contextID, source_object->backend_object, source_attach, attach_nums[i], &source_attach->backend_object)) {
948 talloc_free(mem_ctx);
949 return MAPISTORE_ERROR;
952 dest_attach = emsmdbp_object_attachment_init(mem_ctx, emsmdbp_ctx, dest_object->object.message->messageID, dest_object);
954 || mapistore_message_create_attachment(emsmdbp_ctx->mstore_ctx, contextID, dest_object->backend_object, dest_attach, &dest_attach->backend_object, &dest_num)) {
955 talloc_free(mem_ctx);
956 return MAPISTORE_ERROR;
959 ret = emsmdbp_copy_properties(emsmdbp_ctx, source_attach, dest_attach, NULL);
960 if (ret != MAPI_E_SUCCESS) {
961 talloc_free(mem_ctx);
966 talloc_free(mem_ctx);
968 return MAPI_E_SUCCESS;
972 \details Copy properties from an object to another object
974 \param emsmdbp_ctx pointer to the emsmdb provider context
975 \param source_object pointer to the source object
976 \param target_object pointer to the target object
977 \param excluded_properties pointer to a SPropTagArray listing properties that must not be copied
978 \param deep_copy indicates whether subobjects must be copied
980 \return Allocated emsmdbp object on success, otherwise NULL
982 _PUBLIC_ int emsmdbp_object_copy_properties(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *source_object, struct emsmdbp_object *target_object, struct SPropTagArray *excluded_properties, bool deep_copy)
986 if (!(source_object->type == EMSMDBP_OBJECT_FOLDER
987 || source_object->type == EMSMDBP_OBJECT_MAILBOX
988 || source_object->type == EMSMDBP_OBJECT_MESSAGE
989 || source_object->type == EMSMDBP_OBJECT_ATTACHMENT)) {
990 DEBUG(0, (__location__": object must be EMSMDBP_OBJECT_FOLDER, EMSMDBP_OBJECT_MAILBOX, EMSMDBP_OBJECT_MESSAGE or EMSMDBP_OBJECT_ATTACHMENT (type = %d)\n", source_object->type));
991 ret = MAPI_E_NO_SUPPORT;
994 if (target_object->type != source_object->type) {
995 DEBUG(0, ("source and destination objects type must match (type = %d)\n", target_object->type));
996 ret = MAPI_E_NO_SUPPORT;
1000 /* copy properties (common to all object types) */
1001 ret = emsmdbp_copy_properties(emsmdbp_ctx, source_object, target_object, excluded_properties);
1002 if (ret != MAPI_E_SUCCESS) {
1006 /* type specific ops */
1007 switch (source_object->type) {
1008 case EMSMDBP_OBJECT_MESSAGE:
1009 if (emsmdbp_is_mapistore(source_object) && emsmdbp_is_mapistore(target_object)) {
1010 ret = emsmdbp_copy_message_recipients_mapistore(emsmdbp_ctx, source_object, target_object);
1011 if (ret != MAPI_E_SUCCESS) {
1015 ret = emsmdbp_copy_message_attachments_mapistore(emsmdbp_ctx, source_object, target_object);
1016 if (ret != MAPI_E_SUCCESS) {
1022 DEBUG(0, ("Cannot copy recipients or attachments to or from non-mapistore messages\n"));
1027 DEBUG(0, ("Cannot deep copy non-message objects\n"));
1037 \details Initialize a mailbox object
1039 \param mem_ctx pointer to the memory context
1040 \param emsmdbp_ctx pointer to the emsmdb provider context
1041 \param request pointer to the Logon MAPI request
1042 \param mailboxstore boolean which specifies whether the mailbox
1043 object is a PF store or a private mailbox store
1045 \return Allocated emsmdbp object on success, otherwise NULL
1047 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_mailbox_init(TALLOC_CTX *mem_ctx,
1048 struct emsmdbp_context *emsmdbp_ctx,
1052 struct emsmdbp_object *object;
1053 const char *displayName, *cn;
1054 const char * const recipient_attrs[] = { "*", NULL };
1056 struct ldb_result *res = NULL;
1059 if (!emsmdbp_ctx) return NULL;
1060 if (!essDN) return NULL;
1062 object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, NULL);
1063 if (!object) return NULL;
1065 /* Initialize the mailbox object */
1066 object->object.mailbox = talloc_zero(object, struct emsmdbp_object_mailbox);
1067 if (!object->object.mailbox) {
1068 talloc_free(object);
1072 object->type = EMSMDBP_OBJECT_MAILBOX;
1073 object->object.mailbox->owner_Name = NULL;
1074 object->object.mailbox->owner_EssDN = NULL;
1075 object->object.mailbox->szUserDN = NULL;
1076 object->object.mailbox->folderID = 0x0;
1077 object->object.mailbox->mailboxstore = mailboxstore;
1079 if (mailboxstore == true) {
1080 object->object.mailbox->owner_EssDN = talloc_strdup(object->object.mailbox, essDN);
1081 ret = ldb_search(emsmdbp_ctx->samdb_ctx, mem_ctx, &res,
1082 ldb_get_default_basedn(emsmdbp_ctx->samdb_ctx),
1083 LDB_SCOPE_SUBTREE, recipient_attrs, "legacyExchangeDN=%s",
1084 object->object.mailbox->owner_EssDN);
1085 if (!ret && res->count == 1) {
1086 cn = ldb_msg_find_attr_as_string(res->msgs[0], "cn", NULL);
1088 object->object.mailbox->owner_username = talloc_strdup(object->object.mailbox, cn);
1090 /* Retrieve Mailbox folder identifier */
1091 openchangedb_get_SystemFolderID(emsmdbp_ctx->oc_ctx, object->object.mailbox->owner_username,
1092 0x1, &object->object.mailbox->folderID);
1094 displayName = ldb_msg_find_attr_as_string(res->msgs[0], "displayName", NULL);
1096 object->object.mailbox->owner_Name = talloc_strdup(object->object.mailbox,
1101 /* Retrieve Public folder identifier */
1102 openchangedb_get_PublicFolderID(emsmdbp_ctx->oc_ctx, EMSMDBP_PF_ROOT, &object->object.mailbox->folderID);
1105 object->object.mailbox->szUserDN = talloc_strdup(object->object.mailbox, emsmdbp_ctx->szUserDN);
1114 \details Initialize a folder object
1116 \param mem_ctx pointer to the memory context
1117 \param emsmdbp_ctx pointer to the emsmdb provider context
1118 \param folderID the folder identifier
1119 \param parent emsmdbp object of the parent folder for this folder
1121 \return Allocated emsmdbp object on success, otherwise NULL
1123 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_folder_init(TALLOC_CTX *mem_ctx,
1124 struct emsmdbp_context *emsmdbp_ctx,
1126 struct emsmdbp_object *parent_object)
1128 struct emsmdbp_object *object;
1131 if (!emsmdbp_ctx) return NULL;
1133 object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent_object);
1134 if (!object) return NULL;
1136 object->object.folder = talloc_zero(object, struct emsmdbp_object_folder);
1137 if (!object->object.folder) {
1138 talloc_free(object);
1142 object->type = EMSMDBP_OBJECT_FOLDER;
1143 object->object.folder->folderID = folderID;
1144 object->object.folder->mapistore_root = false;
1145 object->object.folder->contextID = (uint32_t) -1;
1150 int emsmdbp_folder_get_folder_count(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *folder, uint32_t *row_countp)
1155 if (emsmdbp_is_mapistore(folder)) {
1156 retval = mapistore_folder_get_child_count(emsmdbp_ctx->mstore_ctx, emsmdbp_get_contextID(folder),
1157 folder->backend_object, MAPISTORE_FOLDER_TABLE, row_countp);
1160 if (folder->type == EMSMDBP_OBJECT_FOLDER) {
1161 folderID = folder->object.folder->folderID;
1163 else if (folder->type == EMSMDBP_OBJECT_MAILBOX) {
1164 folderID = folder->object.folder->folderID;
1167 DEBUG(5, ("unsupported object type\n"));
1168 return MAPISTORE_ERROR;
1170 printf("emsmdbp_folder_get_folder_count: folderID = %"PRIu64"\n", folderID);
1171 retval = openchangedb_get_folder_count(emsmdbp_ctx->oc_ctx, folderID, row_countp);
1177 _PUBLIC_ enum mapistore_error emsmdbp_folder_delete(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *parent_folder, uint64_t fid, uint8_t flags)
1179 enum mapistore_error ret;
1180 enum MAPISTATUS mapiret;
1181 TALLOC_CTX *mem_ctx;
1183 uint32_t context_id;
1187 mem_ctx = talloc_zero(NULL, TALLOC_CTX);
1189 mailboxstore = emsmdbp_is_mailboxstore(parent_folder);
1190 if (emsmdbp_is_mapistore(parent_folder)) { /* fid is not a mapistore root */
1191 DEBUG(0, ("Deleting mapistore folder\n"));
1192 /* handled by mapistore */
1193 context_id = emsmdbp_get_contextID(parent_folder);
1195 ret = mapistore_folder_open_folder(emsmdbp_ctx->mstore_ctx, context_id, parent_folder->backend_object, mem_ctx, fid, &subfolder);
1196 if (ret != MAPISTORE_SUCCESS) {
1200 ret = mapistore_folder_delete(emsmdbp_ctx->mstore_ctx, context_id, subfolder, flags);
1201 if (ret != MAPISTORE_SUCCESS) {
1206 mapiret = openchangedb_get_mapistoreURI(mem_ctx, emsmdbp_ctx->oc_ctx, fid, &mapistoreURL, mailboxstore);
1207 if (mapiret != MAPI_E_SUCCESS) {
1208 ret = MAPISTORE_ERR_NOT_FOUND;
1212 mapiret = openchangedb_delete_folder(emsmdbp_ctx->oc_ctx, fid);
1213 if (mapiret != MAPI_E_SUCCESS) {
1214 ret = MAPISTORE_ERR_NOT_FOUND;
1218 if (mapistoreURL) { /* fid is mapistore root */
1219 ret = mapistore_search_context_by_uri(emsmdbp_ctx->mstore_ctx, mapistoreURL, &context_id, &subfolder);
1220 if (ret == MAPISTORE_SUCCESS) {
1221 mapistore_add_context_ref_count(emsmdbp_ctx->mstore_ctx, context_id);
1223 ret = mapistore_add_context(emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->username, mapistoreURL, fid, &context_id, &subfolder);
1224 if (ret != MAPISTORE_SUCCESS) {
1229 ret = mapistore_folder_delete(emsmdbp_ctx->mstore_ctx, context_id, subfolder, flags);
1230 if (ret != MAPISTORE_SUCCESS) {
1234 mapistore_del_context(emsmdbp_ctx->mstore_ctx, context_id);
1238 ret = MAPISTORE_SUCCESS;
1241 talloc_free(mem_ctx);
1246 _PUBLIC_ struct emsmdbp_object *emsmdbp_folder_open_table(TALLOC_CTX *mem_ctx,
1247 struct emsmdbp_object *parent_object,
1248 uint32_t table_type, uint32_t handle_id)
1250 struct emsmdbp_object *table_object;
1252 uint8_t mstore_type;
1255 if (!(parent_object->type != EMSMDBP_OBJECT_FOLDER || parent_object->type != EMSMDBP_OBJECT_MAILBOX)) {
1256 DEBUG(0, (__location__": parent_object must be EMSMDBP_OBJECT_FOLDER or EMSMDBP_OBJECT_MAILBOX (type = %d)\n", parent_object->type));
1260 if (parent_object->type == EMSMDBP_OBJECT_FOLDER && parent_object->object.folder->postponed_props) {
1261 emsmdbp_object_folder_commit_creation(parent_object->emsmdbp_ctx, parent_object, true);
1264 table_object = emsmdbp_object_table_init(mem_ctx, parent_object->emsmdbp_ctx, parent_object);
1266 table_object->object.table->handle = handle_id;
1267 table_object->object.table->ulType = table_type;
1268 if (emsmdbp_is_mapistore(parent_object)) {
1269 switch (table_type) {
1270 case MAPISTORE_MESSAGE_TABLE:
1271 mstore_type = MAPISTORE_MESSAGE_TABLE;
1273 case MAPISTORE_FAI_TABLE:
1274 mstore_type = MAPISTORE_FAI_TABLE;
1276 case MAPISTORE_FOLDER_TABLE:
1277 mstore_type = MAPISTORE_FOLDER_TABLE;
1279 case MAPISTORE_PERMISSIONS_TABLE:
1280 mstore_type = MAPISTORE_PERMISSIONS_TABLE;
1283 DEBUG(5, ("Unhandled table type for folders: %d\n", table_type));
1287 ret = mapistore_folder_open_table(parent_object->emsmdbp_ctx->mstore_ctx, emsmdbp_get_contextID(parent_object), parent_object->backend_object, table_object, mstore_type, handle_id, &table_object->backend_object, &table_object->object.table->denominator);
1288 if (ret != MAPISTORE_SUCCESS) {
1289 talloc_free(table_object);
1290 table_object = NULL;
1294 if (table_type == MAPISTORE_FOLDER_TABLE) {
1295 /* this gets data both for openchangedb and mapistore: needs improvement */
1296 emsmdbp_folder_get_folder_count(parent_object->emsmdbp_ctx, parent_object, &table_object->object.table->denominator);
1299 /* Retrieve folder ID */
1300 switch (parent_object->type) {
1301 case EMSMDBP_OBJECT_FOLDER:
1302 folderID = parent_object->object.folder->folderID;
1304 case EMSMDBP_OBJECT_MAILBOX:
1305 folderID = parent_object->object.mailbox->folderID;
1308 DEBUG(5, ("Unsupported object type"));
1309 table_object->object.table->denominator = 0;
1310 return table_object;
1313 /* Non-mapistore message tables */
1314 switch (table_type) {
1315 case MAPISTORE_MESSAGE_TABLE:
1316 openchangedb_get_message_count(parent_object->emsmdbp_ctx->oc_ctx,
1318 &table_object->object.table->denominator,
1321 case MAPISTORE_FAI_TABLE:
1322 openchangedb_get_message_count(parent_object->emsmdbp_ctx->oc_ctx,
1324 &table_object->object.table->denominator,
1328 DEBUG(0, ("Unhandled openchangedb table type for folders: %d\n", table_type));
1329 table_object->object.table->denominator = 0;
1333 if (!emsmdbp_is_mapistore(parent_object)) {
1334 /* Retrieve folder ID */
1335 switch (parent_object->type) {
1336 case EMSMDBP_OBJECT_FOLDER:
1337 folderID = parent_object->object.folder->folderID;
1339 case EMSMDBP_OBJECT_MAILBOX:
1340 folderID = parent_object->object.mailbox->folderID;
1343 DEBUG(5, ("Unsupported object type"));
1344 table_object->object.table->denominator = 0;
1345 return table_object;
1347 DEBUG(0, ("Initializaing openchangedb table\n"));
1348 openchangedb_table_init((TALLOC_CTX *)table_object, table_type, folderID, &table_object->backend_object);
1353 return table_object;
1357 \details Initialize a table object
1359 \param mem_ctx pointer to the memory context
1360 \param emsmdbp_ctx pointer to the emsmdb provider context
1361 \param parent emsmdbp object of the parent
1363 \return Allocated emsmdbp object on success, otherwise NULL
1365 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_table_init(TALLOC_CTX *mem_ctx,
1366 struct emsmdbp_context *emsmdbp_ctx,
1367 struct emsmdbp_object *parent)
1369 struct emsmdbp_object *object;
1372 if (!emsmdbp_ctx) return NULL;
1373 if (!parent) return NULL;
1374 if (parent->type != EMSMDBP_OBJECT_FOLDER && parent->type != EMSMDBP_OBJECT_MAILBOX && parent->type != EMSMDBP_OBJECT_MESSAGE) return NULL;
1376 /* Initialize table object */
1377 object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
1378 if (!object) return NULL;
1380 object->object.table = talloc_zero(object, struct emsmdbp_object_table);
1381 if (!object->object.table) {
1382 talloc_free(object);
1386 object->type = EMSMDBP_OBJECT_TABLE;
1387 object->object.table->prop_count = 0;
1388 object->object.table->properties = NULL;
1389 object->object.table->numerator = 0;
1390 object->object.table->denominator = 0;
1391 object->object.table->ulType = 0;
1392 object->object.table->restricted = false;
1393 object->object.table->subscription_list = NULL;
1398 _PUBLIC_ int emsmdbp_object_table_get_available_properties(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *table_object, struct SPropTagArray **propertiesp)
1401 struct SPropTagArray *properties;
1404 if (!table_object->type == EMSMDBP_OBJECT_TABLE) {
1405 return MAPISTORE_ERROR;
1408 if (emsmdbp_is_mapistore(table_object)) {
1409 contextID = emsmdbp_get_contextID(table_object);
1410 retval = mapistore_table_get_available_properties(emsmdbp_ctx->mstore_ctx, contextID, table_object->backend_object, mem_ctx, propertiesp);
1413 properties = talloc_zero(mem_ctx, struct SPropTagArray);
1414 properties->aulPropTag = talloc_zero(properties, enum MAPITAGS);
1415 /* TODO: this list might not be complete */
1416 SPropTagArray_add(properties, properties, PR_FID);
1417 SPropTagArray_add(properties, properties, PR_PARENT_FID);
1418 SPropTagArray_add(properties, properties, PR_DISPLAY_NAME_UNICODE);
1419 SPropTagArray_add(properties, properties, PR_COMMENT_UNICODE);
1420 SPropTagArray_add(properties, properties, PR_ACCESS);
1421 SPropTagArray_add(properties, properties, PR_CREATION_TIME);
1422 SPropTagArray_add(properties, properties, PR_NTSD_MODIFICATION_TIME);
1423 SPropTagArray_add(properties, properties, PR_LAST_MODIFICATION_TIME);
1424 SPropTagArray_add(properties, properties, PR_ADDITIONAL_REN_ENTRYIDS);
1425 SPropTagArray_add(properties, properties, PR_ADDITIONAL_REN_ENTRYIDS_EX);
1426 SPropTagArray_add(properties, properties, PR_CREATOR_SID);
1427 SPropTagArray_add(properties, properties, PR_LAST_MODIFIER_SID);
1428 SPropTagArray_add(properties, properties, PR_ATTR_HIDDEN);
1429 SPropTagArray_add(properties, properties, PR_ATTR_SYSTEM);
1430 SPropTagArray_add(properties, properties, PR_ATTR_READONLY);
1431 SPropTagArray_add(properties, properties, PR_EXTENDED_ACL_DATA);
1432 SPropTagArray_add(properties, properties, PR_CONTAINER_CLASS_UNICODE);
1433 SPropTagArray_add(properties, properties, PR_MESSAGE_CLASS_UNICODE);
1434 SPropTagArray_add(properties, properties, PR_RIGHTS);
1435 SPropTagArray_add(properties, properties, PR_CONTENT_COUNT);
1436 SPropTagArray_add(properties, properties, PidTagAssociatedContentCount);
1437 SPropTagArray_add(properties, properties, PR_SUBFOLDERS);
1438 SPropTagArray_add(properties, properties, PR_MAPPING_SIGNATURE);
1439 SPropTagArray_add(properties, properties, PR_USER_ENTRYID);
1440 SPropTagArray_add(properties, properties, PR_MAILBOX_OWNER_ENTRYID);
1441 SPropTagArray_add(properties, properties, PR_MAILBOX_OWNER_NAME_UNICODE);
1442 SPropTagArray_add(properties, properties, PR_IPM_APPOINTMENT_ENTRYID);
1443 SPropTagArray_add(properties, properties, PR_IPM_CONTACT_ENTRYID);
1444 SPropTagArray_add(properties, properties, PR_IPM_JOURNAL_ENTRYID);
1445 SPropTagArray_add(properties, properties, PR_IPM_NOTE_ENTRYID);
1446 SPropTagArray_add(properties, properties, PR_IPM_TASK_ENTRYID);
1447 SPropTagArray_add(properties, properties, PR_IPM_DRAFTS_ENTRYID);
1448 SPropTagArray_add(properties, properties, PR_REMINDERS_ONLINE_ENTRYID);
1449 SPropTagArray_add(properties, properties, PR_IPM_PUBLIC_FOLDERS_ENTRYID);
1450 SPropTagArray_add(properties, properties, PR_FOLDER_XVIEWINFO_E);
1451 SPropTagArray_add(properties, properties, PR_FOLDER_VIEWLIST);
1452 SPropTagArray_add(properties, properties, PR_FREEBUSY_ENTRYIDS);
1453 *propertiesp = properties;
1455 retval = MAPISTORE_SUCCESS;
1461 _PUBLIC_ void **emsmdbp_object_table_get_row_props(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *table_object, uint32_t row_id, enum mapistore_query_type query_type, enum MAPISTATUS **retvalsp)
1463 void **data_pointers;
1464 enum MAPISTATUS retval;
1465 enum mapistore_error ret;
1466 enum MAPISTATUS *retvals;
1467 struct emsmdbp_object_table *table;
1468 struct mapistore_property_data *properties;
1469 uint32_t contextID, i, num_props, *obj_count;
1470 struct emsmdbp_object *rowobject;
1472 uint64_t parentFolderId;
1473 bool mapistore_folder;
1474 uint8_t *has_subobj;
1477 struct Binary_r *binr;
1479 table = table_object->object.table;
1480 num_props = table_object->object.table->prop_count;
1482 data_pointers = talloc_array(mem_ctx, void *, num_props);
1483 memset(data_pointers, 0, sizeof(void *) * num_props);
1484 retvals = talloc_array(mem_ctx, enum MAPISTATUS, num_props);
1485 memset(retvals, 0, sizeof(uint32_t) * num_props);
1487 contextID = emsmdbp_get_contextID(table_object);
1488 if (emsmdbp_is_mapistore(table_object)) {
1489 retval = mapistore_table_get_row(emsmdbp_ctx->mstore_ctx, contextID,
1490 table_object->backend_object, data_pointers,
1491 query_type, row_id, &properties);
1492 if (retval == MAPI_E_SUCCESS) {
1493 for (i = 0; i < num_props; i++) {
1494 data_pointers[i] = properties[i].data;
1496 if (properties[i].error) {
1497 if (properties[i].error == MAPISTORE_ERR_NOT_FOUND)
1498 retvals[i] = MAPI_E_NOT_FOUND;
1499 else if (properties[i].error == MAPISTORE_ERR_NO_MEMORY)
1500 retvals[i] = MAPI_E_NOT_ENOUGH_MEMORY;
1502 retvals[i] = MAPI_E_NO_SUPPORT;
1503 DEBUG (4, ("%s: unknown mapistore error: %.8x\n", __PRETTY_FUNCTION__, properties[i].error));
1507 if (properties[i].data == NULL) {
1508 retvals[i] = MAPI_E_NOT_FOUND;
1514 DEBUG(5, ("%s: invalid object (likely due to a restriction)\n", __location__));
1515 talloc_free(retvals);
1516 talloc_free(data_pointers);
1520 if (table_object->parent_object->type == EMSMDBP_OBJECT_FOLDER) {
1521 parentFolderId = table_object->parent_object->object.folder->folderID;
1523 else if (table_object->parent_object->type == EMSMDBP_OBJECT_MAILBOX) {
1524 parentFolderId = table_object->parent_object->object.mailbox->folderID;
1527 DEBUG(5, ("%s: non-mapistore tables can only be client of folder objects\n", __location__));
1528 talloc_free(retvals);
1529 talloc_free(data_pointers);
1533 odb_ctx = talloc_zero(NULL, void);
1535 /* Setup table_filter for openchangedb */
1536 /* switch (table_object->object.table->ulType) { */
1537 /* case MAPISTORE_MESSAGE_TABLE: */
1538 /* table_filter = talloc_asprintf(odb_ctx, "(&(PidTagParentFolderId=%"PRIu64")(PidTagMessageId=*))", folderID); */
1540 /* case MAPISTORE_FOLDER_TABLE: */
1541 /* table_filter = talloc_asprintf(odb_ctx, "(&(PidTagParentFolderId=%"PRIu64")(PidTagFolderId=*))", folderID); */
1544 /* DEBUG(5, ("[%s:%d]: Unsupported table type for openchangedb: %d\n", __FUNCTION__, __LINE__, */
1545 /* table_object->object.table->ulType)); */
1546 /* talloc_free(retvals); */
1547 /* talloc_free(data_pointers); */
1551 /* 1. retrieve the object id from odb */
1552 switch (table_object->object.table->ulType) {
1553 case MAPISTORE_FOLDER_TABLE:
1554 retval = openchangedb_table_get_property(odb_ctx, table_object->backend_object, emsmdbp_ctx->oc_ctx, PR_FID, row_id, (query_type == MAPISTORE_LIVEFILTERED_QUERY), (void **) &rowFMId);
1556 case MAPISTORE_MESSAGE_TABLE:
1557 retval = openchangedb_table_get_property(odb_ctx, table_object->backend_object, emsmdbp_ctx->oc_ctx, PR_MID, row_id, (query_type == MAPISTORE_LIVEFILTERED_QUERY), (void **) &rowFMId);
1559 /* case MAPISTORE_FAI_TABLE:
1560 retval = openchangedb_table_get_property(odb_ctx, table_object->backend_object, emsmdbp_ctx->oc_ctx,
1561 PR_MID, row_id, (query_type == MAPISTORE_LIVEFILTERED_QUERY), (void **) &rowFMId);
1564 DEBUG(5, ("table type %d not supported for non-mapistore table\n", table_object->object.table->ulType));
1565 retval = MAPI_E_INVALID_OBJECT;
1567 /* printf("openchangedb_table_get_property retval = 0x%.8x\n", retval); */
1568 if (retval != MAPI_E_SUCCESS) {
1569 talloc_free(retvals);
1570 talloc_free(data_pointers);
1571 talloc_free(odb_ctx);
1575 /* 2. open the corresponding object */
1576 switch (table_object->object.table->ulType) {
1577 case MAPISTORE_FOLDER_TABLE:
1578 ret = emsmdbp_object_open_folder(odb_ctx, table_object->parent_object->emsmdbp_ctx, table_object->parent_object, *(uint64_t *)rowFMId, &rowobject);
1579 mapistore_folder = emsmdbp_is_mapistore(rowobject);
1581 case MAPISTORE_MESSAGE_TABLE:
1582 ret = emsmdbp_object_message_open(odb_ctx, table_object->parent_object->emsmdbp_ctx, table_object->parent_object, parentFolderId, *(uint64_t *)rowFMId, false, &rowobject, NULL);
1583 mapistore_folder = false;
1586 DEBUG(5, ("you should never get here\n"));
1589 if (ret != MAPISTORE_SUCCESS) {
1590 talloc_free(retvals);
1591 talloc_free(data_pointers);
1592 talloc_free(odb_ctx);
1596 /* read the row properties */
1597 retval = MAPI_E_SUCCESS;
1598 for (i = 0; retval != MAPI_E_INVALID_OBJECT && i < num_props; i++) {
1599 if (mapistore_folder) {
1600 /* a hack to avoid fetching dynamic fields from openchange.ldb */
1601 switch (table->properties[i]) {
1602 case PR_CONTENT_COUNT:
1603 obj_count = talloc_zero(data_pointers, uint32_t);
1604 retval = mapistore_folder_get_child_count(emsmdbp_ctx->mstore_ctx, contextID, rowobject,
1605 MAPISTORE_MESSAGE_TABLE, obj_count);
1606 data_pointers[i] = obj_count;
1608 case PidTagAssociatedContentCount:
1609 obj_count = talloc_zero(data_pointers, uint32_t);
1610 retval = mapistore_folder_get_child_count(emsmdbp_ctx->mstore_ctx, contextID, rowobject,
1611 MAPISTORE_FAI_TABLE, obj_count);
1612 data_pointers[i] = obj_count;
1614 case PidTagFolderChildCount:
1615 obj_count = talloc_zero(data_pointers, uint32_t);
1616 retval = emsmdbp_folder_get_folder_count(emsmdbp_ctx, rowobject, obj_count);
1617 data_pointers[i] = obj_count;
1619 case PidTagSourceKey:
1620 owner = emsmdbp_get_owner(table_object);
1621 emsmdbp_source_key_from_fmid(data_pointers, emsmdbp_ctx, owner, rowobject->object.folder->folderID, &binr);
1622 data_pointers[i] = binr;
1625 obj_count = talloc_zero(NULL, uint32_t);
1626 retval = emsmdbp_folder_get_folder_count(emsmdbp_ctx, rowobject, obj_count);
1627 has_subobj = talloc_zero(data_pointers, uint8_t);
1628 *has_subobj = (*obj_count > 0) ? 1 : 0;
1629 data_pointers[i] = has_subobj;
1630 talloc_free(obj_count);
1632 case PR_CONTENT_UNREAD:
1633 case PidTagDeletedCountTotal:
1634 /* TODO: temporary */
1635 obj_count = talloc_zero(data_pointers, uint32_t);
1636 data_pointers[i] = obj_count;
1637 retval = MAPI_E_SUCCESS;
1640 retval = openchangedb_table_get_property(data_pointers, table_object->backend_object,
1641 emsmdbp_ctx->oc_ctx,
1642 table->properties[i],
1644 (query_type == MAPISTORE_LIVEFILTERED_QUERY),
1646 /* retval = openchangedb_get_table_property(data_pointers, emsmdbp_ctx->oc_ctx, */
1647 /* emsmdbp_ctx->username, */
1648 /* table_filter, table->properties[i], */
1649 /* row_id, data_pointers + i); */
1653 retval = openchangedb_table_get_property(data_pointers, table_object->backend_object,
1654 emsmdbp_ctx->oc_ctx,
1655 table->properties[i],
1657 (query_type == MAPISTORE_LIVEFILTERED_QUERY),
1661 /* DEBUG(5, (" %.8x: %d", table->properties[j], retval)); */
1662 if (retval == MAPI_E_INVALID_OBJECT) {
1663 DEBUG(5, ("%s: invalid object in non-mapistore folder, count set to 0\n", __location__));
1664 talloc_free(retvals);
1665 talloc_free(data_pointers);
1666 talloc_free(odb_ctx);
1670 retvals[i] = retval;
1674 talloc_free(odb_ctx);
1678 *retvalsp = retvals;
1681 return data_pointers;
1684 _PUBLIC_ void emsmdbp_fill_table_row_blob(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx,
1685 DATA_BLOB *table_row, uint16_t num_props,
1686 enum MAPITAGS *properties,
1687 void **data_pointers, enum MAPISTATUS *retvals)
1691 enum MAPITAGS property;
1697 for (i = 0; !flagged && i < num_props; i++) {
1698 if (retvals[i] != MAPI_E_SUCCESS) {
1704 libmapiserver_push_property(mem_ctx,
1705 0x0000000b, (const void *)&flagged,
1706 table_row, 0, 0, 0);
1709 libmapiserver_push_property(mem_ctx,
1710 0x00000000, (const void *)&flagged,
1711 table_row, 0, 1, 0);
1714 for (i = 0; i < num_props; i++) {
1715 property = properties[i];
1716 retval = retvals[i];
1717 if (retval != MAPI_E_SUCCESS) {
1718 property = (property & 0xFFFF0000) + PT_ERROR;
1722 data = data_pointers[i];
1725 libmapiserver_push_property(mem_ctx,
1726 property, data, table_row,
1727 flagged?PT_ERROR:0, flagged, 0);
1732 \details Initialize a message object
1734 \param mem_ctx pointer to the memory context
1735 \param emsmdbp_ctx pointer to the emsmdb provider context
1736 \param messageID the message identifier
1737 \param parent emsmdbp object of the parent
1739 \return Allocated emsmdbp object on success, otherwise NULL
1741 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_message_init(TALLOC_CTX *mem_ctx,
1742 struct emsmdbp_context *emsmdbp_ctx,
1744 struct emsmdbp_object *parent)
1746 struct emsmdbp_object *object;
1749 if (!emsmdbp_ctx) return NULL;
1750 if (!parent) return NULL;
1751 if (parent->type != EMSMDBP_OBJECT_FOLDER && parent->type != EMSMDBP_OBJECT_MAILBOX) {
1752 DEBUG(5, ("expecting EMSMDBP_OBJECT_FOLDER/_MAILBOX as type of parent object\n"));
1756 /* Initialize message object */
1757 object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
1758 if (!object) return NULL;
1760 object->object.message = talloc_zero(object, struct emsmdbp_object_message);
1761 if (!object->object.message) {
1762 talloc_free(object);
1766 object->type = EMSMDBP_OBJECT_MESSAGE;
1767 object->object.message->messageID = messageID;
1768 object->object.message->read_write = false;
1773 static int emsmdbp_days_in_month(int month, int year)
1775 static int max_mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1779 dec_year = year % 100;
1781 && ((((year + 1900) / 100) % 4) == 0))
1782 || (dec_year % 4) == 0) {
1786 days = max_mdays[month];
1790 days = max_mdays[month];
1796 static int emsmdbp_mins_in_ymon(uint32_t ymon)
1798 return emsmdbp_days_in_month((ymon & 0xf) - 1, ymon >> 4) * 24 * 60;
1801 static inline void emsmdbp_freebusy_make_range(struct tm *start_time, struct tm *end_time)
1804 struct tm time_data;
1805 int mw_delta, month;
1807 /* (from OXOPFFB - 3.1.4.1.1)
1808 Start of range is 12:00 A.M. UTC on the first day of the month or the first day of the week, whichever occurs earlier at the time of publishing.
1809 End of range is calculated by adding the value of the PidTagFreeBusyCountMonths property ([MS-OXOCAL] section 2.2.12.1) to start of range.
1811 Since PidTagFreeBusyCountMonths is not supported yet, we use a count of 3 months
1815 time_data = *gmtime(&now);
1816 time_data.tm_hour = 0;
1817 time_data.tm_min = 0;
1818 time_data.tm_sec = 0;
1820 /* take the first day of the week OR the first day of the month */
1821 month = time_data.tm_mon;
1822 if (time_data.tm_mday < 7) {
1823 mw_delta = (time_data.tm_wday + 1 - time_data.tm_mday);
1825 if (time_data.tm_mon > 0) {
1829 time_data.tm_mon = 11;
1830 time_data.tm_year--;
1832 time_data.tm_mday = emsmdbp_days_in_month(time_data.tm_mon, time_data.tm_year) + 1 - mw_delta;
1835 time_data.tm_mday = 1;
1840 time_data.tm_mday = 1;
1843 *start_time = time_data;
1845 time_data.tm_mon = month + 2;
1846 if (time_data.tm_mon > 11) {
1847 time_data.tm_year++;
1848 time_data.tm_mon -= 12;
1850 time_data.tm_mday = emsmdbp_days_in_month(time_data.tm_mon, time_data.tm_year) + 1 - mw_delta;
1851 time_data.tm_hour = 23;
1852 time_data.tm_min = 59;
1853 time_data.tm_sec = 59;
1855 *end_time = time_data;
1858 static void emsmdbp_freebusy_convert_filetime(struct FILETIME *ft_value, uint32_t *ymon, uint32_t *mins)
1864 nt_time = ((NTTIME) ft_value->dwHighDateTime << 32) | ft_value->dwLowDateTime;
1865 u_time = nt_time_to_unix(nt_time);
1866 gm_time = gmtime(&u_time);
1868 *ymon = ((gm_time->tm_year + 1900) << 4) | (gm_time->tm_mon + 1);
1869 *mins = gm_time->tm_min + (gm_time->tm_hour + ((gm_time->tm_mday - 1) * 24)) * 60;
1872 static uint16_t emsmdbp_freebusy_find_month_range(uint32_t ymon, uint32_t *months_ranges, uint16_t nbr_months, bool *overflow)
1876 if (nbr_months > 0) {
1877 if (months_ranges[0] > ymon) {
1882 if (months_ranges[nbr_months - 1] < ymon) {
1884 return (nbr_months - 1);
1888 for (range = 0; range < nbr_months; range++) {
1889 if (months_ranges[range] == ymon) {
1897 return (uint16_t) -1;
1900 /* TODO: both following methods could be merged. This would certainly enhance performance by avoiding to wander through long arrays multiple times */
1901 static void emsmdbp_freebusy_fill_fbarray(uint8_t **minutes_array, uint32_t *months_ranges, uint16_t nbr_months, struct FILETIME *start, struct FILETIME *end)
1903 uint32_t i, max, start_ymon, start_mins, end_ymon, end_mins;
1904 uint16_t start_mr_idx, end_mr_idx;
1905 bool start_range_overflow, end_range_overflow;
1907 emsmdbp_freebusy_convert_filetime(start, &start_ymon, &start_mins);
1908 emsmdbp_freebusy_convert_filetime(end, &end_ymon, &end_mins);
1910 start_mr_idx = emsmdbp_freebusy_find_month_range(start_ymon, months_ranges, nbr_months, &start_range_overflow);
1911 if (start_range_overflow) {
1914 end_mr_idx = emsmdbp_freebusy_find_month_range(end_ymon, months_ranges, nbr_months, &end_range_overflow);
1915 if (end_range_overflow) {
1916 end_mins = emsmdbp_mins_in_ymon(end_ymon);
1920 if (end_mr_idx > start_mr_idx) {
1921 /* end occurs after start range */
1924 for (i = start_mr_idx + 1; i < end_mr_idx; i++) {
1925 memset(minutes_array[i], 1, emsmdbp_mins_in_ymon(months_ranges[i]));
1929 memset(minutes_array[end_mr_idx], 1, end_mins);
1931 max = emsmdbp_mins_in_ymon(start_ymon); /* = max chunk for first range */
1934 /* end occurs on same range as start */
1938 memset(minutes_array[start_mr_idx] + start_mins, 1, (max - start_mins));
1941 static void emsmdbp_freebusy_compile_fbarray(TALLOC_CTX *mem_ctx, uint8_t *minutes_array, struct Binary_r *fb_bin)
1945 struct ndr_push *ndr;
1946 TALLOC_CTX *local_mem_ctx;
1948 local_mem_ctx = talloc_zero(NULL, TALLOC_CTX);
1950 ndr = ndr_push_init_ctx(local_mem_ctx);
1952 filled = (minutes_array[0] != 0);
1954 ndr_push_uint16(ndr, NDR_SCALARS, 0);
1957 for (i = 1; i < max_mins_per_month; i++) {
1958 if (filled && !minutes_array[i]) {
1959 ndr_push_uint16(ndr, NDR_SCALARS, (i - 1));
1962 else if (!filled && minutes_array[i]) {
1963 ndr_push_uint16(ndr, NDR_SCALARS, i);
1968 ndr_push_uint16(ndr, NDR_SCALARS, (max_mins_per_month - 1));
1971 fb_bin->cb = ndr->offset;
1972 fb_bin->lpb = ndr->data;
1973 (void) talloc_reference(mem_ctx, fb_bin->lpb);
1975 talloc_free(local_mem_ctx);
1978 static void emsmdbp_freebusy_merge_subarray(uint8_t *minutes_array, uint8_t *included_array)
1982 for (i = 0; i < max_mins_per_month; i++) {
1983 if (included_array[i]) {
1984 minutes_array[i] = 1;
1989 static void emsmdbp_object_message_fill_freebusy_properties(struct emsmdbp_object *message_object)
1991 /* freebusy mechanism:
1992 - lookup events in range now + 3 months, requesting end date, start date and PidLidBusyStatus
1993 - fill (olTentative) PidTagScheduleInfoMonthsTentative,
1994 PidTagScheduleInfoFreeBusyTentative
1995 - fill (olBusy) PidTagScheduleInfoMonthsBusy,
1996 PidTagScheduleInfoFreeBusyBusy
1997 - fill (olOutOfOffice) PidTagScheduleInfoMonthsAway,
1998 PidTagScheduleInfoFreeBusyAway
1999 - fill (olBusy + olOutOfOffice) PidTagScheduleInfoMonthsMerged,
2000 PidTagScheduleInfoFreeBusyMerged
2001 - fill PidTagFreeBusyPublishStart, PidTagFreeBusyPublishEnd and
2002 PidTagFreeBusyRangeTimestamp.
2003 - fill PidTagFreeBusyMessageEmailAddress */
2005 TALLOC_CTX *mem_ctx;
2006 struct emsmdbp_object_message_freebusy_properties *fb_props;
2007 char *subject, *email, *username, *tmp;
2008 struct SPropTagArray *props;
2009 void **data_pointers;
2010 enum MAPISTATUS *retvals = NULL;
2011 struct emsmdbp_object *mailbox, *inbox, *calendar, *table;
2012 uint64_t inboxFID, calendarFID;
2014 struct mapi_SRestriction and_res;
2016 struct tm start_tm, end_tm;
2017 time_t start_time, end_time;
2019 struct mapi_SRestriction_and time_restrictions[2];
2020 int i, month, nbr_months;
2021 uint8_t **minutes_array, **tentative_array, **busy_array, **oof_array;
2024 mem_ctx = talloc_zero(NULL, TALLOC_CTX);
2026 /* 1. retrieve subject and deduce username */
2027 props = talloc_zero(mem_ctx, struct SPropTagArray);
2029 props->aulPropTag = talloc_zero(props, enum MAPITAGS);
2030 props->aulPropTag[0] = PR_NORMALIZED_SUBJECT_UNICODE;
2031 data_pointers = emsmdbp_object_get_properties(mem_ctx, message_object->emsmdbp_ctx, message_object, props, &retvals);
2032 if (!data_pointers || retvals[0] != MAPI_E_SUCCESS) {
2035 subject = data_pointers[0];
2036 // format is "..../CN="
2037 username = strrchr(subject, '/');
2042 username = talloc_strdup(mem_ctx, username);
2044 fb_props = talloc_zero(message_object, struct emsmdbp_object_message_freebusy_properties);
2045 message_object->object.message->fb_properties = fb_props;
2047 // WARNING: the mechanism here will fail if username is not all lower-case, as LDB does not support case-insensitive queries
2050 *tmp = tolower(*tmp);
2053 email = talloc_asprintf(mem_ctx, "/o=First Organization/ou=First Administrative Group/cn=Recipients/cn=%s", username);
2054 fb_props->email_address = email;
2056 /* open user mailbox */
2057 mailbox = emsmdbp_object_mailbox_init(mem_ctx, message_object->emsmdbp_ctx, email, true);
2063 openchangedb_get_SystemFolderID(message_object->emsmdbp_ctx->oc_ctx, username, EMSMDBP_INBOX, &inboxFID);
2064 if (emsmdbp_object_open_folder_by_fid(mem_ctx, message_object->emsmdbp_ctx, mailbox, inboxFID, &inbox) != MAPISTORE_SUCCESS) {
2068 /* retrieve Calendar entry id */
2069 props->aulPropTag[0] = PR_IPM_APPOINTMENT_ENTRYID;
2070 data_pointers = emsmdbp_object_get_properties(mem_ctx, message_object->emsmdbp_ctx, inbox, props, &retvals);
2071 if (!data_pointers || retvals[0] != MAPI_E_SUCCESS) {
2075 for (i = 0; i < 6; i++) {
2077 calendarFID |= *(((struct Binary_r *) data_pointers[0])->lpb + (43 - i));
2082 /* open user calendar */
2083 if (emsmdbp_object_open_folder_by_fid(mem_ctx, message_object->emsmdbp_ctx, mailbox, calendarFID, &calendar) != MAPISTORE_SUCCESS) {
2086 if (!emsmdbp_is_mapistore(calendar)) {
2087 DEBUG(5, ("non-mapistore calendars are not supported for freebusy\n"));
2091 /* fetch events from this month for 3 months: start + enddate + fbstatus */
2092 table = emsmdbp_folder_open_table(mem_ctx, calendar, MAPISTORE_MESSAGE_TABLE, 0);
2096 contextID = emsmdbp_get_contextID(calendar);
2098 /* fetch freebusy range */
2099 emsmdbp_freebusy_make_range(&start_tm, &end_tm);
2101 unix_to_nt_time(&nt_time, time(NULL));
2102 fb_props->timestamp.dwLowDateTime = (nt_time & 0xffffffff);
2103 fb_props->timestamp.dwHighDateTime = nt_time >> 32;
2106 setenv("TZ", "", 1);
2108 start_time = mktime(&start_tm);
2109 end_time = mktime(&end_tm);
2111 setenv("TZ", tz, 1);
2118 /* setup restriction */
2119 and_res.rt = RES_AND;
2120 and_res.res.resAnd.cRes = 2;
2121 and_res.res.resAnd.res = time_restrictions;
2123 time_restrictions[0].rt = RES_PROPERTY;
2124 time_restrictions[0].res.resProperty.relop = RELOP_GE;
2125 time_restrictions[0].res.resProperty.ulPropTag = PidLidAppointmentEndWhole;
2126 time_restrictions[0].res.resProperty.lpProp.ulPropTag = PidLidAppointmentEndWhole;
2127 unix_to_nt_time(&nt_time, start_time);
2128 time_restrictions[0].res.resProperty.lpProp.value.ft.dwLowDateTime = (nt_time & 0xffffffff);
2129 time_restrictions[0].res.resProperty.lpProp.value.ft.dwHighDateTime = nt_time >> 32;
2130 fb_props->publish_start = (uint32_t) (nt_time / (60 * 10000000));
2132 time_restrictions[1].rt = RES_PROPERTY;
2133 time_restrictions[1].res.resProperty.relop = RELOP_LE;
2134 time_restrictions[1].res.resProperty.ulPropTag = PidLidAppointmentStartWhole;
2135 time_restrictions[1].res.resProperty.lpProp.ulPropTag = PidLidAppointmentStartWhole;
2136 unix_to_nt_time(&nt_time, end_time);
2137 time_restrictions[1].res.resProperty.lpProp.value.ft.dwLowDateTime = (nt_time & 0xffffffff);
2138 time_restrictions[1].res.resProperty.lpProp.value.ft.dwHighDateTime = nt_time >> 32;
2139 fb_props->publish_end = (uint32_t) (nt_time / (60 * 10000000));
2141 mapistore_table_set_restrictions(message_object->emsmdbp_ctx->mstore_ctx, contextID, table->backend_object, &and_res, &state);
2143 /* setup table columns */
2145 props->aulPropTag = talloc_array(props, enum MAPITAGS, props->cValues);
2146 props->aulPropTag[0] = PidLidAppointmentStartWhole;
2147 props->aulPropTag[1] = PidLidAppointmentEndWhole;
2148 props->aulPropTag[2] = PidLidBusyStatus;
2149 mapistore_table_set_columns(message_object->emsmdbp_ctx->mstore_ctx, contextID, table->backend_object, props->cValues, props->aulPropTag);
2150 table->object.table->prop_count = props->cValues;
2151 table->object.table->properties = props->aulPropTag;
2153 /* setup months arrays */
2154 if (start_tm.tm_year == end_tm.tm_year) {
2155 nbr_months = (end_tm.tm_mon - start_tm.tm_mon + 1);
2158 nbr_months = (12 - start_tm.tm_mon) + end_tm.tm_mon + 1;
2160 fb_props->months_ranges = talloc_array(fb_props, uint32_t, nbr_months);
2161 if (start_tm.tm_year == end_tm.tm_year) {
2162 for (i = 0; i < nbr_months; i++) {
2163 fb_props->months_ranges[i] = ((start_tm.tm_year + 1900) << 4) + (start_tm.tm_mon + 1 + i);
2167 month = start_tm.tm_mon;
2169 while (month < 12) {
2170 fb_props->months_ranges[i] = ((start_tm.tm_year + 1900) << 4) + month + 1;
2175 while (month < end_tm.tm_mon) {
2176 fb_props->months_ranges[i] = ((end_tm.tm_year + 1900) << 4) + month + 1;
2180 fb_props->months_ranges[i] = ((end_tm.tm_year + 1900) << 4) + month + 1;
2183 /* fetch events and fill freebusy arrays */
2184 tentative_array = talloc_array(mem_ctx, uint8_t *, nbr_months);
2185 busy_array = talloc_array(mem_ctx, uint8_t *, nbr_months);
2186 oof_array = talloc_array(mem_ctx, uint8_t *, nbr_months);
2187 for (i = 0; i < nbr_months; i++) {
2188 tentative_array[i] = talloc_array(tentative_array, uint8_t, max_mins_per_month);
2189 memset(tentative_array[i], 0, max_mins_per_month);
2190 busy_array[i] = talloc_array(tentative_array, uint8_t, max_mins_per_month);
2191 memset(busy_array[i], 0, max_mins_per_month);
2192 oof_array[i] = talloc_array(tentative_array, uint8_t, max_mins_per_month);
2193 memset(oof_array[i], 0, max_mins_per_month);
2197 while ((data_pointers = emsmdbp_object_table_get_row_props(mem_ctx, message_object->emsmdbp_ctx, table, i, MAPISTORE_PREFILTERED_QUERY, &retvals))) {
2198 if (retvals[0] == MAPI_E_SUCCESS && retvals[1] == MAPI_E_SUCCESS && retvals[2] == MAPI_E_SUCCESS) {
2199 switch (*((uint32_t *) data_pointers[2])) {
2201 minutes_array = tentative_array;
2204 minutes_array = busy_array;
2207 minutes_array = oof_array;
2210 minutes_array = NULL;
2212 if (minutes_array) {
2213 emsmdbp_freebusy_fill_fbarray(minutes_array, fb_props->months_ranges, nbr_months, data_pointers[0], data_pointers[1]);
2219 /* compile minutes array into arrays of ranges */
2220 fb_props->nbr_months = nbr_months;
2221 fb_props->freebusy_tentative = talloc_array(fb_props, struct Binary_r, nbr_months);
2222 fb_props->freebusy_busy = talloc_array(fb_props, struct Binary_r, nbr_months);
2223 fb_props->freebusy_away = talloc_array(fb_props, struct Binary_r, nbr_months);
2224 fb_props->freebusy_merged = talloc_array(fb_props, struct Binary_r, nbr_months);
2225 for (i = 0; i < nbr_months; i++) {
2226 emsmdbp_freebusy_compile_fbarray(fb_props, tentative_array[i], fb_props->freebusy_tentative + i);
2227 emsmdbp_freebusy_compile_fbarray(fb_props, busy_array[i], fb_props->freebusy_busy + i);
2228 emsmdbp_freebusy_compile_fbarray(fb_props, oof_array[i], fb_props->freebusy_away + i);
2229 emsmdbp_freebusy_merge_subarray(busy_array[i], oof_array[i]);
2230 emsmdbp_freebusy_compile_fbarray(fb_props, busy_array[i], fb_props->freebusy_merged + i);
2234 talloc_free(mem_ctx);
2239 _PUBLIC_ enum mapistore_error emsmdbp_object_message_open(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *parent_object, uint64_t folderID, uint64_t messageID, bool read_write, struct emsmdbp_object **messageP, struct mapistore_message **msgp)
2241 struct emsmdbp_object *folder_object, *message_object = NULL;
2244 TALLOC_CTX *local_mem_ctx;
2245 enum mapistore_error ret = MAPISTORE_SUCCESS;
2247 if (!messageP) return MAPISTORE_ERROR;
2248 if (!parent_object) return MAPISTORE_ERROR;
2250 local_mem_ctx = talloc_zero(NULL, TALLOC_CTX);
2251 ret = emsmdbp_object_open_folder_by_fid(local_mem_ctx, emsmdbp_ctx, parent_object, folderID, &folder_object);
2252 if (ret != MAPISTORE_SUCCESS) {
2256 mapistore = emsmdbp_is_mapistore(folder_object);
2257 switch (mapistore) {
2259 /* system/special folder */
2260 message_object = emsmdbp_object_message_init(mem_ctx, emsmdbp_ctx, messageID, folder_object);
2261 ret = openchangedb_message_open(mem_ctx, emsmdbp_ctx->oc_ctx, messageID, folderID, &message_object->backend_object, (void **)msgp);
2262 if (ret != MAPISTORE_SUCCESS) {
2263 printf("Invalid openchangedb message\n");
2264 talloc_free(message_object);
2268 emsmdbp_object_message_fill_freebusy_properties(message_object);
2271 /* mapistore implementation goes here */
2272 message_object = emsmdbp_object_message_init(mem_ctx, emsmdbp_ctx, messageID, folder_object);
2273 contextID = emsmdbp_get_contextID(folder_object);
2274 ret = mapistore_folder_open_message(emsmdbp_ctx->mstore_ctx, contextID, folder_object->backend_object, message_object, messageID, read_write, &message_object->backend_object);
2275 if (ret == MAPISTORE_SUCCESS && msgp) {
2276 if (mapistore_message_get_message_data(emsmdbp_ctx->mstore_ctx, contextID, message_object->backend_object, mem_ctx, msgp) != MAPISTORE_SUCCESS) {
2277 ret = MAPISTORE_ERROR;
2280 if (ret != MAPISTORE_SUCCESS) {
2281 talloc_free(message_object);
2286 talloc_free(local_mem_ctx);
2288 if (ret == MAPISTORE_SUCCESS) {
2289 message_object->object.message->read_write = read_write;
2290 *messageP = message_object;
2296 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_message_open_attachment_table(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *message_object)
2298 struct emsmdbp_object *table_object;
2302 if (!emsmdbp_ctx) return NULL;
2303 if (!message_object || message_object->type != EMSMDBP_OBJECT_MESSAGE) return NULL;
2305 switch (emsmdbp_is_mapistore(message_object)) {
2307 /* system/special folder */
2308 DEBUG(0, ("[%s] not implemented yet - shouldn't occur\n", __location__));
2309 table_object = NULL;
2312 contextID = emsmdbp_get_contextID(message_object);
2314 table_object = emsmdbp_object_table_init(mem_ctx, emsmdbp_ctx, message_object);
2316 table_object->object.table->ulType = MAPISTORE_ATTACHMENT_TABLE;
2317 mapistore_message_get_attachment_table(emsmdbp_ctx->mstore_ctx, contextID,
2318 message_object->backend_object,
2319 table_object, &table_object->backend_object,
2320 &table_object->object.table->denominator);
2324 return table_object;
2328 \details Initialize a stream object
2330 \param mem_ctx pointer to the memory context
2331 \param emsmdbp_ctx pointer to the emsmdb provider cotnext
2332 \param property the stream property identifier
2333 \param parent emsmdbp object of the parent
2335 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_stream_init(TALLOC_CTX *mem_ctx,
2336 struct emsmdbp_context *emsmdbp_ctx,
2337 struct emsmdbp_object *parent)
2339 struct emsmdbp_object *object;
2342 if (!emsmdbp_ctx) return NULL;
2343 if (!parent) return NULL;
2345 object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
2346 if (!object) return NULL;
2348 object->object.stream = talloc_zero(object, struct emsmdbp_object_stream);
2349 if (!object->object.stream) {
2350 talloc_free(object);
2354 object->type = EMSMDBP_OBJECT_STREAM;
2355 object->object.stream->property = 0;
2356 object->object.stream->needs_commit = false;
2357 object->object.stream->stream.buffer.data = NULL;
2358 object->object.stream->stream.buffer.length = 0;
2359 object->object.stream->stream.position = 0;
2366 \details Initialize a attachment object
2368 \param mem_ctx pointer to the memory context
2369 \param emsmdbp_ctx pointer to the emsmdb provider cotnext
2370 \param folderID the folder identifier
2371 \param messageID the message identifier
2372 \param parent emsmdbp object of the parent
2374 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_attachment_init(TALLOC_CTX *mem_ctx,
2375 struct emsmdbp_context *emsmdbp_ctx,
2377 struct emsmdbp_object *parent)
2379 struct emsmdbp_object *object;
2382 if (!emsmdbp_ctx) return NULL;
2383 if (!parent) return NULL;
2385 object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
2386 if (!object) return NULL;
2388 object->object.attachment = talloc_zero(object, struct emsmdbp_object_attachment);
2389 if (!object->object.attachment) {
2390 talloc_free(object);
2394 object->type = EMSMDBP_OBJECT_ATTACHMENT;
2395 object->object.attachment->attachmentID = -1;
2401 \details Initialize a notification subscription object
2403 \param mem_ctx pointer to the memory context
2404 \param emsmdbp_ctx pointer to the emsmdb provider cotnext
2405 \param whole_store whether the subscription applies to the specified change on the entire store or stricly on the specified folder/message
2406 \param folderID the folder identifier
2407 \param messageID the message identifier
2408 \param parent emsmdbp object of the parent
2410 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_subscription_init(TALLOC_CTX *mem_ctx,
2411 struct emsmdbp_context *emsmdbp_ctx,
2412 struct emsmdbp_object *parent)
2414 struct emsmdbp_object *object;
2417 if (!emsmdbp_ctx) return NULL;
2418 if (!parent) return NULL;
2420 object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
2421 if (!object) return NULL;
2423 object->object.subscription = talloc_zero(object, struct emsmdbp_object_subscription);
2424 if (!object->object.subscription) {
2425 talloc_free(object);
2429 object->type = EMSMDBP_OBJECT_SUBSCRIPTION;
2430 object->object.subscription->subscription_list = NULL;
2435 _PUBLIC_ int emsmdbp_object_get_available_properties(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *object, struct SPropTagArray **propertiesp)
2439 if (!(object->type == EMSMDBP_OBJECT_FOLDER
2440 || object->type == EMSMDBP_OBJECT_MAILBOX
2441 || object->type == EMSMDBP_OBJECT_MESSAGE
2442 || object->type == EMSMDBP_OBJECT_ATTACHMENT)) {
2443 DEBUG(0, (__location__": object must be EMSMDBP_OBJECT_FOLDER, EMSMDBP_OBJECT_MAILBOX, EMSMDBP_OBJECT_MESSAGE or EMSMDBP_OBJECT_ATTACHMENT (type = %d)\n", object->type));
2444 return MAPISTORE_ERROR;
2447 if (!emsmdbp_is_mapistore(object)) {
2448 DEBUG(5, (__location__": only mapistore is supported at this time\n"));
2449 return MAPISTORE_ERROR;
2452 contextID = emsmdbp_get_contextID(object);
2454 return mapistore_properties_get_available_properties(emsmdbp_ctx->mstore_ctx, contextID, object->backend_object, mem_ctx, propertiesp);
2457 static int emsmdbp_object_get_properties_systemspecialfolder(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *object, struct SPropTagArray *properties, void **data_pointers, enum MAPISTATUS *retvals)
2459 enum MAPISTATUS retval = MAPI_E_SUCCESS;
2460 struct emsmdbp_object_folder *folder;
2463 uint32_t *obj_count;
2464 uint8_t *has_subobj;
2465 struct Binary_r *binr;
2468 struct FILETIME *ft;
2470 folder = (struct emsmdbp_object_folder *) object->object.folder;
2471 for (i = 0; i < properties->cValues; i++) {
2472 if (properties->aulPropTag[i] == PR_FOLDER_CHILD_COUNT) {
2473 obj_count = talloc_zero(data_pointers, uint32_t);
2474 retval = openchangedb_get_folder_count(emsmdbp_ctx->oc_ctx, object->object.folder->folderID, obj_count);
2475 data_pointers[i] = obj_count;
2477 else if (properties->aulPropTag[i] == PR_SUBFOLDERS) {
2478 obj_count = talloc_zero(NULL, uint32_t);
2479 retval = openchangedb_get_folder_count(emsmdbp_ctx->oc_ctx, object->object.folder->folderID, obj_count);
2480 has_subobj = talloc_zero(data_pointers, uint8_t);
2481 *has_subobj = (*obj_count > 0) ? 1 : 0;
2482 data_pointers[i] = has_subobj;
2483 talloc_free(obj_count);
2485 else if (properties->aulPropTag[i] == PR_SOURCE_KEY) {
2486 owner = emsmdbp_get_owner(object);
2487 emsmdbp_source_key_from_fmid(data_pointers, emsmdbp_ctx, owner, object->object.folder->folderID, &binr);
2488 data_pointers[i] = binr;
2489 retval = MAPI_E_SUCCESS;
2491 else if (properties->aulPropTag[i] == PR_CONTENT_COUNT
2492 || properties->aulPropTag[i] == PidTagAssociatedContentCount
2493 || properties->aulPropTag[i] == PR_CONTENT_UNREAD
2494 || properties->aulPropTag[i] == PR_DELETED_COUNT_TOTAL) {
2495 obj_count = talloc_zero(data_pointers, uint32_t);
2497 data_pointers[i] = obj_count;
2498 retval = MAPI_E_SUCCESS;
2500 else if (properties->aulPropTag[i] == PidTagLocalCommitTimeMax) {
2501 /* TODO: temporary hack */
2502 unix_time = time(NULL) & 0xffffff00;
2503 unix_to_nt_time(&nt_time, unix_time);
2504 ft = talloc_zero(data_pointers, struct FILETIME);
2505 ft->dwLowDateTime = (nt_time & 0xffffffff);
2506 ft->dwHighDateTime = nt_time >> 32;
2507 data_pointers[i] = ft;
2508 retval = MAPI_E_SUCCESS;
2511 retval = openchangedb_get_folder_property(data_pointers, emsmdbp_ctx->oc_ctx, properties->aulPropTag[i], folder->folderID, data_pointers + i);
2513 retvals[i] = retval;
2516 return MAPISTORE_SUCCESS;
2519 static int emsmdbp_object_get_properties_message(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx,
2520 struct emsmdbp_object *object, struct SPropTagArray *properties,
2521 void **data_pointers, enum MAPISTATUS *retvals)
2523 enum MAPISTATUS retval;
2526 struct Binary_r *binr;
2527 struct emsmdbp_object_message_freebusy_properties *fb_props;
2528 struct LongArray_r *long_array;
2529 struct BinaryArray_r *bin_array;
2531 fb_props = object->object.message->fb_properties;
2533 /* Look over properties */
2534 for (i = 0; i < properties->cValues; i++) {
2535 if (properties->aulPropTag[i] == PR_SOURCE_KEY) {
2536 owner = emsmdbp_get_owner(object);
2537 emsmdbp_source_key_from_fmid(data_pointers, emsmdbp_ctx, owner, object->object.message->folderID,
2539 data_pointers[i] = binr;
2540 retval = MAPI_E_SUCCESS;
2543 switch (properties->aulPropTag[i]) {
2544 case PR_SCHDINFO_MONTHS_TENTATIVE:
2545 case PR_SCHDINFO_MONTHS_BUSY:
2546 case PR_SCHDINFO_MONTHS_OOF:
2547 case PR_SCHDINFO_MONTHS_MERGED:
2548 long_array = talloc_zero(data_pointers, struct LongArray_r);
2549 long_array->cValues = fb_props->nbr_months;
2550 long_array->lpl = fb_props->months_ranges;
2551 data_pointers[i] = long_array;
2552 retval = MAPI_E_SUCCESS;
2554 case PR_SCHDINFO_FREEBUSY_TENTATIVE:
2555 bin_array = talloc_zero(data_pointers, struct BinaryArray_r);
2556 bin_array->cValues = fb_props->nbr_months;
2557 bin_array->lpbin = fb_props->freebusy_tentative;
2558 data_pointers[i] = bin_array;
2559 retval = MAPI_E_SUCCESS;
2561 case PR_SCHDINFO_FREEBUSY_BUSY:
2562 bin_array = talloc_zero(data_pointers, struct BinaryArray_r);
2563 bin_array->cValues = fb_props->nbr_months;
2564 bin_array->lpbin = fb_props->freebusy_busy;
2565 data_pointers[i] = bin_array;
2566 retval = MAPI_E_SUCCESS;
2568 case PR_SCHDINFO_FREEBUSY_OOF:
2569 bin_array = talloc_zero(data_pointers, struct BinaryArray_r);
2570 bin_array->cValues = fb_props->nbr_months;
2571 bin_array->lpbin = fb_props->freebusy_away;
2572 data_pointers[i] = bin_array;
2573 retval = MAPI_E_SUCCESS;
2575 case PR_SCHDINFO_FREEBUSY_MERGED:
2576 bin_array = talloc_zero(data_pointers, struct BinaryArray_r);
2577 bin_array->cValues = fb_props->nbr_months;
2578 bin_array->lpbin = fb_props->freebusy_merged;
2579 data_pointers[i] = bin_array;
2580 retval = MAPI_E_SUCCESS;
2582 case PR_FREEBUSY_PUBLISH_START:
2583 data_pointers[i] = &fb_props->publish_start;
2584 retval = MAPI_E_SUCCESS;
2586 case PR_FREEBUSY_PUBLISH_END:
2587 data_pointers[i] = &fb_props->publish_end;
2588 retval = MAPI_E_SUCCESS;
2590 case PidTagFreeBusyMessageEmailAddress:
2591 data_pointers[i] = fb_props->email_address;
2592 retval = MAPI_E_SUCCESS;
2594 case PR_FREEBUSY_RANGE_TIMESTAMP:
2595 data_pointers[i] = &fb_props->timestamp;
2596 retval = MAPI_E_SUCCESS;
2599 retval = openchangedb_message_get_property(data_pointers, object->backend_object, properties->aulPropTag[i], data_pointers + i);
2603 retval = openchangedb_message_get_property(data_pointers, object->backend_object, properties->aulPropTag[i], data_pointers + i);
2606 retvals[i] = retval;
2609 return MAPI_E_SUCCESS;
2612 static int emsmdbp_object_get_properties_mapistore_root(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *object, struct SPropTagArray *properties, void **data_pointers, enum MAPISTATUS *retvals)
2614 enum MAPISTATUS retval = MAPI_E_SUCCESS;
2615 struct emsmdbp_object_folder *folder;
2617 struct Binary_r *binr;
2620 uint32_t *obj_count;
2621 uint8_t *has_subobj;
2622 /* time_t unix_time; */
2623 /* NTTIME nt_time; */
2624 /* struct FILETIME *ft; */
2626 contextID = emsmdbp_get_contextID(object);
2628 folder = (struct emsmdbp_object_folder *) object->object.folder;
2629 for (i = 0; i < properties->cValues; i++) {
2630 if (properties->aulPropTag[i] == PR_CONTENT_COUNT) {
2631 /* a hack to avoid fetching dynamic fields from openchange.ldb */
2632 obj_count = talloc_zero(data_pointers, uint32_t);
2633 retval = mapistore_folder_get_child_count(emsmdbp_ctx->mstore_ctx, contextID, object->backend_object, MAPISTORE_MESSAGE_TABLE, obj_count);
2635 data_pointers[i] = obj_count;
2638 else if (properties->aulPropTag[i] == PR_SOURCE_KEY) {
2639 owner = emsmdbp_get_owner(object);
2640 emsmdbp_source_key_from_fmid(data_pointers, emsmdbp_ctx, owner, object->object.folder->folderID, &binr);
2641 data_pointers[i] = binr;
2642 retval = MAPI_E_SUCCESS;
2644 else if (properties->aulPropTag[i] == PR_FOLDER_TYPE) {
2645 obj_count = talloc_zero(data_pointers, uint32_t);
2646 *obj_count = FOLDER_GENERIC;
2647 data_pointers[i] = obj_count;
2648 retval = MAPI_E_SUCCESS;
2650 else if (properties->aulPropTag[i] == PidTagAssociatedContentCount) {
2651 obj_count = talloc_zero(data_pointers, uint32_t);
2652 retval = mapistore_folder_get_child_count(emsmdbp_ctx->mstore_ctx, emsmdbp_get_contextID(object), object->backend_object,
2653 MAPISTORE_FAI_TABLE, obj_count);
2655 data_pointers[i] = obj_count;
2658 else if (properties->aulPropTag[i] == PR_FOLDER_CHILD_COUNT) {
2659 obj_count = talloc_zero(data_pointers, uint32_t);
2660 retval = emsmdbp_folder_get_folder_count(emsmdbp_ctx, object, obj_count);
2662 data_pointers[i] = obj_count;
2665 else if (properties->aulPropTag[i] == PR_SUBFOLDERS) {
2666 obj_count = talloc_zero(NULL, uint32_t);
2667 retval = emsmdbp_folder_get_folder_count(emsmdbp_ctx, object, obj_count);
2669 has_subobj = talloc_zero(data_pointers, uint8_t);
2670 *has_subobj = (*obj_count > 0) ? 1 : 0;
2671 data_pointers[i] = has_subobj;
2673 talloc_free(obj_count);
2675 else if (properties->aulPropTag[i] == PR_CONTENT_UNREAD || properties->aulPropTag[i] == PR_DELETED_COUNT_TOTAL) {
2676 /* TODO: temporary hack */
2677 obj_count = talloc_zero(data_pointers, uint32_t);
2679 data_pointers[i] = obj_count;
2680 retval = MAPI_E_SUCCESS;
2682 else if (properties->aulPropTag[i] == PidTagLocalCommitTimeMax || properties->aulPropTag[i] == PR_ACCESS || properties->aulPropTag[i] == PR_ACCESS_LEVEL) {
2683 struct mapistore_property_data prop_data;
2685 mapistore_properties_get_properties(emsmdbp_ctx->mstore_ctx, contextID,
2686 object->backend_object,
2689 properties->aulPropTag + i,
2691 data_pointers[i] = prop_data.data;
2692 retval = prop_data.error;
2695 retval = openchangedb_get_folder_property(data_pointers, emsmdbp_ctx->oc_ctx, properties->aulPropTag[i], folder->folderID, data_pointers + i);
2697 retvals[i] = retval;
2700 return MAPISTORE_SUCCESS;
2703 static int emsmdbp_object_get_properties_mailbox(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *object, struct SPropTagArray *properties, void **data_pointers, enum MAPISTATUS *retvals)
2706 struct SBinary_short *bin;
2708 for (i = 0; i < properties->cValues; i++) {
2709 switch (properties->aulPropTag[i]) {
2710 case PR_MAPPING_SIGNATURE:
2711 case PidTagIpmPublicFoldersEntryId:
2712 retvals[i] = MAPI_E_NO_ACCESS;
2714 case PR_USER_ENTRYID:
2715 bin = talloc_zero(data_pointers, struct SBinary_short);
2716 retvals[i] = entryid_set_AB_EntryID(data_pointers, object->object.mailbox->szUserDN, bin);
2717 data_pointers[i] = bin;
2719 case PR_MAILBOX_OWNER_ENTRYID:
2720 if (object->object.mailbox->mailboxstore == false) {
2721 retvals[i] = MAPI_E_NO_ACCESS;
2723 bin = talloc_zero(data_pointers, struct SBinary_short);
2724 retvals[i] = entryid_set_AB_EntryID(data_pointers, object->object.mailbox->owner_EssDN,
2726 data_pointers[i] = bin;
2729 case PidTagMailboxOwnerName:
2730 if (object->object.mailbox->mailboxstore == false) {
2731 retvals[i] = MAPI_E_NO_ACCESS;
2733 retvals[i] = MAPI_E_SUCCESS;
2734 data_pointers[i] = talloc_strdup(data_pointers, object->object.mailbox->owner_Name);
2738 retvals[i] = openchangedb_get_folder_property(data_pointers, emsmdbp_ctx->oc_ctx, properties->aulPropTag[i], object->object.mailbox->folderID, data_pointers + i);
2742 return MAPISTORE_SUCCESS;
2745 static int emsmdbp_object_get_properties_mapistore(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *object, struct SPropTagArray *properties, void **data_pointers, enum MAPISTATUS *retvals)
2747 uint32_t contextID = -1;
2748 struct mapistore_property_data *prop_data;
2751 contextID = emsmdbp_get_contextID(object);
2752 prop_data = talloc_array(NULL, struct mapistore_property_data, properties->cValues);
2753 memset(prop_data, 0, sizeof(struct mapistore_property_data) * properties->cValues);
2755 ret = mapistore_properties_get_properties(emsmdbp_ctx->mstore_ctx, contextID,
2756 object->backend_object,
2758 properties->cValues,
2759 properties->aulPropTag,
2761 if (ret == MAPISTORE_SUCCESS) {
2762 for (i = 0; i < properties->cValues; i++) {
2763 if (prop_data[i].error) {
2764 if (prop_data[i].error == MAPISTORE_ERR_NOT_FOUND) {
2765 retvals[i] = MAPI_E_NOT_FOUND;
2768 retvals[i] = MAPI_E_NO_SUPPORT;
2769 DEBUG (4, ("%s: unknown mapistore error: %.8x\n", __PRETTY_FUNCTION__, prop_data[i].error));
2773 if (prop_data[i].data == NULL) {
2774 retvals[i] = MAPI_E_NOT_FOUND;
2777 data_pointers[i] = prop_data[i].data;
2778 (void) talloc_reference(data_pointers, prop_data[i].data);
2783 talloc_free(prop_data);
2788 _PUBLIC_ void **emsmdbp_object_get_properties(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *object, struct SPropTagArray *properties, enum MAPISTATUS **retvalsp)
2790 void **data_pointers;
2791 enum MAPISTATUS *retvals;
2795 data_pointers = talloc_array(mem_ctx, void *, properties->cValues);
2796 memset(data_pointers, 0, sizeof(void *) * properties->cValues);
2798 retvals = talloc_array(mem_ctx, enum MAPISTATUS, properties->cValues);
2799 memset(retvals, 0, sizeof(enum MAPISTATUS) * properties->cValues);
2801 /* Temporary hack: If this is a mapistore root container
2802 * (e.g. Inbox, Calendar etc.), directly stored under
2803 * IPM.Subtree, then fetch properties from openchange
2804 * dispatcher db, not mapistore */
2805 if (object && object->type == EMSMDBP_OBJECT_FOLDER &&
2806 object->object.folder->mapistore_root == true) {
2807 if (object->object.folder->postponed_props) {
2808 emsmdbp_object_folder_commit_creation(emsmdbp_ctx, object, true);
2811 retval = emsmdbp_object_get_properties_mapistore_root(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
2813 mapistore = emsmdbp_is_mapistore(object);
2816 DEBUG(5, ("[%s] what's that hack!??\n", __location__));
2820 switch (mapistore) {
2822 switch (object->type) {
2823 case EMSMDBP_OBJECT_MAILBOX:
2824 retval = emsmdbp_object_get_properties_mailbox(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
2826 case EMSMDBP_OBJECT_FOLDER:
2827 retval = emsmdbp_object_get_properties_systemspecialfolder(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
2829 case EMSMDBP_OBJECT_MESSAGE:
2830 retval = emsmdbp_object_get_properties_message(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
2833 retval = MAPISTORE_ERROR;
2838 /* folder or messages handled by mapistore */
2839 retval = emsmdbp_object_get_properties_mapistore(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
2845 *retvalsp = retvals;
2849 talloc_free(data_pointers);
2850 data_pointers = NULL;
2853 return data_pointers;
2856 /* TODO: handling of "property problems" */
2857 _PUBLIC_ int emsmdbp_object_set_properties(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *object, struct SRow *rowp)
2859 uint32_t contextID, new_cvalues;
2861 enum mapistore_error ret;
2862 struct SRow *postponed_props;
2865 if (!emsmdbp_ctx) return MAPI_E_CALL_FAILED;
2866 if (!object) return MAPI_E_CALL_FAILED;
2867 if (!rowp) return MAPI_E_CALL_FAILED;
2868 if (!(object->type == EMSMDBP_OBJECT_FOLDER
2869 || object->type == EMSMDBP_OBJECT_MAILBOX
2870 || object->type == EMSMDBP_OBJECT_MESSAGE
2871 || object->type == EMSMDBP_OBJECT_ATTACHMENT)) {
2872 DEBUG(0, (__location__": object must be EMSMDBP_OBJECT_FOLDER, EMSMDBP_OBJECT_MAILBOX, EMSMDBP_OBJECT_MESSAGE or EMSMDBP_OBJECT_ATTACHMENT (type = %d)\n", object->type));
2873 return MAPI_E_NO_SUPPORT;
2876 if (object->type == EMSMDBP_OBJECT_FOLDER) {
2877 postponed_props = object->object.folder->postponed_props;
2878 if (postponed_props) {
2879 new_cvalues = postponed_props->cValues + rowp->cValues;
2880 postponed_props->lpProps = talloc_realloc(postponed_props, postponed_props->lpProps, struct SPropValue, new_cvalues);
2881 mapi_copy_spropvalues(postponed_props, rowp->lpProps, postponed_props->lpProps + postponed_props->cValues, rowp->cValues);
2882 postponed_props->cValues = new_cvalues;
2884 ret = emsmdbp_object_folder_commit_creation(emsmdbp_ctx, object, false);
2885 if (ret == MAPISTORE_SUCCESS) {
2886 return MAPI_E_SUCCESS;
2889 return MAPI_E_NOT_FOUND;
2894 /* Temporary hack: If this is a mapistore root container
2895 * (e.g. Inbox, Calendar etc.), directly stored under
2896 * IPM.Subtree, then set properties from openchange
2897 * dispatcher db, not mapistore */
2898 if (object->type == EMSMDBP_OBJECT_FOLDER
2899 && object->object.folder->mapistore_root == true) {
2900 openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, object->object.folder->folderID, rowp);
2901 contextID = emsmdbp_get_contextID(object);
2902 mapistore_properties_set_properties(emsmdbp_ctx->mstore_ctx, contextID, object->backend_object, rowp);
2905 contextID = emsmdbp_get_contextID(object);
2906 mapistore = emsmdbp_is_mapistore(object);
2907 switch (mapistore) {
2909 if (object->type == EMSMDBP_OBJECT_FOLDER) {
2910 openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, object->object.folder->folderID, rowp);
2912 else if (object->type == EMSMDBP_OBJECT_MAILBOX) {
2913 openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, object->object.mailbox->folderID, rowp);
2915 else if (object->type == EMSMDBP_OBJECT_MESSAGE) {
2916 openchangedb_message_set_properties((TALLOC_CTX *)object->object.message,
2917 object->backend_object, rowp);
2920 DEBUG(0, ("Setting properties on openchangedb not implemented yet for non-folder object type\n"));
2921 return MAPI_E_NO_SUPPORT;
2925 mapistore_properties_set_properties(emsmdbp_ctx->mstore_ctx, contextID, object->backend_object, rowp);
2930 return MAPI_E_SUCCESS;
2933 _PUBLIC_ void emsmdbp_fill_row_blob(TALLOC_CTX *mem_ctx,
2934 struct emsmdbp_context *emsmdbp_ctx,
2936 DATA_BLOB *property_row,
2937 struct SPropTagArray *properties,
2938 void **data_pointers,
2939 enum MAPISTATUS *retvals,
2940 bool *untyped_status)
2944 enum MAPITAGS property;
2949 for (i = 0; !flagged && i < properties->cValues; i++) {
2950 if (retvals[i] != MAPI_E_SUCCESS || untyped_status[i] || !data_pointers[i]) {
2956 for (i = 0; i < properties->cValues; i++) {
2957 retval = retvals[i];
2958 if (retval != MAPI_E_SUCCESS) {
2959 property = (properties->aulPropTag[i] & 0xFFFF0000) + PT_ERROR;
2963 property = properties->aulPropTag[i];
2964 data = data_pointers[i];
2966 libmapiserver_push_property(mem_ctx,
2967 property, data, property_row,
2968 flagged ? PT_ERROR : 0, flagged, untyped_status[i]);
2972 _PUBLIC_ struct emsmdbp_stream_data *emsmdbp_stream_data_from_value(TALLOC_CTX *mem_ctx, enum MAPITAGS prop_tag, void *value)
2975 struct emsmdbp_stream_data *stream_data;
2976 size_t converted_size;
2978 stream_data = talloc_zero(mem_ctx, struct emsmdbp_stream_data);
2979 stream_data->prop_tag = prop_tag;
2980 prop_type = prop_tag & 0xffff;
2981 if (prop_type == PT_STRING8) {
2982 stream_data->data.length = strlen(value) + 1;
2983 stream_data->data.data = value;
2984 (void) talloc_reference(stream_data, stream_data->data.data);
2986 else if (prop_type == PT_UNICODE) {
2987 stream_data->data.length = strlen_m_ext((char *) value, CH_UTF8, CH_UTF16LE) * 2;
2988 stream_data->data.data = talloc_array(stream_data, uint8_t, stream_data->data.length + 2);
2989 convert_string(CH_UTF8, CH_UTF16LE,
2990 value, strlen(value),
2991 stream_data->data.data, stream_data->data.length,
2993 memset(stream_data->data.data + stream_data->data.length, 0, 2 * sizeof(uint8_t));
2995 else if (prop_type == PT_BINARY) {
2996 stream_data->data.length = ((struct Binary_r *) value)->cb;
2997 stream_data->data.data = ((struct Binary_r *) value)->lpb;
2998 (void) talloc_reference(stream_data, stream_data->data.data);
3001 talloc_free(stream_data);
3008 _PUBLIC_ DATA_BLOB emsmdbp_stream_read_buffer(struct emsmdbp_stream *stream, uint32_t length)
3011 uint32_t real_length;
3013 real_length = length;
3014 if (real_length + stream->position > stream->buffer.length) {
3015 real_length = stream->buffer.length - stream->position;
3017 buffer.length = real_length;
3018 buffer.data = stream->buffer.data + stream->position;
3019 stream->position += real_length;
3024 _PUBLIC_ void emsmdbp_stream_write_buffer(TALLOC_CTX *mem_ctx, struct emsmdbp_stream *stream, DATA_BLOB new_buffer)
3026 uint32_t new_position, old_length;
3029 new_position = stream->position + new_buffer.length;
3030 if (new_position >= stream->buffer.length) {
3031 old_length = stream->buffer.length;
3032 stream->buffer.length = new_position;
3033 if (stream->buffer.data) {
3034 old_data = stream->buffer.data;
3035 stream->buffer.data = talloc_realloc(mem_ctx, stream->buffer.data, uint8_t, stream->buffer.length);
3036 if (!stream->buffer.data) {
3037 DEBUG(5, ("WARNING: [bug] lost buffer pointer (data = NULL)\n"));
3038 stream->buffer.data = talloc_array(mem_ctx, uint8_t, stream->buffer.length);
3039 memcpy(stream->buffer.data, old_data, old_length);
3043 stream->buffer.data = talloc_array(mem_ctx, uint8_t, stream->buffer.length);
3047 memcpy(stream->buffer.data + stream->position, new_buffer.data, new_buffer.length);
3048 stream->position = new_position;
3051 _PUBLIC_ struct emsmdbp_stream_data *emsmdbp_object_get_stream_data(struct emsmdbp_object *object, enum MAPITAGS prop_tag)
3053 struct emsmdbp_stream_data *current_data;
3055 for (current_data = object->stream_data; current_data; current_data = current_data->next) {
3056 if (current_data->prop_tag == prop_tag) {
3057 DEBUG(5, ("[%s]: found data for tag %.8x\n", __FUNCTION__, prop_tag));
3058 return current_data;
3066 \details Initialize a synccontext object
3068 \param mem_ctx pointer to the memory context
3069 \param emsmdbp_ctx pointer to the emsmdb provider cotnext
3070 \param whole_store whether the subscription applies to the specified change on the entire store or stricly on the specified folder/message
3071 \param folderID the folder identifier
3072 \param messageID the message identifier
3073 \param parent emsmdbp object of the parent
3075 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_synccontext_init(TALLOC_CTX *mem_ctx,
3076 struct emsmdbp_context *emsmdbp_ctx,
3077 struct emsmdbp_object *parent_object)
3079 struct emsmdbp_object *synccontext_object;
3082 if (!emsmdbp_ctx) return NULL;
3083 if (!parent_object) return NULL;
3084 if (!(parent_object->type == EMSMDBP_OBJECT_FOLDER || parent_object->type == EMSMDBP_OBJECT_MAILBOX)) {
3085 DEBUG(0, (__location__": parent_object must be EMSMDBP_OBJECT_FOLDER or EMSMDBP_OBJECT_MAILBOX (type = %d)\n", parent_object->type));
3089 synccontext_object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent_object);
3090 if (!synccontext_object) return NULL;
3092 synccontext_object->object.synccontext = talloc_zero(synccontext_object, struct emsmdbp_object_synccontext);
3093 if (!synccontext_object->object.synccontext) {
3094 talloc_free(synccontext_object);
3098 synccontext_object->type = EMSMDBP_OBJECT_SYNCCONTEXT;
3100 (void) talloc_reference(synccontext_object->object.synccontext, parent_object);
3101 synccontext_object->object.synccontext->state_property = 0;
3102 synccontext_object->object.synccontext->state_stream.buffer.length = 0;
3103 synccontext_object->object.synccontext->state_stream.buffer.data = talloc_zero(synccontext_object->object.synccontext, uint8_t);
3104 synccontext_object->object.synccontext->stream.buffer.length = 0;
3105 synccontext_object->object.synccontext->stream.buffer.data = NULL;
3107 synccontext_object->object.synccontext->cnset_seen = talloc_zero(emsmdbp_ctx, struct idset);
3108 openchangedb_get_MailboxReplica(emsmdbp_ctx->oc_ctx, emsmdbp_ctx->username, NULL, &synccontext_object->object.synccontext->cnset_seen->repl.guid);
3109 synccontext_object->object.synccontext->cnset_seen->ranges = talloc_zero(synccontext_object->object.synccontext->cnset_seen, struct globset_range);
3110 synccontext_object->object.synccontext->cnset_seen->range_count = 1;
3111 synccontext_object->object.synccontext->cnset_seen->ranges->next = NULL;
3112 synccontext_object->object.synccontext->cnset_seen->ranges->prev = synccontext_object->object.synccontext->cnset_seen->ranges;
3113 synccontext_object->object.synccontext->cnset_seen->ranges->low = 0xffffffffffffffffLL;
3114 synccontext_object->object.synccontext->cnset_seen->ranges->high = 0x0;
3116 /* synccontext_object->object.synccontext->property_tags.cValues = 0; */
3117 /* synccontext_object->object.synccontext->property_tags.aulPropTag = NULL; */
3119 return synccontext_object;
3123 \details Initialize a ftcontext object
3125 \param mem_ctx pointer to the memory context
3126 \param emsmdbp_ctx pointer to the emsmdb provider cotnext
3127 \param whole_store whether the subscription applies to the specified change on the entire store or stricly on the specified folder/message
3128 \param folderID the folder identifier
3129 \param messageID the message identifier
3130 \param parent emsmdbp object of the parent
3132 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_ftcontext_init(TALLOC_CTX *mem_ctx,
3133 struct emsmdbp_context *emsmdbp_ctx,
3134 struct emsmdbp_object *parent)
3136 struct emsmdbp_object *object;
3139 if (!emsmdbp_ctx) return NULL;
3140 if (!parent) return NULL;
3142 object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
3143 if (!object) return NULL;
3145 object->object.ftcontext = talloc_zero(object, struct emsmdbp_object_ftcontext);
3146 if (!object->object.ftcontext) {
3147 talloc_free(object);
3151 object->type = EMSMDBP_OBJECT_FTCONTEXT;