Logo Search packages:      
Sourcecode: libical version File versions  Download package

icalcap_rr.c

#include "config.h"

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif

#include "icalcap.h"
#include "icalcap_session.h"
#include "icalcap_server.h"

#include "icalcap_impl.h"
#include "icalcap_message_impl.h"
#include "icalcap_session_impl.h"
#include "icalcap_server_impl.h"

icalcomponent *icalcap_component_new_from_string(const char *data);

static int  default_msg_handler(RRCAP *cap, RRFrame *frame, GError **error);
static void client_final_handler(RRCAP *cap);

/**
 * Implementation of functions in icalcap
 */
void
icalcap_free_rr(icalcap *cap) {

      g_return_if_fail(cap);

      if (cap->username)
            free(cap->username);

      if (cap->authname)
            free(cap->authname);

      g_free(cap);
}

/**
 * Implementation of functions in icalcap_session
 */
icalcap_session *
icalcap_session_new_rr(void) {

      icalcap_session *sess;
      GError  *error = NULL;

      /* Initialize roadrunner */
      if (!rr_init(0, NULL, &error))
            return 0;

      if ((sess = g_new0(icalcap_session, 1)) == NULL) {
            /* FIXME return an error */
            return NULL;
      }

      sess->cfg = rr_cap_config_new();

      /* Tell roadrunner which profiles we want to support */
      sess->profreg = rr_profile_registry_new();
      rr_profile_registry_add_profile(sess->profreg, RR_TYPE_CAP, NULL);
      rr_profile_registry_add_profile(sess->profreg, RR_TYPE_TLS, NULL);
      rr_profile_registry_add_profile(sess->profreg, RR_TYPE_SASL_DIGEST_MD5, NULL);

      return sess;
}

int
icalcap_session_connect_rr(icalcap_session *sess, const char *hostname, const int port) {

      GError             *error = NULL;

      if (sess == NULL) {
            /* FIXME return the error */
            return FALSE;
      }

      /* Create a connection object */
      sess->connection = rr_tcp_connection_new(sess->profreg, hostname, port, &error);
      if (sess->connection == NULL) {
            /* FIXME return the error */
            return FALSE;
      }

      return TRUE;
}

int
icalcap_session_login_rr(icalcap_session *sess, const char *username, const char *authname,
                  const char *password) {

      /* assert cap != NULL */
      GError      *error = NULL;

      rr_sasl_set_username(sess->connection, username);
      rr_sasl_set_authname(sess->connection, authname);
      rr_sasl_set_password(sess->connection, password);

      /* FIXME */
      if (!rr_sasl_login(sess->connection, RR_TYPE_SASL_DIGEST_MD5, 
                      "foo.example.com", NULL, &error)) {
            /* FIXME return the error */
            return 0;
      }

      return 1;
}

icalcap *
icalcap_session_start_rr(const icalcap_session *sess, icalcap_msg_handler handler) {

      /* assert sess != NULL */
      icalcap            *cap;
      RRCAP        *channel;
      GError             *error = NULL;

      if ((cap = g_new0(icalcap, 1)) == NULL) {
            /* FIXME return an error */
            return NULL;
      }

      if (handler != NULL) {
            rr_cap_config_set_msg_handler(sess->cfg, default_msg_handler, (void *)handler);
            /* FIXME rr_cap_config_set_final_handler(cfg, client_final_handler); */
      }

      if ((channel = rr_cap_client_start(sess->connection, sess->cfg, &error)) == NULL) {
            /* FIXME return the error */
            goto FAILED;
      }

      cap->chan = channel;
      channel->hl = cap;

      return cap;

FAILED:
      g_free(cap);
      return NULL;
}

int
icalcap_stop_rr(icalcap *cap) {

      /* assert cap != NULL */
      GError      *error = NULL;

      if (!rr_cap_close(cap->chan, &error)) {
            /* FIXME return the error */
            return 0;
      }

      cap->chan = NULL;
      g_free(cap);

      return 1;
}

int
icalcap_session_disconnect_rr(icalcap_session *sess) {

      /* assert cap != NULL */
      GError      *error = NULL;

      if (!rr_connection_disconnect(sess->connection, &error)) {
            /* FIXME return the error */
            return 0;
      }

      sess->connection = NULL;
      g_free(sess);

      if (!rr_exit(&error)) {
            /* FIXME return the error */
            return 0;
      }

      return 1;
}

/**
 * Implementation of functions in icalcap_server
 */

/**
 * If the user properly authenticated (via SASL), initialize the channel
 * credentials. Otherwise, refuse to open the channel.
 */
