/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Exports the BookListener interface. Maintains a queue of messages
* which come in on the interface.
*
* Author:
* Nat Friedman (nat@ximian.com)
*
* Copyright 2000, Ximian, Inc.
*/
#include <config.h>
#include <bonobo/bonobo-main.h>
#include "e-book-listener.h"
#include "e-book-marshal.h"
static EBookStatus e_book_listener_convert_status (GNOME_Evolution_Addressbook_BookListener_CallStatus status);
enum {
RESPONSES_QUEUED,
LAST_SIGNAL
};
static guint e_book_listener_signals [LAST_SIGNAL];
static BonoboObjectClass *parent_class;
struct _EBookListenerPrivate {
GList *response_queue;
gint timeout_id;
guint timeout_lock : 1;
guint stopped : 1;
};
static void
response_free (EBookListenerResponse *resp)
{
if (resp == NULL)
return;
g_free (resp->msg);
g_free (resp->id);
if (resp->book != CORBA_OBJECT_NIL) {
CORBA_Environment ev;
CORBA_exception_init (&ev);
bonobo_object_release_unref (resp->book, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("e_book_listener_destroy: "
"Exception destroying book "
"in response queue!\n");
}
CORBA_exception_free (&ev);
}
if (resp->cursor != CORBA_OBJECT_NIL) {
CORBA_Environment ev;
CORBA_exception_init (&ev);
bonobo_object_release_unref (resp->cursor, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("e_book_listener_destroy: "
"Exception destroying cursor "
"in response queue!\n");
}
CORBA_exception_free (&ev);
}
if (resp->book_view != CORBA_OBJECT_NIL) {
CORBA_Environment ev;
CORBA_exception_init (&ev);
bonobo_object_release_unref (resp->book_view, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("e_book_listener_destroy: "
"Exception destroying book_view "
"in response queue!\n");
}
CORBA_exception_free (&ev);
}
g_free (resp);
}
static gboolean
e_book_listener_check_queue (EBookListener *listener)
{
if (listener->priv->timeout_lock)
return TRUE;
listener->priv->timeout_lock = TRUE;
if (listener->priv->response_queue != NULL && !listener->priv->stopped) {
g_signal_emit (listener, e_book_listener_signals [RESPONSES_QUEUED], 0);
}
if (listener->priv->response_queue == NULL || listener->priv->stopped) {
listener->priv->timeout_id = 0;
listener->priv->timeout_lock = FALSE;
bonobo_object_unref (BONOBO_OBJECT (listener)); /* release the timeout's reference */
return FALSE;
}
listener->priv->timeout_lock = FALSE;
return TRUE;
}
static void
e_book_listener_queue_response (EBookListener *listener,
EBookListenerResponse *response)
{
if (response == NULL)
return;
if (listener->priv->stopped) {
response_free (response);
return;
}
listener->priv->response_queue = g_list_append (listener->priv->response_queue, response);
if (listener->priv->timeout_id == 0) {
/* 20 == an arbitrary small integer */
listener->priv->timeout_id = g_timeout_add (20, (GSourceFunc) e_book_listener_check_queue, listener);
/* Hold a reference on behalf of the timeout */
bonobo_object_ref (BONOBO_OBJECT (listener));
}
}
/* Add, Remove, Modify */
static void
e_book_listener_queue_generic_response (EBookListener *listener,
EBookListenerOperation op,
EBookStatus status)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = op;
resp->status = status;
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_open_response (EBookListener *listener,
EBookStatus status,
GNOME_Evolution_Addressbook_Book book)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = OpenBookResponse;
resp->status = status;
resp->book = book;
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_open_progress (EBookListener *listener,
const char *msg,
short percent)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = OpenProgressEvent;
resp->msg = g_strdup (msg);
resp->percent = percent;
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_create_card_response (EBookListener *listener,
EBookStatus status,
const char *id)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = CreateCardResponse;
resp->status = status;
resp->id = g_strdup (id);
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_get_vcard_response (EBookListener *listener,
EBookStatus status,
const char *vcard)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = GetCardResponse;
resp->status = status;
resp->vcard = g_strdup (vcard);
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_get_cursor_response (EBookListener *listener,
EBookStatus status,
GNOME_Evolution_Addressbook_CardCursor cursor)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = GetCursorResponse;
resp->status = status;
resp->cursor = cursor;
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_get_view_response (EBookListener *listener,
EBookStatus status,
GNOME_Evolution_Addressbook_BookView book_view)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = GetBookViewResponse;
resp->status = status;
resp->book_view = book_view;
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_get_changes_response (EBookListener *listener,
EBookStatus status,
GNOME_Evolution_Addressbook_BookView book_view)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = GetChangesResponse;
resp->status = status;
resp->book_view = book_view;
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_link_status (EBookListener *listener,
gboolean connected)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = LinkStatusEvent;
resp->connected = connected;
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_writable_status (EBookListener *listener,
gboolean writable)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = WritableStatusEvent;
resp->writable = writable;
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_authentication_response (EBookListener *listener,
EBookStatus status)
{
EBookListenerResponse *resp;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = AuthenticationResponse;
resp->status = status;
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_get_supported_fields_response (EBookListener *listener,
EBookStatus status,
const GNOME_Evolution_Addressbook_stringlist *fields)
{
EBookListenerResponse *resp;
int i;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = GetSupportedFieldsResponse;
resp->status = status;
resp->list = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL);
for (i = 0; i < fields->_length; i ++) {
e_list_append (resp->list, fields->_buffer[i]);
}
e_book_listener_queue_response (listener, resp);
}
static void
e_book_listener_queue_get_supported_auth_methods_response (EBookListener *listener,
EBookStatus status,
const GNOME_Evolution_Addressbook_stringlist *auth_methods)
{
EBookListenerResponse *resp;
int i;
if (listener->priv->stopped)
return;
resp = g_new0 (EBookListenerResponse, 1);
resp->op = GetSupportedAuthMethodsResponse;
resp->status = status;
resp->list = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL);
for (i = 0; i < auth_methods->_length; i ++) {
e_list_append (resp->list, auth_methods->_buffer[i]);
}
e_book_listener_queue_response (listener, resp);
}
static void
impl_BookListener_respond_create_card (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
const CORBA_char* id,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
e_book_listener_queue_create_card_response (
listener,
e_book_listener_convert_status (status),
id);
}
static void
impl_BookListener_respond_remove_cards (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
e_book_listener_queue_generic_response (
listener, RemoveCardResponse,
e_book_listener_convert_status (status));
}
static void
impl_BookListener_respond_modify_card (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
e_book_listener_queue_generic_response (
listener, ModifyCardResponse,
e_book_listener_convert_status (status));
}
static void
impl_BookListener_respond_get_vcard (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
const CORBA_char* card,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
e_book_listener_queue_get_vcard_response (
listener,
e_book_listener_convert_status (status),
g_strdup (card));
}
static void
impl_BookListener_respond_get_cursor (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
const GNOME_Evolution_Addressbook_CardCursor cursor,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
GNOME_Evolution_Addressbook_CardCursor cursor_copy;
cursor_copy = bonobo_object_dup_ref (cursor, ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
g_warning ("EBookListener: Exception while duplicating CardCursor!\n");
return;
}
e_book_listener_queue_get_cursor_response (
listener,
e_book_listener_convert_status (status),
cursor_copy);
}
static void
impl_BookListener_respond_get_view (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
const GNOME_Evolution_Addressbook_BookView book_view,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
GNOME_Evolution_Addressbook_BookView book_view_copy;
book_view_copy = bonobo_object_dup_ref (book_view, ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
g_warning ("EBookListener: Exception while duplicating BookView.\n");
return;
}
e_book_listener_queue_get_view_response (
listener,
e_book_listener_convert_status (status),
book_view_copy);
}
static void
impl_BookListener_respond_get_changes (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
const GNOME_Evolution_Addressbook_BookView book_view,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
GNOME_Evolution_Addressbook_BookView book_view_copy;
book_view_copy = bonobo_object_dup_ref (book_view, ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
g_warning ("EBookListener: Exception while duplicating BookView.\n");
return;
}
e_book_listener_queue_get_changes_response (
listener,
e_book_listener_convert_status (status),
book_view_copy);
}
static void
impl_BookListener_respond_open_book (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
const GNOME_Evolution_Addressbook_Book book,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
GNOME_Evolution_Addressbook_Book book_copy;
book_copy = bonobo_object_dup_ref (book, ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
g_warning ("EBookListener: Exception while duplicating Book!\n");
return;
}
e_book_listener_queue_open_response (
listener,
e_book_listener_convert_status (status),
book_copy);
}
static void
impl_BookListener_report_open_book_progress (PortableServer_Servant servant,
const CORBA_char *status_message,
const CORBA_short percent,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
e_book_listener_queue_open_progress (
listener, status_message, percent);
}
static void
impl_BookListener_respond_authentication_result (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
e_book_listener_queue_authentication_response (
listener, status);
}
static void
impl_BookListener_response_get_supported_fields (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
const GNOME_Evolution_Addressbook_stringlist *fields,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
e_book_listener_queue_get_supported_fields_response (
listener, status, fields);
}
static void
impl_BookListener_response_get_supported_auth_methods (PortableServer_Servant servant,
const GNOME_Evolution_Addressbook_BookListener_CallStatus status,
const GNOME_Evolution_Addressbook_stringlist *auth_methods,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
e_book_listener_queue_get_supported_auth_methods_response (
listener, status, auth_methods);
}
static void
impl_BookListener_report_connection_status (PortableServer_Servant servant,
const CORBA_boolean connected,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
e_book_listener_queue_link_status (
listener, connected);
}
static void
impl_BookListener_report_writable (PortableServer_Servant servant,
const CORBA_boolean writable,
CORBA_Environment *ev)
{
EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant));
e_book_listener_queue_writable_status (listener, writable);
}
/**
* e_book_listener_check_pending:
* @listener: the #EBookListener
*
* Returns: the number of items on the response queue,
* or -1 if the @listener is isn't an #EBookListener.
*/
int
e_book_listener_check_pending (EBookListener *listener)
{
g_return_val_if_fail (listener != NULL, -1);
g_return_val_if_fail (E_IS_BOOK_LISTENER (listener), -1);
return g_list_length (listener->priv->response_queue);
}
/**
* e_book_listener_pop_response:
* @listener: the #EBookListener for which a request is to be popped
*
* Returns: an #EBookListenerResponse if there are responses on the
* queue to be returned; %NULL if there aren't, or if the @listener
* isn't an EBookListener.
*/
EBookListenerResponse *
e_book_listener_pop_response (EBookListener *listener)
{
EBookListenerResponse *resp;
GList *popped;
g_return_val_if_fail (listener != NULL, NULL);
g_return_val_if_fail (E_IS_BOOK_LISTENER (listener), NULL);
if (listener->priv->response_queue == NULL)
return NULL;
resp = listener->priv->response_queue->data;
popped = listener->priv->response_queue;
listener->priv->response_queue =
g_list_remove_link (listener->priv->response_queue,
listener->priv->response_queue);
g_list_free_1 (popped);
return resp;
}
static EBookStatus
e_book_listener_convert_status (const GNOME_Evolution_Addressbook_BookListener_CallStatus status)
{
switch (status) {
case GNOME_Evolution_Addressbook_BookListener_Success:
return E_BOOK_STATUS_SUCCESS;
case GNOME_Evolution_Addressbook_BookListener_RepositoryOffline:
return E_BOOK_STATUS_REPOSITORY_OFFLINE;
case GNOME_Evolution_Addressbook_BookListener_PermissionDenied:
return E_BOOK_STATUS_PERMISSION_DENIED;
case GNOME_Evolution_Addressbook_BookListener_CardNotFound:
return E_BOOK_STATUS_CARD_NOT_FOUND;
case GNOME_Evolution_Addressbook_BookListener_CardIdAlreadyExists:
return E_BOOK_STATUS_CARD_ID_ALREADY_EXISTS;
case GNOME_Evolution_Addressbook_BookListener_ProtocolNotSupported:
return E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED;
case GNOME_Evolution_Addressbook_BookListener_AuthenticationFailed:
return E_BOOK_STATUS_AUTHENTICATION_FAILED;
case GNOME_Evolution_Addressbook_BookListener_AuthenticationRequired:
return E_BOOK_STATUS_AUTHENTICATION_REQUIRED;
case GNOME_Evolution_Addressbook_BookListener_TLSNotAvailable:
return E_BOOK_STATUS_TLS_NOT_AVAILABLE;
case GNOME_Evolution_Addressbook_BookListener_NoSuchBook:
return E_BOOK_STATUS_NO_SUCH_BOOK;
case GNOME_Evolution_Addressbook_BookListener_OtherError:
return E_BOOK_STATUS_OTHER_ERROR;
default:
g_warning ("e_book_listener_convert_status: Unknown status "
"from card server: %d\n", (int) status);
return E_BOOK_STATUS_UNKNOWN;
}
}
static void
e_book_listener_construct (EBookListener *listener)
{
/* nothing to do here */
}
/**
* e_book_listener_new:
* @book: the #EBook for which the listener is to be bound
*
* Creates and returns a new #EBookListener for the book.
*
* Returns: a new #EBookListener
*/
EBookListener *
e_book_listener_new ()
{
EBookListener *listener;
listener = g_object_new (E_TYPE_BOOK_LISTENER, NULL);
e_book_listener_construct (listener);
return listener;
}
static void
e_book_listener_init (EBookListener *listener)
{
listener->priv = g_new0 (EBookListenerPrivate, 1);
}
void
e_book_listener_stop (EBookListener *listener)
{
g_return_if_fail (E_IS_BOOK_LISTENER (listener));
listener->priv->stopped = TRUE;
}
static void
e_book_listener_dispose (GObject *object)
{
EBookListener *listener = E_BOOK_LISTENER (object);
if (listener->priv) {
GList *l;
/* Remove our response queue handler: In theory, this
can never happen since we always hold a reference
to the listener while the timeout is running. */
if (listener->priv->timeout_id) {
g_source_remove (listener->priv->timeout_id);
}
/* Clean up anything still sitting in response_queue */
for (l = listener->priv->response_queue; l != NULL; l = l->next) {
EBookListenerResponse *resp = l->data;
response_free (resp);
}
g_list_free (listener->priv->response_queue);
g_free (listener->priv);
listener->priv = NULL;
}
if (G_OBJECT_CLASS (parent_class)->dispose)
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
e_book_listener_class_init (EBookListenerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
POA_GNOME_Evolution_Addressbook_BookListener__epv *epv;
parent_class = g_type_class_ref (BONOBO_TYPE_OBJECT);
e_book_listener_signals [RESPONSES_QUEUED] =
g_signal_new ("responses_queued",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EBookListenerClass, responses_queued),
NULL, NULL,
e_book_marshal_NONE__NONE,
G_TYPE_NONE, 0);
object_class->dispose = e_book_listener_dispose;
epv = &klass->epv;
epv->notifyOpenBookProgress = impl_BookListener_report_open_book_progress;
epv->notifyBookOpened = impl_BookListener_respond_open_book;
epv->notifyCardCreated = impl_BookListener_respond_create_card;
epv->notifyCardsRemoved = impl_BookListener_respond_remove_cards;
epv->notifyCardModified = impl_BookListener_respond_modify_card;
epv->notifyAuthenticationResult = impl_BookListener_respond_authentication_result;
epv->notifySupportedFields = impl_BookListener_response_get_supported_fields;
epv->notifySupportedAuthMethods = impl_BookListener_response_get_supported_auth_methods;
epv->notifyCardRequested = impl_BookListener_respond_get_vcard;
epv->notifyCursorRequested = impl_BookListener_respond_get_cursor;
epv->notifyViewRequested = impl_BookListener_respond_get_view;
epv->notifyChangesRequested = impl_BookListener_respond_get_changes;
epv->notifyConnectionStatus = impl_BookListener_report_connection_status;
epv->notifyWritable = impl_BookListener_report_writable;
}
BONOBO_TYPE_FUNC_FULL (
EBookListener,
GNOME_Evolution_Addressbook_BookListener,
BONOBO_TYPE_OBJECT,
e_book_listener);