31#include <ne_request.h> 
   32#include <ne_session.h> 
   39#include <ne_redirect.h> 
   54    .description = 
"MS Exchange Web Service calendars",
 
 
  117    ast_debug(1, 
"Destroying pvt for Exchange Web Service calendar %s\n", 
"pvt->owner->name");
 
  119        ne_session_destroy(pvt->
session);
 
  121    ne_uri_free(&pvt->
uri);
 
 
  147    ne_strnzcpy(username, pvt->
user, NE_ABUFSIZ);
 
 
  153static int ssl_verify(
void *userdata, 
int failures, 
const ne_ssl_certificate *cert)
 
  156    if (failures & NE_SSL_UNTRUSTED) {
 
 
  175static int startelm(
void *userdata, 
int parent, 
const char *nspace, 
const char *
name, 
const char **atts)
 
  181        return NE_XML_DECLINE;
 
  185    if (!strcmp(
name, 
"Envelope") ||
 
  187        !strcmp(
name, 
"FindItemResponse") ||
 
  188        !strcmp(
name, 
"GetItemResponse") ||
 
  189        !strcmp(
name, 
"CreateItemResponse") ||
 
  190        !strcmp(
name, 
"ResponseMessages") ||
 
  191        !strcmp(
name, 
"FindItemResponseMessage") || !strcmp(
name, 
"GetItemResponseMessage") ||
 
  192        !strcmp(
name, 
"Items")
 
  195    } 
else if (!strcmp(
name, 
"RootFolder")) {
 
  199        ast_debug(3, 
"EWS: XML: <RootFolder>\n");
 
  200        if (sscanf(ne_xml_get_attr(ctx->
parser, atts, 
NULL, 
"TotalItemsInView"), 
"%u", &items) != 1) {
 
  202            ne_xml_set_error(ctx->
parser, 
"Could't read number of events.");
 
  206        ast_debug(3, 
"EWS: %u calendar items to load\n", items);
 
  211            return NE_XML_DECLINE;
 
  214    } 
else if (!strcmp(
name, 
"CalendarItem")) {
 
  216        ast_debug(3, 
"EWS: XML: <CalendarItem>\n");
 
  235    } 
else if (!strcmp(
name, 
"ItemId")) {
 
  254    } 
else if (!strcmp(
name, 
"Subject")) {
 
  268    } 
else if (!strcmp(
name, 
"Start")) {
 
  271    } 
else if (!strcmp(
name, 
"End")) {
 
  274    } 
else if (!strcmp(
name, 
"LegacyFreeBusyStatus")) {
 
  277    } 
else if (!strcmp(
name, 
"Organizer") ||
 
  279            !strcmp(
name, 
"Name")))) {
 
  286    } 
else if (!strcmp(
name, 
"Location")) {
 
  293    } 
else if (!strcmp(
name, 
"Categories")) {
 
  303    } 
else if (!strcmp(
name, 
"Importance")) {
 
  310    } 
