added support for table, message and folder subscriptions
authorwsourdeau <wsourdeau@71d39326-ef09-db11-b2a4-00e04c779ad1>
Mon, 7 Mar 2011 18:51:42 +0000 (18:51 +0000)
committerwsourdeau <wsourdeau@71d39326-ef09-db11-b2a4-00e04c779ad1>
Mon, 7 Mar 2011 18:51:42 +0000 (18:51 +0000)
git-svn-id: https://svn.openchange.org/openchange@2726 71d39326-ef09-db11-b2a4-00e04c779ad1

branches/sogo/Makefile
branches/sogo/mapiproxy/libmapiserver/libmapiserver.h
branches/sogo/mapiproxy/libmapiserver/libmapiserver_oxcnotif.c
branches/sogo/mapiproxy/libmapistore/mapistore.h
branches/sogo/mapiproxy/libmapistore/mapistore_interface.c
branches/sogo/mapiproxy/libmapistore/mapistore_notification.c
branches/sogo/mapiproxy/servers/default/emsmdb/dcesrv_exchange_emsmdb.c
branches/sogo/mapiproxy/servers/default/emsmdb/dcesrv_exchange_emsmdb.h
branches/sogo/mapiproxy/servers/default/emsmdb/emsmdbp_object.c
branches/sogo/mapiproxy/servers/default/emsmdb/oxcfold.c
branches/sogo/mapiproxy/servers/default/emsmdb/oxcnotif.c

index 3c593d2fd07370a25ea282e8ebadc5a1f3d10ab5..d33af73ec12d87f02c596ab212fb86f1d67f4632 100644 (file)
@@ -866,6 +866,7 @@ mapiproxy/libmapistore.$(SHLIBEXT).$(PACKAGE_VERSION):      mapiproxy/libmapistore/m
                                                        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)
index 7222b99481ae21d51f454896a080005d3e1e2089..ec739787532f8095546fd8bdae987ba3f875f630 100644 (file)
  */
 #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:
@@ -387,6 +395,7 @@ uint16_t libmapiserver_RopSaveChangesAttachment_size(struct EcDoRpc_MAPI_REPL *)
 
 /* 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);
index ee8ac0e12215dfc8e7e0a2b927591069b705e432..8165c790485ca4153142171e8eef865d878d11ce 100644 (file)
@@ -25,7 +25,9 @@
    \brief OXCNOTIF ROP Response size calculations
  */
 
+
 #include "libmapiserver.h"
+#include <util/debug.h>
 
 /**
    \details Calculate RegisterNotification Rop size
@@ -36,3 +38,155 @@ _PUBLIC_ uint16_t libmapiserver_RopRegisterNotification_size(void)
 {
        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;
+}
index f532082a2c412db33a6f3031f8675220a1e0d689..cb512b6b2cd7ba39fcfb421e397228332f3a25d6 100644 (file)
@@ -183,6 +183,8 @@ struct mapistore_context {
        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;
 };
 
@@ -271,6 +273,84 @@ int mapistore_indexing_record_del_mid(struct mapistore_context *, uint32_t, uint
 /* 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 */
