[svn-commits] twilson: branch group/calendaring_ews r263903 - /team/group/calendaring_ews/res/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue May 18 17:22:30 CDT 2010


Author: twilson
Date: Tue May 18 17:22:27 2010
New Revision: 263903

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=263903
Log:
Add write support for res_calendar_ews

This commit was done at 1.4 mph.

Modified:
    team/group/calendaring_ews/res/res_calendar.c
    team/group/calendaring_ews/res/res_calendar_ews.c

Modified: team/group/calendaring_ews/res/res_calendar.c
URL: http://svnview.digium.com/svn/asterisk/team/group/calendaring_ews/res/res_calendar.c?view=diff&rev=263903&r1=263902&r2=263903
==============================================================================
--- team/group/calendaring_ews/res/res_calendar.c (original)
+++ team/group/calendaring_ews/res/res_calendar.c Tue May 18 17:22:27 2010
@@ -1260,6 +1260,7 @@
 	char *val_dup = NULL;
 	struct ast_calendar *cal = NULL;
 	struct ast_calendar_event *event = NULL;
+	struct timeval tv = ast_tvnow();
 	AST_DECLARE_APP_ARGS(fields,
 		AST_APP_ARG(field)[10];
 	);
@@ -1323,6 +1324,14 @@
 		} else {
 			ast_log(LOG_WARNING, "Unknown calendar event field '%s'\n", fields.field[i]);
 		}
