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

« back to all changes in this revision

Viewing changes to mapiproxy/servers/default/emsmdb/emsmdbp_provisioning.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:
 
1
/*
 
2
   OpenChange Server implementation
 
3
 
 
4
   EMSMDBP: EMSMDB Provider implementation
 
5
 
 
6
   Copyright (C) Wolfgang Sourdeau 2012
 
7
 
 
8
   This program is free software; you can redistribute it and/or modify
 
9
   it under the terms of the GNU General Public License as published by
 
10
   the Free Software Foundation; either version 3 of the License, or
 
11
   (at your option) any later version.
 
12
   
 
13
   This program is distributed in the hope that it will be useful,
 
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
   GNU General Public License for more details.
 
17
   
 
18
   You should have received a copy of the GNU General Public License
 
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
 */
 
21
 
 
22
/**
 
23
   \file emsmdbp_provisioning.c
 
24
 
 
25
   \brief Account provisioning
 
26
 */
 
27
 
 
28
#include <ctype.h>
 
29
#include <string.h>
 
30
#include <sys/mman.h>
 
31
 
 
32
 
 
33
#include "dcesrv_exchange_emsmdb.h"
 
34
 
 
35
#include <gen_ndr/ndr_property.h>
 
36
 
 
37
_PUBLIC_ enum MAPISTATUS emsmdbp_mailbox_provision_public_freebusy(struct emsmdbp_context *emsmdbp_ctx, const char *EssDN)
 
38
{
 
39
        enum MAPISTATUS         ret;
 
40
        char                    *dn_root, *dn_user, *cn_ptr;
 
41
        uint64_t                public_fb_fid, group_fid, fb_mid, change_num;
 
42
        size_t                  i, max;
 
43
        void                    *message_object;
 
44
        struct SRow             property_row;
 
45
        TALLOC_CTX              *mem_ctx;
 
46
 
 
47
        mem_ctx = talloc_zero(NULL, TALLOC_CTX);
 
48
 
 
49
        dn_root = talloc_asprintf(mem_ctx, "EX:%s", EssDN);
 
50
        cn_ptr = strstr(dn_root, "/cn");
 
51
        if (!cn_ptr) {
 
52
                ret = MAPI_E_INVALID_PARAMETER;
 
53
                goto end;
 
54
        }
 
55
 
 
56
        dn_user = talloc_asprintf(mem_ctx, "USER-%s", cn_ptr);
 
57
        *cn_ptr = 0;
 
58
 
 
59
        /* convert dn_root to lowercase */
 
60
        max = cn_ptr - dn_root;
 
61
        for (i = 3; i < max; i++) {
 
62
                dn_root[i] = tolower(dn_root[i]);
 
63
        }
 
64
 
 
65
        /* convert dn_user to uppercase. Yes, it's stupid like that. */
 
66
        max = strlen(dn_user);
 
67
        for (i = 5; i < max; i++) {
 
68
                dn_user[i] = toupper(dn_user[i]);
 
69
        }
 
70
 
 
71
        ret = openchangedb_get_PublicFolderID(emsmdbp_ctx->oc_ctx, EMSMDBP_PF_FREEBUSY, &public_fb_fid);
 
72
        if (ret != MAPI_E_SUCCESS) {
 
73
                DEBUG(5, ("provisioning: freebusy root folder not found in openchange.ldb\n"));
 
74
                goto end;
 
75
        }
 
76
 
 
77
        ret = openchangedb_get_fid_by_name(emsmdbp_ctx->oc_ctx, public_fb_fid, dn_root, &group_fid);
 
78
        if (ret != MAPI_E_SUCCESS) {
 
79
                openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &group_fid);
 
80
                openchangedb_get_new_changeNumber(emsmdbp_ctx->oc_ctx, &change_num);
 
81
                openchangedb_create_folder(emsmdbp_ctx->oc_ctx, public_fb_fid, group_fid, change_num, NULL, -1);
 
82
        }
 
83
 
 
84
        ret = openchangedb_get_mid_by_subject(emsmdbp_ctx->oc_ctx, group_fid, dn_user, false, &fb_mid);
 
85
        if (ret != MAPI_E_SUCCESS) {
 
86
                openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &fb_mid);
 
87
                openchangedb_get_new_changeNumber(emsmdbp_ctx->oc_ctx, &change_num);
 
88
                openchangedb_message_create(mem_ctx, emsmdbp_ctx->oc_ctx, fb_mid, group_fid, false, &message_object);
 
