Work on integrating libcurl <-> libev
authorWilfried Goesgens <dothebart@citadel.org>
Tue, 3 May 2011 19:52:05 +0000 (19:52 +0000)
committerWilfried Goesgens <dothebart@citadel.org>
Tue, 3 May 2011 19:52:05 +0000 (19:52 +0000)
citadel/modules/curl/serv_curl.c [new file with mode: 0644]
citadel/modules/curl/serv_curl.h [new file with mode: 0644]
citadel/modules/extnotify/extnotify.h
citadel/modules/extnotify/extnotify_main.c
citadel/modules/extnotify/funambol65.c

diff --git a/citadel/modules/curl/serv_curl.c b/citadel/modules/curl/serv_curl.c
new file mode 100644 (file)
index 0000000..a8db1f2
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 1998-2009 by the citadel.org team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  thanks to some guy in #libev
+ */
+
+#include "sysdep.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pwd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <syslog.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include <sys/wait.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <libcitadel.h>
+#include "citadel.h"
+#include "server.h"
+#include "citserver.h"
+#include "support.h"
+
+#include "ctdl_module.h"
+#include "serv_curl.h"
+
+evcurl_global_data global;
+
+
+extern struct ev_loop *event_base;
+
+void SockStateCb(void *data, int sock, int read, int write);
+
+#define MOPT(s, v) \
+       do {                                                        \
+       sta = curl_multi_setopt(mhnd, (CURLMOPT_##s), (v));         \
+       if (sta) {                                                  \
+               CtdlLogPrintf(CTDL_ERR, "error setting option " #s " on curl multi handle: %s\n", curl_easy_strerror(sta)); \
+               exit (1);                                           \
+       }                                                           \
+} while (0)
+
+
+void ____InitC_ares_dns(AsyncIO *IO)
+{
+       int optmask = 0;
+       if (IO->DNSChannel == NULL) {
+               optmask |= ARES_OPT_SOCK_STATE_CB;
+               IO->DNSOptions.sock_state_cb = SockStateCb;
+               IO->DNSOptions.sock_state_cb_data = IO;
+               ares_init_options(&IO->DNSChannel, &IO->DNSOptions, optmask);
+       }
+}
+
+
+
+/*****************************************************************************
+ *                   libevent / c-ares integration                           *
+ *****************************************************************************/
+static void ____DNS_send_callback(struct ev_loop *loop, ev_io *watcher, int revents)
+{
+       AsyncIO *IO = watcher->data;
+       
+       ares_process_fd(IO->DNSChannel, ARES_SOCKET_BAD, IO->dns_send_event.fd);
+}
+static void ____DNS_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents)
+{
+       AsyncIO *IO = watcher->data;
+       
+       ares_process_fd(IO->DNSChannel, IO->dns_recv_event.fd, ARES_SOCKET_BAD);
+}
+
+void ____SockStateCb(void *data, int sock, int read, int write) 
+{
+/*
+       struct timeval tvbuf, maxtv, *ret;
+       
+       int64_t time = 10;
+*/
+       AsyncIO *IO = data;
+/* already inside of the event queue. */       
+
+       if (read) {
+               if ((IO->dns_recv_event.fd != sock) &&
+                   (IO->dns_recv_event.fd != 0)) {
+                       ev_io_stop(event_base, &IO->dns_recv_event);
+               }
+               IO->dns_recv_event.fd = sock;
+               ev_io_init(&IO->dns_recv_event, ____DNS_recv_callback, IO->dns_recv_event.fd, EV_READ);
+               IO->dns_recv_event.data = IO;
+               ev_io_start(event_base, &IO->dns_recv_event);
+       } 
+       if (write) {
+               if ((IO->dns_send_event.fd != sock) &&
+                   (IO->dns_send_event.fd != 0)) {
+                       ev_io_stop(event_base, &IO->dns_send_event);
+               }
+               IO->dns_send_event.fd = sock;
+               ev_io_init(&IO->dns_send_event, ____DNS_send_callback, IO->dns_send_event.fd, EV_WRITE);
+               IO->dns_send_event.data = IO;
+               ev_io_start(event_base, &IO->dns_send_event);
+       }
+/*
+
+               ev_io_start(event_base, &IO->dns_io_event);
+       
+               maxtv.tv_sec = time/1000;
+               maxtv.tv_usec = (time % 1000) * 1000;
+               
+               ret = ares_timeout(IO->DNSChannel, &maxtv, &tvbuf);
+       }
+*/
+       if ((read == 0) && (write == 0)) {
+               ev_io_stop(event_base, &IO->dns_recv_event);
+               ev_io_stop(event_base, &IO->dns_send_event);
+       }
+}
+
+
+
+
+
+
+static void
+gotstatus(evcurl_global_data *global, int nnrun) 
+{
+       CURLM *mhnd;
+       CURLMsg *msg;
+       int nmsg;
+/*
+       if (EVCURL_GLOBAL_MAGIC != global.magic)
+       {
+               CtdlLogPrintf(CTDL_ERR, "internal error: gotstatus on wrong struct");
+               return;
+       }
+*/
+       global->nrun = nnrun;
+       mhnd = global->mhnd;
+
+       CtdlLogPrintf(CTDL_ERR, "about to call curl_multi_info_read\n");
+       while ((msg = curl_multi_info_read(mhnd, &nmsg))) {
+               CtdlLogPrintf(CTDL_ERR, "got curl multi_info message msg=%d", msg->msg);
+               if (CURLMSG_DONE == msg->msg) {
+                       CtdlLogPrintf(CTDL_ERR, "request complete\n");
+                       CURL *chnd = msg->easy_handle;
+                       char *chandle;
+                       CURLcode sta = curl_easy_getinfo(chnd, CURLINFO_PRIVATE, &chandle);
+                       if (sta)
+                               CtdlLogPrintf(CTDL_ERR, "error asking curl for private cookie of curl handle: %s\n", curl_easy_strerror(sta));
+                       evcurl_request_data  *handle = (void *)chandle;
+                       if (global != handle->global || chnd != handle->chnd)
+                               CtdlLogPrintf(CTDL_ERR, "internal evcurl error: unknown curl handle completed\n");
+                       sta = msg->data.result;
+                       if (sta) {
+                               CtdlLogPrintf(CTDL_ERR, "error description: %s\n", handle->errdesc);
+                               CtdlLogPrintf(CTDL_ERR, "error performing request: %s\n", curl_easy_strerror(sta));
+                       }
+                       long httpcode;
+                       sta = curl_easy_getinfo(chnd, CURLINFO_RESPONSE_CODE, &httpcode);
+                       if (sta)
+                               CtdlLogPrintf(CTDL_ERR, "error asking curl for response code from request: %s\n", curl_easy_strerror(sta));
+                       CtdlLogPrintf(CTDL_ERR, "http response code was %ld\n", (long)httpcode);
+                       CURLMcode msta = curl_multi_remove_handle(mhnd, chnd);
+                       if (msta)
+                               CtdlLogPrintf(CTDL_ERR, "warning problem detaching completed handle from curl multi: %s\n", curl_multi_strerror(msta));
+                       handle->attached = 0;
+               }
+       }
+       if (0 == nnrun) {
+               ev_unloop(EV_DEFAULT, EVUNLOOP_ONE); /* remove in production */
+       }
+}
+
+static void
+stepmulti(evcurl_global_data *global, curl_socket_t fd) {
+       int nnrun;
+       CURLMcode msta = curl_multi_socket_action(global->mhnd, fd, 0, &nnrun);
+       if (msta)
+               CtdlLogPrintf(CTDL_ERR, "error in curl processing events on multi handle, fd %d: %s\n", (int)fd, curl_multi_strerror(msta));
+       if (global->nrun != nnrun)
+               gotstatus(global, nnrun);
+}
+
+static void
+gottime(struct ev_loop *loop, ev_timer *timeev, int events) {
+       CtdlLogPrintf(CTDL_ERR,"waking up curl for timeout\n");
+       evcurl_global_data *global = (void *)timeev->data;
+       stepmulti(global, CURL_SOCKET_TIMEOUT);
+}
+
+static void
+gotio(struct ev_loop *loop, ev_io *ioev, int events) {
+       CtdlLogPrintf(CTDL_ERR,"waking up curl for io on fd %d\n", (int)ioev->fd);
+       sockwatcher_data *sockwatcher = (void *)ioev->data;
+       stepmulti(sockwatcher->global, ioev->fd);
+}
+
+static size_t
+gotdata(void *data, size_t size, size_t nmemb, void *cglobal) {
+       evcurl_request_data *D = (evcurl_request_data*) data;
+       return CurlFillStrBuf_callback(D->ReplyData, size, nmemb, cglobal);
+}
+
+static int
+gotwatchtime(CURLM *multi, long tblock_ms, void *cglobal) {
+       CtdlLogPrintf(CTDL_ERR,"gotwatchtime called %ld ms\n", tblock_ms);
+       evcurl_global_data *global = cglobal;
+       ev_timer_stop(EV_DEFAULT, &global->timeev);
+       if (tblock_ms < 0 || 14000 < tblock_ms)
+               tblock_ms = 14000;
+       ev_timer_set(&global->timeev, 0.5e-3 + 1.0e-3 * tblock_ms, 14.0);
+       ev_timer_start(EV_DEFAULT_UC, &global->timeev);
+       return 0;
+}
+
+static int
+gotwatchsock(CURL *easy, curl_socket_t fd, int action, void *cglobal, void *csockwatcher) {
+       evcurl_global_data *global = cglobal;
+       CURLM *mhnd = global->mhnd;
+       CtdlLogPrintf(CTDL_ERR,"gotwatchsock called fd=%d action=%d\n", (int)fd, action);
+       sockwatcher_data *sockwatcher = csockwatcher;
+       if (!sockwatcher) {
+               CtdlLogPrintf(CTDL_ERR,"called first time to register this sockwatcker\n");
+               sockwatcher = malloc(sizeof(sockwatcher_data));
+               sockwatcher->global = global;
+               ev_init(&sockwatcher->ioev, &gotio);
+               sockwatcher->ioev.data = (void *)sockwatcher;
+               curl_multi_assign(mhnd, fd, sockwatcher);
+       }
+       if (CURL_POLL_REMOVE == action) {
+               CtdlLogPrintf(CTDL_ERR,"called last time to unregister this sockwatcher\n");
+               free(sockwatcher);
+       } else {
+               int events = (action & CURL_POLL_IN ? EV_READ : 0) | (action & CURL_POLL_OUT ? EV_WRITE : 0);
+               ev_io_stop(EV_DEFAULT, &sockwatcher->ioev);
+               if (events) {
+                       ev_io_set(&sockwatcher->ioev, fd, events);
+                       ev_io_start(EV_DEFAULT, &sockwatcher->ioev);
+               }
+       }
+       return 0;
+}
+
+void curl_init_connectionpool(void) 
+{
+       CURLM *mhnd ;
+//     global.magic = EVCURL_GLOBAL_MAGIC;
+
+       ev_timer_init(&global.timeev, &gottime, 14.0, 14.0);
+       global.timeev.data = (void *)&global;
+       global.nrun = -1;
+       CURLcode sta = curl_global_init(CURL_GLOBAL_ALL);
+               /* note: probably replace with curl_global_init_mem if used with perl */
+       if (sta) 
+       {
+               CtdlLogPrintf(CTDL_ERR,"error initializing curl library: %s\n", curl_easy_strerror(sta));
+               exit(1);
+       }
+/*
+       if (!ev_default_loop(EVFLAG_AUTO))
+       {
+               CtdlLogPrintf(CTDL_ERR,"error initializing libev\n");
+               exit(2);
+       }
+*/
+       mhnd = global.mhnd = curl_multi_init();
+       if (!mhnd)
+       {
+               CtdlLogPrintf(CTDL_ERR,"error initializing curl multi handle\n");
+               exit(3);
+       }
+
+       MOPT(SOCKETFUNCTION, &gotwatchsock);
+       MOPT(SOCKETDATA, (void *)&global);
+       MOPT(TIMERFUNCTION, &gotwatchtime);
+       MOPT(TIMERDATA, (void *)&global);
+
+       /* well, just there to fire the sample request?*/
+       ev_timer_start(EV_DEFAULT, &global.timeev);
+       return;
+}
+
+
+
+
+int evcurl_init(evcurl_request_data *handle, 
+               void *CustomData, 
+               const char* Desc,
+               int CallBack) 
+{
+       CURLcode sta;
+       CURL *chnd;
+
+       handle->global = &global;
+       handle->attached = 0;
+       chnd = handle->chnd = curl_easy_init();
+       if (!chnd)
+       {
+               CtdlLogPrintf(CTDL_ERR, "error initializing curl handle\n");
+               return 1;
+       }
+
+       strcpy(handle->errdesc, Desc);
+
+       OPT(VERBOSE, (long)1);
+               /* unset in production */
+       OPT(NOPROGRESS, (long)1); 
+       OPT(NOSIGNAL, (long)1);
+       OPT(FAILONERROR, (long)1);
+       OPT(ENCODING, "");
+       OPT(FOLLOWLOCATION, (long)1);
+       OPT(MAXREDIRS, (long)7);
+       OPT(USERAGENT, CITADEL);
+
+       OPT(TIMEOUT, (long)1800);
+       OPT(LOW_SPEED_LIMIT, (long)64);
+       OPT(LOW_SPEED_TIME, (long)600);
+       OPT(CONNECTTIMEOUT, (long)600); 
+       OPT(PRIVATE, (void *)handle);
+
+
+       OPT(WRITEFUNCTION, &gotdata); 
+       OPT(WRITEDATA, (void *)handle);
+       OPT(ERRORBUFFER, handle->errdesc);
+
+               /* point to a structure that points back to the perl structure and stuff */
+       OPT(URL, handle->URL->PlainUrl);
+       if (StrLength(handle->URL->CurlCreds))
+       {
+               OPT(HTTPAUTH, (long)CURLAUTH_BASIC);
+               OPT(USERPWD, ChrPtr(handle->URL->CurlCreds));
+       }
+#ifdef CURLOPT_HTTP_CONTENT_DECODING
+       OPT(HTTP_CONTENT_DECODING, 1);
+       OPT(ENCODING, "");
+#endif
+       if (StrLength(handle->PostData) > 0)
+       { 
+               OPT(POSTFIELDS, ChrPtr(handle->PostData));
+               OPT(POSTFIELDSIZE, StrLength(handle->PostData));
+
+       }
+       else if ((handle->PlainPostDataLen != 0) && (handle->PlainPostData != NULL))
+       {
+               OPT(POSTFIELDS, handle->PlainPostData);
+               OPT(POSTFIELDSIZE, handle->PlainPostDataLen);
+       }
+
+       if (handle->headers != NULL)
+               OPT(HTTPHEADER, handle->headers);
+
+       return 1;
+}
+
+void
+evcurl_handle_start(evcurl_request_data *handle) 
+{
+       CURLMcode msta = curl_multi_add_handle(handle->global->mhnd, handle->chnd);
+       if (msta)
+               CtdlLogPrintf(CTDL_ERR, "error attaching to curl multi handle: %s\n", curl_multi_strerror(msta));
+       handle->attached = 1;
+}
+
+
+
+CTDL_MODULE_INIT(curl_client)
+{
+       if (!threading)
+       {
+               curl_init_connectionpool();
+/*
+               int r = ares_library_init(ARES_LIB_INIT_ALL);
+               if (0 != r) {
+                       // TODO
+                       // ThrowException(Exception::Error(String::New(ares_strerror(r))));
+////                   assert(r == 0);
+               }
+*/     }
+       return "curl";
+}
diff --git a/citadel/modules/curl/serv_curl.h b/citadel/modules/curl/serv_curl.h
new file mode 100644 (file)
index 0000000..295e328
--- /dev/null
@@ -0,0 +1,47 @@
+#include <event_client.h>
+#include <curl/curl.h>
+
+typedef struct _evcurl_global_data {
+       int magic;
+       CURLM *mhnd;
+       ev_timer timeev;
+       int nrun;
+} evcurl_global_data;
+
+typedef struct _evcurl_request_data 
+{
+       evcurl_global_data *global;
+       CURL *chnd;
+       char errdesc[CURL_ERROR_SIZE];
+       int attached;
+       char* PlainPostData;
+       long PlainPostDataLen;
+       StrBuf *PostData;
+       StrBuf *ReplyData;
+       ParsedURL *URL;
+       struct curl_slist * headers;
+} evcurl_request_data;
+
+typedef struct _sockwatcher_data 
+{
+       evcurl_global_data *global;
+       ev_io ioev;
+} sockwatcher_data;
+
+
+
+
+#define OPT(s, v) \
+       do { \
+               sta = curl_easy_setopt(chnd, (CURLOPT_##s), (v)); \
+               if (sta)  {                                             \
+                       CtdlLogPrintf(CTDL_ERR, "error setting option " #s " on curl handle: %s", curl_easy_strerror(sta)); \
+       } } while (0)
+
+
+int evcurl_init(evcurl_request_data *handle, 
+               void *CustomData, 
+               const char* Desc,
+               int CallBack);
+
+void evcurl_handle_start(evcurl_request_data *handle);
index c41291bce95e41a010cb8b75857b7dd68af23b78..645f458f43cae30c404d3a3df60e1695dfd48d39 100644 (file)
@@ -18,9 +18,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "../curl/serv_curl.h"
 
 #define FUNAMBOL_CONFIG_TEXT "funambol"
 #define PAGER_CONFIG_MESSAGE "__ Push email settings __"
@@ -32,6 +30,7 @@ extern "C" {
 typedef struct _NotifyContext {
        StrBuf **NotifyHostList;
        HashList *NotifyErrors;
+       evcurl_request_data HTTPData;
 } NotifyContext;
 
 int notify_http_server(char *remoteurl, 
@@ -48,8 +47,5 @@ void extNotify_getPrefs(long configMsgNum, char *configMsg);
 long extNotify_getConfigMessage(char *username);
 void process_notify(long msgnum, void *usrdata);
 
-#ifdef __cplusplus
-}
-#endif
 
 
index 3e80ef4d775e628f5c977928d8b4652c79ceaf7e..31f2f0932617e02de577be0f705bb4f8d348f065 100644 (file)
@@ -164,7 +164,7 @@ void do_extnotify_queue(void)
 
        NotifyContext Ctx;
        static int doing_queue = 0;
-       int i = 0;
+       //int i = 0;
     
        /*
         * This is a simple concurrency check to make sure only one queue run
@@ -189,7 +189,7 @@ void do_extnotify_queue(void)
        }
        CtdlForEachMessage(MSGS_ALL, 0L, NULL,
                           SPOOLMIME, NULL, process_notify, &Ctx);
-
+/*
        while ((Ctx.NotifyHostList != NULL) && (Ctx.NotifyHostList[i] != NULL))
                FreeStrBuf(&Ctx.NotifyHostList[i]);
 
@@ -212,7 +212,7 @@ void do_extnotify_queue(void)
                DeleteHashPos(&It);
                DeleteHash(&Ctx.NotifyErrors);
        }
-
+*/
        CtdlLogPrintf(CTDL_DEBUG, "serv_extnotify: queue run completed\n");
        doing_queue = 0;
 }
index d3315b0033e761dff2eaa9ec6b39083db2902255..0e88c91ff4881c8013f4a16acee8f1ae9f4145d9 100644 (file)
@@ -58,63 +58,14 @@ int notify_http_server(char *remoteurl,
                       long MsgNum, 
                       NotifyContext *Ctx) 
 {
-       char curl_errbuf[CURL_ERROR_SIZE];
-       char *pchs, *pche;
-       char userpass[SIZ];
+       CURLcode sta;
        char msgnumstr[128];
        char *buf = NULL;
-       CURL *curl;
-       CURLcode res;
-       struct curl_slist * headers=NULL;
-       char errmsg[1024] = "";
        char *SOAPMessage = NULL;
        char *contenttype = NULL;
        StrBuf *ReplyBuf;
+       CURL *chnd;
 
-       curl = curl_easy_init();
-       if (!curl) {
-               CtdlLogPrintf(CTDL_ALERT, "Unable to initialize libcurl.\n");
-               return 1;
-       }
-
-       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
-       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
-       ReplyBuf = NewStrBuf();
-       curl_easy_setopt(curl, CURLOPT_WRITEDATA, ReplyBuf);
-       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlFillStrBuf_callback);
-       curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errmsg);
-       curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
-       curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);
-
-       pchs = strchr(remoteurl, ':');
-       pche = strchr(remoteurl, '@');
-       if ((pche != NULL) && 
-           (pchs != NULL) && 
-           (pchs < pche) && ((pche - pchs) < SIZ)) {
-               memcpy(userpass, pchs + 3, pche - pchs - 3);
-               
-               userpass[pche - pchs - 3] = '\0';
-               curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
-               curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
-
-       }
-#ifdef CURLOPT_HTTP_CONTENT_DECODING
-       curl_easy_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 1);
-       curl_easy_setopt(curl, CURLOPT_ENCODING, "");
-#endif
-       curl_easy_setopt(curl, CURLOPT_USERAGENT, CITADEL);
-       curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);           /* die after 180 seconds */
-       if (
-               (!IsEmptyStr(config.c_ip_addr))
-               && (strcmp(config.c_ip_addr, "*"))
-               && (strcmp(config.c_ip_addr, "::"))
-               && (strcmp(config.c_ip_addr, "0.0.0.0"))
-       ) {
-               curl_easy_setopt(curl, CURLOPT_INTERFACE, config.c_ip_addr);
-       }
-
-       headers = curl_slist_append(headers,"Accept: application/soap+xml, application/mime, multipart/related, text/*");
-       headers = curl_slist_append(headers,"Pragma: no-cache");
 
        if (tlen > 0) {
                /* Load the template message. Get mallocs done too */
@@ -131,7 +82,7 @@ int notify_http_server(char *remoteurl,
                        CtdlLogPrintf(CTDL_ERR, buf);
 
                        CtdlAideMessage(buf, "External notifier unable to find message template!");
-                       goto free;
+                       goto abort;
                }
                mimetype = GuessMimeByFilename(template, tlen);
 
@@ -156,7 +107,7 @@ int notify_http_server(char *remoteurl,
                        CtdlLogPrintf(CTDL_ERR, buf);
 
                        CtdlAideMessage(buf, "External notifier unable to load message template!");
-                       goto free;
+                       goto abort;
                }
                // Do substitutions
                help_subst(SOAPMessage, "^notifyuser", user);
@@ -164,62 +115,111 @@ int notify_http_server(char *remoteurl,
                help_subst(SOAPMessage, "^msgid", msgid);
                help_subst(SOAPMessage, "^msgnum", msgnumstr);
 
-               curl_easy_setopt(curl, CURLOPT_URL, remoteurl);
-
                /* pass our list of custom made headers */
 
                contenttype=(char*) malloc(40+strlen(mimetype));
                sprintf(contenttype,"Content-Type: %s; charset=utf-8", mimetype);
 
-               headers = curl_slist_append(headers, "SOAPAction: \"\"");
-               headers = curl_slist_append(headers, contenttype);
+               Ctx->HTTPData.headers = curl_slist_append(Ctx->HTTPData.headers, "SOAPAction: \"\"");
+               Ctx->HTTPData.headers = curl_slist_append(Ctx->HTTPData.headers, contenttype);
+               Ctx->HTTPData.headers = curl_slist_append(Ctx->HTTPData.headers, "Accept: application/soap+xml, application/mime, multipart/related, text/*");
+               Ctx->HTTPData.headers = curl_slist_append(Ctx->HTTPData.headers, "Pragma: no-cache");
 
                /* Now specify the POST binary data */
-
-               curl_easy_setopt(curl, CURLOPT_POSTFIELDS, SOAPMessage);
-               curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(SOAPMessage));
-               curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+               Ctx->HTTPData.PlainPostData = SOAPMessage;
+               Ctx->HTTPData.PlainPostDataLen = strlen(SOAPMessage);
        }
        else {
                help_subst(remoteurl, "^notifyuser", user);
                help_subst(remoteurl, "^syncsource", config.c_funambol_source);
                help_subst(remoteurl, "^msgid", msgid);
                help_subst(remoteurl, "^msgnum", msgnumstr);
-               curl_easy_setopt(curl, CURLOPT_URL, remoteurl);
-               curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+               Ctx->HTTPData.headers = curl_slist_append(Ctx->HTTPData.headers, "Accept: application/soap+xml, application/mime, multipart/related, text/*");
+               Ctx->HTTPData.headers = curl_slist_append(Ctx->HTTPData.headers, "Pragma: no-cache");
        }
 
-       res = curl_easy_perform(curl);
+       ParseURL(&Ctx->HTTPData.URL, NewStrBufPlain (remoteurl, -1), 80);
+       CurlPrepareURL(Ctx->HTTPData.URL);
+       int CallBack;
+       if (! evcurl_init(&Ctx->HTTPData, 
+                         Ctx, 
+                         "Citadel ExtNotify",
+                         CallBack))
+       {
+               CtdlLogPrintf(CTDL_ALERT, "Unable to initialize libcurl.\n");
+               goto abort;
+       }
+       chnd = Ctx->HTTPData.chnd;
+       OPT(SSL_VERIFYPEER, 0);
+       OPT(SSL_VERIFYHOST, 0);
+/*
+       ReplyBuf = NewStrBuf();
+       curl_easy_setopt(curl, CURLOPT_WRITEDATA, ReplyBuf);
+       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlFillStrBuf_callback);
+*/
+       if (
+               (!IsEmptyStr(config.c_ip_addr))
+               && (strcmp(config.c_ip_addr, "*"))
+               && (strcmp(config.c_ip_addr, "::"))
+               && (strcmp(config.c_ip_addr, "0.0.0.0"))
+       ) {
+               OPT(INTERFACE, config.c_ip_addr);
+       }
+
+       evcurl_handle_start(&Ctx->HTTPData);
+
+       return 0;
+abort:
+///    curl_slist_free_all (headers);
+///    curl_easy_cleanup(curl);
+       if (contenttype) free(contenttype);
+       if (SOAPMessage != NULL) free(SOAPMessage);
+       if (buf != NULL) free(buf);
+       FreeStrBuf (&ReplyBuf);
+       return 1;
+}
+
+
+
+int EvaluateResult(NotifyContext *Ctx, int res, int b)
+{
        if (res) {
                StrBuf *ErrMsg;
 
-               CtdlLogPrintf(CTDL_ALERT, "libcurl error %d: %s\n", res, errmsg);
+               CtdlLogPrintf(CTDL_ALERT, "libcurl error %d: %s\n", 
+                             res, 
+                             Ctx->HTTPData.errdesc);
                ErrMsg = NewStrBufPlain(HKEY("Error sending your Notification\n"));
-               StrBufAppendPrintf(ErrMsg, "\nlibcurl error %d: %s\n", res, errmsg);
-               StrBufAppendBufPlain(ErrMsg, curl_errbuf, -1, 0);
+               StrBufAppendPrintf(ErrMsg, "\nlibcurl error %d: %s\n", 
+                                  res, 
+                                  Ctx->HTTPData.errdesc);
+///            StrBufAppendBufPlain(ErrMsg, curl_errbuf, -1, 0);
                StrBufAppendBufPlain(ErrMsg, HKEY("\nWas Trying to send: \n"), 0);
-               StrBufAppendBufPlain(ErrMsg, remoteurl, -1, 0);
-               if (tlen > 0) {
+               StrBufAppendBufPlain(ErrMsg, Ctx->HTTPData.URL->PlainUrl, -1, 0);
+               if (Ctx->HTTPData.PlainPostDataLen > 0) {
                        StrBufAppendBufPlain(ErrMsg, HKEY("\nThe Post document was: \n"), 0);
-                       StrBufAppendBufPlain(ErrMsg, SOAPMessage, -1, 0);
+                       StrBufAppendBufPlain(ErrMsg, 
+                                            Ctx->HTTPData.PlainPostData, 
+                                            Ctx->HTTPData.PlainPostDataLen, 0);
                        StrBufAppendBufPlain(ErrMsg, HKEY("\n\n"), 0);                  
                }
-               if (StrLength(ReplyBuf) > 0) {                  
+               if (StrLength(Ctx->HTTPData.ReplyData) > 0) {                   
                        StrBufAppendBufPlain(ErrMsg, HKEY("\n\nThe Serverreply was: \n\n"), 0);
-                       StrBufAppendBuf(ErrMsg, ReplyBuf, 0);
+                       StrBufAppendBuf(ErrMsg, Ctx->HTTPData.ReplyData, 0);
                }
                else 
                        StrBufAppendBufPlain(ErrMsg, HKEY("\n\nThere was no Serverreply.\n\n"), 0);
-               ExtNotify_PutErrorMessage(Ctx, ErrMsg);
+               ///ExtNotify_PutErrorMessage(Ctx, ErrMsg);
+               CtdlAideMessage(ChrPtr(ErrMsg), "External notifier unable to load message template!");
        }
 
        CtdlLogPrintf(CTDL_DEBUG, "Funambol notified\n");
-free:
-       curl_slist_free_all (headers);
-       curl_easy_cleanup(curl);
-       if (contenttype) free(contenttype);
-       if (SOAPMessage != NULL) free(SOAPMessage);
-       if (buf != NULL) free(buf);
-       FreeStrBuf (&ReplyBuf);
+
+////   curl_slist_free_all (headers);
+///    curl_easy_cleanup(curl);
+       ///if (contenttype) free(contenttype);
+       ///if (SOAPMessage != NULL) free(SOAPMessage);
+       ///if (buf != NULL) free(buf);
+       ///FreeStrBuf (&ReplyBuf);
        return 0;
 }