~ubuntu-branches/debian/sid/openchange/sid

« back to all changes in this revision

Viewing changes to mapiproxy/servers/default/emsmdb/emsmdbp_object.c

  • Committer: Package Import Robot
  • Author(s): Jelmer Vernooij
  • Date: 2012-04-12 20:07:57 UTC
  • mfrom: (11 sid)
  • mto: This revision was merged to the branch mainline in revision 12.
  • Revision ID: package-import@ubuntu.com-20120412200757-k933d9trljmxj1l4
Tags: 1:1.0-4
* openchangeserver: Add dependency on openchangeproxy.
* Rebuild against newer version of Samba 4.
* Use dpkg-buildflags.
* Migrate to Git, update Vcs-Git header.
* Switch to debhelper 9.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
   \brief Server-side specific objects init/release routines
26
26
 */
27
27
 
 
28
#include <ctype.h>
 
29
#include <time.h>
 
30
 
28
31
#include "mapiproxy/dcesrv_mapiproxy.h"
29
32
#include "mapiproxy/libmapiproxy/libmapiproxy.h"
 
33
#include "mapiproxy/libmapiserver/libmapiserver.h"
 
34
#include "mapiproxy/libmapistore/mapistore_nameid.h"
 
35
#include "libmapi/property_tags.h"
 
36
#include "libmapi/property_altnames.h"
 
37
 
30
38
#include "dcesrv_exchange_emsmdb.h"
31
39
 
 
40
static const int        max_mins_per_month = 31 * 24 * 60;
 
41
 
32
42
const char *emsmdbp_getstr_type(struct emsmdbp_object *object)
33
43
{
34
44
        switch (object->type) {
44
54
                return "table";
45
55
        case EMSMDBP_OBJECT_STREAM:
46
56
                return "stream";
 
57
        case EMSMDBP_OBJECT_ATTACHMENT:
 
58
                return "attachment";
 
59
        case EMSMDBP_OBJECT_SUBSCRIPTION:
 
60
                return "subscription";
 
61
        case EMSMDBP_OBJECT_SYNCCONTEXT:
 
62
                return "synccontext";
 
63
        case EMSMDBP_OBJECT_FTCONTEXT:
 
64
                return "ftcontext";
47
65
        default:
48
66
                return "unknown";
49
67
        }
50
68
}
51
69
 
52
 
 
53
70
/**
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
56
73
 
57
 
   \param handles pointer to the MAPI handle to lookup
 
74
   \param object pointer to the emsmdp object
58
75
 
59
76
   \return true if parent is using mapistore, otherwise false
60
77
 */
61
 
bool emsmdbp_is_mapistore(struct mapi_handles *handles)
 
78
bool emsmdbp_is_mapistore(struct emsmdbp_object *object)
62
79
{
63
 
        void                    *data;
64
 
        struct emsmdbp_object   *object;
65
 
 
66
80
        /* Sanity checks - probably pointless */
67
 
        if (!handles) {
 
81
        if (!object) {
68
82
                return false;
69
83
        }
70
84
 
71
 
        mapi_handles_get_private_data(handles, &data);
72
 
        object = (struct emsmdbp_object *)data;
73
 
 
74
85
        switch (object->type) {
75
86
        case EMSMDBP_OBJECT_MAILBOX:
76
87
                return false;
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) {
 
90
                        return true;
 
91
                }
85
92
        default:
86
 
                return false;
 
93
                if (object->parent_object) {
 
94
                        return emsmdbp_is_mapistore(object->parent_object);
 
95
                }
87
96
        }
88
97
 
89
98
        return false;
90
99
}
91
100
 
 
101
static struct emsmdbp_object *emsmdbp_get_mailbox(struct emsmdbp_object *object)
 
102
{
 
103
        if (object->type == EMSMDBP_OBJECT_MAILBOX) {
 
104
                return object;
 
105
        }
 
106
 
 
107
        return emsmdbp_get_mailbox(object->parent_object);
 
108
}
92
109
 
93
110
/**
94
111
   \details Convenient function to determine whether specified
95
112
   mapi_handles refers to object within mailbox or public folders
96
113
   store.
97
114
 
98
 
   \param handles pointer to the MAPI handle to lookup
99
 
 
100
 
   \return true if parent is within mailbox store, otherwise false
101
 
 */
102
 
bool emsmdbp_is_mailboxstore(struct mapi_handles *handles)
103
 
{
104
 
        void                    *data;
105
 
        struct emsmdbp_object   *object;
106
 
 
107
 
        /* Sanity checks - irrelevant */
108
 
 
109
 
        mapi_handles_get_private_data(handles, &data);
110
 
        object = (struct emsmdbp_object *)data;
111
 
 
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;
117
 
        default:
118
 
                break;
119
 
        }
120
 
        
121
 
        /* We should never hit this case */
122
 
        return true;
 
115
   \param object pointer to the emsmdp object
 
116
 
 
117
   \return true if parent is within mailbox store, otherwise false
 
118
 */
 
119
bool emsmdbp_is_mailboxstore(struct emsmdbp_object *object)
 
120
{
 
121
        struct emsmdbp_object *mailbox = emsmdbp_get_mailbox(object);
 
122
 
 
123
        return mailbox->object.mailbox->mailboxstore;
 
124
}
 
125
 
 
126
/**
 
127
   \details Convenience function to determine the owner of an object
 
128
 
 
129
   \param object pointer to the emsmdp object
 
130
 
 
131
   \return true if parent is within mailbox store, otherwise false
 
132
 */
 
133
char *emsmdbp_get_owner(struct emsmdbp_object *object)
 
134
{
 
135
        struct emsmdbp_object *mailbox;
 
136
 
 
137
        mailbox = emsmdbp_get_mailbox(object);
 
138
 
 
139
        return mailbox->object.mailbox->owner_username;
123
140
}
124
141
 
125
142
 
126
143
/**
127
144
   \details Return the contextID associated to a handle
128
145
 
129
 
   \param handles pointer to the MAPI handle to lookup
 
146
   \param object pointer to the emsmdp object
130
147
 
131
148
   \return contextID value on success, otherwise -1
132
149
 */
133
 
uint32_t emsmdbp_get_contextID(struct mapi_handles *handles)
 
150
_PUBLIC_ uint32_t emsmdbp_get_contextID(struct emsmdbp_object *object)
134
151
{
135
 
        void                    *data;
136
 
        struct emsmdbp_object   *object;
137
 
 
138
 
        mapi_handles_get_private_data(handles, &data);
139
 
        object = (struct emsmdbp_object *) data;
140
 
 
141
152
        switch (object->type) {
142
153
        case EMSMDBP_OBJECT_MAILBOX:
143
154
                return -1;
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;
 
158
                }
150
159
        default:
151
 
                return -1;
 
160
                if (object->parent_object) {
 
161
                        return emsmdbp_get_contextID(object->parent_object);
 
162
                }
152
163
        }
153
164
 
154
165
        return -1;
155
166
}
156
167
 
 
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)
 
169
{
 
170
        uint64_t        folderID;
 
171
 
 
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;
 
176
 
 
177
        if (parent_folder->type == EMSMDBP_OBJECT_FOLDER) {
 
178
                folderID = parent_folder->object.folder->folderID;
 
179
        }
 
180
        else if (parent_folder->type == EMSMDBP_OBJECT_MAILBOX) {
 
181
                folderID = parent_folder->object.mailbox->folderID;
 
182
        }
 
183
        else {
 
184
                return MAPISTORE_ERROR;
 
185
        }
 
186
 
 
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;
 
190
                }
 
191
 
 
192
                return MAPISTORE_SUCCESS;
 
193
        }
 
194
        else {
 
195
                return openchangedb_get_fid_by_name(emsmdbp_ctx->oc_ctx, folderID, name, fidp);
 
196
        }
 
197
}
 
198
 
 
199
static enum mapistore_context_role emsmdbp_container_class_to_role(const char *container_class)
 
200
{
 
201
        enum mapistore_context_role     i, role = MAPISTORE_FALLBACK_ROLE;
 
202
        static const char               **container_classes = NULL;
 
203
        bool                            found = false;
 
204
 
 
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";
 
209
                }
 
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] = "";
 
216
        }
 
217
 
 
218
        if (container_class) {
 
219
                for (i = 0; !found && i < MAPISTORE_MAX_ROLES; i++) {
 
220
                        if (strcmp(container_class, container_classes[i]) == 0) {
 
221
                                role = i;
 
222
                                found = true;
 
223
                        }
 
224
                }
 
225
        }
 
226
 
 
227
        return role;
 
228
}
 
229
 
 
230
static enum mapistore_error emsmdbp_object_folder_commit_creation(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *new_folder, bool force_container_class)
 
231
{
 
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;
 
237
        TALLOC_CTX                      *mem_ctx;
 
238
        uint64_t                        parent_fid, fid;
 
239
        uint32_t                        context_id;
 
240
 
 
241
        if (!new_folder->object.folder->postponed_props) {
 
242
                return ret;
 
243
        }
 
244
 
 
245
        mem_ctx = talloc_zero(NULL, TALLOC_CTX);
 
246
 
 
247
        value = get_SPropValue_SRow(new_folder->object.folder->postponed_props, PR_CONTAINER_CLASS_UNICODE);
 
248
        if (!value) {
 
249
                /* Sometimes Outlook does pass non-unicode values. */
 
250
                value = get_SPropValue_SRow(new_folder->object.folder->postponed_props, PR_CONTAINER_CLASS);
 
251
        }
 
252
        if (value) {
 
253
                role = emsmdbp_container_class_to_role(value->value.lpszW);
 
254
        }
 
255
        else if (force_container_class) {
 
256
                DEBUG(5, (__location__": forcing folder backend role to 'fallback'\n"));
 
257
                role = MAPISTORE_FALLBACK_ROLE;
 
258
        }
 
259
        else {
 
260
                DEBUG(5, (__location__": container class not set yet\n"));
 
261
                goto end;
 
262
        }
 
263
 
 
264
        value = get_SPropValue_SRow(new_folder->object.folder->postponed_props, PR_DISPLAY_NAME_UNICODE);
 
265
        if (!value) {
 
266
                DEBUG(5, (__location__": display name not set yet\n"));
 
267
                goto end;
 
268
        }
 
269
 
 
270
        fid = new_folder->object.folder->folderID;
 
271
        owner = emsmdbp_get_owner(new_folder);
 
272
 
 
273
        ret = mapistore_create_root_folder(owner, role, fid, value->value.lpszW, mem_ctx, &mapistore_uri);
 
274
        if (ret != MAPISTORE_SUCCESS) {
 
275
                goto end;
 
276
        }
 
277
 
 
278
        ret = mapistore_add_context(emsmdbp_ctx->mstore_ctx, owner, mapistore_uri, fid, &context_id, &new_folder->backend_object);
 
279
        if (ret != MAPISTORE_SUCCESS) {
 
280
                abort();
 
281
        }
 
282
 
 
283
        new_folder->object.folder->contextID = context_id;
 
284
 
 
285
        if (new_folder->parent_object->type == EMSMDBP_OBJECT_MAILBOX) {
 
286
                parent_fid = new_folder->parent_object->object.mailbox->folderID;
 
287
        }
 
288
        else { /* EMSMDBP_OBJECT_FOLDER */
 
289
                parent_fid = new_folder->parent_object->object.folder->folderID;
 
290
        }
 
291
 
 
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));
 
297
                abort();
 
298
        }
 
299
 
 
300
        mapistore_indexing_record_add_fid(emsmdbp_ctx->mstore_ctx, context_id, owner, fid);
 
301
        new_folder->object.folder->contextID = context_id;
 
302
 
 
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);
 
305
 
 
306
        talloc_unlink(new_folder, new_folder->object.folder->postponed_props);
 
307
        new_folder->object.folder->postponed_props = NULL;
 
308
 
 
309
        DEBUG(5, ("new mapistore context created at uri: %s\n", mapistore_uri));
 
310
 
 
311
end:
 
312
        talloc_free(mem_ctx);
 
313
 
 
314
        return ret;
 
315
}
 
316
 
 
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)
 
318
{
 
319
        uint64_t                        parentFolderID, testFolderID;
 
320
        struct SPropValue               *value;
 
321
        int                             retval;
 
322
        struct emsmdbp_object           *new_folder;
 
323
        struct SRow                     *postponed_props;
 
324
 
 
325
        /* Sanity checks */
 
326
        if (!emsmdbp_ctx) return MAPISTORE_ERROR;
 
327
        if (!parent_folder) return MAPISTORE_ERROR;
 
328
        if (!rowp) return MAPISTORE_ERROR;
 
329
 
 
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;
 
339
                        }
 
