summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/easy.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/easy.c')
-rw-r--r--Utilities/cmcurl/easy.c474
1 files changed, 393 insertions, 81 deletions
diff --git a/Utilities/cmcurl/easy.c b/Utilities/cmcurl/easy.c
index fb116fd..f3c2273 100644
--- a/Utilities/cmcurl/easy.c
+++ b/Utilities/cmcurl/easy.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -29,14 +29,18 @@
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
+#endif
#include <errno.h>
#include "strequal.h"
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef WIN32
#include <time.h>
#include <io.h>
#else
@@ -44,7 +48,9 @@
#include <sys/socket.h>
#endif
#include <netinet/in.h>
+#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -71,20 +77,37 @@
#include "urldata.h"
#include <curl/curl.h>
#include "transfer.h"
-#include "ssluse.h"
+#include "sslgen.h"
#include "url.h"
#include "getinfo.h"
#include "hostip.h"
#include "share.h"
-#include "curl_memory.h"
+#include "strdup.h"
+#include "memory.h"
+#include "progress.h"
+#include "easyif.h"
+#include "sendf.h" /* for failf function prototype */
+#include <ca-bundle.h>
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+#include <iconv.h>
+/* set default codesets for iconv */
+#ifndef CURL_ICONV_CODESET_OF_NETWORK
+#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
+#endif
+#ifndef CURL_ICONV_CODESET_FOR_UTF8
+#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8"
+#endif
+#define ICONV_ERROR (size_t)-1
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+
/* The last #include file should be: */
#include "memdebug.h"
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef USE_WINSOCK
/* win32_cleanup() is for win32 socket cleanup functionality, the opposite
of win32_init() */
static void win32_cleanup(void)
@@ -100,12 +123,12 @@ static CURLcode win32_init(void)
WSADATA wsaData;
int err;
-#ifdef ENABLE_IPV6
- wVersionRequested = MAKEWORD(2, 0);
-#else
- wVersionRequested = MAKEWORD(1, 1);
+#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
+ Error IPV6_requires_winsock2
#endif
+ wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
+
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
@@ -160,17 +183,31 @@ static void idna_init (void)
#endif /* USE_LIBIDN */
/* true globals -- for curl_global_init() and curl_global_cleanup() */
-static unsigned int initialized = 0;
-static long init_flags = 0;
+static unsigned int initialized;
+static long init_flags;
+
+/*
+ * strdup (and other memory functions) is redefined in complicated
+ * ways, but at this point it must be defined as the system-supplied strdup
+ * so the callback pointer is initialized correctly.
+ */
+#if defined(_WIN32_WCE)
+#define system_strdup _strdup
+#elif !defined(HAVE_STRDUP)
+#define system_strdup curlx_strdup
+#else
+#define system_strdup strdup
+#endif
/*
* If a memory-using function (like curl_getenv) is used before
* curl_global_init() is called, we need to have these pointers set already.
*/
+
curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
curl_free_callback Curl_cfree = (curl_free_callback)free;
curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
-curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)strdup;
+curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
/**
@@ -179,18 +216,19 @@ curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
*/
CURLcode curl_global_init(long flags)
{
- if (initialized)
+ if (initialized++)
return CURLE_OK;
/* Setup the default memory functions here (again) */
Curl_cmalloc = (curl_malloc_callback)malloc;
Curl_cfree = (curl_free_callback)free;
Curl_crealloc = (curl_realloc_callback)realloc;
- Curl_cstrdup = (curl_strdup_callback)strdup;
+ Curl_cstrdup = (curl_strdup_callback)system_strdup;
Curl_ccalloc = (curl_calloc_callback)calloc;
if (flags & CURL_GLOBAL_SSL)
- Curl_SSL_init();
+ if (!Curl_ssl_init())
+ return CURLE_FAILED_INIT;
if (flags & CURL_GLOBAL_WIN32)
if (win32_init() != CURLE_OK)
@@ -205,7 +243,6 @@ CURLcode curl_global_init(long flags)
idna_init();
#endif
- initialized = 1;
init_flags = flags;
return CURLE_OK;
@@ -219,7 +256,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
curl_free_callback f, curl_realloc_callback r,
curl_strdup_callback s, curl_calloc_callback c)
{
- CURLcode code;
+ CURLcode code = CURLE_OK;
/* Invalid input, return immediately */
if (!m || !f || !r || !s || !c)
@@ -251,10 +288,13 @@ void curl_global_cleanup(void)
if (!initialized)
return;
+ if (--initialized)
+ return;
+
Curl_global_host_cache_dtor();
if (init_flags & CURL_GLOBAL_SSL)
- Curl_SSL_cleanup();
+ Curl_ssl_cleanup();
if (init_flags & CURL_GLOBAL_WIN32)
win32_cleanup();
@@ -263,7 +303,6 @@ void curl_global_cleanup(void)
amiga_cleanup();
#endif
- initialized = 0;
init_flags = 0;
}
@@ -296,14 +335,10 @@ CURL *curl_easy_init(void)
* curl_easy_setopt() is the external interface for setting options on an
* easy handle.
*/
-typedef int (*func_T)(void);
+
CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
{
va_list arg;
- func_T param_func;
- long param_long;
- void *param_obj;
- curl_off_t param_offset;
struct SessionHandle *data = curl;
CURLcode ret;
@@ -312,38 +347,95 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
va_start(arg, tag);
- /* PORTING NOTE:
- Object pointers can't necessarily be casted to function pointers and
- therefore we need to know what type it is and read the correct type
- at once. This should also correct problems with different sizes of
- the types.
- */
-
- if(tag < CURLOPTTYPE_OBJECTPOINT) {
- /* This is a LONG type */
- param_long = va_arg(arg, long);
- ret = Curl_setopt(data, tag, param_long);
- }
- else if(tag < CURLOPTTYPE_FUNCTIONPOINT) {
- /* This is a object pointer type */
- param_obj = va_arg(arg, void *);
- ret = Curl_setopt(data, tag, param_obj);
- }
- else if(tag < CURLOPTTYPE_OFF_T) {
- /* This is a function pointer type */
- param_func = va_arg(arg, func_T );
- ret = Curl_setopt(data, tag, param_func);
- }
- else {
- /* This is a curl_off_t type */
- param_offset = va_arg(arg, curl_off_t);
- ret = Curl_setopt(data, tag, param_offset);
- }
+ ret = Curl_setopt(data, tag, arg);
va_end(arg);
return ret;
}
+#ifdef CURL_MULTIEASY
+/***************************************************************************
+ * This function is still only for testing purposes. It makes a great way
+ * to run the full test suite on the multi interface instead of the easy one.
+ ***************************************************************************
+ *
+ * The *new* curl_easy_perform() is the external interface that performs a
+ * transfer previously setup.
+ *
+ * Wrapper-function that: creates a multi handle, adds the easy handle to it,
+ * runs curl_multi_perform() until the transfer is done, then detaches the
+ * easy handle, destroys the multi handle and returns the easy handle's return
+ * code. This will make everything internally use and assume multi interface.
+ */
+CURLcode curl_easy_perform(CURL *easy)
+{
+ CURLM *multi;
+ CURLMcode mcode;
+ CURLcode code = CURLE_OK;
+ int still_running;
+ struct timeval timeout;
+ int rc;
+ CURLMsg *msg;
+ fd_set fdread;
+ fd_set fdwrite;
+ fd_set fdexcep;
+ int maxfd;
+
+ if(!easy)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ multi = curl_multi_init();
+ if(!multi)
+ return CURLE_OUT_OF_MEMORY;
+
+ mcode = curl_multi_add_handle(multi, easy);
+ if(mcode) {
+ curl_multi_cleanup(multi);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* we start some action by calling perform right away */
+
+ do {
+ while(CURLM_CALL_MULTI_PERFORM ==
+ curl_multi_perform(multi, &still_running));
+
+ if(!still_running)
+ break;
+
+ FD_ZERO(&fdread);
+ FD_ZERO(&fdwrite);
+ FD_ZERO(&fdexcep);
+
+ /* timeout once per second */
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ /* get file descriptors from the transfers */
+ curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
+
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+
+ if(rc == -1)
+ /* select error */
+ break;
+
+ /* timeout or data to send/receive => loop! */
+ } while(still_running);
+
+ msg = curl_multi_info_read(multi, &rc);
+ if(msg)
+ code = msg->data.result;
+
+ mcode = curl_multi_remove_handle(multi, easy);
+ /* what to do if it fails? */
+
+ mcode = curl_multi_cleanup(multi);
+ /* what to do if it fails? */
+
+ return code;
+}
+#else
/*
* curl_easy_perform() is the external interface that performs a transfer
* previously setup.
@@ -358,16 +450,18 @@ CURLcode curl_easy_perform(CURL *curl)
if ( ! (data->share && data->share->hostcache) ) {
if (Curl_global_host_cache_use(data) &&
- data->hostcache != Curl_global_host_cache_get()) {
- if (data->hostcache)
- Curl_hash_destroy(data->hostcache);
- data->hostcache = Curl_global_host_cache_get();
+ (data->dns.hostcachetype != HCACHE_GLOBAL)) {
+ if (data->dns.hostcachetype == HCACHE_PRIVATE)
+ Curl_hash_destroy(data->dns.hostcache);
+ data->dns.hostcache = Curl_global_host_cache_get();
+ data->dns.hostcachetype = HCACHE_GLOBAL;
}
- if (!data->hostcache) {
- data->hostcache = Curl_mk_dnscache();
+ if (!data->dns.hostcache) {
+ data->dns.hostcachetype = HCACHE_PRIVATE;
+ data->dns.hostcache = Curl_mk_dnscache();
- if(!data->hostcache)
+ if(!data->dns.hostcache)
/* While we possibly could survive and do good without a host cache,
the fact that creating it failed indicates that things are truly
screwed up and we should bail out! */
@@ -376,8 +470,16 @@ CURLcode curl_easy_perform(CURL *curl)
}
+ if(!data->state.connc) {
+ /* oops, no connection cache, make one up */
+ data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1);
+ if(!data->state.connc)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
return Curl_perform(data);
}
+#endif
/*
* curl_easy_cleanup() is the external interface to cleaning/freeing the given
@@ -390,15 +492,26 @@ void curl_easy_cleanup(CURL *curl)
if(!data)
return;
- if ( ! (data->share && data->share->hostcache) ) {
- if ( !Curl_global_host_cache_use(data)) {
- Curl_hash_destroy(data->hostcache);
- }
- }
Curl_close(data);
}
/*
+ * Store a pointed to the multi handle within the easy handle's data struct.
+ */
+void Curl_easy_addmulti(struct SessionHandle *data,
+ void *multi)
+{
+ data->multi = multi;
+}
+
+void Curl_easy_initHandleData(struct SessionHandle *data)
+{
+ memset(&data->reqdata, 0, sizeof(struct HandleData));
+
+ data->reqdata.maxdownload = -1;
+}
+
+/*
* curl_easy_getinfo() is an external interface that allows an app to retrieve
* information from a performed transfer and similar.
*/
@@ -445,21 +558,21 @@ CURL *curl_easy_duphandle(CURL *incurl)
/* copy all userdefined values */
outcurl->set = data->set;
- outcurl->state.numconnects = data->state.numconnects;
- outcurl->state.connects = (struct connectdata **)
- malloc(sizeof(struct connectdata *) * outcurl->state.numconnects);
- if(!outcurl->state.connects) {
+ if(data->state.used_interface == Curl_if_multi)
+ outcurl->state.connc = data->state.connc;
+ else
+ outcurl->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1);
+
+ if(!outcurl->state.connc)
break;
- }
- memset(outcurl->state.connects, 0,
- sizeof(struct connectdata *)*outcurl->state.numconnects);
+ outcurl->state.lastconnect = -1;
outcurl->progress.flags = data->progress.flags;
outcurl->progress.callback = data->progress.callback;
-#ifndef CURL_DISABLE_HTTP
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
if(data->cookies) {
/* If cookies are enabled in the parent handle, we enable them
in the clone as well! */
@@ -474,18 +587,14 @@ CURL *curl_easy_duphandle(CURL *incurl)
#endif /* CURL_DISABLE_HTTP */
/* duplicate all values in 'change' */
+
if(data->change.url) {
outcurl->change.url = strdup(data->change.url);
if(!outcurl->change.url)
break;
outcurl->change.url_alloc = TRUE;
}
- if(data->change.proxy) {
- outcurl->change.proxy = strdup(data->change.proxy);
- if(!outcurl->change.proxy)
- break;
- outcurl->change.proxy_alloc = TRUE;
- }
+
if(data->change.referer) {
outcurl->change.referer = strdup(data->change.referer);
if(!outcurl->change.referer)
@@ -499,18 +608,29 @@ CURL *curl_easy_duphandle(CURL *incurl)
break;
#endif
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+ outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK);
+ outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST);
+ outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_FOR_UTF8);
+#endif
+
+ Curl_easy_initHandleData(outcurl);
+
+ outcurl->magic = CURLEASY_MAGIC_NUMBER;
+
fail = FALSE; /* we reach this point and thus we are OK */
} while(0);
if(fail) {
if(outcurl) {
- if(outcurl->state.connects)
- free(outcurl->state.connects);
+ if(outcurl->state.connc->type == CONNCACHE_PRIVATE)
+ Curl_rm_connc(outcurl->state.connc);
if(outcurl->state.headerbuff)
free(outcurl->state.headerbuff);
- if(outcurl->change.proxy)
- free(outcurl->change.proxy);
if(outcurl->change.url)
free(outcurl->change.url);
if(outcurl->change.referer)
@@ -531,12 +651,21 @@ void curl_easy_reset(CURL *curl)
{
struct SessionHandle *data = (struct SessionHandle *)curl;
+ Curl_safefree(data->reqdata.pathbuffer);
+ data->reqdata.pathbuffer=NULL;
+
+ Curl_safefree(data->reqdata.proto.generic);
+ data->reqdata.proto.generic=NULL;
+
/* zero out UserDefined data: */
memset(&data->set, 0, sizeof(struct UserDefined));
/* zero out Progress data: */
memset(&data->progress, 0, sizeof(struct Progress));
+ /* init Handle data */
+ Curl_easy_initHandleData(data);
+
/* The remainder of these calls have been taken from Curl_open() */
data->set.out = stdout; /* default output to stdout */
@@ -550,6 +679,7 @@ void curl_easy_reset(CURL *curl)
data->set.fread = (curl_read_callback)fread;
data->set.infilesize = -1; /* we don't know any size */
+ data->set.postfieldsize = -1;
data->state.current_speed = -1; /* init to negative == impossible */
@@ -561,6 +691,7 @@ void curl_easy_reset(CURL *curl)
/* make libcurl quiet by default: */
data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
+ data->progress.flags |= PGRS_HIDE;
/* Set the default size of the SSL session ID cache */
data->set.ssl.numsessions = 5;
@@ -580,4 +711,185 @@ void curl_easy_reset(CURL *curl)
/* This is our prefered CA cert bundle since install time */
data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
#endif
+
+ data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth
+ type */
}
+
+#ifdef CURL_DOES_CONVERSIONS
+/*
+ * Curl_convert_to_network() is an internal function
+ * for performing ASCII conversions on non-ASCII platforms.
+ */
+CURLcode Curl_convert_to_network(struct SessionHandle *data,
+ char *buffer, size_t length)
+{
+ CURLcode rc;
+
+ if(data->set.convtonetwork) {
+ /* use translation callback */
+ rc = data->set.convtonetwork(buffer, length);
+ if(rc != CURLE_OK) {
+ failf(data,
+ "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s",
+ rc, curl_easy_strerror(rc));
+ }
+ return(rc);
+ } else {
+#ifdef HAVE_ICONV
+ /* do the translation ourselves */
+ char *input_ptr, *output_ptr;
+ size_t in_bytes, out_bytes, rc;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(data->outbound_cd == (iconv_t)-1) {
+ data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST);
+ if(data->outbound_cd == (iconv_t)-1) {
+ failf(data,
+ "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+ CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST,
+ errno, strerror(errno));
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if ((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ failf(data,
+ "The Curl_convert_to_network iconv call failed with errno %i: %s",
+ errno, strerror(errno));
+ return CURLE_CONV_FAILED;
+ }
+#else
+ failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
+ return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_convert_from_network() is an internal function
+ * for performing ASCII conversions on non-ASCII platforms.
+ */
+CURLcode Curl_convert_from_network(struct SessionHandle *data,
+ char *buffer, size_t length)
+{
+ CURLcode rc;
+
+ if(data->set.convfromnetwork) {
+ /* use translation callback */
+ rc = data->set.convfromnetwork(buffer, length);
+ if(rc != CURLE_OK) {
+ failf(data,
+ "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s",
+ rc, curl_easy_strerror(rc));
+ }
+ return(rc);
+ } else {
+#ifdef HAVE_ICONV
+ /* do the translation ourselves */
+ char *input_ptr, *output_ptr;
+ size_t in_bytes, out_bytes, rc;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(data->inbound_cd == (iconv_t)-1) {
+ data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK);
+ if(data->inbound_cd == (iconv_t)-1) {
+ failf(data,
+ "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+ CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK,
+ errno, strerror(errno));
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if ((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ failf(data,
+ "The Curl_convert_from_network iconv call failed with errno %i: %s",
+ errno, strerror(errno));
+ return CURLE_CONV_FAILED;
+ }
+#else
+ failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
+ return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_convert_from_utf8() is an internal function
+ * for performing UTF-8 conversions on non-ASCII platforms.
+ */
+CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
+ char *buffer, size_t length)
+{
+ CURLcode rc;
+
+ if(data->set.convfromutf8) {
+ /* use translation callback */
+ rc = data->set.convfromutf8(buffer, length);
+ if(rc != CURLE_OK) {
+ failf(data,
+ "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s",
+ rc, curl_easy_strerror(rc));
+ }
+ return(rc);
+ } else {
+#ifdef HAVE_ICONV
+ /* do the translation ourselves */
+ char *input_ptr, *output_ptr;
+ size_t in_bytes, out_bytes, rc;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(data->utf8_cd == (iconv_t)-1) {
+ data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_FOR_UTF8);
+ if(data->utf8_cd == (iconv_t)-1) {
+ failf(data,
+ "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+ CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_FOR_UTF8,
+ errno, strerror(errno));
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ rc = iconv(data->utf8_cd, (const char**)&input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if ((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ failf(data,
+ "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
+ errno, strerror(errno));
+ return CURLE_CONV_FAILED;
+ }
+ if (output_ptr < input_ptr) {
+ /* null terminate the now shorter output string */
+ *output_ptr = 0x00;
+ }
+#else
+ failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
+ return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+ }
+
+ return CURLE_OK;
+}
+
+#endif /* CURL_DOES_CONVERSIONS */