index f3b54e612340d3af620fbc1cf6d42189ab94af04..89607a520cf4bc87247811903bead973ddff8888 100644 (file)
@@ -62,6 +62,7 @@ _PUBLIC_ struct mapistore_context *mapistore_init(TALLOC_CTX *mem_ctx, const cha
 
        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));
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e9b1f83ef1d937afcf6b5e376071a03bb203e23f 100644 (file)
@@ -0,0 +1,158 @@
+/*
+   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 = &notification->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 = &notification->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;
+}
index 5f481060b9b7ba73a567132946db0060601816c4..100d6b60f6e7f70c0da0e1c9ab70567deaca532c 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include "mapiproxy/dcesrv_mapiproxy.h"
+#include "mapiproxy/libmapiserver/libmapiserver.h"
 #include "dcesrv_exchange_emsmdb.h"
 
 struct exchange_emsmdb_session         *emsmdb_session = NULL;
@@ -250,6 +251,442 @@ static enum MAPISTATUS dcesrv_EcDoDisconnect(struct dcesrv_call_state *dce_call,
        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,
@@ -257,6 +694,8 @@ static struct mapi_response *EcDoRpc_process_transaction(TALLOC_CTX *mem_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;
@@ -275,7 +714,10 @@ static struct mapi_response *EcDoRpc_process_transaction(TALLOC_CTX *mem_ctx,
                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++) {
@@ -710,11 +1152,25 @@ static struct mapi_response *EcDoRpc_process_transaction(TALLOC_CTX *mem_ctx,
                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;
index e960b7de7fc629a24907577756b0af58cd840869..673efc46a6c83acddfb74f6a497a713e69eaf063 100644 (file)
@@ -52,10 +52,10 @@ struct emsmdbp_context {
        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;
@@ -70,7 +70,8 @@ enum emsmdbp_object_type {
        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 {
@@ -107,6 +108,7 @@ struct emsmdbp_object_table {
        uint32_t                        numerator;
        uint32_t                        denominator;
        bool                            mapistore;
+        struct mapistore_subscription_list   *subscription_list;
 };
 
 struct emsmdbp_object_stream {
@@ -128,6 +130,13 @@ struct emsmdbp_object_attachment {
        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;
@@ -135,6 +144,7 @@ union emsmdbp_objects {
        struct emsmdbp_object_table     *table;
        struct emsmdbp_object_stream    *stream;
        struct emsmdbp_object_attachment *attachment;
+       struct emsmdbp_object_subscription *subscription;
 };
 
 struct emsmdbp_object {
@@ -209,6 +219,7 @@ struct emsmdbp_object *emsmdbp_object_table_init(TALLOC_CTX *, struct emsmdbp_co
 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 *);
index 96807c132f2ef5f80fe06191e47948af2855de2f..7ed17224153b4f0ca86dc1705190b67b4a0905e8 100644 (file)
@@ -44,6 +44,8 @@ const char *emsmdbp_getstr_type(struct emsmdbp_object *object)
                return "table";
        case EMSMDBP_OBJECT_STREAM:
                return "stream";
+       case EMSMDBP_OBJECT_SUBSCRIPTION:
+               return "subscription";
        default:
                return "unknown";
        }
@@ -151,6 +153,8 @@ uint32_t emsmdbp_get_contextID(struct mapi_handles *handles)
                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;
        }
@@ -209,7 +213,7 @@ static int emsmdbp_commit_stream(struct mapistore_context *mstore_ctx, struct em
 
                                 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);
@@ -297,6 +301,10 @@ static int emsmdbp_object_destructor(void *data)
                                 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;
@@ -317,6 +325,14 @@ static int emsmdbp_object_destructor(void *data)
                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;
@@ -571,6 +587,7 @@ _PUBLIC_ struct emsmdbp_object *emsmdbp_object_table_init(TALLOC_CTX *mem_ctx,
        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) {
@@ -744,3 +761,53 @@ _PUBLIC_ struct emsmdbp_object *emsmdbp_object_attachment_init(TALLOC_CTX *mem_c
 
        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;
+}
index ecfc2dd73e83bacf2e26aa147e8f452118e989a4..03082d2d9be9e9106e7f0e68dbd3359410d296d0 100644 (file)
@@ -204,6 +204,9 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetHierarchyTable(TALLOC_CTX *mem_ctx,
        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;
@@ -280,6 +283,24 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetHierarchyTable(TALLOC_CTX *mem_ctx,
                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);
@@ -313,6 +334,9 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetContentsTable(TALLOC_CTX *mem_ctx,
        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;
@@ -389,7 +413,6 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetContentsTable(TALLOC_CTX *mem_ctx,
        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:
@@ -405,7 +428,30 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetContentsTable(TALLOC_CTX *mem_ctx,
 
                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);
 
index c92507b6db1b387623f93662b15aaf4878ae1025..c25a469e777d18c74d164c82f39f2009c7eef1ae 100644 (file)
@@ -54,8 +54,15 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopRegisterNotification(TALLOC_CTX *mem_ctx,
                                                         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"));
 
@@ -66,18 +73,52 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopRegisterNotification(TALLOC_CTX *mem_ctx,
        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();