static gboolean proppatch_sd (E2kContext *ctx, ExchangeDelegatesFolder *folder) { GByteArray *binsd; E2kProperties *props; const gchar *href = ""; E2kResultIter *iter; E2kResult *result; E2kHTTPStatus status; binsd = e2k_security_descriptor_to_binary (folder->sd); if (!binsd) return FALSE; props = e2k_properties_new (); e2k_properties_set_binary (props, E2K_PR_EXCHANGE_SD_BINARY, binsd); iter = e2k_context_bproppatch_start (ctx, NULL, folder->uri, &href, 1, props, FALSE); e2k_properties_free (props); result = e2k_result_iter_next (iter); if (result) { status = result->status; e2k_result_iter_free (iter); } else status = e2k_result_iter_free (iter); return E2K_HTTP_STATUS_IS_SUCCESSFUL (status); }
/** * e2k_freebusy_add_from_calendar_uri: * @fb: an #E2kFreebusy * @uri: the URI of a calendar folder * @start_tt: start of the range to add * @end_tt: end of the range to add * * This queries the server for events between @start_tt and @end_tt in * the calendar at @uri (which the caller must have permission to * read) and adds them @fb. Any previously-existing events during that * range are removed. * * Return value: an HTTP status code. **/ E2kHTTPStatus e2k_freebusy_add_from_calendar_uri (E2kFreebusy *fb, const char *uri, time_t start_tt, time_t end_tt) { char *start, *end, *busystatus; E2kBusyStatus busy; E2kRestriction *rn; E2kResultIter *iter; E2kResult *result; e2k_freebusy_clear_interval (fb, start_tt, end_tt); start = e2k_make_timestamp (start_tt); end = e2k_make_timestamp (end_tt); rn = e2k_restriction_andv ( e2k_restriction_prop_string (E2K_PR_DAV_CONTENT_CLASS, E2K_RELOP_EQ, "urn:content-classes:appointment"), e2k_restriction_prop_date (E2K_PR_CALENDAR_DTEND, E2K_RELOP_GT, start), e2k_restriction_prop_date (E2K_PR_CALENDAR_DTSTART, E2K_RELOP_LT, end), e2k_restriction_prop_string (E2K_PR_CALENDAR_BUSY_STATUS, E2K_RELOP_NE, "FREE"), NULL); iter = e2k_context_search_start (fb->ctx, NULL, uri, freebusy_props, n_freebusy_props, rn, NULL, TRUE); e2k_restriction_unref (rn); g_free (start); g_free (end); while ((result = e2k_result_iter_next (iter))) { start = e2k_properties_get_prop (result->props, E2K_PR_CALENDAR_DTSTART); end = e2k_properties_get_prop (result->props, E2K_PR_CALENDAR_DTEND); busystatus = e2k_properties_get_prop (result->props, E2K_PR_CALENDAR_BUSY_STATUS); if (!start || !end || !busystatus) continue; if (!strcmp (busystatus, "TENTATIVE")) busy = E2K_BUSYSTATUS_TENTATIVE; else if (!strcmp (busystatus, "OUTOFOFFICE")) busy = E2K_BUSYSTATUS_OOF; else busy = E2K_BUSYSTATUS_BUSY; e2k_freebusy_add_interval (fb, busy, e2k_parse_timestamp (start), e2k_parse_timestamp (end)); } return e2k_result_iter_free (iter); }
/* Fetch the list of delegates from the freebusy message. */ static gboolean get_user_list (ExchangeDelegates *delegates) { E2kContext *ctx; E2kResultIter *iter; E2kResult *result; GPtrArray *display_names, *entryids, *privflags; GByteArray *entryid; ExchangeDelegatesUser *user; gint i; ctx = exchange_account_get_context (delegates->account); iter = e2k_context_bpropfind_start (ctx, NULL, delegates->account->home_uri, &exchange_localfreebusy_path, 1, delegation_props, G_N_ELEMENTS (delegation_props)); result = e2k_result_iter_next (iter); if (!result || !E2K_HTTP_STATUS_IS_SUCCESSFUL (result->status)) { e2k_result_iter_free (iter); return FALSE; } delegates->users = g_ptr_array_new (); delegates->added_users = g_ptr_array_new (); delegates->removed_users = g_ptr_array_new (); display_names = e2k_properties_get_prop (result->props, PR_DELEGATES_DISPLAY_NAMES); entryids = e2k_properties_get_prop (result->props, PR_DELEGATES_ENTRYIDS); privflags = e2k_properties_get_prop (result->props, PR_DELEGATES_SEE_PRIVATE); entryid = e2k_properties_get_prop (result->props, PR_CREATOR_ENTRYID); delegates->creator_entryid = g_byte_array_new (); g_byte_array_append (delegates->creator_entryid, entryid->data, entryid->len); if (!display_names || !entryids || !privflags) { e2k_result_iter_free (iter); return TRUE; } for (i = 0; i < display_names->len && i < entryids->len && i < privflags->len; i++) { user = exchange_delegates_user_new (display_names->pdata[i]); user->see_private = privflags->pdata[i] && atoi (privflags->pdata[i]); entryid = entryids->pdata[i]; user->entryid = g_byte_array_new (); g_byte_array_append (user->entryid, entryid->data, entryid->len); g_signal_connect (user, "edited", G_CALLBACK (set_perms_for_user), delegates); g_ptr_array_add (delegates->users, user); } e2k_result_iter_free (iter); return TRUE; }
static void delegates_apply (ExchangeDelegates *delegates) { ExchangeDelegatesUser *user; E2kGlobalCatalog *gc; E2kContext *ctx; GPtrArray *display_names, *entryids, *privflags; GByteArray *entryid_dup; gchar *error = NULL; E2kProperties *props; gint i; E2kGlobalCatalogStatus status; if (!delegates->loaded_folders) return; /* We can't do this atomically/transactionally, so we need to * make sure that if we fail at any step, things are still in * a semi-consistent state. So we do: * * 1. Remove old delegates from AD * 2. Update LocalFreebusy.EML (the canonical list of delegates) * 3. Add new delegates to AD * 4. Update security descriptors * * If step 1 fails, nothing is changed. * * If step 2 fails, delegates who should have been removed * will have been removed from AD but nothing else, so they * will still show up as being delegates and the user can try * to remove them again later. * * If step 3 fails, delegates who should have been added will * not be in AD, but will be listed as delegates, so the user * can remove them and try adding them again later. * * If step 4 fails, the user can still correct the folder * permissions by hand. */ gc = exchange_account_get_global_catalog (delegates->account); if (!gc) { error = g_strdup (_("Could not access Active Directory")); goto done; } if ((delegates->removed_users || delegates->added_users) && !delegates->self_dn) { E2kGlobalCatalogEntry *entry; status = e2k_global_catalog_lookup ( gc, NULL, /* FIXME: cancellable */ E2K_GLOBAL_CATALOG_LOOKUP_BY_LEGACY_EXCHANGE_DN, delegates->account->legacy_exchange_dn, 0, &entry); if (status != E2K_GLOBAL_CATALOG_OK) { error = g_strdup (_("Could not find self in Active Directory")); goto done; } delegates->self_dn = g_strdup (entry->dn); e2k_global_catalog_entry_free (gc, entry); } /* 1. Remove old delegates from AD */ while (delegates->removed_users && delegates->removed_users->len) { user = delegates->removed_users->pdata[0]; if (!user->dn && !get_user_dn (gc, user)) { error = g_strdup_printf ( _("Could not find delegate %s in Active Directory"), user->display_name); goto done; } /* FIXME: cancellable */ status = e2k_global_catalog_remove_delegate (gc, NULL, delegates->self_dn, user->dn); if (status != E2K_GLOBAL_CATALOG_OK && status != E2K_GLOBAL_CATALOG_NO_DATA) { error = g_strdup_printf ( _("Could not remove delegate %s"), user->display_name); goto done; } g_object_unref (user); g_ptr_array_remove_index_fast (delegates->removed_users, 0); } /* 2. Update LocalFreebusy.EML */ ctx = exchange_account_get_context (delegates->account); if (delegates->users->len) { display_names = g_ptr_array_new (); entryids = g_ptr_array_new (); privflags = g_ptr_array_new (); for (i = 0; i < delegates->users->len; i++) { user = delegates->users->pdata[i]; g_ptr_array_add (display_names, g_strdup (user->display_name)); entryid_dup = g_byte_array_new (); g_byte_array_append (entryid_dup, user->entryid->data, user->entryid->len); g_ptr_array_add (entryids, entryid_dup); g_ptr_array_add (privflags, g_strdup_printf ("%d", user->see_private)); } props = e2k_properties_new (); e2k_properties_set_string_array ( props, PR_DELEGATES_DISPLAY_NAMES, display_names); e2k_properties_set_binary_array ( props, PR_DELEGATES_ENTRYIDS, entryids); e2k_properties_set_int_array ( props, PR_DELEGATES_SEE_PRIVATE, privflags); } else if (delegates->removed_users) { props = e2k_properties_new (); e2k_properties_remove (props, PR_DELEGATES_DISPLAY_NAMES); e2k_properties_remove (props, PR_DELEGATES_ENTRYIDS); e2k_properties_remove (props, PR_DELEGATES_SEE_PRIVATE); } else props = NULL; if (props) { E2kResultIter *iter; E2kResult *result; iter = e2k_context_bproppatch_start ( ctx, NULL, delegates->account->home_uri, &exchange_localfreebusy_path, 1, props, FALSE); e2k_properties_free (props); result = e2k_result_iter_next (iter); if (result) { status = result->status; e2k_result_iter_free (iter); } else status = e2k_result_iter_free (iter); if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) { error = g_strdup (_("Could not update list of delegates.")); goto done; } } /* 3. Add new delegates to AD */ while (delegates->added_users && delegates->added_users->len) { user = delegates->added_users->pdata[0]; /* An added user must have come from the GC so * we know user->dn is set. */ /* FIXME: cancellable */ status = e2k_global_catalog_add_delegate (gc, NULL, delegates->self_dn, user->dn); if (status != E2K_GLOBAL_CATALOG_OK && status != E2K_GLOBAL_CATALOG_EXISTS) { error = g_strdup_printf ( _("Could not add delegate %s"), user->display_name); goto done; } g_ptr_array_remove_index_fast (delegates->added_users, 0); g_object_unref (user); } /* 4. Update security descriptors */ for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) proppatch_sd (ctx, &delegates->folder[i]); proppatch_sd (ctx, &delegates->freebusy_folder); done: if (error) { e_alert_run_dialog_for_args (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":delegate-fail-error", error, NULL); g_free (error); } }
/* Read the folder security descriptors and match them up with the * list of delegates. */ static gboolean get_folder_security (ExchangeDelegates *delegates) { GPtrArray *hrefs; E2kContext *ctx; E2kHTTPStatus status; E2kResultIter *iter; E2kResult *result; xmlNode *xml_form; GByteArray *binary_form; ExchangeDelegatesUser *user; guint32 perms; gint i, u; /* If we've been here before, just return the success or * failure result from last time. */ if (delegates->freebusy_folder.uri) return delegates->loaded_folders; if (!exchange_account_get_global_catalog (delegates->account)) { e_alert_run_dialog_for_args (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":delegates-no-gcs-error", NULL); return FALSE; } ctx = exchange_account_get_context (delegates->account); hrefs = g_ptr_array_new (); for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) { delegates->folder[i].uri = exchange_account_get_standard_uri ( delegates->account, exchange_delegates_user_folder_names[i]); if (delegates->folder[i].uri) { g_ptr_array_add (hrefs, (gchar *) e2k_uri_relative ( delegates->account->home_uri, delegates->folder[i].uri)); } } g_ptr_array_add (hrefs, (gchar *) exchange_localfreebusy_path); iter = e2k_context_bpropfind_start ( ctx, NULL, delegates->account->home_uri, (const gchar **) hrefs->pdata, hrefs->len, sd_props, G_N_ELEMENTS (sd_props)); g_ptr_array_free (hrefs, TRUE); while ((result = e2k_result_iter_next (iter))) { xml_form = e2k_properties_get_prop (result->props, E2K_PR_EXCHANGE_SD_XML); binary_form = e2k_properties_get_prop (result->props, E2K_PR_EXCHANGE_SD_BINARY); if (xml_form && binary_form) { set_sd_for_href (delegates, result->href, e2k_security_descriptor_new (xml_form, binary_form)); } } status = e2k_result_iter_free (iter); if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) { e_alert_run_dialog_for_args (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":delegates-perm-read-error", NULL); return FALSE; } if (!fill_in_sids (delegates)) { delegates->loaded_folders = FALSE; e_alert_run_dialog_for_args (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":perm-deter-error", NULL); return FALSE; } /* Fill in delegate structures from the security descriptors */ for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) { for (u = 0; u < delegates->users->len; u++) { user = delegates->users->pdata[u]; perms = e2k_security_descriptor_get_permissions ( delegates->folder[i].sd, user->sid); user->role[i] = e2k_permissions_role_find (perms); } } delegates->loaded_folders = TRUE; return TRUE; }