From 96dde76b99897352aa3d0877a0b621a9e605733e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 May 2000 14:12:12 +0000 Subject: [PATCH] moved here from the newlib branch --- CHANGES | 33 ++ FAQ | 11 - config-win32.h | 3 + config.h.in | 6 + configure.in | 34 +- curl.1 | 2 +- include/curl/curl.h | 452 ++++++++++----- include/curl/easy.h | 46 ++ include/curl/types.h | 45 ++ lib/Makefile.am | 4 +- lib/Makefile.in | 8 +- lib/cookie.c | 9 +- lib/dict.c | 30 +- lib/dict.h | 3 +- lib/download.c | 509 +---------------- lib/download.h | 4 +- lib/escape.c | 9 +- lib/escape.h | 2 +- lib/file.c | 30 +- lib/file.h | 2 +- lib/formdata.c | 15 +- lib/ftp.c | 436 ++++++++------ lib/ftp.h | 8 +- lib/getdate.c | 4 +- lib/getdate.h | 25 +- lib/getdate.y | 4 +- lib/getenv.c | 30 - lib/http.c | 240 +++++--- lib/http.h | 5 +- lib/ldap.c | 38 +- lib/ldap.h | 3 +- lib/netrc.c | 1 + lib/progress.c | 223 ++++---- lib/progress.h | 5 +- lib/sendf.c | 4 +- lib/setup.h | 4 +- lib/speedcheck.c | 6 +- lib/speedcheck.h | 2 +- lib/ssluse.c | 6 + lib/telnet.c | 36 +- lib/telnet.h | 3 +- lib/url.c | 1177 +++++++++++++++++++------------------- lib/url.h | 44 ++ lib/urldata.h | 235 +++++++- lib/version.c | 2 +- lib/writeout.c | 1 + lib/writeout.h | 4 + maketgz | 13 +- src/Makefile.am | 2 +- src/config-win32.h | 3 + src/hugehelp.c | 1290 +++++++++++++++++++++--------------------- src/main.c | 253 ++++++--- src/urlglob.c | 38 +- src/version.h | 2 +- 54 files changed, 2824 insertions(+), 2580 deletions(-) create mode 100644 include/curl/easy.h create mode 100644 include/curl/types.h diff --git a/CHANGES b/CHANGES index 6863087c3..21803337f 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,39 @@ Version XX +Daniel (21 May 2000) +- Updated lots of #defines, enums and variable type names in the library. No + more weird URG or URLTAG prefixes. All types and names should be curl- + prefixed to avoid name space clashes. The FLAGS-parameter to the former + curl_urlget() has been converted into a bunch of flags to use in separate + setopt calls. I'm still focusing on the easy-interface, as the curl tool is + now using that. + +- Bjorn Reese has provided me with an asynchronous name resolver that I plan + to use in upcoming versions of curl to be able to gracefully timeout name + lookups. + +Version 7.0beta released + +Daniel (18 May 2000) +- Introduced LIBCURL_VERSION_NUM to the curl.h include file to better allow + source codes to be dependent on the lib version. This define is now set to + a dexadecimal number, with 8 bits each for major number, minor number and + patch number. In other words, version 1.2.3 would make it 0x010203. It also + makes a larger number a newer version. + +Daniel (17 May 2000) +- Martin Kammerhofer correctly pointed out several flaws in the FTP range + option. I corrected them. +- Removed the win32 winsock init crap from the lib to the src/main.c file + in the application instead. They can't be in the lib, especially not for + multithreaded purposes. + +Daniel (16 May 2000) +- Rewrote the src/main.c source to use the new easy-interface to libcurl 7. + There is still more work to do, but the first step is now taken. + is the include file to use. + Daniel (14 May 2000) - FTP URLs are now treated slightly different, more according to RFC 1738. - FTP sessions are now performed differently, with CWD commands to change diff --git a/FAQ b/FAQ index 1b120cb0e..1a9fec3dc 100644 --- a/FAQ +++ b/FAQ @@ -83,14 +83,3 @@ configre doesn't find OpenSSL even when it is installed things work Submitted by: Bob Allison - -Will you write a script for me getting ZZZ from YYY? -==================================================== - - No. - - I try to help out to solve issues with curl and related stuff, but I really - do have a lot of stuff on my daily schedule and I'd prefer if you did not - ask me to do your jobs. Writing scripts is very easy. Using curl might be - tricky, but once you're past the initial mistakes the road to success is - very short and straight-forward. diff --git a/config-win32.h b/config-win32.h index 713fdd628..4f6ab62d4 100644 --- a/config-win32.h +++ b/config-win32.h @@ -71,6 +71,9 @@ /* Define if you have the strcasecmp function. */ /*#define HAVE_STRCASECMP 1*/ +/* Define if you have the stricmp function. */ +#define HAVE_STRICMP 1 + /* Define if you have the strdup function. */ #define HAVE_STRDUP 1 diff --git a/config.h.in b/config.h.in index 7157972e7..c9f96d75e 100644 --- a/config.h.in +++ b/config.h.in @@ -82,12 +82,18 @@ /* Define if you have the strcasecmp function. */ #undef HAVE_STRCASECMP +/* Define if you have the strcmpi function. */ +#undef HAVE_STRCMPI + /* Define if you have the strdup function. */ #undef HAVE_STRDUP /* Define if you have the strftime function. */ #undef HAVE_STRFTIME +/* Define if you have the stricmp function. */ +#undef HAVE_STRICMP + /* Define if you have the strstr function. */ #undef HAVE_STRSTR diff --git a/configure.in b/configure.in index d5520cda6..116fa7267 100644 --- a/configure.in +++ b/configure.in @@ -2,13 +2,7 @@ dnl $Id$ dnl Process this file with autoconf to produce a configure script. AC_INIT(lib/urldata.h) AM_CONFIG_HEADER(config.h src/config.h) -AM_INIT_AUTOMAKE(curl,"3-test") - -dnl -dnl Detect the canonical host and target build environment -dnl -AC_CANONICAL_HOST -AC_CANONICAL_TARGET +AM_INIT_AUTOMAKE(curl,"7.0beta") dnl Checks for programs. AC_PROG_CC @@ -26,27 +20,6 @@ dnl ********************************************************************** dnl nsl lib? AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, gethostbyname)) -dnl At least one system has been identified to require BOTH nsl and -dnl socket libs to link properly. -if test "$ac_cv_lib_nsl_gethostbyname" = "$ac_cv_func_gethostbyname"; then - AC_MSG_CHECKING([trying both nsl and socket libs]) - my_ac_save_LIBS=$LIBS - LIBS="-lnsl -lsocket $LIBS" - AC_TRY_LINK( , - [gethostbyname();], - my_ac_link_result=success, - my_ac_link_result=failure ) - - if test "$my_ac_link_result" = "failure"; then - AC_MSG_RESULT([no]) - AC_MSG_ERROR([couldn't find libraries for gethostbyname()]) - dnl restore LIBS - LIBS=$my_ac_save_LIBS - else - AC_MSG_RESULT([yes]) - fi -fi - dnl resolve lib? AC_CHECK_FUNC(strcasecmp, , AC_CHECK_LIB(resolve, strcasecmp)) @@ -219,14 +192,13 @@ AC_CHECK_FUNCS( socket \ RAND_screen ) - - AC_PATH_PROG( PERL, perl, , $PATH:/usr/local/bin/perl:/usr/bin/:/usr/local/bin ) AC_SUBST(PERL) AC_PATH_PROGS( NROFF, gnroff nroff, , $PATH:/usr/bin/:/usr/local/bin ) +AC_SUBST(NROFF) AC_PROG_RANLIB AC_PROG_YACC @@ -236,8 +208,6 @@ dnl $PATH:/usr/bin/:/usr/local/bin ) dnl AC_SUBST(RANLIB) AC_OUTPUT( Makefile \ - curl.spec \ - curl-ssl.spec \ src/Makefile \ lib/Makefile ) dnl perl/checklinks.pl \ diff --git a/curl.1 b/curl.1 index aa2152d2c..7683a117d 100644 --- a/curl.1 +++ b/curl.1 @@ -204,7 +204,7 @@ A quick and very simple example of how to setup a to allow curl to ftp to the machine host.domain.com with user name 'myself' and password 'secret' should look similar to: -.B "machine host.domain.com user myself password secret" +.B "machine host.domain.com login myself password secret" .IP "-N/--no-buffer" Disables the buffering of the output stream. In normal work situations, curl will use a standard buffered output stream that will have the effect that it diff --git a/include/curl/curl.h b/include/curl/curl.h index 8a27c3e73..4226df93b 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1,5 +1,5 @@ -#ifndef __CURL_H -#define __CURL_H +#ifndef __CURL_CURL_H +#define __CURL_CURL_H /***************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -39,6 +39,25 @@ * * ------------------------------------------------------------ ****************************************************************************/ + +/* The include stuff here is mainly for time_t! */ +#ifdef vms +# include +# include +#else +# include +# if TIME_WITH_SYS_TIME +# include +# include +# else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +# endif +#endif /* defined (vms) */ + #ifndef TRUE #define TRUE 1 #endif @@ -46,71 +65,8 @@ #define FALSE 0 #endif +#include -#define CONF_DEFAULT 0 -#define CONF_PROXY (1<<0) /* set if proxy is in use */ -#define CONF_PORT (1<<1) /* set if different port than protcol-defines is - used */ -#define CONF_HTTP (1<<2) /* http get */ -#define CONF_GOPHER (1<<3) /* gopher get */ -#define CONF_FTP (1<<4) /* ftp get (binary mode) */ -#define CONF_VERBOSE (1<<5) /* talk a lot */ - -#define CONF_TELNET (1<<6) - -#define CONF_HEADER (1<<8) /* throw the header out too */ -#define CONF_USERPWD (1<<9) /* user+passwd has been specified */ -#define CONF_NOPROGRESS (1<<10) /* shut off the progress meter (auto) - see also _MUTE */ -#define CONF_NOBODY (1<<11) /* use HEAD to get http document */ -#define CONF_FAILONERROR (1<<12) /* Makes urlget() fail with a return code - WITHOUT writing anything to the output if - a return code >=300 is returned from the - server. */ -#define CONF_RANGE (1<<13) /* Byte-range request, specified parameter is set */ -#define CONF_UPLOAD (1<<14) /* this is an upload, only supported for ftp - currently */ - -#define CONF_POST (1<<15) /* HTTP POST method */ - -/* When getting an FTP directory, this switch makes the listing only show file - names and nothing else. Makes machine parsing of the output possible. This - enforces the NLST command to the ftp server, compared to the otherwise - used: LIST. */ -#define CONF_FTPLISTONLY (1<<16) - -/* Set the referer string */ -#define CONF_REFERER (1<<17) -#define CONF_PROXYUSERPWD (1<<18) /* Proxy user+passwd has been specified */ - -/* For FTP, use PORT instead of PASV! */ -#define CONF_FTPPORT (1<<19) - -/* FTP: Append instead of overwrite on upload! */ -#define CONF_FTPAPPEND (1<<20) - -#define CONF_HTTPS (1<<21) /* Use SSLeay for encrypted communication */ - -#define CONF_NETRC (1<<22) /* read user+password from .netrc */ - -#define CONF_FOLLOWLOCATION (1<<23) /* get the page that the Location: tells - us to get */ - -#define CONF_FTPASCII (1<<24) /* use TYPE A for transfer */ - -#define CONF_HTTPPOST (1<<25) /* this causes a multipart/form-data - HTTP POST */ -#define CONF_NOPROT (1<<26) /* host name specified without protocol */ - -#define CONF_PUT (1<<27) /* PUT the input file */ - -#define CONF_MUTE (1<<28) /* force NOPROGRESS */ - -#define CONF_DICT (1<<29) /* DICT:// protocol */ - -#define CONF_FILE (1<<30) /* FILE:// protocol */ - -#define CONF_LDAP (1<<31) /* LDAP:// protocol */ struct HttpHeader { struct HttpHeader *next; /* next entry in the list */ @@ -132,68 +88,69 @@ struct HttpPost { may return other values, stay prepared. */ typedef enum { - URG_OK = 0, - URG_UNSUPPORTED_PROTOCOL, - URG_FAILED_INIT, - URG_URL_MALFORMAT, - URG_URL_MALFORMAT_USER, - URG_COULDNT_RESOLVE_PROXY, - URG_COULDNT_RESOLVE_HOST, - URG_COULDNT_CONNECT, - URG_FTP_WEIRD_SERVER_REPLY, - URG_FTP_ACCESS_DENIED, - URG_FTP_USER_PASSWORD_INCORRECT, - URG_FTP_WEIRD_PASS_REPLY, - URG_FTP_WEIRD_USER_REPLY, - URG_FTP_WEIRD_PASV_REPLY, - URG_FTP_WEIRD_227_FORMAT, - URG_FTP_CANT_GET_HOST, - URG_FTP_CANT_RECONNECT, - URG_FTP_COULDNT_SET_BINARY, - URG_PARTIAL_FILE, - URG_FTP_COULDNT_RETR_FILE, - URG_FTP_WRITE_ERROR, - URG_FTP_QUOTE_ERROR, - URG_HTTP_NOT_FOUND, - URG_WRITE_ERROR, + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, + CURLE_FAILED_INIT, + CURLE_URL_MALFORMAT, + CURLE_URL_MALFORMAT_USER, + CURLE_COULDNT_RESOLVE_PROXY, + CURLE_COULDNT_RESOLVE_HOST, + CURLE_COULDNT_CONNECT, + CURLE_FTP_WEIRD_SERVER_REPLY, + CURLE_FTP_ACCESS_DENIED, + CURLE_FTP_USER_PASSWORD_INCORRECT, + CURLE_FTP_WEIRD_PASS_REPLY, + CURLE_FTP_WEIRD_USER_REPLY, + CURLE_FTP_WEIRD_PASV_REPLY, + CURLE_FTP_WEIRD_227_FORMAT, + CURLE_FTP_CANT_GET_HOST, + CURLE_FTP_CANT_RECONNECT, + CURLE_FTP_COULDNT_SET_BINARY, + CURLE_PARTIAL_FILE, + CURLE_FTP_COULDNT_RETR_FILE, + CURLE_FTP_WRITE_ERROR, + CURLE_FTP_QUOTE_ERROR, + CURLE_HTTP_NOT_FOUND, + CURLE_WRITE_ERROR, - URG_MALFORMAT_USER, /* the user name is illegally specified */ - URG_FTP_COULDNT_STOR_FILE, /* failed FTP upload */ - URG_READ_ERROR, /* could open/read from file */ + CURLE_MALFORMAT_USER, /* the user name is illegally specified */ + CURLE_FTP_COULDNT_STOR_FILE, /* failed FTP upload */ + CURLE_READ_ERROR, /* could open/read from file */ - URG_OUT_OF_MEMORY, - URG_OPERATION_TIMEOUTED, /* the timeout time was reached */ - URG_FTP_COULDNT_SET_ASCII, /* TYPE A failed */ + CURLE_OUT_OF_MEMORY, + CURLE_OPERATION_TIMEOUTED, /* the timeout time was reached */ + CURLE_FTP_COULDNT_SET_ASCII, /* TYPE A failed */ - URG_FTP_PORT_FAILED, /* FTP PORT operation failed */ + CURLE_FTP_PORT_FAILED, /* FTP PORT operation failed */ - URG_FTP_COULDNT_USE_REST, /* the REST command failed */ - URG_FTP_COULDNT_GET_SIZE, /* the SIZE command failed */ + CURLE_FTP_COULDNT_USE_REST, /* the REST command failed */ + CURLE_FTP_COULDNT_GET_SIZE, /* the SIZE command failed */ - URG_HTTP_RANGE_ERROR, /* The RANGE "command" didn't seem to work */ + CURLE_HTTP_RANGE_ERROR, /* The RANGE "command" didn't seem to work */ - URG_HTTP_POST_ERROR, + CURLE_HTTP_POST_ERROR, - URG_SSL_CONNECT_ERROR, /* something was wrong when connecting with SSL */ + CURLE_SSL_CONNECT_ERROR, /* something was wrong when connecting with SSL */ - URG_FTP_BAD_DOWNLOAD_RESUME, /* couldn't resume download */ + CURLE_FTP_BAD_DOWNLOAD_RESUME, /* couldn't resume download */ - URG_FILE_COULDNT_READ_FILE, + CURLE_FILE_COULDNT_READ_FILE, - URG_LDAP_CANNOT_BIND, - URG_LDAP_SEARCH_FAILED, - URG_LIBRARY_NOT_FOUND, - URG_FUNCTION_NOT_FOUND, + CURLE_LDAP_CANNOT_BIND, + CURLE_LDAP_SEARCH_FAILED, + CURLE_LIBRARY_NOT_FOUND, + CURLE_FUNCTION_NOT_FOUND, + + CURLE_ABORTED_BY_CALLBACK, - URL_LAST -} UrgError; + CURLE_BAD_FUNCTION_ARGUMENT, + CURLE_BAD_CALLING_ORDER, + + CURL_LAST +} CURLcode; /* This is just to make older programs not break: */ -#define URG_FTP_PARTIAL_FILE URG_PARTIAL_FILE - -#define URGTAG_DONE -1 -#define URGTAG_LAST -1 -#define URGTAG_END -1 +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE #define URLGET_ERROR_SIZE 256 @@ -201,19 +158,19 @@ typedef enum { #define URL_MAX_LENGTH 4096 #define URL_MAX_LENGTH_TXT "4095" -/* name is uppercase URGTAG_, - type is one of the defined URGTYPE_ +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ number is unique identifier */ -#define T(name,type,number) URGTAG_ ## name = URGTYPE_ ## type + number +#define T(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number /* long may be 32 or 64 bits, but we should never depend on anything else but 32 */ -#define URGTYPE_LONG 0 -#define URGTYPE_OBJECTPOINT 10000 -#define URGTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 typedef enum { - URGTAG_NOTHING, /* the first unused */ + T(NOTHING, LONG, 0), /********* the first one is unused ************/ /* This is the FILE * the regular output should be written to. */ T(FILE, OBJECTPOINT, 1), @@ -222,28 +179,29 @@ typedef enum { T(URL, OBJECTPOINT, 2), /* Port number to connect to, if other than default. Specify the CONF_PORT - flag in the URGTAG_FLAGS to activate this */ + flag in the CURLOPT_FLAGS to activate this */ T(PORT, LONG, 3), - /* Name of proxy to use. Specify the CONF_PROXY flag in the URGTAG_FLAGS to + /* Name of proxy to use. Specify the CONF_PROXY flag in the CURLOPT_FLAGS to activate this */ T(PROXY, OBJECTPOINT, 4), /* Name and password to use when fetching. Specify the CONF_USERPWD flag in - the URGTAG_FLAGS to activate this */ + the CURLOPT_FLAGS to activate this */ T(USERPWD, OBJECTPOINT, 5), /* Name and password to use with Proxy. Specify the CONF_PROXYUSERPWD - flag in the URGTAG_FLAGS to activate this */ + flag in the CURLOPT_FLAGS to activate this */ T(PROXYUSERPWD, OBJECTPOINT, 6), /* Range to get, specified as an ASCII string. Specify the CONF_RANGE flag - in the URGTAG_FLAGS to activate this */ + in the CURLOPT_FLAGS to activate this */ T(RANGE, OBJECTPOINT, 7), +#if 0 /* Configuration flags */ T(FLAGS, LONG, 8), - +#endif /* Specified file stream to upload from (use as input): */ T(INFILE, OBJECTPOINT, 9), @@ -262,7 +220,7 @@ typedef enum { /* Time-out the read operation after this amount of seconds */ T(TIMEOUT, LONG, 13), - /* If the URGTAG_INFILE is used, this can be used to inform urlget about how + /* If the CURLOPT_INFILE is used, this can be used to inform urlget about how large the file being sent really is. That allows better error checking and better verifies that the upload was succcessful. -1 means unknown size. */ @@ -364,8 +322,25 @@ typedef enum { as described elsewhere. */ T(WRITEINFO, OBJECTPOINT, 40), - URGTAG_LASTENTRY /* the last unusued */ -} UrgTag; + /* Previous FLAG bits */ + T(VERBOSE, LONG, 41), /* talk a lot */ + T(HEADER, LONG, 42), /* throw the header out too */ + T(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + T(NOBODY, LONG, 44), /* use HEAD to get http document */ + T(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */ + T(UPLOAD, LONG, 46), /* this is an upload */ + T(POST, LONG, 47), /* HTTP POST method */ + T(FTPLISTONLY, LONG, 48), /* Use NLST when listing ftp dir */ + + T(FTPAPPEND, LONG, 50), /* Append instead of overwrite on upload! */ + T(NETRC, LONG, 51), /* read user+password from .netrc */ + T(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + T(FTPASCII, LONG, 53), /* use TYPE A for transfer */ + T(PUT, LONG, 54), /* PUT the input file */ + T(MUTE, LONG, 55), /* force NOPROGRESS */ + + CURLOPT_LASTENTRY /* the last unusued */ +} CURLoption; #define CURL_PROGRESS_STATS 0 /* default progress display */ #define CURL_PROGRESS_BAR 1 @@ -388,23 +363,11 @@ typedef char bool; #endif /* (rabe) */ #endif -/********************************************************************** - * - * >>> urlget() interface #defines changed in v5! <<< - * - * You enter parameters as tags. Tags are specified as a pair of parameters. - * The first parameter in a pair is the tag identifier, telling urlget what - * kind of tag it is, and the second is the data. The tags may come in any - * order but MUST ALWAYS BE TERMINATED with an ending URGTAG_DONE (which - * needs no data). - * - * _Very_ simple example: - * - * curl_urlget(URGTAG_URL, "http://www.fts.frontec.se/~dast/", URGTAG_DONE); - * - ***********************************************************************/ - +#if 0 +/* At last, I stand here in front of you today and can officially proclaim + this function prototype as history... 17th of May, 2000 */ UrgError curl_urlget(UrgTag, ...); +#endif /* external form function */ int curl_FormParse(char *string, @@ -418,9 +381,10 @@ char *curl_GetEnv(char *variable); char *curl_version(void); /* This is the version number */ -#define LIBCURL_VERSION "6.5.2" +#define LIBCURL_VERSION "7.0beta" +#define LIBCURL_VERSION_NUM 0x070000 -/* linked-list structure for QUOTE */ +/* linked-list structure for the CURLOPT_QUOTE option */ struct curl_slist { char *data; struct curl_slist *next; @@ -429,4 +393,192 @@ struct curl_slist { struct curl_slist *curl_slist_append(struct curl_slist *list, char *data); void curl_slist_free_all(struct curl_slist *list); -#endif /* __URLGET_H */ +/* + * NAME curl_init() + * + * DESCRIPTION + * + * Inits libcurl globally. This must be used before any libcurl calls can + * be used. This may install global plug-ins or whatever. (This does not + * do winsock inits in Windows.) + * + * EXAMPLE + * + * curl_init(); + * + */ +CURLcode curl_init(void); + +/* + * NAME curl_init() + * + * DESCRIPTION + * + * Frees libcurl globally. This must be used after all libcurl calls have + * been used. This may remove global plug-ins or whatever. (This does not + * do winsock cleanups in Windows.) + * + * EXAMPLE + * + * curl_free(curl); + * + */ +void curl_free(void); + +/* + * NAME curl_open() + * + * DESCRIPTION + * + * Opens a general curl session. It does not try to connect or do anything + * on the network because of this call. The specified URL is only required + * to enable curl to figure out what protocol to "activate". + * + * A session should be looked upon as a series of requests to a single host. A + * session interacts with one host only, using one single protocol. + * + * The URL is not required. If set to "" or NULL, it can still be set later + * using the curl_setopt() function. If the curl_connect() function is called + * without the URL being known, it will return error. + * + * EXAMPLE + * + * CURLcode result; + * CURL *curl; + * result = curl_open(&curl, "http://curl.haxx.nu/libcurl/"); + * if(result != CURL_OK) { + * return result; + * } + * */ +CURLcode curl_open(CURL **curl, char *url); + +/* + * NAME curl_setopt() + * + * DESCRIPTION + * + * Sets a particular option to the specified value. + * + * EXAMPLE + * + * CURL curl; + * curl_setopt(curl, CURL_HTTP_FOLLOW_LOCATION, TRUE); + */ +CURLcode curl_setopt(CURL *handle, CURLoption option, ...); + +/* + * NAME curl_close() + * + * DESCRIPTION + * + * Closes a session previously opened with curl_open() + * + * EXAMPLE + * + * CURL *curl; + * CURLcode result; + * + * result = curl_close(curl); + */ +CURLcode curl_close(CURL *curl); /* the opposite of curl_open() */ + +CURLcode curl_read(CURLconnect *c_conn, char *buf, size_t buffersize, + size_t *n); +CURLcode curl_write(CURLconnect *c_conn, char *buf, size_t amount, + size_t *n); + +/* + * NAME curl_connect() + * + * DESCRIPTION + * + * Connects to the peer server and performs the initial setup. This function + * writes a connect handle to its second argument that is a unique handle for + * this connect. This allows multiple connects from the same handle returned + * by curl_open(). + * + * EXAMPLE + * + * CURLCode result; + * CURL curl; + * CURLconnect connect; + * result = curl_connect(curl, &connect); + */ + +CURLcode curl_connect(CURL *curl, CURLconnect **in_connect); + +/* + * NAME curl_do() + * + * DESCRIPTION + * + * (Note: May 3rd 2000: this function does not currently allow you to + * specify a document, it will use the one set previously) + * + * This function asks for the particular document, file or resource that + * resides on the server we have connected to. You may specify a full URL, + * just an absolute path or even a relative path. That means, if you're just + * getting one file from the remote site, you can use the same URL as input + * for both curl_open() as well as for this function. + * + * In the even there is a host name, port number, user name or password parts + * in the URL, you can use the 'flags' argument to ignore them completely, or + * at your choice, make the function fail if you're trying to get a URL from + * different host than you connected to with curl_connect(). + * + * You can only get one document at a time using the same connection. When one + * document has been received you can although request again. + * + * When the transfer is done, curl_done() MUST be called. + * + * EXAMPLE + * + * CURLCode result; + * char *url; + * CURLconnect *connect; + * result = curl_do(connect, url, CURL_DO_NONE); */ +CURLcode curl_do(CURLconnect *in_conn); + +/* + * NAME curl_done() + * + * DESCRIPTION + * + * When the transfer following a curl_do() call is done, this function should + * get called. + * + * EXAMPLE + * + * CURLCode result; + * char *url; + * CURLconnect *connect; + * result = curl_done(connect); */ +CURLcode curl_done(CURLconnect *connect); + +/* + * NAME curl_disconnect() + * + * DESCRIPTION + * + * Disconnects from the peer server and performs connection cleanup. + * + * EXAMPLE + * + * CURLcode result; + * CURLconnect *connect; + * result = curl_disconnect(connect); */ +CURLcode curl_disconnect(CURLconnect *connect); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is for cases + * where the specified time is relative now, like 'two weeks' or 'tomorrow' + * etc. + */ +time_t curl_getdate(const char *p, const time_t *now); + +#endif /* __CURL_CURL_H */ diff --git a/include/curl/easy.h b/include/curl/easy.h new file mode 100644 index 000000000..687696c2c --- /dev/null +++ b/include/curl/easy.h @@ -0,0 +1,46 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +CURL *curl_easy_init(void); +CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURLcode curl_easy_perform(CURL *curl); +void curl_easy_cleanup(CURL *curl); +#endif diff --git a/include/curl/types.h b/include/curl/types.h new file mode 100644 index 000000000..15f7067e4 --- /dev/null +++ b/include/curl/types.h @@ -0,0 +1,45 @@ +#ifndef __CURL_TYPES_H +#define __CURL_TYPES_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +typedef void CURL; +typedef void CURLconnect; + +#endif /* __CURL_TYPES_H */ diff --git a/lib/Makefile.am b/lib/Makefile.am index 3951d88a0..02f25152e 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -7,7 +7,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libcurl.a # Some flags needed when trying to cause warnings ;-) -#CFLAGS = -g -Wall -pedantic +CFLAGS = -g -Wall #-pedantic INCLUDES = -I$(top_srcdir)/include @@ -23,7 +23,7 @@ download.c getdate.h ldap.c ssluse.c version.c \ download.h getenv.c ldap.h ssluse.h \ escape.c getenv.h mprintf.c telnet.c \ escape.h getpass.c netrc.c telnet.h \ -writeout.c writeout.h +writeout.c writeout.h highlevel.c strequal.c strequal.h easy.c # Say $(srcdir), so GNU make does not report an ambiguity with the .y.c rule. $(srcdir)/getdate.c: getdate.y diff --git a/lib/Makefile.in b/lib/Makefile.in index 84be952ee..aece159e1 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -77,11 +77,11 @@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libcurl.a # Some flags needed when trying to cause warnings ;-) -#CFLAGS = -g -Wall -pedantic +CFLAGS = -g -Wall #-pedantic INCLUDES = -I$(top_srcdir)/include -libcurl_a_SOURCES = arpa_telnet.h file.c getpass.h netrc.h timeval.c base64.c file.h hostip.c progress.c timeval.h base64.h formdata.c hostip.h progress.h cookie.c formdata.h http.c sendf.c cookie.h ftp.c http.h sendf.h url.c dict.c ftp.h if2ip.c speedcheck.c url.h dict.h getdate.c if2ip.h speedcheck.h urldata.h download.c getdate.h ldap.c ssluse.c version.c download.h getenv.c ldap.h ssluse.h escape.c getenv.h mprintf.c telnet.c escape.h getpass.c netrc.c telnet.h writeout.c writeout.h +libcurl_a_SOURCES = arpa_telnet.h file.c getpass.h netrc.h timeval.c base64.c file.h hostip.c progress.c timeval.h base64.h formdata.c hostip.h progress.h cookie.c formdata.h http.c sendf.c cookie.h ftp.c http.h sendf.h url.c dict.c ftp.h if2ip.c speedcheck.c url.h dict.h getdate.c if2ip.h speedcheck.h urldata.h download.c getdate.h ldap.c ssluse.c version.c download.h getenv.c ldap.h ssluse.h escape.c getenv.h mprintf.c telnet.c escape.h getpass.c netrc.c telnet.h writeout.c writeout.h highlevel.c strequal.c strequal.h easy.c mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = ../config.h ../src/config.h @@ -97,9 +97,9 @@ libcurl_a_LIBADD = libcurl_a_OBJECTS = file.o timeval.o base64.o hostip.o progress.o \ formdata.o cookie.o http.o sendf.o ftp.o url.o dict.o if2ip.o \ speedcheck.o getdate.o download.o ldap.o ssluse.o version.o getenv.o \ -escape.o mprintf.o telnet.o getpass.o netrc.o writeout.o +escape.o mprintf.o telnet.o getpass.o netrc.o writeout.o highlevel.o \ +strequal.o easy.o AR = ar -CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ diff --git a/lib/cookie.c b/lib/cookie.c index 00497bc94..8038dafe3 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -62,6 +62,7 @@ Example set of cookies: #include "cookie.h" #include "setup.h" #include "getdate.h" +#include "strequal.h" /**************************************************************************** * @@ -131,7 +132,7 @@ struct Cookie *cookie_add(struct CookieInfo *c, } else if(strequal("expires", name)) { co->expirestr=strdup(what); - co->expires = get_date(what, &now); + co->expires = curl_getdate(what, &now); } else if(!co->name) { co->name = strdup(name); @@ -173,9 +174,11 @@ struct Cookie *cookie_add(struct CookieInfo *c, return NULL; } /* strip off the possible end-of-line characters */ - if(ptr=strchr(lineptr, '\r')) + ptr=strchr(lineptr, '\r'); + if(ptr) *ptr=0; /* clear it */ - if(ptr=strchr(lineptr, '\n')) + ptr=strchr(lineptr, '\n'); + if(ptr) *ptr=0; /* clear it */ firstptr=strtok(lineptr, "\t"); /* first tokenize it on the TAB */ diff --git a/lib/dict.c b/lib/dict.c index cf604ec5b..c9721bd85 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -92,12 +92,17 @@ #include "sendf.h" #include "progress.h" +#include "strequal.h" #define _MPRINTF_REPLACE /* use our functions only */ #include +CURLcode dict_done(struct connectdata *conn) +{ + return CURLE_OK; +} -UrgError dict(struct UrlData *data, char *path, long *bytecount) +CURLcode dict(struct connectdata *conn) { int nth; char *word; @@ -106,9 +111,13 @@ UrgError dict(struct UrlData *data, char *path, long *bytecount) char *strategy = NULL; char *nthdef = NULL; /* This is not part of the protocol, but required by RFC 2229 */ - UrgError result=URG_OK; - - if(data->conf & CONF_USERPWD) { + CURLcode result=CURLE_OK; + struct UrlData *data=conn->data; + + char *path = conn->path; + long *bytecount = &conn->bytecount; + + if(data->bits.user_passwd) { /* AUTH is missing */ } @@ -162,7 +171,7 @@ UrgError dict(struct UrlData *data, char *path, long *bytecount) word ); - result = Transfer(data, data->firstsocket, -1, FALSE, bytecount, + result = Transfer(conn, data->firstsocket, -1, FALSE, bytecount, -1, NULL); /* no upload */ if(result) @@ -210,7 +219,7 @@ UrgError dict(struct UrlData *data, char *path, long *bytecount) word ); - result = Transfer(data, data->firstsocket, -1, FALSE, bytecount, + result = Transfer(conn, data->firstsocket, -1, FALSE, bytecount, -1, NULL); /* no upload */ if(result) @@ -234,7 +243,7 @@ UrgError dict(struct UrlData *data, char *path, long *bytecount) "QUIT\n", ppath); - result = Transfer(data, data->firstsocket, -1, FALSE, bytecount, + result = Transfer(conn, data->firstsocket, -1, FALSE, bytecount, -1, NULL); if(result) @@ -243,10 +252,5 @@ UrgError dict(struct UrlData *data, char *path, long *bytecount) } } -#if 0 - ProgressEnd(data); -#endif - pgrsDone(data); - - return URG_OK; + return CURLE_OK; } diff --git a/lib/dict.h b/lib/dict.h index edff0c434..85e6e3b09 100644 --- a/lib/dict.h +++ b/lib/dict.h @@ -40,6 +40,7 @@ * * ------------------------------------------------------------ ****************************************************************************/ -UrgError dict(struct UrlData *data, char *path, long *bytecountp); +CURLcode dict(struct connectdata *conn); +CURLcode dict_done(struct connectdata *conn); #endif diff --git a/lib/download.c b/lib/download.c index 380330b1b..d7ba12b36 100644 --- a/lib/download.c +++ b/lib/download.c @@ -78,20 +78,16 @@ #include "speedcheck.h" #include "sendf.h" -#ifdef USE_ZLIB -#include -#endif - -#define MAX(x,y) ((x)>(y)?(x):(y)) +#include /* --- download and upload a stream from/to a socket --- */ /* Parts of this function was brought to us by the friendly Mark Butler . */ -UrgError -Transfer (struct UrlData *data, - /* READ stuff */ +CURLcode +Transfer(CURLconnect *c_conn, + /* READ stuff */ int sockfd, /* socket to read from or -1 */ int size, /* -1 if unknown at this point */ bool getheader, /* TRUE if header parsing is wanted */ @@ -101,492 +97,21 @@ Transfer (struct UrlData *data, int writesockfd, /* socket to write to, it may very well be the same we read from. -1 disables */ long *writebytecountp /* return number of bytes written or NULL */ - - -) + ) { - char *buf = data->buffer; - size_t nread; - int bytecount = 0; /* number of bytes read */ - int writebytecount = 0; /* number of bytes written */ - long contentlength=0; /* size of incoming data */ - struct timeval start = tvnow(); - struct timeval now = start; - bool header = TRUE; /* incoming data has HTTP header */ - int headerline = 0; /* counts header lines to better track the - first one */ + struct connectdata *conn = (struct connectdata *)c_conn; + if(!conn) + return CURLE_BAD_FUNCTION_ARGUMENT; - char *hbufp; /* points at *end* of header line */ - int hbuflen = 0; - char *str; /* within buf */ - char *str_start; /* within buf */ - char *end_ptr; /* within buf */ - char *p; /* within headerbuff */ - bool content_range = FALSE; /* set TRUE if Content-Range: was found */ - int offset = 0; /* possible resume offset read from the - Content-Range: header */ - int code = 0; /* error code from the 'HTTP/1.? XXX' line */ + /* now copy all input parameters */ + conn->sockfd = sockfd; + conn->size = size; + conn->getheader = getheader; + conn->bytecountp = bytecountp; + conn->writesockfd = writesockfd; + conn->writebytecountp = writebytecountp; - /* for the low speed checks: */ - UrgError urg; - time_t timeofdoc=0; - long bodywrites=0; + return CURLE_OK; - char newurl[URL_MAX_LENGTH]; /* buffer for Location: URL */ - - /* the highest fd we use + 1 */ - int maxfd = (sockfd>writesockfd?sockfd:writesockfd)+1; - - hbufp = data->headerbuff; - - myalarm (0); /* switch off the alarm-style timeout */ - - now = tvnow(); - start = now; - -#define KEEP_READ 1 -#define KEEP_WRITE 2 - - pgrsTime(data, TIMER_PRETRANSFER); - - if (!getheader) { - header = FALSE; - if(size > 0) - pgrsSetDownloadSize(data, size); - } - { - fd_set readfd; - fd_set writefd; - fd_set rkeepfd; - fd_set wkeepfd; - struct timeval interval; - int keepon=0; - - /* timeout every X second - - makes a better progressmeter (i.e even when no data is read, the - meter can be updated and reflect reality) - - allows removal of the alarm() crap - - variable timeout is easier - */ - - FD_ZERO (&readfd); /* clear it */ - if(sockfd != -1) { - FD_SET (sockfd, &readfd); /* read socket */ - keepon |= KEEP_READ; - } - - FD_ZERO (&writefd); /* clear it */ - if(writesockfd != -1) { - FD_SET (writesockfd, &writefd); /* write socket */ - keepon |= KEEP_WRITE; - } - - /* get these in backup variables to be able to restore them on each lap in - the select() loop */ - rkeepfd = readfd; - wkeepfd = writefd; - - while (keepon) { - readfd = rkeepfd; /* set those every lap in the loop */ - writefd = wkeepfd; - interval.tv_sec = 1; - interval.tv_usec = 0; - - switch (select (maxfd, &readfd, &writefd, NULL, &interval)) { - case -1: /* select() error, stop reading */ -#ifdef EINTR - /* The EINTR is not serious, and it seems you might get this more - ofen when using the lib in a multi-threaded environment! */ - if(errno == EINTR) - ; - else -#endif - keepon = 0; /* no more read or write */ - continue; - case 0: /* timeout */ - break; - default: - if((keepon & KEEP_READ) && FD_ISSET(sockfd, &readfd)) { - /* read! */ -#ifdef USE_SSLEAY - if (data->use_ssl) { - nread = SSL_read (data->ssl, buf, BUFSIZE - 1); - } - else { -#endif - nread = sread (sockfd, buf, BUFSIZE - 1); -#ifdef USE_SSLEAY - } -#endif /* USE_SSLEAY */ - - /* NULL terminate, allowing string ops to be used */ - if (0 < (signed int) nread) - buf[nread] = 0; - - /* if we receive 0 or less here, the server closed the connection and - we bail out from this! */ - else if (0 >= (signed int) nread) { - keepon &= ~KEEP_READ; - break; - } - - str = buf; /* Default buffer to use when we write the - buffer, it may be changed in the flow below - before the actual storing is done. */ - - /* Since this is a two-state thing, we check if we are parsing - headers at the moment or not. */ - - if (header) { - /* we are in parse-the-header-mode */ - - /* header line within buffer loop */ - do { - int hbufp_index; - - str_start = str; /* str_start is start of line within buf */ - - end_ptr = strchr (str_start, '\n'); - - if (!end_ptr) { - /* no more complete header lines within buffer */ - /* copy what is remaining into headerbuff */ - int str_length = (int)strlen(str); - - if (hbuflen + (int)str_length >= data->headersize) { - char *newbuff; - long newsize=MAX((hbuflen+str_length)*3/2, - data->headersize*2); - hbufp_index = hbufp - data->headerbuff; - newbuff = (char *)realloc(data->headerbuff, newsize); - if(!newbuff) { - failf (data, "Failed to alloc memory for big header!"); - return URG_READ_ERROR; - } - data->headersize=newsize; - data->headerbuff = newbuff; - hbufp = data->headerbuff + hbufp_index; - } - strcpy (hbufp, str); - hbufp += strlen (str); - hbuflen += strlen (str); - break; /* read more and try again */ - } - - str = end_ptr + 1; /* move just past new line */ - - if (hbuflen + (str - str_start) >= data->headersize) { - char *newbuff; - long newsize=MAX((hbuflen+(str-str_start))*3/2, - data->headersize*2); - hbufp_index = hbufp - data->headerbuff; - newbuff = (char *)realloc(data->headerbuff, newsize); - if(!newbuff) { - failf (data, "Failed to alloc memory for big header!"); - return URG_READ_ERROR; - } - data->headersize= newsize; - data->headerbuff = newbuff; - hbufp = data->headerbuff + hbufp_index; - } - - /* copy to end of line */ - strncpy (hbufp, str_start, str - str_start); - hbufp += str - str_start; - hbuflen += str - str_start; - *hbufp = 0; - - p = data->headerbuff; - - /* we now have a full line that p points to */ - if (('\n' == *p) || ('\r' == *p)) { - /* Zero-length line means end of header! */ - if (-1 != size) /* if known */ - size += bytecount; /* we append the already read size */ - - - if ('\r' == *p) - p++; /* pass the \r byte */ - if ('\n' == *p) - p++; /* pass the \n byte */ - - pgrsSetDownloadSize(data, size); - - header = FALSE; /* no more header to parse! */ - - /* now, only output this if the header AND body are requested: - */ - if ((data->conf & (CONF_HEADER | CONF_NOBODY)) == - CONF_HEADER) { - if((p - data->headerbuff) != - data->fwrite (data->headerbuff, 1, - p - data->headerbuff, data->out)) { - failf (data, "Failed writing output"); - return URG_WRITE_ERROR; - } - } - if(data->writeheader) { - /* obviously, the header is requested to be written to - this file: */ - if((p - data->headerbuff) != - data->fwrite (data->headerbuff, 1, p - data->headerbuff, - data->writeheader)) { - failf (data, "Failed writing output"); - return URG_WRITE_ERROR; - } - } - break; /* exit header line loop */ - } - - if (!headerline++) { - /* This is the first header, it MUST be the error code line - or else we consiser this to be the body right away! */ - if (sscanf (p, " HTTP/1.%*c %3d", &code)) { - /* 404 -> URL not found! */ - if ( - ( ((data->conf & CONF_FOLLOWLOCATION) && (code >= 400)) - || - !(data->conf & CONF_FOLLOWLOCATION) && (code >= 300)) - && (data->conf & CONF_FAILONERROR)) { - /* If we have been told to fail hard on HTTP-errors, - here is the check for that: */ - /* serious error, go home! */ - failf (data, "The requested file was not found"); - return URG_HTTP_NOT_FOUND; - } - data->progress.httpcode = code; - } - else { - header = FALSE; /* this is not a header line */ - break; - } - } - /* check for Content-Length: header lines to get size */ - if (strnequal("Content-Length", p, 14) && - sscanf (p+14, ": %ld", &contentlength)) - size = contentlength; - else if (strnequal("Content-Range", p, 13) && - sscanf (p+13, ": bytes %d-", &offset)) { - if (data->resume_from == offset) { - /* we asked for a resume and we got it */ - content_range = TRUE; - } - } - else if(data->cookies && - strnequal("Set-Cookie: ", p, 11)) { - cookie_add(data->cookies, TRUE, &p[12]); - } - else if(strnequal("Last-Modified:", p, - strlen("Last-Modified:")) && - data->timecondition) { - time_t secs=time(NULL); - timeofdoc = get_date(p+strlen("Last-Modified:"), &secs); - } - else if ((code >= 300 && code < 400) && - (data->conf & CONF_FOLLOWLOCATION) && - strnequal("Location", p, 8) && - sscanf (p+8, ": %" URL_MAX_LENGTH_TXT "s", newurl)) { - /* this is the URL that the server advices us to get - instead */ - data->newurl = strdup (newurl); - } - - if (data->conf & CONF_HEADER) { - if(hbuflen != data->fwrite (p, 1, hbuflen, data->out)) { - failf (data, "Failed writing output"); - return URG_WRITE_ERROR; - } - } - if(data->writeheader) { - /* the header is requested to be written to this file */ - if(hbuflen != data->fwrite (p, 1, hbuflen, - data->writeheader)) { - failf (data, "Failed writing output"); - return URG_WRITE_ERROR; - } - } - - /* reset hbufp pointer && hbuflen */ - hbufp = data->headerbuff; - hbuflen = 0; - } - while (*str); /* header line within buffer */ - - /* We might have reached the end of the header part here, but - there might be a non-header part left in the end of the read - buffer. */ - - if (!header) { - /* the next token and forward is not part of - the header! */ - - /* we subtract the remaining header size from the buffer */ - nread -= (str - buf); - } - - } /* end if header mode */ - - /* This is not an 'else if' since it may be a rest from the header - parsing, where the beginning of the buffer is headers and the end - is non-headers. */ - if (str && !header && (nread > 0)) { - - if(0 == bodywrites) { - /* These checks are only made the first time we are about to - write a chunk of the body */ - if(data->conf&CONF_HTTP) { - /* HTTP-only checks */ - if (data->resume_from && !content_range ) { - /* we wanted to resume a download, although the server - doesn't seem to support this */ - failf (data, "HTTP server doesn't seem to support byte ranges. Cannot resume."); - return URG_HTTP_RANGE_ERROR; - } - else if (data->newurl) { - /* abort after the headers if "follow Location" is set */ - infof (data, "Follow to new URL: %s\n", data->newurl); - return URG_OK; - } - else if(data->timecondition && !data->range) { - /* A time condition has been set AND no ranges have been - requested. This seems to be what chapter 13.3.4 of - RFC 2616 defines to be the correct action for a - HTTP/1.1 client */ - if((timeofdoc > 0) && (data->timevalue > 0)) { - switch(data->timecondition) { - case TIMECOND_IFMODSINCE: - default: - if(timeofdoc < data->timevalue) { - infof(data, - "The requested document is not new enough"); - return URG_OK; - } - break; - case TIMECOND_IFUNMODSINCE: - if(timeofdoc > data->timevalue) { - infof(data, - "The requested document is not old enough"); - return URG_OK; - } - break; - } /* switch */ - } /* two valid time strings */ - } /* we have a time condition */ - } /* this is HTTP */ - } /* this is the first time we write a body part */ - bodywrites++; - - if(data->maxdownload && - (bytecount + nread > data->maxdownload)) { - nread = data->maxdownload - bytecount; - if(nread < 0 ) /* this should be unusual */ - nread = 0; - keepon &= ~KEEP_READ; /* we're done reading */ - } - - bytecount += nread; - - pgrsSetDownloadCounter(data, (double)bytecount); - - if (nread != data->fwrite (str, 1, nread, data->out)) { - failf (data, "Failed writing output"); - return URG_WRITE_ERROR; - } - - } /* if (! header and data to read ) */ - } /* if( read from socket ) */ - - if((keepon & KEEP_WRITE) && FD_ISSET(writesockfd, &writefd)) { - /* write */ - - char scratch[BUFSIZE * 2]; - int i, si; - int bytes_written; - - if(data->crlf) - buf = data->buffer; /* put it back on the buffer */ - - nread = data->fread(buf, 1, BUFSIZE, data->in); - writebytecount += nread; - - pgrsSetUploadCounter(data, (double)writebytecount); - - if (nread<=0) { - /* done */ - keepon &= ~KEEP_WRITE; /* we're done writing */ - break; - } - - /* convert LF to CRLF if so asked */ - if (data->crlf) { - for(i = 0, si = 0; i < (int)nread; i++, si++) { - if (buf[i] == 0x0a) { - scratch[si++] = 0x0d; - scratch[si] = 0x0a; - } - else { - scratch[si] = buf[i]; - } - } - nread = si; - buf = scratch; /* point to the new buffer */ - } - - /* write to socket */ -#ifdef USE_SSLEAY - if (data->use_ssl) { - bytes_written = SSL_write(data->ssl, buf, nread); - } - else { -#endif - bytes_written = swrite(writesockfd, buf, nread); -#ifdef USE_SSLEAY - } -#endif /* USE_SSLEAY */ - if(nread != bytes_written) { - failf(data, "Failed uploading data"); - return URG_WRITE_ERROR; - } - - } - - break; - } - - now = tvnow(); - pgrsUpdate(data); - - urg = speedcheck (data, now); - if (urg) - return urg; - - if (data->timeout && (tvdiff (now, start) > data->timeout)) { - failf (data, "Operation timed out with %d out of %d bytes received", - bytecount, size); - return URG_OPERATION_TIMEOUTED; - } -#ifdef MULTIDOC - if(contentlength && bytecount >= contentlength) { - /* we're done with this download, now stop it */ - break; - } -#endif - } - } - if(!(data->conf&CONF_NOBODY) && contentlength && - (bytecount != contentlength)) { - failf(data, "transfer closed with %d bytes remaining to read", - contentlength-bytecount); - return URG_PARTIAL_FILE; - } - pgrsUpdate(data); - - if(bytecountp) - *bytecountp = bytecount; /* read count */ - if(writebytecountp) - *writebytecountp = writebytecount; /* write count */ - - return URG_OK; } - - + diff --git a/lib/download.h b/lib/download.h index 414085df4..86ba03498 100644 --- a/lib/download.h +++ b/lib/download.h @@ -39,8 +39,8 @@ * * ------------------------------------------------------------ ****************************************************************************/ -UrgError -Transfer (struct UrlData *data, +CURLcode +Transfer (struct connectdata *data, int sockfd, /* socket to read from or -1 */ int size, /* -1 if unknown at this point */ bool getheader, /* TRUE if header parsing is wanted */ diff --git a/lib/escape.c b/lib/escape.c index 274cd2dcd..6ac8847a6 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -81,16 +81,15 @@ char *curl_escape(char *string) return ns; } -char *curl_unescape(char *string) +char *curl_unescape(char *string, int length) { - int alloc = strlen(string)+1; + int alloc = (length?length:strlen(string))+1; char *ns = malloc(alloc); unsigned char in; int index=0; int hex; - - - while(*string) { + + while(--alloc) { in = *string; if('+' == in) in = ' '; diff --git a/lib/escape.h b/lib/escape.h index bca4d8bd9..5c080c209 100644 --- a/lib/escape.h +++ b/lib/escape.h @@ -44,6 +44,6 @@ * allocated string or NULL if an error occurred. */ char *curl_escape(char *string); -char *curl_unescape(char *string); +char *curl_unescape(char *string, int length); #endif diff --git a/lib/file.c b/lib/file.c index af966016b..532a65fb3 100644 --- a/lib/file.c +++ b/lib/file.c @@ -100,23 +100,25 @@ #include -UrgError file(struct UrlData *data, char *path, long *bytecountp) +CURLcode file(struct connectdata *conn) { /* This implementation ignores the host name in conformance with RFC 1738. Only local files (reachable via the standard file system) are supported. This means that files on remotely mounted directories (via NFS, Samba, NT sharing) can be accessed through a file:// URL */ - + CURLcode res = CURLE_OK; + char *path = conn->path; struct stat statbuf; size_t expected_size=-1; size_t nread; + struct UrlData *data = conn->data; char *buf = data->buffer; int bytecount = 0; struct timeval start = tvnow(); struct timeval now = start; int fd; - char *actual_path = curl_unescape(path); + char *actual_path = curl_unescape(path, 0); #if defined(WIN32) || defined(__EMX__) int i; @@ -134,7 +136,7 @@ UrgError file(struct UrlData *data, char *path, long *bytecountp) if(fd == -1) { failf(data, "Couldn't open file %s", path); - return URG_FILE_COULDNT_READ_FILE; + return CURLE_FILE_COULDNT_READ_FILE; } if( -1 != fstat(fd, &statbuf)) { /* we could stat it, then read out the size */ @@ -151,7 +153,7 @@ UrgError file(struct UrlData *data, char *path, long *bytecountp) if(expected_size != -1) pgrsSetDownloadSize(data, expected_size); - while (1) { + while (res == CURLE_OK) { nread = read(fd, buf, BUFSIZE-1); if (0 <= nread) @@ -166,21 +168,19 @@ UrgError file(struct UrlData *data, char *path, long *bytecountp) file descriptor). */ if(nread != data->fwrite (buf, 1, nread, data->out)) { failf (data, "Failed writing output"); - return URG_WRITE_ERROR; + return CURLE_WRITE_ERROR; } now = tvnow(); - pgrsUpdate(data); -#if 0 - ProgressShow (data, bytecount, start, now, FALSE); -#endif + if(pgrsUpdate(data)) + res = CURLE_ABORTED_BY_CALLBACK; } now = tvnow(); -#if 0 - ProgressShow (data, bytecount, start, now, TRUE); -#endif - pgrsUpdate(data); + if(pgrsUpdate(data)) + res = CURLE_ABORTED_BY_CALLBACK; close(fd); - return URG_OK; + free(actual_path); + + return res; } diff --git a/lib/file.h b/lib/file.h index eeaeef4f4..e6ad0e6ce 100644 --- a/lib/file.h +++ b/lib/file.h @@ -40,6 +40,6 @@ * * ------------------------------------------------------------ ****************************************************************************/ -UrgError file(struct UrlData *data, char *path, long *bytecountp); +CURLcode file(struct connectdata *conn); #endif diff --git a/lib/formdata.c b/lib/formdata.c index eff0212e4..fb6ad0f69 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -60,6 +60,8 @@ #include #include "formdata.h" +#include "strequal.h" + /* Length of the random boundary string. The risk of this being used in binary data is very close to zero, 64^32 makes 6277101735386680763835789423207666416102355444464034512896 @@ -377,7 +379,7 @@ void FormFree(struct FormData *form) free(form->line); /* free the line */ free(form); /* free the struct */ - } while(form=next); /* continue */ + } while((form=next)); /* continue */ } struct FormData *getFormData(struct HttpPost *post, @@ -513,11 +515,16 @@ struct FormData *getFormData(struct HttpPost *post, int FormInit(struct Form *form, struct FormData *formdata ) { - form->data = formdata; - form->sent = 0; - if(!formdata) return 1; /* error */ + + /* First, make sure that we'll send a nice terminating sequence at the end + * of the post. We *DONT* add this string to the size of the data since this + * is actually AFTER the data. */ + AddFormDataf(&formdata, "\r\n\r\n"); + + form->data = formdata; + form->sent = 0; return 0; } diff --git a/lib/ftp.c b/lib/ftp.c index 4af86fb48..0844cc78a 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -149,7 +149,7 @@ void curl_slist_free_all(struct curl_slist *list) } -static UrgError AllowServerConnect(struct UrlData *data, +static CURLcode AllowServerConnect(struct UrlData *data, int sock) { fd_set rdset; @@ -167,11 +167,11 @@ static UrgError AllowServerConnect(struct UrlData *data, case -1: /* error */ /* let's die here */ failf(data, "Error while waiting for server connect"); - return URG_FTP_PORT_FAILED; + return CURLE_FTP_PORT_FAILED; case 0: /* timeout */ /* let's die here */ failf(data, "Timeout while waiting for server connect"); - return URG_FTP_PORT_FAILED; + return CURLE_FTP_PORT_FAILED; default: /* we have received data here */ { @@ -185,7 +185,7 @@ static UrgError AllowServerConnect(struct UrlData *data, if( -1 == s) { /* DIE! */ failf(data, "Error accept()ing server connect"); - return URG_FTP_PORT_FAILED; + return CURLE_FTP_PORT_FAILED; } infof(data, "Connection accepted from server\n"); @@ -193,7 +193,7 @@ static UrgError AllowServerConnect(struct UrlData *data, } break; } - return URG_OK; + return CURLE_OK; } @@ -202,7 +202,7 @@ static UrgError AllowServerConnect(struct UrlData *data, #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \ isdigit((int)line[2]) && (' ' == line[3])) -static int GetLastResponse(int sockfd, char *buf, +int GetLastResponse(int sockfd, char *buf, struct UrlData *data) { int nread; @@ -230,7 +230,7 @@ static int GetLastResponse(int sockfd, char *buf, } *ptr=0; /* zero terminate */ - if(data->conf & CONF_VERBOSE) { + if(data->bits.verbose) { fputs("< ", data->err); fwrite(buf, 1, nread, data->err); fputs("\n", data->err); @@ -310,32 +310,37 @@ static char *URLfix(char *string) } #endif -static -UrgError _ftp(struct UrlData *data, - long *bytecountp, - char *ftpuser, - char *ftppasswd, - char *ppath) +/* ftp_connect() should do everything that is to be considered a part + of the connection phase. */ +CURLcode ftp_connect(struct connectdata *conn) { /* this is FTP and no proxy */ size_t nread; - UrgError result; + struct UrlData *data=conn->data; char *buf = data->buffer; /* this is our buffer */ - /* for the ftp PORT mode */ - int portsock=-1; - struct sockaddr_in serv_addr; + struct FTP *ftp; - struct curl_slist *qitem; /* QUOTE item */ + ftp = (struct FTP *)malloc(sizeof(struct FTP)); + if(!ftp) + return CURLE_OUT_OF_MEMORY; + + memset(ftp, 0, sizeof(struct FTP)); + data->proto.ftp = ftp; + + /* get some initial data into the ftp struct */ + ftp->bytecountp = &conn->bytecount; + ftp->user = data->user; + ftp->passwd = data->passwd; /* The first thing we do is wait for the "220*" line: */ nread = GetLastResponse(data->firstsocket, buf, data); if(strncmp(buf, "220", 3)) { failf(data, "This doesn't seem like a nice ftp-server response"); - return URG_FTP_WEIRD_SERVER_REPLY; + return CURLE_FTP_WEIRD_SERVER_REPLY; } /* send USER */ - sendf(data->firstsocket, data, "USER %s\r\n", ftpuser); + sendf(data->firstsocket, data, "USER %s\r\n", ftp->user); /* wait for feedback */ nread = GetLastResponse(data->firstsocket, buf, data); @@ -344,19 +349,19 @@ UrgError _ftp(struct UrlData *data, /* 530 User ... access denied (the server denies to log the specified user) */ failf(data, "Access denied: %s", &buf[4]); - return URG_FTP_ACCESS_DENIED; + return CURLE_FTP_ACCESS_DENIED; } else if(!strncmp(buf, "331", 3)) { /* 331 Password required for ... (the server requires to send the user's password too) */ - sendf(data->firstsocket, data, "PASS %s\r\n", ftppasswd); + sendf(data->firstsocket, data, "PASS %s\r\n", ftp->passwd); nread = GetLastResponse(data->firstsocket, buf, data); if(!strncmp(buf, "530", 3)) { /* 530 Login incorrect. (the username and/or the password are incorrect) */ failf(data, "the username and/or the password are incorrect"); - return URG_FTP_USER_PASSWORD_INCORRECT; + return CURLE_FTP_USER_PASSWORD_INCORRECT; } else if(!strncmp(buf, "230", 3)) { /* 230 User ... logged in. @@ -366,7 +371,7 @@ UrgError _ftp(struct UrlData *data, } else { failf(data, "Odd return code after PASS"); - return URG_FTP_WEIRD_PASS_REPLY; + return CURLE_FTP_WEIRD_PASS_REPLY; } } else if(! strncmp(buf, "230", 3)) { @@ -376,9 +381,105 @@ UrgError _ftp(struct UrlData *data, } else { failf(data, "Odd return code after USER"); - return URG_FTP_WEIRD_USER_REPLY; + return CURLE_FTP_WEIRD_USER_REPLY; } + return CURLE_OK; +} + + +/* argument is already checked for validity */ +CURLcode ftp_done(struct connectdata *conn) +{ + struct UrlData *data = conn->data; + struct FTP *ftp = data->proto.ftp; + size_t nread; + char *buf = data->buffer; /* this is our buffer */ + struct curl_slist *qitem; /* QUOTE item */ + + if(data->bits.upload) { + if((-1 != data->infilesize) && (data->infilesize != *ftp->bytecountp)) { + failf(data, "Wrote only partial file (%d out of %d bytes)", + *ftp->bytecountp, data->infilesize); + return CURLE_PARTIAL_FILE; + } + } + else { + if((-1 != conn->size) && (conn->size != *ftp->bytecountp) && + (data->maxdownload != *ftp->bytecountp)) { + failf(data, "Received only partial file"); + return CURLE_PARTIAL_FILE; + } + else if(0 == *ftp->bytecountp) { + failf(data, "No data was received!"); + return CURLE_FTP_COULDNT_RETR_FILE; + } + } + /* shut down the socket to inform the server we're done */ + sclose(data->secondarysocket); + data->secondarysocket = -1; + + /* now let's see what the server says about the transfer we + just performed: */ + nread = GetLastResponse(data->firstsocket, buf, data); + + /* 226 Transfer complete */ + if(strncmp(buf, "226", 3)) { + failf(data, "%s", buf+4); + return CURLE_FTP_WRITE_ERROR; + } + + /* Send any post-transfer QUOTE strings? */ + if(data->postquote) { + qitem = data->postquote; + /* Send all QUOTE strings in same order as on command-line */ + while (qitem) { + /* Send string */ + if (qitem->data) { + sendf(data->firstsocket, data, "%s\r\n", qitem->data); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if (buf[0] != '2') { + failf(data, "QUOT string not accepted: %s", + qitem->data); + return CURLE_FTP_QUOTE_ERROR; + } + } + qitem = qitem->next; + } + } + + if(ftp->file) + free(ftp->file); + if(ftp->dir) + free(ftp->dir); + + /* TBD: the ftp struct is still allocated here */ + + return CURLE_OK; +} + + + +static +CURLcode _ftp(struct connectdata *conn) +{ + /* this is FTP and no proxy */ + size_t nread; + CURLcode result; + struct UrlData *data=conn->data; + char *buf = data->buffer; /* this is our buffer */ + /* for the ftp PORT mode */ + int portsock=-1; + struct sockaddr_in serv_addr; + + struct curl_slist *qitem; /* QUOTE item */ + /* the ftp struct is already inited in ftp_connect() */ + struct FTP *ftp = data->proto.ftp; + + long *bytecountp = ftp->bytecountp; + /* Send any QUOTE strings? */ if(data->quote) { qitem = data->quote; @@ -393,7 +494,7 @@ UrgError _ftp(struct UrlData *data, if (buf[0] != '2') { failf(data, "QUOT string not accepted: %s", qitem->data); - return URG_FTP_QUOTE_ERROR; + return CURLE_FTP_QUOTE_ERROR; } } qitem = qitem->next; @@ -402,18 +503,18 @@ UrgError _ftp(struct UrlData *data, /* If we have selected NOBODY, it means that we only want file information. Which in FTP can't be much more than the file size! */ - if(data->conf & CONF_NOBODY) { + if(data->bits.no_body) { /* The SIZE command is _not_ RFC 959 specified, and therefor many servers may not support it! It is however the only way we have to get a file's size! */ int filesize; - sendf(data->firstsocket, data, "SIZE %s\r\n", ppath); + sendf(data->firstsocket, data, "SIZE %s\r\n", ftp->file); nread = GetLastResponse(data->firstsocket, buf, data); if(strncmp(buf, "213", 3)) { failf(data, "Couldn't get file size: %s", buf+4); - return URG_FTP_COULDNT_GET_SIZE; + return CURLE_FTP_COULDNT_GET_SIZE; } /* get the size from the ascii string: */ filesize = atoi(buf+4); @@ -422,21 +523,21 @@ UrgError _ftp(struct UrlData *data, if(strlen(buf) != data->fwrite(buf, 1, strlen(buf), data->out)) { failf (data, "Failed writing output"); - return URG_WRITE_ERROR; + return CURLE_WRITE_ERROR; } if(data->writeheader) { /* the header is requested to be written to this file */ if(strlen(buf) != data->fwrite (buf, 1, strlen(buf), data->writeheader)) { failf (data, "Failed writing output"); - return URG_WRITE_ERROR; + return CURLE_WRITE_ERROR; } } - return URG_OK; + return CURLE_OK; } /* We have chosen to use the PORT command */ - if(data->conf & CONF_FTPPORT) { + if(data->bits.ftp_use_port) { struct sockaddr_in sa; struct hostent *h=NULL; size_t size; @@ -481,28 +582,28 @@ UrgError _ftp(struct UrlData *data, if(getsockname(portsock, (struct sockaddr *) &add, (int *)&size)<0) { failf(data, "getsockname() failed"); - return URG_FTP_PORT_FAILED; + return CURLE_FTP_PORT_FAILED; } porttouse = ntohs(add.sin_port); if ( listen(portsock, 1) < 0 ) { failf(data, "listen(2) failed on socket"); - return URG_FTP_PORT_FAILED; + return CURLE_FTP_PORT_FAILED; } } else { failf(data, "bind(2) failed on socket"); - return URG_FTP_PORT_FAILED; + return CURLE_FTP_PORT_FAILED; } } else { failf(data, "socket(2) failed (%s)"); - return URG_FTP_PORT_FAILED; + return CURLE_FTP_PORT_FAILED; } } else { failf(data, "could't find my own IP address (%s)", myhost); - return URG_FTP_PORT_FAILED; + return CURLE_FTP_PORT_FAILED; } { struct in_addr in; @@ -520,7 +621,7 @@ UrgError _ftp(struct UrlData *data, if(strncmp(buf, "200", 3)) { failf(data, "Server does not grok PORT, try without it!"); - return URG_FTP_PORT_FAILED; + return CURLE_FTP_PORT_FAILED; } } else { /* we use the PASV command */ @@ -531,7 +632,7 @@ UrgError _ftp(struct UrlData *data, if(strncmp(buf, "227", 3)) { failf(data, "Odd return code after PASV"); - return URG_FTP_WEIRD_PASV_REPLY; + return CURLE_FTP_WEIRD_PASV_REPLY; } else { int ip[4]; @@ -561,13 +662,13 @@ UrgError _ftp(struct UrlData *data, } if(!*str) { failf(data, "Couldn't interpret this 227-reply: %s", buf); - return URG_FTP_WEIRD_227_FORMAT; + return CURLE_FTP_WEIRD_227_FORMAT; } sprintf(newhost, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); he = GetHost(data, newhost); if(!he) { failf(data, "Can't resolve new host %s", newhost); - return URG_FTP_CANT_GET_HOST; + return CURLE_FTP_CANT_GET_HOST; } @@ -579,7 +680,7 @@ UrgError _ftp(struct UrlData *data, serv_addr.sin_family = he->h_addrtype; serv_addr.sin_port = htons(newport); - if(data->conf & CONF_VERBOSE) { + if(data->bits.verbose) { struct in_addr in; #if 1 struct hostent * answer; @@ -620,26 +721,38 @@ UrgError _ftp(struct UrlData *data, failf(data, "Can't connect to ftp server"); break; } - return URG_FTP_CANT_RECONNECT; + return CURLE_FTP_CANT_RECONNECT; } } } /* we have the (new) data connection ready */ - if(data->conf & CONF_UPLOAD) { + /* change directory first */ + + if(ftp->dir && ftp->dir[0]) { + sendf(data->firstsocket, data, "CWD %s\r\n", ftp->dir); + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "250", 3)) { + failf(data, "Couldn't change to directory %s", ftp->dir); + return CURLE_FTP_ACCESS_DENIED; + } + } + + if(data->bits.upload) { /* Set type to binary (unless specified ASCII) */ sendf(data->firstsocket, data, "TYPE %s\r\n", - (data->conf&CONF_FTPASCII)?"A":"I"); + (data->bits.ftp_ascii)?"A":"I"); nread = GetLastResponse(data->firstsocket, buf, data); if(strncmp(buf, "200", 3)) { failf(data, "Couldn't set %s mode", - (data->conf&CONF_FTPASCII)?"ASCII":"binary"); - return (data->conf&CONF_FTPASCII)? URG_FTP_COULDNT_SET_ASCII: - URG_FTP_COULDNT_SET_BINARY; + (data->bits.ftp_ascii)?"ASCII":"binary"); + return (data->bits.ftp_ascii)? CURLE_FTP_COULDNT_SET_ASCII: + CURLE_FTP_COULDNT_SET_BINARY; } if(data->resume_from) { @@ -660,13 +773,13 @@ UrgError _ftp(struct UrlData *data, /* we could've got a specified offset from the command line, but now we know we didn't */ - sendf(data->firstsocket, data, "SIZE %s\r\n", ppath); + sendf(data->firstsocket, data, "SIZE %s\r\n", ftp->file); nread = GetLastResponse(data->firstsocket, buf, data); if(strncmp(buf, "213", 3)) { failf(data, "Couldn't get file size: %s", buf+4); - return URG_FTP_COULDNT_GET_SIZE; + return CURLE_FTP_COULDNT_GET_SIZE; } /* get the size from the ascii string: */ @@ -687,11 +800,11 @@ UrgError _ftp(struct UrlData *data, if(strncmp(buf, "350", 3)) { failf(data, "Couldn't use REST: %s", buf+4); - return URG_FTP_COULDNT_USE_REST; + return CURLE_FTP_COULDNT_USE_REST; } #else /* enable append instead */ - data->conf |= CONF_FTPAPPEND; + data->bits.ftp_append = 1; #endif /* Now, let's read off the proper amount of bytes from the input. If we knew it was a proper file we could've just @@ -710,7 +823,7 @@ UrgError _ftp(struct UrlData *data, if(actuallyread != readthisamountnow) { failf(data, "Could only read %d bytes from the input\n", passed); - return URG_FTP_COULDNT_USE_REST; + return CURLE_FTP_COULDNT_USE_REST; } } while(passed != data->resume_from); @@ -721,7 +834,7 @@ UrgError _ftp(struct UrlData *data, if(data->infilesize <= 0) { infof(data, "File already completely uploaded\n"); - return URG_OK; + return CURLE_OK; } } /* we've passed, proceed as normal */ @@ -729,21 +842,21 @@ UrgError _ftp(struct UrlData *data, } /* Send everything on data->in to the socket */ - if(data->conf & CONF_FTPAPPEND) + if(data->bits.ftp_append) /* we append onto the file instead of rewriting it */ - sendf(data->firstsocket, data, "APPE %s\r\n", ppath); + sendf(data->firstsocket, data, "APPE %s\r\n", ftp->file); else - sendf(data->firstsocket, data, "STOR %s\r\n", ppath); + sendf(data->firstsocket, data, "STOR %s\r\n", ftp->file); nread = GetLastResponse(data->firstsocket, buf, data); if(atoi(buf)>=400) { failf(data, "Failed FTP upload:%s", buf+3); /* oops, we never close the sockets! */ - return URG_FTP_COULDNT_STOR_FILE; + return CURLE_FTP_COULDNT_STOR_FILE; } - if(data->conf & CONF_FTPPORT) { + if(data->bits.ftp_use_port) { result = AllowServerConnect(data, portsock); if( result ) return result; @@ -758,24 +871,19 @@ UrgError _ftp(struct UrlData *data, #if 0 ProgressInit(data, data->infilesize); #endif - result = Transfer(data, -1, -1, FALSE, NULL, /* no download */ + result = Transfer(conn, -1, -1, FALSE, NULL, /* no download */ data->secondarysocket, bytecountp); if(result) return result; - if((-1 != data->infilesize) && (data->infilesize != *bytecountp)) { - failf(data, "Wrote only partial file (%d out of %d bytes)", - *bytecountp, data->infilesize); - return URG_PARTIAL_FILE; - } } else { /* Retrieve file or directory */ bool dirlist=FALSE; long downloadsize=-1; - if(data->conf&CONF_RANGE && data->range) { - int from, to; + if(data->bits.set_range && data->range) { + long from, to; int totalsize=-1; char *ptr; char *ptr2; @@ -788,32 +896,34 @@ UrgError _ftp(struct UrlData *data, /* we didn't get any digit */ to=-1; } - if(-1 == to) { + if((-1 == to) && (from>=0)) { /* X - */ data->resume_from = from; + infof(data, "FTP RANGE %d to end of file\n", from); } else if(from < 0) { /* -Y */ - from = 0; - to = -from; - totalsize = to-from; - data->maxdownload = totalsize; + totalsize = -from; + data->maxdownload = -from; + data->resume_from = from; + infof(data, "FTP RANGE the last %d bytes\n", totalsize); } else { - /* X- */ + /* X-Y */ totalsize = to-from; - data->maxdownload = totalsize; + data->maxdownload = totalsize+1; /* include the last mentioned byte */ + data->resume_from = from; + infof(data, "FTP RANGE from %d getting %d bytes\n", from, data->maxdownload); } infof(data, "range-download from %d to %d, totally %d bytes\n", from, to, totalsize); } - +#if 0 if(!ppath[0]) /* make sure this becomes a valid name */ ppath="./"; - - if((data->conf & CONF_FTPLISTONLY) || - ('/' == ppath[strlen(ppath)-1] )) { +#endif + if((data->bits.ftp_list_only) || !ftp->file) { /* The specified path ends with a slash, and therefore we think this is a directory that is requested, use LIST. But before that we need to set ASCII transfer mode. */ @@ -826,30 +936,29 @@ UrgError _ftp(struct UrlData *data, if(strncmp(buf, "200", 3)) { failf(data, "Couldn't set ascii mode"); - return URG_FTP_COULDNT_SET_ASCII; + return CURLE_FTP_COULDNT_SET_ASCII; } /* if this output is to be machine-parsed, the NLST command will be better used since the LIST command output is not specified or standard in any way */ - sendf(data->firstsocket, data, "%s %s\r\n", + sendf(data->firstsocket, data, "%s\r\n", data->customrequest?data->customrequest: - (data->conf&CONF_FTPLISTONLY?"NLST":"LIST"), - ppath); + (data->bits.ftp_list_only?"NLST":"LIST")); } else { /* Set type to binary (unless specified ASCII) */ sendf(data->firstsocket, data, "TYPE %s\r\n", - (data->conf&CONF_FTPASCII)?"A":"I"); + (data->bits.ftp_list_only)?"A":"I"); nread = GetLastResponse(data->firstsocket, buf, data); if(strncmp(buf, "200", 3)) { failf(data, "Couldn't set %s mode", - (data->conf&CONF_FTPASCII)?"ASCII":"binary"); - return (data->conf&CONF_FTPASCII)? URG_FTP_COULDNT_SET_ASCII: - URG_FTP_COULDNT_SET_BINARY; + (data->bits.ftp_ascii)?"ASCII":"binary"); + return (data->bits.ftp_ascii)? CURLE_FTP_COULDNT_SET_ASCII: + CURLE_FTP_COULDNT_SET_BINARY; } if(data->resume_from) { @@ -860,7 +969,7 @@ UrgError _ftp(struct UrlData *data, * of the file we're gonna get. If we can get the size, this is by far * the best way to know if we're trying to resume beyond the EOF. */ - sendf(data->firstsocket, data, "SIZE %s\r\n", ppath); + sendf(data->firstsocket, data, "SIZE %s\r\n", ftp->file); nread = GetLastResponse(data->firstsocket, buf, data); @@ -875,13 +984,27 @@ UrgError _ftp(struct UrlData *data, int foundsize=atoi(buf+4); /* We got a file size report, so we check that there actually is a part of the file left to get, or else we go home. */ - if(foundsize <= data->resume_from) { - failf(data, "Offset (%d) was beyond file size (%d)", - data->resume_from, foundsize); - return URG_FTP_BAD_DOWNLOAD_RESUME; + if(data->resume_from< 0) { + /* We're supposed to download the last abs(from) bytes */ + if(foundsize < -data->resume_from) { + failf(data, "Offset (%d) was beyond file size (%d)", + data->resume_from, foundsize); + return CURLE_FTP_BAD_DOWNLOAD_RESUME; + } + /* convert to size to download */ + downloadsize = -data->resume_from; + /* download from where? */ + data->resume_from = foundsize - downloadsize; + } + else { + if(foundsize <= data->resume_from) { + failf(data, "Offset (%d) was beyond file size (%d)", + data->resume_from, foundsize); + return CURLE_FTP_BAD_DOWNLOAD_RESUME; + } + /* Now store the number of bytes we are expected to download */ + downloadsize = foundsize-data->resume_from; } - /* Now store the number of bytes we are expected to download */ - downloadsize = foundsize-data->resume_from; } /* Set resume file transfer offset */ @@ -894,11 +1017,11 @@ UrgError _ftp(struct UrlData *data, if(strncmp(buf, "350", 3)) { failf(data, "Couldn't use REST: %s", buf+4); - return URG_FTP_COULDNT_USE_REST; + return CURLE_FTP_COULDNT_USE_REST; } } - sendf(data->firstsocket, data, "RETR %s\r\n", ppath); + sendf(data->firstsocket, data, "RETR %s\r\n", ftp->file); } nread = GetLastResponse(data->firstsocket, buf, data); @@ -968,12 +1091,12 @@ UrgError _ftp(struct UrlData *data, if(size <= 0) { failf(data, "Offset (%d) was beyond file size (%d)", data->resume_from, data->resume_from+size); - return URG_PARTIAL_FILE; + return CURLE_PARTIAL_FILE; } } #endif - if(data->conf & CONF_FTPPORT) { + if(data->bits.ftp_use_port) { result = AllowServerConnect(data, portsock); if( result ) return result; @@ -982,95 +1105,74 @@ UrgError _ftp(struct UrlData *data, infof(data, "Getting file with size: %d\n", size); /* FTP download: */ - result=Transfer(data, data->secondarysocket, size, FALSE, + result=Transfer(conn, data->secondarysocket, size, FALSE, bytecountp, -1, NULL); /* no upload here */ if(result) return result; - - if((-1 != size) && (size != *bytecountp)) { - failf(data, "Received only partial file"); - return URG_PARTIAL_FILE; - } - else if(0 == *bytecountp) { - failf(data, "No data was received!"); - return URG_FTP_COULDNT_RETR_FILE; - } } else { failf(data, "%s", buf+4); - return URG_FTP_COULDNT_RETR_FILE; + return CURLE_FTP_COULDNT_RETR_FILE; } } /* end of transfer */ -#if 0 - ProgressEnd(data); -#endif - pgrsDone(data); - /* shut down the socket to inform the server we're done */ - sclose(data->secondarysocket); - data->secondarysocket = -1; - - /* now let's see what the server says about the transfer we - just performed: */ - nread = GetLastResponse(data->firstsocket, buf, data); - - /* 226 Transfer complete */ - if(strncmp(buf, "226", 3)) { - failf(data, "%s", buf+4); - return URG_FTP_WRITE_ERROR; - } - - /* Send any post-transfer QUOTE strings? */ - if(data->postquote) { - qitem = data->postquote; - /* Send all QUOTE strings in same order as on command-line */ - while (qitem) { - /* Send string */ - if (qitem->data) { - sendf(data->firstsocket, data, "%s\r\n", qitem->data); - - nread = GetLastResponse(data->firstsocket, buf, data); - - if (buf[0] != '2') { - failf(data, "QUOT string not accepted: %s", - qitem->data); - return URG_FTP_QUOTE_ERROR; - } - } - qitem = qitem->next; - } - } - - - return URG_OK; + return CURLE_OK; } /* -- deal with the ftp server! -- */ -UrgError ftp(struct UrlData *data, - long *bytecountp, - char *ftpuser, - char *ftppasswd, - char *urlpath) +/* argument is already checked for validity */ +CURLcode ftp(struct connectdata *conn) { - char *realpath; - UrgError retcode; + CURLcode retcode; -#if 0 - realpath = URLfix(urlpath); -#else - realpath = curl_unescape(urlpath); -#endif - if(realpath) { - retcode = _ftp(data, bytecountp, ftpuser, ftppasswd, realpath); - free(realpath); + struct UrlData *data = conn->data; + struct FTP *ftp; + int dirlength=0; /* 0 forces strlen() */ + + /* the ftp struct is already inited in ftp_connect() */ + ftp = data->proto.ftp; + + /* We split the path into dir and file parts *before* we URLdecode + it */ + ftp->file = strrchr(conn->ppath, '/'); + if(ftp->file) { + ftp->file++; /* point to the first letter in the file name part or + remain NULL */ + } + else { + ftp->file = conn->ppath; /* there's only a file part */ + } + dirlength=ftp->file-conn->ppath; + + if(*ftp->file) { + ftp->file = curl_unescape(ftp->file, 0); + if(NULL == ftp->file) { + failf(data, "no memory"); + return CURLE_OUT_OF_MEMORY; + } } else - /* then we try the original path */ - retcode = _ftp(data, bytecountp, ftpuser, ftppasswd, urlpath); + ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL + pointer */ + + ftp->urlpath = conn->ppath; + if(dirlength) { + ftp->dir = curl_unescape(ftp->urlpath, dirlength); + if(NULL == ftp->dir) { + if(ftp->file) + free(ftp->file); + failf(data, "no memory"); + return CURLE_OUT_OF_MEMORY; /* failure */ + } + } + else + ftp->dir = NULL; + + retcode = _ftp(conn); return retcode; } diff --git a/lib/ftp.h b/lib/ftp.h index b7d265927..3eb73e15f 100644 --- a/lib/ftp.h +++ b/lib/ftp.h @@ -40,11 +40,9 @@ * * ------------------------------------------------------------ ****************************************************************************/ -UrgError ftp(struct UrlData *data, - long *bytecountp, - char *ftpuser, - char *ftppasswd, - char *ppath); +CURLcode ftp(struct connectdata *conn); +CURLcode ftp_done(struct connectdata *conn); +CURLcode ftp_connect(struct connectdata *conn); struct curl_slist *curl_slist_append(struct curl_slist *list, char *data); void curl_slist_free_all(struct curl_slist *list); diff --git a/lib/getdate.c b/lib/getdate.c index 021ed851d..75efdcfb6 100644 --- a/lib/getdate.c +++ b/lib/getdate.c @@ -1864,7 +1864,7 @@ difftm (struct tm *a, struct tm *b) } time_t -get_date (const char *p, const time_t *now) +curl_getdate (const char *p, const time_t *now) { struct tm tm, tm0, *tmp; time_t Start; @@ -1998,7 +1998,7 @@ main (ac, av) buff[MAX_BUFF_LEN] = 0; while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) { - d = get_date (buff, (time_t *) NULL); + d = curl_getdate (buff, (time_t *) NULL); if (d == -1) (void) printf ("Bad format - couldn't convert.\n"); else diff --git a/lib/getdate.h b/lib/getdate.h index 674c474f1..ebb6d2c5a 100644 --- a/lib/getdate.h +++ b/lib/getdate.h @@ -1,18 +1,11 @@ -/* Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc. - - 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 2, 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. */ +/* +** Originally written by Steven M. Bellovin while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** and Jim Berets in August, 1990. +** +** This code is in the public domain and has no copyright. +*/ #if HAVE_CONFIG_H # include @@ -43,4 +36,4 @@ # endif #endif /* defined (vms) */ -time_t get_date PARAMS ((const char *p, const time_t *now)); +time_t curl_getdate PARAMS ((const char *p, const time_t *now)); diff --git a/lib/getdate.y b/lib/getdate.y index efcf04255..80f10120c 100644 --- a/lib/getdate.y +++ b/lib/getdate.y @@ -914,7 +914,7 @@ difftm (struct tm *a, struct tm *b) } time_t -get_date (const char *p, const time_t *now) +curl_getdate (const char *p, const time_t *now) { struct tm tm, tm0, *tmp; time_t Start; @@ -1048,7 +1048,7 @@ main (ac, av) buff[MAX_BUFF_LEN] = 0; while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) { - d = get_date (buff, (time_t *) NULL); + d = curl_getdate (buff, (time_t *) NULL); if (d == -1) (void) printf ("Bad format - couldn't convert.\n"); else diff --git a/lib/getenv.c b/lib/getenv.c index e39d3c194..54b0118b6 100644 --- a/lib/getenv.c +++ b/lib/getenv.c @@ -22,18 +22,6 @@ * Portions created by the Initial Developer are Copyright (C) 1998. * All Rights Reserved. * - * Contributor(s): - * Rafael Sagula - * Sampo Kellomaki - * Linas Vepstas - * Bjorn Reese - * Johan Anderson - * Kjell Ericson - * Troy Engel - * Ryan Nelson - * Bjorn Stenberg - * Angus Mackay - * * ------------------------------------------------------------ * Main author: * - Daniel Stenberg @@ -47,24 +35,6 @@ * $State$ * $Locker$ * - * ------------------------------------------------------------ - * $Log$ - * Revision 1.2 2000-01-10 23:36:14 bagder - * syncing with local edit - * - * Revision 1.4 1999/09/06 06:59:40 dast - * Changed email info - * - * Revision 1.3 1999/08/13 07:34:48 dast - * Changed the URL in the header - * - * Revision 1.2 1999/03/13 00:56:09 dast - * Big changes done due to url.c being split up in X smaller files and that - * the lib is now more stand-alone. - * - * Revision 1.1.1.1 1999/03/11 22:23:34 dast - * Imported sources - * ****************************************************************************/ #include diff --git a/lib/http.c b/lib/http.c index 3f030b4a1..0f41e7c09 100644 --- a/lib/http.c +++ b/lib/http.c @@ -94,6 +94,9 @@ #include "progress.h" #include "base64.h" #include "cookie.h" +#include "strequal.h" +#include "url.h" +#include "ssluse.h" #define _MPRINTF_REPLACE /* use our functions only */ #include @@ -115,33 +118,114 @@ bool static checkheaders(struct UrlData *data, char *thisheader) return FALSE; } -UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount) +CURLcode http_connect(struct connectdata *conn) { - /* Send the GET line to the HTTP server */ + struct UrlData *data; - struct FormData *sendit=NULL; - int postsize=0; - UrgError result; - char *buf; - struct Cookie *co = NULL; - char *p_pragma = NULL; - char *p_accept = NULL; - long readbytecount; - long writebytecount; + data=conn->data; - buf = data->buffer; /* this is our buffer */ + /* If we are not using a proxy and we want a secure connection, + * perform SSL initialization & connection now. + * If using a proxy with https, then we must tell the proxy to CONNECT + * us to the host we want to talk to. Only after the connect + * has occured, can we start talking SSL + */ + if (conn->protocol & PROT_HTTPS) { + if (data->bits.httpproxy) { - if ( (data->conf&(CONF_HTTP|CONF_FTP)) && - (data->conf&CONF_UPLOAD)) { - data->conf |= CONF_PUT; + /* OK, now send the connect statment */ + sendf(data->firstsocket, data, + "CONNECT %s:%d HTTP/1.0\015\012" + "%s" + "%s" + "\r\n", + data->hostname, data->remote_port, + (data->bits.proxy_user_passwd)?data->ptr_proxyuserpwd:"", + (data->useragent?data->ptr_uagent:"") + ); + + /* wait for the proxy to send us a HTTP/1.0 200 OK header */ + /* Daniel rewrote this part Nov 5 1998 to make it more obvious */ + { + int httperror=0; + int subversion=0; + while(GetLine(data->firstsocket, data->buffer, data)) { + if('\r' == data->buffer[0]) + break; /* end of headers */ + if(2 == sscanf(data->buffer, "HTTP/1.%d %d", + &subversion, + &httperror)) { + ; + } + } + if(200 != httperror) { + if(407 == httperror) + /* Added Nov 6 1998 */ + failf(data, "Proxy requires authorization!"); + else + failf(data, "Received error code %d from proxy", httperror); + return CURLE_READ_ERROR; + } + } + infof (data, "Proxy has replied to CONNECT request\n"); + } + + /* now, perform the SSL initialization for this socket */ + if(UrgSSLConnect (data)) { + return CURLE_SSL_CONNECT_ERROR; + } } -#if 0 /* old version */ - if((data->conf&(CONF_HTTP|CONF_UPLOAD)) == - (CONF_HTTP|CONF_UPLOAD)) { - /* enable PUT! */ - data->conf |= CONF_PUT; + + return CURLE_OK; +} +CURLcode http_done(struct connectdata *conn) +{ + struct UrlData *data; + long *bytecount = &conn->bytecount; + struct HTTP *http; + + data=conn->data; + http=data->proto.http; + + if(data->bits.http_formpost) { + *bytecount = http->readbytecount + http->writebytecount; + + FormFree(http->sendit); /* Now free that whole lot */ + + data->fread = http->storefread; /* restore */ + data->in = http->in; /* restore */ + } + else if(data->bits.http_put) { + *bytecount = http->readbytecount + http->writebytecount; + } + + /* TBD: the HTTP struct remains allocated here */ + + return CURLE_OK; +} + + +CURLcode http(struct connectdata *conn) +{ + struct UrlData *data=conn->data; + char *buf = data->buffer; /* this is a short cut to the buffer */ + CURLcode result; + struct HTTP *http; + struct Cookie *co=NULL; /* no cookies from start */ + char *ppath = conn->ppath; /* three previous function arguments */ + char *host = conn->name; + long *bytecount = &conn->bytecount; + + http = (struct HTTP *)malloc(sizeof(struct HTTP)); + if(!http) + return CURLE_OUT_OF_MEMORY; + memset(http, 0, sizeof(struct HTTP)); + data->proto.http = http; + + if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) && + data->bits.upload) { + data->bits.http_put=1; } -#endif /* The User-Agent string has been built in url.c already, because it might have been used in the proxy connect, but if we have got a header with @@ -152,17 +236,17 @@ UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount) data->ptr_uagent=NULL; } - if((data->conf & CONF_USERPWD) && !checkheaders(data, "Authorization:")) { + if((data->bits.user_passwd) && !checkheaders(data, "Authorization:")) { char authorization[512]; sprintf(data->buffer, "%s:%s", data->user, data->passwd); base64Encode(data->buffer, authorization); data->ptr_userpwd = maprintf( "Authorization: Basic %s\015\012", authorization); } - if((data->conf & CONF_RANGE) && !checkheaders(data, "Range:")) { + if((data->bits.set_range) && !checkheaders(data, "Range:")) { data->ptr_rangeline = maprintf("Range: bytes=%s\015\012", data->range); } - if((data->conf & CONF_REFERER) && !checkheaders(data, "Referer:")) { + if((data->bits.http_set_referer) && !checkheaders(data, "Referer:")) { data->ptr_ref = maprintf("Referer: %s\015\012", data->referer); } if(data->cookie && !checkheaders(data, "Cookie:")) { @@ -173,16 +257,16 @@ UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount) co = cookie_getlist(data->cookies, host, ppath, - data->conf&CONF_HTTPS?TRUE:FALSE); + conn->protocol&PROT_HTTPS?TRUE:FALSE); } - if ((data->conf & CONF_PROXY) && (!(data->conf & CONF_HTTPS))) { + if ((data->bits.httpproxy) && !(conn->protocol&PROT_HTTPS)) { /* The path sent to the proxy is in fact the entire URL */ strncpy(ppath, data->url, URL_MAX_LENGTH-1); } - if(data->conf & CONF_HTTPPOST) { + if(data->bits.http_formpost) { /* we must build the whole darned post sequence first, so that we have a size of the whole shebang before we start to send it */ - sendit = getFormData(data->httppost, &postsize); + http->sendit = getFormData(data->httppost, &http->postsize); } if(!checkheaders(data, "Host:")) @@ -190,10 +274,10 @@ UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount) if(!checkheaders(data, "Pragma:")) - p_pragma = "Pragma: no-cache\r\n"; + http->p_pragma = "Pragma: no-cache\r\n"; if(!checkheaders(data, "Accept:")) - p_accept = "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"; + http->p_accept = "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"; do { sendf(data->firstsocket, data, @@ -210,19 +294,19 @@ UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount) "%s", /* referer */ data->customrequest?data->customrequest: - (data->conf&CONF_NOBODY?"HEAD": - (data->conf&(CONF_POST|CONF_HTTPPOST))?"POST": - (data->conf&CONF_PUT)?"PUT":"GET"), + (data->bits.no_body?"HEAD": + (data->bits.http_post || data->bits.http_formpost)?"POST": + (data->bits.http_put)?"PUT":"GET"), ppath, - (data->conf&CONF_PROXYUSERPWD && data->ptr_proxyuserpwd)?data->ptr_proxyuserpwd:"", - (data->conf&CONF_USERPWD && data->ptr_userpwd)?data->ptr_userpwd:"", - (data->conf&CONF_RANGE && data->ptr_rangeline)?data->ptr_rangeline:"", + (data->bits.proxy_user_passwd && data->ptr_proxyuserpwd)?data->ptr_proxyuserpwd:"", + (data->bits.user_passwd && data->ptr_userpwd)?data->ptr_userpwd:"", + (data->bits.set_range && data->ptr_rangeline)?data->ptr_rangeline:"", (data->useragent && *data->useragent && data->ptr_uagent)?data->ptr_uagent:"", (data->ptr_cookie?data->ptr_cookie:""), /* Cookie: */ (data->ptr_host?data->ptr_host:""), /* Host: host */ - p_pragma?p_pragma:"", - p_accept?p_accept:"", - (data->conf&CONF_REFERER && data->ptr_ref)?data->ptr_ref:"" /* Referer: */ + http->p_pragma?http->p_pragma:"", + http->p_accept?http->p_accept:"", + (data->bits.http_set_referer && data->ptr_ref)?data->ptr_ref:"" /* Referer: */ ); if(co) { @@ -234,9 +318,10 @@ UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount) sendf(data->firstsocket, data, "Cookie:"); } - count++; sendf(data->firstsocket, data, - " %s=%s;", co->name, co->value); + "%s%s=%s", count?"; ":"", co->name, + co->value); + count++; } co = co->next; /* next cookie please */ } @@ -284,8 +369,8 @@ UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount) data->headers = data->headers->next; } - if(data->conf&(CONF_POST|CONF_HTTPPOST)) { - if(data->conf & CONF_POST) { + if(data->bits.http_post || data->bits.http_formpost) { + if(data->bits.http_post) { /* this is the simple x-www-form-urlencoded style */ sendf(data->firstsocket, data, "Content-Length: %d\015\012" @@ -295,53 +380,39 @@ UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount) data->postfields ); } else { - struct Form form; - size_t (*storefread)(char *, size_t , size_t , FILE *); - FILE *in; - long conf; - if(FormInit(&form, sendit)) { + if(FormInit(&http->form, http->sendit)) { failf(data, "Internal HTTP POST error!\n"); - return URG_HTTP_POST_ERROR; + return CURLE_HTTP_POST_ERROR; } - storefread = data->fread; /* backup */ - in = data->in; /* backup */ + http->storefread = data->fread; /* backup */ + http->in = data->in; /* backup */ data->fread = (size_t (*)(char *, size_t, size_t, FILE *)) FormReader; /* set the read function to read from the generated form data */ - data->in = (FILE *)&form; + data->in = (FILE *)&http->form; sendf(data->firstsocket, data, "Content-Length: %d\r\n", - postsize-2); + http->postsize-2); - pgrsSetUploadSize(data, postsize); -#if 0 - ProgressInit(data, postsize); -#endif + pgrsSetUploadSize(data, http->postsize); - result = Transfer(data, data->firstsocket, -1, TRUE, &readbytecount, - data->firstsocket, &writebytecount); - *bytecount = readbytecount + writebytecount; - - FormFree(sendit); /* Now free that whole lot */ - - if(result) + result = Transfer(conn, data->firstsocket, -1, TRUE, + &http->readbytecount, + data->firstsocket, + &http->writebytecount); + if(result) { + FormFree(http->sendit); /* free that whole lot */ return result; - - data->fread = storefread; /* restore */ - data->in = in; /* restore */ - - sendf(data->firstsocket, data, - "\r\n\r\n"); + } } } - else if(data->conf&CONF_PUT) { + else if(data->bits.http_put) { /* Let's PUT the data to the server! */ - long conf; if(data->infilesize>0) { sendf(data->firstsocket, data, @@ -352,39 +423,28 @@ UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount) sendf(data->firstsocket, data, "\015\012"); -#if 0 - ProgressInit(data, data->infilesize); -#endif pgrsSetUploadSize(data, data->infilesize); - result = Transfer(data, data->firstsocket, -1, TRUE, &readbytecount, - data->firstsocket, &writebytecount); - - *bytecount = readbytecount + writebytecount; - + result = Transfer(conn, data->firstsocket, -1, TRUE, + &http->readbytecount, + data->firstsocket, + &http->writebytecount); if(result) return result; } else { sendf(data->firstsocket, data, "\r\n"); - } - if(0 == *bytecount) { + /* HTTP GET/HEAD download: */ - result = Transfer(data, data->firstsocket, -1, TRUE, bytecount, + result = Transfer(conn, data->firstsocket, -1, TRUE, bytecount, -1, NULL); /* nothing to upload */ } if(result) return result; - -#if 0 - ProgressEnd(data); -#endif - pgrsDone(data); - } while (0); /* this is just a left-over from the multiple document download attempts */ - return URG_OK; + return CURLE_OK; } diff --git a/lib/http.h b/lib/http.h index be35842cf..6a4d8c835 100644 --- a/lib/http.h +++ b/lib/http.h @@ -40,6 +40,9 @@ * * ------------------------------------------------------------ ****************************************************************************/ -UrgError http(struct UrlData *data, char *path, char *host, long *bytecountp); + +CURLcode http(struct connectdata *conn); +CURLcode http_done(struct connectdata *conn); +CURLcode http_connect(struct connectdata *conn); #endif diff --git a/lib/ldap.c b/lib/ldap.c index dde15873a..e38135cc5 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -72,7 +72,7 @@ #define DYNA_GET_FUNCTION(type, fnc) \ (fnc) = (type)DynaGetFunction(#fnc); \ if ((fnc) == NULL) { \ - return URG_FUNCTION_NOT_FOUND; \ + return CURLE_FUNCTION_NOT_FOUND; \ } \ /*********************************************************************** @@ -129,16 +129,21 @@ static void * DynaGetFunction(char *name) static int WriteProc(void *param, char *text, int len) { struct UrlData *data = (struct UrlData *)param; - - printf("%s\n", text); + + data->fwrite(text, 1, strlen(text), data->out); return 0; } +CURLcode ldap_done(struct connectdata *conn) +{ + return CURLE_OK; +} + /*********************************************************************** */ -UrgError ldap(struct UrlData *data, char *path, long *bytecount) +CURLcode ldap(struct connectdata *conn) { - UrgError status = URG_OK; + CURLcode status = CURLE_OK; int rc; void *(*ldap_open)(char *, int); int (*ldap_simple_bind_s)(void *, char *, char *); @@ -152,24 +157,19 @@ UrgError ldap(struct UrlData *data, char *path, long *bytecount) void *server; void *result; void *entryIterator; -#if 0 - char *dn; - char **attrArray; - char *attrIterator; - char *attrString; - void *dummy; -#endif + int ldaptext; + struct UrlData *data=conn->data; infof(data, "LDAP: %s %s\n", data->url); DynaOpen(); if (libldap == NULL) { failf(data, "The needed LDAP library/libraries couldn't be opened"); - return URG_LIBRARY_NOT_FOUND; + return CURLE_LIBRARY_NOT_FOUND; } - ldaptext = data->conf & CONF_FTPASCII; /* This is a dirty hack */ + ldaptext = data->bits.ftp_ascii; /* This is a dirty hack */ /* The types are needed because ANSI C distinguishes between * pointer-to-object (data) and pointer-to-function. @@ -188,17 +188,17 @@ UrgError ldap(struct UrlData *data, char *path, long *bytecount) if (server == NULL) { failf(data, "LDAP: Cannot connect to %s:%d", data->hostname, data->port); - status = URG_COULDNT_CONNECT; + status = CURLE_COULDNT_CONNECT; } else { rc = ldap_simple_bind_s(server, data->user, data->passwd); if (rc != 0) { failf(data, "LDAP: %s", ldap_err2string(rc)); - status = URG_LDAP_CANNOT_BIND; + status = CURLE_LDAP_CANNOT_BIND; } else { rc = ldap_url_search_s(server, data->url, 0, &result); if (rc != 0) { failf(data, "LDAP: %s", ldap_err2string(rc)); - status = URG_LDAP_SEARCH_FAILED; + status = CURLE_LDAP_SEARCH_FAILED; } else { for (entryIterator = ldap_first_entry(server, result); entryIterator; @@ -210,7 +210,7 @@ UrgError ldap(struct UrlData *data, char *path, long *bytecount) "", 0, 0); if (rc != 0) { failf(data, "LDAP: %s", ldap_err2string(rc)); - status = URG_LDAP_SEARCH_FAILED; + status = CURLE_LDAP_SEARCH_FAILED; } } else { rc = ldap_entry2html(server, NULL, entryIterator, NULL, @@ -218,7 +218,7 @@ UrgError ldap(struct UrlData *data, char *path, long *bytecount) "", 0, 0, NULL, NULL); if (rc != 0) { failf(data, "LDAP: %s", ldap_err2string(rc)); - status = URG_LDAP_SEARCH_FAILED; + status = CURLE_LDAP_SEARCH_FAILED; } } } diff --git a/lib/ldap.h b/lib/ldap.h index d88880ede..0fcacc0b8 100644 --- a/lib/ldap.h +++ b/lib/ldap.h @@ -40,6 +40,7 @@ * * ------------------------------------------------------------ ****************************************************************************/ -UrgError ldap(struct UrlData *data, char *path, long *bytecount); +CURLcode ldap(struct connectdata *conn); +CURLcode ldap_done(struct connectdata *conn); #endif /* __LDAP_H */ diff --git a/lib/netrc.c b/lib/netrc.c index f0e1382fe..73d94ab77 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -56,6 +56,7 @@ #include "setup.h" #include "getenv.h" +#include "strequal.h" /* Debug this single source file with: 'make netrc' then run './netrc'! diff --git a/lib/progress.c b/lib/progress.c index 1bb5aec0c..35847fab4 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -118,7 +118,7 @@ void pgrsDone(struct UrlData *data) void pgrsMode(struct UrlData *data, int mode) { /* mode should include a hidden mode as well */ - if(data->conf&(CONF_NOPROGRESS|CONF_MUTE)) + if(data->bits.hide_progress || data->bits.mute) data->progress.flags |= PGRS_HIDE; /* don't show anything */ else { data->progress.mode = mode; /* store type */ @@ -187,10 +187,36 @@ void pgrsSetUploadSize(struct UrlData *data, double size) */ -void pgrsUpdate(struct UrlData *data) +int pgrsUpdate(struct UrlData *data) { struct timeval now; + char max5[6][6]; + double dlpercen=0; + double ulpercen=0; + double total_percen=0; + + double total_transfer; + double total_expected_transfer; + +#define CURR_TIME 5 + + static double speeder[ CURR_TIME ]; + static int speeder_c=0; + + int nowindex = speeder_c% CURR_TIME; + int checkindex; + int count; + + char time_left[10]; + char time_total[10]; + char time_current[10]; + + double ulestimate=0; + double dlestimate=0; + + double total_estimate; + if(data->progress.flags & PGRS_HIDE) ; /* We do enter this function even if we don't wanna see anything, since this is were lots of the calculations are being made that will be used @@ -206,133 +232,109 @@ void pgrsUpdate(struct UrlData *data) now = tvnow(); /* what time is it */ - switch(data->progress.mode) { - case CURL_PROGRESS_STATS: - default: - { - char max5[6][6]; - double dlpercen=0; - double ulpercen=0; - double total_percen=0; + if(data->progress.lastshow == tvlong(now)) + return 0; /* never update this more than once a second if the end isn't + reached */ + data->progress.lastshow = now.tv_sec; - double total_transfer; - double total_expected_transfer; + /* The exact time spent so far */ + data->progress.timespent = tvdiff (now, data->progress.start); -#define CURR_TIME 5 + /* The average download speed this far */ + data->progress.dlspeed = data->progress.downloaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0); - static double speeder[ CURR_TIME ]; - static int speeder_c=0; + /* The average upload speed this far */ + data->progress.ulspeed = data->progress.uploaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0); - int nowindex = speeder_c% CURR_TIME; - int checkindex; - int count; - - char time_left[10]; - char time_total[10]; - char time_current[10]; - - double ulestimate=0; - double dlestimate=0; - - double total_estimate; - - if(data->progress.lastshow == tvlong(now)) - return; /* never update this more than once a second if the end isn't - reached */ - data->progress.lastshow = now.tv_sec; - - /* The exact time spent so far */ - data->progress.timespent = tvdiff (now, data->progress.start); - - /* The average download speed this far */ - data->progress.dlspeed = data->progress.downloaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0); - - /* The average upload speed this far */ - data->progress.ulspeed = data->progress.uploaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0); - - /* Let's do the "current speed" thing, which should use the fastest + /* Let's do the "current speed" thing, which should use the fastest of the dl/ul speeds */ - speeder[ nowindex ] = data->progress.downloaded>data->progress.uploaded? - data->progress.downloaded:data->progress.uploaded; - speeder_c++; /* increase */ - count = ((speeder_c>=CURR_TIME)?CURR_TIME:speeder_c) - 1; - checkindex = (speeder_c>=CURR_TIME)?speeder_c%CURR_TIME:0; + speeder[ nowindex ] = data->progress.downloaded>data->progress.uploaded? + data->progress.downloaded:data->progress.uploaded; + speeder_c++; /* increase */ + count = ((speeder_c>=CURR_TIME)?CURR_TIME:speeder_c) - 1; + checkindex = (speeder_c>=CURR_TIME)?speeder_c%CURR_TIME:0; - /* find out the average speed the last CURR_TIME seconds */ - data->progress.current_speed = - (speeder[nowindex]-speeder[checkindex])/(count?count:1); + /* find out the average speed the last CURR_TIME seconds */ + data->progress.current_speed = + (speeder[nowindex]-speeder[checkindex])/(count?count:1); - if(data->progress.flags & PGRS_HIDE) - return; + if(data->progress.flags & PGRS_HIDE) + return 0; + else if(data->fprogress) { + return data->fprogress(data->progress_client, + data->progress.size_dl, + data->progress.downloaded, + data->progress.size_ul, + data->progress.uploaded); + } /* Figure out the estimated time of arrival for the upload */ - if(data->progress.flags & PGRS_UL_SIZE_KNOWN) { - if(!data->progress.ulspeed) - data->progress.ulspeed=1; - ulestimate = data->progress.size_ul / data->progress.ulspeed; - ulpercen = (data->progress.uploaded / data->progress.size_ul)*100; - } + if(data->progress.flags & PGRS_UL_SIZE_KNOWN) { + if(!data->progress.ulspeed) + data->progress.ulspeed=1; + ulestimate = data->progress.size_ul / data->progress.ulspeed; + ulpercen = (data->progress.uploaded / data->progress.size_ul)*100; + } - /* ... and the download */ - if(data->progress.flags & PGRS_DL_SIZE_KNOWN) { - if(!data->progress.dlspeed) - data->progress.dlspeed=1; - dlestimate = data->progress.size_dl / data->progress.dlspeed; - dlpercen = (data->progress.downloaded / data->progress.size_dl)*100; - } + /* ... and the download */ + if(data->progress.flags & PGRS_DL_SIZE_KNOWN) { + if(!data->progress.dlspeed) + data->progress.dlspeed=1; + dlestimate = data->progress.size_dl / data->progress.dlspeed; + dlpercen = (data->progress.downloaded / data->progress.size_dl)*100; + } - /* Now figure out which of them that is slower and use for the for + /* Now figure out which of them that is slower and use for the for total estimate! */ - total_estimate = ulestimate>dlestimate?ulestimate:dlestimate; + total_estimate = ulestimate>dlestimate?ulestimate:dlestimate; - /* If we have a total estimate, we can display that and the expected + /* If we have a total estimate, we can display that and the expected time left */ - if(total_estimate) { - time2str(time_left, total_estimate-(int) data->progress.timespent); - time2str(time_total, total_estimate); - } - else { - /* otherwise we blank those times */ - strcpy(time_left, "--:--:--"); - strcpy(time_total, "--:--:--"); - } - /* The time spent so far is always known */ - time2str(time_current, data->progress.timespent); + if(total_estimate) { + time2str(time_left, total_estimate-(int) data->progress.timespent); + time2str(time_total, total_estimate); + } + else { + /* otherwise we blank those times */ + strcpy(time_left, "--:--:--"); + strcpy(time_total, "--:--:--"); + } + /* The time spent so far is always known */ + time2str(time_current, data->progress.timespent); - /* Get the total amount of data expected to get transfered */ - total_expected_transfer = - (data->progress.flags & PGRS_UL_SIZE_KNOWN? - data->progress.size_ul:data->progress.uploaded)+ - (data->progress.flags & PGRS_DL_SIZE_KNOWN? - data->progress.size_dl:data->progress.downloaded); + /* Get the total amount of data expected to get transfered */ + total_expected_transfer = + (data->progress.flags & PGRS_UL_SIZE_KNOWN? + data->progress.size_ul:data->progress.uploaded)+ + (data->progress.flags & PGRS_DL_SIZE_KNOWN? + data->progress.size_dl:data->progress.downloaded); - /* We have transfered this much so far */ - total_transfer = data->progress.downloaded + data->progress.uploaded; + /* We have transfered this much so far */ + total_transfer = data->progress.downloaded + data->progress.uploaded; - /* Get the percentage of data transfered so far */ - if(total_expected_transfer) - total_percen=(double)(total_transfer/total_expected_transfer)*100; + /* Get the percentage of data transfered so far */ + if(total_expected_transfer) + total_percen=(double)(total_transfer/total_expected_transfer)*100; + + fprintf(stderr, + "\r%3d %s %3d %s %3d %s %s %s %s %s %s %s", + (int)total_percen, /* total % */ + max5data(total_expected_transfer, max5[2]), /* total size */ + (int)dlpercen, /* rcvd % */ + max5data(data->progress.downloaded, max5[0]), /* rcvd size */ + (int)ulpercen, /* xfer % */ + max5data(data->progress.uploaded, max5[1]), /* xfer size */ + + max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */ + max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */ + time_total, /* total time */ + time_current, /* current time */ + time_left, /* time left */ + max5data(data->progress.current_speed, max5[5]) /* current speed */ + ); - fprintf(stderr, - "\r%3d %s %3d %s %3d %s %s %s %s %s %s %s", - (int)total_percen, /* total % */ - max5data(total_expected_transfer, max5[2]), /* total size */ - (int)dlpercen, /* rcvd % */ - max5data(data->progress.downloaded, max5[0]), /* rcvd size */ - (int)ulpercen, /* xfer % */ - max5data(data->progress.uploaded, max5[1]), /* xfer size */ - - max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */ - max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */ - time_total, /* total time */ - time_current, /* current time */ - time_left, /* time left */ - max5data(data->progress.current_speed, max5[5]) /* current speed */ - ); - } - break; #if 0 case CURL_PROGRESS_BAR: /* original progress bar code by Lars Aas */ @@ -365,7 +367,8 @@ void pgrsUpdate(struct UrlData *data) prev = point; break; #endif - } + + return 0; } diff --git a/lib/progress.h b/lib/progress.h index 8c407f76c..f4e0dcfaa 100644 --- a/lib/progress.h +++ b/lib/progress.h @@ -52,13 +52,14 @@ typedef enum { TIMER_LAST /* must be last */ } timerid; +void pgrsDone(struct UrlData *data); void pgrsMode(struct UrlData *data, int mode); void pgrsStartNow(struct UrlData *data); void pgrsSetDownloadSize(struct UrlData *data, double size); void pgrsSetUploadSize(struct UrlData *data, double size); void pgrsSetDownloadCounter(struct UrlData *data, double size); - void pgrsSetUploadCounter(struct UrlData *data, double size); -void pgrsUpdate(struct UrlData *data); +void pgrsSetUploadCounter(struct UrlData *data, double size); +int pgrsUpdate(struct UrlData *data); void pgrsTime(struct UrlData *data, timerid timer); diff --git a/lib/sendf.c b/lib/sendf.c index 387984d9d..42c344dcf 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -61,7 +61,7 @@ void infof(struct UrlData *data, char *fmt, ...) { va_list ap; - if(data->conf & CONF_VERBOSE) { + if(data->bits.verbose) { va_start(ap, fmt); fputs("* ", data->err); vfprintf(data->err, fmt, ap); @@ -95,7 +95,7 @@ int sendf(int fd, struct UrlData *data, char *fmt, ...) va_end(ap); if(!s) return 0; /* failure */ - if(data->conf & CONF_VERBOSE) + if(data->bits.verbose) fprintf(data->err, "> %s", s); #ifndef USE_SSLEAY bytes_written = swrite(fd, s, strlen(s)); diff --git a/lib/setup.h b/lib/setup.h index 083e89093..c800fa8d3 100644 --- a/lib/setup.h +++ b/lib/setup.h @@ -57,8 +57,6 @@ #endif #endif - - #ifndef OS #ifdef WIN32 #define OS "win32" @@ -99,6 +97,7 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO) #endif #endif +#if 0 #ifdef HAVE_STRCASECMP #define strnequal(x,y,z) !(strncasecmp)(x,y,z) #define strequal(x,y) !(strcasecmp)(x,y) @@ -107,6 +106,7 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO) #define strnequal(x,y,z) !strnicmp(x,y,z) #define strequal(x,y) !stricmp(x,y) #endif +#endif /* Below we define four functions. They should 1. close a socket diff --git a/lib/speedcheck.c b/lib/speedcheck.c index 5647b50e2..48772b39c 100644 --- a/lib/speedcheck.c +++ b/lib/speedcheck.c @@ -48,7 +48,7 @@ #include "sendf.h" #include "speedcheck.h" -UrgError speedcheck(struct UrlData *data, +CURLcode speedcheck(struct UrlData *data, struct timeval now) { static struct timeval keeps_speed; @@ -69,13 +69,13 @@ UrgError speedcheck(struct UrlData *data, "Less than %d bytes/sec transfered the last %d seconds", data->low_speed_limit, data->low_speed_time); - return URG_OPERATION_TIMEOUTED; + return CURLE_OPERATION_TIMEOUTED; } } else { /* we keep up the required speed all right */ keeps_speed = now; } - return URG_OK; + return CURLE_OK; } diff --git a/lib/speedcheck.h b/lib/speedcheck.h index 27e7ba2f6..e07bdbcc6 100644 --- a/lib/speedcheck.h +++ b/lib/speedcheck.h @@ -44,7 +44,7 @@ #include "timeval.h" -UrgError speedcheck(struct UrlData *data, +CURLcode speedcheck(struct UrlData *data, struct timeval now); #endif diff --git a/lib/ssluse.c b/lib/ssluse.c index 0eae0a93c..6eb9b77bb 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -38,6 +38,12 @@ * ------------------------------------------------------------ ****************************************************************************/ +/* + * The original SSL code was written by + * Linas Vepstas and Sampo Kellomaki + */ + + #include #include diff --git a/lib/telnet.c b/lib/telnet.c index 8ca12450d..68571829d 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -225,7 +225,7 @@ static void printoption(struct UrlData *data, char *fmt; char *opt; - if (data->conf & CONF_VERBOSE) + if (data->bits.verbose) { if (cmd == IAC) { @@ -628,7 +628,7 @@ static void printsub(struct UrlData *data, { int i = 0; - if (data->conf & CONF_VERBOSE) + if (data->bits.verbose) { if (direction) { @@ -871,23 +871,29 @@ void telwrite(struct UrlData *data, } } -UrgError telnet(struct UrlData *data) +CURLcode telnet_done(struct connectdata *conn) { - int sockfd = data->firstsocket; - fd_set readfd; - fd_set keepfd; + return CURLE_OK; +} - bool keepon = TRUE; - char *buf = data->buffer; - int nread; +CURLcode telnet(struct connectdata *conn) +{ + struct UrlData *data = conn->data; + int sockfd = data->firstsocket; + fd_set readfd; + fd_set keepfd; - init_telnet(data); + bool keepon = TRUE; + char *buf = data->buffer; + int nread; + + init_telnet(data); - FD_ZERO (&readfd); /* clear it */ - FD_SET (sockfd, &readfd); - FD_SET (1, &readfd); + FD_ZERO (&readfd); /* clear it */ + FD_SET (sockfd, &readfd); + FD_SET (1, &readfd); - keepfd = readfd; + keepfd = readfd; while (keepon) { @@ -931,7 +937,7 @@ UrgError telnet(struct UrlData *data) telrcv(data, (unsigned char *)buf, nread); } } - return URG_OK; + return CURLE_OK; } diff --git a/lib/telnet.h b/lib/telnet.h index 25b7f2d29..f9d55b78b 100644 --- a/lib/telnet.h +++ b/lib/telnet.h @@ -40,6 +40,7 @@ * * ------------------------------------------------------------ ****************************************************************************/ -UrgError telnet(struct UrlData *data); +CURLcode telnet(struct connectdata *conn); +CURLcode telnet_done(struct connectdata *conn); #endif diff --git a/lib/url.c b/lib/url.c index 75dd89559..5938c5771 100644 --- a/lib/url.c +++ b/lib/url.c @@ -38,11 +38,6 @@ * ------------------------------------------------------------ ****************************************************************************/ -/* - * SSL code intially written by - * Linas Vepstas and Sampo Kellomaki - */ - /* -- WIN32 approved -- */ #include #include @@ -116,6 +111,8 @@ #include "getpass.h" #include "progress.h" #include "cookie.h" +#include "strequal.h" +#include "writeout.h" /* And now for the protocols */ #include "ftp.h" @@ -124,81 +121,28 @@ #include "http.h" #include "file.h" #include "ldap.h" -#include "writeout.h" + +#include #define _MPRINTF_REPLACE /* use our functions only */ #include /* -- -- */ -/*********************************************************************** - * Start with some silly functions to make win32-systems survive - ***********************************************************************/ -#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) -static void win32_cleanup(void) + +CURLcode _urlget(struct UrlData *data); + +/* does nothing, returns OK */ +CURLcode curl_init(void) { - WSACleanup(); + return CURLE_OK; } -static UrgError win32_init(void) -{ - WORD wVersionRequested; - WSADATA wsaData; - int err; - wVersionRequested = MAKEWORD(1, 1); - - err = WSAStartup(wVersionRequested, &wsaData); - - if (err != 0) - /* Tell the user that we couldn't find a useable */ - /* winsock.dll. */ - return URG_FAILED_INIT; - - /* Confirm that the Windows Sockets DLL supports 1.1.*/ - /* Note that if the DLL supports versions greater */ - /* than 1.1 in addition to 1.1, it will still return */ - /* 1.1 in wVersion since that is the version we */ - /* requested. */ - - if ( LOBYTE( wsaData.wVersion ) != 1 || - HIBYTE( wsaData.wVersion ) != 1 ) { - /* Tell the user that we couldn't find a useable */ - - /* winsock.dll. */ - WSACleanup(); - return URG_FAILED_INIT; - } - return URG_OK; -} -/* The Windows Sockets DLL is acceptable. Proceed. */ -#else -static UrgError win32_init(void) { return URG_OK; } -#define win32_cleanup() -#endif - - -/* - * This is the main global constructor for the lib. Call this before - * _any_ libcurl usage. If this fails, *NO* libcurl functions may be - * used, or havoc may be the result. - */ -UrgError curl_init(void) -{ - return win32_init(); -} - -/* - * This is the main global destructor for the lib. Call this after - * _all_ libcurl usage is done. - */ +/* does nothing */ void curl_free(void) { - win32_cleanup(); } -static UrgError _urlget(struct UrlData *data); - - void urlfree(struct UrlData *data, bool totally) { #ifdef USE_SSLEAY @@ -278,190 +222,55 @@ void urlfree(struct UrlData *data, bool totally) } } -typedef struct UrlData CURL; +CURLcode curl_close(CURL *curl) +{ + struct UrlData *data=(struct UrlData *)curl; + + void *protocol = data->proto.generic; -UrgError curl_open(CURL **curl, char *url) + /* total session cleanup */ + urlfree(data, TRUE); + + if(protocol) + free(protocol); + + free(data); + + return CURLE_OK; +} + +CURLcode curl_open(CURL **curl, char *url) { /* We don't yet support specifying the URL at this point */ - - /* Very simple start-up: alloc the struct, init it with zeroes and return */ - CURL *data = (CURL *)malloc(sizeof(CURL)); - if(data) { - memset(data, 0, sizeof(CURL)); - *curl = data; - return URG_OK; - } - - /* this is a very serious error */ - return URG_OUT_OF_MEMORY; -} - -typedef unsigned int CURLoption; - -UrgError curl_setopt(CURL *curl, CURLoption option, ...) -{ - struct UrlData *data = curl; - va_list param; - char *cookiefile; - - va_start(param, option); - - switch(option) { - case URGTAG_TIMECONDITION: - data->timecondition = va_arg(param, long); - break; - - case URGTAG_TIMEVALUE: - data->timevalue = va_arg(param, long); - break; - - case URGTAG_SSLVERSION: - data->ssl_version = va_arg(param, long); - break; - - case URGTAG_COOKIEFILE: - cookiefile = (char *)va_arg(param, void *); - if(cookiefile) { - data->cookies = cookie_init(cookiefile); - } - break; - case URGTAG_WRITEHEADER: - data->writeheader = (FILE *)va_arg(param, FILE *); - break; - case URGTAG_COOKIE: - data->cookie = va_arg(param, char *); - break; - case URGTAG_ERRORBUFFER: - data->errorbuffer = va_arg(param, char *); - break; - case URGTAG_FILE: - data->out = va_arg(param, FILE *); - break; - case URGTAG_FTPPORT: - data->ftpport = va_arg(param, char *); - break; - case URGTAG_HTTPHEADER: - data->headers = va_arg(param, struct HttpHeader *); - break; - case URGTAG_CUSTOMREQUEST: - data->customrequest = va_arg(param, char *); - break; - case URGTAG_HTTPPOST: - data->httppost = va_arg(param, struct HttpPost *); - break; - case URGTAG_INFILE: - data->in = va_arg(param, FILE *); - break; - case URGTAG_INFILESIZE: - data->infilesize = va_arg(param, long); - break; - case URGTAG_LOW_SPEED_LIMIT: - data->low_speed_limit=va_arg(param, long); - break; - case URGTAG_LOW_SPEED_TIME: - data->low_speed_time=va_arg(param, long); - break; - case URGTAG_URL: - data->url = va_arg(param, char *); - break; - case URGTAG_PORT: - /* this typecast is used to fool the compiler to NOT warn for a - "cast from pointer to integer of different size" */ - data->port = (unsigned short)(va_arg(param, long)); - break; - case URGTAG_POSTFIELDS: - data->postfields = va_arg(param, char *); - break; - case URGTAG_PROGRESSMODE: - data->progress.mode = va_arg(param, long); - break; - case URGTAG_REFERER: - data->referer = va_arg(param, char *); - break; - case URGTAG_PROXY: - data->proxy = va_arg(param, char *); - break; - case URGTAG_FLAGS: - data->conf = va_arg(param, long); - break; - case URGTAG_TIMEOUT: - data->timeout = va_arg(param, long); - break; - case URGTAG_USERAGENT: - data->useragent = va_arg(param, char *); - break; - case URGTAG_USERPWD: - data->userpwd = va_arg(param, char *); - break; - case URGTAG_POSTQUOTE: - data->postquote = va_arg(param, struct curl_slist *); - break; - case URGTAG_PROXYUSERPWD: - data->proxyuserpwd = va_arg(param, char *); - break; - case URGTAG_RANGE: - data->range = va_arg(param, char *); - break; - case URGTAG_RESUME_FROM: - data->resume_from = va_arg(param, long); - break; - case URGTAG_STDERR: - data->err = va_arg(param, FILE *); - break; - case URGTAG_WRITEFUNCTION: - data->fwrite = va_arg(param, void *); - break; - case URGTAG_WRITEINFO: - data->writeinfo = va_arg(param, char *); - break; - case URGTAG_READFUNCTION: - data->fread = va_arg(param, void *); - break; - case URGTAG_SSLCERT: - data->cert = va_arg(param, char *); - break; - case URGTAG_SSLCERTPASSWD: - data->cert_passwd = va_arg(param, char *); - break; - case URGTAG_CRLF: - data->crlf = va_arg(param, long); - break; - case URGTAG_QUOTE: - data->quote = va_arg(param, struct curl_slist *); - break; - default: - /* unknown tag and its companion, just ignore: */ - return URG_READ_ERROR; /* correct this */ - } - return URG_OK; -} - - -typedef int (*func_T)(void); - -UrgError curl_urlget(UrgTag tag, ...) -{ - va_list arg; - func_T param_func = (func_T)0; - long param_long = 0; - void *param_obj = NULL; - UrgError res; - struct UrlData *data; - /* this is for the lame win32 socket crap */ - if(curl_init()) - return URG_FAILED_INIT; + /* Very simple start-up: alloc the struct, init it with zeroes and return */ + data = (struct UrlData *)malloc(sizeof(struct UrlData)); + if(data) { + memset(data, 0, sizeof(struct UrlData)); + data->handle = STRUCT_OPEN; + data->interface = CURLI_NORMAL; /* normal interface by default */ - /* We use curl_open() with undefined URL so far */ - res = curl_open(&data, NULL); - if(res == URG_OK) { - /* data is now filled with good-looking zeroes */ + /* We do some initial setup here, all those fields that can't be just 0 */ + data-> headerbuff=(char*)malloc(HEADERSIZE); + if(!data->headerbuff) { + free(data); /* free the memory again */ + return CURLE_OUT_OF_MEMORY; + } + + data-> headersize=HEADERSIZE; + +#if 0 /* Let's set some default values: */ - curl_setopt(data, URGTAG_FILE, stdout); /* default output to stdout */ - curl_setopt(data, URGTAG_INFILE, stdin); /* default input from stdin */ - curl_setopt(data, URGTAG_STDERR, stderr); /* default stderr to stderr! */ + curl_setopt(data, CURLOPT_FILE, stdout); /* default output to stdout */ + curl_setopt(data, CURLOPT_INFILE, stdin); /* default input from stdin */ + curl_setopt(data, CURLOPT_STDERR, stderr); /* default stderr to stderr! */ +#endif + + data->out = stdout; /* default output to stdout */ + data->in = stdin; /* default input from stdin */ + data->err = stderr; /* default stderr to stderr */ data->firstsocket = -1; /* no file descriptor */ data->secondarysocket = -1; /* no file descriptor */ @@ -476,141 +285,204 @@ UrgError curl_urlget(UrgTag tag, ...) data->current_speed = -1; /* init to negative == impossible */ - va_start(arg, tag); - - while(tag != URGTAG_DONE) { - /* PORTING NOTE: - Ojbect 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 < URGTYPE_OBJECTPOINT) { - /* This is a LONG type */ - param_long = va_arg(arg, long); - curl_setopt(data, tag, param_long); - } - else if(tag < URGTYPE_FUNCTIONPOINT) { - /* This is a object pointer type */ - param_obj = va_arg(arg, void *); - curl_setopt(data, tag, param_obj); - } - else { - param_func = va_arg(arg, func_T ); - curl_setopt(data, tag, param_func); - } - - /* printf("tag: %d\n", tag); */ - tag = va_arg(arg, UrgTag); - } - - va_end(arg); - - pgrsMode(data, data->progress.mode); - pgrsStartNow(data); - - data-> headerbuff=(char*)malloc(HEADERSIZE); - if(!data->headerbuff) - return URG_FAILED_INIT; - - data-> headersize=HEADERSIZE; - - res = _urlget(data); /* fetch the URL please */ - - while((res == URG_OK) && data->newurl) { - /* Location: redirect */ - char prot[16]; - char path[URL_MAX_LENGTH]; - - if(2 != sscanf(data->newurl, "%15[^:]://%" URL_MAX_LENGTH_TXT - "s", prot, path)) { - /*** - *DANG* this is an RFC 2068 violation. The URL is supposed - to be absolute and this doesn't seem to be that! - *** - Instead, we have to TRY to append this new path to the old URL - to the right of the host part. Oh crap, this is doomed to cause - problems in the future... - */ - char *protsep; - char *pathsep; - char *newest; - - /* protsep points to the start of the host name */ - protsep=strstr(data->url, "//"); - if(!protsep) - protsep=data->url; - else { - data->port=0; /* we got a full URL and then we should reset the - port number here to re-initiate it later */ - protsep+=2; /* pass the // */ - } - - if('/' != data->newurl[0]) { - /* First we need to find out if there's a ?-letter in the URL, and - cut it and the right-side of that off */ - pathsep = strrchr(protsep, '?'); - if(pathsep) - *pathsep=0; - - /* we have a relative path to append to the last slash if - there's one available */ - pathsep = strrchr(protsep, '/'); - if(pathsep) - *pathsep=0; - } - else { - /* We got a new absolute path for this server, cut off from the - first slash */ - pathsep = strchr(protsep, '/'); - if(pathsep) - *pathsep=0; - } - - newest=(char *)malloc( strlen(data->url) + - 1 + /* possible slash */ - strlen(data->newurl) + 1/* zero byte */); - - if(!newest) - return URG_OUT_OF_MEMORY; - sprintf(newest, "%s%s%s", data->url, ('/' == data->newurl[0])?"":"/", - data->newurl); - free(data->newurl); - data->newurl = newest; - } - else { - /* This was an absolute URL, clear the port number! */ - data->port = 0; - } - - data->url = data->newurl; - data->newurl = NULL; /* don't show! */ - - infof(data, "Follows Location: to new URL: '%s'\n", data->url); - - /* clean up the sockets and SSL stuff from the previous "round" */ - urlfree(data, FALSE); - - res = _urlget(data); - } - if(data->newurl) - free(data->newurl); - - } - else - res = URG_FAILED_INIT; /* failed */ - - if((URG_OK == res) && data->writeinfo) { - /* Time to output some info to stdout */ - WriteOut(data); + *curl = data; + return CURLE_OK; } + /* this is a very serious error */ + return CURLE_OUT_OF_MEMORY; +} - /* total cleanup */ - urlfree(data, TRUE); +CURLcode curl_setopt(CURL *curl, CURLoption option, ...) +{ + struct UrlData *data = curl; + va_list param; + char *cookiefile; - return res; + va_start(param, option); + + switch(option) { + case CURLOPT_VERBOSE: + data->bits.verbose = va_arg(param, long); + break; + case CURLOPT_HEADER: + data->bits.http_include_header = va_arg(param, long); + break; + case CURLOPT_NOPROGRESS: + data->bits.hide_progress = va_arg(param, long); + if(data->bits.hide_progress) + data->progress.flags |= PGRS_HIDE; + break; + case CURLOPT_NOBODY: + data->bits.no_body = va_arg(param, long); + break; + case CURLOPT_FAILONERROR: + data->bits.http_fail_on_error = va_arg(param, long); + break; + case CURLOPT_UPLOAD: + data->bits.upload = va_arg(param, long); + break; + case CURLOPT_POST: + data->bits.http_post = va_arg(param, long); + break; + case CURLOPT_FTPLISTONLY: + data->bits.ftp_list_only = va_arg(param, long); + break; + case CURLOPT_FTPAPPEND: + data->bits.ftp_append = va_arg(param, long); + break; + case CURLOPT_NETRC: + data->bits.use_netrc = va_arg(param, long); + break; + case CURLOPT_FOLLOWLOCATION: + data->bits.http_follow_location = va_arg(param, long); + break; + case CURLOPT_FTPASCII: + data->bits.ftp_ascii = va_arg(param, long); + break; + case CURLOPT_PUT: + data->bits.http_put = va_arg(param, long); + break; + case CURLOPT_MUTE: + data->bits.mute = va_arg(param, long); + break; + + case CURLOPT_TIMECONDITION: + data->timecondition = va_arg(param, long); + break; + + case CURLOPT_TIMEVALUE: + data->timevalue = va_arg(param, long); + break; + + case CURLOPT_SSLVERSION: + data->ssl_version = va_arg(param, long); + break; + + case CURLOPT_COOKIEFILE: + cookiefile = (char *)va_arg(param, void *); + if(cookiefile) { + data->cookies = cookie_init(cookiefile); + } + break; + case CURLOPT_WRITEHEADER: + data->writeheader = (FILE *)va_arg(param, FILE *); + break; + case CURLOPT_COOKIE: + data->cookie = va_arg(param, char *); + break; + case CURLOPT_ERRORBUFFER: + data->errorbuffer = va_arg(param, char *); + break; + case CURLOPT_FILE: + data->out = va_arg(param, FILE *); + break; + case CURLOPT_FTPPORT: + data->ftpport = va_arg(param, char *); + data->bits.ftp_use_port = data->ftpport?1:0; + break; + case CURLOPT_HTTPHEADER: + data->headers = va_arg(param, struct HttpHeader *); + break; + case CURLOPT_CUSTOMREQUEST: + data->customrequest = va_arg(param, char *); + break; + case CURLOPT_HTTPPOST: + data->httppost = va_arg(param, struct HttpPost *); + data->bits.http_formpost = data->httppost?1:0; + break; + case CURLOPT_INFILE: + data->in = va_arg(param, FILE *); + break; + case CURLOPT_INFILESIZE: + data->infilesize = va_arg(param, long); + break; + case CURLOPT_LOW_SPEED_LIMIT: + data->low_speed_limit=va_arg(param, long); + break; + case CURLOPT_LOW_SPEED_TIME: + data->low_speed_time=va_arg(param, long); + break; + case CURLOPT_URL: + data->url = va_arg(param, char *); + break; + case CURLOPT_PORT: + /* this typecast is used to fool the compiler to NOT warn for a + "cast from pointer to integer of different size" */ + data->port = (unsigned short)(va_arg(param, long)); + break; + case CURLOPT_POSTFIELDS: + data->postfields = va_arg(param, char *); + break; + case CURLOPT_PROGRESSMODE: + data->progress.mode = va_arg(param, long); + break; + case CURLOPT_REFERER: + data->referer = va_arg(param, char *); + data->bits.http_set_referer = (data->referer && *data->referer)?1:0; + break; + case CURLOPT_PROXY: + data->proxy = va_arg(param, char *); + data->bits.httpproxy = data->proxy?1:0; + break; +#if 0 + case CURLOPT_FLAGS: + conf_to_internal(data, va_arg(param, long)); + break; +#endif + case CURLOPT_TIMEOUT: + data->timeout = va_arg(param, long); + break; + case CURLOPT_USERAGENT: + data->useragent = va_arg(param, char *); + break; + case CURLOPT_USERPWD: + data->userpwd = va_arg(param, char *); + data->bits.user_passwd = data->userpwd?1:0; + break; + case CURLOPT_POSTQUOTE: + data->postquote = va_arg(param, struct curl_slist *); + break; + case CURLOPT_PROXYUSERPWD: + data->proxyuserpwd = va_arg(param, char *); + data->bits.proxy_user_passwd = data->proxyuserpwd?1:0; + break; + case CURLOPT_RANGE: + data->range = va_arg(param, char *); + data->bits.set_range = data->range?1:0; + break; + case CURLOPT_RESUME_FROM: + data->resume_from = va_arg(param, long); + break; + case CURLOPT_STDERR: + data->err = va_arg(param, FILE *); + break; + case CURLOPT_WRITEFUNCTION: + data->fwrite = va_arg(param, write_callback); + break; + case CURLOPT_WRITEINFO: + data->writeinfo = va_arg(param, char *); + break; + case CURLOPT_READFUNCTION: + data->fread = va_arg(param, read_callback); + break; + case CURLOPT_SSLCERT: + data->cert = va_arg(param, char *); + break; + case CURLOPT_SSLCERTPASSWD: + data->cert_passwd = va_arg(param, char *); + break; + case CURLOPT_CRLF: + data->crlf = va_arg(param, long); + break; + case CURLOPT_QUOTE: + data->quote = va_arg(param, struct curl_slist *); + break; + default: + /* unknown tag and its companion, just ignore: */ + return CURLE_READ_ERROR; /* correct this */ + } + return CURLE_OK; } @@ -618,8 +490,7 @@ UrgError curl_urlget(UrgTag tag, ...) * Read everything until a newline. */ -static int GetLine(int sockfd, char *buf, - struct UrlData *data) +int GetLine(int sockfd, char *buf, struct UrlData *data) { int nread; int read_rc=1; @@ -645,7 +516,7 @@ static int GetLine(int sockfd, char *buf, } *ptr=0; /* zero terminate */ - if(data->conf & CONF_VERBOSE) { + if(data->bits.verbose) { fputs("< ", data->err); fwrite(buf, 1, nread, data->err); fputs("\n", data->err); @@ -654,7 +525,6 @@ static int GetLine(int sockfd, char *buf, } - #ifndef WIN32 #ifndef RETSIGTYPE #define RETSIGTYPE void @@ -667,35 +537,114 @@ RETSIGTYPE alarmfunc(int signal) } #endif -/* ====================================================== */ +CURLcode curl_write(CURLconnect *c_conn, char *buf, size_t amount, + size_t *n) +{ + struct connectdata *conn = (struct connectdata *)c_conn; + struct UrlData *data; + size_t bytes_written; + + if(!n || !conn || (conn->handle != STRUCT_CONNECT)) + return CURLE_FAILED_INIT; + data = conn->data; + +#ifdef USE_SSLEAY + if (data->use_ssl) { + bytes_written = SSL_write(data->ssl, buf, amount); + } + else { +#endif + bytes_written = swrite(conn->writesockfd, buf, amount); +#ifdef USE_SSLEAY + } +#endif /* USE_SSLEAY */ + + *n = bytes_written; + return CURLE_OK; +} + +CURLcode curl_read(CURLconnect *c_conn, char *buf, size_t buffersize, + size_t *n) +{ + struct connectdata *conn = (struct connectdata *)c_conn; + struct UrlData *data; + size_t nread; + + if(!n || !conn || (conn->handle != STRUCT_CONNECT)) + return CURLE_FAILED_INIT; + data = conn->data; + +#ifdef USE_SSLEAY + if (data->use_ssl) { + nread = SSL_read (data->ssl, buf, buffersize); + } + else { +#endif + nread = sread (conn->sockfd, buf, buffersize); +#ifdef USE_SSLEAY + } +#endif /* USE_SSLEAY */ + *n = nread; + return CURLE_OK; +} + +CURLcode curl_disconnect(CURLconnect *c_connect) +{ + struct connectdata *conn = c_connect; + + struct UrlData *data = conn->data; + + /* clean up the sockets and SSL stuff from the previous "round" */ + urlfree(data, FALSE); + + return CURLE_OK; +} + /* - * urlget - * (result put on stdout) + * NAME curl_connect() * - * ::= "://" [ ":" ] "/" + * DESCRIPTION * - * = "HTTP" | "HTTPS" | "GOPHER" | "FTP" + * Connects to the peer server and performs the initial setup. This function + * writes a connect handle to its second argument that is a unique handle for + * this connect. This allows multiple connects from the same handle returned + * by curl_open(). * - * When FTP: + * EXAMPLE * - * ::= [ ":" "@" ] + * CURLCode result; + * CURL curl; + * CURLconnect connect; + * result = curl_connect(curl, &connect); */ -static UrgError _urlget(struct UrlData *data) +CURLcode curl_connect(CURL *curl, CURLconnect **in_connect) { - struct hostent *hp=NULL; - struct sockaddr_in serv_addr; + char *tmp; char *buf; - char proto[64]; - char gname[256]="default.com"; - char *name; - char path[URL_MAX_LENGTH]="/"; - char *ppath, *tmp; - long bytecount; - struct timeval now; - - UrgError result; + CURLcode result; char resumerange[12]=""; + struct UrlData *data = curl; + struct connectdata *conn; + + if(!data || (data->handle != STRUCT_OPEN)) + return CURLE_BAD_FUNCTION_ARGUMENT; /* TBD: make error codes */ + + if(!data->url) + return CURLE_URL_MALFORMAT; + + conn = (struct connectdata *)malloc(sizeof(struct connectdata)); + if(!conn) { + *in_connect = NULL; /* clear the pointer */ + return CURLE_OUT_OF_MEMORY; + } + *in_connect = conn; + + memset(conn, 0, sizeof(struct connectdata)); + conn->handle = STRUCT_CONNECT; + + conn->data = data; /* remember our daddy */ + conn->state = CONN_INIT; buf = data->buffer; /* this is our buffer */ @@ -709,59 +658,60 @@ static UrgError _urlget(struct UrlData *data) * to SSL connect through the proxy -- and we don't know if we * will need to use SSL until we parse the url ... */ - if((1 == sscanf(data->url, "file://%" URL_MAX_LENGTH_TXT "[^\n]", - path))) { + if((2 == sscanf(data->url, "%64[^:]://%" URL_MAX_LENGTH_TXT "[^\n]", + conn->proto, + conn->path)) && strequal(conn->proto, "file")) { /* we deal with file:/// differently since it supports no hostname other than "localhost" and "127.0.0.1", - which ist unique among the protocols specified in RFC 1738 */ - if (strstr(path, "localhost/") || strstr(path, "127.0.0.1/")) - strcpy(path, &path[10]); /* ... since coincidentally - both host strings are of - equal length */ - /* otherwise, / is quietly ommitted */ + which is unique among the protocols specified in RFC 1738 */ + if (strnequal(conn->path, "localhost/", 10) || + strnequal(conn->path, "127.0.0.1/", 10)) + /* ... since coincidentally both host strings are of equal length + otherwise, / is quietly ommitted */ + strcpy(conn->path, &conn->path[10]); - - /* that's it, no more fiddling with proxies, redirections, - or SSL for files, go directly to the file reading function */ - result = file(data, path, &bytecount); - if(result) - return result; - - return URG_OK; + strcpy(conn->proto, "file"); } - else if (2 > sscanf(data->url, "%64[^\n:]://%256[^\n/]%" URL_MAX_LENGTH_TXT "[^\n]", - proto, gname, path)) { - + else { + /* Set default host and default path */ + strcpy(conn->gname, "curl.haxx.nu"); + strcpy(conn->path, "/"); + + if (2 > sscanf(data->url, + "%64[^\n:]://%256[^\n/]%" URL_MAX_LENGTH_TXT "[^\n]", + conn->proto, conn->gname, conn->path)) { - /* badly formatted, let's try the browser-style _without_ 'http://' */ - if((1 > sscanf(data->url, "%256[^\n/]%" URL_MAX_LENGTH_TXT "[^\n]", gname, - path)) ) { - failf(data, " malformed"); - return URG_URL_MALFORMAT; - } - if(strnequal(gname, "FTP", 3)) { - strcpy(proto, "ftp"); - } - else if(strnequal(gname, "GOPHER", 6)) - strcpy(proto, "gopher"); + /* badly formatted, let's try the browser-style _without_ 'http://' */ + if((1 > sscanf(data->url, "%256[^\n/]%" URL_MAX_LENGTH_TXT "[^\n]", + conn->gname, conn->path)) ) { + failf(data, " malformed"); + return CURLE_URL_MALFORMAT; + } + if(strnequal(conn->gname, "FTP", 3)) { + strcpy(conn->proto, "ftp"); + } + else if(strnequal(conn->gname, "GOPHER", 6)) + strcpy(conn->proto, "gopher"); #ifdef USE_SSLEAY - else if(strnequal(gname, "HTTPS", 5)) - strcpy(proto, "https"); + else if(strnequal(conn->gname, "HTTPS", 5)) + strcpy(conn->proto, "https"); #endif /* USE_SSLEAY */ - else if(strnequal(gname, "TELNET", 6)) - strcpy(proto, "telnet"); - else if (strnequal(gname, "DICT", sizeof("DICT")-1)) - strcpy(proto, "DICT"); - else if (strnequal(gname, "LDAP", sizeof("LDAP")-1)) - strcpy(proto, "LDAP"); - else - strcpy(proto, "http"); + else if(strnequal(conn->gname, "TELNET", 6)) + strcpy(conn->proto, "telnet"); + else if (strnequal(conn->gname, "DICT", sizeof("DICT")-1)) + strcpy(conn->proto, "DICT"); + else if (strnequal(conn->gname, "LDAP", sizeof("LDAP")-1)) + strcpy(conn->proto, "LDAP"); + else { + strcpy(conn->proto, "http"); + } - data->conf |= CONF_NOPROT; + conn->protocol |= PROT_MISSING; /* not given in URL */ + } } - if((data->conf & CONF_USERPWD) && ! (data->conf & CONF_NETRC)) { + if(data->bits.user_passwd && !data->bits.use_netrc) { if(':' != *data->userpwd) { if((1 <= sscanf(data->userpwd, "%127[^:]:%127s", data->user, data->passwd))) { @@ -774,11 +724,11 @@ static UrgError _urlget(struct UrlData *data) } if(!data->user[0]) { failf(data, "USER malformat: user name can't be zero length"); - return URG_MALFORMAT_USER; + return CURLE_MALFORMAT_USER; } } - if(data->conf & CONF_PROXYUSERPWD) { + if(data->bits.proxy_user_passwd) { if(':' != *data->proxyuserpwd) { if((1 <= sscanf(data->proxyuserpwd, "%127[^:]:%127s", data->proxyuser, data->proxypasswd))) { @@ -791,16 +741,16 @@ static UrgError _urlget(struct UrlData *data) } if(!data->proxyuser[0]) { failf(data, " Proxy USER malformat: user name can't be zero length"); - return URG_MALFORMAT_USER; + return CURLE_MALFORMAT_USER; } } - name = gname; - ppath = path; - data->hostname = name; + conn->name = conn->gname; + conn->ppath = conn->path; + data->hostname = conn->name; - if(!(data->conf & CONF_PROXY)) { + if(!data->bits.httpproxy) { /* If proxy was not specified, we check for default proxy environment variables, to enable i.e Lynx compliance: @@ -824,9 +774,9 @@ static UrgError _urlget(struct UrlData *data) nope=no_proxy?strtok(no_proxy, ", "):NULL; while(nope) { - if(strlen(nope) <= strlen(name)) { + if(strlen(nope) <= strlen(conn->name)) { char *checkn= - name + strlen(name) - strlen(nope); + conn->name + strlen(conn->name) - strlen(nope); if(strnequal(nope, checkn, strlen(nope))) { /* no proxy for this host! */ break; @@ -836,7 +786,7 @@ static UrgError _urlget(struct UrlData *data) } if(!nope) { /* It was not listed as without proxy */ - char *protop = proto; + char *protop = conn->proto; char *envp = proxy_env; char *prox; @@ -861,29 +811,29 @@ static UrgError _urlget(struct UrlData *data) if(proxy && *proxy) { /* we have a proxy here to set */ data->proxy = proxy; - data->conf |= CONF_PROXY; + data->bits.httpproxy=1; } } /* if (!nope) - it wasn't specfied non-proxy */ } /* NO_PROXY wasn't specified or '*' */ } /* if not using proxy */ - if((data->conf & (CONF_PROXY|CONF_NOPROT)) == (CONF_PROXY|CONF_NOPROT) ) { + if((conn->protocol&PROT_MISSING) && data->bits.httpproxy ) { /* We're guessing prefixes here and since we're told to use a proxy, we need to add the protocol prefix to the URL string before we continue! */ char *reurl; - reurl = maprintf("%s://%s", proto, data->url); + reurl = maprintf("%s://%s", conn->proto, data->url); if(!reurl) - return URG_OUT_OF_MEMORY; + return CURLE_OUT_OF_MEMORY; data->url = reurl; if(data->freethis) free(data->freethis); data->freethis = reurl; - data->conf &= ~CONF_NOPROT; /* switch that one off again */ + conn->protocol &= ~PROT_MISSING; /* switch that one off again */ } /* RESUME on a HTTP page is a tricky business. First, let's just check that @@ -894,11 +844,11 @@ static UrgError _urlget(struct UrlData *data) server, we just fail since we can't rewind the file writing from within this function. */ if(data->resume_from) { - if(!(data->conf & CONF_RANGE)) { + if(!data->bits.set_range) { /* if it already was in use, we just skip this */ sprintf(resumerange, "%d-", data->resume_from); data->range=resumerange; /* tell ourselves to fetch this range */ - data->conf |= CONF_RANGE; /* switch on range usage */ + data->bits.set_range = 1; /* switch on range usage */ } } @@ -916,50 +866,69 @@ static UrgError _urlget(struct UrlData *data) * works differently, depending on whether its SSL or not). */ - if (strequal(proto, "HTTP")) { + if (strequal(conn->proto, "HTTP")) { if(!data->port) data->port = PORT_HTTP; data->remote_port = PORT_HTTP; - data->conf |= CONF_HTTP; + conn->protocol |= PROT_HTTP; + conn->curl_do = http; + conn->curl_done = http_done; } - else if (strequal(proto, "HTTPS")) { + else if (strequal(conn->proto, "HTTPS")) { #ifdef USE_SSLEAY if(!data->port) data->port = PORT_HTTPS; data->remote_port = PORT_HTTPS; - data->conf |= CONF_HTTP; - data->conf |= CONF_HTTPS; + conn->protocol |= PROT_HTTP; + conn->protocol |= PROT_HTTPS; + + conn->curl_do = http; + conn->curl_done = http_done; + conn->curl_connect = http_connect; + #else /* USE_SSLEAY */ failf(data, "SSL is disabled, https: not supported!"); - return URG_UNSUPPORTED_PROTOCOL; + return CURLE_UNSUPPORTED_PROTOCOL; #endif /* !USE_SSLEAY */ } - else if (strequal(proto, "GOPHER")) { + else if (strequal(conn->proto, "GOPHER")) { if(!data->port) data->port = PORT_GOPHER; data->remote_port = PORT_GOPHER; /* Skip // in path if present */ - if (isdigit((int)path[1])) { - ppath = strchr(&path[1], '/'); - if (ppath == NULL) - ppath = path; + if (isdigit((int)conn->path[1])) { + conn->ppath = strchr(&conn->path[1], '/'); + if (conn->ppath == NULL) + conn->ppath = conn->path; } - data->conf |= CONF_GOPHER; + conn->protocol |= PROT_GOPHER; + conn->curl_do = http; + conn->curl_done = http_done; } - else if(strequal(proto, "FTP")) { + else if(strequal(conn->proto, "FTP")) { char *type; if(!data->port) data->port = PORT_FTP; data->remote_port = PORT_FTP; - data->conf |= CONF_FTP; + conn->protocol |= PROT_FTP; - ppath++; /* don't include the initial slash */ + if(data->bits.httpproxy) { + conn->curl_do = http; + conn->curl_done = http_done; + } + else { + conn->curl_do = ftp; + conn->curl_done = ftp_done; + conn->curl_connect = ftp_connect; + } + + conn->ppath++; /* don't include the initial slash */ /* FTP URLs support an extension like ";type=" that we'll try to get now! */ - type=strstr(ppath, ";type="); + type=strstr(conn->ppath, ";type="); if(!type) { - type=strstr(gname, ";type="); + type=strstr(conn->gname, ";type="); } if(type) { char command; @@ -967,54 +936,59 @@ static UrgError _urlget(struct UrlData *data) command = toupper(type[6]); switch(command) { case 'A': /* ASCII mode */ - data->conf |= CONF_FTPASCII; + data->bits.ftp_ascii = 1; break; case 'D': /* directory mode */ - data->conf |= CONF_FTPLISTONLY; + data->bits.ftp_list_only = 1; break; case 'I': /* binary mode */ default: /* switch off ASCII */ - data->conf &= ~CONF_FTPASCII; + data->bits.ftp_ascii = 0; break; } } } - else if(strequal(proto, "TELNET")) { + else if(strequal(conn->proto, "TELNET")) { /* telnet testing factory */ - data->conf |= CONF_TELNET; + conn->protocol |= PROT_TELNET; if(!data->port) data->port = PORT_TELNET; data->remote_port = PORT_TELNET; + + conn->curl_do = telnet; + conn->curl_done = telnet_done; + } - else if (strequal(proto, "DICT")) { - data->conf |= CONF_DICT; + else if (strequal(conn->proto, "DICT")) { + conn->protocol |= PROT_DICT; if(!data->port) data->port = PORT_DICT; data->remote_port = PORT_DICT; + conn->curl_do = dict; + conn->curl_done = dict_done; } - else if (strequal(proto, "LDAP")) { - data->conf |= CONF_LDAP; + else if (strequal(conn->proto, "LDAP")) { + conn->protocol |= PROT_LDAP; if(!data->port) data->port = PORT_LDAP; data->remote_port = PORT_LDAP; + conn->curl_do = ldap; + conn->curl_done = ldap_done; } - /* file:// is handled above */ - /* else if (strequal(proto, "FILE")) { - data->conf |= CONF_FILE; + else if (strequal(conn->proto, "FILE")) { + conn->protocol |= PROT_FILE; - result = file(data, path, &bytecount); - if(result) - return result; + conn->curl_do = file; + /* no done() function */ + } - return URG_OK; - }*/ else { - failf(data, "Unsupported protocol: %s", proto); - return URG_UNSUPPORTED_PROTOCOL; + failf(data, "Unsupported protocol: %s", conn->proto); + return CURLE_UNSUPPORTED_PROTOCOL; } - if(data->conf & CONF_NETRC) { + if(data->bits.use_netrc) { if(ParseNetrc(data->hostname, data->user, data->passwd)) { infof(data, "Couldn't find host %s in the .netrc file, using defaults", data->hostname); @@ -1025,25 +999,26 @@ static UrgError _urlget(struct UrlData *data) strcpy(data->user, CURL_DEFAULT_USER); if(!data->passwd[0]) strcpy(data->passwd, CURL_DEFAULT_PASSWORD); - if(data->conf & CONF_HTTP) { - data->conf |= CONF_USERPWD; + if(conn->protocol&PROT_HTTP) { + data->bits.user_passwd = 1; /* enable user+password */ } } - else if(!(data->conf & CONF_USERPWD) && - (data->conf & (CONF_FTP|CONF_HTTP)) ) { + else if(!(data->bits.user_passwd) && + (conn->protocol & (PROT_FTP|PROT_HTTP)) ) { /* This is a FTP or HTTP URL, and we haven't got the user+password in the extra parameter, we will now try to extract the possible user+password pair in a string like: ftp://user:password@ftp.my.site:8021/README */ char *ptr=NULL; /* assign to remove possible warnings */ - if(':' == *name) { + if(':' == *conn->name) { failf(data, "URL malformat: user can't be zero length"); - return URG_URL_MALFORMAT_USER; + return CURLE_URL_MALFORMAT_USER; } - if((1 <= sscanf(name, "%127[^:]:%127[^@]", - data->user, data->passwd)) && (ptr=strchr(name, '@'))) { - name = ++ptr; - data->conf |= CONF_USERPWD; + if((1 <= sscanf(conn->name, "%127[^:]:%127[^@]", + data->user, data->passwd)) && + (ptr=strchr(conn->name, '@'))) { + conn->name = ++ptr; + data->bits.user_passwd=1; /* enable user+password */ } else { strcpy(data->user, CURL_DEFAULT_USER); @@ -1051,19 +1026,19 @@ static UrgError _urlget(struct UrlData *data) } } - if(!(data->conf & CONF_PROXY)) { + if(!data->bits.httpproxy) { /* If not connecting via a proxy, extract the port from the URL, if it is * there, thus overriding any defaults that might have been set above. */ - tmp = strchr(name, ':'); + tmp = strchr(conn->name, ':'); if (tmp) { *tmp++ = '\0'; data->port = atoi(tmp); } /* Connect to target host right on */ - if(!(hp = GetHost(data, name))) { - failf(data, "Couldn't resolv host '%s'", name); - return URG_COULDNT_RESOLVE_HOST; + if(!(conn->hp = GetHost(data, conn->name))) { + failf(data, "Couldn't resolv host '%s'", conn->name); + return CURLE_COULDNT_RESOLVE_HOST; } } else { @@ -1079,12 +1054,12 @@ static UrgError _urlget(struct UrlData *data) if(NULL == proxydup) { failf(data, "memory shortage"); - return URG_OUT_OF_MEMORY; + return CURLE_OUT_OF_MEMORY; } /* we use proxy all right, but we wanna know the remote port for SSL reasons */ - tmp = strchr(name, ':'); + tmp = strchr(conn->name, ':'); if (tmp) { *tmp++ = '\0'; /* cut off the name there */ data->remote_port = atoi(tmp); @@ -1111,9 +1086,9 @@ static UrgError _urlget(struct UrlData *data) } /* connect to proxy */ - if(!(hp = GetHost(data, proxyptr))) { + if(!(conn->hp = GetHost(data, proxyptr))) { failf(data, "Couldn't resolv proxy '%s'", proxyptr); - return URG_COULDNT_RESOLVE_PROXY; + return CURLE_COULDNT_RESOLVE_PROXY; } free(proxydup); /* free the duplicate pointer and not the modified */ @@ -1122,14 +1097,16 @@ static UrgError _urlget(struct UrlData *data) data->firstsocket = socket(AF_INET, SOCK_STREAM, 0); - memset((char *) &serv_addr, '\0', sizeof(serv_addr)); - memcpy((char *)&(serv_addr.sin_addr), hp->h_addr, hp->h_length); - serv_addr.sin_family = hp->h_addrtype; + memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr)); + memcpy((char *)&(conn->serv_addr.sin_addr), + conn->hp->h_addr, conn->hp->h_length); + conn->serv_addr.sin_family = conn->hp->h_addrtype; + conn->serv_addr.sin_port = htons(data->port); - serv_addr.sin_port = htons(data->port); - - if (connect(data->firstsocket, (struct sockaddr *) &serv_addr, - sizeof(serv_addr)) < 0) { + if (connect(data->firstsocket, + (struct sockaddr *) &(conn->serv_addr), + sizeof(conn->serv_addr) + ) < 0) { switch(errno) { #ifdef ECONNREFUSED /* this should be made nicer */ @@ -1146,10 +1123,10 @@ static UrgError _urlget(struct UrlData *data) failf(data, "Can't connect to server: %d", errno); break; } - return URG_COULDNT_CONNECT; + return CURLE_COULDNT_CONNECT; } - if(data->conf & CONF_PROXYUSERPWD) { + if(data->bits.proxy_user_passwd) { char authorization[512]; sprintf(data->buffer, "%s:%s", data->proxyuser, data->proxypasswd); base64Encode(data->buffer, authorization); @@ -1157,74 +1134,27 @@ static UrgError _urlget(struct UrlData *data) data->ptr_proxyuserpwd = maprintf("Proxy-authorization: Basic %s\015\012", authorization); } - if(data->conf & (CONF_HTTPS|CONF_HTTP|CONF_PROXY)) { + if((conn->protocol&PROT_HTTP) || data->bits.httpproxy) { if(data->useragent) { data->ptr_uagent = maprintf("User-Agent: %s\015\012", data->useragent); } } - - /* If we are not using a proxy and we want a secure connection, - * perform SSL initialization & connection now. - * If using a proxy with https, then we must tell the proxy to CONNECT - * us to the host we want to talk to. Only after the connect - * has occured, can we start talking SSL - */ - if (data->conf & CONF_HTTPS) { - if (data->conf & CONF_PROXY) { - - /* OK, now send the connect statment */ - sendf(data->firstsocket, data, - "CONNECT %s:%d HTTP/1.0\015\012" - "%s" - "%s" - "\r\n", - data->hostname, data->remote_port, - (data->conf&CONF_PROXYUSERPWD)?data->ptr_proxyuserpwd:"", - (data->useragent?data->ptr_uagent:"") - ); - - /* wait for the proxy to send us a HTTP/1.0 200 OK header */ - /* Daniel rewrote this part Nov 5 1998 to make it more obvious */ - { - int httperror=0; - int subversion=0; - while(GetLine(data->firstsocket, data->buffer, data)) { - if('\r' == data->buffer[0]) - break; /* end of headers */ - if(2 == sscanf(data->buffer, "HTTP/1.%d %d", - &subversion, - &httperror)) { - ; - } - } - if(200 != httperror) { - if(407 == httperror) - /* Added Nov 6 1998 */ - failf(data, "Proxy requires authorization!"); - else - failf(data, "Received error code %d from proxy", httperror); - return URG_READ_ERROR; - } - } - infof (data, "Proxy has replied to CONNECT request\n"); - } - - /* now, perform the SSL initialization for this socket */ - if(UrgSSLConnect (data)) { - return URG_SSL_CONNECT_ERROR; - } + if(conn->curl_connect) { + /* is there a post-connect() procedure? */ + result = conn->curl_connect(conn); } + pgrsTime(data, TIMER_CONNECT); - now = tvnow(); /* time this *after* the connect is done */ - bytecount = 0; + conn->now = tvnow(); /* time this *after* the connect is done */ + conn->bytecount = 0; /* Figure out the ip-number and the first host name it shows: */ { struct in_addr in; - (void) memcpy(&in.s_addr, *hp->h_addr_list, sizeof (in.s_addr)); - infof(data, "Connected to %s (%s)\n", hp->h_name, inet_ntoa(in)); + (void) memcpy(&in.s_addr, *conn->hp->h_addr_list, sizeof (in.s_addr)); + infof(data, "Connected to %s (%s)\n", conn->hp->h_name, inet_ntoa(in)); } #if 0 /* Kerberos experiements! Beware! Take cover! */ @@ -1243,36 +1173,67 @@ static UrgError _urlget(struct UrlData *data) } #endif - if((data->conf&(CONF_FTP|CONF_PROXY)) == CONF_FTP) { - result = ftp(data, &bytecount, data->user, data->passwd, ppath); - if(result) - return result; - } - else if(data->conf & CONF_TELNET) { - result=telnet(data); - if(result) - return result; - } - else if (data->conf & CONF_LDAP) { - result = ldap(data, path, &bytecount); - if (result) - return result; - } - else if (data->conf & CONF_DICT) { - result = dict(data, path, &bytecount); - if(result) - return result; - } - else { - result = http(data, ppath, name, &bytecount); - if(result) - return result; - } - if(bytecount) { - double ittook = tvdiff (tvnow(), now); - infof(data, "%i bytes transfered in %.3lf seconds (%.0lf bytes/sec).\n", - bytecount, ittook, (double)bytecount/(ittook!=0.0?ittook:1)); - } - return URG_OK; + return CURLE_OK; +} + +CURLcode curl_done(CURLconnect *c_connect) +{ + struct connectdata *conn = c_connect; + struct UrlData *data; + CURLcode result; + + if(!conn || (conn->handle!= STRUCT_CONNECT)) { + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(conn->state != CONN_DO) { + /* This can only be called after a curl_do() */ + return CURLE_BAD_CALLING_ORDER; + } + data = conn->data; + + /* this calls the protocol-specific function pointer previously set */ + if(conn->curl_done) + result = conn->curl_done(conn); + else + result = CURLE_OK; + + pgrsDone(data); /* done with the operation */ + + conn->state = CONN_DONE; + + return result; +} + +CURLcode curl_do(CURLconnect *in_conn) +{ + struct connectdata *conn = in_conn; + CURLcode result; + + if(!conn || (conn->handle!= STRUCT_CONNECT)) { + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(conn->state != CONN_INIT) { + return CURLE_BAD_CALLING_ORDER; + } + + if(conn->curl_do) { + /* generic protocol-specific function pointer set in curl_connect() */ + result = conn->curl_do(conn); + if(result) { + conn->state = CONN_ERROR; + return result; + } + } + + conn->state = CONN_DO; /* we have entered this state */ + +#if 0 + if(conn->bytecount) { + double ittook = tvdiff (tvnow(), conn->now); + infof(data, "%i bytes transfered in %.3lf seconds (%.0lf bytes/sec).\n", + conn->bytecount, ittook, (double)conn->bytecount/(ittook!=0.0?ittook:1)); + } +#endif + return CURLE_OK; } diff --git a/lib/url.h b/lib/url.h index e69de29bb..334fa9767 100644 --- a/lib/url.h +++ b/lib/url.h @@ -0,0 +1,44 @@ +#ifndef __URL_H +#define __URL_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +int GetLine(int sockfd, char *buf, struct UrlData *data); + +#endif diff --git a/lib/urldata.h b/lib/urldata.h index 0515d6817..debaaa9b5 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -67,6 +67,7 @@ #define CURL_DEFAULT_PASSWORD "curl_by_Daniel.Stenberg@haxx.nu" #include "cookie.h" +#include "formdata.h" #ifdef USE_SSLEAY /* SSLeay stuff usually in /usr/local/ssl/include */ @@ -87,8 +88,12 @@ #endif #endif +#include + #include "timeval.h" + + /* Download buffer size, keep it fairly big for speed reasons */ #define BUFSIZE (1024*50) @@ -96,6 +101,88 @@ of need. */ #define HEADERSIZE 256 +#ifndef MAX +#define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +typedef enum { + STRUCT_NONE, + STRUCT_OPEN, + STRUCT_CONNECT, + STRUCT_LAST +} Handle; + +typedef enum { + CONN_NONE, /* illegal state */ + CONN_INIT, /* curl_connect() has been called */ + CONN_DO, /* curl_do() has been called successfully */ + CONN_DONE, /* curl_done() has been called successfully */ + CONN_ERROR, /* and error has occurred */ + CONN_LAST /* illegal state */ +} ConnState; + + +/* + * The connectdata struct contains all fields and variables that should be + * unique for an entire connection. + */ +struct connectdata { + /**** Fields set when inited and not modified again */ + + /* To better see what kind of struct that is passed as input, *ALL* publicly + returned handles MUST have this initial 'Handle'. */ + Handle handle; /* struct identifier */ + struct UrlData *data; /* link to the root CURL struct */ + + /**** curl_connect() phase fields */ + ConnState state; /* for state dependent actions */ + + long protocol; /* PROT_* flags concerning the protocol set */ +#define PROT_MISSING (1<<0) +#define PROT_GOPHER (1<<1) +#define PROT_HTTP (1<<2) +#define PROT_HTTPS (1<<3) +#define PROT_FTP (1<<4) +#define PROT_TELNET (1<<5) +#define PROT_DICT (1<<6) +#define PROT_LDAP (1<<7) +#define PROT_FILE (1<<8) + + struct hostent *hp; + struct sockaddr_in serv_addr; + char proto[64]; + char gname[256]; + char *name; + char path[URL_MAX_LENGTH]; + char *ppath; + long bytecount; + struct timeval now; + + /* These two functions MUST be set by the curl_connect() function to be + be protocol dependent */ + CURLcode (*curl_do)(struct connectdata *connect); + CURLcode (*curl_done)(struct connectdata *connect); + + /* This function *MAY* be set to a protocol-dependent function that is run + * after the connect() and everything is done, as a step in the connection. + */ + CURLcode (*curl_connect)(struct connectdata *connect); + + /**** curl_get() phase fields */ + + /* READ stuff */ + int sockfd; /* socket to read from or -1 */ + int size; /* -1 if unknown at this point */ + bool getheader; /* TRUE if header parsing is wanted */ + long *bytecountp; /* return number of bytes read or NULL */ + + /* WRITE stuff */ + int writesockfd; /* socket to write to, it may very well be + the same we read from. -1 disables */ + long *writebytecountp; /* return number of bytes written or NULL */ + +}; + struct Progress { long lastshow; /* time() of the last displayed progress meter or NULL to force redraw at next call */ @@ -121,42 +208,160 @@ struct Progress { int httpcode; }; +/**************************************************************************** + * HTTP unique setup + ***************************************************************************/ +struct HTTP { + struct FormData *sendit; + int postsize; + char *p_pragma; + char *p_accept; + long readbytecount; + long writebytecount; + + /* For FORM posting */ + struct Form form; + size_t (*storefread)(char *, size_t , size_t , FILE *); + FILE *in; +}; + +/**************************************************************************** + * FTP unique setup + ***************************************************************************/ +struct FTP { + long *bytecountp; + char *user; + char *passwd; + char *urlpath; /* the originally given path part of the URL */ + char *dir; /* decoded directory */ + char *file; /* decoded file */ +}; + +struct Configbits { + bool ftp_append; + bool ftp_ascii; + bool http_post; + bool http_set_referer; + bool http_fail_on_error; + bool http_formpost; + bool http_include_header; + bool http_follow_location; + bool http_put; + bool no_body; + bool ftp_list_only; + bool use_netrc; + bool ftp_use_port; + bool set_port; + bool set_range; + bool mute; + bool hide_progress; + bool upload; + bool user_passwd; + bool proxy_user_passwd; + bool verbose; + bool httpproxy; +}; + +typedef size_t (*progress_callback)(void *clientp, + size_t dltotal, + size_t dlnow, + size_t ultotal, + size_t ulnow); + +typedef size_t (*write_callback)(char *buffer, + size_t size, + size_t nitems, + FILE *outstream); + +typedef size_t (*read_callback)(char *buffer, + size_t size, + size_t nitems, + FILE *instream); + +/* What type of interface that intiated this struct */ +typedef enum { + CURLI_NONE, + CURLI_EASY, + CURLI_NORMAL, + CURLI_LAST +} CurlInterface; + +/* + * As of April 11, 2000 we're now trying to split up the urldata struct in + * three different parts: + * + * (Global) + * 1 - No matter how many hosts and requests that are being performed, this + * goes for all of them. + * + * (Session) + * 2 - Host and protocol-specific. No matter if we do several transfers to and + * from this host, these variables stay the same. + * + * (Request) + * 3 - Request-specific. Variables that are of interest for this particular + * transfer being made right now. + * + */ + struct UrlData { + Handle handle; /* struct identifier */ + CurlInterface interface; + + /*************** Global - specific items ************/ + FILE *err; /* the stderr writes goes here */ + char *errorbuffer; /* store failure messages in here */ + + /*************** Session - specific items ************/ + char *proxy; /* if proxy, set it here, set CONF_PROXY to use this */ + char *proxyuserpwd; /* Proxy , if used */ + + /*************** Request - specific items ************/ + + union { + struct HTTP *http; + struct HTTP *gopher; /* alias, just for the sake of being more readable */ + struct HTTP *https; /* alias, just for the sake of being more readable */ + struct FTP *ftp; +#if 0 /* no need for special ones for these: */ + struct TELNET *telnet; + struct FILE *file; + struct LDAP *ldap; + struct DICT *dict; +#endif + void *generic; + } proto; + FILE *out; /* the fetched file goes here */ FILE *in; /* the uploaded file is read from here */ - FILE *err; /* the stderr writes goes here */ FILE *writeheader; /* write the header to this is non-NULL */ char *url; /* what to get */ char *freethis; /* if non-NULL, an allocated string for the URL */ - char *hostname; /* hostname to contect, as parsed from url */ + char *hostname; /* hostname to connect, as parsed from url */ unsigned short port; /* which port to use (if non-protocol bind) set CONF_PORT to use this */ unsigned short remote_port; /* what remote port to connect to, not the proxy port! */ - char *proxy; /* if proxy, set it here, set CONF_PROXY to use this */ - long conf; /* configure flags */ + struct Configbits bits; /* new-style (v7) flag data */ + char *userpwd; /* , if used */ - char *proxyuserpwd; /* Proxy , if used */ char *range; /* range, if used. See README for detailed specification on this syntax. */ char *postfields; /* if POST, set the fields' values here */ char *referer; - char *errorbuffer; /* store failure messages in here */ char *useragent; /* User-Agent string */ char *ftpport; /* port to send with the PORT command */ - /* function that stores the output:*/ - size_t (*fwrite)(char *buffer, - size_t size, - size_t nitems, - FILE *outstream); + /* function that stores the output:*/ + write_callback fwrite; /* function that reads the input:*/ - size_t (*fread)(char *buffer, - size_t size, - size_t nitems, - FILE *outstream); + read_callback fread; + + /* function that wants progress information */ + progress_callback fprogress; + void *progress_client; /* pointer to pass to the progress callback */ long timeout; /* in seconds, 0 means no timeout */ long infilesize; /* size of file to upload, -1 means unknown */ diff --git a/lib/version.c b/lib/version.c index 73be0d7f9..ea54b2a49 100644 --- a/lib/version.c +++ b/lib/version.c @@ -58,7 +58,7 @@ char *curl_version(void) #ifdef USE_SSLEAY #if (SSLEAY_VERSION_NUMBER >= 0x900000) - sprintf(ptr, " (SSL %x.%x.%x)", + sprintf(ptr, " (SSL %lx.%lx.%lx)", (SSLEAY_VERSION_NUMBER>>28)&0xff, (SSLEAY_VERSION_NUMBER>>20)&0xff, (SSLEAY_VERSION_NUMBER>>12)&0xf); diff --git a/lib/writeout.c b/lib/writeout.c index 415d9e2ce..d86306286 100644 --- a/lib/writeout.c +++ b/lib/writeout.c @@ -41,6 +41,7 @@ #include #include +#include "strequal.h" #include "writeout.h" typedef enum { diff --git a/lib/writeout.h b/lib/writeout.h index d730bbfff..faf047709 100644 --- a/lib/writeout.h +++ b/lib/writeout.h @@ -1,3 +1,5 @@ +#ifndef __WRITEOUT_H +#define __WRITEOUT_H /***************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -41,3 +43,5 @@ #include "urldata.h" void WriteOut(struct UrlData *data); + +#endif diff --git a/maketgz b/maketgz index 6ad429b5d..79982d0d3 100755 --- a/maketgz +++ b/maketgz @@ -7,15 +7,24 @@ read version libversion="$version" +# +# Now we have a section to get the major, minor and patch number from the +# full version string. We create a single hexadecimal number from it '0xMMmmpp' +# +perl='$a=;@p=split("\\.",$a);for(0..2){printf STDOUT ("%02x",$p[0+$_]);}'; + +numeric=`echo $libversion | perl -e "$perl"` + echo "CURL version number?" read curlversion HEADER=include/curl/curl.h CHEADER=src/version.h - # Replace version number in header file: -sed 's/#define LIBCURL_VERSION.*/#define LIBCURL_VERSION "'$libversion'"/g' $HEADER >$HEADER.new +sed -e 's/^#define LIBCURL_VERSION .*/#define LIBCURL_VERSION "'$libversion'"/g' \ + -e 's/^#define LIBCURL_VERSION_NUM .*/#define LIBCURL_VERSION_NUM 0x'$numeric'/g' \ + $HEADER >$HEADER.new # Save old header file cp -p $HEADER $HEADER.old diff --git a/src/Makefile.am b/src/Makefile.am index 561142ed3..21a799acd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,7 @@ # Some flags needed when trying to cause warnings ;-) # CFLAGS = -Wall -pedantic -CPPFLAGS = -DGLOBURL -DCURL_SEPARATORS +#CPPFLAGS = -DGLOBURL -DCURL_SEPARATORS INCLUDES = -I$(top_srcdir)/include diff --git a/src/config-win32.h b/src/config-win32.h index ba60773eb..55d3e3a5f 100644 --- a/src/config-win32.h +++ b/src/config-win32.h @@ -2,6 +2,9 @@ /* Define if you have the strcasecmp function. */ /*#define HAVE_STRCASECMP 1*/ +/* Define if you have the stricmp function. */ +#define HAVE_STRICMP 1 + /* Define cpu-machine-OS */ #define OS "win32" diff --git a/src/hugehelp.c b/src/hugehelp.c index dde24867a..316d3e39d 100644 --- a/src/hugehelp.c +++ b/src/hugehelp.c @@ -9,725 +9,694 @@ puts ( " | (__| |_| | _ <| |___ \n" " \\___|\\___/|_| \\_\\_____|\n" "NAME\n" -" curl - get a URL with FTP, TELNET, LDAP, GOPHER, DICT,\n" -" FILE, HTTP or HTTPS syntax.\n" +" curl - get a URL with FTP, TELNET, LDAP, GOPHER, DICT, FILE,\n" +" HTTP or HTTPS syntax.\n" "\n" "SYNOPSIS\n" -" curl [options] url\n" +" curl [options] url\n" "\n" "DESCRIPTION\n" -" curl is a client to get documents/files from servers,\n" -" using any of the supported protocols. The command is\n" -" designed to work without user interaction or any kind of\n" -" interactivity.\n" +" curl is a client to get documents/files from servers, using\n" +" any of the supported protocols. The command is designed to\n" +" work without user interaction or any kind of interactivity.\n" "\n" -" curl offers a busload of useful tricks like proxy support,\n" -" user authentication, ftp upload, HTTP post, SSL (https:)\n" -" connections, cookies, file transfer resume and more.\n" +" curl offers a busload of useful tricks like proxy support,\n" +" user authentication, ftp upload, HTTP post, SSL (https:)\n" +" connections, cookies, file transfer resume and more.\n" "\n" "URL\n" -" The URL syntax is protocol dependent. You'll find a\n" -" detailed description in RFC 2396.\n" +" The URL syntax is protocol dependent. You'll find a detailed\n" +" description in RFC 2396.\n" "\n" -" You can specify multiple URLs or parts of URLs by writing\n" -" part sets within braces as in:\n" +" You can specify multiple URLs or parts of URLs by writing\n" +" part sets within braces as in:\n" "\n" -" http://site.{one,two,three}.com\n" +" http://site.{one,two,three}.com\n" "\n" -" or you can get sequences of alphanumeric series by using\n" -" [] as in:\n" +" or you can get sequences of alphanumeric series by using []\n" +" as in:\n" "\n" -" ftp://ftp.numericals.com/file[1-100].txt\n" -" ftp://ftp.numericals.com/file[001-100].txt (with lead-\n" -" ing zeros)\n" -" ftp://ftp.letters.com/file[a-z].txt\n" +" ftp://ftp.numericals.com/file[1-100].txt\n" +" ftp://ftp.numericals.com/file[001-100].txt (with leading\n" +" zeros)\n" +" ftp://ftp.letters.com/file[a-z].txt\n" "\n" -" It is possible to specify up to 9 sets or series for a\n" -" URL, but no nesting is supported at the moment:\n" +" It is possible to specify up to 9 sets or series for a URL,\n" +" but no nesting is supported at the moment:\n" "\n" -" http://www.any.org/archive[1996-1999]/vol-\n" -" ume[1-4]part{a,b,c,index}.html\n" +" http://www.any.org/archive[1996-1999]/vol­\n" +" ume[1-4]part{a,b,c,index}.html\n" "\n" "OPTIONS\n" -" -a/--append\n" -" (FTP) When used in a ftp upload, this will tell\n" -" curl to append to the target file instead of over-\n" -" writing it. If the file doesn't exist, it will be\n" -" created.\n" -"\n" -" -A/--user-agent \n" -" (HTTP) Specify the User-Agent string to send to the\n" -" HTTP server. Some badly done CGIs fail if its not\n" -" set to \"Mozilla/4.0\". To encode blanks in the\n" -" string, surround the string with single quote\n" -" marks. This can also be set with the -H/--header\n" -" flag of course.\n" -" -b/--cookie \n" -" (HTTP) Pass the data to the HTTP server as a\n" -" cookie. It is supposedly the data previously\n" -" received from the server in a \"Set-Cookie:\" line.\n" -" The data should be in the format \"NAME1=VALUE1;\n" -" NAME2=VALUE2\".\n" -"\n" -" If no '=' letter is used in the line, it is treated\n" -" as a filename to use to read previously stored\n" -" cookie lines from, which should be used in this\n" -" session if they match. Using this method also acti-\n" -" vates the \"cookie parser\" which will make curl\n" -" record incoming cookies too, which may be handy if\n" -" you're using this in combination with the\n" -" -L/--location option. The file format of the file\n" -" to read cookies from should be plain HTTP headers\n" -" or the netscape cookie file format.\n" -"\n" -" NOTE that the file specified with -b/--cookie is\n" -" only used as input. No cookies will be stored in\n" -" the file. To store cookies, save the HTTP headers\n" -" to a file using -D/--dump-header!\n" -"\n" -" -B/--ftp-ascii\n" -" (FTP/LDAP) Use ASCII transfer when getting an FTP\n" -" file or LDAP info. For FTP, this can also be\n" -" enforced by using an URL that ends with \";type=A\".\n" -"\n" -" -c/--continue\n" -" Continue/Resume a previous file transfer. This\n" -" instructs curl to continue appending data on the\n" -" file where it was previously left, possibly because\n" -" of a broken connection to the server. There must be\n" -" a named physical file to append to for this to\n" -" work. Note: Upload resume is depening on a command\n" -" named SIZE not always present in all ftp servers!\n" -" Upload resume is for FTP only. HTTP resume is only\n" -" possible with HTTP/1.1 or later servers.\n" -"\n" -" -C/--continue-at \n" -" Continue/Resume a previous file transfer at the\n" -" given offset. The given offset is the exact number\n" -" of bytes that will be skipped counted from the\n" -" beginning of the source file before it is trans-\n" -" fered to the destination. If used with uploads,\n" -" the ftp server command SIZE will not be used by\n" -" curl. Upload resume is for FTP only. HTTP resume\n" -" is only possible with HTTP/1.1 or later servers.\n" -"\n" -" -d/--data \n" -" (HTTP) Sends the specified data in a POST request\n" -" to the HTTP server. Note that the data is sent\n" -" exactly as specified with no extra processing. The\n" -" data is expected to be \"url-encoded\". This will\n" -" cause curl to pass the data to the server using the\n" -" content-type application/x-www-form-urlencoded.\n" -" Compare to -F.\n" -"\n" -" If you start the data with the letter @, the rest\n" -" should be a file name to read the data from, or -\n" -" if you want curl to read the data from stdin. The\n" -" contents of the file must already be url-encoded.\n" -"\n" -" -D/--dump-header \n" -" (HTTP/FTP) Write the HTTP headers to this file.\n" -" Write the FTP file info to this file if -I/--head\n" -" is used.\n" -"\n" -" This option is handy to use when you want to store\n" -" the cookies that a HTTP site sends to you. The\n" -" cookies could then be read in a second curl invoke\n" -" by using the -b/--cookie option!\n" -"\n" -" -e/--referer \n" -" (HTTP) Sends the \"Referer Page\" information to the\n" -" HTTP server. Some badly done CGIs fail if it's not\n" -" set. This can also be set with the -H/--header flag\n" -" of course.\n" -"\n" -" -E/--cert \n" -" (HTTPS) Tells curl to use the specified certificate\n" -" file when getting a file with HTTPS. The certifi-\n" -" cate must be in PEM format. If the optional pass-\n" -" word isn't specified, it will be queried for on the\n" -" terminal. Note that this certificate is the private\n" -" key and the private certificate concatenated!\n" -"\n" -" -f/--fail\n" -" (HTTP) Fail silently (no output at all) on server\n" -" errors. This is mostly done like this to better\n" -" enable scripts etc to better deal with failed\n" -" attempts. In normal cases when a HTTP server fails\n" -" to deliver a document, it returns a HTML document\n" -" stating so (which often also describes why and\n" -" more). This flag will prevent curl from outputting\n" -" that and fail silently instead.\n" -"\n" -" -F/--form \n" -" (HTTP) This lets curl emulate a filled in form in\n" -" which a user has pressed the submit button. This\n" -" causes curl to POST data using the content-type\n" -" multipart/form-data according to RFC1867. This\n" -" enables uploading of binary files etc. To force the\n" -" 'content' part to be read from a file, prefix the\n" -" file name with an @ sign. Example, to send your\n" -" password file to the server, where 'password' is\n" -" the name of the form-field to which /etc/passwd\n" -" will be the input:\n" -" curl -F password=@/etc/passwd www.mypasswords.com\n" -"\n" -" To read the file's content from stdin insted of a\n" -" file, use - where the file name should've been.\n" -"\n" -" -h/--help\n" -" Usage help.\n" -"\n" -" -H/--header
\n" -" (HTTP) Extra header to use when getting a web page.\n" -" You may specify any number of extra headers. Note\n" -" that if you should add a custom header that has the\n" -" same name as one of the internal ones curl would\n" -" use, your externally set header will be used\n" -" instead of the internal one. This allows you to\n" -" make even trickier stuff than curl would normally\n" -" do. You should not replace internally set headers\n" -" without knowing perfectly well what you're doing.\n" -"\n" -" -i/--include\n" -" (HTTP) Include the HTTP-header in the output. The\n" -" HTTP-header includes things like server-name, date\n" -" of the document, HTTP-version and more...\n" -"\n" -" -I/--head\n" -" (HTTP/FTP) Fetch the HTTP-header only! HTTP-servers\n" -" feature the command HEAD which this uses to get\n" -" nothing but the header of a document. When used on\n" -" a FTP file, curl displays the file size only.\n" -"\n" -" -K/--config \n" -" Specify which config file to read curl arguments\n" -" from. The config file is a text file in which com-\n" -" mand line arguments can be written which then will\n" -" be used as if they were written on the actual com-\n" -" mand line. If the first column of a config line is\n" -" a '#' character, the rest of the line will be\n" -" treated as a comment.\n" -"\n" -" Specify the filename as '-' to make curl read the\n" -" file from stdin.\n" -"\n" -" -l/--list-only\n" -" (FTP) When listing an FTP directory, this switch\n" -" forces a name-only view. Especially useful if you\n" -" want to machine-parse the contents of an FTP direc-\n" -" tory since the normal directory view doesn't use a\n" -" standard look or format.\n" -"\n" -" -L/--location\n" -" (HTTP/HTTPS) If the server reports that the\n" -" requested page has a different location (indicated\n" -" with the header line Location:) this flag will let\n" -" curl attempt to reattempt the get on the new place.\n" -" If used together with -i or -I, headers from all\n" -" requested pages will be shown.\n" -"\n" -" -m/--max-time \n" -" Maximum time in seconds that you allow the whole\n" -" operation to take. This is useful for preventing\n" -" your batch jobs from hanging for hours due to slow\n" -" networks or links going down. This doesn't work\n" -" properly in win32 systems.\n" -"\n" -" -M/--manual\n" -" Manual. Display the huge help text.\n" -"\n" -" -n/--netrc\n" -" Makes curl scan the .netrc file in the user's home\n" -" directory for login name and password. This is typ-\n" -" ically used for ftp on unix. If used with http,\n" -" curl will enable user authentication. See netrc(5)\n" -" for details on the file format. Curl will not com-\n" -" plain if that file hasn't the right permissions (it\n" -" should not be world nor group readable). The envi-\n" -" ronment variable \"HOME\" is used to find the home\n" -" directory.\n" -"\n" -" A quick and very simple example of how to setup a\n" -" .netrc to allow curl to ftp to the machine\n" -" host.domain.com with user name\n" -"\n" -" machine host.domain.com user myself password secret\n" -"\n" -" -N/--no-buffer\n" -" Disables the buffering of the output stream. In\n" -" normal work situations, curl will use a standard\n" -" buffered output stream that will have the effect\n" -" that it will output the data in chunks, not neces-\n" -" sarily exactly when the data arrives. Using this\n" -" option will disable that buffering.\n" -"\n" -" -o/--output \n" -" Write output to instead of stdout. If you\n" -" are using {} or [] to fetch multiple documents, you\n" -" can use '#' followed by a number in the \n" -" specifier. That variable will be replaced with the\n" -" current string for the URL being fetched. Like in:\n" -"\n" -" curl http://{one,two}.site.com -o \"file_#1.txt\"\n" -"\n" -" or use several variables like:\n" -"\n" -" curl http://{site,host}.host[1-5].com -o \"#1_#2\"\n" -"\n" -" -O/--remote-name\n" -" Write output to a local file named like the remote\n" -" file we get. (Only the file part of the remote file\n" -" is used, the path is cut off.)\n" -"\n" -" -P/--ftpport
\n" -" (FTP) Reverses the initiator/listener roles when\n" -" connecting with ftp. This switch makes Curl use the\n" -" PORT command instead of PASV. In practice, PORT\n" -" tells the server to connect to the client's speci-\n" -" fied address and port, while PASV asks the server\n" -" for an ip address and port to connect to.
\n" -" should be one of:\n" -"\n" -" interface i.e \"eth0\" to specify which interface's\n" -" IP address you want to use (Unix only)\n" -"\n" -" IP address i.e \"192.168.10.1\" to specify exact IP\n" -" number\n" -"\n" -" host name i.e \"my.host.domain\" to specify machine\n" -"\n" -" - (any single-letter string) to make it\n" -" pick the machine's default\n" -"\n" -" -q If used as the first parameter on the command line,\n" -" the $HOME/.curlrc file will not be read and used as\n" -" a config file.\n" -"\n" -" -Q/--quote \n" -" (FTP) Send an arbitrary command to the remote FTP\n" -" server, by using the QUOTE command of the server.\n" -" Not all servers support this command, and the set\n" -" of QUOTE commands are server specific! Quote com-\n" -" mands are sent BEFORE the transfer is taking place.\n" -" To make commands take place after a successful\n" -" transfer, prefix them with a dash '-'. You may\n" -" specify any amount of commands to be run before and\n" -" after the transfer. If the server returns failure\n" -" for one of the commands, the entire operation will\n" -" be aborted.\n" -"\n" -" -r/--range \n" -" (HTTP/FTP) Retrieve a byte range (i.e a partial\n" -" document) from a HTTP/1.1 or FTP server. Ranges can\n" -" be specified in a number of ways.\n" -"\n" -" 0-499 specifies the first 500 bytes\n" -"\n" -" 500-999 specifies the second 500 bytes\n" -"\n" -" -500 specifies the last 500 bytes\n" -"\n" -" 9500 specifies the bytes from offset 9500 and\n" -" forward\n" -"\n" -" 0-0,-1 specifies the first and last byte\n" -" only(*)(H)\n" -"\n" -" 500-700,600-799\n" -" specifies 300 bytes from offset 500(H)\n" -"\n" -" 100-199,500-599\n" -" specifies two separate 100 bytes\n" -" ranges(*)(H)\n" -"\n" -" (*) = NOTE that this will cause the server to reply with a\n" -" multipart response!\n" -"\n" -" You should also be aware that many HTTP/1.1 servers do not\n" -" have this feature enabled, so that when you attempt to get\n" -" a range, you'll instead get the whole document.\n" -"\n" -" FTP range downloads only support the simple syntax 'start-\n" -" stop' (optionally with one of the numbers omitted). It\n" -" depends on the non-RFC command SIZE.\n" -"\n" -" -s/--silent\n" -" Silent mode. Don't show progress meter or error\n" -" messages. Makes Curl mute.\n" -"\n" -" -S/--show-error\n" -" When used with -s it makes curl show error message\n" -" if it fails.\n" -"\n" -" -t/--upload\n" -" Transfer the stdin data to the specified file. Curl\n" -" will read everything from stdin until EOF and store\n" -" with the supplied name. If this is used on a\n" -" http(s) server, the PUT command will be used.\n" -"\n" -" -T/--upload-file \n" -" Like -t, but this transfers the specified local\n" -" file. If there is no file part in the specified\n" -" URL, Curl will append the local file name. NOTE\n" -" that you must use a trailing / on the last direc-\n" -" tory to really prove to Curl that there is no file\n" -" name or curl will think that your last directory\n" -" name is the remote file name to use. That will most\n" -" likely cause the upload operation to fail. If this\n" -" is used on a http(s) server, the PUT command will\n" -" be used.\n" -"\n" -" -u/--user \n" -" Specify user and password to use when fetching. See\n" -" README.curl for detailed examples of how to use\n" -" this. If no password is specified, curl will ask\n" -" for it interactively.\n" -"\n" -" -U/--proxy-user \n" -" Specify user and password to use for Proxy\n" -" authentication. If no password is specified, curl\n" -" will ask for it interactively.\n" -"\n" -" -v/--verbose\n" -" Makes the fetching more verbose/talkative. Mostly\n" -" usable for debugging. Lines starting with '>' means\n" -" data sent by curl, '<' means data received by curl\n" -" that is hidden in normal cases and lines starting\n" -" with '*' means additional info provided by curl.\n" -"\n" -" -V/--version\n" -" Displays the full version of curl, libcurl and\n" -" other 3rd party libraries linked with the exe-\n" -" cutable.\n" -"\n" -" -w/--write-out \n" -" Defines what to display after a completed and suc-\n" -" cessful operation. The format is a string that may\n" -" contain plain text mixed with any number of vari-\n" -" ables. The string can be specified as \"string\", to\n" -" get read from a particular file you specify it\n" -" \"@filename\" and to tell curl to read the format\n" -" from stdin you write \"@-\".\n" -"\n" -" The variables present in the output format will be\n" -" substituted by the value or text that curl thinks\n" -" fit, as described below. All variables are speci-\n" -" fied like %{variable_name} and to output a normal %\n" -" you just write them like %%. You can output a new-\n" -" line by using \\n, a carrige return with \\r and a\n" -" tab space with \\t.\n" -"\n" -" NOTE: The %-letter is a special letter in the\n" -" win32-environment, where all occurrences of % must\n" -" be doubled when using this option.\n" -"\n" -" Available variables are at this point:\n" -"\n" -" url_effective The URL that was fetched last. This\n" -" is mostly meaningful if you've told\n" -" curl to follow location: headers.\n" -"\n" -" http_code The numerical code that was found in\n" -" the last retrieved HTTP(S) page.\n" -"\n" -" time_total The total time, in seconds, that the\n" -" full operation lasted. The time will\n" -" be displayed with millisecond reso-\n" -" lution.\n" -"\n" -" time_namelookup\n" -" The time, in seconds, it took from\n" -" the start until the name resolving\n" -" was completed.\n" -" time_connect The time, in seconds, it took from\n" -" the start until the connect to the\n" -" remote host (or proxy) was com-\n" -" pleted.\n" -"\n" -" time_pretransfer\n" -" The time, in seconds, it took from\n" -" the start until the file transfer is\n" -" just about to begin. This includes\n" -" all pre-transfer commands and nego-\n" -" tiations that are specific to the\n" -" particular protocol(s) involved.\n" -"\n" -" size_download The total amount of bytes that were\n" -" downloaded.\n" -"\n" -" size_upload The total amount of bytes that were\n" -" uploaded.\n" -"\n" -" speed_download The average download speed that curl\n" -" measured for the complete download.\n" -"\n" -" speed_upload The average upload speed that curl\n" -" measured for the complete download.\n" -"\n" -" -x/--proxy \n" -" Use specified proxy. If the port number is not\n" -" specified, it is assumed at port 1080.\n" -"\n" -" -X/--request \n" -" (HTTP) Specifies a custom request to use when com-\n" -" municating with the HTTP server. The specified\n" -" request will be used instead of the standard GET.\n" -" Read the HTTP 1.1 specification for details and\n" -" explanations.\n" -"\n" -" (FTP) Specifies a custom FTP command to use instead\n" -" of LIST when doing file lists with ftp.\n" -"\n" -" -y/--speed-time