2 MAPI Backup application suite
6 Copyright (C) Julien Kerihuel 2007
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/>.
22 #include "openchangebackup.h"
23 #include <libmapi/defs_private.h>
26 * Initialize OCB (OpenChange Backup) subsystem
27 * and open a pointer on the LDB database
29 struct ocb_context *ocb_init(TALLOC_CTX *mem_ctx, const char *dbpath)
31 struct ocb_context *ocb_ctx = NULL;
34 struct event_context *ev;
37 OCB_RETVAL_IF_CODE(!mem_ctx, "invalid memory context", NULL, NULL);
38 OCB_RETVAL_IF_CODE(!dbpath, "dbpath not set", NULL, NULL);
40 ocb_ctx = talloc_zero(mem_ctx, struct ocb_context);
42 ev = event_context_init(ocb_ctx);
46 ocb_ctx->ldb_ctx = ldb_init((TALLOC_CTX *)ocb_ctx, ev);
47 if (!ocb_ctx->ldb_ctx) goto failed;
49 url = talloc_asprintf(mem_ctx, "tdb://%s", dbpath);
50 ret = ldb_connect(ocb_ctx->ldb_ctx, url, 0, NULL);
52 if (ret != LDB_SUCCESS) goto failed;
61 * Release OCB subsystem
63 uint32_t ocb_release(struct ocb_context *ocb_ctx)
65 OCB_RETVAL_IF(!ocb_ctx, "subsystem not initialized\n", NULL);
72 * init and prepare a record
75 int ocb_record_init(struct ocb_context *ocb_ctx, const char *objclass, const char *dn,
76 const char *id, struct mapi_SPropValue_array *props)
79 struct ldb_context *ldb_ctx;
80 struct ldb_result *res;
81 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
82 struct ldb_dn *basedn;
84 const char * const attrs[] = { "*", NULL };
87 OCB_RETVAL_IF(!ocb_ctx, "Subsystem not initialized", NULL);
88 OCB_RETVAL_IF(!dn, "Not a valid DN", NULL);
89 OCB_RETVAL_IF(!id, "Not a valid ID", NULL);
91 mem_ctx = (TALLOC_CTX *)ocb_ctx;
92 ldb_ctx = ocb_ctx->ldb_ctx;
94 /* Check if the record already exists */
95 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, dn);
96 OCB_RETVAL_IF(res->msgs, "Record already exists", NULL);
98 /* Retrieve the record basedn */
99 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
100 OCB_RETVAL_IF(!ldb_dn_validate(basedn), "Invalid DN", NULL);
102 ocb_ctx->msg = ldb_msg_new(mem_ctx);
103 ocb_ctx->msg->dn = ldb_dn_copy(mem_ctx, basedn);
105 /* add records for cn */
106 ldb_msg_add_string(ocb_ctx->msg, "cn", id);
108 /* add filters attributes */
109 ldb_msg_add_string(ocb_ctx->msg, "objectClass", objclass);
118 * Commit the record with all its attributes: single transaction
120 uint32_t ocb_record_commit(struct ocb_context *ocb_ctx)
125 OCB_RETVAL_IF(!ocb_ctx, "Subsystem not initialized", NULL);
126 OCB_RETVAL_IF(!ocb_ctx->ldb_ctx, "LDB context not initialized", NULL);
127 OCB_RETVAL_IF(!ocb_ctx->msg, "Message not initialized", NULL);
129 ret = ldb_add(ocb_ctx->ldb_ctx, ocb_ctx->msg);
130 if (ret != LDB_SUCCESS) {
131 DEBUG(3, ("LDB operation failed: %s\n", ldb_errstring(ocb_ctx->ldb_ctx)));
135 talloc_free(ocb_ctx->msg);
142 * Add a property (attr, value) couple to the current record
144 uint32_t ocb_record_add_property(struct ocb_context *ocb_ctx,
145 struct mapi_SPropValue *lpProp)
154 OCB_RETVAL_IF(!ocb_ctx, "Subsystem not initialized", NULL);
155 OCB_RETVAL_IF(!ocb_ctx->ldb_ctx, "LDB context not initialized", NULL);
156 OCB_RETVAL_IF(!ocb_ctx->msg, "Message not initialized", NULL);
158 mem_ctx = (TALLOC_CTX *)ocb_ctx->msg;
160 tag = get_proptag_name(lpProp->ulPropTag);
162 attr = talloc_asprintf(mem_ctx, "%s", tag);
164 attr = talloc_asprintf(mem_ctx, "PR-x%.8x", lpProp->ulPropTag);
167 for (i = 0; attr[i]; i++) {
168 if (attr[i] == '_') attr[i] = '-';
171 switch (lpProp->ulPropTag & 0xFFFF) {
173 ldb_msg_add_fmt(ocb_ctx->msg, attr, "%hd", lpProp->value.i);
176 ldb_msg_add_string(ocb_ctx->msg, attr, lpProp->value.lpszA);
179 ldb_msg_add_string(ocb_ctx->msg, attr, lpProp->value.lpszW);
181 case PT_ERROR: /* We shouldn't need to backup error properties */
184 ldb_msg_add_fmt(ocb_ctx->msg, attr, "%d", lpProp->value.l);
187 ldb_msg_add_fmt(ocb_ctx->msg, attr, "%s",
188 ((lpProp->value.b == true) ? "true" : "false"));
191 ldb_msg_add_fmt(ocb_ctx->msg, attr, "%16"PRIx64, lpProp->value.d);
194 value = ocb_ldb_timestring(mem_ctx, &lpProp->value.ft);
195 ldb_msg_add_string(ocb_ctx->msg, attr, value);
199 if (lpProp->value.bin.cb) {
200 value = ldb_base64_encode(mem_ctx, (char *)lpProp->value.bin.lpb,
201 lpProp->value.bin.cb);
202 ldb_msg_add_string(ocb_ctx->msg, attr, value);
206 for (i = 0; i < lpProp->value.MVl.cValues; i++) {
207 ldb_msg_add_fmt(ocb_ctx->msg, attr, "%d",
208 lpProp->value.MVl.lpl[i]);
212 for (i = 0; i < lpProp->value.MVbin.cValues; i++) {
213 struct SBinary_short bin;
215 bin = lpProp->value.MVbin.bin[i];
217 value = ldb_base64_encode(mem_ctx, (char *)bin.lpb, bin.cb);
218 ldb_msg_add_string(ocb_ctx->msg, attr, value);
223 for (i = 0; i < lpProp->value.MVszA.cValues; i++) {
224 ldb_msg_add_string(ocb_ctx->msg, attr,
225 lpProp->value.MVszA.strings[i].lppszA);
229 printf("%s case %d not supported\n", attr, lpProp->ulPropTag & 0xFFFF);
238 * Retrieve UUID from Sbinary_short struct
239 * Generally used to map PR_STORE_KEY to a string
240 * Used for attachments
242 char *get_record_uuid(TALLOC_CTX *mem_ctx, const struct SBinary_short *bin)
247 OCB_RETVAL_IF_CODE(!bin, "Invalid PR_RECORD_KEY val", NULL, NULL);
248 lpb = talloc_asprintf(mem_ctx, "%.2X", bin->lpb[0]);
249 for (i = 1; i < bin->cb; i++) {
250 lpb = talloc_asprintf_append(lpb, "%.2X", bin->lpb[i]);
258 * Extract MAPI object unique ID from PR_SOURCE_KEY Sbinary_short data:
259 * PR_SOURCE_KEY = 22 bytes field
260 * - 16 first bytes = MAPI Store GUID
261 * - 6 last bytes = MAPI object unique ID
263 char *get_MAPI_uuid(TALLOC_CTX *mem_ctx, const struct SBinary_short *bin)
268 OCB_RETVAL_IF_CODE(!bin || bin->cb != 22, "Invalid SBinary", NULL, NULL);
270 ab = talloc_asprintf(mem_ctx, "%.2X", bin->lpb[16]);
271 for (i = 17; i < bin->cb; i++) {
272 ab = talloc_asprintf_append(ab, "%.2X", bin->lpb[i]);
280 * Retrieve the store GUID from a given record.
281 * This GUID should be unique for each store and identical for all
282 * objects belonging to this store
284 char *get_MAPI_store_guid(TALLOC_CTX *mem_ctx, const struct SBinary_short *bin)
289 OCB_RETVAL_IF_CODE(!bin || bin->cb != 22, "Invalid SBinary", NULL, NULL);
291 ab = talloc_asprintf(mem_ctx, "%.2X", bin->lpb[0]);
292 for (i = 1; i < 16; i++) {
293 ab = talloc_asprintf_append(ab, "%.2X", bin->lpb[i]);
301 * Convert date from MAPI property to ldb format
302 * Easier to manipulate
304 char *ocb_ldb_timestring(TALLOC_CTX *mem_ctx, struct FILETIME *ft)
309 OCB_RETVAL_IF_CODE(!ft, "Invalid FILTIME", NULL, NULL);
311 time = ft->dwHighDateTime;
313 time |= ft->dwLowDateTime;
315 t = nt_time_to_unix(time);
316 return ldb_timestring(mem_ctx, t);