Handle FID/MID uniqueness BY MAILBOX rather than BY SERVER
[jelmer/openchange.git] / mapiproxy / libmapistore / mapistore_backend_public.c
1 /*
2    OpenChange Storage Abstraction Layer library
3
4    OpenChange Project
5
6    Note: init and load functions have been copied from
7    samba4/source4/param/util.c initially written by Jelmer.
8
9    Copyright (C) Jelmer Vernooij 2005-2007
10    Copyright (C) Julien Kerihuel 2009-2011
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16    
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21    
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  */
25
26 /**
27    \file mapistore_backend_public.c
28
29    \brief Provides a public API mapistore backends can use to interact
30    with mapistore internals. Some functions are just wrappers over
31    existing mapistore functions.
32  */
33
34 #include "mapistore_errors.h"
35 #include "mapistore.h"
36 #include "mapistore_common.h"
37 #include "mapistore_private.h"
38 #include "mapistore_backend.h"
39
40
41 /**
42    \details Open a wrapped context to a LDB database
43
44    This function is a wrapper to mapistore_ldb_wrap_connect which
45    helps keeping mapistore_backend_context opaque to backends.
46
47    \param ctx pointer to the mapistore backend opaque context
48    \param path the path to the database (mapistore.ldb) to open
49
50    \return valid LDB context pointer on success, otherwise NULL
51  */
52 struct ldb_context *mapistore_public_ldb_connect(struct mapistore_backend_context *ctx,
53                                                  const char *path)
54 {
55         struct mapistore_context        *mstore_ctx = (struct mapistore_context *)ctx;
56         struct tevent_context           *ev;
57
58         /* Sanity checks */
59         if (!path || !mstore_ctx) {
60                 return NULL;
61         }
62
63         ev = tevent_context_init(mstore_ctx);
64         if (!ev) return NULL;
65
66         return mapistore_ldb_wrap_connect(mstore_ctx, ev, path, 0);
67 }
68
69
70 /**
71    \details Let a backend checks if a message of folder is already
72    indexed in mapistore.ldb
73
74    \param ctx pointer to the mapistore backend opaque context
75    \param username the username where to look for the URI
76    \param mapistore_uri the mapistore URI to lookup
77
78    \return MAPISTORE_ERR_EXIST if the URI was found,
79    MAPISTORE_ERR_NOT_FOUND if it wasn't, other MAPISTORE error
80  */
81 enum MAPISTORE_ERROR mapistore_exist(struct mapistore_backend_context *ctx,
82                                      const char *username,
83                                      const char *mapistore_uri)
84 {
85         enum MAPISTORE_ERROR            retval;
86         struct mapistore_context        *mstore_ctx;
87
88         /* Sanity checks */
89         MAPISTORE_RETVAL_IF(!ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
90         MAPISTORE_RETVAL_IF(!ctx->mstore_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
91         MAPISTORE_RETVAL_IF(!mapistore_uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
92
93         mstore_ctx = ctx->mstore_ctx;
94
95         /* Step 1. Create an indexing context */
96         retval = mapistore_indexing_context_add(mstore_ctx,
97                                                 username,
98                                                 &(mstore_ctx->mapistore_indexing_list));
99         MAPISTORE_RETVAL_IF(retval, retval, NULL);
100
101         /* Step 2. Search the URI */
102         retval = mapistore_indexing_record_search_uri(mstore_ctx->mapistore_indexing_list, mapistore_uri);
103
104         return retval;
105 }
106
107 /**
108    \details Let backends register a folder and index it within
109    mapistore indexing database
110
111    \param ctx pointer to the mapistore backend opaque context
112    \param username the username used to register the folder
113    \param parent_uri the mapistore URI of the parent folder
114    \param mapistore_uri the mapistore URI to register
115    \param range the number of message IDs we want to reserve for this
116    folder
117
118    \return MAPISTORE success on success, otherwise MAPISTORE error
119  */
120 enum MAPISTORE_ERROR mapistore_register_folder(struct mapistore_backend_context *ctx,
121                                                const char *username,
122                                                const char *parent_uri,
123                                                const char *mapistore_uri,
124                                                uint64_t range)
125 {
126         enum MAPISTORE_ERROR            retval;
127         struct mapistore_context        *mstore_ctx;
128         uint64_t                        parent_fid;
129         uint64_t                        fid;
130         uint64_t                        rstart;
131         uint64_t                        rend;
132
133         /* Sanity checks */
134         MAPISTORE_RETVAL_IF(!ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
135         MAPISTORE_RETVAL_IF(!ctx->mstore_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
136         MAPISTORE_RETVAL_IF(!username, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
137         MAPISTORE_RETVAL_IF(!mapistore_uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
138
139         if (!range) {
140                 range = MAPISTORE_INDEXING_DFLT_ALLOC_RANGE_VAL;
141         }
142
143         mstore_ctx = ctx->mstore_ctx;
144
145         /* Step 1. Ensure the URI doesn't exist */
146         retval = mapistore_exist(ctx, username, mapistore_uri);
147         MAPISTORE_RETVAL_IF(retval != MAPISTORE_ERR_NOT_FOUND, retval, NULL);
148
149         /* Step 2. Create or retrieve an indexing context */
150         retval = mapistore_indexing_context_add(mstore_ctx, username, &(mstore_ctx->mapistore_indexing_list));
151         MAPISTORE_RETVAL_IF(retval, retval, NULL);
152
153         /* Step 3. Ensure the parent_fid URI exists and retrieve its
154          * folder identifier value */
155         retval = mapistore_indexing_get_record_fmid_by_uri(mstore_ctx->mapistore_indexing_list, parent_uri, &parent_fid);
156         if (retval) goto finish;
157
158         /* Step 4. Ask for a new FID */
159         retval = mapistore_get_new_fmid(mstore_ctx->processing_ctx, username, &fid);
160         if (retval) goto finish;
161
162         /* Step 5. Register the folder within the indexing database */
163         retval = mapistore_indexing_add_fmid_record(mstore_ctx->mapistore_indexing_list, fid, 
164                                                     mapistore_uri, parent_fid, 
165                                                     MAPISTORE_INDEXING_FOLDER);
166         if (retval) goto finish;
167
168         /* Step 6. Request an allocation range for messages */
169         retval = mapistore_get_new_allocation_range(mstore_ctx->processing_ctx,
170                                                     username, range, &rstart, &rend);
171         if (retval) goto finish;
172
173         /* Step 7. Set the allocation range for the folder */
174         retval = mapistore_indexing_add_folder_record_allocation_range(mstore_ctx->mapistore_indexing_list,
175                                                                        fid, rstart, rend);
176         if (retval) goto finish;
177
178         /* Step 8. Delete the indexing context */
179 finish:
180         retval = mapistore_indexing_context_del(mstore_ctx, username);
181         return retval;
182 }