Fix a variety of memory leaks
[asterisk/asterisk.git] / res / res_calendar_caldav.c
index c7c8f2f..b1dd628 100644 (file)
  */
 
 /*! \file
- * \brief Resource for handling iCalnedar calendars
+ * \brief Resource for handling CalDAV calendars
  */
 
 /*** MODULEINFO
        <depend>neon</depend>
        <depend>ical</depend>
        <depend>libxml2</depend>
+       <support_level>core</support_level>
 ***/
+
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <libical/ical.h>
-#include <neon/ne_session.h>
-#include <neon/ne_uri.h>
-#include <neon/ne_request.h>
-#include <neon/ne_auth.h>
+#include <ne_session.h>
+#include <ne_uri.h>
+#include <ne_request.h>
+#include <ne_auth.h>
+#include <ne_redirect.h>
 #include <libxml/xmlmemory.h>
 #include <libxml/parser.h>
 
@@ -122,6 +125,15 @@ static int auth_credentials(void *userdata, const char *realm, int attempts, cha
        return 0;
 }
 
+static int debug_response_handler(void *userdata, ne_request *req, const ne_status *st)
+{
+       if (st->code < 200 || st->code > 299) {
+               ast_debug(1, "Unexpected response from server, %d: %s\n", st->code, st->reason_phrase);
+               return 0;
+       }
+       return 1;
+}
+
 static struct ast_str *caldav_request(struct caldav_pvt *pvt, const char *method, struct ast_str *req_body, struct ast_str *subdir, const char *content_type)
 {
        struct ast_str *response;
@@ -142,17 +154,15 @@ static struct ast_str *caldav_request(struct caldav_pvt *pvt, const char *method
        snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : "");
 
        req = ne_request_create(pvt->session, method, buf);
-       ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response);
+       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);
 
        ret = ne_request_dispatch(req);
        ne_request_destroy(req);
 
-       if (ret != NE_OK || !ast_str_strlen(response)) {
-               if (ret != NE_OK) {
-                       ast_log(LOG_WARNING, "Unknown response to CalDAV calendar %s, request %s to %s: %s\n", pvt->owner->name, method, buf, ne_get_error(pvt->session));
-               }
+       if (ret != NE_OK) {
+               ast_log(LOG_WARNING, "Unknown response to CalDAV calendar %s, request %s to %s: %s\n", pvt->owner->name, method, buf, ne_get_error(pvt->session));
                ast_free(response);
                return NULL;
        }
@@ -178,9 +188,8 @@ static int caldav_write_event(struct ast_calendar_event *event)
                return -1;
        }
        if (!(body = ast_str_create(512)) ||
-               !(subdir = ast_str_create(32)) ||
-               !(response = ast_str_create(512))) {
-               ast_log(LOG_ERROR, "Could not allocate memory for request and response!\n");
+               !(subdir = ast_str_create(32))) {
+               ast_log(LOG_ERROR, "Could not allocate memory for request!\n");
                goto write_cleanup;
        }
 
@@ -216,6 +225,12 @@ static int caldav_write_event(struct ast_calendar_event *event)
        if (!ast_strlen_zero(event->location)) {
                icalcomponent_add_property(icalevent, icalproperty_new_location(event->location));
        }
+       if (!ast_strlen_zero(event->categories)) {
+               icalcomponent_add_property(icalevent, icalproperty_new_categories(event->categories));
+       }
+       if (event->priority > 0) {
+               icalcomponent_add_property(icalevent, icalproperty_new_priority(event->priority));
+       }
 
        switch (event->busy_state) {
        case AST_CALENDAR_BS_BUSY:
@@ -235,9 +250,9 @@ static int caldav_write_event(struct ast_calendar_event *event)
        ast_str_append(&body, 0, "%s", icalcomponent_as_ical_string(calendar));
        ast_str_set(&subdir, 0, "%s%s.ics", pvt->url[strlen(pvt->url) - 1] == '/' ? "" : "/", event->uid);
 
-       response = caldav_request(pvt, "PUT", body, subdir, "text/calendar");
-
-       ret = 0;
+       if ((response = caldav_request(pvt, "PUT", body, subdir, "text/calendar"))) {
+               ret = 0;
+       }
 
 write_cleanup:
        if (body) {
@@ -293,6 +308,10 @@ static struct ast_str *caldav_get_events_between(struct caldav_pvt *pvt, time_t
 
        response = caldav_request(pvt, "REPORT", body, NULL, NULL);
        ast_free(body);
+       if (response && !ast_str_strlen(response)) {
+               ast_free(response);
+               return NULL;
+       }
 
        return response;
 }
@@ -365,6 +384,14 @@ static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, vo
                ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
        }
 
+       if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) {
+               ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop));
+       }
+
+       if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) {
+               event->priority = icalvalue_get_integer(icalproperty_get_value(prop));
+       }
+
        if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
                ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
        } else {
@@ -389,10 +416,12 @@ static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, vo
                        return;
                }
                data = icalproperty_get_attendee(prop);
-               if (!ast_strlen_zero(data)) {
-                       attendee->data = ast_strdup(data);;
-                       AST_LIST_INSERT_TAIL(&event->attendees, attendee, next);
+               if (ast_strlen_zero(data)) {
+                       ast_free(attendee);
+                       continue;
                }
+               attendee->data = ast_strdup(data);
+               AST_LIST_INSERT_TAIL(&event->attendees, attendee, next);
        }
 
 
@@ -428,7 +457,7 @@ static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, vo
                /* XXX Technically you can check RELATED to see if the event fires from the END of the event
                 * But, I'm not sure I've ever seen anyone implement it in calendaring software, so I'm ignoring for now */
                tmp = icaltime_add(start, trigger.duration);
-               event->alarm = icaltime_as_timet_with_zone(tmp, utc);
+               event->alarm = icaltime_as_timet_with_zone(tmp, icaltime_get_timezone(start));
        }
 
        ao2_link(pvt->events, event);
@@ -629,6 +658,7 @@ static void *caldav_load_calendar(void *void_data)
        }
 
        pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
+       ne_redirect_register(pvt->session);
        ne_set_server_auth(pvt->session, auth_credentials, pvt);
        if (!strcasecmp(pvt->uri.scheme, "https")) {
                ne_ssl_trust_default_ca(pvt->session);
@@ -690,7 +720,8 @@ static int unload_module(void)
        return 0;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk CalDAV Calendar Integration",
+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,
        );