summaryrefslogtreecommitdiff
path: root/src/libicalcap
diff options
context:
space:
mode:
Diffstat (limited to 'src/libicalcap')
-rw-r--r--src/libicalcap/CMakeLists.txt101
-rw-r--r--src/libicalcap/Makefile.am73
-rw-r--r--src/libicalcap/client.c193
-rw-r--r--src/libicalcap/icalcap.c44
-rw-r--r--src/libicalcap/icalcap.h47
-rw-r--r--src/libicalcap/icalcap_impl.h34
-rw-r--r--src/libicalcap/icalcap_message.c225
-rw-r--r--src/libicalcap/icalcap_message_impl.h33
-rw-r--r--src/libicalcap/icalcap_rr.c550
-rw-r--r--src/libicalcap/icalcap_server.c52
-rw-r--r--src/libicalcap/icalcap_server.h19
-rw-r--r--src/libicalcap/icalcap_server_impl.h31
-rw-r--r--src/libicalcap/icalcap_session.c62
-rw-r--r--src/libicalcap/icalcap_session.h15
-rw-r--r--src/libicalcap/icalcap_session_impl.h36
-rw-r--r--src/libicalcap/icalcap_utils.c145
16 files changed, 1660 insertions, 0 deletions
diff --git a/src/libicalcap/CMakeLists.txt b/src/libicalcap/CMakeLists.txt
new file mode 100644
index 00000000..f7fc0f5b
--- /dev/null
+++ b/src/libicalcap/CMakeLists.txt
@@ -0,0 +1,101 @@
+include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/libical )
+
+
+########### next target ###############
+
+SET(client_SRCS client.c)
+
+add_executable(client ${client_SRCS})
+
+target_link_libraries(client)
+
+
+########### install files ###############
+
+install(FILES
+ icalcap.h
+ icalcap_impl.h
+ icalcap_message_impl.h
+ icalcap_server.h
+ icalcap_server_impl.h
+ icalcap_session.h
+ icalcap_session_impl.h
+ DESTINATION ${INCLUDE_INSTALL_DIR}/libicalcap)
+
+
+
+#original Makefile.am contents follow:
+
+##======================================================================
+## FILE: Makefile.am
+## CREATOR: acampi
+##
+## $Id: Makefile.am,v 1.4 2008-01-02 20:07:33 dothebart Exp $
+##
+##
+## (C) COPYRIGHT 2003, Andrea Campi, mailto:a.campi@inet.it
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of either:
+##
+## The LGPL as published by the Free Software Foundation, version
+## 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+##
+## Or:
+##
+## The Mozilla Public License Version 1.0. You may obtain a copy of
+## the License at http://www.mozilla.org/MPL/
+##
+##
+##
+##======================================================================
+#
+#
+#lib_LTLIBRARIES = libicalcap-evolution.la
+#
+#INCLUDES = \
+# -I$(top_builddir) \
+# -I$(top_srcdir)/src \
+# -I$(top_builddir)/src \
+# -I$(top_srcdir)/src/libical \
+# -I$(top_builddir)/libical \
+# -I$(srcdir) \
+# -DWITH_RR $(RRCAP_CFLAGS)
+#
+#libicalcap_evolution_la_LDFLAGS = $(RRCAP_LIBS) -version-info 48:0:48
+#
+#
+#libicalcap_evolution_la_SOURCES = \
+# icalcap.c \
+# icalcap.h \
+# icalcap_impl.h \
+# icalcap_message.c \
+# icalcap_message_impl.h \
+# icalcap_rr.c \
+# icalcap_server.c \
+# icalcap_server.h \
+# icalcap_server_impl.h \
+# icalcap_session.c \
+# icalcap_session.h \
+# icalcap_session_impl.h \
+# icalcap_utils.c
+#
+#libicalcap_evolutionincludedir = $(includedir)
+#
+#libicalcap_evolutioninclude_HEADERS = \
+# icalcap.h \
+# icalcap_impl.h \
+# icalcap_message_impl.h \
+# icalcap_server.h \
+# icalcap_server_impl.h \
+# icalcap_session.h \
+# icalcap_session_impl.h
+#
+#
+#noinst_PROGRAMS = client
+#
+#LDADD = ../libicalss/libicalss-evolution.la ../libicalvcal/libicalvcal-evolution.la ../libical/libical-evolution.la libicalcap-evolution.la $(RRCAP_LIBS)
+#
+#
+#client_SOURCES = client.c
+#
diff --git a/src/libicalcap/Makefile.am b/src/libicalcap/Makefile.am
new file mode 100644
index 00000000..022e58ad
--- /dev/null
+++ b/src/libicalcap/Makefile.am
@@ -0,0 +1,73 @@
+#======================================================================
+# FILE: Makefile.am
+# CREATOR: acampi
+#
+# $Id: Makefile.am,v 1.4 2008-01-02 20:07:33 dothebart Exp $
+#
+#
+# (C) COPYRIGHT 2003, Andrea Campi, mailto:a.campi@inet.it
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of either:
+#
+# The LGPL as published by the Free Software Foundation, version
+# 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+#
+# Or:
+#
+# The Mozilla Public License Version 1.0. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+#
+#
+#======================================================================
+
+
+lib_LTLIBRARIES = libicalcap-evolution.la
+
+INCLUDES = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src \
+ -I$(top_srcdir)/src/libical \
+ -I$(top_builddir)/libical \
+ -I$(srcdir) \
+ -DWITH_RR $(RRCAP_CFLAGS)
+
+libicalcap_evolution_la_LDFLAGS = $(RRCAP_LIBS) -version-info 48:0:48
+
+
+libicalcap_evolution_la_SOURCES = \
+ icalcap.c \
+ icalcap.h \
+ icalcap_impl.h \
+ icalcap_message.c \
+ icalcap_message_impl.h \
+ icalcap_rr.c \
+ icalcap_server.c \
+ icalcap_server.h \
+ icalcap_server_impl.h \
+ icalcap_session.c \
+ icalcap_session.h \
+ icalcap_session_impl.h \
+ icalcap_utils.c
+
+libicalcap_evolutionincludedir = $(includedir)
+
+libicalcap_evolutioninclude_HEADERS = \
+ icalcap.h \
+ icalcap_impl.h \
+ icalcap_message_impl.h \
+ icalcap_server.h \
+ icalcap_server_impl.h \
+ icalcap_session.h \
+ icalcap_session_impl.h
+
+
+noinst_PROGRAMS = client
+
+LDADD = ../libicalss/libicalss-evolution.la ../libicalvcal/libicalvcal-evolution.la ../libical/libical-evolution.la libicalcap-evolution.la $(RRCAP_LIBS)
+
+
+client_SOURCES = client.c
+
diff --git a/src/libicalcap/client.c b/src/libicalcap/client.c
new file mode 100644
index 00000000..8330ecd3
--- /dev/null
+++ b/src/libicalcap/client.c
@@ -0,0 +1,193 @@
+/*-
+ * $Id: client.c,v 1.3 2008-01-02 20:07:33 dothebart Exp $
+ *
+ * See the file LICENSE for redistribution information.
+ * If you have not received a copy of the license, please contact CodeFactory
+ * by email at info@codefactory.se, or on the web at http://www.codefactory.se/
+ * You may also write to: CodeFactory AB, SE-903 47, Umeå, Sweden.
+ *
+ * Copyright (c) 2002 Jonas Borgström <jonas@codefactory.se>
+ * Copyright (c) 2002 Daniel Lundin <daniel@codefactory.se>
+ * Copyright (c) 2002 CodeFactory AB. All rights reserved.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <librr/rr.h>
+
+#include "icalcap.h"
+#include "icalcap_session.h"
+
+#define CLIENT_CAPABILITY \
+"Content-Type: text/html\n\n\
+BEGIN:VCALENDAR\n\
+VERSION:2.0\n\
+PRODIR:rrcap-client\n\
+CMD:REPLY\n\
+BEGIN:VREPLY\n\
+CAP-VERSION:1.0\n\
+PRODID:rrcap-client\n\
+QUERY-LEVEL:CAL-QL-NONE\n\
+CAR-LEVEL:CAR-FULL-NONE\n\
+DATE-MAX:99991231T235959Z\n\
+DATE-MIN:00000101T000000Z\n\
+MAX-COMPONENT-SIZE:0\n\
+COMPONENTS:VCALENDAR,VTODO,VJOURNAL,VEVENT,VCAR,\n\
+ VALARM,VFREEBUSY,VTIMEZONE,STANDARD,DAYLIGHT,VREPLY\n\
+ITIP-VERSION:2447\n\
+RECUR-ACCEPTED:TRUE\n\
+RECUR-EXPAND:TRUE\n\
+RECUR-LIMIT:0\n\
+STORES-EXPANDED:FALSE\n\
+END:VREPLY\n\
+END:VCALENDAR\n"
+
+
+icalcomponent *
+icalcap_send_cmd(const icalcap *cap, const gchar *cmd, const gchar *id, int timeout) {
+
+ icalcap_message*capmsg;
+ icalcomponent *comp, *ret = NULL;
+ icalproperty *prop;
+
+ prop = icalproperty_vanew_cmd(
+ icalproperty_string_to_enum(cmd),
+ icalparameter_new_id(id),
+ 0);
+
+ if (timeout > 0) {
+ char buf[16];
+
+ snprintf(buf, 16, "%d", timeout);
+ icalproperty_add_parameter(prop,
+ icalparameter_new_latency(buf));
+
+ icalproperty_add_parameter(prop,
+ icalparameter_new_actionparam(ICAL_ACTIONPARAM_ABORT));
+ }
+
+ comp = icalcomponent_vanew(
+ ICAL_VCALENDAR_COMPONENT,
+ icalproperty_new_version("2.0"),
+ icalproperty_new_prodid("-//I.Net spa//NONSGML//EN"),
+ prop,
+ 0);
+
+ capmsg = icalcap_message_new(cap, comp);
+ ret = icalcap_message_sync_send(capmsg, timeout);
+ icalcap_message_free(capmsg);
+ icalcomponent_free(comp);
+
+ return ret;
+}
+
+icalcomponent *
+icalcap_new_reply_component(const char *id, const icalcomponent *comp) {
+
+ if (comp == NULL)
+ return NULL;
+
+ return icalcomponent_vanew(
+ ICAL_VCALENDAR_COMPONENT,
+ icalproperty_new_version("2.0"),
+ icalproperty_new_prodid("-//I.Net spa//NONSGML//EN"),
+ icalproperty_vanew_cmd(
+ ICAL_CMD_REPLY,
+/* icalparameter_new_id(id), */
+ 0),
+ comp,
+ 0);
+}
+
+
+static int
+msg_handler(const icalcap_message *capmsg) {
+
+ icalcomponent *reply;
+ char *temp;
+
+ temp = icalcomponent_as_ical_string_r(capmsg->comp);
+ g_message("Got: %s", temp);
+ free(temp);
+
+ /* FIXME Check it's a GET-CAPABILITY */
+
+ reply = icalcap_new_reply_component(NULL, capmsg->comp);
+ if (reply == NULL) {
+ return FALSE;
+ }
+
+ icalcomponent_add_property(reply,
+ icalproperty_new_prodid("client"));
+
+ icalcomponent_free(reply);
+ return TRUE;
+}
+
+int
+main (gint argc, gchar **argv)
+{
+ icalcap_session*conn;
+ icalcap *cap;
+ icalcomponent *comp;
+
+ int i, n;
+ int verbose = 0;
+
+ if ((conn = icalcap_session_new()) == NULL) {
+ fprintf(stderr, "Init failed\n");
+ exit(0);
+ }
+
+ if (!icalcap_session_connect(conn, "gundam.inet.it", 0)) {
+ fprintf(stderr, "Connect failed\n");
+ exit(0);
+ }
+
+ if (!icalcap_session_login(conn, "user@example.com", "user@example.com", "password")) {
+ fprintf(stderr, "Login failed\n");
+ exit(0);
+ }
+
+ if ((cap = icalcap_session_start(conn, msg_handler)) == NULL) {
+ fprintf(stderr, "Start failed\n");
+ exit(0);
+ }
+
+ if (argc > 1 && *argv[1] == '1')
+ n = 100;
+ else
+ n = 1;
+
+ for (i=0; i<n; i++) {
+ g_print("Test 1: %d\n", i);
+
+ if ((comp = icalcap_send_cmd(cap, "GET-CAPABILITY", "zero",15))
+ == NULL) {
+ fprintf(stderr, "Send failed\n");
+ exit(0);
+ }
+
+ if (verbose) {
+ char *obj = icalcomponent_as_ical_string_r(comp);
+ g_print("Got %s\n", obj);
+ g_free(obj);
+ }
+
+ if (comp)
+ icalcomponent_free(comp);
+ }
+
+ if (!icalcap_stop(cap)) {
+ fprintf(stderr, "Stop failed\n");
+ exit(0);
+ }
+
+ if (!icalcap_session_disconnect(conn)) {
+ fprintf(stderr, "Disconnect failed\n");
+ exit(0);
+ }
+
+ return 0;
+}
diff --git a/src/libicalcap/icalcap.c b/src/libicalcap/icalcap.c
new file mode 100644
index 00000000..8d404f0a
--- /dev/null
+++ b/src/libicalcap/icalcap.c
@@ -0,0 +1,44 @@
+#include "config.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "icalcap.h"
+#include "icalcap_impl.h"
+#include "icalcap_session_impl.h" /* FIXME */
+
+
+void
+icalcap_free(icalcap *cap) {
+
+#ifdef WITH_RR
+ icalcap_free_rr(cap);
+#endif
+}
+
+int
+icalcap_stop(icalcap *cap) {
+
+#ifdef WITH_RR
+ return icalcap_stop_rr(cap);
+#else
+ return 0;
+#endif
+}
+
+const char *
+icalcap_get_username(const icalcap *cap) {
+
+#ifdef WITH_RR
+ if (cap == NULL || cap->username == NULL)
+ return NULL;
+
+ return cap->username;
+#else
+ return NULL;
+#endif
+}
diff --git a/src/libicalcap/icalcap.h b/src/libicalcap/icalcap.h
new file mode 100644
index 00000000..de7b471a
--- /dev/null
+++ b/src/libicalcap/icalcap.h
@@ -0,0 +1,47 @@
+#ifndef __ICALCAP_H__
+#define __ICALCAP_H__
+
+#include <libical/ical.h>
+
+/*
+ * Opaque objects
+ */
+typedef struct _icalcap icalcap;
+typedef struct _icalerror icalerror;
+typedef struct _icalcap_message icalcap_message;
+
+/*
+ * Callback
+ */
+typedef int (*icalcap_msg_handler)(const icalcap_message *msg);
+
+/*
+ * icalcap member functions
+ */
+void icalcap_free(icalcap *cap);
+int icalcap_stop(icalcap *cap);
+const char *icalcap_get_username(const icalcap *cap);
+
+/*
+ * icalcap_message member functions
+ */
+
+struct _icalcap_message {
+ icalcap *cap;
+ int type;
+
+ icalcomponent *comp;
+};
+
+icalcap_message*icalcap_message_new(const icalcap *cap, const icalcomponent *comp);
+icalcap_message*icalcap_message_new_reply(const icalcap_message *capmsg, const icalcomponent *comp);
+void icalcap_message_free(icalcap_message *capmsg);
+
+int icalcap_message_reply_error(const icalcap_message *orig, enum icalrequeststatus status,
+ const char *msg, const char *debug);
+int icalcap_message_reply_component(const icalcap_message *orig, icalcomponent *comp);
+
+int icalcap_message_send(icalcap_message *capmsg);
+icalcomponent *icalcap_message_sync_send(icalcap_message *capmsg, int timeout);
+
+#endif
diff --git a/src/libicalcap/icalcap_impl.h b/src/libicalcap/icalcap_impl.h
new file mode 100644
index 00000000..19f8c1db
--- /dev/null
+++ b/src/libicalcap/icalcap_impl.h
@@ -0,0 +1,34 @@
+#ifndef __ICALCAP_IMPL_H__
+#define __ICALCAP_IMPL_H__
+
+#include "icalcap_session.h"
+
+#ifdef WITH_RR
+
+#include <librr/rr.h>
+#include <librrsasl/rr-sasl.h>
+#include <librrtls/rr-tls.h>
+#include <librrcap/rr-cap.h>
+
+struct _icalcap {
+ RRCAP *chan;
+ const char *username,
+ *authname;
+};
+
+struct _icalerror {
+ GError *err;
+};
+
+
+void icalcap_free_rr(icalcap *cap);
+
+int icalcap_stop_rr(icalcap *cap);
+
+icalcomponent *icalcap_send_component_rr(const icalcap *cap, const icalcomponent *comp, int timeout);
+
+#else
+#error "No implementation of icalcap found!"
+#endif
+
+#endif
diff --git a/src/libicalcap/icalcap_message.c b/src/libicalcap/icalcap_message.c
new file mode 100644
index 00000000..32abbf0a
--- /dev/null
+++ b/src/libicalcap/icalcap_message.c
@@ -0,0 +1,225 @@
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "ical.h"
+#include "icalcap.h"
+#include "icalcap_message_impl.h"
+
+
+/**
+ * constructor
+ *
+ * Create a new icalcap_message from a component. This represents a command.
+ */
+icalcap_message *
+icalcap_message_new(const icalcap *cap, const icalcomponent *comp) {
+
+ icalcap_message *ret = NULL;
+
+#ifdef WITH_RR
+ ret = icalcap_message_new_rr(cap, comp);
+#else
+ ret = NULL;
+#endif
+ return ret;
+}
+
+/**
+ * constructor
+ *
+ * Create a new icalcap_message from a component. This represents a reply.
+ */
+icalcap_message *
+icalcap_message_new_reply(const icalcap_message *capmsg, const icalcomponent *comp) {
+
+#ifdef WITH_RR
+ return icalcap_message_new_reply_rr(capmsg, comp);
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * destructor
+ *
+ * Delete icalcap_message
+ */
+void
+icalcap_message_free(icalcap_message *capmsg) {
+
+#ifdef WITH_RR
+ icalcap_message_free_rr(capmsg);
+#else
+#endif
+}
+
+/**
+ * Send the icalcap_message and wait for an answer.
+ * The icalcap_message will be invalid after this call, and only valid call will be
+ * icalcap_message_free().
+ */
+icalcomponent *
+icalcap_message_sync_send(icalcap_message *capmsg, int timeout) {
+
+ g_return_val_if_fail(capmsg, NULL);
+
+#ifdef WITH_RR
+ return icalcap_message_sync_send_rr(capmsg, timeout);
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * Send the icalcap_message.
+ * The icalcap_message will be invalid after this call, and only valid call will be
+ * icalcap_message_free().
+ */
+int
+icalcap_message_send(icalcap_message *capmsg) {
+
+ int rc = FALSE;
+ char *str;
+
+ g_return_val_if_fail(capmsg, FALSE);
+
+#ifdef WITH_RR
+ rc = icalcap_message_send_reply_rr(capmsg);
+#else
+ rc = FALSE;
+#endif
+
+ return rc;
+}
+
+/**
+ * Convenience method to send a component in reply to the given icalcap_message.
+ * The icalcomponent is not modified in any way.
+ *
+ * FIXME should be const icalcomponent *
+ */
+int
+icalcap_message_reply_component(const icalcap_message *orig, icalcomponent *in) {
+
+ icalcap_message*reply;
+ int rc;
+
+ reply = icalcap_message_new_reply(orig, in);
+ if (reply == NULL)
+ return FALSE;
+
+ rc = icalcap_message_send(reply);
+ icalcap_message_free(reply);
+
+ return rc;
+}
+
+/* Only used by icalcap_message_reply_error */
+static icalcomponent *new_reply_component(const icalcap_message *capmsg, const icalcomponent *comp);
+
+/**
+ * Convenience method to send an error in reply to the given icalcap_message.
+ */
+int
+icalcap_message_reply_error(const icalcap_message *orig, enum icalrequeststatus status,
+ const char *msg, const char *debug) {
+
+ struct icalreqstattype stat;
+ icalcomponent *comp, *vreply;
+ int rc;
+
+ /* Prepare the REQUEST-STATUS */
+ stat = icalreqstattype_from_string(
+ icalenum_reqstat_code(status));
+
+ if (msg != NULL) {
+ /* FIXME we used to do
+ stat.desc = strdup(msg);
+ but this created a memory leak. Maybe the destructor for reqstat? */
+ stat.desc = msg;
+ } else {
+ stat.desc = icalenum_reqstat_desc(status);
+ }
+
+ if (debug != NULL)
+ stat.debug = debug;
+
+ /* Prepare a VREPLY component */
+ vreply = icalcomponent_vanew(
+ ICAL_VREPLY_COMPONENT,
+ icalproperty_new_requeststatus(stat),
+ 0);
+ if (vreply == NULL) {
+ /* FIXME */
+ return FALSE;
+ }
+
+ comp = new_reply_component(orig, vreply);
+
+ rc = icalcap_message_reply_component(orig, comp);
+
+ icalcomponent_free(comp);
+ icalcomponent_free(vreply);
+
+ return rc;
+}
+
+
+/* internal use */
+
+/* only used by new_reply_component */
+static const char *
+get_id(icalcomponent *comp) {
+
+ icalproperty *prop;
+ icalparameter *param;
+
+ prop = icalcomponent_get_first_property(comp, ICAL_CMD_PROPERTY);
+ if (prop == NULL)
+ return NULL;
+
+ param = icalproperty_get_first_parameter(prop, ICAL_ID_PARAMETER);
+ if (param == NULL)
+ return NULL;
+
+ return icalparameter_get_id(param);
+}
+
+/* only used by icalcap_message_reply_error */
+static icalcomponent *
+new_reply_component(const icalcap_message *capmsg, const icalcomponent *comp) {
+
+ icalcomponent *clone, *cal, *root;
+ icalproperty *cmd;
+ const char *id;
+
+ cmd = icalproperty_new_cmd(ICAL_CMD_REPLY);
+
+ if (capmsg->comp != NULL) {
+ id = get_id(capmsg->comp);
+
+ if (id != NULL)
+ icalproperty_add_parameter(cmd, icalparameter_new_id(id));
+ }
+
+ cal = icalcomponent_vanew(
+ ICAL_VCALENDAR_COMPONENT,
+ icalproperty_new_version("2.0"),
+ icalproperty_new_prodid("-//I.Net spa//NONSGML//EN"),
+ cmd,
+ 0);
+
+ if (comp != NULL) {
+ clone = icalcomponent_new_clone(comp);
+ icalcomponent_add_component(cal, clone);
+ }
+
+ root = icalcomponent_vanew(
+ ICAL_XROOT_COMPONENT,
+ cal,
+ 0);
+ return root;
+}
diff --git a/src/libicalcap/icalcap_message_impl.h b/src/libicalcap/icalcap_message_impl.h
new file mode 100644
index 00000000..fa44f4dc
--- /dev/null
+++ b/src/libicalcap/icalcap_message_impl.h
@@ -0,0 +1,33 @@
+#ifndef __ICALCAP_MESSAGE_IMPL_H__
+#define __ICALCAP_MESSAGE_IMPL_H__
+
+#ifdef WITH_RR
+
+#include <libical/ical.h>
+#include <librr/rr.h>
+
+#define ICALCAP_MESSAGE_CMD 1
+#define ICALCAP_MESSAGE_REPLY 1
+
+struct _icalcap_message_rr {
+ const icalcap *cap;
+ int type;
+
+ icalcomponent *comp;
+
+ RRFrame *frame;
+ RRMessage *msg;
+};
+
+icalcap_message*icalcap_message_new_rr(const icalcap *cap, const icalcomponent *comp);
+icalcap_message*icalcap_message_new_reply_rr(const icalcap_message *capmsg, const icalcomponent *comp);
+void icalcap_message_free_rr(icalcap_message *capmsg);
+
+int icalcap_message_send_reply_rr(icalcap_message *capmsg);
+icalcomponent *icalcap_message_sync_send_rr(icalcap_message *capmsg, int timeout);
+
+#else
+#error "No implementation of icalcap found!"
+#endif
+
+#endif
diff --git a/src/libicalcap/icalcap_rr.c b/src/libicalcap/icalcap_rr.c
new file mode 100644
index 00000000..6c963434
--- /dev/null
+++ b/src/libicalcap/icalcap_rr.c
@@ -0,0 +1,550 @@
+#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;
+}
diff --git a/src/libicalcap/icalcap_server.c b/src/libicalcap/icalcap_server.c
new file mode 100644
index 00000000..77b84845
--- /dev/null
+++ b/src/libicalcap/icalcap_server.c
@@ -0,0 +1,52 @@
+#include "config.h"
+
+#include "icalcap.h"
+#include "icalcap_server.h"
+#include "icalcap_server_impl.h"
+
+
+icalcap_server *
+icalcap_server_new(icalcap_auth_handler auth_cb, icalcap_chanup_handler chanup_cb,
+ icalcap_msg_handler msg_cb) {
+
+#ifdef WITH_RR
+ return icalcap_server_new_rr(auth_cb, chanup_cb, msg_cb);
+#else
+ return NULL;
+#endif
+}
+
+int
+icalcap_server_listen(icalcap_server *cap, const char *hostname, const int _port) {
+
+ int port = _port;
+
+ if (port <= 0)
+ port = 1026;
+
+#ifdef WITH_RR
+ return icalcap_server_listen_rr(cap, hostname, port);
+#else
+ return 0;
+#endif
+}
+
+int
+icalcap_server_run(const icalcap_server *cap) {
+
+#ifdef WITH_RR
+ return icalcap_server_run_rr(cap);
+#else
+ return 0;
+#endif
+}
+
+int
+icalcap_server_shutdown(icalcap_server *cap) {
+
+#ifdef WITH_RR
+ return icalcap_server_shutdown_rr(cap);
+#else
+ return 0;
+#endif
+}
diff --git a/src/libicalcap/icalcap_server.h b/src/libicalcap/icalcap_server.h
new file mode 100644
index 00000000..53c73d3b
--- /dev/null
+++ b/src/libicalcap/icalcap_server.h
@@ -0,0 +1,19 @@
+#ifndef __ICALCAP_SERVER_H__
+#define __ICALCAP_SERVER_H__
+
+#include "icalcap.h"
+
+typedef struct _icalcap_server icalcap_server;
+
+typedef int (*icalcap_auth_handler)(const icalcap *cap, const char *piggyback);
+typedef void (*icalcap_chanup_handler)(const icalcap *cap);
+
+icalcap_server*icalcap_server_new(icalcap_auth_handler auth_cb,
+ icalcap_chanup_handler chanup_cb,
+ icalcap_msg_handler msg_cb);
+
+int icalcap_server_listen(icalcap_server *cap, const char *hostname, const int port);
+int icalcap_server_run(const icalcap_server *cap);
+int icalcap_server_shutdown(icalcap_server *cap);
+
+#endif
diff --git a/src/libicalcap/icalcap_server_impl.h b/src/libicalcap/icalcap_server_impl.h
new file mode 100644
index 00000000..c5d527d2
--- /dev/null
+++ b/src/libicalcap/icalcap_server_impl.h
@@ -0,0 +1,31 @@
+#ifndef __ICALCAP_SERVER_IMPL_H__
+#define __ICALCAP_SERVER_IMPL_H__
+
+#ifdef WITH_RR
+
+#include <librr/rr.h>
+#include <librrsasl/rr-sasl.h>
+#include <librrtls/rr-tls.h>
+#include <librrcap/rr-cap.h>
+
+struct _icalcap_server {
+ RRProfileRegistry *profreg;
+ RRListener *listener;
+ RRCAPConfig *cfg;
+ icalcap_msg_handler handler;
+};
+
+icalcap_server *icalcap_server_new_rr(icalcap_auth_handler auth_cb,
+ icalcap_chanup_handler chanup_cb,
+ icalcap_msg_handler msg_cb);
+int icalcap_server_listen_rr(icalcap_server *cap,
+ const char *hostname,
+ const int port);
+int icalcap_server_run_rr(const icalcap_server *cap);
+int icalcap_server_shutdown_rr(icalcap_server *cap);
+
+#else
+#error "No implementation of icalcap found!"
+#endif
+
+#endif
diff --git a/src/libicalcap/icalcap_session.c b/src/libicalcap/icalcap_session.c
new file mode 100644
index 00000000..2f8fb2a7
--- /dev/null
+++ b/src/libicalcap/icalcap_session.c
@@ -0,0 +1,62 @@
+#include "config.h"
+
+#include "icalcap.h"
+#include "icalcap_session.h"
+#include "icalcap_session_impl.h"
+
+
+icalcap_session *
+icalcap_session_new(void) {
+
+#ifdef WITH_RR
+ return icalcap_session_new_rr();
+#else
+ return NULL;
+#endif
+}
+
+int
+icalcap_session_connect(icalcap_session *sess, const char *hostname, const int _port) {
+
+ int port = _port;
+
+ if (port <= 0)
+ port = 1026;
+
+#ifdef WITH_RR
+ return icalcap_session_connect_rr(sess, hostname, port);
+#else
+ return 0;
+#endif
+}
+
+int
+icalcap_session_login(icalcap_session *sess, const char *username, const char *authname,
+ const char *password) {
+
+#ifdef WITH_RR
+ return icalcap_session_login_rr(sess, username, authname, password);
+#else
+ return 0;
+#endif
+}
+
+icalcap *
+icalcap_session_start(const icalcap_session *sess, icalcap_msg_handler handler) {
+
+#ifdef WITH_RR
+ return icalcap_session_start_rr(sess, handler);
+#else
+ return 0;
+#endif
+}
+
+int
+icalcap_session_disconnect(icalcap_session *sess) {
+
+#ifdef WITH_RR
+ return icalcap_session_disconnect_rr(sess);
+#else
+ return 0;
+#endif
+}
diff --git a/src/libicalcap/icalcap_session.h b/src/libicalcap/icalcap_session.h
new file mode 100644
index 00000000..c12d434b
--- /dev/null
+++ b/src/libicalcap/icalcap_session.h
@@ -0,0 +1,15 @@
+#ifndef __ICALCAP_SESSION_H__
+#define __ICALCAP_SESSION_H__
+
+#include "icalcap.h"
+
+typedef struct _icalcap_session icalcap_session;
+
+icalcap_session*icalcap_session_new(void);
+int icalcap_session_connect(icalcap_session *cap, const char *hostname, const int port);
+int icalcap_session_login(icalcap_session *cap, const char *username, const char *authname,
+ const char *password);
+icalcap*icalcap_session_start(const icalcap_session *cap, icalcap_msg_handler handler);
+int icalcap_session_disconnect(icalcap_session *cap);
+
+#endif
diff --git a/src/libicalcap/icalcap_session_impl.h b/src/libicalcap/icalcap_session_impl.h
new file mode 100644
index 00000000..26bb7d10
--- /dev/null
+++ b/src/libicalcap/icalcap_session_impl.h
@@ -0,0 +1,36 @@
+#ifndef __ICALCAP_SESSION_IMPL_H__
+#define __ICALCAP_SESSION_IMPL_H__
+
+#ifdef WITH_RR
+
+#include <librr/rr.h>
+#include <librrsasl/rr-sasl.h>
+#include <librrtls/rr-tls.h>
+#include <librrcap/rr-cap.h>
+
+struct _icalcap_session {
+ RRProfileRegistry *profreg;
+ RRConnection *connection;
+ RRCAPConfig *cfg;
+ icalcap_msg_handler handler;
+
+ char *username;
+};
+
+icalcap_session*icalcap_session_new_rr(void);
+int icalcap_session_connect_rr(icalcap_session *cap,
+ const char *hostname,
+ const int port);
+int icalcap_session_login_rr(icalcap_session *cap,
+ const char *username,
+ const char *authname,
+ const char *password);
+icalcap *icalcap_session_start_rr(const icalcap_session *cap,
+ icalcap_msg_handler handler);
+int icalcap_session_disconnect_rr(icalcap_session *cap);
+
+#else
+#error "No implementation of icalcap found!"
+#endif
+
+#endif
diff --git a/src/libicalcap/icalcap_utils.c b/src/libicalcap/icalcap_utils.c
new file mode 100644
index 00000000..7308f8fb
--- /dev/null
+++ b/src/libicalcap/icalcap_utils.c
@@ -0,0 +1,145 @@
+/*-
+ * $Id: icalcap_utils.c,v 1.3 2008-01-02 20:07:38 dothebart Exp $
+ *
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002 Andrea Campi <a.campi@inet.it>
+ */
+
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "icalcap.h"
+
+#define CONTENT_TYPE "Content-Type: text/calendar"
+
+
+icalcomponent *
+icalcap_component_new_from_string(const char *data) {
+
+ icalcomponent *ret = NULL;
+ char *mtype;
+
+ /* FIXME split the check */
+ if (strncmp(data, CONTENT_TYPE, strlen(CONTENT_TYPE))) {
+ return NULL;
+ }
+
+ mtype = (char *)data+strlen(CONTENT_TYPE);
+
+ ret = icalcomponent_new_from_string(mtype);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+#ifdef DEBUG
+ g_message("icalcap_component_new_from_string icalcomponent_new_from_string = %p", ret);
+#endif
+
+ /* FIXME
+ * Validate here: should check at least the version
+ */
+ if (icalcomponent_isa(ret) != ICAL_VCALENDAR_COMPONENT &&
+ icalcomponent_isa(ret) != ICAL_XROOT_COMPONENT) {
+ icalcomponent_free(ret);
+
+ return NULL;
+ }
+
+ return ret;
+}
+
+#if 0
+RRCAPCmdArgs *
+msg_parse(RRCAP *cap, icalcomponent *comp) {
+
+ icalproperty *prop;
+ icalparameter *param;
+ icalvalue *value;
+ RRCAPCmdArgs *ret = g_new0(RRCAPCmdArgs, 1);
+ char *str;
+
+ ret->comp = comp;
+
+ /* Find the command */
+ if ((prop = icalcomponent_get_first_property(comp, ICAL_CMD_PROPERTY)) == NULL) {
+ rr_cap_send_error(cap, NULL, ICAL_9_0_UNRECOGNIZED_COMMAND,
+ "No CMD sent", NULL);
+ goto FAILED;
+ }
+ if ((value = icalproperty_get_value(prop)) == NULL) {
+ str = icalproperty_as_ical_string_r(prop);
+ rr_cap_send_error(cap, NULL, ICAL_9_0_UNRECOGNIZED_COMMAND,
+ "CMD has no value", str);
+ free(str);
+ goto FAILED;
+ }
+ ret->cmd = icalvalue_get_cmd(value);
+
+ /* Look for params */
+
+ /* ID */
+ if ((param = icalproperty_get_first_parameter(prop,
+ ICAL_ID_PARAMETER)) != NULL) {
+ if ((ret->id = icalparameter_get_id(param)) == NULL) {
+ str = icalproperty_as_ical_string_r(prop);
+ rr_cap_send_error(cap, NULL,
+ ICAL_9_0_UNRECOGNIZED_COMMAND,
+ "ID param is garbled",
+ str);
+ free(str);
+ goto FAILED;
+ }
+ }
+
+ /* LATENCY */
+ if ((param = icalproperty_get_first_parameter(prop,
+ ICAL_LATENCY_PARAMETER)) != NULL) {
+ const char *tmp;
+ if ((tmp = icalparameter_get_latency(param)) == NULL) {
+ str = icalproperty_as_ical_string_r(prop);
+ rr_cap_send_error(cap, NULL,
+ ICAL_9_0_UNRECOGNIZED_COMMAND,
+ "LATENCY is garbled",
+ str);
+ free(str);
+ goto FAILED;
+ }
+
+ ret->latency = atoi(tmp);
+ }
+
+ /* ACTION */
+ if ((param = icalproperty_get_first_parameter(prop,
+ ICAL_ACTIONPARAM_PARAMETER)) != NULL) {
+ if ((ret->action = icalparameter_get_actionparam(param))
+ == NULL) {
+ str = icalproperty_as_ical_string_r(prop);
+ rr_cap_send_error(cap, NULL,
+ ICAL_9_0_UNRECOGNIZED_COMMAND,
+ "ACTION is garbled",
+ str);
+ free(str);
+ goto FAILED;
+ }
+ }
+
+ if ((ret->latency >= 0) ^ (ret->action != ICAL_ACTIONPARAM_NONE)) {
+ str = icalproperty_as_ical_string_r(prop);
+ rr_cap_send_error(cap, NULL, ICAL_9_0_UNRECOGNIZED_COMMAND,
+ "LATENCY and ACTION must be both present",
+ str);
+ free(str);
+ goto FAILED;
+ }
+
+ return ret;
+
+FAILED:
+ g_free(ret);
+ return NULL;
+}
+#endif