aboutsummaryrefslogtreecommitdiffstats
path: root/libical/src/libicalcap/icalcap_rr.c
diff options
context:
space:
mode:
Diffstat (limited to 'libical/src/libicalcap/icalcap_rr.c')
-rw-r--r--libical/src/libicalcap/icalcap_rr.c545
1 files changed, 545 insertions, 0 deletions
diff --git a/libical/src/libicalcap/icalcap_rr.c b/libical/src/libicalcap/icalcap_rr.c
new file mode 100644
index 0000000000..7e464ee155
--- /dev/null
+++ b/libical/src/libicalcap/icalcap_rr.c
@@ -0,0 +1,545 @@
+#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;
+
+ if (comp == NULL) {
+ /* FIXME return an error */
+ return NULL;
+ }
+
+ ret = _icalcap_message_new_from_component_rr(cap, ICALCAP_MESSAGE_CMD, NULL);
+
+ str = g_strdup_printf("%s\n\n%s",
+ "Content-Type: text/calendar",
+ icalcomponent_as_ical_string(comp));
+
+ 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)) {
+ g_string_append(str, icalcomponent_as_ical_string(cc));
+ }
+
+ 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;
+}