Compare commits

..

30 Commits

Author SHA1 Message Date
Daniel Stenberg
948c3b3aa9 7.6.1 commit 2001-02-13 13:37:14 +00:00
Daniel Stenberg
a140e5311d moved the protocol-specific free to allow easier multiple transfers 2001-02-13 13:34:16 +00:00
Daniel Stenberg
7686ac3f2c ftp response fix, netrc fix for non-http/ftp, https put research 2001-02-12 13:20:04 +00:00
Daniel Stenberg
54778134e4 corrected the prototype 2001-02-12 13:19:09 +00:00
Daniel Stenberg
c59baa06f0 Added 3.10 and a few minor updates 2001-02-12 10:05:09 +00:00
Daniel Stenberg
c107303ade very minor indentation fix 2001-02-12 08:22:19 +00:00
Daniel Stenberg
21b05afc99 removed getenv.h from the package as it was unused 2001-02-12 08:21:45 +00:00
Daniel Stenberg
eebcf7d4f5 Not used anymore 2001-02-09 07:33:58 +00:00
Daniel Stenberg
8d169dfadd Added a failf() call in the error-check just added 2001-02-09 07:14:28 +00:00
Daniel Stenberg
b12e334d83 if netrc is parsed and our host was found in there, set data->bits.user_passwd
unconditioanlly!
2001-02-08 13:53:13 +00:00
Daniel Stenberg
7e36c4437e today's FTP response check fix 2001-02-08 13:52:38 +00:00
Daniel Stenberg
3c7a80a275 postit.c was added as a HTML form file upload example 2001-02-08 08:26:54 +00:00
Daniel Stenberg
61e2a8108b 7.6.1-pre3 2001-02-07 09:49:06 +00:00
Daniel Stenberg
abb14de7e0 GetLine() didn't properly act on -1 lengths returned from Curl_read() 2001-02-07 09:31:03 +00:00
Daniel Stenberg
ccd57e58f6 Added #define ssize_t int since ssize_t doesn't seem to exist in normal
win32 systems
2001-02-07 09:23:54 +00:00
Daniel Stenberg
58d70db92e no longer #includes "getenv.h" 2001-02-07 08:36:23 +00:00
Daniel Stenberg
09f6fc22ed silly me, corrected the strlcat() to compile 2001-02-06 09:12:39 +00:00
Daniel Stenberg
833ce37cb9 new openbsd inspired implementation of strlcat() 2001-02-06 09:08:24 +00:00
Daniel Stenberg
07e7018564 nntp@iname.com's suggested fix to set the libpath 2001-02-06 07:14:44 +00:00
Daniel Stenberg
db70cd28b3 adjusted the IPv6 stuff to compile and build on Linux as well 2001-02-05 23:35:44 +00:00
Daniel Stenberg
f6e2bfd464 Jun-ichiro itojun Hagino's IPv6 adjustments 2001-02-05 23:04:44 +00:00
Daniel Stenberg
1ae5dab8fb Robert Weaver's VC experiences 2001-02-05 22:35:55 +00:00
Daniel Stenberg
c6355e6a43 Added a telnet section 2001-02-05 22:35:21 +00:00
Daniel Stenberg
7d26eb61fe Added a few more configure option explanations 2001-02-05 10:24:12 +00:00
Daniel Stenberg
8613ce377f the new getinfo() stuff and the cygwin patch 2001-02-04 20:10:52 +00:00
Daniel Stenberg
d6b94488a1 Added blurb about the win32 thing that precents a DLL from using a pointer
passed to it from user-space!
2001-02-04 20:10:02 +00:00
Daniel Stenberg
5d7b32d09f extended 5.5 2001-02-04 20:08:42 +00:00
Daniel Stenberg
ed16d30ea8 CURLINFO_CONTENT_LENGTH_DOWNLOAD and CURLINFO_CONTENT_LENGTH_UPLOAD documented 2001-02-04 20:07:53 +00:00
Daniel Stenberg
6f7c70fbbc CURLINFO_CONTENT_LENGTH_DOWNLOAD and CURLINFO_CONTENT_LENGTH_UPLOAD were
added as suggested by Bob Schader
2001-02-04 20:03:30 +00:00
Daniel Stenberg
9ab5d30e3b Ingo Ralf Blum made it compile with the newest cygwin 2001-02-04 19:00:27 +00:00
29 changed files with 691 additions and 103 deletions

69
CHANGES
View File

