Пример #1
0
gboolean
add_contact_from_test_case_verify (EBookClient *book_client,
                                   const gchar *case_name,
                                   EContact **contact)
{
	gchar *vcard;
	EContact *contact_orig;
	EContact *contact_final;
	gchar *uid;
	GError *error = NULL;

	vcard = new_vcard_from_test_case (case_name);
	contact_orig = e_contact_new_from_vcard (vcard);
	g_free (vcard);
	if (!e_book_client_add_contact_sync (book_client, contact_orig, &uid, NULL, &error))
		g_error ("add contact sync: %s", error->message);

	e_contact_set (contact_orig, E_CONTACT_UID, uid);

	if (!e_book_client_get_contact_sync (book_client, uid, &contact_final, NULL, &error))
		g_error ("get contact sync: %s", error->message);

        /* verify the contact was added "successfully" (not thorough) */
	g_assert (contacts_are_equal_shallow (contact_orig, contact_final));

	if (contact)
                *contact = contact_final;
	else
		g_object_unref (contact_final);
	g_object_unref (contact_orig);
	g_free (uid);

	return TRUE;
}
static void
e_book_backend_vcf_modify_contact (EBookBackendSync *backend,
				   EDataBook *book,
				   guint32 opid,
				   const gchar *vcard,
				   EContact **contact,
				   GError **perror)
{
	EBookBackendVCF *bvcf = E_BOOK_BACKEND_VCF (backend);
	GList *elem;
	const gchar *id;

	/* create a new ecard from the request data */
	*contact = e_contact_new_from_vcard (vcard);
	id = e_contact_get_const (*contact, E_CONTACT_UID);

	g_mutex_lock (bvcf->priv->mutex);
	elem = g_hash_table_lookup (bvcf->priv->contacts, id);
	if (!elem) {
		g_mutex_unlock (bvcf->priv->mutex);
		g_propagate_error (perror, EDB_ERROR (CONTACT_NOT_FOUND));
		return;
	}

	g_free (elem->data);
	elem->data = g_strdup (vcard);
	bvcf->priv->dirty = TRUE;
	if (!bvcf->priv->flush_timeout_tag)
		bvcf->priv->flush_timeout_tag = g_timeout_add (FILE_FLUSH_TIMEOUT,
							       vcf_flush_file, bvcf);
	g_mutex_unlock (bvcf->priv->mutex);
}
static gboolean
test_bulk_add_remove (EBookClient *client,
                      const gchar *vcard_str,
                      gint batch_size)
{
	gint i;
	GSList *contacts = NULL;
	GSList *added_uids = NULL;
	GSList *book_uids = NULL;
	EBookQuery *query = NULL;
	gchar *sexp = NULL;
	const GSList *l;

	query = e_book_query_any_field_contains ("");
	sexp = e_book_query_to_string (query);
	e_book_query_unref (query);

	for (i = 0; i < batch_size; ++i) {
		EContact *contact = e_contact_new_from_vcard (vcard_str);
		contacts = g_slist_append (contacts, contact);
	}

	g_print ("  * Bulk addition of %d contacts...\n", batch_size);
	/* Bulk addition */
	g_return_val_if_fail (e_book_client_add_contacts_sync (client, contacts, &added_uids, NULL, NULL), FALSE);
	g_return_val_if_fail (added_uids != NULL, FALSE);
	g_return_val_if_fail (added_uids->data != NULL, FALSE);
	g_return_val_if_fail (g_slist_length (added_uids) == batch_size, FALSE);

	/* Make sure the uids are in the address book */
	g_return_val_if_fail (e_book_client_get_contacts_uids_sync (client, sexp, &book_uids, NULL, NULL), FALSE);
	for (l = added_uids; l != NULL; l = l->next) {
		g_return_val_if_fail (check_string_in_slist (book_uids, (const gchar *) l->data), FALSE);
	}
	g_slist_free_full (book_uids, g_free);

	g_print ("  * Bulk removal of %d contacts...\n", batch_size);
	/* Bulk removal */
	g_return_val_if_fail (e_book_client_remove_contacts_sync (client, added_uids, NULL, NULL), FALSE);

	/* Make sure the uids are no longer in the address book */
	book_uids = NULL;
	g_return_val_if_fail (e_book_client_get_contacts_uids_sync (client, sexp, &book_uids, NULL, NULL), FALSE);
	for (l = added_uids; l != NULL; l = l->next) {
		g_return_val_if_fail (!check_string_in_slist (book_uids, (const gchar *) l->data), FALSE);
	}
	g_slist_free_full (book_uids, g_free);

	g_free (sexp);
	g_slist_free_full (added_uids, g_free);
	g_slist_free_full (contacts, g_object_unref);
	return TRUE;
}
Пример #4
0
gint
main (gint argc,
      gchar **argv)
{
    EBook *book;
    EContact *contact;
    GList *changes;
    GError *error = NULL;
    EBookChange *change;
    gchar *uri;

    g_type_init ();

    book = ebook_test_utils_book_new_temp (&uri);
    ebook_test_utils_book_open (book, FALSE);

    /* get an initial change set */
    if (!e_book_get_changes (book, "changeidtest", &changes, &error)) {
        printf ("failed to get changes: %s\n", error->message);
        exit (0);
    }

    /* make a change to the book */
    contact = e_contact_new_from_vcard (NEW_VCARD);
    ebook_test_utils_book_add_contact (book, contact);

    /* get another change set */
    if (!e_book_get_changes (book, "changeidtest", &changes, &error)) {
        printf ("failed to get second set of changes: %s\n", error->message);
        exit (0);
    }

    /* make sure that 1 change has occurred */
    if (g_list_length (changes) != 1) {
        printf ("got back %d changes, was expecting 1\n", g_list_length (changes));
        exit (0);
    }

    change = changes->data;
    if (change->change_type != E_BOOK_CHANGE_CARD_ADDED) {
        printf ("was expecting a CARD_ADDED change, but didn't get it.\n");
        exit (0);
    }

    printf ("got changed vcard back: %s\n", (gchar *) e_contact_get_const (change->contact, E_CONTACT_UID));

    e_book_free_change_list (changes);

    g_object_unref (contact);

    return 0;
}
Пример #5
0
/**
 * e_book_backend_db_cache_get_contacts:
 * @db: DB Handle
 * @query: an s-expression
 *
 * Returns a list of #EContact elements from @cache matching @query.
 * When done with the list, the caller must unref the contacts and
 * free the list.
 *
 * Returns: A #GList of pointers to #EContact.
 **/