static int
server_init_handler(RRCAP *chan, const gchar *piggyback, GError **error) {

      icalcap                  *cap;
      RRConnection             *connection;

      icalcap_auth_handler    func;
      const gchar        *username, *authname;
      int               rc;

      g_return_val_if_fail(chan, FALSE);
      g_return_val_if_fail(chan->cfg, FALSE);
      g_return_val_if_fail(chan->cfg->server_init_data, FALSE);

      connection = rr_channel_get_connection(RR_CHANNEL(chan));
      if ((username = rr_sasl_get_username(connection)) == NULL)
            return FALSE;
      if ((authname = rr_sasl_get_authname(connection)) == NULL)
            return FALSE;

      if ((cap = g_new0(icalcap, 1)) == NULL) {
            return FALSE;
      }

      cap->chan = chan;
      chan->hl = cap;

      cap->username = strdup(username);
      cap->authname = strdup(authname);

      func = (icalcap_auth_handler)chan->cfg->server_init_data;
      return func(cap, piggyback);
}

static void
server_confirmation_handler(RRCAP *chan) {

      icalcap_chanup_handler  func;

      g_return_if_fail(chan);
      g_return_if_fail(chan->cfg);
      g_return_if_fail(chan->cfg->server_confirmation_data);

      func = (icalcap_chanup_handler)chan->cfg->server_confirmation_data;

      func(chan->hl);
}

static gboolean
server_frame_handler(RRCAP *cap, RRFrame *frame, GError **error)
{
      if (frame->type == RR_FRAME_TYPE_MSG)
            /* FIXME */
            return default_msg_handler(cap, frame, error);
      else
            return FALSE;
}

static void
server_final_handler(RRCAP *cap)
{
      g_return_if_fail(cap);
      g_return_if_fail(RR_CAP(cap));

      if (cap->hl != NULL) {
            icalcap_free(cap->hl);
            cap->hl = NULL;
      }
}

/*
 * FIXME Do we want to pass argc and argv in?
 */
icalcap_server *
icalcap_server_new_rr(icalcap_auth_handler auth_cb, icalcap_chanup_handler chanup_cb,
                                                icalcap_msg_handler msg_cb) {

      icalcap_server *serv;
      GError             *error = NULL;

      /* Initialize roadrunner */
      if (!rr_init(0, NULL, &error))
            return 0;

      if ((serv = g_new0(icalcap_server, 1)) == NULL) {
            /* FIXME return an error */
            return NULL;
      }
      serv->handler = msg_cb;

      /* This is somewhat hackish */
      serv->cfg = rr_cap_config_new();
      rr_cap_config_set_msg_handler(serv->cfg, NULL, (void *)msg_cb);
      rr_cap_config_set_frame_handler(serv->cfg, server_frame_handler);
      rr_cap_config_set_final_handler(serv->cfg, server_final_handler);
      rr_cap_config_set_server_init_handler(serv->cfg, server_init_handler, (void *)auth_cb);
      rr_cap_config_set_server_confirmation_handler(serv->cfg,
                                    server_confirmation_handler, (void *)chanup_cb);

      /* Tell roadrunner which profiles we want to support */
      serv->profreg = rr_profile_registry_new();
      rr_profile_registry_add_profile(serv->profreg, RR_TYPE_CAP, serv->cfg);
      rr_profile_registry_add_profile(serv->profreg, RR_TYPE_TLS, NULL);
      rr_profile_registry_add_profile(serv->profreg, RR_TYPE_SASL_DIGEST_MD5, NULL);

      return serv;
}

int
icalcap_server_listen_rr(icalcap_server *serv, const char *hostname, const int port) {

      GError             *error = NULL;
      g_return_val_if_fail(serv, FALSE);

      /* Create a listener object */
      serv->listener = rr_tcp_listener_new(serv->profreg, hostname, port, &error);
      if (serv->listener == NULL) {
            /* FIXME return the error */
            return FALSE;
      }

      return TRUE;
}

int
icalcap_server_run_rr(const icalcap_server *serv) {

      /* assert cap != NULL */
      GError      *error = NULL;

      if (!rr_wait_until_done(&error)) {
            /* FIXME return the error */
            return FALSE;
      }

      return TRUE;
}

int
icalcap_server_shutdown_rr(icalcap_server *serv) {

      /* assert cap != NULL */
      GError      *error = NULL;

      if (!rr_listener_shutdown(serv->listener, &error)) {
            /* FIXME return the error */
            return 0;
      }

      serv->listener = NULL;
      g_free(serv);

      return 1;
}

/*
 * icalcap_message.c
 */

/*
 * Internal constructor
 */
static struct _icalcap_message_rr *
_icalcap_message_new_from_component_rr(const icalcap *cap, int type, icalcomponent *comp) {

      struct _icalcap_message_rr    *ret;

      if ((ret = g_new0(struct _icalcap_message_rr, 1)) == NULL) {
            /* FIXME return an error */
            return NULL;
      }

      ret->cap    = cap;
      ret->type   = type;

      ret->comp   = comp;

      return ret;
}

static icalcap_message *
_icalcap_message_new_from_frame_rr(const icalcap *cap, int type, RRFrame *frame) {

      struct _icalcap_message_rr    *ret;

      if ((ret = g_new0(struct _icalcap_message_rr, 1)) == NULL) {
            /* FIXME return an error */
            return NULL;
      }

      ret->cap    = cap;
      ret->type   = type;
      ret->frame  = frame;

      ret->comp   = icalcap_component_new_from_string(ret->frame->payload);

      return (icalcap_message *)ret;
}

