* add support for custom notifiers
[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
34
35 size_t extnotify_callback(void *ptr, size_t size, size_t nmemb, void *stream)
36 {
37         return size * nmemb; /* don't care, just discard it so it doesn't end up on the console... */
38 }
39 struct fh_data {
40         char *buf;
41         int total_bytes_received;
42         int maxbytes;
43 };
44
45 /*
46 * \brief Sends a message to the Funambol server notifying 
47 * of new mail for a user
48 * Returns 0 if unsuccessful
49 */
50 int notify_http_server(char *remoteurl, 
51                        const char* template, long tlen, 
52                        char *user,
53                        char *msgid, 
54                        long MsgNum) 
55 {
56         char *pchs, *pche;
57         char userpass[SIZ];
58         char retbuf[SIZ];
59         char msgnumstr[128];
60         char *buf = NULL;
61         CURL *curl;
62         CURLcode res;
63         struct curl_slist * headers=NULL;
64         char errmsg[1024] = "";
65         char *SOAPMessage = NULL;
66         char *contenttype = NULL;
67         struct fh_data fh = {
68                 retbuf,
69                 0,
70                 SIZ
71         };
72                 
73         curl = curl_easy_init();
74         if (!curl) {
75                 CtdlLogPrintf(CTDL_ALERT, "Unable to initialize libcurl.\n");
76                 return 1;
77         }
78
79         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
80         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
81         curl_easy_setopt(curl, CURLOPT_WRITEDATA, fh);
82         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, extnotify_callback); /* don't care..*/
83         curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errmsg);
84         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
85
86         pchs = strchr(remoteurl, ':');
87         pche = strchr(remoteurl, '@');
88         if ((pche != NULL) && 
89             (pchs != NULL) && 
90             (pchs < pche) && ((pche - pchs) < SIZ)) {
91                 memcpy(userpass, pchs + 3, pche - pchs - 3);
92                 
93                 userpass[pche - pchs - 3] = '\0';
94                 curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
95                 curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
96
97         }
98 #ifdef CURLOPT_HTTP_CONTENT_DECODING
99         curl_easy_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 1);
100         curl_easy_setopt(curl, CURLOPT_ENCODING, "");
101 #endif
102         curl_easy_setopt(curl, CURLOPT_USERAGENT, CITADEL);
103         curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);           /* die after 180 seconds */
104         if (!IsEmptyStr(config.c_ip_addr)) {
105                 curl_easy_setopt(curl, CURLOPT_INTERFACE, config.c_ip_addr);
106         }
107
108         headers = curl_slist_append(headers,"Accept: application/soap+xml, application/dime, multipart/related, text/*");
109         headers = curl_slist_append(headers,"Pragma: no-cache");
110
111         if (tlen > 0) {
112                 /* Load the template message. Get mallocs done too */
113                 FILE *Ftemplate = NULL;
114                 const char *mimetype;
115
116                 Ftemplate = fopen(template, "r");
117                 if (Ftemplate == NULL) {
118                         char buf[SIZ];
119
120                         snprintf(buf, SIZ, 
121                                  "Cannot load template file %s [%s]won't send notification\r\n", 
122                                  file_funambol_msg, strerror(errno));
123                         CtdlLogPrintf(CTDL_ERR, buf);
124
125                         aide_message(buf, "External notifier unable to find message template!");
126                         goto free;
127                 }
128                 mimetype = GuessMimeByFilename(template, tlen);
129
130                 snprintf(msgnumstr, 128, "%ld", MsgNum);
131
132                 buf = malloc(SIZ);
133                 memset(buf, 0, SIZ);
134                 SOAPMessage = malloc(3072);
135                 memset(SOAPMessage, 0, 3072);
136         
137                 while(fgets(buf, SIZ, Ftemplate) != NULL) {
138                         strcat(SOAPMessage, buf);
139                 }
140                 fclose(Ftemplate);
141         
142                 if (strlen(SOAPMessage) < 0) {
143                         char buf[SIZ];
144
145                         snprintf(buf, SIZ, 
146                                  "Cannot load template file %s; won't send notification\r\n", 
147                                  file_funambol_msg);
148                         CtdlLogPrintf(CTDL_ERR, buf);
149
150                         aide_message(buf, "External notifier unable to load message template!");
151                         goto free;
152                 }
153                 // Do substitutions
154                 help_subst(SOAPMessage, "^notifyuser", user);
155                 help_subst(SOAPMessage, "^syncsource", config.c_funambol_source);
156                 help_subst(SOAPMessage, "^msgid", msgid);
157                 help_subst(SOAPMessage, "^msgnum", msgnumstr);
158
159                 curl_easy_setopt(curl, CURLOPT_URL, remoteurl);
160
161                 /* pass our list of custom made headers */
162
163                 contenttype=(char*) malloc(40+strlen(mimetype));
164                 sprintf(contenttype,"Content-type: %s; charset=utf-8", mimetype);
165
166                 headers = curl_slist_append(headers, "SOAPAction: \"\"");
167                 headers = curl_slist_append(headers, contenttype);
168
169                 /* Now specify the POST binary data */
170
171                 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, SOAPMessage);
172                 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(SOAPMessage));
173                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
174         }
175         else {
176                 help_subst(remoteurl, "^notifyuser", user);
177                 help_subst(remoteurl, "^syncsource", config.c_funambol_source);
178                 help_subst(remoteurl, "^msgid", msgid);
179                 help_subst(remoteurl, "^msgnum", msgnumstr);
180                 curl_easy_setopt(curl, CURLOPT_URL, remoteurl);
181                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
182         }
183
184         res = curl_easy_perform(curl);
185         if (res) {
186                 CtdlLogPrintf(CTDL_ALERT, "libcurl error %d: %s\n", res, errmsg);
187         }
188
189         CtdlLogPrintf(CTDL_DEBUG, "Funambol notified\n");
190 free:
191         curl_slist_free_all (headers);
192         curl_easy_cleanup(curl);
193         if (contenttype) free(contenttype);
194         if (SOAPMessage != NULL) free(SOAPMessage);
195         if (buf != NULL) free(buf);
196         return 0;
197 }
198
199
200 /*      
201         sprintf(port, "%d", config.c_funambol_port);
202         sock = sock_connect(config.c_funambol_host, port, "tcp");
203         if (sock >= 0) 
204                 CtdlLogPrintf(CTDL_DEBUG, "Connected to Funambol!\n");
205         else {
206                 char buf[SIZ];
207
208                 snprintf(buf, SIZ, 
209                          "Unable to connect to %s:%d [%s]; won't send notification\r\n", 
210                          config.c_funambol_host, 
211                          config.c_funambol_port, 
212                          strerror(errno));
213                 CtdlLogPrintf(CTDL_ERR, buf);
214
215                 aide_message(buf, "External notifier unable to connect remote host!");
216                 goto bail;
217         }
218 */
219 //      if (funambolCreds != NULL) free(funambolCreds);
220         //if (SOAPHeader != NULL) free(SOAPHeader);
221         ///close(sock);
222
223         /* Build the HTTP request header */
224
225         
226 /*
227         sprintf(SOAPHeader, "POST %s HTTP/1.0\r\nContent-type: text/xml; charset=utf-8\r\n",
228                 FUNAMBOL_WS);
229         strcat(SOAPHeader,"Accept: application/soap+xml, application/dime, multipart/related, text/*\r\n");
230         sprintf(buf, "User-Agent: %s/%d\r\nHost: %s:%d\r\nCache-control: no-cache\r\n",
231                 "Citadel",
232                 REV_LEVEL,
233                 config.c_funambol_host,
234                 config.c_funambol_port
235                 );
236         strcat(SOAPHeader,buf);
237         strcat(SOAPHeader,"Pragma: no-cache\r\nSOAPAction: \"\"\r\n");
238         sprintf(buf, "Content-Length: %d \r\n",
239                 strlen(SOAPMessage));
240         strcat(SOAPHeader, buf);
241 */
242         
243 /*      funambolCreds = malloc(strlen(config.c_funambol_auth)*2);
244         memset(funambolCreds, 0, strlen(config.c_funambol_auth)*2);
245         CtdlEncodeBase64(funambolCreds, config.c_funambol_auth, strlen(config.c_funambol_auth), 0);     
246         sprintf(buf, "Authorization: Basic %s\r\n\r\n",
247                 funambolCreds);
248         strcat(SOAPHeader, buf);
249         
250         sock_write(sock, SOAPHeader, strlen(SOAPHeader));
251         sock_write(sock, SOAPMessage, strlen(SOAPMessage));
252         sock_shutdown(sock, SHUT_WR);
253         
254         / * Response * /
255         CtdlLogPrintf(CTDL_DEBUG, "Awaiting response\n");
256         if (sock_getln(sock, buf, SIZ) < 0) {
257                 goto free;
258         }
259         CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
260         if (strncasecmp(buf, "HTTP/1.1 200 OK", strlen("HTTP/1.1 200 OK"))) {
261                 
262                 goto free;
263         }
264 */