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);
}
/* 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;
}
Esempio n. 5
0
/**
 * e2k_freebusy_new:
 * @ctx: an #E2kContext
 * @public_uri: the URI of the MAPI public folder tree
 * @dn: the legacy Exchange DN of a user
 *
 * Creates a new #E2kFreebusy, filled in with information from the
 * indicated user's published free/busy information. This uses the
 * public free/busy folder; the caller does not need permission to
 * access the @dn's Calendar.
 *
 * Note that currently, this will fail and return %NULL if the user
 * does not already have free/busy information stored on the server.
 *
 * Return value: the freebusy information
 **/
E2kFreebusy *
e2k_freebusy_new (E2kContext *ctx, const char *public_uri, const char *dn)
{
	E2kFreebusy *fb;
	char *uri, *time;
	GPtrArray *monthyears, *fbdatas;
	E2kHTTPStatus status;
	E2kResult *results;
	int nresults = 0, i;

	uri = fb_uri_for_dn (public_uri, dn);
	g_return_val_if_fail (uri, NULL);

	status = e2k_context_propfind (ctx, NULL, uri,
				       public_freebusy_props,
				       n_public_freebusy_props,
				       &results, &nresults);
	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status) || nresults == 0) {
		/* FIXME: create it */
		g_free (uri);
		return NULL;
	}

	fb = g_new0 (E2kFreebusy, 1);
	fb->uri = uri;
	fb->dn = g_strdup (dn);
	fb->ctx = ctx;
	g_object_ref (ctx);

	for (i = 0; i < E2K_BUSYSTATUS_MAX; i++)
		fb->events[i] = g_array_new (FALSE, FALSE, sizeof (E2kFreebusyEvent));

	time = e2k_properties_get_prop (
		results[0].props, PR_FREEBUSY_START_RANGE);
	fb->start = time ? e2k_systime_to_time_t (strtol (time, NULL, 10)) : 0;
	time = e2k_properties_get_prop (
		results[0].props, PR_FREEBUSY_END_RANGE);
	fb->end = time ? e2k_systime_to_time_t (strtol (time, NULL, 10)) : 0;

	monthyears = e2k_properties_get_prop (
		results[0].props, PR_FREEBUSY_ALL_MONTHS);
	fbdatas = e2k_properties_get_prop (
		results[0].props, PR_FREEBUSY_ALL_EVENTS);
	add_data_for_status (fb, monthyears, fbdatas, fb->events[E2K_BUSYSTATUS_ALL]);

	monthyears = e2k_properties_get_prop (
		results[0].props, PR_FREEBUSY_TENTATIVE_MONTHS);
	fbdatas = e2k_properties_get_prop (
		results[0].props, PR_FREEBUSY_TENTATIVE_EVENTS);
	add_data_for_status (fb, monthyears, fbdatas, fb->events[E2K_BUSYSTATUS_TENTATIVE]);

	monthyears = e2k_properties_get_prop (
		results[0].props, PR_FREEBUSY_BUSY_MONTHS);
	fbdatas = e2k_properties_get_prop (
		results[0].props, PR_FREEBUSY_BUSY_EVENTS);
	add_data_for_status (fb, monthyears, fbdatas, fb->events[E2K_BUSYSTATUS_BUSY]);

	monthyears = e2k_properties_get_prop (
		results[0].props, PR_FREEBUSY_OOF_MONTHS);
	fbdatas = e2k_properties_get_prop (
		results[0].props, PR_FREEBUSY_OOF_EVENTS);
	add_data_for_status (fb, monthyears, fbdatas, fb->events[E2K_BUSYSTATUS_OOF]);

	e2k_results_free (results, nresults);
	return fb;
}