Moved all the OpenID Relying Party code that I've written so far
authorArt Cancro <ajc@citadel.org>
Mon, 19 May 2008 03:33:03 +0000 (03:33 +0000)
committerArt Cancro <ajc@citadel.org>
Mon, 19 May 2008 03:33:03 +0000 (03:33 +0000)
into the Citadel server, with only glue code in WebCit.  This
will allow Relying Party support to be implemented without requiring
a highly trusted webcit client, and it also eliminates the need to
link libcurl into webcit.

citadel/modules/openid/serv_openid_rp.c [new file with mode: 0644]
citadel/modules/rssclient/serv_rssclient.c
webcit/Makefile.in
webcit/auth.c
webcit/httpfetch.c [deleted file]

diff --git a/citadel/modules/openid/serv_openid_rp.c b/citadel/modules/openid/serv_openid_rp.c
new file mode 100644 (file)
index 0000000..488345d
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * $Id$
+ *
+ * OpenID 1.1 "relying party" implementation
+ *
+ */
+
+#include "sysdep.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pwd.h>
+#include <errno.h>
+#include <sys/types.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 <string.h>
+#include <limits.h>
+#include <curl/curl.h>
+#include "ctdl_module.h"
+
+
+/* 
+ * Locate a <link> tag and, given its 'rel=' parameter, return its 'href' parameter
+ */
+void extract_link(char *target_buf, int target_size, char *rel, char *source_buf)
+{
+       char *ptr = source_buf;
+
+       if (!target_buf) return;
+       if (!rel) return;
+       if (!source_buf) return;
+
+       target_buf[0] = 0;
+
+       while (ptr = bmstrcasestr(ptr, "<link"), ptr != NULL) {
+
+               char work_buffer[1024];
+               char *link_tag_start = NULL;
+               char *link_tag_end = NULL;
+
+               char rel_tag[1024];
+               char href_tag[1024];
+
+               link_tag_start = ptr;
+               link_tag_end = strchr(ptr, '>');
+               rel_tag[0] = 0;
+               href_tag[0] = 0;
+
+               if ((link_tag_end) && (link_tag_end > link_tag_start)) {
+                       int len;
+                       len = link_tag_end - link_tag_start;
+                       if (len > sizeof work_buffer) len = sizeof work_buffer;
+                       memcpy(work_buffer, link_tag_start, len);
+               
+                       char *rel_start = NULL;
+                       char *rel_end = NULL;
+                       rel_start = bmstrcasestr(work_buffer, "rel=");
+                       if (rel_start) {
+                               rel_start = strchr(rel_start, '\"');
+                               if (rel_start) {
+                                       ++rel_start;
+                                       rel_end = strchr(rel_start, '\"');
+                                       if ((rel_end) && (rel_end > rel_start)) {
+                                               safestrncpy(rel_tag, rel_start, rel_end - rel_start + 1);
+                                       }
+                               }
+                       }
+
+                       char *href_start = NULL;
+                       char *href_end = NULL;
+                       href_start = bmstrcasestr(work_buffer, "href=");
+                       if (href_start) {
+                               href_start = strchr(href_start, '\"');
+                               if (href_start) {
+                                       ++href_start;
+                                       href_end = strchr(href_start, '\"');
+                                       if ((href_end) && (href_end > href_start)) {
+                                               safestrncpy(href_tag, href_start, href_end - href_start + 1);
+                                       }
+                               }
+                       }
+
+                       if (!strcasecmp(rel, rel_tag)) {
+                               safestrncpy(target_buf, href_tag, target_size);
+                               return;
+                       }
+
+               }
+
+       ++ptr;
+       }
+
+
+}
+
+
+
+struct fh_data {
+       char *buf;
+       int total_bytes_received;
+       int maxbytes;
+};
+
+
+size_t fh_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+       struct fh_data *fh = (struct fh_data *) stream;
+       int got_bytes = (size * nmemb);
+
+       if (fh->total_bytes_received + got_bytes > fh->maxbytes) {
+               got_bytes = fh->maxbytes - fh->total_bytes_received;
+       }
+       if (got_bytes > 0) {
+               memcpy(&fh->buf[fh->total_bytes_received], ptr, got_bytes);
+               fh->total_bytes_received += got_bytes;
+       }
+
+       return got_bytes;
+}
+
+
+
+/*
+ * Begin an HTTP fetch (returns number of bytes actually fetched, or -1 for error)
+ * We first try 'curl' or 'wget' because they have more robust HTTP handling, and also
+ * support HTTPS.  If neither one works, we fall back to a built in mini HTTP client.
+ */
+int fetch_http(char *url, char *target_buf, int maxbytes)
+{
+       CURL *curl;
+       CURLcode res;
+       char errmsg[1024] = "";
+       struct fh_data fh = {
+               target_buf,
+               0,
+               maxbytes
+       };
+
+       if (!url) return(-1);
+       if (!target_buf) return(-1);
+       memset(target_buf, 0, maxbytes);
+
+       curl = curl_easy_init();
+       if (!curl) {
+               CtdlLogPrintf(CTDL_ALERT, "Unable to initialize libcurl.\n");
+               return(-1);
+       }
+
+       curl_easy_setopt(curl, CURLOPT_URL, url);
+       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
+       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
+       curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fh);
+       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fh_callback);
+       curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errmsg);
+       curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
+
+       res = curl_easy_perform(curl);
+       if (res) {
+               CtdlLogPrintf(CTDL_ALERT, "libcurl error %d: %s\n", res, errmsg);
+       }
+
+       curl_easy_cleanup(curl);
+       return fh.total_bytes_received;
+}
+
+
+
+
+/*
+ * Begin the first portion of an OpenID checkid_setup operation.
+ */
+void cmd_oid1(char *argbuf) {
+       char openid_url[1024];
+       char return_to[1024];
+       char trust_root[1024];
+       int i;
+       char buf[SIZ];
+
+       if (CC->logged_in) {
+               cprintf("%d Already logged in.\n", ERROR + ALREADY_LOGGED_IN);
+               return;
+       }
+
+       extract_token(openid_url, argbuf, 0, '|', sizeof openid_url);
+       extract_token(return_to, argbuf, 1, '|', sizeof return_to);
+       extract_token(trust_root, argbuf, 2, '|', sizeof trust_root);
+
+       i = fetch_http(openid_url, buf, sizeof buf - 1);
+       buf[sizeof buf - 1] = 0;
+       CtdlLogPrintf(CTDL_DEBUG, "fetch got %d bytes:\n", i);
+       if (i > 0) {
+               char openid_server[1024];
+               char openid_delegate[1024];
+
+               extract_link(openid_server, sizeof openid_server, "openid.server", buf);
+               extract_link(openid_delegate, sizeof openid_delegate, "openid.delegate", buf);
+
+               if (IsEmptyStr(openid_server)) {
+                       cprintf("%d There is no OpenID identity provider at this URL.\n", ERROR);
+                       return;
+               }
+
+               /* Empty delegate is legal; we just use the openid_url instead */
+               if (IsEmptyStr(openid_delegate)) {
+                       safestrncpy(openid_delegate, openid_url, sizeof openid_delegate);
+               }
+
+               /* Now we know where to redirect to. */
+
+               char redirect_string[4096];
+               char escaped_identity[1024];
+               char escaped_return_to[1024];
+               char escaped_trust_root[1024];
+
+               urlesc(escaped_identity, sizeof escaped_identity, openid_delegate);
+               urlesc(escaped_return_to, sizeof escaped_return_to, return_to);
+               urlesc(escaped_trust_root, sizeof escaped_trust_root, trust_root);
+
+               snprintf(redirect_string, sizeof redirect_string,
+                       "%s"
+                       "?openid.mode=checkid_setup"
+                       "&openid_identity=%s"
+                       "&openid.return_to=%s"
+                       "&openid.trust_root=%s"
+                       ,
+                       openid_server, escaped_identity, escaped_return_to, escaped_trust_root
+               );
+               cprintf("%d %s\n", CIT_OK, redirect_string);
+               return;
+       }
+
+       cprintf("%d Unable to fetch OpenID URL\n", ERROR);
+}
+
+
+
+
+
+/* To insert this module into the server activate the next block by changing the #if 0 to #if 1 */
+CTDL_MODULE_INIT(openid_rp)
+{
+       if (!threading)
+       {
+               CtdlRegisterProtoHook(cmd_oid1, "OID1", "Begin OpenID checkid_setup operation");
+       }
+
+   /* return our Subversion id for the Log */
+   return "$Id$";
+}
index fdf509f2e00662880e56957b583388b1f15caebd..f176ae7c5846036da958f4ad97c2bca4da6e2316 100644 (file)
@@ -352,6 +352,9 @@ void rss_do_fetching(char *url, char *rooms) {
 
        CURL *curl;
        CURLcode res;
+       char errmsg[1024] = "";
+
+       CtdlLogPrintf(CTDL_DEBUG, "Fetching RSS feed <%s>\n", url);
 
        curl = curl_easy_init();
        if (!curl) {
@@ -371,6 +374,8 @@ void rss_do_fetching(char *url, char *rooms) {
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, xp);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, rss_libcurl_callback);
+       curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errmsg);
+       curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
 
        memset(&ri, 0, sizeof(struct rss_item));
        ri.roomlist = rooms;
