[evolution-mapi] Bug #667714 - Support for setting user's folder permissions
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-mapi] Bug #667714 - Support for setting user's folder permissions
- Date: Tue, 24 Jan 2012 12:36:22 +0000 (UTC)
commit b31a29b1d2cd82be56e8f84d1091c18bb96eb7a0
Author: Milan Crha <mcrha redhat com>
Date: Tue Jan 24 13:35:51 2012 +0100
Bug #667714 - Support for setting user's folder permissions
po/POTFILES.in | 2 +
src/account-setup-eplugin/Makefile.am | 6 +-
.../e-mapi-account-settings.c | 469 ++++++--
src/account-setup-eplugin/e-mapi-account-setup.c | 98 ++-
src/account-setup-eplugin/e-mapi-account-setup.h | 10 +
.../e-mapi-edit-folder-permissions.c | 1283 ++++++++++++++++++++
.../e-mapi-edit-folder-permissions.h | 43 +
src/account-setup-eplugin/e-mapi-search-gal-user.c | 756 ++++++++++++
src/account-setup-eplugin/e-mapi-search-gal-user.h | 46 +
.../e-mapi-subscribe-foreign-folder.c | 1 -
.../org-gnome-exchange-mapi.eplug.xml | 43 +-
src/addressbook/e-book-backend-mapi-gal.c | 2 +-
src/libexchangemapi/e-mapi-connection.c | 335 +++++-
src/libexchangemapi/e-mapi-connection.h | 48 +
src/libexchangemapi/e-mapi-utils.c | 38 +
src/libexchangemapi/e-mapi-utils.h | 4 +
16 files changed, 3075 insertions(+), 109 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1cdc8dc..c44f2ec 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,6 +1,8 @@
src/account-setup-eplugin/e-mapi-account-listener.c
src/account-setup-eplugin/e-mapi-account-setup.c
src/account-setup-eplugin/e-mapi-account-settings.c
+src/account-setup-eplugin/e-mapi-edit-folder-permissions.c
+src/account-setup-eplugin/e-mapi-search-gal-user.c
src/account-setup-eplugin/e-mapi-subscribe-foreign-folder.c
src/account-setup-eplugin/org-gnome-exchange-mapi.eplug.xml
src/addressbook/e-book-backend-mapi.c
diff --git a/src/account-setup-eplugin/Makefile.am b/src/account-setup-eplugin/Makefile.am
index 6058f40..22193e9 100644
--- a/src/account-setup-eplugin/Makefile.am
+++ b/src/account-setup-eplugin/Makefile.am
@@ -23,7 +23,11 @@ liborg_gnome_exchange_mapi_la_SOURCES = \
e-mapi-account-listener.c \
e-mapi-account-listener.h \
e-mapi-subscribe-foreign-folder.c \
- e-mapi-subscribe-foreign-folder.h
+ e-mapi-subscribe-foreign-folder.h \
+ e-mapi-edit-folder-permissions.c \
+ e-mapi-edit-folder-permissions.h \
+ e-mapi-search-gal-user.c \
+ e-mapi-search-gal-user.h
liborg_gnome_exchange_mapi_la_LIBADD = \
$(top_builddir)/src/libexchangemapi/libexchangemapi-1.0.la \
diff --git a/src/account-setup-eplugin/e-mapi-account-settings.c b/src/account-setup-eplugin/e-mapi-account-settings.c
index c079280..6aa4a85 100644
--- a/src/account-setup-eplugin/e-mapi-account-settings.c
+++ b/src/account-setup-eplugin/e-mapi-account-settings.c
@@ -30,6 +30,7 @@
#include <libedataserver/e-xml-hash-utils.h>
#include <libedataserverui/e-passwords.h>
+#include <libedataserverui/e-source-selector.h>
#include <libedataserver/e-account.h>
#include <e-util/e-util.h>
#include <e-util/e-dialog-utils.h>
@@ -48,11 +49,12 @@
#include "e-mapi-account-listener.h"
#include "e-mapi-subscribe-foreign-folder.h"
+#include "e-mapi-edit-folder-permissions.h"
-#define FOLDERSIZE_MENU_ITEM 0
+#include "camel/camel-mapi-store.h"
+#include "camel/camel-mapi-store-summary.h"
-gboolean e_plugin_ui_init (GtkUIManager *ui_manager, EShellView *shell_view);
-GtkWidget *org_gnome_e_mapi_settings (EPlugin *epl, EConfigHookItemFactoryData *data);
+#define FOLDERSIZE_MENU_ITEM 0
enum {
COL_FOLDERSIZE_NAME = 0,
@@ -218,61 +220,49 @@ folder_size_clicked (GtkButton *button,
static gchar *
get_profile_name_from_folder_tree (EShellView *shell_view,
- gchar **pfolder_uri,
+ gchar **pfolder_path,
CamelStore **pstore)
{
EShellSidebar *shell_sidebar;
EMFolderTree *folder_tree;
- gchar *folder_uri;
- GtkTreeSelection *selection;
- gchar *profile = NULL;
+ gchar *profile = NULL, *selected_path = NULL;
+ CamelStore *selected_store = NULL;
/* Get hold of Folder Tree */
shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
- folder_uri = em_folder_tree_get_selected_uri (folder_tree);
- selection = em_folder_tree_model_get_selection (EM_FOLDER_TREE_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (folder_tree))));
- if (selection) {
- GtkTreeIter iter;
- GtkTreeModel *model = NULL;
-
- if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
- gboolean is_folder = FALSE;
- CamelStore *store = NULL;
-
- gtk_tree_model_get (model, &iter,
- COL_BOOL_IS_FOLDER, &is_folder,
- COL_POINTER_CAMEL_STORE, &store,
- -1);
-
- if (is_folder && !store) {
- CamelFolder *folder = em_folder_tree_get_selected_folder (folder_tree);
-
- if (folder)
- store = camel_folder_get_parent_store (folder);
- }
+ if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_path) ||
+ em_folder_tree_store_root_selected (folder_tree, &selected_store)) {
+ if (selected_store) {
+ CamelProvider *provider = camel_service_get_provider (CAMEL_SERVICE (selected_store));
- if (CAMEL_IS_SERVICE (store)) {
+ if (provider && g_ascii_strcasecmp (provider->protocol, "mapi") == 0) {
CamelService *service;
CamelSettings *settings;
- service = CAMEL_SERVICE (store);
+ service = CAMEL_SERVICE (selected_store);
settings = camel_service_get_settings (service);
g_object_get (settings, "profile", &profile, NULL);
if (pstore && profile)
- *pstore = g_object_ref (store);
+ *pstore = g_object_ref (selected_store);
+
+ if (pfolder_path)
+ *pfolder_path = selected_path;
+ else
+ g_free (selected_path);
+
+ selected_path = NULL;
}
+
+ g_object_unref (selected_store);
}
+
+ g_free (selected_path);
}
g_object_unref (folder_tree);
- if (pfolder_uri)
- *pfolder_uri = folder_uri;
- else
- g_free (folder_uri);
-
return profile;
}
@@ -280,16 +270,12 @@ static void
action_folder_size_cb (GtkAction *action,
EShellView *shell_view)
{
- gchar *folder_uri = NULL;
- gchar *profile = NULL;
-
- profile = get_profile_name_from_folder_tree (shell_view, &folder_uri, NULL);
- g_return_if_fail (folder_uri != NULL);
+ gchar *profile;
- if (g_str_has_prefix (folder_uri, "mapi://"))
+ profile = get_profile_name_from_folder_tree (shell_view, NULL, NULL);
+ if (profile)
mapi_settings_run_folder_size_dialog (profile, NULL);
- g_free (folder_uri);
g_free (profile);
}
@@ -307,8 +293,6 @@ action_subscribe_foreign_folder_cb (GtkAction *action,
if (!profile)
return;
- g_free (profile);
-
parent = GTK_WINDOW (e_shell_view_get_shell_window (shell_view));
backend = e_shell_view_get_shell_backend (shell_view);
g_object_get (G_OBJECT (backend), "session", &session, NULL);
@@ -317,8 +301,59 @@ action_subscribe_foreign_folder_cb (GtkAction *action,
g_object_unref (session);
g_object_unref (store);
+ g_free (profile);
}
+static void
+action_folder_permissions_mail_cb (GtkAction *action,
+ EShellView *shell_view)
+{
+ gchar *profile, *folder_path = NULL;
+ GtkWindow *parent;
+ CamelStore *store = NULL;
+ CamelMapiStore *mapi_store;
+ CamelNetworkSettings *network_settings;
+ CamelStoreInfo *si;
+
+ profile = get_profile_name_from_folder_tree (shell_view, &folder_path, &store);
+ if (!profile)
+ return;
+
+ mapi_store = CAMEL_MAPI_STORE (store);
+ g_return_if_fail (mapi_store != NULL);
+ g_return_if_fail (folder_path != NULL);
+
+ network_settings = CAMEL_NETWORK_SETTINGS (camel_service_get_settings (CAMEL_SERVICE (store)));
+ g_return_if_fail (network_settings != NULL);
+
+ parent = GTK_WINDOW (e_shell_view_get_shell_window (shell_view));
+
+ si = camel_store_summary_path (mapi_store->summary, folder_path);
+ if (!si) {
+ e_notice (parent, GTK_MESSAGE_ERROR, _("Cannot edit permissions of folder '%s', choose other folder."), folder_path);
+ } else {
+ CamelMapiStoreInfo *msi = (CamelMapiStoreInfo *) si;
+
+ e_mapi_edit_folder_permissions (parent,
+ profile,
+ camel_network_settings_get_user (network_settings),
+ camel_network_settings_get_host (network_settings),
+ camel_service_get_display_name (CAMEL_SERVICE (store)),
+ folder_path,
+ msi->folder_id,
+ (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0 ? E_MAPI_FOLDER_CATEGORY_FOREIGN :
+ (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0 ? E_MAPI_FOLDER_CATEGORY_PUBLIC :
+ E_MAPI_FOLDER_CATEGORY_PERSONAL,
+ msi->foreign_username,
+ FALSE);
+ }
+
+ g_object_unref (store);
+ g_free (folder_path);
+}
+
+GtkWidget *org_gnome_e_mapi_settings (EPlugin *epl, EConfigHookItemFactoryData *data);
+
/* used only in Account Editor */
GtkWidget *
org_gnome_e_mapi_settings (EPlugin *epl, EConfigHookItemFactoryData *data)
@@ -378,7 +413,32 @@ org_gnome_e_mapi_settings (EPlugin *epl, EConfigHookItemFactoryData *data)
return GTK_WIDGET (vsettings);
}
-static GtkActionEntry folder_context_entries[] = {
+static void
+mapi_plugin_enable_actions (GtkActionGroup *action_group,
+ const GtkActionEntry *entries,
+ guint n_entries,
+ gboolean can_show,
+ gboolean is_online)
+{
+ gint ii;
+
+ g_return_if_fail (action_group != NULL);
+ g_return_if_fail (entries != NULL);
+
+ for (ii = 0; ii < n_entries; ii++) {
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (action_group, entries[ii].name);
+ if (!action)
+ continue;
+
+ gtk_action_set_visible (action, can_show);
+ if (can_show)
+ gtk_action_set_sensitive (action, is_online);
+ }
+}
+
+static GtkActionEntry mail_account_context_entries[] = {
{ "mail-mapi-folder-size",
NULL,
@@ -395,56 +455,53 @@ static GtkActionEntry folder_context_entries[] = {
G_CALLBACK (action_subscribe_foreign_folder_cb) }
};
+static GtkActionEntry mail_folder_context_entries[] = {
+ { "mail-mapi-folder-permissions",
+ "folder-new",
+ N_("Permissions..."),
+ NULL,
+ N_("Edit MAPI folder permissions"),
+ G_CALLBACK (action_folder_permissions_mail_cb) }
+};
+
static void
-mapi_plugin_update_actions_cb (EShellView *shell_view,
- GtkActionEntry *entries)
+mapi_plugin_update_actions_mail_cb (EShellView *shell_view,
+ GtkActionEntry *entries)
{
EShellWindow *shell_window;
GtkActionGroup *action_group;
GtkUIManager *ui_manager;
EShellSidebar *shell_sidebar;
EMFolderTree *folder_tree;
- gchar *folder_uri = NULL;
- CamelURL *url = NULL;
- gboolean show_menu_entry = FALSE;
- gint ii;
- GSList *actions = NULL, *iter;
+ CamelStore *selected_store = NULL;
+ gchar *selected_path = NULL;
+ gboolean account_node = FALSE, folder_node = FALSE;
gboolean online = FALSE;
shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
- folder_uri = em_folder_tree_get_selected_uri (folder_tree);
- g_object_unref (folder_tree);
- if (!(folder_uri && *folder_uri)) {
- g_free (folder_uri);
- return;
+ if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_path) ||
+ em_folder_tree_store_root_selected (folder_tree, &selected_store)) {
+ if (selected_store) {
+ CamelProvider *provider = camel_service_get_provider (CAMEL_SERVICE (selected_store));
+
+ if (provider && g_ascii_strcasecmp (provider->protocol, "mapi") == 0) {
+ account_node = !selected_path || !*selected_path;
+ folder_node = !account_node;
+ }
+
+ g_object_unref (selected_store);
+ }
}
+ g_object_unref (folder_tree);
- shell_window = e_shell_view_get_shell_window (shell_view);
+ g_free (selected_path);
+ shell_window = e_shell_view_get_shell_window (shell_view);
ui_manager = e_shell_window_get_ui_manager (shell_window);
action_group = e_lookup_action_group (ui_manager, "mail");
- for (ii = 0; ii < G_N_ELEMENTS (folder_context_entries); ii++) {
- GtkAction *action;
-
- action = gtk_action_group_get_action (action_group, folder_context_entries[ii].name);
- if (action)
- actions = g_slist_prepend (actions, action);
- }
-
- /* Show / Hide action entry */
- if (g_str_has_prefix (folder_uri, "mapi://")) {
- show_menu_entry = TRUE;
- url = camel_url_new (folder_uri, NULL);
- if (url && url->path && strlen (url->path) > 1)
- show_menu_entry = FALSE;
- camel_url_free (url);
- }
-
- g_free (folder_uri);
-
- if (show_menu_entry) {
+ if (account_node || folder_node) {
EShellBackend *backend;
CamelSession *session = NULL;
@@ -457,20 +514,15 @@ mapi_plugin_update_actions_cb (EShellView *shell_view,
g_object_unref (session);
}
- for (iter = actions; iter; iter = iter->next) {
- GtkAction *action = iter->data;
-
- gtk_action_set_visible (action, show_menu_entry);
- if (show_menu_entry)
- gtk_action_set_sensitive (action, online);
- }
-
- g_slist_free (actions);
+ mapi_plugin_enable_actions (action_group, mail_account_context_entries, G_N_ELEMENTS (mail_account_context_entries), account_node, online);
+ mapi_plugin_enable_actions (action_group, mail_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), folder_node, online);
}
+gboolean mapi_ui_init_mail (GtkUIManager *ui_manager, EShellView *shell_view);
+
gboolean
-e_plugin_ui_init (GtkUIManager *ui_manager,
- EShellView *shell_view)
+mapi_ui_init_mail (GtkUIManager *ui_manager,
+ EShellView *shell_view)
{
EShellWindow *shell_window;
GtkActionGroup *action_group;
@@ -480,14 +532,247 @@ e_plugin_ui_init (GtkUIManager *ui_manager,
/* Add actions to the "mail" action group. */
e_action_group_add_actions_localized (action_group, GETTEXT_PACKAGE,
- folder_context_entries, G_N_ELEMENTS (folder_context_entries), shell_view);
+ mail_account_context_entries, G_N_ELEMENTS (mail_account_context_entries), shell_view);
+ e_action_group_add_actions_localized (action_group, GETTEXT_PACKAGE,
+ mail_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), shell_view);
/* Decide whether we want this option to be visible or not */
g_signal_connect (shell_view, "update-actions",
- G_CALLBACK (mapi_plugin_update_actions_cb),
+ G_CALLBACK (mapi_plugin_update_actions_mail_cb),
shell_view);
g_object_unref (action_group);
return TRUE;
}
+
+static gboolean
+get_selected_mapi_source (EShellView *shell_view,
+ ESource **selected_source)
+{
+ ESource *source;
+ gchar *uri = NULL;
+ EShellSidebar *shell_sidebar;
+ ESourceSelector *selector = NULL;
+
+ g_return_val_if_fail (shell_view != NULL, FALSE);
+
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ g_return_val_if_fail (shell_sidebar != NULL, FALSE);
+
+ g_object_get (shell_sidebar, "selector", &selector, NULL);
+ g_return_val_if_fail (selector != NULL, FALSE);
+
+ source = e_source_selector_peek_primary_selection (selector);
+ uri = source ? e_source_get_uri (source) : NULL;
+ if (uri && g_str_has_prefix (uri, "mapi://"))
+ source = g_object_ref (source);
+ else
+ source = NULL;
+
+ g_free (uri);
+ g_object_unref (selector);
+
+ if (selected_source)
+ *selected_source = source;
+ else if (source)
+ g_object_unref (source);
+
+ return source != NULL;
+}
+
+/* how many menu entries are defined; all calendar/tasks/memos/contacts
+ actions should have same count */
+#define MAPI_ESOURCE_NUM_ENTRIES 1
+
+static void
+update_mapi_source_entries_cb (EShellView *shell_view,
+ GtkActionEntry *entries)
+{
+ GtkActionGroup *action_group;
+ EShell *shell;
+ EShellWindow *shell_window;
+ const gchar *group;
+ gboolean is_mapi_source, is_online;
+
+ g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+ g_return_if_fail (entries != NULL);
+
+ if (strstr (entries->name, "calendar"))
+ group = "calendar";
+ else if (strstr (entries->name, "tasks"))
+ group = "tasks";
+ else if (strstr (entries->name, "memos"))
+ group = "memos";
+ else if (strstr (entries->name, "contacts"))
+ group = "contacts";
+ else
+ g_return_if_reached ();
+
+ is_mapi_source = get_selected_mapi_source (shell_view, NULL);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ is_online = shell && e_shell_get_online (shell);
+ action_group = e_shell_window_get_action_group (shell_window, group);
+
+ mapi_plugin_enable_actions (action_group, entries, MAPI_ESOURCE_NUM_ENTRIES, is_mapi_source, is_online);
+}
+
+static void
+setup_mapi_source_actions (EShellView *shell_view,
+ GtkActionEntry *entries,
+ guint n_entries)
+{
+ EShellWindow *shell_window;
+ const gchar *group;
+
+ g_return_if_fail (shell_view != NULL);
+ g_return_if_fail (entries != NULL);
+ g_return_if_fail (n_entries > 0);
+ g_return_if_fail (n_entries == MAPI_ESOURCE_NUM_ENTRIES);
+
+ if (strstr (entries->name, "calendar"))
+ group = "calendar";
+ else if (strstr (entries->name, "tasks"))
+ group = "tasks";
+ else if (strstr (entries->name, "memos"))
+ group = "memos";
+ else if (strstr (entries->name, "contacts"))
+ group = "contacts";
+ else
+ g_return_if_reached ();
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ e_action_group_add_actions_localized (
+ e_shell_window_get_action_group (shell_window, group), GETTEXT_PACKAGE,
+ entries, MAPI_ESOURCE_NUM_ENTRIES, shell_view);
+
+ g_signal_connect (shell_view, "update-actions", G_CALLBACK (update_mapi_source_entries_cb), entries);
+}
+
+static void
+action_folder_permissions_source_cb (GtkAction *action,
+ EShellView *shell_view)
+{
+ ESource *source = NULL;
+ mapi_id_t folder_id = 0;
+ const gchar *foreign_username;
+ gboolean is_public;
+
+ g_return_if_fail (action != NULL);
+ g_return_if_fail (shell_view != NULL);
+ g_return_if_fail (get_selected_mapi_source (shell_view, &source));
+ g_return_if_fail (source != NULL);
+ g_return_if_fail (e_mapi_util_mapi_id_from_string (e_source_get_property (source, "folder-id"), &folder_id));
+ g_return_if_fail (gtk_action_get_name (action) != NULL);
+
+ foreign_username = e_source_get_property (source, "foreign-username");
+ is_public = !foreign_username && g_strcmp0 (e_source_get_property (source, "public"), "yes") == 0;
+
+ e_mapi_edit_folder_permissions (NULL,
+ e_source_get_property (source, "profile"),
+ e_source_get_property (source, "username"),
+ e_source_get_property (source, "host"),
+ e_source_group_peek_name (e_source_peek_group (source)),
+ e_source_peek_name (source),
+ folder_id,
+ foreign_username ? E_MAPI_FOLDER_CATEGORY_FOREIGN :
+ is_public ? E_MAPI_FOLDER_CATEGORY_PUBLIC :
+ E_MAPI_FOLDER_CATEGORY_PERSONAL,
+ foreign_username,
+ strstr (gtk_action_get_name (action), "calendar") != NULL);
+
+ g_object_unref (source);
+}
+
+static GtkActionEntry calendar_context_entries[] = {
+
+ { "calendar-mapi-folder-permissions",
+ "folder-new",
+ N_("Permissions..."),
+ NULL,
+ N_("Edit MAPI calendar permissions"),
+ G_CALLBACK (action_folder_permissions_source_cb) }
+};
+
+gboolean mapi_ui_init_calendar (GtkUIManager *ui_manager, EShellView *shell_view);
+
+gboolean
+mapi_ui_init_calendar (GtkUIManager *ui_manager,
+ EShellView *shell_view)
+{
+ setup_mapi_source_actions (shell_view,
+ calendar_context_entries,
+ G_N_ELEMENTS (calendar_context_entries));
+
+ return TRUE;
+}
+
+static GtkActionEntry tasks_context_entries[] = {
+
+ { "tasks-mapi-folder-permissions",
+ "folder-new",
+ N_("Permissions..."),
+ NULL,
+ N_("Edit MAPI tasks permissions"),
+ G_CALLBACK (action_folder_permissions_source_cb) }
+};
+
+gboolean mapi_ui_init_tasks (GtkUIManager *ui_manager, EShellView *shell_view);
+
+gboolean
+mapi_ui_init_tasks (GtkUIManager *ui_manager,
+ EShellView *shell_view)
+{
+ setup_mapi_source_actions (shell_view,
+ tasks_context_entries,
+ G_N_ELEMENTS (tasks_context_entries));
+
+ return TRUE;
+}
+static GtkActionEntry memos_context_entries[] = {
+
+ { "memos-mapi-folder-permissions",
+ "folder-new",
+ N_("Permissions..."),
+ NULL,
+ N_("Edit MAPI memos permissions"),
+ G_CALLBACK (action_folder_permissions_source_cb) }
+};
+
+gboolean mapi_ui_init_memos (GtkUIManager *ui_manager, EShellView *shell_view);
+
+gboolean
+mapi_ui_init_memos (GtkUIManager *ui_manager,
+ EShellView *shell_view)
+{
+ setup_mapi_source_actions (shell_view,
+ memos_context_entries,
+ G_N_ELEMENTS (memos_context_entries));
+
+ return TRUE;
+}
+static GtkActionEntry contacts_context_entries[] = {
+
+ { "contacts-mapi-folder-permissions",
+ "folder-new",
+ N_("Permissions..."),
+ NULL,
+ N_("Edit MAPI contacts permissions"),
+ G_CALLBACK (action_folder_permissions_source_cb) }
+};
+
+gboolean mapi_ui_init_contacts (GtkUIManager *ui_manager, EShellView *shell_view);
+
+gboolean
+mapi_ui_init_contacts (GtkUIManager *ui_manager,
+ EShellView *shell_view)
+{
+ setup_mapi_source_actions (shell_view,
+ contacts_context_entries,
+ G_N_ELEMENTS (contacts_context_entries));
+
+ return TRUE;
+}
diff --git a/src/account-setup-eplugin/e-mapi-account-setup.c b/src/account-setup-eplugin/e-mapi-account-setup.c
index 03d18ef..fd8af88 100644
--- a/src/account-setup-eplugin/e-mapi-account-setup.c
+++ b/src/account-setup-eplugin/e-mapi-account-setup.c
@@ -32,6 +32,7 @@
#include <gtk/gtk.h>
#include <libedataserver/e-xml-hash-utils.h>
+#include <libedataserver/e-credentials.h>
#include <libedataserverui/e-passwords.h>
#include <libedataserver/e-account.h>
#include <e-util/e-dialog-utils.h>
@@ -248,7 +249,7 @@ static char*
prompt_password(const gchar *user, const gchar *host, const gchar *key,
EMConfigTargetSettings *account)
{
- int pw_flags = E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET;
+ guint32 pw_flags = E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET;
gchar *password, *title;
gboolean save = TRUE;
@@ -1235,7 +1236,7 @@ e_mapi_run_in_thread_with_feedback (GtkWindow *parent,
dialog = gtk_dialog_new_with_buttons ("",
parent,
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_DIALOG_MODAL,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
NULL);
@@ -1264,3 +1265,96 @@ e_mapi_run_in_thread_with_feedback (GtkWindow *parent,
g_return_if_fail (g_thread_create (run_with_feedback_thread, rfd, FALSE, NULL));
}
+
+EMapiConnection *
+e_mapi_account_open_connection_for (GtkWindow *parent,
+ const gchar *login_profile,
+ const gchar *login_username,
+ const gchar *login_url,
+ GCancellable *cancellable,
+ GError **perror)
+{
+ guint32 prompt_flags = E_PASSWORDS_SECRET | E_PASSWORDS_ONLINE | E_PASSWORDS_DISABLE_REMEMBER;
+ EMapiConnection *conn = NULL;
+ gchar *password = NULL;
+ SoupURI *suri;
+ gchar *key_str, *title;
+
+ g_return_val_if_fail (login_profile != NULL, NULL);
+ g_return_val_if_fail (login_username != NULL, NULL);
+ g_return_val_if_fail (login_url != NULL, NULL);
+
+ /* use the one from mailer, if there, otherwise open new */
+ conn = e_mapi_connection_find (login_profile);
+ if (conn)
+ return conn;
+
+ if (strchr (login_url, '/') != NULL) {
+ suri = soup_uri_new (login_url);
+ } else {
+ gchar *url = g_strconcat ("http://", login_url, NULL);
+ suri = soup_uri_new (url);
+ g_free (url);
+ }
+
+ g_return_val_if_fail (suri != NULL, NULL);
+
+ soup_uri_set_user (suri, login_username);
+ soup_uri_set_password (suri, NULL);
+ soup_uri_set_fragment (suri, NULL);
+
+ key_str = soup_uri_to_string (suri, FALSE);
+ title = g_strdup_printf (_("Enter Password for %s %s"), soup_uri_get_user (suri), soup_uri_get_host (suri));
+
+ soup_uri_free (suri);
+
+ g_return_val_if_fail (key_str != NULL, NULL);
+
+ password = e_passwords_get_password (NULL, key_str);
+ if (!password)
+ password = e_passwords_ask_password (title, NULL, key_str, NULL, prompt_flags, NULL, parent);
+
+ prompt_flags |= E_PASSWORDS_REPROMPT;
+
+ do {
+ conn = e_mapi_connection_new (login_profile, password, cancellable, perror);
+
+ if (!conn && !g_cancellable_is_cancelled (cancellable)) {
+ e_credentials_util_safe_free_string (password);
+ password = e_passwords_ask_password (title, NULL, key_str, NULL, prompt_flags, NULL, parent);
+ }
+ } while (!conn && !g_cancellable_is_cancelled (cancellable));
+
+ e_credentials_util_safe_free_string (password);
+ g_free (key_str);
+ g_free (title);
+
+ return conn;
+}
+
+static gpointer
+unref_conn_in_thread (gpointer ptr)
+{
+ EMapiConnection *conn = ptr;
+
+ g_return_val_if_fail (conn != NULL, NULL);
+
+ g_object_unref (conn);
+
+ return NULL;
+}
+
+/* because this also disconnects from a server, which can take its time */
+void
+e_mapi_account_unref_conn_in_thread (EMapiConnection *conn)
+{
+ GError *error = NULL;
+
+ if (!conn)
+ return;
+
+ if (!g_thread_create (unref_conn_in_thread, conn, FALSE, &error)) {
+ g_warning ("%s: Failed to run thread: %s", G_STRFUNC, error ? error->message : "Unknown error");
+ g_object_unref (conn);
+ }
+}
diff --git a/src/account-setup-eplugin/e-mapi-account-setup.h b/src/account-setup-eplugin/e-mapi-account-setup.h
index 7551db8..3239872 100644
--- a/src/account-setup-eplugin/e-mapi-account-setup.h
+++ b/src/account-setup-eplugin/e-mapi-account-setup.h
@@ -27,6 +27,7 @@
#include <gtk/gtk.h>
#include "e-mapi-account-listener.h"
+#include <e-mapi-connection.h>
#define MAPI_URI_PREFIX "mapi://"
#define MAPI_PREFIX_LENGTH 7
@@ -46,4 +47,13 @@ void e_mapi_run_in_thread_with_feedback (GtkWindow *parent,
gpointer user_data,
GDestroyNotify free_user_data);
+EMapiConnection * e_mapi_account_open_connection_for (GtkWindow *parent,
+ const gchar *login_profile,
+ const gchar *login_username,
+ const gchar *login_url,
+ GCancellable *cancellable,
+ GError **perror);
+
+void e_mapi_account_unref_conn_in_thread (EMapiConnection *conn);
+
#endif /* E_MAPI_ACCOUNT_SETUP_H */
diff --git a/src/account-setup-eplugin/e-mapi-edit-folder-permissions.c b/src/account-setup-eplugin/e-mapi-edit-folder-permissions.c
new file mode 100644
index 0000000..4692d1c
--- /dev/null
+++ b/src/account-setup-eplugin/e-mapi-edit-folder-permissions.c
@@ -0,0 +1,1283 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Milan Crha <mcrha redhat com>
+ *
+ * Copyright (C) 2012 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+
+#include "e-mapi-account-setup.h"
+#include "e-mapi-edit-folder-permissions.h"
+#include "e-mapi-search-gal-user.h"
+#include "e-mapi-utils.h"
+
+#define E_MAPI_PERM_DLG_WIDGETS "e-mapi-perm-dlg-widgets"
+
+enum {
+ COL_NAME = 0,
+ COL_PERMISSION_LEVEL,
+ COL_E_MAPI_PERMISSION_ENTRY,
+ COL_E_MAPI_GAL_USER_TYPE,
+ COL_IS_NEW
+};
+
+struct EMapiPermissionsDialogWidgets
+{
+ gchar *login_profile;
+ gchar *login_username;
+ gchar *login_url;
+ mapi_id_t folder_id;
+ EMapiFolderCategory folder_category;
+ gchar *foreign_username;
+
+ EMapiConnection *conn;
+
+ gboolean updating;
+
+ GtkWidget *dialog;
+ GtkWidget *tree_view;
+
+ GtkWidget *add_button;
+ GtkWidget *remove_button;
+ GtkWidget *level_combo;
+
+ GtkWidget *read_none_radio;
+ GtkWidget *read_full_radio;
+ GtkWidget *read_fb_simple_check;
+ GtkWidget *read_fb_detail_check;
+
+ GtkWidget *write_create_items_check;
+ GtkWidget *write_create_subfolders_check;
+ GtkWidget *write_edit_own_check;
+ GtkWidget *write_edit_all_check;
+
+ GtkWidget *delete_none_radio;
+ GtkWidget *delete_own_radio;
+ GtkWidget *delete_all_radio;
+
+ GtkWidget *other_folder_owner_check;
+ GtkWidget *other_folder_contact_check;
+ GtkWidget *other_folder_visible_check;
+};
+
+static const struct EMapiPredefinedLevels {
+ const gchar *name;
+ uint32_t rights;
+} predefined_levels[] = {
+ { NC_("PermissionsLevel", "None"), 0 },
+ { NC_("PermissionsLevel", "Owner"), E_MAPI_PERMISSION_BIT_READ_ANY |
+ E_MAPI_PERMISSION_BIT_CREATE |
+ E_MAPI_PERMISSION_BIT_CREATE_SUBFOLDER |
+ E_MAPI_PERMISSION_BIT_EDIT_OWNED |
+ E_MAPI_PERMISSION_BIT_EDIT_ANY |
+ E_MAPI_PERMISSION_BIT_DELETE_OWNED |
+ E_MAPI_PERMISSION_BIT_DELETE_ANY |
+ E_MAPI_PERMISSION_BIT_FOLDER_OWNER |
+ E_MAPI_PERMISSION_BIT_FOLDER_CONTACT |
+ E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE },
+ { NC_("PermissionsLevel", "Publishing Editor"),
+ E_MAPI_PERMISSION_BIT_READ_ANY |
+ E_MAPI_PERMISSION_BIT_CREATE |
+ E_MAPI_PERMISSION_BIT_CREATE_SUBFOLDER |
+ E_MAPI_PERMISSION_BIT_EDIT_OWNED |
+ E_MAPI_PERMISSION_BIT_EDIT_ANY |
+ E_MAPI_PERMISSION_BIT_DELETE_OWNED |
+ E_MAPI_PERMISSION_BIT_DELETE_ANY |
+ E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE },
+ { NC_("PermissionsLevel", "Editor"),
+ E_MAPI_PERMISSION_BIT_READ_ANY |
+ E_MAPI_PERMISSION_BIT_CREATE |
+ E_MAPI_PERMISSION_BIT_EDIT_OWNED |
+ E_MAPI_PERMISSION_BIT_EDIT_ANY |
+ E_MAPI_PERMISSION_BIT_DELETE_OWNED |
+ E_MAPI_PERMISSION_BIT_DELETE_ANY |
+ E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE },
+ { NC_("PermissionsLevel", "Publishing Author"),
+ E_MAPI_PERMISSION_BIT_READ_ANY |
+ E_MAPI_PERMISSION_BIT_CREATE |
+ E_MAPI_PERMISSION_BIT_CREATE_SUBFOLDER |
+ E_MAPI_PERMISSION_BIT_EDIT_OWNED |
+ E_MAPI_PERMISSION_BIT_DELETE_OWNED |
+ E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE },
+ { NC_("PermissionsLevel", "Author"),
+ E_MAPI_PERMISSION_BIT_READ_ANY |
+ E_MAPI_PERMISSION_BIT_CREATE |
+ E_MAPI_PERMISSION_BIT_EDIT_OWNED |
+ E_MAPI_PERMISSION_BIT_DELETE_OWNED |
+ E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE },
+ { NC_("PermissionsLevel", "Nonediting Author"),
+ E_MAPI_PERMISSION_BIT_READ_ANY |
+ E_MAPI_PERMISSION_BIT_CREATE |
+ E_MAPI_PERMISSION_BIT_DELETE_OWNED |
+ E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE },
+ { NC_("PermissionsLevel", "Reviewer"),
+ E_MAPI_PERMISSION_BIT_READ_ANY |
+ E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE },
+ { NC_("PermissionsLevel", "Contributor"),
+ E_MAPI_PERMISSION_BIT_CREATE |
+ E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE },
+ { NC_("PermissionsLevel", "Custom"), ~0 } /* make sure 'Custom' is always the last */
+};
+
+static void
+edit_permissions_widgets_free (gpointer ptr)
+{
+ struct EMapiPermissionsDialogWidgets *widgets = ptr;
+
+ if (!widgets)
+ return;
+
+ g_free (widgets->login_profile);
+ g_free (widgets->login_username);
+ g_free (widgets->login_url);
+ g_free (widgets->foreign_username);
+ if (widgets->conn)
+ e_mapi_account_unref_conn_in_thread (widgets->conn);
+ g_free (widgets);
+}
+
+static void
+folder_permissions_clear_all_entries (GObject *dialog)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_if_fail (dialog != NULL);
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+ g_return_if_fail (widgets->tree_view != NULL);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widgets->tree_view));
+ g_return_if_fail (model != NULL);
+
+ if (!gtk_tree_model_get_iter_first (model, &iter))
+ return;
+
+ do {
+ EMapiPermissionEntry *pem = NULL;
+
+ gtk_tree_model_get (model, &iter, COL_E_MAPI_PERMISSION_ENTRY, &pem, -1);
+
+ e_mapi_permission_entry_free (pem);
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ gtk_list_store_clear (GTK_LIST_STORE (model));
+}
+
+static void
+write_folder_permissions_thread (GObject *dialog,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ mapi_object_t obj_folder;
+ gboolean opened;
+ const GSList *entries = user_data;
+
+ g_return_if_fail (dialog != NULL);
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+ g_return_if_fail (widgets->conn != NULL);
+
+ if (widgets->folder_category == E_MAPI_FOLDER_CATEGORY_FOREIGN)
+ opened = e_mapi_connection_open_foreign_folder (widgets->conn, widgets->foreign_username, widgets->folder_id, &obj_folder, cancellable, perror);
+ else if (widgets->folder_category == E_MAPI_FOLDER_CATEGORY_PUBLIC)
+ opened = e_mapi_connection_open_public_folder (widgets->conn, widgets->folder_id, &obj_folder, cancellable, perror);
+ else
+ opened = e_mapi_connection_open_personal_folder (widgets->conn, widgets->folder_id, &obj_folder, cancellable, perror);
+
+ if (opened) {
+ e_mapi_connection_set_permissions (widgets->conn, &obj_folder, widgets->read_fb_simple_check != NULL, entries, cancellable, perror);
+ e_mapi_connection_close_folder (widgets->conn, &obj_folder, cancellable, perror);
+ }
+}
+
+static void
+write_folder_permissions_idle (GObject *dialog,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
+{
+ /* does this only if no error was raised from the thread function */
+ folder_permissions_clear_all_entries (dialog);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+edit_permissions_response_cb (GObject *dialog,
+ gint response_id)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ GSList *write_entries = NULL;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_if_fail (dialog != NULL);
+
+ if (response_id != GTK_RESPONSE_OK) {
+ folder_permissions_clear_all_entries (dialog);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ return;
+ }
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+ g_return_if_fail (widgets->tree_view != NULL);
+ g_return_if_fail (widgets->conn != NULL);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widgets->tree_view));
+ g_return_if_fail (model != NULL);
+
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ do {
+ EMapiPermissionEntry *pem = NULL;
+
+ gtk_tree_model_get (model, &iter, COL_E_MAPI_PERMISSION_ENTRY, &pem, -1);
+
+ if (pem)
+ write_entries = g_slist_prepend (write_entries, pem);
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ write_entries = g_slist_reverse (write_entries);
+ }
+
+ e_mapi_run_in_thread_with_feedback (GTK_WINDOW (dialog), dialog,
+ _("Writing folder permissions, please wait..."),
+ write_folder_permissions_thread,
+ write_folder_permissions_idle,
+ write_entries, (GDestroyNotify) g_slist_free);
+}
+
+static void
+enable_all_widgets (struct EMapiPermissionsDialogWidgets *widgets,
+ gboolean enabled)
+{
+ g_return_if_fail (widgets != NULL);
+
+ gtk_widget_set_sensitive (widgets->add_button, enabled || gtk_widget_get_sensitive (widgets->tree_view));
+ gtk_widget_set_sensitive (widgets->remove_button, enabled);
+ gtk_widget_set_sensitive (widgets->level_combo, enabled);
+ gtk_widget_set_sensitive (widgets->read_none_radio, enabled);
+ gtk_widget_set_sensitive (widgets->read_full_radio, enabled);
+ if (widgets->read_fb_simple_check)
+ gtk_widget_set_sensitive (widgets->read_fb_simple_check, enabled);
+ if (widgets->read_fb_detail_check)
+ gtk_widget_set_sensitive (widgets->read_fb_detail_check, enabled);
+ gtk_widget_set_sensitive (widgets->write_create_items_check, enabled);
+ gtk_widget_set_sensitive (widgets->write_create_subfolders_check, enabled);
+ gtk_widget_set_sensitive (widgets->write_edit_own_check, enabled);
+ gtk_widget_set_sensitive (widgets->write_edit_all_check, enabled);
+ gtk_widget_set_sensitive (widgets->delete_none_radio, enabled);
+ gtk_widget_set_sensitive (widgets->delete_own_radio, enabled);
+ gtk_widget_set_sensitive (widgets->delete_all_radio, enabled);
+ gtk_widget_set_sensitive (widgets->other_folder_owner_check, enabled);
+ gtk_widget_set_sensitive (widgets->other_folder_contact_check, enabled);
+ gtk_widget_set_sensitive (widgets->other_folder_visible_check, enabled);
+}
+
+static uint32_t
+folder_permissions_dialog_to_rights (GObject *dialog)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ uint32_t rights;
+
+ g_return_val_if_fail (dialog != NULL, 0);
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_val_if_fail (widgets != NULL, 0);
+
+ #define set_bit_by_active(x, bt) G_STMT_START { \
+ if (widgets->x && \
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->x)) && \
+ gtk_widget_get_sensitive (widgets->x)) { \
+ rights |= bt; \
+ } } G_STMT_END
+
+ rights = 0;
+
+ set_bit_by_active (read_none_radio, 0);
+ set_bit_by_active (read_full_radio, E_MAPI_PERMISSION_BIT_READ_ANY);
+ set_bit_by_active (read_fb_simple_check, E_MAPI_PERMISSION_BIT_FREE_BUSY_SIMPLE);
+ set_bit_by_active (read_fb_detail_check, E_MAPI_PERMISSION_BIT_FREE_BUSY_DETAILED);
+ set_bit_by_active (write_create_items_check, E_MAPI_PERMISSION_BIT_CREATE);
+ set_bit_by_active (write_create_subfolders_check, E_MAPI_PERMISSION_BIT_CREATE_SUBFOLDER);
+ set_bit_by_active (write_edit_own_check, E_MAPI_PERMISSION_BIT_EDIT_OWNED);
+ set_bit_by_active (write_edit_all_check, E_MAPI_PERMISSION_BIT_EDIT_ANY | E_MAPI_PERMISSION_BIT_EDIT_OWNED);
+ set_bit_by_active (delete_none_radio, 0);
+ set_bit_by_active (delete_own_radio, E_MAPI_PERMISSION_BIT_DELETE_OWNED);
+ set_bit_by_active (delete_all_radio, E_MAPI_PERMISSION_BIT_DELETE_ANY | E_MAPI_PERMISSION_BIT_DELETE_OWNED);
+ set_bit_by_active (other_folder_owner_check, E_MAPI_PERMISSION_BIT_FOLDER_OWNER);
+ set_bit_by_active (other_folder_contact_check, E_MAPI_PERMISSION_BIT_FOLDER_CONTACT);
+ set_bit_by_active (other_folder_visible_check, E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE);
+
+ #undef set_bit_by_active
+
+ return rights;
+}
+
+static void
+update_folder_permissions_sensitivity (GObject *dialog,
+ gboolean member_valid,
+ EMapiGalUserType user_type)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+
+ g_return_if_fail (dialog != NULL);
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+
+ enable_all_widgets (widgets, member_valid);
+
+ if (user_type == E_MAPI_GAL_USER_DEFAULT ||
+ user_type == E_MAPI_GAL_USER_ANONYMOUS)
+ gtk_widget_set_sensitive (widgets->other_folder_contact_check, FALSE);
+
+ if (member_valid)
+ gtk_widget_set_sensitive (widgets->remove_button,
+ user_type != E_MAPI_GAL_USER_DEFAULT &&
+ user_type != E_MAPI_GAL_USER_ANONYMOUS);
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_all_check))) {
+ gtk_widget_set_sensitive (widgets->write_edit_own_check, FALSE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widgets->write_edit_own_check), TRUE);
+ }
+}
+
+static void
+update_folder_permissions_by_rights (GObject *dialog,
+ uint32_t rights)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+
+ g_return_if_fail (dialog != NULL);
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+
+ #define set_active(x, act) G_STMT_START { if (widgets->x) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widgets->x), act); } G_STMT_END
+ #define set_active_by_bit(x, bt) set_active (x, (rights & (bt)) != 0)
+
+ widgets->updating = TRUE;
+
+ set_active (read_none_radio, TRUE);
+ set_active_by_bit (read_full_radio, E_MAPI_PERMISSION_BIT_READ_ANY);
+ set_active_by_bit (read_fb_simple_check, E_MAPI_PERMISSION_BIT_FREE_BUSY_SIMPLE);
+ set_active_by_bit (read_fb_detail_check, E_MAPI_PERMISSION_BIT_FREE_BUSY_DETAILED);
+ set_active_by_bit (write_create_items_check, E_MAPI_PERMISSION_BIT_CREATE);
+ set_active_by_bit (write_create_subfolders_check, E_MAPI_PERMISSION_BIT_CREATE_SUBFOLDER);
+ set_active_by_bit (write_edit_own_check, E_MAPI_PERMISSION_BIT_EDIT_OWNED | E_MAPI_PERMISSION_BIT_EDIT_ANY);
+ set_active_by_bit (write_edit_all_check, E_MAPI_PERMISSION_BIT_EDIT_ANY);
+ set_active (delete_none_radio, TRUE);
+ set_active_by_bit (delete_own_radio, E_MAPI_PERMISSION_BIT_DELETE_OWNED);
+ set_active_by_bit (delete_all_radio, E_MAPI_PERMISSION_BIT_DELETE_ANY);
+ set_active_by_bit (other_folder_owner_check, E_MAPI_PERMISSION_BIT_FOLDER_OWNER);
+ set_active_by_bit (other_folder_contact_check, E_MAPI_PERMISSION_BIT_FOLDER_CONTACT);
+ set_active_by_bit (other_folder_visible_check, E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE);
+
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_all_check)) &&
+ gtk_widget_get_sensitive (widgets->write_edit_all_check)) {
+ gtk_widget_set_sensitive (widgets->write_edit_own_check, TRUE);
+ } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_all_check))) {
+ gtk_widget_set_sensitive (widgets->write_edit_own_check, FALSE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widgets->write_edit_own_check), TRUE);
+ }
+
+ if (widgets->read_fb_simple_check && widgets->read_fb_detail_check) {
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->read_fb_detail_check)) &&
+ gtk_widget_get_sensitive (widgets->read_fb_detail_check)) {
+ gtk_widget_set_sensitive (widgets->read_fb_simple_check, TRUE);
+ } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->read_fb_detail_check))) {
+ gtk_widget_set_sensitive (widgets->read_fb_simple_check, FALSE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widgets->read_fb_simple_check), TRUE);
+ }
+ }
+
+ widgets->updating = FALSE;
+
+ #undef set_active_by_bit
+ #undef set_active
+}
+
+static void
+update_folder_permissions_tree_view (GObject *dialog,
+ struct EMapiPermissionsDialogWidgets *widgets)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ uint32_t rights;
+
+ g_return_if_fail (dialog != NULL);
+ g_return_if_fail (widgets != NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widgets->tree_view));
+ if (selection && gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ gchar *combo_text;
+ EMapiPermissionEntry *pem = NULL;
+
+ combo_text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (widgets->level_combo));
+ rights = folder_permissions_dialog_to_rights (dialog);
+
+ gtk_tree_model_get (model, &iter, COL_E_MAPI_PERMISSION_ENTRY, &pem, -1);
+
+ if (pem) {
+ if (!widgets->read_fb_simple_check)
+ rights = rights | (pem->member_rights & (E_MAPI_PERMISSION_BIT_FREE_BUSY_DETAILED | E_MAPI_PERMISSION_BIT_FREE_BUSY_SIMPLE));
+
+ pem->member_rights = rights;
+
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_PERMISSION_LEVEL, combo_text, -1);
+ }
+
+ g_free (combo_text);
+ }
+}
+
+static void
+update_permission_level_combo_by_dialog (GObject *dialog)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ uint32_t rights;
+ gint ii;
+
+ g_return_if_fail (dialog != NULL);
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+
+ if (widgets->updating)
+ return;
+
+ rights = folder_permissions_dialog_to_rights (dialog);
+ rights = rights & ~(E_MAPI_PERMISSION_BIT_FREE_BUSY_DETAILED |
+ E_MAPI_PERMISSION_BIT_FREE_BUSY_SIMPLE);
+
+ for (ii = 0; ii < G_N_ELEMENTS (predefined_levels) - 1; ii++) {
+ if (predefined_levels[ii].rights == rights) {
+ break;
+ }
+ }
+
+ /* ii points to the matched or the last item, which is 'Custom' */
+ widgets->updating = TRUE;
+ gtk_combo_box_set_active (GTK_COMBO_BOX (widgets->level_combo), ii);
+
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_all_check)) &&
+ gtk_widget_get_sensitive (widgets->write_edit_all_check)) {
+ gtk_widget_set_sensitive (widgets->write_edit_own_check, TRUE);
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_own_check))) {
+ rights |= E_MAPI_PERMISSION_BIT_EDIT_OWNED;
+
+ for (ii = 0; ii < G_N_ELEMENTS (predefined_levels) - 1; ii++) {
+ if (predefined_levels[ii].rights == rights) {
+ break;
+ }
+ }
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (widgets->level_combo), ii);
+ }
+ } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->write_edit_all_check))) {
+ gtk_widget_set_sensitive (widgets->write_edit_own_check, FALSE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widgets->write_edit_own_check), TRUE);
+ }
+
+ if (widgets->read_fb_simple_check && widgets->read_fb_detail_check) {
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->read_fb_detail_check)) &&
+ gtk_widget_get_sensitive (widgets->read_fb_detail_check)) {
+ gtk_widget_set_sensitive (widgets->read_fb_simple_check, TRUE);
+ } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widgets->read_fb_detail_check))) {
+ gtk_widget_set_sensitive (widgets->read_fb_simple_check, FALSE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widgets->read_fb_simple_check), TRUE);
+ }
+ }
+
+ update_folder_permissions_tree_view (dialog, widgets);
+
+ widgets->updating = FALSE;
+}
+
+static void
+update_permission_dialog_by_level_combo (GObject *dialog)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ uint32_t rights;
+ gint ii;
+
+ g_return_if_fail (dialog != NULL);
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+
+ if (widgets->updating)
+ return;
+
+ ii = gtk_combo_box_get_active (GTK_COMBO_BOX (widgets->level_combo));
+ if (ii < 0 || ii >= G_N_ELEMENTS (predefined_levels) - 1)
+ return;
+
+ rights = folder_permissions_dialog_to_rights (dialog);
+ rights = predefined_levels[ii].rights | (rights & (E_MAPI_PERMISSION_BIT_FREE_BUSY_DETAILED |
+ E_MAPI_PERMISSION_BIT_FREE_BUSY_SIMPLE));
+
+ widgets->updating = TRUE;
+ update_folder_permissions_by_rights (dialog, rights);
+ update_folder_permissions_tree_view (dialog, widgets);
+ widgets->updating = FALSE;
+}
+
+static void
+add_button_clicked_cb (GObject *dialog)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ gchar *display_name = NULL;
+ struct SBinary_short *entry_id = NULL;
+ EMapiGalUserType user_type = E_MAPI_GAL_USER_NONE;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_if_fail (dialog != NULL);
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+
+ if (widgets->updating)
+ return;
+
+ g_return_if_fail (widgets->tree_view != NULL);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widgets->tree_view));
+ g_return_if_fail (model != NULL);
+
+ if (e_mapi_search_gal_user_modal (GTK_WINDOW (dialog), widgets->conn, NULL, &user_type, &display_name, NULL, NULL, &entry_id)) {
+ EMapiPermissionEntry *pem;
+ GtkTreeSelection *selection;
+ gboolean found = FALSE;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widgets->tree_view));
+ g_return_if_fail (selection != NULL);
+
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ do {
+ EMapiGalUserType ut = E_MAPI_GAL_USER_NONE;
+
+ pem = NULL;
+
+ gtk_tree_model_get (model, &iter,
+ COL_E_MAPI_PERMISSION_ENTRY, &pem,
+ COL_E_MAPI_GAL_USER_TYPE, &ut,
+ -1);
+
+ if ((ut != E_MAPI_GAL_USER_REGULAR && ut == user_type) ||
+ (ut == E_MAPI_GAL_USER_REGULAR && pem && e_mapi_util_recip_entryid_equal (&pem->entry_id, entry_id))) {
+ gtk_tree_selection_select_iter (selection, &iter);
+ found = TRUE;
+ break;
+ }
+ } while (gtk_tree_model_iter_next (model, &iter));
+ }
+
+ if (!found) {
+ GtkListStore *store = GTK_LIST_STORE (model);
+
+ pem = e_mapi_permission_entry_new (display_name, entry_id,
+ user_type == E_MAPI_GAL_USER_ANONYMOUS ? E_MAPI_PERMISSION_MEMBER_ID_ANONYMOUS_CLIENT :
+ user_type == E_MAPI_GAL_USER_DEFAULT ? E_MAPI_PERMISSION_MEMBER_ID_DEFAULT_USER : 0,
+ user_type == E_MAPI_GAL_USER_ANONYMOUS ? 0 : E_MAPI_PERMISSION_BIT_FREE_BUSY_SIMPLE);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_NAME, pem->username,
+ COL_PERMISSION_LEVEL, g_dgettext ("PermissionsLevel", predefined_levels[0].name),
+ COL_E_MAPI_PERMISSION_ENTRY, pem,
+ COL_E_MAPI_GAL_USER_TYPE, user_type,
+ COL_IS_NEW, TRUE,
+ -1);
+
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
+ }
+
+ g_free (display_name);
+ if (entry_id) {
+ g_free (entry_id->lpb);
+ g_free (entry_id);
+ }
+}
+
+static void
+remove_button_clicked_cb (GObject *dialog)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model = NULL;
+ GtkTreeIter iter;
+
+ g_return_if_fail (dialog != NULL);
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+
+ if (widgets->updating)
+ return;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widgets->tree_view));
+ if (selection && gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ GtkTreeIter select;
+ gboolean can_select = FALSE;
+ EMapiPermissionEntry *pem = NULL;
+
+ select = iter;
+ can_select = gtk_tree_model_iter_next (model, &select);
+ if (!can_select) {
+ select = iter;
+ can_select = gtk_tree_model_iter_previous (model, &select);
+ }
+
+ if (can_select)
+ gtk_tree_selection_select_iter (selection, &select);
+
+ gtk_tree_model_get (model, &iter, COL_E_MAPI_PERMISSION_ENTRY, &pem, -1);
+
+ if (gtk_list_store_remove (GTK_LIST_STORE (model), &iter))
+ e_mapi_permission_entry_free (pem);
+ }
+}
+
+static void
+folder_permissions_free_found_entries (gpointer ptr)
+{
+ GSList **entries = ptr;
+
+ if (!entries)
+ return;
+
+ g_slist_free_full (*entries, (GDestroyNotify) e_mapi_permission_entry_free);
+ *entries = NULL;
+ g_free (entries);
+}
+
+static void
+read_folder_permissions_thread (GObject *dialog,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ mapi_object_t obj_folder;
+ gboolean opened;
+ GSList **pentries = user_data;
+
+ g_return_if_fail (dialog != NULL);
+ g_return_if_fail (pentries != NULL);
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+ g_return_if_fail (widgets->login_profile != NULL);
+ g_return_if_fail (widgets->login_username != NULL);
+ g_return_if_fail (widgets->login_url != NULL);
+
+ widgets->conn = e_mapi_account_open_connection_for (GTK_WINDOW (dialog),
+ widgets->login_profile,
+ widgets->login_username,
+ widgets->login_url,
+ cancellable,
+ perror);
+
+ if (!widgets->conn)
+ g_cancellable_cancel (cancellable);
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ if (widgets->folder_category == E_MAPI_FOLDER_CATEGORY_FOREIGN)
+ opened = e_mapi_connection_open_foreign_folder (widgets->conn, widgets->foreign_username, widgets->folder_id, &obj_folder, cancellable, perror);
+ else if (widgets->folder_category == E_MAPI_FOLDER_CATEGORY_PUBLIC)
+ opened = e_mapi_connection_open_public_folder (widgets->conn, widgets->folder_id, &obj_folder, cancellable, perror);
+ else
+ opened = e_mapi_connection_open_personal_folder (widgets->conn, widgets->folder_id, &obj_folder, cancellable, perror);
+
+ if (opened) {
+ e_mapi_connection_get_permissions (widgets->conn, &obj_folder, widgets->read_fb_simple_check != NULL, pentries, cancellable, perror);
+ e_mapi_connection_close_folder (widgets->conn, &obj_folder, cancellable, perror);
+ }
+}
+
+static void
+read_folder_permissions_idle (GObject *dialog,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ GSList **pentries = user_data;
+ GSList *entry;
+ GtkListStore *store;
+ GtkTreeIter iter;
+
+ g_return_if_fail (dialog != NULL);
+ g_return_if_fail (pentries != NULL);
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ widgets = g_object_get_data (dialog, E_MAPI_PERM_DLG_WIDGETS);
+ g_return_if_fail (widgets != NULL);
+ g_return_if_fail (widgets->tree_view != NULL);
+
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (widgets->tree_view)));
+ g_return_if_fail (store != NULL);
+
+ for (entry = *pentries; entry; entry = entry->next) {
+ EMapiPermissionEntry *pem = entry->data;
+ EMapiGalUserType user_type;
+ const gchar *perm_level;
+ uint32_t rights;
+ gint ii;
+
+ if (!pem)
+ continue;
+
+ /* steal the pem */
+ entry->data = NULL;
+
+ if (!pem->username || !*pem->username) {
+ g_free (pem->username);
+
+ if (pem->member_id == E_MAPI_PERMISSION_MEMBER_ID_ANONYMOUS_CLIENT)
+ pem->username = g_strdup (C_("User", "Anonymous"));
+ else if (pem->member_id == E_MAPI_PERMISSION_MEMBER_ID_DEFAULT_USER)
+ pem->username = g_strdup (C_("User", "Default"));
+ else
+ pem->username = g_strdup (C_("User", "Unknown"));
+ }
+
+ rights = pem->member_rights;
+ rights = rights & ~(E_MAPI_PERMISSION_BIT_FREE_BUSY_DETAILED |
+ E_MAPI_PERMISSION_BIT_FREE_BUSY_SIMPLE);
+
+ for (ii = 0; ii < G_N_ELEMENTS (predefined_levels) - 1; ii++) {
+ if (predefined_levels[ii].rights == rights) {
+ break;
+ }
+ }
+
+ perm_level = g_dgettext ("PermissionsLevel", predefined_levels[ii].name);
+
+ user_type = E_MAPI_GAL_USER_REGULAR;
+ if (pem->member_id == E_MAPI_PERMISSION_MEMBER_ID_ANONYMOUS_CLIENT)
+ user_type = E_MAPI_GAL_USER_ANONYMOUS;
+ else if (pem->member_id == E_MAPI_PERMISSION_MEMBER_ID_DEFAULT_USER)
+ user_type = E_MAPI_GAL_USER_DEFAULT;
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_NAME, pem->username,
+ COL_PERMISSION_LEVEL, perm_level,
+ COL_E_MAPI_PERMISSION_ENTRY, pem,
+ COL_E_MAPI_GAL_USER_TYPE, user_type,
+ COL_IS_NEW, FALSE,
+ -1);
+ }
+
+ gtk_widget_set_sensitive (widgets->add_button, TRUE);
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (widgets->dialog), GTK_RESPONSE_OK, TRUE);
+}
+
+static void
+folder_permissions_tree_selection_changed_cb (GtkTreeSelection *selection,
+ struct EMapiPermissionsDialogWidgets *widgets)
+{
+ GObject *dialog;
+ GtkTreeModel *model = NULL;
+ GtkTreeIter iter;
+ gboolean has_selected;
+
+ g_return_if_fail (selection != NULL);
+ g_return_if_fail (widgets != NULL);
+ g_return_if_fail (widgets->dialog != NULL);
+ g_return_if_fail (widgets->add_button != NULL);
+ g_return_if_fail (widgets->remove_button != NULL);
+
+ dialog = G_OBJECT (widgets->dialog);
+ has_selected = gtk_tree_selection_get_selected (selection, &model, &iter);
+
+ gtk_widget_set_sensitive (widgets->add_button, TRUE);
+ gtk_widget_set_sensitive (widgets->remove_button, has_selected);
+
+ if (has_selected) {
+ EMapiGalUserType user_type = E_MAPI_GAL_USER_NONE;
+ EMapiPermissionEntry *pem = NULL;
+
+ gtk_tree_model_get (model, &iter,
+ COL_E_MAPI_PERMISSION_ENTRY, &pem,
+ COL_E_MAPI_GAL_USER_TYPE, &user_type,
+ -1);
+
+ update_folder_permissions_sensitivity (dialog, pem != NULL, user_type);
+ update_folder_permissions_by_rights (dialog, pem ? pem->member_rights : 0);
+ } else {
+ update_folder_permissions_sensitivity (dialog, FALSE, E_MAPI_GAL_USER_NONE);
+ update_folder_permissions_by_rights (dialog, 0);
+ }
+
+ update_permission_level_combo_by_dialog (dialog);
+}
+
+static GtkWidget *
+create_permissions_tree_view (GObject *dialog,
+ struct EMapiPermissionsDialogWidgets *widgets)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ gint pos;
+
+ g_return_val_if_fail (widgets != NULL, NULL);
+
+ tree_view = GTK_TREE_VIEW (gtk_tree_view_new_with_model (
+ GTK_TREE_MODEL (gtk_list_store_new (5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_BOOLEAN))));
+
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "editable", FALSE, NULL);
+ pos = gtk_tree_view_insert_column_with_attributes (tree_view, -1, _("Name"), renderer, "text", COL_NAME, NULL);
+ column = gtk_tree_view_get_column (tree_view, pos - 1);
+ gtk_tree_view_column_set_expand (column, TRUE);
+
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "editable", FALSE, NULL);
+ gtk_tree_view_insert_column_with_attributes (tree_view, -1, _("Permission level"), renderer, "text", COL_PERMISSION_LEVEL, NULL);
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+ g_signal_connect (selection, "changed", G_CALLBACK (folder_permissions_tree_selection_changed_cb), widgets);
+
+ widgets->tree_view = GTK_WIDGET (tree_view);
+
+ return widgets->tree_view;
+}
+
+/* Opens dialog to subscribe to folders of other
+ users in the given store */
+void
+e_mapi_edit_folder_permissions (GtkWindow *parent,
+ const gchar *login_profile,
+ const gchar *login_username,
+ const gchar *login_url,
+ const gchar *account_name,
+ const gchar *folder_name,
+ mapi_id_t folder_id,
+ EMapiFolderCategory folder_category,
+ const gchar *foreign_username,
+ gboolean with_freebusy)
+{
+ struct EMapiPermissionsDialogWidgets *widgets;
+ PangoAttrList *attrs;
+ GObject *dialog;
+ GtkWidget *content;
+ GtkWidget *label, *widget, *button, *frame, *hvbox;
+ GtkScrolledWindow *scrolled_window;
+ GtkComboBoxText *combo_text;
+ GtkGrid *grid;
+ GSList *radio_group, **found_entries;
+ gchar *str;
+ gint row, ii;
+
+ g_return_if_fail (login_profile != NULL);
+ g_return_if_fail (login_username != NULL);
+ g_return_if_fail (login_url != NULL);
+ g_return_if_fail (account_name != NULL);
+ g_return_if_fail (folder_name != NULL);
+ g_return_if_fail (folder_id != 0);
+
+ widgets = g_new0 (struct EMapiPermissionsDialogWidgets, 1);
+ widgets->login_profile = g_strdup (login_profile);
+ widgets->login_username = g_strdup (login_username);
+ widgets->login_url = g_strdup (login_url);
+ widgets->folder_id = folder_id;
+ widgets->folder_category = folder_category;
+ widgets->foreign_username = g_strdup (foreign_username);
+
+ widgets->dialog = gtk_dialog_new_with_buttons (
+ _("Edit MAPI folder permissions..."),
+ parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
+
+ dialog = G_OBJECT (widgets->dialog);
+ g_signal_connect (dialog, "response", G_CALLBACK (edit_permissions_response_cb), NULL);
+ g_object_set_data_full (dialog, E_MAPI_PERM_DLG_WIDGETS, widgets, edit_permissions_widgets_free);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+ grid = GTK_GRID (gtk_grid_new ());
+ gtk_grid_set_row_homogeneous (grid, FALSE);
+ gtk_grid_set_row_spacing (grid, 6);
+ gtk_grid_set_column_homogeneous (grid, FALSE);
+ gtk_grid_set_column_spacing (grid, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
+ gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid));
+
+ row = 0;
+
+ label = gtk_label_new (_("Account:"));
+ g_object_set (G_OBJECT (label),
+ "hexpand", FALSE,
+ "vexpand", FALSE,
+ "xalign", 0.0,
+ "halign", GTK_ALIGN_START,
+ NULL);
+
+ attrs = pango_attr_list_new ();
+ pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+ widget = gtk_label_new (account_name);
+ g_object_set (G_OBJECT (widget),
+ "hexpand", TRUE,
+ "vexpand", FALSE,
+ "use-underline", FALSE,
+ "attributes", attrs,
+ "xalign", 0.0,
+ "halign", GTK_ALIGN_START,
+ NULL);
+ pango_attr_list_unref (attrs);
+
+ gtk_grid_attach (grid, label, 0, row, 1, 1);
+ gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+ row++;
+
+ label = gtk_label_new (_("Folder name:"));
+ g_object_set (G_OBJECT (label),
+ "hexpand", FALSE,
+ "vexpand", FALSE,
+ "xalign", 0.0,
+ NULL);
+
+ widget = gtk_label_new (folder_name);
+ gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_MIDDLE);
+ gtk_widget_set_tooltip_text (widget, folder_name);
+ g_object_set (G_OBJECT (widget),
+ "hexpand", TRUE,
+ "vexpand", FALSE,
+ "xalign", 0.0,
+ NULL);
+
+ gtk_grid_attach (grid, label, 0, row, 1, 1);
+ gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+ row++;
+
+ label = gtk_label_new (_("Folder ID:"));
+ g_object_set (G_OBJECT (label),
+ "hexpand", FALSE,
+ "vexpand", FALSE,
+ "xalign", 0.0,
+ NULL);
+
+ str = e_mapi_util_mapi_id_to_string (folder_id);
+ widget = gtk_label_new (str);
+ g_free (str);
+ g_object_set (G_OBJECT (widget),
+ "hexpand", TRUE,
+ "vexpand", FALSE,
+ "xalign", 0.0,
+ "selectable", TRUE,
+ NULL);
+
+ gtk_grid_attach (grid, label, 0, row, 1, 1);
+ gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+ row++;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ scrolled_window = GTK_SCROLLED_WINDOW (widget);
+ gtk_scrolled_window_set_min_content_width (scrolled_window, 120);
+ gtk_scrolled_window_set_min_content_height (scrolled_window, 120);
+ gtk_container_add (GTK_CONTAINER (widget), create_permissions_tree_view (dialog, widgets));
+ g_object_set (G_OBJECT (widget),
+ "hexpand", TRUE,
+ "vexpand", TRUE,
+ "shadow-type", GTK_SHADOW_IN,
+ NULL);
+
+ gtk_grid_attach (grid, widget, 0, row, 2, 1);
+
+ row++;
+
+ hvbox = gtk_grid_new ();
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_HORIZONTAL);
+ gtk_grid_set_column_spacing (GTK_GRID (hvbox), 6);
+ gtk_grid_set_column_homogeneous (GTK_GRID (hvbox), TRUE);
+ g_object_set (G_OBJECT (hvbox),
+ "hexpand", FALSE,
+ "vexpand", FALSE,
+ "halign", GTK_ALIGN_END,
+ NULL);
+
+ button = gtk_button_new_from_stock (GTK_STOCK_ADD);
+ widgets->add_button = button;
+ gtk_container_add (GTK_CONTAINER (hvbox), button);
+
+ button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+ widgets->remove_button = button;
+ gtk_container_add (GTK_CONTAINER (hvbox), button);
+
+ gtk_grid_attach (grid, hvbox, 0, row, 2, 1);
+
+ row++;
+
+ widget = gtk_frame_new (_("Permissions"));
+ g_object_set (G_OBJECT (widget),
+ "hexpand", TRUE,
+ "vexpand", FALSE,
+ NULL);
+ gtk_grid_attach (grid, widget, 0, row, 2, 1);
+
+ grid = GTK_GRID (gtk_grid_new ());
+ gtk_grid_set_row_homogeneous (grid, FALSE);
+ gtk_grid_set_row_spacing (grid, 6);
+ gtk_grid_set_column_homogeneous (grid, FALSE);
+ gtk_grid_set_column_spacing (grid, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
+ gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (grid));
+
+ row = 0;
+
+ hvbox = gtk_grid_new ();
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_HORIZONTAL);
+ gtk_grid_set_column_spacing (GTK_GRID (hvbox), 6);
+
+ label = gtk_label_new_with_mnemonic (_("Permi_ssion level:"));
+ g_object_set (G_OBJECT (label),
+ "hexpand", FALSE,
+ "vexpand", FALSE,
+ "xalign", 0.0,
+ NULL);
+
+ widget = GTK_WIDGET (g_object_new (gtk_combo_box_text_get_type (),
+ "has-entry", FALSE,
+ "entry-text-column", 0,
+ "hexpand", TRUE,
+ "vexpand", FALSE,
+ NULL));
+ widgets->level_combo = widget;
+
+ combo_text = GTK_COMBO_BOX_TEXT (widget);
+ for (ii = 0; ii < G_N_ELEMENTS (predefined_levels); ii++)
+ gtk_combo_box_text_append_text (combo_text, g_dgettext ("PermissionsLevel", predefined_levels[ii].name));
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_text), 0);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
+ gtk_container_add (GTK_CONTAINER (hvbox), label);
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ gtk_grid_attach (grid, hvbox, 0, row, 2, 1);
+
+ row++;
+
+ frame = gtk_frame_new (C_("Permissions", "Read"));
+ g_object_set (G_OBJECT (frame),
+ "hexpand", FALSE,
+ "vexpand", FALSE,
+ NULL);
+
+ hvbox = gtk_grid_new ();
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_VERTICAL);
+ gtk_grid_set_column_spacing (GTK_GRID (hvbox), 2);
+ gtk_container_add (GTK_CONTAINER (frame), hvbox);
+
+ widget = gtk_radio_button_new_with_label (NULL, C_("Permissions", "None"));
+ widgets->read_none_radio = widget;
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ widget = gtk_radio_button_new_with_label (radio_group, C_("Permissions", "Full Details"));
+ widgets->read_full_radio = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ if (with_freebusy) {
+ widget = gtk_check_button_new_with_label (C_("Permissions", "Simple Free/Busy"));
+ widgets->read_fb_simple_check = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ widget = gtk_check_button_new_with_label (C_("Permissions", "Detailed Free/Busy"));
+ widgets->read_fb_detail_check = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+ }
+
+ gtk_grid_attach (grid, frame, 0, row, 1, 1);
+
+ frame = gtk_frame_new (C_("Permissions", "Write"));
+ g_object_set (G_OBJECT (frame),
+ "hexpand", FALSE,
+ "vexpand", FALSE,
+ NULL);
+
+ hvbox = gtk_grid_new ();
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_VERTICAL);
+ gtk_grid_set_column_spacing (GTK_GRID (hvbox), 2);
+ gtk_container_add (GTK_CONTAINER (frame), hvbox);
+
+ widget = gtk_check_button_new_with_label (C_("Permissions", "Create items"));
+ widgets->write_create_items_check = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ widget = gtk_check_button_new_with_label (C_("Permissions", "Create subfolders"));
+ widgets->write_create_subfolders_check = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ widget = gtk_check_button_new_with_label (C_("Permissions", "Edit own"));
+ widgets->write_edit_own_check = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ widget = gtk_check_button_new_with_label (C_("Permissions", "Edit all"));
+ widgets->write_edit_all_check = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ gtk_grid_attach (grid, frame, 1, row, 1, 1);
+
+ row++;
+
+ frame = gtk_frame_new (C_("Permissions", "Delete items"));
+ g_object_set (G_OBJECT (frame),
+ "hexpand", FALSE,
+ "vexpand", FALSE,
+ NULL);
+
+ hvbox = gtk_grid_new ();
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_VERTICAL);
+ gtk_grid_set_column_spacing (GTK_GRID (hvbox), 2);
+ gtk_container_add (GTK_CONTAINER (frame), hvbox);
+
+ widget = gtk_radio_button_new_with_label (NULL, C_("Permissions", "None"));
+ widgets->delete_none_radio = widget;
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ widget = gtk_radio_button_new_with_label (radio_group, C_("Permissions", "Own"));
+ widgets->delete_own_radio = widget;
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ widget = gtk_radio_button_new_with_label (radio_group, C_("Permissions", "All"));
+ widgets->delete_all_radio = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ gtk_grid_attach (grid, frame, 0, row, 1, 1);
+
+ frame = gtk_frame_new (C_("Permissions", "Other"));
+ g_object_set (G_OBJECT (frame),
+ "hexpand", FALSE,
+ "vexpand", FALSE,
+ NULL);
+
+ hvbox = gtk_grid_new ();
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (hvbox), GTK_ORIENTATION_VERTICAL);
+ gtk_grid_set_column_spacing (GTK_GRID (hvbox), 2);
+ gtk_container_add (GTK_CONTAINER (frame), hvbox);
+
+ widget = gtk_check_button_new_with_label (C_("Permissions", "Folder owner"));
+ widgets->other_folder_owner_check = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ widget = gtk_check_button_new_with_label (C_("Permissions", "Folder contact"));
+ widgets->other_folder_contact_check = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ widget = gtk_check_button_new_with_label (C_("Permissions", "Folder visible"));
+ widgets->other_folder_visible_check = widget;
+ gtk_container_add (GTK_CONTAINER (hvbox), widget);
+
+ gtk_grid_attach (grid, frame, 1, row, 1, 1);
+
+ row++;
+
+ g_signal_connect_swapped (widgets->add_button,
+ "clicked", G_CALLBACK (add_button_clicked_cb), dialog);
+ g_signal_connect_swapped (widgets->remove_button,
+ "clicked", G_CALLBACK (remove_button_clicked_cb), dialog);
+ g_signal_connect_swapped (widgets->level_combo,
+ "changed", G_CALLBACK (update_permission_dialog_by_level_combo), dialog);
+ g_signal_connect_swapped (widgets->read_none_radio,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->read_full_radio,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ if (widgets->read_fb_simple_check)
+ g_signal_connect_swapped (widgets->read_fb_simple_check,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ if (widgets->read_fb_detail_check)
+ g_signal_connect_swapped (widgets->read_fb_detail_check,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->write_create_items_check,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->write_create_subfolders_check,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->write_edit_own_check,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->write_edit_all_check,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->delete_none_radio,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->delete_own_radio,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->delete_all_radio,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->other_folder_owner_check,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->other_folder_contact_check,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+ g_signal_connect_swapped (widgets->other_folder_visible_check,
+ "toggled", G_CALLBACK (update_permission_level_combo_by_dialog), dialog);
+
+ enable_all_widgets (widgets, FALSE);
+
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (widgets->dialog), GTK_RESPONSE_OK, FALSE);
+
+ gtk_widget_show_all (content);
+ gtk_widget_show (GTK_WIDGET (dialog));
+
+ found_entries = g_new0 (GSList *, 1);
+
+ e_mapi_run_in_thread_with_feedback (GTK_WINDOW (dialog), dialog,
+ _("Reading folder permissions, please wait..."),
+ read_folder_permissions_thread,
+ read_folder_permissions_idle,
+ found_entries, folder_permissions_free_found_entries);
+}
diff --git a/src/account-setup-eplugin/e-mapi-edit-folder-permissions.h b/src/account-setup-eplugin/e-mapi-edit-folder-permissions.h
new file mode 100644
index 0000000..8e9d613
--- /dev/null
+++ b/src/account-setup-eplugin/e-mapi-edit-folder-permissions.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Milan Crha <mcrha redhat com>
+ *
+ * Copyright (C) 2012 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_MAPI_EDIT_FOLDER_PERMISSIONS_H
+#define E_MAPI_EDIT_FOLDER_PERMISSIONS_H
+
+#include <gtk/gtk.h>
+#include <libmapi/libmapi.h>
+
+#include <e-mapi-folder.h>
+
+void e_mapi_edit_folder_permissions (GtkWindow *parent,
+ const gchar *login_profile,
+ const gchar *login_username,
+ const gchar *login_url,
+ const gchar *account_name,
+ const gchar *folder_name,
+ mapi_id_t folder_id,
+ EMapiFolderCategory folder_category,
+ const gchar *foreign_username,
+ gboolean with_freebusy);
+
+#endif /* E_MAPI_EDIT_FOLDER_PERMISSIONS_H */
diff --git a/src/account-setup-eplugin/e-mapi-search-gal-user.c b/src/account-setup-eplugin/e-mapi-search-gal-user.c
new file mode 100644
index 0000000..dc3ac5e
--- /dev/null
+++ b/src/account-setup-eplugin/e-mapi-search-gal-user.c
@@ -0,0 +1,756 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Milan Crha <mcrha redhat com>
+ *
+ * Copyright (C) 2012 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+
+#include "e-mapi-account-setup.h"
+#include "e-mapi-search-gal-user.h"
+#include "e-mapi-utils.h"
+#include "e-mapi-defs.h"
+
+#define E_MAPI_SEARCH_DLG_DATA "e-mapi-search-dlg-data"
+
+enum {
+ COL_DISPLAY_NAME = 0,
+ COL_EMAIL,
+ COL_USER_DN,
+ COL_ENTRY_ID,
+ COL_USER_TYPE
+};
+
+struct EMapiSearchGalUserData
+{
+ EMapiConnection *conn;
+ GCancellable *cancellable;
+ gchar *search_text;
+ guint32 search_extra;
+ GtkWidget *tree_view;
+ GtkWidget *info_label;
+ guint schedule_search_id;
+};
+
+static void
+e_mapi_search_gal_user_data_free (gpointer ptr)
+{
+ struct EMapiSearchGalUserData *pgu = ptr;
+
+ if (!pgu)
+ return;
+
+ if (pgu->schedule_search_id) {
+ g_source_remove (pgu->schedule_search_id);
+ pgu->schedule_search_id = 0;
+ }
+ if (pgu->cancellable) {
+ g_cancellable_cancel (pgu->cancellable);
+ g_object_unref (pgu->cancellable);
+ pgu->cancellable = NULL;
+ }
+ g_object_unref (pgu->conn);
+ g_free (pgu->search_text);
+ g_free (pgu);
+}
+
+struct EMapiGalSearchUser
+{
+ gchar *display_name;
+ gchar *email;
+ gchar *dn;
+ struct SBinary_short *entry_id;
+};
+
+static void
+e_mapi_search_gal_user_free (gpointer ptr)
+{
+ struct EMapiGalSearchUser *user = ptr;
+
+ if (!user)
+ return;
+
+ g_free (user->display_name);
+ g_free (user->email);
+ g_free (user->dn);
+ if (user->entry_id)
+ g_free (user->entry_id->lpb);
+ g_free (user->entry_id);
+ g_free (user);
+}
+
+struct EMapiSearchIdleData
+{
+ EMapiConnection *conn;
+ gchar *search_text;
+ GCancellable *cancellable;
+
+ GObject *dialog;
+ GSList *found_users; /* struct EMapiGalSearchUser * */
+ guint found_total;
+};
+
+static void
+e_mapi_search_idle_data_free (gpointer ptr)
+{
+ struct EMapiSearchIdleData *sid = ptr;
+
+ if (!sid)
+ return;
+
+ g_object_unref (sid->conn);
+ g_object_unref (sid->cancellable);
+ g_free (sid->search_text);
+ g_slist_free_full (sid->found_users, e_mapi_search_gal_user_free);
+ g_free (sid);
+}
+
+static void
+empty_search_gal_tree_view (GtkWidget *tree_view)
+{
+ GtkListStore *store;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ struct SBinary_short *entry_id;
+
+ g_return_if_fail (tree_view != NULL);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+ g_return_if_fail (model != NULL);
+
+ store = GTK_LIST_STORE (model);
+ g_return_if_fail (store != NULL);
+
+ if (!gtk_tree_model_get_iter_first (model, &iter))
+ return;
+
+ do {
+ entry_id = NULL;
+ gtk_tree_model_get (model, &iter,
+ COL_ENTRY_ID, &entry_id,
+ -1);
+
+ if (entry_id) {
+ g_free (entry_id->lpb);
+ g_free (entry_id);
+ }
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ gtk_list_store_clear (store);
+}
+
+static void
+search_gal_add_user (GtkListStore *store,
+ const gchar *display_name,
+ const gchar *email,
+ const gchar *user_dn,
+ struct SBinary_short *entry_id, /* takes ownership of the pointer */
+ EMapiGalUserType user_type)
+{
+ GtkTreeIter iter;
+
+ g_return_if_fail (store != NULL);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_DISPLAY_NAME, display_name,
+ COL_EMAIL, email,
+ COL_USER_DN, user_dn,
+ COL_ENTRY_ID, entry_id,
+ COL_USER_TYPE, user_type,
+ -1);
+}
+
+static gboolean
+search_gal_finish_idle (gpointer user_data)
+{
+ struct EMapiSearchIdleData *sid = user_data;
+
+ g_return_val_if_fail (sid != NULL, FALSE);
+ g_return_val_if_fail (sid->dialog != NULL, FALSE);
+
+ if (!g_cancellable_is_cancelled (sid->cancellable)) {
+ struct EMapiSearchGalUserData *pgu;
+ GtkListStore *store;
+ guint added = 0;
+ GSList *fu;
+
+ pgu = g_object_get_data (sid->dialog, E_MAPI_SEARCH_DLG_DATA);
+ g_return_val_if_fail (pgu != NULL, FALSE);
+ g_return_val_if_fail (pgu->tree_view != NULL, FALSE);
+ g_return_val_if_fail (pgu->info_label != NULL, FALSE);
+
+ empty_search_gal_tree_view (pgu->tree_view);
+
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (pgu->tree_view)));
+ g_return_val_if_fail (store != NULL, FALSE);
+
+ for (fu = sid->found_users; fu; fu = fu->next) {
+ struct EMapiGalSearchUser *user = fu->data;
+
+ if (!user)
+ continue;
+
+ search_gal_add_user (store, user->display_name, user->email, user->dn, user->entry_id, E_MAPI_GAL_USER_REGULAR);
+ user->entry_id = NULL;
+
+ added++;
+ }
+
+ if (!added) {
+ gtk_label_set_text (GTK_LABEL (pgu->info_label), _("No users found"));
+ } else if (added == sid->found_total) {
+ gchar *str;
+ str = g_strdup_printf (ngettext ("Found one user", "Found %d users", added), added);
+ gtk_label_set_text (GTK_LABEL (pgu->info_label), str);
+ g_free (str);
+ } else {
+ gchar *str;
+ str = g_strdup_printf (ngettext ("Found %d users, but showing only first %d", "Found %d users, but showing only first %d", sid->found_total), sid->found_total, added);
+ gtk_label_set_text (GTK_LABEL (pgu->info_label), str);
+ g_free (str);
+ }
+ }
+
+ e_mapi_search_idle_data_free (sid);
+
+ return FALSE;
+}
+
+static gboolean
+build_gal_search_restriction_cb (EMapiConnection *conn,
+ TALLOC_CTX *mem_ctx,
+ struct mapi_SRestriction **restrictions,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
+{
+ const gchar *search_text = user_data;
+ struct mapi_SRestriction *restriction;
+
+ g_return_val_if_fail (mem_ctx != NULL, FALSE);
+ g_return_val_if_fail (restrictions != NULL, FALSE);
+ g_return_val_if_fail (search_text != NULL, FALSE);
+ g_return_val_if_fail (*search_text, FALSE);
+
+ restriction = talloc_zero (mem_ctx, struct mapi_SRestriction);
+ g_return_val_if_fail (restriction != NULL, FALSE);
+
+ restriction->rt = RES_OR;
+ restriction->res.resOr.cRes = 2;
+ restriction->res.resOr.res = talloc_zero_array (mem_ctx, struct mapi_SRestriction_or, restriction->res.resOr.cRes + 1);
+
+ restriction->res.resOr.res[0].rt = RES_CONTENT;
+ restriction->res.resOr.res[0].res.resContent.fuzzy = FL_SUBSTRING | FL_IGNORECASE;
+ restriction->res.resOr.res[0].res.resContent.ulPropTag = PidTagDisplayName;
+ restriction->res.resOr.res[0].res.resContent.lpProp.ulPropTag = PidTagDisplayName;
+ restriction->res.resOr.res[0].res.resContent.lpProp.value.lpszW = talloc_strdup (mem_ctx, search_text);
+
+ restriction->res.resOr.res[1].rt = RES_CONTENT;
+ restriction->res.resOr.res[1].res.resContent.fuzzy = FL_SUBSTRING | FL_IGNORECASE;
+ restriction->res.resOr.res[1].res.resContent.ulPropTag = PidTagPrimarySmtpAddress;
+ restriction->res.resOr.res[1].res.resContent.lpProp.ulPropTag = PidTagPrimarySmtpAddress;
+ restriction->res.resOr.res[1].res.resContent.lpProp.value.lpszW = talloc_strdup (mem_ctx, search_text);
+
+ *restrictions = restriction;
+
+ return TRUE;
+}
+
+static gboolean
+list_gal_search_mids_cb (EMapiConnection *conn,
+ TALLOC_CTX *mem_ctx,
+ const ListObjectsData *object_data,
+ guint32 obj_index,
+ guint32 obj_total,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
+{
+ g_return_val_if_fail (object_data != NULL, FALSE);
+ g_return_val_if_fail (user_data != NULL, FALSE);
+
+ if (object_data->obj_type == MAPI_MAILUSER) {
+ GSList **pmids = user_data;
+ mapi_id_t *mid;
+
+ mid = g_new0 (mapi_id_t, 1);
+ *mid = object_data->mid;
+
+ *pmids = g_slist_prepend (*pmids, mid);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+search_gal_build_properties_cb (EMapiConnection *conn,
+ TALLOC_CTX *mem_ctx,
+ struct SPropTagArray *props,
+ gpointer data,
+ GCancellable *cancellable,
+ GError **perror)
+{
+ g_return_val_if_fail (mem_ctx != NULL, FALSE);
+ g_return_val_if_fail (props != NULL, FALSE);
+
+ SPropTagArray_add (mem_ctx, props, PidTagEntryId);
+ SPropTagArray_add (mem_ctx, props, PidTagDisplayName);
+ SPropTagArray_add (mem_ctx, props, PidTagPrimarySmtpAddress);
+ SPropTagArray_add (mem_ctx, props, PidTagEmailAddress);
+
+ return TRUE;
+}
+
+static gboolean
+transfer_gal_search_objects_cb (EMapiConnection *conn,
+ TALLOC_CTX *mem_ctx,
+ /* const */ EMapiObject *object,
+ guint32 obj_index,
+ guint32 obj_total,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
+{
+
+ struct EMapiSearchIdleData *sid = user_data;
+ const gchar *display_name, *email, *user_dn;
+ const struct SBinary_short *entry_id;
+
+ g_return_val_if_fail (object != NULL, FALSE);
+ g_return_val_if_fail (sid != NULL, FALSE);
+
+ display_name = e_mapi_util_find_array_propval (&object->properties, PidTagDisplayName);
+ email = e_mapi_util_find_array_propval (&object->properties, PidTagPrimarySmtpAddress);
+ entry_id = e_mapi_util_find_array_propval (&object->properties, PidTagEntryId);
+ user_dn = e_mapi_util_find_array_propval (&object->properties, PidTagEmailAddress);
+
+ if (entry_id && (display_name || email)) {
+ struct EMapiGalSearchUser *user;
+
+ user = g_new0 (struct EMapiGalSearchUser, 1);
+ user->display_name = g_strdup (display_name);
+ user->email = g_strdup (email);
+ user->dn = g_strdup (user_dn);
+ user->entry_id = g_new0 (struct SBinary_short, 1);
+ user->entry_id->cb = entry_id->cb;
+ if (entry_id->cb > 0)
+ user->entry_id->lpb = g_memdup (entry_id->lpb, entry_id->cb);
+
+ sid->found_users = g_slist_prepend (sid->found_users, user);
+ }
+
+ return TRUE;
+}
+
+static gint
+sort_mids_by_id (gconstpointer pmid1, gconstpointer pmid2)
+{
+ const mapi_id_t *mid1 = pmid1, *mid2 = pmid2;
+
+ if (!mid1 && !mid2)
+ return 0;
+
+ if (!mid1)
+ return -1;
+ if (!mid2)
+ return 1;
+
+ /* simple subtract *mid1 - *mid2 may overflow gint */
+ if (*mid1 < *mid2)
+ return -1;
+ if (*mid1 > *mid2)
+ return 1;
+ return 0;
+}
+
+static gpointer
+search_gal_thread (gpointer user_data)
+{
+ struct EMapiSearchIdleData *sid = user_data;
+
+ g_return_val_if_fail (sid != NULL, NULL);
+
+ if (!g_cancellable_is_cancelled (sid->cancellable)) {
+ GError *error = NULL;
+ GSList *mids = NULL;
+
+ if (e_mapi_connection_list_gal_objects (sid->conn,
+ build_gal_search_restriction_cb, sid->search_text,
+ list_gal_search_mids_cb, &mids,
+ sid->cancellable, &error)) {
+ mids = g_slist_sort (mids, sort_mids_by_id);
+ sid->found_total = g_slist_length (mids);
+ if (sid->found_total > 30) {
+ GSList *tmp = mids, *iter;
+ gint count;
+
+ mids = NULL;
+ for (iter = tmp, count = 0; iter && count < 30; iter = iter->next, count++) {
+ mids = g_slist_prepend (mids, iter->data);
+ iter->data = NULL;
+ }
+
+ g_slist_free_full (tmp, g_free);
+
+ mids = g_slist_reverse (mids);
+ }
+
+ if (mids) {
+ e_mapi_connection_transfer_gal_objects (sid->conn, mids,
+ search_gal_build_properties_cb, NULL,
+ transfer_gal_search_objects_cb, sid,
+ sid->cancellable, &error);
+
+ g_slist_free_full (mids, g_free);
+ }
+
+ sid->found_users = g_slist_reverse (sid->found_users);
+ }
+
+ if (error &&
+ !g_error_matches (error, E_MAPI_ERROR, MAPI_E_USER_CANCEL) &&
+ !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_warning ("%s: Failed to search GAL: %s", G_STRFUNC, error->message);
+ }
+
+ g_clear_error (&error);
+
+ g_idle_add (search_gal_finish_idle, sid);
+ } else {
+ e_mapi_search_idle_data_free (sid);
+ }
+
+ return NULL;
+}
+
+static gboolean
+schedule_search_cb (gpointer user_data)
+{
+ struct EMapiSearchIdleData *sid = user_data;
+
+ g_return_val_if_fail (sid != NULL, FALSE);
+ g_return_val_if_fail (sid->dialog != NULL, FALSE);
+
+ if (!g_cancellable_is_cancelled (sid->cancellable)) {
+ struct EMapiSearchGalUserData *pgu;
+ GError *error = NULL;
+
+ pgu = g_object_get_data (sid->dialog, E_MAPI_SEARCH_DLG_DATA);
+ g_return_val_if_fail (pgu != NULL, FALSE);
+ g_return_val_if_fail (pgu->tree_view != NULL, FALSE);
+
+ pgu->schedule_search_id = 0;
+ sid->conn = g_object_ref (pgu->conn);
+ sid->search_text = g_strdup (pgu->search_text);
+
+ if (g_thread_create (search_gal_thread, sid, FALSE, &error)) {
+ sid = NULL;
+ } else {
+ g_object_unref (sid->conn);
+ g_warning ("%s: Failed to create search thread: %s", G_STRFUNC, error ? error->message : "Unknown error");
+ }
+
+ g_clear_error (&error);
+ }
+
+ e_mapi_search_idle_data_free (sid);
+
+ return FALSE;
+}
+
+static void
+search_term_changed_cb (GtkEntry *entry,
+ GObject *dialog)
+{
+ struct EMapiSearchGalUserData *pgu;
+
+ g_return_if_fail (dialog != NULL);
+
+ pgu = g_object_get_data (dialog, E_MAPI_SEARCH_DLG_DATA);
+ g_return_if_fail (pgu != NULL);
+ g_return_if_fail (pgu->tree_view != NULL);
+
+ if (pgu->schedule_search_id) {
+ g_source_remove (pgu->schedule_search_id);
+ pgu->schedule_search_id = 0;
+ }
+
+ if (pgu->cancellable) {
+ g_cancellable_cancel (pgu->cancellable);
+ g_object_unref (pgu->cancellable);
+ }
+
+ pgu->cancellable = g_cancellable_new ();
+
+ if (entry) {
+ g_free (pgu->search_text);
+ pgu->search_text = g_strdup (gtk_entry_get_text (entry));
+ }
+
+ empty_search_gal_tree_view (pgu->tree_view);
+
+ if (!pgu->search_text || !*pgu->search_text) {
+ GtkListStore *store;
+
+ gtk_label_set_text (GTK_LABEL (pgu->info_label), _("Search for a user"));
+
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (pgu->tree_view)));
+
+ if ((pgu->search_extra & E_MAPI_GAL_USER_DEFAULT) != 0)
+ search_gal_add_user (store, C_("User", "Default"), NULL, NULL, NULL, E_MAPI_GAL_USER_DEFAULT);
+
+ if ((pgu->search_extra & E_MAPI_GAL_USER_ANONYMOUS) != 0)
+ search_gal_add_user (store, C_("User", "Anonymous"), NULL, NULL, NULL, E_MAPI_GAL_USER_ANONYMOUS);
+ } else {
+ struct EMapiSearchIdleData *sid;
+
+ sid = g_new0 (struct EMapiSearchIdleData, 1);
+ sid->cancellable = g_object_ref (pgu->cancellable);
+ sid->dialog = dialog;
+
+ gtk_label_set_text (GTK_LABEL (pgu->info_label), _("Searching..."));
+ pgu->schedule_search_id = g_timeout_add (333, schedule_search_cb, sid);
+ }
+}
+
+static void
+dialog_realized_cb (GObject *dialog)
+{
+ struct EMapiSearchGalUserData *pgu;
+
+ g_return_if_fail (dialog != NULL);
+
+ pgu = g_object_get_data (dialog, E_MAPI_SEARCH_DLG_DATA);
+ g_return_if_fail (pgu != NULL);
+ g_return_if_fail (pgu->tree_view != NULL);
+
+ if (pgu->cancellable)
+ return;
+
+ search_term_changed_cb (NULL, dialog);
+}
+
+static void
+search_gal_user_selection_changed_cb (GtkTreeSelection *selection,
+ GtkDialog *dialog)
+{
+ g_return_if_fail (selection != NULL);
+ g_return_if_fail (dialog != NULL);
+
+ gtk_dialog_set_response_sensitive (dialog,
+ GTK_RESPONSE_OK,
+ gtk_tree_selection_get_selected (selection, NULL, NULL));
+}
+
+static void
+search_gal_user_row_activated_cb (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ GtkDialog *dialog)
+{
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (dialog != NULL);
+
+ if (path && column)
+ gtk_dialog_response (dialog, GTK_RESPONSE_OK);
+}
+
+static GtkWidget *
+create_users_tree_view (GtkWidget *dialog,
+ struct EMapiSearchGalUserData *pgu)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ gint pos;
+
+ g_return_val_if_fail (dialog != NULL, NULL);
+ g_return_val_if_fail (pgu != NULL, NULL);
+
+ tree_view = GTK_TREE_VIEW (gtk_tree_view_new_with_model (
+ GTK_TREE_MODEL (gtk_list_store_new (5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_UINT))));
+
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "editable", FALSE, NULL);
+ pos = gtk_tree_view_insert_column_with_attributes (tree_view, -1, _("Name"), renderer, "text", COL_DISPLAY_NAME, NULL);
+ column = gtk_tree_view_get_column (tree_view, pos - 1);
+ gtk_tree_view_column_set_expand (column, TRUE);
+
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "editable", FALSE, NULL);
+ gtk_tree_view_insert_column_with_attributes (tree_view, -1, _("E-mail"), renderer, "text", COL_EMAIL, NULL);
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+ search_gal_user_selection_changed_cb (selection, GTK_DIALOG (dialog));
+ g_signal_connect (selection, "changed", G_CALLBACK (search_gal_user_selection_changed_cb), dialog);
+
+ g_signal_connect (tree_view, "row-activated", G_CALLBACK (search_gal_user_row_activated_cb), dialog);
+
+ pgu->tree_view = GTK_WIDGET (tree_view);
+
+ return pgu->tree_view;
+}
+
+gboolean
+e_mapi_search_gal_user_modal (GtkWindow *parent,
+ EMapiConnection *conn,
+ const gchar *search_this,
+ EMapiGalUserType *searched_type,
+ gchar **display_name,
+ gchar **email,
+ gchar **user_dn,
+ struct SBinary_short **entry_id)
+{
+ gboolean res = FALSE;
+ struct EMapiSearchGalUserData *pgu;
+ GtkWidget *dialog;
+ GtkWidget *content, *label, *widget;
+ GtkGrid *grid;
+ GtkScrolledWindow *scrolled_window;
+ gint row;
+
+ g_return_val_if_fail (conn != NULL, FALSE);
+ g_return_val_if_fail (searched_type != NULL, FALSE);
+ g_return_val_if_fail (display_name || email || entry_id || user_dn, FALSE);
+
+ pgu = g_new0 (struct EMapiSearchGalUserData, 1);
+ pgu->conn = g_object_ref (conn);
+ pgu->search_extra = 0; /* always none, as default/anonymous user cannot be added to permissions */
+
+ dialog = gtk_dialog_new_with_buttons (
+ _("Choose MAPI user..."),
+ parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
+
+ g_object_set_data_full (G_OBJECT (dialog), E_MAPI_SEARCH_DLG_DATA, pgu, e_mapi_search_gal_user_data_free);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+ grid = GTK_GRID (gtk_grid_new ());
+ gtk_grid_set_row_homogeneous (grid, FALSE);
+ gtk_grid_set_row_spacing (grid, 6);
+ gtk_grid_set_column_homogeneous (grid, FALSE);
+ gtk_grid_set_column_spacing (grid, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
+ gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid));
+
+ row = 0;
+
+ label = gtk_label_new_with_mnemonic (_("_Search:"));
+ g_object_set (G_OBJECT (label),
+ "hexpand", FALSE,
+ "vexpand", FALSE,
+ "xalign", 0.0,
+ NULL);
+
+ widget = gtk_entry_new ();
+ g_object_set (G_OBJECT (widget),
+ "hexpand", TRUE,
+ "vexpand", FALSE,
+ NULL);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
+ if (search_this && *search_this) {
+ gtk_entry_set_text (GTK_ENTRY (widget), search_this);
+ pgu->search_text = g_strdup (search_this);
+ }
+
+ g_signal_connect (widget, "changed", G_CALLBACK (search_term_changed_cb), dialog);
+
+ gtk_grid_attach (grid, label, 0, row, 1, 1);
+ gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+ row++;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ scrolled_window = GTK_SCROLLED_WINDOW (widget);
+ gtk_scrolled_window_set_min_content_width (scrolled_window, 120);
+ gtk_scrolled_window_set_min_content_height (scrolled_window, 120);
+ gtk_container_add (GTK_CONTAINER (widget), create_users_tree_view (dialog, pgu));
+ g_object_set (G_OBJECT (widget),
+ "hexpand", TRUE,
+ "vexpand", TRUE,
+ "shadow-type", GTK_SHADOW_IN,
+ NULL);
+
+ gtk_grid_attach (grid, widget, 0, row, 2, 1);
+
+ row++;
+
+ label = gtk_label_new (_("Search for a user"));
+ g_object_set (G_OBJECT (label),
+ "hexpand", TRUE,
+ "vexpand", FALSE,
+ "xalign", 0.0,
+ NULL);
+
+ pgu->info_label = label;
+
+ gtk_grid_attach (grid, label, 0, row, 2, 1);
+
+ row++;
+
+ gtk_widget_show_all (content);
+
+ g_signal_connect (dialog, "realize", G_CALLBACK (dialog_realized_cb), NULL);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ GtkTreeSelection *selection;
+ GtkTreeModel *model = NULL;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pgu->tree_view));
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ guint ut = E_MAPI_GAL_USER_NONE;
+
+ gtk_tree_model_get (model, &iter, COL_USER_TYPE, &ut, -1);
+
+ *searched_type = ut;
+ if (display_name)
+ gtk_tree_model_get (model, &iter, COL_DISPLAY_NAME, display_name, -1);
+ if (email)
+ gtk_tree_model_get (model, &iter, COL_EMAIL, email, -1);
+ if (user_dn)
+ gtk_tree_model_get (model, &iter, COL_USER_DN, user_dn, -1);
+ if (entry_id) {
+ gtk_tree_model_get (model, &iter, COL_ENTRY_ID, entry_id, -1);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_ENTRY_ID, NULL, -1);
+ }
+
+ res = TRUE;
+ }
+ }
+
+ gtk_widget_destroy (dialog);
+
+ return res;
+}
diff --git a/src/account-setup-eplugin/e-mapi-search-gal-user.h b/src/account-setup-eplugin/e-mapi-search-gal-user.h
new file mode 100644
index 0000000..cec196d
--- /dev/null
+++ b/src/account-setup-eplugin/e-mapi-search-gal-user.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Milan Crha <mcrha redhat com>
+ *
+ * Copyright (C) 2012 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_MAPI_SEARCH_GAL_USER_H
+#define E_MAPI_SEARCH_GAL_USER_H
+
+#include <gtk/gtk.h>
+#include <e-mapi-connection.h>
+
+typedef enum {
+ E_MAPI_GAL_USER_NONE = 0,
+ E_MAPI_GAL_USER_DEFAULT = 1 << 0,
+ E_MAPI_GAL_USER_ANONYMOUS = 1 << 1,
+ E_MAPI_GAL_USER_REGULAR = 1 << 2
+} EMapiGalUserType;
+
+gboolean e_mapi_search_gal_user_modal (GtkWindow *parent,
+ EMapiConnection *conn,
+ const gchar *search_this,
+ EMapiGalUserType *searched_type, /* one of from the enum */
+ gchar **display_name,
+ gchar **email,
+ gchar **user_dn,
+ struct SBinary_short **entry_id); /* allocated with GLib, not talloc */
+
+#endif /* E_MAPI_SEARCH_GAL_USER_H */
diff --git a/src/account-setup-eplugin/e-mapi-subscribe-foreign-folder.c b/src/account-setup-eplugin/e-mapi-subscribe-foreign-folder.c
index 44a2167..65dec46 100644
--- a/src/account-setup-eplugin/e-mapi-subscribe-foreign-folder.c
+++ b/src/account-setup-eplugin/e-mapi-subscribe-foreign-folder.c
@@ -35,7 +35,6 @@
#include "e-mapi-account-setup.h"
#include "e-mapi-subscribe-foreign-folder.h"
-#include "e-mapi-debug.h"
#include "e-mapi-utils.h"
#ifndef PidTagMailboxOwnerName
diff --git a/src/account-setup-eplugin/org-gnome-exchange-mapi.eplug.xml b/src/account-setup-eplugin/org-gnome-exchange-mapi.eplug.xml
index 849aee0..59ab8b3 100644
--- a/src/account-setup-eplugin/org-gnome-exchange-mapi.eplug.xml
+++ b/src/account-setup-eplugin/org-gnome-exchange-mapi.eplug.xml
@@ -77,22 +77,51 @@
</group>
</hook>
+ <hook class="org.gnome.evolution.mail.popup:1.0">
+ <menu id="org.gnome.evolution.mail.foldertree.popup" target="folder"
+ factory="org_gnome_folder_size_display_popup">
+ </menu>
+ </hook>
+
<hook class="org.gnome.evolution.ui:1.0">
- <ui-manager id="org.gnome.evolution.mail">
+ <ui-manager id="org.gnome.evolution.mail" callback="mapi_ui_init_mail">
<popup name="mail-folder-popup">
<placeholder name="mail-folder-popup-actions">
<menuitem action="mail-mapi-folder-size"/>
<menuitem action="mail-mapi-subscribe-foreign-folder"/>
+ <menuitem action="mail-mapi-folder-permissions"/>
</placeholder>
</popup>
</ui-manager>
- </hook>
- <hook class="org.gnome.evolution.mail.popup:1.0">
- <menu id="org.gnome.evolution.mail.foldertree.popup" target="folder"
- factory="org_gnome_folder_size_display_popup">
- </menu>
+ <ui-manager id="org.gnome.evolution.calendars" callback="mapi_ui_init_calendar">
+ <popup name="calendar-popup">
+ <placeholder name="calendar-popup-actions">
+ <menuitem action="calendar-mapi-folder-permissions"/>
+ </placeholder>
+ </popup>
+ </ui-manager>
+ <ui-manager id="org.gnome.evolution.tasks" callback="mapi_ui_init_tasks">
+ <popup name="task-list-popup">
+ <placeholder name="task-list-popup-actions">
+ <menuitem action="tasks-mapi-folder-permissions"/>
+ </placeholder>
+ </popup>
+ </ui-manager>
+ <ui-manager id="org.gnome.evolution.memos" callback="mapi_ui_init_memos">
+ <popup name="memo-list-popup">
+ <placeholder name="memo-list-popup-actions">
+ <menuitem action="memos-mapi-folder-permissions"/>
+ </placeholder>
+ </popup>
+ </ui-manager>
+ <ui-manager id="org.gnome.evolution.contacts" callback="mapi_ui_init_contacts">
+ <popup name="address-book-popup">
+ <placeholder name="address-book-popup-actions">
+ <menuitem action="contacts-mapi-folder-permissions"/>
+ </placeholder>
+ </popup>
+ </ui-manager>
</hook>
-
</e-plugin>
</e-plugin-list>
diff --git a/src/addressbook/e-book-backend-mapi-gal.c b/src/addressbook/e-book-backend-mapi-gal.c
index 0c7b549..b4711cb 100644
--- a/src/addressbook/e-book-backend-mapi-gal.c
+++ b/src/addressbook/e-book-backend-mapi-gal.c
@@ -219,7 +219,7 @@ ebbm_gal_transfer_contacts (EBookBackendMAPI *ebma,
tg.book_view = book_view;
tg.notify_contact_data = notify_contact_data;
- status = e_mapi_connection_transfer_gal_objects (conn, get_mids, transfer_gal_cb, &tg, cancellable, &mapi_error);
+ status = e_mapi_connection_transfer_gal_objects (conn, get_mids, NULL, NULL, transfer_gal_cb, &tg, cancellable, &mapi_error);
if (mapi_error) {
mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch GAL entries"));
diff --git a/src/libexchangemapi/e-mapi-connection.c b/src/libexchangemapi/e-mapi-connection.c
index a3bc2a1..39a3dae 100644
--- a/src/libexchangemapi/e-mapi-connection.c
+++ b/src/libexchangemapi/e-mapi-connection.c
@@ -1145,6 +1145,7 @@ e_mapi_connection_get_folder_properties (EMapiConnection *conn,
CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
e_return_val_mapi_error_if_fail (obj_folder != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+ e_return_val_mapi_error_if_fail (cb != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
LOCK ();
mem_ctx = talloc_new (priv->session);
@@ -1335,6 +1336,278 @@ foreach_tablerow (EMapiConnection *conn,
return ms;
}
+static gboolean
+gather_folder_permissions_cb (EMapiConnection *conn,
+ TALLOC_CTX *mem_ctx,
+ struct SRow *srow,
+ guint32 row_index,
+ guint32 rows_total,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **perror)
+{
+ GSList **entries = user_data;
+ const gchar *username;
+ const struct Binary_r *pentry_id;
+ const uint64_t *pid;
+ const uint32_t *prights;
+
+ g_return_val_if_fail (srow != NULL, FALSE);
+ g_return_val_if_fail (entries != NULL, FALSE);
+
+ username = e_mapi_util_find_row_propval (srow, PidTagMemberName);
+ pid = e_mapi_util_find_row_propval (srow, PidTagMemberId);
+ pentry_id = e_mapi_util_find_row_propval (srow, PidTagEntryId);
+ prights = e_mapi_util_find_row_propval (srow, PidTagMemberRights);
+
+ if (prights && pid) {
+ EMapiPermissionEntry *pem;
+ struct SBinary_short entry_id;
+
+ entry_id.cb = pentry_id ? pentry_id->cb : 0;
+ entry_id.lpb = pentry_id ? pentry_id->lpb : NULL;
+
+ pem = e_mapi_permission_entry_new (username, pentry_id ? &entry_id : NULL, *pid, *prights);
+ g_return_val_if_fail (pem != NULL, FALSE);
+
+ *entries = g_slist_prepend (*entries, pem);
+ } else {
+ g_debug ("%s: Skipping [%d/%d] (%s) No rights or member ID set", G_STRFUNC, row_index, rows_total, username ? username : "no member name");
+ }
+
+ return TRUE;
+}
+
+gboolean
+e_mapi_connection_get_permissions (EMapiConnection *conn,
+ mapi_object_t *obj_folder,
+ gboolean with_freebusy,
+ GSList **entries, /* EMapiPermissionEntry */
+ GCancellable *cancellable,
+ GError **perror)
+{
+ enum MAPISTATUS ms = MAPI_E_RESERVED;
+ struct SPropTagArray *propTagArray;
+ mapi_object_t obj_table;
+ TALLOC_CTX *mem_ctx;
+
+ CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+ e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+ e_return_val_mapi_error_if_fail (obj_folder != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+ e_return_val_mapi_error_if_fail (entries != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+
+ LOCK ();
+ mem_ctx = talloc_new (priv->session);
+ mapi_object_init (&obj_table);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+ ms = MAPI_E_USER_CANCEL;
+ goto cleanup;
+ }
+
+ ms = GetPermissionsTable (obj_folder, with_freebusy ? IncludeFreeBusy : 0, &obj_table);
+ if (ms != MAPI_E_SUCCESS) {
+ make_mapi_error (perror, "GetPermissionsTable", ms);
+ goto cleanup;
+ }
+
+ propTagArray = set_SPropTagArray (mem_ctx, 4,
+ PidTagMemberId,
+ PidTagEntryId,
+ PidTagMemberName,
+ PidTagMemberRights);
+
+ /* Set primary columns to be fetched */
+ ms = SetColumns (&obj_table, propTagArray);
+ if (ms != MAPI_E_SUCCESS) {
+ make_mapi_error (perror, "SetColumns", ms);
+ goto cleanup;
+ }
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+ ms = MAPI_E_USER_CANCEL;
+ goto cleanup;
+ }
+
+ *entries = NULL;
+
+ ms = foreach_tablerow (conn, mem_ctx, &obj_table, gather_folder_permissions_cb, entries, cancellable, perror);
+ if (ms == MAPI_E_SUCCESS) {
+ *entries = g_slist_reverse (*entries);
+ } else {
+ g_slist_free_full (*entries, (GDestroyNotify) e_mapi_permission_entry_free);
+ *entries = NULL;
+ }
+
+ cleanup:
+ mapi_object_release (&obj_table);
+ talloc_free (mem_ctx);
+ UNLOCK();
+
+ return ms == MAPI_E_SUCCESS;
+}
+
+gboolean
+e_mapi_connection_set_permissions (EMapiConnection *conn,
+ mapi_object_t *obj_folder,
+ gboolean with_freebusy,
+ const GSList *entries, /* EMapiPermissionEntry */
+ GCancellable *cancellable,
+ GError **perror)
+{
+ enum MAPISTATUS ms = MAPI_E_RESERVED;
+ struct mapi_PermissionsData *rows = NULL;
+ GSList *current_entries = NULL;
+ TALLOC_CTX *mem_ctx;
+
+ CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+ e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+ e_return_val_mapi_error_if_fail (obj_folder != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+
+ LOCK ();
+ mem_ctx = talloc_new (priv->session);
+
+ rows = talloc_zero (mem_ctx, struct mapi_PermissionsData);
+ if (!rows) {
+ ms = MAPI_E_NOT_ENOUGH_RESOURCES;
+ make_mapi_error (perror, "talloc_zero", ms);
+ goto cleanup;
+ }
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+ ms = MAPI_E_USER_CANCEL;
+ goto cleanup;
+ }
+
+ if (!e_mapi_connection_get_permissions (conn, obj_folder, with_freebusy, ¤t_entries, cancellable, perror)) {
+ ms = MAPI_E_CALL_FAILED;
+ make_mapi_error (perror, "e_mapi_connection_get_permissions", ms);
+ goto cleanup;
+ }
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+ ms = MAPI_E_USER_CANCEL;
+ goto cleanup;
+ }
+
+ rows->ModifyCount = g_slist_length ((GSList *) entries) + g_slist_length (current_entries);
+ if (rows->ModifyCount > 0) {
+ const GSList *iter, *citer;
+ GSList *removed_entries = g_slist_copy (current_entries);
+ gint row_index = 0;
+
+ rows->PermissionsData = talloc_array (rows, struct PermissionData, rows->ModifyCount);
+ if (!rows->PermissionsData) {
+ ms = MAPI_E_NOT_ENOUGH_RESOURCES;
+ make_mapi_error (perror, "talloc_zero", ms);
+ g_slist_free (removed_entries);
+ goto cleanup;
+ }
+
+ for (iter = entries; iter; iter = iter->next) {
+ const EMapiPermissionEntry *pem = iter->data, *cpem = NULL;
+
+ if (!pem) {
+ ms = MAPI_E_INVALID_PARAMETER;
+ make_mapi_error (perror, "entries::data", ms);
+ g_slist_free (removed_entries);
+ goto cleanup;
+ }
+
+ for (citer = current_entries; citer; citer = citer->next) {
+ cpem = citer->data;
+
+ if (cpem && ((cpem->entry_id.cb == pem->entry_id.cb && cpem->member_id == pem->member_id) ||
+ (cpem->entry_id.cb > 0 && e_mapi_util_recip_entryid_equal (&cpem->entry_id, &pem->entry_id)))) {
+ removed_entries = g_slist_remove (removed_entries, cpem);
+ break;
+ }
+
+ cpem = NULL;
+ }
+
+ if (cpem == NULL) {
+ rows->PermissionsData[row_index].PermissionDataFlags = ROW_ADD;
+ rows->PermissionsData[row_index].lpProps.cValues = 2;
+ rows->PermissionsData[row_index].lpProps.lpProps = talloc_zero_array (rows, struct mapi_SPropValue, 3);
+ if (!rows->PermissionsData[row_index].lpProps.lpProps) {
+ ms = MAPI_E_NOT_ENOUGH_RESOURCES;
+ make_mapi_error (perror, "talloc_zero", ms);
+ g_slist_free (removed_entries);
+ goto cleanup;
+ }
+
+ rows->PermissionsData[row_index].lpProps.lpProps[0].ulPropTag = PidTagEntryId;
+ rows->PermissionsData[row_index].lpProps.lpProps[0].value.bin = pem->entry_id;
+
+ rows->PermissionsData[row_index].lpProps.lpProps[1].ulPropTag = PidTagMemberRights;
+ rows->PermissionsData[row_index].lpProps.lpProps[1].value.l = pem->member_rights;
+
+ row_index++;
+ } else if (cpem->member_rights != pem->member_rights) {
+ rows->PermissionsData[row_index].PermissionDataFlags = ROW_MODIFY;
+ rows->PermissionsData[row_index].lpProps.cValues = 2;
+ rows->PermissionsData[row_index].lpProps.lpProps = talloc_zero_array (rows, struct mapi_SPropValue, 3);
+ if (!rows->PermissionsData[row_index].lpProps.lpProps) {
+ ms = MAPI_E_NOT_ENOUGH_RESOURCES;
+ make_mapi_error (perror, "talloc_zero", ms);
+ g_slist_free (removed_entries);
+ goto cleanup;
+ }
+
+ rows->PermissionsData[row_index].lpProps.lpProps[0].ulPropTag = PidTagMemberId;
+ rows->PermissionsData[row_index].lpProps.lpProps[0].value.d = pem->member_id;
+
+ rows->PermissionsData[row_index].lpProps.lpProps[1].ulPropTag = PidTagMemberRights;
+ rows->PermissionsData[row_index].lpProps.lpProps[1].value.l = pem->member_rights;
+
+ row_index++;
+ }
+ }
+
+ for (citer = removed_entries; citer; citer = citer->next) {
+ const EMapiPermissionEntry *cpem = citer->data;
+
+ if (cpem) {
+ rows->PermissionsData[row_index].PermissionDataFlags = ROW_REMOVE;
+ rows->PermissionsData[row_index].lpProps.cValues = 1;
+ rows->PermissionsData[row_index].lpProps.lpProps = talloc_zero_array (rows, struct mapi_SPropValue, 2);
+ if (!rows->PermissionsData[row_index].lpProps.lpProps) {
+ ms = MAPI_E_NOT_ENOUGH_RESOURCES;
+ make_mapi_error (perror, "talloc_zero", ms);
+ g_slist_free (removed_entries);
+ goto cleanup;
+ }
+
+ rows->PermissionsData[row_index].lpProps.lpProps[0].ulPropTag = PidTagMemberId;
+ rows->PermissionsData[row_index].lpProps.lpProps[0].value.d = cpem->member_id;
+
+ row_index++;
+ }
+ }
+
+ rows->ModifyCount = row_index;
+
+ g_slist_free (removed_entries);
+ }
+
+ if (rows->ModifyCount > 0) {
+ ms = ModifyPermissions (obj_folder, with_freebusy ? ModifyPerms_IncludeFreeBusy : 0, rows);
+ if (ms != MAPI_E_SUCCESS) {
+ make_mapi_error (perror, "ModifyPermissions", ms);
+ goto cleanup;
+ }
+ }
+
+ cleanup:
+ g_slist_free_full (current_entries, (GDestroyNotify) e_mapi_permission_entry_free);
+ talloc_free (rows);
+ talloc_free (mem_ctx);
+ UNLOCK();
+
+ return ms == MAPI_E_SUCCESS;
+}
+
struct ListObjectsInternalData
{
ListObjectsCB cb;
@@ -4062,6 +4335,8 @@ fill_reverse_replace_hash (gpointer key,
gboolean
e_mapi_connection_transfer_gal_objects (EMapiConnection *conn,
const GSList *mids,
+ BuildReadPropsCB brp_cb,
+ gpointer brp_cb_user_data,
TransferObjectCB cb,
gpointer cb_user_data,
GCancellable *cancellable,
@@ -4115,10 +4390,19 @@ e_mapi_connection_transfer_gal_objects (EMapiConnection *conn,
goto cleanup;
}
- if (!e_mapi_book_utils_get_supported_mapi_proptags (mem_ctx, &propTagArray) || !propTagArray) {
- ms = MAPI_E_CALL_FAILED;
- make_mapi_error (perror, "e_mapi_book_utils_get_supported_mapi_proptags", ms);
- goto cleanup;
+ if (brp_cb) {
+ propTagArray = set_SPropTagArray (mem_ctx, 1, PidTagObjectType);
+ if (!brp_cb (conn, mem_ctx, propTagArray, brp_cb_user_data, cancellable, perror)) {
+ ms = MAPI_E_CALL_FAILED;
+ make_mapi_error (perror, "brp_cb", ms);
+ goto cleanup;
+ }
+ } else {
+ if (!e_mapi_book_utils_get_supported_mapi_proptags (mem_ctx, &propTagArray) || !propTagArray) {
+ ms = MAPI_E_CALL_FAILED;
+ make_mapi_error (perror, "e_mapi_book_utils_get_supported_mapi_proptags", ms);
+ goto cleanup;
+ }
}
for (ii = 0; ii < propTagArray->cValues; ii++) {
@@ -4190,7 +4474,7 @@ e_mapi_connection_transfer_gal_object (EMapiConnection *conn,
gboolean res;
mids = g_slist_append (NULL, &message_id);
- res = e_mapi_connection_transfer_gal_objects (conn, mids, cb, cb_user_data, cancellable, perror);
+ res = e_mapi_connection_transfer_gal_objects (conn, mids, NULL, NULL, cb, cb_user_data, cancellable, perror);
g_slist_free (mids);
return res;
@@ -4722,6 +5006,11 @@ e_mapi_connection_resolve_named_props (EMapiConnection *conn,
talloc_free (names);
}
+ if (ms == MAPI_E_NOT_FOUND) {
+ res = TRUE;
+ goto cleanup;
+ }
+
if (ms != MAPI_E_SUCCESS) {
make_mapi_error (perror, "mapi_nameid_GetIDsFromNames", ms);
goto cleanup;
@@ -6484,3 +6773,39 @@ e_mapi_object_add_attachment (EMapiObject *object,
attach->next = attachment;
}
}
+
+EMapiPermissionEntry *
+e_mapi_permission_entry_new (const gchar *username,
+ const struct SBinary_short *entry_id,
+ uint64_t member_id,
+ uint32_t member_rights)
+{
+ EMapiPermissionEntry *entry;
+
+ entry = g_new0 (EMapiPermissionEntry, 1);
+ entry->username = g_strdup (username);
+
+ if (entry_id && entry_id->lpb) {
+ entry->entry_id.cb = entry_id->cb;
+ entry->entry_id.lpb = g_memdup (entry_id->lpb, entry_id->cb);
+ } else {
+ entry->entry_id.cb = 0;
+ entry->entry_id.lpb = NULL;
+ }
+
+ entry->member_id = member_id;
+ entry->member_rights = member_rights;
+
+ return entry;
+}
+
+void
+e_mapi_permission_entry_free (EMapiPermissionEntry *entry)
+{
+ if (!entry)
+ return;
+
+ g_free (entry->username);
+ g_free (entry->entry_id.lpb);
+ g_free (entry);
+}
diff --git a/src/libexchangemapi/e-mapi-connection.h b/src/libexchangemapi/e-mapi-connection.h
index 63d4797..6c03899 100644
--- a/src/libexchangemapi/e-mapi-connection.h
+++ b/src/libexchangemapi/e-mapi-connection.h
@@ -105,6 +105,38 @@ void e_mapi_object_add_recipient (EMapiObject *object,
void e_mapi_object_add_attachment (EMapiObject *object,
EMapiAttachment *attachment);
+#define E_MAPI_PERMISSION_MEMBER_ID_ANONYMOUS_CLIENT (~((uint64_t) 0))
+#define E_MAPI_PERMISSION_MEMBER_ID_DEFAULT_USER ((uint64_t) 0)
+
+typedef enum {
+ E_MAPI_PERMISSION_BIT_FREE_BUSY_DETAILED = 0x00001000,
+ E_MAPI_PERMISSION_BIT_FREE_BUSY_SIMPLE = 0x00000800,
+ E_MAPI_PERMISSION_BIT_FOLDER_VISIBLE = 0x00000400,
+ E_MAPI_PERMISSION_BIT_FOLDER_CONTACT = 0x00000200,
+ E_MAPI_PERMISSION_BIT_FOLDER_OWNER = 0x00000100,
+ E_MAPI_PERMISSION_BIT_CREATE_SUBFOLDER = 0x00000080,
+ E_MAPI_PERMISSION_BIT_DELETE_ANY = 0x00000040,
+ E_MAPI_PERMISSION_BIT_EDIT_ANY = 0x00000020,
+ E_MAPI_PERMISSION_BIT_DELETE_OWNED = 0x00000010,
+ E_MAPI_PERMISSION_BIT_EDIT_OWNED = 0x00000008,
+ E_MAPI_PERMISSION_BIT_CREATE = 0x00000002,
+ E_MAPI_PERMISSION_BIT_READ_ANY = 0x00000001
+} EMapiPermissionBits;
+
+typedef struct {
+ gchar *username; /* PidTagMemberName - display name for a user */
+
+ struct SBinary_short entry_id; /* PidTagEntryId of the user */
+ uint64_t member_id; /* PidTagMemberId of the user */
+ uint32_t member_rights; /* PidTagMemberRights of the user */
+} EMapiPermissionEntry;
+
+EMapiPermissionEntry * e_mapi_permission_entry_new (const gchar *username,
+ const struct SBinary_short *entry_id,
+ uint64_t member_id,
+ uint32_t member_rights);
+void e_mapi_permission_entry_free (EMapiPermissionEntry *entry);
+
typedef enum {
E_MAPI_CREATE_FLAG_NONE = 0,
E_MAPI_CREATE_FLAG_SUBMIT = 1 << 0
@@ -236,6 +268,20 @@ gboolean e_mapi_connection_get_folder_properties (EMapiConnection *conn,
GCancellable *cancellable,
GError **perror);
+gboolean e_mapi_connection_get_permissions (EMapiConnection *conn,
+ mapi_object_t *obj_folder,
+ gboolean with_freebusy,
+ GSList **entries, /* out, EMapiPermissionEntry */
+ GCancellable *cancellable,
+ GError **perror);
+
+gboolean e_mapi_connection_set_permissions (EMapiConnection *conn,
+ mapi_object_t *obj_folder,
+ gboolean with_freebusy,
+ const GSList *entries, /* EMapiPermissionEntry */
+ GCancellable *cancellable,
+ GError **perror);
+
gboolean e_mapi_connection_list_objects (EMapiConnection *conn,
mapi_object_t *obj_folder,
BuildRestrictionsCB build_rs_cb,
@@ -301,6 +347,8 @@ gboolean e_mapi_connection_list_gal_objects (EMapiConnection *conn,
gboolean e_mapi_connection_transfer_gal_objects (EMapiConnection *conn,
const GSList *mids,
+ BuildReadPropsCB brp_cb, /* NULL for all supported */
+ gpointer brp_cb_user_data,
TransferObjectCB cb,
gpointer cb_user_data,
GCancellable *cancellable,
diff --git a/src/libexchangemapi/e-mapi-utils.c b/src/libexchangemapi/e-mapi-utils.c
index d7b075f..707acfa 100644
--- a/src/libexchangemapi/e-mapi-utils.c
+++ b/src/libexchangemapi/e-mapi-utils.c
@@ -589,6 +589,44 @@ e_mapi_util_recip_entryid_decode (EMapiConnection *conn, const struct Binary_r *
return FALSE;
}
+gboolean
+e_mapi_util_recip_entryid_decode_dn (const struct SBinary_short *entryid,
+ gchar **exchange_dn)
+{
+ struct Binary_r ei;
+
+ if (!entryid)
+ return FALSE;
+
+ ei.cb = entryid->cb;
+ ei.lpb = entryid->lpb;
+
+ return recip_entryid_decode_ex (&ei, exchange_dn);
+}
+
+gboolean
+e_mapi_util_recip_entryid_equal (const struct SBinary_short *entryid1,
+ const struct SBinary_short *entryid2)
+{
+ gchar *dn1 = NULL, *dn2 = NULL;
+ gboolean same = FALSE;
+
+ if (!entryid1 && !entryid2)
+ return TRUE;
+
+ if (!entryid1 || !entryid2 || !entryid1->lpb || !entryid2->lpb || entryid1->cb != entryid2->cb)
+ return FALSE;
+
+ same = e_mapi_util_recip_entryid_decode_dn (entryid1, &dn1) &&
+ e_mapi_util_recip_entryid_decode_dn (entryid2, &dn2) &&
+ dn1 && dn2 && g_ascii_strcasecmp (dn1, dn2) == 0;
+
+ g_free (dn1);
+ g_free (dn2);
+
+ return same;
+}
+
/**
* e_mapi_util_profiledata_from_settings:
* @empd: destination for profile settings
diff --git a/src/libexchangemapi/e-mapi-utils.h b/src/libexchangemapi/e-mapi-utils.h
index 7dc02ed..97d9369 100644
--- a/src/libexchangemapi/e-mapi-utils.h
+++ b/src/libexchangemapi/e-mapi-utils.h
@@ -54,6 +54,10 @@ gboolean e_mapi_util_recip_entryid_decode (EMapiConnection *conn,
const struct Binary_r *entyrid,
gchar **display_name,
gchar **email);
+gboolean e_mapi_util_recip_entryid_decode_dn (const struct SBinary_short *entryid,
+ gchar **exchange_dn);
+gboolean e_mapi_util_recip_entryid_equal (const struct SBinary_short *entryid1,
+ const struct SBinary_short *entryid2);
void e_mapi_util_profiledata_from_settings (EMapiProfileData *empd,
CamelMapiSettings *settings);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]