340
                        else if (retval == MAPISTORE_ERR_DENIED) {
 
341
                                DEBUG(5, (__location__": folder creation denied\n"));
 
342
                                return MAPI_E_NO_ACCESS;
 
343
                        }
 
344
                        else {
 
345
                                return MAPI_E_NOT_FOUND;
 
346
                        }
 
347
                }
 
348
        }
 
349
        else {
 
350
                parentFolderID = parent_folder->object.folder->folderID;
 
351
                value = get_SPropValue_SRow(rowp, PR_DISPLAY_NAME_UNICODE);
 
352
                if (!value) {
 
353
                        value = get_SPropValue_SRow(rowp, PR_DISPLAY_NAME);
 
354
                }
 
355
                if (!value) {
 
356
                        talloc_free(new_folder);
 
357
                        return MAPI_E_INVALID_PARAMETER;
 
358
                }
 
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;
 
365
                }
 
366
 
 
367
                value = get_SPropValue_SRow(rowp, PidTagChangeNumber);
 
368
                if (value) {
 
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;
 
375
 
 
376
                        emsmdbp_object_folder_commit_creation(emsmdbp_ctx, new_folder, false);
 
377
                }
 
378
                else {
 
379
                        DEBUG(0, (__location__": PidTagChangeNumber *must* be present\n"));
 
380
                        abort();
 
381
                }
 
382
        }
 
383
        *new_folderp = new_folder;
 
384
 
 
385
        return MAPI_E_SUCCESS;
 
386
}
 
387
 
 
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)
 
389
{
 
390
        struct emsmdbp_object                   *folder_object, *mailbox_object;
 
391
        enum mapistore_error                    retval;
 
392
        enum MAPISTATUS                         ret;
 
393
        char                                    *path;
 
394
        char                                    *owner;
 
395
        uint32_t                                contextID;
 
396
        uint64_t                                parent_fid, oc_parent_fid;
 
397
        void                                    *local_ctx;
 
398
 
 
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);
 
405
                        return retval;
 
406
                }
 
407
        }
 
408
        else {
 
409
                local_ctx = talloc_zero(NULL, void);
 
410
        
 
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__));
 
416
 
 
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);
 
420
                        } else {
 
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);
 
426
                                        return retval;
 
427
                                }
 
428
                                mapistore_indexing_record_add_fid(emsmdbp_ctx->mstore_ctx, contextID, owner, fid);
 
429
                        }
 
430
                        folder_object->object.folder->contextID = contextID;
 
431
                        /* (void) talloc_reference(folder_object, folder_object->backend_object); */
 
432
                }
 
433
                else {
 
434
                        switch (parent->type) {
 
435
                        case EMSMDBP_OBJECT_MAILBOX:
 
436
                                parent_fid = parent->object.mailbox->folderID;
 
437
                                break;
 
438
                        case EMSMDBP_OBJECT_FOLDER:
 
439
                                parent_fid = parent->object.folder->folderID;
 
440
                                break;
 
441
                        default:
 
442
                                DEBUG(5, ("you should never get here\n"));
 
443
                                abort();
 
444
                        }
 
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;
 
452
                        }
 
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;
 
458
                        }
 
459
                        DEBUG(0, ("%s: opening openchangedb folder\n", __FUNCTION__));
 
460
                }
 
461
                talloc_free(local_ctx);
 
462
        }
 
463
 
 
464
        *folder_object_p = folder_object;
 
465
 
 
466
        return MAPISTORE_SUCCESS;
 
467
}
 
468
 
 
469
_PUBLIC_ int emsmdbp_get_uri_from_fid(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, uint64_t fid, char **urip)
 
470
{
 
471
        enum MAPISTATUS retval;
 
472
        bool            soft_deleted;
 
473
 
 
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;
 
477
        }
 
478
        return mapistore_indexing_record_get_uri(emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->username, mem_ctx, fid, urip, &soft_deleted);
 
479
}
 
480
 
 
481
_PUBLIC_ int emsmdbp_get_fid_from_uri(struct emsmdbp_context *emsmdbp_ctx, const char *uri, uint64_t *fidp)
 
482
{
 
483
        int     ret;
 
484
        bool    soft_deleted;
 
485
 
 
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);
 
489
        }
 
490
 
 
491
        return ret;
 
492
}
 
493
 
 
494
static char *emsmdbp_compute_parent_uri(TALLOC_CTX *mem_ctx, char *uri)
 
495
{
 
496
        char *parent_uri, *slash, *lastchar;
 
497
        int len;
 
498
 
 
499
        if (!uri) return NULL;
 
500
 
 
501
        parent_uri = talloc_strdup(mem_ctx, uri);
 
502
        len = strlen(parent_uri);
 
503
        lastchar = parent_uri + len - 1;
 
504
        if (*lastchar == '/') {
 
505
                *lastchar = 0;
 
506
        }
 
507
        slash = strrchr(parent_uri, '/');
 
508
        if (slash) {
 
509
                *(slash + 1) = 0;
 
510
        }
 
511
        else {
 
512
                talloc_free(parent_uri);
 
513
                parent_uri = NULL;
 
514
        }
 
515
 
 
516
        return parent_uri;
 
517
}
 
518
 
 
519
static int emsmdbp_get_parent_fid(struct emsmdbp_context *emsmdbp_ctx, uint64_t fid, uint64_t *parent_fidp)
 
520
{
 
521
        TALLOC_CTX      *mem_ctx;
 
522
        int             retval = MAPISTORE_SUCCESS;
 
523
        bool            soft_deleted;
 
524
        char            *uri, *parent_uri;
 
525
 
 
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) {
 
529
                goto end;
 
530
        }
 
531
        retval = openchangedb_get_parent_fid(emsmdbp_ctx->oc_ctx, fid, parent_fidp, false);
 
532
        if (retval == MAPISTORE_SUCCESS) {
 
533
                goto end;
 
534
        }
 
535
 
 
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);
 
539
                if (parent_uri) {
 
540
                        retval = emsmdbp_get_fid_from_uri(emsmdbp_ctx, parent_uri, parent_fidp);
 
541
                }
 
542
                else {
 
543
                        retval = MAPISTORE_ERR_NOT_FOUND;
 
544
                }
 
545
        }
 
546
 
 
547
end:
 
548
        talloc_free(mem_ctx);
 
549
 
 
550
        return retval;
 
551
}
157
552
 
158
553
/**
159
 
   \details Retrieve the folder handle matching given fid
160
 
 
161
 
   \param handles_ctx pointer to the handles context
162
 
   \param fid folder identifier to lookup
163
 
 
164
 
   \return pointer to valid mapi_handles structure on success, otherwise NULL
 
554
   \details Return the folder object associated to specified folder identified
 
555
 
 
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
 
560
 
 
561
   \return Valid emsmdbp object structure on success, otherwise NULL
165
562
 */
166
 
struct mapi_handles *emsmdbp_object_get_folder_handle_by_fid(struct mapi_handles_context *handles_ctx,
167
 
                                                             uint64_t fid)
 
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)
168
564
{
169
 
        struct mapi_handles     *handle;
170
 
        struct emsmdbp_object   *object;
171
 
        void                    *data;
 
565
        uint64_t                parent_fid;
 
566
        int                     retval;
 
567
        struct emsmdbp_object   *parent_object;
 
568
        
 
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;
 
575
        }
 
576
        else {
 
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;
 
581
                }
 
582
        }
172
583
 
173
 
        for (handle = handles_ctx->handles; handle; handle = handle->next) {
174
 
                mapi_handles_get_private_data(handle, &data);
175
 
                if (data) {
176
 
                        object = (struct emsmdbp_object *) data;
177
 
                        if (object->type == EMSMDBP_OBJECT_FOLDER && object->object.folder->folderID == fid) {
178
 
                                return handle;
 
584
        retval = emsmdbp_get_parent_fid(emsmdbp_ctx, fid, &parent_fid);
 
585
        if (retval == MAPISTORE_SUCCESS) {
 
586
                if (parent_fid) {
 
587
                        retval = emsmdbp_object_open_folder_by_fid(mem_ctx, emsmdbp_ctx, context_object, parent_fid, &parent_object);
 
588
                        if (retval != MAPISTORE_SUCCESS) {
 
589
                                return retval;
179
590
                        }
180
 
                }
181
 
        }
182
 
 
183
 
        return NULL;
 
591
                        return emsmdbp_object_open_folder(mem_ctx, emsmdbp_ctx, parent_object, fid, folder_object_p);
 
592
                }
 
593
                else {
 
594
                        *folder_object_p = emsmdbp_object_folder_init(mem_ctx, emsmdbp_ctx, fid, NULL);
 
595
                        return MAPISTORE_SUCCESS;
 
596
                }
 
597
        }
 
598
 
 
599
        return MAPISTORE_ERROR;
 
600
}
 
601
 
 
602
_PUBLIC_ int emsmdbp_object_stream_commit(struct emsmdbp_object *stream_object)
 
603
{
 
604
        int                             rc;
 
605
        struct emsmdbp_object_stream    *stream;
 
606
        void                            *stream_data;
 
607
        uint8_t                         *utf8_buffer;
 
608
        struct Binary_r                 *binary_data;
 
609
        struct SRow                     aRow;
 
610
        size_t                          converted_size;
 
611
        uint16_t                        propType;
 
612
 
 
613
        if (!stream_object || stream_object->type != EMSMDBP_OBJECT_STREAM) return MAPISTORE_ERROR;
 
614
 
 
615
        stream = stream_object->object.stream;
 
616
 
 
617
        rc = MAPISTORE_SUCCESS;
 
618
        if (stream->needs_commit) {
 
619
                stream->needs_commit = false;
 
620
                aRow.cValues = 1;
 
621
                aRow.lpProps = talloc_zero(NULL, struct SPropValue);
 
622
 
 
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;
 
629
                }
 
630
                else if (propType == PT_STRING8) {
 
631
                        stream_data = stream->stream.buffer.data;
 
632
                }
 
633
                else {
 
634
                        /* PT_UNICODE */
 
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;
 
641
                }
 
642
                set_SPropValue_proptag(aRow.lpProps, stream->property, stream_data);
 
643
 
 
644
                emsmdbp_object_set_properties(stream_object->emsmdbp_ctx, stream_object->parent_object, &aRow);
 
645
                talloc_free(aRow.lpProps);
 
646
        }
 
647
 
 
648
        return rc;
184
649
}
185
650
 
186
651
/**
193
658
static int emsmdbp_object_destructor(void *data)
194
659
{
195
660
        struct emsmdbp_object   *object = (struct emsmdbp_object *) data;
196
 
        int                     ret;
 
661
        int                     ret = MAPISTORE_SUCCESS;
 
662
        uint32_t                contextID;
197
663
 
198
664
        if (!data) return -1;
199
 
        
 
665
        if (!emsmdbp_is_mapistore(object)) goto nomapistore;
 
666
 
200
667
        DEBUG(4, ("[%s:%d]: emsmdbp %s object released\n", __FUNCTION__, __LINE__,
201
668
                  emsmdbp_getstr_type(object)));
202
669
 
 
670
        contextID = emsmdbp_get_contextID(object);
203
671
        switch (object->type) {
204
672
        case EMSMDBP_OBJECT_FOLDER:
205
 
                ret = mapistore_del_context(object->mstore_ctx, object->object.folder->contextID);
 
673
                if (object->object.folder->mapistore_root) {
 
674
                        ret = mapistore_del_context(object->emsmdbp_ctx->mstore_ctx, contextID);
 
675
                }
206
676
                DEBUG(4, ("[%s:%d] mapistore folder context retval = %d\n", __FUNCTION__, __LINE__, ret));
207
677
                break;
 
678
        case EMSMDBP_OBJECT_TABLE:
 
679
                if (emsmdbp_is_mapistore(object) && object->backend_object && object->object.table->handle > 0) {
 
680
                        mapistore_table_handle_destructor(object->emsmdbp_ctx->mstore_ctx, emsmdbp_get_contextID(object), object->backend_object, object->object.table->handle);
 
681
                }
 
682
                if (object->object.table->subscription_list) {
 
683
                        DLIST_REMOVE(object->emsmdbp_ctx->mstore_ctx->subscriptions, object->object.table->subscription_list);
 
684
                        talloc_free(object->object.table->subscription_list);
 
685
                        /* talloc_unlink(object->emsmdbp_ctx, object->object.table->subscription_list); */
 
