2 MAPI Proxy - Cache module
6 Copyright (C) Julien Kerihuel 2008
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.
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.
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/>.
25 \brief LDB routines for the cache module
28 #include "mapiproxy/dcesrv_mapiproxy.h"
29 #include "mapiproxy/libmapiproxy/libmapiproxy.h"
30 #include "mapiproxy/modules/mpm_cache.h"
31 #include "libmapi/libmapi.h"
32 #include "libmapi/libmapi_private.h"
33 #include <util/debug.h>
36 \details Create the cache database
38 \param dce_ctx pointer to the session context
39 \param database the complete path to the tdb store
40 \param ldb_ctx pointer to pointer on the the LDB context
42 \return NT_STATUS_OK on success, otherwise NT_ERROR:
43 NT_STATUS_NO_MEMORY, NT_STATUS_NOT_FOUND.
45 NTSTATUS mpm_cache_ldb_createdb(struct dcesrv_context *dce_ctx,
47 struct ldb_context **ldb_ctx)
49 struct ldb_context *tmp_ctx;
50 struct tevent_context *ev;
53 ev = tevent_context_init(dce_ctx);
54 if (!ev) return NT_STATUS_NO_MEMORY;
56 tmp_ctx = ldb_init(dce_ctx, ev);
57 if (!tmp_ctx) return NT_STATUS_NO_MEMORY;
59 ret = ldb_connect(tmp_ctx, database, 0, NULL);
60 if (ret != LDB_SUCCESS) {
61 return NT_STATUS_NOT_FOUND;
71 \details Add a folder record to the TDB store
73 \param mem_ctx pointer to the memory context
74 \param ldb_ctx pointer to the LDB context
75 \param FolderId the ID we will be using to uniquely create the
78 \return NT_STATUS_OK on success, otherwise NT_STATUS_NOT_FOUND
80 static NTSTATUS mpm_cache_ldb_add_folder(TALLOC_CTX *mem_ctx,
81 struct ldb_context *ldb_ctx,
84 struct ldb_message *msg;
88 msg = ldb_msg_new(mem_ctx);
90 return NT_STATUS_NO_MEMORY;
93 dn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=Cache", FolderId);
94 msg->dn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
97 return NT_STATUS_NO_MEMORY;
100 ret = ldb_add(ldb_ctx, msg);
102 DEBUG(0, ("* [%s:%d] Failed to modify record %s: %s\n",
103 MPM_LOCATION, ldb_dn_get_linearized(msg->dn),
104 ldb_errstring(ldb_ctx)));
105 return NT_STATUS_UNSUCCESSFUL;
113 \details Add a message record to the TDB store
115 \param mem_ctx pointer to the memory context
116 \param ldb_ctx pointer to the LDB context
117 \param message pointer to the mpm_message entry with the folder and
120 \return NT_STATUS_OK on success, otherwise a NT error
122 NTSTATUS mpm_cache_ldb_add_message(TALLOC_CTX *mem_ctx,
123 struct ldb_context *ldb_ctx,
124 struct mpm_message *message)
127 struct ldb_message *msg;
129 struct ldb_result *res;
133 /* First check if the CN=Folder,CN=Cache entry exists */
134 basedn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=Cache", message->FolderId);
135 dn = ldb_dn_new(mem_ctx, ldb_ctx, basedn);
137 if (!dn) return NT_STATUS_UNSUCCESSFUL;
138 ret = ldb_search(ldb_ctx, mem_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
139 if (ret == LDB_SUCCESS && !res->count) {
140 DEBUG(5, ("* [%s:%d] We have to create folder TDB record: CN=0x%"PRIx64",CN=Cache\n",
141 MPM_LOCATION, message->FolderId));
142 status = mpm_cache_ldb_add_folder(mem_ctx, ldb_ctx, message->FolderId);
143 if (!NT_STATUS_IS_OK(status)) return status;
146 /* Search if the message doesn't already exist */
147 basedn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
148 message->MessageId, message->FolderId);
149 dn = ldb_dn_new(mem_ctx, ldb_ctx, basedn);
151 if (!dn) return NT_STATUS_UNSUCCESSFUL;
152 ret = ldb_search(ldb_ctx, mem_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
153 if (res->count) return NT_STATUS_OK;
155 /* Create the CN=Message,CN=Folder,CN=Cache */
156 msg = ldb_msg_new(mem_ctx);
157 if (msg == NULL) return NT_STATUS_NO_MEMORY;
159 basedn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
160 message->MessageId, message->FolderId);
161 msg->dn = ldb_dn_new(ldb_ctx, ldb_ctx, basedn);
163 if (!msg->dn) return NT_STATUS_NO_MEMORY;
165 ret = ldb_add(ldb_ctx, msg);
167 DEBUG(0, ("* [%s:%d] Failed to modify record %s: %s\n",
168 MPM_LOCATION, ldb_dn_get_linearized(msg->dn),
169 ldb_errstring(ldb_ctx)));
170 return NT_STATUS_UNSUCCESSFUL;
178 \details Add an attachment record to the TDB store
180 \param mem_ctx pointer to the memory context
181 \param ldb_ctx pointer to the LDB context
182 \param attach pointer to the mpm_attachment entry
184 \return NT_STATUS_OK on success, otherwise a NT error
186 NTSTATUS mpm_cache_ldb_add_attachment(TALLOC_CTX *mem_ctx,
187 struct ldb_context *ldb_ctx,
188 struct mpm_attachment *attach)
190 struct mpm_message *message;
191 struct ldb_message *msg;
193 struct ldb_result *res;
197 message = attach->message;
199 /* Search if the attachment doesn't already exist */
200 basedn = talloc_asprintf(mem_ctx, "CN=%d,CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
201 attach->AttachmentID, message->MessageId,
203 dn = ldb_dn_new(mem_ctx, ldb_ctx, basedn);
205 if (!dn) return NT_STATUS_UNSUCCESSFUL;
206 ret = ldb_search(ldb_ctx, mem_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
207 if (ret == LDB_SUCCESS && res->count) return NT_STATUS_OK;
209 DEBUG(2, ("* [%s:%d] Create the attachment TDB record\n", MPM_LOCATION));
211 msg = ldb_msg_new(mem_ctx);
212 if (msg == NULL) return NT_STATUS_NO_MEMORY;
214 basedn = talloc_asprintf(mem_ctx, "CN=%d,CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
215 attach->AttachmentID, message->MessageId,
217 msg->dn = ldb_dn_new(ldb_ctx, ldb_ctx, basedn);
219 if (!msg->dn) return NT_STATUS_NO_MEMORY;
221 ret = ldb_add(ldb_ctx, msg);
223 DEBUG(0, ("* [%s:%d] Failed to modify record %s: %s\n",
224 MPM_LOCATION, ldb_dn_get_linearized(msg->dn),
225 ldb_errstring(ldb_ctx)));
226 return NT_STATUS_UNSUCCESSFUL;
234 \details Add stream references to a message or attachment in the
237 \param mpm pointer to the cache module general structure
238 \param ldb_ctx pointer to the LDB context
239 \param stream pointer to the mpm_stream entry
241 \return NT_STATUS_OK on success, otherwise NT error
243 NTSTATUS mpm_cache_ldb_add_stream(struct mpm_cache *mpm,
244 struct ldb_context *ldb_ctx,
245 struct mpm_stream *stream)
248 struct mpm_message *message;
249 struct mpm_attachment *attach;
250 struct ldb_message *msg;
252 const char * const attrs[] = { "*", NULL };
253 struct ldb_result *res;
259 mem_ctx = (TALLOC_CTX *) mpm;
261 if (stream->attachment) {
262 attach = stream->attachment;
263 message = attach->message;
264 } else if (stream->message) {
266 message = stream->message;
271 /* This is a stream for an attachment */
272 if (stream->attachment) {
273 basedn = talloc_asprintf(mem_ctx, "CN=%d,CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
274 attach->AttachmentID, message->MessageId,
276 dn = ldb_dn_new(mem_ctx, ldb_ctx, basedn);
278 if (!dn) return NT_STATUS_UNSUCCESSFUL;
280 ret = ldb_search(ldb_ctx, mem_ctx, &res, dn, LDB_SCOPE_BASE, attrs,
281 "(0x%x=*)", stream->PropertyTag);
283 if (ret == LDB_SUCCESS && res->count == 1) {
284 attribute = talloc_asprintf(mem_ctx, "0x%x", stream->PropertyTag);
285 basedn = (char *) ldb_msg_find_attr_as_string(res->msgs[0], attribute, NULL);
286 talloc_free(attribute);
287 DEBUG(2, ("* [%s:%d] Loading from cache 0x%x = %s\n", MPM_LOCATION,
288 stream->PropertyTag, basedn));
289 stream->filename = talloc_strdup(mem_ctx, basedn);
290 stream->cached = true;
291 stream->ahead = false;
292 mpm_cache_stream_open(mpm, stream);
297 /* Otherwise create the stream with basedn above */
298 basedn = talloc_asprintf(mem_ctx, "CN=%d,CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
299 attach->AttachmentID, message->MessageId,
302 DEBUG(2, ("* [%s:%d] Create the stream TDB record for attachment\n", MPM_LOCATION));
305 if (stream->message) {
306 basedn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
307 message->MessageId, message->FolderId);
308 dn = ldb_dn_new(mem_ctx, ldb_ctx, basedn);
310 if (!dn) return NT_STATUS_UNSUCCESSFUL;
312 ret = ldb_search(ldb_ctx, mem_ctx, &res, dn, LDB_SCOPE_BASE, attrs, "(0x%x=*)", stream->PropertyTag);
314 if (ret == LDB_SUCCESS && res->count == 1) {
315 attribute = talloc_asprintf(mem_ctx, "0x%x", stream->PropertyTag);
316 basedn = (char *) ldb_msg_find_attr_as_string(res->msgs[0], attribute, NULL);
317 talloc_free(attribute);
318 DEBUG(2, ("* [%s:%d] Loading from cache 0x%x = %s\n", MPM_LOCATION,
319 stream->PropertyTag, basedn));
320 stream->filename = talloc_strdup(mem_ctx, basedn);
321 stream->cached = true;
322 stream->ahead = false;
323 mpm_cache_stream_open(mpm, stream);
328 /* Otherwise create the stream with basedn above */
329 basedn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
330 message->MessageId, message->FolderId);
332 DEBUG(2, ("* [%s:%d] Modify the message TDB record and append stream information\n",
336 stream->cached = false;
337 mpm_cache_stream_open(mpm, stream);
339 msg = ldb_msg_new(mem_ctx);
340 if (msg == NULL) return NT_STATUS_NO_MEMORY;
342 msg->dn = ldb_dn_new(ldb_ctx, ldb_ctx, basedn);
344 if (!msg->dn) return NT_STATUS_NO_MEMORY;
346 attribute = talloc_asprintf(mem_ctx, "0x%x", stream->PropertyTag);
347 ldb_msg_add_fmt(msg, attribute, "%s", stream->filename);
348 talloc_free(attribute);
350 attribute = talloc_asprintf(mem_ctx, "0x%x_StreamSize", stream->PropertyTag);
351 ldb_msg_add_fmt(msg, attribute, "%d", stream->StreamSize);
352 talloc_free(attribute);
354 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
355 for (i=0;i<msg->num_elements;i++) {
356 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
359 ret = ldb_modify(ldb_ctx, msg);
361 DEBUG(0, ("* [%s:%d] Failed to modify record %s: %s\n",
362 MPM_LOCATION, ldb_dn_get_linearized(msg->dn),
363 ldb_errstring(ldb_ctx)));
364 return NT_STATUS_UNSUCCESSFUL;