res_stasis: Add ability to switch applications.
[asterisk/asterisk.git] / res / res_calendar_caldav.c
index b1dd628..425a1e3 100644 (file)
  */
 
 /*** MODULEINFO
+       <depend>res_calendar</depend>
        <depend>neon</depend>
        <depend>ical</depend>
        <depend>libxml2</depend>
-       <support_level>core</support_level>
+       <support_level>extended</support_level>
 ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include <libical/ical.h>
 #include <ne_session.h>
 #include <ne_uri.h>
@@ -41,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <libxml/parser.h>
 
 #include "asterisk/module.h"
+#include "asterisk/channel.h"
 #include "asterisk/calendar.h"
 #include "asterisk/lock.h"
 #include "asterisk/config.h"
@@ -79,6 +79,7 @@ static void caldav_destructor(void *obj)
        if (pvt->session) {
                ne_session_destroy(pvt->session);
        }
+       ne_uri_free(&pvt->uri);
        ast_string_field_free_memory(pvt);
 
        ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
@@ -157,6 +158,7 @@ static struct ast_str *caldav_request(struct caldav_pvt *pvt, const char *method
        ne_add_response_body_reader(req, debug_response_handler, fetch_response_reader, &response);
        ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body));
        ne_add_request_header(req, "Content-type", ast_strlen_zero(content_type) ? "text/xml" : content_type);
+       ne_add_request_header(req, "Depth", "1");
 
        ret = ne_request_dispatch(req);
        ne_request_destroy(req);
@@ -201,7 +203,10 @@ static int caldav_write_event(struct ast_calendar_event *event)
                for (x = 0; x < 8; x++) {
                        val[x] = ast_random();
                }
-               ast_string_field_build(event, uid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
+               ast_string_field_build(event, uid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
+                       (unsigned)val[0], (unsigned)val[1], (unsigned)val[2],
+                       (unsigned)val[3], (unsigned)val[4], (unsigned)val[5],
+                       (unsigned)val[6], (unsigned)val[7]);
        }
 
        calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
@@ -316,7 +321,7 @@ static struct ast_str *caldav_get_events_between(struct caldav_pvt *pvt, time_t
        return response;
 }
 
-static time_t icalfloat_to_timet(icaltimetype time) 
+static time_t icalfloat_to_timet(icaltimetype time)
 {
        struct ast_tm tm = {0,};
        struct timeval tv;
@@ -400,7 +405,7 @@ static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, vo
                        ast_string_field_set(event, uid, event->summary);
                } else {
                        char tmp[100];
-                       snprintf(tmp, sizeof(tmp), "%lu", event->start);
+                       snprintf(tmp, sizeof(tmp), "%ld", event->start);
                        ast_string_field_set(event, uid, tmp);
                }
        }
@@ -474,17 +479,26 @@ struct xmlstate {
        time_t end;
 };
 
-static void handle_start_element(void *data, const xmlChar *fullname, const xmlChar **atts)
+static const xmlChar *caldav_node_localname = BAD_CAST "calendar-data";
+static const xmlChar *caldav_node_nsuri     = BAD_CAST "urn:ietf:params:xml:ns:caldav";
+
+static void handle_start_element(void *data,
+                                                                const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri,
+                                                                int nb_namespaces, const xmlChar **namespaces,
+                                                                int nb_attributes, int nb_defaulted, const xmlChar **attributes)
 {
        struct xmlstate *state = data;
 
-       if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data")) {
-               state->in_caldata = 1;
-               ast_str_reset(state->cdata);
+       if (xmlStrcmp(localname, caldav_node_localname) || xmlStrcmp(uri, caldav_node_nsuri)) {
+               return;
        }
+
+       state->in_caldata = 1;
+       ast_str_reset(state->cdata);
 }
 
-static void handle_end_element(void *data, const xmlChar *name)
+static void handle_end_element(void *data,
+                                                          const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri)
 {
        struct xmlstate *state = data;
        struct icaltimetype start, end;
@@ -492,7 +506,7 @@ static void handle_end_element(void *data, const xmlChar *name)
        icalcomponent *iter;
        icalcomponent *comp;
 
-       if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data")) {
+       if (xmlStrcmp(localname, caldav_node_localname) || xmlStrcmp(uri, caldav_node_nsuri)) {
                return;
        }
 
@@ -555,9 +569,23 @@ static int update_caldav(struct caldav_pvt *pvt)
        state.start = start;
        state.end = end;
 
+       /*
+        * We want SAX2, so you assume that we want to call xmlSAXVersion() here, and
+        * that certainly seems like the right thing to do, but the default SAX
+        * handling functions assume that the 'data' pointer is going to be a
+        * xmlParserCtxtPtr, not a user data pointer, so we have to make sure that we
+        * are only calling the handlers that we control.
+        *
+        * So instead we hack things up a bit, clearing the struct and then assigning
+        * the magic number manually.
+        *
+        * There may be a cleaner way to do this, but frankly the libxml2 docs are
+        * pretty sparse.
+        */
        memset(&saxHandler, 0, sizeof(saxHandler));
-       saxHandler.startElement = handle_start_element;
-       saxHandler.endElement = handle_end_element;
+       saxHandler.initialized = XML_SAX2_MAGIC;
+       saxHandler.startElementNs = handle_start_element;
+       saxHandler.endElementNs = handle_end_element;
        saxHandler.characters = handle_characters;
 
        xmlSAXUserParseMemory(&saxHandler, &state, ast_str_buffer(response), ast_str_strlen(response));
@@ -721,7 +749,9 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk CalDAV Calendar Integration",
-               .load = load_module,
-               .unload = unload_module,
-               .load_pri = AST_MODPRI_DEVSTATE_PLUGIN,
-       );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .load_pri = AST_MODPRI_DEVSTATE_PLUGIN,
+       .requires = "res_calendar",
+);