@@ -388,10 +393,10 @@ void rss_do_fetching(char *url, char *rooms) {
        if (CtdlThreadCheckStop())
                goto shutdown ;
 
-
        res = curl_easy_perform(curl);
-       //while got bytes
-       //XML_Parse(xp, buf, got_bytes, 0);
+       if (res) {
+               CtdlLogPrintf(CTDL_ALERT, "libcurl error %d: %s\n", res, errmsg);
+       }
 
        if (CtdlThreadCheckStop())
                goto shutdown ;
index cdb62ab34253c9ad9bba40cc941d8691a8da825b..8d5bdc9f456c439fb2f15c9022c975d80ebd6916 100644 (file)
@@ -51,7 +51,7 @@ webcit: webserver.o context_loop.o ical_dezonify.o \
        groupdav_main.o groupdav_get.o groupdav_propfind.o fmt_date.o \
        groupdav_options.o autocompletion.o gettext.o tabs.o sieve.o \
        groupdav_delete.o groupdav_put.o http_datestring.o setup_wizard.o \
-       downloads.o  addressbook_popup.o pushemail.o sysdep.o httpfetch.o \
+       downloads.o  addressbook_popup.o pushemail.o sysdep.o \
        $(LIBOBJS)
        $(CC) webserver.o context_loop.o cookie_conversion.o \
        webcit.o auth.o tcp_sockets.o mainmenu.o serv_func.o who.o listsub.o \
@@ -63,7 +63,7 @@ webcit: webserver.o context_loop.o ical_dezonify.o \
        groupdav_main.o groupdav_get.o groupdav_propfind.o groupdav_delete.o \
        groupdav_options.o autocompletion.o tabs.o smtpqueue.o sieve.o \
        groupdav_put.o http_datestring.o setup_wizard.o fmt_date.o \
-       gettext.o downloads.o addressbook_popup.o pushemail.o sysdep.o httpfetch.o \
+       gettext.o downloads.o addressbook_popup.o pushemail.o sysdep.o \
        $(LIBOBJS) $(LIBS) $(LDFLAGS) -o webcit
 
 .c.o:
index f0eed0e6a098b1865d6f3094f2b1b527d1db8eef..94abedfbeead97d3fbc9817c78fdc106cd4706f0 100644 (file)
@@ -259,88 +259,12 @@ void do_login(void)
 }
 
 