@@ -6,11 +6,76 @@
History of Changes
Version 7.6.1
Daniel (9 February 2001)
- Frank Reid and Cain Hopwood provided information and research around a HTTPS
PUT/upload problem we seem to have. No solution found yet.
Daniel (8 February 2001)
- An interesting discussion is how to specify an empty password without having
curl ask for it interactively? The current implmentation takes an empty
password as a request for a password prompt. However, I still want to
support a blank user field. Thus, today if you enter "-u :" (without user
and password) curl will prompt for the password. Tricky. How would you
specify you want the prompt otherwise?
- Made the netrc parse result possible to use for other protocols than FTP and
HTTP (such as the upcoming TELNET fixes).
- The previously mentioned "MSVC++ problems" turned out to be a non-issue.
- Added a HTTP file upload code example in the docs/examples/ section on
request.
- Adjusted the FTP response fix slightly.
Version 7.6.1-pre3
Daniel (7 February 2001)
- SM found a flaw in the response reading function for FTP that could make
libcurl not get out of the loop properly when it should, if libcurl got -1
returned when reading the socket.
- I found a similar mistake in http.c when using a proxy and reading the
results from the proxy connection.
Daniel (6 February 2001)
- A friendly person named "SM" (nntp at iname.com) pointed out that the VC
makefile in src/ needed the libpath set for the debug build to work.
- Daniel Gehriger stepped in to assist with the VC++ stuff Robert Weaver
brought up yesterday.
Daniel (5 February 2001)
- Jun-ichiro itojun Hagino brought a big patch that brings IPv6-awareness to
a bunch of different areas within libcurl.
- Robert Weaver told me about the problems the MS VC++ 6.0 compiler has with
the 'static' keyword on a number of libcurl functions. I might need to add a
patch that redefines static when libcurl is compiled with that compiler.
How do I know when VC++ compiles, anyone?
Daniel (4 February 2001)
- curl_getinfo() was extended with two new options:
CURLINFO_CONTENT_LENGTH_DOWNLOAD and CURLINFO_CONTENT_LENGTH_UPLOAD. They
return the full assumed content length of the transfer in the given
direction. The CURLINFO_CONTENT_LENGTH_DOWNLOAD will be the Content-Length:
size of a HTTP download. Added descriptions to the man page as well. This
was done after discussions with Bob Schader.
Daniel (3 February 2001)
- Ingo Ralf Blum provided another fix that makes curl build under the more
recent cygwin installations. It seems they've changed the preset defines to
not include WIN32 anymore.
Version 7.6.1-pre2
Daniel (31 January 2001)
- Curl_read() and curl_read() now return a ssize_t for the size, as it had to
be able to return -1. The telnet support crashed due to this and there was
a possibility to weird behaviour all over.
be able to return -1. The telnet support crashed due to this and there was a
possibility to weird behaviour all over. Linus Nielsen Feltzing helped me
find this.
- Added a configure.in check for a working getaddrinfo() if IPv6 is requested.
I also made the configure script feature --enable-debug which sets a couple

View File

@@ -39,3 +39,7 @@
/* Define if you want to enable IPv6 support */
#undef ENABLE_IPV6
/* Define this to 'int' if ssize_t is not an available typedefed type */
#undef ssize_t

View File

@@ -23,6 +23,9 @@
/* Define to `unsigned' if <sys/types.h> doesn't define. */
/* #undef size_t */
/* Define this to 'int' if ssize_t is not an available typedefed type */
#define ssize_t int
/* Define if you have the ANSI C header files. */
#define STDC_HEADERS 1

View File

