2
OpenChange Server implementation
4
OpenChangeDB table object implementation
6
Copyright (C) Julien Kerihuel 2011
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/>.
23
\file openchangedb_table.c
25
\brief OpenChange Dispatcher database table routines
30
#include "mapiproxy/dcesrv_mapiproxy.h"
31
#include "libmapiproxy.h"
32
#include "libmapi/libmapi.h"
33
#include "libmapi/libmapi_private.h"
36
/details Initialize an openchangedb table
38
\param mem_ctx pointer to the memory context to use for allocation
39
\param table_type the type of table this object represents
40
\param folderID the identifier of the folder this table represents
41
\param table_object pointer on pointer to the table object to return
43
\return MAPI_E_SUCCESS on success, otherwise MAPISTORE error
45
_PUBLIC_ enum MAPISTATUS openchangedb_table_init(TALLOC_CTX *mem_ctx, uint8_t table_type,
46
uint64_t folderID, void **table_object)
48
struct openchangedb_table *table;
51
MAPI_RETVAL_IF(!table_object, MAPI_E_NOT_INITIALIZED, NULL);
53
table = talloc_zero(mem_ctx, struct openchangedb_table);
55
return MAPI_E_NOT_ENOUGH_MEMORY;
57
/* printf("openchangedb_table_init: folderID=%"PRIu64"\n", folderID); */
58
table->folderID = folderID;
59
table->table_type = table_type;
60
table->lpSortCriteria = NULL;
61
table->restrictions = NULL;
64
*table_object = (void *)table;
66
return MAPI_E_SUCCESS;
71
\details Set sort order to specified openchangedb table object
73
\param table_object pointer to the table object
74
\param lpSortCriteria pointer to the sort order to save
76
\return MAPI_E_SUCCESS on success, otherwise MAPI error
78
_PUBLIC_ enum MAPISTATUS openchangedb_table_set_sort_order(void *table_object,
79
struct SSortOrderSet *lpSortCriteria)
81
struct openchangedb_table *table;
84
MAPI_RETVAL_IF(!table_object, MAPI_E_NOT_INITIALIZED, NULL);
85
MAPI_RETVAL_IF(!lpSortCriteria, MAPI_E_INVALID_PARAMETER, NULL);
87
table = (struct openchangedb_table *) table_object;
90
talloc_free(table->res);
94
if (table->lpSortCriteria) {
95
talloc_free(table->lpSortCriteria);
98
table->lpSortCriteria = talloc_memdup((TALLOC_CTX *)table, lpSortCriteria, sizeof(struct SSortOrderSet));
99
if (!table->lpSortCriteria) {
100
return MAPI_E_NOT_ENOUGH_MEMORY;
102
table->lpSortCriteria->aSort = talloc_memdup((TALLOC_CTX *)table->lpSortCriteria, lpSortCriteria->aSort, lpSortCriteria->cSorts * sizeof(struct SSortOrder));
103
if (!table->lpSortCriteria->aSort) {
104
return MAPI_E_NOT_ENOUGH_MEMORY;
108
table->lpSortCriteria = NULL;
111
return MAPI_E_SUCCESS;
115
_PUBLIC_ enum MAPISTATUS openchangedb_table_set_restrictions(void *table_object,
116
struct mapi_SRestriction *res)
118
struct openchangedb_table *table;
121
MAPI_RETVAL_IF(!table_object, MAPI_E_NOT_INITIALIZED, NULL);
122
MAPI_RETVAL_IF(!res, MAPI_E_INVALID_PARAMETER, NULL);
124
table = (struct openchangedb_table *) table_object;
127
talloc_free(table->res);
131
if (table->restrictions) {
132
talloc_free(table->restrictions);
133
table->restrictions = NULL;
136
MAPI_RETVAL_IF(!res, MAPI_E_SUCCESS, NULL);
138
table->restrictions = talloc_zero((TALLOC_CTX *)table_object, struct mapi_SRestriction);
142
table->restrictions->rt = res->rt;
143
table->restrictions->res.resProperty.relop = res->res.resProperty.relop;
144
table->restrictions->res.resProperty.ulPropTag = res->res.resProperty.ulPropTag;
145
table->restrictions->res.resProperty.lpProp.ulPropTag = res->res.resProperty.lpProp.ulPropTag;
147
switch (table->restrictions->res.resProperty.lpProp.ulPropTag & 0xFFFF) {
149
table->restrictions->res.resProperty.lpProp.value.lpszA = talloc_strdup((TALLOC_CTX *)table->restrictions, res->res.resProperty.lpProp.value.lpszA);
152
table->restrictions->res.resProperty.lpProp.value.lpszW = talloc_strdup((TALLOC_CTX *)table->restrictions, res->res.resProperty.lpProp.value.lpszW);
155
DEBUG(0, ("Unsupported property type for RES_PROPERTY restriction\n"));
160
DEBUG(0, ("Unsupported restriction type: 0x%x\n", res->rt));
163
return MAPI_E_SUCCESS;
166
static char *openchangedb_table_build_filter(TALLOC_CTX *mem_ctx, struct openchangedb_table *table, uint64_t row_fmid, struct mapi_SRestriction *restrictions)
169
const char *PidTagAttr = NULL;
171
switch (table->table_type) {
172
case 0x3 /* EMSMDBP_TABLE_FAI_TYPE */:
173
filter = talloc_asprintf(mem_ctx, "(&(objectClass=faiMessage)(PidTagParentFolderId=%"PRIu64")(PidTagMessageId=", table->folderID);
175
case 0x2 /* EMSMDBP_TABLE_MESSAGE_TYPE */:
176
filter = talloc_asprintf(mem_ctx, "(&(objectClass=systemMessage)(PidTagParentFolderId=%"PRIu64")(PidTagMessageId=", table->folderID);
178
case 0x1 /* EMSMDBP_TABLE_FOLDER_TYPE */:
179
filter = talloc_asprintf(mem_ctx, "(&(PidTagParentFolderId=%"PRIu64")(PidTagFolderId=", table->folderID);
184
filter = talloc_asprintf_append(filter, "*)");
187
filter = talloc_asprintf_append(filter, "%"PRIu64")", row_fmid);
191
switch (restrictions->rt) {
193
/* Retrieve PidTagName */
194
PidTagAttr = openchangedb_property_get_attribute(restrictions->res.resProperty.ulPropTag);
199
filter = talloc_asprintf_append(filter, "(%s=", PidTagAttr);
200
switch (restrictions->res.resProperty.ulPropTag & 0xFFFF) {
202
filter = talloc_asprintf_append(filter, "%s)", restrictions->res.resProperty.lpProp.value.lpszA);
205
filter = talloc_asprintf_append(filter, "%s)", restrictions->res.resProperty.lpProp.value.lpszW);
208
DEBUG(0, ("Unsupported RES_PROPERTY property type: 0x%.4x\n", (restrictions->res.resProperty.ulPropTag & 0xFFFF)));
216
filter = talloc_asprintf_append(filter, ")");
221
_PUBLIC_ enum MAPISTATUS openchangedb_table_get_property(TALLOC_CTX *mem_ctx,
223
struct ldb_context *ldb_ctx,
224
enum MAPITAGS proptag,
229
struct openchangedb_table *table;
230
char *ldb_filter = NULL;
231
struct ldb_result *res = NULL, *live_res = NULL;
232
const char * const attrs[] = { "*", NULL };
233
const char *PidTagAttr = NULL, *childIdAttr;
238
OPENCHANGE_RETVAL_IF(!table_object, MAPI_E_NOT_INITIALIZED, NULL);
239
OPENCHANGE_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
240
OPENCHANGE_RETVAL_IF(!data, MAPI_E_NOT_INITIALIZED, NULL);
242
table = (struct openchangedb_table *)table_object;
246
/* Build ldb filter */
248
ldb_filter = openchangedb_table_build_filter(NULL, table, 0, NULL);
249
DEBUG(0, ("(live-filtered) ldb_filter = %s\n", ldb_filter));
252
ldb_filter = openchangedb_table_build_filter(NULL, table, 0, table->restrictions);
253
DEBUG(0, ("(pre-filtered) ldb_filter = %s\n", ldb_filter));
255
OPENCHANGE_RETVAL_IF(!ldb_filter, MAPI_E_TOO_COMPLEX, NULL);
256
ret = ldb_search(ldb_ctx, (TALLOC_CTX *)table_object, &table->res, ldb_get_default_basedn(ldb_ctx), LDB_SCOPE_SUBTREE, attrs, ldb_filter, NULL);
257
talloc_free(ldb_filter);
258
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_INVALID_OBJECT, NULL);
262
/* Ensure position is within search results range */
263
OPENCHANGE_RETVAL_IF(pos >= res->count, MAPI_E_INVALID_OBJECT, NULL);
265
/* If live filtering, make sure the specified row match the restrictions */
267
switch (table->table_type) {
268
case 0x3 /* EMSMDBP_TABLE_FAI_TYPE */:
269
case 0x2 /* EMSMDBP_TABLE_MESSAGE_TYPE */:
270
childIdAttr = "PidTagMessageId";
272
case 0x1 /* EMSMDBP_TABLE_FOLDER_TYPE */:
273
childIdAttr = "PidTagFolderId";
276
DEBUG(0, ("unsupported table type for openchangedb: %d\n", table->table_type));
279
row_fmid = openchangedb_get_property_data(mem_ctx, res, pos, PR_MID, childIdAttr);
280
if (!row_fmid || !*row_fmid) {
281
DEBUG(0, ("ldb object must have a '%s' field\n", childIdAttr));
284
ldb_filter = openchangedb_table_build_filter(NULL, table, *row_fmid, table->restrictions);
285
OPENCHANGE_RETVAL_IF(!ldb_filter, MAPI_E_TOO_COMPLEX, NULL);
286
DEBUG(0, (" row ldb_filter = %s\n", ldb_filter));
287
ret = ldb_search(ldb_ctx, NULL, &live_res, ldb_get_default_basedn(ldb_ctx), LDB_SCOPE_SUBTREE, attrs, ldb_filter, NULL);
288
talloc_free(ldb_filter);
289
OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_INVALID_OBJECT, NULL);
290
if (live_res->count == 0) {
291
talloc_free(live_res);
292
return MAPI_E_INVALID_OBJECT;
294
talloc_free(live_res);
297
/* hacks for some attributes specific to tables */
298
if (proptag == PR_INST_ID) {
299
if (table->table_type == 1) {
306
else if (proptag == PR_INSTANCE_NUM) {
307
*data = talloc_zero(mem_ctx, uint32_t);
308
return MAPI_E_SUCCESS;
311
/* Convert proptag into PidTag attribute */
312
if ((table->table_type != 0x1) && proptag == PR_FID) {
313
proptag = PR_PARENT_FID;
315
PidTagAttr = openchangedb_property_get_attribute(proptag);
316
OPENCHANGE_RETVAL_IF(!PidTagAttr, MAPI_E_NOT_FOUND, NULL);
318
/* Ensure the element exists */
319
OPENCHANGE_RETVAL_IF(!ldb_msg_find_element(res->msgs[pos], PidTagAttr), MAPI_E_NOT_FOUND, NULL);
321
/* Check if this is a "special property" */
322
*data = openchangedb_get_special_property(mem_ctx, ldb_ctx, res, proptag, PidTagAttr);
323
OPENCHANGE_RETVAL_IF(*data != NULL, MAPI_E_SUCCESS, NULL);
325
/* Check if this is NOT a "special property" */
326
*data = openchangedb_get_property_data(mem_ctx, res, pos, proptag, PidTagAttr);
327
OPENCHANGE_RETVAL_IF(*data != NULL, MAPI_E_SUCCESS, NULL);
329
return MAPI_E_NOT_FOUND;