89
                property_row.cValues = 1;
 
90
                property_row.lpProps = talloc_zero(mem_ctx, struct SPropValue);
 
91
                property_row.lpProps[0].ulPropTag = PR_NORMALIZED_SUBJECT_UNICODE;
 
92
                property_row.lpProps[0].value.lpszW = dn_user;
 
93
                openchangedb_message_set_properties(mem_ctx, message_object, &property_row);
 
94
                openchangedb_message_save(message_object, 0);
 
95
        }
 
96
 
 
97
        ret = MAPI_E_SUCCESS;
 
98
 
 
99
end:
 
100
        talloc_free(mem_ctx);
 
101
 
 
102
        return ret;
 
103
}
 
104
 
 
105
_PUBLIC_ enum MAPISTATUS emsmdbp_mailbox_provision(struct emsmdbp_context *emsmdbp_ctx, const char *username)
 
106
{
 
107
/* auto-provisioning:
 
108
 
 
109
  During private logon:
 
110
   - fetch list of available folders from all backends + list of capabilities (handled folder types) + fallback entry
 
111
   - if fallback is not available: FAIL
 
112
   - fetch list of existing folders from openchangedb
 
113
   - if mailbox does not exist:
 
114
    - create basic structure
 
115
    - if certain folders are not available (Inbox, Deleted Items, Spooler Queue, Outbox), use fallback
 
116
   - synchronize list of non-mandatory and secondary folders
 
117
    - update relevant entry ids in relevant objects
 
118
   - ability to leave creation of fallback and other url to the relevant backend
 
119
   - freebusy entry
 
120
 
 
121
  folder creation = createfolder + setprops (class) + release
 
122
 
 
123
 
 
124
* RopLogon entries (mandatory) (autoprovisioning)
 
125
 
 
126
mailbox (Root): (None)
 
127
 
 
128
"Common Views": (None) (sogo://wsourdeau:wsourdeau@common-views/)          -> fallback
 
129
"Deferred Action": (None) (sogo://wsourdeau:wsourdeau@deferred-actions/)   -> fallback
 
130
"Search" (Finder): None (sogo://wsourdeau:wsourdeau@search/)               -> fallback
 
131
"Schedule": (None) (sogo://wsourdeau:wsourdeau@schedule/)                  -> fallback
 
132
"Shortcuts": (None) (sogo://wsourdeau:wsourdeau@shortcuts/)                -> fallback
 
133
"Spooler Queue": (None) (sogo://wsourdeau:wsourdeau@spooler-queue/)        -> fallback
 
134
"Views": (sogo://wsourdeau:wsourdeau@views/)                               -> fallback
 
135
 
 
136
"IPM Subtree" (Top of Personal Folders): (None)
 
137
 
 
138
* autoprovisioning backend based
 
139
 
 
140
"Inbox": IPF.Note (sogo://wsourdeau:wsourdeau@inbox/)
 
141
"Outbox": IPF.Note (sogo://wsourdeau:wsourdeau@outbox/)
 
142
"Sent Items": IPF.Note (sogo://wsourdeau:wsourdeau@sent-items/)
 
143
"Deleted Items": IPF.Note (sogo://wsourdeau:wsourdeau@deleted-items/)
 
144
 
 
145
* additional special folders
 
146
"Calendar": IPF.Appointment (PidTagIpmAppointmentEntryId)
 
147
"Contacts": IPF.Contact (PidTagIpmContactEntryId)
 
148
"Notes": IPF.StickyNote (PidTagIpmNoteEntryId)
 
149
"Tasks": IPF.Task (PidTagIpmTaskEntryId)
 
150
"Journal": IPF.Journal (PidTagIpmJournalEntryId)
 
151
"Drafts": IPF.Note (PidTagIpmDraftsEntryId)
 
152
 
 
153
* client-created:
 
154
 
 
155
"Freebusy Data": 
 
156
"Reminders": Outlook.Reminder (sogo://wsourdeau:wsourdeau@reminders/)  (PidTagRemindersOnlineEntryId)    -> fallback
 
157
"To-Do blabnla"
 
158
"Sync Issues": IPF.Note (PidTagAdditionalRenEntryIds)
 
159
"Junk E-mail": IPF.Note (PidTagAdditionalRenEntryIds)
 
160
...
 
161
 
 
162
 
 
163
 
 
164
Exchange hierarchy for virgin account:
 
165
 
 
166
FolderId: 0x67ca828f02000001      Display Name: "                        ";  Container Class: MAPI_E_NOT_FOUND;        Message Class: MAPI_E_NOT_FOUND; Has Subfolders: TRUE; 
 
167
 
 
168
  FolderId: 0x71ca828f02000001    Display Name: "            Common Views";  Container Class: MAPI_E_NOT_FOUND;        Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
169
  FolderId: 0x69ca828f02000001    Display Name: "         Deferred Action";  Container Class: MAPI_E_NOT_FOUND;        Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
170
  FolderId: 0x6fca828f02000001    Display Name: "                  Finder";  Container Class: MAPI_E_NOT_FOUND;        Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
171
  FolderId: 0x72ca828f02000001    Display Name: "                Schedule";  Container Class: MAPI_E_NOT_FOUND;        Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
172
  FolderId: 0x73ca828f02000001    Display Name: "               Shortcuts";  Container Class: MAPI_E_NOT_FOUND;        Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
173
  FolderId: 0x6aca828f02000001    Display Name: "           Spooler Queue";  Container Class: MAPI_E_NOT_FOUND;        Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
174
  FolderId: 0x70ca828f02000001    Display Name: "                   Views";  Container Class: MAPI_E_NOT_FOUND;        Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
175
 
 
176
  FolderId: 0x68ca828f02000001    Display Name: "Top of Information Store";  Container Class: MAPI_E_NOT_FOUND;        Message Class: MAPI_E_NOT_FOUND; Has Subfolders: TRUE; 
 
177
 
 
178
    FolderId: 0x6bca828f02000001  Display Name: "      Boîte de réception";  Container Class: "            IPF.Note";  Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
179
    FolderId: 0x6cca828f02000001  Display Name: "           Boîte d'envoi";  Container Class: "            IPF.Note";  Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
180
    FolderId: 0x67c3828f02000001  Display Name: "              Brouillons";  Container Class: "            IPF.Note";  Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
181
    FolderId: 0x65c3828f02000001  Display Name: "              Calendrier";  Container Class: "     IPF.Appointment";  Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
182
    FolderId: 0x66c3828f02000001  Display Name: "                Contacts";  Container Class: "         IPF.Contact";  Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
183
    FolderId: 0x6dca828f02000001  Display Name: "        Éléments envoyés";  Container Class: "            IPF.Note";  Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
184
    FolderId: 0x6eca828f02000001  Display Name: "      Éléments supprimés";  Container Class: "            IPF.Note";  Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
185
    FolderId: 0x68c3828f02000001  Display Name: "                 Journal";  Container Class: "         IPF.Journal";  Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
186
    FolderId: 0x69c3828f02000001  Display Name: "                   Notes";  Container Class: "      IPF.StickyNote";  Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
187
    FolderId: 0x6ac3828f02000001  Display Name: "                  Tâches";  Container Class: "            IPF.Task";  Message Class: MAPI_E_NOT_FOUND; Has Subfolders: FALSE; 
 
188
 
 
189
 
 
190
 
 
191
 */
 
192
        TALLOC_CTX                              *mem_ctx;
 
193
        enum MAPISTATUS                         ret;
 
194
        enum mapistore_error                    retval;
 
195
        struct mapistore_contexts_list          *contexts_list;
 
196
        struct StringArrayW_r                   *existing_uris;
 
197
        struct mapistore_contexts_list          *main_entries[MAPISTORE_MAX_ROLES], *secondary_entries[MAPISTORE_MAX_ROLES], *next_entry, *current_entry;
 
198
        static const char                       *folder_names[] = {NULL, "Root", "Deferred Action", "Spooler Queue", "Common Views", "Schedule", "Finder", "Views", "Shortcuts", "Top of Information Store", "Inbox", "Outbox", "Sent Items", "Deleted Items"};
 
199
        static struct emsmdbp_special_folder    special_folders[] = {{MAPISTORE_DRAFTS_ROLE, PR_IPM_DRAFTS_ENTRYID, "Drafts"},
 
200
                                                                     {MAPISTORE_CALENDAR_ROLE, PR_IPM_APPOINTMENT_ENTRYID, "Calendar"},
 
201
                                                                     {MAPISTORE_CONTACTS_ROLE, PR_IPM_CONTACT_ENTRYID, "Contacts"},
 
202
                                                                     {MAPISTORE_TASKS_ROLE, PR_IPM_TASK_ENTRYID, "Tasks"},
 
203
                                                                     {MAPISTORE_NOTES_ROLE, PR_IPM_NOTE_ENTRYID, "Notes"},
 
204
                                                                     {MAPISTORE_JOURNAL_ROLE, PR_IPM_JOURNAL_ENTRYID, "Journal"}};
 
205
        const char                              **container_classes;
 
206
        uint32_t                                context_id;
 
207
        uint64_t                                mailbox_fid = 0, ipm_fid, inbox_fid = 0, current_fid, found_fid, current_cn;
 
208
        char                                    *fallback_url, *entryid_dump;
 
209
        const char                              *mapistore_url, *current_name, *base_name;
 
210
        struct emsmdbp_special_folder           *current_folder;
 
211
        struct SRow                             property_row;
 
212
        int                                     i, j, nbr_special_folders = sizeof(special_folders) / sizeof(struct emsmdbp_special_folder);
 
213
        DATA_BLOB                               entryid_data;
 
214
        struct FolderEntryId                    folder_entryid;
 
215
        struct Binary_r                         *entryId;
 
216
        bool                                    exists;
 
217
        void                                    *backend_object;
 
218
 
 
219
        mem_ctx = talloc_zero(NULL, TALLOC_CTX);
 
220
 
 
221
        ldb_transaction_start(emsmdbp_ctx->oc_ctx);
 
222
 
 
223
        /* Retrieve list of folders from backends */
 
224
        retval = mapistore_list_contexts_for_user(emsmdbp_ctx->mstore_ctx, username, mem_ctx, &contexts_list);
 
225
        if (retval != MAPISTORE_SUCCESS) {
 
226
                talloc_free(mem_ctx);
 
227
                return MAPI_E_DISK_ERROR;
 
228
        }
 
229
 
 
230
        /* Fix mapistore uris in returned entries */
 
231
        current_entry = contexts_list;
 
232
        while (current_entry) {
 
233
                mapistore_url = current_entry->url;
 
234
                if (mapistore_url) {
 
235
                        if (mapistore_url[strlen(mapistore_url)-1] != '/') {
 
236
                                current_entry->url = talloc_asprintf(mem_ctx, "%s/", mapistore_url);
 
237
                        }
 
238
                        /* DEBUG(5, ("received entry: '%s' (%p)\n", current_entry->url, current_entry)); */
 
239
                }
 
240
                else {
 
241
                        DEBUG(5, ("received entry without uri\n"));
 
242
                        abort();
 
243
                }
 
244
                current_entry = current_entry->next;
 
245
        }
 
246
 
 
247
        /* Retrieve list of existing entries */
 
248
        ret = openchangedb_get_MAPIStoreURIs(emsmdbp_ctx->oc_ctx, username, mem_ctx, &existing_uris);
 
249
        if (ret == MAPI_E_SUCCESS) {
 
250
                for (i = 0; i < existing_uris->cValues; i++) {
 
251
                        /* DEBUG(5, ("checking entry '%s'\n", existing_uris->lppszW[i])); */
 
252
                        exists = false;
 
253
                        mapistore_url = existing_uris->lppszW[i];
 
254
                        if (mapistore_url[strlen(mapistore_url)-1] != '/') {
 
255
                                abort();
 
256
                        }
 
257
                        current_entry = contexts_list;
 
258
                        while (!exists && current_entry) {
 
259
                                /* DEBUG(5, ("  compare with '%s'\n", current_entry->url)); */
 
260
                                if (strcmp(mapistore_url, current_entry->url) == 0) {
 
261
                                        /* DEBUG(5, ("  entry found\n")); */
 
262
                                        exists = true;
 
263
                                }
 
264
                                current_entry = current_entry->next;
 
265
                        }
 
266
                        if (!exists) {
 
267
                                DEBUG(5, ("  removing entry '%s'\n", mapistore_url));
 
268
                                openchangedb_get_fid(emsmdbp_ctx->oc_ctx, mapistore_url, &found_fid);
 
269
                                openchangedb_delete_folder(emsmdbp_ctx->oc_ctx, found_fid);
 
270
                        }
 
271
                }
 
272
        }
 
273
 
 
274
        container_classes = talloc_array(mem_ctx, const char *, MAPISTORE_MAX_ROLES);
 
275
        for (i = MAPISTORE_MAIL_ROLE; i < MAPISTORE_MAX_ROLES; i++) {
 
276
                container_classes[i] = "IPF.Note";
 
277
        }
 
278
        container_classes[MAPISTORE_CALENDAR_ROLE] = "IPF.Appointment";
 
279
        container_classes[MAPISTORE_CONTACTS_ROLE] = "IPF.Contact";
 
280
        container_classes[MAPISTORE_TASKS_ROLE] = "IPF.Task";
 
281
        container_classes[MAPISTORE_NOTES_ROLE] = "IPF.StickyNote";
 
282
        container_classes[MAPISTORE_JOURNAL_ROLE] = "IPF.Journal";
 
283
 
 
284
        memset(&property_row, 0, sizeof(struct SRow));
 
285
        memset(main_entries, 0, sizeof(struct mapistore_contexts_list *) * MAPISTORE_MAX_ROLES);
 
286
        memset(secondary_entries, 0, sizeof(struct mapistore_contexts_list *) * MAPISTORE_MAX_ROLES);
 
287
 
 
288
        /* Sort them between our main_entries and secondary_entries */
 
289
        current_entry = contexts_list;
 
290
        while (current_entry) {
 
291
                next_entry = current_entry->next;
 
292
                current_entry->next = NULL;
 
293
                current_entry->prev = NULL;
 
294
                if (current_entry->main_folder) {
 
295
                        if (main_entries[current_entry->role]) {
 
296
                                DEBUG(5, ("duplicate entry for role %d ignored\n  existing entry: %s\n  current entry: %s\n",
 
297
                                          current_entry->role, main_entries[current_entry->role]->url, current_entry->url));
 
298
                        }
 
299
                        else {
 
300
                                main_entries[current_entry->role] = current_entry;
 
301
                        }
 
302
                }
 
303
                else {
 
304
                        DLIST_ADD_END(secondary_entries[current_entry->role], current_entry, void);
 
305
                }
 
306
                current_entry = next_entry;
 
307
        }
 
308
 
 
309
        /* Fallback role MUST exist */
 
310
        if (!main_entries[MAPISTORE_FALLBACK_ROLE]) {
 
311
                DEBUG(5, ("No fallback provisioning role was found while such role is mandatory. Provisiong must be done manually.\n"));
 
312
                talloc_free(mem_ctx);
 
313
                return MAPI_E_DISK_ERROR;
 
314
        }
 
315
        fallback_url = main_entries[MAPISTORE_FALLBACK_ROLE]->url;
 
316
        if (fallback_url[strlen(fallback_url)-1] != '/') {
 
317
                fallback_url = talloc_asprintf(mem_ctx, "%s/", fallback_url);
 
318
        }
 
319
 
 
320
        /* Mailbox and subfolders */
 
321
        ret = openchangedb_get_SystemFolderID(emsmdbp_ctx->oc_ctx, username, EMSMDBP_MAILBOX_ROOT, &mailbox_fid);
 
322
        if (ret != MAPI_E_SUCCESS) {
 
323
                openchangedb_create_mailbox(emsmdbp_ctx->oc_ctx, username, EMSMDBP_MAILBOX_ROOT, &mailbox_fid);
 
324
        }
 
325
        property_row.lpProps = talloc_array(mem_ctx, struct SPropValue, 2); /* allocate max needed until the end of the function */
 
326
        property_row.cValues = 1;
 
327
        property_row.lpProps[0].ulPropTag = PR_DISPLAY_NAME_UNICODE;
 
328
        for (i = EMSMDBP_DEFERRED_ACTION; i < EMSMDBP_TOP_INFORMATION_STORE; i++) {
 
329
                /* TODO: mapistore_tag change */
 
330
                ret = openchangedb_get_SystemFolderID(emsmdbp_ctx->oc_ctx, username, i, &current_fid);
 
331
                if (ret != MAPI_E_SUCCESS) {
 
332
                        openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &current_fid);
 
333
                        openchangedb_get_new_changeNumber(emsmdbp_ctx->oc_ctx, &current_cn);
 
334
                        mapistore_url = talloc_asprintf(mem_ctx, "%s0x%"PRIx64"/", fallback_url, current_fid);
 
335
                        openchangedb_create_folder(emsmdbp_ctx->oc_ctx, mailbox_fid, current_fid, current_cn, mapistore_url, i);
 
336
                        property_row.lpProps->value.lpszW = folder_names[i];
 
337
                        openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, current_fid, &property_row);
 
338
 
 
339
                        /* instantiate the new folder in the backend to make sure it is initialized properly */
 
340
                        retval = mapistore_add_context(emsmdbp_ctx->mstore_ctx, username, mapistore_url, current_fid, &context_id, &backend_object);
 
341
                        mapistore_indexing_record_add_fid(emsmdbp_ctx->mstore_ctx, context_id, username, current_fid);
 
342
                        mapistore_del_context(emsmdbp_ctx->mstore_ctx, context_id);
 
343
                }
 
