[evolution-data-server/openismus-work] Initially make the local addressbook store received binary photos as files and report the uris.
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/openismus-work] Initially make the local addressbook store received binary photos as files and report the uris.
- Date: Sat, 2 Jul 2011 22:36:36 +0000 (UTC)
commit df703351641f2725f63d1c82854ff1be93df625d
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date: Fri Jul 1 16:00:48 2011 -0400
Initially make the local addressbook store received binary photos as files and report the uris.
addressbook/backends/file/e-book-backend-file.c | 311 +++++++++++++++++++----
1 files changed, 263 insertions(+), 48 deletions(-)
---
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c
index a65e126..2c50426 100644
--- a/addressbook/backends/file/e-book-backend-file.c
+++ b/addressbook/backends/file/e-book-backend-file.c
@@ -80,12 +80,219 @@ struct _EBookBackendFilePrivate {
guint id;
};
+typedef enum {
+ GET_PATH_DB_DIR,
+ GET_PATH_PHOTO_DIR,
+ GET_PATH_PHOTO
+} GetPathType;
+
+typedef enum {
+ STATUS_NORMAL = 0,
+ STATUS_MODIFIED,
+ STATUS_ERROR
+} PhotoModifiedStatus;
+
G_LOCK_DEFINE_STATIC (global_env);
static struct {
gint ref_count;
DB_ENV *env;
} global_env;
+static gboolean
+create_directory (const gchar *dirname,
+ GError **error)
+{
+ gint rv;
+
+ rv = g_mkdir_with_parents (dirname, 0700);
+ if (rv == -1 && errno != EEXIST) {
+ g_warning ("failed to make directory %s: %s", dirname, g_strerror (errno));
+ if (errno == EACCES || errno == EPERM)
+ g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
+ else
+ g_propagate_error (error,
+ e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR,
+ "Failed to make directory %s: %s",
+ dirname, g_strerror (errno)));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gchar *
+e_book_backend_file_extract_path_from_source (ESource *source,
+ GetPathType path_type,
+ EContact *contact,
+ EContactField field)
+{
+ const gchar *user_data_dir;
+ const gchar *source_dir;
+ gchar *mangled_source_dir;
+ gchar *filename = NULL, *str;
+ gchar *uid = NULL, *final = NULL;
+
+ user_data_dir = e_get_user_data_dir ();
+ source_dir = e_source_peek_relative_uri (source);
+
+ if (!source_dir || !g_str_equal (source_dir, "system"))
+ source_dir = e_source_peek_uid (source);
+
+ /* Mangle the URI to not contain invalid characters. */
+ mangled_source_dir = g_strdelimit (g_strdup (source_dir), ":/", '_');
+
+ if (contact && field) {
+ uid = g_strdup (e_contact_get_const (contact, E_CONTACT_UID));
+ uid = g_strdelimit (uid, NULL, '_');
+
+ str = g_strdup (e_contact_field_name (field));
+ str = g_strdelimit (str, NULL, '_');
+
+ final = g_strdup_printf ("%s_%s", uid, str);
+ g_free (str);
+ }
+
+ switch (path_type) {
+ case GET_PATH_DB_DIR:
+ filename = g_build_filename
+ (user_data_dir, "addressbook", mangled_source_dir, "db", NULL);
+ break;
+ case GET_PATH_PHOTO_DIR:
+ filename = g_build_filename
+ (user_data_dir, "addressbook", mangled_source_dir, "photos", NULL);
+ break;
+ case GET_PATH_PHOTO:
+ filename = g_build_filename
+ (user_data_dir, "addressbook", mangled_source_dir, "photos", final, NULL);
+ break;
+ default:
+ break;
+ }
+ g_free (mangled_source_dir);
+ g_free (final);
+ g_free (uid);
+
+ return filename;
+}
+
+static gchar *
+safe_name_for_photo (EBookBackendFile *bf,
+ ESource *source,
+ EContact *contact,
+ EContactField field)
+{
+ gchar *filename = NULL, *tmp;
+ gint i = 0;
+
+ do {
+ g_free (filename);
+ tmp = e_book_backend_file_extract_path_from_source (source, GET_PATH_PHOTO, contact, field);
+ filename = g_strdup_printf ("%s_%02d.data", tmp, i);
+ g_free (tmp);
+ i++;
+ } while (g_file_test (filename, G_FILE_TEST_EXISTS));
+
+ return filename;
+}
+
+static PhotoModifiedStatus
+maybe_transform_vcard_field_for_photo (EBookBackendFile *bf,
+ ESource *source,
+ EContact *contact,
+ EContactField field,
+ GError **error)
+{
+ PhotoModifiedStatus status = STATUS_NORMAL;
+ EContactPhoto *photo;
+
+ if (field != E_CONTACT_PHOTO && field != E_CONTACT_LOGO)
+ return status;
+
+ photo = e_contact_get (contact, field);
+ if (!photo)
+ return status;
+
+ if (photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
+ EContactPhoto *new_photo;
+ gchar *new_photo_path;
+ gchar *directory;
+ gchar *uri;
+
+ /* XXX Create a good file extension based on mime type */
+ new_photo_path = safe_name_for_photo (bf, source, contact, field);
+ directory = g_path_get_dirname (new_photo_path);
+ g_free (directory);
+
+ if ((uri =
+ g_filename_to_uri (new_photo_path, NULL, error)) == NULL) {
+
+ status = STATUS_ERROR;
+ } else if (!create_directory (directory, error)) {
+
+ g_free (uri);
+ status = STATUS_ERROR;
+ } else if (!g_file_set_contents (new_photo_path,
+ (const gchar *)photo->data.inlined.data,
+ photo->data.inlined.length,
+ error)) {
+
+ g_free (uri);
+ status = STATUS_ERROR;
+ } else {
+ g_message ("Transforming vcard photo to uri %s\n", uri);
+
+ new_photo = g_new (EContactPhoto, 1);
+ new_photo->type = E_CONTACT_PHOTO_TYPE_URI;
+ new_photo->data.uri = uri;
+
+ e_contact_set (contact, field, new_photo);
+
+ status = STATUS_MODIFIED;
+ }
+
+ g_free (new_photo_path);
+ }
+
+ return status;
+}
+
+/*
+ * When a contact is added or modified we receive a vCard,
+ * this function checks if we've received inline data
+ * and replaces it with a uri notation.
+ *
+ * Returns the actual data and stores the size in 'len'
+ */
+static PhotoModifiedStatus
+maybe_transform_vcard_for_photo (EBookBackendFile *bf,
+ EContact *contact,
+ gchar **vcard_ret,
+ GError **error)
+{
+ EBookBackend *backend = E_BOOK_BACKEND (bf);
+ ESource *source = e_book_backend_get_source (backend);
+ gboolean modified = FALSE;
+ PhotoModifiedStatus status;
+
+ status = maybe_transform_vcard_field_for_photo (bf, source, contact, E_CONTACT_PHOTO, error);
+ modified = (status == STATUS_MODIFIED);
+
+ if (status != STATUS_ERROR) {
+ status = maybe_transform_vcard_field_for_photo (bf, source, contact, E_CONTACT_LOGO, error);
+ modified = modified || (status == STATUS_MODIFIED);
+ }
+
+ if (status != STATUS_ERROR) {
+ if (modified) {
+ *vcard_ret = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+ status = STATUS_MODIFIED;
+ }
+ }
+
+ return status;
+}
+
+
+
static void
db_error_to_gerror (const gint db_error, GError **perror)
{
@@ -195,18 +402,22 @@ do_create(EBookBackendFile *bf,
EContact **contact,
GError **perror)
{
- DB *db = bf->priv->file_db;
- DBT id_dbt, vcard_dbt;
- gint db_error;
- gchar *id;
- gchar *vcard;
- const gchar *rev;
+ DB *db = bf->priv->file_db;
+ DBT id_dbt, vcard_dbt;
+ gint db_error;
+ gchar *id = NULL;
+ gchar *vcard = NULL;
+ const gchar *rev;
+ PhotoModifiedStatus status = STATUS_NORMAL;
g_assert (bf);
g_assert (vcard_req);
g_assert (contact);
retry:
+ g_free (id);
+ g_free (vcard);
+
id = e_book_backend_file_create_next_id (bf);
string_to_dbt (id, &id_dbt);
@@ -223,9 +434,6 @@ do_create(EBookBackendFile *bf,
db_error = db->put (db, NULL, &id_dbt, &vcard_dbt, DB_NOOVERWRITE);
- g_free (vcard);
- g_free (id);
-
if (0 == db_error) {
db_error = db->sync (db, 0);
if (db_error != 0) {
@@ -242,9 +450,43 @@ do_create(EBookBackendFile *bf,
}
}
- db_error_to_gerror (db_error, perror);
+ /* If we havent failed yet, now we might have to overwrite
+ * the entry with a transformed contact.
+ *
+ * We wait until the last minute to re-enter any new contact
+ * with photo data into the database because we need to know
+ * the contact UID in order to know where to store the data
+ * (and in order to derive the correct uri for the vCard).
+ */
+ if (0 == db_error) {
- return db_error == 0;
+ gchar *transformed_vcard = NULL;
+
+ status = maybe_transform_vcard_for_photo (bf, *contact, &transformed_vcard, perror);
+
+ if (status == STATUS_MODIFIED && transformed_vcard) {
+ /* XXX
+ *
+ * Here we need to mark the newly entered contact as
+ * modified and tell the sender that it's contact was
+ * implicitly modified.
+ *
+ */
+ string_to_dbt (id, &id_dbt);
+ string_to_dbt (transformed_vcard, &vcard_dbt);
+
+ db_error = db->put (db, NULL, &id_dbt, &vcard_dbt, 0);
+ }
+ g_free (transformed_vcard);
+ }
+
+ g_free (vcard);
+ g_free (id);
+
+ if (perror && !perror)
+ db_error_to_gerror (db_error, perror);
+
+ return db_error == 0 && status == STATUS_NORMAL;
}
static void
@@ -275,8 +517,8 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
DBT id_dbt;
gint db_error;
gchar *id;
- GList *l;
- GList *removed_cards = NULL;
+ GList *l;
+ GList *removed_cards = NULL;
for (l = id_list; l; l = l->next) {
id = l->data;
@@ -306,6 +548,11 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
gchar *id = l->data;
e_book_backend_summary_remove_contact (bf->priv->summary, id);
}
+
+ /* XXX Collect the uris that need to be removed and track the views
+ * until they've received the remove notification before actually
+ * deleting the photo fields.
+ */
}
static void
@@ -1018,31 +1265,6 @@ e_book_backend_file_get_changes (EBookBackendSync *backend,
e_dbhash_destroy (ehash);
}
-static gchar *
-e_book_backend_file_extract_path_from_source (ESource *source)
-{
- const gchar *user_data_dir;
- const gchar *source_dir;
- gchar *mangled_source_dir;
- gchar *filename;
-
- user_data_dir = e_get_user_data_dir ();
- source_dir = e_source_peek_relative_uri (source);
-
- if (!source_dir || !g_str_equal (source_dir, "system"))
- source_dir = e_source_peek_uid (source);
-
- /* Mangle the URI to not contain invalid characters. */
- mangled_source_dir = g_strdelimit (g_strdup (source_dir), ":/", '_');
-
- filename = g_build_filename (
- user_data_dir, "addressbook", mangled_source_dir, NULL);
-
- g_free (mangled_source_dir);
-
- return filename;
-}
-
static void
e_book_backend_file_authenticate_user (EBookBackendSync *backend,
EDataBook *book,
@@ -1255,7 +1477,7 @@ e_book_backend_file_load_source (EBookBackend *backend,
struct stat sb;
DB_HASH_STAT *hashstat;
- dirname = e_book_backend_file_extract_path_from_source (source);
+ dirname = e_book_backend_file_extract_path_from_source (source, GET_PATH_DB_DIR, NULL, 0);
filename = g_build_filename (dirname, "addressbook.db", NULL);
db_error = e_db3_utils_maybe_recover (filename);
@@ -1369,18 +1591,11 @@ e_book_backend_file_load_source (EBookBackend *backend,
db_error = (*db->open) (db, NULL, filename, NULL, DB_HASH, DB_RDONLY | DB_THREAD, 0666);
if (db_error != 0 && !only_if_exists) {
- gint rv;
-
/* the database didn't exist, so we create the
directory then the .db */
db->close (db, 0);
- rv = g_mkdir_with_parents (dirname, 0700);
- if (rv == -1 && errno != EEXIST) {
- g_warning ("failed to make directory %s: %s", dirname, g_strerror (errno));
- if (errno == EACCES || errno == EPERM)
- g_propagate_error (perror, EDB_ERROR (PERMISSION_DENIED));
- else
- g_propagate_error (perror, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, "Failed to make directory %s: %s", dirname, g_strerror (errno)));
+
+ if (!create_directory (dirname, perror)) {
g_free (dirname);
g_free (filename);
return;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]