[Messaging] Added DBus signal handling
authorJerzy Pabich <j.pabich@samsung.com>
Tue, 16 Dec 2014 09:24:19 +0000 (10:24 +0100)
committerJerzy Pabich <j.pabich@samsung.com>
Tue, 16 Dec 2014 12:24:12 +0000 (13:24 +0100)
Change-Id: I9241b4b3f11fd50b8d4bd0c4131da99f597529f7
Signed-off-by: Jerzy Pabich <j.pabich@samsung.com>
19 files changed:
src/messaging/DBus/Connection.cpp [new file with mode: 0644]
src/messaging/DBus/Connection.h [new file with mode: 0644]
src/messaging/DBus/EmailSignalProxy.cpp [new file with mode: 0644]
src/messaging/DBus/EmailSignalProxy.h [new file with mode: 0644]
src/messaging/DBus/LoadAttachmentProxy.cpp [new file with mode: 0644]
src/messaging/DBus/LoadAttachmentProxy.h [new file with mode: 0644]
src/messaging/DBus/LoadBodyProxy.cpp [new file with mode: 0644]
src/messaging/DBus/LoadBodyProxy.h [new file with mode: 0644]
src/messaging/DBus/MessageProxy.cpp [new file with mode: 0644]
src/messaging/DBus/MessageProxy.h [new file with mode: 0644]
src/messaging/DBus/Proxy.cpp [new file with mode: 0644]
src/messaging/DBus/Proxy.h [new file with mode: 0644]
src/messaging/DBus/SendProxy.cpp [new file with mode: 0644]
src/messaging/DBus/SendProxy.h [new file with mode: 0644]
src/messaging/DBus/SyncProxy.cpp [new file with mode: 0644]
src/messaging/DBus/SyncProxy.h [new file with mode: 0644]
src/messaging/email_manager.cc
src/messaging/email_manager.h
src/messaging/messaging.gyp

diff --git a/src/messaging/DBus/Connection.cpp b/src/messaging/DBus/Connection.cpp
new file mode 100644 (file)
index 0000000..e1a4934
--- /dev/null
@@ -0,0 +1,60 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "Connection.h"
+#include "common/logger.h"
+//#include <PlatformException.h>
+#include <cstring>
+#include <email-types.h>
+#include "../message_service.h"
+
+namespace extension {
+namespace messaging {
+namespace DBus {
+
+Connection& Connection::getInstance()
+{
+    LOGD("Entered");
+    static Connection instance;
+    return instance;
+}
+
+GDBusConnection* Connection::getDBus()
+{
+    return m_dbus;
+}
+
+Connection::Connection()
+{
+    dbus_g_thread_init();
+    g_type_init();
+
+    m_dbus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &m_error);
+    if (!m_dbus || m_error) {
+        LOGE("Could not get connection");
+    }
+    LOGD("Connection set");
+}
+
+Connection::~Connection()
+{
+    g_object_unref(m_dbus);
+}
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
diff --git a/src/messaging/DBus/Connection.h b/src/messaging/DBus/Connection.h
new file mode 100644 (file)
index 0000000..07084e3
--- /dev/null
@@ -0,0 +1,49 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef __TIZEN_DBUS_CONNECTION_H__
+#define __TIZEN_DBUS_CONNECTION_H__
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <gio/gio.h>
+
+namespace extension {
+namespace messaging {
+namespace DBus {
+
+class Connection {
+public:
+    static Connection& getInstance();
+
+    GDBusConnection* getDBus();
+
+private:
+    Connection();
+    Connection(const Connection&);
+    void operator=(const Connection&);
+    virtual ~Connection();
+
+    GDBusConnection* m_dbus;
+    GError* m_error;
+};
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
+
+#endif
diff --git a/src/messaging/DBus/EmailSignalProxy.cpp b/src/messaging/DBus/EmailSignalProxy.cpp
new file mode 100644 (file)
index 0000000..72149f1
--- /dev/null
@@ -0,0 +1,85 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file        EmailSignalProxy.cpp
+ */
+
+#include "EmailSignalProxy.h"
+#include "common/logger.h"
+#include <cstring>
+//#include <PlatformException.h>
+
+namespace extension {
+namespace messaging {
+namespace DBus {
+
+EmailSignalProxy::EmailSignalProxy(const std::string& proxy_path,
+        const std::string& proxy_iface) :
+        Proxy (proxy_path,
+                      proxy_iface,
+                      Proxy::DBUS_NAME_SIGNAL_EMAIL,   //specify email signal details
+                      DBUS_PATH_NETWORK_STATUS,
+                      DBUS_IFACE_NETWORK_STATUS)
+{
+}
+
+EmailSignalProxy::~EmailSignalProxy()
+{
+
+}
+
+void EmailSignalProxy::signalCallback(GDBusConnection* connection,
+        const gchar* sender_name,
+        const gchar* object_path,
+        const gchar* interface_name,
+        const gchar* signal_name,
+        GVariant* parameters)
+{
+    int status, mail_id, op_handle, error_code;
+    char* source = NULL;
+
+    try {
+        g_variant_get(parameters, "(iisii)",
+                &status,
+                &mail_id,
+                &source,
+                &op_handle,
+                &error_code);
+
+        //It is better to log this only when subclass is responsible of handling
+        //passed signal (usually determined by status value).
+        //
+        //LOGD("email:\n  status: %d\n  mail_id: %d\n  "
+        //        "source: %s\n  op_handle: %d\n  error_code: %d",
+        //        status, mail_id, source, op_handle, error_code);
+
+        handleEmailSignal(status, mail_id, source, op_handle, error_code);
+
+//    } catch(const Common::BasePlatformException& exception) {
+//        LOGE("Unhandled exception: %s (%s)!", (exception.getName()).c_str(),
+//             (exception.getMessage()).c_str());
+    } catch(...) {
+        LOGE("Unhandled exception!");
+    }
+
+    g_free(source);
+}
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
diff --git a/src/messaging/DBus/EmailSignalProxy.h b/src/messaging/DBus/EmailSignalProxy.h
new file mode 100644 (file)
index 0000000..7478981
--- /dev/null
@@ -0,0 +1,64 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file        EmailSignalProxy.h
+ */
+
+#ifndef __TIZEN_DBUS_EMAIL_SIGNAL_PROXY_H__
+#define __TIZEN_DBUS_EMAIL_SIGNAL_PROXY_H__
+
+#include "Proxy.h"
+
+namespace extension {
+namespace messaging {
+namespace DBus {
+
+class EmailSignalProxy;
+typedef std::shared_ptr<EmailSignalProxy> EmailSignalProxyPtr;
+
+class EmailSignalProxy : public Proxy {
+public:
+    EmailSignalProxy(const std::string& proxy_path,
+            const std::string& proxy_iface);
+    virtual ~EmailSignalProxy();
+
+protected:
+    /**
+     * Override this method in subclass to handle email signal
+     */
+    virtual void handleEmailSignal(const int status,
+            const int mail_id,
+            const std::string& source,
+            const int op_handle,
+            const int error_code) = 0;
+
+    virtual void signalCallback(GDBusConnection *connection,
+            const gchar *sender_name,
+            const gchar *object_path,
+            const gchar *interface_name,
+            const gchar *signal_name,
+            GVariant *parameters);
+
+private:
+};
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
+
+#endif // __TIZEN_DBUS_EMAIL_SIGNAL_PROXY_H__
diff --git a/src/messaging/DBus/LoadAttachmentProxy.cpp b/src/messaging/DBus/LoadAttachmentProxy.cpp
new file mode 100644 (file)
index 0000000..55eac0b
--- /dev/null
@@ -0,0 +1,231 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file        LoadAttachmentProxy.cpp
+ */
+
+#include "LoadAttachmentProxy.h"
+#include <Logger.h>
+#include <PlatformException.h>
+#include <cstring>
+#include <email-types.h>
+#include "MessageService.h"
+#include "Message.h"
+#include "MessageBody.h"
+#include "EmailManager.h"
+#include "JSMessageAttachment.h"
+#include <email-api.h>
+#include <JSWebAPIErrorFactory.h>
+
+namespace DeviceAPI {
+namespace Messaging {
+namespace DBus {
+
+/**
+  * This method perform very specified task (see warning comment) so it should not be
+  * visible outside LoadAttachmentProxy class.
+  */
+void updateAttachmentDataWithEmailGetAttachmentData(
+        std::shared_ptr<MessageAttachment> attachment)
+{
+    struct ScopedEmailAttachmentData {
+        ScopedEmailAttachmentData() : data(NULL) { }
+        ~ScopedEmailAttachmentData() {
+            if(data) {
+                email_free_attachment_data(&data, 1);
+            }
+        }
+        email_attachment_data_t* operator->() { return data; }
+        email_attachment_data_t* data;
+    } attachment_data_holder;
+
+    LOGD("attachmentId = %d", attachment->getId());
+
+    /*
+     * WARNING: email_get_attachment_data seems to be getting NOT COMPLETE
+     *          email_attachment_data_t object, observed that:
+     *              mail_id is 0
+     *              account_id is 0
+     *              mailbox_id is 0
+     *          Thus currently only attachment_path and attachment_mime_type is used!
+     *
+     *          To get COMPLETE data please use: Message::convertEmailToMessageAttachment
+     *          mtehod which fetches all attachments from specified email.
+     */
+    int err = email_get_attachment_data(attachment->getId(), &attachment_data_holder.data);
+    if (EMAIL_ERROR_NONE != err ||
+        NULL == attachment_data_holder.data) {
+        LOGE("Couldn't get attachment data for attachmentId:%d", attachment->getId());
+        throw Common::UnknownException("Couldn't get attachment.");
+    }
+
+    LOGD("attachment name : %s", attachment_data_holder->attachment_name);
+
+    if(attachment_data_holder->attachment_mime_type) {
+        attachment->setMimeType(attachment_data_holder->attachment_mime_type);
+    }
+
+    bool isSaved = false;
+    if (attachment_data_holder->attachment_path) {
+        LOGD("set attachment path: %s", attachment_data_holder->attachment_path);
+        attachment->setFilePath(attachment_data_holder->attachment_path);
+
+        LOGD("save_status: %d", attachment_data_holder->save_status);
+        LOGD("attachment_size : %d", attachment_data_holder->attachment_size);
+    }
+    isSaved = attachment_data_holder->save_status;
+    attachment->setIsSaved(isSaved);
+}
+
+LoadAttachmentProxy::LoadAttachmentProxy(const std::string& path,
+        const std::string& iface) :
+        EmailSignalProxy(path, iface)
+{
+}
+
+LoadAttachmentProxy::~LoadAttachmentProxy()
+{
+}
+
+void LoadAttachmentProxy::addCallback(MessageAttachmentCallbackData* callbackOwned)
+{
+    if(callbackOwned->getMessageAttachment()) {
+        LOGD("Registered callback for attachment_id: %d mail_id:%d op_handle:%d nth:%d",
+            callbackOwned->getMessageAttachment()->getId(),
+            callbackOwned->getMessageAttachment()->getMessageId(),
+            callbackOwned->getOperationHandle(),
+            callbackOwned->getNth());
+    }
+
+    m_callback_set.insert(callbackOwned);
+}
+
+void LoadAttachmentProxy::removeCallback(MessageAttachmentCallbackData* callback)
+{
+    if(callback->getMessageAttachment()) {
+        LOGD("Removed callback for attachment_id: %d mail_id:%d op_handle:%d nth:%d",
+            callback->getMessageAttachment()->getId(),
+            callback->getMessageAttachment()->getMessageId(),
+            callback->getOperationHandle(),
+            callback->getNth());
+    }
+
+    m_callback_set.erase(callback);
+}
+
+MessageAttachmentCallbackData* LoadAttachmentProxy::findCallback(const int nth,
+        const int mail_id)
+{
+    CallbackSet::iterator it = m_callback_set.begin();
+    for (; it != m_callback_set.end(); ++it) {
+        MessageAttachmentCallbackData* callback = *it;
+        if (nth == callback->getNth() &&
+            mail_id == callback->getMessageAttachment()->getMessageId()) {
+            return callback;
+        }
+    }
+
+    LOGW("Could not find callback with nth: %d and mail_id: %d", nth, mail_id);
+    return NULL;
+}
+
+void LoadAttachmentProxy::handleEmailSignal(const int status,
+            const int mail_id,
+            const std::string& source,
+            const int op_handle,
+            const int error_code)
+{
+    if(NOTI_DOWNLOAD_ATTACH_FINISH != status &&
+            NOTI_DOWNLOAD_ATTACH_FAIL != status) {
+        return;
+    }
+
+    LOGD("received email signal with:\n  status: %d\n  mail_id: %d\n  "
+            "source: %s\n  op_handle(nth): %d\n  error_code: %d",
+            status, mail_id, source.c_str(), op_handle, error_code);
+
+    MessageAttachmentCallbackData* callback = NULL;
+
+    //It seems that D-Bus signal op_handle is equal to nth in:
+    // int email_download_attachment(int mail_id, int nth, int *handle)
+    // and not handle returned from above call!!
+    const int nth = op_handle;
+
+    try {
+        // From old implementation it looks that op_handle(nth) is is equal to
+        // index (1 based) of attachment inside email thus it is not globally unique!
+        // Therfore we need to test if mail_id match.
+        // For details see old implementation MailSync.cp line 461
+
+        callback = findCallback(nth, mail_id);
+        if(!callback) {
+            //We should not log not found pair since it could be requested by
+            //different application.
+            return;
+        }
+
+        LOGD("Found callback for pair mailId:%d nth:%d", mail_id, nth);
+
+        if(NOTI_DOWNLOAD_ATTACH_FINISH == status) {
+            LOGD("Message attachment downloaded!");
+
+            std::shared_ptr<MessageAttachment> att = callback->getMessageAttachment();
+            updateAttachmentDataWithEmailGetAttachmentData(att);
+            LOGD("Updated Message attachment object");
+
+            try {
+                JSContextRef context = callback->getContext();
+                JSObjectRef jsMessageAtt = JSMessageAttachment::makeJSObject(context, att);
+                callback->callSuccessCallback(jsMessageAtt);
+            } catch (...) {
+                LOGW("Couldn't create JSMessageAttachment object!");
+                throw Common::UnknownException(
+                        "Couldn't create JSMessageAttachment object!");
+            }
+
+        } else if(NOTI_DOWNLOAD_ATTACH_FAIL) {
+            LOGD("Load message attachment failed!");
+            JSObjectRef errobj = Common::JSWebAPIErrorFactory::makeErrorObject(
+                    callback->getContext(),
+                    callback->getErrorName(),
+                    callback->getErrorMessage());
+            callback->callErrorCallback(errobj);
+        }
+    } catch (const Common::BasePlatformException& e) {
+        LOGE("Exception in signal callback");
+        JSObjectRef errobj = Common::JSWebAPIErrorFactory::makeErrorObject(
+                callback->getContext(), e);
+        callback->callErrorCallback(errobj);
+    } catch (...) {
+        LOGE("Exception in signal callback");
+        JSObjectRef errobj = Common::JSWebAPIErrorFactory::makeErrorObject(
+                callback->getContext(),
+                Common::JSWebAPIErrorFactory::UNKNOWN_ERROR,
+                "Handling signal callback failed");
+        callback->callErrorCallback(errobj);
+    }
+
+    if(callback) {
+        removeCallback(callback);
+        delete callback;
+    }
+}
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
diff --git a/src/messaging/DBus/LoadAttachmentProxy.h b/src/messaging/DBus/LoadAttachmentProxy.h
new file mode 100644 (file)
index 0000000..06db27d
--- /dev/null
@@ -0,0 +1,69 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file        LoadAttachmentProxy.h
+ */
+
+#ifndef __TIZEN_DBUS_LOAD_ATTACHMENT_PROXY_H__
+#define __TIZEN_DBUS_LOAD_ATTACHMENT_PROXY_H__
+
+#include "EmailSignalProxy.h"
+#include <set>
+
+namespace DeviceAPI {
+namespace Messaging {
+
+class MessageAttachmentCallbackData;
+
+namespace DBus {
+
+class LoadAttachmentProxy;
+typedef std::shared_ptr<LoadAttachmentProxy> LoadAttachmentProxyPtr;
+
+class LoadAttachmentProxy : public EmailSignalProxy {
+public:
+
+    // Callback is owned by this set
+    typedef std::set<MessageAttachmentCallbackData*> CallbackSet;
+
+    LoadAttachmentProxy(const std::string& path,
+            const std::string& iface);
+    virtual ~LoadAttachmentProxy();
+
+    //Passed callback will be owned by this proxy
+    void addCallback(MessageAttachmentCallbackData* callbackOwned);
+    void removeCallback(MessageAttachmentCallbackData* callback);
+
+protected:
+    virtual void handleEmailSignal(const int status,
+            const int mail_id,
+            const std::string& source,
+            const int op_handle,
+            const int error_code);
+
+private:
+    MessageAttachmentCallbackData* findCallback(const int nth, const int mail_id);
+
+    CallbackSet m_callback_set;
+};
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
+
+#endif // __TIZEN_DBUS_LOAD_ATTACHMENT_PROXY_H__
diff --git a/src/messaging/DBus/LoadBodyProxy.cpp b/src/messaging/DBus/LoadBodyProxy.cpp
new file mode 100644 (file)
index 0000000..990d04f
--- /dev/null
@@ -0,0 +1,206 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file        LoadBodyProxy.cpp
+ */
+
+#include "LoadBodyProxy.h"
+#include <Logger.h>
+#include <PlatformException.h>
+#include <cstring>
+#include <email-types.h>
+#include "MessageService.h"
+#include "Message.h"
+#include "MessageBody.h"
+#include "EmailManager.h"
+#include "JSMessage.h"
+#include <JSWebAPIErrorFactory.h>
+
+namespace DeviceAPI {
+namespace Messaging {
+namespace DBus {
+
+LoadBodyProxy::LoadBodyProxy(const std::string& path,
+        const std::string& iface) :
+        EmailSignalProxy(path, iface)
+{
+
+}
+
+LoadBodyProxy::~LoadBodyProxy()
+{
+
+}
+
+void LoadBodyProxy::addCallback(MessageBodyCallbackData* callbackOwned)
+{
+    m_callback_set.insert(callbackOwned);
+}
+
+void LoadBodyProxy::removeCallback(MessageBodyCallbackData* callback)
+{
+    m_callback_set.erase(callback);
+}
+
+MessageBodyCallbackData* LoadBodyProxy::findCallbackByOpHandle(const int op_handle)
+{
+    CallbackSet::iterator it = m_callback_set.begin();
+    for (; it != m_callback_set.end(); ++it) {
+
+        MessageBodyCallbackData* callback = *it;
+        if (op_handle == callback->getOperationHandle()) {
+            return callback;
+        }
+    }
+
+    LOGW("Could not find callback with op_handle: %d", op_handle);
+    return NULL;
+}
+
+void LoadBodyProxy::handleEmailSignal(const int status,
+        const int mail_id,
+        const std::string& source,
+        const int op_handle,
+        const int error_code)
+{
+    switch(status) {
+        //We should handle this signal since it is DOWNLOAD_BODY_*
+        case NOTI_DOWNLOAD_BODY_START:
+        case NOTI_DOWNLOAD_BODY_FINISH:
+        case NOTI_DOWNLOAD_BODY_FAIL: {
+        } break;
+
+        // This values have not been explicitly handled in old implementation
+        //  NOTI_DOWNLOAD_BODY_CANCEL
+        //  NOTI_DOWNLOAD_MULTIPART_BODY
+        //
+        // 1. I assume that NOTI_DOWNLOAD_MULTIPART_BODY is called several times
+        // before final NOTI_DOWNLOAD_BODY_FINISH is called, thus we should not
+        // remove nor delete callback.
+        //
+        // 2. I assume that NOTI_DOWNLOAD_BODY_CANCEL is called before
+        // NOTI_DOWNLOAD_BODY_FAIL so we should do the same as in point 1.
+        case NOTI_DOWNLOAD_BODY_CANCEL:
+        case NOTI_DOWNLOAD_MULTIPART_BODY:
+        default: {
+            // This signal is not related with load message body or there is nothing
+            // to do so we can return now.
+            return;
+        } break;
+    }
+
+    LOGD("received email signal with:\n  status: %d\n  mail_id: %d\n  "
+        "source: %s\n  op_handle: %d\n  error_code: %d",
+        status, mail_id, source.c_str(), op_handle, error_code);
+
+    if(NOTI_DOWNLOAD_BODY_START == status) {
+        LOGD("Download message body started ...");
+        // There is nothing more to do so we can return now.
+        return;
+    }
+
+    MessageBodyCallbackData* callback = NULL;
+    try {
+        callback = findCallbackByOpHandle(op_handle);
+        if (!callback) {
+            LOGE("Callback is null");
+        } else {
+            if( (NOTI_DOWNLOAD_BODY_FINISH == status) ||
+                (NOTI_DOWNLOAD_BODY_FAIL == status &&
+                         EMAIL_ERROR_MAIL_IS_ALREADY_DOWNLOADED == error_code)) {
+
+                // Old implementation is not verifying whether message update failed,
+                // it just calls success callback.
+                if(callback->getMessage()) {
+                    email_mail_data_t* mail_data = EmailManager::loadMessage(
+                             callback->getMessage()->getId());
+                    if (mail_data) {
+                        callback->getMessage()->updateEmailMessage(*mail_data);
+                        EmailManager::freeMessage(mail_data);
+                        mail_data = NULL;
+                    }
+
+                    //TODO: this should be reviewed when attachments and
+                    //      loadAttachments have been completed.
+                    //TODO: see old implementation lines 608-635 in MailSync.cpp
+                    /*
+                    * This is original Messaging implementation:
+                    *
+                    * std::vector<IAttachmentPtr> attachments = mail->getAttachments();
+                    * std::vector<IAttachmentPtr> inlineAttachments = mail->getInlineAttachments();
+                    *
+                    * for (unsigned int idx = 0; idx < attachments.size() ; idx++ )
+                    * {
+                    *   LoggerD("set Attachment ID = " << attachments[idx]->getAttachmentID());
+                    *   attachments[idx]->setMessage(event->m_message);
+                    *
+                    * }
+                    * for (unsigned int idx = 0; idx < inlineAttachments.size() ; idx++ )
+                    * {
+                    *   LoggerD("set inline Attachment ID = " << inlineAttachments[idx]->getAttachmentID());
+                    *   inlineAttachments[idx]->setMessage(event->m_message);
+                    * }
+                    */
+                }
+
+                LOGD("Message body downloaded!");
+                try {
+                    JSContextRef context = callback->getContext();
+                    JSObjectRef jsMessage = JSMessage::makeJSObject(context,
+                             callback->getMessage());
+                    callback->callSuccessCallback(jsMessage);
+                } catch (...) {
+                    LOGW("Couldn't create JSMessage object!");
+                    throw Common::UnknownException(
+                            "Couldn't create JSMessage object!");
+                }
+
+            } else if(NOTI_DOWNLOAD_BODY_FAIL == status) {
+                LOGD("Load message body failed!");
+                JSObjectRef errobj = Common::JSWebAPIErrorFactory::makeErrorObject(
+                        callback->getContext(),
+                        callback->getErrorName(),
+                        callback->getErrorMessage());
+                callback->callErrorCallback(errobj);
+            }
+        }
+    }
+    catch (const Common::BasePlatformException& e) {
+        LOGE("Exception in signal callback");
+        JSObjectRef errobj = Common::JSWebAPIErrorFactory::makeErrorObject(
+                callback->getContext(), e);
+        callback->callErrorCallback(errobj);
+    }
+    catch (...) {
+        LOGE("Exception in signal callback");
+        JSObjectRef errobj = Common::JSWebAPIErrorFactory::makeErrorObject(
+                callback->getContext(),
+                Common::JSWebAPIErrorFactory::UNKNOWN_ERROR,
+                "Handling signal callback failed");
+        callback->callErrorCallback(errobj);
+    }
+
+    if(callback) {
+        removeCallback(callback);
+        delete callback;
+    }
+}
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
diff --git a/src/messaging/DBus/LoadBodyProxy.h b/src/messaging/DBus/LoadBodyProxy.h
new file mode 100644 (file)
index 0000000..2fffa37
--- /dev/null
@@ -0,0 +1,73 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file        LoadBodyProxy.h
+ */
+
+#ifndef __TIZEN_DBUS_LOAD_BODY_PROXY_H__
+#define __TIZEN_DBUS_LOAD_BODY_PROXY_H__
+
+#include "EmailSignalProxy.h"
+#include <set>
+
+namespace DeviceAPI {
+namespace Messaging {
+
+class MessageBodyCallbackData;
+
+namespace DBus {
+
+class LoadBodyProxy;
+typedef std::shared_ptr<LoadBodyProxy> LoadBodyProxyPtr;
+
+class LoadBodyProxy : public EmailSignalProxy {
+public:
+
+    // Callback is owned by this set
+    typedef std::set<MessageBodyCallbackData*> CallbackSet;
+
+    LoadBodyProxy(const std::string& path,
+            const std::string& iface);
+    virtual ~LoadBodyProxy();
+
+    //Passed callback will be owned by this proxy
+    void addCallback(MessageBodyCallbackData* callbackOwned);
+    void removeCallback(MessageBodyCallbackData* callback);
+
+protected:
+    virtual void handleEmailSignal(const int status,
+            const int mail_id,
+            const std::string& source,
+            const int op_handle,
+            const int error_code);
+
+private:
+    /**
+     * Find callback by operation handle returned from:
+     *  int email_download_body(..., int *handle);
+     */
+    MessageBodyCallbackData* findCallbackByOpHandle(const int op_handle);
+
+    CallbackSet m_callback_set;
+};
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
+
+#endif // __TIZEN_DBUS_LOAD_BODY_PROXY_H__
diff --git a/src/messaging/DBus/MessageProxy.cpp b/src/messaging/DBus/MessageProxy.cpp
new file mode 100644 (file)
index 0000000..32d4782
--- /dev/null
@@ -0,0 +1,290 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "MessageProxy.h"
+#include "Connection.h"
+#include <Logger.h>
+#include <Message.h>
+#include <MessageEmail.h>
+#include <MessageConversation.h>
+#include <MessageFolder.h>
+#include <ChangeListenerContainer.h>
+#include <EmailManager.h>
+#include <PlatformException.h>
+
+namespace DeviceAPI {
+namespace Messaging {
+namespace DBus {
+
+MessageProxy::MessageProxy():
+        Proxy(Proxy::DBUS_PATH_EMAIL_STORAGE_CHANGE,
+                     Proxy::DBUS_IFACE_EMAIL_STORAGE_CHANGE,
+                     Proxy::DBUS_NAME_SIGNAL_EMAIL,
+                     Proxy::DBUS_PATH_EMAIL_STORAGE_CHANGE,
+                     Proxy::DBUS_IFACE_EMAIL_STORAGE_CHANGE)
+{
+}
+
+MessageProxy::~MessageProxy()
+{
+}
+
+void MessageProxy::signalCallback(GDBusConnection *connection,
+            const gchar *sender_name,
+            const gchar *object_path,
+            const gchar *interface_name,
+            const gchar *signal_name,
+            GVariant *parameters)
+{
+    LOGD("Enter");
+    int status, account_id, object_id, thread_id;
+    char* name;
+    g_variant_get(parameters, "(iiisi)",
+            &status,
+            &account_id,
+            &object_id,
+            &name,
+            &thread_id);
+    LOGD("status: %d", status);
+    LOGD("account_id: %d", account_id);
+    LOGD("object_id: %d", object_id);
+    LOGD("name: %s", name);
+    LOGD("thread_id: %d", thread_id);
+
+    try {
+        switch (status) {
+            case NOTI_MAIL_ADD:
+            case NOTI_MAIL_UPDATE:
+                handleEmailEvent(account_id, object_id, thread_id, status);
+                break;
+            case NOTI_MAIL_DELETE:
+                //ids of removing messages are sent with name in format:
+                //id1,id2,id3,
+                handleEmailRemoveEvent(account_id, name);
+                break;
+            case NOTI_MAIL_DELETE_FINISH:
+            case NOTI_MAIL_DELETE_FAIL:
+                //notify EmailManager, maybe it tries to delete mail
+                notifyEmailManager(name, static_cast<email_noti_on_storage_event>(status));
+                break;
+            case NOTI_THREAD_DELETE:
+                handleThreadRemoveEvent(account_id, object_id);
+                break;
+            case NOTI_MAILBOX_ADD:
+            case NOTI_MAILBOX_UPDATE:
+            case NOTI_MAILBOX_FIELD_UPDATE:
+            case NOTI_MAILBOX_RENAME:
+            case NOTI_MAILBOX_DELETE:
+                handleMailboxEvent(account_id, object_id, status);
+                break;
+            default:
+                LOGD("Unrecognized status: %d", status);
+        }
+    } catch (const Common::BasePlatformException& err) {
+        LOGE("%s (%s)", (err.getName()).c_str(), (err.getMessage()).c_str());
+    } catch (...) {
+        LOGE("Failed to call callback");
+    }
+    g_free(name);
+}
+
+void MessageProxy::handleEmailEvent(int account_id, int mail_id, int thread_id, int event)
+{
+    LOGD("Enter");
+
+    if(NOTI_MAIL_UPDATE == event) {
+        //getting thread_id from message
+        email_mail_data_t *mail_data = NULL;
+
+        if(EMAIL_ERROR_NONE != email_get_mail_data(mail_id, &mail_data)) {
+            if (mail_data) email_free_mail_data(&mail_data, 1);
+
+            LOGE("Failed to get mail data during setting conversation id in MessageProxy.");
+            return;
+        }
+
+        thread_id = mail_data->thread_id;
+
+        if(EMAIL_ERROR_NONE != email_free_mail_data(&mail_data,1)) {
+            LOGE("Failed to free mail data memory");
+        }
+    }
+
+    email_mail_data_t* mail_data = EmailManager::getInstance().loadMessage(mail_id);
+    if (mail_data == NULL) {
+        throw Common::UnknownException("Failed to load email");
+    }
+    std::shared_ptr<Message> msg = Message::convertPlatformEmailToObject(*mail_data);
+    ConversationPtr conv = MessageConversation::convertEmailConversationToObject(
+            thread_id);
+
+    EventMessages* eventMsg = new EventMessages();
+    eventMsg->service_type = MessageType::EMAIL;
+    eventMsg->service_id = account_id;
+    eventMsg->items.push_back(msg);
+    EventConversations* eventConv = new EventConversations();
+    eventConv->service_type = MessageType::EMAIL;
+    eventConv->service_id = account_id;
+    eventConv->items.push_back(conv);
+    switch (event) {
+        case NOTI_MAIL_ADD:
+            ChangeListenerContainer::getInstance().callMessageAdded(eventMsg);
+            if (conv->getMessageCount() == 1) {
+                LOGD("This thread is new, triggering conversationAdded");
+                ChangeListenerContainer::getInstance().callConversationAdded(eventConv);
+            } else {
+                LOGD("This thread is not new, but it's updated");
+                ChangeListenerContainer::getInstance().callConversationUpdated(eventConv);
+            }
+            break;
+        case NOTI_MAIL_UPDATE:
+            ChangeListenerContainer::getInstance().callMessageUpdated(eventMsg);
+            ChangeListenerContainer::getInstance().callConversationUpdated(eventConv);
+            break;
+        default:
+            LOGW("Unknown event type: %d", event);
+            break;
+
+    }
+    delete eventMsg;
+    delete eventConv;
+
+    EmailManager::getInstance().freeMessage(mail_data);
+}
+
+std::vector<int> getMailIds(const std::string& idsString)
+{
+    std::stringstream idsStream(idsString);
+    std::string item;
+    std::vector<int> ids;
+    while (std::getline(idsStream, item, ',')) {
+        if (item.length() > 0) {
+            int id;
+            std::stringstream stream(item);
+            stream >> id;
+            if (stream) {
+                LOGD("Mail delete id: %d", id);
+                ids.push_back(id);
+            }
+        }
+    }
+    return ids;
+}
+
+void MessageProxy::handleEmailRemoveEvent(int account_id, const std::string& idsString)
+{
+    LOGD("Enter");
+    std::vector<int> ids = getMailIds(idsString);
+    if (ids.empty()) {
+        LOGD("Mail id list is empty.");
+        return;
+    }
+    EventMessages* eventMsg = new EventMessages();
+    eventMsg->service_type = MessageType::EMAIL;
+    eventMsg->service_id = account_id;
+    for (auto it = ids.begin(); it != ids.end(); ++it) {
+        //it turns out that this event is triggered after messages are removed
+        //so we just create empty messages with id and type
+        std::shared_ptr<Message> msg = std::make_shared<MessageEmail>();
+        msg->setId(*it);
+        eventMsg->items.push_back(msg);
+    }
+    ChangeListenerContainer::getInstance().callMessageRemoved(eventMsg);
+    delete eventMsg;
+    eventMsg = NULL;
+}
+
+void MessageProxy::notifyEmailManager(const std::string& idsString,
+        email_noti_on_storage_event status)
+{
+    LOGD("Enter");
+    std::vector<int> ids = getMailIds(idsString);
+    if (ids.empty()) {
+        LOGD("Mail id list is empty.");
+        return;
+    }
+    EmailManager::getInstance().removeStatusCallback(ids, status);
+}
+
+void MessageProxy::handleThreadRemoveEvent(int account_id, int thread_id)
+{
+    LOGD("Enter");
+    //event is called after thread is removed, so we just set thread id
+    ConversationPtr conv = std::make_shared<MessageConversation>();
+    conv->setConversationId(thread_id);
+
+    EventConversations* eventConv = new EventConversations();
+    eventConv->service_type = MessageType::EMAIL;
+    eventConv->service_id = account_id;
+    eventConv->items.push_back(conv);
+    ChangeListenerContainer::getInstance().callConversationRemoved(eventConv);
+    delete eventConv;
+    eventConv = NULL;
+}
+
+void MessageProxy::handleMailboxEvent(int account_id, int mailbox_id, int event)
+{
+    LOGD("Enter");
+
+    EventFolders* eventFolder = new EventFolders();
+    eventFolder->service_type = MessageType::EMAIL;
+    eventFolder->service_id = account_id;
+    FolderPtr folder;
+    if (event == NOTI_MAILBOX_DELETE) {
+        //this event is triggered after mailbox is removed
+        //so we just create folder with id
+        folder.reset(new MessageFolder(std::to_string(mailbox_id),
+                "", //parent_id
+                "", //service_id
+                "", //content_type
+                "", //name
+                "", //path
+                MessageFolderType::MESSAGE_FOLDER_TYPE_NOTSTANDARD,
+                false));
+    } else {
+        email_mailbox_t* mail_box = NULL;
+        if (EMAIL_ERROR_NONE != email_get_mailbox_by_mailbox_id(mailbox_id, &mail_box)) {
+            LOGE("Mailbox not retrieved");
+            delete eventFolder;
+            throw Common::UnknownException("Failed to load mailbox");
+        }
+        folder.reset(new MessageFolder(*mail_box));
+        if (EMAIL_ERROR_NONE != email_free_mailbox(&mail_box, 1)) {
+            LOGD("Failed to free email_free_mailbox");
+        }
+    }
+    eventFolder->items.push_back(folder);
+    switch (event) {
+        case NOTI_MAILBOX_ADD:
+            ChangeListenerContainer::getInstance().callFolderAdded(eventFolder);
+            break;
+        case NOTI_MAILBOX_UPDATE:
+        case NOTI_MAILBOX_FIELD_UPDATE:
+            ChangeListenerContainer::getInstance().callFolderUpdated(eventFolder);
+            break;
+        case NOTI_MAILBOX_DELETE:
+            ChangeListenerContainer::getInstance().callFolderRemoved(eventFolder);
+            break;
+        default:
+            LOGW("Unknown event type: %d", event);
+    }
+    delete eventFolder;
+}
+
+} //DBus
+} //Messaging
+} //DeviceAPI
diff --git a/src/messaging/DBus/MessageProxy.h b/src/messaging/DBus/MessageProxy.h
new file mode 100644 (file)
index 0000000..7b6d456
--- /dev/null
@@ -0,0 +1,65 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef __TIZEN_MESSAGE_PROXY_H
+#define __TIZEN_MESSAGE_PROXY_H
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <gio/gio.h>
+#include <memory>
+#include <string>
+#include <email-types.h>
+#include "Proxy.h"
+
+namespace DeviceAPI {
+namespace Messaging {
+namespace DBus {
+
+class MessageProxy: public Proxy {
+public:
+    MessageProxy();
+    virtual ~MessageProxy();
+protected:
+    virtual void signalCallback(GDBusConnection *connection,
+            const gchar *sender_name,
+            const gchar *object_path,
+            const gchar *interface_name,
+            const gchar *signal_name,
+            GVariant *parameters);
+    /**
+     * Handles e-mail add and update only.
+     * @param account_id
+     * @param mail_id
+     * @param thread_id
+     * @param event
+     */
+    void handleEmailEvent(int account_id, int mail_id, int thread_id, int event);
+    void handleEmailRemoveEvent(int account_id, const std::string& idsString);
+    void notifyEmailManager(const std::string& idsString, email_noti_on_storage_event status);
+    void handleThreadRemoveEvent(int account_id, int thread_id);
+    void handleMailboxEvent(int account_id, int mailbox_id, int event);
+};
+
+typedef std::shared_ptr<MessageProxy> MessageProxyPtr;
+
+} //DBus
+} //Messaging
+} //DeviceAPI
+
+#endif /* __TIZEN_MESSAGE_PROXY_H */
+
diff --git a/src/messaging/DBus/Proxy.cpp b/src/messaging/DBus/Proxy.cpp
new file mode 100644 (file)
index 0000000..a6692a0
--- /dev/null
@@ -0,0 +1,163 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file        Proxy.cpp
+ */
+
+#include "Proxy.h"
+#include "common/logger.h"
+//#include <PlatformException.h>
+#include <cstring>
+#include <email-types.h>
+#include "../message_service.h"
+
+namespace extension {
+namespace messaging {
+namespace DBus {
+
+const char* Proxy::DBUS_PATH_NETWORK_STATUS = "/User/Email/NetworkStatus";
+const char* Proxy::DBUS_IFACE_NETWORK_STATUS = "User.Email.NetworkStatus";
+const char* Proxy::DBUS_PATH_EMAIL_STORAGE_CHANGE = "/User/Email/StorageChange";
+const char* Proxy::DBUS_IFACE_EMAIL_STORAGE_CHANGE = "User.Email.StorageChange";
+const char* Proxy::DBUS_NAME_SIGNAL_EMAIL = "email";
+
+Proxy::Proxy(const std::string& proxy_path,
+            const std::string& proxy_iface,
+            const std::string& signal_name,
+            const std::string& signal_path,
+            const std::string& signal_iface) :
+                m_conn(Connection::getInstance()),
+                m_sub_id(0),
+                m_path(proxy_path),
+                m_iface(proxy_iface),
+                m_signal_name(signal_name),
+                m_signal_path(signal_path),
+                m_signal_iface(signal_iface),
+                m_error(NULL),
+                m_dbus_signal_subscribed(false)
+{
+    LOGD("Proxy:\n"
+            "  proxy_path: %s\n  proxy_iface: %s"
+            "  signal_name: %s\n signal_path:%s\n signal_iface:%s",
+            m_path.c_str(), m_iface.c_str(),
+            m_signal_name.c_str(), m_signal_path.c_str(), m_signal_iface.c_str());
+
+    const gchar* unique_name = g_dbus_connection_get_unique_name(m_conn.getDBus());
+    LOGD("Generated unique name: %d", unique_name);
+
+    // path and interface are not obligatory to receive, but
+    // they should be set to send the signals.
+    m_proxy = g_dbus_proxy_new_sync(m_conn.getDBus(),
+            G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+            NULL, unique_name, m_path.c_str(), m_iface.c_str(), NULL, &m_error);
+    if (!m_proxy || m_error) {
+        LOGE("Could not get proxy");
+        //TODO throw Common::UnknownException("Could not get proxy");
+    }
+}
+
+Proxy::~Proxy()
+{
+    signalUnsubscribe();
+}
+
+void Proxy::signalCallbackProxy(GDBusConnection *connection,
+        const gchar *sender_name,
+        const gchar *object_path,
+        const gchar *interface_name,
+        const gchar *signal_name,
+        GVariant *parameters,
+        gpointer user_data)
+{
+    Proxy* this_ptr = static_cast<Proxy*>(user_data);
+    if (!this_ptr) {
+        LOGW("Proxy is null, nothing to do");
+        return;
+    }
+
+    try {
+        //It is better to log this only when subclass is responsible of handling
+        //passed signal. If you need it put it into your signalCallback(...) method
+        //LOGD("signal: %s from: %s path: %s interface: %s",
+        //        signal_name, sender_name, object_path, interface_name);
+
+        this_ptr->signalCallback(connection, sender_name, object_path, interface_name,
+                signal_name, parameters);
+
+//    } catch(const Common::BasePlatformException& exception) {
+//        LOGE("Unhandled exception: %s (%s)!", (exception.getName()).c_str(),
+//             (exception.getMessage()).c_str());
+    } catch(...) {
+        LOGE("Unhandled exception!");
+    }
+}
+
+void Proxy::signalSubscribe()
+{
+    if(m_dbus_signal_subscribed) {
+        LOGW("Proxy has already subscribed for listening DBus signal");
+        return;
+    }
+
+    const char* sender = NULL;
+    m_sub_id = g_dbus_connection_signal_subscribe(m_conn.getDBus(),
+            sender,
+            m_signal_iface.c_str(),
+            m_signal_name.c_str(),
+            m_signal_path.c_str(),
+            NULL,
+            G_DBUS_SIGNAL_FLAGS_NONE,
+            signalCallbackProxy,
+            static_cast<gpointer>(this),
+            NULL);
+    LOGD("g_dbus_connection_signal_subscribe returned id: %d", m_sub_id);
+
+    m_dbus_signal_subscribed = true;
+}
+
+void Proxy::signalUnsubscribe()
+{
+    if (!m_dbus_signal_subscribed) {
+        LOGW("Proxy hasn't subscribed for listening DBus signal");
+        return;
+    }
+
+    g_dbus_connection_signal_unsubscribe(m_conn.getDBus(), m_sub_id);
+    LOGD("g_dbus_connection_signal_unsubscribe finished");
+
+    m_dbus_signal_subscribed = false;
+}
+
+const std::string& Proxy::getSignalName() const
+{
+    return m_signal_name;
+}
+
+const std::string& Proxy::getSignalPath() const
+{
+    return m_signal_path;
+}
+
+const std::string& Proxy::getSignalInterfaceName() const
+{
+    return m_signal_iface;
+}
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
diff --git a/src/messaging/DBus/Proxy.h b/src/messaging/DBus/Proxy.h
new file mode 100644 (file)
index 0000000..75bab09
--- /dev/null
@@ -0,0 +1,125 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file        Proxy.h
+ */
+
+#ifndef __TIZEN_DBUS_PROXY_H__
+#define __TIZEN_DBUS_PROXY_H__
+
+#include "Connection.h"
+#include <memory>
+#include <string>
+#include <mutex>
+#include <map>
+#include "common/callback_user_data.h"
+
+namespace extension {
+namespace messaging {
+namespace DBus {
+
+
+class Proxy;
+typedef std::shared_ptr<Proxy> ProxyPtr;
+
+/**
+ * This is generic dbus signal listener proxy.
+ */
+class Proxy {
+public:
+    /**
+     * List of Tizen path and interface names:
+     */
+    static const char* DBUS_PATH_NETWORK_STATUS;
+    static const char* DBUS_IFACE_NETWORK_STATUS;
+    static const char* DBUS_PATH_EMAIL_STORAGE_CHANGE;
+    static const char* DBUS_IFACE_EMAIL_STORAGE_CHANGE;
+    /**
+     * Name of email signal
+     */
+    static const char* DBUS_NAME_SIGNAL_EMAIL;
+
+    /**
+     * @param proxy_path - path of this proxy
+     * @param proxy_iface - interface name of this proxy
+     *
+     * @param signal_name - expected signal name
+     * @param signal_path - expected signal path
+     * @param signal_iface - expected signal interface name
+     */
+    Proxy(const std::string& proxy_path,
+            const std::string& proxy_iface,
+            const std::string& signal_name,
+            const std::string& signal_path,
+            const std::string& signal_iface);
+
+    virtual ~Proxy();
+
+    void signalSubscribe();
+    void signalUnsubscribe();
+
+    const std::string& getSignalName() const;
+    const std::string& getSignalPath() const;
+    const std::string& getSignalInterfaceName() const;
+
+protected:
+    /**
+     * Please implement this method in subclass to handle signal.
+     * Executed by static void signalCallbackProxy(...).
+     */
+    virtual void signalCallback(GDBusConnection *connection,
+            const gchar *sender_name,
+            const gchar *object_path,
+            const gchar *interface_name,
+            const gchar *signal_name,
+            GVariant *parameters) = 0;
+
+private:
+    /**
+     * This method (registered with g_dbus_connection_signal_subscribe) is executed by
+     * DBus when signal is received. It calls
+     * (static_cast<Proxy*>(user_data))->signalCallback(...)
+     */
+    static void signalCallbackProxy(GDBusConnection *connection,
+            const gchar *sender_name,
+            const gchar *object_path,
+            const gchar *interface_name,
+            const gchar *signal_name,
+            GVariant *parameters,
+            gpointer user_data);
+
+    Connection& m_conn;
+    guint m_sub_id;
+
+    std::string m_path;
+    std::string m_iface;
+
+    std::string m_signal_name;
+    std::string m_signal_path;
+    std::string m_signal_iface;
+
+    GError* m_error;
+    GDBusProxy* m_proxy;
+    bool m_dbus_signal_subscribed;
+};
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
+
+#endif // __TIZEN_DBUS_PROXY_H__
diff --git a/src/messaging/DBus/SendProxy.cpp b/src/messaging/DBus/SendProxy.cpp
new file mode 100644 (file)
index 0000000..1e5a836
--- /dev/null
@@ -0,0 +1,64 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "SendProxy.h"
+
+#include <Logger.h>
+#include <email-types.h>
+#include <EmailManager.h>
+
+namespace DeviceAPI {
+namespace Messaging {
+namespace DBus {
+
+SendProxy::SendProxy():
+        EmailSignalProxy(Proxy::DBUS_PATH_NETWORK_STATUS,
+                     Proxy::DBUS_IFACE_NETWORK_STATUS)
+{
+}
+
+SendProxy::~SendProxy()
+{
+}
+
+void SendProxy::handleEmailSignal(const int status,
+            const int account_id,
+            const std::string& source,
+            const int mail_id,
+            const int error_code)
+{
+    LOGD("Enter");
+    switch (status) {
+        case NOTI_SEND_FINISH:
+        case NOTI_SEND_FAIL:
+            LOGD("Recognized status for email send");
+            LOGD("received email signal with:\n  status: %d\n  account_id: %d\n  "
+                "source: %s\n  mail_id: %d\n  error_code: %d",
+                status, account_id, source.c_str(), mail_id, error_code);
+            EmailManager::getInstance().sendStatusCallback(mail_id,
+                    static_cast<email_noti_on_network_event>(status),
+                    error_code);
+            break;
+        default:
+            LOGD("Unrecognized status %d, ignoring", status);
+    }
+}
+
+
+} //DBus
+} //Messaging
+} //DeviceAPI
\ No newline at end of file
diff --git a/src/messaging/DBus/SendProxy.h b/src/messaging/DBus/SendProxy.h
new file mode 100644 (file)
index 0000000..1493c8e
--- /dev/null
@@ -0,0 +1,47 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef __TIZEN_SEND_PROXY_H
+#define __TIZEN_SEND_PROXY_H
+
+#include "EmailSignalProxy.h"
+
+namespace DeviceAPI {
+namespace Messaging {
+namespace DBus {
+
+class SendProxy: public EmailSignalProxy {
+public:
+    SendProxy();
+    virtual ~SendProxy();
+protected:
+    virtual void handleEmailSignal(const int status,
+            const int account_id,
+            const std::string& source,
+            const int op_handle,
+            const int error_code);
+
+};
+
+typedef std::shared_ptr<SendProxy> SendProxyPtr;
+
+} //DBus
+} //Messaging
+} //DeviceAPI
+
+#endif /* __TIZEN_SEND_PROXY_H */
+
diff --git a/src/messaging/DBus/SyncProxy.cpp b/src/messaging/DBus/SyncProxy.cpp
new file mode 100644 (file)
index 0000000..5c7f5fe
--- /dev/null
@@ -0,0 +1,166 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file        SyncProxy.cpp
+ */
+
+#include "SyncProxy.h"
+#include "common/logger.h"
+//#include <PlatformException.h>
+#include <cstring>
+#include <email-types.h>
+#include "../message_service.h"
+
+namespace extension {
+namespace messaging {
+namespace DBus {
+
+SyncProxy::SyncProxy(const std::string& path,
+        const std::string& iface) :
+        EmailSignalProxy(path, iface)
+{
+
+}
+
+SyncProxy::~SyncProxy()
+{
+
+}
+
+void SyncProxy::addCallback(long op_id, common::CallbackUserData* callbackOwned)
+{
+    m_callback_map.insert(std::make_pair(op_id, callbackOwned));
+}
+
+common::CallbackUserData* SyncProxy::getCallback(long op_id)
+{
+    common::CallbackUserData* cb = NULL;
+    CallbackMap::iterator it = m_callback_map.find(op_id);
+    if (it != m_callback_map.end()) {
+        cb = it->second;
+        return cb;
+    }
+    LOGE("Could not find callback");
+    //TODO throw Common::UnknownException("Could not find callback");
+    return cb;
+}
+
+void SyncProxy::removeCallback(long op_id){
+    CallbackMap::iterator it = m_callback_map.find(op_id);
+    if (it != m_callback_map.end()) {
+        common::CallbackUserData* cb = it->second;
+        delete cb;
+        cb = NULL;
+        m_callback_map.erase(it);
+    }
+    else {
+        LOGE("Could not find callback");
+        //TODO throw Common::UnknownException("Could not find callback");
+    }
+}
+
+void SyncProxy::handleEmailSignal(const int status,
+            const int mail_id,
+            const std::string& source,
+            const int op_handle,
+            const int error_code)
+{
+    if( NOTI_DOWNLOAD_START != status &&
+            NOTI_DOWNLOAD_FINISH != status &&
+            NOTI_DOWNLOAD_FAIL != status ) {
+        // Nothing to do: this status is not related to sync nor syncFolder request
+        return;
+    }
+
+    LOGD("received email signal with:\n  status: %d\n  mail_id: %d\n  "
+            "source: %s\n  op_handle: %d\n  error_code: %d",
+            status, mail_id, source.c_str(), op_handle, error_code);
+
+    if (NOTI_DOWNLOAD_START == status) {
+        LOGD("Sync started...");
+        // There is nothing more to do so we can return now.
+        return;
+    }
+
+    common::CallbackUserData* callback = NULL;
+    CallbackMap::iterator callback_it;
+
+    try {
+        callback_it =  findSyncCallbackByOpHandle(op_handle);
+        callback = callback_it->second;
+        if (!callback) {
+            LOGE("Callback is null");
+            //TODO throw Common::UnknownException("Callback is null");
+        }
+
+        switch (status) {
+            case NOTI_DOWNLOAD_FINISH:
+                LoggerD("Sync finished!");
+                //TODO callback->callSuccessCallback();
+                break;
+
+            case NOTI_DOWNLOAD_FAIL:
+                LoggerD("Sync failed!");
+                //TODO callback->callErrorCallback();
+                break;
+
+            default:
+                break;
+        }
+    }
+//    catch (const Common::BasePlatformException& e) {
+//        // this situation may occur when there is no callback in the
+//        // map with specified opId (for example stopSync() has
+//        // removed it), but sync() was already started - only
+//        // warning here:
+//        LOGE("Exception in signal callback");
+//    }
+    catch(...)
+    {
+        LOGE("Exception in signal callback");
+    }
+
+    if(callback) {
+        delete callback;
+        m_callback_map.erase(callback_it);
+    }
+}
+
+SyncProxy::CallbackMap::iterator SyncProxy::findSyncCallbackByOpHandle(
+        const int op_handle)
+{
+    CallbackMap::iterator it = m_callback_map.begin();
+    for (; it != m_callback_map.end(); ++it) {
+        SyncCallbackData* cb = dynamic_cast<SyncCallbackData*>(it->second);
+        if (!cb) continue;
+
+        if (op_handle == cb->getOperationHandle()) {
+            return it;
+        }
+    }
+    // this situation may occur when there is no callback in the
+    // map with specified opId (for example stopSync() has
+    // removed it), but sync() was already started - only
+    // warning here:
+    LOGW("Could not find callback with op_handle: %d", op_handle);
+    //TODO throw Common::UnknownException("Could not find callback");
+}
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
diff --git a/src/messaging/DBus/SyncProxy.h b/src/messaging/DBus/SyncProxy.h
new file mode 100644 (file)
index 0000000..eff6924
--- /dev/null
@@ -0,0 +1,70 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file        SyncProxy.h
+ */
+
+#ifndef __TIZEN_DBUS_SYNC_PROXY_H__
+#define __TIZEN_DBUS_SYNC_PROXY_H__
+
+#include "EmailSignalProxy.h"
+
+namespace extension {
+namespace messaging {
+namespace DBus {
+
+class SyncProxy;
+typedef std::shared_ptr<SyncProxy> SyncProxyPtr;
+
+class SyncProxy : public EmailSignalProxy {
+public:
+
+    // Callback is owned by this map
+    typedef std::map<long, common::CallbackUserData*> CallbackMap;
+
+    SyncProxy(const std::string& path,
+            const std::string& iface);
+    virtual ~SyncProxy();
+
+    //Passed callback will be owned by this proxy
+    void addCallback(long op_id, common::CallbackUserData* callbackOwned);
+    common::CallbackUserData* getCallback(long op_id);
+    void removeCallback(long op_id);
+
+protected:
+    virtual void handleEmailSignal(const int status,
+            const int mail_id,
+            const std::string& source,
+            const int op_handle,
+            const int error_code);
+
+private:
+    /**
+     * Find callback by operation handle returned from:
+     *  int email_sync_header(..., int *handle);
+     */
+    CallbackMap::iterator findSyncCallbackByOpHandle(const int op_handle);
+
+    CallbackMap m_callback_map;
+};
+
+} //namespace DBus
+} //namespace Messaging
+} //namespace DeviceAPI
+
+#endif // __TIZEN_DBUS_SYNC_PROXY_H__
index 8afa325cfec4a7ff37ec828d53c84127957f7b3e..148a13cff109ac92d5f82d163a10007d04b14af0 100644 (file)
@@ -74,7 +74,7 @@ const std::string FIND_FOLDERS_ATTRIBUTE_ACCOUNTID_NAME  = "serviceId";
 
 EmailManager& EmailManager::getInstance()
 {
-    LOGD("Entered");
+    LoggerD("Entered");
 
     static EmailManager instance;
     return instance;
@@ -82,7 +82,7 @@ EmailManager& EmailManager::getInstance()
 
 EmailManager::EmailManager()
 {
-    LOGD("Entered");
+    LoggerD("Entered");
     getUniqueOpId();
     const int non_err = EMAIL_ERROR_NONE;
 
@@ -101,15 +101,15 @@ EmailManager::EmailManager()
         m_slot_size = slot_size;
     }
 
-//    m_proxy_sync = std::make_shared<DBus::SyncProxy>(
-//                                      DBus::Proxy::DBUS_PATH_NETWORK_STATUS,
-//                                      DBus::Proxy::DBUS_IFACE_NETWORK_STATUS);
-//    if (!m_proxy_sync) {
-//        LOGE("Sync proxy is null");
-//        throw Common::UnknownException("Sync proxy is null");
-//    }
-//    m_proxy_sync->signalSubscribe();
-//
+    m_proxy_sync = std::make_shared<DBus::SyncProxy>(
+                                      DBus::Proxy::DBUS_PATH_NETWORK_STATUS,
+                                      DBus::Proxy::DBUS_IFACE_NETWORK_STATUS);
+    if (!m_proxy_sync) {
+        LOGE("Sync proxy is null");
+        //TODO throw Common::UnknownException("Sync proxy is null");
+    }
+    m_proxy_sync->signalSubscribe();
+
 //    m_proxy_load_body = std::make_shared<DBus::LoadBodyProxy>(
 //                                        DBus::Proxy::DBUS_PATH_NETWORK_STATUS,
 //                                        DBus::Proxy::DBUS_IFACE_NETWORK_STATUS);
@@ -145,7 +145,7 @@ EmailManager::EmailManager()
 
 EmailManager::~EmailManager()
 {
-    LOGD("Entered");
+    LoggerD("Entered");
 }
 
 //void EmailManager::addDraftMessagePlatform(int account_id,
@@ -646,7 +646,7 @@ EmailManager::~EmailManager()
 
 void EmailManager::sync(void* data)
 {
-    LOGD("Entered");
+    LoggerD("Entered");
     SyncCallbackData* callback = static_cast<SyncCallbackData*>(data);
     if(!callback){
         LOGE("Callback is null");
index 539610b4d3245a6e39aefe93d9360cd9765cdf15..fd553a7c5b5e4ab71609eb12c8123f6a153bca14 100644 (file)
@@ -39,8 +39,8 @@
 #include "messaging_util.h"
 #include "message_service.h"
 
-//#include "DBus/Connection.h"
-//#include "DBus/SyncProxy.h"
+#include "DBus/Connection.h"
+#include "DBus/SyncProxy.h"
 //#include "DBus/LoadBodyProxy.h"
 //#include "DBus/LoadAttachmentProxy.h"
 //#include "DBus/MessageProxy.h"
@@ -120,7 +120,7 @@ private:
 
     int m_slot_size;
 
-//    DBus::SyncProxyPtr m_proxy_sync;
+    DBus::SyncProxyPtr m_proxy_sync;
 //    DBus::LoadBodyProxyPtr m_proxy_load_body;
 //    DBus::LoadAttachmentProxyPtr m_proxy_load_attachment;
 //    DBus::MessageProxyPtr m_proxy_messageStorage;
index 8fb0dc392673246b3df9be442e3984649526b43c..7ba4641687b9879d8693500549681f2b3932d188 100644 (file)
         'message_attachment.cc',
         'message_attachment.h',
         'message_body.cc',
-        'message_body.h'
+        'message_body.h',
+        'DBus/Connection.cpp',
+        'DBus/Connection.h',
+        'DBus/EmailSignalProxy.cpp',
+        'DBus/EmailSignalProxy.h',
+        #'DBus/LoadAttachmentProxy.cpp',
+        #'DBus/LoadAttachmentProxy.h',
+        #'DBus/LoadBodyProxy.cpp',
+        #'DBus/LoadBodyProxy.h',
+        #'DBus/MessageProxy.cpp',
+        #'DBus/MessageProxy.h',
+        'DBus/Proxy.cpp',
+        'DBus/Proxy.h',
+        #'DBus/SendProxy.cpp',
+        #'DBus/SendProxy.h',
+        'DBus/SyncProxy.cpp',
+        'DBus/SyncProxy.h',
       ],
       'includes': [
         '../common/pkg-config.gypi',