686
                }
 
687
                break;
 
688
        case EMSMDBP_OBJECT_STREAM:
 
689
                emsmdbp_object_stream_commit(object);
 
690
                break;
 
691
        case EMSMDBP_OBJECT_SUBSCRIPTION:
 
692
                if (object->object.subscription->subscription_list) {
 
693
                        DLIST_REMOVE(object->emsmdbp_ctx->mstore_ctx->subscriptions, object->object.subscription->subscription_list);
 
694
                        talloc_free(object->object.subscription->subscription_list);
 
695
                }
 
696
                break;
 
697
        case EMSMDBP_OBJECT_UNDEF:
 
698
        case EMSMDBP_OBJECT_MAILBOX:
208
699
        case EMSMDBP_OBJECT_MESSAGE:
209
 
                ret = mapistore_release_record(object->mstore_ctx, object->object.message->contextID,
210
 
                                               object->object.message->messageID, MAPISTORE_MESSAGE);
211
 
                ret = mapistore_del_context(object->mstore_ctx, object->object.message->contextID);
212
 
                DEBUG(4, ("[%s:%d] mapistore message context retval = %d\n", __FUNCTION__, __LINE__, ret));
213
 
        default:
 
700
        case EMSMDBP_OBJECT_ATTACHMENT:
 
701
        case EMSMDBP_OBJECT_FTCONTEXT:
 
702
        case EMSMDBP_OBJECT_SYNCCONTEXT:
214
703
                break;
215
704
        }
216
 
 
217
 
        talloc_free(object);
 
705
        
 
706
nomapistore:
 
707
        talloc_unlink(object, object->parent_object);
218
708
 
219
709
        return 0;
220
710
}
227
717
 
228
718
   \return Allocated emsmdbp object on success, otherwise NULL
229
719
 */
230
 
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_init(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx)
 
720
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_init(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *parent_object)
231
721
{
232
722
        struct emsmdbp_object   *object = NULL;
233
723
 
237
727
        talloc_set_destructor((void *)object, (int (*)(void *))emsmdbp_object_destructor);
238
728
 
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);
 
738
 
 
739
        object->stream_data = NULL;
246
740
 
247
741
        return object;
248
742
}
249
743
 
 
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)
 
745
{
 
746
        TALLOC_CTX              *mem_ctx;
 
747
        bool                    *properties_exclusion;
 
748
        struct SPropTagArray    *properties, *needed_properties;
 
749
        void                    **data_pointers;
 
750
        enum MAPISTATUS         *retvals = NULL;
 
751
        struct SRow             *aRow;
 
752
        struct SPropValue       newValue;
 
753
        uint32_t                i;
 
754
 
 
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;
 
760
        }
 
761
 
 
762
        /* 1. Exclusions */
 
763
        properties_exclusion = talloc_array(mem_ctx, bool, 65536);
 
764
        memset(properties_exclusion, 0, 65536 * sizeof(bool));
 
765
 
 
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;
 
776
 
 
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;
 
781
                }
 
782
        }
 
783
 
 
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]);
 
789
                }
 
790
        }
 
791
 
 
792
        data_pointers = emsmdbp_object_get_properties(mem_ctx, emsmdbp_ctx, source_object, needed_properties, &retvals);
 
793
        if (data_pointers) {
 
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);
 
800
                        }
 
801
                }
 
802
                if (emsmdbp_object_set_properties(emsmdbp_ctx, dest_object, aRow) != MAPISTORE_SUCCESS) {
 
803
                        talloc_free(mem_ctx);
 
804
                        return MAPI_E_NO_SUPPORT;
 
805
                }
 
806
        }
 
807
        else {
 
808
                talloc_free(mem_ctx);
 
809
                return MAPI_E_NO_SUPPORT;
 
810
        }
 
811
 
 
812
        talloc_free(mem_ctx);
 
813
 
 
814
        return MAPI_E_SUCCESS;
 
815
}
 
816
 
 
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 */
 
821
};
 
822
 
 
823
static inline void emsmdbp_fill_prop_index(struct emsmdbp_prop_index *prop_index, struct SPropTagArray *properties)
 
824
{
 
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;
 
829
        }
 
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;
 
833
        }
 
834
}
 
835
 
 
836
static inline int emsmdbp_copy_message_recipients_mapistore(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *source_object, struct emsmdbp_object *dest_object)
 
837
{
 
838
        TALLOC_CTX                      *mem_ctx;
 
839
        struct mapistore_message        *msg_data;
 
840
        uint32_t                        contextID, i;
 
841
        struct emsmdbp_prop_index       prop_index;
 
842
        struct SPropTagArray            *new_columns;
 
843
        void                            **new_data;
 
844
 
 
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;
 
848
        }
 
849
 
 
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);
 
854
 
 
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);
 
859
 
 
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;
 
866
 
 
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];
 
872
                        }
 
873
                        else {
 
874
                                new_data[0] = NULL;
 
875
                        }
 
876
                        if (prop_index.email_address != (uint32_t) -1) {
 
877
                                new_data[1] = msg_data->recipients[i].data[prop_index.email_address];
 
878
                        }
 
879
                        else {
 
880
                                new_data[1] = NULL;
 
881
                        }
 
882
                        msg_data->recipients[i].data = new_data;
 
883
                }
 
884
                msg_data->columns = new_columns;
 
885
 
 
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);
 
888
        }
 
889
 
 
890
        talloc_free(mem_ctx);
 
891
 
 
892
        return MAPI_E_SUCCESS;
 
893
}
 
894
 
 
895
static inline int emsmdbp_copy_message_attachments_mapistore(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *source_object, struct emsmdbp_object *dest_object)
 
896
{
 
897
        TALLOC_CTX              *mem_ctx;
 
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;
 
904
        int                     ret;
 
905
 
 
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;
 
909
        }
 
910
 
 
911
        mem_ctx = talloc_zero(NULL, TALLOC_CTX);
 
912
 
 
913
        /* we fetch the attachment nums */
 
914
        table_object = emsmdbp_object_message_open_attachment_table(mem_ctx, emsmdbp_ctx, source_object);
 
915
        if (!table_object) {
 
916
                talloc_free(mem_ctx);
 
917
                return MAPI_E_NOT_FOUND;
 
918
        }
 
919
 
 
920
        column = PR_ATTACH_NUM;
 
921
        table_object->object.table->prop_count = 1;
 
922
        table_object->object.table->properties = &column;
 
923
 
 
924
        contextID = emsmdbp_get_contextID(table_object);
 
925
        mapistore_table_set_columns(emsmdbp_ctx->mstore_ctx, contextID, table_object->backend_object, 1, &column);
 
926
 
 
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;
 
934
                }
 
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;
 
939
                }
 
940
                attach_nums[i] = *(uint32_t *) data_pointers[0];
 
941
        }
 
942
 
 
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);
 
946
                if (!source_attach
 
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;
 
950
                }
 
951
 
 
952
                dest_attach = emsmdbp_object_attachment_init(mem_ctx, emsmdbp_ctx, dest_object->object.message->messageID, dest_object);
 
953
                if (!dest_attach
 
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;
 
957
                }
 
958
 
 
959
                ret = emsmdbp_copy_properties(emsmdbp_ctx, source_attach, dest_attach, NULL);
 
960
                if (ret != MAPI_E_SUCCESS) {
 
961
                        talloc_free(mem_ctx);
 
962
                        return ret;
 
963
                }
 
964
        }
 
965
 
 
966
        talloc_free(mem_ctx);
 
967
 
 
968
        return MAPI_E_SUCCESS;
 
969
}
 
970
 
 
971
/**
 
972
   \details Copy properties from an object to another object
 
973
 
 
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
 
979
 
 
980
   \return Allocated emsmdbp object on success, otherwise NULL
 
981
 */
 
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)
 
983
{
 
984
        int ret;
 
985
 
 
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;
 
992
                goto end;
 
993
        }
 
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;
 
997
                goto end;
 
998
        }
 
999
 
 
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) {
 
1003
                goto end;
 
1004
        }
 
1005
 
 
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) {
 
1012
                                goto end;
 
1013
                        }
 
1014
                        if (deep_copy) {
 
1015
                                ret = emsmdbp_copy_message_attachments_mapistore(emsmdbp_ctx, source_object, target_object);
 
1016
                                if (ret != MAPI_E_SUCCESS) {
 
1017
                                        goto end;
 
1018
                                }
 
1019
                        }
 
1020
                }
 
1021
                else {
 
1022
                        DEBUG(0, ("Cannot copy recipients or attachments to or from non-mapistore messages\n"));
 
1023
                }
 
1024
                break;
 
1025
        default:
 
1026
                if (deep_copy) {
 
1027
                        DEBUG(0, ("Cannot deep copy non-message objects\n"));
 
1028
                }
 
1029
        }
 
1030
 
 
1031
end:
 
1032
 
 
1033
        return ret;
 
1034
}
250
1035
 
251
1036
/**
252
1037
   \details Initialize a mailbox object
261
1046
 */
262
1047
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_mailbox_init(TALLOC_CTX *mem_ctx,
263
1048
                                                            struct emsmdbp_context *emsmdbp_ctx,
264
 
                                                            struct EcDoRpc_MAPI_REQ *request,
 
1049
                                                            const char *essDN,
265
1050
                                                            bool mailboxstore)
266
1051
{
267
1052
        struct emsmdbp_object           *object;
268
 
        const char                      *displayName;
 
1053
        const char                      *displayName, *cn;
269
1054
        const char * const              recipient_attrs[] = { "*", NULL };
270
1055
        int                             ret;
271
1056
        struct ldb_result               *res = NULL;
272
1057
 
273
1058
        /* Sanity checks */
274
1059
        if (!emsmdbp_ctx) return NULL;
275
 
        if (!request) return NULL;
 
1060
        if (!essDN) return NULL;
276
1061
 
277
 
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx);
 
1062
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, NULL);
278
1063
        if (!object) return NULL;
279
1064
 
280
1065
        /* Initialize the mailbox object */
292
1077
        object->object.mailbox->mailboxstore = mailboxstore;
293
1078
 
294
1079
        if (mailboxstore == true) {
295
 
                object->object.mailbox->owner_EssDN = talloc_strdup(object->object.mailbox, 
296
 
                                                                    request->u.mapi_Logon.EssDN);
 
1080
                object->object.mailbox->owner_EssDN = talloc_strdup(object->object.mailbox, essDN);
297
1081
                ret = ldb_search(emsmdbp_ctx->samdb_ctx, mem_ctx, &res,
298
1082
                                 ldb_get_default_basedn(emsmdbp_ctx->samdb_ctx),
299
1083
                                 LDB_SCOPE_SUBTREE, recipient_attrs, "legacyExchangeDN=%s", 
300
1084
                                 object->object.mailbox->owner_EssDN);
 
1085
                if (!ret && res->count == 1) {
 
1086
                        cn = ldb_msg_find_attr_as_string(res->msgs[0], "cn", NULL);
 
1087
                        if (cn) {
 
1088
                                object->object.mailbox->owner_username = talloc_strdup(object->object.mailbox,  cn);
301
1089
 
302
 
                if (res->count == 1) {
 
1090
                                /* Retrieve Mailbox folder identifier */
 
1091
                                openchangedb_get_SystemFolderID(emsmdbp_ctx->oc_ctx, object->object.mailbox->owner_username,
 
1092
                                                                0x1, &object->object.mailbox->folderID);
 
1093
                        }
303
1094
                        displayName = ldb_msg_find_attr_as_string(res->msgs[0], "displayName", NULL);
304
1095
                        if (displayName) {
305
1096
                                object->object.mailbox->owner_Name = talloc_strdup(object->object.mailbox, 
306
1097
                                                                                   displayName);
307
 
 
308
 
                                /* Retrieve Mailbox folder identifier */
309
 
                                openchangedb_get_SystemFolderID(emsmdbp_ctx->oc_ctx, 
310
 
                                                                object->object.mailbox->owner_Name,
311
 
                                                                0x1, &object->object.mailbox->folderID);
312
1098
                        }
313
1099
                }
314
1100
        } else {
315
1101
                /* Retrieve Public folder identifier */
316
 
                openchangedb_get_PublicFolderID(emsmdbp_ctx->oc_ctx, 0x1, &object->object.mailbox->folderID);
 
1102
                openchangedb_get_PublicFolderID(emsmdbp_ctx->oc_ctx, EMSMDBP_PF_ROOT, &object->object.mailbox->folderID);
317
1103
        }
318
1104
 
319
1105
        object->object.mailbox->szUserDN = talloc_strdup(object->object.mailbox, emsmdbp_ctx->szUserDN);
330
1116
   \param mem_ctx pointer to the memory context
331
1117
   \param emsmdbp_ctx pointer to the emsmdb provider context
332
1118
   \param folderID the folder identifier
333
 
   \param parent handle to the parent folder for this folder
 
1119
   \param parent emsmdbp object of the parent folder for this folder
334
1120
 
335
1121
   \return Allocated emsmdbp object on success, otherwise NULL
336
1122
 */
337
1123
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_folder_init(TALLOC_CTX *mem_ctx,
338
1124
                                                           struct emsmdbp_context *emsmdbp_ctx,
339
1125
                                                           uint64_t folderID,
340
 
                                                           struct mapi_handles *parent)
 
1126
                                                           struct emsmdbp_object *parent_object)