@@ -53,15 +53,9 @@ dnl
AC_DEFUN(CURL_CHECK_WORKING_GETADDRINFO,[
AC_CACHE_CHECK(for working getaddrinfo, ac_cv_working_getaddrinfo,[
AC_TRY_RUN( [
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/types.h>
#include <sys/socket.h>
#endif
void main(void) {
struct addrinfo hints, *ai;
@@ -434,6 +428,10 @@ AC_MSG_CHECKING([if Kerberos4 support is requested])
if test "$want_krb4" = yes
then
if test "$ipv6" = "yes"; then
echo krb4 is not compatible with IPv6
exit 1
fi
AC_MSG_RESULT(yes)
dnl Check for & handle argument to --with-krb4
@@ -661,6 +659,9 @@ AC_CHECK_SIZEOF(long double, 8)
# check for 'long long'
AC_CHECK_SIZEOF(long long, 4)
# check for ssize_t
AC_CHECK_TYPE(ssize_t, int)
dnl Get system canonical name
AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED(OS, "${host}")
@@ -691,7 +692,8 @@ AC_CHECK_FUNCS( socket \
setvbuf \
sigaction \
signal \
getpass_r
getpass_r \
strlcat
)
dnl removed 'getpass' check on October 26, 2000

View File

@@ -1,4 +1,4 @@
Updated: January 29, 2001 (http://curl.haxx.se/docs/faq.shtml)
Updated: February 12, 2001 (http://curl.haxx.se/docs/faq.shtml)
_ _ ____ _
___| | | | _ \| |
/ __| | | | |_) | |
@@ -31,6 +31,7 @@ FAQ
3.7 Can I use curl to delete/rename a file through FTP?
3.8 How do I tell curl to follow HTTP redirects?
3.9 How do I use curl in PHP?
3.10 What about SOAP, WEBDAV, XML-RPC or similar protocols over HTTP?
4. Running Problems
4.1 Problems connecting to SSL servers.
@@ -53,7 +54,7 @@ FAQ
5.2 How can I receive all data into a large memory chunk?
5.3 How do I fetch multiple files with libcurl?
5.4 Does libcurl do Winsock initing on win32 systems?
5.5 Does CURLOPT_FILE work on win32 ?
5.5 Does CURLOPT_FILE and CURLOPT_INFILE work on win32 ?
5.6 What about Keep-Alive or persistant connections?
6. License Issues
@@ -106,8 +107,8 @@ FAQ
or with PHP.
Curl is not a single-OS program. Curl exists, compiles, builds and runs
under a wide range of operating systems, including all modern Unixes,
Windows, Amiga, BeOS, OS/2, OS X, QNX etc.
under a wide range of operating systems, including all modern Unixes (and a
bunch of older ones too), Windows, Amiga, BeOS, OS/2, OS X, QNX etc.
1.4 When will you make curl do XXXX ?
@@ -230,7 +231,7 @@ FAQ
You can't simply use -F or -d at your choice. The web server that will
receive your post assumes one of the formats. If the form you're trying to
"fake" sets the type to 'multipart/form-data', than and only then you must
"fake" sets the type to 'multipart/form-data', then and only then you must
use the -F type. In all the most common cases, you should use -d which then
causes a posting with the type 'application/x-www-form-urlencoded'.
@@ -294,6 +295,16 @@ FAQ
invoke the curl tool using a command line. This is the way to use curl if
you're using PHP3 or PHP4 built without curl module support.
3.10 What about SOAP, WEBDAV, XML-RPC or similar protocols over HTTP?
Curl adheres to the HTTP spec, which basically means you can play with *any*
protocol that is built ontop of HTTP. Protocols such as SOAP, WEBDAV and
XML-RPC are all such ones. You can use -X to set custom requests and -H to
set custom headers (or replace internally generated ones).
Using libcurl or PHP's curl modules is just as fine and you'd just use the
proper library options to do the same.
4. Running Problems
4.1. Problems connecting to SSL servers.
@@ -426,7 +437,8 @@ FAQ
4.9. Curl can't authenticate to the server that requires NTLM?
NTLM is a Microsoft proprietary protocol. Unfortunately, curl does not
currently support that.
currently support that. Proprietary formats are evil. You should not use
such ones.
5. libcurl Issues
@@ -491,14 +503,15 @@ FAQ
use several different libraries and parts, and there's no reason for every
single library to do this.
5.5 Does CURLOPT_FILE work on win32 ?
5.5 Does CURLOPT_FILE and CURLOPT_INFILE work on win32 ?
Yes, but you cannot open a FILE * and pass the pointer to a DLL and have
that DLL use the FILE *. You must use CURLOPT_WRITEFUNCTION as well to set a
function that writes the file, even if that simply writes the data to the
specified FILE*.
that DLL use the FILE *. If you set CURLOPT_FILE you must also use
CURLOPT_WRITEFUNCTION as well to set a function that writes the file, even
if that simply writes the data to the specified FILE*. Similarly, if you use
CURLOPT_INFILE you must also specify CURLOPT_READFUNCTION.
(provided by Joel DeYoung)
(Provided by Joel DeYoung and Bob Schader)
5.6 What about Keep-Alive or persistant connections?
@@ -511,7 +524,7 @@ FAQ
6. License Issues
NOTE: This section is now updated to concern curl 7.5.2 or later!
NOTE: This section concerns curl 7.5.2 or later!
Curl and libcurl are released under a MIT/X derivate license *or* the MPL,
the Mozilla Public License. To get a really good answer to your license
@@ -529,27 +542,25 @@ FAQ
6.2. I have a closed-source program, can I use the libcurl library?
Yes.
Yes!
libcurl does not put any restrictions on the program that uses the
library.
libcurl does not put any restrictions on the program that uses the library.
6.3. I have a BSD licensed program, can I use the libcurl library?
Yes.
Yes!
libcurl does not put any restrictions on the program that uses the
library.
libcurl does not put any restrictions on the program that uses the library.
6.4. I have a program that uses LGPL libraries, can I use libcurl?
Yes.
Yes!
The LGPL license don't clash with other licenses.
The LGPL license doesn't clash with other licenses.
6.5. Can I modify curl/libcurl for my program and keep the changes secret?
Yes.
Yes!
The MIT/X derivate license practically allows you to do almost anything with
the sources, on the condition that the copyright texts in the sources are
@@ -557,9 +568,11 @@ FAQ
6.6. Can you please change the curl/libcurl license to XXXX?
No. We carefully picked this license years ago and a large amount of people
have contributed with source code knowing that this is the license we
use. This license puts the restrictions we want on curl/libcurl and it does
not spread to other programs or libraries that use it. The recent dual
license modification should make it possible for everyone to use libcurl or
curl in their projects, no matter what license they already have in use.
No.
We carefully picked this license years ago and a large amount of people have
contributed with source code knowing that this is the license we use. This
license puts the restrictions we want on curl/libcurl and it does not spread
to other programs or libraries that use it. The recent dual license
modification should make it possible for everyone to use libcurl or curl in
their projects, no matter what license they already have in use.

View File

@@ -84,9 +84,10 @@ UNIX
KNOWN PROBLEMS
If you happen to have autoconf installed, but a version older than
2.12 you will get into trouble. Then you can still build curl by
issuing these commands: (from Ralph Beckmann)
If you happen to have autoconf installed, but a version older than 2.12
you will get into trouble. Then you can still build curl by issuing these
commands (note that this requires curl to be built staticly): (from Ralph
Beckmann)
./configure [...]
cd lib; make; cd ..
@@ -139,6 +140,14 @@ UNIX
./configure --with-krb4=/usr/athena
If your system support shared libraries, but you want to built a static
version only, you can disable building the shared version by using:
./configure --disable-shared
If you're a curl developer and use gcc, you might want to enable more
debug options with the --enable-debug option.
Win32
=====

View File

@@ -726,6 +726,25 @@ KERBEROS4 FTP TRANSFER
There's no use for a password on the -u switch, but a blank one will make
curl ask for one and you already entered the real password to kauth.
TELNET
The curl telnet support is basic and very easy to use. Curl passes all data
passed to it on stdin to the remote server. Connect to a remote telnet
server using a command line similar to:
curl telnet://remote.server.com
And enter the data to pass to the server on stdin. The result will be sent
to stdout or to the file you specify with -o.
You might want the -N/--no-buffer option to switch off the buffered output
for slow connections or similar.
NOTE: the telnet protocol does not specify any way to login with a specified
user and password so curl can't do that automatically. To do that, you need
to track when the login prompt is received and send the username and
password accordingly.
MAILING LIST
We have an open mailing list to discuss curl, its development and things

View File

@@ -788,6 +788,7 @@ If you do find bugs, mail them to curl-bug@haxx.se.
- Loic Dachary <loic@senga.org>
- Robert Weaver <robert.weaver@sabre.com>
- Ingo Ralf Blum <ingoralfblum@ingoralfblum.com>
- Jun-ichiro itojun Hagino <itojun@iijlab.net>
.SH WWW
http://curl.haxx.se

View File

@@ -2,7 +2,7 @@
.\" nroff -man [file]
.\" Written by daniel@haxx.se
.\"
.TH curl_easy_init 3 "22 November 2000" "Curl 7.5" "libcurl Manual"
.TH curl_easy_init 3 "4 February 2001" "Curl 7.6.1" "libcurl Manual"
.SH NAME
curl_easy_getinfo - Extract information from a curl session (added in 7.4)
.SH SYNOPSIS
@@ -81,6 +81,14 @@ than one request if FOLLOWLOCATION is true.
Pass a pointer to a long to receive the result of the certification
verification that was requested (using the CURLOPT_SSL_VERIFYPEER option to
curl_easy_setopt). (Added in 7.4.2)
.TP
.B CURLINFO_CONTENT_LENGTH_DOWNLOAD
Pass a pointer to a double to receive the content-length of the download.
(Added in 7.6.1)
.TP
.B CURLINFO_CONTENT_LENGTH_UPLOAD
Pass a pointer to a double to receive the specified size of the upload.
(Added in 7.6.1)
.PP
.SH RETURN VALUE

View File

@@ -2,7 +2,7 @@
.\" nroff -man [file]
.\" Written by daniel@haxx.se
.\"
.TH curl_easy_setopt 3 "28 November 2000" "Curl 7.5" "libcurl Manual"
.TH curl_easy_setopt 3 "2 February 2001" "Curl 7.5" "libcurl Manual"
.SH NAME
curl_easy_setopt - Set curl easy-session options
.SH SYNOPSIS
@@ -35,6 +35,12 @@ Data pointer to pass instead of FILE * to the file write function. Note that
if you specify the
.I CURLOPT_WRITEFUNCTION
, this is the pointer you'll get as input.
NOTE: If you're using libcurl as a win32 .DLL, you MUST use a
.I CURLOPT_WRITEFUNCTION
if you set the
.I CURLOPT_FILE
option.
.TP
.B CURLOPT_WRITEFUNCTION
Function pointer that should use match the following prototype:
@@ -53,6 +59,12 @@ Data pointer to pass instead of FILE * to the file read function. Note that if
you specify the
.I CURLOPT_READFUNCTION
, this is the pointer you'll get as input.
NOTE: If you're using libcurl as a win32 .DLL, you MUST use a
.I CURLOPT_READFUNCTION
if you set the
.I CURLOPT_INFILE
option.
.TP
.B CURLOPT_READFUNCTION
Function pointer that should use match the following prototype:

View File

@@ -2,13 +2,13 @@
.\" nroff -man [file]
.\" Written by daniel@haxx.se
.\"
.TH curl_formparse 3 "6 June 2000" "Curl 7.0" "libcurl Manual"
.TH curl_formparse 3 "8 February 2001" "Curl 7.0" "libcurl Manual"
.SH NAME
curl_formparse - add a section to a multipart/formdata HTTP POST
.SH SYNOPSIS
.B #include <curl/curl.h>
.sp
.BI "CURLcode *curl_formparse(char *" string, "struct HttpPost **" firstitem,
.BI "CURLcode curl_formparse(char *" string, "struct HttpPost **" firstitem,
.BI "struct HttpPost ** "lastitem ");"
.ad
.SH DESCRIPTION

View File

@@ -5,7 +5,7 @@
AUTOMAKE_OPTIONS = foreign no-dependencies
EXTRA_DIST =
README curlgtk.c sepheaders.c simple.c
README curlgtk.c sepheaders.c simple.c postit.c
all:
@echo "done"

68
docs/examples/postit.c Normal file
View File

@@ -0,0 +1,68 @@
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* $Id$
*
* Example code that uploads a file name 'foo' to a remote script that accepts
* "HTML form based" (as described in RFC1738) uploads using HTTP POST.
*
* The imaginary form we'll fill in looks like:
*
* <form method="post" enctype="multipart/form-data" action="examplepost.cgi">
* Enter file: <input type="file" name="sendfile" size="40">
* Enter file name: <input type="text" name="filename" size="30">
* <input type="submit" value="send" name="submit">
* </form>
*
* This exact source code has not been verified to work.
*/
#include <stdio.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
int main(int argc, char **argv)
{
CURL *curl;
CURLcode res;
struct HttpPost *formpost=NULL;
struct HttpPost *lastptr=NULL;
/* Fill in the file upload field */
curl_formparse("sendfile=@foo",
&formpost,
&lastptr);
/* Fill in the filename field */
curl_formparse("filename=foo",
&formpost,
&lastptr);
/* Fill in the submit field too, even if this is rarely needed */
curl_formparse("submit=send",
&formpost,
&lastptr);
curl = curl_easy_init();
if(curl) {
/* what URL that receives this POST */
curl_easy_setopt(curl, CURLOPT_URL, "http://curl.haxx.se/examplepost.cgi");
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
/* then cleanup the formpost chain */
curl_formfree(formpost);
}
return 0;
}

View File

@@ -452,7 +452,7 @@ char *curl_getenv(char *variable);
char *curl_version(void);
/* This is the version number */
#define LIBCURL_VERSION "7.6.1-pre2"
#define LIBCURL_VERSION "7.6.1"
#define LIBCURL_VERSION_NUM 0x070601
/* linked-list structure for the CURLOPT_QUOTE option (and other) */
@@ -676,7 +676,10 @@ typedef enum {
CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13,
CURLINFO_FILETIME = CURLINFO_LONG + 14,
CURLINFO_LASTONE = 15
CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15,
CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16,
CURLINFO_LASTONE = 17
} CURLINFO;
/*

View File

@@ -55,7 +55,7 @@ dict.c ftp.h if2ip.c speedcheck.c url.h \
dict.h getdate.c if2ip.h speedcheck.h urldata.h \
getdate.h ldap.c ssluse.c version.c \
getenv.c ldap.h ssluse.h \
escape.c getenv.h mprintf.c telnet.c \
escape.c mprintf.c telnet.c \
escape.h getpass.c netrc.c telnet.h \
getinfo.c transfer.c strequal.c strequal.h easy.c \
security.h security.c krb4.c krb4.h memdebug.c memdebug.h inet_ntoa_r.h

274
lib/ftp.c
View File

@@ -282,6 +282,10 @@ int Curl_GetFTPResponse(int sockfd, char *buf,
*/
if(CURLE_OK != Curl_read(conn, sockfd, ptr, 1, &keepon))
keepon = FALSE;
else if(keepon <= 0) {
error = SELECT_ERROR;
failf(data, "Connection aborted");
}
else if ((*ptr == '\n') || (*ptr == '\r'))
keepon = FALSE;
}
@@ -541,9 +545,6 @@ CURLcode Curl_ftp_done(struct connectdata *conn)
}
}
free(ftp);
data->proto.ftp=NULL; /* it is gone */
return CURLE_OK;
}
@@ -564,6 +565,9 @@ CURLcode _ftp(struct connectdata *conn)
#if defined (HAVE_INET_NTOA_R)
char ntoa_buf[64];
#endif
#ifdef ENABLE_IPV6
struct addrinfo *ai;
#endif
struct curl_slist *qitem; /* QUOTE item */
/* the ftp struct is already inited in ftp_connect() */
@@ -702,6 +706,178 @@ CURLcode _ftp(struct connectdata *conn)
/* We have chosen to use the PORT command */
if(data->bits.ftp_use_port) {
#ifdef ENABLE_IPV6
struct addrinfo hints, *res, *ai;
struct sockaddr_storage ss;
int sslen;
char hbuf[NI_MAXHOST];
char *localaddr;
struct sockaddr *sa=(struct sockaddr *)&ss;
#ifdef NI_WITHSCOPEID
const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
#else
const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
#endif
unsigned char *ap;
unsigned char *pp;
int alen, plen;
char portmsgbuf[4096], tmp[4096];
char *p;
char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
char **modep;
/*
* we should use Curl_if2ip? given pickiness of recent ftpd,
* I believe we should use the same address as the control connection.
*/
sslen = sizeof(ss);
if (getsockname(data->firstsocket, (struct sockaddr *)&ss, &sslen) < 0)
return CURLE_FTP_PORT_FAILED;
if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
niflags))
return CURLE_FTP_PORT_FAILED;
memset(&hints, 0, sizeof(hints));
hints.ai_family = sa->sa_family;
/*hints.ai_family = ss.ss_family;
this way can be used if sockaddr_storage is properly defined, as glibc
2.1.X doesn't do*/
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if (getaddrinfo(hbuf, "0", &hints, &res))
return CURLE_FTP_PORT_FAILED;
portsock = -1;
for (ai = res; ai; ai = ai->ai_next) {
portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (portsock < 0)
continue;
if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
close(portsock);
portsock = -1;
continue;
}
if (listen(portsock, 1) < 0) {
close(portsock);
portsock = -1;
continue;
}
break;
}
if (portsock < 0) {
failf(data, strerror(errno));
freeaddrinfo(res);
return CURLE_FTP_PORT_FAILED;
}
sslen = sizeof(ss);
if (getsockname(portsock, sa, &sslen) < 0) {
failf(data, strerror(errno));
freeaddrinfo(res);
return CURLE_FTP_PORT_FAILED;
}
for (modep = mode; modep && *modep; modep++) {
int lprtaf, eprtaf;
switch (sa->sa_family) {
case AF_INET:
ap = (char *)&((struct sockaddr_in *)&ss)->sin_addr;
alen = sizeof(((struct sockaddr_in *)&ss)->sin_addr);
pp = (char *)&((struct sockaddr_in *)&ss)->sin_port;
plen = sizeof(((struct sockaddr_in *)&ss)->sin_port);
lprtaf = 4;
eprtaf = 1;
break;
case AF_INET6:
ap = (char *)&((struct sockaddr_in6 *)&ss)->sin6_addr;
alen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_addr);
pp = (char *)&((struct sockaddr_in6 *)&ss)->sin6_port;
plen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_port);
lprtaf = 6;
eprtaf = 2;
break;
default:
ap = pp = NULL;
lprtaf = eprtaf = -1;
break;
}
if (strcmp(*modep, "EPRT") == 0) {
if (eprtaf < 0)
continue;
if (getnameinfo((struct sockaddr *)&ss, sslen,
portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp), niflags))
continue;
/* do not transmit IPv6 scope identifier to the wire */
if (sa->sa_family == AF_INET6) {
char *q = strchr(portmsgbuf, '%');
if (q)
*q = '\0';
}
ftpsendf(data->firstsocket, conn, "%s |%d|%s|%s|", *modep, eprtaf,
portmsgbuf, tmp);
} else if (strcmp(*modep, "LPRT") == 0 || strcmp(*modep, "PORT") == 0) {
int i;
if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
continue;
if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
continue;
portmsgbuf[0] = '\0';
if (strcmp(*modep, "LPRT") == 0) {
snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) {
goto again;
}
}
for (i = 0; i < alen; i++) {
if (portmsgbuf[0])
snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
else
snprintf(tmp, sizeof(tmp), "%u", ap[i]);
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) {
goto again;
}
}
if (strcmp(*modep, "LPRT") == 0) {
snprintf(tmp, sizeof(tmp), ",%d", plen);
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
goto again;
}
for (i = 0; i < plen; i++) {
snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) {
goto again;
}
}
ftpsendf(data->firstsocket, conn, "%s %s", *modep, portmsgbuf);
}
nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
if (nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if (ftpcode != 200) {
failf(data, "Server does not grok %s", *modep);
continue;
} else
break;
again:;
}
if (!*modep) {
close(portsock);
freeaddrinfo(res);
return CURLE_FTP_PORT_FAILED;
}
#else
struct sockaddr_in sa;
struct hostent *h=NULL;
char *hostdataptr=NULL;
@@ -809,26 +985,43 @@ CURLcode _ftp(struct connectdata *conn)
failf(data, "Server does not grok PORT, try without it!");
return CURLE_FTP_PORT_FAILED;
}
#endif /* ENABLE_IPV6 */
}
else { /* we use the PASV command */
#if 0
char *mode[] = { "EPSV", "LPSV", "PASV", NULL };
int results[] = { 229, 228, 227, 0 };
#else
char *mode[] = { "PASV", NULL };
int results[] = { 227, 0 };
#endif
int modeoff;
ftpsendf(data->firstsocket, conn, "PASV");
for (modeoff = 0; mode[modeoff]; modeoff++) {
ftpsendf(data->firstsocket, conn, mode[modeoff]);
nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if (ftpcode == results[modeoff])
break;
}
if(ftpcode != 227) {
if (!mode[modeoff]) {
failf(data, "Odd return code after PASV");
return CURLE_FTP_WEIRD_PASV_REPLY;
}
else {
else if (strcmp(mode[modeoff], "PASV") == 0) {
int ip[4];
int port[2];
unsigned short newport; /* remote port, not necessary the local one */
unsigned short connectport; /* the local port connect() should use! */
char newhost[32];
#ifdef ENABLE_IPV6
struct addrinfo *res;
#else
struct hostent *he;
#endif
char *str=buf,*ip_addr;
char *hostdataptr=NULL;
@@ -863,20 +1056,78 @@ CURLcode _ftp(struct connectdata *conn)
* proxy again here. We already have the name info for it since the
* previous lookup.
*/
#ifdef ENABLE_IPV6
res = conn->res;
#else
he = conn->hp;
#endif
connectport =
(unsigned short)data->port; /* we connect to the proxy's port */
}
else {
/* normal, direct, ftp connection */
#ifdef ENABLE_IPV6
res = Curl_getaddrinfo(data, newhost, newport);
if(!res)
#else
he = Curl_gethost(data, newhost, &hostdataptr);
if(!he) {
if(!he)
#endif
{
failf(data, "Can't resolve new host %s", newhost);
return CURLE_FTP_CANT_GET_HOST;
}
connectport = newport; /* we connect to the remote port */
}
#ifdef ENABLE_IPV6
data->secondarysocket = -1;
for (ai = res; ai; ai = ai->ai_next) {
/* XXX for now, we can do IPv4 only */
if (ai->ai_family != AF_INET)
continue;
data->secondarysocket = socket(ai->ai_family, ai->ai_socktype,
ai->ai_protocol);
if (data->secondarysocket < 0)
continue;
if(data->bits.verbose) {
char hbuf[NI_MAXHOST];
char nbuf[NI_MAXHOST];
char sbuf[NI_MAXSERV];
#ifdef NI_WITHSCOPEID
const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
#else
const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
#endif
if (getnameinfo(res->ai_addr, res->ai_addrlen, nbuf, sizeof(nbuf),
sbuf, sizeof(sbuf), niflags)) {
snprintf(nbuf, sizeof(nbuf), "?");
snprintf(sbuf, sizeof(sbuf), "?");
}
if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
NULL, 0, 0)) {
infof(data, "Connecting to %s port %s\n", nbuf, sbuf);
} else {
infof(data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf);
}
}
if (connect(data->secondarysocket, ai->ai_addr, ai->ai_addrlen) < 0) {
close(data->secondarysocket);
data->secondarysocket = -1;
continue;
}
break;
}
if (data->secondarysocket < 0) {
failf(data, strerror(errno));
return CURLE_FTP_CANT_RECONNECT;
}
#else
data->secondarysocket = socket(AF_INET, SOCK_STREAM, 0);
memset((char *) &serv_addr, '\0', sizeof(serv_addr));
@@ -971,6 +1222,7 @@ CURLcode _ftp(struct connectdata *conn)
}
return CURLE_FTP_CANT_RECONNECT;
}
#endif /*ENABLE_IPV6*/
if (data->bits.tunnel_thru_httpproxy) {
/* We want "seamless" FTP operations through HTTP proxy tunnel */
@@ -979,6 +1231,8 @@ CURLcode _ftp(struct connectdata *conn)
if(CURLE_OK != result)
return result;
}
} else {
return CURLE_FTP_CANT_RECONNECT;
}
}
/* we have the (new) data connection ready */

