From: Andy Spencer Date: Fri, 2 Dec 2016 07:57:54 +0000 (+0000) Subject: Use CURL simple API for EWS calendars X-Git-Url: http://pileus.org/git/?p=lackey;a=commitdiff_plain;h=e039ae3090ac4f66851b2c9301ba1521e2fc2b85 Use CURL simple API for EWS calendars --- diff --git a/cals/ews.c b/cals/ews.c index b8ecaa3..6358045 100644 --- a/cals/ews.c +++ b/cals/ews.c @@ -17,6 +17,8 @@ #include +#include + #include "util.h" #include "conf.h" #include "date.h" @@ -32,14 +34,89 @@ typedef struct ews_t { char *password; char *location; char *domain; + + // Parsing + CURL *curl; + buf_t buf; + + // Debugging + int debug; + int indent; } ews_t; /* Static data */ static ews_t *calendars; +static CURLM *curlm; + +/* SOAP Requests */ +static char *req_calendar = + "\n" + "\n" + " \n" + " \n" + " \n" + " IdOnly\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" +; /* Local functions */ +static void dump_xml(const char *buf, int len) +{ + int indent = 0; + for (int i = 0; i < len; i++) { + const char prev = i>0 ? buf[i-1] : '\0'; + const char this = buf[i]; + const char next = i') { + putchar('\n'); + for (int j = 0; j < indent*4; j++) + putchar(' '); + } + if (this == '>' && prev == '/') + indent--; + if (this == '<' && next != '/' && next != '?') + indent++; + putchar(buf[i]); + } + putchar('\n'); +} + +static size_t on_write(void *buf, size_t size, size_t n, ews_t *cal) +{ + int len = size * n; + append(&cal->buf, buf, len); + return len; +} + static void sync_ews(ews_t *cal) { + CURLcode err; + long status; + struct curl_slist *hdr = NULL; + + /* Debug output */ debug("Loading EWS:"); debug(" type = %s", cal->cal.type); debug(" name = %s", cal->cal.name); @@ -48,6 +125,58 @@ static void sync_ews(ews_t *cal) debug(" password = %s", cal->password); debug(" location = %s", cal->location); debug(" domain = %s", cal->domain); + + /* Setup HTTP request */ + if (!(cal->curl = curl_easy_init())) + error("Curl easy init failed"); + if (curl_easy_setopt(cal->curl, CURLOPT_URL, cal->location)) + error("Curl easy setopt failed"); + if (curl_easy_setopt(cal->curl, CURLOPT_WRITEFUNCTION, on_write)) + error("Curl easy set write function failed"); + if (curl_easy_setopt(cal->curl, CURLOPT_WRITEDATA, cal)) + error("Curl easy set write data failed"); + + /* Skip SSL checks */ + if (curl_easy_setopt(cal->curl, CURLOPT_SSL_VERIFYPEER, 0L)) + error("Curl easy set no verify peer failed"); + if (curl_easy_setopt(cal->curl, CURLOPT_SSL_VERIFYHOST, 0L)) + error("Curl easy set no verify hosts failed"); + + /* Set login info */ + if (curl_easy_setopt(cal->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY)) + error("Curl easy set http auth failed"); + if (curl_easy_setopt(cal->curl, CURLOPT_USERNAME, cal->username)) + error("Curl easy set username failed"); + if (curl_easy_setopt(cal->curl, CURLOPT_PASSWORD, cal->password)) + error("Curl easy set password failed"); + + /* Setup SOAP request */ + hdr = curl_slist_append(hdr, "Accept: text/xml"); + hdr = curl_slist_append(hdr, "Content-Type: text/xml"); + if (curl_easy_setopt(cal->curl, CURLOPT_HTTPHEADER, hdr)) + error("Curl easy set http header failed"); + if (curl_easy_setopt(cal->curl, CURLOPT_POST, 1L)) + error("Curl easy set post failed"); + if (curl_easy_setopt(cal->curl, CURLOPT_POSTFIELDS, req_calendar)) + error("Curl easy set post failed"); + + /* Curl Easy */ + if ((err = curl_easy_perform(cal->curl))) + error("Curl easy perform failed: %s", curl_easy_strerror(err)); + if ((err = curl_easy_getinfo(cal->curl, CURLINFO_RESPONSE_CODE, &status))) + error("Curl easy get info failed: %s", curl_easy_strerror(err)); + + /* Output response */ + if (cal->debug) + printf("EWS -- HTTP Status %ld\n", status); + if (cal->debug && !cal->buf.data) + printf("EWS -- No Response Data\n"); + if (cal->debug) + dump_xml(cal->buf.data, cal->buf.len); + + /* Cleanup */ + curl_easy_cleanup(cal->curl); + release(&cal->buf); } /* Config parser */ @@ -112,6 +241,25 @@ todo_t *ews_todos(date_t start, date_t end) /* Test functions */ void ews_test(char *url, char *user, char *pass) { + ews_t cal = { + .location = url, + .username = user && user[0] ? user : NULL, + .password = pass && pass[0] ? pass : NULL, + .debug = 1, + }; + + /* Setup CURL */ printf("EWS -- test start\n"); + if (curl_global_init(CURL_GLOBAL_DEFAULT)) + error("Curl global init failed"); + if (!(curlm = curl_multi_init())) + error("Curl multi init failed"); + + /* Sync the calendar */ + sync_ews(&cal); + + /* Cleanup */ + curl_multi_cleanup(curlm); + curl_global_cleanup(); printf("EWS -- test end\n"); } diff --git a/makefile b/makefile index a479829..552b59b 100644 --- a/makefile +++ b/makefile @@ -11,7 +11,7 @@ MANPREFIX ?= $(PREFIX)/share/man # Compiler GCC ?= gcc CFLAGS ?= -Wall --std=c99 -LDFLAGS ?= -lncursesw -lical +LDFLAGS ?= -lncursesw -lical -lcurl # Sources PROG ?= lackey diff --git a/src/util.c b/src/util.c index d74a746..2f11d07 100644 --- a/src/util.c +++ b/src/util.c @@ -106,6 +106,27 @@ void *alloc0(int size) return data; } +void append(buf_t *buf, const void *data, int len) +{ + if (buf->len + len + 1 > buf->max) { + buf->max += (((buf->len+len)/4096)+1)*4096; + buf->data = realloc(buf->data, buf->max); + if (!buf->data) + error("buffer reallocation allocation failed"); + } + memcpy(buf->data + buf->len, data, len); + buf->len += len; + ((char*)buf->data)[buf->len] = '\0'; +} + +void release(buf_t *buf) +{ + free(buf->data); + buf->data = 0; + buf->len = 0; + buf->max = 0; +} + /* File functions */ char *read_file(const char *path, int *len) { diff --git a/src/util.h b/src/util.h index 4f5d16e..5992461 100644 --- a/src/util.h +++ b/src/util.h @@ -25,6 +25,13 @@ #define new0(type) alloc0(sizeof(type)) +/* Types */ +typedef struct { + void *data; + int len; + int max; +} buf_t; + /* Debug functions */ void util_init(void); @@ -35,6 +42,8 @@ int match(const char *a, const char *b); /* Memory functions */ void *alloc0(int size); +void append(buf_t *buf, const void *data, int len); +void release(buf_t *buf); /* File functions */ char *read_file(const char *path, int *len);