aboutsummaryrefslogtreecommitdiffstats
path: root/addressbook/backend/pas/pas-backend-file.c
diff options
context:
space:
mode:
authorJP Rosevear <jpr@src.gnome.org>2003-11-07 13:52:24 +0800
committerJP Rosevear <jpr@src.gnome.org>2003-11-07 13:52:24 +0800
commit200606f92810d3de322e5ee96f8326e1a656f8bb (patch)
treeda0dc27f5311128dcb6e7eb6400931e45743372e /addressbook/backend/pas/pas-backend-file.c
parente5472b4cc9a4bb80b89437a16f8b77943ea35555 (diff)
downloadgsoc2013-evolution-200606f92810d3de322e5ee96f8326e1a656f8bb.tar.gz
gsoc2013-evolution-200606f92810d3de322e5ee96f8326e1a656f8bb.tar.zst
gsoc2013-evolution-200606f92810d3de322e5ee96f8326e1a656f8bb.zip
Various changes to merge in evolution-data-server reliance.
svn path=/trunk/; revision=23206
Diffstat (limited to 'addressbook/backend/pas/pas-backend-file.c')
-rw-r--r--addressbook/backend/pas/pas-backend-file.c1169
1 files changed, 0 insertions, 1169 deletions
diff --git a/addressbook/backend/pas/pas-backend-file.c b/addressbook/backend/pas/pas-backend-file.c
deleted file mode 100644
index 73f1797320..0000000000
--- a/addressbook/backend/pas/pas-backend-file.c
+++ /dev/null
@@ -1,1169 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Author:
- * Nat Friedman (nat@ximian.com)
- *
- * Copyright 2000, Ximian, Inc.
- */
-
-#include "config.h"
-#include "pas-backend-file.h"
-#include "pas-backend-card-sexp.h"
-#include "pas-backend-summary.h"
-#include "pas-book.h"
-#include "pas-book-view.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <time.h>
-#include <errno.h>
-#include <db.h>
-#include <sys/stat.h>
-
-#include <e-util/e-db3-utils.h>
-
-#if DB_VERSION_MAJOR != 3 || \
- DB_VERSION_MINOR != 1 || \
- DB_VERSION_PATCH != 17
-#error Including wrong DB3. Need libdb 3.1.17.
-#endif
-
-#include <gal/util/e-util.h>
-#include <gal/widgets/e-unicode.h>
-
-#include <ebook/e-contact.h>
-#include <e-util/e-dbhash.h>
-#include <e-util/e-db3-utils.h>
-#include <libgnome/gnome-i18n.h>
-
-#define CHANGES_DB_SUFFIX ".changes.db"
-
-#define PAS_BACKEND_FILE_VERSION_NAME "PAS-DB-VERSION"
-#define PAS_BACKEND_FILE_VERSION "0.2"
-
-#define PAS_ID_PREFIX "pas-id-"
-#define SUMMARY_FLUSH_TIMEOUT 5000
-
-static PASBackendSyncClass *pas_backend_file_parent_class;
-
-struct _PASBackendFilePrivate {
- char *uri;
- char *dirname;
- char *filename;
- char *summary_filename;
- DB *file_db;
- PASBackendSummary *summary;
-};
-
-static void
-string_to_dbt(const char *str, DBT *dbt)
-{
- memset (dbt, 0, sizeof (*dbt));
- dbt->data = (void*)str;
- dbt->size = strlen (str) + 1;
-}
-
-static void
-build_summary (PASBackendFilePrivate *bfpriv)
-{
- DB *db = bfpriv->file_db;
- DBC *dbc;
- int db_error;
- DBT id_dbt, vcard_dbt;
-
- db_error = db->cursor (db, NULL, &dbc, 0);
-
- if (db_error != 0) {
- g_warning ("build_summary: error building list\n");
- return;
- }
-
- memset (&vcard_dbt, 0, sizeof (vcard_dbt));
- memset (&id_dbt, 0, sizeof (id_dbt));
- db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_FIRST);
-
- while (db_error == 0) {
-
- /* don't include the version in the list of cards */
- if (id_dbt.size != strlen(PAS_BACKEND_FILE_VERSION_NAME) + 1
- || strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) {
- EContact *contact = e_contact_new_from_vcard (vcard_dbt.data);
- pas_backend_summary_add_contact (bfpriv->summary, contact);
- g_object_unref (contact);
- }
-
- db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_NEXT);
-
- }
-}
-
-static char *
-pas_backend_file_create_unique_id (void)
-{
- /* use a 32 counter and the 32 bit timestamp to make an id.
- it's doubtful 2^32 id's will be created in a second, so we
- should be okay. */
- static guint c = 0;
- return g_strdup_printf (PAS_ID_PREFIX "%08lX%08X", time(NULL), c++);
-}
-
-static EContact *
-do_create(PASBackendFile *bf,
- const char *vcard_req)
-{
- DB *db = bf->priv->file_db;
- DBT id_dbt, vcard_dbt;
- int db_error;
- char *id;
- EContact *contact;
- char *vcard;
-
- id = pas_backend_file_create_unique_id ();
-
- string_to_dbt (id, &id_dbt);
-
- contact = e_contact_new_from_vcard (vcard_req);
- e_contact_set(contact, E_CONTACT_UID, id);
- vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-
- string_to_dbt (vcard, &vcard_dbt);
-
- db_error = db->put (db, NULL, &id_dbt, &vcard_dbt, 0);
-
- g_free (vcard);
-
- if (0 == db_error) {
- db_error = db->sync (db, 0);
- if (db_error != 0)
- g_warning ("db->sync failed.\n");
- }
- else {
- g_object_unref (contact);
- contact = NULL;
- }
-
- g_free (id);
- return contact;
-}
-
-static PASBackendSyncStatus
-pas_backend_file_create_contact (PASBackendSync *backend,
- PASBook *book,
- const char *vcard,
- EContact **contact)
-{
- PASBackendFile *bf = PAS_BACKEND_FILE (backend);
-
- *contact = do_create (bf, vcard);
- if (*contact) {
- pas_backend_summary_add_contact (bf->priv->summary, *contact);
- return GNOME_Evolution_Addressbook_Success;
- }
- else {
- /* XXX need a different call status for this case, i
- think */
- return GNOME_Evolution_Addressbook_ContactNotFound;
- }
-}
-
-static PASBackendSyncStatus
-pas_backend_file_remove_contacts (PASBackendSync *backend,
- PASBook *book,
- GList *id_list,
- GList **ids)
-{
- PASBackendFile *bf = PAS_BACKEND_FILE (backend);
- DB *db = bf->priv->file_db;
- DBT id_dbt, vcard_dbt;
- int db_error;
- char *id;
- GList *l;
- GList *removed_cards = NULL;
- GNOME_Evolution_Addressbook_CallStatus rv = GNOME_Evolution_Addressbook_Success;
-
- for (l = id_list; l; l = l->next) {
- id = l->data;
-
- string_to_dbt (id, &id_dbt);
- memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-
- db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0);
- if (0 != db_error) {
- rv = GNOME_Evolution_Addressbook_ContactNotFound;
- continue;
- }
-
- db_error = db->del (db, NULL, &id_dbt, 0);
- if (0 != db_error) {
- rv = GNOME_Evolution_Addressbook_ContactNotFound;
- continue;
- }
-
- removed_cards = g_list_prepend (removed_cards, id);
- }
-
- /* if we actually removed some, try to sync */
- if (removed_cards) {
- db_error = db->sync (db, 0);
- if (db_error != 0)
- g_warning ("db->sync failed.\n");
- }
-
- *ids = removed_cards;
-
- for (l = removed_cards; l; l = l->next) {
- char *id = l->data;
- pas_backend_summary_remove_contact (bf->priv->summary, id);
- }
-
- return rv;
-}
-
-static PASBackendSyncStatus
-pas_backend_file_modify_contact (PASBackendSync *backend,
- PASBook *book,
- const char *vcard,
- EContact **contact)
-{
- PASBackendFile *bf = PAS_BACKEND_FILE (backend);
- DB *db = bf->priv->file_db;
- DBT id_dbt, vcard_dbt;
- int db_error;
- char *id, *lookup_id;
-
- *contact = e_contact_new_from_vcard (vcard);
- id = e_contact_get(*contact, E_CONTACT_UID);
-
- /* This is disgusting, but for a time cards were added with
- ID's that are no longer used (they contained both the uri
- and the id.) If we recognize it as a uri (file:///...) trim
- off everything before the last '/', and use that as the
- id.*/
- if (!strncmp (id, "file:///", strlen ("file:///"))) {
- lookup_id = strrchr (id, '/') + 1;
- }
- else
- lookup_id = id;
-
- string_to_dbt (lookup_id, &id_dbt);
- memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-
- /* get the old ecard - the one that's presently in the db */
- db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0);
- if (0 != db_error)
- return GNOME_Evolution_Addressbook_ContactNotFound;
-
- string_to_dbt (vcard, &vcard_dbt);
-
- db_error = db->put (db, NULL, &id_dbt, &vcard_dbt, 0);
-
- if (0 == db_error) {
- db_error = db->sync (db, 0);
- if (db_error != 0)
- g_warning ("db->sync failed.\n");
-
- pas_backend_summary_remove_contact (bf->priv->summary, id);
- pas_backend_summary_add_contact (bf->priv->summary, *contact);
- }
- g_free (id);
-
- if (0 == db_error)
- return GNOME_Evolution_Addressbook_Success;
- else
- return GNOME_Evolution_Addressbook_ContactNotFound;
-}
-
-static PASBackendSyncStatus
-pas_backend_file_get_contact (PASBackendSync *backend,
- PASBook *book,
- const char *id,
- char **vcard)
-{
- PASBackendFile *bf;
- DB *db;
- DBT id_dbt, vcard_dbt;
- int db_error = 0;
-
- bf = PAS_BACKEND_FILE (pas_book_get_backend (book));
- db = bf->priv->file_db;
-
- string_to_dbt (id, &id_dbt);
- memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-
- db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0);
-
- if (db_error == 0) {
- *vcard = g_strdup (vcard_dbt.data);
- return GNOME_Evolution_Addressbook_Success;
- } else {
- *vcard = g_strdup ("");
- return GNOME_Evolution_Addressbook_ContactNotFound;
- }
-}
-
-static PASBackendSyncStatus
-pas_backend_file_get_contact_list (PASBackendSync *backend,
- PASBook *book,
- const char *query,
- GList **contacts)
-{
- PASBackendFile *bf = PAS_BACKEND_FILE (backend);
- DB *db = bf->priv->file_db;
- DBC *dbc;
- int db_error;
- DBT id_dbt, vcard_dbt;
- PASBackendCardSExp *card_sexp = NULL;
- gboolean search_needed;
- const char *search = query;
- GList *contact_list = NULL;
-
- printf ("pas_backend_file_get_contact_list (%s)\n", search);
-
- search_needed = TRUE;
-
- if (!strcmp (search, "(contains \"x-evolution-any-field\" \"\")"))
- search_needed = FALSE;
-
- card_sexp = pas_backend_card_sexp_new (search);
- if (!card_sexp) {
- /* XXX this needs to be an invalid query error of some sort*/
- return GNOME_Evolution_Addressbook_ContactNotFound;
- }
-
- db_error = db->cursor (db, NULL, &dbc, 0);
-
- if (db_error != 0) {
- /* XXX this needs to be some CouldNotOpen error */
- return GNOME_Evolution_Addressbook_ContactNotFound;
- }
-
- memset (&vcard_dbt, 0, sizeof (vcard_dbt));
- memset (&id_dbt, 0, sizeof (id_dbt));
- db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_FIRST);
-
- while (db_error == 0) {
-
- /* don't include the version in the list of cards */
- if (id_dbt.size != strlen(PAS_BACKEND_FILE_VERSION_NAME) + 1
- || strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) {
-
- if ((!search_needed) || (card_sexp != NULL && pas_backend_card_sexp_match_vcard (card_sexp, vcard_dbt.data))) {
- contact_list = g_list_append (contact_list, g_strdup (vcard_dbt.data));
- }
- }
-
- db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_NEXT);
-
- }
-
- *contacts = contact_list;
- return db_error != DB_NOTFOUND
- ? GNOME_Evolution_Addressbook_OtherError
- : GNOME_Evolution_Addressbook_Success;
-}
-
-typedef struct {
- GMutex *mutex;
- gboolean stopped;
-} FileBackendSearchClosure;
-
-static void
-pas_backend_file_start_book_view (PASBackend *backend,
- PASBookView *book_view)
-{
- FileBackendSearchClosure *closure = g_new0 (FileBackendSearchClosure, 1);
- PASBackendFile *bf = PAS_BACKEND_FILE (backend);
- const char *query;
- DB *db;
- DBT id_dbt, vcard_dbt;
- int db_error;
- gboolean stopped = FALSE;
-
- printf ("starting initial population of book view\n");
-
- /* ref the book view because it'll be removed and unrefed
- when/if it's stopped */
- g_object_ref (book_view);
-
- db = bf->priv->file_db;
- query = pas_book_view_get_card_query (book_view);
-
- closure->mutex = g_mutex_new();
- closure->stopped = FALSE;
- g_object_set_data (G_OBJECT (book_view), "PASBackendFile.BookView::closure", closure);
-
- if ( ! strcmp (query, "(contains \"x-evolution-any-field\" \"\")"))
- pas_book_view_notify_status_message (book_view, _("Loading..."));
- else
- pas_book_view_notify_status_message (book_view, _("Searching..."));
-
- if (pas_backend_summary_is_summary_query (bf->priv->summary, query)) {
- /* do a summary query */
- GPtrArray *ids = pas_backend_summary_search (bf->priv->summary, pas_book_view_get_card_query (book_view));
- int i;
-
- for (i = 0; i < ids->len; i ++) {
- char *id = g_ptr_array_index (ids, i);
-
- g_mutex_lock (closure->mutex);
- stopped = closure->stopped;
- g_mutex_unlock (closure->mutex);
-
- if (stopped) {
- g_mutex_free (closure->mutex);
- g_free (closure);
- break;
- }
-
- string_to_dbt (id, &id_dbt);
- memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-
- db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0);
-
- if (db_error == 0) {
- EContact *contact = e_contact_new_from_vcard (vcard_dbt.data);
- pas_book_view_notify_update (book_view, contact);
- g_object_unref (contact);
- }
- }
-
- g_ptr_array_free (ids, TRUE);
- }
- else {
- /* iterate over the db and do the query there */
- DBC *dbc;
-
- memset (&id_dbt, 0, sizeof (id_dbt));
- memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-
- db_error = db->cursor (db, NULL, &dbc, 0);
-
- db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_FIRST);
- while (db_error == 0) {
-
- g_mutex_lock (closure->mutex);
- stopped = closure->stopped;
- g_mutex_unlock (closure->mutex);
-
- if (stopped) {
- g_mutex_free (closure->mutex);
- g_free (closure);
- break;
- }
-
- /* don't include the version in the list of cards */
- if (strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) {
- char *vcard_string = vcard_dbt.data;
- EContact *contact = e_contact_new_from_vcard (vcard_string);
-
- /* notify_update will check if it matches for us */
- pas_book_view_notify_update (book_view, contact);
- g_object_unref (contact);
- }
-
- db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_NEXT);
- }
-
- dbc->c_close (dbc);
-
- if (db_error != DB_NOTFOUND)
- g_warning ("pas_backend_file_search: error building list\n");
-
- }
-
- g_mutex_lock (closure->mutex);
- stopped = closure->stopped;
- g_mutex_unlock (closure->mutex);
- if (!stopped)
- pas_book_view_notify_complete (book_view, GNOME_Evolution_Addressbook_Success);
-
- g_mutex_free (closure->mutex);
- g_free (closure);
-
- g_object_set_data (G_OBJECT (book_view), "PASBackendFile.BookView::closure", NULL);
-
- /* unref the */
- g_object_unref (book_view);
-
- printf ("finished initial population of book view\n");
-}
-
-static void
-pas_backend_file_stop_book_view (PASBackend *backend,
- PASBookView *book_view)
-{
- FileBackendSearchClosure *closure = g_object_get_data (G_OBJECT (book_view), "PASBackendFile.BookView::closure");
- if (!closure) {
- printf ("book view is already done populating\n");
- return;
- }
-
- printf ("stopping book view!\n");
- g_mutex_lock (closure->mutex);
- closure->stopped = TRUE;
- g_mutex_lock (closure->mutex);
-}
-
-typedef struct {
- DB *db;
-
- GList *add_cards;
- GList *add_ids;
- GList *mod_cards;
- GList *mod_ids;
- GList *del_ids;
- GList *del_cards;
-} PASBackendFileChangeContext;
-
-static void
-pas_backend_file_changes_foreach_key (const char *key, gpointer user_data)
-{
- PASBackendFileChangeContext *ctx = user_data;
- DB *db = ctx->db;
- DBT id_dbt, vcard_dbt;
- int db_error = 0;
-
- string_to_dbt (key, &id_dbt);
- memset (&vcard_dbt, 0, sizeof (vcard_dbt));
- db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0);
-
- if (db_error != 0) {
- EContact *contact;
- char *id = id_dbt.data;
- char *vcard_string;
-
- contact = e_contact_new ();
- e_contact_set (contact, E_CONTACT_UID, id);
-
- vcard_string = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-
- ctx->del_ids = g_list_append (ctx->del_ids,
- g_strdup (id));
- ctx->del_cards = g_list_append (ctx->del_cards,
- vcard_string);
-
- g_object_unref (contact);
- }
-}
-
-static PASBackendSyncStatus
-pas_backend_file_get_changes (PASBackendSync *backend,
- PASBook *book,
- const char *change_id,
- GList **changes_out)
-{
- PASBackendFile *bf = PAS_BACKEND_FILE (backend);
- int db_error = 0;
- DBT id_dbt, vcard_dbt;
- char *filename;
- EDbHash *ehash;
- GList *i, *v;
- DB *db = bf->priv->file_db;
- DBC *dbc;
- GList *changes = NULL;
- PASBackendFileChangeContext ctx;
- PASBackendSyncStatus result;
-
- memset (&id_dbt, 0, sizeof (id_dbt));
- memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-
- memset (&ctx, 0, sizeof (ctx));
-
- ctx.db = db;
-
- /* Find the changed ids */
- filename = g_strdup_printf ("%s/%s" CHANGES_DB_SUFFIX, bf->priv->dirname, change_id);
- ehash = e_dbhash_new (filename);
- g_free (filename);
-
- db_error = db->cursor (db, NULL, &dbc, 0);
-
- if (db_error != 0) {
- g_warning ("pas_backend_file_changes: error building list\n");
- } else {
- db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_FIRST);
-
- while (db_error == 0) {
-
- /* don't include the version in the list of cards */
- if (id_dbt.size != strlen(PAS_BACKEND_FILE_VERSION_NAME) + 1
- || strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) {
- EContact *contact;
- char *id = id_dbt.data;
- char *vcard_string;
-
- /* Remove fields the user can't change
- * and can change without the rest of the
- * card changing
- */
- contact = e_contact_new_from_vcard (vcard_dbt.data);
-#if notyet
- g_object_set (card, "last_use", NULL, "use_score", 0.0, NULL);
-#endif
- vcard_string = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
- g_object_unref (contact);
-
- /* check what type of change has occurred, if any */
- switch (e_dbhash_compare (ehash, id, vcard_string)) {
- case E_DBHASH_STATUS_SAME:
- break;
- case E_DBHASH_STATUS_NOT_FOUND:
- ctx.add_cards = g_list_append (ctx.add_cards, vcard_string);
- ctx.add_ids = g_list_append (ctx.add_ids, g_strdup(id));
- break;
- case E_DBHASH_STATUS_DIFFERENT:
- ctx.mod_cards = g_list_append (ctx.mod_cards, vcard_string);
- ctx.mod_ids = g_list_append (ctx.mod_ids, g_strdup(id));
- break;
- }
- }
-
- db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_NEXT);
- }
- dbc->c_close (dbc);
- }
-
- e_dbhash_foreach_key (ehash, (EDbHashFunc)pas_backend_file_changes_foreach_key, &ctx);
-
- /* Send the changes */
- if (db_error != DB_NOTFOUND) {
- g_warning ("pas_backend_file_changes: error building list\n");
- *changes_out = NULL;
- result = GNOME_Evolution_Addressbook_OtherError;
- }
- else {
- /* Update the hash and build our changes list */
- for (i = ctx.add_ids, v = ctx.add_cards; i != NULL; i = i->next, v = v->next){
- char *id = i->data;
- char *vcard = v->data;
-
- e_dbhash_add (ehash, id, vcard);
- changes = g_list_prepend (changes,
- pas_backend_change_add_new (vcard));
-
- g_free (i->data);
- g_free (v->data);
- }
- for (i = ctx.mod_ids, v = ctx.mod_cards; i != NULL; i = i->next, v = v->next){
- char *id = i->data;
- char *vcard = v->data;
-
- e_dbhash_add (ehash, id, vcard);
- changes = g_list_prepend (changes,
- pas_backend_change_modify_new (vcard));
-
- g_free (i->data);
- g_free (v->data);
- }
- for (i = ctx.del_ids, v = ctx.del_cards; i != NULL; i = i->next, v = v->next){
- char *id = i->data;
- char *vcard = v->data;
-
- e_dbhash_remove (ehash, id);
-
- changes = g_list_prepend (changes,
- pas_backend_change_delete_new (vcard));
- g_free (i->data);
- g_free (v->data);
- }
-
- e_dbhash_write (ehash);
-
- result = GNOME_Evolution_Addressbook_Success;
- *changes_out = changes;
- }
-
- e_dbhash_destroy (ehash);
-
- return GNOME_Evolution_Addressbook_Success;
-}
-
-static char *
-pas_backend_file_extract_path_from_uri (const char *uri)
-{
- g_assert (strncasecmp (uri, "file://", 7) == 0);
-
- return g_strdup (uri + 7);
-}
-
-static PASBackendSyncStatus
-pas_backend_file_authenticate_user (PASBackendSync *backend,
- PASBook *book,
- const char *user,
- const char *passwd,
- const char *auth_method)
-{
- return GNOME_Evolution_Addressbook_Success;
-}
-
-static PASBackendSyncStatus
-pas_backend_file_get_supported_fields (PASBackendSync *backend,
- PASBook *book,
- GList **fields_out)
-{
- GList *fields = NULL;
- int i;
-
- /* XXX we need a way to say "we support everything", since the
- file backend does */
- for (i = 1; i < E_CONTACT_FIELD_LAST; i ++)
- fields = g_list_append (fields, g_strdup (e_contact_field_name (i)));
-
- *fields_out = fields;
- return GNOME_Evolution_Addressbook_Success;
-}
-
-/*
-** versions:
-**
-** 0.0 just a list of cards
-**
-** 0.1 same as 0.0, but with the version tag
-**
-** 0.2 not a real format upgrade, just a hack to fix broken ids caused
-** by a bug in early betas, but we only need to convert them if
-** the previous version is 0.1, since the bug existed after 0.1
-** came about.
-*/
-static gboolean
-pas_backend_file_upgrade_db (PASBackendFile *bf, char *old_version)
-{
- DB *db = bf->priv->file_db;
- int db_error;
- DBT version_name_dbt, version_dbt;
-
- if (strcmp (old_version, "0.0")
- && strcmp (old_version, "0.1")) {
- g_warning ("unsupported version '%s' found in PAS backend file\n",
- old_version);
- return FALSE;
- }
-
- if (!strcmp (old_version, "0.1")) {
- /* we just loop through all the cards in the db,
- giving them valid ids if they don't have them */
- DBT id_dbt, vcard_dbt;
- DBC *dbc;
- int card_failed = 0;
-
- db_error = db->cursor (db, NULL, &dbc, 0);
- if (db_error != 0) {
- g_warning ("unable to get cursor");
- return FALSE;
- }
-
- memset (&id_dbt, 0, sizeof (id_dbt));
- memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-
- db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_FIRST);
-
- while (db_error == 0) {
- if (id_dbt.size != strlen(PAS_BACKEND_FILE_VERSION_NAME) + 1
- || strcmp (id_dbt.data, PAS_BACKEND_FILE_VERSION_NAME)) {
- EContact *contact;
-
- contact = e_contact_new_from_vcard (vcard_dbt.data);
-
- /* the cards we're looking for are
- created with a normal id dbt, but
- with the id field in the vcard set
- to something that doesn't match.
- so, we need to modify the card to
- have the same id as the the dbt. */
- if (strcmp (id_dbt.data, e_contact_get_const (contact, E_CONTACT_UID))) {
- char *vcard;
-
- e_contact_set (contact, E_CONTACT_UID, id_dbt.data);
-
- vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
- string_to_dbt (vcard, &vcard_dbt);
-
- db_error = db->put (db, NULL,
- &id_dbt, &vcard_dbt, 0);
-
- g_free (vcard);
-
- if (db_error != 0)
- card_failed++;
- }
-
- g_object_unref (contact);
- }
-
- db_error = dbc->c_get(dbc, &id_dbt, &vcard_dbt, DB_NEXT);
- }
-
- if (card_failed) {
- g_warning ("failed to update %d cards\n", card_failed);
- return FALSE;
- }
- }
-
- string_to_dbt (PAS_BACKEND_FILE_VERSION_NAME, &version_name_dbt);
- string_to_dbt (PAS_BACKEND_FILE_VERSION, &version_dbt);
-
- db_error = db->put (db, NULL, &version_name_dbt, &version_dbt, 0);
- if (db_error == 0)
- return TRUE;
- else
- return FALSE;
-}
-
-static gboolean
-pas_backend_file_maybe_upgrade_db (PASBackendFile *bf)
-{
- DB *db = bf->priv->file_db;
- DBT version_name_dbt, version_dbt;
- int db_error;
- char *version;
- gboolean ret_val = TRUE;
-
- string_to_dbt (PAS_BACKEND_FILE_VERSION_NAME, &version_name_dbt);
- memset (&version_dbt, 0, sizeof (version_dbt));
-
- db_error = db->get (db, NULL, &version_name_dbt, &version_dbt, 0);
- if (db_error == 0) {
- /* success */
- version = g_strdup (version_dbt.data);
- }
- else {
- /* key was not in file */
- version = g_strdup ("0.0");
- }
-
- if (strcmp (version, PAS_BACKEND_FILE_VERSION))
- ret_val = pas_backend_file_upgrade_db (bf, version);
-
- g_free (version);
-
- return ret_val;
-}
-
-#include "ximian-vcard.h"
-
-static GNOME_Evolution_Addressbook_CallStatus
-pas_backend_file_load_uri (PASBackend *backend,
- const char *uri,
- gboolean only_if_exists)
-{
- PASBackendFile *bf = PAS_BACKEND_FILE (backend);
- char *dirname, *filename;
- gboolean writable = FALSE;
- int db_error;
- DB *db;
- int major, minor, patch;
- time_t db_mtime;
- struct stat sb;
-
- g_free(bf->priv->uri);
- bf->priv->uri = g_strdup (uri);
-
- db_version (&major, &minor, &patch);
-
- if (major != 3 ||
- minor != 1 ||
- patch != 17) {
- g_warning ("Wrong version of libdb.");
- return GNOME_Evolution_Addressbook_OtherError;
- }
-
- dirname = pas_backend_file_extract_path_from_uri (uri);
- filename = g_build_filename (dirname, "addressbook.db", NULL);
-
- db_error = e_db3_utils_maybe_recover (filename);
- if (db_error != 0)
- return GNOME_Evolution_Addressbook_OtherError;
-
- db_error = db_create (&db, NULL, 0);
- if (db_error != 0)
- return GNOME_Evolution_Addressbook_OtherError;
-
- db_error = db->open (db, filename, NULL, DB_HASH, 0, 0666);
-
- if (db_error == DB_OLD_VERSION) {
- db_error = e_db3_utils_upgrade_format (filename);
-
- if (db_error != 0)
- return GNOME_Evolution_Addressbook_OtherError;
-
- db_error = db->open (db, filename, NULL, DB_HASH, 0, 0666);
- }
-
- bf->priv->file_db = db;
-
- if (db_error == 0) {
- writable = TRUE;
- } else {
- db_error = db->open (db, filename, NULL, DB_HASH, DB_RDONLY, 0666);
-
- if (db_error != 0) {
- int rv;
-
- /* the database didn't exist, so we create the
- directory then the .db */
- rv = mkdir (dirname, 0777);
- if (rv == -1 && errno != EEXIST) {
- g_warning ("failed to make directory %s: %s", dirname, strerror (errno));
- if (errno == EACCES || errno == EPERM)
- return GNOME_Evolution_Addressbook_PermissionDenied;
- else
- return GNOME_Evolution_Addressbook_OtherError;
- }
-
- db_error = db->open (db, filename, NULL, DB_HASH, DB_CREATE, 0666);
-
- if (db_error == 0 && !only_if_exists) {
- EContact *contact;
-
- contact = do_create(bf, XIMIAN_VCARD);
- /* XXX check errors here */
- g_object_unref (contact);
-
- writable = TRUE;
- }
- }
- }
-
- if (db_error != 0) {
- bf->priv->file_db = NULL;
- return GNOME_Evolution_Addressbook_OtherError;
- }
-
- if (!pas_backend_file_maybe_upgrade_db (bf)) {
- db->close (db, 0);
- bf->priv->file_db = NULL;
- return GNOME_Evolution_Addressbook_OtherError;
- }
-
- g_free (bf->priv->dirname);
- g_free (bf->priv->filename);
- bf->priv->dirname = dirname;
- bf->priv->filename = filename;
-
- if (stat (bf->priv->filename, &sb) == -1) {
- db->close (db, 0);
- bf->priv->file_db = NULL;
- return GNOME_Evolution_Addressbook_OtherError;
- }
- db_mtime = sb.st_mtime;
-
- g_free (bf->priv->summary_filename);
- bf->priv->summary_filename = g_strconcat (bf->priv->filename, ".summary", NULL);
- bf->priv->summary = pas_backend_summary_new (bf->priv->summary_filename, SUMMARY_FLUSH_TIMEOUT);
-
- if (pas_backend_summary_is_up_to_date (bf->priv->summary, db_mtime) == FALSE
- || pas_backend_summary_load (bf->priv->summary) == FALSE ) {
- build_summary (bf->priv);
- }
-
- pas_backend_set_is_loaded (backend, TRUE);
- pas_backend_set_is_writable (backend, writable);
-
- return GNOME_Evolution_Addressbook_Success;
-}
-
-static int
-select_changes (const struct dirent *d)
-{
- char *p;
-
- if (strlen (d->d_name) < strlen (CHANGES_DB_SUFFIX))
- return 0;
-
- p = strstr (d->d_name, CHANGES_DB_SUFFIX);
- if (!p)
- return 0;
-
- if (strlen (p) != strlen (CHANGES_DB_SUFFIX))
- return 0;
-
- return 1;
-}
-
-static PASBackendSyncStatus
-pas_backend_file_remove (PASBackendSync *backend,
- PASBook *book)
-{
- PASBackendFile *bf = PAS_BACKEND_FILE (backend);
- struct dirent **namelist;
- int n;
-
- if (-1 == unlink (bf->priv->filename)) {
- if (errno == EACCES || errno == EPERM)
- return GNOME_Evolution_Addressbook_PermissionDenied;
- else
- return GNOME_Evolution_Addressbook_OtherError;
- }
-
- /* unref the summary before we remove the file so it's not written out again */
- g_object_unref (bf->priv->summary);
- bf->priv->summary = NULL;
- if (-1 == unlink (bf->priv->filename))
- g_warning ("failed to remove summary file `%s`: %s", bf->priv->summary_filename, strerror (errno));
-
- /* scandir to select all the "*.changes.db" files, then remove them */
- n = scandir (bf->priv->dirname,
- &namelist, select_changes, alphasort);
- if (n < 0) {
- g_warning ("scandir of directory `%s' failed: %s", bf->priv->dirname, strerror (errno));
- }
- else {
- while (n -- ) {
- char *full_path = g_build_filename (bf->priv->dirname, namelist[n]->d_name, NULL);
- if (-1 == unlink (full_path)) {
- g_warning ("failed to remove change db `%s': %s", full_path, strerror (errno));
- }
- g_free (full_path);
- free (namelist[n]);
- }
- free (namelist);
- }
-
- if (-1 == rmdir (bf->priv->dirname))
- g_warning ("failed to remove directory `%s`: %s", bf->priv->dirname, strerror (errno));
-
- /* we may not have actually succeeded in removing the
- backend's files/dirs, but there's nothing we can do about
- it here.. the only time we should return failure is if we
- failed to remove the actual data. a failure should mean
- that the addressbook is still valid */
- return GNOME_Evolution_Addressbook_Success;
-}
-
-static char *
-pas_backend_file_get_static_capabilities (PASBackend *backend)
-{
- return g_strdup("local,do-initial-query,bulk-removes");
-}
-
-static GNOME_Evolution_Addressbook_CallStatus
-pas_backend_file_cancel_operation (PASBackend *backend, PASBook *book)
-{
- return GNOME_Evolution_Addressbook_CouldNotCancel;
-}
-
-static gboolean
-pas_backend_file_construct (PASBackendFile *backend)
-{
- g_assert (backend != NULL);
- g_assert (PAS_IS_BACKEND_FILE (backend));
-
- if (! pas_backend_construct (PAS_BACKEND (backend)))
- return FALSE;
-
- return TRUE;
-}
-
-/**
- * pas_backend_file_new:
- */
-PASBackend *
-pas_backend_file_new (void)
-{
- PASBackendFile *backend;
-
- backend = g_object_new (PAS_TYPE_BACKEND_FILE, NULL);
-
- if (! pas_backend_file_construct (backend)) {
- g_object_unref (backend);
-
- return NULL;
- }
-
- return PAS_BACKEND (backend);
-}
-
-static void
-pas_backend_file_dispose (GObject *object)
-{
- PASBackendFile *bf;
-
- bf = PAS_BACKEND_FILE (object);
-
- if (bf->priv) {
- if (bf->priv->summary)
- g_object_unref(bf->priv->summary);
- g_free (bf->priv->uri);
- g_free (bf->priv->filename);
- g_free (bf->priv->dirname);
- g_free (bf->priv->summary_filename);
-
- g_free (bf->priv);
- bf->priv = NULL;
- }
-
- G_OBJECT_CLASS (pas_backend_file_parent_class)->dispose (object);
-}
-
-static void
-pas_backend_file_class_init (PASBackendFileClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- PASBackendSyncClass *sync_class;
- PASBackendClass *backend_class;
-
- pas_backend_file_parent_class = g_type_class_peek_parent (klass);
-
- sync_class = PAS_BACKEND_SYNC_CLASS (klass);
- backend_class = PAS_BACKEND_CLASS (klass);
-
- /* Set the virtual methods. */
- backend_class->load_uri = pas_backend_file_load_uri;
- backend_class->get_static_capabilities = pas_backend_file_get_static_capabilities;
- backend_class->start_book_view = pas_backend_file_start_book_view;
- backend_class->stop_book_view = pas_backend_file_stop_book_view;
- backend_class->cancel_operation = pas_backend_file_cancel_operation;
-
- sync_class->remove_sync = pas_backend_file_remove;
- sync_class->create_contact_sync = pas_backend_file_create_contact;
- sync_class->remove_contacts_sync = pas_backend_file_remove_contacts;
- sync_class->modify_contact_sync = pas_backend_file_modify_contact;
- sync_class->get_contact_sync = pas_backend_file_get_contact;
- sync_class->get_contact_list_sync = pas_backend_file_get_contact_list;
- sync_class->get_changes_sync = pas_backend_file_get_changes;
- sync_class->authenticate_user_sync = pas_backend_file_authenticate_user;
- sync_class->get_supported_fields_sync = pas_backend_file_get_supported_fields;
-
- object_class->dispose = pas_backend_file_dispose;
-}
-
-static void
-pas_backend_file_init (PASBackendFile *backend)
-{
- PASBackendFilePrivate *priv;
-
- priv = g_new0 (PASBackendFilePrivate, 1);
- priv->uri = NULL;
-
- backend->priv = priv;
-}
-
-/**
- * pas_backend_file_get_type:
- */
-GType
-pas_backend_file_get_type (void)
-{
- static GType type = 0;
-
- if (! type) {
- GTypeInfo info = {
- sizeof (PASBackendFileClass),
- NULL, /* base_class_init */
- NULL, /* base_class_finalize */
- (GClassInitFunc) pas_backend_file_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (PASBackendFile),
- 0, /* n_preallocs */
- (GInstanceInitFunc) pas_backend_file_init
- };
-
- type = g_type_register_static (PAS_TYPE_BACKEND_SYNC, "PASBackendFile", &info, 0);
- }
-
- return type;
-}