mapiproxy/libmapistore/mapistore_ldb_wrap.po \
mapiproxy/libmapistore/mapistore_indexing.po \
mapiproxy/libmapistore/mapistore_namedprops.po \
+ mapiproxy/libmapistore/mapistore_notification.po \
libmapi.$(SHLIBEXT).$(PACKAGE_VERSION)
@echo "Linking $@"
@$(CC) -o $@ $(DSOOPT) $^ -L. $(LDFLAGS) $(LIBS) $(TDB_LIBS) $(DL_LIBS) -Wl,-soname,libmapistore.$(SHLIBEXT).$(LIBMAPISTORE_SO_VERSION)
*/
#define SIZE_DFLT_ROPDELETEMESSAGE 1
+/**
+ \details Notify Rop has non-default fixed response size for:
+ -# RopId: uint8_t
+ -# NotificationHandle: uint32_t
+ -# LogonId: uint8_t
+ -# NotificationType: uint16_t
+ */
+#define SIZE_DFLT_ROPNOTIFY 8
/**
\details GetSearchCriteria Rop has fixed response size for:
/* definitions from libmapiserver_oxcnotif.c */
uint16_t libmapiserver_RopRegisterNotification_size(void);
+uint16_t libmapiserver_RopNotify_size(struct EcDoRpc_MAPI_REPL *);
/* definitions from libmapiserver_oxcdata.c */
uint16_t libmapiserver_TypedString_size(struct TypedString);
\brief OXCNOTIF ROP Response size calculations
*/
+
#include "libmapiserver.h"
+#include <util/debug.h>
/**
\details Calculate RegisterNotification Rop size
{
return SIZE_DFLT_MAPI_RESPONSE;
}
+
+/**
+ \details Calculate Notify Rop size
+
+ \return Size of Notify response
+ */
+_PUBLIC_ uint16_t libmapiserver_RopNotify_size(struct EcDoRpc_MAPI_REPL *response)
+{
+ union NotificationData *NotificationData;
+
+ uint16_t size = SIZE_DFLT_ROPNOTIFY;
+
+ /* TODO: to be completed... */
+
+ NotificationData = &response->u.mapi_Notify.NotificationData;
+ switch (response->u.mapi_Notify.NotificationType) {
+ /* Folders */
+ case 0x3010: /* different forms of folder modifications */
+ size += sizeof (uint32_t);
+ case 0x1010:
+ case 0x2010:
+ size += sizeof (uint32_t);
+ case 0x0010: /* folder modified */
+ size += sizeof(uint64_t) + sizeof(uint16_t);
+ if (NotificationData->FolderModifiedNotification_10.TagCount != 0xffff) {
+ size += sizeof(enum MAPITAGS) * NotificationData->FolderModifiedNotification_10.TagCount;
+ }
+ break;
+
+ case 0x0004: /* folder created */
+ case 0x8004: /* message created */
+ case 0x8010: /* message modified */
+ size += sizeof(uint16_t);
+ if (NotificationData->MessageCreatedNotification.TagCount != 0xffff) {
+ size += sizeof(enum MAPITAGS) * NotificationData->MessageCreatedNotification.TagCount;
+ }
+ case 0x8008: /* message deleted */
+ case 0x0008: /* folder deleted */
+ size += 2 * sizeof(uint64_t);
+ break;
+
+ /* Tables */
+ case 0x0100: /* hierarchy table changed */
+ size += sizeof(uint16_t); /* TableEventType */
+ switch (NotificationData->HierarchyTableChange.TableEvent) {
+ case TABLE_ROW_ADDED:
+ size += 2 * sizeof(uint64_t); /* FID and InsertAfterFID */
+ size += sizeof(uint16_t) + NotificationData->HierarchyTableChange.HierarchyTableChangeUnion.HierarchyRowAddedNotification.Columns.length; /* blob length */
+ break;
+ case TABLE_ROW_DELETED:
+ size += sizeof(uint64_t); /* FID */
+ break;
+ case TABLE_ROW_MODIFIED:
+ size += 2 * sizeof(uint64_t); /* FID and InsertAfterFID */
+ size += sizeof(uint16_t) + NotificationData->HierarchyTableChange.HierarchyTableChangeUnion.HierarchyRowModifiedNotification.Columns.length; /* blob length */
+ break;
+ default: /* TABLE_CHANGED and TABLE_RESTRICT_DONE */
+ size += 0;
+ }
+ break;
+ case 0x8100: /* contents table changed */
+ size += sizeof(uint16_t); /* TableEventType */
+ switch (NotificationData->ContentsTableChange.TableEvent) {
+ case TABLE_ROW_ADDED:
+ size += 2 * (2 * sizeof(uint64_t) + sizeof(uint32_t)); /* FID, MID, Instance, InsertAfterFID, InsertAfterMID, InsertAfterInstance */
+ size += sizeof(uint16_t) + NotificationData->ContentsTableChange.ContentsTableChangeUnion.ContentsRowAddedNotification.Columns.length; /* blob length */
+ break;
+ case TABLE_ROW_DELETED:
+ size += 2 * sizeof(uint64_t) + sizeof(uint32_t); /* FID, MID, Instance */
+ break;
+ case TABLE_ROW_MODIFIED:
+ size += 2 * (2 * sizeof(uint64_t) + sizeof(uint32_t)); /* FID, MID, Instance, InsertAfterFID, InsertAfterMID, InsertAfterInstance */
+ size += sizeof(uint16_t) + NotificationData->ContentsTableChange.ContentsTableChangeUnion.ContentsRowModifiedNotification.Columns.length;
+ break;
+ default: /* TABLE_CHANGED and TABLE_RESTRICT_DONE */
+ size += 0;
+ }
+ break;
+ case 0xc100: /* search table changed */
+ size += sizeof(uint16_t); /* TableEventType */
+ switch (NotificationData->SearchTableChange.TableEvent) {
+ case TABLE_ROW_ADDED:
+ size += 2 * (2 * sizeof(uint64_t) + sizeof(uint32_t)); /* FID, MID, Instance, InsertAfterFID, InsertAfterMID, InsertAfterInstance */
+ size += sizeof(uint16_t) + NotificationData->SearchTableChange.ContentsTableChangeUnion.ContentsRowAddedNotification.Columns.length; /* blob length */
+ break;
+ case TABLE_ROW_DELETED:
+ size += 2 * sizeof(uint64_t) + sizeof(uint32_t); /* FID, MID, Instance */
+ break;
+ case TABLE_ROW_MODIFIED:
+ size += 2 * (2 * sizeof(uint64_t) + sizeof(uint32_t)); /* FID, MID, Instance, InsertAfterFID, InsertAfterMID, InsertAfterInstance */
+ size += sizeof(uint16_t) + NotificationData->SearchTableChange.ContentsTableChangeUnion.ContentsRowModifiedNotification.Columns.length;
+ break;
+ default: /* TABLE_CHANGED and TABLE_RESTRICT_DONE */
+ size += 0;
+ }
+ break;
+
+ /* case 0x0002: */
+ /* case 0x8002: */
+ /* size += sizeof(struct NewMailNotification); */
+ /* if (response->u.mapi_Notify.NewMailNotification.UnicodeFlag) { */
+ /* size += strlen_m_ext(response->u.mapi_Notify.NewMailNotification.MessageClass.lpszW, CH_UTF8, CH_UTF16BE) * 2 + 2; */
+ /* } */
+ /* else { */
+ /* size += strlen(response->u.mapi_Notify.NewMailNotification.MessageClass.lpszA) + 1; */
+ /* } */
+ /* break; */
+ /* case 0x0020: */
+ /* case 0x0040: */
+ /* size += sizeof(struct FolderMoveCopyNotification); */
+ /* break; */
+ /* case 0x0080: */
+ /* size += sizeof(struct SearchCompleteNotification); */
+ /* break; */
+ /* case 0x0100: */
+ /* size += sizeof(struct HierarchyTableChange); */
+ /* break; */
+ /* case 0x0200: */
+ /* size += sizeof(struct IcsNotification); */
+ /* break; */
+ /* case 0x1010: */
+ /* size += sizeof(struct FolderModifiedNotification_1010); */
+ /* break; */
+ /* case 0x2010: */
+ /* size += sizeof(struct FolderModifiedNotification_2010); */
+ /* break; */
+ /* case 0x3010: */
+ /* size += sizeof(struct FolderModifiedNotification_3010); */
+ /* break; */
+ /* case 0x8020: */
+ /* case 0x8040: */
+ /* size += sizeof(struct MessageMoveCopyNotification); */
+ /* break; */
+ /* case 0x8100: */
+ /* case 0xc100: */
+ /* size += sizeof(struct ContentsTableChange); */
+ /* break; */
+ /* case 0xc004: */
+ /* size += sizeof(struct SearchMessageCreatedNotification); */
+ /* break; */
+ /* case 0xc008: */
+ /* size += sizeof(struct SearchMessageRemovedNotification); */
+ /* break; */
+ /* case 0xc010: */
+ /* size += sizeof(struct SearchMessageModifiedNotification); */
+ /* break; */
+ default:
+ DEBUG(5, ("unhandled size case %.4x, expect buffer errors soon\n", response->u.mapi_Notify.NotificationType));
+ }
+
+ return size;
+}
struct processing_context *processing_ctx;
struct backend_context_list *context_list;
struct indexing_context_list *indexing_list;
+ struct mapistore_subscription_list *subscriptions;
+ struct mapistore_notification_list *notifications;
void *nprops_ctx;
};
/* definitions from mapistore_namedprops.c */
int mapistore_namedprops_get_mapped_id(void *ldb_ctx, struct MAPINAMEID, uint16_t *);
+/* definitions from mapistore_notifications.c (proof-of-concept) */
+
+/* notifications subscriptions */
+struct mapistore_subscription_list {
+ struct mapistore_subscription *subscription;
+ struct mapistore_subscription_list *next;
+ struct mapistore_subscription_list *prev;
+};
+
+struct mapistore_table_subscription_parameters {
+ uint8_t table_type;
+ uint64_t folder_id; /* the parent folder id */
+};
+
+struct mapistore_object_subscription_parameters {
+ bool whole_store;
+ uint64_t folder_id;
+ uint64_t object_id;
+};
+
+struct mapistore_subscription {
+ uint32_t handle;
+ uint16_t notification_types;
+ union {
+ struct mapistore_table_subscription_parameters table_parameters;
+ struct mapistore_object_subscription_parameters object_parameters;
+ } parameters;
+};
+
+struct mapistore_subscription *mapistore_new_subscription(TALLOC_CTX *, uint32_t, uint16_t, void *);
+
+/* notifications (implementation) */
+
+struct mapistore_notification_list {
+ struct mapistore_notification *notification;
+ struct mapistore_notification_list *next;
+ struct mapistore_notification_list *prev;
+};
+
+enum mapistore_notification_type {
+ MAPISTORE_OBJECT_CREATED = 1,
+ MAPISTORE_OBJECT_MODIFIED = 2,
+ MAPISTORE_OBJECT_DELETED = 3
+};
+
+struct mapistore_table_notification_parameters {
+ uint8_t table_type;
+ uint32_t row_id;
+
+ uint32_t handle;
+ uint64_t folder_id; /* the parent folder id */
+ uint64_t object_id; /* the folder/message id */
+ uint32_t instance_id;
+};
+
+struct mapistore_object_notification_parameters {
+ uint64_t folder_id; /* the parent folder id */
+ uint64_t object_id; /* the folder/message id */
+ uint16_t tag_count;
+ enum MAPITAGS *tags;
+ bool new_message_count;
+ uint32_t message_count;
+};
+
+struct mapistore_notification {
+ uint32_t object_type;
+ enum mapistore_notification_type event;
+ union {
+ struct mapistore_table_notification_parameters table_parameters;
+ struct mapistore_object_notification_parameters object_parameters;
+ } parameters;
+};
+
+void mapistore_notification_set_context(struct mapistore_context *);
+struct mapistore_subscription_list *mapistore_find_matching_subscriptions(struct mapistore_context *, struct mapistore_notification *);
+
+void mapistore_push_notification(uint8_t, enum mapistore_notification_type, void *);
+
__END_DECLS
#endif /* ! __MAPISTORE_H */
mstore_ctx->context_list = NULL;
mstore_ctx->indexing_list = talloc_zero(mstore_ctx, struct indexing_context_list);
+ mstore_ctx->subscriptions = NULL;
mstore_ctx->nprops_ctx = NULL;
retval = mapistore_namedprops_init(mstore_ctx, &(mstore_ctx->nprops_ctx));
+/*
+ OpenChange Storage Abstraction Layer library
+
+ OpenChange Project
+
+ Copyright (C) Wolfgang Sourdeau 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <talloc.h>
+#include <dlinklist.h>
+
+#include "mapistore.h"
+
+static struct mapistore_context *active_context = NULL;
+
+struct mapistore_subscription *mapistore_new_subscription(TALLOC_CTX *mem_ctx, uint32_t handle,
+ uint16_t notification_types,
+ void *notification_parameters)
+{
+ struct mapistore_subscription *new_subscription;
+ struct mapistore_table_subscription_parameters *table_parameters;
+ struct mapistore_object_subscription_parameters *object_parameters;
+
+ new_subscription = talloc_zero(mem_ctx, struct mapistore_subscription);
+ new_subscription->handle = handle;
+ new_subscription->notification_types = notification_types;
+ if (notification_types == fnevTableModified) {
+ table_parameters = notification_parameters;
+ new_subscription->parameters.table_parameters = *table_parameters;
+ }
+ else {
+ object_parameters = notification_parameters;
+ new_subscription->parameters.object_parameters = *object_parameters;
+ }
+
+ return new_subscription;
+}
+
+void mapistore_notification_set_context(struct mapistore_context *new_context)
+{
+ active_context = new_context;
+}
+
+void mapistore_push_notification(uint8_t object_type, enum mapistore_notification_type event, void *parameters)
+{
+ struct mapistore_notification *new_notification;
+ struct mapistore_notification_list *new_list;
+ struct mapistore_table_notification_parameters *table_parameters;
+ struct mapistore_object_notification_parameters *object_parameters;
+
+ if (active_context) {
+ new_list = talloc_zero(active_context, struct mapistore_notification_list);
+ new_notification = talloc_zero(new_list, struct mapistore_notification);
+ new_list->notification = new_notification;
+ new_notification->object_type = object_type;
+ new_notification->event = event;
+ if (object_type == MAPISTORE_TABLE) {
+ table_parameters = parameters;
+ new_notification->parameters.table_parameters = *table_parameters;
+ }
+ else {
+ object_parameters = parameters;
+ new_notification->parameters.object_parameters = *object_parameters;
+ if (new_notification->parameters.object_parameters.tag_count > 0
+ && new_notification->parameters.object_parameters.tag_count != 0xffff) {
+ new_notification->parameters.object_parameters.tags
+ = talloc_memdup(new_notification, new_notification->parameters.object_parameters.tags,
+ sizeof(enum MAPITAGS) * new_notification->parameters.object_parameters.tag_count);
+ }
+ }
+ DLIST_ADD_END(active_context->notifications, new_list, void);
+ }
+ else {
+ DEBUG(0, ("cannot push notification when no context is active\n"));
+ }
+}
+
+static bool notification_matches_subscription(struct mapistore_notification *notification, struct mapistore_subscription *subscription)
+{
+ bool result;
+ struct mapistore_table_notification_parameters *n_table_parameters;
+ struct mapistore_table_subscription_parameters *s_table_parameters;
+ struct mapistore_object_notification_parameters *n_object_parameters;
+ struct mapistore_object_subscription_parameters *s_object_parameters;
+
+ result = false;
+
+ if (notification->object_type == MAPISTORE_TABLE) {
+ if (subscription->notification_types & fnevTableModified) {
+ n_table_parameters = ¬ification->parameters.table_parameters;
+ if (subscription->handle == n_table_parameters->handle) {
+ s_table_parameters = &subscription->parameters.table_parameters;
+ result = (n_table_parameters->table_type == s_table_parameters->table_type
+ && n_table_parameters->folder_id == s_table_parameters->folder_id);
+ }
+ }
+ }
+ else {
+ if (((subscription->notification_types & fnevObjectCreated)
+ && notification->event == MAPISTORE_OBJECT_CREATED)
+ || ((subscription->notification_types & fnevObjectModified)
+ && notification->event == MAPISTORE_OBJECT_MODIFIED)
+ || ((subscription->notification_types & fnevObjectDeleted)
+ && notification->event == MAPISTORE_OBJECT_DELETED)) {
+ n_object_parameters = ¬ification->parameters.object_parameters;
+ s_object_parameters = &subscription->parameters.object_parameters;
+ if (s_object_parameters->whole_store)
+ result = true;
+ else {
+ if (notification->object_type == MAPISTORE_FOLDER) {
+ result = (n_object_parameters->object_id == s_object_parameters->folder_id);
+ }
+ else if (notification->object_type == MAPISTORE_MESSAGE) {
+ result = (n_object_parameters->folder_id == s_object_parameters->folder_id
+ && (s_object_parameters->object_id == 0
+ || n_object_parameters->object_id == s_object_parameters->object_id));
+ }
+ else {
+ DEBUG(5, ("[%s] warning: considering notification for unhandled object: %d...\n",
+ __PRETTY_FUNCTION__, notification->object_type));
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+struct mapistore_subscription_list *mapistore_find_matching_subscriptions(struct mapistore_context *mstore_ctx, struct mapistore_notification *notification)
+{
+ struct mapistore_subscription_list *matching_subscriptions, *new_element, *current_element;
+
+ matching_subscriptions = NULL;
+
+ current_element = mstore_ctx->subscriptions;
+ while (current_element) {
+ if (notification_matches_subscription(notification, current_element->subscription)) {
+ new_element = talloc_memdup(mstore_ctx, current_element, sizeof(struct mapistore_subscription_list));
+ DLIST_ADD_END(matching_subscriptions, new_element, void);
+ }
+ current_element = current_element->next;
+ }
+
+ return matching_subscriptions;
+}
*/
#include "mapiproxy/dcesrv_mapiproxy.h"
+#include "mapiproxy/libmapiserver/libmapiserver.h"
#include "dcesrv_exchange_emsmdb.h"
struct exchange_emsmdb_session *emsmdb_session = NULL;
return MAPI_E_SUCCESS;
}
+#warning 'emsmdbp_get_table_object_props' is a dup from the code found in oxctabl:RopQueryRows
+static void **emsmdbp_get_table_object_props(struct emsmdbp_context *emsmdbp_ctx, struct emsmdbp_object *table_object, uint32_t row_id, uint32_t **retvalsp)
+{
+ void **data_pointers;
+ enum MAPISTATUS retval;
+ uint32_t *retvals;
+ struct emsmdbp_object_table *table;
+ struct mapistore_property_data *properties;
+ uint32_t i, num_props;
+
+ table = table_object->object.table;
+ num_props = table_object->object.table->prop_count;
+
+ data_pointers = talloc_array(table_object, void *, num_props);
+ memset(data_pointers, 0, sizeof(void *) * num_props);
+ retvals = talloc_array(table_object, uint32_t, num_props);
+ memset(retvals, 0, sizeof(uint32_t) * num_props);
+
+ if (table_object->poc_api) {
+ properties = talloc_array(NULL, struct mapistore_property_data, num_props);
+ memset(properties, 0, sizeof(struct mapistore_property_data) * num_props);
+ retval = mapistore_pocop_get_table_row(emsmdbp_ctx->mstore_ctx, table->contextID,
+ table_object->poc_backend_object,
+ MAPISTORE_PREFILTERED_QUERY, row_id, properties);
+ if (retval == MAPI_E_SUCCESS) {
+ for (i = 0; i < num_props; i++) {
+ data_pointers[i] = properties[i].data;
+
+ if (properties[i].error) {
+ if (properties[i].error == MAPISTORE_ERR_NOT_FOUND)
+ retvals[i] = MAPI_E_NOT_FOUND;
+ else if (properties[i].error == MAPISTORE_ERR_NO_MEMORY)
+ retvals[i] = MAPI_E_NOT_ENOUGH_MEMORY;
+ else {
+ DEBUG (4, ("%s: unknown mapistore error: %.8x", __PRETTY_FUNCTION__, properties[i].error));
+ }
+ }
+ else {
+ if (properties[i].data == NULL)
+ retvals[i] = MAPI_E_NOT_FOUND;
+ else
+ talloc_steal(data_pointers, properties[i].data);
+ }
+ }
+ }
+ else {
+ DEBUG(5, ("%s: invalid object (likely due to a restriction)\n", __location__));
+ talloc_free(retvals);
+ retvals = NULL;
+ talloc_free(data_pointers);
+ data_pointers = NULL;
+ }
+ talloc_free(properties);
+ }
+ else {
+ retval = MAPI_E_SUCCESS;
+ for (i = 0; retval != MAPI_E_INVALID_OBJECT && i < num_props; i++) {
+ retval = mapistore_get_table_property(emsmdbp_ctx->mstore_ctx, table->contextID,
+ table->ulType,
+ MAPISTORE_PREFILTERED_QUERY,
+ table->folderID,
+ table->properties[i],
+ row_id, data_pointers + i);
+ if (retval == MAPI_E_INVALID_OBJECT) {
+ DEBUG(5, ("%s: invalid object (likely due to a restriction)\n", __location__));
+ talloc_free(retvals);
+ retvals = NULL;
+ talloc_free(data_pointers);
+ data_pointers = NULL;
+ }
+ else {
+ retvals[i] = retval;
+ }
+ }
+ }
+
+ if (retvalsp)
+ *retvalsp = retvals;
+
+ return data_pointers;
+}
+
+#warning 'emsmdbp_fill_table_row' is a dup from the code found in oxctabl:RopQueryRows
+static void emsmdbp_fill_table_row(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx,
+ DATA_BLOB *table_row, uint16_t num_props,
+ enum MAPITAGS *properties,
+ void **data_pointers, uint32_t *retvals)
+{
+ uint16_t i;
+ uint8_t flagged;
+ enum MAPITAGS property;
+ void *data;
+ uint32_t retval;
+
+ flagged = 0;
+
+ for (i = 0; !flagged && i < num_props; i++) {
+ if (retvals[i] != MAPI_E_SUCCESS) {
+ flagged = 1;
+ }
+ }
+
+ if (flagged) {
+ libmapiserver_push_property(mem_ctx,
+ lpcfg_iconv_convenience(emsmdbp_ctx->lp_ctx),
+ 0x0000000b, (const void *)&flagged,
+ table_row, 0, 0, 0);
+ }
+ else {
+ libmapiserver_push_property(mem_ctx,
+ lpcfg_iconv_convenience(emsmdbp_ctx->lp_ctx),
+ 0x00000000, (const void *)&flagged,
+ table_row, 0, 1, 0);
+ }
+
+ for (i = 0; i < num_props; i++) {
+ property = properties[i];
+ retval = retvals[i];
+ if (retval != MAPI_E_SUCCESS) {
+ property = (property & 0xFFFF0000) + PT_ERROR;
+ data = &retval;
+ }
+ else {
+ data = data_pointers[i];
+ }
+
+ libmapiserver_push_property(mem_ctx, lpcfg_iconv_convenience(emsmdbp_ctx->lp_ctx),
+ property, data, table_row,
+ flagged?PT_ERROR:0, flagged, 0);
+ }
+}
+
+static void emsmdbp_fill_notification(TALLOC_CTX *mem_ctx,
+ struct emsmdbp_context *emsmdbp_ctx,
+ struct EcDoRpc_MAPI_REPL *mapi_repl,
+ struct mapistore_subscription *subscription,
+ struct mapistore_notification *notification,
+ uint16_t *sizep)
+{
+ struct Notify_repl *reply;
+ struct emsmdbp_object *handle_object;
+ struct emsmdbp_object_table *table;
+ struct mapi_handles *handle_object_handle;
+ enum MAPISTATUS retval;
+ void **data_pointers;
+ DATA_BLOB *table_row;
+ uint32_t *retvals;
+ uint32_t *previous_row_properties;
+ uint32_t saved_prop_count, *saved_properties;
+ uint64_t prev_fid, prev_mid;
+ uint32_t prev_instance;
+
+ mapi_repl->opnum = op_MAPI_Notify;
+ reply = &mapi_repl->u.mapi_Notify;
+ reply->LogonId = 0; /* TODO: seems to be always 0 ? */
+
+ retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, subscription->handle, &handle_object_handle);
+ if (retval) {
+ reply->NotificationType = fnevCriticalError;
+ DEBUG(5, ("notification handle not found\n"));
+ goto end;
+ }
+ retval = mapi_handles_get_private_data(handle_object_handle, (void **) &handle_object);
+ if (retval) {
+ reply->NotificationType = fnevCriticalError;
+ DEBUG(5, ("object not found for notification handle\n"));
+ goto end;
+ }
+
+ reply->NotificationHandle = subscription->handle;
+ switch (notification->object_type) {
+ case MAPISTORE_MESSAGE:
+ reply->NotificationType = fnevMbit;
+ break;
+ case MAPISTORE_FOLDER:
+ if (notification->parameters.object_parameters.new_message_count) {
+ reply->NotificationType = fnevTbit;
+ }
+ else {
+ reply->NotificationType = 0;
+ }
+ break;
+ case MAPISTORE_TABLE:
+ reply->NotificationType = fnevTableModified;
+ if (notification->parameters.table_parameters.table_type != MAPISTORE_FOLDER_TABLE) {
+ reply->NotificationType |= (fnevMbit | fnevSbit);
+ }
+ break;
+ default:
+ reply->NotificationType = fnevCriticalError;
+ DEBUG(5, ("unknown value for notification object type: %d\n", notification->object_type));
+ goto end;
+ }
+
+ if (notification->object_type == MAPISTORE_TABLE) {
+ table = handle_object->object.table;
+
+ /* FIXME: here is a hack to update table counters and which would not be needed if the backend had access to the table structure... */
+ if (notification->event == MAPISTORE_OBJECT_CREATED) {
+ table->denominator++;
+ }
+ else if (notification->event == MAPISTORE_OBJECT_DELETED) {
+ table->denominator--;
+ if (table->numerator >= table->denominator) {
+ table->numerator = table->denominator;
+ }
+ }
+
+ if (notification->parameters.table_parameters.table_type == MAPISTORE_FOLDER_TABLE) {
+ if (notification->event == MAPISTORE_OBJECT_CREATED || notification->event == MAPISTORE_OBJECT_MODIFIED) {
+ if (notification->parameters.table_parameters.row_id > 0) {
+ /* FIXME: this hack enables the fetching of some properties from the previous row */
+ saved_prop_count = table->prop_count;
+ saved_properties = table->properties;
+ previous_row_properties = talloc_array(NULL, uint32_t, 1);
+ previous_row_properties[0] = PR_FID;
+ table->properties = previous_row_properties;
+ table->prop_count = 1;
+ if (handle_object->poc_api) {
+ mapistore_pocop_set_table_columns(emsmdbp_ctx->mstore_ctx, table->contextID, handle_object->poc_backend_object, table->prop_count, (enum MAPITAGS *) table->properties);
+ }
+ data_pointers = emsmdbp_get_table_object_props(emsmdbp_ctx, handle_object,
+ notification->parameters.table_parameters.row_id - 1,
+ &retvals);
+ if (data_pointers) {
+ prev_fid = *(uint32_t *) data_pointers[0];
+ talloc_free(data_pointers);
+ }
+ else {
+ prev_fid = -1;
+ }
+
+ table->prop_count = saved_prop_count;
+ table->properties = saved_properties;
+ talloc_free(previous_row_properties);
+ if (handle_object->poc_api) {
+ mapistore_pocop_set_table_columns(emsmdbp_ctx->mstore_ctx, table->contextID, handle_object->poc_backend_object, table->prop_count, (enum MAPITAGS *) table->properties);
+ }
+ }
+ else {
+ prev_fid = 0;
+ }
+
+ table_row = talloc_zero(mem_ctx, DATA_BLOB);
+ data_pointers = emsmdbp_get_table_object_props(emsmdbp_ctx, handle_object,
+ notification->parameters.table_parameters.row_id,
+ &retvals);
+ emsmdbp_fill_table_row(mem_ctx, emsmdbp_ctx, table_row, table->prop_count, (enum MAPITAGS *) table->properties, data_pointers, retvals);
+ talloc_free(data_pointers);
+ talloc_free(retvals);
+ }
+
+ /* FIXME: for some reason, TABLE_ROW_MODIFIED and TABLE_ROW_DELETED do not work... */
+ reply->NotificationData.SearchTableChange.TableEvent = TABLE_CHANGED;
+ switch (notification->event) {
+ case MAPISTORE_OBJECT_CREATED:
+ /* case MAPISTORE_OBJECT_MODIFIED: */
+ reply->NotificationData.HierarchyTableChange.TableEvent = (notification->event == MAPISTORE_OBJECT_CREATED ? TABLE_ROW_ADDED : TABLE_ROW_MODIFIED);
+ reply->NotificationData.HierarchyTableChange.HierarchyTableChangeUnion.HierarchyRowAddedNotification.FID = notification->parameters.table_parameters.object_id;
+ reply->NotificationData.HierarchyTableChange.HierarchyTableChangeUnion.HierarchyRowAddedNotification.InsertAfterFID = prev_fid;
+ reply->NotificationData.HierarchyTableChange.HierarchyTableChangeUnion.HierarchyRowAddedNotification.Columns = *table_row;
+ break;
+ /* case MAPISTORE_OBJECT_DELETED: */
+ /* reply->NotificationData.HierarchyTableChange.TableEvent = TABLE_ROW_DELETED; */
+ /* reply->NotificationData.HierarchyTableChange.HierarchyTableChangeUnion.HierarchyRowDeletedNotification.FID = notification->parameters.table_parameters.object_id; */
+ /* break; */
+ /* default: */
+ /* reply->NotificationType = fnevCriticalError; */
+ /* DEBUG(5, ("unknown value for notification event: %d\n", notification->event)); */
+ /* goto end; */
+ }
+ }
+ else {
+ if (notification->event == MAPISTORE_OBJECT_CREATED || notification->event == MAPISTORE_OBJECT_MODIFIED) {
+ if (notification->parameters.table_parameters.row_id > 0) {
+ /* FIXME: this hack enables the fetching of some properties from the previous row */
+ saved_prop_count = table->prop_count;
+ saved_properties = table->properties;
+ previous_row_properties = talloc_array(NULL, uint32_t, 3);
+ previous_row_properties[0] = PR_FID;
+ previous_row_properties[1] = PR_MID;
+ previous_row_properties[2] = PR_INSTANCE_NUM;
+ table->properties = previous_row_properties;
+ table->prop_count = 3;
+ if (handle_object->poc_api) {
+ mapistore_pocop_set_table_columns(emsmdbp_ctx->mstore_ctx, table->contextID, handle_object->poc_backend_object, table->prop_count, (enum MAPITAGS *) table->properties);
+ }
+ data_pointers = emsmdbp_get_table_object_props(emsmdbp_ctx, handle_object, notification->parameters.table_parameters.row_id - 1, NULL);
+ if (data_pointers) {
+ prev_fid = *(uint64_t *) data_pointers[0];
+ prev_mid = *(uint64_t *) data_pointers[1];
+ prev_instance = *(uint32_t *) data_pointers[2];
+ talloc_free(data_pointers);
+ }
+ else {
+ prev_fid = -1;
+ prev_mid = -1;
+ prev_instance = -1;
+ }
+
+ table->prop_count = saved_prop_count;
+ table->properties = saved_properties;
+ talloc_free(previous_row_properties);
+ if (handle_object->poc_api) {
+ mapistore_pocop_set_table_columns(emsmdbp_ctx->mstore_ctx, table->contextID, handle_object->poc_backend_object, table->prop_count, (enum MAPITAGS *) table->properties);
+ }
+ }
+ else {
+ prev_fid = 0;
+ prev_mid = 0;
+ prev_instance = 0;
+ }
+
+ table_row = talloc_zero(mem_ctx, DATA_BLOB);
+ data_pointers = emsmdbp_get_table_object_props(emsmdbp_ctx, handle_object,
+ notification->parameters.table_parameters.row_id,
+ &retvals);
+ emsmdbp_fill_table_row(mem_ctx, emsmdbp_ctx, table_row, table->prop_count, (enum MAPITAGS *) table->properties, data_pointers, retvals);
+ talloc_free(data_pointers);
+ talloc_free(retvals);
+ }
+
+ /* FIXME: for some reason, TABLE_ROW_MODIFIED and TABLE_ROW_DELETED do not work... */
+ reply->NotificationData.SearchTableChange.TableEvent = TABLE_CHANGED;
+ switch (notification->event) {
+ case MAPISTORE_OBJECT_CREATED:
+ /* case MAPISTORE_OBJECT_MODIFIED: */
+ reply->NotificationData.SearchTableChange.TableEvent = (notification->event == MAPISTORE_OBJECT_CREATED ? TABLE_ROW_ADDED : TABLE_ROW_MODIFIED);
+ reply->NotificationData.SearchTableChange.ContentsTableChangeUnion.ContentsRowAddedNotification.FID = notification->parameters.table_parameters.folder_id;
+ reply->NotificationData.SearchTableChange.ContentsTableChangeUnion.ContentsRowAddedNotification.MID = notification->parameters.table_parameters.object_id;
+ reply->NotificationData.SearchTableChange.ContentsTableChangeUnion.ContentsRowAddedNotification.Instance = notification->parameters.table_parameters.instance_id;
+ reply->NotificationData.SearchTableChange.ContentsTableChangeUnion.ContentsRowAddedNotification.InsertAfterFID = prev_fid;
+ reply->NotificationData.SearchTableChange.ContentsTableChangeUnion.ContentsRowAddedNotification.InsertAfterMID = prev_mid;
+ reply->NotificationData.SearchTableChange.ContentsTableChangeUnion.ContentsRowAddedNotification.InsertAfterInstance = prev_instance;
+ reply->NotificationData.SearchTableChange.ContentsTableChangeUnion.ContentsRowAddedNotification.Columns = *table_row;
+ break;
+ /* case MAPISTORE_OBJECT_DELETED: */
+ /* reply->NotificationData.SearchTableChange.TableEvent = TABLE_ROW_DELETED; */
+ /* reply->NotificationData.SearchTableChange.ContentsTableChangeUnion.ContentsRowDeletedNotification.FID = notification->parameters.table_parameters.folder_id; */
+ /* reply->NotificationData.SearchTableChange.ContentsTableChangeUnion.ContentsRowDeletedNotification.MID = notification->parameters.table_parameters.object_id; */
+ /* reply->NotificationData.SearchTableChange.ContentsTableChangeUnion.ContentsRowDeletedNotification.Instance = notification->parameters.table_parameters.instance_id; */
+ /* break; */
+ /* default: */
+ /* reply->NotificationType = fnevCriticalError; */
+ /* DEBUG(5, ("unknown value for notification event: %d\n", notification->event)); */
+ /* goto end; */
+ }
+ }
+ }
+ else {
+ switch (notification->event) {
+ case MAPISTORE_OBJECT_CREATED:
+ reply->NotificationType |= fnevObjectCreated;
+ break;
+ case MAPISTORE_OBJECT_DELETED:
+ reply->NotificationType |= fnevObjectDeleted;
+ break;
+ case MAPISTORE_OBJECT_MODIFIED:
+ reply->NotificationType |= fnevObjectModified;
+ break;
+ default:
+ reply->NotificationType = fnevCriticalError;
+ DEBUG(5, ("unknown value for notification event: %d\n", notification->event));
+ goto end;
+ }
+ if (notification->object_type == MAPISTORE_MESSAGE) {
+ switch (notification->event) {
+ case MAPISTORE_OBJECT_CREATED:
+ reply->NotificationData.MessageCreatedNotification.FID = notification->parameters.object_parameters.folder_id;
+ reply->NotificationData.MessageCreatedNotification.MID = notification->parameters.object_parameters.object_id;
+ reply->NotificationData.MessageCreatedNotification.TagCount = notification->parameters.object_parameters.tag_count;
+ if (notification->parameters.object_parameters.tag_count
+ && notification->parameters.object_parameters.tag_count != 0xffff) {
+ reply->NotificationData.MessageCreatedNotification.NotificationTags.Tags = talloc_memdup(mem_ctx, notification->parameters.object_parameters.tags, notification->parameters.object_parameters.tag_count * sizeof(enum MAPITAGS));
+ }
+ else {
+ reply->NotificationData.MessageCreatedNotification.NotificationTags.Tags = NULL;
+ }
+ break;
+ case MAPISTORE_OBJECT_MODIFIED:
+ reply->NotificationData.MessageModifiedNotification.FID = notification->parameters.object_parameters.folder_id;
+ reply->NotificationData.MessageModifiedNotification.MID = notification->parameters.object_parameters.object_id;
+ reply->NotificationData.MessageModifiedNotification.TagCount = notification->parameters.object_parameters.tag_count;
+ if (notification->parameters.object_parameters.tag_count
+ && notification->parameters.object_parameters.tag_count != 0xffff) {
+ reply->NotificationData.MessageModifiedNotification.NotificationTags.Tags = talloc_memdup(mem_ctx, notification->parameters.object_parameters.tags, notification->parameters.object_parameters.tag_count * sizeof(enum MAPITAGS));
+ }
+ else {
+ reply->NotificationData.MessageModifiedNotification.NotificationTags.Tags = NULL;
+ }
+ break;
+ default: /* MAPISTORE_OBJECT_DELETED */
+ reply->NotificationData.MessageDeletedNotification.FID = notification->parameters.object_parameters.folder_id;
+ reply->NotificationData.MessageDeletedNotification.MID = notification->parameters.object_parameters.object_id;
+ }
+ }
+ else { /* MAPISTORE_FOLDER */
+ switch (notification->event) {
+ case MAPISTORE_OBJECT_CREATED:
+ reply->NotificationData.FolderCreatedNotification.ParentFID = notification->parameters.object_parameters.folder_id;
+ reply->NotificationData.FolderCreatedNotification.FID = notification->parameters.object_parameters.object_id;
+ reply->NotificationData.FolderCreatedNotification.TagCount = notification->parameters.object_parameters.tag_count;
+ if (notification->parameters.object_parameters.tag_count
+ && notification->parameters.object_parameters.tag_count != 0xffff) {
+ reply->NotificationData.FolderCreatedNotification.NotificationTags.Tags = talloc_memdup(mem_ctx, notification->parameters.object_parameters.tags, notification->parameters.object_parameters.tag_count * sizeof(enum MAPITAGS));
+ }
+ else {
+ reply->NotificationData.FolderCreatedNotification.NotificationTags.Tags = NULL;
+ }
+ break;
+ case MAPISTORE_OBJECT_MODIFIED:
+ reply->NotificationData.FolderModifiedNotification_10.FID = notification->parameters.object_parameters.object_id;
+ reply->NotificationData.FolderModifiedNotification_10.TagCount = notification->parameters.object_parameters.tag_count;
+ if (notification->parameters.object_parameters.tag_count
+ && notification->parameters.object_parameters.tag_count != 0xffff) {
+ reply->NotificationData.FolderModifiedNotification_10.NotificationTags.Tags = talloc_memdup(mem_ctx, notification->parameters.object_parameters.tags, notification->parameters.object_parameters.tag_count * sizeof(enum MAPITAGS));
+ }
+ else {
+ reply->NotificationData.FolderModifiedNotification_10.NotificationTags.Tags = NULL;
+ }
+
+ if (notification->parameters.object_parameters.new_message_count) {
+ reply->NotificationData.FolderModifiedNotification_1010.TotalMessageCount = notification->parameters.object_parameters.message_count;
+ }
+
+ break;
+ default: /* MAPISTORE_OBJECT_DELETED */
+ reply->NotificationData.FolderDeletedNotification.ParentFID = notification->parameters.object_parameters.folder_id;
+ reply->NotificationData.FolderDeletedNotification.FID = notification->parameters.object_parameters.object_id;
+ }
+ }
+ }
+
+end:
+ *sizep += libmapiserver_RopNotify_size(mapi_repl);
+}
static struct mapi_response *EcDoRpc_process_transaction(TALLOC_CTX *mem_ctx,
struct emsmdbp_context *emsmdbp_ctx,
{
enum MAPISTATUS retval;
struct mapi_response *mapi_response;
+ struct mapistore_notification_list *notification_holder;
+ struct mapistore_subscription_list *subscription_list, *subscription_holder;
uint32_t handles_length;
uint16_t size = 0;
uint32_t i;
mapi_response->mapi_len = 2;
return mapi_response;
}
-
+
+ /* prepare notification context (TODO: will not work with multi-threading) */
+ mapistore_notification_set_context(emsmdbp_ctx->mstore_ctx);
+
/* Step 2. Process serialized MAPI requests */
mapi_response->mapi_repl = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REPL);
for (i = 0, idx = 0, size = 0; mapi_request->mapi_req[i].opnum != 0; i++) {
if (mapi_request->mapi_req[i].opnum != op_MAPI_Release) {
idx++;
}
-
}
/* Step 3. Notifications/Pending calls should be processed here */
- mapi_response->mapi_repl[idx].opnum = 0;
+ while ((notification_holder = emsmdbp_ctx->mstore_ctx->notifications)) {
+ subscription_list = mapistore_find_matching_subscriptions(emsmdbp_ctx->mstore_ctx, notification_holder->notification);
+ while ((subscription_holder = subscription_list)) {
+ mapi_response->mapi_repl = talloc_realloc(mem_ctx, mapi_response->mapi_repl, struct EcDoRpc_MAPI_REPL, idx + 2);
+ emsmdbp_fill_notification(mapi_response->mapi_repl, emsmdbp_ctx, &(mapi_response->mapi_repl[idx]), subscription_holder->subscription, notification_holder->notification, &size);
+ DLIST_REMOVE(subscription_list, subscription_holder);
+ talloc_free(subscription_holder);
+ idx++;
+ }
+
+ DLIST_REMOVE(emsmdbp_ctx->mstore_ctx->notifications, notification_holder);
+ talloc_free(notification_holder);
+ }
+ mapistore_notification_set_context(NULL);
+
+ mapi_response->mapi_repl[idx].opnum = 0;
/* Step 4. Fill mapi_response structure */
handles_length = mapi_request->mapi_len - mapi_request->length;
struct ldb_context *samdb_ctx;
struct mapistore_context *mstore_ctx;
struct mapi_handles_context *handles_ctx;
+
TALLOC_CTX *mem_ctx;
};
-
struct exchange_emsmdb_session {
uint32_t pullTimeStamp;
struct mpm_session *session;
EMSMDBP_OBJECT_MESSAGE = 0x3,
EMSMDBP_OBJECT_TABLE = 0x4,
EMSMDBP_OBJECT_STREAM = 0x5,
- EMSMDBP_OBJECT_ATTACHMENT = 0x6
+ EMSMDBP_OBJECT_ATTACHMENT = 0x6,
+ EMSMDBP_OBJECT_SUBSCRIPTION = 0x7
};
struct emsmdbp_object_mailbox {
uint32_t numerator;
uint32_t denominator;
bool mapistore;
+ struct mapistore_subscription_list *subscription_list;
};
struct emsmdbp_object_stream {
bool mapistore;
};
+struct emsmdbp_object_subscription {
+ uint32_t handle;
+ uint32_t contextID;
+ struct mapistore_subscription_list *subscription_list;
+ bool mapistore;
+};
+
union emsmdbp_objects {
struct emsmdbp_object_mailbox *mailbox;
struct emsmdbp_object_folder *folder;
struct emsmdbp_object_table *table;
struct emsmdbp_object_stream *stream;
struct emsmdbp_object_attachment *attachment;
+ struct emsmdbp_object_subscription *subscription;
};
struct emsmdbp_object {
struct emsmdbp_object *emsmdbp_object_message_init(TALLOC_CTX *, struct emsmdbp_context *, uint64_t, struct mapi_handles *);
struct emsmdbp_object *emsmdbp_object_stream_init(TALLOC_CTX *, struct emsmdbp_context *, uint32_t, enum OpenStream_OpenModeFlags, struct mapi_handles *);
struct emsmdbp_object *emsmdbp_object_attachment_init(TALLOC_CTX *, struct emsmdbp_context *, uint64_t, struct mapi_handles *);
+struct emsmdbp_object *emsmdbp_object_subscription_init(TALLOC_CTX *, struct emsmdbp_context *, struct mapi_handles *);
/* definitions from oxcfold.c */
enum MAPISTATUS EcDoRpc_RopOpenFolder(TALLOC_CTX *, struct emsmdbp_context *, struct EcDoRpc_MAPI_REQ *, struct EcDoRpc_MAPI_REPL *, uint32_t *, uint16_t *);
return "table";
case EMSMDBP_OBJECT_STREAM:
return "stream";
+ case EMSMDBP_OBJECT_SUBSCRIPTION:
+ return "subscription";
default:
return "unknown";
}
return object->object.stream->contextID;
case EMSMDBP_OBJECT_ATTACHMENT:
return object->object.attachment->contextID;
+ case EMSMDBP_OBJECT_SUBSCRIPTION:
+ return object->object.subscription->contextID;
default:
return -1;
}
stream_buffer = talloc_array(aRow.lpProps, uint8_t, stream_size + 1);
*(stream_buffer + stream_size) = 0;
- read(stream->fd, stream_buffer, stream_size);
+ stream_size = read(stream->fd, stream_buffer, stream_size);
if ((stream->property & PT_BINARY) == PT_BINARY) {
binary_data = talloc(aRow.lpProps, struct Binary_r);
mapistore_pocop_release(object->mstore_ctx, object->object.table->contextID,
object->poc_backend_object);
}
+ if (object->object.table->subscription_list) {
+ DEBUG(5, (" list object: removing subscription from context list\n"));
+ DLIST_REMOVE(object->mstore_ctx->subscriptions, object->object.table->subscription_list);
+ }
ret = mapistore_del_context(object->mstore_ctx, object->object.message->contextID);
DEBUG(4, ("[%s:%d] mapistore message context retval = %d\n", __FUNCTION__, __LINE__, ret));
break;
ret = mapistore_del_context(object->mstore_ctx, object->object.attachment->contextID);
DEBUG(4, ("[%s:%d] mapistore stream context retval = %d\n", __FUNCTION__, __LINE__, ret));
break;
+ case EMSMDBP_OBJECT_SUBSCRIPTION:
+ if (object->object.subscription->subscription_list) {
+ DEBUG(5, (" subscription object: removing subscription from context list\n"));
+ DLIST_REMOVE(object->mstore_ctx->subscriptions, object->object.subscription->subscription_list);
+ }
+ ret = mapistore_del_context(object->mstore_ctx, object->object.folder->contextID);
+ DEBUG(4, ("[%s:%d] mapistore subscription context retval = %d\n", __FUNCTION__, __LINE__, ret));
+ break;
default:
DEBUG(4, ("[%s:%d] destroying unhandled object type: %d\n", __FUNCTION__, __LINE__, object->type));
break;
object->object.table->ulType = 0;
object->object.table->mapistore = false;
object->object.table->contextID = -1;
+ object->object.table->subscription_list = NULL;
mapistore = emsmdbp_is_mapistore(parent);
if (mapistore == true) {
return object;
}
+
+/**
+ \details Initialize a notification subscription object
+
+ \param mem_ctx pointer to the memory context
+ \param emsmdbp_ctx pointer to the emsmdb provider cotnext
+ \param whole_store whether the subscription applies to the specified change on the entire store or stricly on the specified folder/message
+ \param folderID the folder identifier
+ \param messageID the message identifier
+ \param parent pointer to the parent MAPI handle
+ */
+_PUBLIC_ struct emsmdbp_object *emsmdbp_object_subscription_init(TALLOC_CTX *mem_ctx,
+ struct emsmdbp_context *emsmdbp_ctx,
+ struct mapi_handles *parent)
+{
+ enum MAPISTATUS retval;
+ struct emsmdbp_object *object;
+ void *data;
+ bool mapistore = false;
+
+ /* Sanity checks */
+ if (!emsmdbp_ctx) return NULL;
+
+ /* Retrieve parent object */
+ retval = mapi_handles_get_private_data(parent, &data);
+ if (retval) return NULL;
+
+ object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx);
+ if (!object) return NULL;
+
+ object->object.subscription = talloc_zero(object, struct emsmdbp_object_subscription);
+ if (!object->object.subscription) {
+ talloc_free(object);
+ return NULL;
+ }
+
+ object->type = EMSMDBP_OBJECT_SUBSCRIPTION;
+ object->object.subscription->subscription_list = NULL;
+
+ mapistore = emsmdbp_is_mapistore(parent);
+ if (mapistore == true) {
+ object->object.subscription->mapistore = true;
+ object->object.subscription->contextID = emsmdbp_get_contextID(parent);
+ }
+ else {
+ object->object.subscription->contextID = -1;
+ }
+
+ return object;
+}
struct mapi_handles *parent;
struct mapi_handles *rec = NULL;
struct emsmdbp_object *object = NULL;
+ struct mapistore_subscription_list *subscription_list;
+ struct mapistore_subscription *subscription;
+ struct mapistore_table_subscription_parameters subscription_parameters;
void *data;
uint64_t folderID;
uint32_t contextID;
retval = mapi_handles_set_private_data(rec, object);
object->object.table->denominator = mapi_repl->u.mapi_GetHierarchyTable.RowCount;
object->object.table->ulType = EMSMDBP_TABLE_FOLDER_TYPE;
+
+ /* notifications */
+ if ((mapi_req->u.mapi_GetHierarchyTable.TableFlags & TableFlags_NoNotifications)) {
+ DEBUG(5, (" notifications skipped\n"));
+ }
+ else {
+ /* we attach the subscription to the session object */
+ subscription_list = talloc_zero(object, struct mapistore_subscription_list);
+ DLIST_ADD(emsmdbp_ctx->mstore_ctx->subscriptions, subscription_list);
+
+ subscription_parameters.table_type = MAPISTORE_FOLDER_TABLE;
+ subscription_parameters.folder_id = folderID;
+
+ /* note that a mapistore_subscription can exist without a corresponding emsmdbp_object (tables) */
+ subscription = mapistore_new_subscription(subscription_list, rec->handle, fnevTableModified, &subscription_parameters);
+ subscription_list->subscription = subscription;
+ object->object.table->subscription_list = subscription_list;
+ }
}
*size += libmapiserver_RopGetHierarchyTable_size(mapi_repl);
struct mapi_handles *parent;
struct mapi_handles *rec = NULL;
struct emsmdbp_object *object = NULL;
+ struct mapistore_subscription_list *subscription_list;
+ struct mapistore_subscription *subscription;
+ struct mapistore_table_subscription_parameters subscription_parameters;
void *data;
uint64_t folderID;
uint32_t contextID;
object = emsmdbp_object_table_init((TALLOC_CTX *)rec, emsmdbp_ctx, parent);
if (object) {
retval = mapi_handles_set_private_data(rec, object);
-
mapistore = emsmdbp_is_mapistore(parent);
switch (mapistore) {
case false:
object->object.table->denominator = mapi_repl->u.mapi_GetHierarchyTable.RowCount;
object->object.table->ulType = table_type;
- }
+
+ /* notifications */
+ if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_NoNotifications)) {
+ DEBUG(5, (" notifications skipped\n"));
+ }
+ else {
+ /* we attach the subscription to the session object */
+ subscription_list = talloc_zero(object, struct mapistore_subscription_list);
+ DLIST_ADD(emsmdbp_ctx->mstore_ctx->subscriptions, subscription_list);
+
+ if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_Associated)) {
+ subscription_parameters.table_type = MAPISTORE_FAI_TABLE;
+ }
+ else {
+ subscription_parameters.table_type = MAPISTORE_MESSAGE_TABLE;
+ }
+ subscription_parameters.folder_id = folderID;
+
+ /* note that a mapistore_subscription can exist without a corresponding emsmdbp_object (tables) */
+ subscription = mapistore_new_subscription(subscription_list, rec->handle, fnevTableModified, &subscription_parameters);
+ subscription_list->subscription = subscription;
+ object->object.table->subscription_list = subscription_list;
+ }
+ }
*size += libmapiserver_RopGetContentsTable_size(mapi_repl);
uint32_t *handles, uint16_t *size)
{
enum MAPISTATUS retval;
- struct mapi_handles *rec = NULL;
+ struct mapi_handles *parent_rec = NULL;
+ struct mapi_handles *subscription_rec = NULL;
uint32_t handle;
+ struct emsmdbp_object *parent_object;
+ struct emsmdbp_object *subscription_object;
+ struct mapistore_subscription *subscription;
+ struct mapistore_subscription_list *subscription_list;
+ struct mapistore_object_subscription_parameters subscription_parameters;
+ void *data;
DEBUG(4, ("exchange_emsmdb: [OXCNOTIF] RegisterNotification (0x29)\n"));
OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
- /* FIXME: Handle this call properly */
mapi_repl->opnum = mapi_req->opnum;
mapi_repl->handle_idx = mapi_req->u.mapi_RegisterNotification.handle_idx;
mapi_repl->error_code = MAPI_E_SUCCESS;
handle = handles[mapi_req->handle_idx];
- retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
+ retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent_rec);
+ if (retval) {
+ mapi_repl->error_code = MAPI_E_INVALID_OBJECT;
+ DEBUG(5, (" handle (%x) not found: %x\n", handle, mapi_req->handle_idx));
+ goto end;
+ }
+
+ retval = mapi_handles_get_private_data(parent_rec, &data);
+ if (retval) {
+ mapi_repl->error_code = retval;
+ DEBUG(5, (" handle data not found, idx = %x\n", mapi_req->handle_idx));
+ goto end;
+ }
+ parent_object = (struct emsmdbp_object *) data;
+
+ retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &subscription_rec);
if (retval) {
mapi_repl->error_code = retval;
goto end;
}
- handles[mapi_repl->handle_idx] = rec->handle;
+ handles[mapi_repl->handle_idx] = subscription_rec->handle;
+
+ /* emsmdb_object */
+ subscription_object = emsmdbp_object_subscription_init(subscription_rec, emsmdbp_ctx, parent_rec);
+ mapi_handles_set_private_data(subscription_rec, subscription_object);
+
+ /* we attach the subscription to the session object.
+ note: a mapistore_subscription can exist without a corresponding emsmdbp_object (tables) */
+ subscription_list = talloc_zero(subscription_object, struct mapistore_subscription_list);
+ DLIST_ADD(emsmdbp_ctx->mstore_ctx->subscriptions, subscription_list);
+
+ subscription_parameters.folder_id = mapi_req->u.mapi_RegisterNotification.FolderId.ID;
+ subscription_parameters.object_id = mapi_req->u.mapi_RegisterNotification.MessageId.ID;
+ subscription_parameters.whole_store = mapi_req->u.mapi_RegisterNotification.WantWholeStore;
+
+ subscription = mapistore_new_subscription(subscription_list, subscription_rec->handle,
+ mapi_req->u.mapi_RegisterNotification.NotificationFlags,
+ &subscription_parameters);
+ subscription_list->subscription = subscription;
+
+ subscription_object->object.subscription->subscription_list = subscription_list;
end:
*size += libmapiserver_RopRegisterNotification_size();