* migrate extnotify to libcurl
[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                        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;
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                 mimetype = GuessMimeByFilename(template, tlen);
118                 if (template == NULL) {
119                         char buf[SIZ];
120
121                         snprintf(buf, SIZ, 
122                                  "Cannot load template file %s [%s]won't send notification\r\n", 
123                                  file_funambol_msg, strerror(errno));
124                         CtdlLogPrintf(CTDL_ERR, buf);
125
126                         aide_message(buf, "External notifier unable to find message template!");
127                         goto free;
128                 }
129                 snprintf(msgnumstr, 128, "%ld", MsgNum);
130
131                 buf = malloc(SIZ);
132                 memset(buf, 0, SIZ);
133                 SOAPMessage = malloc(3072);
134                 memset(SOAPMessage, 0, 3072);
135         
136                 while(fgets(buf, SIZ, Ftemplate) != NULL) {
137                         strcat(SOAPMessage, buf);
138                 }
139                 fclose(Ftemplate);
140         
141                 if (strlen(SOAPMessage) < 0) {
142                         char buf[SIZ];
143
144                         snprintf(buf, SIZ, 
145                                  "Cannot load template file %s; won't send notification\r\n", 
146                                  file_funambol_msg);
147                         CtdlLogPrintf(CTDL_ERR, buf);
148
149                         aide_message(buf, "External notifier unable to load message template!");
150                         goto free;
151                 }
152                 // Do substitutions
153                 help_subst(SOAPMessage, "^notifyuser", user);
154                 help_subst(SOAPMessage, "^syncsource", config.c_funambol_source);
155                 help_subst(SOAPMessage, "^msgid", msgid);
156                 help_subst(SOAPMessage, "^msgnum", msgnumstr);
157
158                 curl_easy_setopt(curl, CURLOPT_URL, remoteurl);
159
160                 /* pass our list of custom made headers */
161
162                 contenttype=(char*) malloc(40+strlen(mimetype));
163                 sprintf(contenttype,"Content-type: %s; charset=utf-8", mimetype);
164
165                 headers = curl_slist_append(headers, "SOAPAction: \"\"");
166                 headers = curl_slist_append(headers, contenttype);
167
168                 /* Now specify the POST binary data */
169
170                 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, SOAPMessage);
171                 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(SOAPMessage));
172                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
173         }
174         else {
175                 help_subst(remoteurl, "^notifyuser", user);
176                 help_subst(remoteurl, "^syncsource", config.c_funambol_source);
177                 help_subst(remoteurl, "^msgid", msgid);
178                 help_subst(remoteurl, "^msgnum", msgnumstr);
179                 curl_easy_setopt(curl, CURLOPT_URL, remoteurl);
180                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
181         }
182
183         res = curl_easy_perform(curl);
184         if (res) {
185                 CtdlLogPrintf(CTDL_ALERT, "libcurl error %d: %s\n", res, errmsg);
186         }
187
188         CtdlLogPrintf(CTDL_DEBUG, "Funambol notified\n");
189 free:
190         curl_slist_free_all (headers);
191         curl_easy_cleanup(curl);
192         if (contenttype) free(contenttype);
193         if (SOAPMessage != NULL) free(SOAPMessage);
194         if (buf != NULL) free(buf);
195         return 0;
196 }
197
198
199 /*      
200         sprintf(port, "%d", config.c_funambol_port);
201         sock = sock_connect(config.c_funambol_host, port, "tcp");
202         if (sock >= 0) 
203                 CtdlLogPrintf(CTDL_DEBUG, "Connected to Funambol!\n");
204         else {
205                 char buf[SIZ];
206
207                 snprintf(buf, SIZ, 
208                          "Unable to connect to %s:%d [%s]; won't send notification\r\n", 
209                          config.c_funambol_host, 
210                          config.c_funambol_port, 
211                          strerror(errno));
212                 CtdlLogPrintf(CTDL_ERR, buf);
213
214                 aide_message(buf, "External notifier unable to connect remote host!");
215                 goto bail;
216         }
217 */
218 //      if (funambolCreds != NULL) free(funambolCreds);
219         //if (SOAPHeader != NULL) free(SOAPHeader);
220         ///close(sock);
221
222         /* Build the HTTP request header */
223
224         
225 /*
226         sprintf(SOAPHeader, "POST %s HTTP/1.0\r\nContent-type: text/xml; charset=utf-8\r\n",
227                 FUNAMBOL_WS);
228         strcat(SOAPHeader,"Accept: application/soap+xml, application/dime, multipart/related, text/*\r\n");
229         sprintf(buf, "User-Agent: %s/%d\r\nHost: %s:%d\r\nCache-control: no-cache\r\n",
230                 "Citadel",
231                 REV_LEVEL,
232                 config.c_funambol_host,
233                 config.c_funambol_port
234                 );
235         strcat(SOAPHeader,buf);
236         strcat(SOAPHeader,"Pragma: no-cache\r\nSOAPAction: \"\"\r\n");
237         sprintf(buf, "Content-Length: %d \r\n",
238                 strlen(SOAPMessage));
239         strcat(SOAPHeader, buf);
240 */
241         
242 /*      funambolCreds = malloc(strlen(config.c_funambol_auth)*2);
243         memset(funambolCreds, 0, strlen(config.c_funambol_auth)*2);
244         CtdlEncodeBase64(funambolCreds, config.c_funambol_auth, strlen(config.c_funambol_auth), 0);     
245         sprintf(buf, "Authorization: Basic %s\r\n\r\n",
246                 funambolCreds);
247         strcat(SOAPHeader, buf);
248         
249         sock_write(sock, SOAPHeader, strlen(SOAPHeader));
250         sock_write(sock, SOAPMessage, strlen(SOAPMessage));
251         sock_shutdown(sock, SHUT_WR);
252         
253         / * Response * /
254         CtdlLogPrintf(CTDL_DEBUG, "Awaiting response\n");
255         if (sock_getln(sock, buf, SIZ) < 0) {
256                 goto free;
257         }
258         CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
259         if (strncasecmp(buf, "HTTP/1.1 200 OK", strlen("HTTP/1.1 200 OK"))) {
260                 
261                 goto free;
262         }
263 */