View File

@@ -1,28 +0,0 @@
#ifndef __GETENV_H
#define __GETENV_H
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
* licenses. You may pick one of these licenses.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id$
*****************************************************************************/
#include <curl/curl.h>
#endif

View File

@@ -103,6 +103,12 @@ CURLcode curl_getinfo(CURL *curl, CURLINFO info, ...)
case CURLINFO_SSL_VERIFYRESULT:
*param_longp = data->ssl.certverifyresult;
break;
case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
*param_doublep = data->progress.size_dl;
break;
case CURLINFO_CONTENT_LENGTH_UPLOAD:
*param_doublep = data->progress.size_ul;
break;
default:
return CURLE_BAD_FUNCTION_ARGUMENT;
}

View File

@@ -83,6 +83,29 @@ static char *MakeIP(unsigned long num,char *addr, int addr_len)
return (addr);
}
#ifdef ENABLE_IPV6
struct addrinfo *Curl_getaddrinfo(struct UrlData *data,
char *hostname,
int port)
{
struct addrinfo hints, *res;
int error;
char sbuf[NI_MAXSERV];
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
snprintf(sbuf, sizeof(sbuf), "%d", port);
error = getaddrinfo(hostname, sbuf, &hints, &res);
if (error) {
infof(data, "getaddrinfo(3) failed for %s\n", hostname);
return NULL;
}
return res;
}
#endif
/* The original code to this function was once stolen from the Dancer source
code, written by Bjorn Reese, it has since been patched and modified
considerably. */