GList *
e_book_backend_db_cache_get_contacts (DB *db,
                                      const gchar *query)
{
	DBC	*dbc;
	DBT	uid_dbt, vcard_dbt;
	gint	db_error;
	GList *list = NULL;
	EBookBackendSExp *sexp = NULL;
	EContact *contact;

	if (query) {
		sexp = e_book_backend_sexp_new (query);
		if (!sexp)
			return NULL;
	}

	db_error = db->cursor (db, NULL, &dbc, 0);
	if (db_error != 0) {
		g_warning ("db->cursor failed with %d", db_error);
		if (sexp)
			g_object_unref (sexp);
		return NULL;
	}

	memset (&vcard_dbt, 0 , sizeof (vcard_dbt));
	memset (&uid_dbt, 0, sizeof (uid_dbt));
	db_error = dbc->c_get (dbc, &uid_dbt, &vcard_dbt, DB_FIRST);

	while (db_error == 0) {
		if (vcard_dbt.data && !strncmp (vcard_dbt.data, "BEGIN:VCARD", 11)) {
			contact = e_contact_new_from_vcard (vcard_dbt.data);

			if (!sexp || e_book_backend_sexp_match_contact (sexp, contact))
				list = g_list_prepend (list, contact);
			else
				g_object_unref (contact);
		}
		db_error = dbc->c_get (dbc, &uid_dbt, &vcard_dbt, DB_NEXT);
	}

	db_error = dbc->c_close (dbc);
	if (db_error != 0)
		g_warning ("db->c_close failed with %d", db_error);

	if (sexp)
		g_object_unref (sexp);

	return g_list_reverse (list);
}
static EBookBackendSyncStatus
e_book_backend_scalix_create_contact (EBookBackendSync * backend,
                                      EDataBook * book,
                                      guint32 opid,
                                      const char *vcard, EContact ** contact)
{
    EBookBackendScalix *bs;
    EBookBackendScalixPrivate *priv;
    ScalixObject *object;
    EContact *econtact;
    gboolean res;
    char *uid;

    bs = E_BOOK_BACKEND_SCALIX (backend);
    priv = E_BOOK_BACKEND_SCALIX_GET_PRIVATE (bs);

    econtact = e_contact_new_from_vcard (vcard);
    gboolean is_list =
        GPOINTER_TO_INT (e_contact_get (econtact, E_CONTACT_IS_LIST));

    if (is_list == TRUE) {
        object = SCALIX_OBJECT (scalix_contact_list_new (vcard));
    } else {
        object = SCALIX_OBJECT (scalix_contact_new (vcard));
    }

    if (object == NULL) {
        return GNOME_Evolution_Addressbook_OtherError;
    }

    res = scalix_container_add_object (priv->container, object);

    if (res == FALSE) {
        g_object_unref (object);
        return GNOME_Evolution_Addressbook_OtherError;
    }

    g_object_get (object, "uid", &uid, NULL);
    g_object_unref (object);

    object = scalix_container_refresh_object (priv->container, uid);

    if (object == NULL) {
        return GNOME_Evolution_Addressbook_OtherError;
    }

    *contact = E_CONTACT (object);

    return GNOME_Evolution_Addressbook_Success;
}
static void
add_contacts (EwsBookBackendSqliteDB *ebsdb)
{
	GSList *contacts = NULL;
	EContact *con;

	g_print ("Adding contact \n");
	op = "add contact";

	con = e_contact_new_from_vcard (vcard_str);
	contacts = g_slist_append (contacts, con);
	ews_book_backend_sqlitedb_add_contacts (ebsdb, folderid, contacts, FALSE, &error);

	g_object_unref (con);
}
/*
 * Helper function to load a contact from a vcard file.
 */
static EContact *
contact_from_file (const gchar *vcard_file)
{
	EContact *contact;
	GError *error;
	gchar *vcard = NULL;

	if (!g_file_get_contents (vcard_file, &vcard, NULL, &error))
		g_error ("Failed to load vcard: %s", error->message);

	contact = e_contact_new_from_vcard (vcard);
	g_free (vcard);

	return contact;
}
/**
 * e_book_backend_sexp_match_vcard:
 * @sexp: an #EBookBackendSExp
 * @vcard: a VCard string
 *
 * Checks if @vcard matches @sexp.
 *
 * Returns: %TRUE if the VCard matches, %FALSE otherwise.
 **/
gboolean
e_book_backend_sexp_match_vcard (EBookBackendSExp *sexp,
                                 const gchar *vcard)
{
	EContact *contact;
	gboolean retval;

	contact = e_contact_new_from_vcard (vcard);

	retval = e_book_backend_sexp_match_contact (sexp, contact);

	g_object_unref (contact);

	return retval;
}
static void
insert_contact (EBookBackendVCF *vcf, gchar *vcard)
{
	EContact *contact = e_contact_new_from_vcard (vcard);
	gchar *id;

	id = e_contact_get (contact, E_CONTACT_UID);
	if (id) {
		gchar *vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);

		vcf->priv->contact_list = g_list_prepend (vcf->priv->contact_list, vcard);

		g_hash_table_insert (vcf->priv->contacts,
				     id,
				     vcf->priv->contact_list);
	}
}
Пример #11
0
static EBookBackendSyncStatus
e_book_backend_scalix_modify_contact (EBookBackendSync * backend,
                                      EDataBook * book,
                                      guint32 opid,
                                      const char *vcard, EContact ** contact)
{
    EBookBackendScalix *bs;
    EBookBackendScalixPrivate *priv;
    ScalixObject *object;
    gboolean res;
    EContact *econtact;

    bs = E_BOOK_BACKEND_SCALIX (backend);
    priv = E_BOOK_BACKEND_SCALIX_GET_PRIVATE (bs);

    econtact = e_contact_new_from_vcard (vcard);
    gboolean is_list =
        GPOINTER_TO_INT (e_contact_get (econtact, E_CONTACT_IS_LIST));

    if (is_list == TRUE) {
        object = SCALIX_OBJECT (scalix_contact_list_new (vcard));
    } else {
        object = SCALIX_OBJECT (scalix_contact_new (vcard));
    }

    if (object == NULL) {
        return GNOME_Evolution_Addressbook_OtherError;
    }

    /* REVIEW: do we have to ask the cache for the object here first?
     * (to "save" the mapi stuff?) */

    res = scalix_container_update_object (priv->container, object, TRUE);

    if (res == FALSE) {
        g_object_unref (object);
        return GNOME_Evolution_Addressbook_OtherError;
    }

    *contact = E_CONTACT (object);

    return GNOME_Evolution_Addressbook_Success;

}
static gpointer
book_view_thread (gpointer data)
{
	EDataBookView *book_view = data;
	VCFBackendSearchClosure *closure = get_closure (book_view);
	const gchar *query;
	GList *l;

	/* ref the book view because it'll be removed and unrefed
	   when/if it's stopped */
	e_data_book_view_ref (book_view);

	query = e_data_book_view_get_card_query (book_view);

	if ( !strcmp (query, "(contains \"x-evolution-any-field\" \"\")"))
		e_data_book_view_notify_status_message (book_view, _("Loading..."));
	else
		e_data_book_view_notify_status_message (book_view, _("Searching..."));

	d(printf ("signalling parent thread\n"));
	e_flag_set (closure->running);

	for (l = closure->bvcf->priv->contact_list; l; l = l->next) {
		gchar *vcard_string = l->data;
		EContact *contact = e_contact_new_from_vcard (vcard_string);
		e_data_book_view_notify_update (closure->view, contact);
		g_object_unref (contact);

		if (!e_flag_is_set (closure->running))
			break;
	}

	if (e_flag_is_set (closure->running))
		e_data_book_view_notify_complete (closure->view, NULL /* Success */);

	/* unref the book view */
	e_data_book_view_unref (book_view);

	d(printf ("finished initial population of book view\n"));

	return NULL;
}
static EContact *
do_create (EBookBackendVCF  *bvcf,
	  const gchar     *vcard_req,
	  gboolean        dirty_the_file)
{
	gchar           *id;
	EContact       *contact;
	gchar           *vcard;
	const gchar     *rev;

	/* at the very least we need the unique_id generation to be
	   protected by the lock, even if the actual vcard parsing
	   isn't. */
	g_mutex_lock (bvcf->priv->mutex);
	id = e_book_backend_vcf_create_unique_id ();

	contact = e_contact_new_from_vcard (vcard_req);
	e_contact_set (contact, E_CONTACT_UID, id);
	g_free (id);

	rev = e_contact_get_const (contact,  E_CONTACT_REV);
	if (!(rev && *rev))
		set_revision (contact);

	vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);

	insert_contact (bvcf, vcard);

	if (dirty_the_file) {
		bvcf->priv->dirty = TRUE;

		if (!bvcf->priv->flush_timeout_tag)
			bvcf->priv->flush_timeout_tag = g_timeout_add (FILE_FLUSH_TIMEOUT,
								       vcf_flush_file, bvcf);
	}

	g_mutex_unlock (bvcf->priv->mutex);

	return contact;
}
/**
 * e_book_backend_db_cache_get_contact:
 * @db: DB Handle
 * @uid: a unique contact ID
 *
 * Get a cached contact. Note that the returned #EContact will be
 * newly created, and must be unreffed by the caller when no longer
 * needed.
 *
 * Returns: A cached #EContact, or %NULL if @uid is not cached.
 **/
