4230e9122f6acbf4cdd4f19b68fd313688555ff1
[tridge/openchange.git] / trunk / mapiproxy / libmapistore / mapistore_interface.c
1 /*
2    OpenChange Storage Abstraction Layer library
3
4    OpenChange Project
5
6    Copyright (C) Julien Kerihuel 2009-2011
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 mapistore_interface.c
24
25    \brief MAPISTORE public user interface
26    
27    This file contains general functions, primarily for
28    users of the store (rather than storage providers).
29  */
30
31 #define __STDC_FORMAT_MACROS    1
32 #include <inttypes.h>
33
34 #include "mapistore_errors.h"
35 #include "mapistore.h"
36 #include "mapistore_private.h"
37 #include "mapistore_backend.h"
38 #include "mapistore_common.h"
39 #include <dlinklist.h>
40 #include "libmapi/libmapi_private.h"
41
42 #include <string.h>
43
44 /* FIXME: we can use backend_ctx->mapistore_indexing_list instead of
45  * initializing/uninitializing it each time. This also suppose we get
46  * finally ride of libmapistore/mapistore_indexing.c */
47
48 /**
49    \details Initialize the mapistore context
50
51    \param mem_ctx pointer to the memory context
52    \param path the path to the location to load the backend providers from (NULL for default)
53
54    \return allocate mapistore context on success, otherwise NULL
55  */
56 _PUBLIC_ struct mapistore_context *mapistore_init(TALLOC_CTX *mem_ctx, const char *path)
57 {
58         enum MAPISTORE_ERROR            retval;
59         struct mapistore_context        *mstore_ctx;
60
61         mstore_ctx = talloc_zero(mem_ctx, struct mapistore_context);
62         if (!mstore_ctx) {
63                 return NULL;
64         }
65
66         mstore_ctx->processing_ctx = talloc_zero(mstore_ctx, struct processing_context);
67
68         retval = mapistore_init_mapping_context(mstore_ctx->processing_ctx);
69         if (retval != MAPISTORE_SUCCESS) {
70                 MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, "mapistore mapping context init failed: %s\n",
71                                    mapistore_errstr(retval));
72                 talloc_free(mstore_ctx);
73                 return NULL;
74         }
75
76         retval = mapistore_backend_init(mstore_ctx, path);
77         if (retval != MAPISTORE_SUCCESS) {
78                 MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, "mapistore backend init failed: %s\n", mapistore_errstr(retval));
79                 talloc_free(mstore_ctx);
80                 return NULL;
81         }
82
83         mstore_ctx->context_list = NULL;
84
85         /* MAPISTORE_v1 */
86         mstore_ctx->indexing_list = talloc_zero(mstore_ctx, struct indexing_context_list);
87         /* !MAPISTORE_v1 */
88
89         /* MAPISTORE_v2 */
90         mstore_ctx->mapistore_indexing_list = talloc_zero(mstore_ctx, struct mapistore_indexing_context_list);
91
92         mstore_ctx->mapistore_nprops_ctx = NULL;
93         retval = mapistore_namedprops_init(mstore_ctx, &(mstore_ctx->mapistore_nprops_ctx));
94         if (retval != MAPISTORE_SUCCESS) {
95                 MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, 
96                                    "mapistore named properties database init failed: %s\n", 
97                                    mapistore_errstr(retval));
98                 talloc_free(mstore_ctx);
99                 return NULL;
100         }
101         /* MAPISTORE_v2 */
102
103         mstore_ctx->lp_ctx = loadparm_init(mstore_ctx);
104         lpcfg_load_default(mstore_ctx->lp_ctx);
105
106         return mstore_ctx;
107 }
108
109
110 /**
111    \details Release the mapistore context and destroy any data
112    associated
113
114    \param mstore_ctx pointer to the mapistore context
115
116    \note The function needs to rely on talloc destructors which is not
117    implemented in code yet.
118
119    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
120  */
121 _PUBLIC_ enum MAPISTORE_ERROR mapistore_release(struct mapistore_context *mstore_ctx)
122 {
123         /* Sanity checks */
124         MAPISTORE_RETVAL_IF(!mstore_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
125
126         talloc_free(mstore_ctx->mapistore_nprops_ctx);
127         talloc_free(mstore_ctx->processing_ctx);
128         talloc_free(mstore_ctx->context_list);
129         talloc_free(mstore_ctx);
130
131         return MAPISTORE_SUCCESS;
132 }
133
134
135 /**
136    \details Set the mapistore debug level
137
138    \param mstore_ctx pointer to the mapistore context
139    \param level the debug level to set
140
141    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
142  */
143 enum MAPISTORE_ERROR mapistore_set_debuglevel(struct mapistore_context *mstore_ctx, uint32_t level)
144 {
145         char    *debuglevel;
146         bool    ret;
147
148         /* Sanity checks */
149         MAPISTORE_RETVAL_IF(!mstore_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
150         MAPISTORE_RETVAL_IF(!mstore_ctx->lp_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
151
152         debuglevel = talloc_asprintf(talloc_autofree_context(), "%u", level);
153         ret = lpcfg_set_cmdline(mstore_ctx->lp_ctx, "log level", debuglevel);
154         talloc_free(debuglevel);
155
156         return (ret == true) ? MAPISTORE_SUCCESS : MAPISTORE_ERR_INVALID_PARAMETER;
157 }
158
159
160 /**
161    \details Add a new connection context to mapistore
162
163    \param mstore_ctx pointer to the mapistore context
164    \param login_user the username used for authentication
165    \param username the username we want to impersonate
166    \param uri the connection context URI
167    \param context_id pointer to the context identifier the function returns
168
169    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
170  */
171 _PUBLIC_ enum MAPISTORE_ERROR mapistore_add_context(struct mapistore_context *mstore_ctx,
172                                                     const char *login_user, const char *username,
173                                                     const char *uri, uint32_t *context_id)
174 {
175         TALLOC_CTX                              *mem_ctx;
176         int                                     retval;
177         struct backend_context                  *backend_ctx;
178         struct backend_context_list             *backend_list;
179         char                                    *uri_namespace;
180         char                                    *namespace_start;
181         char                                    *backend_uri;
182
183         /* Step 1. Perform Sanity Checks on URI */
184         MAPISTORE_RETVAL_IF(!uri || strlen(uri) < 4, MAPISTORE_ERR_INVALID_NAMESPACE, NULL);
185
186         mem_ctx = talloc_named(NULL, 0, "mapistore_add_context");
187         uri_namespace = talloc_strdup(mem_ctx, uri);
188         namespace_start = uri_namespace;
189         uri_namespace= strchr(uri_namespace, ':');
190         if (!uri_namespace) {
191                 MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, "Invalid namespace '%s'\n", namespace_start);
192                 talloc_free(mem_ctx);
193                 return MAPISTORE_ERR_INVALID_NAMESPACE;
194         }
195
196         if (uri_namespace[1] && uri_namespace[1] == '/' &&
197             uri_namespace[2] && uri_namespace[2] == '/' &&
198             uri_namespace[3]) {
199                 backend_uri = talloc_strdup(mem_ctx, &uri_namespace[3]);
200                 uri_namespace[3] = '\0';
201                 backend_ctx = mapistore_backend_create_context((TALLOC_CTX *)mstore_ctx, login_user, username, namespace_start, backend_uri);
202                 if (!backend_ctx) {
203                         return MAPISTORE_ERR_CONTEXT_FAILED;
204                 }
205                 backend_ctx->username = talloc_strdup((TALLOC_CTX *)backend_ctx, username);
206
207                 backend_list = talloc_zero((TALLOC_CTX *) mstore_ctx, struct backend_context_list);
208                 talloc_steal(backend_list, backend_ctx);
209                 backend_list->ctx = backend_ctx;
210                 retval = mapistore_get_context_id(mstore_ctx->processing_ctx, &backend_list->ctx->context_id);
211                 if (retval != MAPISTORE_SUCCESS) {
212                         talloc_free(mem_ctx);
213                         return MAPISTORE_ERR_CONTEXT_FAILED;
214                 }
215                 *context_id = backend_list->ctx->context_id;
216                 DLIST_ADD_END(mstore_ctx->context_list, backend_list, struct backend_context_list *);
217
218         } else {
219                 MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, "Invalid URI '%s'\n", uri);
220                 talloc_free(mem_ctx);
221                 return MAPISTORE_ERR_INVALID_NAMESPACE;
222         }
223
224         talloc_free(mem_ctx);
225         return MAPISTORE_SUCCESS;
226 }
227
228
229 /**
230    \details Increase the reference counter of an existing context
231
232    \param mstore_ctx pointer to the mapistore context
233    \param context_id the context identifier referencing the context to
234    update
235
236    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
237  */
238 _PUBLIC_ enum MAPISTORE_ERROR mapistore_add_context_ref_count(struct mapistore_context *mstore_ctx,
239                                                               uint32_t context_id)
240 {
241         struct backend_context          *backend_ctx;
242         enum MAPISTORE_ERROR            retval;
243
244         /* Sanity checks */
245         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
246
247         /* TODO: Fix context_id sign */
248         MAPISTORE_RETVAL_IF((int)context_id == -1, MAPISTORE_ERR_INVALID_CONTEXT, NULL);
249
250         /* Step 0. Ensure the context exists */
251         MSTORE_DEBUG_INFO(MSTORE_LEVEL_DEBUG, "context to increment is %d\n", context_id);
252         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
253         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
254
255         /* Step 1. Increment the ref count */
256         retval = mapistore_backend_add_ref_count(backend_ctx);
257
258         return retval;
259 }
260
261
262 /**
263    \details Search for an existing context given its uri
264
265    \param mstore_ctx pointer to the mapistore context
266    \param uri the URI to lookup
267    \param context_id pointer to the context identifier to return
268
269    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
270  */
271 _PUBLIC_ enum MAPISTORE_ERROR mapistore_search_context_by_uri(struct mapistore_context *mstore_ctx,
272                                                               const char *uri,
273                                                               uint32_t *context_id)
274 {
275         struct backend_context          *backend_ctx;
276
277         /* Sanity checks */
278         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
279         MAPISTORE_RETVAL_IF(!uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
280
281         backend_ctx = mapistore_backend_lookup_by_uri(mstore_ctx->context_list, uri);
282         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_NOT_FOUND, NULL);
283
284         *context_id = backend_ctx->context_id;
285         return MAPISTORE_SUCCESS;
286 }
287
288
289 /**
290    \details Delete an existing connection context from mapistore
291
292    \param mstore_ctx pointer to the mapistore context
293    \param context_id the context identifier referencing the context to
294    delete
295
296    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
297  */
298 _PUBLIC_ enum MAPISTORE_ERROR mapistore_del_context(struct mapistore_context *mstore_ctx, 
299                                                     uint32_t context_id)
300 {
301         struct backend_context_list     *backend_list;
302         struct backend_context          *backend_ctx;
303         enum MAPISTORE_ERROR            retval;
304         bool                            found = false;
305
306         /* Sanity checks */
307         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
308
309         /* TODO: Fix context_id sign */
310         MAPISTORE_RETVAL_IF((int)context_id == -1, MAPISTORE_ERR_INVALID_CONTEXT, NULL);
311
312         /* Step 0. Ensure the context exists */
313         MSTORE_DEBUG_INFO(MSTORE_LEVEL_DEBUG, "context_id to delete is %d\n", context_id);
314         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
315         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
316
317         /* search the backend_list item */
318         for (backend_list = mstore_ctx->context_list; backend_list; backend_list = backend_list->next) {
319                 if (backend_list->ctx->context_id == context_id) {
320                         found = true;
321                         break;
322                 }               
323         }
324         if (found == false) {
325                 return MAPISTORE_ERROR;
326         }
327
328         /* Step 1. Delete the context within backend */
329         retval = mapistore_backend_delete_context(backend_ctx);
330         switch (retval) {
331         case MAPISTORE_ERR_REF_COUNT:
332                 return MAPISTORE_SUCCESS;
333         case MAPISTORE_SUCCESS:
334                 DLIST_REMOVE(mstore_ctx->context_list, backend_list);
335                 /* Step 2. Add the free'd context id to the free list */
336                 retval = mapistore_free_context_id(mstore_ctx->processing_ctx, context_id);
337                 break;
338         default:
339                 return retval;
340         }
341
342         return retval;
343 }
344
345
346 /**
347    \details Create a root default/system folder within the mailbox and
348    return the folder identifier
349
350    This operation is only meant to be called at mailbox provisioning
351    time.
352
353    \param mstore_ctx pointer to the mapistore context
354    \param context_id the context identifier referencing the backend
355    \param parent_index the parent default system/special folder index
356    \param index the default system/special folder index
357    \param folder_name the folder name to set
358
359    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
360  */
361 _PUBLIC_ enum MAPISTORE_ERROR mapistore_create_root_folder(struct mapistore_context *mstore_ctx,
362                                                            uint32_t context_id,
363                                                            enum MAPISTORE_DFLT_FOLDERS parent_index,
364                                                            enum MAPISTORE_DFLT_FOLDERS index,
365                                                            const char *folder_name)
366 {
367         enum MAPISTORE_ERROR            retval;
368         struct backend_context          *backend_ctx;
369         char                            *mapistore_uri;
370         char                            *parent_uri;
371         uint64_t                        fid;
372         uint64_t                        pfid;
373
374         /* Sanity checks */
375         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
376
377         /* Step 1. Search the context */
378         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
379         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
380
381         /* Step 2. Ensure the parent folder exists and retrieve its FID */
382         retval = mapistore_create_uri(mstore_ctx, parent_index, backend_ctx->backend->uri_namespace,
383                                       backend_ctx->username, &parent_uri);
384         MAPISTORE_RETVAL_IF(retval, retval, NULL);
385
386         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
387         MAPISTORE_RETVAL_IF(retval, retval, NULL);
388
389         retval = mapistore_indexing_record_search_uri(mstore_ctx->mapistore_indexing_list, parent_uri);
390         if (retval != MAPISTORE_ERR_EXIST) {
391                 talloc_free(parent_uri);
392                 goto error;
393         }
394
395         retval = mapistore_indexing_get_record_fmid_by_uri(mstore_ctx->mapistore_indexing_list, parent_uri, &pfid);
396         talloc_free(parent_uri);
397         if (retval) {
398                 goto error;
399         }
400
401         /* Step 3. Generate the URI */
402         retval = mapistore_create_uri(mstore_ctx, index, backend_ctx->backend->uri_namespace,
403                                       backend_ctx->username, &mapistore_uri);
404         if (retval) goto error;
405
406         /* Step 4. Call backend root_mkdir operation */
407         retval =  mapistore_backend_root_mkdir(backend_ctx, index, mapistore_uri, folder_name);
408         if (retval) {
409                 talloc_free(mapistore_uri);
410                 goto error;
411         }
412
413         /* Step 5. Get a new FID for the folder */
414         retval = mapistore_get_new_fmid(mstore_ctx->processing_ctx, backend_ctx->username, &fid);
415         if (retval) {
416                 talloc_free(mapistore_uri);
417                 goto error;
418         }
419         
420         /* Step 6. Register the folder within the indexing database */
421         retval = mapistore_indexing_add_fmid_record(mstore_ctx->mapistore_indexing_list, fid, 
422                                                     mapistore_uri, pfid, MAPISTORE_INDEXING_FOLDER);
423         talloc_free(mapistore_uri);
424         if (retval) goto error;
425
426 error:
427         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
428
429         /* Step 7. Very unlikely to happen ... but still delete the folder */
430         /* if (retval) { */
431
432         /* } */
433
434         return retval;
435 }
436
437 _PUBLIC_ enum MAPISTORE_ERROR mapistore_set_mapistore_uri(struct mapistore_context *mstore_ctx,
438                                                           uint32_t context_id,
439                                                           enum MAPISTORE_DFLT_FOLDERS index,
440                                                           const char *mapistore_uri)
441 {
442         enum MAPISTORE_ERROR            retval;
443         struct backend_context          *backend_ctx;
444         char                            *old_uri;
445         uint64_t                        fmid;
446         
447         /* Sanity checks */
448         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
449         MAPISTORE_RETVAL_IF(!mapistore_uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
450         
451         /* Step 1. Search the context */
452         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
453         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
454         
455         /* Step 2. Retrieve the URI associated to this system/default folder */
456         retval = mapistore_create_uri(mstore_ctx, index, backend_ctx->backend->uri_namespace,
457                                       backend_ctx->username, &old_uri);
458         MAPISTORE_RETVAL_IF(retval, retval, NULL);
459         
460         /* Step 3. Create the mapistore_indexing context */
461         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
462         MAPISTORE_RETVAL_IF(retval, retval, NULL);
463         
464         /* Step 4. Retrieve its FMID from the indexing database */
465         retval = mapistore_indexing_get_record_fmid_by_uri(mstore_ctx->mapistore_indexing_list, old_uri, &fmid);
466         if (retval) goto end;
467         
468         /* Step 5. Update the URI within the indexing database */
469         retval = mapistore_indexing_update_mapistore_uri(mstore_ctx->mapistore_indexing_list, fmid, mapistore_uri);
470         if (retval) goto end;
471         
472 end:
473         /* Step 6. Delete the indexing context */
474         retval = mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
475         
476         return retval;
477 }
478
479 /**
480    \details Retrieve the next backend available in the list
481
482    \param backend_name pointer to the backend name to return
483    \param backend_namespace pointer to the backend namespace to return
484    \param backend_description pointer to the backend description to
485    return
486    \param backend_index pointer to the backend index in the the
487    backend's list to return
488
489    \note backend_index must be initialized to 0 prior any calls to
490    mapistore_get_next_backend.
491
492    \return MAPISTORE_SUCCESS on success, MAPISTORE_ERR_NOT_FOUND if
493    the end of the list is reached, otherwise MAPISTORE error
494  */
495 enum MAPISTORE_ERROR mapistore_get_next_backend(const char **backend_name,
496                                                 const char **backend_namespace,
497                                                 const char **backend_description,
498                                                 uint32_t *backend_index)
499 {
500         enum MAPISTORE_ERROR            retval;
501         const char                      *_backend_name;
502         const char                      *_backend_namespace;
503         const char                      *_backend_description;
504         uint32_t                        _backend_index;
505
506         /* Sanity checks */
507         MAPISTORE_RETVAL_IF(!backend_name && !backend_namespace && !backend_description, 
508                             MAPISTORE_ERR_INVALID_PARAMETER, NULL);
509         MAPISTORE_RETVAL_IF(!backend_index, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
510
511         _backend_index = *backend_index;
512         retval = mapistore_backend_get_next_backend(&_backend_name, 
513                                                     &_backend_namespace,
514                                                     &_backend_description,
515                                                     &_backend_index);
516         MAPISTORE_RETVAL_IF(retval, retval, NULL);
517
518         if (backend_name) {
519                 *backend_name = _backend_name;
520         }
521
522         if (backend_namespace) {
523                 *backend_namespace = _backend_namespace;
524         }
525         
526         if (backend_description) {
527                 *backend_description = _backend_description;
528         }
529
530         *backend_index = _backend_index;
531
532         return MAPISTORE_SUCCESS;
533 }
534
535 /**
536    \details Retrieve the LDIF data associated to registered backends
537    by sequentially calling op_db_provision_namedprops operation.
538
539    \param mstore_ctx pointer to the mapistore context
540    \param backend_name pointer on pointer to the backend name to return
541    \param ldif pointer on pointer to the LDIF data to return
542    \param ntype pointer to the type of LDIF data to return
543
544    \note It is also up to the caller application to free memory
545    associated to ldif data.
546
547    \return MAPISTORE_SUCCESS on success, or MAPISTORE_ERR_NOT_FOUND if
548    there is no more available backends, otherwise MAPISTORE_ERROR
549  */
550 enum MAPISTORE_ERROR mapistore_get_backend_ldif(struct mapistore_context *mstore_ctx,
551                                                 const char *backend_name,
552                                                 char **ldif,
553                                                 enum MAPISTORE_NAMEDPROPS_PROVISION_TYPE *ntype)
554 {
555         enum MAPISTORE_ERROR                            retval;
556         enum MAPISTORE_NAMEDPROPS_PROVISION_TYPE        _ntype;
557         char                                            *_ldif;
558         
559         /* Sanity checks */
560         MAPISTORE_RETVAL_IF(!mstore_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
561         MAPISTORE_RETVAL_IF(!backend_name, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
562         MAPISTORE_RETVAL_IF(!ldif, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
563         MAPISTORE_RETVAL_IF(!ntype, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
564
565         retval = mapistore_backend_get_namedprops_ldif((TALLOC_CTX *) mstore_ctx, backend_name, &_ldif, &_ntype);
566
567         MAPISTORE_RETVAL_IF(retval, retval, NULL);
568
569         *ldif = _ldif;
570         *ntype = _ntype;
571
572         return MAPISTORE_SUCCESS;
573 }
574
575
576 /**
577    \details Release private backend data associated a folder / message
578    opened within the mapistore backend
579
580    \param mstore_ctx pointer to the mapistore context
581    \param context_id the context identifier referencing the backend
582    \param fmid a folder or message identifier
583    \param type the type of fmid, either MAPISTORE_FOLDER or MAPISTORE_MESSAGE
584
585    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
586  */
587 _PUBLIC_ enum MAPISTORE_ERROR mapistore_release_record(struct mapistore_context *mstore_ctx,
588                                                        uint32_t context_id,
589                                                        uint64_t fmid,
590                                                        uint8_t type)
591 {
592         enum MAPISTORE_ERROR            retval;
593         struct backend_context          *backend_ctx;
594         char                            *uri;
595
596         /* Sanity checks */
597         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
598         MAPISTORE_RETVAL_IF(!context_id, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
599         MAPISTORE_RETVAL_IF(!fmid, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
600
601         /* Step 1. Search the context */
602         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
603         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
604
605         /* Step 2. Add an indexing context */
606         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
607         MAPISTORE_RETVAL_IF(retval, retval, NULL);
608
609         /* Step 3. Search the URI matching the specified FMID within the username indexing database */
610         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, fmid, &uri);
611         if (retval) {
612                 MSTORE_DEBUG_ERROR(MSTORE_LEVEL_NORMAL, 
613                                    "Failed to find URI matching the following FMID for user %s: 0x%.16"PRIx64"\n",
614                                    backend_ctx->username, fmid);
615                 goto error;
616         }
617
618         /* Step 4. Call backend release_record */
619         retval = mapistore_backend_release_record(backend_ctx, (const char *)uri, type);
620
621 error:
622         /* Step 5. Delete indexing context */
623         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
624         return retval;
625 }
626
627
628 /**
629    \details Associate an indexing context to a mapistore context
630
631    \param mstore_ctx pointer to the mapistore context
632    \param username account name referencing the indexing record
633    \param context_id the context identifier referencing the context to
634    alter
635
636    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
637  */
638 _PUBLIC_ enum MAPISTORE_ERROR mapistore_add_context_indexing(struct mapistore_context *mstore_ctx,
639                                                              const char *username,
640                                                              uint32_t context_id)
641 {
642         struct indexing_context_list    *indexing_ctx;
643         struct backend_context          *backend_ctx;
644
645         /* Sanity checks */
646         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
647         MAPISTORE_RETVAL_IF(!username, MAPISTORE_ERROR, NULL);
648         /* TODO: Fix context_id sign */
649         MAPISTORE_RETVAL_IF((int)context_id == -1, MAPISTORE_ERROR, NULL);
650
651         /* Step 0. Ensure the context exists */
652         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
653         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
654         /* If the indexing pointer is already existing, return success */
655         MAPISTORE_RETVAL_IF(backend_ctx->indexing, MAPISTORE_SUCCESS, NULL);
656
657         /* Step 1. Search the indexing record */
658         indexing_ctx = mapistore_indexing_search(mstore_ctx, username);
659         MAPISTORE_RETVAL_IF(!indexing_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
660
661         /* Step 2. Reference the indexing record within backend context */
662         backend_ctx->indexing = indexing_ctx;
663
664         /* Step 3. Increment the indexing ref counter */
665         mapistore_indexing_add_ref_count(indexing_ctx);
666
667         MSTORE_DEBUG_SUCCESS(MSTORE_LEVEL_DEBUG, "Add content indexing for username: %s\n", backend_ctx->indexing->username);
668         return MAPISTORE_SUCCESS;
669 }
670
671
672 void mapistore_set_errno(int status)
673 {
674         errno = status;
675 }
676
677
678 /**
679    \details return a string explaining what a mapistore error constant
680    means.
681
682    \param mapistore_err the mapistore error constant
683
684    \return constant string
685  */
686 _PUBLIC_ const char *mapistore_errstr(enum MAPISTORE_ERROR mapistore_err)
687 {
688         switch (mapistore_err) {
689         case MAPISTORE_SUCCESS:
690                 return "Success";
691         case MAPISTORE_ERROR:
692                 return "Non-specific error";
693         case MAPISTORE_ERR_NO_MEMORY:
694                 return "No memory available";
695         case MAPISTORE_ERR_ALREADY_INITIALIZED:
696                 return "Already initialized";
697         case MAPISTORE_ERR_NOT_INITIALIZED:
698                 return "Not initialized";
699         case MAPISTORE_ERR_CORRUPTED:
700                 return "Corrupted";
701         case MAPISTORE_ERR_INVALID_PARAMETER:
702                 return "Invalid parameter";
703         case MAPISTORE_ERR_NO_DIRECTORY:
704                 return "No such file or directory";
705         case MAPISTORE_ERR_DATABASE_INIT:
706                 return "Database initialization failed";
707         case MAPISTORE_ERR_DATABASE_OPS:
708                 return "Database operation failed";
709         case MAPISTORE_ERR_BACKEND_REGISTER:
710                 return "Storage backend registration failed";
711         case MAPISTORE_ERR_BACKEND_INIT:
712                 return "Storage backend initialization failed";
713         case MAPISTORE_ERR_CONTEXT_FAILED:
714                 return "Context creation failed";
715         case MAPISTORE_ERR_INVALID_NAMESPACE:
716                 return "Invalid namespace";
717         case MAPISTORE_ERR_NOT_FOUND:
718                 return "Record or data not found";
719         case MAPISTORE_ERR_REF_COUNT:
720                 return "Reference count still exists";
721         case MAPISTORE_ERR_EXIST:
722                 return "Already exists";
723         case MAPISTORE_ERR_INVALID_OBJECT:
724                 return "Invalid object";
725         case MAPISTORE_ERR_INVALID_CONTEXT:
726                 return "Invalid mapistore context";
727         case MAPISTORE_ERR_INVALID_URI:
728                 return "Invalid mapistore URI";
729         case MAPISTORE_ERR_NOT_IMPLEMENTED:
730                 return "Not implemented";
731         case MAPISTORE_ERR_RESERVED:
732                 return "Record or data reserved";
733         }
734
735         return "Unknown error";
736 }
737
738
739 _PUBLIC_ enum MAPISTORE_ERROR mapistore_create_uri(struct mapistore_context *mstore_ctx,
740                                                    uint32_t index,
741                                                    const char *namespace_uri,
742                                                    const char *username,
743                                                    char **_uri)
744 {
745         enum MAPISTORE_ERROR    ret;
746         char                    *uri;
747         char                    *ref_str;
748         char                    *ns;
749
750         /* Sanity checks */
751         MAPISTORE_RETVAL_IF((!namespace_uri || strlen(namespace_uri) < 4), MAPISTORE_ERR_INVALID_NAMESPACE, NULL);
752
753         ref_str = (char *)namespace_uri;
754         ns = strchr(namespace_uri, ':');
755         if (!ns) {
756                 MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, "Invalid namespace '%s'\n", ref_str);
757                 return MAPISTORE_ERR_INVALID_NAMESPACE;
758         }
759
760         if (ns[1] && ns[1] == '/' && ns[2] && ns[2] == '/') {
761                 if (ns[3]) {
762                         ns[3] = '\0';
763                 }
764                 ret = mapistore_backend_create_uri((TALLOC_CTX *)mstore_ctx, index, ref_str, username, &uri);
765                 if (ret == MAPISTORE_SUCCESS) {
766                         *_uri = uri;
767                 }
768                 return ret;
769         }
770
771         return MAPISTORE_ERR_NOT_FOUND;
772 }
773
774 /**
775    \details Return the URI for a default folder within a given context
776
777    \param mstore_ctx pointer to the mapistore context
778    \param context_id the context identifier
779    \param index the mapistore default folder to search
780    \param _uri pointer on pointer to the mapistore URI to return
781
782    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
783  */
784 enum MAPISTORE_ERROR mapistore_create_context_uri(struct mapistore_context *mstore_ctx,
785                                                   uint32_t context_id, 
786                                                   enum MAPISTORE_DFLT_FOLDERS index,
787                                                   char **_uri)
788 {
789         enum MAPISTORE_ERROR            retval;
790         struct backend_context          *backend_ctx;
791         char                            *uri;
792
793         /* Sanity checks */
794         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
795         MAPISTORE_RETVAL_IF(!context_id, MAPISTORE_ERR_INVALID_CONTEXT, NULL);
796         MAPISTORE_RETVAL_IF(!index, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
797         MAPISTORE_RETVAL_IF(!_uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
798
799         /* Step 1. Search the context */
800         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
801         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
802
803         retval = mapistore_create_uri(mstore_ctx, index, backend_ctx->backend->uri_namespace, backend_ctx->username, &uri);
804         MAPISTORE_RETVAL_IF(retval, retval, NULL);
805
806         *_uri = uri;
807         
808         return MAPISTORE_SUCCESS;
809 }
810
811 /**
812    \details Return the folder identifier associated to a mapistore URI
813    relative to a context identifier. 
814
815    \param mstore_ctx pointer to the mapistore context
816    \param context_id the mapistore context identifier
817    \param uri the mapistore URI to lookup
818    \param folderID pointer to the folder identifier to return
819
820    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
821  */
822 enum MAPISTORE_ERROR mapistore_get_folder_identifier_from_uri(struct mapistore_context *mstore_ctx,
823                                                               uint32_t context_id,
824                                                               const char *uri,
825                                                               uint64_t *folderID)
826 {
827         enum MAPISTORE_ERROR    retval;
828         struct backend_context  *backend_ctx;
829         uint64_t                fid;
830
831         /* Sanity checks */
832         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
833         MAPISTORE_RETVAL_IF(!context_id, MAPISTORE_ERR_INVALID_CONTEXT, NULL);
834         MAPISTORE_RETVAL_IF(!uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
835         MAPISTORE_RETVAL_IF(!folderID, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
836
837         /* Step 1. Ensure the context exists */
838         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
839         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
840
841         /* Step 2. Add an indexing context */
842         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
843         MAPISTORE_RETVAL_IF(retval, retval, NULL);
844
845         /* Step 3. Search for the FID matching the specified URI within the username indexing database */
846         retval = mapistore_indexing_get_record_fmid_by_uri(mstore_ctx->mapistore_indexing_list, uri, &fid);
847         if (retval) {
848                 MSTORE_DEBUG_ERROR(MSTORE_LEVEL_NORMAL, "Failed to find FID matcthing the following URI for user %s: %s\n",
849                                    backend_ctx->username, uri);
850                 goto error;
851         }
852
853         /* Step 4. Copy parameter */
854         *folderID = fid;
855
856 error:
857         /* Step 5. Delete indexing context */
858         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
859         return retval;
860 }
861
862
863 /**
864    \details Open a directory in mapistore
865
866    \param mstore_ctx pointer to the mapistore context
867    \param context_id the context identifier referencing the backend
868    where the directory will be opened
869    \param parent_fid the parent folder identifier
870    \param fid folder identifier to open
871
872    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
873  */
874 _PUBLIC_ enum MAPISTORE_ERROR mapistore_opendir(struct mapistore_context *mstore_ctx,
875                                                 uint32_t context_id,
876                                                 uint64_t parent_fid,
877                                                 uint64_t fid)
878 {
879         enum MAPISTORE_ERROR            retval;
880         struct backend_context          *backend_ctx;
881         char                            *parent_uri;
882         char                            *folder_uri;
883
884         /* Sanity checks */
885         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
886
887         /* Step 1. Search the context */
888         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
889         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
890
891         /* Step 2. Create an indexing context */
892         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
893         MAPISTORE_RETVAL_IF(retval, retval, NULL);
894
895         /* Step 2. Turn parent folder identifier into URI */
896         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, parent_fid, &parent_uri);
897         if (retval) goto error;
898
899         /* Step 3. Turn folder identifier into URI */
900         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, fid, &folder_uri);
901         if (retval) goto error;
902
903         /* Step 4. Call backend opendir */
904         retval = mapistore_backend_opendir(backend_ctx, parent_uri, folder_uri);
905
906         /* Add a reference count? */
907         
908 error:
909         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
910         return !retval ? MAPISTORE_SUCCESS : MAPISTORE_ERROR;
911 }
912
913
914 /**
915    \details Close a directory in mapistore
916
917    \param mstore_ctx pointer to the mapistore context
918    \param context_id the context identifier referencing the backend
919    where the directory has to be closed/released
920    \param fid the folder identifier referencing the folder to close
921
922    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
923  */
924 _PUBLIC_ enum MAPISTORE_ERROR mapistore_closedir(struct mapistore_context *mstore_ctx,
925                                                  uint32_t context_id,
926                                                  uint64_t fid)
927 {
928         struct backend_context          *backend_ctx;
929
930         /* Sanity checks */
931         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
932
933         /* Step 0. Search the context */
934         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
935         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
936
937         /* mapistore_backend_closedir() */
938
939         return MAPISTORE_SUCCESS;
940 }
941
942
943 /**
944    \details Create a directory in mapistore
945
946    \param mstore_ctx pointer to the mapistore context
947    \param context_id the context identifier referencing the backend
948    where the directory will be created
949    \param parent_fid the parent folder identifier
950    \param folder_name the name for the new folder, must not be null
951    \param folder_desc the description (comment) for the new folder, can be null
952    \param folder_type the type of folder (FOLDER_GENERIC or FOLDER_SEARCH)
953    \param fid the folder ID for the folder that has been created (return value)
954
955    Note that fid is only valid on success
956
957    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
958  */
959 _PUBLIC_ enum MAPISTORE_ERROR mapistore_mkdir(struct mapistore_context *mstore_ctx,
960                                               uint32_t context_id,
961                                               uint64_t parent_fid,
962                                               const char *folder_name,
963                                               const char *folder_desc,
964                                               enum FOLDER_TYPE folder_type,
965                                               uint64_t *fid)
966 {
967         struct backend_context          *backend_ctx = NULL;
968         enum MAPISTORE_ERROR            retval;
969         char                            *parent_uri = NULL;
970         uint64_t                        folder_fid = 0;
971         char                            *folder_uri = NULL;
972
973         /* Sanity checks */
974         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
975         MAPISTORE_RETVAL_IF(!folder_name, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
976         MAPISTORE_RETVAL_IF(!fid, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
977         MAPISTORE_RETVAL_IF(folder_type != FOLDER_GENERIC && folder_type != FOLDER_SEARCH, 
978                             MAPISTORE_ERR_INVALID_PARAMETER, NULL);
979
980         /* Find the backend context to work within */
981         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
982         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);       
983
984         /* Create an indexing context */
985         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
986         MAPISTORE_RETVAL_IF(retval, retval, NULL);
987
988         /* Turn parent folder identifier into URI */
989         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, parent_fid, &parent_uri);
990         if (retval) goto cleanup;
991
992         /* Call backend mkdir */
993         retval = mapistore_backend_mkdir(backend_ctx, parent_uri, folder_name, folder_desc, folder_type, &folder_uri);
994         if (retval) goto cleanup;
995
996         /* Get a new FID for the folder */
997         retval = mapistore_get_new_fmid(mstore_ctx->processing_ctx, backend_ctx->username, &folder_fid);
998         if (retval) goto cleanup;
999
1000         /* Register the folder within the indexing database */
1001         retval = mapistore_indexing_add_fmid_record(mstore_ctx->mapistore_indexing_list, folder_fid,
1002                                                     folder_uri, parent_fid, MAPISTORE_INDEXING_FOLDER);
1003
1004         /* Return that folder ID to the caller for future use */
1005         *fid = folder_fid;
1006
1007 cleanup:
1008         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1009
1010         if (folder_uri) {
1011                 MSTORE_DEBUG_INFO(MSTORE_LEVEL_INFO, "folder_uri = %s\n", folder_uri);
1012                 talloc_free(folder_uri);
1013         }
1014
1015         return retval;
1016 }
1017
1018
1019 /**
1020    \details Remove a directory in mapistore
1021
1022    \param mstore_ctx pointer to the mapistore context
1023    \param context_id the context identifier referencing the backend
1024    \param parent_fid the parent folder identifier
1025    \param fid the folder identifier representing the folder to delete
1026    \param flags flags that control the behaviour of the operation
1027
1028    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1029  */
1030 _PUBLIC_ enum MAPISTORE_ERROR mapistore_rmdir(struct mapistore_context *mstore_ctx,
1031                                               uint32_t context_id,
1032                                               uint64_t parent_fid,
1033                                               uint64_t fid,
1034                                               uint8_t flags)
1035 {
1036         struct backend_context          *backend_ctx;
1037         enum MAPISTORE_ERROR            retval;
1038         char                            *parent_uri;
1039         char                            *folder_uri;
1040
1041         /* Sanity checks */
1042         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1043
1044         /* Step 1. Find the backend context */
1045         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1046         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);       
1047
1048         /* Step 2. Create the mapistore_indexing context */
1049         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1050         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1051
1052         /* Retrieve URI associated to parent and folder ID */
1053         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, parent_fid, &parent_uri);
1054         if (retval) goto error;
1055
1056         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, fid, &folder_uri);
1057         if (retval) goto error;
1058
1059         /* Step 2. Handle deletion of child folders / messages */
1060         if (flags | DEL_FOLDERS) {
1061                 uint64_t        *childFolders;
1062                 uint32_t        childFolderCount;
1063                 int             retval;
1064                 uint32_t        i;
1065
1066                 /* Get subfolders list */
1067                 retval = mapistore_get_child_fids(mstore_ctx, context_id, fid,
1068                                                   &childFolders, &childFolderCount);
1069                 if (retval) {
1070                         retval = MAPISTORE_ERR_NOT_FOUND;
1071                         goto error;
1072                 }
1073
1074                 /* Delete each subfolder in mapistore */
1075                 for (i = 0; i < childFolderCount; ++i) {
1076                         retval = mapistore_rmdir(mstore_ctx, context_id, fid, childFolders[i], flags);
1077                         if (retval) {
1078                                   talloc_free(childFolders);
1079                                   retval = MAPISTORE_ERR_NOT_FOUND;
1080                                   goto error;
1081                         }
1082                 }
1083
1084         }
1085         
1086         /* Step 3. Call backend rmdir */
1087         retval = mapistore_backend_rmdir(backend_ctx, parent_uri, folder_uri);
1088
1089 error:
1090         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1091
1092         return retval;
1093 }
1094
1095
1096 /**
1097    \details Retrieve the number of child folders within a mapistore
1098    folder
1099
1100    \param mstore_ctx pointer to the mapistore context
1101    \param context_id the context identifier referencing the backend
1102    \param fid the folder identifier
1103    \param RowCount pointer to the count result to return
1104
1105    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1106  */
1107 _PUBLIC_ enum MAPISTORE_ERROR mapistore_get_folder_count(struct mapistore_context *mstore_ctx,
1108                                                          uint32_t context_id,
1109                                                          uint64_t fid,
1110                                                          uint32_t *RowCount)
1111 {
1112         struct backend_context          *backend_ctx;
1113         enum MAPISTORE_ERROR            retval;
1114         char                            *folder_uri;
1115
1116         /* Sanity checks */
1117         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1118         MAPISTORE_RETVAL_IF(!RowCount, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1119
1120         /* Step 1. Ensure the context exists */
1121         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1122         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1123
1124         /* Step 2. Create the mapistore_indexing context */
1125         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1126         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1127
1128         /* Step 3. Retrieve the folder URI from the indexing database */
1129         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, fid, &folder_uri);
1130         if (retval) goto error;
1131
1132         /* Step 4. Call backend readdir */
1133         retval = mapistore_backend_readdir_count(backend_ctx, (const char *)folder_uri, MAPISTORE_FOLDER_TABLE, RowCount);
1134
1135 error:
1136         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1137
1138         return retval;
1139 }
1140
1141
1142 /**
1143    \details Retrieve the number of child messages within a mapistore folder
1144
1145    \param mstore_ctx pointer to the mapistore context
1146    \param context_id the context identifier referencing the backend
1147    \param fid the folder identifier
1148    \param RowCount pointer to the count result to return
1149
1150    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1151  */
1152 _PUBLIC_ enum MAPISTORE_ERROR mapistore_get_message_count(struct mapistore_context *mstore_ctx,
1153                                                           uint32_t context_id,
1154                                                           uint64_t fid,
1155                                                           uint32_t *RowCount)
1156 {
1157         struct backend_context          *backend_ctx;
1158         enum MAPISTORE_ERROR            retval;
1159         char                            *folder_uri;
1160
1161         /* Sanity checks */
1162         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1163         MAPISTORE_RETVAL_IF(!RowCount, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1164
1165         /* Step 1. Ensure the context exists */
1166         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1167         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1168         
1169         /* Step 2. Create the mapistore_indexing context */
1170         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1171         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1172
1173         /* Step 3. Retrieve the folder URI from the indexing database */
1174         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, fid, &folder_uri);
1175         if (retval) goto error;
1176
1177         /* Step 2. Call backend readdir_count */
1178         retval = mapistore_backend_readdir_count(backend_ctx, (const char *)folder_uri, MAPISTORE_MESSAGE_TABLE, RowCount);
1179
1180 error:
1181         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1182
1183         return retval;
1184 }
1185
1186
1187 /**
1188    \details Retrieve a MAPI property from a table
1189
1190    \param mstore_ctx pointer to the mapistore context
1191    \param context_id the context identifier referencing the backend
1192    \param table_type the type of table (folders or messges)
1193    \param fid the folder identifier where the search takes place
1194    \param proptag the MAPI property tag to retrieve value for
1195    \param pos the record position in search results
1196    \param data pointer on pointer to the data the function returns
1197
1198    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1199  */
1200 _PUBLIC_ enum MAPISTORE_ERROR mapistore_get_table_property(struct mapistore_context *mstore_ctx,
1201                                                            uint32_t context_id,
1202                                                            enum MAPISTORE_TABLE_TYPE table_type,
1203                                                            uint64_t fid,
1204                                                            enum MAPITAGS proptag,
1205                                                            uint32_t pos,
1206                                                            void **data)
1207 {
1208         struct backend_context          *backend_ctx;
1209         enum MAPISTORE_ERROR            retval;
1210         char                            *folder_uri;
1211
1212         /* Sanity checks */
1213         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1214         MAPISTORE_RETVAL_IF(!data, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1215
1216         /* Step 1. Ensure the context exists */
1217         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1218         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1219
1220         /* Step 2. Create the mapistore_indexing context */
1221         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1222         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1223
1224         /* Step 3. Retrieve the URI for the folder */
1225         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, fid, &folder_uri);
1226         if (retval) goto error;
1227
1228         /* Step 2. Call backend readdir */
1229         retval = mapistore_backend_get_table_property(backend_ctx, (const char *)folder_uri, table_type, pos, proptag, data);
1230
1231 error:
1232         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1233
1234         return retval;
1235 }
1236
1237
1238 /**
1239    \details Open a message in mapistore
1240
1241    \param mstore_ctx pointer to the mapistore context
1242    \param context_id the context identifier referencing the backend
1243    where the directory will be opened
1244    \param parent_fid the parent folder identifier
1245    \param mid the message identifier to open
1246    \param msg pointer to the mapistore_message structure (result)
1247
1248    \return MAPISTORE SUCCESS on success, otherwise MAPISTORE errors
1249  */
1250 _PUBLIC_ enum MAPISTORE_ERROR mapistore_openmessage(struct mapistore_context *mstore_ctx,
1251                                                     uint32_t context_id,
1252                                                     uint64_t parent_fid,
1253                                                     uint64_t mid,
1254                                                     struct mapistore_message *msg)
1255 {
1256         enum MAPISTORE_ERROR            retval;
1257         struct backend_context          *backend_ctx;
1258         char                            *parent_uri;
1259         char                            *message_uri;
1260
1261         /* Sanity checks */
1262         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1263         MAPISTORE_RETVAL_IF(!msg, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1264
1265         /* Step 1. Search the context */
1266         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1267         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1268
1269         /* Step 2. Create the mapistore_indexing context */
1270         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1271         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1272
1273         /* Step 3. Retrieve the URI for parent folder and message */
1274         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, parent_fid, &parent_uri);
1275         if (retval) goto error;
1276
1277         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, mid, &message_uri);
1278         if (retval) goto error;
1279
1280         /* Step 4. Call backend openmessage */
1281         retval = mapistore_backend_openmessage(backend_ctx, parent_uri, message_uri, msg);
1282
1283 error:
1284         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1285
1286         return retval;
1287 }
1288
1289
1290 /**
1291    \details Create a message in mapistore
1292
1293    \param mstore_ctx pointer to the mapistore context
1294    \param context_id the context identifier referencing the backend
1295    where the message will be created
1296    \param parent_fid the parent folder identifier
1297
1298    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1299  */
1300 _PUBLIC_ enum MAPISTORE_ERROR mapistore_createmessage(struct mapistore_context *mstore_ctx,
1301                                                       uint32_t context_id,
1302                                                       uint64_t parent_fid)
1303 {
1304         enum MAPISTORE_ERROR            retval;
1305         struct backend_context          *backend_ctx;
1306         char                            *parent_uri;
1307         char                            *message_uri = NULL;
1308         bool                            uri_register = false;
1309
1310         /* Sanity checks */
1311         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1312
1313         /* Step 1. Search the context */
1314         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1315         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1316
1317         /* Step 2. Create the mapistore_indexing context */
1318         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1319         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1320
1321         /* Step 3. Retrieve the URI for parent folder */
1322         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, parent_fid, &parent_uri);
1323         if (retval) goto error;
1324
1325         /* Step 4. Call backend createmessage */
1326         retval = mapistore_backend_createmessage(backend_ctx, parent_uri, &message_uri, &uri_register);
1327         if (retval) goto error;
1328         
1329         /* Step 5. FIXME: Do appropriate mapistore work depending on uri_register value */
1330
1331 error:
1332         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1333
1334         return retval;
1335 }
1336
1337
1338 /**
1339    \details Commit the changes made to a message in mapistore
1340
1341    \param mstore_ctx pointer to the mapistore context
1342    \param context_id the context identifier referencing the backend
1343    where the message's changes will be saved
1344    \param mid the message identifier to return or save
1345    \param flags flags associated to the commit operation
1346
1347    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1348  */
1349 _PUBLIC_ enum MAPISTORE_ERROR mapistore_savechangesmessage(struct mapistore_context *mstore_ctx,
1350                                                            uint32_t context_id,
1351                                                            uint64_t *mid,
1352                                                            uint8_t flags)
1353 {
1354         enum MAPISTORE_ERROR    retval;
1355         struct backend_context  *backend_ctx;
1356         char                    *message_uri;
1357
1358         /* Sanity checks */
1359         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1360
1361         /* Step 1. Search the context */
1362         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1363         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1364
1365         /* FIXME: It's either a temporary (not committed mid) or an
1366          * existing message. Take appropriate action depending on
1367          * mid value */
1368
1369         /* Step 2. Create the mapistore_indexing context */
1370         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1371         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1372
1373         /* Step 3. Retrieve the URI for parent folder */
1374         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, *mid, &message_uri);
1375         if (retval) goto error;
1376
1377         /* Step 4. Call backend savechangesmessage */
1378         retval = mapistore_backend_savechangesmessage(backend_ctx, message_uri, flags);
1379
1380 error:
1381         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1382
1383         return retval;
1384 }
1385
1386
1387 /**
1388    \details Submits a message for sending.
1389
1390    \param mstore_ctx pointer to the mapistore context
1391    \param context_id the context identifier referencing the backend
1392    where the message will be submitted
1393    \param mid the message identifier representing the message to submit
1394    \param flags flags associated to the submit operation
1395
1396    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1397  */
1398 _PUBLIC_ enum MAPISTORE_ERROR mapistore_submitmessage(struct mapistore_context *mstore_ctx,
1399                                                       uint32_t context_id,
1400                                                       uint64_t *mid,
1401                                                       uint8_t flags)
1402 {
1403         enum MAPISTORE_ERROR    retval;
1404         struct backend_context  *backend_ctx;
1405         char                    *message_uri;
1406
1407         /* Sanity checks */
1408         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1409
1410         /* Step 1. Search the context */
1411         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1412         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1413
1414         /* FIXME: It's either a temporary (not committed mid) or an
1415          * existing message. Take appropriate action depending on
1416          * mid value */
1417
1418         /* Step 2. Create the mapistore_indexing context */
1419         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1420         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1421
1422         /* Step 3. Retrieve the URI for the message */
1423         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, *mid, &message_uri);
1424         if (retval) goto error;
1425
1426         /* Step 2. Call backend submitmessage */
1427         retval = mapistore_backend_submitmessage(backend_ctx, message_uri, flags);
1428
1429 error:
1430         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1431         
1432         return retval;
1433 }
1434
1435
1436 /**
1437    \details Get properties of a message/folder in mapistore
1438
1439    \param mstore_ctx pointer to the mapistore context
1440    \param context_id the context identifier referencing the backend
1441    where properties will be fetched
1442    \param fmid the identifier referencing the message/folder
1443    \param type the object type (folder or message)
1444    \param properties pointer to the list of properties to fetch
1445    \param aRow pointer to the SRow structure
1446
1447    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1448  */
1449 _PUBLIC_ enum MAPISTORE_ERROR mapistore_getprops(struct mapistore_context *mstore_ctx,
1450                                                  uint32_t context_id,
1451                                                  uint64_t fmid,
1452                                                  uint8_t type,
1453                                                  struct SPropTagArray *properties,
1454                                                  struct SRow *aRow)
1455 {
1456         enum MAPISTORE_ERROR    retval;
1457         struct backend_context  *backend_ctx;
1458         char                    *uri;
1459
1460         /* Sanity checks */
1461         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1462
1463         /* Step 1. Search the context */
1464         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1465         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1466
1467         /* Step 2. Create the mapistore_indexing context */
1468         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1469         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1470
1471         /* Step 3. Retrieve the uri for the fmid from the indexing database */
1472         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, fmid, &uri);
1473         if (retval) goto error;
1474
1475         /* Step 4. Call backend getprops */
1476         retval = mapistore_backend_getprops(backend_ctx, uri, type, properties, aRow);
1477
1478 error:
1479         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1480
1481         return retval;
1482 }
1483
1484 /**
1485    \details Search for a folder ID by name
1486
1487    \param mstore_ctx pointer to the mapistore context
1488    \param context_id the context identifier referencing the backend
1489    where the folder will be searched for
1490    \param parent_fid the parent folder identifier
1491    \param name the name of the folder to search for
1492    \param fid the fid (result)
1493
1494    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1495  */
1496 _PUBLIC_ enum MAPISTORE_ERROR mapistore_get_fid_by_name(struct mapistore_context *mstore_ctx,
1497                                                         uint32_t context_id,
1498                                                         uint64_t parent_fid,
1499                                                         const char *name,
1500                                                         uint64_t *fid)
1501 {
1502         enum MAPISTORE_ERROR    retval;
1503         struct backend_context  *backend_ctx;
1504         char                    *uri;
1505         char                    *parent_uri;
1506
1507         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1508         MAPISTORE_RETVAL_IF(!name, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1509         MAPISTORE_RETVAL_IF(!fid, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1510
1511         /* Step 1. Search the context */
1512         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1513         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1514
1515         /* Step 2. Create the mapistore_indexing context */
1516         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1517         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1518
1519         /* Step 3. Retrieve the folder URI from the indexing database */
1520         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, parent_fid, &parent_uri);
1521         if (retval) goto error;
1522
1523         /* Step 2. Call backend getprops */
1524         retval = mapistore_backend_get_fid_by_name(backend_ctx, parent_uri, name, &uri);
1525         if (retval) goto error;
1526
1527         /* Step 3. Retrieve the FID associated to this uri*/
1528         retval = mapistore_indexing_get_record_fmid_by_uri(mstore_ctx->mapistore_indexing_list, uri, fid);
1529
1530 error:
1531         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1532
1533         return retval;
1534 }
1535
1536 /**
1537    \details Set properties of a message/folder in mapistore
1538
1539    \param mstore_ctx pointer to the mapistore context
1540    \param context_id the context identifier referencing the backend
1541    where properties will be stored
1542    \param fmid the identifier referencing the message/folder
1543    \param type the object type (folder or message)
1544    \param aRow pointer to the SRow structure
1545
1546    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1547  */
1548 _PUBLIC_ enum MAPISTORE_ERROR mapistore_setprops(struct mapistore_context *mstore_ctx,
1549                                                  uint32_t context_id,
1550                                                  uint64_t fmid,
1551                                                  uint8_t type,
1552                                                  struct SRow *aRow)
1553 {
1554         enum MAPISTORE_ERROR    retval;
1555         struct backend_context  *backend_ctx;
1556         char                    *uri;
1557
1558         /* Sanity checks */
1559         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1560
1561         /* Step 1. Search the context */
1562         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1563         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1564
1565         /* Step 2. Create mapistore_indexing context */
1566         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1567         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1568
1569         /* Step 3. Retrieve the uri for the fmid from the indexing database */
1570         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, fmid, &uri);
1571         if (retval) goto error;
1572
1573         /* Step 4. Call backend setprops */
1574         retval = mapistore_backend_setprops(backend_ctx, uri, type, aRow);
1575
1576 error:
1577         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1578         
1579         return retval;
1580 }
1581
1582
1583 /**
1584    \details Retrieve the folder IDs of child folders within a mapistore
1585    folder
1586
1587    \param mstore_ctx pointer to the mapistore context
1588    \param context_id the context identifier referencing the backend
1589    \param fid the folder identifier (for the parent folder)
1590    \param child_fids pointer to where to return the array of child fids
1591    \param child_fid_count pointer to the count result to return
1592
1593    \note The caller is responsible for freeing the \p child_fids array
1594    when it is no longer required.
1595    
1596    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1597  */
1598 _PUBLIC_ enum MAPISTORE_ERROR mapistore_get_child_fids(struct mapistore_context *mstore_ctx,
1599                                                        uint32_t context_id,
1600                                                        uint64_t fid,
1601                                                        uint64_t *child_fids[],
1602                                                        uint32_t *child_fid_count)
1603 {
1604         enum MAPISTORE_ERROR            retval;
1605         struct backend_context          *backend_ctx;
1606         char                            *folder_uri;
1607         uint32_t                        i;
1608         void                            *data;
1609
1610         /* Sanity checks */
1611         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1612
1613         /* Step 1. Ensure the context exists */
1614         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1615         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1616
1617         /* Step 2. Create the mapistore_indexing context */
1618         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1619         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1620
1621         /* Step 3. Retrieve the folder URI from the indexing database */
1622         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, fid, &folder_uri);
1623         if (retval) {
1624                 mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1625                 return retval;
1626         }
1627
1628         /* Step 1. Call backend readdir to get the folder count */
1629         retval = mapistore_backend_readdir_count(backend_ctx, folder_uri, MAPISTORE_FOLDER_TABLE, child_fid_count);
1630         if (retval) {
1631                 mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1632                 return retval;
1633         }
1634
1635         retval = mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1636         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1637
1638         /* Step 2. Create a suitable sized array for the fids */
1639         *child_fids = talloc_zero_array((TALLOC_CTX *)mstore_ctx, uint64_t, *child_fid_count);
1640         MAPISTORE_RETVAL_IF(!*child_fids, MAPISTORE_ERR_NO_MEMORY, NULL);
1641
1642         /* Step 3. Fill the array */
1643         for (i = 0; i < *child_fid_count; ++i) {
1644                 // TODO: add error checking for this call
1645                 retval = mapistore_get_table_property(mstore_ctx, context_id, MAPISTORE_FOLDER_TABLE, 
1646                                                       fid, PR_FID, i, &data);
1647                 MAPISTORE_RETVAL_IF(retval, retval, *child_fids);
1648                 (*child_fids)[i] = *((uint64_t*)(data));
1649         }
1650
1651         return retval;
1652 }
1653
1654 /**
1655    \details Delete a message from mapistore
1656
1657    \param mstore_ctx pointer to the mapistore context
1658    \param context_id the context identifier referencing the backend
1659    where the message's to be located is stored
1660    \param mid the message identifier of the folder to delete
1661    \param deletion_type the type of deletion (MAPISTORE_SOFT_DELETE or MAPISTORE_PERMANENT_DELETE)
1662
1663    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
1664  */
1665 _PUBLIC_ enum MAPISTORE_ERROR mapistore_deletemessage(struct mapistore_context *mstore_ctx,
1666                                                       uint32_t context_id,
1667                                                       uint64_t mid,
1668                                                       enum MAPISTORE_DELETION_TYPE deletion_type)
1669 {
1670         enum MAPISTORE_ERROR    retval;
1671         struct backend_context  *backend_ctx;
1672         char                    *message_uri;
1673
1674         /* Sanity checks */
1675         MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
1676
1677         /* Step 1. Search the context */
1678         backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
1679         MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
1680
1681         /* Step 2. Create the mapistore_indexing context */
1682         retval = mapistore_indexing_context_add(mstore_ctx, backend_ctx->username, &(mstore_ctx->mapistore_indexing_list));
1683         MAPISTORE_RETVAL_IF(retval, retval, NULL);
1684
1685         /* Step 3. Retrieve the message URI from the indexing database */
1686         retval = mapistore_indexing_get_record_uri_by_fmid(mstore_ctx->mapistore_indexing_list, mid, &message_uri);
1687         if (retval) goto error;
1688
1689         /* Step 4. Call backend operation */
1690         retval = mapistore_backend_deletemessage(backend_ctx, message_uri, deletion_type);
1691
1692 error:
1693         mapistore_indexing_context_del(mstore_ctx, backend_ctx->username);
1694
1695         return retval;
1696 }