View File

@@ -23,6 +23,11 @@
* $Id$
*****************************************************************************/
struct addrinfo;
struct addrinfo *Curl_getaddrinfo(struct UrlData *data,
char *hostname,
int port);
struct hostent *Curl_gethost(struct UrlData *data,
char *hostname,
char **bufp);

View File

@@ -226,17 +226,18 @@ int GetLine(int sockfd, char *buf, struct connectdata *conn)
(nread<BUFSIZE) && read_rc;
nread++, ptr++) {
if((CURLE_OK != Curl_read(conn, sockfd, ptr, 1, &nread)) ||
(nread <= 0) ||
(*ptr == '\n'))
break;
}
*ptr=0; /* zero terminate */
if(data->bits.verbose) {
fputs("< ", data->err);
fwrite(buf, 1, nread, data->err);
fputs("\n", data->err);
}
return nread;
return nread>0?nread:0;
}
@@ -374,9 +375,6 @@ CURLcode Curl_http_done(struct connectdata *conn)
*bytecount = http->readbytecount + http->writebytecount;
}
free(http);
data->proto.http=NULL; /* it is gone */
return CURLE_OK;
}

View File

@@ -24,7 +24,7 @@
*****************************************************************************/
#include "setup.h"
#if ! defined(WIN32) && ! defined(__BEOS__)
#if ! defined(WIN32) && ! defined(__BEOS__) && !defined(__CYGWIN32__)
extern char *Curl_if2ip(char *interface, char *buf, int buf_size);
#else
#define Curl_if2ip(a,b,c) NULL