else if (!strcmp(
name, 
"RequiredAttendees") || !strcmp(
name, 
"OptionalAttendees")) {
 
  324    return NE_XML_DECLINE;
 
 
  338        ast_log(
LOG_ERROR, 
"Parsing event data, but event object does not exist!\n");
 
  357        if (!strcmp(data, 
"Busy") || !strcmp(data, 
"OOF")) {
 
  361        else if (!strcmp(data, 
"Tentative")) {
 
  362            ast_debug(3, 
"EWS: XML: Busy: tentative\n");
 
 
  392        return NE_XML_DECLINE;
 
  395    if (!strcmp(
name, 
"Subject")) {
 
  405    } 
else if (!strcmp(
name, 
"Organizer")) {
 
  410    } 
else if (!strcmp(
name, 
"Location")) {
 
  415    } 
else if (!strcmp(
name, 
"Categories")) {
 
  420    } 
else if (!strcmp(
name, 
"Importance")) {
 
  434        if (!(attendee = 
ast_calloc(1, 
sizeof(*attendee)))) {
 
  447    } 
else if (!strcmp(
name, 
"CalendarItem")) {
 
  449        ast_debug(3, 
"EWS: XML: </CalendarItem>\n");
 
  455            ast_log(
LOG_ERROR, 
"Event data ended in XML, but event object does not exist!\n");
 
  458    } 
else if (!strcmp(
name, 
"Envelope")) {
 
  462            ast_debug(3, 
"EWS: XML: All events has been parsed, merging…\n");
 
 
  470static const char *
mstime(time_t t, 
char *
buf, 
size_t buflen)
 
  472    struct timeval tv = {
 
 
  501        return "\"http://schemas.microsoft.com/exchange/services/2006/messages/FindItem\"";
 
  503        return "\"http://schemas.microsoft.com/exchange/services/2006/messages/GetItem\"";
 
  505        return "\"http://schemas.microsoft.com/exchange/services/2006/messages/CreateItem\"";
 
 
  515    ne_xml_parser *parser;
 
  518    if (!(ctx && ctx->
pvt)) {
 
  532    ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0);
 
  535    ne_add_request_header(req, 
"Content-Type", 
"text/xml; charset=utf-8");
 
  542    parser = ne_xml_create();
 
  547    ret = ne_xml_dispatch_request(req, parser);
 
  550        ne_request_destroy(req);
 
  551        ne_xml_destroy(parser);
 
  556    ne_request_destroy(req);
 
  557    ne_xml_destroy(parser);
 
 
  566    char start[21], 
end[21];
 
  583        "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " 
  584            "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " 
  585            "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " 
  586            "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" 
  588            "<CreateItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\" " 
  589                "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\" " 
  590                "SendMeetingInvitations=\"SendToNone\" >" 
  591                "<SavedItemFolderId>" 
  592                    "<t:DistinguishedFolderId Id=\"calendar\"/>" 
  593                "</SavedItemFolderId>" 
  595                    "<t:CalendarItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/types\">" 
  596                        "<Subject>%s</Subject>" 
  597                        "<Body BodyType=\"Text\">%s</Body>" 
  598                        "<ReminderIsSet>false</ReminderIsSet>" 
  601                        "<IsAllDayEvent>false</IsAllDayEvent>" 
  602                        "<LegacyFreeBusyStatus>%s</LegacyFreeBusyStatus>" 
  603                        "<Location>%s</Location>",
 
  612    switch (
event->priority) {
 
  630    if (strlen(
event->categories) > 0) {
 
  634        while (category != 
NULL) {
 
 
  652    char start[21], 
end[21];
 
  661    ast_debug(5, 
"EWS: get_ewscal_ids_for()\n");
 
  682        "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " 
  683        "xmlns:ns1=\"http://schemas.microsoft.com/exchange/services/2006/types\" " 
  684        "xmlns:ns2=\"http://schemas.microsoft.com/exchange/services/2006/messages\">" 
  686                "<ns2:FindItem Traversal=\"Shallow\">" 
  688                        "<ns1:BaseShape>IdOnly</ns1:BaseShape>" 
  690                    "<ns2:CalendarView StartDate=\"%s\" EndDate=\"%s\"/>"    
  691                    "<ns2:ParentFolderIds>" 
  692                        "<ns1:DistinguishedFolderId Id=\"calendar\"/>" 
  693                    "</ns2:ParentFolderIds>" 
  696        "</SOAP-ENV:Envelope>",
 
 
  726        "<?xml version=\"1.0\" encoding=\"utf-8\"?>" 
  727        "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " 
  728        "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" 
  730            "<GetItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">" 
  732                    "<t:BaseShape>AllProperties</t:BaseShape>" 
  735                    "<t:ItemId Id=\"%s\"/>" 
  739        "</soap:Envelope>", 
id 
 
  778    ast_debug(5, 
"EWS: ewscal_load_calendar()\n");
 
  781        ast_log(
LOG_ERROR, 
"You must enable calendar support for res_ewscal to load\n");
 
  804        ast_log(
LOG_ERROR, 
"Could not allocate space for fetching events for calendar: %s\n", cal->
name);
 
  820        if (!strcasecmp(v->
name, 
"url")) {
 
  822        } 
else if (!strcasecmp(v->
name, 
"user")) {
 
  824        } 
else if (!strcasecmp(v->
name, 
"secret")) {
 
  832        ast_log(
LOG_WARNING, 
"No URL was specified for Exchange Web Service calendar '%s' - skipping.\n", cal->
name);
 
  839        ast_log(
LOG_WARNING, 
"Could not parse url '%s' for Exchange Web Service calendar '%s' - skipping.\n", pvt->
url, cal->
name);
 
  846        pvt->
uri.scheme = 
"http";
 
  849    if (pvt->
uri.port == 0) {
 
  850        pvt->
uri.port = ne_uri_defaultport(pvt->
uri.scheme);
 
  860    pvt->
session = ne_session_create(pvt->
uri.scheme, pvt->
uri.host, pvt->
uri.port);
 
  861    ne_redirect_register(pvt->
session);
 
  863    ne_set_useragent(pvt->
session, 
"Asterisk");
 
  865    if (!strcasecmp(pvt->
uri.scheme, 
"https")) {
 
  866        ne_ssl_trust_default_ca(pvt->
session);
 
  882        struct timespec ts = {0,};
 
  895            ast_debug(10, 
"Skipping refresh since we got a shutdown signal\n");
 
 
  920    if (ne_version_match(0, 29) && ne_version_match(0, 30)) {
 
  921        ast_log(
LOG_ERROR, 
"Exchange Web Service calendar module require neon >= 0.29.1, but %s is installed.\n", ne_version_string());
 
 
  945    .
requires = 
"res_calendar",
 
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_calloc(num, len)
A wrapper for calloc()
#define ao2_link(container, obj)
Add an object to a container.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_alloc(data_size, destructor_fn)
A general API for managing calendar events with Asterisk.
void ast_calendar_unregister(struct ast_calendar_tech *tech)
Unregister a new calendar technology.
void ast_calendar_merge_events(struct ast_calendar *cal, struct ao2_container *new_events)
Add an event to the list of events for a calendar.
void ast_calendar_config_release(void)
Release the calendar config.
@ AST_CALENDAR_BS_BUSY_TENTATIVE
struct ao2_container * ast_calendar_event_container_alloc(void)
Allocate an astobj2 container for ast_calendar_event objects.
int ast_calendar_register(struct ast_calendar_tech *tech)
Register a new calendar technology.
struct ast_calendar_event * ast_calendar_event_alloc(struct ast_calendar *cal)
Allocate an astobj2 ast_calendar_event object.
struct ast_calendar_event * ast_calendar_unref_event(struct ast_calendar_event *event)
Unreference an ast_calendar_event.
const struct ast_config * ast_calendar_config_acquire(void)
Grab and lock pointer to the calendar config (read only)
static int request(void *obj)
General Asterisk PBX channel definitions.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Configuration File Parser.
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
char * ast_strptime(const char *s, const char *format, struct ast_tm *tm)
Special version of strptime(3) which places the answer in the common structure ast_tm....
Asterisk locking-related definitions:
#define ast_cond_timedwait(cond, mutex, time)
#define ast_mutex_init(pmutex)
#define ast_mutex_unlock(a)
#define ast_mutex_lock(a)
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODPRI_DEVSTATE_PLUGIN
@ AST_MODULE_SUPPORT_EXTENDED
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
static ast_mutex_t refreshlock
static int cdata(void *userdata, int state, const char *cdata, size_t len)
static int startelm(void *userdata, int parent, const char *nspace, const char *name, const char **atts)
static void * unref_ewscal(void *obj)
static time_t mstime_to_time_t(char *mstime)
static int update_ewscal(struct ewscal_pvt *pvt)
static const char * get_soap_action(enum xml_op op)
static void * ewscal_load_calendar(void *data)
static int send_ews_request_and_parse(struct ast_str *request, struct xml_context *ctx)
static int ssl_verify(void *userdata, int failures, const ne_ssl_certificate *cert)
@ XML_EVENT_EMAIL_ADDRESS
@ XML_EVENT_ATTENDEE_LIST
@ XML_EVENT_CALENDAR_ITEM
static struct ast_calendar_tech ewscal_tech
static const char * mstime(time_t t, char *buf, size_t buflen)
static int auth_credentials(void *userdata, const char *realm, int attempts, char *username, char *secret)
static void ewscal_destructor(void *obj)
static int load_module(void)
static const char * msstatus(enum ast_calendar_busy_state state)
static int parse_ewscal_id(struct ewscal_pvt *pvt, const char *id)
static int unload_module(void)
static int ewscal_write_event(struct ast_calendar_event *event)
static struct calendar_id * get_ewscal_ids_for(struct ewscal_pvt *pvt)
static int endelm(void *userdata, int state, const char *nspace, const char *name)
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define AST_STRING_FIELD(name)
Declare a string field.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
size_t attribute_pure ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
struct ast_calendar_attendee * next
enum ast_calendar_busy_state busy_state
const ast_string_field location
const ast_string_field description
const ast_string_field categories
const ast_string_field organizer
struct ast_calendar_event::attendees attendees
const ast_string_field summary
Individual calendaring technology data.
Asterisk calendar structure.
const ast_string_field name
Structure for mutex and tracking information.
Support for dynamic strings.
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
struct calendar_id * next
const ast_string_field url
struct ast_calendar * owner
const ast_string_field user
struct ao2_container * events
const ast_string_field secret
structure to hold users read from phoneprov_users.conf
struct ast_calendar_event * event
struct xml_context::ids ids
struct association categories[]
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().