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.h"
30 #include "mapiproxy/modules/mpm_cache.h"
31 #include <libmapi/defs_private.h>
32 #include <util/debug.h>
35 \details Create the cache database
37 \param dce_ctx pointer to the session context
38 \param database the complete path to the tdb store
39 \param ldb_ctx pointer to pointer on the the LDB context
41 \return NT_STATUS_OK on success, otherwise NT_ERROR:
42 NT_STATUS_NO_MEMORY, NT_STATUS_NOT_FOUND.
44 NTSTATUS mpm_cache_ldb_createdb(struct dcesrv_context *dce_ctx,
46 struct ldb_context **ldb_ctx)
48 struct ldb_context *tmp_ctx;
49 struct event_context *ev;
52 ev = event_context_init(dce_ctx);
53 if (!ev) return NT_STATUS_NO_MEMORY;
55 tmp_ctx = ldb_init(dce_ctx, ev);
56 if (!tmp_ctx) return NT_STATUS_NO_MEMORY;
58 ret = ldb_connect(tmp_ctx, database, 0, NULL);
59 if (ret != LDB_SUCCESS) {
60 return NT_STATUS_NOT_FOUND;
70 \details Add a folder record to the TDB store
72 \param mem_ctx pointer to the memory context
73 \param ldb_ctx pointer to the LDB context
74 \param FolderId the ID we will be using to uniquely create the
77 \return NT_STATUS_OK on success, otherwise NT_STATUS_NOT_FOUND
79 static NTSTATUS mpm_cache_ldb_add_folder(TALLOC_CTX *mem_ctx,
80 struct ldb_context *ldb_ctx,
83 struct ldb_message *msg;
87 msg = ldb_msg_new(mem_ctx);
89 return NT_STATUS_NO_MEMORY;
92 dn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=Cache", FolderId);
93 msg->dn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
96 return NT_STATUS_NO_MEMORY;
99 ret = ldb_add(ldb_ctx, msg);
101 DEBUG(0, ("* [%s:%d] Failed to modify record %s: %s\n",
102 MPM_LOCATION, ldb_dn_get_linearized(msg->dn),
103 ldb_errstring(ldb_ctx)));
104 return NT_STATUS_UNSUCCESSFUL;
112 \details Add a message record to the TDB store
114 \param mem_ctx pointer to the memory context
115 \param ldb_ctx pointer to the LDB context
116 \param message pointer to the mpm_message entry with the folder and
119 \return NT_STATUS_OK on success, otherwise a NT error
121 NTSTATUS mpm_cache_ldb_add_message(TALLOC_CTX *mem_ctx,
122 struct ldb_context *ldb_ctx,
123 struct mpm_message *message)
126 struct ldb_message *msg;
128 struct ldb_result *res;
132 /* First check if the CN=Folder,CN=Cache entry exists */
133 basedn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=Cache", message->FolderId);
134 dn = ldb_dn_new(mem_ctx, ldb_ctx, basedn);
136 if (!dn) return NT_STATUS_UNSUCCESSFUL;
137 ret = ldb_search(ldb_ctx, mem_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
138 if (ret == LDB_SUCCESS && !res->count) {
139 DEBUG(5, ("* [%s:%d] We have to create folder TDB record: CN=0x%"PRIx64",CN=Cache\n",
140 MPM_LOCATION, message->FolderId));
141 status = mpm_cache_ldb_add_folder(mem_ctx, ldb_ctx, message->FolderId);
142 if (!NT_STATUS_IS_OK(status)) return status;
145 /* Search if the message doesn't already exist */
146 basedn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
147 message->MessageId, message->FolderId);
148 dn = ldb_dn_new(mem_ctx, ldb_ctx, basedn);
150 if (!dn) return NT_STATUS_UNSUCCESSFUL;
151 ret = ldb_search(ldb_ctx, mem_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
152 if (res->count) return NT_STATUS_OK;
154 /* Create the CN=Message,CN=Folder,CN=Cache */
155 msg = ldb_msg_new(mem_ctx);
156 if (msg == NULL) return NT_STATUS_NO_MEMORY;
158 basedn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
159 message->MessageId, message->FolderId);
160 msg->dn = ldb_dn_new(ldb_ctx, ldb_ctx, basedn);
162 if (!msg->dn) return NT_STATUS_NO_MEMORY;
164 ret = ldb_add(ldb_ctx, msg);
166 DEBUG(0, ("* [%s:%d] Failed to modify record %s: %s\n",
167 MPM_LOCATION, ldb_dn_get_linearized(msg->dn),
168 ldb_errstring(ldb_ctx)));
169 return NT_STATUS_UNSUCCESSFUL;
177 \details Add an attachment record to the TDB store
179 \param mem_ctx pointer to the memory context
180 \param ldb_ctx pointer to the LDB context
181 \param attach pointer to the mpm_attachment entry
183 \return NT_STATUS_OK on success, otherwise a NT error
185 NTSTATUS mpm_cache_ldb_add_attachment(TALLOC_CTX *mem_ctx,
186 struct ldb_context *ldb_ctx,
187 struct mpm_attachment *attach)
189 struct mpm_message *message;
190 struct ldb_message *msg;
192 struct ldb_result *res;
196 message = attach->message;
198 /* Search if the attachment doesn't already exist */
199 basedn = talloc_asprintf(mem_ctx, "CN=%d,CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
200 attach->AttachmentID, message->MessageId,
202 dn = ldb_dn_new(mem_ctx, ldb_ctx, basedn);
204 if (!dn) return NT_STATUS_UNSUCCESSFUL;
205 ret = ldb_search(ldb_ctx, mem_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
206 if (ret == LDB_SUCCESS && res->count) return NT_STATUS_OK;
208 DEBUG(2, ("* [%s:%d] Create the attachment TDB record\n", MPM_LOCATION));
210 msg = ldb_msg_new(mem_ctx);
211 if (msg == NULL) return NT_STATUS_NO_MEMORY;
213 basedn = talloc_asprintf(mem_ctx, "CN=%d,CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
214 attach->AttachmentID, message->MessageId,
216 msg->dn = ldb_dn_new(ldb_ctx, ldb_ctx, basedn);
218 if (!msg->dn) return NT_STATUS_NO_MEMORY;
220 ret = ldb_add(ldb_ctx, msg);
222 DEBUG(0, ("* [%s:%d] Failed to modify record %s: %s\n",
223 MPM_LOCATION, ldb_dn_get_linearized(msg->dn),
224 ldb_errstring(ldb_ctx)));
225 return NT_STATUS_UNSUCCESSFUL;
233 \details Add stream references to a message or attachment in the
236 \param mpm pointer to the cache module general structure
237 \param ldb_ctx pointer to the LDB context
238 \param stream pointer to the mpm_stream entry
240 \return NT_STATUS_OK on success, otherwise NT error
242 NTSTATUS mpm_cache_ldb_add_stream(struct mpm_cache *mpm,
243 struct ldb_context *ldb_ctx,
244 struct mpm_stream *stream)
247 struct mpm_message *message;
248 struct mpm_attachment *attach;
249 struct ldb_message *msg;
251 const char * const attrs[] = { "*", NULL };
252 struct ldb_result *res;
258 mem_ctx = (TALLOC_CTX *) mpm;
260 if (stream->attachment) {
261 attach = stream->attachment;
262 message = attach->message;
263 } else if (stream->message) {
265 message = stream->message;
270 /* This is a stream for an attachment */
271 if (stream->attachment) {
272 basedn = talloc_asprintf(mem_ctx, "CN=%d,CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
273 attach->AttachmentID, message->MessageId,
275 dn = ldb_dn_new(mem_ctx, ldb_ctx, basedn);
277 if (!dn) return NT_STATUS_UNSUCCESSFUL;
279 attribute = talloc_asprintf(mem_ctx, "(0x%x=*)", stream->PropertyTag);
280 ret = ldb_search(ldb_ctx, mem_ctx, &res, dn, LDB_SCOPE_BASE, attrs,
282 talloc_free(attribute);
284 if (ret == LDB_SUCCESS && res->count == 1) {
285 attribute = talloc_asprintf(mem_ctx, "0x%x", stream->PropertyTag);
286 basedn = (char *) ldb_msg_find_attr_as_string(res->msgs[0], attribute, NULL);
287 talloc_free(attribute);
288 DEBUG(2, ("* [%s:%d] Loading from cache 0x%x = %s\n", MPM_LOCATION,
289 stream->PropertyTag, basedn));
290 stream->filename = talloc_strdup(mem_ctx, basedn);
291 stream->cached = true;
292 stream->ahead = false;
293 mpm_cache_stream_open(mpm, stream);
298 /* Otherwise create the stream with basedn above */
299 basedn = talloc_asprintf(mem_ctx, "CN=%d,CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
300 attach->AttachmentID, message->MessageId,
303 DEBUG(2, ("* [%s:%d] Create the stream TDB record for attachment\n", MPM_LOCATION));
306 if (stream->message) {
307 basedn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
308 message->MessageId, message->FolderId);
309 dn = ldb_dn_new(mem_ctx, ldb_ctx, basedn);
311 if (!dn) return NT_STATUS_UNSUCCESSFUL;
313 attribute = talloc_asprintf(mem_ctx, "(0x%x=*)", stream->PropertyTag);
314 ret = ldb_search(ldb_ctx, mem_ctx, &res, dn, LDB_SCOPE_BASE, attrs, attribute);
315 talloc_free(attribute);
317 if (ret == LDB_SUCCESS && res->count == 1) {
318 attribute = talloc_asprintf(mem_ctx, "0x%x", stream->PropertyTag);
319 basedn = (char *) ldb_msg_find_attr_as_string(res->msgs[0], attribute, NULL);
320 talloc_free(attribute);
321 DEBUG(2, ("* [%s:%d] Loading from cache 0x%x = %s\n", MPM_LOCATION,
322 stream->PropertyTag, basedn));
323 stream->filename = talloc_strdup(mem_ctx, basedn);
324 stream->cached = true;
325 stream->ahead = false;
326 mpm_cache_stream_open(mpm, stream);
331 /* Otherwise create the stream with basedn above */
332 basedn = talloc_asprintf(mem_ctx, "CN=0x%"PRIx64",CN=0x%"PRIx64",CN=Cache",
333 message->MessageId, message->FolderId);
335 DEBUG(2, ("* [%s:%d] Modify the message TDB record and append stream information\n",
339 stream->cached = false;
340 mpm_cache_stream_open(mpm, stream);
342 msg = ldb_msg_new(mem_ctx);
343 if (msg == NULL) return NT_STATUS_NO_MEMORY;
345 msg->dn = ldb_dn_new(ldb_ctx, ldb_ctx, basedn);
347 if (!msg->dn) return NT_STATUS_NO_MEMORY;
349 attribute = talloc_asprintf(mem_ctx, "0x%x", stream->PropertyTag);
350 ldb_msg_add_fmt(msg, attribute, "%s", stream->filename);
351 talloc_free(attribute);
353 attribute = talloc_asprintf(mem_ctx, "0x%x_StreamSize", stream->PropertyTag);
354 ldb_msg_add_fmt(msg, attribute, "%d", stream->StreamSize);
355 talloc_free(attribute);
357 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
358 for (i=0;i<msg->num_elements;i++) {
359 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
362 ret = ldb_modify(ldb_ctx, msg);
364 DEBUG(0, ("* [%s:%d] Failed to modify record %s: %s\n",
365 MPM_LOCATION, ldb_dn_get_linearized(msg->dn),
366 ldb_errstring(ldb_ctx)));
367 return NT_STATUS_UNSUCCESSFUL;