View File

@@ -27,7 +27,8 @@
#include <stdlib.h>
#include <string.h>
#include "getenv.h"
#include <curl/curl.h>
#include "strequal.h"
/* Debug this single source file with:

View File

@@ -66,3 +66,44 @@ int Curl_strnequal(const char *first, const char *second, size_t max)
#endif
}
#ifndef HAVE_STRLCAT
/*
* The strlcat() function appends the NUL-terminated string src to the end
* of dst. It will append at most size - strlen(dst) - 1 bytes, NUL-termi-
* nating the result.
*
* The strlcpy() and strlcat() functions return the total length of the
* string they tried to create. For strlcpy() that means the length of src.
* For strlcat() that means the initial length of dst plus the length of
* src. While this may seem somewhat confusing it was done to make trunca-
* tion detection simple.
*
*
*/
size_t strlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
#endif

View File

@@ -82,7 +82,6 @@
#include <curl/types.h>
#include "netrc.h"
#include "getenv.h"
#include "hostip.h"
#include "transfer.h"
#include "sendf.h"

View File

@@ -80,7 +80,6 @@
#include "netrc.h"
#include "formdata.h"
#include "getenv.h"
#include "base64.h"
#include "ssluse.h"
#include "hostip.h"
@@ -562,8 +561,17 @@ CURLcode curl_disconnect(CURLconnect *c_connect)
struct UrlData *data = conn->data;
if(data->proto.generic)
free(data->proto.generic);
data->proto.generic=NULL; /* it is gone */
#ifdef ENABLE_IPV6
if(conn->res) /* host name info */
freeaddrinfo(conn->res);
#else
if(conn->hostent_buf) /* host name info */
free(conn->hostent_buf);
#endif
if(conn->path) /* the URL path part */
free(conn->path);
@@ -589,6 +597,9 @@ static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
struct sigaction sigact;
#endif
int urllen;
#ifdef ENABLE_IPV6
struct addrinfo *ai;
#endif
/*************************************************************
* Check input data
@@ -741,7 +752,7 @@ static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
/* the name is given, get user+password */
sscanf(data->userpwd, "%127[^:]:%127[^\n]",
data->user, data->passwd);
}
}
else
/* no name given, get the password only */
sscanf(data->userpwd+1, "%127[^\n]", data->passwd);
@@ -1079,15 +1090,15 @@ static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
infof(data, "Couldn't find host %s in the .netrc file, using defaults",
data->hostname);
}
else
data->bits.user_passwd = 1; /* enable user+password */
/* weather we failed or not, we don't know which fields that were filled
in anyway */
if(!data->user[0])
strcpy(data->user, CURL_DEFAULT_USER);
if(!data->passwd[0])
strcpy(data->passwd, CURL_DEFAULT_PASSWORD);
if(conn->protocol&PROT_HTTP) {
data->bits.user_passwd = 1; /* enable user+password */
}
}
else if(!(data->bits.user_passwd) &&
(conn->protocol & (PROT_FTP|PROT_HTTP)) ) {
@@ -1189,13 +1200,23 @@ static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
data->port = data->remote_port; /* it is the same port */
/* Connect to target host right on */
#ifdef ENABLE_IPV6
conn->res = Curl_getaddrinfo(data, conn->name, data->port);
if(!conn->res)
#else
conn->hp = Curl_gethost(data, conn->name, &conn->hostent_buf);
if(!conn->hp) {
if(!conn->hp)
#endif
{
failf(data, "Couldn't resolve host '%s'", conn->name);
return CURLE_COULDNT_RESOLVE_HOST;
}
}
else {
#ifdef ENABLE_IPV6
failf(data, "proxy yet to be supported");
return CURLE_OUT_OF_MEMORY;
#else
char *prox_portno;
char *endofprot;
@@ -1244,9 +1265,11 @@ static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
}
free(proxydup); /* free the duplicate pointer and not the modified */
#endif
}
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
#ifndef ENABLE_IPV6
data->firstsocket = socket(AF_INET, SOCK_STREAM, 0);
memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr));
@@ -1254,6 +1277,7 @@ static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
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);
#endif
#if !defined(WIN32)||defined(__CYGWIN32__)
/* We don't generally like checking for OS-versions, we should make this
@@ -1266,6 +1290,7 @@ static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
#define INADDR_NONE (unsigned long) ~0
#endif
#ifndef ENABLE_IPV6
/*************************************************************
* Select device to bind socket to
*************************************************************/
@@ -1374,10 +1399,31 @@ static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
} /* end of device selection support */
#endif /* end of HAVE_INET_NTOA */
#endif /* end of not WIN32 */
#endif /*ENABLE_IPV6*/
/*************************************************************
* Connect to server/proxy
*************************************************************/
#ifdef ENABLE_IPV6
data->firstsocket = -1;
for (ai = conn->res; ai; ai = ai->ai_next) {
data->firstsocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (data->firstsocket < 0)
continue;
if (connect(data->firstsocket, ai->ai_addr, ai->ai_addrlen) < 0) {
close(data->firstsocket);
data->firstsocket = -1;
continue;
}
break;
}
if (data->firstsocket < 0) {
failf(data, strerror(errno));
return CURLE_COULDNT_CONNECT;
}
#else
if (connect(data->firstsocket,
(struct sockaddr *) &(conn->serv_addr),
sizeof(conn->serv_addr)
@@ -1426,6 +1472,7 @@ static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
}
return CURLE_COULDNT_CONNECT;
}
#endif
/*************************************************************
* Proxy authentication
@@ -1473,11 +1520,31 @@ static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
conn->bytecount = 0;
/* Figure out the ip-number and display the first host name it shows: */
#ifdef ENABLE_IPV6
{
char hbuf[NI_MAXHOST];
#ifdef NI_WITHSCOPEID
const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
#else
const int niflags = NI_NUMERICHOST;
#endif
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0,
niflags)) {
snprintf(hbuf, sizeof(hbuf), "?");
}
if (ai->ai_canonname) {
infof(data, "Connected to %s (%s)\n", ai->ai_canonname, hbuf);
} else {
infof(data, "Connected to %s\n", hbuf);
}
}
#else
{
struct in_addr 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));
}
#endif
#ifdef __EMX__
/* 20000330 mgs
@@ -1509,8 +1576,13 @@ CURLcode curl_connect(CURL *curl, CURLconnect **in_connect)
if(conn) {
if(conn->path)
free(conn->path);
#ifdef ENABLE_IPV6
if(conn->res)
freeaddrinfo(conn->res);
#else
if(conn->hostent_buf)
free(conn->hostent_buf);
#endif
free(conn);
*in_connect=NULL;
}
@@ -1576,7 +1648,13 @@ CURLcode curl_do(CURLconnect *in_conn)
if(!conn || (conn->handle!= STRUCT_CONNECT)) {
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(conn->state != CONN_INIT) {
switch(conn->state) {
case CONN_INIT:
case CONN_DONE:
/* these two states are OK */
break;
default:
/* anything else is bad */
return CURLE_BAD_CALLING_ORDER;
}

View File

@@ -159,9 +159,13 @@ struct connectdata {
#define PROT_LDAP (1<<7)
#define PROT_FILE (1<<8)
#ifdef ENABLE_IPV6
struct addrinfo *res;
#else
char *hostent_buf; /* pointer to allocated memory for name info */
struct hostent *hp;
struct sockaddr_in serv_addr;
#endif
char proto[64]; /* store the protocol string in this buffer */
char gname[257]; /* store the hostname in this buffer */
char *name; /* host name pointer to fool around with */

View File

@@ -17,7 +17,7 @@ LINKR = link.exe /incremental:no /libpath:"../lib"
## Debug
CCD = cl.exe /MDd /Gm /ZI /Od /D "_DEBUG" /GZ
LINKD = link.exe /incremental:yes /debug
LINKD = link.exe /incremental:yes /debug /libpath:"../lib"
CFLAGS = /I "../include" /nologo /W3 /GX /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
LFLAGS = /nologo /out:$(PROGRAM_NAME) /subsystem:console /machine:I386

View File

@@ -1,3 +1,3 @@
#define CURL_NAME "curl"
#define CURL_VERSION "7.6.1-pre2"
#define CURL_VERSION "7.6.1"
#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "