* start implementing sending an error message if the notification fails...
[citadel.git] / citadel / modules / extnotify / funambol65.c
1 /* 
2 * \file 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 #include "extnotify.h"
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <sys/socket.h>
17 #include <time.h>
18 #include <libcitadel.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <curl/curl.h>
22
23 #include "citadel.h"
24 #include "citadel_dirs.h"
25 #include "clientsocket.h"
26 #include "sysdep.h"
27 #include "config.h"
28 #include "sysdep_decls.h"
29 #include "msgbase.h"
30 #include "ctdl_module.h"
31
32 /*
33 * \brief Sends a message to the Funambol server notifying 
34 * of new mail for a user
35 * Returns 0 if unsuccessful
36 */
37 int notify_http_server(char *remoteurl, 
38                        const char* template, long tlen, 
39                        char *user,
40                        char *msgid, 
41                        long MsgNum) 
42 {
43         char curl_errbuf[CURL_ERROR_SIZE];
44         char *pchs, *pche;
45         char userpass[SIZ];
46         char msgnumstr[128];
47         char *buf = NULL;
48         CURL *curl;
49         CURLcode res;
50         struct curl_slist * headers=NULL;
51         char errmsg[1024] = "";
52         char *SOAPMessage = NULL;
53         char *contenttype = NULL;
54         StrBuf *ReplyBuf;
55
56         curl = curl_easy_init();
57         if (!curl) {
58                 CtdlLogPrintf(CTDL_ALERT, "Unable to initialize libcurl.\n");
59                 return 1;
60         }
61
62         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
63         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
64         ReplyBuf = NewStrBuf();
65         curl_easy_setopt(curl, CURLOPT_WRITEDATA, ReplyBuf);
66         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlFillStrBuf_callback);
67         curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errmsg);
68         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
69         curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);
70
71         pchs = strchr(remoteurl, ':');
72         pche = strchr(remoteurl, '@');
73         if ((pche != NULL) && 
74             (pchs != NULL) && 
75             (pchs < pche) && ((pche - pchs) < SIZ)) {
76                 memcpy(userpass, pchs + 3, pche - pchs - 3);
77                 
78                 userpass[pche - pchs - 3] = '\0';
79                 curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
80                 curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
81
82         }
83 #ifdef CURLOPT_HTTP_CONTENT_DECODING
84         curl_easy_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 1);
85         curl_easy_setopt(curl, CURLOPT_ENCODING, "");
86 #endif
87         curl_easy_setopt(curl, CURLOPT_USERAGENT, CITADEL);
88         curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);           /* die after 180 seconds */
89         if (!IsEmptyStr(config.c_ip_addr)) {
90                 curl_easy_setopt(curl, CURLOPT_INTERFACE, config.c_ip_addr);
91         }
92
93         headers = curl_slist_append(headers,"Accept: application/soap+xml, application/dime, multipart/related, text/*");
94         headers = curl_slist_append(headers,"Pragma: no-cache");
95
96         if (tlen > 0) {
97                 /* Load the template message. Get mallocs done too */
98                 FILE *Ftemplate = NULL;
99                 const char *mimetype;
100
101                 Ftemplate = fopen(template, "r");
102                 if (Ftemplate == NULL) {
103                         char buf[SIZ];
104
105                         snprintf(buf, SIZ, 
106                                  "Cannot load template file %s [%s]won't send notification\r\n", 
107                                  file_funambol_msg, strerror(errno));
108                         CtdlLogPrintf(CTDL_ERR, buf);
109
110                         aide_message(buf, "External notifier unable to find message template!");
111                         goto free;
112                 }
113                 mimetype = GuessMimeByFilename(template, tlen);
114
115                 snprintf(msgnumstr, 128, "%ld", MsgNum);
116
117                 buf = malloc(SIZ);
118                 memset(buf, 0, SIZ);
119                 SOAPMessage = malloc(3072);
120                 memset(SOAPMessage, 0, 3072);
121         
122                 while(fgets(buf, SIZ, Ftemplate) != NULL) {
123                         strcat(SOAPMessage, buf);
124                 }
125                 fclose(Ftemplate);
126         
127                 if (strlen(SOAPMessage) < 0) {
128                         char buf[SIZ];
129
130                         snprintf(buf, SIZ, 
131                                  "Cannot load template file %s; won't send notification\r\n", 
132                                  file_funambol_msg);
133                         CtdlLogPrintf(CTDL_ERR, buf);
134
135                         aide_message(buf, "External notifier unable to load message template!");
136                         goto free;
137                 }
138                 // Do substitutions
139                 help_subst(SOAPMessage, "^notifyuser", user);
140                 help_subst(SOAPMessage, "^syncsource", config.c_funambol_source);
141                 help_subst(SOAPMessage, "^msgid", msgid);
142                 help_subst(SOAPMessage, "^msgnum", msgnumstr);
143
144                 curl_easy_setopt(curl, CURLOPT_URL, remoteurl);
145
146                 /* pass our list of custom made headers */
147
148                 contenttype=(char*) malloc(40+strlen(mimetype));
149                 sprintf(contenttype,"Content-type: %s; charset=utf-8", mimetype);
150
151                 headers = curl_slist_append(headers, "SOAPAction: \"\"");
152                 headers = curl_slist_append(headers, contenttype);
153
154                 /* Now specify the POST binary data */
155
156                 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, SOAPMessage);
157                 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(SOAPMessage));
158                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
159         }
160         else {
161                 help_subst(remoteurl, "^notifyuser", user);
162                 help_subst(remoteurl, "^syncsource", config.c_funambol_source);
163                 help_subst(remoteurl, "^msgid", msgid);
164                 help_subst(remoteurl, "^msgnum", msgnumstr);
165                 curl_easy_setopt(curl, CURLOPT_URL, remoteurl);
166                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
167         }
168
169         res = curl_easy_perform(curl);
170         if (res) {
171                 StrBuf *ErrMsg;
172
173                 CtdlLogPrintf(CTDL_ALERT, "libcurl error %d: %s\n", res, errmsg);
174                 ErrMsg = NewStrBufPlain(HKEY("Error sending your Notification\n"));
175                 StrBufAppendPrintf(ErrMsg, "\nlibcurl error %d: %s\n", res, errmsg);
176                 StrBufAppendBufPlain(ErrMsg, curl_errbuf, -1, 0);
177                 StrBufAppendBufPlain(ErrMsg, HKEY("\nWas Trying to send: \n"), 0);
178                 StrBufAppendBufPlain(ErrMsg, remoteurl, -1, 0);
179                 if (tlen > 0) {
180                         StrBufAppendBufPlain(ErrMsg, HKEY("\nThe Post document was: \n"), 0);
181                         StrBufAppendBufPlain(ErrMsg, SOAPMessage, -1, 0);
182                         StrBufAppendBufPlain(ErrMsg, HKEY("\n\n"), 0);                  
183                 }
184                 if (StrLength(ReplyBuf) > 0) {                  
185                         StrBufAppendBufPlain(ErrMsg, HKEY("\n\nThe Serverreply was: \n\n"), 0);
186                         StrBufAppendBuf(ErrMsg, ReplyBuf, 0);
187                 }
188                 else 
189                         StrBufAppendBufPlain(ErrMsg, HKEY("\n\nThere was no Serverreply.\n\n"), 0);
190 /* TODO: this will change the floor we're in :(
191                 quickie_message("Citadel", NULL, NULL, AIDEROOM, ChrPtr(ErrMsg), FMT_FIXED, 
192                                 "Failed to notify external service about inbound mail");
193 */
194                 FreeStrBuf(&ErrMsg);
195         }
196
197         CtdlLogPrintf(CTDL_DEBUG, "Funambol notified\n");
198 free:
199         curl_slist_free_all (headers);
200         curl_easy_cleanup(curl);
201         if (contenttype) free(contenttype);
202         if (SOAPMessage != NULL) free(SOAPMessage);
203         if (buf != NULL) free(buf);
204         FreeStrBuf (&ReplyBuf);
205         return 0;
206 }