From 697761cc337aa77a47140c8df50ed84bc25e23f6 Mon Sep 17 00:00:00 2001 From: Hans Petter Date: Thu, 11 Sep 2003 22:04:44 +0000 Subject: Import new libical from mainline HEAD and make appropriate changes to Evolution. svn path=/trunk/; revision=22538 --- libical/src/libicalcap/Makefile.am | 77 ++++ libical/src/libicalcap/client.c | 187 +++++++++ libical/src/libicalcap/icalcap.c | 44 +++ libical/src/libicalcap/icalcap.h | 47 +++ libical/src/libicalcap/icalcap_impl.h | 34 ++ libical/src/libicalcap/icalcap_message.c | 225 +++++++++++ libical/src/libicalcap/icalcap_message_impl.h | 33 ++ libical/src/libicalcap/icalcap_rr.c | 545 ++++++++++++++++++++++++++ libical/src/libicalcap/icalcap_server.c | 52 +++ libical/src/libicalcap/icalcap_server.h | 19 + libical/src/libicalcap/icalcap_server_impl.h | 31 ++ libical/src/libicalcap/icalcap_session.c | 62 +++ libical/src/libicalcap/icalcap_session.h | 15 + libical/src/libicalcap/icalcap_session_impl.h | 36 ++ libical/src/libicalcap/icalcap_utils.c | 134 +++++++ 15 files changed, 1541 insertions(+) create mode 100644 libical/src/libicalcap/Makefile.am create mode 100644 libical/src/libicalcap/client.c create mode 100644 libical/src/libicalcap/icalcap.c create mode 100644 libical/src/libicalcap/icalcap.h create mode 100644 libical/src/libicalcap/icalcap_impl.h create mode 100644 libical/src/libicalcap/icalcap_message.c create mode 100644 libical/src/libicalcap/icalcap_message_impl.h create mode 100644 libical/src/libicalcap/icalcap_rr.c create mode 100644 libical/src/libicalcap/icalcap_server.c create mode 100644 libical/src/libicalcap/icalcap_server.h create mode 100644 libical/src/libicalcap/icalcap_server_impl.h create mode 100644 libical/src/libicalcap/icalcap_session.c create mode 100644 libical/src/libicalcap/icalcap_session.h create mode 100644 libical/src/libicalcap/icalcap_session_impl.h create mode 100644 libical/src/libicalcap/icalcap_utils.c (limited to 'libical/src/libicalcap') diff --git a/libical/src/libicalcap/Makefile.am b/libical/src/libicalcap/Makefile.am new file mode 100644 index 0000000000..b03a6717e4 --- /dev/null +++ b/libical/src/libicalcap/Makefile.am @@ -0,0 +1,77 @@ +#====================================================================== +# FILE: Makefile.am +# CREATOR: acampi +# +# $Id: Makefile.am,v 1.1 2003/09/11 22:04:28 hansp 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.la + +noinst_LTLIBRARIES = libicalcap-static.la +libicalcap_static_la_SOURCES = $(libicalcap_la_SOURCES) +libicalcap_static_la_LDFLAGS = --all-static + +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_la_LDFLAGS = $(RRCAP_LIBS) -version-info 0:0:0 + + +libicalcap_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 + +libicalcapincludedir = $(includedir) + +libicalcapinclude_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/.libs/libicalss.a ../libicalvcal/.libs/libicalvcal.a $(cxx_libs) ../libical/.libs/libical.a libicalcap.la $(RRCAP_LIBS) + + +client_SOURCES = client.c + diff --git a/libical/src/libicalcap/client.c b/libical/src/libicalcap/client.c new file mode 100644 index 0000000000..399568ac79 --- /dev/null +++ b/libical/src/libicalcap/client.c @@ -0,0 +1,187 @@ +/*- + * $Id$ + * + * 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 + * Copyright (c) 2002 Daniel Lundin + * Copyright (c) 2002 CodeFactory AB. All rights reserved. + */ + +#include +#include + +#include + +#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; + + g_message("Got: %s", icalcomponent_as_ical_string(capmsg->comp)); + + /* 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 +#endif +#ifdef HAVE_STRING_H +#include +#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/libical/src/libicalcap/icalcap.h b/libical/src/libicalcap/icalcap.h new file mode 100644 index 0000000000..5e61bf9c8e --- /dev/null +++ b/libical/src/libicalcap/icalcap.h @@ -0,0 +1,47 @@ +#ifndef __ICALCAP_H__ +#define __ICALCAP_H__ + +#include + +/* + * 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/libical/src/libicalcap/icalcap_impl.h b/libical/src/libicalcap/icalcap_impl.h new file mode 100644 index 0000000000..19f8c1db06 --- /dev/null +++ b/libical/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 +#include +#include +#include + +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/libical/src/libicalcap/icalcap_message.c b/libical/src/libicalcap/icalcap_message.c new file mode 100644 index 0000000000..32abbf0a73 --- /dev/null +++ b/libical/src/libicalcap/icalcap_message.c @@ -0,0 +1,225 @@ +#include "config.h" + +#ifdef HAVE_STRING_H +#include +#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/libical/src/libicalcap/icalcap_message_impl.h b/libical/src/libicalcap/icalcap_message_impl.h new file mode 100644 index 0000000000..ae234d2efa --- /dev/null +++ b/libical/src/libicalcap/icalcap_message_impl.h @@ -0,0 +1,33 @@ +#ifndef __ICALCAP_MESSAGE_IMPL_H__ +#define __ICALCAP_MESSAGE_IMPL_H__ + +#ifdef WITH_RR + +#include +#include + +#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/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 +#endif +#ifdef HAVE_STRING_H +#include +#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; +} diff --git a/libical/src/libicalcap/icalcap_server.c b/libical/src/libicalcap/icalcap_server.c new file mode 100644 index 0000000000..77b8484554 --- /dev/null +++ b/libical/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/libical/src/libicalcap/icalcap_server.h b/libical/src/libicalcap/icalcap_server.h new file mode 100644 index 0000000000..53c73d3bab --- /dev/null +++ b/libical/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/libical/src/libicalcap/icalcap_server_impl.h b/libical/src/libicalcap/icalcap_server_impl.h new file mode 100644 index 0000000000..c5d527d266 --- /dev/null +++ b/libical/src/libicalcap/icalcap_server_impl.h @@ -0,0 +1,31 @@ +#ifndef __ICALCAP_SERVER_IMPL_H__ +#define __ICALCAP_SERVER_IMPL_H__ + +#ifdef WITH_RR + +#include +#include +#include +#include + +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/libical/src/libicalcap/icalcap_session.c b/libical/src/libicalcap/icalcap_session.c new file mode 100644 index 0000000000..2f8fb2a701 --- /dev/null +++ b/libical/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/libical/src/libicalcap/icalcap_session.h b/libical/src/libicalcap/icalcap_session.h new file mode 100644 index 0000000000..c12d434b8c --- /dev/null +++ b/libical/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/libical/src/libicalcap/icalcap_session_impl.h b/libical/src/libicalcap/icalcap_session_impl.h new file mode 100644 index 0000000000..26bb7d107d --- /dev/null +++ b/libical/src/libicalcap/icalcap_session_impl.h @@ -0,0 +1,36 @@ +#ifndef __ICALCAP_SESSION_IMPL_H__ +#define __ICALCAP_SESSION_IMPL_H__ + +#ifdef WITH_RR + +#include +#include +#include +#include + +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/libical/src/libicalcap/icalcap_utils.c b/libical/src/libicalcap/icalcap_utils.c new file mode 100644 index 0000000000..b676f6272d --- /dev/null +++ b/libical/src/libicalcap/icalcap_utils.c @@ -0,0 +1,134 @@ +/*- + * $Id$ + * + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002 Andrea Campi + */ + +#include "config.h" + +#ifdef HAVE_STRING_H +#include +#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); + + 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) { + rr_cap_send_error(cap, NULL, ICAL_9_0_UNRECOGNIZED_COMMAND, + "CMD has no value", icalproperty_as_ical_string(prop)); + 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) { + rr_cap_send_error(cap, NULL, + ICAL_9_0_UNRECOGNIZED_COMMAND, + "ID param is garbled", + icalproperty_as_ical_string(prop)); + goto FAILED; + } + } + + /* LATENCY */ + if ((param = icalproperty_get_first_parameter(prop, + ICAL_LATENCY_PARAMETER)) != NULL) { + const char *tmp; + if ((tmp = icalparameter_get_latency(param)) == NULL) { + rr_cap_send_error(cap, NULL, + ICAL_9_0_UNRECOGNIZED_COMMAND, + "LATENCY is garbled", + icalproperty_as_ical_string(prop)); + 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) { + rr_cap_send_error(cap, NULL, + ICAL_9_0_UNRECOGNIZED_COMMAND, + "ACTION is garbled", + icalproperty_as_ical_string(prop)); + goto FAILED; + } + } + + if ((ret->latency >= 0) ^ (ret->action != ICAL_ACTIONPARAM_NONE)) { + rr_cap_send_error(cap, NULL, ICAL_9_0_UNRECOGNIZED_COMMAND, + "LATENCY and ACTION must be both present", + icalproperty_as_ical_string(prop)); + goto FAILED; + } + + return ret; + +FAILED: + g_free(ret); + return NULL; +} +#endif -- cgit