]> Pileus Git - lackey/commitdiff
Use CURL simple API for EWS calendars
authorAndy Spencer <andy753421@gmail.com>
Fri, 2 Dec 2016 07:57:54 +0000 (07:57 +0000)
committerAndy Spencer <andy753421@gmail.com>
Mon, 12 Jun 2017 05:26:33 +0000 (05:26 +0000)
cals/ews.c
makefile
src/util.c
src/util.h

index b8ecaa3b3d5220da2fd1ea61e25a141e64b1c5a4..63580457e5d06999b6f6948fb5b8a6acb5f8ffaa 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <stdio.h>
 
+#include <curl/curl.h>
+
 #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 =
+       "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
+       "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+       "               xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n"
+       "               xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
+       "               xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\"\n"
+       "               xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\">\n"
+       "    <soap:Body>\n"
+       "        <m:FindItem Traversal=\"Shallow\">\n"
+       "            <m:ItemShape>\n"
+       "                <t:BaseShape>IdOnly</t:BaseShape>\n"
+       "                <t:AdditionalProperties>\n"
+       "                    <t:FieldURI FieldURI=\"calendar:CalendarItemType\" />\n"
+       "                    <t:FieldURI FieldURI=\"calendar:Start\" />\n"
+       "                    <t:FieldURI FieldURI=\"calendar:End\" />\n"
+       "                    <t:FieldURI FieldURI=\"item:ItemClass\" />\n"
+       "                    <t:FieldURI FieldURI=\"item:Subject\" />\n"
+       "                </t:AdditionalProperties>\n"
+       "            </m:ItemShape>\n"
+       "            <m:CalendarView StartDate=\"2016-01-01T00:00:00-00:00\"\n"
+       "                            EndDate=\"2018-01-01T00:00:00-00:00\"\n"
+       "                            MaxEntriesReturned=\"1000\" />\n"
+       "            <m:ParentFolderIds>\n"
+       "                <t:DistinguishedFolderId Id=\"calendar\" />\n"
+       "            </m:ParentFolderIds>\n"
+       "        </m:FindItem>\n"
+       "    </soap:Body>\n"
+       "</soap:Envelope>\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<len ? buf[i+1] : '\0';
+               if (this == '<' && next == '/')
+                       indent--;
+               if (this == '<' && prev == '>') {
+                       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");
 }
index a479829670550784f8ac6107dbbbfafdbc97d268..552b59bf510a3055c1ff5ecd9462fa91f26d796f 100644 (file)
--- 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
index d74a7469d0914c23a909140066c95ec3d501775d..2f11d078f8a90d431cc1675dfdd96f6e305712ef 100644 (file)
@@ -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)
 {
index 4f5d16e7dd0610658163448513780fbc0e02202d..599246105272ba5797b4544631c9c4037caff451 100644 (file)
 
 #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);