+	}
+
+	if (!event->start) {
+		event->start = tv.tv_sec; 
+	}
+
+	if (!event->end) {
+		event->end = tv.tv_sec;
 	}
 
 	if((ret = cal->tech->write_event(event))) {

Modified: team/group/calendaring_ews/res/res_calendar_ews.c
URL: http://svnview.digium.com/svn/asterisk/team/group/calendaring_ews/res/res_calendar_ews.c?view=diff&rev=263903&r1=263902&r2=263903
==============================================================================
--- team/group/calendaring_ews/res/res_calendar_ews.c (original)
+++ team/group/calendaring_ews/res/res_calendar_ews.c Tue May 18 17:22:27 2010
@@ -44,6 +44,7 @@
 
 static void *ewscal_load_calendar(void *data);
 static void *unref_ewscal(void *obj);
+static int ewscal_write_event(struct ast_calendar_event *event);
 
 static struct ast_calendar_tech ewscal_tech = {
 	.type = "ews",
@@ -51,11 +52,13 @@
 	.module = AST_MODULE,
 	.load_calendar = ewscal_load_calendar,
 	.unref_calendar = unref_ewscal,
+	.write_event = ewscal_write_event,
 };
 
 enum xml_op {
 	XML_OP_FIND = 100,
 	XML_OP_GET,
+	XML_OP_CREATE,
 };
 
 struct calendar_id {
@@ -165,10 +168,16 @@
 	/* ast_debug(1, "EWS: XML: Start: %s\n", name); */
 	struct xml_context *ctx = userdata;
 
+	if (ctx->op == XML_OP_CREATE) {
+		return NE_XML_DECLINE;
+	}
+
 	/* Nodes needed for traversing until CalendarItem is found */
 	if (!strcmp(name, "Envelope") ||
 		!strcmp(name, "Body") ||
-		!strcmp(name, "FindItemResponse") || !strcmp(name, "GetItemResponse") ||
+		!strcmp(name, "FindItemResponse") ||
+		!strcmp(name, "GetItemResponse") ||
+		!strcmp(name, "CreateItemResponse") ||
 		!strcmp(name, "ResponseMessages") ||
 		!strcmp(name, "FindItemResponseMessage") || !strcmp(name, "GetItemResponseMessage") ||
 		!strcmp(name, "Items")
@@ -295,50 +304,52 @@
 
 static int cdata(void *userdata, int state, const char *cdata, size_t len)
 {
+	struct xml_context *ctx = userdata;
+	char data[len + 1];
+
 	/* !!! DON'T USE AST_STRING_FIELD FUNCTIONS HERE, JUST COLLECT CTX->CDATA !!! */
-	if (state >= XML_EVENT_NAME) {	/* We've got some interesting CDATA */
-		struct xml_context *ctx = userdata;
-		char data[len + 1];
-
-		if (!ctx->event) {
-			ast_log(LOG_ERROR, "Parsing event data, but event object does not exist!\n");
-			return 1;
-		}
-
-		if (!ctx->cdata) {
-			ast_log(LOG_ERROR, "String for storing CDATA is unitialized!\n");
-			return 1;
-		}
-
-		ast_copy_string(data, cdata, len + 1);
-
-		switch (state) {
-		case XML_EVENT_START:
-			ctx->event->start = mstime_to_time_t(data);
-			break;
-		case XML_EVENT_END:
-			ctx->event->end = mstime_to_time_t(data);
-			break;
-		case XML_EVENT_BUSY:
-			if (!strcmp(data, "Busy") || !strcmp(data, "OOF")) {
-				ast_debug(1, "EWS: XML: Busy: yes\n");
-				ctx->event->busy_state = AST_CALENDAR_BS_BUSY;
-			}
-			else if (!strcmp(data, "Tentative")) {
-				ast_debug(1, "EWS: XML: Busy: tentative\n");
-				ctx->event->busy_state = AST_CALENDAR_BS_BUSY_TENTATIVE;
-			}
-			else {
-				ast_debug(1, "EWS: XML: Busy: no\n");
-				ctx->event->busy_state = AST_CALENDAR_BS_FREE;
-			}
-			break;
-		default:
-			ast_str_append(&ctx->cdata, 0, "%s", data);
-		}
-
-		ast_debug(1, "EWS: XML: CDATA: %s\n", ast_str_buffer(ctx->cdata));
-	}
+	if (state < XML_EVENT_NAME || ctx->op == XML_OP_CREATE) {
+		return 0;
+	}
+
+	if (!ctx->event) {
+		ast_log(LOG_ERROR, "Parsing event data, but event object does not exist!\n");
+		return 1;
+	}
+
+	if (!ctx->cdata) {
+		ast_log(LOG_ERROR, "String for storing CDATA is unitialized!\n");
+		return 1;
+	}
+
+	ast_copy_string(data, cdata, len + 1);
+
+	switch (state) {
+	case XML_EVENT_START:
+		ctx->event->start = mstime_to_time_t(data);
+		break;
+	case XML_EVENT_END:
+		ctx->event->end = mstime_to_time_t(data);
+		break;
+	case XML_EVENT_BUSY:
+		if (!strcmp(data, "Busy") || !strcmp(data, "OOF")) {
+			ast_debug(1, "EWS: XML: Busy: yes\n");
+			ctx->event->busy_state = AST_CALENDAR_BS_BUSY;
+		}
+		else if (!strcmp(data, "Tentative")) {
+			ast_debug(1, "EWS: XML: Busy: tentative\n");
+			ctx->event->busy_state = AST_CALENDAR_BS_BUSY_TENTATIVE;
+		}
+		else {
+			ast_debug(1, "EWS: XML: Busy: no\n");
+			ctx->event->busy_state = AST_CALENDAR_BS_FREE;
+		}
+		break;
+	default:
+		ast_str_append(&ctx->cdata, 0, "%s", data);
+	}
+
+	ast_debug(1, "EWS: XML: CDATA: %s\n", ast_str_buffer(ctx->cdata));
 
 	return 0;
 }
@@ -348,8 +359,8 @@
 	/* ast_debug(1, "EWS: XML: End:   %s\n", name); */
 	struct xml_context *ctx = userdata;
 
-	if (ctx->op == XML_OP_FIND) {
-		return 0;
+	if (ctx->op == XML_OP_FIND || ctx->op == XML_OP_CREATE) {
+		return NE_XML_DECLINE;
 	}
 
 	/* Event name end*/
@@ -408,18 +419,169 @@
 	return 0;
 }
 
+static const char *mstime(time_t t, char *buf, size_t buflen)
+{
+	struct timeval tv = {
+		.tv_sec = t,
+	};
+	struct ast_tm tm;
+
+	ast_localtime(&tv, &tm, "utc");
+	ast_strftime(buf, buflen, "%FT%TZ", &tm);
+
+	return S_OR(buf, "");
+}
+
+static const char *msstatus(enum ast_calendar_busy_state state)
+{
+	switch (state) {
+	case AST_CALENDAR_BS_BUSY_TENTATIVE:
+		return "Tentative";
+	case AST_CALENDAR_BS_BUSY:
+		return "Busy";
+	case AST_CALENDAR_BS_FREE:
+		return "Free";
+	default:
+		return "";
+	}
+}
+
+static const char *get_soap_action(enum xml_op op)
+{
+	switch (op) {
+	case XML_OP_FIND:
+		return "\"http://schemas.microsoft.com/exchange/services/2006/messages/FindItem\"";
+	case XML_OP_GET:
+		return "\"http://schemas.microsoft.com/exchange/services/2006/messages/GetItem\"";
+	case XML_OP_CREATE:
+		return "\"http://schemas.microsoft.com/exchange/services/2006/messages/CreateItem\"";
+	}
+
+	return "";
+}
+
+static int send_ews_request_and_parse(struct ast_str *request, struct xml_context *ctx)
+{
+	int ret;
+	ne_request *req;
+	ne_xml_parser *parser;
+
+	ast_debug(1, "EWS: HTTP request...\n");
+	if (!(ctx && ctx->pvt)) {
+		ast_log(LOG_ERROR, "There is no private!\n");
+		return -1;
+	}
+
+	if (!ast_str_strlen(request)) {
+		ast_log(LOG_ERROR, "No request to send!\n");
+		return -1;
+	}
+
+	ast_debug(3, "%s\n", ast_str_buffer(request));
+
+	/* Prepare HTTP POST request */
+	req = ne_request_create(ctx->pvt->session, "POST", ctx->pvt->uri.path);
+	ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0);
+
+	/* Set headers */
+	ne_add_request_header(req, "Content-Type", "text/xml; charset=utf-8");	/* should be application/soap+xml, but MS… :/ */
+	ne_add_request_header(req, "SOAPAction", get_soap_action(ctx->op));
+
+	/* Set body to SOAP request */
+	ne_set_request_body_buffer(req, ast_str_buffer(request), ast_str_strlen(request));
+
+	/* Prepare XML parser */
+	parser = ne_xml_create();
+	ctx->parser = parser;
+	ne_xml_push_handler(parser, startelm, cdata, endelm, ctx);	/* Callbacks */
+
+	/* Dispatch request and parse response as XML */
+	ret = ne_xml_dispatch_request(req, parser);
+	if (ret != NE_OK) {	/* Error handling */
+		ast_log(LOG_WARNING, "Unable to communicate with Exchange Web Service at '%s': %s\n", ctx->pvt->url, ne_get_error(ctx->pvt->session));
+		ne_request_destroy(req);
+		ast_free(request);
+		ne_xml_destroy(parser);
+		return -1;
+	}
+
+	/* Cleanup */
+	ne_request_destroy(req);
+	ne_xml_destroy(parser);
+
+	return 0;
+}
+
+static int ewscal_write_event(struct ast_calendar_event *event)
+{
+	struct ast_str *request;
+	struct ewscal_pvt *pvt = event->owner->tech_pvt;
+	char start[21], end[21];
+	struct xml_context ctx = {
+		.op = XML_OP_CREATE,
+		.pvt = pvt,
+	};
+	int ret;
+
+	if (!pvt) {
+		return -1;
+	}
+
+	if (!(request = ast_str_create(1024))) {
+		return -1;
+	}
+
+	ast_str_set(&request, 0, 
+		"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
+			"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
+			"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+			"xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">"
+			"<soap:Body>"
+			"<CreateItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\" "
+				"xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\" "
+				"SendMeetingInvitations=\"SendToNone\" >"
+				"<SavedItemFolderId>"
+					"<t:DistinguishedFolderId Id=\"calendar\"/>"
+				"</SavedItemFolderId>"
+				"<Items>"
+					"<t:CalendarItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/types\">"
+						"<Subject>%s</Subject>"
+						"<Body BodyType=\"Text\">%s</Body>"
+						"<ReminderIsSet>false</ReminderIsSet>"
+						"<Start>%s</Start>"
+						"<End>%s</End>"
+						"<IsAllDayEvent>false</IsAllDayEvent>"
+						"<LegacyFreeBusyStatus>%s</LegacyFreeBusyStatus>"
+						"<Location>%s</Location>"
+					"</t:CalendarItem>"
+				"</Items>"
+			"</CreateItem>"
+		"</soap:Body>"
+		"</soap:Envelope>",
+		event->summary,
+		event->description,
+		mstime(event->start, start, sizeof(start)),
+		mstime(event->end, end, sizeof(end)),
+		msstatus(event->busy_state),
+		event->location
+	);
+
+	ret = send_ews_request_and_parse(request, &ctx);
+
+	ast_free(request);
+
+	return ret;
+}
+
 static struct calendar_id *get_ewscal_ids_for(struct ewscal_pvt *pvt)
 {
 	char start[21], end[21];
 	struct ast_tm tm;
 	struct timeval tv;
 	struct ast_str *request;
-	int ret;
-	ne_request *req;
-	ne_xml_parser *parser;
 	struct xml_context ctx = {
+		.op = XML_OP_FIND,
 		.pvt = pvt,
-		.op = XML_OP_FIND,
 	};
 
 	ast_debug(1, "EWS: get_ewscal_ids_for()\n");
@@ -461,48 +623,23 @@
 		"</SOAP-ENV:Envelope>",
 		start, end	/* Timeframe */
 	);
-	ast_debug(3, "%s\n", ast_str_buffer(request));
-
-	/* Prepare HTTP POST request */
-	req = ne_request_create(pvt->session, "POST", pvt->uri.path);
-	ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0);
-
-	/* Set headers */
-	ne_add_request_header(req, "Content-Type", "text/xml; charset=utf-8");	/* should be application/soap+xml, but MS… :/ */
-	ne_add_request_header(req, "SOAPAction", "\"http://schemas.microsoft.com/exchange/services/2006/messages/FindItem\"");
-
-	/* Set body to SOAP request */
-	ne_set_request_body_buffer(req, ast_str_buffer(request), ast_str_strlen(request));
-
-	/* Prepare XML parser */
-	parser = ne_xml_create();
-	ctx.parser = parser;
+
 	AST_LIST_HEAD_INIT_NOLOCK(&ctx.ids);
-	ne_xml_push_handler(parser, startelm, cdata, endelm, &ctx);	/* Callbacks */
 
 	/* Dispatch request and parse response as XML */
-	ret = ne_xml_dispatch_request(req, parser);
-	if (ret != NE_OK) {	/* Error handling */
-		ast_log(LOG_WARNING, "Unable to communicate with Exchange Web Service at '%s': %s\n", pvt->url, ne_get_error(pvt->session));
-		ne_request_destroy(req);
+	if (send_ews_request_and_parse(request, &ctx)) {
 		ast_free(request);
-		ne_xml_destroy(parser);
 		return NULL;
 	}
 
 	/* Cleanup */
 	ast_free(request);
-	ne_request_destroy(req);
-	ne_xml_destroy(parser);
 
 	return AST_LIST_FIRST(&ctx.ids);
 }
 
 static int parse_ewscal_id(struct ewscal_pvt *pvt, const char *id) {
 	struct ast_str *request;
-	int ret;
-	ne_request *req;
-	ne_xml_parser *parser;
 	struct xml_context ctx = {
 		.pvt = pvt,
 		.op = XML_OP_GET,
@@ -528,37 +665,10 @@
 		  "</soap:Body>"
 		"</soap:Envelope>",
 		id);
-	ast_debug(3, "%s\n", ast_str_buffer(request));
-
-	/* Prepare HTTP POST request */
-	req = ne_request_create(pvt->session, "POST", pvt->uri.path);
-	ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0);
-
-	/* Set headers */
-	ne_add_request_header(req, "Content-Type", "text/xml; charset=utf-8");	/* should be application/soap+xml, but MS… :/ */
-	ne_add_request_header(req, "SOAPAction", "\"http://schemas.microsoft.com/exchange/services/2006/messages/GetItem\"");
-
-	/* Set body to SOAP request */
-	ne_set_request_body_buffer(req, ast_str_buffer(request), ast_str_strlen(request));
-
-	/* Prepare XML parser */
-	parser = ne_xml_create();
-	ctx.parser = parser;
-	ne_xml_push_handler(parser, startelm, cdata, endelm, &ctx);	/* Callbacks */
-
-	/* Dispatch request and parse response as XML */
-	ret = ne_xml_dispatch_request(req, parser);
-	if (ret != NE_OK) {	/* Error handling */
-		ast_log(LOG_WARNING, "Unable to communicate with Exchange Web Service at '%s': %s\n", pvt->url, ne_get_error(pvt->session));
-		ne_request_destroy(req);
-		ne_xml_destroy(parser);
+	if (send_ews_request_and_parse(request, &ctx)) {
 		ast_free(request);
 		return -1;
 	}
-
-	/* Cleanup */
-	ne_request_destroy(req);
-	ne_xml_destroy(parser);
 	ast_free(request);
 
 	return 0;




More information about the svn-commits mailing list