f4b0d8d38fc9b8943de839e903e1d08e9773c2bf
[citadel.git] / citadel / modules / extnotify / funambol65.c
1 /*
2  * funambol65.c
3  * Author: Mathew McBride
4  *
5  * This module facilitates notifications to a Funambol server
6  * for push email
7  *
8  * Based on bits of the previous serv_funambol
9  * Contact: <matt@mcbridematt.dhs.org> / <matt@comalies>
10  *
11  * Copyright (c) 2008-2010
12  *
13  * This program is open source software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License version 3.
15  * 
16  * 
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * 
24  * 
25  * 
26  */
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <sys/socket.h>
32 #include <time.h>
33 #include <libcitadel.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <curl/curl.h>
37
38 #include "citadel.h"
39 #include "citadel_dirs.h"
40 #include "clientsocket.h"
41 #include "sysdep.h"
42 #include "config.h"
43 #include "sysdep_decls.h"
44 #include "msgbase.h"
45 #include "ctdl_module.h"
46
47 #include "event_client.h"
48 #include "extnotify.h"
49
50 eNextState EvaluateResult(AsyncIO *IO);
51 eNextState ExtNotifyTerminate(AsyncIO *IO);
52 eNextState ExtNotifyTerminateDB(AsyncIO *IO);
53 eNextState ExtNotifyShutdownAbort(AsyncIO *IO);
54
55 /*
56 * \brief Sends a message to the Funambol server notifying
57 * of new mail for a user
58 * Returns 0 if unsuccessful
59 */
60 int notify_http_server(char *remoteurl,
61                        const char* template, long tlen,
62                        char *user,
63                        char *msgid,
64                        long MsgNum,
65                        NotifyContext *Ctx)
66 {
67         CURLcode sta;
68         char msgnumstr[128];
69         char *buf = NULL;
70         char *SOAPMessage = NULL;
71         char *contenttype = NULL;
72         StrBuf *ReplyBuf;
73         StrBuf *Buf;
74         CURL *chnd;
75         AsyncIO *IO;
76
77         IO = (AsyncIO*) malloc(sizeof(AsyncIO));
78         memset(IO, 0, sizeof(AsyncIO));
79
80         if (! InitcURLIOStruct(IO,
81                                NULL, /* we don't have personal data anymore. */
82                                "Citadel ExtNotify",
83                                EvaluateResult,
84                                ExtNotifyTerminate,
85                                ExtNotifyTerminateDB,
86                                ExtNotifyShutdownAbort))
87         {
88                 syslog(LOG_ALERT, "Unable to initialize libcurl.\n");
89                 goto abort;
90         }
91
92         snprintf(msgnumstr, 128, "%ld", MsgNum);
93
94         if (tlen > 0) {
95                 /* Load the template message. Get mallocs done too */
96                 FILE *Ftemplate = NULL;
97                 const char *mimetype;
98
99                 Ftemplate = fopen(template, "r");
100                 if (Ftemplate == NULL) {
101                         char buf[SIZ];
102
103                         snprintf(buf, SIZ,
104                                  "Cannot load template file %s [%s] "
105                                  "won't send notification\r\n",
106                                  file_funambol_msg,
107                                  strerror(errno));
108                         syslog(LOG_ERR, "%s", buf);
109                         // TODO: once an hour!
110                         CtdlAideMessage(
111                                 buf,
112                                 "External notifier: "
113                                 "unable to find message template!");
114                         goto abort;
115                 }
116                 mimetype = GuessMimeByFilename(template, tlen);
117
118                 buf = malloc(SIZ);
119                 memset(buf, 0, SIZ);
120                 SOAPMessage = malloc(3072);
121                 memset(SOAPMessage, 0, 3072);
122
123                 while(fgets(buf, SIZ, Ftemplate) != NULL) {
124                         strcat(SOAPMessage, buf);
125                 }
126                 fclose(Ftemplate);
127
128                 if (strlen(SOAPMessage) < 0) {
129                         char buf[SIZ];
130
131                         snprintf(buf, SIZ,
132                                  "Cannot load template file %s;"
133                                  " won't send notification\r\n",
134                                  file_funambol_msg);
135                         syslog(LOG_ERR, "%s", buf);
136
137                         CtdlAideMessage(buf, "External notifier: "
138                                         "unable to load message template!");
139                         goto abort;
140                 }
141                 // Do substitutions
142                 help_subst(SOAPMessage, "^notifyuser", user);
143                 help_subst(SOAPMessage, "^syncsource",
144                            config.c_funambol_source);
145                 help_subst(SOAPMessage, "^msgid", msgid);
146                 help_subst(SOAPMessage, "^msgnum", msgnumstr);
147
148                 /* pass our list of custom made headers */
149
150                 contenttype=(char*) malloc(40+strlen(mimetype));
151                 sprintf(contenttype,
152                         "Content-Type: %s; charset=utf-8",
153                         mimetype);
154
155                 IO->HttpReq.headers = curl_slist_append(
156                         IO->HttpReq.headers,
157                         "SOAPAction: \"\"");
158
159                 IO->HttpReq.headers = curl_slist_append(
160                         IO->HttpReq.headers,
161                         contenttype);
162
163                 IO->HttpReq.headers = curl_slist_append(
164                         IO->HttpReq.headers,
165                         "Accept: application/soap+xml, "
166                         "application/mime, multipart/related, text/*");
167
168                 IO->HttpReq.headers = curl_slist_append(
169                         IO->HttpReq.headers,
170                         "Pragma: no-cache");
171
172                 /* Now specify the POST binary data */
173                 IO->HttpReq.PlainPostData = SOAPMessage;
174                 IO->HttpReq.PlainPostDataLen = strlen(SOAPMessage);
175         }
176         else {
177                 help_subst(remoteurl, "^notifyuser", user);
178                 help_subst(remoteurl, "^syncsource", config.c_funambol_source);
179                 help_subst(remoteurl, "^msgid", msgid);
180                 help_subst(remoteurl, "^msgnum", msgnumstr);
181
182                 IO->HttpReq.headers = curl_slist_append(
183                         IO->HttpReq.headers,
184                         "Accept: application/soap+xml, "
185                         "application/mime, multipart/related, text/*");
186
187                 IO->HttpReq.headers = curl_slist_append(
188                         IO->HttpReq.headers,
189                         "Pragma: no-cache");
190         }
191
192         Buf = NewStrBufPlain (remoteurl, -1);
193         ParseURL(&IO->ConnectMe, Buf, 80);
194         FreeStrBuf(&Buf); /* TODO: this is uncool... */
195         CurlPrepareURL(IO->ConnectMe);
196
197         chnd = IO->HttpReq.chnd;
198         OPT(SSL_VERIFYPEER, 0);
199         OPT(SSL_VERIFYHOST, 0);
200
201         QueueCurlContext(IO);
202
203         return 0;
204 abort:
205
206         if (contenttype) free(contenttype);
207         if (SOAPMessage != NULL) free(SOAPMessage);
208         if (buf != NULL) free(buf);
209         FreeStrBuf (&ReplyBuf);
210         return 1;
211 }
212
213
214 eNextState EvaluateResult(AsyncIO *IO)
215 {
216
217         if (IO->HttpReq.httpcode != 200) {
218                 StrBuf *ErrMsg;
219
220                 syslog(LOG_ALERT, "libcurl error %ld: %s\n",
221                               IO->HttpReq.httpcode,
222                               IO->HttpReq.errdesc);
223
224                 ErrMsg = NewStrBufPlain(
225                         HKEY("Error sending your Notification\n"));
226                 StrBufAppendPrintf(ErrMsg, "\nlibcurl error %ld: \n\t\t%s\n",
227                                    IO->HttpReq.httpcode,
228                                    IO->HttpReq.errdesc);
229
230                 StrBufAppendBufPlain(ErrMsg,
231                                      HKEY("\nWas Trying to send: \n"),
232                                      0);
233
234                 StrBufAppendBufPlain(ErrMsg, IO->ConnectMe->PlainUrl, -1, 0);
235                 if (IO->HttpReq.PlainPostDataLen > 0) {
236                         StrBufAppendBufPlain(
237                                 ErrMsg,
238                                 HKEY("\nThe Post document was: \n"),
239                                 0);
240                         StrBufAppendBufPlain(ErrMsg,
241                                              IO->HttpReq.PlainPostData,
242                                              IO->HttpReq.PlainPostDataLen, 0);
243                         StrBufAppendBufPlain(ErrMsg, HKEY("\n\n"), 0);
244                 }
245                 if (StrLength(IO->HttpReq.ReplyData) > 0) {
246                         StrBufAppendBufPlain(
247                                 ErrMsg,
248                                 HKEY("\n\nThe Serverreply was: \n\n"),
249                                 0);
250                         StrBufAppendBuf(ErrMsg, IO->HttpReq.ReplyData, 0);
251                 }
252                 else
253                         StrBufAppendBufPlain(
254                                 ErrMsg,
255                                 HKEY("\n\nThere was no Serverreply.\n\n"),
256                                 0);
257                 ///ExtNotify_PutErrorMessage(Ctx, ErrMsg);
258                 CtdlAideMessage(ChrPtr(ErrMsg),
259                                 "External notifier: "
260                                 "unable to contact notification host!");
261         }
262
263         syslog(LOG_DEBUG, "Funambol notified\n");
264 /*
265         while ((Ctx.NotifyHostList != NULL) && (Ctx.NotifyHostList[i] != NULL))
266                 FreeStrBuf(&Ctx.NotifyHostList[i]);
267
268         if (Ctx.NotifyErrors != NULL)
269         {
270                 long len;
271                 const char *Key;
272                 HashPos *It;
273                 void *vErr;
274                 StrBuf *ErrMsg;
275
276                 It = GetNewHashPos(Ctx.NotifyErrors, 0);
277                 while (GetNextHashPos(Ctx.NotifyErrors,
278                 It, &len, &Key, &vErr) &&
279                        (vErr != NULL)) {
280                         ErrMsg = (StrBuf*) vErr;
281                         quickie_message("Citadel", NULL, NULL,
282                         AIDEROOM, ChrPtr(ErrMsg), FMT_FIXED,
283                         "Failed to notify external service about inbound mail");
284                 }
285
286                 DeleteHashPos(&It);
287                 DeleteHash(&Ctx.NotifyErrors);
288         }
289 */
290
291 ////    curl_slist_free_all (headers);
292 ///     curl_easy_cleanup(curl);
293         ///if (contenttype) free(contenttype);
294         ///if (SOAPMessage != NULL) free(SOAPMessage);
295         ///if (buf != NULL) free(buf);
296         ///FreeStrBuf (&ReplyBuf);
297         return 0;
298 }
299
300 eNextState ExtNotifyTerminateDB(AsyncIO *IO)
301 {
302         free(IO);
303         return eAbort;
304 }
305 eNextState ExtNotifyTerminate(AsyncIO *IO)
306 {
307         free(IO);
308         return eAbort;
309 }
310 eNextState ExtNotifyShutdownAbort(AsyncIO *IO)
311 {
312         free(IO);
313         return eAbort;
314 }