344
        }
 
345
 
 
346
        /* IPM and subfolders */
 
347
        ret = openchangedb_get_SystemFolderID(emsmdbp_ctx->oc_ctx, username, EMSMDBP_TOP_INFORMATION_STORE, &ipm_fid);
 
348
        if (ret != MAPI_E_SUCCESS) {
 
349
                openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &ipm_fid);
 
350
                openchangedb_get_new_changeNumber(emsmdbp_ctx->oc_ctx, &current_cn);
 
351
                property_row.cValues = 2;
 
352
                property_row.lpProps[1].ulPropTag = PR_SUBFOLDERS;
 
353
                property_row.lpProps[0].value.lpszW = folder_names[EMSMDBP_TOP_INFORMATION_STORE];
 
354
                property_row.lpProps[1].value.b = true;
 
355
                openchangedb_create_folder(emsmdbp_ctx->oc_ctx, mailbox_fid, ipm_fid, current_cn, NULL, EMSMDBP_TOP_INFORMATION_STORE);
 
356
                openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, ipm_fid, &property_row);
 
357
                openchangedb_set_ReceiveFolder(emsmdbp_ctx->oc_ctx, username, "IPC", mailbox_fid);
 
358
        }
 
359
        property_row.cValues = 2;
 
360
        property_row.lpProps[1].ulPropTag = PR_CONTAINER_CLASS_UNICODE;
 
361
        property_row.lpProps[1].value.lpszW = "IPF.Note";
 
362
        /* TODO: mapistore_url/mapistore_tag change */
 
363
        for (i = EMSMDBP_INBOX; i < EMSMDBP_MAX_MAILBOX_SYSTEMIDX; i++) {
 
364
                ret = openchangedb_get_SystemFolderID(emsmdbp_ctx->oc_ctx, username, i, &current_fid);
 
365
                if (ret == MAPI_E_SUCCESS) {
 
366
                        if (i == EMSMDBP_INBOX) {
 
367
                                inbox_fid = current_fid;
 
368
                        }
 
369
                } else {
 
370
                        openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &current_fid);
 
371
                        openchangedb_get_new_changeNumber(emsmdbp_ctx->oc_ctx, &current_cn);
 
372
                        current_name = folder_names[i];
 
373
 
 
374
                        switch (i) {
 
375
                        case EMSMDBP_INBOX:
 
376
                                current_entry = main_entries[MAPISTORE_MAIL_ROLE];
 
377
                                inbox_fid = current_fid;
 
378
                                break;
 
379
                        case EMSMDBP_OUTBOX:
 
380
                                current_entry = main_entries[MAPISTORE_OUTBOX_ROLE];
 
381
                                break;
 
382
                        case EMSMDBP_SENT_ITEMS:
 
383
                                current_entry = main_entries[MAPISTORE_SENTITEMS_ROLE];
 
384
                                break;
 
385
                        case EMSMDBP_DELETED_ITEMS:
 
386
                                current_entry = main_entries[MAPISTORE_DELETEDITEMS_ROLE];
 
387
                                break;
 
388
                        default:
 
389
                                current_entry = NULL;
 
390
                        }
 
391
 
 
392
                        if (current_entry) {
 
393
                                if (current_entry->name) {
 
394
                                        current_name = current_entry->name;
 
395
                                }
 
396
                                mapistore_url = current_entry->url;
 
397
                        }
 
398
                        else {
 
399
                                mapistore_url = talloc_asprintf(mem_ctx, "%s0x%"PRIx64"/", fallback_url, current_fid);
 
400
                        }
 
401
 
 
402
                        /* Ensure the name is unique */
 
403
                        base_name = current_name;
 
404
                        j = 1;
 
405
                        while (openchangedb_get_fid_by_name(emsmdbp_ctx->oc_ctx, ipm_fid, current_name, &found_fid) == MAPI_E_SUCCESS) {
 
406
                                current_name = talloc_asprintf(mem_ctx, "%s (%d)", base_name, j);
 
407
                                j++;
 
408
                        }
 
409
 
 
410
                        openchangedb_create_folder(emsmdbp_ctx->oc_ctx, ipm_fid, current_fid, current_cn, mapistore_url, i);
 
411
                        property_row.lpProps[0].value.lpszW = current_name;
 
412
                        openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, current_fid, &property_row);
 
413
 
 
414
                        /* instantiate the new folder in the backend to make sure it is initialized properly */
 
415
                        retval = mapistore_add_context(emsmdbp_ctx->mstore_ctx, username, mapistore_url, current_fid, &context_id, &backend_object);
 
416
                        mapistore_indexing_record_add_fid(emsmdbp_ctx->mstore_ctx, context_id, username, current_fid);
 
417
                        mapistore_del_context(emsmdbp_ctx->mstore_ctx, context_id);
 
418
 
 
419
                        if (i == EMSMDBP_INBOX) {
 
420
                                /* set INBOX as receive folder for "All", "IPM", "Report.IPM" */
 
421
                                openchangedb_set_ReceiveFolder(emsmdbp_ctx->oc_ctx, username, "All", inbox_fid);
 
422
                                openchangedb_set_ReceiveFolder(emsmdbp_ctx->oc_ctx, username, "IPM", inbox_fid);
 
423
                                openchangedb_set_ReceiveFolder(emsmdbp_ctx->oc_ctx, username, "Report.IPM", inbox_fid);
 
424
                        }
 
425
                }
 
426
        }
 
427
 
 
428
        /* Main special folders */
 
429
        /* TODO: handle entryId change + mapistore_url/mapistore_tag change */
 
430
 
 
431
        memset(&folder_entryid, 0, sizeof(struct FolderEntryId));
 
432
        openchangedb_get_MailboxGuid(emsmdbp_ctx->oc_ctx, username, &folder_entryid.ProviderUID);
 
433
        folder_entryid.FolderType = eitLTPrivateFolder;
 
434
        openchangedb_get_MailboxReplica(emsmdbp_ctx->oc_ctx, username, NULL, &folder_entryid.FolderDatabaseGuid);
 
435
 
 
436
        for (i = 0; i < nbr_special_folders; i++) {
 
437
                current_folder = special_folders + i;
 
438
                ret = openchangedb_get_folder_property(mem_ctx, emsmdbp_ctx->oc_ctx, current_folder->entryid_property, mailbox_fid, (void **) &entryId);
 
439
                if (ret != MAPI_E_SUCCESS) {
 
440
                        property_row.cValues = 2;
 
441
                        property_row.lpProps[0].ulPropTag = PR_DISPLAY_NAME_UNICODE;
 
442
 
 
443
                        openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &current_fid);
 
444
                        openchangedb_get_new_changeNumber(emsmdbp_ctx->oc_ctx, &current_cn);
 
445
 
 
446
                        current_name = current_folder->name;
 
447
                        current_entry = main_entries[current_folder->role];
 
448
                        if (current_entry) {
 
449
                                if (current_entry->name) {
 
450
                                        current_name = current_entry->name;
 
451
                                }
 
452
                                mapistore_url = current_entry->url;
 
453
                        }
 
454
                        else {
 
455
                                mapistore_url = talloc_asprintf(mem_ctx, "%s0x%"PRIx64"/", fallback_url, current_fid);
 
456
                        }
 
457
 
 
458
                        /* Ensure the name is unique */
 
459
                        base_name = current_name;
 
460
                        j = 1;
 
461
                        while (openchangedb_get_fid_by_name(emsmdbp_ctx->oc_ctx, ipm_fid, current_name, &found_fid) == MAPI_E_SUCCESS) {
 
462
                                current_name = talloc_asprintf(mem_ctx, "%s (%d)", base_name, j);
 
463
                                j++;
 
464
                        }
 
465
 
 
466
                        property_row.lpProps[0].value.lpszW = current_name;
 
467
                        property_row.lpProps[1].value.lpszW = container_classes[current_folder->role];
 
468
                        openchangedb_create_folder(emsmdbp_ctx->oc_ctx, ipm_fid, current_fid, current_cn, mapistore_url, i);
 
469
                        openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, current_fid, &property_row);
 
470
 
 
471
                        /* instantiate the new folder in the backend to make sure it is initialized properly */
 
472
                        retval = mapistore_add_context(emsmdbp_ctx->mstore_ctx, username, mapistore_url, current_fid, &context_id, &backend_object);
 
473
                        mapistore_indexing_record_add_fid(emsmdbp_ctx->mstore_ctx, context_id, username, current_fid);
 
474
                        mapistore_del_context(emsmdbp_ctx->mstore_ctx, context_id);
 
475
 
 
476
                        /* set entryid on mailbox and inbox */
 
477
                        folder_entryid.FolderGlobalCounter.value = (current_fid >> 16);
 
478
                        ndr_push_struct_blob(&entryid_data, mem_ctx, &folder_entryid, (ndr_push_flags_fn_t)ndr_push_FolderEntryId);
 
479
                        property_row.cValues = 1;
 
480
                        property_row.lpProps[0].ulPropTag = current_folder->entryid_property;
 
481
                        property_row.lpProps[0].value.bin.cb = entryid_data.length;
 
482
                        property_row.lpProps[0].value.bin.lpb = entryid_data.data;
 
483
 
 
484
                        entryid_dump = ndr_print_struct_string(mem_ctx, (ndr_print_fn_t) ndr_print_FolderEntryId, current_name, &folder_entryid);
 
485
                        DEBUG(5, ("%s\n", entryid_dump));
 
486
 
 
487
                        openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, mailbox_fid, &property_row);
 
488
                        openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, inbox_fid, &property_row);
 
489
                }
 
490
        }
 
491
        /* DEBUG(5, ("size of operation: %ld\n", talloc_total_size(mem_ctx))); */
 
492
 
 
493
        /* secondary folders */
 
494
        property_row.cValues = 2;
 
495
        property_row.lpProps[0].ulPropTag = PR_DISPLAY_NAME_UNICODE;
 
496
 
 
497
        for (i = MAPISTORE_MAIL_ROLE; i < MAPISTORE_MAX_ROLES; i++) {
 
498
                /* secondary fallback roles are only used for synchronization */
 
499
                if (i == MAPISTORE_FALLBACK_ROLE) {
 
500
                        continue;
 
501
                }
 
502
 
 
503
                property_row.lpProps[1].value.lpszW = container_classes[i];
 
504
                current_entry = secondary_entries[i];
 
505
                while (current_entry) {
 
506
                        mapistore_url = current_entry->url;
 
507
                        if (openchangedb_get_fid(emsmdbp_ctx->oc_ctx, mapistore_url, &found_fid) != MAPI_E_SUCCESS) {
 
508
                                /* DEBUG(5, ("creating secondary entry '%s'\n", current_entry->url)); */
 
509
                                openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &current_fid);
 
510
                                openchangedb_get_new_changeNumber(emsmdbp_ctx->oc_ctx, &current_cn);
 
511
 
 
512
                                current_name = current_entry->name;
 
513
                                /* Ensure the name is unique */
 
514
                                base_name = current_name;
 
515
                                j = 1;
 
516
                                while (openchangedb_get_fid_by_name(emsmdbp_ctx->oc_ctx, ipm_fid, current_name, &found_fid) == MAPI_E_SUCCESS) {
 
517
                                        current_name = talloc_asprintf(mem_ctx, "%s (%d)", base_name, j);
 
518
                                        j++;
 
519
                                }
 
520
                                property_row.lpProps[0].value.lpszW = current_name;
 
521
 
 
522
                                openchangedb_create_folder(emsmdbp_ctx->oc_ctx, ipm_fid, current_fid, current_cn, mapistore_url, -1);
 
523
                                openchangedb_set_folder_properties(emsmdbp_ctx->oc_ctx, current_fid, &property_row);
 
524
 
 
525
                                /* instantiate the new folder in the backend to make sure it is initialized properly */
 
526
                                retval = mapistore_add_context(emsmdbp_ctx->mstore_ctx, username, mapistore_url, current_fid, &context_id, &backend_object);
 
527
                                mapistore_indexing_record_add_fid(emsmdbp_ctx->mstore_ctx, context_id, username, current_fid);
 
528
                                mapistore_del_context(emsmdbp_ctx->mstore_ctx, context_id);
 
529
                        }
 
530
                        else {
 
531
                                /* DEBUG(5, ("secondary entry '%s' already exists\n", current_entry->url)); */
 
532
                        }
 
533
                        current_entry = current_entry->next;
 
534
                }
 
535
        }
 
536
 
 
537
        ldb_transaction_commit(emsmdbp_ctx->oc_ctx);
 
538
 
 
539
        /* TODO: rename/create/delete folders at IPM level */
 
540
 
 
541
        talloc_free(mem_ctx);
 
542
 
 
543
        return MAPI_E_SUCCESS;
 
544
}