icalcap_message *
icalcap_message_new_rr(const icalcap *cap, const icalcomponent *comp) {

      struct _icalcap_message_rr    *ret;
      gchar                   *str, *obj;

      if (comp == NULL) {
            /* FIXME return an error */
            return NULL;
      }

      ret = _icalcap_message_new_from_component_rr(cap, ICALCAP_MESSAGE_CMD, NULL);

      obj = icalcomponent_as_ical_string_r(comp);
      str = g_strdup_printf("%s\n\n%s",
            "Content-Type: text/calendar",
            obj);
      free(obj);

      ret->msg    = rr_message_static_new(RR_FRAME_TYPE_MSG, str, strlen(str), TRUE);

      return (icalcap_message *)ret;
}

/*
 * This method and its implementation are critical. It has the responsibility for
 * serializing the component. The tricky part is that we have a options for encoding XROOT.
 */
icalcap_message *
icalcap_message_new_reply_rr(const icalcap_message *orig, const icalcomponent *comp) {

      struct _icalcap_message_rr     *in, *ret;
      icalcomponent                  *cc;
      GString                        *str;

      if ((in = (struct _icalcap_message_rr *)orig) == NULL) {
            /* FIXME return an error */
            return NULL;
      }

      ret = _icalcap_message_new_from_component_rr(in->cap, ICALCAP_MESSAGE_REPLY, NULL);

      /* FIXME */
      if (icalcomponent_isa(comp) != ICAL_XROOT_COMPONENT)
            return NULL;

      /* FIXME don't hardcode */
      str = g_string_new("Content-Type: text/calendar\n\n");

      for (cc = icalcomponent_get_first_component(comp,
                              ICAL_VCALENDAR_COMPONENT);
           cc != NULL;
           cc = icalcomponent_get_next_component(comp,
                              ICAL_VCALENDAR_COMPONENT)) {
            char *obj;
            obj = icalcomponent_as_ical_string_r(cc);
            g_string_append(str, obj);
            free(obj);
      }

      ret->msg    = rr_message_static_new(RR_FRAME_TYPE_RPY, str->str, strlen(str->str), TRUE);
      /* FIXME this should now be ok but if change the API we need to change */
      ret->msg->msgno = in->frame->msgno;

      return (icalcap_message *)ret;
}

void
icalcap_message_free_rr(icalcap_message *in) {

      struct _icalcap_message_rr *capmsg = (struct _icalcap_message_rr *)in;
      g_return_if_fail(capmsg);

      if (capmsg->comp != NULL) {
            icalcomponent_free(capmsg->comp);
            capmsg->comp = NULL;
      }

      if (capmsg->msg != NULL) {
            g_free(capmsg->msg);
      }

      g_free(capmsg);
}

int
icalcap_message_send_reply_rr(icalcap_message *in) {

      struct _icalcap_message_rr     *capmsg = (struct _icalcap_message_rr *)in;
      GError                         *error = NULL;
      int                     rc;

      if ((rc = rr_channel_send_message(RR_CHANNEL(capmsg->cap->chan), capmsg->msg, &error)) == 0)
            g_message("error = %s", error->message);
      /* FIXME handle error */

      capmsg->msg = NULL;

      return rc;
}

icalcomponent *
icalcap_message_sync_send_rr(icalcap_message *in, int timeout) {

      struct _icalcap_message_rr     *capmsg = (struct _icalcap_message_rr *)in;
      icalcomponent                  *comp, *ret;

      gchar                    *str2;
      GError                         *error = NULL;
      int                     rc;

      /* FIXME */
      rc = rr_cap_cmd(capmsg->cap->chan, capmsg->msg, 3 * timeout, &str2, &error);
      capmsg->msg = NULL;
      if (rc == 0) {
            g_message("error = %s", error->message);
            /* FIXME handle error */
            return 0;
      }

      comp = icalcap_component_new_from_string(str2);
      g_free(str2);
      if (ret == NULL)
            return NULL;

      return comp;
}

/*
 *
 */

/*
 * FIXME We assume we can safely create an icalcap_message derived object
 * without calls to the base object
 */
int
default_msg_handler(RRCAP *cap, RRFrame *frame, GError **error) {

      icalcap_msg_handler     func;
      icalcap_message        *msg;
      int               ret;

      g_return_val_if_fail(cap, FALSE);
      g_return_val_if_fail(cap->cfg, FALSE);
      g_return_val_if_fail(cap->cfg->msg_handler_data, FALSE);

      func = (icalcap_msg_handler)cap->cfg->msg_handler_data;

      msg = _icalcap_message_new_from_frame_rr(cap->hl, ICALCAP_MESSAGE_CMD, frame);
      if (msg == NULL) {
            /* FIXME */
            g_message("error");
            return FALSE;
      }

      ret = func(msg);
      icalcap_message_free(msg);

      return ret;
}

Generated by  Doxygen 1.6.0   Back to index