/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
#include <config.h>
#include <pthread.h>
#include <string.h>
#include "e-book.h"
#include "e-vcard.h"
#include <bonobo-activation/bonobo-activation.h>
#include <bonobo/bonobo-exception.h>
#include <bonobo/bonobo-main.h>
#include <libgnome/gnome-i18n.h>
#include "e-book-marshal.h"
#include "e-book-listener.h"
#include "addressbook.h"
#include "e-util/e-component-listener.h"
#include "e-util/e-msgport.h"
static GObjectClass *parent_class;
#define CARDSERVER_OAF_ID "OAFIID:GNOME_Evolution_Wombat_ServerFactory"
#define e_return_error_if_fail(expr,error_code) G_STMT_START{ \
if G_LIKELY(expr) { } else \
{ \
g_log (G_LOG_DOMAIN, \
G_LOG_LEVEL_CRITICAL, \
"file %s: line %d (%s): assertion `%s' failed", \
__FILE__, \
__LINE__, \
__PRETTY_FUNCTION__, \
#expr); \
g_set_error (error, E_BOOK_ERROR, (error_code), \
"file %s: line %d (%s): assertion `%s' failed", \
__FILE__, \
__LINE__, \
__PRETTY_FUNCTION__, \
#expr); \
return FALSE; \
}; }G_STMT_END
/* XXX we need a better error message here */
#define E_BOOK_CHECK_STATUS(status,error) G_STMT_START{ \
if ((status) == E_BOOK_ERROR_OK) { \
return TRUE; \
} \
else { \
g_set_error ((error), E_BOOK_ERROR, (status), "EBookStatus returned %d", (status)); \
return FALSE; \
} }G_STMT_END
enum {
OPEN_PROGRESS,
WRITABLE_STATUS,
BACKEND_DIED,
LAST_SIGNAL
};
static guint e_book_signals [LAST_SIGNAL];
typedef struct {
EMutex *mutex;
pthread_cond_t cond;
EBookStatus status;
char *id;
GList *list;
EContact *contact;
EBookView *view;
EBookViewListener *listener;
} EBookOp;
typedef enum {
E_BOOK_URI_NOT_LOADED,
E_BOOK_URI_LOADING,
E_BOOK_URI_LOADED
} EBookLoadState;
struct _EBookPrivate {
GList *book_factories;
GList *iter;
/* cached capabilites */
char *cap;
gboolean cap_queried;
/* cached writable status */
gboolean writable;
EBookListener *listener;
EComponentListener *comp_listener;
GNOME_Evolution_Addressbook_Book corba_book;
EBookLoadState load_state;
EBookOp *current_op;
EMutex *mutex;
gchar *uri;
gulong listener_signal;
gulong died_signal;
};
/* Error quark */
GQuark
e_book_error_quark (void)
{
static GQuark q = 0;
if (q == 0)
q = g_quark_from_static_string ("e-book-error-quark");
return q;
}
/* EBookOp calls */
static EBookOp*
e_book_new_op (EBook *book)
{
EBookOp *op = g_new0 (EBookOp, 1);
op->mutex = e_mutex_new (E_MUTEX_SIMPLE);
pthread_cond_init (&op->cond, 0);
book->priv->current_op = op;
return op;
}
static EBookOp*
e_book_get_op (EBook *book)
{
if (!book->priv->current_op) {
g_warning ("unexpected response");
return NULL;
}
return book->priv->current_op;
}
static void
e_book_op_free (EBookOp *op)
{
/* XXX more stuff here */
pthread_cond_destroy (&op->cond);
e_mutex_destroy (op->mutex);
g_free (op);
}
static void
e_book_op_remove (EBook *book,
EBookOp *op)
{
if (book->priv->current_op != op)
g_warning ("cannot remove op, it's not current");
book->priv->current_op = NULL;
}
static void
e_book_clear_op (EBook *book,
EBookOp *op)
{
e_book_op_remove (book, op);
e_mutex_unlock (op->mutex);
e_book_op_free (op);
}
/**
* e_book_add_card:
* @book: an #EBook
* @contact: an #EContact
*
* adds @contact to @book.
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_add_contact (EBook *book,
EContact *contact,
GError **error)
{
EBookOp *our_op;
EBookStatus status;
CORBA_Environment ev;
char *vcard_str;
printf ("e_book_add_contact\n");
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_add_contact called on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
/* will eventually end up calling e_book_response_add_contact */
GNOME_Evolution_Addressbook_Book_addContact (book->priv->corba_book,
(const GNOME_Evolution_Addressbook_VCard) vcard_str, &ev);
g_free (vcard_str);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::addContact call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
e_contact_set (contact, E_CONTACT_UID, our_op->id);
g_free (our_op->id);
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
static void
e_book_response_add_contact (EBook *book,
EBookStatus status,
char *id)
{
EBookOp *op;
printf ("e_book_response_add_contact\n");
op = e_book_get_op (book);
if (op == NULL) {
g_warning ("e_book_response_add_contact: Cannot find operation ");
return;
}
e_mutex_lock (op->mutex);
op->status = status;
op->id = g_strdup (id);
pthread_cond_signal (&op->cond);
e_mutex_unlock (op->mutex);
}
/**
* e_book_commit_contact:
* @book: an #EBook
* @contact: an #EContact
*
* applies the changes made to @contact to the stored version in
* @book.
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_commit_contact (EBook *book,
EContact *contact,
GError **error)
{
EBookOp *our_op;
EBookStatus status;
CORBA_Environment ev;
char *vcard_str;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_commit_contact called on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
/* will eventually end up calling _e_book_response_generic */
GNOME_Evolution_Addressbook_Book_modifyContact (book->priv->corba_book,
(const GNOME_Evolution_Addressbook_VCard) vcard_str, &ev);
g_free (vcard_str);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::modifyContact call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
e_contact_set (contact, E_CONTACT_UID, our_op->id);
g_free (our_op->id);
/* remove the op from the book's hash of operations */
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
/**
* e_book_get_supported_fields:
* @book: an #EBook
* @fields: a #GList
*
* queries @book for the list of fields it supports. mostly for use
* by the contact editor so it knows what fields to sensitize.
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_get_supported_fields (EBook *book,
GList **fields,
GError **error)
{
EBookOp *our_op;
EBookStatus status;
CORBA_Environment ev;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (fields, E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_get_supported_fields on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
}
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
/* will eventually end up calling
_e_book_response_get_supported_fields */
GNOME_Evolution_Addressbook_Book_getSupportedFields(book->priv->corba_book, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::getSupportedFields call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
*fields = our_op->list;
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
static void
e_book_response_get_supported_fields (EBook *book,
EBookStatus status,
GList *fields)
{
EBookOp *op;
op = e_book_get_op (book);
if (op == NULL) {
g_warning ("e_book_response_get_supported_fields: Cannot find operation ");
return;
}
e_mutex_lock (op->mutex);
op->status = status;
op->list = fields;
pthread_cond_signal (&op->cond);
e_mutex_unlock (op->mutex);
}
/**
* e_book_get_supported_auth_methods:
* @book: an #EBook
* @auth_methods: a #GList
*
* queries @book for the list of authentication methods it supports.
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_get_supported_auth_methods (EBook *book,
GList **auth_methods,
GError **error)
{
EBookOp *our_op;
EBookStatus status;
CORBA_Environment ev;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (auth_methods, E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_get_supported_auth_methods on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
/* will eventually end up calling
e_book_response_get_supported_fields */
GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods(book->priv->corba_book, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::getSupportedAuthMethods call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
*auth_methods = our_op->list;
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
static void
e_book_response_get_supported_auth_methods (EBook *book,
EBookStatus status,
GList *auth_methods)
{
EBookOp *op;
op = e_book_get_op (book);
if (op == NULL) {
g_warning ("e_book_response_get_supported_auth_methods: Cannot find operation ");
return;
}
e_mutex_lock (op->mutex);
op->status = status;
op->list = auth_methods;
pthread_cond_signal (&op->cond);
e_mutex_unlock (op->mutex);
}
/**
* e_book_authenticate_user:
* @book: an #EBook
* @user: a string
* @passwd: a string
* @auth_method: a string
*
* authenticates @user with @passwd, using the auth method
* @auth_method. @auth_method must be one of the authentication
* methods returned using e_book_get_supported_auth_methods.
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_authenticate_user (EBook *book,
const char *user,
const char *passwd,
const char *auth_method,
GError **error)
{
EBookOp *our_op;
EBookStatus status;
CORBA_Environment ev;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (user, E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (passwd, E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (auth_method, E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_authenticate_user on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
/* will eventually end up calling
e_book_response_generic */
GNOME_Evolution_Addressbook_Book_authenticateUser (book->priv->corba_book,
user, passwd,
auth_method,
&ev);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::authenticateUser call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
/**
* e_book_get_contact:
* @book: an #EBook
* @id: a string
* @contact: an #EContact
*
* Fills in @contact with the contents of the vcard in @book
* corresponding to @id.
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_get_contact (EBook *book,
const char *id,
EContact **contact,
GError **error)
{
EBookOp *our_op;
EBookStatus status;
CORBA_Environment ev;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (id, E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (contact, E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_get_contact on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
/* will eventually end up calling e_book_response_generic */
GNOME_Evolution_Addressbook_Book_getContact (book->priv->corba_book,
(const GNOME_Evolution_Addressbook_VCard) id, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::getContact call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
*contact = our_op->contact;
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
static void
e_book_response_get_contact (EBook *book,
EBookStatus status,
EContact *contact)
{
EBookOp *op;
printf ("e_book_response_get_contact\n");
op = e_book_get_op (book);
if (op == NULL) {
g_warning ("e_book_response_get_contact: Cannot find operation ");
return;
}
e_mutex_lock (op->mutex);
op->status = status;
op->contact = contact;
pthread_cond_signal (&op->cond);
e_mutex_unlock (op->mutex);
}
/**
* e_book_remove_contact:
* @book: an #EBook
* @id: a string
*
* Removes the contact with id @id from @book.
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_remove_contact (EBook *book,
const char *id,
GError **error)
{
GList *list;
gboolean rv;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (id, E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_remove_contact on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
e_mutex_lock (book->priv->mutex);
list = g_list_append (NULL, (char*)id);
rv = e_book_remove_contacts (book, list, error);
return rv;
}
/**
* e_book_remove_contacts:
* @book: an #EBook
* @ids: an #GList of const char *id's
*
* Removes the contacts with ids from the list @ids from @book. This is
* always more efficient than calling e_book_remove_contact_by_id if you
* have more than one id to remove, as some backends can implement it
* as a batch request.
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_remove_contacts (EBook *book,
GList *ids,
GError **error)
{
GNOME_Evolution_Addressbook_ContactIdList idlist;
CORBA_Environment ev;
GList *iter;
int num_ids, i;
EBookOp *our_op;
EBookStatus status;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (ids, E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_remove_contacts on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
num_ids = g_list_length (ids);
idlist._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_ContactId_allocbuf (num_ids);
idlist._maximum = num_ids;
idlist._length = num_ids;
for (iter = ids, i = 0; iter; iter = iter->next)
idlist._buffer[i++] = CORBA_string_dup (iter->data);
/* will eventually end up calling e_book_response_generic */
GNOME_Evolution_Addressbook_Book_removeContacts (book->priv->corba_book, &idlist, &ev);
CORBA_free(idlist._buffer);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::removeContacts call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
/**
* e_book_get_book_view:
* @book: an #EBook
* @query: an #EBookQuery
* @requested_fields a #GList containing the names of fields to return, or NULL for all
* @max_results the maximum number of contacts to show (or 0 for all)
*
* need docs here..
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_get_book_view (EBook *book,
EBookQuery *query,
GList *requested_fields,
int max_results,
EBookView **book_view,
GError **error)
{
GNOME_Evolution_Addressbook_stringlist stringlist;
CORBA_Environment ev;
EBookOp *our_op;
EBookStatus status;
int num_fields, i;
GList *iter;
char *query_string;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (query, E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (book_view, E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_get_book_view on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
our_op->listener = e_book_view_listener_new();
num_fields = g_list_length (requested_fields);
stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_fields);
stringlist._maximum = num_fields;
stringlist._length = num_fields;
for (i = 0, iter = requested_fields; iter; iter = iter->next, i ++) {
stringlist._buffer[i] = CORBA_string_dup ((char*)iter->data);
}
query_string = e_book_query_to_string (query);
/* will eventually end up calling e_book_response_get_book_view */
GNOME_Evolution_Addressbook_Book_getBookView (book->priv->corba_book,
bonobo_object_corba_objref(BONOBO_OBJECT(our_op->listener)),
query_string,
&stringlist, max_results, &ev);
CORBA_free(stringlist._buffer);
g_free (query_string);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_warning ("corba exception._major = %d\n", ev._major);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::getBookView call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
*book_view = our_op->view;
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
static void
e_book_response_get_book_view (EBook *book,
EBookStatus status,
GNOME_Evolution_Addressbook_BookView corba_book_view)
{
EBookOp *op;
printf ("e_book_response_get_book_view\n");
op = e_book_get_op (book);
if (op == NULL) {
g_warning ("e_book_response_get_book_view: Cannot find operation ");
return;
}
e_mutex_lock (op->mutex);
op->status = status;
op->view = e_book_view_new (corba_book_view, op->listener);
bonobo_object_ref(BONOBO_OBJECT(op->listener));
pthread_cond_signal (&op->cond);
e_mutex_unlock (op->mutex);
}
/**
* e_book_get_contacts:
* @book: an #EBook
* @query: an #EBookQuery
*
* need docs here..
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_get_contacts (EBook *book,
EBookQuery *query,
GList **contacts,
GError **error)
{
CORBA_Environment ev;
EBookOp *our_op;
EBookStatus status;
char *query_string;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (query, E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (contacts, E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_get_contacts on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
query_string = e_book_query_to_string (query);
/* will eventually end up calling e_book_response_get_contacts */
GNOME_Evolution_Addressbook_Book_getContactList (book->priv->corba_book, query_string, &ev);
g_free (query_string);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_warning ("corba exception._major = %d\n", ev._major);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::getContactList call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
*contacts = our_op->list;
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
static void
e_book_response_get_contacts (EBook *book,
EBookStatus status,
GList *contact_list)
{
EBookOp *op;
op = e_book_get_op (book);
if (op == NULL) {
g_warning ("e_book_response_get_contacts: Cannot find operation ");
return;
}
e_mutex_lock (op->mutex);
op->status = status;
op->list = contact_list;
pthread_cond_signal (&op->cond);
e_mutex_unlock (op->mutex);
}
gboolean
e_book_get_changes (EBook *book,
char *changeid,
GList **changes,
GError **error)
{
CORBA_Environment ev;
EBookOp *our_op;
EBookStatus status;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (changeid, E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (changes, E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_get_changes on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
/* will eventually end up calling e_book_response_get_changes */
GNOME_Evolution_Addressbook_Book_getChanges (book->priv->corba_book, changeid, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_warning ("corba exception._major = %d\n", ev._major);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::getChanges call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
*changes = our_op->list;
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
static void
e_book_response_get_changes (EBook *book,
EBookStatus status,
GList *change_list)
{
EBookOp *op;
op = e_book_get_op (book);
if (op == NULL) {
g_warning ("e_book_response_get_contacts: Cannot find operation ");
return;
}
e_mutex_lock (op->mutex);
op->status = status;
op->list = change_list;
pthread_cond_signal (&op->cond);
e_mutex_unlock (op->mutex);
}
void
e_book_free_change_list (GList *change_list)
{
GList *l;
for (l = change_list; l; l = l->next) {
EBookChange *change = l->data;
g_object_unref (change->contact);
g_free (change);
}
g_list_free (change_list);
}
static void
e_book_response_generic (EBook *book,
EBookStatus status)
{
EBookOp *op;
op = e_book_get_op (book);
if (op == NULL) {
g_warning ("e_book_response_generic: Cannot find operation ");
return;
}
e_mutex_lock (op->mutex);
op->status = status;
pthread_cond_signal (&op->cond);
e_mutex_unlock (op->mutex);
}
/**
* e_book_cancel:
* @book: an #EBook
*
* Used to cancel an already running operation on @book. This
* function makes a synchronous CORBA to the backend telling it to
* cancel the operation. If the operation wasn't cancellable (either
* transiently or permanently) or had already comopleted on the wombat
* side, this function will return E_BOOK_STATUS_COULD_NOT_CANCEL, and
* the operation will continue uncancelled. If the operation could be
* cancelled, this function will return E_BOOK_ERROR_OK, and the
* blocked e_book function corresponding to current operation will
* return with a status of E_BOOK_STATUS_CANCELLED.
*
* Return value: a #EBookStatus value.
**/
gboolean
e_book_cancel (EBook *book,
GError **error)
{
EBookOp *op;
EBookStatus status;
gboolean rv;
CORBA_Environment ev;
e_mutex_lock (book->priv->mutex);
if (book->priv->current_op == NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL,
_("e_book_cancel: there is no current operation"));
return FALSE;
}
op = book->priv->current_op;
e_mutex_lock (op->mutex);
e_mutex_unlock (book->priv->mutex);
status = GNOME_Evolution_Addressbook_Book_cancelOperation(book->priv->corba_book, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
e_mutex_unlock (op->mutex);
CORBA_exception_free (&ev);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::cancelOperation call"));
return FALSE;
}
CORBA_exception_free (&ev);
if (status == E_BOOK_ERROR_OK) {
op->status = E_BOOK_ERROR_CANCELLED;
pthread_cond_signal (&op->cond);
rv = TRUE;
}
else {
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL,
_("e_book_cancel: couldn't cancel"));
rv = FALSE;
}
e_mutex_unlock (op->mutex);
return rv;
}
static void
e_book_response_open (EBook *book,
EBookStatus status)
{
EBookOp *op;
op = e_book_get_op (book);
if (op == NULL) {
g_warning ("e_book_response_open: Cannot find operation ");
return;
}
e_mutex_lock (op->mutex);
op->status = status;
pthread_cond_signal (&op->cond);
e_mutex_unlock (op->mutex);
}
gboolean
e_book_remove (EBook *book,
GError **error)
{
CORBA_Environment ev;
EBookOp *our_op;
EBookStatus status;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_mutex_lock (book->priv->mutex);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED,
_("e_book_remove on book before e_book_load_uri"));
return FALSE;
}
if (book->priv->current_op != NULL) {
e_mutex_unlock (book->priv->mutex);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
_("book busy"));
return FALSE;
}
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
e_mutex_unlock (book->priv->mutex);
CORBA_exception_init (&ev);
/* will eventually end up calling e_book_response_remove */
GNOME_Evolution_Addressbook_Book_remove (book->priv->corba_book, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
_("Corba exception making Book::remove call"));
return FALSE;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
e_book_clear_op (book, our_op);
E_BOOK_CHECK_STATUS (status, error);
}
static void
e_book_response_remove (EBook *book,
EBookStatus status)
{
EBookOp *op;
printf ("e_book_response_remove\n");
op = e_book_get_op (book);
if (op == NULL) {
g_warning ("e_book_response_remove: Cannot find operation ");
return;
}
e_mutex_lock (op->mutex);
op->status = status;
pthread_cond_signal (&op->cond);
e_mutex_unlock (op->mutex);
}
static void
e_book_handle_response (EBookListener *listener, EBookListenerResponse *resp, EBook *book)
{
switch (resp->op) {
case CreateContactResponse:
e_book_response_add_contact (book, resp->status, resp->id);
break;
case RemoveContactResponse:
case ModifyContactResponse:
case AuthenticationResponse:
e_book_response_generic (book, resp->status);
break;
case GetContactResponse: {
EContact *contact = e_contact_new_from_vcard (resp->vcard);
e_book_response_get_contact (book, resp->status, contact);
break;
}
case GetContactListResponse:
e_book_response_get_contacts (book, resp->status, resp->list);
break;
case GetBookViewResponse:
e_book_response_get_book_view(book, resp->status, resp->book_view);
break;
case GetChangesResponse:
e_book_response_get_changes(book, resp->status, resp->list);
break;
case OpenBookResponse:
e_book_response_open (book, resp->status);
break;
case RemoveBookResponse:
e_book_response_remove (book, resp->status);
break;
case GetSupportedFieldsResponse:
e_book_response_get_supported_fields (book, resp->status, resp->list);
break;
case GetSupportedAuthMethodsResponse:
e_book_response_get_supported_auth_methods (book, resp->status, resp->list);
break;
case WritableStatusEvent:
book->priv->writable = resp->writable;
g_signal_emit (book, e_book_signals [WRITABLE_STATUS], 0, resp->writable);
break;
default:
g_error ("EBook: Unknown response code %d!\n",
resp->op);
}
}
gboolean
e_book_unload_uri (EBook *book,
GError **error)
{
CORBA_Environment ev;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (book->priv->load_state != E_BOOK_URI_NOT_LOADED, E_BOOK_ERROR_URI_NOT_LOADED);
/* Release the remote GNOME_Evolution_Addressbook_Book in the PAS. */
CORBA_exception_init (&ev);
bonobo_object_release_unref (book->priv->corba_book, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("e_book_unload_uri: Exception releasing "
"remote book interface!\n");
}
CORBA_exception_free (&ev);
e_book_listener_stop (book->priv->listener);
bonobo_object_unref (BONOBO_OBJECT (book->priv->listener));
book->priv->listener = NULL;
book->priv->load_state = E_BOOK_URI_NOT_LOADED;
g_free (book->priv->cap);
book->priv->cap = NULL;
book->priv->writable = FALSE;
return TRUE;
}
/**
* e_book_load_uri:
*/
static void
backend_died_cb (EComponentListener *cl, gpointer user_data)
{
EBook *book = user_data;
book->priv->load_state = E_BOOK_URI_NOT_LOADED;
g_signal_emit (book, e_book_signals [BACKEND_DIED], 0);
}
static GList *
activate_factories_for_uri (EBook *book, const char *uri)
{
CORBA_Environment ev;
Bonobo_ServerInfoList *info_list = NULL;
int i;
char *protocol, *query, *colon;
GList *factories = NULL;
colon = strchr (uri, ':');
if (!colon) {
g_warning ("e_book_load_uri: Unable to determine protocol in the URI\n");
return FALSE;
}
protocol = g_strndup (uri, colon-uri);
query = g_strdup_printf ("repo_ids.has ('IDL:GNOME/Evolution/BookFactory:1.0')"
" AND addressbook:supported_protocols.has ('%s')", protocol
);
CORBA_exception_init (&ev);
info_list = bonobo_activation_query (query, NULL, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("Eeek! Cannot perform bonobo-activation query for book factories.");
CORBA_exception_free (&ev);
goto done;
return NULL;
}
if (info_list->_length == 0) {
g_warning ("Can't find installed BookFactory that handles protocol '%s'.", protocol);
CORBA_exception_free (&ev);
goto done;
}
CORBA_exception_free (&ev);
for (i = 0; i < info_list->_length; i ++) {
const Bonobo_ServerInfo *info;
GNOME_Evolution_Addressbook_BookFactory factory;
info = info_list->_buffer + i;
factory = bonobo_activation_activate_from_id (info->iid, 0, NULL, NULL);
if (factory == CORBA_OBJECT_NIL)
g_warning ("e_book_construct: Could not obtain a handle "
"to the Personal Addressbook Server with IID `%s'\n", info->iid);
else
factories = g_list_append (factories, factory);
}
done:
if (info_list)
CORBA_free (info_list);
g_free (query);
g_free (protocol);
return factories;
}
gboolean
e_book_load_uri (EBook *book,
const char *uri,
gboolean only_if_exists,
GError **error)
{
GList *factories;
GList *l;
gboolean rv = FALSE;
GNOME_Evolution_Addressbook_Book corba_book = CORBA_OBJECT_NIL;
e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
e_return_error_if_fail (uri, E_BOOK_ERROR_INVALID_ARG);
/* XXX this needs to happen while holding the book's lock i would think... */
e_return_error_if_fail (book->priv->load_state == E_BOOK_URI_NOT_LOADED, E_BOOK_ERROR_URI_ALREADY_LOADED);
/* try to find a list of factories that can handle the protocol */
if (! (factories = activate_factories_for_uri (book, uri))) {
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED,
_("e_book_load_uri: no factories available for uri `%s'"), uri);
return FALSE;
}
book->priv->load_state = E_BOOK_URI_LOADING;
/*
* Create our local BookListener interface.
*/
book->priv->listener = e_book_listener_new ();
if (book->priv->listener == NULL) {
g_warning ("e_book_load_uri: Could not create EBookListener!\n");
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_OTHER_ERROR,
_("e_book_load_uri: Could not create EBookListener"));
return FALSE;
}
book->priv->listener_signal = g_signal_connect (book->priv->listener, "response",
G_CALLBACK (e_book_handle_response), book);
g_free (book->priv->uri);
book->priv->uri = g_strdup (uri);
for (l = factories; l; l = l->next) {
GNOME_Evolution_Addressbook_BookFactory factory = l->data;
EBookOp *our_op;
CORBA_Environment ev;
EBookStatus status;
our_op = e_book_new_op (book);
e_mutex_lock (our_op->mutex);
CORBA_exception_init (&ev);
corba_book = GNOME_Evolution_Addressbook_BookFactory_getBook (factory, book->priv->uri,
bonobo_object_corba_objref (BONOBO_OBJECT (book->priv->listener)),
&ev);
if (ev._major != CORBA_NO_EXCEPTION) {
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
continue;
}
GNOME_Evolution_Addressbook_Book_open (corba_book,
only_if_exists,
&ev);
if (ev._major != CORBA_NO_EXCEPTION) {
/* kill the listener so the book will die */
g_signal_handler_disconnect (book->priv->listener, book->priv->listener_signal);
bonobo_object_unref (book->priv->listener);
book->priv->listener = NULL;
e_book_clear_op (book, our_op);
CORBA_exception_free (&ev);
continue;
}
CORBA_exception_free (&ev);
/* wait for something to happen (both cancellation and a
successful response will notity us via our cv */
e_mutex_cond_wait (&our_op->cond, our_op->mutex);
status = our_op->status;
/* remove the op from the book's hash of operations */
e_book_clear_op (book, our_op);
if (status == E_BOOK_ERROR_CANCELLED
|| status == E_BOOK_ERROR_OK) {
rv = TRUE;
break;
}
}
/* free up the factories */
for (l = factories; l; l = l->next)
CORBA_Object_release ((CORBA_Object)l->data, NULL);
if (rv == TRUE) {
book->priv->corba_book = corba_book;
book->priv->load_state = E_BOOK_URI_LOADED;
book->priv->comp_listener = e_component_listener_new (book->priv->corba_book);
book->priv->died_signal = g_signal_connect (book->priv->comp_listener, "component_died",
G_CALLBACK (backend_died_cb), book);
return TRUE;
}
else {
g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED,
_("e_book_load_uri: no factories available for uri `%s'"), uri);
return FALSE;
}
return rv;
}
gboolean
e_book_load_local_addressbook (EBook *book,
GError **error)
{
char *filename;
char *uri;
gboolean rv;
filename = g_build_filename (g_get_home_dir(),
"evolution/local/Contacts",
NULL);
uri = g_strdup_printf ("file://%s", filename);
g_free (filename);
rv = e_book_load_uri (book, uri, TRUE, error);
g_free (uri);
return rv;
}
const char *
e_book_get_uri (EBook *book)
{
return book->priv->uri;
}
const char *
e_book_get_static_capabilities (EBook *book,
GError **error)
{
if (!book->priv->cap_queried) {
CORBA_Environment ev;
char *temp;
CORBA_exception_init (&ev);
if (book->priv->load_state != E_BOOK_URI_LOADED) {
g_warning ("e_book_unload_uri: No URI is loaded!\n");
return g_strdup("");
}
temp = GNOME_Evolution_Addressbook_Book_getStaticCapabilities(book->priv->corba_book, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("e_book_get_static_capabilities: Exception "
"during get_static_capabilities!\n");
CORBA_exception_free (&ev);
return g_strdup("");
}
book->priv->cap = g_strdup(temp);
book->priv->cap_queried = TRUE;
CORBA_free(temp);
CORBA_exception_free (&ev);
}
return book->priv->cap;
}
gboolean
e_book_check_static_capability (EBook *book,
const char *cap)
{
const char *caps = e_book_get_static_capabilities (book, NULL);
/* XXX this is an inexact test but it works for our use */
if (caps && strstr (caps, cap))
return TRUE;
return FALSE;
}
gboolean
e_book_is_writable (EBook *book)
{
return book->priv->writable;
}
gboolean
e_book_get_self (EContact **contact, EBook **book, GError **error)
{
GError *e = NULL;
if (!e_book_get_default_addressbook (book, &e)) {
g_propagate_error (error, e);
return FALSE;
}
#if notyet
EBook *b;
char *self_uri, *self_uid;
/* XXX get the setting for the self book and self uid from gconf */
b = e_book_new();
if (! e_book_load_uri (b, self_uri, TRUE, error)) {
g_object_unref (b);
return FALSE;
}
if (! e_book_get_contact (b, self_uid,
contact, error)) {
g_object_unref (b);
return FALSE;
}
if (book)
*book = b;
else
g_object_unref (b);
return TRUE;
#endif
}
gboolean
e_book_set_self (EBook *book, const char *id, GError **error)
{
}
gboolean
e_book_get_default_addressbook (EBook **book, GError **error)
{
/* XXX for now just load the local ~/evolution/local/Contacts */
char *path, *uri;
gboolean rv;
*book = e_book_new ();
path = g_build_filename (g_get_home_dir (),
"evolution/local/Contacts",
NULL);
uri = g_strdup_printf ("file://%s", path);
g_free (path);
rv = e_book_load_uri (*book, uri, FALSE, error);
g_free (uri);
if (!rv) {
g_object_unref (*book);
*book = NULL;
}
return rv;
#if notyet
EConfigListener *listener = e_config_listener_new ();
ESourceList *sources = ...;
ESource *default_source;
default_source = e_source_list_peek_source_by_uid (sources,
"default_");
#endif
}
#if notyet
ESourceList*
e_book_get_addressbooks (GError **error)
{
}
#endif
static void*
startup_mainloop (void *arg)
{
bonobo_main();
return NULL;
}
/* one-time start up for libebook */
static void
e_book_activate()
{
static GStaticMutex e_book_lock = G_STATIC_MUTEX_INIT;
static gboolean activated = FALSE;
g_static_mutex_lock (&e_book_lock);
if (!activated) {
pthread_t ebook_mainloop_thread;
activated = TRUE;
pthread_create(&ebook_mainloop_thread, NULL, startup_mainloop, NULL);
}
g_static_mutex_unlock (&e_book_lock);
}
EBook*
e_book_new (void)
{
e_book_activate ();
return g_object_new (E_TYPE_BOOK, NULL);
}
static void
e_book_init (EBook *book)
{
book->priv = g_new0 (EBookPrivate, 1);
book->priv->load_state = E_BOOK_URI_NOT_LOADED;
book->priv->uri = NULL;
book->priv->mutex = e_mutex_new (E_MUTEX_REC);
}
static void
e_book_dispose (GObject *object)
{
EBook *book = E_BOOK (object);
if (book->priv) {
CORBA_Environment ev;
GList *l;
if (book->priv->comp_listener) {
g_signal_handler_disconnect (book->priv->comp_listener, book->priv->died_signal);
g_object_unref (book->priv->comp_listener);
book->priv->comp_listener = NULL;
}
if (book->priv->load_state == E_BOOK_URI_LOADED)
e_book_unload_uri (book, NULL);
CORBA_exception_init (&ev);
for (l = book->priv->book_factories; l; l = l->next) {
CORBA_Object_release ((CORBA_Object)l->data, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("EBook: Exception while releasing BookFactory\n");
CORBA_exception_free (&ev);
CORBA_exception_init (&ev);
}
}
CORBA_exception_free (&ev);
if (book->priv->listener) {
g_signal_handler_disconnect (book->priv->listener, book->priv->listener_signal);
bonobo_object_unref (book->priv->listener);
book->priv->listener = NULL;
}
g_free (book->priv->cap);
g_free (book->priv->uri);
g_free (book->priv);
book->priv = NULL;
}
if (G_OBJECT_CLASS (parent_class)->dispose)
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
e_book_class_init (EBookClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_ref (G_TYPE_OBJECT);
e_book_signals [WRITABLE_STATUS] =
g_signal_new ("writable_status",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EBookClass, writable_status),
NULL, NULL,
e_book_marshal_NONE__BOOL,
G_TYPE_NONE, 1,
G_TYPE_BOOLEAN);
e_book_signals [BACKEND_DIED] =
g_signal_new ("backend_died",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EBookClass, backend_died),
NULL, NULL,
e_book_marshal_NONE__NONE,
G_TYPE_NONE, 0);
object_class->dispose = e_book_dispose;
}
/**
* e_book_get_type:
*/
GType
e_book_get_type (void)
{
static GType type = 0;
if (! type) {
GTypeInfo info = {
sizeof (EBookClass),
NULL, /* base_class_init */
NULL, /* base_class_finalize */
(GClassInitFunc) e_book_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (EBook),
0, /* n_preallocs */
(GInstanceInitFunc) e_book_init
};
type = g_type_register_static (G_TYPE_OBJECT, "EBook", &info, 0);
}
return type;
}