341
1127
{
342
 
        enum MAPISTATUS                 retval;
343
 
        struct emsmdbp_object           *object;
344
 
        char                            *mapistore_uri = NULL;
345
 
        uint32_t                        context_id;
346
 
        int                             ret;
 
1128
        struct emsmdbp_object                   *object;
347
1129
 
348
1130
        /* Sanity checks */
349
1131
        if (!emsmdbp_ctx) return NULL;
350
1132
 
351
 
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx);
 
1133
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent_object);
352
1134
        if (!object) return NULL;
353
1135
 
354
1136
        object->object.folder = talloc_zero(object, struct emsmdbp_object_folder);
358
1140
        }
359
1141
 
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);
365
 
 
366
 
        /* system folders acting as containers don't have
367
 
         * mapistore_uri attributes (Mailbox, IPM Subtree) 
368
 
         */
369
 
        retval = openchangedb_get_mapistoreURI(mem_ctx, emsmdbp_ctx->oc_ctx,
370
 
                                               object->object.folder->folderID, 
371
 
                                               &mapistore_uri, object->object.folder->mailboxstore);
372
 
 
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;
377
 
                } else {
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, 
382
 
                                                              &context_id);
 
1145
        object->object.folder->contextID = (uint32_t) -1;
 
1146
 
 
1147
        return object;
 
1148
}
 
1149
 
 
1150
int emsmdbp_folder_get_folder_count(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *folder, uint32_t *row_countp)
 
1151
{
 
1152
        int             retval;
 
1153
        uint64_t        folderID;
 
1154
 
 
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);
 
1158
        }
 
1159
        else {
 
1160
                if (folder->type == EMSMDBP_OBJECT_FOLDER) {
 
1161
                        folderID = folder->object.folder->folderID;
 
1162
                }
 
1163
                else if (folder->type == EMSMDBP_OBJECT_MAILBOX) {
 
1164
                        folderID = folder->object.folder->folderID;
 
1165
                }
 
1166
                else {
 
1167
                        DEBUG(5, ("unsupported object type\n"));
 
1168
                        return MAPISTORE_ERROR;
 
1169
                }
 
1170
                printf("emsmdbp_folder_get_folder_count: folderID = %"PRIu64"\n", folderID);
 
1171
                retval = openchangedb_get_folder_count(emsmdbp_ctx->oc_ctx, folderID, row_countp);
 
1172
        }
 
1173
 
 
1174
        return retval;
 
1175
}
 
1176
 
 
1177
_PUBLIC_ enum mapistore_error emsmdbp_folder_delete(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *parent_folder, uint64_t fid, uint8_t flags)
 
1178
{
 
1179
        enum mapistore_error    ret;
 
1180
        enum MAPISTATUS         mapiret;
 
1181
        TALLOC_CTX              *mem_ctx;
 
1182
        bool                    mailboxstore;
 
1183
        uint32_t                context_id;
 
1184
        void                    *subfolder;
 
1185
        char                    *mapistoreURL;
 
1186
 
 
1187
        mem_ctx = talloc_zero(NULL, TALLOC_CTX);
 
1188
 
 
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);
 
1194
 
 
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) {
 
1197
                        goto end;
 
1198
                }
 
1199
 
 
1200
                ret = mapistore_folder_delete(emsmdbp_ctx->mstore_ctx, context_id, subfolder, flags);
 
1201
                if (ret != MAPISTORE_SUCCESS) {
 
1202
                        goto end;
 
1203
                }
 
1204
        }
 
1205
        else {
 
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;
 
1209
                        goto end;
 
1210
                }
 
1211
 
 
1212
                mapiret = openchangedb_delete_folder(emsmdbp_ctx->oc_ctx, fid);
 
1213
                if (mapiret != MAPI_E_SUCCESS) {
 
1214
                        ret = MAPISTORE_ERR_NOT_FOUND;
 
1215
                        goto end;
 
1216
                }
 
1217
 
 
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);
385
1222
                        } else {
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) {
392
 
                                        talloc_free(object);
393
 
                                        return NULL;
394
 
                                }
395
 
                                ret = mapistore_add_context_indexing(emsmdbp_ctx->mstore_ctx, 
396
 
                                                                     emsmdbp_ctx->username,
397
 
                                                                     context_id);
398
 
                                ret = mapistore_indexing_record_add_fid(emsmdbp_ctx->mstore_ctx,
399
 
                                                                        context_id, folderID);
400
 
                        }
401
 
                        object->object.folder->contextID = context_id;
402
 
                }
403
 
        } else {
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);
409
 
                } else {
410
 
                        object->object.folder->mapistore = false;
411
 
                }
412
 
        }
413
 
 
414
 
        return object;
415
 
}
416
 
 
 
1225
                                        goto end;
 
1226
                                }
 
1227
                        }
 
1228
 
 
1229
                        ret = mapistore_folder_delete(emsmdbp_ctx->mstore_ctx, context_id, subfolder, flags);
 
1230
                        if (ret != MAPISTORE_SUCCESS) {
 
1231
                                goto end;
 
1232
                        }
 
1233
 
 
1234
                         mapistore_del_context(emsmdbp_ctx->mstore_ctx, context_id);
 
1235
                }
 
1236
        }
 
1237
 
 
1238
        ret = MAPISTORE_SUCCESS;
 
1239
 
 
1240
end:
 
1241
        talloc_free(mem_ctx);
 
1242
 
 
1243
        return ret;
 
1244
}
 
1245
 
 
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)
 
1249
{
 
1250
        struct emsmdbp_object   *table_object;
 
1251
        uint64_t                folderID;
 
1252
        uint8_t                 mstore_type;
 
1253
        int                     ret;
 
1254
 
 
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));
 
1257
                return NULL;
 
1258
        }
 
1259
 
 
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);
 
1262
        }
 
1263
 
 
1264
        table_object = emsmdbp_object_table_init(mem_ctx, parent_object->emsmdbp_ctx, parent_object);
 
1265
        if (table_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;
 
1272
                                break;
 
1273
                        case MAPISTORE_FAI_TABLE:
 
1274
                                mstore_type = MAPISTORE_FAI_TABLE;
 
1275
                                break;
 
1276
                        case MAPISTORE_FOLDER_TABLE:
 
1277
                                mstore_type = MAPISTORE_FOLDER_TABLE;
 
1278
                                break;
 
1279
                        case MAPISTORE_PERMISSIONS_TABLE:
 
1280
                                mstore_type = MAPISTORE_PERMISSIONS_TABLE;
 
1281
                                break;
 
1282
                        default:
 
1283
                                DEBUG(5, ("Unhandled table type for folders: %d\n", table_type));
 
1284
                                abort();
 
1285
                        }
 
1286
 
 
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;
 
1291
                        }
 
1292
                }
 
1293
                else {
 
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);
 
1297
                        }
 
1298
                        else {
 
1299
                                /* Retrieve folder ID */
 
1300
                                switch (parent_object->type) {
 
1301
                                case EMSMDBP_OBJECT_FOLDER:
 
1302
                                        folderID = parent_object->object.folder->folderID;
 
1303
                                        break;
 
1304
                                case EMSMDBP_OBJECT_MAILBOX:
 
1305
                                        folderID = parent_object->object.mailbox->folderID;
 
1306
                                        break;
 
1307
                                default:
 
1308
                                        DEBUG(5, ("Unsupported object type"));
 
1309
                                        table_object->object.table->denominator = 0;
 
1310
                                        return table_object;
 
1311
                                }
 
1312
 
 
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, 
 
1317
                                                                       folderID, 
 
1318
                                                                       &table_object->object.table->denominator,
 
1319
                                                                       false);
 
1320
                                        break;
 
1321
                                case MAPISTORE_FAI_TABLE:
 
1322
                                        openchangedb_get_message_count(parent_object->emsmdbp_ctx->oc_ctx, 
 
1323
                                                                       folderID, 
 
1324
                                                                       &table_object->object.table->denominator,
 
1325
                                                                       true);
 
1326
                                        break;
 
1327
                                default:
 
1328
                                        DEBUG(0, ("Unhandled openchangedb table type for folders: %d\n", table_type));
 
1329
                                        table_object->object.table->denominator = 0;
 
1330
                                        abort();
 
1331
                                }
 
1332
                        }
 
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;
 
1338
                                        break;
 
1339
                                case EMSMDBP_OBJECT_MAILBOX:
 
1340
                                        folderID = parent_object->object.mailbox->folderID;
 
1341
                                        break;
 
1342
                                default:
 
1343
                                        DEBUG(5, ("Unsupported object type"));
 
1344
                                        table_object->object.table->denominator = 0;
 
1345
                                        return table_object;
 
1346
                                }
 
1347
                                DEBUG(0, ("Initializaing openchangedb table\n"));
 
1348
                                openchangedb_table_init((TALLOC_CTX *)table_object, table_type, folderID, &table_object->backend_object);
 
1349
                        }
 
1350
                }
 
1351
        }
 
1352
 
 
1353
        return table_object;    
 
1354
}
417
1355
 
418
1356
/**
419
1357
   \details Initialize a table object
420
1358
 
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
424
1362
 
425
1363
   \return Allocated emsmdbp object on success, otherwise NULL
426
1364
 */
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)
430
1368
{
431
 
        enum MAPISTATUS         retval;
432
1369
        struct emsmdbp_object   *object;
433
 
        struct emsmdbp_object   *folder;
434
 
        void                    *data = NULL;
435
 
        bool                    mapistore = false;
436
 
        int                     ret;
437
1370
 
438
1371
        /* Sanity checks */
439
1372
        if (!emsmdbp_ctx) return NULL;
440
 
 
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;
445
1375
 
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;
449
1379
        
450
1380
        object->object.table = talloc_zero(object, struct emsmdbp_object_table);
454
1384
        }
455
1385
 
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;
465
 
 
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);
472
 
        }
 
1392
        object->object.table->restricted = false;
 
1393
        object->object.table->subscription_list = NULL;
473
1394
 
474
1395
        return object;
475
1396
}
476
1397
 
 
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)
 
1399
{
 
1400
        int                             retval;
 
1401
        struct SPropTagArray            *properties;
 
1402
        uint32_t                        contextID;
 
1403
 
 
1404
        if (!table_object->type == EMSMDBP_OBJECT_TABLE) {
 
1405
                return MAPISTORE_ERROR;
 
1406
        }
 
1407
 
 
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);
 
1411
        }
 
1412
        else {
 
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;
 
1461
 
 
1462
                retval = MAPISTORE_SUCCESS;
 
1463
        }
 
1464
 
 
1465
        return retval;
 
1466
}
 
1467
 
 
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)
 
1469
{
 
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;
 
1478
        uint64_t                        *rowFMId;
 
1479
        uint64_t                        parentFolderId;
 
1480
        bool                            mapistore_folder;
 
1481
        uint8_t                         *has_subobj;
 
1482
        void                            *odb_ctx;
 
1483
        char                            *owner;
 
1484
        struct Binary_r                 *binr;
 
1485
 
 
1486
        table = table_object->object.table;
 
1487
        num_props = table_object->object.table->prop_count;
 
1488
 
 
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);
 
1493
 
 
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;
 
1502
                                        
 
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;
 
1508
                                        else {
 
1509
                                                retvals[i] = MAPI_E_NO_SUPPORT;
 
1510
                                                DEBUG (4, ("%s: unknown mapistore error: %.8x\n", __PRETTY_FUNCTION__, properties[i].error));
 
1511
                                        }
 
