45
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:
54
71
\details Convenient function to determine whether specified
55
mapi_handles refers to object using mapistore or not
72
object is using mapistore or not
57
\param handles pointer to the MAPI handle to lookup
74
\param object pointer to the emsmdp object
59
76
\return true if parent is using mapistore, otherwise false
61
bool emsmdbp_is_mapistore(struct mapi_handles *handles)
78
bool emsmdbp_is_mapistore(struct emsmdbp_object *object)
64
struct emsmdbp_object *object;
66
80
/* Sanity checks - probably pointless */
71
mapi_handles_get_private_data(handles, &data);
72
object = (struct emsmdbp_object *)data;
74
85
switch (object->type) {
75
86
case EMSMDBP_OBJECT_MAILBOX:
77
88
case EMSMDBP_OBJECT_FOLDER:
78
return object->object.folder->mapistore;
79
case EMSMDBP_OBJECT_TABLE:
80
return object->object.table->mapistore;
81
case EMSMDBP_OBJECT_MESSAGE:
82
return object->object.message->mapistore;
83
case EMSMDBP_OBJECT_STREAM:
84
return object->object.stream->mapistore;
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);
94
111
\details Convenient function to determine whether specified
95
112
mapi_handles refers to object within mailbox or public folders
98
\param handles pointer to the MAPI handle to lookup
100
\return true if parent is within mailbox store, otherwise false
102
bool emsmdbp_is_mailboxstore(struct mapi_handles *handles)
105
struct emsmdbp_object *object;
107
/* Sanity checks - irrelevant */
109
mapi_handles_get_private_data(handles, &data);
110
object = (struct emsmdbp_object *)data;
112
switch (object->type) {
113
case EMSMDBP_OBJECT_MAILBOX:
114
return object->object.mailbox->mailboxstore;
115
case EMSMDBP_OBJECT_FOLDER:
116
return object->object.folder->mailboxstore;
121
/* We should never hit this case */
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;
127
144
\details Return the contextID associated to a handle
129
\param handles pointer to the MAPI handle to lookup
146
\param object pointer to the emsmdp object
131
148
\return contextID value on success, otherwise -1
133
uint32_t emsmdbp_get_contextID(struct mapi_handles *handles)
150
_PUBLIC_ uint32_t emsmdbp_get_contextID(struct emsmdbp_object *object)
136
struct emsmdbp_object *object;
138
mapi_handles_get_private_data(handles, &data);
139
object = (struct emsmdbp_object *) data;
141
152
switch (object->type) {
142
153
case EMSMDBP_OBJECT_MAILBOX:
144
155
case EMSMDBP_OBJECT_FOLDER:
145
return object->object.folder->contextID;
146
case EMSMDBP_OBJECT_MESSAGE:
147
return object->object.message->contextID;
148
case EMSMDBP_OBJECT_STREAM:
149
return object->object.stream->contextID;
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);
159
\details Retrieve the folder handle matching given fid
161
\param handles_ctx pointer to the handles context
162
\param fid folder identifier to lookup
164
\return pointer to valid mapi_handles structure on success, otherwise NULL
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
166
struct mapi_handles *emsmdbp_object_get_folder_handle_by_fid(struct mapi_handles_context *handles_ctx,
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)
169
struct mapi_handles *handle;
170
struct emsmdbp_object *object;
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;
173
for (handle = handles_ctx->handles; handle; handle = handle->next) {
174
mapi_handles_get_private_data(handle, &data);
176
object = (struct emsmdbp_object *) data;
177
if (object->type == EMSMDBP_OBJECT_FOLDER && object->object.folder->folderID == fid) {
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);
237
727
talloc_set_destructor((void *)object, (int (*)(void *))emsmdbp_object_destructor);
239
729
object->type = EMSMDBP_OBJECT_UNDEF;
240
object->mstore_ctx = emsmdbp_ctx->mstore_ctx;
730
object->emsmdbp_ctx = emsmdbp_ctx;
241
731
object->object.mailbox = NULL;
242
732
object->object.folder = NULL;
243
733
object->object.message = NULL;
244
734
object->object.stream = NULL;
245
object->private_data = 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"));
252
1037
\details Initialize a mailbox object
360
1142
object->type = EMSMDBP_OBJECT_FOLDER;
361
object->object.folder->contextID = -1;
362
1143
object->object.folder->folderID = folderID;
363
1144
object->object.folder->mapistore_root = false;
364
object->object.folder->mailboxstore = emsmdbp_is_mailboxstore(parent);
366
/* system folders acting as containers don't have
367
* mapistore_uri attributes (Mailbox, IPM Subtree)
369
retval = openchangedb_get_mapistoreURI(mem_ctx, emsmdbp_ctx->oc_ctx,
370
object->object.folder->folderID,
371
&mapistore_uri, object->object.folder->mailboxstore);
373
if (retval == MAPI_E_SUCCESS) {
374
if (!mapistore_uri) {
375
DEBUG(0, ("This is not a mapistore container\n"));
376
object->object.folder->mapistore = false;
378
DEBUG(0, ("This is a mapistore container: uri = %s\n", mapistore_uri));
379
object->object.folder->mapistore = true;
380
object->object.folder->mapistore_root = true;
381
ret = mapistore_search_context_by_uri(emsmdbp_ctx->mstore_ctx, mapistore_uri,
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);
383
1220
if (ret == MAPISTORE_SUCCESS) {
384
ret = mapistore_add_context_ref_count(emsmdbp_ctx->mstore_ctx, context_id);
1221
mapistore_add_context_ref_count(emsmdbp_ctx->mstore_ctx, context_id);
386
ret = mapistore_add_context(emsmdbp_ctx->mstore_ctx,
387
emsmdbp_ctx->login_user,
388
emsmdbp_ctx->username,
389
mapistore_uri, &context_id);
390
DEBUG(0, ("context id: %d (%s)\n", context_id, mapistore_uri));
1223
ret = mapistore_add_context(emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->username, mapistoreURL, fid, &context_id, &subfolder);
391
1224
if (ret != MAPISTORE_SUCCESS) {
395
ret = mapistore_add_context_indexing(emsmdbp_ctx->mstore_ctx,
396
emsmdbp_ctx->username,
398
ret = mapistore_indexing_record_add_fid(emsmdbp_ctx->mstore_ctx,
399
context_id, folderID);
401
object->object.folder->contextID = context_id;
404
if (emsmdbp_is_mapistore(parent)) {
405
object->object.folder->mapistore = true;
406
object->object.folder->contextID = emsmdbp_get_contextID(parent);
407
ret = mapistore_add_context_ref_count(emsmdbp_ctx->mstore_ctx,
408
object->object.folder->contextID);
410
object->object.folder->mapistore = false;
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;
419
1357
\details Initialize a table object
421
1359
\param mem_ctx pointer to the memory context
422
1360
\param emsmdbp_ctx pointer to the emsmdb provider context
423
\param parent pointer to the parent MAPI handle
1361
\param parent emsmdbp object of the parent
425
1363
\return Allocated emsmdbp object on success, otherwise NULL
427
1365
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_table_init(TALLOC_CTX *mem_ctx,
428
1366
struct emsmdbp_context *emsmdbp_ctx,
429
struct mapi_handles *parent)
1367
struct emsmdbp_object *parent)
431
enum MAPISTATUS retval;
432
1369
struct emsmdbp_object *object;
433
struct emsmdbp_object *folder;
435
bool mapistore = false;
438
1371
/* Sanity checks */
439
1372
if (!emsmdbp_ctx) return NULL;
441
/* Retrieve parent object */
442
retval = mapi_handles_get_private_data(parent, &data);
443
if (retval) return NULL;
444
folder = (struct emsmdbp_object *) data;
1373
if (!parent) return NULL;
1374
if (parent->type != EMSMDBP_OBJECT_FOLDER && parent->type != EMSMDBP_OBJECT_MAILBOX && parent->type != EMSMDBP_OBJECT_MESSAGE) return NULL;
446
1376
/* Initialize table object */
447
object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx);
1377
object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
448
1378
if (!object) return NULL;
450
1380
object->object.table = talloc_zero(object, struct emsmdbp_object_table);
456
1386
object->type = EMSMDBP_OBJECT_TABLE;
457
object->object.table->folderID = folder->object.folder->folderID;
458
1387
object->object.table->prop_count = 0;
459
1388
object->object.table->properties = NULL;
460
1389
object->object.table->numerator = 0;
461
1390
object->object.table->denominator = 0;
462
1391
object->object.table->ulType = 0;
463
object->object.table->mapistore = false;
464
object->object.table->contextID = -1;
466
mapistore = emsmdbp_is_mapistore(parent);
467
if (mapistore == true) {
468
object->object.table->mapistore = true;
469
object->object.table->contextID = folder->object.folder->contextID;
470
ret = mapistore_add_context_ref_count(emsmdbp_ctx->mstore_ctx,
471
folder->object.folder->contextID);
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_ACCESS_LEVEL);
1422
SPropTagArray_add(properties, properties, PidTagExtendedFolderFlags);
1423
SPropTagArray_add(properties, properties, PidTagDesignInProgress);
1424
SPropTagArray_add(properties, properties, PidTagSecureOrigination);
1425
SPropTagArray_add(properties, properties, PR_NTSD_MODIFICATION_TIME);
1426
SPropTagArray_add(properties, properties, PR_ADDITIONAL_REN_ENTRYIDS);
1427
SPropTagArray_add(properties, properties, PR_ADDITIONAL_REN_ENTRYIDS_EX);
1428
SPropTagArray_add(properties, properties, PR_CREATION_TIME);
1429
SPropTagArray_add(properties, properties, PR_CREATOR_SID);
1430
SPropTagArray_add(properties, properties, PR_CREATOR_ENTRYID);
1431
SPropTagArray_add(properties, properties, PR_LAST_MODIFICATION_TIME);
1432
SPropTagArray_add(properties, properties, PR_LAST_MODIFIER_SID);
1433
SPropTagArray_add(properties, properties, PR_LAST_MODIFIER_ENTRYID);
1434
SPropTagArray_add(properties, properties, PR_ATTR_HIDDEN);
1435
SPropTagArray_add(properties, properties, PR_ATTR_SYSTEM);
1436
SPropTagArray_add(properties, properties, PR_ATTR_READONLY);
1437
SPropTagArray_add(properties, properties, PR_EXTENDED_ACL_DATA);
1438
SPropTagArray_add(properties, properties, PR_CONTAINER_CLASS_UNICODE);
1439
SPropTagArray_add(properties, properties, PR_MESSAGE_CLASS_UNICODE);
1440
SPropTagArray_add(properties, properties, PR_RIGHTS);
1441
SPropTagArray_add(properties, properties, PR_CONTENT_COUNT);
1442
SPropTagArray_add(properties, properties, PidTagAssociatedContentCount);
1443
SPropTagArray_add(properties, properties, PR_SUBFOLDERS);
1444
SPropTagArray_add(properties, properties, PR_MAPPING_SIGNATURE);
1445
SPropTagArray_add(properties, properties, PR_USER_ENTRYID);
1446
SPropTagArray_add(properties, properties, PR_MAILBOX_OWNER_ENTRYID);
1447
SPropTagArray_add(properties, properties, PR_MAILBOX_OWNER_NAME_UNICODE);
1448
SPropTagArray_add(properties, properties, PR_IPM_APPOINTMENT_ENTRYID);
1449
SPropTagArray_add(properties, properties, PR_IPM_CONTACT_ENTRYID);
1450
SPropTagArray_add(properties, properties, PR_IPM_JOURNAL_ENTRYID);
1451
SPropTagArray_add(properties, properties, PR_IPM_NOTE_ENTRYID);
1452
SPropTagArray_add(properties, properties, PR_IPM_TASK_ENTRYID);
1453
SPropTagArray_add(properties, properties, PR_IPM_DRAFTS_ENTRYID);
1454
SPropTagArray_add(properties, properties, PR_REMINDERS_ONLINE_ENTRYID);
1455
SPropTagArray_add(properties, properties, PR_IPM_PUBLIC_FOLDERS_ENTRYID);
1456
SPropTagArray_add(properties, properties, PR_FOLDER_XVIEWINFO_E);
1457
SPropTagArray_add(properties, properties, PR_FOLDER_VIEWLIST);
1458
SPropTagArray_add(properties, properties, PR_FREEBUSY_ENTRYIDS);
1459
SPropTagArray_add(properties, properties, 0x36de0003); /* some unknown prop that outlook sets */
1460
*propertiesp = properties;
1462
retval = MAPISTORE_SUCCESS;
1468
_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)
1470
void **data_pointers;
1471
enum MAPISTATUS retval;
1472
enum mapistore_error ret;
1473
enum MAPISTATUS *retvals;
1474
struct emsmdbp_object_table *table;
1475
struct mapistore_property_data *properties;
1476
uint32_t contextID, i, num_props, *obj_count;
1477
struct emsmdbp_object *rowobject;
1479
uint64_t parentFolderId;
1480
bool mapistore_folder;
1481
uint8_t *has_subobj;
1484
struct Binary_r *binr;
1486
table = table_object->object.table;
1487
num_props = table_object->object.table->prop_count;
1489
data_pointers = talloc_array(mem_ctx, void *, num_props);
1490
memset(data_pointers, 0, sizeof(void *) * num_props);
1491
retvals = talloc_array(mem_ctx, enum MAPISTATUS, num_props);
1492
memset(retvals, 0, sizeof(uint32_t) * num_props);
1494
contextID = emsmdbp_get_contextID(table_object);
1495
if (emsmdbp_is_mapistore(table_object)) {
1496
retval = mapistore_table_get_row(emsmdbp_ctx->mstore_ctx, contextID,
1497
table_object->backend_object, data_pointers,
1498
query_type, row_id, &properties);
1499
if (retval == MAPI_E_SUCCESS) {
1500
for (i = 0; i < num_props; i++) {
1501
data_pointers[i] = properties[i].data;
1503
if (properties[i].error) {
1504
if (properties[i].error == MAPISTORE_ERR_NOT_FOUND)
1505
retvals[i] = MAPI_E_NOT_FOUND;
1506
else if (properties[i].error == MAPISTORE_ERR_NO_MEMORY)
1507
retvals[i] = MAPI_E_NOT_ENOUGH_MEMORY;
1509
retvals[i] = MAPI_E_NO_SUPPORT;
1510
DEBUG (4, ("%s: unknown mapistore error: %.8x\n", __PRETTY_FUNCTION__, properties[i].error));
1514
if (properties[i].data == NULL) {
1515
retvals[i] = MAPI_E_NOT_FOUND;
1521
DEBUG(5, ("%s: invalid object (likely due to a restriction)\n", __location__));
1522
talloc_free(retvals);
1523
talloc_free(data_pointers);
1527
if (table_object->parent_object->type == EMSMDBP_OBJECT_FOLDER) {
1528
parentFolderId = table_object->parent_object->object.folder->folderID;
1530
else if (table_object->parent_object->type == EMSMDBP_OBJECT_MAILBOX) {
1531
parentFolderId = table_object->parent_object->object.mailbox->folderID;
1534
DEBUG(5, ("%s: non-mapistore tables can only be client of folder objects\n", __location__));
1535
talloc_free(retvals);
1536
talloc_free(data_pointers);
1540
odb_ctx = talloc_zero(NULL, void);
1542
/* Setup table_filter for openchangedb */
1543
/* switch (table_object->object.table->ulType) { */
1544
/* case MAPISTORE_MESSAGE_TABLE: */
1545
/* table_filter = talloc_asprintf(odb_ctx, "(&(PidTagParentFolderId=%"PRIu64")(PidTagMessageId=*))", folderID); */
1547
/* case MAPISTORE_FOLDER_TABLE: */
1548
/* table_filter = talloc_asprintf(odb_ctx, "(&(PidTagParentFolderId=%"PRIu64")(PidTagFolderId=*))", folderID); */
1551
/* DEBUG(5, ("[%s:%d]: Unsupported table type for openchangedb: %d\n", __FUNCTION__, __LINE__, */
1552
/* table_object->object.table->ulType)); */
1553
/* talloc_free(retvals); */
1554
/* talloc_free(data_pointers); */
1558
/* 1. retrieve the object id from odb */
1559
switch (table_object->object.table->ulType) {
1560
case MAPISTORE_FOLDER_TABLE:
1561
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);
1563
case MAPISTORE_MESSAGE_TABLE:
1564
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);
1566
/* case MAPISTORE_FAI_TABLE:
1567
retval = openchangedb_table_get_property(odb_ctx, table_object->backend_object, emsmdbp_ctx->oc_ctx,
1568
PR_MID, row_id, (query_type == MAPISTORE_LIVEFILTERED_QUERY), (void **) &rowFMId);
1571
DEBUG(5, ("table type %d not supported for non-mapistore table\n", table_object->object.table->ulType));
1572
retval = MAPI_E_INVALID_OBJECT;
1574
/* printf("openchangedb_table_get_property retval = 0x%.8x\n", retval); */
1575
if (retval != MAPI_E_SUCCESS) {
1576
talloc_free(retvals);
1577
talloc_free(data_pointers);
1578
talloc_free(odb_ctx);
1582
/* 2. open the corresponding object */
1583
switch (table_object->object.table->ulType) {
1584
case MAPISTORE_FOLDER_TABLE:
1585
ret = emsmdbp_object_open_folder(odb_ctx, table_object->parent_object->emsmdbp_ctx, table_object->parent_object, *(uint64_t *)rowFMId, &rowobject);
1586
mapistore_folder = emsmdbp_is_mapistore(rowobject);
1588
case MAPISTORE_MESSAGE_TABLE:
1589
ret = emsmdbp_object_message_open(odb_ctx, table_object->parent_object->emsmdbp_ctx, table_object->parent_object, parentFolderId, *(uint64_t *)rowFMId, false, &rowobject, NULL);
1590
mapistore_folder = false;
1593
DEBUG(5, ("you should never get here\n"));
1596
if (ret != MAPISTORE_SUCCESS) {
1597
talloc_free(retvals);
1598
talloc_free(data_pointers);
1599
talloc_free(odb_ctx);
1603
/* read the row properties */
1604
retval = MAPI_E_SUCCESS;
1605
for (i = 0; retval != MAPI_E_INVALID_OBJECT && i < num_props; i++) {
1606
if (mapistore_folder) {
1607
/* a hack to avoid fetching dynamic fields from openchange.ldb */
1608
switch (table->properties[i]) {
1609
case PR_CONTENT_COUNT:
1610
obj_count = talloc_zero(data_pointers, uint32_t);
1611
retval = mapistore_folder_get_child_count(emsmdbp_ctx->mstore_ctx, contextID, rowobject,
1612
MAPISTORE_MESSAGE_TABLE, obj_count);
1613
data_pointers[i] = obj_count;
1615
case PidTagAssociatedContentCount:
1616
obj_count = talloc_zero(data_pointers, uint32_t);
1617
retval = mapistore_folder_get_child_count(emsmdbp_ctx->mstore_ctx, contextID, rowobject,
1618
MAPISTORE_FAI_TABLE, obj_count);
1619
data_pointers[i] = obj_count;
1621
case PidTagFolderChildCount:
1622
obj_count = talloc_zero(data_pointers, uint32_t);
1623
retval = emsmdbp_folder_get_folder_count(emsmdbp_ctx, rowobject, obj_count);
1624
data_pointers[i] = obj_count;
1626
case PidTagSourceKey:
1627
owner = emsmdbp_get_owner(table_object);
1628
emsmdbp_source_key_from_fmid(data_pointers, emsmdbp_ctx, owner, rowobject->object.folder->folderID, &binr);
1629
data_pointers[i] = binr;
1632
obj_count = talloc_zero(NULL, uint32_t);
1633
retval = emsmdbp_folder_get_folder_count(emsmdbp_ctx, rowobject, obj_count);
1634
has_subobj = talloc_zero(data_pointers, uint8_t);
1635
*has_subobj = (*obj_count > 0) ? 1 : 0;
1636
data_pointers[i] = has_subobj;
1637
talloc_free(obj_count);
1639
case PR_CONTENT_UNREAD:
1640
case PidTagDeletedCountTotal:
1641
/* TODO: temporary */
1642
obj_count = talloc_zero(data_pointers, uint32_t);
1643
data_pointers[i] = obj_count;
1644
retval = MAPI_E_SUCCESS;
1647
retval = openchangedb_table_get_property(data_pointers, table_object->backend_object,
1648
emsmdbp_ctx->oc_ctx,
1649
table->properties[i],
1651
(query_type == MAPISTORE_LIVEFILTERED_QUERY),
1653
/* retval = openchangedb_get_table_property(data_pointers, emsmdbp_ctx->oc_ctx, */
1654
/* emsmdbp_ctx->username, */
1655
/* table_filter, table->properties[i], */
1656
/* row_id, data_pointers + i); */
1660
retval = openchangedb_table_get_property(data_pointers, table_object->backend_object,
1661
emsmdbp_ctx->oc_ctx,
1662
table->properties[i],
1664
(query_type == MAPISTORE_LIVEFILTERED_QUERY),
1668
/* DEBUG(5, (" %.8x: %d", table->properties[j], retval)); */
1669
if (retval == MAPI_E_INVALID_OBJECT) {
1670
DEBUG(5, ("%s: invalid object in non-mapistore folder, count set to 0\n", __location__));
1671
talloc_free(retvals);
1672
talloc_free(data_pointers);
1673
talloc_free(odb_ctx);
1677
retvals[i] = retval;
1681
talloc_free(odb_ctx);
1685
*retvalsp = retvals;
1688
return data_pointers;
1691
_PUBLIC_ void emsmdbp_fill_table_row_blob(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx,
1692
DATA_BLOB *table_row, uint16_t num_props,
1693
enum MAPITAGS *properties,
1694
void **data_pointers, enum MAPISTATUS *retvals)
1698
enum MAPITAGS property;
1704
for (i = 0; !flagged && i < num_props; i++) {
1705
if (retvals[i] != MAPI_E_SUCCESS) {
1711
libmapiserver_push_property(mem_ctx,
1712
0x0000000b, (const void *)&flagged,
1713
table_row, 0, 0, 0);
1716
libmapiserver_push_property(mem_ctx,
1717
0x00000000, (const void *)&flagged,
1718
table_row, 0, 1, 0);
1721
for (i = 0; i < num_props; i++) {
1722
property = properties[i];
1723
retval = retvals[i];
1724
if (retval != MAPI_E_SUCCESS) {
1725
property = (property & 0xFFFF0000) + PT_ERROR;
1729
data = data_pointers[i];
1732
libmapiserver_push_property(mem_ctx,
1733
property, data, table_row,
1734
flagged?PT_ERROR:0, flagged, 0);
479
1739
\details Initialize a message object
518
1773
object->type = EMSMDBP_OBJECT_MESSAGE;
519
object->object.message->folderID = folder->object.folder->folderID;
520
1774
object->object.message->messageID = messageID;
522
mapistore = emsmdbp_is_mapistore(parent);
523
if (mapistore == true) {
524
object->object.message->mapistore = true;
525
object->object.message->contextID = folder->object.folder->contextID;
526
ret = mapistore_add_context_ref_count(emsmdbp_ctx->mstore_ctx,
527
folder->object.folder->contextID);
1775
object->object.message->read_write = false;
1780
static int emsmdbp_days_in_month(int month, int year)
1782
static int max_mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1786
dec_year = year % 100;
1788
&& ((((year + 1900) / 100) % 4) == 0))
1789
|| (dec_year % 4) == 0) {
1793
days = max_mdays[month];
1797
days = max_mdays[month];
1803
static int emsmdbp_mins_in_ymon(uint32_t ymon)
1805
return emsmdbp_days_in_month((ymon & 0xf) - 1, ymon >> 4) * 24 * 60;
1808
static inline void emsmdbp_freebusy_make_range(struct tm *start_time, struct tm *end_time)
1811
struct tm time_data;
1812
int mw_delta, month;
1814
/* (from OXOPFFB - 3.1.4.1.1)
1815
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.
1816
End of range is calculated by adding the value of the PidTagFreeBusyCountMonths property ([MS-OXOCAL] section 2.2.12.1) to start of range.
1818
Since PidTagFreeBusyCountMonths is not supported yet, we use a count of 3 months
1822
time_data = *gmtime(&now);
1823
time_data.tm_hour = 0;
1824
time_data.tm_min = 0;
1825
time_data.tm_sec = 0;
1827
/* take the first day of the week OR the first day of the month */
1828
month = time_data.tm_mon;
1829
if (time_data.tm_mday < 7) {
1830
mw_delta = (time_data.tm_wday + 1 - time_data.tm_mday);
1832
if (time_data.tm_mon > 0) {
1836
time_data.tm_mon = 11;
1837
time_data.tm_year--;
1839
time_data.tm_mday = emsmdbp_days_in_month(time_data.tm_mon, time_data.tm_year) + 1 - mw_delta;
1842
time_data.tm_mday = 1;
1847
time_data.tm_mday = 1;
1850
*start_time = time_data;
1852
time_data.tm_mon = month + 2;
1853
if (time_data.tm_mon > 11) {
1854
time_data.tm_year++;
1855
time_data.tm_mon -= 12;
1857
time_data.tm_mday = emsmdbp_days_in_month(time_data.tm_mon, time_data.tm_year) + 1 - mw_delta;
1858
time_data.tm_hour = 23;
1859
time_data.tm_min = 59;
1860
time_data.tm_sec = 59;
1862
*end_time = time_data;
1865
static void emsmdbp_freebusy_convert_filetime(struct FILETIME *ft_value, uint32_t *ymon, uint32_t *mins)
1871
nt_time = ((NTTIME) ft_value->dwHighDateTime << 32) | ft_value->dwLowDateTime;
1872
u_time = nt_time_to_unix(nt_time);
1873
gm_time = gmtime(&u_time);
1875
*ymon = ((gm_time->tm_year + 1900) << 4) | (gm_time->tm_mon + 1);
1876
*mins = gm_time->tm_min + (gm_time->tm_hour + ((gm_time->tm_mday - 1) * 24)) * 60;
1879
static uint16_t emsmdbp_freebusy_find_month_range(uint32_t ymon, uint32_t *months_ranges, uint16_t nbr_months, bool *overflow)
1883
if (nbr_months > 0) {
1884
if (months_ranges[0] > ymon) {
1889
if (months_ranges[nbr_months - 1] < ymon) {
1891
return (nbr_months - 1);
1895
for (range = 0; range < nbr_months; range++) {
1896
if (months_ranges[range] == ymon) {
1904
return (uint16_t) -1;
1907
/* TODO: both following methods could be merged. This would certainly enhance performance by avoiding to wander through long arrays multiple times */
1908
static void emsmdbp_freebusy_fill_fbarray(uint8_t **minutes_array, uint32_t *months_ranges, uint16_t nbr_months, struct FILETIME *start, struct FILETIME *end)
1910
uint32_t i, max, start_ymon, start_mins, end_ymon, end_mins;
1911
uint16_t start_mr_idx, end_mr_idx;
1912
bool start_range_overflow, end_range_overflow;
1914
emsmdbp_freebusy_convert_filetime(start, &start_ymon, &start_mins);
1915
emsmdbp_freebusy_convert_filetime(end, &end_ymon, &end_mins);
1917
start_mr_idx = emsmdbp_freebusy_find_month_range(start_ymon, months_ranges, nbr_months, &start_range_overflow);
1918
if (start_range_overflow) {
1921
end_mr_idx = emsmdbp_freebusy_find_month_range(end_ymon, months_ranges, nbr_months, &end_range_overflow);
1922
if (end_range_overflow) {
1923
end_mins = emsmdbp_mins_in_ymon(end_ymon);
1927
if (end_mr_idx > start_mr_idx) {
1928
/* end occurs after start range */
1931
for (i = start_mr_idx + 1; i < end_mr_idx; i++) {
1932
memset(minutes_array[i], 1, emsmdbp_mins_in_ymon(months_ranges[i]));
1936
memset(minutes_array[end_mr_idx], 1, end_mins);
1938
max = emsmdbp_mins_in_ymon(start_ymon); /* = max chunk for first range */
1941
/* end occurs on same range as start */
1945
memset(minutes_array[start_mr_idx] + start_mins, 1, (max - start_mins));
1948
static void emsmdbp_freebusy_compile_fbarray(TALLOC_CTX *mem_ctx, uint8_t *minutes_array, struct Binary_r *fb_bin)
1952
struct ndr_push *ndr;
1953
TALLOC_CTX *local_mem_ctx;
1955
local_mem_ctx = talloc_zero(NULL, TALLOC_CTX);
1957
ndr = ndr_push_init_ctx(local_mem_ctx);
1959
filled = (minutes_array[0] != 0);
1961
ndr_push_uint16(ndr, NDR_SCALARS, 0);
1964
for (i = 1; i < max_mins_per_month; i++) {
1965
if (filled && !minutes_array[i]) {
1966
ndr_push_uint16(ndr, NDR_SCALARS, (i - 1));
1969
else if (!filled && minutes_array[i]) {
1970
ndr_push_uint16(ndr, NDR_SCALARS, i);
1975
ndr_push_uint16(ndr, NDR_SCALARS, (max_mins_per_month - 1));
1978
fb_bin->cb = ndr->offset;
1979
fb_bin->lpb = ndr->data;
1980
(void) talloc_reference(mem_ctx, fb_bin->lpb);
1982
talloc_free(local_mem_ctx);
1985
static void emsmdbp_freebusy_merge_subarray(uint8_t *minutes_array, uint8_t *included_array)
1989
for (i = 0; i < max_mins_per_month; i++) {
1990
if (included_array[i]) {
1991
minutes_array[i] = 1;
1996
static void emsmdbp_object_message_fill_freebusy_properties(struct emsmdbp_object *message_object)
1998
/* freebusy mechanism:
1999
- lookup events in range now + 3 months, requesting end date, start date and PidLidBusyStatus
2000
- fill (olTentative) PidTagScheduleInfoMonthsTentative,
2001
PidTagScheduleInfoFreeBusyTentative
2002
- fill (olBusy) PidTagScheduleInfoMonthsBusy,
2003
PidTagScheduleInfoFreeBusyBusy
2004
- fill (olOutOfOffice) PidTagScheduleInfoMonthsAway,
2005
PidTagScheduleInfoFreeBusyAway
2006
- fill (olBusy + olOutOfOffice) PidTagScheduleInfoMonthsMerged,
2007
PidTagScheduleInfoFreeBusyMerged
2008
- fill PidTagFreeBusyPublishStart, PidTagFreeBusyPublishEnd and
2009
PidTagFreeBusyRangeTimestamp.
2010
- fill PidTagFreeBusyMessageEmailAddress */
2012
TALLOC_CTX *mem_ctx;
2013
struct emsmdbp_object_message_freebusy_properties *fb_props;
2014
char *subject, *email, *username, *tmp;
2015
struct SPropTagArray *props;
2016
void **data_pointers;
2017
enum MAPISTATUS *retvals = NULL;
2018
struct emsmdbp_object *mailbox, *inbox, *calendar, *table;
2019
uint64_t inboxFID, calendarFID;
2021
struct mapi_SRestriction and_res;
2023
struct tm start_tm, end_tm;
2024
time_t start_time, end_time;
2026
struct mapi_SRestriction_and time_restrictions[2];
2027
int i, month, nbr_months;
2028
uint8_t **minutes_array, **tentative_array, **busy_array, **oof_array;
2031
mem_ctx = talloc_zero(NULL, TALLOC_CTX);
2033
/* 1. retrieve subject and deduce username */
2034
props = talloc_zero(mem_ctx, struct SPropTagArray);
2036
props->aulPropTag = talloc_zero(props, enum MAPITAGS);
2037
props->aulPropTag[0] = PR_NORMALIZED_SUBJECT_UNICODE;
2038
data_pointers = emsmdbp_object_get_properties(mem_ctx, message_object->emsmdbp_ctx, message_object, props, &retvals);
2039
if (!data_pointers || retvals[0] != MAPI_E_SUCCESS) {
2042
subject = data_pointers[0];
2043
// format is "..../CN="
2044
username = strrchr(subject, '/');
2049
username = talloc_strdup(mem_ctx, username);
2051
fb_props = talloc_zero(message_object, struct emsmdbp_object_message_freebusy_properties);
2052
message_object->object.message->fb_properties = fb_props;
2054
// WARNING: the mechanism here will fail if username is not all lower-case, as LDB does not support case-insensitive queries
2057
*tmp = tolower(*tmp);
2060
email = talloc_asprintf(mem_ctx, "/o=First Organization/ou=First Administrative Group/cn=Recipients/cn=%s", username);
2061
fb_props->email_address = email;
2063
/* open user mailbox */
2064
mailbox = emsmdbp_object_mailbox_init(mem_ctx, message_object->emsmdbp_ctx, email, true);
2070
openchangedb_get_SystemFolderID(message_object->emsmdbp_ctx->oc_ctx, username, EMSMDBP_INBOX, &inboxFID);
2071
if (emsmdbp_object_open_folder_by_fid(mem_ctx, message_object->emsmdbp_ctx, mailbox, inboxFID, &inbox) != MAPISTORE_SUCCESS) {
2075
/* retrieve Calendar entry id */
2076
props->aulPropTag[0] = PR_IPM_APPOINTMENT_ENTRYID;
2077
data_pointers = emsmdbp_object_get_properties(mem_ctx, message_object->emsmdbp_ctx, inbox, props, &retvals);
2078
if (!data_pointers || retvals[0] != MAPI_E_SUCCESS) {
2082
for (i = 0; i < 6; i++) {
2084
calendarFID |= *(((struct Binary_r *) data_pointers[0])->lpb + (43 - i));
2089
/* open user calendar */
2090
if (emsmdbp_object_open_folder_by_fid(mem_ctx, message_object->emsmdbp_ctx, mailbox, calendarFID, &calendar) != MAPISTORE_SUCCESS) {
2093
if (!emsmdbp_is_mapistore(calendar)) {
2094
DEBUG(5, ("non-mapistore calendars are not supported for freebusy\n"));
2098
/* fetch events from this month for 3 months: start + enddate + fbstatus */
2099
table = emsmdbp_folder_open_table(mem_ctx, calendar, MAPISTORE_MESSAGE_TABLE, 0);
2103
contextID = emsmdbp_get_contextID(calendar);
2105
/* fetch freebusy range */
2106
emsmdbp_freebusy_make_range(&start_tm, &end_tm);
2108
unix_to_nt_time(&nt_time, time(NULL));
2109
fb_props->timestamp.dwLowDateTime = (nt_time & 0xffffffff);
2110
fb_props->timestamp.dwHighDateTime = nt_time >> 32;
2113
setenv("TZ", "", 1);
2115
start_time = mktime(&start_tm);
2116
end_time = mktime(&end_tm);
2118
setenv("TZ", tz, 1);
2125
/* setup restriction */
2126
and_res.rt = RES_AND;
2127
and_res.res.resAnd.cRes = 2;
2128
and_res.res.resAnd.res = time_restrictions;
2130
time_restrictions[0].rt = RES_PROPERTY;
2131
time_restrictions[0].res.resProperty.relop = RELOP_GE;
2132
time_restrictions[0].res.resProperty.ulPropTag = PidLidAppointmentEndWhole;
2133
time_restrictions[0].res.resProperty.lpProp.ulPropTag = PidLidAppointmentEndWhole;
2134
unix_to_nt_time(&nt_time, start_time);
2135
time_restrictions[0].res.resProperty.lpProp.value.ft.dwLowDateTime = (nt_time & 0xffffffff);
2136
time_restrictions[0].res.resProperty.lpProp.value.ft.dwHighDateTime = nt_time >> 32;
2137
fb_props->publish_start = (uint32_t) (nt_time / (60 * 10000000));
2139
time_restrictions[1].rt = RES_PROPERTY;
2140
time_restrictions[1].res.resProperty.relop = RELOP_LE;
2141
time_restrictions[1].res.resProperty.ulPropTag = PidLidAppointmentStartWhole;
2142
time_restrictions[1].res.resProperty.lpProp.ulPropTag = PidLidAppointmentStartWhole;
2143
unix_to_nt_time(&nt_time, end_time);
2144
time_restrictions[1].res.resProperty.lpProp.value.ft.dwLowDateTime = (nt_time & 0xffffffff);
2145
time_restrictions[1].res.resProperty.lpProp.value.ft.dwHighDateTime = nt_time >> 32;
2146
fb_props->publish_end = (uint32_t) (nt_time / (60 * 10000000));
2148
mapistore_table_set_restrictions(message_object->emsmdbp_ctx->mstore_ctx, contextID, table->backend_object, &and_res, &state);
2150
/* setup table columns */
2152
props->aulPropTag = talloc_array(props, enum MAPITAGS, props->cValues);
2153
props->aulPropTag[0] = PidLidAppointmentStartWhole;
2154
props->aulPropTag[1] = PidLidAppointmentEndWhole;
2155
props->aulPropTag[2] = PidLidBusyStatus;
2156
mapistore_table_set_columns(message_object->emsmdbp_ctx->mstore_ctx, contextID, table->backend_object, props->cValues, props->aulPropTag);
2157
table->object.table->prop_count = props->cValues;
2158
table->object.table->properties = props->aulPropTag;
2160
/* setup months arrays */
2161
if (start_tm.tm_year == end_tm.tm_year) {
2162
nbr_months = (end_tm.tm_mon - start_tm.tm_mon + 1);
2165
nbr_months = (12 - start_tm.tm_mon) + end_tm.tm_mon + 1;
2167
fb_props->months_ranges = talloc_array(fb_props, uint32_t, nbr_months);
2168
if (start_tm.tm_year == end_tm.tm_year) {
2169
for (i = 0; i < nbr_months; i++) {
2170
fb_props->months_ranges[i] = ((start_tm.tm_year + 1900) << 4) + (start_tm.tm_mon + 1 + i);
2174
month = start_tm.tm_mon;
2176
while (month < 12) {
2177
fb_props->months_ranges[i] = ((start_tm.tm_year + 1900) << 4) + month + 1;
2182
while (month < end_tm.tm_mon) {
2183
fb_props->months_ranges[i] = ((end_tm.tm_year + 1900) << 4) + month + 1;
2187
fb_props->months_ranges[i] = ((end_tm.tm_year + 1900) << 4) + month + 1;
2190
/* fetch events and fill freebusy arrays */
2191
tentative_array = talloc_array(mem_ctx, uint8_t *, nbr_months);
2192
busy_array = talloc_array(mem_ctx, uint8_t *, nbr_months);
2193
oof_array = talloc_array(mem_ctx, uint8_t *, nbr_months);
2194
for (i = 0; i < nbr_months; i++) {
2195
tentative_array[i] = talloc_array(tentative_array, uint8_t, max_mins_per_month);
2196
memset(tentative_array[i], 0, max_mins_per_month);
2197
busy_array[i] = talloc_array(tentative_array, uint8_t, max_mins_per_month);
2198
memset(busy_array[i], 0, max_mins_per_month);
2199
oof_array[i] = talloc_array(tentative_array, uint8_t, max_mins_per_month);
2200
memset(oof_array[i], 0, max_mins_per_month);
2204
while ((data_pointers = emsmdbp_object_table_get_row_props(mem_ctx, message_object->emsmdbp_ctx, table, i, MAPISTORE_PREFILTERED_QUERY, &retvals))) {
2205
if (retvals[0] == MAPI_E_SUCCESS && retvals[1] == MAPI_E_SUCCESS && retvals[2] == MAPI_E_SUCCESS) {
2206
switch (*((uint32_t *) data_pointers[2])) {
2208
minutes_array = tentative_array;
2211
minutes_array = busy_array;
2214
minutes_array = oof_array;
2217
minutes_array = NULL;
2219
if (minutes_array) {
2220
emsmdbp_freebusy_fill_fbarray(minutes_array, fb_props->months_ranges, nbr_months, data_pointers[0], data_pointers[1]);
2226
/* compile minutes array into arrays of ranges */
2227
fb_props->nbr_months = nbr_months;
2228
fb_props->freebusy_tentative = talloc_array(fb_props, struct Binary_r, nbr_months);
2229
fb_props->freebusy_busy = talloc_array(fb_props, struct Binary_r, nbr_months);
2230
fb_props->freebusy_away = talloc_array(fb_props, struct Binary_r, nbr_months);
2231
fb_props->freebusy_merged = talloc_array(fb_props, struct Binary_r, nbr_months);
2232
for (i = 0; i < nbr_months; i++) {
2233
emsmdbp_freebusy_compile_fbarray(fb_props, tentative_array[i], fb_props->freebusy_tentative + i);
2234
emsmdbp_freebusy_compile_fbarray(fb_props, busy_array[i], fb_props->freebusy_busy + i);
2235
emsmdbp_freebusy_compile_fbarray(fb_props, oof_array[i], fb_props->freebusy_away + i);
2236
emsmdbp_freebusy_merge_subarray(busy_array[i], oof_array[i]);
2237
emsmdbp_freebusy_compile_fbarray(fb_props, busy_array[i], fb_props->freebusy_merged + i);
2241
talloc_free(mem_ctx);
2246
_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)
2248
struct emsmdbp_object *folder_object, *message_object = NULL;
2251
TALLOC_CTX *local_mem_ctx;
2252
enum mapistore_error ret = MAPISTORE_SUCCESS;
2254
if (!messageP) return MAPISTORE_ERROR;
2255
if (!parent_object) return MAPISTORE_ERROR;
2257
local_mem_ctx = talloc_zero(NULL, TALLOC_CTX);
2258
ret = emsmdbp_object_open_folder_by_fid(local_mem_ctx, emsmdbp_ctx, parent_object, folderID, &folder_object);
2259
if (ret != MAPISTORE_SUCCESS) {
2263
mapistore = emsmdbp_is_mapistore(folder_object);
2264
switch (mapistore) {
2266
/* system/special folder */
2267
message_object = emsmdbp_object_message_init(mem_ctx, emsmdbp_ctx, messageID, folder_object);
2268
ret = openchangedb_message_open(mem_ctx, emsmdbp_ctx->oc_ctx, messageID, folderID, &message_object->backend_object, (void **)msgp);
2269
if (ret != MAPISTORE_SUCCESS) {
2270
printf("Invalid openchangedb message\n");
2271
talloc_free(message_object);
2275
emsmdbp_object_message_fill_freebusy_properties(message_object);
2278
/* mapistore implementation goes here */
2279
message_object = emsmdbp_object_message_init(mem_ctx, emsmdbp_ctx, messageID, folder_object);
2280
contextID = emsmdbp_get_contextID(folder_object);
2281
ret = mapistore_folder_open_message(emsmdbp_ctx->mstore_ctx, contextID, folder_object->backend_object, message_object, messageID, read_write, &message_object->backend_object);
2282
if (ret == MAPISTORE_SUCCESS && msgp) {
2283
if (mapistore_message_get_message_data(emsmdbp_ctx->mstore_ctx, contextID, message_object->backend_object, mem_ctx, msgp) != MAPISTORE_SUCCESS) {
2284
ret = MAPISTORE_ERROR;
2287
if (ret != MAPISTORE_SUCCESS) {
2288
talloc_free(message_object);
2293
talloc_free(local_mem_ctx);
2295
if (ret == MAPISTORE_SUCCESS) {
2296
message_object->object.message->read_write = read_write;
2297
*messageP = message_object;
2303
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_message_open_attachment_table(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *message_object)
2305
struct emsmdbp_object *table_object;
2309
if (!emsmdbp_ctx) return NULL;
2310
if (!message_object || message_object->type != EMSMDBP_OBJECT_MESSAGE) return NULL;
2312
switch (emsmdbp_is_mapistore(message_object)) {
2314
/* system/special folder */
2315
DEBUG(0, ("[%s] not implemented yet - shouldn't occur\n", __location__));
2316
table_object = NULL;
2319
contextID = emsmdbp_get_contextID(message_object);
2321
table_object = emsmdbp_object_table_init(mem_ctx, emsmdbp_ctx, message_object);
2323
table_object->object.table->ulType = MAPISTORE_ATTACHMENT_TABLE;
2324
mapistore_message_get_attachment_table(emsmdbp_ctx->mstore_ctx, contextID,
2325
message_object->backend_object,
2326
table_object, &table_object->backend_object,
2327
&table_object->object.table->denominator);
2331
return table_object;
535
2335
\details Initialize a stream object
568
2361
object->type = EMSMDBP_OBJECT_STREAM;
569
object->object.stream->property = property;
571
mapistore = emsmdbp_is_mapistore(parent);
572
if (mapistore == true) {
573
object->object.stream->mapistore = true;
574
object->object.stream->contextID = emsmdbp_get_contextID(parent);
2362
object->object.stream->property = 0;
2363
object->object.stream->needs_commit = false;
2364
object->object.stream->stream.buffer.data = NULL;
2365
object->object.stream->stream.buffer.length = 0;
2366
object->object.stream->stream.position = 0;
2373
\details Initialize a attachment object
2375
\param mem_ctx pointer to the memory context
2376
\param emsmdbp_ctx pointer to the emsmdb provider cotnext
2377
\param folderID the folder identifier
2378
\param messageID the message identifier
2379
\param parent emsmdbp object of the parent
2381
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_attachment_init(TALLOC_CTX *mem_ctx,
2382
struct emsmdbp_context *emsmdbp_ctx,
2384
struct emsmdbp_object *parent)
2386
struct emsmdbp_object *object;
2389
if (!emsmdbp_ctx) return NULL;
2390
if (!parent) return NULL;
2392
object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
2393
if (!object) return NULL;
2395
object->object.attachment = talloc_zero(object, struct emsmdbp_object_attachment);
2396
if (!object->object.attachment) {
2397
talloc_free(object);
2401
object->type = EMSMDBP_OBJECT_ATTACHMENT;
2402
object->object.attachment->attachmentID = -1;
2408
\details Initialize a notification subscription object
2410
\param mem_ctx pointer to the memory context
2411
\param emsmdbp_ctx pointer to the emsmdb provider cotnext
2412
\param whole_store whether the subscription applies to the specified change on the entire store or stricly on the specified folder/message
2413
\param folderID the folder identifier
2414
\param messageID the message identifier
2415
\param parent emsmdbp object of the parent
2417
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_subscription_init(TALLOC_CTX *mem_ctx,
2418
struct emsmdbp_context *emsmdbp_ctx,
2419
struct emsmdbp_object *parent)
2421
struct emsmdbp_object *object;
2424
if (!emsmdbp_ctx) return NULL;
2425
if (!parent) return NULL;
2427
object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
2428
if (!object) return NULL;
2430
object->object.subscription = talloc_zero(object, struct emsmdbp_object_subscription);
2431
if (!object->object.subscription) {
2432
talloc_free(object);
2436
object->type = EMSMDBP_OBJECT_SUBSCRIPTION;
2437
object->object.subscription->subscription_list = NULL;
2442
_PUBLIC_ int emsmdbp_object_get_available_properties(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *object, struct SPropTagArray **propertiesp)
2446
if (!(object->type == EMSMDBP_OBJECT_FOLDER
2447
|| object->type == EMSMDBP_OBJECT_MAILBOX
2448
|| object->type == EMSMDBP_OBJECT_MESSAGE
2449
|| object->type == EMSMDBP_OBJECT_ATTACHMENT)) {
2450
DEBUG(0, (__location__": object must be EMSMDBP_OBJECT_FOLDER, EMSMDBP_OBJECT_MAILBOX, EMSMDBP_OBJECT_MESSAGE or EMSMDBP_OBJECT_ATTACHMENT (type = %d)\n", object->type));
2451
return MAPISTORE_ERROR;
2454
if (!emsmdbp_is_mapistore(object)) {
2455
DEBUG(5, (__location__": only mapistore is supported at this time\n"));
2456
return MAPISTORE_ERROR;
2459
contextID = emsmdbp_get_contextID(object);
2461
return mapistore_properties_get_available_properties(emsmdbp_ctx->mstore_ctx, contextID, object->backend_object, mem_ctx, propertiesp);
2464
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)
2466
enum MAPISTATUS retval = MAPI_E_SUCCESS;
2467
struct emsmdbp_object_folder *folder;
2470
uint32_t *obj_count;
2471
uint8_t *has_subobj;
2472
struct Binary_r *binr;
2475
struct FILETIME *ft;
2477
folder = (struct emsmdbp_object_folder *) object->object.folder;
2478
for (i = 0; i < properties->cValues; i++) {
2479
if (properties->aulPropTag[i] == PR_FOLDER_CHILD_COUNT) {
2480
obj_count = talloc_zero(data_pointers, uint32_t);
2481
retval = openchangedb_get_folder_count(emsmdbp_ctx->oc_ctx, object->object.folder->folderID, obj_count);
2482
data_pointers[i] = obj_count;
2484
else if (properties->aulPropTag[i] == PR_SUBFOLDERS) {
2485
obj_count = talloc_zero(NULL, uint32_t);
2486
retval = openchangedb_get_folder_count(emsmdbp_ctx->oc_ctx, object->object.folder->folderID, obj_count);
2487
has_subobj = talloc_zero(data_pointers, uint8_t);
2488
*has_subobj = (*obj_count > 0) ? 1 : 0;
2489
data_pointers[i] = has_subobj;
2490
talloc_free(obj_count);
2492
else if (properties->aulPropTag[i] == PR_SOURCE_KEY) {
2493
owner = emsmdbp_get_owner(object);
2494
emsmdbp_source_key_from_fmid(data_pointers, emsmdbp_ctx, owner, object->object.folder->folderID, &binr);
2495
data_pointers[i] = binr;
2496
retval = MAPI_E_SUCCESS;
2498
else if (properties->aulPropTag[i] == PR_CONTENT_COUNT
2499
|| properties->aulPropTag[i] == PidTagAssociatedContentCount
2500
|| properties->aulPropTag[i] == PR_CONTENT_UNREAD
2501
|| properties->aulPropTag[i] == PR_DELETED_COUNT_TOTAL) {
2502
obj_count = talloc_zero(data_pointers, uint32_t);
2504
data_pointers[i] = obj_count;
2505
retval = MAPI_E_SUCCESS;
2507
else if (properties->aulPropTag[i] == PidTagLocalCommitTimeMax) {
2508
/* TODO: temporary hack */
2509
unix_time = time(NULL) & 0xffffff00;
2510
unix_to_nt_time(&nt_time, unix_time);
2511
ft = talloc_zero(data_pointers, struct FILETIME);
2512
ft->dwLowDateTime = (nt_time & 0xffffffff);
2513
ft->dwHighDateTime = nt_time >> 32;
2514
data_pointers[i] = ft;
2515
retval = MAPI_E_SUCCESS;
2518
retval = openchangedb_get_folder_property(data_pointers, emsmdbp_ctx->oc_ctx, properties->aulPropTag[i], folder->folderID, data_pointers + i);
2520
retvals[i] = retval;
2523
return MAPISTORE_SUCCESS;
2526
static int emsmdbp_object_get_properties_message(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx,
2527
struct emsmdbp_object *object, struct SPropTagArray *properties,
2528
void **data_pointers, enum MAPISTATUS *retvals)
2530
enum MAPISTATUS retval;
2533
struct Binary_r *binr;
2534
struct emsmdbp_object_message_freebusy_properties *fb_props;
2535
struct LongArray_r *long_array;
2536
struct BinaryArray_r *bin_array;
2538
fb_props = object->object.message->fb_properties;
2540
/* Look over properties */
2541
for (i = 0; i < properties->cValues; i++) {
2542
if (properties->aulPropTag[i] == PR_SOURCE_KEY) {
2543
owner = emsmdbp_get_owner(object);
2544
emsmdbp_source_key_from_fmid(data_pointers, emsmdbp_ctx, owner, object->object.message->folderID,
2546
data_pointers[i] = binr;
2547
retval = MAPI_E_SUCCESS;
2550
switch (properties->aulPropTag[i]) {
2551
case PR_SCHDINFO_MONTHS_TENTATIVE:
2552
case PR_SCHDINFO_MONTHS_BUSY:
2553
case PR_SCHDINFO_MONTHS_OOF:
2554
case PR_SCHDINFO_MONTHS_MERGED:
2555
long_array = talloc_zero(data_pointers, struct LongArray_r);
2556
long_array->cValues = fb_props->nbr_months;
2557
long_array->lpl = fb_props->months_ranges;
2558
data_pointers[i] = long_array;
2559
retval = MAPI_E_SUCCESS;
2561
case PR_SCHDINFO_FREEBUSY_TENTATIVE:
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_tentative;
2565
data_pointers[i] = bin_array;
2566
retval = MAPI_E_SUCCESS;
2568
case PR_SCHDINFO_FREEBUSY_BUSY:
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_busy;
2572
data_pointers[i] = bin_array;
2573
retval = MAPI_E_SUCCESS;
2575
case PR_SCHDINFO_FREEBUSY_OOF:
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_away;
2579
data_pointers[i] = bin_array;
2580
retval = MAPI_E_SUCCESS;
2582
case PR_SCHDINFO_FREEBUSY_MERGED:
2583
bin_array = talloc_zero(data_pointers, struct BinaryArray_r);
2584
bin_array->cValues = fb_props->nbr_months;
2585
bin_array->lpbin = fb_props->freebusy_merged;
2586
data_pointers[i] = bin_array;
2587
retval = MAPI_E_SUCCESS;
2589
case PR_FREEBUSY_PUBLISH_START:
2590
data_pointers[i] = &fb_props->publish_start;
2591
retval = MAPI_E_SUCCESS;
2593
case PR_FREEBUSY_PUBLISH_END:
2594
data_pointers[i] = &fb_props->publish_end;
2595
retval = MAPI_E_SUCCESS;
2597
case PidTagFreeBusyMessageEmailAddress:
2598
data_pointers[i] = fb_props->email_address;
2599
retval = MAPI_E_SUCCESS;
2601
case PR_FREEBUSY_RANGE_TIMESTAMP:
2602
data_pointers[i] = &fb_props->timestamp;
2603
retval = MAPI_E_SUCCESS;
2606
retval = openchangedb_message_get_property(data_pointers, object->backend_object, properties->aulPropTag[i], data_pointers + i);
2610
retval = openchangedb_message_get_property(data_pointers, object->backend_object, properties->aulPropTag[i], data_pointers + i);
2613
retvals[i] = retval;
2616
return MAPI_E_SUCCESS;
2619
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)
2621
enum MAPISTATUS retval = MAPI_E_SUCCESS;
2622
struct emsmdbp_object_folder *folder;
2624
struct Binary_r *binr;
2627
uint32_t *obj_count;
2628
uint8_t *has_subobj;
2629
/* time_t unix_time; */
2630
/* NTTIME nt_time; */
2631
/* struct FILETIME *ft; */
2633
contextID = emsmdbp_get_contextID(object);
2635
folder = (struct emsmdbp_object_folder *) object->object.folder;
2636
for (i = 0; i < properties->cValues; i++) {
2637
if (properties->aulPropTag[i] == PR_CONTENT_COUNT) {
2638
/* a hack to avoid fetching dynamic fields from openchange.ldb */
2639
obj_count = talloc_zero(data_pointers, uint32_t);
2640
retval = mapistore_folder_get_child_count(emsmdbp_ctx->mstore_ctx, contextID, object->backend_object, MAPISTORE_MESSAGE_TABLE, obj_count);
2642
data_pointers[i] = obj_count;
2645
else if (properties->aulPropTag[i] == PidTagAssociatedContentCount) {
2646
obj_count = talloc_zero(data_pointers, uint32_t);
2647
retval = mapistore_folder_get_child_count(emsmdbp_ctx->mstore_ctx, emsmdbp_get_contextID(object), object->backend_object, MAPISTORE_FAI_TABLE, obj_count);
2649
data_pointers[i] = obj_count;
2652
else if (properties->aulPropTag[i] == PR_FOLDER_CHILD_COUNT) {
2653
obj_count = talloc_zero(data_pointers, uint32_t);
2654
retval = emsmdbp_folder_get_folder_count(emsmdbp_ctx, object, obj_count);
2656
data_pointers[i] = obj_count;
2659
else if (properties->aulPropTag[i] == PR_SUBFOLDERS) {
2660
obj_count = talloc_zero(NULL, uint32_t);
2661
retval = emsmdbp_folder_get_folder_count(emsmdbp_ctx, object, obj_count);
2663
has_subobj = talloc_zero(data_pointers, uint8_t);
2664
*has_subobj = (*obj_count > 0) ? 1 : 0;
2665
data_pointers[i] = has_subobj;
2667
talloc_free(obj_count);
2669
else if (properties->aulPropTag[i] == PR_SOURCE_KEY) {
2670
owner = emsmdbp_get_owner(object);
2671
emsmdbp_source_key_from_fmid(data_pointers, emsmdbp_ctx, owner, object->object.folder->folderID, &binr);
2672
data_pointers[i] = binr;
2673
retval = MAPI_E_SUCCESS;
2675
else if (properties->aulPropTag[i] == PR_FOLDER_TYPE) {
2676
obj_count = talloc_zero(data_pointers, uint32_t);
2677
*obj_count = FOLDER_GENERIC;
2678
data_pointers[i] = obj_count;
2679
retval = MAPI_E_SUCCESS;
2681
else if (properties->aulPropTag[i] == PR_CONTENT_UNREAD || properties->aulPropTag[i] == PR_DELETED_COUNT_TOTAL) {
2682
/* TODO: temporary hack */
2683
obj_count = talloc_zero(data_pointers, uint32_t);
2685
data_pointers[i] = obj_count;
2686
retval = MAPI_E_SUCCESS;
2688
else if (properties->aulPropTag[i] == PidTagLocalCommitTimeMax || properties->aulPropTag[i] == PR_ACCESS || properties->aulPropTag[i] == PR_ACCESS_LEVEL) {
2689
struct mapistore_property_data prop_data;
2691
mapistore_properties_get_properties(emsmdbp_ctx->mstore_ctx, contextID,
2692
object->backend_object,
2695
properties->aulPropTag + i,
2697
data_pointers[i] = prop_data.data;
2698
retval = prop_data.error;
2701
retval = openchangedb_get_folder_property(data_pointers, emsmdbp_ctx->oc_ctx, properties->aulPropTag[i], folder->folderID, data_pointers + i);
2703
retvals[i] = retval;
2706
return MAPISTORE_SUCCESS;
2709
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)
2712
struct SBinary_short *bin;
2714
for (i = 0; i < properties->cValues; i++) {
2715
switch (properties->aulPropTag[i]) {
2716
case PR_MAPPING_SIGNATURE:
2717
case PidTagIpmPublicFoldersEntryId:
2718
retvals[i] = MAPI_E_NO_ACCESS;
2720
case PR_USER_ENTRYID:
2721
bin = talloc_zero(data_pointers, struct SBinary_short);
2722
retvals[i] = entryid_set_AB_EntryID(data_pointers, object->object.mailbox->szUserDN, bin);
2723
data_pointers[i] = bin;
2725
case PR_MAILBOX_OWNER_ENTRYID:
2726
if (object->object.mailbox->mailboxstore == false) {
2727
retvals[i] = MAPI_E_NO_ACCESS;
2729
bin = talloc_zero(data_pointers, struct SBinary_short);
2730
retvals[i] = entryid_set_AB_EntryID(data_pointers, object->object.mailbox->owner_EssDN,
2732
data_pointers[i] = bin;
2735
case PidTagMailboxOwnerName:
2736
if (object->object.mailbox->mailboxstore == false) {
2737
retvals[i] = MAPI_E_NO_ACCESS;
2739
retvals[i] = MAPI_E_SUCCESS;
2740
data_pointers[i] = talloc_strdup(data_pointers, object->object.mailbox->owner_Name);
2744
retvals[i] = openchangedb_get_folder_property(data_pointers, emsmdbp_ctx->oc_ctx, properties->aulPropTag[i], object->object.mailbox->folderID, data_pointers + i);
2748
return MAPISTORE_SUCCESS;
2751
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)
2753
uint32_t contextID = -1;
2754
struct mapistore_property_data *prop_data;
2757
contextID = emsmdbp_get_contextID(object);
2758
prop_data = talloc_array(NULL, struct mapistore_property_data, properties->cValues);
2759
memset(prop_data, 0, sizeof(struct mapistore_property_data) * properties->cValues);
2761
ret = mapistore_properties_get_properties(emsmdbp_ctx->mstore_ctx, contextID,
2762
object->backend_object,
2764
properties->cValues,
2765
properties->aulPropTag,
2767
if (ret == MAPISTORE_SUCCESS) {
2768
for (i = 0; i < properties->cValues; i++) {
2769
if (prop_data[i].error) {
2770
if (prop_data[i].error == MAPISTORE_ERR_NOT_FOUND) {
2771
retvals[i] = MAPI_E_NOT_FOUND;
2774
retvals[i] = MAPI_E_NO_SUPPORT;
2775
DEBUG (4, ("%s: unknown mapistore error: %.8x\n", __PRETTY_FUNCTION__, prop_data[i].error));
2779
if (prop_data[i].data == NULL) {
2780
retvals[i] = MAPI_E_NOT_FOUND;
2783
data_pointers[i] = prop_data[i].data;
2784
(void) talloc_reference(data_pointers, prop_data[i].data);
2789
talloc_free(prop_data);
2794
_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)
2796
void **data_pointers;
2797
enum MAPISTATUS *retvals;
2801
data_pointers = talloc_array(mem_ctx, void *, properties->cValues);
2802
memset(data_pointers, 0, sizeof(void *) * properties->cValues);
2804
retvals = talloc_array(mem_ctx, enum MAPISTATUS, properties->cValues);
2805
memset(retvals, 0, sizeof(enum MAPISTATUS) * properties->cValues);
2807
/* Temporary hack: If this is a mapistore root container
2808
* (e.g. Inbox, Calendar etc.), directly stored under
2809
* IPM.Subtree, then fetch properties from openchange
2810
* dispatcher db, not mapistore */
2811
if (object && object->type == EMSMDBP_OBJECT_FOLDER &&
2812
object->object.folder->mapistore_root == true) {
2813
if (object->object.folder->postponed_props) {
2814
emsmdbp_object_folder_commit_creation(emsmdbp_ctx, object, true);
2817
retval = emsmdbp_object_get_properties_mapistore_root(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
2819
mapistore = emsmdbp_is_mapistore(object);
2822
DEBUG(5, ("[%s] what's that hack!??\n", __location__));
2826
switch (mapistore) {
2828
switch (object->type) {
2829
case EMSMDBP_OBJECT_MAILBOX:
2830
retval = emsmdbp_object_get_properties_mailbox(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
2832
case EMSMDBP_OBJECT_FOLDER:
2833
retval = emsmdbp_object_get_properties_systemspecialfolder(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
2835
case EMSMDBP_OBJECT_MESSAGE:
2836
retval = emsmdbp_object_get_properties_message(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
2839
retval = MAPISTORE_ERROR;
2844
/* folder or messages handled by mapistore */
2845
retval = emsmdbp_object_get_properties_mapistore(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
2851
*retvalsp = retvals;
2855
talloc_free(data_pointers);
2856
data_pointers = NULL;
2859
return data_pointers;
2862
/* TODO: handling of "property problems" */
2863
_PUBLIC_ int emsmdbp_object_set_properties(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *object, struct SRow *rowp)
2865
uint32_t contextID, new_cvalues;
2867
enum mapistore_error ret;
2868
struct SRow *postponed_props;
2871
if (!emsmdbp_ctx) return MAPI_E_CALL_FAILED;
2872
if (!object) return MAPI_E_CALL_FAILED;
2873
if (!rowp) return MAPI_E_CALL_FAILED;
2874
if (!(object->type == EMSMDBP_OBJECT_FOLDER
2875
|| object->type == EMSMDBP_OBJECT_MAILBOX
2876
|| object->type == EMSMDBP_OBJECT_MESSAGE
2877
|| object->type == EMSMDBP_OBJECT_ATTACHMENT)) {
2878
DEBUG(0, (__location__": object must be EMSMDBP_OBJECT_FOLDER, EMSMDBP_OBJECT_MAILBOX, EMSMDBP_OBJECT_MESSAGE or EMSMDBP_OBJECT_ATTACHMENT (type = %d)\n", object->type));
2879
return MAPI_E_NO_SUPPORT;
2882
if (object->type == EMSMDBP_OBJECT_FOLDER) {
2883
postponed_props = object->object.folder->postponed_props;
2884
if (postponed_props) {
2885
new_cvalues = postponed_props->cValues + rowp->cValues;
2886
postponed_props->lpProps = talloc_realloc(postponed_props, postponed_props->lpProps, struct SPropValue, new_cvalues);
2887
mapi_copy_spropvalues(postponed_props, rowp->lpProps, postponed_props->lpProps + postponed_props->cValues, rowp->cValues);
2888
postponed_props->cValues = new_cvalues;
2890
ret = emsmdbp_object_folder_commit_creation(emsmdbp_ctx, object, false);
2891
if (ret == MAPISTORE_SUCCESS) {
2892
return MAPI_E_SUCCESS;
2895
return MAPI_E_NOT_FOUND;
2900
/* Temporary hack: If this is a mapistore root container
2901
* (e.g. Inbox, Calendar etc.), directly stored under
2902
* IPM.Subtree, then set properties from openchange
2903
* dispatcher db, not mapistore */
2904
if (object->type == EMSMDBP_OBJECT_FOLDER
2905
&& object->object.folder->mapistore_root == true) {
2906
openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, object->object.folder->folderID, rowp);
2907
contextID = emsmdbp_get_contextID(object);
2908
mapistore_properties_set_properties(emsmdbp_ctx->mstore_ctx, contextID, object->backend_object, rowp);
2911
contextID = emsmdbp_get_contextID(object);
2912
mapistore = emsmdbp_is_mapistore(object);
2913
switch (mapistore) {
2915
if (object->type == EMSMDBP_OBJECT_FOLDER) {
2916
openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, object->object.folder->folderID, rowp);
2918
else if (object->type == EMSMDBP_OBJECT_MAILBOX) {
2919
openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, object->object.mailbox->folderID, rowp);
2921
else if (object->type == EMSMDBP_OBJECT_MESSAGE) {
2922
openchangedb_message_set_properties((TALLOC_CTX *)object->object.message,
2923
object->backend_object, rowp);
2926
DEBUG(0, ("Setting properties on openchangedb not implemented yet for non-folder object type\n"));
2927
return MAPI_E_NO_SUPPORT;
2931
mapistore_properties_set_properties(emsmdbp_ctx->mstore_ctx, contextID, object->backend_object, rowp);
2936
return MAPI_E_SUCCESS;
2939
_PUBLIC_ void emsmdbp_fill_row_blob(TALLOC_CTX *mem_ctx,
2940
struct emsmdbp_context *emsmdbp_ctx,
2942
DATA_BLOB *property_row,
2943
struct SPropTagArray *properties,
2944
void **data_pointers,
2945
enum MAPISTATUS *retvals,
2946
bool *untyped_status)
2950
enum MAPITAGS property;
2955
for (i = 0; !flagged && i < properties->cValues; i++) {
2956
if (retvals[i] != MAPI_E_SUCCESS || untyped_status[i] || !data_pointers[i]) {
2962
for (i = 0; i < properties->cValues; i++) {
2963
retval = retvals[i];
2964
if (retval != MAPI_E_SUCCESS) {
2965
property = (properties->aulPropTag[i] & 0xFFFF0000) + PT_ERROR;
2969
property = properties->aulPropTag[i];
2970
data = data_pointers[i];
2972
libmapiserver_push_property(mem_ctx,
2973
property, data, property_row,
2974
flagged ? PT_ERROR : 0, flagged, untyped_status[i]);
2978
_PUBLIC_ struct emsmdbp_stream_data *emsmdbp_stream_data_from_value(TALLOC_CTX *mem_ctx, enum MAPITAGS prop_tag, void *value)
2981
struct emsmdbp_stream_data *stream_data;
2982
size_t converted_size;
2984
stream_data = talloc_zero(mem_ctx, struct emsmdbp_stream_data);
2985
stream_data->prop_tag = prop_tag;
2986
prop_type = prop_tag & 0xffff;
2987
if (prop_type == PT_STRING8) {
2988
stream_data->data.length = strlen(value) + 1;
2989
stream_data->data.data = value;
2990
(void) talloc_reference(stream_data, stream_data->data.data);
2992
else if (prop_type == PT_UNICODE) {
2993
stream_data->data.length = strlen_m_ext((char *) value, CH_UTF8, CH_UTF16LE) * 2;
2994
stream_data->data.data = talloc_array(stream_data, uint8_t, stream_data->data.length + 2);
2995
convert_string(CH_UTF8, CH_UTF16LE,
2996
value, strlen(value),
2997
stream_data->data.data, stream_data->data.length,
2999
memset(stream_data->data.data + stream_data->data.length, 0, 2 * sizeof(uint8_t));
3001
else if (prop_type == PT_BINARY) {
3002
stream_data->data.length = ((struct Binary_r *) value)->cb;
3003
stream_data->data.data = ((struct Binary_r *) value)->lpb;
3004
(void) talloc_reference(stream_data, stream_data->data.data);
3007
talloc_free(stream_data);
3014
_PUBLIC_ DATA_BLOB emsmdbp_stream_read_buffer(struct emsmdbp_stream *stream, uint32_t length)
3017
uint32_t real_length;
3019
real_length = length;
3020
if (real_length + stream->position > stream->buffer.length) {
3021
real_length = stream->buffer.length - stream->position;
3023
buffer.length = real_length;
3024
buffer.data = stream->buffer.data + stream->position;
3025
stream->position += real_length;
3030
_PUBLIC_ void emsmdbp_stream_write_buffer(TALLOC_CTX *mem_ctx, struct emsmdbp_stream *stream, DATA_BLOB new_buffer)
3032
uint32_t new_position, old_length;
3035
new_position = stream->position + new_buffer.length;
3036
if (new_position >= stream->buffer.length) {
3037
old_length = stream->buffer.length;
3038
stream->buffer.length = new_position;
3039
if (stream->buffer.data) {
3040
old_data = stream->buffer.data;
3041
stream->buffer.data = talloc_realloc(mem_ctx, stream->buffer.data, uint8_t, stream->buffer.length);
3042
if (!stream->buffer.data) {
3043
DEBUG(5, ("WARNING: [bug] lost buffer pointer (data = NULL)\n"));
3044
stream->buffer.data = talloc_array(mem_ctx, uint8_t, stream->buffer.length);
3045
memcpy(stream->buffer.data, old_data, old_length);
3049
stream->buffer.data = talloc_array(mem_ctx, uint8_t, stream->buffer.length);
3053
memcpy(stream->buffer.data + stream->position, new_buffer.data, new_buffer.length);
3054
stream->position = new_position;
3057
_PUBLIC_ struct emsmdbp_stream_data *emsmdbp_object_get_stream_data(struct emsmdbp_object *object, enum MAPITAGS prop_tag)
3059
struct emsmdbp_stream_data *current_data;
3061
for (current_data = object->stream_data; current_data; current_data = current_data->next) {
3062
if (current_data->prop_tag == prop_tag) {
3063
DEBUG(5, ("[%s]: found data for tag %.8x\n", __FUNCTION__, prop_tag));
3064
return current_data;
3072
\details Initialize a synccontext object
3074
\param mem_ctx pointer to the memory context
3075
\param emsmdbp_ctx pointer to the emsmdb provider cotnext
3076
\param whole_store whether the subscription applies to the specified change on the entire store or stricly on the specified folder/message
3077
\param folderID the folder identifier
3078
\param messageID the message identifier
3079
\param parent emsmdbp object of the parent
3081
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_synccontext_init(TALLOC_CTX *mem_ctx,
3082
struct emsmdbp_context *emsmdbp_ctx,
3083
struct emsmdbp_object *parent_object)
3085
struct emsmdbp_object *synccontext_object;
3088
if (!emsmdbp_ctx) return NULL;
3089
if (!parent_object) return NULL;
3090
if (!(parent_object->type == EMSMDBP_OBJECT_FOLDER || parent_object->type == EMSMDBP_OBJECT_MAILBOX)) {
3091
DEBUG(0, (__location__": parent_object must be EMSMDBP_OBJECT_FOLDER or EMSMDBP_OBJECT_MAILBOX (type = %d)\n", parent_object->type));
3095
synccontext_object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent_object);
3096
if (!synccontext_object) return NULL;
3098
synccontext_object->object.synccontext = talloc_zero(synccontext_object, struct emsmdbp_object_synccontext);
3099
if (!synccontext_object->object.synccontext) {
3100
talloc_free(synccontext_object);
3104
synccontext_object->type = EMSMDBP_OBJECT_SYNCCONTEXT;
3106
(void) talloc_reference(synccontext_object->object.synccontext, parent_object);
3107
synccontext_object->object.synccontext->state_property = 0;
3108
synccontext_object->object.synccontext->state_stream.buffer.length = 0;
3109
synccontext_object->object.synccontext->state_stream.buffer.data = talloc_zero(synccontext_object->object.synccontext, uint8_t);
3110
synccontext_object->object.synccontext->stream.buffer.length = 0;
3111
synccontext_object->object.synccontext->stream.buffer.data = NULL;
3113
synccontext_object->object.synccontext->cnset_seen = talloc_zero(emsmdbp_ctx, struct idset);
3114
openchangedb_get_MailboxReplica(emsmdbp_ctx->oc_ctx, emsmdbp_ctx->username, NULL, &synccontext_object->object.synccontext->cnset_seen->repl.guid);
3115
synccontext_object->object.synccontext->cnset_seen->ranges = talloc_zero(synccontext_object->object.synccontext->cnset_seen, struct globset_range);
3116
synccontext_object->object.synccontext->cnset_seen->range_count = 1;
3117
synccontext_object->object.synccontext->cnset_seen->ranges->next = NULL;
3118
synccontext_object->object.synccontext->cnset_seen->ranges->prev = synccontext_object->object.synccontext->cnset_seen->ranges;
3119
synccontext_object->object.synccontext->cnset_seen->ranges->low = 0xffffffffffffffffLL;
3120
synccontext_object->object.synccontext->cnset_seen->ranges->high = 0x0;
3122
/* synccontext_object->object.synccontext->property_tags.cValues = 0; */
3123
/* synccontext_object->object.synccontext->property_tags.aulPropTag = NULL; */
3125
return synccontext_object;
3129
\details Initialize a ftcontext object
3131
\param mem_ctx pointer to the memory context
3132
\param emsmdbp_ctx pointer to the emsmdb provider cotnext
3133
\param whole_store whether the subscription applies to the specified change on the entire store or stricly on the specified folder/message
3134
\param folderID the folder identifier
3135
\param messageID the message identifier
3136
\param parent emsmdbp object of the parent
3138
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_ftcontext_init(TALLOC_CTX *mem_ctx,
3139
struct emsmdbp_context *emsmdbp_ctx,
3140
struct emsmdbp_object *parent)
3142
struct emsmdbp_object *object;
3145
if (!emsmdbp_ctx) return NULL;
3146
if (!parent) return NULL;
3148
object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
3149
if (!object) return NULL;
3151
object->object.ftcontext = talloc_zero(object, struct emsmdbp_object_ftcontext);
3152
if (!object->object.ftcontext) {
3153
talloc_free(object);
3157
object->type = EMSMDBP_OBJECT_FTCONTEXT;