2 * Copyright (C) 2016 Andy Spencer <andy753421@gmail.com>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <curl/curl.h>
31 typedef struct ews_t {
57 static ews_t *calendars;
61 static char *req_calendar =
62 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
63 "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
64 " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n"
65 " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
66 " xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\"\n"
67 " xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\">\n"
69 " <m:FindItem Traversal=\"Shallow\">\n"
71 " <t:BaseShape>IdOnly</t:BaseShape>\n"
72 " <t:AdditionalProperties>\n"
73 " <t:FieldURI FieldURI=\"calendar:CalendarItemType\" />\n"
74 " <t:FieldURI FieldURI=\"calendar:Start\" />\n"
75 " <t:FieldURI FieldURI=\"calendar:End\" />\n"
76 " <t:FieldURI FieldURI=\"item:ItemClass\" />\n"
77 " <t:FieldURI FieldURI=\"item:Subject\" />\n"
78 " </t:AdditionalProperties>\n"
80 " <m:CalendarView StartDate=\"2016-01-01T00:00:00-00:00\"\n"
81 " EndDate=\"2018-01-01T00:00:00-00:00\"\n"
82 " MaxEntriesReturned=\"1000\" />\n"
83 " <m:ParentFolderIds>\n"
84 " <t:DistinguishedFolderId Id=\"calendar\" />\n"
85 " </m:ParentFolderIds>\n"
92 static void on_start(void *_cal, const char *tag, const char **attrs)
99 cal->indent*4, "", tag);
100 for (int i = 0; attrs[i]; i += 2) {
101 printf("%*s %s=\"%s\"\n",
102 cal->indent*4+6, "--",
103 attrs[i+0], attrs[i+1]);
110 if (match(tag, "t:CalendarItem")) {
111 cal->event = new0(event_t);
112 cal->event->cal = &cal->cal;
113 if (!cal->first_event) {
114 cal->first_event = cal->event;
115 cal->last_event = cal->event;
117 cal->event->prev = cal->last_event;
118 cal->last_event->next = cal->event;
119 cal->last_event = cal->event;
121 } else if (cal->event) {
122 if (match(tag, "t:Subject"))
123 cal->next_text = &cal->event->name;
124 if (match(tag, "t:Start"))
125 cal->next_date = &cal->event->start;
126 if (match(tag, "t:End"))
127 cal->next_date = &cal->event->end;
131 static void on_end(void *_cal, const char *tag)
138 printf("%*s \"%s\"\n",
139 cal->indent*4+2, "--",
140 (char*)cal->buf.data);
145 if (cal->next_text && cal->buf.len) {
146 *cal->next_text = strcopy(cal->buf.data);
148 if (cal->next_date && cal->buf.len) {
149 int year, month, day, hour, min, sec;
151 int cnt = sscanf(cal->buf.data, "%d-%d-%dT%d:%d:%d%c",
152 &year, &month, &day, &hour, &min, &sec, &zone);
154 error("Error parsing time: [%s]", cal->buf.data);
156 error("Expected UTC timestamp: [%s]", cal->buf.data);
158 .tm_year = year-1900,
165 *cal->next_date = get_date(timegm(&tm));
169 if (match(tag, "t:CalendarItem"))
171 cal->next_text = NULL;
172 cal->next_date = NULL;
176 static void on_data(void *_cal, const char *data, int len)
179 if (cal->debug || cal->next_text || cal->next_date)
180 append(&cal->buf, data, len);
183 static size_t on_write(void *buf, size_t size, size_t n, ews_t *cal)
186 XML_Parse(cal->expat, buf, len, 0);
190 static void sync_ews(ews_t *cal)
194 struct curl_slist *hdr = NULL;
197 debug("Loading EWS:");
198 debug(" type = %s", cal->cal.type);
199 debug(" name = %s", cal->cal.name);
200 debug(" desc = %s", cal->cal.desc);
201 debug(" username = %s", cal->username);
202 debug(" password = %s", cal->password);
203 debug(" location = %s", cal->location);
204 debug(" domain = %s", cal->domain);
207 if (!(cal->expat = XML_ParserCreate(NULL)))
208 error("XML Parser Create");
209 XML_SetUserData(cal->expat, cal);
210 XML_SetStartElementHandler(cal->expat, on_start);
211 XML_SetEndElementHandler(cal->expat, on_end);
212 XML_SetCharacterDataHandler(cal->expat, on_data);
214 /* Setup HTTP request */
215 if (!(cal->curl = curl_easy_init()))
216 error("Curl easy init failed");
217 if (curl_easy_setopt(cal->curl, CURLOPT_URL, cal->location))
218 error("Curl easy setopt failed");
219 if (curl_easy_setopt(cal->curl, CURLOPT_WRITEFUNCTION, on_write))
220 error("Curl easy set write function failed");
221 if (curl_easy_setopt(cal->curl, CURLOPT_WRITEDATA, cal))
222 error("Curl easy set write data failed");
224 /* Skip SSL checks */
225 if (curl_easy_setopt(cal->curl, CURLOPT_SSL_VERIFYPEER, 0L))
226 error("Curl easy set no verify peer failed");
227 if (curl_easy_setopt(cal->curl, CURLOPT_SSL_VERIFYHOST, 0L))
228 error("Curl easy set no verify hosts failed");
231 if (curl_easy_setopt(cal->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY))
232 error("Curl easy set http auth failed");
233 if (curl_easy_setopt(cal->curl, CURLOPT_USERNAME, cal->username))
234 error("Curl easy set username failed");
235 if (curl_easy_setopt(cal->curl, CURLOPT_PASSWORD, cal->password))
236 error("Curl easy set password failed");
238 /* Setup SOAP request */
239 hdr = curl_slist_append(hdr, "Accept: text/xml");
240 hdr = curl_slist_append(hdr, "Content-Type: text/xml");
241 if (curl_easy_setopt(cal->curl, CURLOPT_HTTPHEADER, hdr))
242 error("Curl easy set http header failed");
243 if (curl_easy_setopt(cal->curl, CURLOPT_POST, 1L))
244 error("Curl easy set post failed");
245 if (curl_easy_setopt(cal->curl, CURLOPT_POSTFIELDS, req_calendar))
246 error("Curl easy set post failed");
249 if ((err = curl_easy_perform(cal->curl)))
250 error("Curl easy perform failed: %s", curl_easy_strerror(err));
251 if ((err = curl_easy_getinfo(cal->curl, CURLINFO_RESPONSE_CODE, &status)))
252 error("Curl easy get info failed: %s", curl_easy_strerror(err));
254 /* Output response */
256 printf("EWS -- HTTP Status %ld\n", status);
257 if (cal->debug && !cal->buf.data)
258 printf("EWS -- No Response Data\n");
261 curl_easy_cleanup(cal->curl);
262 XML_ParserFree(cal->expat);
266 void ews_config(const char *group, const char *name, const char *key, const char *value)
268 ews_t *cal = NULL, *last = NULL;
270 /* Make sure it's valid */
271 if (!match(group, "ews") || !name)
274 /* Find existing calendar */
275 for (cal = calendars; cal; last = cal, cal = cal->next)
276 if (match(cal->cal.name, name))
279 /* Create new calendar */
282 cal->cal.type = "ews";
283 cal->cal.name = get_name(name);
290 /* Set calendar values */
291 if (match(key, "location"))
292 cal->location = get_string(value);
293 else if (match(key, "username"))
294 cal->username = get_string(value);
295 else if (match(key, "password"))
296 cal->password = get_string(value);
297 else if (match(key, "domain"))
298 cal->domain = get_string(value);
302 cal_t *ews_cals(void)
304 for (ews_t *cal = calendars; cal; cal = cal->next) {
306 cal->cal.next = &cal->next->cal;
309 return &calendars->cal;
312 /* Event functions */
313 event_t *ews_events(date_t start, date_t end)
315 event_t *events = NULL;
316 for (ews_t *cal = calendars; cal; cal = cal->next)
317 events = merge_events(events, cal->first_event);
318 for (event_t *e = events; e; e = e->next)
319 debug("Event: %s", e->name);
324 todo_t *ews_todos(date_t start, date_t end)
330 void ews_test(char *url, char *user, char *pass)
334 .username = user && user[0] ? user : NULL,
335 .password = pass && pass[0] ? pass : NULL,
340 printf("EWS -- test start\n");
341 if (curl_global_init(CURL_GLOBAL_DEFAULT))
342 error("Curl global init failed");
343 if (!(curlm = curl_multi_init()))
344 error("Curl multi init failed");
346 /* Sync the calendar */
350 curl_multi_cleanup(curlm);
351 curl_global_cleanup();
352 printf("EWS -- test end\n");