EContact *
e_book_backend_db_cache_get_contact (DB *db, const gchar *uid)
{
	DBT	uid_dbt, vcard_dbt;
	gint	db_error;
	EContact *contact = NULL;

	g_return_val_if_fail (uid != NULL, NULL);

	string_to_dbt (uid, &uid_dbt);
	memset (&vcard_dbt, 0 , sizeof (vcard_dbt));
	vcard_dbt.flags = DB_DBT_MALLOC;

	db_error = db->get (db, NULL, &uid_dbt, &vcard_dbt,0);
	if (db_error != 0) {
		g_warning ("db->get failed with %d", db_error);
		return NULL;
	}

	contact = e_contact_new_from_vcard ((const gchar *)vcard_dbt.data);
	g_free (vcard_dbt.data);
	return contact;
}
/**
 * e_data_book_view_notify_update_vcard:
 * @book_view: an #EDataBookView
 * @vcard: a plain vCard
 *
 * Notify listeners that @vcard has changed. This can
 * trigger an add, change or removal event depending on
 * whether the change causes the contact to start matching,
 * no longer match, or stay matching the query specified
 * by @book_view.  This method should be preferred over
 * #e_data_book_view_notify_update when the native
 * representation of a contact is a vCard.
 **/
void
e_data_book_view_notify_update_vcard (EDataBookView *book_view, gchar *vcard)
{
    EDataBookViewPrivate *priv = book_view->priv;
    gboolean currently_in_view, want_in_view;
    const gchar *id;
    EContact *contact;

    if (!priv->running) {
        g_free (vcard);
        return;
    }

    g_mutex_lock (priv->pending_mutex);

    contact = e_contact_new_from_vcard (vcard);
    id = e_contact_get_const (contact, E_CONTACT_UID);
    currently_in_view = id_is_in_view (book_view, id);
    want_in_view =
        e_book_backend_sexp_match_contact (priv->card_sexp, contact);

    if (want_in_view) {
        if (currently_in_view)
            notify_change (book_view, vcard);
        else
            notify_add (book_view, id, vcard);
    } else {
        if (currently_in_view)
            notify_remove (book_view, id);
    }

    /* Do this last so that id is still valid when notify_ is called */
    g_object_unref (contact);
    g_free (vcard);

    g_mutex_unlock (priv->pending_mutex);
}
Пример #16
0
static gboolean
test_econtact (const gchar *vcard_str)
{
	EContact *c1, *c2;
	gchar *str;

	/* do not parse */
	c1 = e_contact_new_from_vcard (vcard_str);
	str = e_vcard_to_string (E_VCARD (c1), EVC_FORMAT_VCARD_30);
	g_return_val_if_fail (str != NULL, FALSE);
	g_return_val_if_fail (g_ascii_strcasecmp (str, vcard_str) == 0, FALSE);
	g_return_val_if_fail (e_vcard_is_parsed (E_VCARD (c1)) == FALSE, FALSE);

	g_free (str);

	/* parse */
	e_contact_get_const (c1, E_CONTACT_UID);
	g_return_val_if_fail (e_vcard_is_parsed (E_VCARD (c1)) == TRUE, FALSE);
	str = e_vcard_to_string (E_VCARD (c1), EVC_FORMAT_VCARD_30);
	g_return_val_if_fail (str != NULL, FALSE);
	g_return_val_if_fail (g_ascii_strcasecmp (str, vcard_str) == 0, FALSE);

	g_free (str);

	/* parse */
	e_contact_get_const (c1, E_CONTACT_FULL_NAME);
	str = e_vcard_to_string (E_VCARD (c1), EVC_FORMAT_VCARD_30);
	g_return_val_if_fail (str != NULL, FALSE);
	g_return_val_if_fail (g_ascii_strcasecmp (str, vcard_str) == 0, FALSE);

	g_free (str);
	g_object_unref (c1);

	/* not parsed again */
	c1 = e_contact_new_from_vcard (vcard_str);
	e_contact_set (c1, E_CONTACT_UID, "other-uid");
	g_return_val_if_fail (e_vcard_is_parsed (E_VCARD (c1)) == FALSE, FALSE);
	g_return_val_if_fail (compare_single_value (E_VCARD (c1), "UID", "other-uid"), FALSE);
	g_return_val_if_fail (e_vcard_is_parsed (E_VCARD (c1)) == FALSE, FALSE);
	str = e_vcard_to_string (E_VCARD (c1), EVC_FORMAT_VCARD_30);
	c2 = e_contact_new_from_vcard (str);
	g_return_val_if_fail (e_vcard_is_parsed (E_VCARD (c2)) == FALSE, FALSE);
	g_free (str);

	g_return_val_if_fail (compare_single_value (E_VCARD (c2), "UID", "other-uid"), FALSE);

	g_object_unref (c2);

	/* parse */
	e_contact_get_const (c1, E_CONTACT_FULL_NAME);
	g_return_val_if_fail (e_vcard_is_parsed (E_VCARD (c1)) == TRUE, FALSE);
	g_return_val_if_fail (compare_single_value (E_VCARD (c1), "UID", "other-uid"), FALSE);
	str = e_vcard_to_string (E_VCARD (c1), EVC_FORMAT_VCARD_30);
	c2 = e_contact_new_from_vcard (str);
	g_free (str);

	g_return_val_if_fail (compare_single_value (E_VCARD (c2), "UID", "other-uid"), FALSE);
	g_return_val_if_fail (has_only_one (E_VCARD (c1), "UID"), FALSE);
	g_return_val_if_fail (has_only_one (E_VCARD (c2), "UID"), FALSE);

	g_object_unref (c2);
	g_object_unref (c1);

	/* do not parse */
	c1 = e_contact_new_from_vcard_with_uid (vcard_str, "other-uid");
	g_return_val_if_fail (e_vcard_is_parsed (E_VCARD (c1)) == FALSE, FALSE);
	g_return_val_if_fail (compare_single_value (E_VCARD (c1), "UID", "other-uid"), FALSE);
	g_return_val_if_fail (e_vcard_is_parsed (E_VCARD (c1)) == FALSE, FALSE);
	str = e_vcard_to_string (E_VCARD (c1), EVC_FORMAT_VCARD_30);
	c2 = e_contact_new_from_vcard (str);
	g_free (str);

	g_return_val_if_fail (compare_single_value (E_VCARD (c2), "UID", "other-uid"), FALSE);

	g_object_unref (c2);

	/* parse */
	e_contact_get_const (c1, E_CONTACT_FULL_NAME);
	g_return_val_if_fail (compare_single_value (E_VCARD (c1), "UID", "other-uid"), FALSE);
	g_return_val_if_fail (e_vcard_is_parsed (E_VCARD (c1)) == TRUE, FALSE);
	str = e_vcard_to_string (E_VCARD (c1), EVC_FORMAT_VCARD_30);
	c2 = e_contact_new_from_vcard (str);
	g_free (str);

	g_return_val_if_fail (compare_single_value (E_VCARD (c2), "UID", "other-uid"), FALSE);
	g_return_val_if_fail (has_only_one (E_VCARD (c1), "UID"), FALSE);
	g_return_val_if_fail (has_only_one (E_VCARD (c2), "UID"), FALSE);

	g_object_unref (c2);
	g_object_unref (c1);

	return TRUE;
}
static void
e_book_backend_webdav_modify_contacts (EBookBackend *backend,
                                       EDataBook *book,
                                       guint32 opid,
                                       GCancellable *cancellable,
                                       const GSList *vcards)
{
	EBookBackendWebdav        *webdav  = E_BOOK_BACKEND_WEBDAV (backend);
	EBookBackendWebdavPrivate *priv    = webdav->priv;
	EContact                  *contact;
	GSList                     modified_contacts = {NULL,};
	const gchar                *uid;
	const gchar                *etag;
	guint status;
	gchar *status_reason = NULL;
	const gchar *vcard = vcards->data;

	if (!e_backend_get_online (E_BACKEND (backend))) {
		e_data_book_respond_create_contacts (
			book, opid,
			EDB_ERROR (REPOSITORY_OFFLINE), NULL);
		return;
	}

	/* We make the assumption that the vCard list we're passed is always exactly one element long, since we haven't specified "bulk-modifies"
	 * in our static capability list. This is because there is no clean way to roll back changes in case of an error. */
	if (vcards->next != NULL) {
		e_data_book_respond_modify_contacts (
			book, opid,
			EDB_ERROR_EX (
				NOT_SUPPORTED,
				_("The backend does not support bulk modifications")),
			NULL);
		return;
	}

	/* modify contact */
	contact = e_contact_new_from_vcard (vcard);
	status = upload_contact (webdav, contact, &status_reason, cancellable);
	if (status != 201 && status != 204) {
		g_object_unref (contact);
		if (status == 401 || status == 407) {
			e_data_book_respond_modify_contacts (book, opid, webdav_handle_auth_request (webdav), NULL);
			g_free (status_reason);
			return;
		}
		/* data changed on server while we were editing */
		if (status == 412) {
			/* too bad no special error code in evolution for this... */
			e_data_book_respond_modify_contacts (book, opid,
				e_data_book_create_error_fmt (
				E_DATA_BOOK_STATUS_OTHER_ERROR,
				_("Contact on server changed -> not modifying")),
				NULL);
			g_free (status_reason);
			return;
		}

		e_data_book_respond_modify_contacts (book, opid,
			e_data_book_create_error_fmt (
			E_DATA_BOOK_STATUS_OTHER_ERROR,
			_("Modify contact failed with HTTP status: %d (%s)"),
			status, status_reason),
			NULL);
		g_free (status_reason);
		return;
	}

	g_free (status_reason);

	uid = e_contact_get_const (contact, E_CONTACT_UID);
	g_mutex_lock (&priv->cache_lock);
	e_book_backend_cache_remove_contact (priv->cache, uid);

	etag = e_contact_get_const (contact, E_CONTACT_REV);

	/* PUT request didn't return an etag? try downloading to get one */
	if (etag == NULL || (etag[0] == 'W' && etag[1] == '/')) {
		EContact *new_contact;

		g_warning ("Server didn't return etag for modified address resource");
		new_contact = download_contact (webdav, uid, cancellable);
		if (new_contact != NULL) {
			contact = new_contact;
		}
	}
	e_book_backend_cache_add_contact (priv->cache, contact);
	g_mutex_unlock (&priv->cache_lock);

	modified_contacts.data = contact;
	e_data_book_respond_modify_contacts (book, opid, EDB_ERROR (SUCCESS), &modified_contacts);

	g_object_unref (contact);
}
Пример #18
0
GSList *
eab_contact_list_from_string (const gchar *str)
{
	GSList *contacts = NULL;
	GString *gstr = g_string_new (NULL);
	gchar *str_stripped;
	gchar *p = (gchar *) str;
	gchar *q;

	if (!p)
		return NULL;

	if (!strncmp (p, "Book: ", 6)) {
		p = strchr (p, '\n');
		if (!p) {
			g_warning (G_STRLOC ": Got book but no newline!");
			return NULL;
		}
		p++;
	}

	while (*p) {
		if (*p != '\r') g_string_append_c (gstr, *p);

		p++;
	}

	p = str_stripped = g_string_free (gstr, FALSE);

	/* Note: The vCard standard says
	 *
	 * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
	 *         items *CRLF "END" [ws] ":" [ws] "VCARD"
	 *
	 * which means we can have whitespace (e.g. "BEGIN : VCARD"). So we're not being
	 * fully compliant here, although I'm not sure it matters. The ideal solution
	 * would be to have a vcard parsing function that returned the end of the vcard
	 * parsed. Arguably, contact list parsing should all be in libebook's e-vcard.c,
	 * where we can do proper parsing and validation without code duplication. */

	for (p = eab_strstrcase (p, "BEGIN:VCARD"); p; p = eab_strstrcase (q, "\nBEGIN:VCARD")) {
		gchar *card_str;

		if (*p == '\n')
			p++;

		for (q = eab_strstrcase (p, "END:VCARD"); q; q = eab_strstrcase (q, "END:VCARD")) {
			gchar *temp;

			q += 9;
			temp = q;
			if (*temp)
				temp += strspn (temp, "\r\n\t ");

			if (*temp == '\0' || !g_ascii_strncasecmp (temp, "BEGIN:VCARD", 11))
				break;  /* Found the outer END:VCARD */
		}

		if (!q)
			break;

		card_str = g_strndup (p, q - p);
		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard (card_str));
		g_free (card_str);
	}

	g_free (str_stripped);

	return g_slist_reverse (contacts);
}
gint
main (gint argc,
      gchar **argv)
{
	EBookClient *book_client;
	GError *error = NULL;
	EContact *contact;
	gchar *vcard;

	main_initialize ();

	/*
	 * Setup
	 */
	book_client = new_temp_client (NULL);
	g_return_val_if_fail (book_client != NULL, 1);

	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
		report_error ("client open sync", &error);
		g_object_unref (book_client);
		return 1;
	}

	/*
	 * Sync version
	 */
	if (!add_contact_from_test_case_verify (book_client, "simple-1", &contact)) {
		g_object_unref (book_client);
		return 1;
	}

	g_object_unref (contact);

	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
		report_error ("client remove sync", &error);
		g_object_unref (book_client);
		return 1;
	}

	g_object_unref (book_client);

	/*
	 * Async version
	 */
	book_client = new_temp_client (NULL);
	g_return_val_if_fail (book_client != NULL, 1);

	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
		report_error ("client open sync", &error);
		g_object_unref (book_client);
		return 1;
	}

	vcard = new_vcard_from_test_case ("simple-1");
	contact = e_contact_new_from_vcard (vcard);
	g_free (vcard);

	e_book_client_add_contact (book_client, contact, NULL, add_contact_cb, NULL);
	g_object_unref (contact);

	start_main_loop (NULL, NULL);

	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
		report_error ("client remove sync", &error);
		g_object_unref (book_client);
		return 1;
	}

	g_object_unref (book_client);

	return get_main_loop_stop_result ();
}
static void
ebbm_contacts_modify_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *vcards, GSList **modified_contacts, GError **error)
{
	EBookBackendMAPIContacts *ebmac;
	EBookBackendMAPIContactsPrivate *priv;
	EMapiConnection *conn;
	EMapiCreateitemData mcd;
	EContact *contact;
	GError *mapi_error = NULL;
	mapi_id_t mid;

	e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
	e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
	e_mapi_return_data_book_error_if_fail (vcards != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
	e_mapi_return_data_book_error_if_fail (modified_contacts != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);

	ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
	e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);

	priv = ebmac->priv;
	e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);

	if (vcards->next != NULL) {
		g_propagate_error (error, EDB_ERROR_EX (NOT_SUPPORTED, _("The backend does not support bulk modifications")));
		return;
	}

	e_book_backend_mapi_lock_connection (ebma);

	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
	if (!conn) {
		e_book_backend_mapi_unlock_connection (ebma);

		if (!mapi_error)
			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
		else
			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
		g_clear_error (&mapi_error);

		return;
	}

	contact = e_contact_new_from_vcard (vcards->data);
	if (!contact) {
		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
		e_book_backend_mapi_unlock_connection (ebma);
		return;
	}

	e_book_backend_mapi_get_db (ebma, &mcd.db);
	mcd.contact = contact;

	if (e_mapi_util_mapi_id_from_string (e_contact_get_const (contact, E_CONTACT_UID), &mid)) {
		mapi_object_t obj_folder;
		gboolean status;

		status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error);

		if (status) {
			status = e_mapi_connection_modify_object (conn, &obj_folder, mid,
								  ebbm_contact_to_object, &mcd,
								  cancellable, &mapi_error);

			e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
		}

		e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
		if (!status) {
			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to modify item on a server"));
			if (mapi_error)
				g_error_free (mapi_error);

			g_object_unref (contact);
		} else {
			*modified_contacts = g_slist_append (NULL, contact);
		}
	} else {
		g_debug ("%s: Failed to decode MID from '%s'", G_STRFUNC, (const gchar *) e_contact_get_const (contact, E_CONTACT_UID));
	}

	e_book_backend_mapi_unlock_connection (ebma);
}
static gboolean
test_bulk_modify (EBookClient *client,
                  const gchar *vcard_str,
                  gint batch_size)
{
	gint i;
	EContact *contact;
	GSList *contacts = NULL;
	GSList *added_uids = NULL;
	const GSList *l, *ll;
	const gchar *old_first_name = "xyz mix";
	const gchar *new_first_name = "abc mix";

	for (i = 0; i < batch_size; ++i) {
		EContact *contact = e_contact_new_from_vcard (vcard_str);
		contacts = g_slist_append (contacts, contact);
	}

	g_print ("  * Bulk addition of %d contacts...\n", batch_size);
	/* Bulk addition */
	g_return_val_if_fail (e_book_client_add_contacts_sync (client, contacts, &added_uids, NULL, NULL), FALSE);
	g_return_val_if_fail (added_uids != NULL, FALSE);
	g_return_val_if_fail (added_uids->data != NULL, FALSE);
	g_return_val_if_fail (g_slist_length (added_uids) == batch_size, FALSE);

	g_print ("  * Bulk modification of %d contacts...\n", batch_size);
	ll = added_uids;
	for (l = contacts; l != NULL; l = l->next) {
		const gchar * uid = ll->data;
		contact = E_CONTACT (l->data);

		/* Set contact UID */
		e_contact_set (contact, E_CONTACT_UID, uid);

		/* Change contact first name */
		e_contact_set (contact, E_CONTACT_GIVEN_NAME, new_first_name);

		ll = ll->next;
	}
	g_return_val_if_fail (e_book_client_modify_contacts_sync (client, contacts, NULL, NULL), FALSE);

	/* Validate */
	for (ll = added_uids; ll != NULL; ll = ll->next) {
		const gchar *first_name;
		const gchar *uid = ll->data;
		contact = NULL;

		g_return_val_if_fail (e_book_client_get_contact_sync (client, uid, &contact, NULL, NULL), FALSE);

		/* Check contact first name */
		first_name = e_contact_get_const (contact, E_CONTACT_GIVEN_NAME);
		g_return_val_if_fail (g_strcmp0 (first_name, new_first_name) == 0, FALSE);

		g_object_unref (contact);
	}

	/* Test failure case */
	g_print ("  * Bulk modification of %d contacts (expected failure)...\n", batch_size);
	contact = E_CONTACT (g_slist_nth_data (contacts, g_slist_length (contacts) - 2));
	g_return_val_if_fail (e_book_client_remove_contact_sync (client, contact, NULL, NULL), FALSE);
	for (l = contacts; l != NULL; l = l->next) {
		contact = E_CONTACT (l->data);
		/* Change contact first name */
		e_contact_set (contact, E_CONTACT_GIVEN_NAME, old_first_name);
	}
	g_return_val_if_fail (!e_book_client_modify_contacts_sync (client, contacts, NULL, NULL), FALSE);

	/* Remove the UID that no longer exists from the added_uid list */
	added_uids = g_slist_delete_link (added_uids, g_slist_nth (added_uids, g_slist_length (added_uids) - 2));

	/* Validate */
	for (ll = added_uids; ll != NULL; ll = ll->next) {
		const gchar *first_name;
		const gchar *uid = ll->data;
		contact = NULL;

		g_return_val_if_fail (e_book_client_get_contact_sync (client, uid, &contact, NULL, NULL), FALSE);

		/* Check contact first name */
		first_name = e_contact_get_const (contact, E_CONTACT_GIVEN_NAME);
		g_return_val_if_fail (g_strcmp0 (first_name, new_first_name) == 0, FALSE);

		g_object_unref (contact);
	}

	g_print ("  * Bulk removal of %d contacts...\n", batch_size);

	/* Bulk removal */
	g_return_val_if_fail (e_book_client_remove_contacts_sync (client, added_uids, NULL, NULL), FALSE);

	g_slist_free_full (added_uids, g_free);
	g_slist_free_full (contacts, g_object_unref);
	return TRUE;
}
static void
ebbm_contacts_create_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable, const GSList *vcards, GSList **added_contacts, GError **error)
{
	EBookBackendMAPIContacts *ebmac;
	EBookBackendMAPIContactsPrivate *priv;
	EMapiConnection *conn;
	EMapiCreateitemData mcd;
	GError *mapi_error = NULL;
	mapi_id_t mid = 0;
	mapi_object_t obj_folder;
	gboolean status;
	gchar *id;
	EContact *contact;

	e_mapi_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
	e_mapi_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
	e_mapi_return_data_book_error_if_fail (vcards != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
	e_mapi_return_data_book_error_if_fail (added_contacts != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);

	ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
	e_mapi_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);

	priv = ebmac->priv;
	e_mapi_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);

	if (vcards->next) {
		g_propagate_error (error, EDB_ERROR_EX (NOT_SUPPORTED, _("The backend does not support bulk additions")));
		return;
	}

	e_book_backend_mapi_lock_connection (ebma);

	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
	if (!conn) {
		e_book_backend_mapi_unlock_connection (ebma);

		if (!mapi_error)
			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
		else
			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
		g_clear_error (&mapi_error);

		return;
	}

	contact = e_contact_new_from_vcard (vcards->data);
	if (!contact) {
		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
		e_book_backend_mapi_unlock_connection (ebma);
		return;
	}

	e_book_backend_mapi_get_db (ebma, &mcd.db);
	mcd.contact = contact;

	status = ebbm_contacts_open_folder (ebmac, conn, &obj_folder, cancellable, &mapi_error);

	if (status) {
		e_mapi_connection_create_object (conn, &obj_folder, E_MAPI_CREATE_FLAG_NONE,
						 ebbm_contact_to_object, &mcd,
						 &mid, cancellable, &mapi_error);
		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
	}

	e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
	e_book_backend_mapi_unlock_connection (ebma);

	if (!mid) {
		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to create item on a server"));

		if (mapi_error)
			g_error_free (mapi_error);

		g_object_unref (contact);
		return;
	}

	id = e_mapi_util_mapi_id_to_string (mid);

	/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
	e_contact_set (contact, E_CONTACT_UID, id);
	e_contact_set (contact, E_CONTACT_BOOK_UID, e_book_backend_mapi_get_book_uid (ebma));

	g_free (id);

	*added_contacts = g_slist_append (NULL, contact);
}