-/* 
- * Locate a <link> tag and, given its 'rel=' parameter, return its 'href' parameter
- */
-void extract_link(char *target_buf, int target_size, char *rel, char *source_buf)
-{
-       char *ptr = source_buf;
-
-       if (!target_buf) return;
-       if (!rel) return;
-       if (!source_buf) return;
-
-       target_buf[0] = 0;
-
-       while (ptr = bmstrcasestr(ptr, "<link"), ptr != NULL) {
-
-               char work_buffer[1024];
-               char *link_tag_start = NULL;
-               char *link_tag_end = NULL;
-
-               char rel_tag[1024];
-               char href_tag[1024];
-
-               link_tag_start = ptr;
-               link_tag_end = strchr(ptr, '>');
-               rel_tag[0] = 0;
-               href_tag[0] = 0;
-
-               if ((link_tag_end) && (link_tag_end > link_tag_start)) {
-                       int len;
-                       len = link_tag_end - link_tag_start;
-                       if (len > sizeof work_buffer) len = sizeof work_buffer;
-                       memcpy(work_buffer, link_tag_start, len);
-               
-                       char *rel_start = NULL;
-                       char *rel_end = NULL;
-                       rel_start = bmstrcasestr(work_buffer, "rel=");
-                       if (rel_start) {
-                               rel_start = strchr(rel_start, '\"');
-                               if (rel_start) {
-                                       ++rel_start;
-                                       rel_end = strchr(rel_start, '\"');
-                                       if ((rel_end) && (rel_end > rel_start)) {
-                                               safestrncpy(rel_tag, rel_start, rel_end - rel_start + 1);
-                                       }
-                               }
-                       }
-
-                       char *href_start = NULL;
-                       char *href_end = NULL;
-                       href_start = bmstrcasestr(work_buffer, "href=");
-                       if (href_start) {
-                               href_start = strchr(href_start, '\"');
-                               if (href_start) {
-                                       ++href_start;
-                                       href_end = strchr(href_start, '\"');
-                                       if ((href_end) && (href_end > href_start)) {
-                                               safestrncpy(href_tag, href_start, href_end - href_start + 1);
-                                       }
-                               }
-                       }
-
-                       if (!strcasecmp(rel, rel_tag)) {
-                               safestrncpy(target_buf, href_tag, target_size);
-                               return;
-                       }
-
-               }
-
-       ++ptr;
-       }
-
-
-}
-
-
 /* 
  * Perform authentication using OpenID
  * assemble the checkid_setup request and then redirect to the user's identity provider
  */
 void do_openid_login(void)
 {
-       int i;
        char buf[4096];
 
        if (havebstr("language")) {
@@ -353,48 +277,22 @@ void do_openid_login(void)
                return;
        }
        if (havebstr("login_action")) {
-               i = fetch_http(bstr("openid_url"), buf, sizeof buf - 1);
-               buf[sizeof buf - 1] = 0;
-               if (i > 0) {
-                       char openid_server[1024];
-                       char openid_delegate[1024];
-                       
-                       extract_link(openid_server, sizeof openid_server, "openid.server", buf);
-                       extract_link(openid_delegate, sizeof openid_delegate, "openid.delegate", buf);
-
-                       /* Empty delegate is legal; we just use the openid_url instead */
-                       if (IsEmptyStr(openid_delegate)) {
-                               safestrncpy(openid_delegate, bstr("openid_url"), sizeof openid_delegate);
-                       }
+               snprintf(buf, sizeof buf,
+                       "OID1 %s|%s://%s/finish_openid_login|%s://%s",
+                       bstr("openid_url"),
+                       (is_https ? "https" : "http"), WC->http_host,
+                       (is_https ? "https" : "http"), WC->http_host
+               );
 
-                       /* Now we know where to redirect to. */
-
-                       char redirect_string[4096];
-                       char escaped_identity[1024];
-                       char escaped_return_to[1024];
-                       char escaped_trust_root[1024];
-
-                       stresc(escaped_identity, sizeof escaped_identity, openid_delegate, 0, 1);
-
-                       snprintf(buf, sizeof buf, "%s://%s/finish_openid_login",
-                               (is_https ? "https" : "http"), WC->http_host);
-                       stresc(escaped_return_to, sizeof escaped_identity, buf, 0, 1);
-
-                       snprintf(buf, sizeof buf, "%s://%s",
-                               (is_https ? "https" : "http"), WC->http_host);
-                       stresc(escaped_trust_root, sizeof escaped_identity, buf, 0, 1);
-
-                       snprintf(redirect_string, sizeof redirect_string,
-                               "%s"
-                               "?openid.mode=checkid_setup"
-                               "&openid_identity=%s"
-                               "&openid.return_to=%s"
-                               "&openid.trust_root=%s"
-                               ,
-                               openid_server, escaped_identity, escaped_return_to, escaped_trust_root
-                       );
-                       lprintf(CTDL_DEBUG, "OpenID server contacted; redirecting to %s\n", redirect_string);
-                       http_redirect(redirect_string);
+               serv_puts(buf);
+               serv_getln(buf, sizeof buf);
+               if (buf[0] == '2') {
+                       lprintf(CTDL_DEBUG, "OpenID server contacted; redirecting to %s\n", &buf[4]);
+                       http_redirect(&buf[4]);
+                       return;
+               }
+               else {
+                       display_openid_login(&buf[4]);
                        return;
                }
        }
diff --git a/webcit/httpfetch.c b/webcit/httpfetch.c
deleted file mode 100644 (file)
index e4c48af..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * mini http client
- */
-
-
-#include "webcit.h"
-#include "webserver.h"
-#define CLIENT_TIMEOUT 15
-#define sock_close(sock) close(sock)
-
-int sock_connect(char *host, char *service, char *protocol)
-{
-       struct hostent *phe;
-       struct servent *pse;
-       struct protoent *ppe;
-       struct sockaddr_in sin;
-       struct sockaddr_in egress_sin;
-       int s, type;
-
-       if ((host == NULL) || IsEmptyStr(host)) 
-               return(-1);
-       if ((service == NULL) || IsEmptyStr(service)) 
-               return(-1);
-       if ((protocol == NULL) || IsEmptyStr(protocol)) 
-               return(-1);
-
-       memset(&sin, 0, sizeof(sin));
-       sin.sin_family = AF_INET;
-
-       pse = getservbyname(service, protocol);
-       if (pse) {
-               sin.sin_port = pse->s_port;
-       } else if ((sin.sin_port = htons((u_short) atoi(service))) == 0) {
-               lprintf(CTDL_CRIT, "Can't get %s service entry: %s\n",
-                       service, strerror(errno));
-               return(-1);
-       }
-       phe = gethostbyname(host);
-       if (phe) {
-               memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
-       } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
-               lprintf(CTDL_ERR, "Can't get %s host entry: %s\n",
-                       host, strerror(errno));
-               return(-1);
-       }
-       if ((ppe = getprotobyname(protocol)) == 0) {
-               lprintf(CTDL_CRIT, "Can't get %s protocol entry: %s\n",
-                       protocol, strerror(errno));
-               return(-1);
-       }
-       if (!strcmp(protocol, "udp")) {
-               type = SOCK_DGRAM;
-       } else {
-               type = SOCK_STREAM;
-       }
-
-       s = socket(PF_INET, type, ppe->p_proto);
-       if (s < 0) {
-               lprintf(CTDL_CRIT, "Can't create socket: %s\n", strerror(errno));
-               return(-1);
-       }
-
-       /* If citserver is bound to a specific IP address on the host, make
-        * sure we use that address for outbound connections.  FIXME make this work in webcit
-        */
-       memset(&egress_sin, 0, sizeof(egress_sin));
-       egress_sin.sin_family = AF_INET;
-       //      if (!IsEmptyStr(config.c_ip_addr)) {
-               //      egress_sin.sin_addr.s_addr = inet_addr(config.c_ip_addr);
-               //      if (egress_sin.sin_addr.s_addr == !INADDR_ANY) {
-                       //      egress_sin.sin_addr.s_addr = INADDR_ANY;
-               //      }
-
-               /* If this bind fails, no problem; we can still use INADDR_ANY */
-               bind(s, (struct sockaddr *)&egress_sin, sizeof(egress_sin));
-        //     }
-
-       /* Now try to connect to the remote host. */
-       if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
-               lprintf(CTDL_ERR, "Can't connect to %s:%s: %s\n",
-                       host, service, strerror(errno));
-               close(s);
-               return(-1);
-       }
-
-       return (s);
-}
-
-
-
-/*
- * sock_read_to() - input binary data from socket, with a settable timeout.
- * Returns the number of bytes read, or -1 for error.
- * If keep_reading_until_full is nonzero, we keep reading until we get the number of requested bytes
- */
-int sock_read_to(int sock, char *buf, int bytes, int timeout, int keep_reading_until_full)
-{
-       int len,rlen;
-       fd_set rfds;
-       struct timeval tv;
-       int retval;
-
-       len = 0;
-       while (len<bytes) {
-               FD_ZERO(&rfds);
-               FD_SET(sock, &rfds);
-               tv.tv_sec = timeout;
-               tv.tv_usec = 0;
-
-               retval = select(sock+1, &rfds, NULL, NULL, &tv);
-
-               if (FD_ISSET(sock, &rfds) == 0) {       /* timed out */
-                       lprintf(CTDL_ERR, "sock_read_to() timed out.\n");
-                       return(-1);
-               }
-
-               rlen = read(sock, &buf[len], bytes-len);
-               if (rlen<1) {
-                       lprintf(CTDL_ERR, "sock_read_to() failed: %s\n",
-                               strerror(errno));
-                       return(-1);
-               }
-               len = len + rlen;
-               if (!keep_reading_until_full) return(len);
-       }
-       return(bytes);
-}
-
-
-/*
- * sock_write() - send binary to server.
- * Returns the number of bytes written, or -1 for error.
- */
-int sock_write(int sock, char *buf, int nbytes)
-{
-       int bytes_written = 0;
-       int retval;
-       while (bytes_written < nbytes) {
-               retval = write(sock, &buf[bytes_written],
-                              nbytes - bytes_written);
-               if (retval < 1) {
-                       return (-1);
-               }
-               bytes_written = bytes_written + retval;
-       }
-       return (bytes_written);
-}
-
-
-
-/*
- * Input string from socket - implemented in terms of sock_read_to()
- * 
- */
-int sock_getln(int sock, char *buf, int bufsize)
-{
-       int i;
-
-       /* Read one character at a time.
-        */
-       for (i = 0;; i++) {
-               if (sock_read_to(sock, &buf[i], 1, CLIENT_TIMEOUT, 1) < 0) return(-1);
-               if (buf[i] == '\n' || i == (bufsize-1))
-                       break;
-       }
-
-       /* If we got a long line, discard characters until the newline.
-        */
-       if (i == (bufsize-1))
-               while (buf[i] != '\n')
-                       if (sock_read_to(sock, &buf[i], 1, CLIENT_TIMEOUT, 1) < 0) return(-1);
-
-       /* Strip any trailing CR and LF characters.
-        */
-       buf[i] = 0;
-       while ( (i > 0)
-               && ( (buf[i - 1]==13)
-                    || ( buf[i - 1]==10)) ) {
-               i--;
-               buf[i] = 0;
-       }
-       return(i);
-}
-
-
-
-/*
- * sock_puts() - send line to server - implemented in terms of serv_write()
- * Returns the number of bytes written, or -1 for error.
- */
-int sock_puts(int sock, char *buf)
-{
-       int i, j;
-
-       i = sock_write(sock, buf, strlen(buf));
-       if (i<0) return(i);
-       j = sock_write(sock, "\n", 1);
-       if (j<0) return(j);
-       return(i+j);
-}
-
-
-
-
-
-
-/*
- * Fallback handler for fetch_http() that uses our built-in mini client
- */
-int fetch_http_using_mini_client(char *url, char *target_buf, int maxbytes)
-{
-       char buf[1024];
-       char httphost[1024];
-       int httpport = 80;
-       char httpurl[1024];
-       int sock = (-1);
-       int got_bytes = (-1);
-       int redirect_count = 0;
-       int total_bytes_received = 0;
-       int i = 0;
-
-       /* Parse the URL */
-       snprintf(buf, (sizeof buf)-1, "%s", url);
-       i = parse_url(buf, httphost, &httpport, httpurl);
-       if (i == 1) {
-               snprintf(buf, (sizeof buf)-1, "http://%s", url);
-               i = parse_url(buf, httphost, &httpport, httpurl);
-       }
-       if (i == 4) {
-               strcat(buf, "/");
-               i = parse_url(buf, httphost, &httpport, httpurl);
-       }
-       if (i != 0) {
-               lprintf(CTDL_ALERT, "Invalid URL: %s (%d)\n", url, i);
-               return(-1);
-       }
-
-retry: lprintf(CTDL_NOTICE, "Connecting to <%s>\n", httphost);
-       sprintf(buf, "%d", httpport);
-       sock = sock_connect(httphost, buf, "tcp");
-       if (sock >= 0) {
-               lprintf(CTDL_DEBUG, "Connected!\n");
-
-               snprintf(buf, sizeof buf, "GET %s HTTP/1.0", httpurl);
-               lprintf(CTDL_DEBUG, "<%s\n", buf);
-               sock_puts(sock, buf);
-
-               snprintf(buf, sizeof buf, "Host: %s", httphost);
-               lprintf(CTDL_DEBUG, "<%s\n", buf);
-               sock_puts(sock, buf);
-
-               snprintf(buf, sizeof buf, "User-Agent: WebCit");
-               lprintf(CTDL_DEBUG, "<%s\n", buf);
-               sock_puts(sock, buf);
-
-               snprintf(buf, sizeof buf, "Accept: */*");
-               lprintf(CTDL_DEBUG, "<%s\n", buf);
-               sock_puts(sock, buf);
-
-               sock_puts(sock, "");
-
-               if (sock_getln(sock, buf, sizeof buf) >= 0) {
-                       lprintf(CTDL_DEBUG, ">%s\n", buf);
-                       remove_token(buf, 0, ' ');
-
-                       /* 200 OK */
-                       if (buf[0] == '2') {
-
-                               while (got_bytes = sock_getln(sock, buf, sizeof buf),
-                                     (got_bytes >= 0 && (strcmp(buf, "")) && (strcmp(buf, "\r"))) ) {
-                                       /* discard headers */
-                               }
-
-                               while (got_bytes = sock_read_to(sock, buf, sizeof buf, CLIENT_TIMEOUT, 0),
-                                     (got_bytes>0)  ) {
-
-                                       if (total_bytes_received + got_bytes > maxbytes) {
-                                               got_bytes = maxbytes - total_bytes_received;
-                                       }
-                                       if (got_bytes > 0) {
-                                               memcpy(&target_buf[total_bytes_received], buf, got_bytes);
-                                               total_bytes_received += got_bytes;
-                                       }
-
-                               }
-                       }
-
-                       /* 30X redirect */
-                       else if ( (!strncmp(buf, "30", 2)) && (redirect_count < 16) ) {
-                               while (got_bytes = sock_getln(sock, buf, sizeof buf),
-                                     (got_bytes >= 0 && (strcmp(buf, "")) && (strcmp(buf, "\r"))) ) {
-                                       if (!strncasecmp(buf, "Location:", 9)) {
-                                               ++redirect_count;
-                                               strcpy(buf, &buf[9]);
-                                               striplt(buf);
-                                               if (parse_url(buf, httphost, &httpport, httpurl) == 0) {
-                                                       sock_close(sock);
-                                                       goto retry;
-                                               }
-                                               else {
-                                                       lprintf(CTDL_ALERT, "Invalid URL: %s\n", buf);
-                                               }
-                                       }
-                               }
-                       }
-
-               }
-               sock_close(sock);
-       }
-       else {
-               lprintf(CTDL_ERR, "Could not connect: %s\n", strerror(errno));
-       }
-
-       return total_bytes_received;
-}
-
-
-
-/*
- * Begin an HTTP fetch (returns number of bytes actually fetched, or -1 for error)
- * We first try 'curl' or 'wget' because they have more robust HTTP handling, and also
- * support HTTPS.  If neither one works, we fall back to a built in mini HTTP client.
- */
-int fetch_http(char *url, char *target_buf, int maxbytes)
-{
-       FILE *fp;
-       char cmd[1024];
-       int bytes_received = 0;
-       char ch;
-
-       memset(target_buf, 0, maxbytes);
-
-       /* First try curl */
-       snprintf(cmd, sizeof cmd, "curl -L %s </dev/null 2>/dev/null", url);
-       fp = popen(cmd, "r");
-
-       /* Then try wget */
-       if (!fp) {
-               snprintf(cmd, sizeof cmd, "wget -q -O - %s </dev/null 2>/dev/null", url);
-               fp = popen(cmd, "r");
-       }
-
-       if (fp) {
-               while ( (!feof(fp)) && (bytes_received < maxbytes) ) {
-                       ch = fgetc(fp);
-                       if (ch != EOF) {
-                               target_buf[bytes_received++] = ch;
-                       }
-               }
-               pclose(fp);
-               return bytes_received;
-       }
-
-       /* Fall back to the built-in mini handler */
-       return fetch_http_using_mini_client(url, target_buf, maxbytes);
-}