1512
                                }
 
1513
                                else {
 
1514
                                        if (properties[i].data == NULL) {
 
1515
                                                retvals[i] = MAPI_E_NOT_FOUND;
 
1516
                                        }
 
1517
                                }
 
1518
                        }
 
1519
                }
 
1520
                else {
 
1521
                        DEBUG(5, ("%s: invalid object (likely due to a restriction)\n", __location__));
 
1522
                        talloc_free(retvals);
 
1523
                        talloc_free(data_pointers);
 
1524
                        return NULL;
 
1525
                }
 
1526
        } else {
 
1527
                if (table_object->parent_object->type == EMSMDBP_OBJECT_FOLDER) {
 
1528
                        parentFolderId = table_object->parent_object->object.folder->folderID;
 
1529
                }
 
1530
                else if (table_object->parent_object->type == EMSMDBP_OBJECT_MAILBOX) {
 
1531
                        parentFolderId = table_object->parent_object->object.mailbox->folderID;
 
1532
                }
 
1533
                else {
 
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);
 
1537
                        return NULL;
 
1538
                }
 
1539
 
 
1540
                odb_ctx = talloc_zero(NULL, void);
 
1541
 
 
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); */
 
1546
                /*      break; */
 
1547
                /* case MAPISTORE_FOLDER_TABLE: */
 
1548
                /*      table_filter = talloc_asprintf(odb_ctx, "(&(PidTagParentFolderId=%"PRIu64")(PidTagFolderId=*))", folderID); */
 
1549
                /*      break; */
 
1550
                /* default: */
 
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); */
 
1555
                /*      return NULL; */
 
1556
                /* } */
 
1557
 
 
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);
 
1562
                        break;
 
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);
 
1565
                        break;
 
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);
 
1569
                           break; */
 
1570
                default:
 
1571
                        DEBUG(5, ("table type %d not supported for non-mapistore table\n", table_object->object.table->ulType));
 
1572
                        retval = MAPI_E_INVALID_OBJECT;
 
1573
                }
 
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);
 
1579
                        return NULL;
 
1580
                }
 
1581
 
 
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);
 
1587
                        break;
 
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;
 
1591
                        break;
 
1592
                default:
 
1593
                        DEBUG(5, ("you should never get here\n"));
 
1594
                        abort();
 
1595
                }
 
1596
                if (ret != MAPISTORE_SUCCESS) {
 
1597
                        talloc_free(retvals);
 
1598
                        talloc_free(data_pointers);
 
1599
                        talloc_free(odb_ctx);
 
1600
                        return NULL;
 
1601
                }
 
1602
 
 
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;
 
1614
                                        break;
 
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;
 
1620
                                        break;
 
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;
 
1625
                                        break;
 
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;
 
1630
                                        break;
 
1631
                                case PR_SUBFOLDERS:
 
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);
 
1638
                                        break;
 
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;
 
1645
                                        break;
 
1646
                                default:
 
1647
                                        retval = openchangedb_table_get_property(data_pointers, table_object->backend_object, 
 
1648
                                                                                 emsmdbp_ctx->oc_ctx,
 
1649
                                                                                 table->properties[i], 
 
1650
                                                                                 row_id,
 
1651
                                                                                 (query_type == MAPISTORE_LIVEFILTERED_QUERY),
 
1652
                                                                                 data_pointers + i);
 
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); */
 
1657
                                }
 
1658
                        }
 
1659
                        else {
 
1660
                                retval = openchangedb_table_get_property(data_pointers, table_object->backend_object, 
 
1661
                                                                         emsmdbp_ctx->oc_ctx,
 
1662
                                                                         table->properties[i], 
 
1663
                                                                         row_id,
 
1664
                                                                         (query_type == MAPISTORE_LIVEFILTERED_QUERY),
 
1665
                                                                         data_pointers + i);
 
1666
                        }
 
1667
 
 
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);
 
1674
                                return NULL;
 
1675
                        }
 
1676
                        else {
 
1677
                                retvals[i] = retval;
 
1678
                        }
 
1679
                }
 
1680
 
 
1681
                talloc_free(odb_ctx);
 
1682
        }
 
1683
 
 
1684
        if (retvalsp) {
 
1685
                *retvalsp = retvals;
 
1686
        }
 
1687
 
 
1688
        return data_pointers;
 
1689
}
 
1690
 
 
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)
 
1695
{
 
1696
        uint16_t i;
 
1697
        uint8_t flagged;
 
1698
        enum MAPITAGS property;
 
1699
        void *data;
 
1700
        uint32_t retval;
 
1701
 
 
1702
        flagged = 0;
 
1703
 
 
1704
        for (i = 0; !flagged && i < num_props; i++) {
 
1705
                if (retvals[i] != MAPI_E_SUCCESS) {
 
1706
                        flagged = 1;
 
1707
                }
 
1708
        }
 
1709
 
 
1710
        if (flagged) {
 
1711
                libmapiserver_push_property(mem_ctx,
 
1712
                                            0x0000000b, (const void *)&flagged,
 
1713
                                            table_row, 0, 0, 0);
 
1714
        }
 
1715
        else {
 
1716
                libmapiserver_push_property(mem_ctx,
 
1717
                                            0x00000000, (const void *)&flagged,
 
1718
                                            table_row, 0, 1, 0);
 
1719
        }
 
1720
 
 
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;
 
1726
                        data = &retval;
 
1727
                }
 
1728
                else {
 
1729
                        data = data_pointers[i];
 
1730
                }
 
1731
 
 
1732
                libmapiserver_push_property(mem_ctx,
 
1733
                                            property, data, table_row,
 
1734
                                            flagged?PT_ERROR:0, flagged, 0);
 
1735
        }
 
1736
}
477
1737
 
478
1738
/**
479
1739
   \details Initialize a message object
481
1741
   \param mem_ctx pointer to the memory context
482
1742
   \param emsmdbp_ctx pointer to the emsmdb provider context
483
1743
   \param messageID the message identifier
484
 
   \param parent pointer to the parent MAPI handle
 
1744
   \param parent emsmdbp object of the parent
485
1745
 
486
1746
   \return Allocated emsmdbp object on success, otherwise NULL
487
1747
 */
488
1748
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_message_init(TALLOC_CTX *mem_ctx,
489
1749
                                                            struct emsmdbp_context *emsmdbp_ctx,
490
1750
                                                            uint64_t messageID,
491
 
                                                            struct mapi_handles *parent)
 
1751
                                                            struct emsmdbp_object *parent)
492
1752
{
493
 
        enum MAPISTATUS         retval;
494
1753
        struct emsmdbp_object   *object;
495
 
        struct emsmdbp_object   *folder;
496
 
        void                    *data = NULL;
497
 
        bool                    mapistore = false;
498
 
        int                     ret;
499
1754
 
500
1755
        /* Sanity checks */
501
1756
        if (!emsmdbp_ctx) return NULL;
502
 
 
503
 
        /* Retrieve parent object */
504
 
        retval = mapi_handles_get_private_data(parent, &data);
505
 
        if (retval) return NULL;
506
 
        folder = (struct emsmdbp_object *) data;
 
1757
        if (!parent) return NULL;
 
1758
        if (parent->type != EMSMDBP_OBJECT_FOLDER && parent->type != EMSMDBP_OBJECT_MAILBOX) {
 
1759
                DEBUG(5, ("expecting EMSMDBP_OBJECT_FOLDER/_MAILBOX as type of parent object\n"));
 
1760
                return NULL;
 
1761
        }
507
1762
 
508
1763
        /* Initialize message object */
509
 
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx);
 
1764
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
510
1765
        if (!object) return NULL;
511
1766
 
512
1767
        object->object.message = talloc_zero(object, struct emsmdbp_object_message);
516
1771
        }
517
1772
 
518
1773
        object->type = EMSMDBP_OBJECT_MESSAGE;
519
 
        object->object.message->folderID = folder->object.folder->folderID;
520
1774
        object->object.message->messageID = messageID;
521
 
 
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);
528
 
        } 
529
 
 
530
 
        return object;  
531
 
}
532
 
 
 
1775
        object->object.message->read_write = false;
 
1776
 
 
1777
        return object;
 
1778
}
 
1779
 
 
1780
static int emsmdbp_days_in_month(int month, int year)
 
1781
{
 
1782
        static int      max_mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
1783
        int             dec_year, days;
 
1784
 
 
1785
        if (month == 1) {
 
1786
                dec_year = year % 100;
 
1787
                if ((dec_year == 0
 
1788
                     && ((((year + 1900) / 100) % 4) == 0))
 
1789
                    || (dec_year % 4) == 0) {
 
1790
                        days = 29;
 
1791
                }
 
1792
                else {
 
1793
                        days = max_mdays[month];
 
1794
                }
 
1795
        }
 
1796
        else {
 
1797
                days = max_mdays[month];
 
1798
        }
 
1799
 
 
1800
        return days;
 
1801
}
 
1802
 
 
1803
static int emsmdbp_mins_in_ymon(uint32_t ymon)
 
1804
{
 
1805
        return emsmdbp_days_in_month((ymon & 0xf) - 1, ymon >> 4) * 24 * 60;
 
1806
}
 
1807
 
 
1808
static inline void emsmdbp_freebusy_make_range(struct tm *start_time, struct tm *end_time)
 
1809
{
 
1810
        time_t                                                  now;
 
1811
        struct tm                                               time_data;
 
1812
        int                                                     mw_delta, month;
 
1813
 
 
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.
 
1817
 
 
1818
           Since PidTagFreeBusyCountMonths is not supported yet, we use a count of 3 months
 
1819
        */
 
1820
 
 
1821
        now = time(NULL);
 
1822
        time_data = *gmtime(&now);
 
1823
        time_data.tm_hour = 0;
 
1824
        time_data.tm_min = 0;
 
1825
        time_data.tm_sec = 0;
 
1826
 
 
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);
 
1831
                if (mw_delta > 0) {
 
1832
                        if (time_data.tm_mon > 0) {
 
1833
                                time_data.tm_mon--;
 
1834
                        }
 
1835
                        else {
 
1836
                                time_data.tm_mon = 11;
 
1837
                                time_data.tm_year--;
 
1838
                        }
 
1839
                        time_data.tm_mday = emsmdbp_days_in_month(time_data.tm_mon, time_data.tm_year) + 1 - mw_delta;
 
1840
                }
 
1841
                else {
 
1842
                        time_data.tm_mday = 1;
 
1843
                }
 
1844
        }
 
1845
        else {
 
1846
                mw_delta = 0;
 
1847
                time_data.tm_mday = 1;
 
1848
        }
 
1849
 
 
1850
        *start_time = time_data;
 
1851
 
 
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;
 
1856
        }
 
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;
 
1861
 
 
1862
        *end_time = time_data;
 
1863
}
 
1864
 
 
1865
static void emsmdbp_freebusy_convert_filetime(struct FILETIME *ft_value, uint32_t *ymon, uint32_t *mins)
 
1866
{
 
1867
        NTTIME          nt_time;
 
1868
        time_t          u_time;
 
1869
        struct tm       *gm_time;
 
1870
 
 
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);
 
1874
 
 
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;
 
1877
}
 
1878
 
 
1879
static uint16_t emsmdbp_freebusy_find_month_range(uint32_t ymon, uint32_t *months_ranges, uint16_t nbr_months, bool *overflow)
 
1880
{
 
1881
        uint16_t        range;
 
1882
 
 
1883
        if (nbr_months > 0) {
 
1884
                if (months_ranges[0] > ymon) {
 
1885
                        *overflow = true;
 
1886
                        return 0;
 
1887
                }
 
1888
                else {
 
1889
                        if (months_ranges[nbr_months - 1] < ymon) {
 
1890
                                *overflow = true;
 
1891
                                return (nbr_months - 1);
 
1892
                        }
 
1893
                        else {
 
1894
                                *overflow = false;
 
1895
                                for (range = 0; range < nbr_months; range++) {
 
1896
                                        if (months_ranges[range] == ymon) {
 
1897
                                                return range;
 
1898
                                        }
 
1899
                                }
 
1900
                        }
 
1901
                }
 
1902
        }
 
1903
 
 
1904
        return (uint16_t) -1;
 
1905
}
 
1906
 
 
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)
 
1909
{
 
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;
 
1913
 
 
1914
        emsmdbp_freebusy_convert_filetime(start, &start_ymon, &start_mins);
 
1915
        emsmdbp_freebusy_convert_filetime(end, &end_ymon, &end_mins);
 
1916
 
 
1917
        start_mr_idx = emsmdbp_freebusy_find_month_range(start_ymon, months_ranges, nbr_months, &start_range_overflow);
 
1918
        if (start_range_overflow) {
 
1919
                start_mins = 0;
 
1920
        }
 
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);
 
1924
        }
 
1925
 
 
1926
        /* head */
 
1927
        if (end_mr_idx > start_mr_idx) {
 
1928
                /* end occurs after start range */
 
1929
 
 
1930
                /* middle */
 
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]));
 
1933
                }
 
1934
 
 
1935
                /* tail */
 
1936
                memset(minutes_array[end_mr_idx], 1, end_mins);
 
1937
 
 
1938
                max = emsmdbp_mins_in_ymon(start_ymon); /* = max chunk for first range */
 
1939
        }
 
1940
        else {
 
1941
                /* end occurs on same range as start */
 
1942
 
 
1943
                max = end_mins;
 
1944
        }
 
1945
        memset(minutes_array[start_mr_idx] + start_mins, 1, (max - start_mins));
 
1946
}
 
1947
 
 
1948
static void emsmdbp_freebusy_compile_fbarray(TALLOC_CTX *mem_ctx, uint8_t *minutes_array, struct Binary_r *fb_bin)
 
1949
{
 
1950
        int                     i;
 
1951
        bool                    filled;
 
1952
        struct ndr_push         *ndr;
 
1953
        TALLOC_CTX              *local_mem_ctx;
 
1954
 
 
1955
        local_mem_ctx = talloc_zero(NULL, TALLOC_CTX);
 
1956
 
 
1957
        ndr = ndr_push_init_ctx(local_mem_ctx);
 
1958
 
 
1959
        filled = (minutes_array[0] != 0);
 
1960
        if (filled) {
 
1961
                ndr_push_uint16(ndr, NDR_SCALARS, 0);
 
1962
        }
 
1963
 
 
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));
 
1967
                        filled = false;
 
1968
                }
 
1969
                else if (!filled && minutes_array[i]) {
 
1970
                        ndr_push_uint16(ndr, NDR_SCALARS, i);
 
1971
                        filled = true;
 
1972
                }
 
1973
        }
 
1974
        if (filled) {
 
1975
                ndr_push_uint16(ndr, NDR_SCALARS, (max_mins_per_month - 1));
 
1976
        }
 
1977
 
 
1978
        fb_bin->cb = ndr->offset;
 
1979
        fb_bin->lpb = ndr->data;
 
1980
        (void) talloc_reference(mem_ctx, fb_bin->lpb);
 
1981
 
 
1982
        talloc_free(local_mem_ctx);
 
1983
}
 
1984
 
 
1985
static void emsmdbp_freebusy_merge_subarray(uint8_t *minutes_array, uint8_t *included_array)
 
1986
{
 
1987
        int i;
 
1988
 
 
1989
        for (i = 0; i < max_mins_per_month; i++) {
 
1990
                if (included_array[i]) {
 
1991
                        minutes_array[i] = 1;
 
1992
                }
 
1993
        }
 
1994
}
 
1995
 
 
1996
static void emsmdbp_object_message_fill_freebusy_properties(struct emsmdbp_object *message_object)
 
1997
{
 
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 */
 
2011
 
 
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;
 
2020
        uint32_t                                                contextID;
 
2021
        struct mapi_SRestriction                                and_res;
 
2022
        uint8_t                                                 state;
 
2023
        struct tm                                               start_tm, end_tm;
 
2024
        time_t                                                  start_time, end_time;
 
2025
        NTTIME                                                  nt_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;
 
2029
        char                                                    *tz;
 
2030
 
 
2031
        mem_ctx = talloc_zero(NULL, TALLOC_CTX);
 
2032
 
 
2033
        /* 1. retrieve subject and deduce username */
 
2034
        props = talloc_zero(mem_ctx, struct SPropTagArray);
 
2035
        props->cValues = 1;
 
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) {
 
2040
                goto end;
 
2041
        }
 
2042
        subject = data_pointers[0];
 
2043
        // format is "..../CN="
 
2044
        username = strrchr(subject, '/');
 
2045
        if (!username) {
 
2046
                goto end;
 
2047
        }
 
2048
        username += 4;
 
2049
        username = talloc_strdup(mem_ctx, username);
 
2050
 
 
2051
        fb_props = talloc_zero(message_object, struct emsmdbp_object_message_freebusy_properties);
 
2052
        message_object->object.message->fb_properties = fb_props;
 
2053
 
 
2054
        // WARNING: the mechanism here will fail if username is not all lower-case, as LDB does not support case-insensitive queries
 
2055
        tmp = username;
 
2056
        while (*tmp) {
 
2057
                *tmp = tolower(*tmp);
 
2058
                tmp++;
 
2059
        }
 
2060
        email = talloc_asprintf(mem_ctx, "/o=First Organization/ou=First Administrative Group/cn=Recipients/cn=%s", username);
 
2061
        fb_props->email_address = email;
 
2062
 
 
2063
        /* open user mailbox */
 
2064
        mailbox = emsmdbp_object_mailbox_init(mem_ctx, message_object->emsmdbp_ctx, email, true);
 
2065
        if (!mailbox) {
 
2066
                goto end;
 
2067
        }
 
2068
 
 
2069
        /* open Inbox */
 
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) {
 
2072
                goto end;
 
2073
        }
 
2074
 
 
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) {
 
2079
                goto end;
 
2080
        }
 
2081
        calendarFID = 0;
 
2082
        for (i = 0; i < 6; i++) {
 
2083
                calendarFID <<= 8;
 
2084
                calendarFID |= *(((struct Binary_r *) data_pointers[0])->lpb + (43 - i));
 
2085
        }
 
2086
        calendarFID <<= 16;
 
2087
        calendarFID |= 1;
 
2088
 
 
2089
        /* open user calendar */
 
2090
        if (emsmdbp_object_open_folder_by_fid(mem_ctx, message_object->emsmdbp_ctx, mailbox, calendarFID, &calendar) != MAPISTORE_SUCCESS) {
 
2091
                goto end;
 
2092
        }
 
2093
        if (!emsmdbp_is_mapistore(calendar)) {
 
2094
                DEBUG(5, ("non-mapistore calendars are not supported for freebusy\n"));
 
2095
                goto end;
 
2096
        }
 
2097
 
 
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);
 
2100
        if (!table) {
 
2101
                goto end;
 
2102
        }
 
2103
        contextID = emsmdbp_get_contextID(calendar);
 
2104
 
 
2105
        /* fetch freebusy range */
 
2106
        emsmdbp_freebusy_make_range(&start_tm, &end_tm);
 
2107
 
 
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;
 
2111
 
 
2112
        tz = getenv("TZ");
 
2113
        setenv("TZ", "", 1);
 
2114
        tzset();
 
2115
        start_time = mktime(&start_tm);
 
2116
        end_time = mktime(&end_tm);
 
2117
        if (tz) {
 
2118
                setenv("TZ", tz, 1);
 
2119
        }
 
2120
        else {
 
2121
                unsetenv("TZ");
 
2122
        }
 
2123
        tzset();
 
2124
 
 
2125
        /* setup restriction */
 
2126
        and_res.rt = RES_AND;
 
2127
        and_res.res.resAnd.cRes = 2;
 
2128
        and_res.res.resAnd.res = time_restrictions;
 
2129
 
 
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));
 
2138
 
 
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));
 
2147
 
 
2148
        mapistore_table_set_restrictions(message_object->emsmdbp_ctx->mstore_ctx, contextID, table->backend_object, &and_res, &state);
 
2149
 
 
2150
        /* setup table columns */
 
2151
        props->cValues = 3;
 
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;
 
2159
 
 
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);
 
2163
        }
 
2164
        else {
 
2165
                nbr_months = (12 - start_tm.tm_mon) + end_tm.tm_mon + 1;
 
2166
        }
 
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);
 
2171
                }
 
2172
        }
 
2173
        else {
 
2174
                month = start_tm.tm_mon;
 
2175
                i = 0;
 
2176
                while (month < 12) {
 
2177
                        fb_props->months_ranges[i] = ((start_tm.tm_year + 1900) << 4) + month + 1;
 
2178
                        i++;
 
2179
                        month++;
 
2180
                }
 
2181
                month = 0;
 
2182
                while (month < end_tm.tm_mon) {
 
2183
                        fb_props->months_ranges[i] = ((end_tm.tm_year + 1900) << 4) + month + 1;
 
2184
                        i++;
 
2185
                        month++;
 
2186
                }
 
2187
                fb_props->months_ranges[i] = ((end_tm.tm_year + 1900) << 4) + month + 1;
 
2188
        }
 
2189
 
 
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);
 
2201
        }
 
2202
 
 
2203
        i = 0;
 
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])) {
 
2207
                        case olTentative:
 
2208
                                minutes_array = tentative_array;
 
2209
                                break;
 
2210
                        case olBusy:
 
2211
                                minutes_array = busy_array;
 
2212
                                break;
 
2213
                        case olOutOfOffice:
 
2214
                                minutes_array = oof_array;
 
2215
                                break;
 
2216
                        default:
 
2217
                                minutes_array = NULL;
 
2218
                        }
 
2219
                        if (minutes_array) {
 
2220
                                emsmdbp_freebusy_fill_fbarray(minutes_array, fb_props->months_ranges, nbr_months, data_pointers[0], data_pointers[1]);
 
2221
                        }
 
2222
                }
 
2223
                i++;
 
2224
        }
 
2225
 
 
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);
 
2238
        }
 
2239
 
 
2240
end:
 
2241
        talloc_free(mem_ctx);
 
2242
 
 
2243
        return;
 
2244
}
 
2245
 
 
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)
 
2247
{
 
2248
        struct emsmdbp_object *folder_object, *message_object = NULL;
 
2249
        uint32_t contextID;
 
2250
        bool mapistore;
 
2251
        TALLOC_CTX *local_mem_ctx;
 
2252
        enum mapistore_error ret = MAPISTORE_SUCCESS;
 
2253
 
 
2254
        if (!messageP) return MAPISTORE_ERROR;
 
2255
        if (!parent_object) return MAPISTORE_ERROR;
 
2256
 
 
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)  {
 
2260
                goto end;
 
2261
        }
 
2262
 
 
2263
        mapistore = emsmdbp_is_mapistore(folder_object);
 
2264
        switch (mapistore) {
 
2265
        case false:
 
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);
 
2272
                        goto end;
 
2273
                }
 
2274
 
 
2275
                emsmdbp_object_message_fill_freebusy_properties(message_object);
 
2276
                break;
 
2277
        case true:
 
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;
 
2285
                        }
 
2286
                }
 
2287
                if (ret != MAPISTORE_SUCCESS) {
 
2288
                        talloc_free(message_object);
 
2289
                }
 
2290
        }
 
2291
 
 
2292
end:
 
2293
        talloc_free(local_mem_ctx);
 
2294
 
 
2295
        if (ret == MAPISTORE_SUCCESS) {
 
2296
                message_object->object.message->read_write = read_write;
 
2297
                *messageP = message_object;
 
2298
        }
 
2299
 
 
2300
        return ret;
 
2301
}
 
2302
 
 
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)
 
2304
{
 
2305
        struct emsmdbp_object   *table_object;
 
2306
        uint32_t                contextID;
 
2307
 
 
2308
        /* Sanity checks */
 
2309
        if (!emsmdbp_ctx) return NULL;
 
2310
        if (!message_object || message_object->type != EMSMDBP_OBJECT_MESSAGE) return NULL;
 
2311
 
 
2312
        switch (emsmdbp_is_mapistore(message_object)) {
 
2313
        case false:
 
2314
                /* system/special folder */
 
2315
                DEBUG(0, ("[%s] not implemented yet - shouldn't occur\n", __location__));
 
2316
                table_object = NULL;
 
2317
                break;
 
2318
        case true:
 
2319
                contextID = emsmdbp_get_contextID(message_object);
 
2320
 
 
2321
                table_object = emsmdbp_object_table_init(mem_ctx, emsmdbp_ctx, message_object);
 
2322
                if (table_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);
 
2328
                }
 
2329
        }
 
2330
 
 
2331
        return table_object;
 
2332
}
533
2333
 
