From d8112cd98b5f8c8402e04220018b6a96f789869d Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Wed, 13 Sep 2017 15:08:39 -0400 Subject: res_calendar: Various fixes * The way that we were looking at XML elements for CalDAV was extremely fragile, so use SAX2 for increased robustness. * Don't complain about a 'channel' not be specified if autoreminder is not set. Assume that if 'channel' is not set, we don't want to be notified. * Fix some truncated CLI output in 'calendar show calendar' and make the 'Autoreminder' description a bit more clear ASTERISK-24588 #close Reported by: Stefan Gofferje ASTERISK-25523 #close Reported by: Jesper Change-Id: I200d11afca6a47e7d97888f286977e2e69874b2c --- res/res_calendar.c | 23 ++++++++++++++++++----- res/res_calendar_caldav.c | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 13 deletions(-) (limited to 'res') diff --git a/res/res_calendar.c b/res/res_calendar.c index e4c89dfd7..bf385dba6 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -488,6 +488,13 @@ static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *c } } + if (cal->autoreminder && ast_strlen_zero(cal->notify_channel)) { + ast_log(LOG_WARNING, + "You have set 'autoreminder' but not 'channel' for calendar '%s.' " + "Notifications will not occur.\n", + cal->name); + } + if (new_calendar) { cal->thread = AST_PTHREADT_NULL; ast_cond_init(&cal->unload, NULL); @@ -495,7 +502,7 @@ static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *c if (ast_pthread_create(&cal->thread, NULL, cal->tech->load_calendar, cal)) { /* If we start failing to create threads, go ahead and return NULL * and the tech module will be unregistered - */ + */ ao2_unlink(calendars, cal); cal = unref_calendar(cal); } @@ -954,7 +961,7 @@ static int schedule_calendar_event(struct ast_calendar *cal, struct ast_calendar event = cmp_event ? cmp_event : old_event; ao2_lock(event); - if (!cmp_event || old_event->alarm != event->alarm) { + if (!ast_strlen_zero(cal->notify_channel) && (!cmp_event || old_event->alarm != event->alarm)) { changed = 1; if (cal->autoreminder) { alarm_notify_sched = (event->start - (60 * cal->autoreminder) - now.tv_sec) * 1000; @@ -963,7 +970,7 @@ static int schedule_calendar_event(struct ast_calendar *cal, struct ast_calendar } /* For now, send the notification if we missed it, but the meeting hasn't happened yet */ - if (event->start >= now.tv_sec) { + if (event->start >= now.tv_sec) { if (alarm_notify_sched <= 0) { alarm_notify_sched = 1; } @@ -1596,7 +1603,7 @@ static char *epoch_to_string(char *buf, size_t buflen, time_t epoch) static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { -#define FORMAT "%-17.17s : %-20.20s\n" +#define FORMAT "%-18.18s : %-20.20s\n" #define FORMAT2 "%-12.12s: %-40.60s\n" struct ao2_iterator i; struct ast_calendar *cal; @@ -1645,7 +1652,13 @@ static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_c ast_cli(a->fd, FORMAT, "Notify appdata", cal->notify_appdata); ast_cli(a->fd, "%-17.17s : %d\n", "Refresh time", cal->refresh); ast_cli(a->fd, "%-17.17s : %d\n", "Timeframe", cal->timeframe); - ast_cli(a->fd, "%-17.17s : %d\n", "Autoreminder", cal->autoreminder); + + if (cal->autoreminder) { + ast_cli(a->fd, "%-17.17s : %d minutes before event\n", "Autoreminder", cal->autoreminder); + } else { + ast_cli(a->fd, "%-17.17s : None\n", "Autoreminder"); + } + ast_cli(a->fd, "%s\n", "Events"); ast_cli(a->fd, "%s\n", "------"); diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c index 3c1c74a4c..b6822b085 100644 --- a/res/res_calendar_caldav.c +++ b/res/res_calendar_caldav.c @@ -156,6 +156,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); @@ -476,17 +477,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") || !xmlStrcasecmp(fullname, BAD_CAST "caldav: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; @@ -494,7 +504,7 @@ static void handle_end_element(void *data, const xmlChar *name) icalcomponent *iter; icalcomponent *comp; - if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data") && xmlStrcasecmp(name, BAD_CAST "caldav:calendar-data")) { + if (xmlStrcmp(localname, caldav_node_localname) || xmlStrcmp(uri, caldav_node_nsuri)) { return; } @@ -557,9 +567,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)); -- cgit v1.2.3