534
2334
/**
535
2335
   \details Initialize a stream object
537
2337
   \param mem_ctx pointer to the memory context
538
2338
   \param emsmdbp_ctx pointer to the emsmdb provider cotnext
539
2339
   \param property the stream property identifier
540
 
   \param parent pointer to the parent MAPI handle
 
2340
   \param parent emsmdbp object of the parent
541
2341
 */
542
2342
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_stream_init(TALLOC_CTX *mem_ctx,
543
2343
                                                           struct emsmdbp_context *emsmdbp_ctx,
544
 
                                                           uint32_t property,
545
 
                                                           struct mapi_handles *parent)
 
2344
                                                           struct emsmdbp_object *parent)
546
2345
{
547
 
        enum MAPISTATUS         retval;
548
2346
        struct emsmdbp_object   *object;
549
 
        void                    *data;
550
 
        bool                    mapistore = false;
551
2347
 
552
2348
        /* Sanity checks */
553
2349
        if (!emsmdbp_ctx) return NULL;
 
2350
        if (!parent) return NULL;
554
2351
 
555
 
        /* Retrieve parent object */
556
 
        retval = mapi_handles_get_private_data(parent, &data);
557
 
        if (retval) return NULL;
558
 
        
559
 
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx);
 
2352
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
560
2353
        if (!object) return NULL;
561
2354
 
562
2355
        object->object.stream = talloc_zero(object, struct emsmdbp_object_stream);
566
2359
        }
567
2360
 
568
2361
        object->type = EMSMDBP_OBJECT_STREAM;
569
 
        object->object.stream->property = property;
570
 
 
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);
575
 
        }
 
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;
 
2367
 
 
2368
        return object;
 
2369
}
 
2370
 
 
2371
 
 
2372
/**
 
2373
   \details Initialize a attachment object
 
2374
 
 
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 
 
2380
 */
 
2381
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_attachment_init(TALLOC_CTX *mem_ctx,
 
2382
                                                               struct emsmdbp_context *emsmdbp_ctx,
 
2383
                                                               uint64_t messageID,
 
2384
                                                               struct emsmdbp_object *parent)
 
2385
{
 
2386
        struct emsmdbp_object   *object;
 
2387
 
 
2388
        /* Sanity checks */
 
2389
        if (!emsmdbp_ctx) return NULL;
 
2390
        if (!parent) return NULL;
 
2391
 
 
2392
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
 
2393
        if (!object) return NULL;
 
2394
 
 
2395
        object->object.attachment = talloc_zero(object, struct emsmdbp_object_attachment);
 
2396
        if (!object->object.attachment) {
 
2397
                talloc_free(object);
 
2398
                return NULL;
 
2399
        }
 
2400
 
 
2401
        object->type = EMSMDBP_OBJECT_ATTACHMENT;
 
2402
        object->object.attachment->attachmentID = -1;
 
2403
 
 
2404
        return object;
 
2405
}
 
2406
 
 
2407
/**
 
2408
   \details Initialize a notification subscription object
 
2409
 
 
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
 
2416
 */
 
2417
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_subscription_init(TALLOC_CTX *mem_ctx,
 
2418
                                                                 struct emsmdbp_context *emsmdbp_ctx,
 
2419
                                                                 struct emsmdbp_object *parent)
 
2420
{
 
2421
        struct emsmdbp_object   *object;
 
2422
 
 
2423
        /* Sanity checks */
 
2424
        if (!emsmdbp_ctx) return NULL;
 
2425
        if (!parent) return NULL;
 
2426
 
 
2427
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
 
2428
        if (!object) return NULL;
 
2429
 
 
2430
        object->object.subscription = talloc_zero(object, struct emsmdbp_object_subscription);
 
2431
        if (!object->object.subscription) {
 
2432
                talloc_free(object);
 
2433
                return NULL;
 
2434
        }
 
2435
 
 
2436
        object->type = EMSMDBP_OBJECT_SUBSCRIPTION;
 
2437
        object->object.subscription->subscription_list = NULL;
 
2438
 
 
2439
        return object;
 
2440
}
 
2441
 
 
2442
_PUBLIC_ int emsmdbp_object_get_available_properties(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *object, struct SPropTagArray **propertiesp)
 
2443
{
 
2444
        uint32_t contextID;
 
2445
 
 
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;
 
2452
        }
 
2453
        
 
2454
        if (!emsmdbp_is_mapistore(object)) {
 
2455
                DEBUG(5, (__location__": only mapistore is supported at this time\n"));
 
2456
                return MAPISTORE_ERROR;
 
2457
        }
 
2458
 
 
2459
        contextID = emsmdbp_get_contextID(object);
 
2460
 
 
2461
        return mapistore_properties_get_available_properties(emsmdbp_ctx->mstore_ctx, contextID, object->backend_object, mem_ctx, propertiesp);
 
2462
}
 
2463
 
 
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)
 
2465
{
 
2466
        enum MAPISTATUS                 retval = MAPI_E_SUCCESS;
 
2467
        struct emsmdbp_object_folder    *folder;
 
2468
        char                            *owner;
 
2469
        int                             i;
 
2470
        uint32_t                        *obj_count;
 
2471
        uint8_t                         *has_subobj;
 
2472
        struct Binary_r                 *binr;
 
2473
        time_t                          unix_time;
 
2474
        NTTIME                          nt_time;
 
2475
        struct FILETIME                 *ft;
 
2476
 
 
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;
 
2483
                }
 
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);
 
2491
                }
 
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;
 
2497
                }
 
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);
 
2503
                        *obj_count = 0;
 
2504
                        data_pointers[i] = obj_count;
 
2505
                        retval = MAPI_E_SUCCESS;
 
2506
                }
 
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;
 
2516
                }
 
2517
                else {
 
2518
                        retval = openchangedb_get_folder_property(data_pointers, emsmdbp_ctx->oc_ctx, properties->aulPropTag[i], folder->folderID, data_pointers + i);
 
2519
                }
 
2520
                retvals[i] = retval;
 
2521
        }
 
2522
 
 
2523
        return MAPISTORE_SUCCESS;
 
2524
}
 
2525
 
 
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)
 
2529
{
 
2530
        enum MAPISTATUS                                         retval;
 
2531
        int                                                     i;
 
2532
        char                                                    *owner;
 
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;
 
2537
 
 
2538
        fb_props = object->object.message->fb_properties;
 
2539
 
 
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,
 
2545
                                                     &binr);
 
2546
                        data_pointers[i] = binr;
 
2547
                        retval = MAPI_E_SUCCESS;
 
2548
                } else {
 
2549
                        if (fb_props) {
 
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;
 
2560
                                        break;
 
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;
 
2567
                                        break;
 
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;
 
2574
                                        break;
 
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;
 
2581
                                        break;
 
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;
 
2588
                                        break;
 
2589
                                case PR_FREEBUSY_PUBLISH_START:
 
2590
                                        data_pointers[i] = &fb_props->publish_start;
 
2591
                                        retval = MAPI_E_SUCCESS;
 
2592
                                        break;
 
2593
                                case PR_FREEBUSY_PUBLISH_END:
 
2594
                                        data_pointers[i] = &fb_props->publish_end;
 
2595
                                        retval = MAPI_E_SUCCESS;
 
2596
                                        break;
 
2597
                                case PidTagFreeBusyMessageEmailAddress:
 
2598
                                        data_pointers[i] = fb_props->email_address;
 
2599
                                        retval = MAPI_E_SUCCESS;
 
2600
                                        break;
 
2601
                                case PR_FREEBUSY_RANGE_TIMESTAMP:
 
2602
                                        data_pointers[i] = &fb_props->timestamp;
 
2603
                                        retval = MAPI_E_SUCCESS;
 
2604
                                        break;
 
2605
                                default:
 
2606
                                        retval = openchangedb_message_get_property(data_pointers, object->backend_object, properties->aulPropTag[i], data_pointers + i);
 
2607
                                }
 
2608
                        }
 
2609
                        else {
 
2610
                                retval = openchangedb_message_get_property(data_pointers, object->backend_object, properties->aulPropTag[i], data_pointers + i);
 
2611
                        }
 
2612
                }
 
2613
                retvals[i] = retval;
 
2614
        }
 
2615
 
 
2616
        return MAPI_E_SUCCESS;
 
2617
}
 
2618
 
 
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)
 
2620
{
 
2621
        enum MAPISTATUS                 retval = MAPI_E_SUCCESS;
 
2622
        struct emsmdbp_object_folder    *folder;
 
2623
        char                            *owner;
 
2624
        struct Binary_r                 *binr;
 
2625
        int                             i;
 
2626
        uint32_t                        contextID;
 
2627
        uint32_t                        *obj_count;
 
2628
        uint8_t                         *has_subobj;
 
2629
        /* time_t                               unix_time; */
 
2630
        /* NTTIME                               nt_time; */
 
2631
        /* struct FILETIME                      *ft; */
 
2632
 
 
2633
        contextID = emsmdbp_get_contextID(object);
 
2634
 
 
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);
 
2641
                        if (!retval) {
 
2642
                                data_pointers[i] = obj_count;
 
2643
                        }
 
2644
                }
 
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);
 
2648
                        if (!retval) {
 
2649
                                data_pointers[i] = obj_count;
 
2650
                        }
 
2651
                }
 
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);
 
2655
                        if (!retval) {
 
2656
                                data_pointers[i] = obj_count;
 
2657
                        }
 
2658
                }
 
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);
 
2662
                        if (!retval) {
 
2663
                                has_subobj = talloc_zero(data_pointers, uint8_t);
 
2664
                                *has_subobj = (*obj_count > 0) ? 1 : 0;
 
2665
                                data_pointers[i] = has_subobj;
 
2666
                        }
 
2667
                        talloc_free(obj_count);
 
2668
                }
 
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;
 
2674
                }
 
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;
 
2680
                }
 
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);
 
2684
                        *obj_count = 0;
 
2685
                        data_pointers[i] = obj_count;
 
2686
                        retval = MAPI_E_SUCCESS;
 
2687
                }
 
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;
 
2690
 
 
2691
                        mapistore_properties_get_properties(emsmdbp_ctx->mstore_ctx, contextID,
 
2692
                                                            object->backend_object,
 
2693
                                                            data_pointers,
 
2694
                                                            1,
 
2695
                                                            properties->aulPropTag + i,
 
2696
                                                            &prop_data);
 
2697
                        data_pointers[i] = prop_data.data;
 
2698
                        retval = prop_data.error;
 
2699
                }
 
2700
                else {
 
2701
                        retval = openchangedb_get_folder_property(data_pointers, emsmdbp_ctx->oc_ctx, properties->aulPropTag[i], folder->folderID, data_pointers + i);
 
2702
                }
 
2703
                retvals[i] = retval;
 
2704
        }
 
2705
 
 
2706
        return MAPISTORE_SUCCESS;
 
2707
}
 
2708
 
 
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)
 
2710
{
 
2711
        uint32_t                        i;
 
2712
        struct SBinary_short            *bin;
 
2713
 
 
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;
 
2719
                        break;
 
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;
 
2724
                        break;
 
2725
                case PR_MAILBOX_OWNER_ENTRYID:
 
2726
                        if (object->object.mailbox->mailboxstore == false) {
 
2727
                                retvals[i] = MAPI_E_NO_ACCESS;
 
2728
                        } else {
 
2729
                                bin = talloc_zero(data_pointers, struct SBinary_short);
 
2730
                                retvals[i] = entryid_set_AB_EntryID(data_pointers, object->object.mailbox->owner_EssDN,
 
2731
                                                                    bin);
 
2732
                                data_pointers[i] = bin;
 
2733
                        }
 
2734
                        break;
 
2735
                case PidTagMailboxOwnerName:
 
2736
                        if (object->object.mailbox->mailboxstore == false) {
 
2737
                                retvals[i] = MAPI_E_NO_ACCESS;
 
2738
                        } else {
 
2739
                                retvals[i] = MAPI_E_SUCCESS;
 
2740
                                data_pointers[i] = talloc_strdup(data_pointers, object->object.mailbox->owner_Name);
 
2741
                        }
 
2742
                        break;
 
2743
                default:
 
2744
                        retvals[i] = openchangedb_get_folder_property(data_pointers, emsmdbp_ctx->oc_ctx, properties->aulPropTag[i], object->object.mailbox->folderID, data_pointers + i);
 
2745
                }
 
2746
        }
 
2747
 
 
2748
        return MAPISTORE_SUCCESS;
 
2749
}
 
2750
 
 
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)
 
2752
{
 
2753
        uint32_t                contextID = -1;
 
2754
        struct mapistore_property_data  *prop_data;
 
2755
        int                     i, ret;
 
2756
 
 
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);
 
2760
 
 
2761
        ret = mapistore_properties_get_properties(emsmdbp_ctx->mstore_ctx, contextID,
 
2762
                                                  object->backend_object,
 
2763
                                                  prop_data,
 
2764
                                                  properties->cValues,
 
2765
                                                  properties->aulPropTag,
 
2766
                                                  prop_data);
 
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;
 
2772
                                }
 
2773
                                else {
 
2774
                                        retvals[i] = MAPI_E_NO_SUPPORT;
 
2775
                                        DEBUG (4, ("%s: unknown mapistore error: %.8x\n", __PRETTY_FUNCTION__, prop_data[i].error));
 
2776
                                }
 
2777
                        }
 
2778
                        else {
 
2779
                                if (prop_data[i].data == NULL) {
 
2780
                                        retvals[i] = MAPI_E_NOT_FOUND;
 
2781
                                }
 
2782
                                else {
 
2783
                                        data_pointers[i] = prop_data[i].data;
 
2784
                                        (void) talloc_reference(data_pointers, prop_data[i].data);
 
2785
                                }
 
2786
                        }
 
2787
                }
 
2788
        }
 
2789
        talloc_free(prop_data);
 
2790
 
 
2791
        return ret;
 
2792
}
 
2793
 
 
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)
 
2795
{
 
2796
        void            **data_pointers;
 
2797
        enum MAPISTATUS *retvals;
 
2798
        bool            mapistore;
 
2799
        int             retval;
 
2800
 
 
2801
        data_pointers = talloc_array(mem_ctx, void *, properties->cValues);
 
2802
        memset(data_pointers, 0, sizeof(void *) * properties->cValues);
 
2803
 
 
2804
        retvals = talloc_array(mem_ctx, enum MAPISTATUS, properties->cValues);
 
2805
        memset(retvals, 0, sizeof(enum MAPISTATUS) * properties->cValues);
 
2806
 
 
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);
 
2815
                }
 
2816
 
 
2817
                retval = emsmdbp_object_get_properties_mapistore_root(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
 
2818
        } else {
 
2819
                mapistore = emsmdbp_is_mapistore(object);
 
2820
                /* Nasty hack */
 
2821
                if (!object) {
 
2822
                        DEBUG(5, ("[%s] what's that hack!??\n", __location__));
 
2823
                        mapistore = true;
 
2824
                }
 
2825
 
 
2826
                switch (mapistore) {
 
2827
                case false:
 
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);
 
2831
                                break;
 
2832
                        case EMSMDBP_OBJECT_FOLDER:
 
2833
                                retval = emsmdbp_object_get_properties_systemspecialfolder(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
 
2834
                                break;
 
2835
                        case EMSMDBP_OBJECT_MESSAGE:
 
2836
                                retval = emsmdbp_object_get_properties_message(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
 
2837
                                break;
 
2838
                        default:
 
2839
                                retval = MAPISTORE_ERROR;
 
2840
                                break;
 
2841
                        }
 
2842
                        break;
 
2843
                case true:
 
2844
                        /* folder or messages handled by mapistore */
 
2845
                        retval = emsmdbp_object_get_properties_mapistore(mem_ctx, emsmdbp_ctx, object, properties, data_pointers, retvals);
 
2846
                        break;
 
2847
                }
 
2848
        }
 
2849
 
 
2850
        if (retvalsp) {
 
2851
                *retvalsp = retvals;
 
2852
        }
 
2853
 
 
2854
        if (retval) {
 
2855
                talloc_free(data_pointers);
 
2856
                data_pointers = NULL;
 
2857
        }
 
2858
 
 
2859
        return data_pointers;
 
2860
}
 
2861
 
 
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)
 
2864
{
 
2865
        uint32_t                contextID, new_cvalues;
 
2866
        bool                    mapistore;
 
2867
        enum mapistore_error    ret;
 
2868
        struct SRow             *postponed_props;
 
2869
 
 
2870
        /* Sanity checks */
 
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;
 
2880
        }
 
2881
 
 
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;
 
2889
 
 
2890
                        ret = emsmdbp_object_folder_commit_creation(emsmdbp_ctx, object, false);
 
2891
                        if (ret == MAPISTORE_SUCCESS) {
 
2892
                                return MAPI_E_SUCCESS;
 
2893
                        }
 
2894
                        else {
 
2895
                                return MAPI_E_NOT_FOUND;
 
2896
                        }
 
2897
                }
 
2898
        }
 
2899
 
 
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);
 
2909
        }
 
2910
        else {
 
2911
                contextID = emsmdbp_get_contextID(object);
 
2912
                mapistore = emsmdbp_is_mapistore(object);
 
2913
                switch (mapistore) {
 
2914
                case false:
 
2915
                        if (object->type == EMSMDBP_OBJECT_FOLDER) {
 
2916
                                openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, object->object.folder->folderID, rowp);
 
2917
                        }
 
2918
                        else if (object->type == EMSMDBP_OBJECT_MAILBOX) {
 
2919
                                openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, object->object.mailbox->folderID, rowp);
 
2920
                        }
 
2921
                        else if (object->type == EMSMDBP_OBJECT_MESSAGE) {
 
2922
                                openchangedb_message_set_properties((TALLOC_CTX *)object->object.message, 
 
2923
                                                                    object->backend_object, rowp);
 
2924
                        }
 
2925
                        else {
 
2926
                                DEBUG(0, ("Setting properties on openchangedb not implemented yet for non-folder object type\n"));
 
2927
                                return MAPI_E_NO_SUPPORT;
 
2928
                        }
 
2929
                        break;
 
2930
                case true:
 
2931
                        mapistore_properties_set_properties(emsmdbp_ctx->mstore_ctx, contextID, object->backend_object, rowp);
 
2932
                        break;
 
2933
                }
 
2934
        }
 
2935
 
 
2936
        return MAPI_E_SUCCESS;
 
2937
}
 
2938
 
 
2939
_PUBLIC_ void emsmdbp_fill_row_blob(TALLOC_CTX *mem_ctx,
 
2940
                                    struct emsmdbp_context *emsmdbp_ctx,
 
2941
                                    uint8_t *layout,
 
2942
                                    DATA_BLOB *property_row,
 
2943
                                    struct SPropTagArray *properties,
 
2944
                                    void **data_pointers,
 
2945
                                    enum MAPISTATUS *retvals,
 
2946
                                    bool *untyped_status)
 
2947
{
 
2948
        uint16_t i;
 
2949
        uint8_t flagged;
 
2950
        enum MAPITAGS property;
 
2951
        void *data;
 
2952
        uint32_t retval;
 
2953
 
 
2954
        flagged = 0;
 
2955
        for (i = 0; !flagged && i < properties->cValues; i++) {
 
2956
                if (retvals[i] != MAPI_E_SUCCESS || untyped_status[i] || !data_pointers[i]) {
 
2957
                        flagged = 1;
 
2958
                }
 
2959
        }
 
2960
        *layout = flagged;
 
2961
 
 
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;
 
2966
                        data = &retval;
 
2967
                }
 
2968
                else {
 
2969
                        property = properties->aulPropTag[i];
 
2970
                        data = data_pointers[i];
 
2971
                }
 
2972
                libmapiserver_push_property(mem_ctx,
 
2973
                                            property, data, property_row,
 
2974
                                            flagged ? PT_ERROR : 0, flagged, untyped_status[i]);
 
2975
        }
 
2976
}
 
2977
 
 
2978
_PUBLIC_ struct emsmdbp_stream_data *emsmdbp_stream_data_from_value(TALLOC_CTX *mem_ctx, enum MAPITAGS prop_tag, void *value)
 
2979
{
 
2980
        uint16_t                        prop_type;
 
2981
        struct emsmdbp_stream_data      *stream_data;
 
2982
        size_t                          converted_size;
 
2983
 
 
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);
 
2991
        }
 
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,
 
2998
                               &converted_size);
 
2999
                memset(stream_data->data.data + stream_data->data.length, 0, 2 * sizeof(uint8_t));
 
3000
        }
 
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);
 
3005
        }
 
3006
        else {
 
3007
                talloc_free(stream_data);
 
3008
                return NULL;
 
3009
        }
 
3010
 
 
3011
        return stream_data;
 
3012
}
 
3013
 
 
3014
_PUBLIC_ DATA_BLOB emsmdbp_stream_read_buffer(struct emsmdbp_stream *stream, uint32_t length)
 
3015
{
 
3016
        DATA_BLOB buffer;
 
3017
        uint32_t real_length;
 
3018
 
 
3019
        real_length = length;
 
3020
        if (real_length + stream->position > stream->buffer.length) {
 
3021
                real_length = stream->buffer.length - stream->position;
 
3022
        }
 
3023
        buffer.length = real_length;
 
3024
        buffer.data = stream->buffer.data + stream->position;
 
3025
        stream->position += real_length;
 
3026
 
 
3027
        return buffer;
 
3028
}
 
3029
 
 
3030
_PUBLIC_ void emsmdbp_stream_write_buffer(TALLOC_CTX *mem_ctx, struct emsmdbp_stream *stream, DATA_BLOB new_buffer)
 
3031
{
 
3032
        uint32_t new_position, old_length;
 
3033
        uint8_t *old_data;
 
3034
 
 
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);
 
3046
                        }
 
3047
                }
 
3048
                else {
 
3049
                        stream->buffer.data = talloc_array(mem_ctx, uint8_t, stream->buffer.length);
 
3050
                }
 
3051
        }
 
3052
 
 
3053
        memcpy(stream->buffer.data + stream->position, new_buffer.data, new_buffer.length);
 
3054
        stream->position = new_position;
 
3055
}
 
3056
 
 
3057
_PUBLIC_ struct emsmdbp_stream_data *emsmdbp_object_get_stream_data(struct emsmdbp_object *object, enum MAPITAGS prop_tag)
 
3058
{
 
3059
        struct emsmdbp_stream_data *current_data;
 
3060
 
 
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;
 
3065
                }
 
3066
        }
 
3067
 
 
3068
        return NULL;
 
3069
}
 
3070
 
 
3071
/**
 
3072
   \details Initialize a synccontext object
 
3073
 
 
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
 
3080
 */
 
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)
 
3084
{
 
3085
        struct emsmdbp_object   *synccontext_object;
 
3086
 
 
3087
        /* Sanity checks */
 
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));
 
3092
                return NULL;
 
3093
        }
 
3094
 
 
3095
        synccontext_object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent_object);
 
3096
        if (!synccontext_object) return NULL;
 
3097
 
 
3098
        synccontext_object->object.synccontext = talloc_zero(synccontext_object, struct emsmdbp_object_synccontext);
 
3099
        if (!synccontext_object->object.synccontext) {
 
3100
                talloc_free(synccontext_object);
 
3101
                return NULL;
 
3102
        }
 
3103
 
 
3104
        synccontext_object->type = EMSMDBP_OBJECT_SYNCCONTEXT;
 
3105
 
 
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;
 
3112
 
 
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;
 
3121
 
 
3122
        /* synccontext_object->object.synccontext->property_tags.cValues = 0; */
 
3123
        /* synccontext_object->object.synccontext->property_tags.aulPropTag = NULL; */
 
3124
 
 
3125
        return synccontext_object;
 
3126
}
 
3127
 
 
3128
/**
 
3129
   \details Initialize a ftcontext object
 
3130
 
 
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
 
3137
 */
 
3138
_PUBLIC_ struct emsmdbp_object *emsmdbp_object_ftcontext_init(TALLOC_CTX *mem_ctx,
 
3139
                                                              struct emsmdbp_context *emsmdbp_ctx,
 
3140
                                                              struct emsmdbp_object *parent)
 
3141
{
 
3142
        struct emsmdbp_object   *object;
 
3143
 
 
3144
        /* Sanity checks */
 
3145
        if (!emsmdbp_ctx) return NULL;
 
3146
        if (!parent) return NULL;
 
3147
 
 
3148
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx, parent);
 
3149
        if (!object) return NULL;
 
3150
 
 
3151
        object->object.ftcontext = talloc_zero(object, struct emsmdbp_object_ftcontext);
 
3152
        if (!object->object.ftcontext) {
 
3153
                talloc_free(object);
 
3154
                return NULL;
 
3155
        }
 
3156
 
 
3157
        object->type = EMSMDBP_OBJECT_FTCONTEXT;
576
3158
 
577
3159
        return object;
578
3160
}