1 /*
2  * Copyright (c) 2001-2012 Mark Hessling <mark@rexx.org> All rights reserved.
3  *
4  * This program and the accompanying materials are made available under
5  * the terms of the Common Public License v1.0 which accompanies this
6  * distribution. A copy is also available at the following address:
7  * http://www.opensource.org/licenses/cpl1.0.php
8  */
9 /*
10  * For diffs between libcurl versions:
11  * http://upstream-tracker.org/versions/libcurl.html
12  */
13 /*
14  * Not implemented:
15  *   setopt()
16  *      CURLOPT_SEEKFUNCTION - 7.18.0
17  *      CURLOPT_SEEKDATA - 7.18.0
18  *      CURLOPT_SSH_KEYFUNCTION - 7.19.6
19  *      CURLOPT_SSH_KEYDATA - 7.19.6
20  *      CURLOPT_INTERLEAVEFUNCTION - 7.20.0
21  *      CURLOPT_INTERLEAVEDATA - 7.20.0
22  *      CURLOPT_CLOSESOCKETFUNCTION - 7.21.7
23  *      CURLOPT_CLOSESOCKETDATA - 7.21.7
24  *   curl_easy_pause() not implemented
25  *
26  *   getopt()
27  *      CURLINFO_CERTINFO - 7.19.1
28  */
29 /*
30  * CURLOPT options to add:
31  * 7.33.0 XOAUTH2_BEARER                x      x
32  *        DNS_INTERFACE
33  *        DNS_LOCAL_IP4
34  *        DNS_LOCAL_IP6
35  * 7.34.0 LOGIN_OPTIONS                 x      x
36  * 7.36.0 SSL_ENABLE_NPN
37  *        SSL_ENABLE_ALPN
38  *        EXPECT_100_TIMEOUT_MS
39  * 7.37.0 PROXYHEADER
40  *        HEADEROPT
41  * 7.39.0 PINNEDPUBLICKEY
42  * 7.40.0 UNIX_SOCKET_PATH
43  * 7.41.0 SSL_VERIFYSTATUS              x      x
44  */
45 
46 /*
47  * Error handling:
48  *                              error_rexxcurl       error_curl
49  *
50  * ------------------------------------------------------------
51  * wrong # params           ******* syntax error **********
52  * internal error                   set                 N/A
53  * cURL runtime errors              -1                  set
54  */
55 #pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
56 
57 #ifdef HAVE_CONFIG_H
58 # include "config.h"
59 #else
60 # include "defines.h"
61 #endif
62 
63 #if defined(__EMX__) && defined(USE_OS2REXX)
64 # define INCL_DOS
65 # define INCL_WIN
66 # define INCL_GPI
67 # include "rxpack.h"
68 # include "rexxcurl.h"
69 #else
70 # include "rexxcurl.h"
71 # include "rxpack.h"
72 #endif
73 
74 char *RxPackageName = "rexxcurl";
75 
76 #define LIBCURL_SUPPORTED_VERSION LIBCURL_VERSION_NUM
77 
78 #define API_REXXCALLBACK_PRESENT 1
79 #define API_REXXCALLBACK_MISSING 0
80 
81 #if defined(WIN32)
82 HMODULE handle=NULL;
83 
84 typedef CURL * T_CURL_EASY_INIT(void);
85 T_CURL_EASY_INIT *p_curl_easy_init;
86 
87 typedef CURLcode T_CURL_EASY_SETOPT(CURL *curl, CURLoption option, ...);
88 T_CURL_EASY_SETOPT *p_curl_easy_setopt;
89 
90 typedef void T_CURL_EASY_RESET(CURL *curl );
91 T_CURL_EASY_RESET *p_curl_easy_reset;
92 
93 typedef CURLcode T_CURL_EASY_PERFORM(CURL *curl);
94 T_CURL_EASY_PERFORM *p_curl_easy_perform;
95 
96 typedef void T_CURL_EASY_CLEANUP(CURL *curl);
97 T_CURL_EASY_CLEANUP *p_curl_easy_cleanup;
98 
99 typedef CURLcode T_CURL_EASY_GETINFO(CURL *curl, CURLINFO info, ...);
100 T_CURL_EASY_GETINFO *p_curl_easy_getinfo;
101 
102 typedef CURLFORMcode T_CURL_FORMADD(struct curl_httppost **httppost, struct curl_httppost **last_post, ...);
103 T_CURL_FORMADD *p_curl_formadd;
104 
105 typedef void T_CURL_FORMFREE(struct curl_httppost *form);
106 T_CURL_FORMFREE *p_curl_formfree;
107 
108 typedef void T_CURL_GLOBAL_CLEANUP(void);
109 T_CURL_GLOBAL_CLEANUP *p_curl_global_cleanup;
110 
111 typedef void T_CURL_GLOBAL_INIT(long flags);
112 T_CURL_GLOBAL_INIT *p_curl_global_init;
113 
114 typedef struct curl_slist *T_CURL_SLIST_APPEND(struct curl_slist *, const char *);
115 T_CURL_SLIST_APPEND *p_curl_slist_append;
116 
117 typedef void T_CURL_SLIST_FREE_ALL(struct curl_slist *);
118 T_CURL_SLIST_FREE_ALL *p_curl_slist_free_all;
119 
120 typedef char *T_CURL_VERSION(void);
121 T_CURL_VERSION *p_curl_version;
122 
123 typedef curl_version_info_data *T_CURL_VERSION_INFO(CURLversion);
124 T_CURL_VERSION_INFO *p_curl_version_info;
125 
126 typedef char *T_CURL_EASY_ESCAPE(CURL *curl, char *url, int length);
127 T_CURL_EASY_ESCAPE *p_curl_easy_escape;
128 
129 typedef void T_CURL_FREE(void *ptr);
130 T_CURL_FREE *p_curl_free;
131 
132 typedef char *T_CURL_EASY_UNESCAPE(CURL *curl, char *url, int inlength, int *outlength);
133 T_CURL_EASY_UNESCAPE *p_curl_easy_unescape;
134 
135 # define CURL_EASY_INIT ((*p_curl_easy_init))
136 # define CURL_EASY_SETOPT ((*p_curl_easy_setopt))
137 # define CURL_EASY_RESET ((*p_curl_easy_reset))
138 # define CURL_EASY_PERFORM ((*p_curl_easy_perform))
139 # define CURL_EASY_CLEANUP ((*p_curl_easy_cleanup))
140 # define CURL_EASY_GETINFO ((*p_curl_easy_getinfo))
141 # define CURL_FORMADD ((*p_curl_formadd))
142 # define CURL_FORMFREE ((*p_curl_formfree))
143 # define CURL_GLOBAL_INIT ((*p_curl_global_init))
144 # define CURL_GLOBAL_CLEANUP ((*p_curl_global_cleanup))
145 # define CURL_SLIST_APPEND ((*p_curl_slist_append))
146 # define CURL_SLIST_FREE_ALL ((*p_curl_slist_free_all))
147 # define CURL_VERSION ((*p_curl_version))
148 # define CURL_VERSION_INFO ((*p_curl_version_info))
149 # define CURL_EASY_ESCAPE ((*p_curl_easy_escape))
150 # define CURL_EASY_UNESCAPE ((*p_curl_easy_unescape))
151 # define CURL_FREE ((*p_curl_free))
152 #else
153 # define CURL_EASY_INIT curl_easy_init
154 # define CURL_EASY_SETOPT curl_easy_setopt
155 # define CURL_EASY_RESET curl_easy_reset
156 # define CURL_EASY_PERFORM curl_easy_perform
157 # define CURL_EASY_CLEANUP curl_easy_cleanup
158 # define CURL_EASY_GETINFO curl_easy_getinfo
159 # define CURL_FORMADD curl_formadd
160 # define CURL_FORMFREE curl_formfree
161 # define CURL_GLOBAL_INIT curl_global_init
162 # define CURL_GLOBAL_CLEANUP curl_global_cleanup
163 # define CURL_SLIST_APPEND curl_slist_append
164 # define CURL_SLIST_FREE_ALL curl_slist_free_all
165 # define CURL_VERSION curl_version
166 # define CURL_VERSION_INFO curl_version_info
167 # define CURL_EASY_ESCAPE curl_easy_escape
168 # define CURL_EASY_UNESCAPE curl_easy_unescape
169 # define CURL_FREE curl_free
170 #endif
171 
172 #define INTERR_CURL_ERROR            1
173 #define INTERR_CURL_ERROR_STRING     "Error from cURL"
174 #define INTERR_INVALID_NUMBER        2
175 #define INTERR_INVALID_NUMBER_STRING "Invalid Number"
176 #define INTERR_INVALID_OPTION        3
177 #define INTERR_INVALID_OPTION_STRING "Invalid Option"
178 #define INTERR_NO_MEMORY             4
179 #define INTERR_NO_MEMORY_STRING      "Out of memory"
180 #define INTERR_INVALID_HANDLE        5
181 #define INTERR_INVALID_HANDLE_STRING "Invalid cURL handle"
182 #define INTERR_INVALID_FILE          6
183 #define INTERR_INVALID_FILE_STRING   "Invalid filename"
184 #define INTERR_INVALID_BOOL          7
185 #define INTERR_INVALID_BOOL_STRING   "Invalid boolean"
186 #define INTERR_INVALID_STEM          8
187 #define INTERR_INVALID_STEM_STRING   "Expecting a stem as parameter"
188 #define INTERR_INVALID_VARIABLE      9
189 #define INTERR_INVALID_VARIABLE_STRING "Invalid variable:"
190 #define INTERR_READONLY_VARIABLE     10
191 #define INTERR_READONLY_VARIABLE_STRING "Cannot set readonly variable"
192 #define INTERR_TOO_FEW_ARGS          11
193 #define INTERR_TOO_FEW_ARGS_STRING   "Too few arguments supplied"
194 #define INTERR_MANDATORY_FIELD       12
195 #define INTERR_MANDATORY_FIELD_STRING   "Field must be specified"
196 #define INTERR_WRITING_TEMP_FILE     13
197 #define INTERR_WRITING_TEMP_FILE_STRING "Error writing to temporary file"
198 #define INTERR_STEM_VALUE     14
199 #define INTERR_STEM_VALUE_STRING "Stem values must be in form of name=value"
200 
201 /*
202  * The following are option types for setopt()
203  * For those items that are not "basic" types, there is another
204  * table below which contains the definitions of the sub-options
205  */
206 #define RXCURLOPT_STRING        1  /* string */
207 #define RXCURLOPT_LIST          2  /* stem for slist */
208 #define RXCURLOPT_LONG          3  /* 32bit number */
209 #define RXCURLOPT_OUTFILE       4  /* output file */
210 #define RXCURLOPT_INFILE        5  /* input file - passed to cURL as FILE **/
211 #define RXCURLOPT_BOOL          6  /* bool */
212 #define RXCURLOPT_POLICY        7  /* policy */
213 #define RXCURLOPT_POST_DATA     8  /* stem for httppostdata */
214 #define RXCURLOPT_POST_FIELDS   9  /* stem for httppostfields */
215 #define RXCURLOPT_OUTSTEM      10  /* stem for outstem */
216 #define RXCURLOPT_HEADERSTEM   11  /* stem for headerstem */
217 #define RXCURLOPT_PROXYTYPE    12  /* proxytype */
218 #define RXCURLOPT_HTTP_VERSION 13  /* http_version */
219 #define RXCURLOPT_NETRC        14  /* netrc */
220 #define RXCURLOPT_TIMECOND     15  /* timecondition */
221 #define RXCURLOPT_IPRESOLVE    16  /* ipresolve */
222 #define RXCURLOPT_BITMAP       17  /* generic bitmap */
223 #define RXCURLOPT_BITMAP_AUTH  18  /* authorisation bitmap */
224 #define RXCURLOPT_LONGLONG     19  /* 64bit number */
225 #define RXCURLOPT_CALLBACK     20  /* libcurl callback */
226 #define RXCURLOPT_FTPSSL       21  /* ftp ssl */
227 #define RXCURLOPT_FTPSSLAUTH   22  /* ftp ssl auth */
228 #define RXCURLOPT_POST_FORM    23  /* option for processing after curl_formadd() calls */
229 #define RXCURLOPT_FTPSSLCCC    24  /* ftp ssl cc */
230 #define RXCURLOPT_INFILENAME   25  /* input file - validated as existing filename - passed to cURL as filename */
231 #define RXCURLOPT_BITMAP_SSHAUTH 26 /* SSH authorisation bitmap */
232 #define RXCURLOPT_FTP_CREATE_MISSING_DIRS  27 /* FTP create missing dirs */
233 #define RXCURLOPT_RTSP_REQUEST 28  /* RTSP Request options */
234 #define RXCURLOPT_PROTOCOLS    29  /* options for protocols */
235 #define RXCURLOPT_GSSAPI_DELEGATION 30  /* options for gssapi delegation */
236 #define RXCURLOPT_SSL_OPTIONS 31  /* options for SSL */
237 #define RXCURLOPT_BITMAP_REDIR 32  /* post redirection bitmap */
238 #define RXCURLOPT_BITMAP_TLSAUTH 33 /* TLS authorisation types */
239 #define RXCURLOPT_INSTEM        34 /* input stem - passed to cURL as FILE **/
240 #define RXCURLOPT_ERRFILE       35 /* error file */
241 
242 #define RXCURLINFO_STRING       1  /* string */
243 #define RXCURLINFO_LONG         2  /* number */
244 #define RXCURLINFO_DOUBLE       3  /* double */
245 #define RXCURLINFO_LIST         4  /* stem for slist */
246 #define RXCURLINFO_CERTINFO     5  /* certinfo struct */
247 #define RXCURLINFO_BITMAP       6  /* bitmap input, word list output based on curlsetopt sub-options*/
248 
249 static char *curl_errors[] =
250 {
251    "OK",                      /* 0 */
252    "UNSUPPORTED_PROTOCOL",    /* 1 */
253    "FAILED_INIT",             /* 2 */
254    "URL_MALFORMAT",           /* 3 */
255 #if LIBCURL_VERSION_NUM >= 0x071505
256    "NOT_BUILT_IN",            /* 4 */
257 #else
258    "URL_MALFORMAT_USER",      /* 4 */
259 #endif
260    "COULDNT_RESOLVE_PROXY",   /* 5 */
261    "COULDNT_RESOLVE_HOST",    /* 6 */
262    "COULDNT_CONNECT",         /* 7 */
263    "FTP_WEIRD_SERVER_REPLY",  /* 8 */
264    "FTP_ACCESS_DENIED",       /* 9 */
265 #if LIBCURL_VERSION_NUM >= 0x071800
266    "FTP_ACCEPT_FAILED",       /* 10 */
267 #else
268    "FTP_USER_PASSWORD_INCORRECT", /* 10 */
269 #endif
270    "FTP_WEIRD_PASS_REPLY",    /* 11 */
271 #if LIBCURL_VERSION_NUM >= 0x071800
272    "FTP_ACCEPT_TIMEOUT",      /* 12 */
273 #else
274    "FTP_WEIRD_USER_REPLY",    /* 12 */
275 #endif
276    "FTP_WEIRD_PASV_REPLY",    /* 13 */
277    "FTP_WEIRD_227_FORMAT",    /* 14 */
278    "FTP_CANT_GET_HOST",       /* 15 */
279    "FTP_CANT_RECONNECT",      /* 16 */
280    "FTP_COULDNT_SET_BINARY",  /* 17 */
281    "PARTIAL_FILE",            /* 18 */
282    "FTP_COULDNT_RETR_FILE",   /* 19 */
283    "FTP_WRITE_ERROR",         /* 20 */
284    "FTP_QUOTE_ERROR",         /* 21 */
285    "HTTP_NOT_FOUND",          /* 22 */
286    "WRITE_ERROR",             /* 23 */
287    "MALFORMAT_USER",          /* 24 - user name is illegally specified */
288    "FTP_COULDNT_STOR_FILE",   /* 25 - failed FTP upload */
289    "READ_ERROR",              /* 26 - could open/read from file */
290    "OUT_OF_MEMORY",           /* 27 */
291    "OPERATION_TIMEOUTED",     /* 28 - the timeout time was reached */
292    "FTP_COULDNT_SET_ASCII",   /* 29 - TYPE A failed */
293    "FTP_PORT_FAILED",         /* 30 - FTP PORT operation failed */
294    "FTP_COULDNT_USE_REST",    /* 31 - the REST command failed */
295    "FTP_COULDNT_GET_SIZE",    /* 32 - the SIZE command failed */
296    "HTTP_RANGE_ERROR",        /* 33 - RANGE "command" didn"'t work */
297    "HTTP_POST_ERROR",         /* 34 */
298    "SSL_CONNECT_ERROR",       /* 35 - wrong when connecting with SSL */
299    "FTP_BAD_DOWNLOAD_RESUME", /* 36 - couldn"'t resume download */
300    "FILE_COULDNT_READ_FILE",  /* 37 */
301    "LDAP_CANNOT_BIND",        /* 38 */
302    "LDAP_SEARCH_FAILED",      /* 39 */
303    "LIBRARY_NOT_FOUND",       /* 40 */
304    "FUNCTION_NOT_FOUND",      /* 41 */
305    "ABORTED_BY_CALLBACK",     /* 42 */
306    "BAD_FUNCTION_ARGUMENT",   /* 43 */
307    "BAD_CALLING_ORDER",       /* 44 */
308    "HTTP_PORT_FAILED",        /* 45 - HTTP Interface operation failed */
309    "BAD_PASSWORD_ENTERED",    /* 46 - my_getpass() returns fail */
310    "TOO_MANY_REDIRECTS ",     /* 47 - catch endless re-direct loops */
311 #if LIBCURL_VERSION_NUM >= 0x071505
312    "UNKNOWN_OPTION",          /* 48 - User specified an unknown option */
313 #else
314    "UNKNOWN_TELNET_OPTION",   /* 48 - User specified an unknown option */
315 #endif
316    "TELNET_OPTION_SYNTAX ",   /* 49 - Malformed telnet option */
317    "OBSOLETE",                /* 50 - removed after 7.7.3 */
318    "SSL_PEER_CERTIFICATE",    /* 51 - peer"'s certificate wasn't ok */
319    "GOT_NOTHING",             /* 52 - when this is a specific error */
320    "SSL_ENGINE_NOTFOUND",     /* 53 - SSL crypto engine not found */
321    "SSL_ENGINE_SETFAILED",    /* 54 - can not set SSL crypto engine as default */
322    "SEND_ERROR",              /* 55 - failed sending network data */
323    "RECV_ERROR",              /* 56 - failure in receiving network data */
324    "SHARE_IN_USE",            /* 57 - share is in use */
325    "SSL_CERTPROBLEM",         /* 58 - problem with the local certificate */
326    "SSL_CIPHER",              /* 59 - couldn't use specified cipher */
327    "SSL_CACERT",              /* 60 - problem with the CA cert (path?) */
328    "BAD_CONTENT_ENCODING",    /* 61 - Unrecognized transfer encoding */
329    "LDAP_INVALID_URL",        /* 62 - Invalid LDAP URL */
330    "FILESIZE_EXCEEDED",       /* 63 - Maximum file size exceeded */
331    "USE_SSL_FAILED",          /* 64 - Requested USE SSL level failed */
332    "SEND_FAIL_REWIND",        /* 65 - When doing a send operation curl had to rewind the data to retransmit, but the rewinding operation failed */
333    "SSL_ENGINE_INITFAILED",   /* 66 - Initiating the SSL Engine failed */
334    "LOGIN_DENIED",            /* 67 - The remote server denied curl to login (Added in 7.13.1) */
335    "TFTP_NOTFOUND",           /* 68 - file not found on server */
336    "TFTP_PERM",               /* 69 - permission problem on server */
337    "TFTP_DISKFULL",           /* 70 - out of disk space on server */
338    "TFTP_ILLEGAL",            /* 71 - Illegal TFTP operation */
339    "TFTP_UNKNOWNID",          /* 72 - Unknown transfer ID */
340    "TFTP_EXISTS",             /* 73 - File already exists */
341    "TFTP_NOSUCHUSER",         /* 74 - No such user */
342    "CONV_FAILED",             /* 75 - conversion failed */
343    "CONV_REQD",               /* 76 - caller must register conversion callbacks using curl_easy_setopt options CURLOPT_CONV_FROM_NETWORK_FUNCTION,CURLOPT_CONV_TO_NETWORK_FUNCTION, and CURLOPT_CONV_FROM_UTF8_FUNCTION */
344    "SSL_CACERT_BADFILE",      /* 77 - could not load CACERT file, missing or wrong format */
345    "REMOTE_FILE_NOT_FOUND",   /* 78 - remote file not found */
346    "SSH",                     /* 79 - error from the SSH layer, somewhat generic so the error message will be of interest when this has happened */
347    "SSL_SHUTDOWN_FAILED",     /* 80 - Failed to shut down the SSL */
348 #if LIBCURL_VERSION_NUM >= 0x071202
349    "AGAIN",                   /* 81 - socket is not ready for send/recv, wait till it's ready and try again (Added in 7.18.2) */
350 #endif
351 #if LIBCURL_VERSION_NUM >= 0x071300
352    "SSL_CRL_BADFILE",         /* 82 - could not load CRL file, missing or wrong format (Added in 7.19.0) */
353    "SSL_ISSUER_ERROR",        /* 83 - Issuer check failed.  (Added in 7.19.0) */
354 #endif
355 #if LIBCURL_VERSION_NUM >= 0x071400
356    "FTP_PRET_FAILED",         /* 84 - a PRET command failed */
357    "RTSP_CSEQ_ERROR",         /* 85 - mismatch of RTSP CSeq numbers */
358    "RTSP_SESSION_ERROR",      /* 86 - mismatch of RTSP Session Identifiers */
359 #endif
360 #if LIBCURL_VERSION_NUM >= 0x071500
361    "FTP_BAD_FILE_LIST",       /* 87 - unable to parse FTP file list */
362    "CHUNK_FAILED",            /* 88 - chunk callback reported error */
363 #endif
364    NULL
365 };
366 static char *curl_formadd_errors[] =
367 {
368    "OK",                  /* 0 */
369    "MEMORY",              /* 1 */
370    "OPTION_TWICE",        /* 2 */
371    "NULL",                /* 3 */
372    "UNKNOWN_OPTION",      /* 4 */
373    "INCOMPLETE",          /* 5 */
374    "ILLEGAL_ARRAY",       /* 6 */
375    "DISABLED",            /* 7 */
376 };
377 
378 typedef struct
379 {
380    char *name;
381    unsigned long number;
382    int optiontype; /* things like STEM, STRING, INT */
383    char *newname;  /* name of new value if this setting is deprecated, NULL means it is still valid */
384 } curl_options;
385 
386 static curl_options RexxCurlOptions[] =
387 {
388 #if LIBCURL_VERSION_NUM >= 0x071506
389    { "ACCEPTENCODING"  ,CURLOPT_ACCEPT_ENCODING ,RXCURLOPT_STRING      , NULL },
390 #endif
391 #if LIBCURL_VERSION_NUM >= 0x071800
392    { "ACCEPTTIMEOUTMS" ,CURLOPT_ACCEPTTIMEOUT_MS,RXCURLOPT_LONG        , NULL },
393 #endif
394 #if LIBCURL_VERSION_NUM >= 0x071300
395    { "ADDRESSSCOPE"    ,CURLOPT_ADDRESS_SCOPE   ,RXCURLOPT_LONG        , NULL },
396 #endif
397 #if LIBCURL_VERSION_NUM >= 0x071100
398    { "APPEND"          ,CURLOPT_APPEND          ,RXCURLOPT_BOOL        , NULL },
399 #endif
400 #if LIBCURL_VERSION_NUM >= 0x070a02
401    { "BUFFERSIZE"      ,CURLOPT_BUFFERSIZE      ,RXCURLOPT_LONG        , NULL },
402 #endif
403    { "CAINFO"          ,CURLOPT_CAINFO          ,RXCURLOPT_INFILENAME  , NULL },
404 #if LIBCURL_VERSION_NUM >= 0x070a02
405    { "CAPATH"          ,CURLOPT_CAPATH          ,RXCURLOPT_STRING      , NULL },
406 #endif
407 #if LIBCURL_VERSION_NUM >= 0x071301
408    { "CERTINFO"        ,CURLOPT_CERTINFO        ,RXCURLOPT_LONG        , NULL },
409 #endif
410 #if LIBCURL_VERSION_NUM < 0x072600
411    { "CLOSEPOLICY"     ,CURLOPT_CLOSEPOLICY     ,RXCURLOPT_POLICY      , NULL },
412 #endif
413 #if LIBCURL_VERSION_NUM >= 0x070f02
414    { "CONNECTONLY"     ,CURLOPT_CONNECT_ONLY    ,RXCURLOPT_LONG        , NULL },
415 #endif
416    { "CONNECTTIMEOUT"  ,CURLOPT_CONNECTTIMEOUT  ,RXCURLOPT_LONG        , NULL },
417 #if LIBCURL_VERSION_NUM >= 0x071002
418    { "CONNECTTIMEOUTMS",CURLOPT_CONNECTTIMEOUT_MS ,RXCURLOPT_LONG      , NULL },
419 #endif
420    { "COOKIE"          ,CURLOPT_COOKIE          ,RXCURLOPT_STRING      , NULL },
421    { "COOKIEFILE"      ,CURLOPT_COOKIEFILE      ,RXCURLOPT_INFILENAME  , NULL },
422 #if LIBCURL_VERSION_NUM >= 0x070900
423    { "COOKIEJAR"       ,CURLOPT_COOKIEJAR       ,RXCURLOPT_STRING      , NULL },
424 #endif
425 #if LIBCURL_VERSION_NUM >= 0x070e01
426    { "COOKIELIST"      ,CURLOPT_COOKIELIST      ,RXCURLOPT_STRING      , NULL },
427 #endif
428 #if LIBCURL_VERSION_NUM >= 0x070a02
429    { "COOKIESESSION"   ,CURLOPT_COOKIESESSION   ,RXCURLOPT_BOOL        , NULL },
430 #endif
431    { "CRLF"            ,CURLOPT_CRLF            ,RXCURLOPT_BOOL        , NULL },
432 #if LIBCURL_VERSION_NUM >= 0x071300
433    { "CRLFILE"         ,CURLOPT_CRLFILE         ,RXCURLOPT_STRING      , NULL },
434 #endif
435    { "CUSTOMREQUEST"   ,CURLOPT_CUSTOMREQUEST   ,RXCURLOPT_STRING      , NULL },
436 #if LIBCURL_VERSION_NUM >= 0x071100
437    { "DIRLISTONLY"     ,CURLOPT_DIRLISTONLY     ,RXCURLOPT_BOOL        , NULL },
438 #endif
439 #if LIBCURL_VERSION_NUM >= 0x070a02
440    { "DNSCACHETIMEOUT" ,CURLOPT_DNS_CACHE_TIMEOUT,RXCURLOPT_LONG       , NULL },
441 #if LIBCURL_VERSION_NUM >= 0x071800
442    { "DNSSERVERS"      ,CURLOPT_DNS_SERVERS     ,RXCURLOPT_STRING      , NULL },
443 #endif
444    { "DNSUSEGLOBALCACHE",CURLOPT_DNS_USE_GLOBAL_CACHE,RXCURLOPT_BOOL   , NULL },
445 #endif
446    { "EGDSOCKET"       ,CURLOPT_EGDSOCKET       ,RXCURLOPT_STRING      , NULL },
447 #if LIBCURL_VERSION_NUM >= 0x070a02
448 # if LIBCURL_VERSION_NUM >= 0x071506
449    { "ENCODING"        ,CURLOPT_ACCEPT_ENCODING ,RXCURLOPT_STRING      , "ACCEPTENCODING" },
450 # else
451    { "ENCODING"        ,CURLOPT_ENCODING        ,RXCURLOPT_STRING      , NULL },
452 # endif
453 #endif
454    { "ERRFILE"         ,CURLOPT_STDERR          ,RXCURLOPT_ERRFILE     , NULL },
455    { "FAILONERROR"     ,CURLOPT_FAILONERROR     ,RXCURLOPT_BOOL        , NULL },
456    { "FILETIME"        ,CURLOPT_FILETIME        ,RXCURLOPT_BOOL        , NULL },
457    { "FOLLOWLOCATION"  ,CURLOPT_FOLLOWLOCATION  ,RXCURLOPT_BOOL        , NULL },
458    { "FORBIDREUSE"     ,CURLOPT_FORBID_REUSE    ,RXCURLOPT_BOOL        , NULL },
459    { "FRESHCONNECT"    ,CURLOPT_FRESH_CONNECT   ,RXCURLOPT_BOOL        , NULL },
460 #if LIBCURL_VERSION_NUM >= 0x070e05
461    { "FTPALTERNATIVETOUSER", CURLOPT_FTP_ALTERNATIVE_TO_USER, RXCURLOPT_STRING , NULL },
462 #endif
463 #if LIBCURL_VERSION_NUM >= 0x071100
464    { "FTPAPPEND"       ,CURLOPT_APPEND          ,RXCURLOPT_BOOL        , "APPEND" },
465 #else
466    { "FTPAPPEND"       ,CURLOPT_FTPAPPEND       ,RXCURLOPT_BOOL        , NULL },
467 #endif
468    { "FTPCMDS"         ,CURLOPT_QUOTE           ,RXCURLOPT_LIST        , NULL },
469    { "FTPCMDSAFTER"    ,CURLOPT_POSTQUOTE       ,RXCURLOPT_LIST        , NULL },
470    { "FTPCMDSBEFORE"   ,CURLOPT_PREQUOTE        ,RXCURLOPT_LIST        , NULL },
471 #if LIBCURL_VERSION_NUM >= 0x070a07
472 # if LIBCURL_VERSION_NUM >= 0x071304
473    { "FTPCREATEMISSINGDIRS", CURLOPT_FTP_CREATE_MISSING_DIRS, RXCURLOPT_FTP_CREATE_MISSING_DIRS , NULL },
474 # else
475    { "FTPCREATEMISSINGDIRS", CURLOPT_FTP_CREATE_MISSING_DIRS, RXCURLOPT_LONG , NULL },
476 # endif
477 #endif
478    { "FTPCRLF"         ,CURLOPT_CRLF            ,RXCURLOPT_BOOL        , NULL },
479 #if LIBCURL_VERSION_NUM >= 0x071100
480    { "FTPLISTONLY"     ,CURLOPT_DIRLISTONLY     ,RXCURLOPT_BOOL        , "DIRLISTONLY" },
481 #else
482    { "FTPLISTONLY"     ,CURLOPT_FTPLISTONLY     ,RXCURLOPT_BOOL        , NULL },
483 #endif
484    { "FTPPORT"         ,CURLOPT_FTPPORT         ,RXCURLOPT_STRING      , NULL },
485 #if LIBCURL_VERSION_NUM >= 0x070a08
486    { "FTPRESPONSETIMEOUT", CURLOPT_FTP_RESPONSE_TIMEOUT, RXCURLOPT_LONG, NULL },
487 #endif
488 #if LIBCURL_VERSION_NUM >= 0x070e00
489    { "FTPSKIPPASVIP"   ,CURLOPT_FTP_SKIP_PASV_IP,RXCURLOPT_BOOL        , NULL },
490 #endif
491 #if LIBCURL_VERSION_NUM >= 0x070b00
492 # if LIBCURL_VERSION_NUM >= 0x071100
493    { "FTPSSL"          ,CURLOPT_USE_SSL         ,RXCURLOPT_FTPSSL      , "USESSL" },
494 # else
495    { "FTPSSL"          ,CURLOPT_FTP_SSL         ,RXCURLOPT_FTPSSL      , NULL },
496 # endif
497 #endif
498 #if LIBCURL_VERSION_NUM >= 0x070c02
499    { "FTPSSLAUTH"      ,CURLOPT_FTPSSLAUTH      ,RXCURLOPT_FTPSSLAUTH  , NULL },
500 #endif
501 #if LIBCURL_VERSION_NUM >= 0x071001
502    { "FTPSSLCCC"       ,CURLOPT_FTP_SSL_CCC     ,RXCURLOPT_FTPSSLCCC   , NULL },
503 #endif
504 #if LIBCURL_VERSION_NUM >= 0x070a05
505    { "FTPUSEEPRT"      ,CURLOPT_FTP_USE_EPRT    ,RXCURLOPT_BOOL        , NULL },
506 #endif
507 #if LIBCURL_VERSION_NUM >= 0x070a02
508    { "FTPUSEEPSV"      ,CURLOPT_FTP_USE_EPSV    ,RXCURLOPT_BOOL        , NULL },
509 #endif
510 #if LIBCURL_VERSION_NUM >= 0x071400
511    { "FTPUSEPRET"      ,CURLOPT_FTP_USE_PRET    ,RXCURLOPT_BOOL        , NULL },
512 #endif
513 #if LIBCURL_VERSION_NUM >= 0x071600
514    { "GSSAPIDELEGATION",CURLOPT_GSSAPI_DELEGATION,RXCURLOPT_GSSAPI_DELEGATION , NULL },
515 #endif
516    { "HEADER"          ,CURLOPT_HEADER          ,RXCURLOPT_BOOL        , NULL },
517 
518 #if LIBCURL_VERSION_NUM >= 0x072600
519    { "HEADERFILE"      ,CURLOPT_HEADERDATA      ,RXCURLOPT_OUTFILE     , NULL },
520    { "HEADERSTEM"      ,CURLOPT_HEADERDATA      ,RXCURLOPT_HEADERSTEM  , NULL },
521 #else
522    { "HEADERFILE"      ,CURLOPT_WRITEHEADER     ,RXCURLOPT_OUTFILE     , NULL },
523    { "HEADERSTEM"      ,CURLOPT_WRITEHEADER     ,RXCURLOPT_HEADERSTEM  , NULL },
524 #endif
525 
526 #if LIBCURL_VERSION_NUM >= 0x070a03
527    { "HTTP200ALIASES"  ,CURLOPT_HTTP200ALIASES  ,RXCURLOPT_LIST        , NULL },
528 #endif
529 #if LIBCURL_VERSION_NUM >= 0x070a06
530    { "HTTPAUTH"        ,CURLOPT_HTTPAUTH        ,RXCURLOPT_BITMAP_AUTH , NULL },
531 #endif
532 #if LIBCURL_VERSION_NUM >= 0x071002
533    { "HTTPCONTENTDECODING",CURLOPT_HTTP_CONTENT_DECODING,RXCURLOPT_BOOL , NULL },
534 #endif
535 #if LIBCURL_VERSION_NUM >= 0x070801
536    { "HTTPGET"         ,CURLOPT_HTTPGET         ,RXCURLOPT_BOOL        , NULL },
537 #endif
538    { "HTTPHEADER"      ,CURLOPT_HTTPHEADER      ,RXCURLOPT_LIST        , NULL },
539    { "HTTPPOST"        ,CURLOPT_POST            ,RXCURLOPT_BOOL        , NULL },
540    { "HTTPPOSTDATA"    ,CURLOPT_HTTPPOST        ,RXCURLOPT_POST_DATA   , NULL },
541    { "HTTPPOSTFIELDS"  ,CURLOPT_POSTFIELDS      ,RXCURLOPT_POST_FIELDS , NULL },
542    { "HTTPPOSTFORM"    ,CURLOPT_HTTPPOST        ,RXCURLOPT_POST_FORM   , NULL },
543    { "HTTPPROXYTUNNEL" ,CURLOPT_HTTPPROXYTUNNEL ,RXCURLOPT_BOOL        , NULL },
544    { "HTTPPUT"         ,CURLOPT_PUT             ,RXCURLOPT_BOOL        , NULL },
545 #if LIBCURL_VERSION_NUM >= 0x071002
546    { "HTTPTRANSFERDECODING",CURLOPT_HTTP_TRANSFER_DECODING,RXCURLOPT_BOOL , NULL },
547 #endif
548    { "HTTPVERSION"     ,CURLOPT_HTTP_VERSION    ,RXCURLOPT_HTTP_VERSION, NULL },
549 #if LIBCURL_VERSION_NUM >= 0x070e01
550    { "IGNORECONTENTLENGTH",CURLOPT_IGNORE_CONTENT_LENGTH,RXCURLOPT_LONG, NULL },
551 #endif
552 
553 #if LIBCURL_VERSION_NUM >= 0x072600
554    { "INFILE"          ,CURLOPT_READDATA        ,RXCURLOPT_INFILE      , NULL },
555    { "INSTEM"          ,CURLOPT_READDATA        ,RXCURLOPT_INSTEM      , NULL },
556 #else
557    { "INFILE"          ,CURLOPT_INFILE          ,RXCURLOPT_INFILE      , NULL },
558    { "INSTEM"          ,CURLOPT_INFILE          ,RXCURLOPT_INSTEM      , NULL },
559 #endif
560 
561    { "INTERFACE"       ,CURLOPT_INTERFACE       ,RXCURLOPT_STRING      , NULL },
562 #if LIBCURL_VERSION_NUM >= 0x070a08
563    { "IPRESOLVE"       ,CURLOPT_IPRESOLVE       ,RXCURLOPT_IPRESOLVE   , NULL },
564 #endif
565 #if LIBCURL_VERSION_NUM >= 0x071300
566    { "ISSUERCERT"      ,CURLOPT_ISSUERCERT      ,RXCURLOPT_STRING      , NULL },
567 #endif
568 #if LIBCURL_VERSION_NUM >= 0x071100
569    { "KEYPASSWD"       ,CURLOPT_KEYPASSWD       ,RXCURLOPT_STRING      , NULL },
570 #endif
571 #if LIBCURL_VERSION_NUM >= 0x071100
572    { "KRB4LEVEL"       ,CURLOPT_KRBLEVEL        ,RXCURLOPT_STRING      , "KRBLEVEL" },
573    { "KRBLEVEL"        ,CURLOPT_KRBLEVEL        ,RXCURLOPT_STRING      , NULL },
574 #else
575    { "KRB4LEVEL"       ,CURLOPT_KRB4LEVEL       ,RXCURLOPT_STRING      , NULL },
576 #endif
577 #if LIBCURL_VERSION_NUM >= 0x070f02
578    { "LOCALPORT"       ,CURLOPT_LOCALPORT       ,RXCURLOPT_LONG        , NULL },
579    { "LOCALPORTRANGE"  ,CURLOPT_LOCALPORTRANGE  ,RXCURLOPT_LONG        , NULL },
580 #endif
581 #if LIBCURL_VERSION_NUM >= 0x072200
582    { "LOGINOPTIONS"    ,CURLOPT_LOGIN_OPTIONS   ,RXCURLOPT_STRING      , NULL },
583 #endif
584    { "LOWSPEEDLIMIT"   ,CURLOPT_LOW_SPEED_LIMIT ,RXCURLOPT_LONG        , NULL },
585    { "LOWSPEEDTIME"    ,CURLOPT_LOW_SPEED_TIME  ,RXCURLOPT_LONG        , NULL },
586 #if LIBCURL_VERSION_NUM >= 0x071900
587    { "MAILAUTH"        ,CURLOPT_MAIL_AUTH       ,RXCURLOPT_STRING      , NULL },
588 #endif
589 #if LIBCURL_VERSION_NUM >= 0x071400
590    { "MAILFROM"        ,CURLOPT_MAIL_FROM       ,RXCURLOPT_STRING      , NULL },
591    { "MAILRCPT"        ,CURLOPT_MAIL_RCPT       ,RXCURLOPT_LIST        , NULL },
592 #endif
593    { "MAXCONNECTS"     ,CURLOPT_MAXCONNECTS     ,RXCURLOPT_LONG        , NULL },
594 #if LIBCURL_VERSION_NUM >= 0x070a08
595    { "MAXFILESIZE"     ,CURLOPT_MAXFILESIZE     ,RXCURLOPT_LONGLONG    , NULL },
596 #endif
597 #if LIBCURL_VERSION_NUM >= 0x070e05
598    { "MAXRECVSPEEDLARGE", CURLOPT_MAX_RECV_SPEED_LARGE, RXCURLOPT_LONGLONG , NULL },
599 #endif
600    { "MAXREDIRS"       ,CURLOPT_MAXREDIRS       ,RXCURLOPT_LONG        , NULL },
601 #if LIBCURL_VERSION_NUM >= 0x070e05
602    { "MAXSENDSPEEDLARGE", CURLOPT_MAX_SEND_SPEED_LARGE, RXCURLOPT_LONGLONG , NULL },
603 #endif
604    { "NETRC"           ,CURLOPT_NETRC           ,RXCURLOPT_NETRC       , NULL },
605 #if LIBCURL_VERSION_NUM >= 0x070a09
606    { "NETRCFILE"       ,CURLOPT_NETRC_FILE      ,RXCURLOPT_INFILENAME  , NULL },
607 #endif
608 #if LIBCURL_VERSION_NUM >= 0x071004
609    { "NEWDIRECTORYPERMS" ,CURLOPT_NEW_DIRECTORY_PERMS ,RXCURLOPT_LONG  , NULL },
610 #endif
611    { "NOBODY"          ,CURLOPT_NOBODY          ,RXCURLOPT_BOOL        , NULL },
612 #if LIBCURL_VERSION_NUM >= 0x070900
613    { "NOPROGRESS"      ,CURLOPT_NOPROGRESS      ,RXCURLOPT_BOOL        , NULL },
614 #endif
615 #if LIBCURL_VERSION_NUM >= 0x071304
616    { "NOPROXY"         ,CURLOPT_NOPROXY         ,RXCURLOPT_STRING      , NULL },
617 #endif
618 #if LIBCURL_VERSION_NUM >= 0x070a02
619    { "NOSIGNAL"        ,CURLOPT_NOSIGNAL        ,RXCURLOPT_BOOL        , NULL },
620 #endif
621 
622 #if LIBCURL_VERSION_NUM >= 0x072600
623    { "OUTFILE"         ,CURLOPT_WRITEDATA       ,RXCURLOPT_OUTFILE     , NULL },
624    { "OUTSTEM"         ,CURLOPT_WRITEDATA       ,RXCURLOPT_OUTSTEM     , NULL },
625 #else
626    { "OUTFILE"         ,CURLOPT_FILE            ,RXCURLOPT_OUTFILE     , NULL },
627    { "OUTSTEM"         ,CURLOPT_FILE            ,RXCURLOPT_OUTSTEM     , NULL },
628 #endif
629 
630 #if LIBCURL_VERSION_NUM >= 0x071301
631    { "PASSWORD"        ,CURLOPT_PASSWORD        ,RXCURLOPT_STRING      , NULL },
632 #endif
633 #if LIBCURL_VERSION_NUM >= 0x071101
634 # if LIBCURL_VERSION_NUM >= 0x071301
635    { "POST301"         ,CURLOPT_POSTREDIR       ,RXCURLOPT_BITMAP_REDIR, "POSTREDIR" },
636 # else
637    { "POST301"         ,CURLOPT_POST301         ,RXCURLOPT_BOOL        , NULL },
638 # endif
639 #endif
640 
641 /* don't explicitly allow this as an option   { "POSTFIELDSIZE"   ,CURLOPT_POSTFIELDSIZE   ,RXCURLOPT_LONG        , NULL }, */
642 
643 #if LIBCURL_VERSION_NUM >= 0x070a02
644    { "POSTQUOTE"       ,CURLOPT_POSTQUOTE       ,RXCURLOPT_LIST        , NULL },
645 #endif
646 #if LIBCURL_VERSION_NUM >= 0x071301
647    { "POSTREDIR"       ,CURLOPT_POSTREDIR       ,RXCURLOPT_BITMAP_REDIR, NULL },
648 #endif
649 #if LIBCURL_VERSION_NUM >= 0x070a02
650    { "PREQUOTE"        ,CURLOPT_PREQUOTE        ,RXCURLOPT_LIST        , NULL },
651 #endif
652 #if LIBCURL_VERSION_NUM >= 0x070a03
653    { "PRIVATE"         ,CURLOPT_PRIVATE         ,RXCURLOPT_STRING      , NULL },
654 #endif
655 #if defined( REXXCALLBACK )
656    { "PROGRESSFUNCTION",CURLOPT_PROGRESSFUNCTION,RXCURLOPT_CALLBACK    , NULL },
657 #endif
658 #if LIBCURL_VERSION_NUM >= 0x071304
659    { "PROTOCOLS"       ,CURLOPT_PROTOCOLS       ,RXCURLOPT_PROTOCOLS   , NULL },
660 #endif
661    { "PROXY"           ,CURLOPT_PROXY           ,RXCURLOPT_STRING      , NULL },
662 #if LIBCURL_VERSION_NUM >= 0x070a07
663    { "PROXYAUTH"       ,CURLOPT_PROXYAUTH       ,RXCURLOPT_BITMAP_AUTH , NULL },
664 #endif
665 #if LIBCURL_VERSION_NUM >= 0x071301
666    { "PROXYPASSWORD"   ,CURLOPT_PROXYPASSWORD   ,RXCURLOPT_STRING      , NULL },
667 #endif
668 #if LIBCURL_VERSION_NUM >= 0x070900
669    { "PROXYPORT"       ,CURLOPT_PROXYPORT       ,RXCURLOPT_LONG        , NULL },
670 #endif
671 #if LIBCURL_VERSION_NUM >= 0x071200
672    { "PROXYTRANSFERMODE",CURLOPT_PROXY_TRANSFER_MODE,RXCURLOPT_LONG    , NULL },
673 #endif
674 #if LIBCURL_VERSION_NUM >= 0x070a02
675    { "PROXYTYPE"       ,CURLOPT_PROXYTYPE       ,RXCURLOPT_PROXYTYPE   , NULL },
676 #endif
677 #if LIBCURL_VERSION_NUM >= 0x071301
678    { "PROXYUSERNAME"   ,CURLOPT_PROXYUSERNAME   ,RXCURLOPT_STRING      , NULL },
679 #endif
680    { "PROXYUSERPWD"    ,CURLOPT_PROXYUSERPWD    ,RXCURLOPT_STRING      , NULL },
681 #if LIBCURL_VERSION_NUM >= 0x070a02
682    { "QUOTE"           ,CURLOPT_QUOTE           ,RXCURLOPT_LIST        , NULL },
683 #endif
684    { "RANDOMFILE"      ,CURLOPT_RANDOM_FILE     ,RXCURLOPT_STRING      , NULL },
685    { "RANGE"           ,CURLOPT_RANGE           ,RXCURLOPT_STRING      , NULL },
686 #if LIBCURL_VERSION_NUM >= 0x071304
687    { "REDIRPROTOCOLS"  ,CURLOPT_REDIR_PROTOCOLS ,RXCURLOPT_PROTOCOLS   , NULL },
688 #endif
689    { "REFERER"         ,CURLOPT_REFERER         ,RXCURLOPT_STRING      , NULL },
690 #if LIBCURL_VERSION_NUM >= 0x071503
691    { "RESOLVE"         ,CURLOPT_RESOLVE         ,RXCURLOPT_LIST        , NULL },
692 #endif
693    { "RESUMEFROM"      ,CURLOPT_RESUME_FROM     ,RXCURLOPT_LONGLONG    , NULL },
694 #if LIBCURL_VERSION_NUM >= 0x071400
695    { "RTSPCLIENTCSEQ"  ,CURLOPT_RTSP_CLIENT_CSEQ,RXCURLOPT_LONG        , NULL },
696    { "RTSPHEADER"      ,CURLOPT_RTSPHEADER      ,RXCURLOPT_LIST        , NULL },
697    { "RTSPREQUEST"     ,CURLOPT_RTSP_REQUEST    ,RXCURLOPT_RTSP_REQUEST, NULL },
698    { "RTSPSERVERCSEQ"  ,CURLOPT_RTSP_SERVER_CSEQ,RXCURLOPT_LONG        , NULL },
699    { "RTSPSESSIONID"   ,CURLOPT_RTSP_SESSION_ID ,RXCURLOPT_STRING      , NULL },
700    { "RTSPSTREAMURI"   ,CURLOPT_RTSP_STREAM_URI ,RXCURLOPT_STRING      , NULL },
701    { "RTSPTRANSPORT"   ,CURLOPT_RTSP_TRANSPORT  ,RXCURLOPT_STRING      , NULL },
702 #endif
703 #if LIBCURL_VERSION_NUM >= 0x071304
704    { "SOCKS5GSSAPINEC" ,CURLOPT_SOCKS5_GSSAPI_NEC, RXCURLOPT_LONG      , NULL },
705    { "SOCKS5GSSAPISERVICE", CURLOPT_SOCKS5_GSSAPI_SERVICE, RXCURLOPT_STRING      , NULL },
706 #endif
707 #if LIBCURL_VERSION_NUM >= 0x070d00 && LIBCURL_VERSION_NUM < 0x071000
708    { "SOURCEPOSTQUOTE" ,CURLOPT_SOURCE_POSTQUOTE,RXCURLOPT_LIST        , NULL },
709    { "SOURCEPREQUOTE"  ,CURLOPT_SOURCE_PREQUOTE ,RXCURLOPT_LIST        , NULL },
710    { "SOURCEQUOTE"     ,CURLOPT_SOURCE_QUOTE    ,RXCURLOPT_LIST        , NULL },
711    { "SOURCEURL"       ,CURLOPT_SOURCE_URL      ,RXCURLOPT_STRING      , NULL },
712    { "SOURCEUSERPWD"   ,CURLOPT_SOURCE_USERPWD  ,RXCURLOPT_STRING      , NULL },
713 #endif
714 #if LIBCURL_VERSION_NUM >= 0x071001
715    { "SSHAUTHTYPES"    ,CURLOPT_SSH_AUTH_TYPES  ,RXCURLOPT_BITMAP_SSHAUTH , NULL },
716 #endif
717 #if LIBCURL_VERSION_NUM >= 0x071101
718    { "SSHHOSTPUBLICKEYMD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, RXCURLOPT_STRING , NULL },
719 #endif
720 #if LIBCURL_VERSION_NUM >= 0x071306
721 # if defined( REXXCALLBACK )
722    { "SSHKEYFUNCTION"  ,CURLOPT_SSH_KEYFUNCTION, RXCURLOPT_CALLBACK    , NULL },
723 # endif
724    { "SSHKNOWNHOSTS"   ,CURLOPT_SSH_KNOWNHOSTS  ,RXCURLOPT_STRING      , NULL },
725 #endif
726 #if LIBCURL_VERSION_NUM >= 0x071001
727    { "SSHPRIVATEKEYFILE", CURLOPT_SSH_PRIVATE_KEYFILE, RXCURLOPT_INFILENAME , NULL },
728    { "SSHPUBLICKEYFILE" , CURLOPT_SSH_PUBLIC_KEYFILE, RXCURLOPT_INFILENAME , NULL },
729 #endif
730    { "SSLCERT"         ,CURLOPT_SSLCERT         ,RXCURLOPT_STRING      , NULL },
731 #if LIBCURL_VERSION_NUM >= 0x071100
732    { "SSLCERTPASSWD"   ,CURLOPT_KEYPASSWD       ,RXCURLOPT_STRING      , "KEYPASSWD" },
733 #else
734    { "SSLCERTPASSWD"   ,CURLOPT_SSLCERTPASSWD   ,RXCURLOPT_STRING      , NULL },
735 #endif
736 #if LIBCURL_VERSION_NUM >= 0x070a02
737    { "SSLCERTTYPE"     ,CURLOPT_SSLCERTTYPE     ,RXCURLOPT_STRING      , NULL },
738 #endif
739 #if LIBCURL_VERSION_NUM >= 0x070900
740    { "SSLCIPHERLIST"   ,CURLOPT_SSL_CIPHER_LIST ,RXCURLOPT_STRING      , NULL },
741 #endif
742 #if LIBCURL_VERSION_NUM >= 0x070a02
743    { "SSLENGINE"       ,CURLOPT_SSLENGINE       ,RXCURLOPT_STRING      , NULL },
744    { "SSLENGINEDEFAULT",CURLOPT_SSLENGINE_DEFAULT,RXCURLOPT_STRING     , NULL },
745    { "SSLKEY"          ,CURLOPT_SSLKEY          ,RXCURLOPT_STRING      , NULL },
746 # if LIBCURL_VERSION_NUM >= 0x071100
747    { "SSLKEYPASSWD"    ,CURLOPT_KEYPASSWD       ,RXCURLOPT_STRING      , "KEYPASSWD" },
748 # else
749    { "SSLKEYPASSWD"    ,CURLOPT_SSLKEYPASSWD    ,RXCURLOPT_STRING      , NULL },
750 # endif
751    { "SSLKEYTYPE"      ,CURLOPT_SSLKEYTYPE      ,RXCURLOPT_STRING      , NULL },
752 #endif
753 #if LIBCURL_VERSION_NUM >= 0x071900
754    { "SSLOPTIONS"      ,CURLOPT_SSL_OPTIONS     ,RXCURLOPT_SSL_OPTIONS , NULL },
755 #endif
756    { "SSLPEERCERT"     ,CURLOPT_CAINFO          ,RXCURLOPT_STRING      , NULL },
757 #if LIBCURL_VERSION_NUM >= 0x071000
758    { "SSLSESSIONIDCACHE", CURLOPT_SSL_SESSIONID_CACHE, RXCURLOPT_BOOL  , NULL },
759 #endif
760 #if LIBCURL_VERSION_NUM >= 0x070801
761    { "SSLVERIFYHOST"   ,CURLOPT_SSL_VERIFYHOST  ,RXCURLOPT_LONG        , NULL },
762 #endif
763    { "SSLVERIFYPEER"   ,CURLOPT_SSL_VERIFYPEER  ,RXCURLOPT_BOOL        , NULL },
764 #if LIBCURL_VERSION_NUM >= 0x072A00
765    { "SSLVERIFYSTATUS" ,CURLOPT_SSL_VERIFYSTATUS,RXCURLOPT_BOOL        , NULL },
766 #endif
767    { "SSLVERSION"      ,CURLOPT_SSLVERSION      ,RXCURLOPT_LONG        , NULL },
768 #if LIBCURL_VERSION_NUM >= 0x071900
769    { "TCPKEEPALIVE"     ,CURLOPT_TCP_KEEPALIVE  ,RXCURLOPT_BOOL        , NULL },
770    { "TCPKEEPIDLE"      ,CURLOPT_TCP_KEEPIDLE   ,RXCURLOPT_LONG        , NULL },
771    { "TCPKEEPINTVL"     ,CURLOPT_TCP_KEEPINTVL  ,RXCURLOPT_LONG        , NULL },
772 #endif
773 #if LIBCURL_VERSION_NUM >= 0x070d00
774    { "TCPNODELAY"       ,CURLOPT_TCP_NODELAY    ,RXCURLOPT_BOOL        , NULL },
775 #endif
776 #if LIBCURL_VERSION_NUM >= 0x071304
777    { "TFTPBLKSIZE"      ,CURLOPT_TFTP_BLKSIZE   ,RXCURLOPT_LONG        , NULL },
778 #endif
779    { "TIMECONDITION"   ,CURLOPT_TIMECONDITION   ,RXCURLOPT_TIMECOND    , NULL },
780    { "TIMEOUT"         ,CURLOPT_TIMEOUT         ,RXCURLOPT_LONG        , NULL },
781 #if LIBCURL_VERSION_NUM >= 0x071002
782    { "TIMEOUTMS"       ,CURLOPT_TIMEOUT_MS      ,RXCURLOPT_LONG        , NULL },
783 #endif
784    { "TIMEVALUE"       ,CURLOPT_TIMEVALUE       ,RXCURLOPT_LONG        , NULL },
785 #if LIBCURL_VERSION_NUM >= 0x071504
786    { "TLSAUTHPASSWORD" ,CURLOPT_TLSAUTH_PASSWORD,RXCURLOPT_STRING      , NULL },
787    { "TLSAUTHTYPE"     ,CURLOPT_TLSAUTH_TYPE    ,RXCURLOPT_BITMAP_TLSAUTH, NULL },
788    { "TLSAUTHUSERNAME" ,CURLOPT_TLSAUTH_USERNAME,RXCURLOPT_STRING      , NULL },
789 #endif
790 #if LIBCURL_VERSION_NUM >= 0x071506
791    { "TRANSFERENCODING",CURLOPT_TRANSFER_ENCODING,RXCURLOPT_BOOL      , NULL },
792 #endif
793    { "TRANSFERTEXT"    ,CURLOPT_TRANSFERTEXT    ,RXCURLOPT_BOOL        , NULL },
794 #if LIBCURL_VERSION_NUM >= 0x070908
795    { "UNRESTRICTEDAUTH",CURLOPT_UNRESTRICTED_AUTH  ,RXCURLOPT_BOOL     , NULL },
796 #endif
797    { "UPLOAD"          ,CURLOPT_UPLOAD          ,RXCURLOPT_BOOL        , NULL },
798    { "URL"             ,CURLOPT_URL             ,RXCURLOPT_STRING      , NULL },
799    { "USERAGENT"       ,CURLOPT_USERAGENT       ,RXCURLOPT_STRING      , NULL },
800 #if LIBCURL_VERSION_NUM >= 0x071301
801    { "USERNAME"        ,CURLOPT_USERNAME        ,RXCURLOPT_STRING      , NULL },
802 #endif
803    { "USERPWD"         ,CURLOPT_USERPWD         ,RXCURLOPT_STRING      , NULL },
804 #if LIBCURL_VERSION_NUM >= 0x071100
805    { "USESSL"          ,CURLOPT_USE_SSL         ,RXCURLOPT_FTPSSL      , NULL },
806 #endif
807    { "VERBOSE"         ,CURLOPT_VERBOSE         ,RXCURLOPT_BOOL        , NULL },
808 #if LIBCURL_VERSION_NUM >= 0x071500
809 /* not implemented; need lots of callbacks */
810 /*   { "WILDCARDMATCH"   ,CURLOPT_WILDCARDMATCH   ,RXCURLOPT_BOOL        , NULL },*/
811 #endif
812 #if LIBCURL_VERSION_NUM >= 0x072100
813    { "XOAUTH2BEARER"   ,CURLOPT_XOAUTH2_BEARER  ,RXCURLOPT_STRING      , NULL },
814 #endif
815    { NULL              ,0                       ,0                     , NULL }
816 };
817 
818 static curl_options RexxCurlGetinfos[] =
819 {
820 #if LIBCURL_VERSION_NUM >= 0x071300
821    { "APPCONNECT_TIME"        ,CURLINFO_APPCONNECT_TIME        ,RXCURLINFO_DOUBLE, NULL },
822 #endif
823 #if LIBCURL_VERSION_NUM >= 0x071301
824    { "CERTINFO"               ,CURLINFO_CERTINFO               ,RXCURLINFO_CERTINFO, NULL },
825 #endif
826 #if LIBCURL_VERSION_NUM >= 0x071304
827    { "CONDITION_UNMET"        ,CURLINFO_CONDITION_UNMET        ,RXCURLINFO_LONG  , NULL },
828 #endif
829    { "CONNECT_TIME"           ,CURLINFO_CONNECT_TIME           ,RXCURLINFO_DOUBLE, NULL },
830    { "CONTENT_LENGTH_DOWNLOAD",CURLINFO_CONTENT_LENGTH_DOWNLOAD,RXCURLINFO_DOUBLE, NULL },
831    { "CONTENT_LENGTH_UPLOAD"  ,CURLINFO_CONTENT_LENGTH_UPLOAD  ,RXCURLINFO_DOUBLE, NULL },
832 #if LIBCURL_VERSION_NUM >= 0x070a02
833    { "CONTENT_TYPE"           ,CURLINFO_CONTENT_TYPE           ,RXCURLINFO_STRING, NULL },
834 #endif
835 #if LIBCURL_VERSION_NUM >= 0x070e01
836    { "COOKIELIST"             ,CURLINFO_COOKIELIST             ,RXCURLINFO_LIST  , NULL },
837 #endif
838    { "EFFECTIVE_URL"          ,CURLINFO_EFFECTIVE_URL          ,RXCURLINFO_STRING, NULL },
839    { "FILE_TIME"              ,CURLINFO_FILETIME               ,RXCURLINFO_LONG  , NULL },
840 #if LIBCURL_VERSION_NUM >= 0x070f04
841    { "FTP_ENTRY_PATH"         ,CURLINFO_FTP_ENTRY_PATH         ,RXCURLINFO_STRING, NULL },
842 #endif
843    { "HEADER_SIZE"            ,CURLINFO_HEADER_SIZE            ,RXCURLINFO_LONG  , NULL },
844 #if LIBCURL_VERSION_NUM >= 0x070a08
845    { "HTTPAUTH_AVAIL"         ,CURLINFO_HTTPAUTH_AVAIL         ,RXCURLINFO_BITMAP, NULL },
846 #endif
847 #if LIBCURL_VERSION_NUM >= 0x070a07
848    { "HTTP_CODE"              ,CURLINFO_RESPONSE_CODE          ,RXCURLINFO_LONG  , "RESPONSE_CODE" },
849 #else
850    { "HTTP_CODE"              ,CURLINFO_HTTP_CODE              ,RXCURLINFO_LONG  , NULL },
851 #endif
852    { "HTTP_CONNECTCODE"       ,CURLINFO_HTTP_CONNECTCODE       ,RXCURLINFO_LONG  , NULL },
853 #if LIBCURL_VERSION_NUM >= 0x070f02
854    { "LASTSOCKET"             ,CURLINFO_LASTSOCKET             ,RXCURLINFO_LONG  , NULL },
855 #endif
856 #if LIBCURL_VERSION_NUM >= 0x071500
857    { "LOCAL_IP"               ,CURLINFO_LOCAL_IP               ,RXCURLINFO_STRING, NULL },
858 #endif
859 #if LIBCURL_VERSION_NUM >= 0x071500
860    { "LOCAL_PORT"             ,CURLINFO_LOCAL_PORT             ,RXCURLINFO_LONG  , NULL },
861 #endif
862    { "NAMELOOKUP_TIME"        ,CURLINFO_NAMELOOKUP_TIME        ,RXCURLINFO_DOUBLE, NULL },
863 #if LIBCURL_VERSION_NUM >= 0x070c03
864    { "NUM_CONNECTS"           ,CURLINFO_NUM_CONNECTS           ,RXCURLINFO_LONG  , NULL },
865 #endif
866 #if LIBCURL_VERSION_NUM >= 0x070c02
867    { "OS_ERRNO"               ,CURLINFO_OS_ERRNO               ,RXCURLINFO_LONG  , NULL },
868 #endif
869    { "PRETRANSFER_TIME"       ,CURLINFO_PRETRANSFER_TIME       ,RXCURLINFO_DOUBLE, NULL },
870 #if LIBCURL_VERSION_NUM >= 0x071300
871    { "PRIMARY_IP"             ,CURLINFO_PRIMARY_IP             ,RXCURLINFO_STRING, NULL },
872 #endif
873 #if LIBCURL_VERSION_NUM >= 0x071500
874    { "PRIMARY_PORT"           ,CURLINFO_PRIMARY_PORT           ,RXCURLINFO_LONG  , NULL },
875 #endif
876 #if LIBCURL_VERSION_NUM >= 0x070a03
877    { "PRIVATE"                ,CURLINFO_PRIVATE                ,RXCURLINFO_STRING, NULL },
878 #endif
879 #if LIBCURL_VERSION_NUM >= 0x070a08
880    { "PROXYAUTH_AVAIL"        ,CURLINFO_PROXYAUTH_AVAIL        ,RXCURLINFO_BITMAP, NULL },
881 #endif
882 #if LIBCURL_VERSION_NUM >= 0x070907
883    { "REDIRECT_COUNT"         ,CURLINFO_REDIRECT_COUNT         ,RXCURLINFO_LONG  , NULL },
884    { "REDIRECT_TIME"          ,CURLINFO_REDIRECT_TIME          ,RXCURLINFO_DOUBLE, NULL },
885 #endif
886 #if LIBCURL_VERSION_NUM >= 0x071202
887    { "REDIRECT_URL"           ,CURLINFO_REDIRECT_URL           ,RXCURLINFO_STRING, NULL },
888 #endif
889    { "REQUEST_SIZE"           ,CURLINFO_REQUEST_SIZE           ,RXCURLINFO_LONG  , NULL },
890 #if LIBCURL_VERSION_NUM >= 0x070a08
891    { "RESPONSE_CODE"          ,CURLINFO_RESPONSE_CODE          ,RXCURLINFO_LONG  , NULL },
892 #endif
893 #if LIBCURL_VERSION_NUM >= 0x071400
894    { "RTSP_CLIENT_CSEQ"       ,CURLINFO_RTSP_CLIENT_CSEQ       ,RXCURLINFO_LONG  , NULL },
895    { "RTSP_CSEQ_RECV"         ,CURLINFO_RTSP_CSEQ_RECV         ,RXCURLINFO_LONG  , NULL },
896    { "RTSP_SERVER_CSEQ"       ,CURLINFO_RTSP_SERVER_CSEQ       ,RXCURLINFO_LONG  , NULL },
897    { "RTSP_SESSION_ID"        ,CURLINFO_RTSP_SESSION_ID        ,RXCURLINFO_STRING, NULL },
898 #endif
899    { "SIZE_DOWNLOAD"          ,CURLINFO_SIZE_DOWNLOAD          ,RXCURLINFO_DOUBLE, NULL },
900    { "SIZE_UPLOAD"            ,CURLINFO_SIZE_UPLOAD            ,RXCURLINFO_DOUBLE, NULL },
901    { "SPEED_DOWNLOAD"         ,CURLINFO_SPEED_DOWNLOAD         ,RXCURLINFO_DOUBLE, NULL },
902    { "SPEED_UPLOAD"           ,CURLINFO_SPEED_UPLOAD           ,RXCURLINFO_DOUBLE, NULL },
903 #if LIBCURL_VERSION_NUM >= 0x070c03
904    { "SSL_ENGINES"            ,CURLINFO_SSL_ENGINES            ,RXCURLINFO_LIST  , NULL },
905 #endif
906    { "SSL_VERIFYRESULT"       ,CURLINFO_SSL_VERIFYRESULT       ,RXCURLINFO_LONG  , NULL },
907 #if LIBCURL_VERSION_NUM >= 0x070a02
908    { "STARTTRANSFER_TIME"     ,CURLINFO_STARTTRANSFER_TIME     ,RXCURLINFO_DOUBLE, NULL },
909 #endif
910    { "TOTAL_TIME"             ,CURLINFO_TOTAL_TIME             ,RXCURLINFO_DOUBLE, NULL },
911    { NULL                     ,0                               ,0                , NULL }
912 };
913 
914 static curl_options RexxCurlSubOptions[] =
915 {
916    { "OLDEST"                 ,CURLCLOSEPOLICY_OLDEST             ,RXCURLOPT_POLICY , NULL },
917    { "LEAST_RECENTLY_USED"    ,CURLCLOSEPOLICY_LEAST_RECENTLY_USED,RXCURLOPT_POLICY , NULL },
918    { "LEAST_TRAFFIC"          ,CURLCLOSEPOLICY_LEAST_TRAFFIC      ,RXCURLOPT_POLICY , NULL },
919    { "SLOWEST"                ,CURLCLOSEPOLICY_SLOWEST            ,RXCURLOPT_POLICY , NULL },
920    { "CALLBACK"               ,CURLCLOSEPOLICY_CALLBACK           ,RXCURLOPT_POLICY , NULL },
921    { "NONE"                   ,CURL_HTTP_VERSION_NONE             ,RXCURLOPT_HTTP_VERSION , NULL },
922    { "VERSION_1_0"            ,CURL_HTTP_VERSION_1_0              ,RXCURLOPT_HTTP_VERSION , NULL },
923    { "VERSION_1_1"            ,CURL_HTTP_VERSION_1_1              ,RXCURLOPT_HTTP_VERSION , NULL },
924 #if LIBCURL_VERSION_NUM >= 0x070a08
925    { "OPTIONAL"               ,CURL_NETRC_OPTIONAL                ,RXCURLOPT_NETRC , NULL },
926    { "IGNORED"                ,CURL_NETRC_IGNORED                 ,RXCURLOPT_NETRC , NULL },
927    { "REQUIRED"               ,CURL_NETRC_REQUIRED                ,RXCURLOPT_NETRC , NULL },
928 #endif
929    { "IFMODSINCE"             ,CURL_TIMECOND_IFMODSINCE           ,RXCURLOPT_TIMECOND , NULL },
930    { "IFUNMODSINCE"           ,CURL_TIMECOND_IFUNMODSINCE         ,RXCURLOPT_TIMECOND , NULL },
931    { "LASTMOD"                ,CURL_TIMECOND_LASTMOD              ,RXCURLOPT_TIMECOND , NULL },
932 #if LIBCURL_VERSION_NUM >= 0x070a02
933    { "HTTP"                   ,CURLPROXY_HTTP                     ,RXCURLOPT_PROXYTYPE , NULL },
934    { "SOCKS4"                 ,CURLPROXY_SOCKS4                   ,RXCURLOPT_PROXYTYPE , NULL },
935    { "SOCKS5"                 ,CURLPROXY_SOCKS5                   ,RXCURLOPT_PROXYTYPE , NULL },
936 #endif
937 #if LIBCURL_VERSION_NUM >= 0x071304
938    { "HTTP_1_0"               ,CURLPROXY_HTTP_1_0                 ,RXCURLOPT_PROXYTYPE , NULL },
939 #endif
940 #if LIBCURL_VERSION_NUM >= 0x071200
941    { "SOCKS4A"                ,CURLPROXY_SOCKS4A                  ,RXCURLOPT_PROXYTYPE , NULL },
942    { "SOCKS5_HOSTNAME"        ,CURLPROXY_SOCKS5_HOSTNAME          ,RXCURLOPT_PROXYTYPE , NULL },
943 #endif
944 #if LIBCURL_VERSION_NUM >= 0x070a08
945    { "WHATEVER"               ,CURL_IPRESOLVE_WHATEVER            ,RXCURLOPT_IPRESOLVE , NULL },
946    { "V4"                     ,CURL_IPRESOLVE_V4                  ,RXCURLOPT_IPRESOLVE , NULL },
947    { "V6"                     ,CURL_IPRESOLVE_V6                  ,RXCURLOPT_IPRESOLVE , NULL },
948    { "IPRESOLVE_WHATEVER"     ,CURL_IPRESOLVE_WHATEVER            ,RXCURLOPT_IPRESOLVE , "WHATEVER" },
949    { "IPRESOLVE_V4"           ,CURL_IPRESOLVE_V4                  ,RXCURLOPT_IPRESOLVE , "V4"       },
950    { "IPRESOLVE_V6"           ,CURL_IPRESOLVE_V6                  ,RXCURLOPT_IPRESOLVE , "V6"       },
951 #endif
952 #if LIBCURL_VERSION_NUM >= 0x070a06
953    { "BASIC"                  ,CURLAUTH_BASIC                     ,RXCURLOPT_BITMAP_AUTH , NULL },
954    { "DIGEST"                 ,CURLAUTH_DIGEST                    ,RXCURLOPT_BITMAP_AUTH , NULL },
955    { "AUTH_BASIC"             ,CURLAUTH_BASIC                     ,RXCURLOPT_BITMAP_AUTH , "BASIC"  },
956    { "AUTH_DIGEST"            ,CURLAUTH_DIGEST                    ,RXCURLOPT_BITMAP_AUTH , "DIGEST" },
957 # if LIBCURL_VERSION_NUM >= 0x071303
958    { "DIGEST_IE"              ,CURLAUTH_DIGEST_IE                 ,RXCURLOPT_BITMAP_AUTH , NULL },
959 # endif
960    { "GSSNEGOTIATE"           ,CURLAUTH_GSSNEGOTIATE              ,RXCURLOPT_BITMAP_AUTH , NULL },
961    { "NTLM"                   ,CURLAUTH_NTLM                      ,RXCURLOPT_BITMAP_AUTH , NULL },
962    { "AUTH_GSSNEGOTIATE"      ,CURLAUTH_GSSNEGOTIATE              ,RXCURLOPT_BITMAP_AUTH , "GSSNEGOTIATE" },
963    { "AUTH_NTLM"              ,CURLAUTH_NTLM                      ,RXCURLOPT_BITMAP_AUTH , "NTLM"         },
964 # if LIBCURL_VERSION_NUM >= 0x071600
965    { "NTLM_WB"                ,CURLAUTH_NTLM_WB                   ,RXCURLOPT_BITMAP_AUTH , NULL },
966 # endif
967    { "ANY"                    ,CURLAUTH_ANY                       ,RXCURLOPT_BITMAP_AUTH , NULL },
968    { "ANYSAFE"                ,CURLAUTH_ANYSAFE                   ,RXCURLOPT_BITMAP_AUTH , NULL },
969    { "AUTH_ANY"               ,CURLAUTH_ANY                       ,RXCURLOPT_BITMAP_AUTH , "ANY"     },
970    { "AUTH_ANYSAFE"           ,CURLAUTH_ANYSAFE                   ,RXCURLOPT_BITMAP_AUTH , "ANYSAFE" },
971 #endif
972 # if LIBCURL_VERSION_NUM >= 0x071503
973    { "ONLY"                   ,CURLAUTH_ONLY                      ,RXCURLOPT_BITMAP_AUTH , NULL },
974    { "AUTH_ONLY"              ,CURLAUTH_ONLY                      ,RXCURLOPT_BITMAP_AUTH , "ONLY" },
975 #endif
976 #if LIBCURL_VERSION_NUM >= 0x071001
977    { "PUBLICKEY"              ,CURLSSH_AUTH_PUBLICKEY             ,RXCURLOPT_BITMAP_SSHAUTH , NULL },
978    { "PASSWORD"               ,CURLSSH_AUTH_PASSWORD              ,RXCURLOPT_BITMAP_SSHAUTH , NULL },
979    { "HOST"                   ,CURLSSH_AUTH_HOST                  ,RXCURLOPT_BITMAP_SSHAUTH , NULL },
980    { "KEYBOARD"               ,CURLSSH_AUTH_KEYBOARD              ,RXCURLOPT_BITMAP_SSHAUTH , NULL },
981    { "ANY"                    ,CURLSSH_AUTH_ANY                   ,RXCURLOPT_BITMAP_SSHAUTH , NULL },
982    { "AUTH_PUBLICKEY"         ,CURLSSH_AUTH_PUBLICKEY             ,RXCURLOPT_BITMAP_SSHAUTH , "PUBLICKEY" },
983    { "AUTH_PASSWORD"          ,CURLSSH_AUTH_PASSWORD              ,RXCURLOPT_BITMAP_SSHAUTH , "PASSWORD"  },
984    { "AUTH_HOST"              ,CURLSSH_AUTH_HOST                  ,RXCURLOPT_BITMAP_SSHAUTH , "HOST"      },
985    { "AUTH_KEYBOARD"          ,CURLSSH_AUTH_KEYBOARD              ,RXCURLOPT_BITMAP_SSHAUTH , "KEYBOARD"  },
986    { "AUTH_ANY"               ,CURLSSH_AUTH_ANY                   ,RXCURLOPT_BITMAP_SSHAUTH , "ANY"       },
987 #endif
988 #if LIBCURL_VERSION_NUM >= 0x070b00
989 # if LIBCURL_VERSION_NUM >= 0x071100
990    { "NONE"                   ,CURLUSESSL_NONE                    ,RXCURLOPT_FTPSSL , NULL },
991    { "TRY"                    ,CURLUSESSL_TRY                     ,RXCURLOPT_FTPSSL , NULL },
992    { "CONTROL"                ,CURLUSESSL_CONTROL                 ,RXCURLOPT_FTPSSL , NULL },
993    { "ALL"                    ,CURLUSESSL_ALL                     ,RXCURLOPT_FTPSSL , NULL },
994 # else
995    { "NONE"                   ,CURLFTPSSL_NONE                    ,RXCURLOPT_FTPSSL , NULL },
996    { "TRY"                    ,CURLFTPSSL_TRY                     ,RXCURLOPT_FTPSSL , NULL },
997    { "CONTROL"                ,CURLFTPSSL_CONTROL                 ,RXCURLOPT_FTPSSL , NULL },
998    { "ALL"                    ,CURLFTPSSL_ALL                     ,RXCURLOPT_FTPSSL , NULL },
999 # endif
1000 #endif
1001 #if LIBCURL_VERSION_NUM >= 0x070c02
1002    { "DEFAULT"                ,CURLFTPAUTH_DEFAULT                ,RXCURLOPT_FTPSSLAUTH , NULL },
1003    { "SSL"                    ,CURLFTPAUTH_SSL                    ,RXCURLOPT_FTPSSLAUTH , NULL },
1004    { "TLS"                    ,CURLFTPAUTH_TLS                    ,RXCURLOPT_FTPSSLAUTH , NULL },
1005 #endif
1006 #if LIBCURL_VERSION_NUM >= 0x071001
1007    { "NONE"                   ,CURLFTPSSL_CCC_NONE                ,RXCURLOPT_FTPSSLCCC , NULL },
1008    { "PASSIVE"                ,CURLFTPSSL_CCC_PASSIVE             ,RXCURLOPT_FTPSSLCCC , NULL },
1009    { "ACTIVE"                 ,CURLFTPSSL_CCC_ACTIVE              ,RXCURLOPT_FTPSSLCCC , NULL },
1010 #endif
1011 #if LIBCURL_VERSION_NUM >= 0x071304
1012    { "CREATE_DIR_NONE"        ,CURLFTP_CREATE_DIR_NONE            ,RXCURLOPT_FTP_CREATE_MISSING_DIRS , NULL },
1013    { "CREATE_DIR"             ,CURLFTP_CREATE_DIR                 ,RXCURLOPT_FTP_CREATE_MISSING_DIRS , NULL },
1014    { "CREATE_DIR_RETRY"       ,CURLFTP_CREATE_DIR_RETRY           ,RXCURLOPT_FTP_CREATE_MISSING_DIRS , NULL },
1015 #endif
1016 #if LIBCURL_VERSION_NUM >= 0x071400
1017    { "OPTIONS "              ,CURL_RTSPREQ_ANNOUNCE              ,RXCURLOPT_RTSP_REQUEST , NULL },
1018    { "DESCRIBE"              ,CURL_RTSPREQ_SETUP                 ,RXCURLOPT_RTSP_REQUEST , NULL },
1019    { "ANNOUNCE"              ,CURL_RTSPREQ_PLAY                  ,RXCURLOPT_RTSP_REQUEST , NULL },
1020    { "SETUP"                 ,CURL_RTSPREQ_PAUSE                 ,RXCURLOPT_RTSP_REQUEST , NULL },
1021    { "PLAY"                  ,CURL_RTSPREQ_TEARDOWN              ,RXCURLOPT_RTSP_REQUEST , NULL },
1022    { "PAUSE"                 ,CURL_RTSPREQ_GET_PARAMETER         ,RXCURLOPT_RTSP_REQUEST , NULL },
1023    { "TEARDOWN"              ,CURL_RTSPREQ_SET_PARAMETER         ,RXCURLOPT_RTSP_REQUEST , NULL },
1024    { "GET_PARAMETER"         ,CURL_RTSPREQ_RECORD                ,RXCURLOPT_RTSP_REQUEST , NULL },
1025    { "SET_PARAMETER"         ,CURL_RTSPREQ_RECEIVE               ,RXCURLOPT_RTSP_REQUEST , NULL },
1026 #endif
1027 #if LIBCURL_VERSION_NUM >= 0x071304
1028    { "ALL"                    ,CURLPROTO_ALL                      ,RXCURLOPT_PROTOCOLS    , NULL },
1029    { "HTTP"                   ,CURLPROTO_HTTP                     ,RXCURLOPT_PROTOCOLS    , NULL },
1030    { "HTTPS"                  ,CURLPROTO_HTTPS                    ,RXCURLOPT_PROTOCOLS    , NULL },
1031    { "FTP"                    ,CURLPROTO_FTP                      ,RXCURLOPT_PROTOCOLS    , NULL },
1032    { "FTPS"                   ,CURLPROTO_FTPS                     ,RXCURLOPT_PROTOCOLS    , NULL },
1033    { "SCP"                    ,CURLPROTO_SCP                      ,RXCURLOPT_PROTOCOLS    , NULL },
1034    { "SFTP"                   ,CURLPROTO_SFTP                     ,RXCURLOPT_PROTOCOLS    , NULL },
1035    { "TELNET"                 ,CURLPROTO_TELNET                   ,RXCURLOPT_PROTOCOLS    , NULL },
1036    { "LDAP"                   ,CURLPROTO_LDAP                     ,RXCURLOPT_PROTOCOLS    , NULL },
1037    { "LDAPS"                  ,CURLPROTO_LDAPS                    ,RXCURLOPT_PROTOCOLS    , NULL },
1038    { "DICT"                   ,CURLPROTO_DICT                     ,RXCURLOPT_PROTOCOLS    , NULL },
1039    { "FILE"                   ,CURLPROTO_FILE                     ,RXCURLOPT_PROTOCOLS    , NULL },
1040    { "TFTP"                   ,CURLPROTO_TFTP                     ,RXCURLOPT_PROTOCOLS    , NULL },
1041 #endif
1042 # if LIBCURL_VERSION_NUM >= 0x071400
1043    { "IMAP"                   ,CURLPROTO_IMAP                     ,RXCURLOPT_PROTOCOLS    , NULL },
1044    { "IMAPS"                  ,CURLPROTO_IMAPS                    ,RXCURLOPT_PROTOCOLS    , NULL },
1045    { "POP3"                   ,CURLPROTO_POP3                     ,RXCURLOPT_PROTOCOLS    , NULL },
1046    { "POP3S"                  ,CURLPROTO_POP3S                    ,RXCURLOPT_PROTOCOLS    , NULL },
1047    { "SMTP"                   ,CURLPROTO_SMTP                     ,RXCURLOPT_PROTOCOLS    , NULL },
1048    { "SMTPS"                  ,CURLPROTO_SMTPS                    ,RXCURLOPT_PROTOCOLS    , NULL },
1049    { "RTSP"                   ,CURLPROTO_RTSP                     ,RXCURLOPT_PROTOCOLS    , NULL },
1050 #endif
1051 #if LIBCURL_VERSION_NUM >= 0x071600
1052    { "FLAG"                   ,CURLGSSAPI_DELEGATION_FLAG         ,RXCURLOPT_GSSAPI_DELEGATION , NULL },
1053    { "NONE"                   ,CURLGSSAPI_DELEGATION_NONE         ,RXCURLOPT_GSSAPI_DELEGATION , NULL },
1054    { "POLICY_FLAG"            ,CURLGSSAPI_DELEGATION_POLICY_FLAG  ,RXCURLOPT_GSSAPI_DELEGATION , NULL },
1055 #endif
1056 #if LIBCURL_VERSION_NUM >= 0x071900
1057    { "ALLOW_BEAST"            ,CURLSSLOPT_ALLOW_BEAST             ,RXCURLOPT_SSL_OPTIONS  , NULL },
1058 #endif
1059 #if LIBCURL_VERSION_NUM >= 0x072C00
1060    { "NO_REVOKE"              ,CURLSSLOPT_NO_REVOKE               ,RXCURLOPT_SSL_OPTIONS  , NULL },
1061 #endif
1062 #if LIBCURL_VERSION_NUM >= 0x071301
1063    { "GET_ALL"                ,CURL_REDIR_GET_ALL                 ,RXCURLOPT_BITMAP_REDIR , NULL },
1064    { "POST_301"               ,CURL_REDIR_POST_301                ,RXCURLOPT_BITMAP_REDIR , NULL },
1065    { "POST_302"               ,CURL_REDIR_POST_302                ,RXCURLOPT_BITMAP_REDIR , NULL },
1066 # if LIBCURL_VERSION_NUM >= 0x071a00
1067    { "POST_303"               ,CURL_REDIR_POST_303                ,RXCURLOPT_BITMAP_REDIR , NULL },
1068 # endif
1069    { "POST_ALL"               ,CURL_REDIR_POST_ALL                ,RXCURLOPT_BITMAP_REDIR , NULL },
1070 #endif
1071 #if LIBCURL_VERSION_NUM >= 0x071504
1072    { "NONE"                   ,CURL_TLSAUTH_NONE                  ,RXCURLOPT_BITMAP_TLSAUTH,NULL },
1073    { "SRP"                    ,CURL_TLSAUTH_SRP                   ,RXCURLOPT_BITMAP_TLSAUTH,NULL },
1074 #endif
1075    { NULL                     ,0                                  ,0 , NULL }
1076 };
1077 
1078 #define NUMBER_REXXCURL_OPTIONS (sizeof(RexxCurlOptions)/sizeof(curl_options))
1079 static curl_version_info_data *version_info = NULL;
1080 
1081 RxPackageConstantDef RexxCURLConstants[] =
1082 {
1083    { "DIRSEP"   , 1, 0 , FILE_SEPARATOR_STR ,0.0, 0 },
1084    { "KHMATCH_MISMATCH", 0, CURLKHMATCH_MISMATCH, NULL, 0.0, 0 },
1085    { "KHMATCH_MISSING", 0, CURLKHMATCH_MISSING, NULL, 0.0, 0 },
1086    { "KHMATCH_OK", 0, CURLKHMATCH_OK, NULL, 0.0, 0 },
1087    { "KHSTAT_DEFER", 0, CURLKHSTAT_DEFER, NULL, 0.0, 0 },
1088    { "KHSTAT_FINE", 0, CURLKHSTAT_FINE, NULL, 0.0, 0 },
1089    { "KHSTAT_FINE_ADD_TO_FILE", 0, CURLKHSTAT_FINE_ADD_TO_FILE, NULL, 0.0, 0 },
1090    { "KHSTAT_REJECT", 0, CURLKHSTAT_REJECT, NULL, 0.0, 0 },
1091    { "KHTYPE_DSS", 0, CURLKHTYPE_DSS, NULL, 0.0, 0 },
1092    { "KHTYPE_RSA", 0, CURLKHTYPE_RSA, NULL, 0.0, 0 },
1093    { "KHTYPE_RSA1", 0, CURLKHTYPE_RSA1, NULL, 0.0, 0 },
1094    { "KHTYPE_UNKNOWN", 0, CURLKHTYPE_UNKNOWN, NULL, 0.0, 0 },
1095    { "PATHSEP"  , 1, 0 , PATH_SEPARATOR_STR ,0.0, 0 },
1096    { NULL       , 0, 0 , NULL               ,0.0, 0 },
1097 };
1098 
1099 rxfunc( CurlLoadFuncs );
1100 rxfunc( CurlDropFuncs );
1101 rxfunc( CurlInit );
1102 rxfunc( CurlSetopt );
1103 rxfunc( CurlPerform );
1104 rxfunc( CurlGetinfo );
1105 rxfunc( CurlCleanup );
1106 rxfunc( CurlReset );
1107 rxfunc( CurlVariable );
1108 rxfunc( CurlQueryFunction );
1109 rxfunc( CurlFormAdd );
1110 rxfunc( CurlFormFree );
1111 rxfunc( CurlEscape );
1112 rxfunc( CurlUnescape );
1113 
1114 /*-----------------------------------------------------------------------------
1115  * Table of CURL Functions. Used to install/de-install functions.
1116  * If you change this table, don't forget to change the table at the end
1117  * of this file.
1118  *----------------------------------------------------------------------------*/
1119 RexxFunction RexxCURLFunctions[] = {
1120    { "CURLINIT"         ,CurlInit        ,"CurlInit"        , 1  },
1121    { "CURLCLEANUP"      ,CurlCleanup     ,"CurlCleanup"     , 1  },
1122    { "CURLSETOPT"       ,CurlSetopt      ,"CurlSetopt"      , 1  },
1123    { "CURLRESET"        ,CurlReset       ,"CurlReset"       , 1  },
1124    { "CURLPERFORM"      ,CurlPerform     ,"CurlPerform"     , 1  },
1125    { "CURLGETINFO"      ,CurlGetinfo     ,"CurlGetinfo"     , 1  },
1126    { "CURLVARIABLE"     ,CurlVariable    ,"CurlVariable"    , 1  },
1127    { "CURLQUERYFUNCTION",CurlQueryFunction,"CurlQueryFunction", 1  },
1128    { "CURLFORMADD"      ,CurlFormAdd     ,"CurlFormAdd"     , 1  },
1129    { "CURLFORMFREE"     ,CurlFormFree    ,"CurlFormFree"    , 1  },
1130    { "CURLESCAPE"       ,CurlEscape      ,"CurlEscape"      , 1  },
1131    { "CURLUNESCAPE"     ,CurlUnescape    ,"CurlUnescape"    , 1  },
1132    { "CURLDROPFUNCS"    ,CurlDropFuncs   ,"CurlDropFuncs"   , 1  },
1133    { "CURLLOADFUNCS"    ,CurlLoadFuncs   ,"CurlLoadFuncs"   , 0  }, /* Don't load for DLL */
1134    { NULL, NULL, NULL,0 }
1135 };
1136 
1137 
1138 #define DEFAULT_REXXCURL_ERROR        "CURLERROR."
1139 #define INTERRM_PREFIX        "INTERRM"
1140 #define INTCODE_PREFIX        "INTCODE"
1141 #define CURLERRM_PREFIX       "CURLERRM"
1142 #define CURLCODE_PREFIX       "CURLCODE"
1143 
1144 typedef struct
1145 {
1146    RxPackageGlobalDataDef *RxPackageGlobalData;
1147    RXSTRING str; /* str.strlength identifies how many bytes remaining */
1148    unsigned long index; /* where to start copying data from */
1149 } instem_option;
1150 
1151 typedef struct
1152 {
1153    int g_rexxcurl_error;
1154    CURLcode g_curl_error;
1155    char curl_error[CURL_ERROR_SIZE+1];
1156    char rexxcurl_error_prefix[350];
1157    int outstem_index;
1158    int outstem_tail;
1159    char *outstem_strptr;
1160    char *outstem_line_terminator;
1161    int outstem_strlength;
1162    int headerstem_index;
1163    int headerstem_tail;
1164    int progress_index;
1165    rx_long_long max_long;
1166    char UsedOptions[NUMBER_REXXCURL_OPTIONS];
1167    FILE *FilePtrs[NUMBER_REXXCURL_OPTIONS];
1168    char *StringPtrs[NUMBER_REXXCURL_OPTIONS];
1169    instem_option *instem_options[NUMBER_REXXCURL_OPTIONS];
1170    struct curl_slist *SListPtrs[NUMBER_REXXCURL_OPTIONS];
1171    struct curl_httppost *HttpPostFirstPtrs[NUMBER_REXXCURL_OPTIONS];
1172    struct curl_httppost *HttpPostLastPtrs[NUMBER_REXXCURL_OPTIONS];
1173    RxPackageGlobalDataDef *RxPackageGlobalData;
1174 } REXXCURLDATA;
1175 
1176 static int have_rexxcallback = API_REXXCALLBACK_MISSING;
1177 static int g_global_init_called = 0;
1178 
1179 /*
1180  * If we don't have the RexxFreeMemory() API, then emulate it
1181  */
1182 #ifndef REXXFREEMEMORY
RexxFreeMemory(PVOID ptr)1183 static APIRET APIENTRY RexxFreeMemory( PVOID ptr )
1184 {
1185 #if defined( WIN32 )
1186    GlobalFree( ptr );
1187 #elif defined( __OS2__ )
1188    DosFreeMem( ptr );
1189 #else
1190    free( ptr );
1191 #endif
1192    return 0;
1193 }
1194 # define REXXFREEMEMORY
1195 #endif
1196 
1197 /*
1198  * If we don't have the RexxAllocateMemory() API, then emulate it
1199  */
1200 #ifndef REXXALLOCATEMEMORY
RexxAllocateMemory(ULONG size)1201 static PVOID APIENTRY RexxAllocateMemory( ULONG size )
1202 {
1203    PVOID ret;
1204 # if defined( WIN32 )
1205    ret = (PVOID)( GlobalLock( GlobalAlloc ( GMEM_FIXED, size ) ) );
1206    return ret;
1207 # elif defined( __OS2__ )
1208    if ( ( BOOL )DosAllocMem( &ret, size, fPERM|PAG_COMMIT ) )
1209       return NULL;
1210    else
1211       return ret;
1212 # else
1213    ret = (PVOID)malloc( size );
1214    return ret;
1215 # endif
1216 }
1217 # define REXXALLOCATEMEMORY
1218 #endif
1219 
1220 #if defined(WIN32)
1221 static CURLcode win32_init(void);
1222 static void win32_cleanup(void);
1223 
RexxCURLLoadCURL()1224 void RexxCURLLoadCURL()
1225 {
1226    char LoadError[256];
1227    if ( handle == NULL )
1228    {
1229       handle = LoadLibrary( REXXCURL_LIBCURL_DLL_NAME ) ;
1230       if ( handle == NULL )
1231       {
1232          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1233          fprintf( stderr, "Failed to load cURL dll \"%s\": LoadLibrary() failed: ", REXXCURL_LIBCURL_DLL_NAME  );
1234          exit(1);
1235       }
1236 
1237       p_curl_easy_init = (T_CURL_EASY_INIT *)GetProcAddress( (HMODULE)handle, "curl_easy_init" );
1238       if ( p_curl_easy_init == NULL )
1239       {
1240          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1241          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: %s", "curl_easy_init", LoadError );
1242          exit(1);
1243       }
1244       p_curl_easy_setopt = (T_CURL_EASY_SETOPT *)GetProcAddress( (HMODULE)handle, "curl_easy_setopt" );
1245       if ( p_curl_easy_setopt == NULL )
1246       {
1247          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1248          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_easy_setopt" );
1249          exit(1);
1250       }
1251       p_curl_easy_reset = (T_CURL_EASY_SETOPT *)GetProcAddress( (HMODULE)handle, "curl_easy_reset" );
1252       if ( p_curl_easy_reset == NULL )
1253       {
1254          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1255          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_easy_reset" );
1256          exit(1);
1257       }
1258       p_curl_easy_getinfo = (T_CURL_EASY_GETINFO *)GetProcAddress( (HMODULE)handle, "curl_easy_getinfo" );
1259       if ( p_curl_easy_getinfo == NULL )
1260       {
1261          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1262          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_easy_getinfo" );
1263          exit(1);
1264       }
1265       p_curl_easy_perform = (T_CURL_EASY_PERFORM *)GetProcAddress( (HMODULE)handle, "curl_easy_perform" );
1266       if ( p_curl_easy_perform == NULL )
1267       {
1268          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1269          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_easy_perform" );
1270          exit(1);
1271       }
1272       p_curl_easy_cleanup = (T_CURL_EASY_CLEANUP *)GetProcAddress( (HMODULE)handle, "curl_easy_cleanup" );
1273       if ( p_curl_easy_cleanup == NULL )
1274       {
1275          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1276          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_easy_cleanup" );
1277          exit(1);
1278       }
1279       p_curl_formadd = (T_CURL_FORMADD *)GetProcAddress( (HMODULE)handle, "curl_formadd" );
1280       if ( p_curl_formadd == NULL )
1281       {
1282          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1283          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_formadd" );
1284          exit(1);
1285       }
1286       p_curl_formfree = (T_CURL_FORMFREE *)GetProcAddress( (HMODULE)handle, "curl_formfree" );
1287       if ( p_curl_formfree == NULL )
1288       {
1289          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1290          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_formfree" );
1291          exit(1);
1292       }
1293       p_curl_global_init = (T_CURL_GLOBAL_INIT *)GetProcAddress( (HMODULE)handle, "curl_global_init" );
1294       if ( p_curl_global_init == NULL )
1295       {
1296          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1297          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_global_init" );
1298          exit(1);
1299       }
1300       p_curl_global_cleanup = (T_CURL_GLOBAL_CLEANUP *)GetProcAddress( (HMODULE)handle, "curl_global_cleanup" );
1301       if ( p_curl_global_cleanup == NULL )
1302       {
1303          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1304          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_global_cleanup" );
1305          exit(1);
1306       }
1307       p_curl_slist_append = (T_CURL_SLIST_APPEND *)GetProcAddress( (HMODULE)handle, "curl_slist_append" );
1308       if ( p_curl_slist_append == NULL )
1309       {
1310          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1311          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_slist_append" );
1312          exit(1);
1313       }
1314       p_curl_slist_free_all = (T_CURL_SLIST_FREE_ALL *)GetProcAddress( (HMODULE)handle, "curl_slist_free_all" );
1315       if ( p_curl_slist_free_all == NULL )
1316       {
1317          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1318          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_slist_free_all" );
1319          exit(1);
1320       }
1321       p_curl_version = (T_CURL_VERSION *)GetProcAddress( (HMODULE)handle, "curl_version" );
1322       if ( p_curl_version == NULL )
1323       {
1324          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1325          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_version" );
1326          exit(1);
1327       }
1328       p_curl_version_info = (T_CURL_VERSION_INFO *)GetProcAddress( (HMODULE)handle, "curl_version_info" );
1329       if ( p_curl_version_info == NULL )
1330       {
1331          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1332          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_version_info" );
1333          exit(1);
1334       }
1335       p_curl_easy_escape = (T_CURL_EASY_ESCAPE *)GetProcAddress( (HMODULE)handle, "curl_easy_escape" );
1336       if ( p_curl_easy_escape == NULL )
1337       {
1338          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1339          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_easy_escape" );
1340          exit(1);
1341       }
1342       p_curl_easy_unescape = (T_CURL_EASY_UNESCAPE *)GetProcAddress( (HMODULE)handle, "curl_easy_unescape" );
1343       if ( p_curl_easy_unescape == NULL )
1344       {
1345          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1346          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_easy_unescape" );
1347          exit(1);
1348       }
1349       p_curl_free = (T_CURL_FREE *)GetProcAddress( (HMODULE)handle, "curl_free" );
1350       if ( p_curl_free == NULL )
1351       {
1352          FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
1353          fprintf( stderr, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", "curl_free" );
1354          exit(1);
1355       }
1356    }
1357 }
1358 
RexxCURLUnloadCURL(void)1359 void RexxCURLUnloadCURL(void)
1360 {
1361    if ( handle )
1362    {
1363       FreeLibrary( handle );
1364       handle = NULL;
1365    }
1366 }
1367 #endif
1368 
RexxCURLSetVersionInfoConstants(RxPackageGlobalDataDef * RxPackageGlobalData)1369 void RexxCURLSetVersionInfoConstants( RxPackageGlobalDataDef *RxPackageGlobalData )
1370 {
1371    const char * const*prot;
1372    char name[350];
1373    char value[100];
1374    char *support;
1375    int namelen;
1376    int valuelen;
1377    int count;
1378 
1379    InternalTrace( RxPackageGlobalData, "RexxCURLSetVersionInfoConstants", NULL );
1380 
1381    namelen = sprintf( name, "%sVERSION", RxGetConstantPrefix( RxPackageGlobalData ) );
1382    SetRexxVariable( RxPackageGlobalData, name, namelen, (char *)version_info->version, (version_info->version) ? strlen( version_info->version ) : 0 );
1383    namelen = sprintf( name, "%sVERSION_NUM", RxGetConstantPrefix( RxPackageGlobalData ) );
1384    valuelen = sprintf( value, "%d", version_info->version_num );
1385    SetRexxVariable( RxPackageGlobalData, name, namelen, value, valuelen );
1386 
1387    namelen = sprintf( name, "%sHOST", RxGetConstantPrefix( RxPackageGlobalData ) );
1388    SetRexxVariable( RxPackageGlobalData, name, namelen, (char *)version_info->host, (version_info->host) ? strlen( version_info->host ) : 0 );
1389 
1390    namelen = sprintf( name, "%sSSL_VERSION", RxGetConstantPrefix( RxPackageGlobalData ) );
1391    SetRexxVariable( RxPackageGlobalData, name, namelen, (char *)version_info->ssl_version, (version_info->ssl_version) ? strlen( version_info->ssl_version ) : 0 );
1392 
1393    namelen = sprintf( name, "%sLIBZ_VERSION", RxGetConstantPrefix( RxPackageGlobalData ) );
1394    SetRexxVariable( RxPackageGlobalData, name, namelen, (char *)version_info->libz_version, (version_info->libz_version) ? strlen( version_info->libz_version ) : 0 );
1395 
1396    namelen = sprintf( name, "%sARES", RxGetConstantPrefix( RxPackageGlobalData ) );
1397    SetRexxVariable( RxPackageGlobalData, name, namelen, (char *)version_info->ares, (version_info->ares) ? strlen( version_info->ares ) : 0 );
1398    namelen = sprintf( name, "%sARES_NUM", RxGetConstantPrefix( RxPackageGlobalData ) );
1399    valuelen = sprintf( value, "%d", version_info->ares_num );
1400    SetRexxVariable( RxPackageGlobalData, name, namelen, value, valuelen );
1401 
1402    namelen = sprintf( name, "%sLIBIDN", RxGetConstantPrefix( RxPackageGlobalData ) );
1403    SetRexxVariable( RxPackageGlobalData, name, namelen, (char *)version_info->libidn, (version_info->libidn) ? strlen( version_info->libidn ) : 0 );
1404 
1405    support = "";
1406    valuelen = 0;
1407    namelen = sprintf( name, "%sLIBSSH_VERSION", RxGetConstantPrefix( RxPackageGlobalData ) );
1408 #if LIBCURL_VERSION_NUM >= 0x071001
1409    support = (char *)version_info->libssh_version;
1410    valuelen = (version_info->libssh_version) ? strlen( version_info->libssh_version ) : 0;
1411 #endif
1412    SetRexxVariable( RxPackageGlobalData, name, namelen, support, valuelen );
1413 
1414    namelen = sprintf( name, "%sICONV_VER_NUM", RxGetConstantPrefix( RxPackageGlobalData ) );
1415    support = "0";
1416    valuelen = 1;
1417 #if LIBCURL_VERSION_NUM >= 0x070e05
1418    valuelen = sprintf( value, "%d", version_info->iconv_ver_num );
1419    support = value;
1420 #endif
1421    SetRexxVariable( RxPackageGlobalData, name, namelen, support, valuelen );
1422    /*
1423     * Determine supported features
1424     */
1425    namelen = sprintf( name, "%sSUPPORTS_IPV6", RxGetConstantPrefix( RxPackageGlobalData ) );
1426    SetRexxVariable( RxPackageGlobalData, name, namelen, ( version_info->features & CURL_VERSION_IPV6 ) ? "1" : "0", 1 );
1427    namelen = sprintf( name, "%sSUPPORTS_KERBEROS4", RxGetConstantPrefix( RxPackageGlobalData ) );
1428    SetRexxVariable( RxPackageGlobalData, name, namelen, ( version_info->features & CURL_VERSION_KERBEROS4 ) ? "1" : "0", 1 );
1429 
1430    namelen = sprintf( name, "%sSUPPORTS_SSL", RxGetConstantPrefix( RxPackageGlobalData ) );
1431    support = "0";
1432 #if LIBCURL_VERSION_NUM >= 0x070a00
1433    support = ( version_info->features & CURL_VERSION_SSL ) ? "1" : "0";
1434 #endif
1435    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1436 
1437    namelen = sprintf( name, "%sSUPPORTS_LIBZ", RxGetConstantPrefix( RxPackageGlobalData ) );
1438    support = "0";
1439 #if LIBCURL_VERSION_NUM >= 0x070a00
1440    support = ( version_info->features & CURL_VERSION_LIBZ ) ? "1" : "0";
1441 #endif
1442    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1443 
1444    namelen = sprintf( name, "%sSUPPORTS_NTLM", RxGetConstantPrefix( RxPackageGlobalData ) );
1445    support = "0";
1446 #if LIBCURL_VERSION_NUM >= 0x070a06
1447    support = ( version_info->features & CURL_VERSION_NTLM ) ? "1" : "0";
1448 #endif
1449    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1450 
1451    namelen = sprintf( name, "%sSUPPORTS_GSSNEGOTIATE", RxGetConstantPrefix( RxPackageGlobalData ) );
1452    support = "0";
1453 #if LIBCURL_VERSION_NUM >= 0x070a06
1454    support = ( version_info->features & CURL_VERSION_GSSNEGOTIATE ) ? "1" : "0";
1455 #endif
1456    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1457 
1458    namelen = sprintf( name, "%sSUPPORTS_DEBUG", RxGetConstantPrefix( RxPackageGlobalData ) );
1459    support = "0";
1460 #if LIBCURL_VERSION_NUM >= 0x070a06
1461    support = ( version_info->features & CURL_VERSION_DEBUG ) ? "1" : "0";
1462 #endif
1463    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1464 
1465    namelen = sprintf( name, "%sSUPPORTS_CURLDEBUG", RxGetConstantPrefix( RxPackageGlobalData ) );
1466    support = "0";
1467 #if LIBCURL_VERSION_NUM >= 0x071306
1468    support = ( version_info->features & CURL_VERSION_CURLDEBUG ) ? "1" : "0";
1469 #endif
1470    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1471 
1472    namelen = sprintf( name, "%sSUPPORTS_ASYNCHDNS", RxGetConstantPrefix( RxPackageGlobalData ) );
1473    support = "0";
1474 #if LIBCURL_VERSION_NUM >= 0x070a07
1475    support = ( version_info->features & CURL_VERSION_ASYNCHDNS ) ? "1" : "0";
1476 #endif
1477    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1478 
1479    namelen = sprintf( name, "%sSUPPORTS_SPNEGO", RxGetConstantPrefix( RxPackageGlobalData ) );
1480    support = "0";
1481 #if LIBCURL_VERSION_NUM >= 0x070a08
1482    support = ( version_info->features & CURL_VERSION_SPNEGO ) ? "1" : "0";
1483 #endif
1484    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1485 
1486    namelen = sprintf( name, "%sSUPPORTS_LARGEFILE", RxGetConstantPrefix( RxPackageGlobalData ) );
1487    support = "0";
1488 #if LIBCURL_VERSION_NUM >= 0x070b01
1489    support = ( version_info->features & CURL_VERSION_LARGEFILE ) ? "1" : "0";
1490 #endif
1491    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1492 
1493    namelen = sprintf( name, "%sSUPPORTS_IDN", RxGetConstantPrefix( RxPackageGlobalData ) );
1494    support = "0";
1495 #if LIBCURL_VERSION_NUM >= 0x070c00
1496    support = ( version_info->features & CURL_VERSION_IDN ) ? "1" : "0";
1497 #endif
1498    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1499 
1500    namelen = sprintf( name, "%sSUPPORTS_SSPI", RxGetConstantPrefix( RxPackageGlobalData ) );
1501    support = "0";
1502 #if LIBCURL_VERSION_NUM >= 0x070d02
1503    support = ( version_info->features & CURL_VERSION_SSPI ) ? "1" : "0";
1504 #endif
1505    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1506 
1507    namelen = sprintf( name, "%sSUPPORTS_CONV", RxGetConstantPrefix( RxPackageGlobalData ) );
1508    support = "0";
1509 #if LIBCURL_VERSION_NUM >= 0x070e04
1510    support = ( version_info->features & CURL_VERSION_CONV ) ? "1" : "0";
1511 #endif
1512    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1513 
1514    namelen = sprintf( name, "%sSUPPORTS_TLSAUTH_SRP", RxGetConstantPrefix( RxPackageGlobalData ) );
1515    support = "0";
1516 #if LIBCURL_VERSION_NUM >= 0x071504
1517    support = ( version_info->features & CURL_VERSION_TLSAUTH_SRP ) ? "1" : "0";
1518 #endif
1519    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1520 
1521    namelen = sprintf( name, "%sSUPPORTS_NTLM_WB", RxGetConstantPrefix( RxPackageGlobalData ) );
1522    support = "0";
1523 #if LIBCURL_VERSION_NUM >= 0x071600
1524    support = ( version_info->features & CURL_VERSION_NTLM_WB ) ? "1" : "0";
1525 #endif
1526    SetRexxVariable( RxPackageGlobalData, name, namelen, support, 1 );
1527    /*
1528     * Set supported protocols
1529     */
1530    prot = version_info->protocols;
1531    count = 1;
1532    while ( *prot )
1533    {
1534       namelen = sprintf( name, "%sPROTOCOLS.%d", RxGetConstantPrefix( RxPackageGlobalData ), count );
1535       SetRexxVariable( RxPackageGlobalData, name, namelen, (char *)*prot, strlen( *prot ) );
1536       prot++;
1537       count++;
1538    }
1539    namelen = sprintf( name, "%sPROTOCOLS.0", RxGetConstantPrefix( RxPackageGlobalData ) );
1540    valuelen = sprintf( value, "%d", count-1 );
1541    SetRexxVariable( RxPackageGlobalData, name, namelen, value, valuelen );
1542 }
1543 
1544 /*
1545  * These functions used by loader.c to obtain package-specific info
1546  * There probably is no need for this function at all as the INI EXIT should
1547  * do all the work!  FIX ME
1548  */
RexxCURLInitialiser(RxPackageGlobalDataDef * RxPackageGlobalData)1549 int RexxCURLInitialiser( RxPackageGlobalDataDef *RxPackageGlobalData )
1550 {
1551    InternalTrace( RxPackageGlobalData, "RexxCURLInitialiser", NULL );
1552 #if 0
1553 
1554 #if defined(WIN32)
1555    RexxCURLLoadCURL();
1556 #endif
1557    /*
1558     * Check the version of the library we have loaded at runtime against the version we support;
1559     * not necessarily the version we built with.
1560     * We crash and burn if the version at runtime is < the supported version
1561     */
1562    version_info = CURL_VERSION_INFO(CURLVERSION_NOW);
1563    if ( version_info )
1564    {
1565       if ( version_info->version_num < LIBCURL_SUPPORTED_VERSION )
1566       {
1567          fprintf(stderr,"WARNING! Incompatible version of cURL found. The version of cURL found: %s is less than the supported version: %s.\n", version_info->version, LIBCURL_VERSION );
1568       }
1569       /*
1570        * Set our version info variables
1571        */
1572       RexxCURLSetVersionInfoConstants( RxPackageGlobalData );
1573    }
1574 #endif
1575    return 0;
1576 }
1577 
RexxCURLTerminator(RxPackageGlobalDataDef * RxPackageGlobalData)1578 int RexxCURLTerminator( RxPackageGlobalDataDef *RxPackageGlobalData  )
1579 {
1580    InternalTrace( RxPackageGlobalData , "RexxCURLTerminator", NULL );
1581    CURL_GLOBAL_CLEANUP();
1582 #if defined(WIN32)
1583    RexxCURLUnloadCURL();
1584 //   win32_cleanup();
1585 #endif
1586    return 0;
1587 }
1588 
1589 /*
1590  * Every package MUST have one of these, otherwise ooRexx will crash
1591  */
RexxCURLInitHandler(REH_ARG0_TYPE ExitNum,REH_ARG1_TYPE Subfun,REH_ARG2_TYPE PBlock)1592 REH_RETURN RexxCURLInitHandler( REH_ARG0_TYPE ExitNum, REH_ARG1_TYPE Subfun, REH_ARG2_TYPE PBlock )
1593 {
1594    unsigned long tmp_long;
1595    REXXCURLDATA *RexxCURLData;
1596    /*
1597     * Get thread-safe-data
1598     */
1599    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
1600    InternalTrace(RxPackageGlobalData ,"RexxCURLInitHandler", "ExitNum %ld Subfun %ld",ExitNum, Subfun);
1601 #if defined(WIN32)
1602    /*
1603     * Load the entry points for the libcurl DLL
1604     */
1605    RexxCURLLoadCURL();
1606 #endif
1607    /*
1608     * Determine if the Rexx interpreter has RexxCallBack()
1609     * If USE_REGINA then we have it.
1610     * If USE_REXXTRANS then we MIGHT have it; we need to call RxTransHaveRexxCallBack()
1611     * to check.
1612     * If REXXCALLBACK defined, then we also have it.
1613     * All other situations, we DON'T have it.
1614     * We need to determine this BEFORE calling SetPackageConstants()
1615     */
1616 #if defined( USE_REGINA )
1617    have_rexxcallback = API_REXXCALLBACK_PRESENT;
1618 #elif defined ( USE_REXXTRANS )
1619    if ( RexxTransHaveRexxCallBack() )
1620       have_rexxcallback = API_REXXCALLBACK_PRESENT;
1621 #elif defined( REXXCALLBACK )
1622       have_rexxcallback = API_REXXCALLBACK_PRESENT;
1623 #else
1624    /*
1625     * The default value for HAVE_REXXCALLBACK variable is not set, so we don't have to change anything
1626     */
1627 #endif
1628    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
1629 #if defined(WIN32_NOT_REQUIRED)
1630    if ( win32_init() )
1631       return 1;
1632 #endif
1633    if ( !g_global_init_called )
1634    {
1635       g_global_init_called = 1;
1636       CURL_GLOBAL_INIT(CURL_GLOBAL_ALL);
1637    }
1638    strcpy( RexxCURLData->rexxcurl_error_prefix, DEFAULT_REXXCURL_ERROR );
1639    /*
1640     * Get ourselves the maximum value of an unsigned long into max_long
1641     * to use when determining if we need to use long longs later
1642     */
1643    memset( &tmp_long, 0xFF, sizeof(tmp_long) );
1644    RexxCURLData->max_long = (rx_long_long)(tmp_long/2);
1645    SetPackageConstants( RxPackageGlobalData, RexxCURLConstants, 0 );
1646    /*
1647     * Check the version of the library we have loaded at runtime against the version we support;
1648     * not necessarily the version we built with.
1649     * We crash and burn if the version at runtime is < the supported version
1650     */
1651    version_info = CURL_VERSION_INFO(CURLVERSION_NOW);
1652    if ( version_info )
1653    {
1654       if ( version_info->version_num < LIBCURL_SUPPORTED_VERSION )
1655       {
1656          fprintf(stderr,"WARNING! Incompatible version of cURL found. The version of cURL found: %s is less than the supported version: %s.\n", version_info->version, LIBCURL_VERSION );
1657       }
1658       /*
1659        * Set our version info variables
1660        */
1661       RexxCURLSetVersionInfoConstants( RxPackageGlobalData );
1662    }
1663    return 0L;
1664 }
1665 
RexxCURLTermHandler(LONG ExitNum,LONG Subfun,PEXIT PBlock)1666 LONG APIENTRY RexxCURLTermHandler( LONG ExitNum, LONG Subfun, PEXIT PBlock )
1667 {
1668    DEBUGDUMP(fprintf(stderr,"%s-%d: In rexxcurlTermHandler() ExitNum %ld Subfun %ld\n",__FILE__,__LINE__,ExitNum, Subfun);)
1669    return 0L;
1670 }
1671 
getRexxCURLSubcomHandler(void)1672 RexxSubcomHandler *getRexxCURLSubcomHandler( void )
1673 {
1674    return NULL;
1675 }
1676 
getRexxCURLInitHandler(void)1677 RexxExitHandler *getRexxCURLInitHandler( void )
1678 {
1679    return RexxCURLInitHandler;
1680 }
1681 
getRexxCURLTermHandler(void)1682 RexxExitHandler *getRexxCURLTermHandler( void )
1683 {
1684    return RexxCURLTermHandler;
1685 }
1686 
getRexxCURLFunctions(void)1687 RexxFunction *getRexxCURLFunctions( void )
1688 {
1689    return RexxCURLFunctions;
1690 }
1691 
getRexxCURLConstants(void)1692 RxPackageConstantDef *getRexxCURLConstants( void )
1693 {
1694    return RexxCURLConstants;
1695 }
1696 
getRexxCURLInitialiser(void)1697 PackageInitialiser *getRexxCURLInitialiser( void )
1698 {
1699    return RexxCURLInitialiser;
1700 }
1701 
getRexxCURLTerminator(void)1702 PackageTerminator *getRexxCURLTerminator( void )
1703 {
1704    return RexxCURLTerminator;
1705 }
1706 
getRexxCURLFunctionAddress(char * name)1707 void *getRexxCURLFunctionAddress( char *name )
1708 {
1709    int i, size = sizeof( RexxCURLFunctions ) / sizeof( RexxFunction ) ;
1710 
1711    for (i = 0; i < size && RexxCURLFunctions[i].InternalName; i++)
1712    {
1713       if ( strcmp( RexxCURLFunctions[i].InternalName, name) == 0 )
1714          return RexxCURLFunctions[i].EntryPoint;
1715    }
1716    return NULL;
1717 }
1718 
INIT_RXPACKAGE(RxPackageGlobalDataDef * RxPackageGlobalData)1719 void *INIT_RXPACKAGE ( RxPackageGlobalDataDef *RxPackageGlobalData )
1720 {
1721    /*
1722     * This needs to allocate memory for RexxCURLData structure,
1723     */
1724    RxPackageGlobalData->RXPACKAGE_tsd = (REXXCURLDATA *)MALLOC_TSD( RxPackageGlobalData, sizeof(REXXCURLDATA) );
1725    if ( RxPackageGlobalData->RXPACKAGE_tsd )
1726       memset( RxPackageGlobalData->RXPACKAGE_tsd , 0, sizeof(REXXCURLDATA) );
1727    /*
1728     * TODO
1729     * If any global variable that require initialisation or allocation of memory, add them here
1730     */
1731    return (void *)RxPackageGlobalData->RXPACKAGE_tsd;
1732 }
1733 
TERM_RXPACKAGE(RxPackageGlobalDataDef * RxPackageGlobalData)1734 void TERM_RXPACKAGE ( RxPackageGlobalDataDef *RxPackageGlobalData )
1735 {
1736    /*
1737     * This needs to free memory allocated in INIT_RXPACKAGE()
1738     * and call any database-specific termination code
1739     */
1740    /*
1741     * Get the TSD if required
1742    REXXCURLDATA *RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
1743     */
1744    /*
1745     * Free any items in the RexxCURLData struct that were allocated in INIT_RXPACKAGE
1746     */
1747    /*
1748     * Free the RexxCURLData struct
1749     */
1750    FREE_TSD( RxPackageGlobalData, RxPackageGlobalData->RXPACKAGE_tsd );
1751    RxPackageGlobalData = NULL;
1752 }
1753 
1754 #if defined(WIN32)
win32_cleanup(void)1755 static void win32_cleanup(void)
1756 {
1757   WSACleanup();
1758 }
1759 
win32_init(void)1760 static CURLcode win32_init(void)
1761 {
1762   WORD wVersionRequested;
1763   WSADATA wsaData;
1764   int err;
1765   wVersionRequested = MAKEWORD(1, 1);
1766 
1767   err = WSAStartup(wVersionRequested, &wsaData);
1768 
1769   if (err != 0)
1770     /* Tell the user that we couldn't find a useable */
1771     /* winsock.dll.     */
1772     return 1;
1773 
1774   /* Confirm that the Windows Sockets DLL supports 1.1.*/
1775   /* Note that if the DLL supports versions greater */
1776   /* than 1.1 in addition to 1.1, it will still return */
1777   /* 1.1 in wVersion since that is the version we */
1778   /* requested. */
1779 
1780   if ( LOBYTE( wsaData.wVersion ) != 1 ||
1781        HIBYTE( wsaData.wVersion ) != 1 ) {
1782     /* Tell the user that we couldn't find a useable */
1783 
1784     /* winsock.dll. */
1785     WSACleanup();
1786     return 1;
1787   }
1788   return 0; /* 0 is ok */
1789 }
1790 #endif
1791 
1792 /*-----------------------------------------------------------------------------
1793  * This function is the callback for PROGRESSFUNCTION option.
1794  * We need the client data pointer to get the TSD.
1795  *----------------------------------------------------------------------------*/
rexxcurl_progress_callback(void * clientp,double dltotal,double dlnow,double ultotal,double ulnow)1796 int rexxcurl_progress_callback( void *clientp, double dltotal, double dlnow, double ultotal, double ulnow )
1797 {
1798    int num_args = 4;
1799    char rx_dltotal[20];
1800    char rx_dlnow[20];
1801    char rx_ultotal[20];
1802    char rx_ulnow[20];
1803    PRXSTRING argv;
1804    RXSTRING RetStr;
1805    int rc;
1806    SHORT rcode=0;
1807    REXXCURLDATA *RexxCURLData;
1808    RxPackageGlobalDataDef *RxPackageGlobalData = (RxPackageGlobalDataDef *)clientp;
1809 
1810    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
1811 
1812    if ( have_rexxcallback )
1813    {
1814       argv = (PRXSTRING)malloc( num_args*sizeof(RXSTRING) );
1815       if ( argv == NULL )
1816          return -1;
1817       sprintf( rx_dltotal, "%0.f", dltotal );
1818       sprintf( rx_dlnow, "%0.f", dlnow );
1819       sprintf( rx_ultotal, "%0.f", ultotal );
1820       sprintf( rx_ulnow, "%0.f", ulnow );
1821       MAKERXSTRING( argv[0], rx_dltotal, strlen( rx_dltotal ) );
1822       MAKERXSTRING( argv[1], rx_dlnow, strlen( rx_dlnow ) );
1823       MAKERXSTRING( argv[2], rx_ultotal, strlen( rx_ultotal ) );
1824       MAKERXSTRING( argv[3], rx_ulnow, strlen( rx_ulnow ) );
1825 
1826       MAKERXSTRING( RetStr, NULL, 0 );
1827 #if defined( REXXCALLBACK )
1828       rc = RexxCallBack( RexxCURLData->StringPtrs[RexxCURLData->progress_index], num_args, argv, &rcode, &RetStr );
1829 #else
1830       rc = 0;
1831 #endif
1832       if ( RetStr.strptr )
1833          RexxFreeMemory( RetStr.strptr );
1834       free( argv );
1835       /* free_cb_argv( curr );*/
1836    }
1837    return rcode;
1838 }
1839 
1840 /*-----------------------------------------------------------------------------
1841  * This function is the callback for SSHKEYFUNCTION option.
1842  * We need the client data pointer to get the TSD.
1843  * Args to Rexx procedure:
1844  * knownkeystring - value of key
1845  * knownkeylength - length of known key; 0 indicates base64 encoding, otherwise raw
1846  * knownkeytype   - KHTYPE_UNKNOWN, KHTYPE_RSA, KHTYPE_RSA1, KHTYPE_DSS
1847  * foundkeystring - value of key
1848  * foundkeylength - length of found key; 0 indicates base64 encoding, otherwise raw
1849  * foundkeytype   - KHTYPE_UNKNOWN, KHTYPE_RSA, KHTYPE_RSA1, KHTYPE_DSS
1850  * libcurlviewofkey - KHMATCH_OK (match), KHMATCH_MISMATCH (host found, key mismatch!), KHMATCH_MISSING (no matching host/key found)
1851  *----------------------------------------------------------------------------*/
rexxcurl_sshkey_callback(CURL * easy,const struct curl_khkey * knownkey,const struct curl_khkey * foundkey,enum curl_khmatch match,void * clientp)1852 int rexxcurl_sshkey_callback( CURL *easy,     /* easy handle; ignored */
1853                               const struct curl_khkey *knownkey, /* known */
1854                               const struct curl_khkey *foundkey, /* found */
1855                               enum curl_khmatch match, /* libcurl's view on the keys */
1856                               void *clientp) /* custom pointer passed from app */
1857 {
1858    int num_args = 7;
1859    char rx_knownkeylength[20];
1860    char rx_knownkeytype[20];
1861    char rx_foundkeylength[20];
1862    char rx_foundkeytype[20];
1863    char rx_libcurlviewofkey[20];
1864    int rx_knownkeylength_len;
1865    int rx_knownkeytype_len;
1866    int rx_foundkeylength_len;
1867    int rx_foundkeytype_len;
1868    int rx_libcurlviewofkey_len;
1869    PRXSTRING argv;
1870    RXSTRING RetStr;
1871    int rc;
1872    SHORT rcode=0;
1873    REXXCURLDATA *RexxCURLData;
1874    RxPackageGlobalDataDef *RxPackageGlobalData = (RxPackageGlobalDataDef *)clientp;
1875 
1876    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
1877 
1878    if ( have_rexxcallback )
1879    {
1880       argv = (PRXSTRING)malloc( num_args*sizeof(RXSTRING) );
1881       if ( argv == NULL )
1882          return -1;
1883 
1884       rx_knownkeylength_len = sprintf( rx_knownkeylength, "%lu", (unsigned long) knownkey->len );
1885       rx_knownkeytype_len = sprintf( rx_knownkeytype, "%u", knownkey->keytype );
1886       rx_foundkeylength_len = sprintf( rx_foundkeylength, "%lu", (unsigned long) foundkey->len );
1887       rx_foundkeytype_len = sprintf( rx_foundkeytype, "%u", foundkey->keytype );
1888       rx_libcurlviewofkey_len = sprintf( rx_libcurlviewofkey, "%u", match );
1889 
1890       if ( knownkey->len )
1891       {
1892          MAKERXSTRING( argv[0], knownkey->key, knownkey->len );
1893       }
1894       else
1895       {
1896          MAKERXSTRING( argv[0], knownkey->key, strlen( knownkey->key ) );
1897       }
1898       MAKERXSTRING( argv[1], rx_knownkeylength, rx_knownkeylength_len );
1899       MAKERXSTRING( argv[2], rx_knownkeytype, rx_knownkeytype_len );
1900       if ( foundkey->len )
1901       {
1902          MAKERXSTRING( argv[3], foundkey->key, foundkey->len );
1903       }
1904       else
1905       {
1906          MAKERXSTRING( argv[3], foundkey->key, strlen( foundkey->key ) );
1907       }
1908       MAKERXSTRING( argv[4], rx_foundkeylength, rx_foundkeylength_len );
1909       MAKERXSTRING( argv[5], rx_foundkeytype, rx_foundkeytype_len );
1910       MAKERXSTRING( argv[6], rx_libcurlviewofkey, rx_libcurlviewofkey_len );
1911 
1912       MAKERXSTRING( RetStr, NULL, 0 );
1913 #if defined( REXXCALLBACK )
1914       rc = RexxCallBack( RexxCURLData->StringPtrs[RexxCURLData->progress_index], num_args, argv, &rcode, &RetStr );
1915 #else
1916       rc = 0;
1917 #endif
1918       if ( RetStr.strptr )
1919          RexxFreeMemory( RetStr.strptr );
1920       free( argv );
1921       /* free_cb_argv( curr );*/
1922    }
1923    return rcode;
1924 }
1925 
1926 /*-----------------------------------------------------------------------------
1927  * This function returns the size of the specified file. Returns -1 if the
1928  * file does not exist or is not a "normal" file eg a directory
1929  *----------------------------------------------------------------------------*/
get_file_size(RxPackageGlobalDataDef * RxPackageGlobalData,char * fn)1930 rx_long_long get_file_size( RxPackageGlobalDataDef *RxPackageGlobalData, char *fn )
1931 {
1932    struct stat stat_buf;
1933    size_t rc;
1934    rx_long_long fs;
1935 
1936    rc = stat( fn, &stat_buf ) ;
1937    if (rc == 0)
1938    {
1939       if ( (stat_buf.st_mode & S_IFMT) == S_IFDIR)
1940          fs = -1;
1941       else
1942          fs = (rx_long_long)stat_buf.st_size;
1943    }
1944    else
1945       fs = (rx_long_long)rc;
1946    InternalTrace( RxPackageGlobalData, "get_file_size", "Size of file: %s is: %ld", fn, fs );
1947    return fs;
1948 }
1949 
1950 /*-----------------------------------------------------------------------------
1951  * This function is necessary for Win32/64 platform
1952  * To use InternalTrace we would need to get TSD each time; very inefficient
1953  *----------------------------------------------------------------------------*/
file_write_function(void * ptr,size_t size,size_t nmemb,void * stream)1954 size_t file_write_function( void *ptr, size_t size, size_t nmemb, void *stream )
1955 {
1956    return fwrite( ptr, size, nmemb, stream );
1957 }
1958 
1959 /*-----------------------------------------------------------------------------
1960  * This function is necessary for Win32/64 platform
1961  * To use InternalTrace we would need to get TSD each time; very inefficient
1962  *----------------------------------------------------------------------------*/
debug_function(CURL * handle,curl_infotype type,char * data,size_t size,void * userdata)1963 int debug_function( CURL *handle, curl_infotype type, char *data, size_t size, void *userdata )
1964 {
1965    FILE *fp = (FILE *)userdata;
1966    int c;
1967    char *prefix = "*<><><>";
1968    if ( type == CURLINFO_TEXT )
1969       fprintf( fp, "text: %c %.*s", prefix[type],(int)size, data );
1970    if ( type == CURLINFO_HEADER_IN )
1971       fprintf( fp, "header_in: %c %.*s", prefix[type],(int)size, data );
1972    if ( type == CURLINFO_HEADER_OUT )
1973       fprintf( fp, "header_out:%c %.*s", prefix[type],(int)size, data );
1974    if ( type == CURLINFO_SSL_DATA_IN )
1975    {
1976       fprintf( fp, "ssl_data_in: " );
1977       for ( c = 0; c < size; c++ )
1978       {
1979          char x = (data[c] >= 0x20) ? data[c] : '.';
1980          fputc( x, fp);
1981       }
1982       fputc('\n', fp); /* newline */
1983    }
1984    if ( type == CURLINFO_SSL_DATA_OUT )
1985    {
1986       fprintf( fp, "ssl_data_out: " );
1987       for ( c = 0; c < size; c++ )
1988       {
1989          char x = (data[c] >= 0x20) ? data[c] : '.';
1990          fputc( x, fp);
1991       }
1992       fputc('\n', fp); /* newline */
1993    }
1994    return 0;
1995 }
1996 
1997 
1998 /*-----------------------------------------------------------------------------
1999  * This function is necessary for Win32/64 platform
2000  * To use InternalTrace we would need to get TSD each time; very inefficient
2001  *----------------------------------------------------------------------------*/
file_read_function(void * ptr,size_t size,size_t nmemb,void * stream)2002 size_t file_read_function( void *ptr, size_t size, size_t nmemb, void *stream )
2003 {
2004    return fread( ptr, size, nmemb, stream );
2005 }
2006 
stem_read_function(void * ptr,size_t size,size_t nmemb,void * data)2007 size_t stem_read_function( void *ptr, size_t size, size_t nmemb, void *data )
2008 {
2009    instem_option *opt = (instem_option *)data;
2010    int count = size*nmemb; /* requested size to return */
2011    char *str;
2012    if ( opt->str.strlength )
2013    {
2014       int copy_this_much = opt->str.strlength;
2015       if ( copy_this_much > count)
2016       {
2017          copy_this_much = count;
2018       }
2019       InternalTrace( opt->RxPackageGlobalData, "stem_read_function", "Requested size: %ld Remaining: %ld Returning count: %ld", count, opt->str.strlength, copy_this_much );
2020       str = opt->str.strptr + opt->index;
2021 
2022       memcpy(ptr, str, copy_this_much);
2023       opt->str.strlength -= copy_this_much;
2024       opt->index += copy_this_much;
2025       return copy_this_much;
2026    }
2027    InternalTrace( opt->RxPackageGlobalData, "stem_read_function", "Complete!" );
2028    return 0;
2029 }
2030 
2031 /*-----------------------------------------------------------------------------
2032  * This function creates a compound Rexx variable with the supplied name
2033  * and vale.
2034  *----------------------------------------------------------------------------*/
create_rexx_compound(RxPackageGlobalDataDef * RxPackageGlobalData,char * stem,int tail,char * value,int valuelen)2035 int create_rexx_compound( RxPackageGlobalDataDef *RxPackageGlobalData, char *stem, int tail, char *value, int valuelen )
2036 {
2037    char name[350];
2038    int namelen;
2039 
2040    namelen = sprintf( name, "%s%d", stem, tail );
2041    SetRexxVariable( RxPackageGlobalData, name, namelen, value, valuelen );
2042    return 0;
2043 }
2044 /*-----------------------------------------------------------------------------
2045  * This function writes the output from the site to a stem. Called from
2046  * OUTSTEM option
2047  *----------------------------------------------------------------------------*/
outstem_write_function(void * ptr,size_t size,size_t nmemb,void * stream)2048 size_t outstem_write_function( void *ptr, size_t size, size_t nmemb, void *stream )
2049 {
2050    size_t num_bytes=size*nmemb;
2051    size_t rc;
2052    REXXCURLDATA *RexxCURLData;
2053    /*
2054     * Get thread-safe-data
2055     */
2056    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
2057 
2058    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2059 
2060    InternalTrace( RxPackageGlobalData, "outstem_write_function", "Size of chunk to write: %ld", num_bytes );
2061    if ( RexxCURLData->outstem_strlength)
2062       RexxCURLData->outstem_strptr = (char *)realloc( RexxCURLData->outstem_strptr, RexxCURLData->outstem_strlength + num_bytes + 1);
2063    else
2064       RexxCURLData->outstem_strptr = (char *)malloc( RexxCURLData->outstem_strlength + num_bytes + 1);
2065 
2066    if ( RexxCURLData->outstem_strptr == NULL )
2067    {
2068       rc = -1;
2069    }
2070    else
2071    {
2072       memcpy( RexxCURLData->outstem_strptr+RexxCURLData->outstem_strlength, ptr, num_bytes );
2073       RexxCURLData->outstem_strlength += num_bytes;
2074       RexxCURLData->outstem_strptr[RexxCURLData->outstem_strlength] = '\0';
2075       rc = num_bytes;
2076    }
2077    InternalTrace( RxPackageGlobalData, "outstem_write_function", "Returned with: %ld", num_bytes );
2078    return rc;
2079 }
2080 /*-----------------------------------------------------------------------------
2081  * This function creates the compound variables for the stem.
2082  *----------------------------------------------------------------------------*/
outstem_create(RxPackageGlobalDataDef * RxPackageGlobalData)2083 int outstem_create( RxPackageGlobalDataDef *RxPackageGlobalData )
2084 {
2085    char *tmp,*ptr;
2086    char *eol;
2087    int eollen;
2088    REXXCURLDATA *RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2089 
2090    if ( RexxCURLData->outstem_strptr )
2091    {
2092       eol = RexxCURLData->outstem_line_terminator;
2093       eollen = strlen( eol );
2094       ptr = RexxCURLData->outstem_strptr;
2095       tmp = strstr( ptr, eol );
2096 
2097       while( tmp != NULL )
2098       {
2099          *tmp = '\0';
2100          create_rexx_compound( RxPackageGlobalData, RexxCURLData->StringPtrs[RexxCURLData->outstem_index], ++(RexxCURLData->outstem_tail), (char *)ptr, strlen( ptr ) );
2101          ptr = tmp+eollen;
2102          tmp = strstr( ptr, eol );
2103       }
2104       if ( *ptr != '\0' )
2105       {
2106          create_rexx_compound( RxPackageGlobalData, RexxCURLData->StringPtrs[RexxCURLData->outstem_index], ++(RexxCURLData->outstem_tail), (char *)ptr, strlen( ptr ) );
2107       }
2108    }
2109 
2110    return 0;
2111 }
2112 /*-----------------------------------------------------------------------------
2113  * This function writes the output from the site to a stem. Called from
2114  * HEADERSTEM option
2115  *----------------------------------------------------------------------------*/
headerstem_write_function(void * ptr,size_t size,size_t nmemb,void * stream)2116 size_t headerstem_write_function( void *ptr, size_t size, size_t nmemb, void *stream )
2117 {
2118    size_t num_bytes=size*nmemb;
2119    REXXCURLDATA *RexxCURLData;
2120    /*
2121     * Get thread-safe-data
2122     */
2123    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
2124    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2125    /*
2126     * We are guaranteed that each header is complete and terminated with CRLF, so simply
2127     * set the length of the variable value to 2 less than actual length
2128     */
2129    create_rexx_compound( RxPackageGlobalData , RexxCURLData->StringPtrs[RexxCURLData->headerstem_index], ++(RexxCURLData->headerstem_tail), (char *)ptr, num_bytes - 2 );
2130    /*
2131     * Tell cURL we've read ALL bytes
2132     */
2133    return num_bytes;
2134 }
2135 
2136 /*-----------------------------------------------------------------------------
2137  * Clear the cURL error message.
2138  *----------------------------------------------------------------------------*/
ClearCURLError(RxPackageGlobalDataDef * RxPackageGlobalData)2139 void ClearCURLError( RxPackageGlobalDataDef *RxPackageGlobalData )
2140 {
2141    char var[350];
2142    int varlen;
2143    REXXCURLDATA *RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2144 
2145    InternalTrace( RxPackageGlobalData, "ClearCURLError", NULL );
2146    /*
2147     * Set CURLERROR.CURLERRM variable
2148     */
2149    varlen = sprintf( var,"%s%s", RexxCURLData->rexxcurl_error_prefix, CURLERRM_PREFIX );
2150    (void)SetRexxVariable( RxPackageGlobalData, var, varlen, "", 0 );
2151    /*
2152     * Set CURLERROR.CURLCODE variable
2153     */
2154    varlen = sprintf( var,"%s%s", RexxCURLData->rexxcurl_error_prefix, CURLCODE_PREFIX );
2155    (void)SetRexxVariable( RxPackageGlobalData, var, varlen, "0", 1 );
2156    RexxCURLData->g_curl_error = 0;
2157    return;
2158 }
2159 
2160 /*-----------------------------------------------------------------------------
2161  * Set the cURL error message.
2162  *----------------------------------------------------------------------------*/
SetCURLError(RxPackageGlobalDataDef * RxPackageGlobalData,CURLcode curlcode,char * curlmsg)2163 void SetCURLError( RxPackageGlobalDataDef *RxPackageGlobalData, CURLcode curlcode, char *curlmsg)
2164 {
2165    char var[350];
2166    char msg[350];
2167    int varlen;
2168    int msglen;
2169    REXXCURLDATA *RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2170 
2171    InternalTrace( RxPackageGlobalData, "SetCURLError", "%d,%s", curlcode, curlmsg );
2172 
2173    RexxCURLData->g_curl_error = curlcode;
2174    /*
2175     * Set CURLERROR.CURLERRM variable
2176     */
2177    varlen = sprintf( var,"%s%s", RexxCURLData->rexxcurl_error_prefix, CURLERRM_PREFIX );
2178    (void)SetRexxVariable( RxPackageGlobalData, var, varlen, curlmsg, strlen(curlmsg) );
2179    /*
2180     * Set CURLERROR.CURLCODE variable
2181     */
2182    msglen = sprintf( msg, "%d", RexxCURLData->g_curl_error );
2183    varlen = sprintf( var,"%s%s", RexxCURLData->rexxcurl_error_prefix, CURLCODE_PREFIX );
2184    (void)SetRexxVariable( RxPackageGlobalData, var, varlen, msg, msglen );
2185    return;
2186 }
2187 
2188 /*-----------------------------------------------------------------------------
2189  * Clear the internal error message.
2190  *----------------------------------------------------------------------------*/
ClearIntError(RxPackageGlobalDataDef * RxPackageGlobalData)2191 static int ClearIntError( RxPackageGlobalDataDef *RxPackageGlobalData )
2192 {
2193    char var[350];
2194    int varlen;
2195    REXXCURLDATA *RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2196 
2197    InternalTrace( RxPackageGlobalData, "ClearIntError", NULL );
2198 
2199    RexxCURLData->g_rexxcurl_error = 0;
2200    /*
2201     * Set CURLERROR.INTERRM variable
2202     */
2203    varlen = sprintf( var,"%s%s", RexxCURLData->rexxcurl_error_prefix, INTERRM_PREFIX );
2204    (void)SetRexxVariable( RxPackageGlobalData, var, varlen, "", 0 );
2205    /*
2206     * Set CURLERROR.INTCODE variable
2207     */
2208    varlen = sprintf( var,"%s%s", RexxCURLData->rexxcurl_error_prefix, INTCODE_PREFIX );
2209    (void)SetRexxVariable( RxPackageGlobalData, var, varlen, "0", 1 );
2210 
2211    return( RexxCURLData->g_rexxcurl_error );
2212 }
2213 
2214 /*-----------------------------------------------------------------------------
2215  * Set the internal error message.
2216  *----------------------------------------------------------------------------*/
SetIntError(RxPackageGlobalDataDef * RxPackageGlobalData,char * fn,int lineno,int errcode,char * errmsg)2217 static int SetIntError( RxPackageGlobalDataDef *RxPackageGlobalData, char *fn, int lineno, int errcode, char *errmsg )
2218 {
2219    char msg[350];
2220    char var[350];
2221    int msglen;
2222    int varlen;
2223    REXXCURLDATA *RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2224 
2225    InternalTrace( RxPackageGlobalData, "SetIntError", "%s,%d,%d,%s", fn, lineno, errcode, errmsg );
2226 
2227    RexxCURLData->g_rexxcurl_error = -errcode;
2228 
2229    /*
2230     * Set CURLERROR.INTERRM variable
2231     */
2232    if ( RxGetRunFlags( RxPackageGlobalData ) & MODE_INTERNAL )
2233       msglen = sprintf(msg, "Rexx/CURL-%02d: %s [%s:%d]", errcode, errmsg, fn, lineno);
2234    else
2235       msglen = sprintf(msg, "REXX/CURL-%02d: %s", errcode, errmsg);
2236    varlen = sprintf( var,"%s%s", RexxCURLData->rexxcurl_error_prefix, INTERRM_PREFIX );
2237    (void)SetRexxVariable( RxPackageGlobalData, var, varlen, msg, msglen );
2238 
2239    /*
2240     * Set CURLERROR.INTCODE variable
2241     */
2242    msglen = sprintf( msg, "%d", RexxCURLData->g_rexxcurl_error );
2243    varlen = sprintf( var,"%s%s", RexxCURLData->rexxcurl_error_prefix, INTCODE_PREFIX );
2244    (void)SetRexxVariable( RxPackageGlobalData, var, varlen, msg, msglen );
2245 
2246    return( RexxCURLData->g_rexxcurl_error );
2247 }
2248 
init_options(RxPackageGlobalDataDef * RxPackageGlobalData)2249 static void init_options( RxPackageGlobalDataDef *RxPackageGlobalData )
2250 {
2251    int i;
2252    REXXCURLDATA *RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2253 
2254    InternalTrace( RxPackageGlobalData, "init_options", NULL );
2255 
2256    for ( i = 0; i < NUMBER_REXXCURL_OPTIONS; i++ )
2257    {
2258       RexxCURLData->FilePtrs[i] = NULL;
2259       RexxCURLData->StringPtrs[i] = NULL;
2260       RexxCURLData->SListPtrs[i] = NULL;
2261       RexxCURLData->HttpPostFirstPtrs[i] = NULL;
2262       RexxCURLData->HttpPostLastPtrs[i] = NULL;
2263       RexxCURLData->UsedOptions[i] = '\0';
2264    }
2265 }
2266 
reset_options(RxPackageGlobalDataDef * RxPackageGlobalData)2267 static void reset_options( RxPackageGlobalDataDef *RxPackageGlobalData )
2268 {
2269    int i;
2270    REXXCURLDATA *RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2271 
2272    for ( i = 0; i < NUMBER_REXXCURL_OPTIONS; i++ )
2273    {
2274       if ( RexxCURLData->FilePtrs[i] )
2275       {
2276          fclose( RexxCURLData->FilePtrs[i] );
2277          RexxCURLData->FilePtrs[i] = NULL;
2278       }
2279       if ( RexxCURLData->StringPtrs[i] )
2280       {
2281          free( RexxCURLData->StringPtrs[i] );
2282          RexxCURLData->StringPtrs[i] = NULL;
2283       }
2284       if ( RexxCURLData->SListPtrs[i] )
2285       {
2286          CURL_SLIST_FREE_ALL( RexxCURLData->SListPtrs[i] );
2287          RexxCURLData->SListPtrs[i] = NULL;
2288       }
2289       if ( RexxCURLData->HttpPostFirstPtrs[i] )
2290       {
2291          CURL_FORMFREE( RexxCURLData->HttpPostFirstPtrs[i] );
2292          RexxCURLData->HttpPostFirstPtrs[i] = NULL;
2293          RexxCURLData->HttpPostLastPtrs[i] = NULL;
2294       }
2295       RexxCURLData->UsedOptions[i] = '\0';
2296    }
2297 }
2298 
find_option(RxPackageGlobalDataDef * RxPackageGlobalData,char * str,int len)2299 static int find_option( RxPackageGlobalDataDef *RxPackageGlobalData, char *str, int len )
2300 {
2301    register int i = 0;
2302 
2303    for ( i = 0; RexxCurlOptions[i].name != NULL; i++ )
2304    {
2305       if ( memcmpi( RxPackageGlobalData, str, RexxCurlOptions[i].name, len ) == 0 )
2306       {
2307          /*
2308           * If this is a deprecated option name, print a warning with the new name
2309           */
2310          if ( RexxCurlOptions[i].newname )
2311          {
2312             fprintf( stderr,"WARNING: The option \"%s\" is deprecated. Use option \"%s\" instead.\n", RexxCurlOptions[i].name, RexxCurlOptions[i].newname );
2313          }
2314          return i;
2315       }
2316    }
2317    return ( -1 );
2318 }
2319 
find_getinfo(RxPackageGlobalDataDef * RxPackageGlobalData,char * str,int len)2320 static int find_getinfo( RxPackageGlobalDataDef *RxPackageGlobalData, char *str, int len )
2321 {
2322    register int i = 0;
2323 
2324    for ( i = 0; RexxCurlGetinfos[i].name != NULL; i++ )
2325    {
2326       if ( memcmpi( RxPackageGlobalData, str, RexxCurlGetinfos[i].name, len ) == 0 )
2327       {
2328          /*
2329           * If this is a deprecated option name, print a warning with the new name
2330           */
2331          if ( RexxCurlGetinfos[i].newname )
2332          {
2333             fprintf( stderr,"WARNING: The info option \"%s\" is deprecated. Use info option \"%s\" instead.\n", RexxCurlGetinfos[i].name, RexxCurlGetinfos[i].newname );
2334          }
2335          return i;
2336       }
2337    }
2338    return ( -1 );
2339 }
2340 
find_suboption(RxPackageGlobalDataDef * RxPackageGlobalData,char * str,int len,int optiontype)2341 static int find_suboption( RxPackageGlobalDataDef *RxPackageGlobalData, char *str, int len, int optiontype )
2342 {
2343    register int i = 0;
2344 
2345    for ( i = 0; RexxCurlSubOptions[i].name != NULL; i++ )
2346    {
2347       if ( memcmpi( RxPackageGlobalData, str, RexxCurlSubOptions[i].name, len ) == 0
2348       &&   RexxCurlSubOptions[i].optiontype == optiontype )
2349       {
2350          /*
2351           * If this is a deprecated option name, print a warning with the new name
2352           */
2353          if ( RexxCurlSubOptions[i].newname )
2354          {
2355             fprintf( stderr,"WARNING: The sub-option \"%s\" is deprecated. Use sub-option \"%s\" instead.\n", RexxCurlSubOptions[i].name, RexxCurlSubOptions[i].newname );
2356          }
2357          return i;
2358       }
2359    }
2360    return ( -1 );
2361 }
2362 
2363 /*====== Here come the real interface functions to curl ======*/
2364 
rxfunc(CurlInit)2365 rxfunc( CurlInit )
2366 {
2367    CURL *curl;
2368    REXXCURLDATA *RexxCURLData;
2369    /*
2370     * Get thread-safe-data
2371     */
2372    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
2373    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
2374    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2375 
2376    ClearCURLError( RxPackageGlobalData );
2377    ClearIntError( RxPackageGlobalData );
2378    if ( my_checkparam( RxPackageGlobalData, name, argc, 0, 0 ) )
2379       return( 1 );
2380    /*
2381     * Do some initialisations
2382     */
2383    init_options( RxPackageGlobalData );
2384    curl = CURL_EASY_INIT();
2385    InternalTrace( RxPackageGlobalData, "CurlInit", "After curl_easy_init" );
2386    /*
2387     * Determine if the Rexx interpreter has RexxCallBack()
2388     * If USE_REGINA then we have it.
2389     * If USE_REXXTRANS then we MIGHT have it; we need to call RxTransHaveRexxCallBack()
2390     * to check.
2391     * If REXXCALLBACK defined, then we also have it.
2392     * All other situations, we DON'T have it.
2393     * We need to determine this BEFORE calling SetPackageConstants()
2394     */
2395 #if defined( USE_REGINA )
2396    have_rexxcallback = 1;
2397    InternalTrace( RxPackageGlobalData, "CurlInit", "RexxCallback available: Regina" );
2398 #elif defined ( USE_REXXTRANS )
2399    if ( RexxTransHaveRexxCallBack() )
2400       have_rexxcallback = 1;
2401    InternalTrace( RxPackageGlobalData, "CurlInit", "RexxCallback %s: RexxTrans", have_rexxcallback ? "available" : "unavailable" );
2402 #elif defined( REXXCALLBACK )
2403    have_rexxcallback = 1;
2404    InternalTrace( RxPackageGlobalData, "CurlInit", "RexxCallback available: Other Interpreter" );
2405 #else
2406    have_rexxcallback = 0;
2407    InternalTrace( RxPackageGlobalData, "CurlInit", "RexxCallback unavailable: Other Interpreter" );
2408 #endif
2409    return RxReturnPointer( RxPackageGlobalData, retstr, (void *)curl ) ;
2410 }
2411 
rxfunc(CurlCleanup)2412 rxfunc( CurlCleanup )
2413 {
2414    long curl;
2415    REXXCURLDATA *RexxCURLData;
2416    /*
2417     * Get thread-safe-data
2418     */
2419    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
2420    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
2421    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2422 
2423    if ( RexxCURLData->g_curl_error) ClearCURLError( RxPackageGlobalData );
2424    if ( RexxCURLData->g_rexxcurl_error) ClearIntError( RxPackageGlobalData );
2425    if ( my_checkparam( RxPackageGlobalData, name, argc, 1, 1 ) )
2426       return( 1 );
2427    if ( RxStrToLong( RxPackageGlobalData, &argv[0], &curl ) != 0 )
2428    {
2429       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_HANDLE, INTERR_INVALID_HANDLE_STRING );
2430       return RxReturnNumber( RxPackageGlobalData, retstr, INTERR_INVALID_HANDLE ) ;
2431    }
2432    CURL_EASY_CLEANUP( (CURL *)curl );
2433    reset_options( RxPackageGlobalData );
2434    memset( RexxCURLData->UsedOptions, 0, sizeof(char)*NUMBER_REXXCURL_OPTIONS );
2435    return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
2436 }
2437 
rxfunc(CurlSetopt)2438 rxfunc( CurlSetopt )
2439 {
2440    ULONG rc = 0L;
2441    long curl;
2442    int i,j,opt,sub_opt;
2443    long long_opt;
2444    rx_long_long longlong_opt;
2445    rx_long_long file_size;
2446    CURLcode curl_rc;
2447    CURLFORMcode curlformadd_rc;
2448    RXSTRING value;
2449    int ltlen;
2450    int count = 0;
2451    char *ltstr;
2452    char *tmp;
2453    char eol[2]={10,0};
2454    char tmp_format[100];
2455    char *opentype="wb";
2456    REXXCURLDATA *RexxCURLData;
2457    /*
2458     * Get thread-safe-data
2459     */
2460    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
2461    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
2462    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
2463 
2464    if ( RexxCURLData->g_curl_error) ClearCURLError( RxPackageGlobalData );
2465    if ( RexxCURLData->g_rexxcurl_error) ClearIntError( RxPackageGlobalData );
2466    if ( my_checkparam( RxPackageGlobalData, name, argc, 2, 0 ) )
2467       return( 1 );
2468    if ( RxStrToLong( RxPackageGlobalData, &argv[0], &curl ) != 0 )
2469    {
2470       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_HANDLE, INTERR_INVALID_HANDLE_STRING );
2471       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
2472    }
2473    opt = find_option( RxPackageGlobalData, argv[1].strptr, argv[1].strlength );
2474    if ( opt == (-1) )
2475    {
2476       char buf[1024];
2477       sprintf( buf, "%s: %s", INTERR_INVALID_OPTION_STRING, argv[1].strptr );
2478       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_OPTION, buf );
2479       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
2480    }
2481    /*
2482     * HTTPPOSTDATA does NOT require any further arguments, so only if it is NOT
2483     * this option, check for the mandatory 3rd argument
2484     */
2485    if ( RexxCurlOptions[opt].optiontype != RXCURLOPT_POST_FORM )
2486    {
2487       if ( my_checkparam( RxPackageGlobalData, name, argc, 3, 0 ) )
2488          return( 1 );
2489    }
2490 
2491    switch( RexxCurlOptions[opt].optiontype )
2492    {
2493       case RXCURLOPT_STRING:
2494          if ( RexxCURLData->StringPtrs[opt] )
2495          {
2496             free( RexxCURLData->StringPtrs[opt] );
2497             RexxCURLData->StringPtrs[opt] = NULL;
2498          }
2499          RexxCURLData->StringPtrs[opt] = (char *)malloc( argv[2].strlength + 1 );
2500          if ( RexxCURLData->StringPtrs[opt] == NULL )
2501          {
2502             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
2503             break;
2504          }
2505          memcpy( RexxCURLData->StringPtrs[opt], argv[2].strptr, argv[2].strlength );
2506          RexxCURLData->StringPtrs[opt][argv[2].strlength] = '\0';
2507          /*
2508           * Do any extra processing here for some options
2509           */
2510          switch( RexxCurlOptions[opt].number )
2511          {
2512             default:
2513                break;
2514          }
2515          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, RexxCURLData->StringPtrs[opt] );
2516          if ( curl_rc != CURLE_OK )
2517          {
2518             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2519             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2520             break;
2521          }
2522          break;
2523       case RXCURLOPT_OUTFILE:
2524          /* check if APPEND passed as optional argument */
2525          if ( argc == 4
2526          &&   argv[3].strlength )
2527          {
2528             if ( memcmpi( RxPackageGlobalData, argv[3].strptr, "APPEND", 6 ) == 0 )
2529                opentype = "ab";
2530          }
2531          /* parameter must be the name of a file to write to or blank to turn it off */
2532          if ( argv[2].strlength )
2533          {
2534             RexxCURLData->FilePtrs[opt] = fopen( argv[2].strptr, opentype );
2535             if ( RexxCURLData->FilePtrs[opt] == NULL )
2536             {
2537                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_FILE, INTERR_INVALID_FILE_STRING );
2538                break;
2539             }
2540          }
2541          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, RexxCURLData->FilePtrs[opt] );
2542          if ( curl_rc != CURLE_OK )
2543          {
2544             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2545             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2546             break;
2547          }
2548          switch ( RexxCurlOptions[opt].number )
2549          {
2550 #if LIBCURL_VERSION_NUM >= 0x072600
2551             case CURLOPT_WRITEDATA:
2552             case CURLOPT_HEADERDATA:
2553 #else
2554             case CURLOPT_FILE:
2555             case CURLOPT_WRITEHEADER:
2556 #endif
2557                if ( argv[2].strlength )
2558                {
2559                   /*
2560                    * Always set the write function if we have an output file
2561                    */
2562                   rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_WRITEFUNCTION, &file_write_function );
2563                   if ( curl_rc != CURLE_OK )
2564                   {
2565                      SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2566                      SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2567                      break;
2568                   }
2569                }
2570                break;
2571             default:
2572                break;
2573          }
2574          break;
2575       case RXCURLOPT_ERRFILE:
2576          /* check if APPEND passed as optional argument */
2577          if ( argc == 4
2578          &&   argv[3].strlength )
2579          {
2580             if ( memcmpi( RxPackageGlobalData, argv[3].strptr, "APPEND", 6 ) == 0 )
2581                opentype = "ab";
2582          }
2583          /* parameter must be the name of a file to write to or blank to turn it off */
2584          if ( argv[2].strlength )
2585          {
2586             RexxCURLData->FilePtrs[opt] = fopen( argv[2].strptr, opentype );
2587             if ( RexxCURLData->FilePtrs[opt] == NULL )
2588             {
2589                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_FILE, INTERR_INVALID_FILE_STRING );
2590                break;
2591             }
2592          }
2593          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, RexxCURLData->FilePtrs[opt] );
2594          if ( curl_rc != CURLE_OK )
2595          {
2596             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2597             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2598             break;
2599          }
2600          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_DEBUGDATA, RexxCURLData->FilePtrs[opt] );
2601          if ( curl_rc != CURLE_OK )
2602          {
2603             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2604             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2605             break;
2606          }
2607          switch ( RexxCurlOptions[opt].number )
2608          {
2609             case CURLOPT_STDERR:
2610                if ( argv[2].strlength )
2611                {
2612                   /*
2613                    * Always set the write function if we have an output file
2614                    */
2615                   rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_DEBUGFUNCTION, &debug_function );
2616                   if ( curl_rc != CURLE_OK )
2617                   {
2618                      SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2619                      SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2620                      break;
2621                   }
2622                }
2623                break;
2624             default:
2625                break;
2626          }
2627          break;
2628 
2629       case RXCURLOPT_INFILE:
2630          /* parameter must be the name of a file to read from or blank to turn it off */
2631          if ( argv[2].strlength )
2632          {
2633             RexxCURLData->FilePtrs[opt] = fopen( argv[2].strptr, "rb" );
2634             if ( RexxCURLData->FilePtrs[opt] == NULL )
2635             {
2636                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_FILE, INTERR_INVALID_FILE_STRING );
2637                break;
2638             }
2639          }
2640          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, RexxCURLData->FilePtrs[opt] );
2641          if ( curl_rc != CURLE_OK )
2642          {
2643             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2644             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2645             break;
2646          }
2647          /*
2648           * Now do some extra stuff depending on the option specified...
2649           */
2650          switch ( RexxCurlOptions[opt].number )
2651          {
2652 #if LIBCURL_VERSION_NUM >= 0x072600
2653             case CURLOPT_READDATA:
2654 #else
2655             case CURLOPT_INFILE:
2656 #endif
2657                /*
2658                 * Always set the file size for the specified INFILE
2659                 */
2660                if ( argv[2].strlength )
2661                {
2662                   file_size = get_file_size( RxPackageGlobalData, argv[2].strptr );
2663                }
2664                else
2665                {
2666                   file_size = 0;
2667                }
2668                if ( file_size == -1 )
2669                {
2670                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_FILE, INTERR_INVALID_FILE_STRING );
2671                   break;
2672                }
2673                /*
2674                 * Determine which option to use based on file size
2675                 */
2676 #if LIBCURL_VERSION_NUM >= 0x070b00
2677                if ( file_size > RexxCURLData->max_long )
2678                {
2679                   rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_INFILESIZE_LARGE, file_size );
2680                }
2681                else
2682 #endif
2683                {
2684                   rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_INFILESIZE, (long)file_size );
2685                }
2686                if ( curl_rc != CURLE_OK )
2687                {
2688                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2689                   SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2690                   break;
2691                }
2692                if ( argv[2].strlength )
2693                {
2694                   /*
2695                    * Always set the read function if we have an input file. This is because
2696                    * Win32/64 port requires it!
2697                    */
2698                   rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_READFUNCTION, &file_read_function );
2699                   if ( curl_rc != CURLE_OK )
2700                   {
2701                      SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2702                      SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2703                      break;
2704                   }
2705                }
2706                break;
2707             default:
2708                break;
2709          }
2710 
2711          break;
2712       case RXCURLOPT_INFILENAME:
2713          if ( argv[2].strlength == 0
2714          &&   RexxCurlOptions[opt].number == CURLOPT_COOKIEFILE )
2715          {
2716             /* parameter can be blank for COOKIEFILE */
2717          }
2718          else
2719          {
2720             /* parameter must be the name of a file that we can read; so open it */
2721             RexxCURLData->FilePtrs[opt] = fopen( argv[2].strptr, "rb" );
2722             if ( RexxCURLData->FilePtrs[opt] == NULL )
2723             {
2724                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_FILE, INTERR_INVALID_FILE_STRING );
2725                break;
2726             }
2727             /* close the file and set ptr to NULL */
2728             fclose( RexxCURLData->FilePtrs[opt] );
2729             break;
2730          }
2731          RexxCURLData->FilePtrs[opt] = NULL;
2732 
2733          /* copy the arg to pass to cURL */
2734          if ( RexxCURLData->StringPtrs[opt] )
2735             free( RexxCURLData->StringPtrs[opt] );
2736          RexxCURLData->StringPtrs[opt] = (char *)malloc( argv[2].strlength + 1 );
2737          if ( RexxCURLData->StringPtrs[opt] == NULL )
2738          {
2739             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
2740             break;
2741          }
2742          memcpy( RexxCURLData->StringPtrs[opt], argv[2].strptr, argv[2].strlength );
2743          RexxCURLData->StringPtrs[opt][argv[2].strlength] = '\0';
2744          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, RexxCURLData->StringPtrs[opt] );
2745          if ( curl_rc != CURLE_OK )
2746          {
2747             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2748             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2749             break;
2750          }
2751 
2752          break;
2753       case RXCURLOPT_INSTEM:
2754          /*
2755           * Check that arg[2] is a stem, then convert the stem into
2756           * a string of values
2757           */
2758          if ( argv[2].strlength
2759          &&   argv[2].strptr[argv[2].strlength-1] != '.' )
2760          {
2761             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
2762             break;
2763          }
2764          if ( GetRexxVariableInteger( RxPackageGlobalData, argv[2].strptr, &sub_opt, 0 ) == NULL )
2765          {
2766             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
2767             break;
2768          }
2769          /*
2770           * Reset the rxstring ptr if previously set
2771           */
2772          if ( RexxCURLData->instem_options[opt] )
2773          {
2774             if (RexxCURLData->instem_options[opt]->str.strptr)
2775             {
2776                free( RexxCURLData->instem_options[opt]->str.strptr );
2777             }
2778             RexxCURLData->instem_options[opt]->str.strlength = 0;
2779             RexxCURLData->instem_options[opt]->str.strptr = NULL;
2780             RexxCURLData->instem_options[opt]->str.strlength = 0;
2781             RexxCURLData->instem_options[opt]->index = 0;
2782             free( RexxCURLData->instem_options[opt] );
2783             RexxCURLData->instem_options[opt] = NULL;
2784          }
2785          /*
2786           * Allocate new instem_option
2787           */
2788          RexxCURLData->instem_options[opt] = (instem_option *)malloc( sizeof(instem_option) );
2789          if ( RexxCURLData->instem_options[opt] == NULL )
2790          {
2791             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
2792             break;
2793          }
2794 
2795          for ( i = 1; i <= sub_opt; i++ )
2796          {
2797             if ( GetRexxVariable( RxPackageGlobalData, argv[2].strptr, &value, i ) == NULL )
2798             {
2799                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
2800                return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
2801             }
2802             if ( RexxCURLData->instem_options[opt]->str.strptr == NULL )
2803             {
2804                RexxCURLData->instem_options[opt]->str.strptr = (char *)malloc( value.strlength + 2 );
2805                if ( RexxCURLData->instem_options[opt]->str.strptr == NULL )
2806                {
2807                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
2808                   break;
2809                }
2810                strcpy( RexxCURLData->instem_options[opt]->str.strptr, "" );
2811                RexxCURLData->instem_options[opt]->str.strlength = 0;
2812                RexxCURLData->instem_options[opt]->index = 0;
2813                RexxCURLData->instem_options[opt]->RxPackageGlobalData = RxPackageGlobalData;
2814 //               tmp = RexxCURLData->RxStrings[opt].strptr;
2815             }
2816             else
2817             {
2818                RexxCURLData->instem_options[opt]->str.strptr = (char *)realloc( RexxCURLData->instem_options[opt]->str.strptr, RexxCURLData->instem_options[opt]->str.strlength + value.strlength + 2);
2819                if ( RexxCURLData->instem_options[opt]->str.strptr == NULL )
2820                {
2821                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
2822                   break;
2823                }
2824             }
2825             strcat( RexxCURLData->instem_options[opt]->str.strptr, value.strptr );
2826             RexxCURLData->instem_options[opt]->str.strlength += value.strlength;
2827             /*
2828              * Free the memory allocated in GetRexxVariable()
2829              */
2830             FREE_TSD( RxPackageGlobalData, value.strptr );
2831          }
2832          InternalTrace( RxPackageGlobalData, "CurlSetopt(RXCURLOPT_INSTEM)", "Value: <%s>", (RexxCURLData->instem_options[opt]->str.strptr) ? RexxCURLData->instem_options[opt]->str.strptr : "" );
2833 
2834          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_POSTFIELDSIZE, RexxCURLData->instem_options[opt]->str.strlength );
2835          if ( curl_rc != CURLE_OK )
2836          {
2837             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2838             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2839             break;
2840          }
2841          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_READFUNCTION, stem_read_function );
2842          if ( curl_rc != CURLE_OK )
2843          {
2844             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2845             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2846             break;
2847          }
2848          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_READDATA, RexxCURLData->instem_options[opt] );
2849          if ( curl_rc != CURLE_OK )
2850          {
2851             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2852             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2853             break;
2854          }
2855          break;
2856       case RXCURLOPT_LONG:
2857          if ( RxStrToLong( RxPackageGlobalData, &argv[2], &long_opt ) != 0 )
2858          {
2859             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_NUMBER, INTERR_INVALID_NUMBER_STRING );
2860             break;
2861          }
2862          FunctionTrace( RxPackageGlobalData, "CurlSetopt", "Setting LONG value: %ld", long_opt );
2863          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, long_opt );
2864          if ( curl_rc != CURLE_OK )
2865          {
2866             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2867             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2868             break;
2869          }
2870          break;
2871       case RXCURLOPT_LONGLONG:
2872       {
2873          CURLoption opt_num;
2874          int opt_long_long = 0;
2875 
2876          /*
2877           * Do we try and compare the passed value against MAX_LONG and call
2878           * the LONG option setting instead of the LARGE option???????
2879           */
2880          opt_num = RexxCurlOptions[opt].number;
2881          switch ( RexxCurlOptions[opt].number )
2882          {
2883 #if LIBCURL_VERSION_NUM >= 0x070b00
2884             case CURLOPT_RESUME_FROM:
2885                opt_num = CURLOPT_RESUME_FROM_LARGE;
2886                opt_long_long = 1;
2887                break;
2888 #endif
2889 #if LIBCURL_VERSION_NUM >= 0x070a09
2890             case CURLOPT_MAXFILESIZE:
2891                opt_num = CURLOPT_MAXFILESIZE_LARGE;
2892                opt_long_long = 1;
2893                break;
2894 #endif
2895 #if LIBCURL_VERSION_NUM >= 0x070e05
2896             case CURLOPT_MAX_SEND_SPEED_LARGE:
2897                opt_long_long = 1;
2898                break;
2899 #endif
2900 #if LIBCURL_VERSION_NUM >= 0x070e05
2901             case CURLOPT_MAX_RECV_SPEED_LARGE:
2902                opt_long_long = 1;
2903                break;
2904 #endif
2905             default:
2906                break;
2907          }
2908          if ( opt_long_long )
2909          {
2910             if ( RxStrToLongLong( RxPackageGlobalData, &argv[2], &longlong_opt ) != 0 )
2911             {
2912                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_NUMBER, INTERR_INVALID_NUMBER_STRING );
2913                break;
2914             }
2915             sprintf( tmp_format, "Setting LONGLONG value: %s", RX_LL_FORMAT );
2916             FunctionTrace( RxPackageGlobalData, "CurlSetopt", tmp_format, longlong_opt );
2917             rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, opt_num, longlong_opt );
2918          }
2919          else
2920          {
2921             if ( RxStrToLong( RxPackageGlobalData, &argv[2], &long_opt ) != 0 )
2922             {
2923                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_NUMBER, INTERR_INVALID_NUMBER_STRING );
2924                break;
2925             }
2926             FunctionTrace( RxPackageGlobalData, "CurlSetopt", "Setting LONG(LONG) value: %ld", long_opt );
2927             rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, opt_num, long_opt );
2928          }
2929          if ( curl_rc != CURLE_OK )
2930          {
2931             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2932             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2933             break;
2934          }
2935          break;
2936       }
2937       case RXCURLOPT_BOOL:
2938          if ( RxStrToBool( RxPackageGlobalData, &argv[2], (unsigned long *)&long_opt ) != 0 )
2939          {
2940             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_BOOL, INTERR_INVALID_BOOL_STRING );
2941             break;
2942          }
2943          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, long_opt );
2944          if ( curl_rc != CURLE_OK )
2945          {
2946             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2947             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2948             break;
2949          }
2950          break;
2951       case RXCURLOPT_BITMAP_AUTH:
2952       case RXCURLOPT_BITMAP_REDIR:
2953       case RXCURLOPT_BITMAP_SSHAUTH:
2954       case RXCURLOPT_FTPSSL:
2955       case RXCURLOPT_FTPSSLAUTH:
2956       case RXCURLOPT_FTPSSLCCC:
2957       case RXCURLOPT_SSL_OPTIONS:
2958          long_opt = 0L;
2959          for ( i = 2; i < (int)argc; i++ )
2960          {
2961             sub_opt = find_suboption( RxPackageGlobalData, argv[i].strptr, argv[i].strlength, RexxCurlOptions[opt].optiontype );
2962             if ( sub_opt == (-1) )
2963             {
2964                char buf[1024];
2965                sprintf( buf, "%s: %s", INTERR_INVALID_OPTION_STRING, argv[i].strptr );
2966                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_OPTION, buf );
2967                break;
2968             }
2969             long_opt |= RexxCurlSubOptions[sub_opt].number;
2970          }
2971          if ( sub_opt == (-1) )
2972             break;
2973          FunctionTrace( RxPackageGlobalData, "CurlSetopt", "Setting BITMAP value: %x", long_opt );
2974          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, long_opt );
2975          if ( curl_rc != CURLE_OK )
2976          {
2977             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
2978             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
2979             break;
2980          }
2981          break;
2982       case RXCURLOPT_POLICY:
2983       case RXCURLOPT_PROXYTYPE:
2984       case RXCURLOPT_HTTP_VERSION:
2985       case RXCURLOPT_NETRC:
2986       case RXCURLOPT_TIMECOND:
2987       case RXCURLOPT_IPRESOLVE:
2988       case RXCURLOPT_FTP_CREATE_MISSING_DIRS:
2989       case RXCURLOPT_RTSP_REQUEST:
2990       case RXCURLOPT_PROTOCOLS:
2991          /*
2992           * This handles sub-options that result in a long value passed to CURL_EASY_SETOPT()
2993           */
2994          sub_opt = find_suboption( RxPackageGlobalData, argv[2].strptr, argv[2].strlength, RexxCurlOptions[opt].optiontype );
2995          if ( sub_opt == (-1) )
2996          {
2997             char buf[1024];
2998             sprintf( buf, "%s: %s", INTERR_INVALID_OPTION_STRING, argv[2].strptr );
2999             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_OPTION, buf );
3000             break;
3001          }
3002          long_opt = RexxCurlSubOptions[sub_opt].number;
3003          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, long_opt );
3004          if ( curl_rc != CURLE_OK )
3005          {
3006             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3007             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3008             break;
3009          }
3010          break;
3011       case RXCURLOPT_LIST:
3012          /*
3013           * Check that arg[2] is a stem, then convert the stem into
3014           * a cURL linked list
3015           */
3016          if ( argv[2].strptr[argv[2].strlength-1] != '.' )
3017          {
3018             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3019             break;
3020          }
3021 /* can't do this on ooRexx 4.x as strptr is const         argv[2].strptr[argv[2].strlength] = '\0'; */
3022          if ( GetRexxVariableInteger( RxPackageGlobalData, argv[2].strptr, &sub_opt, 0 ) == NULL )
3023          {
3024             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3025             break;
3026          }
3027          if ( RexxCURLData->SListPtrs[opt] )
3028          {
3029             CURL_SLIST_FREE_ALL( RexxCURLData->SListPtrs[opt] );
3030             RexxCURLData->SListPtrs[opt] = NULL;
3031          }
3032          for ( i = 1; i <= sub_opt; i++ )
3033          {
3034             if ( GetRexxVariable( RxPackageGlobalData, argv[2].strptr, &value, i ) == NULL )
3035             {
3036                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3037                return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3038             }
3039             InternalTrace( RxPackageGlobalData, "CurlSetopt(RXCURLOPT_LIST)", "Variable: <%s%d> Value: <%s>", argv[2].strptr, i, value.strptr );
3040             RexxCURLData->SListPtrs[opt] = CURL_SLIST_APPEND( RexxCURLData->SListPtrs[opt], value.strptr );
3041             /*
3042              * Free the memory allocated in GetRexxVariable()
3043              */
3044             FREE_TSD( RxPackageGlobalData, value.strptr );
3045             if ( RexxCURLData->SListPtrs[opt] == NULL )
3046             {
3047                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3048                return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3049             }
3050          }
3051          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, RexxCURLData->SListPtrs[opt] );
3052          if ( curl_rc != CURLE_OK )
3053          {
3054             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3055             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3056             break;
3057          }
3058          break;
3059       case RXCURLOPT_POST_DATA:
3060          /*
3061           * Check that arg[2] is a stem, then convert the stem into a name/value pair for formdata
3062           */
3063          if ( argv[2].strlength
3064          &&   argv[2].strptr[argv[2].strlength-1] != '.' )
3065          {
3066             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3067             break;
3068          }
3069 /* can't do this on ooRexx 4.x as strptr is const         argv[2].strptr[argv[2].strlength] = '\0'; */
3070          if ( GetRexxVariableInteger( RxPackageGlobalData, argv[2].strptr, &sub_opt, 0 ) == NULL )
3071          {
3072             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3073             break;
3074          }
3075          if ( RexxCURLData->HttpPostFirstPtrs[opt] )
3076          {
3077             CURL_FORMFREE( RexxCURLData->HttpPostFirstPtrs[opt] );
3078          }
3079          RexxCURLData->HttpPostFirstPtrs[opt] = NULL;
3080          RexxCURLData->HttpPostLastPtrs[opt] = NULL;
3081          for ( i = 1; i <= sub_opt; i++ )
3082          {
3083             char *fd_name=NULL, *fd_value=NULL;
3084             if ( GetRexxVariable( RxPackageGlobalData, argv[2].strptr, &value, i ) == NULL )
3085             {
3086                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3087                return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3088             }
3089             fd_name = value.strptr;
3090             for ( j = 0; j < value.strlength; j++ )
3091             {
3092                if ( value.strptr[j] == '=' )
3093                {
3094                   value.strptr[j] = '\0';
3095                   fd_value = &value.strptr[j+1];
3096                   break;
3097                }
3098             }
3099             if ( fd_value == NULL )
3100             {
3101                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_STEM_VALUE, INTERR_STEM_VALUE_STRING );
3102                return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3103             }
3104             InternalTrace( RxPackageGlobalData, "CurlSetopt(RXCURLOPT_POST_DATA)", "Variable: <%s%d> Name: <%s> Value: <%s>", argv[2].strptr, i, fd_name, fd_value );
3105             rc = curlformadd_rc = CURL_FORMADD( &RexxCURLData->HttpPostFirstPtrs[opt], &RexxCURLData->HttpPostLastPtrs[opt], CURLFORM_COPYNAME, fd_name, CURLFORM_COPYCONTENTS, fd_value, CURLFORM_CONTENTSLENGTH, strlen(fd_value), CURLFORM_END );
3106             /*
3107              * Free the memory allocated in GetRexxVariable()
3108              */
3109             FREE_TSD( RxPackageGlobalData, value.strptr );
3110             if ( curlformadd_rc != CURL_FORMADD_OK )
3111             {
3112                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3113                SetCURLError( RxPackageGlobalData,  (CURLcode)curlformadd_rc, curl_formadd_errors[rc] );
3114                return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3115             }
3116          }
3117          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, RexxCURLData->HttpPostFirstPtrs[opt] );
3118          if ( curl_rc != CURLE_OK )
3119          {
3120             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3121             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3122             break;
3123          }
3124          break;
3125       case RXCURLOPT_POST_FORM:
3126          /*
3127           * Always look for HTTPPOSTFORM option
3128           */
3129          opt = find_option( RxPackageGlobalData, "HTTPPOSTFORM", 12 );
3130          if ( opt == (-1) )
3131          {
3132             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_OPTION, INTERR_INVALID_OPTION_STRING );
3133             return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3134          }
3135          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, RexxCURLData->HttpPostFirstPtrs[opt] );
3136          if ( curl_rc != CURLE_OK )
3137          {
3138             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3139             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3140             break;
3141          }
3142          break;
3143       case RXCURLOPT_POST_FIELDS:
3144          /*
3145           * Check that arg[2] is a stem, then convert the stem into
3146           * a string of values
3147           */
3148          if ( argv[2].strlength
3149          &&   argv[2].strptr[argv[2].strlength-1] != '.' )
3150          {
3151             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3152             break;
3153          }
3154 /* can't do this on ooRexx 4.x as strptr is const         argv[2].strptr[argv[2].strlength] = '\0'; */
3155          if ( GetRexxVariableInteger( RxPackageGlobalData, argv[2].strptr, &sub_opt, 0 ) == NULL )
3156          {
3157             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3158             break;
3159          }
3160          /*
3161           * Reset the string ptr if previously set
3162           */
3163          if ( RexxCURLData->StringPtrs[opt] )
3164          {
3165             free( RexxCURLData->StringPtrs[opt] );
3166             RexxCURLData->StringPtrs[opt] = NULL;
3167          }
3168          for ( i = 1; i <= sub_opt; i++ )
3169          {
3170             if ( GetRexxVariable( RxPackageGlobalData, argv[2].strptr, &value, i ) == NULL )
3171             {
3172                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3173                return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3174             }
3175             if ( RexxCURLData->StringPtrs[opt] == NULL )
3176             {
3177                RexxCURLData->StringPtrs[opt] = (char *)malloc( value.strlength + 2 );
3178                if ( RexxCURLData->StringPtrs[opt] == NULL )
3179                {
3180                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3181                   break;
3182                }
3183                strcpy( RexxCURLData->StringPtrs[opt], "" );
3184                tmp = RexxCURLData->StringPtrs[opt];
3185             }
3186             else
3187             {
3188                RexxCURLData->StringPtrs[opt] = (char *)realloc( RexxCURLData->StringPtrs[opt], strlen( RexxCURLData->StringPtrs[opt]) + value.strlength + 2 );
3189                if ( RexxCURLData->StringPtrs[opt] == NULL )
3190                {
3191                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3192                   break;
3193                }
3194             }
3195             /*
3196              * Change of behaviour!  The data should posted shold NOT be changed from what
3197              * the user specifies. To support previous versions, allow optional 3rd arg of
3198              * '&' to prepend '&' between stem values
3199              */
3200             if ( argc > 3
3201             &&   argv[3].strlength > 0 )
3202             {
3203                /* Concatenate argv[3].strptr and the new value to the previous string value
3204                 * Don't prepend for first option
3205                 */
3206                if ( i != 1 )
3207                {
3208                   strcat( RexxCURLData->StringPtrs[opt], argv[3].strptr );
3209                   count += argv[3].strlength;
3210                }
3211             }
3212             strcat( RexxCURLData->StringPtrs[opt], value.strptr );
3213             count += value.strlength;
3214             /*
3215              * Free the memory allocated in GetRexxVariable()
3216              */
3217             FREE_TSD( RxPackageGlobalData, value.strptr );
3218          }
3219          InternalTrace( RxPackageGlobalData, "CurlSetopt(RXCURLOPT_POST_FIELDS)", "Value: <%s> Length: %d", (RexxCURLData->StringPtrs[opt]) ? RexxCURLData->StringPtrs[opt] : "", count );
3220          /*
3221           * Set the length of the generated string...
3222           */
3223          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_POSTFIELDSIZE, count );
3224          if ( curl_rc != CURLE_OK )
3225          {
3226             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3227             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3228             break;
3229          }
3230          /*
3231           * Set the string
3232           */
3233          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, RexxCurlOptions[opt].number, RexxCURLData->StringPtrs[opt] );
3234 //         rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_COPYPOSTFIELDS, RexxCURLData->StringPtrs[opt] );
3235          if ( curl_rc != CURLE_OK )
3236          {
3237             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3238             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3239             break;
3240          }
3241          break;
3242       case RXCURLOPT_OUTSTEM:
3243          /*
3244           * Check that arg[2] is a stem, then setup the write callback
3245           */
3246          if ( argv[2].strlength
3247          &&   argv[2].strptr[argv[2].strlength-1] != '.' )
3248          {
3249             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3250             break;
3251          }
3252          /*
3253           * Save the stem name for the write function...
3254           */
3255          if ( RexxCURLData->StringPtrs[opt] )
3256             free( RexxCURLData->StringPtrs[opt] );
3257          RexxCURLData->StringPtrs[opt] = (char *)malloc( argv[2].strlength + 1 );
3258          if ( RexxCURLData->StringPtrs[opt] == NULL )
3259          {
3260             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3261             break;
3262          }
3263          memcpy( RexxCURLData->StringPtrs[opt], argv[2].strptr, argv[2].strlength );
3264          RexxCURLData->StringPtrs[opt][argv[2].strlength] = '\0';
3265          /*
3266           * Set these globals to allow the write function to know which
3267           * compound variable to write.
3268           */
3269          RexxCURLData->outstem_index = opt;
3270          RexxCURLData->outstem_tail = 0;
3271          if ( RexxCURLData->outstem_strptr )
3272             free( RexxCURLData->outstem_strptr );
3273          RexxCURLData->outstem_strlength = 0;
3274          if ( RexxCURLData->outstem_line_terminator )
3275             free( RexxCURLData->outstem_line_terminator );
3276          RexxCURLData->outstem_line_terminator = 0;
3277          /*
3278           * If we have the optional line terminator (argument 3), allocate space here
3279           * and copy it.  No terminator, default to LF (which was original terminator)
3280           */
3281          if ( argc == 4
3282          &&   argv[3].strlength )
3283          {
3284             ltlen = argv[3].strlength;
3285             ltstr = argv[3].strptr;
3286          }
3287          else
3288          {
3289             ltlen = strlen( eol );
3290             ltstr = eol;
3291          }
3292          RexxCURLData->outstem_line_terminator = malloc( ltlen + 1 );
3293          if ( RexxCURLData->outstem_line_terminator == NULL )
3294          {
3295             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3296             break;
3297          }
3298          strcpy( RexxCURLData->outstem_line_terminator, ltstr );
3299          /*
3300           * Set our write function to store the content
3301           */
3302          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_WRITEFUNCTION, &outstem_write_function );
3303          if ( curl_rc != CURLE_OK )
3304          {
3305             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3306             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3307             break;
3308          }
3309          break;
3310       case RXCURLOPT_HEADERSTEM:
3311          /*
3312           * Check that arg[2] is a stem, then setup the write callback
3313           */
3314          if ( argv[2].strlength
3315          &&   argv[2].strptr[argv[2].strlength-1] != '.' )
3316          {
3317             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3318             break;
3319          }
3320          /*
3321           * Save the stem name for the write function...
3322           */
3323          if ( RexxCURLData->StringPtrs[opt] )
3324             free( RexxCURLData->StringPtrs[opt] );
3325          RexxCURLData->StringPtrs[opt] = (char *)malloc( argv[2].strlength + 1 );
3326          if ( RexxCURLData->StringPtrs[opt] == NULL )
3327          {
3328             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3329             break;
3330          }
3331          memcpy( RexxCURLData->StringPtrs[opt], argv[2].strptr, argv[2].strlength );
3332          RexxCURLData->StringPtrs[opt][argv[2].strlength] = '\0';
3333          /*
3334           * Set these globals to allow the write function to know which
3335           * compound variable to write.
3336           */
3337          RexxCURLData->headerstem_index = opt;
3338          RexxCURLData->headerstem_tail = 0;
3339 
3340          rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_HEADERFUNCTION, &headerstem_write_function );
3341          if ( curl_rc != CURLE_OK )
3342          {
3343             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3344             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3345             break;
3346          }
3347          break;
3348       case RXCURLOPT_CALLBACK:
3349          if ( RexxCURLData->StringPtrs[opt] )
3350             free( RexxCURLData->StringPtrs[opt] );
3351          RexxCURLData->StringPtrs[opt] = (char *)malloc( argv[2].strlength + 1 );
3352          if ( RexxCURLData->StringPtrs[opt] == NULL )
3353          {
3354             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3355             break;
3356          }
3357          memcpy( RexxCURLData->StringPtrs[opt], argv[2].strptr, argv[2].strlength );
3358          RexxCURLData->StringPtrs[opt][argv[2].strlength] = '\0';
3359          /*
3360           * Do any extra processing here for some options
3361           */
3362          switch( RexxCurlOptions[opt].number )
3363          {
3364             case CURLOPT_PROGRESSFUNCTION:
3365                rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_NOPROGRESS, 0 );
3366                if ( curl_rc != CURLE_OK )
3367                {
3368                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3369                   SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3370                   break;
3371                }
3372                rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_PROGRESSFUNCTION, &rexxcurl_progress_callback );
3373                if ( curl_rc != CURLE_OK )
3374                {
3375                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3376                   SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3377                   break;
3378                }
3379                rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_PROGRESSDATA, RxPackageGlobalData );
3380                if ( curl_rc != CURLE_OK )
3381                {
3382                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3383                   SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3384                   break;
3385                }
3386                RexxCURLData->progress_index = opt;
3387                break;
3388             case CURLOPT_SSH_KEYFUNCTION:
3389                rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_SSH_KEYFUNCTION, &rexxcurl_sshkey_callback );
3390                if ( curl_rc != CURLE_OK )
3391                {
3392                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3393                   SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3394                   break;
3395                }
3396                rc = curl_rc = CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_SSH_KEYDATA, RxPackageGlobalData );
3397                if ( curl_rc != CURLE_OK )
3398                {
3399                   SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3400                   SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3401                   break;
3402                }
3403                RexxCURLData->progress_index = opt;
3404                break;
3405             default:
3406                break;
3407          }
3408          break;
3409       default:
3410          /* error */
3411          break;
3412    }
3413    return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3414 }
3415 
rxfunc(CurlReset)3416 rxfunc( CurlReset )
3417 {
3418    ULONG rc = 0L;
3419    long curl;
3420    REXXCURLDATA *RexxCURLData;
3421    /*
3422     * Get thread-safe-data
3423     */
3424    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
3425    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
3426    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
3427 
3428    if ( RexxCURLData->g_curl_error) ClearCURLError( RxPackageGlobalData );
3429    if ( RexxCURLData->g_rexxcurl_error) ClearIntError( RxPackageGlobalData );
3430    if ( my_checkparam( RxPackageGlobalData, name, argc, 1, 1 ) )
3431       return( 1 );
3432    if ( RxStrToLong( RxPackageGlobalData, &argv[0], &curl ) != 0 )
3433    {
3434       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_HANDLE, INTERR_INVALID_HANDLE_STRING );
3435       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3436    }
3437    CURL_EASY_RESET( (CURL *)curl );
3438    return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3439 }
3440 
3441 /*
3442  * Equivalent of curl_formadd()
3443  * Args:
3444  *   curl handle
3445  *   option - COPYCONTENTS or FILECONTENTS
3446  *   name of section
3447  *   data for COPYCONTENTS or multiple content type/filename for FILECONTENTS
3448  *
3449  *   call curlformadd curl, 'COPYCONTENTS', 'htmlcode', 'text/html', mydata
3450  *   call curlformadd curl, 'FILE', 'moreimages', 'image/jpeg', 'pic1.jpg', , 'pic2.jpg'
3451  *   content.1 = 'image/jpeg'; filename.1 = 'pic1.jpg'
3452  *   content.2 = 'text/html' ; filename.2 = 'index.html'
3453  *   content.2 = ''          ; filename.2 = 'pic2.jpg'
3454  *   content.0 = 3; filename.0 = 3
3455  *   call curlformadd curl, 'FILE', 'imagesandhtml', 'content.', 'filename.'
3456  *   call curlsetopt curl, 'HTTPPOSTFORM'
3457  *   call curlperform curl
3458  *   call curlformfree curl
3459 
3460 
3461 array:
3462   i=0 content.1 -> cf[0].option = CONTENTYTPE; cf[0].value = content.1
3463   i=0 filename.1 -> cf[1].option = CONTENTYTPE; cf[1].value = filename.1
3464   i=1 content.2 -> cf[2].option = CONTENTYTPE; cf[2].value = content.1
3465   i=1 filename.2 -> cf[3].option = CONTENTYTPE; cf[3].value = filename.1
3466  */
rxfunc(CurlFormAdd)3467 rxfunc( CurlFormAdd )
3468 {
3469    ULONG rc = 0L;
3470    long curl;
3471    int i,opt;
3472    CURLFORMcode curl_rc;
3473    int count,idx,num_buffers,contenttype;
3474    struct curl_forms *cf;
3475    RXSTRING *values;
3476    REXXCURLDATA *RexxCURLData;
3477    /*
3478     * Get thread-safe-data
3479     */
3480    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
3481    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
3482    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
3483 
3484    if ( RexxCURLData->g_curl_error) ClearCURLError( RxPackageGlobalData );
3485    if ( RexxCURLData->g_rexxcurl_error) ClearIntError( RxPackageGlobalData );
3486    if ( my_checkparam( RxPackageGlobalData, name, argc, 5, 0 ) )
3487       return( 1 );
3488    if ( RxStrToLong( RxPackageGlobalData, &argv[0], &curl ) != 0 )
3489    {
3490       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_HANDLE, INTERR_INVALID_HANDLE_STRING );
3491       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3492    }
3493    /*
3494     * Always look for HTTPPOSTFORM option
3495     */
3496    opt = find_option( RxPackageGlobalData, "HTTPPOSTFORM", 12 );
3497    if ( opt == (-1) )
3498    {
3499       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_OPTION, INTERR_INVALID_OPTION_STRING );
3500       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3501    }
3502    if ( memcmpi( RxPackageGlobalData, "COPYCONTENTS", argv[1].strptr, argv[1].strlength ) == 0 )
3503    {
3504       if ( !RXVALIDSTRING( argv[2] ) )
3505       {
3506          SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_MANDATORY_FIELD, INTERR_MANDATORY_FIELD_STRING );
3507          return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3508       }
3509       InternalTrace( RxPackageGlobalData, "CurlFormAdd(COPYCONTENTS)", "Name: <%s> ContentType: <%s> Value: <%s>", argv[2].strptr, argv[3].strptr, argv[4].strptr );
3510       rc = curl_rc = CURL_FORMADD( &RexxCURLData->HttpPostFirstPtrs[opt],
3511                                    &RexxCURLData->HttpPostLastPtrs[opt],
3512                                    CURLFORM_COPYNAME,
3513                                    argv[2].strptr,
3514                                    CURLFORM_NAMELENGTH,
3515                                    argv[2].strlength,
3516                                    CURLFORM_CONTENTTYPE,
3517                                    argv[3].strptr,
3518                                    CURLFORM_COPYCONTENTS,
3519                                    argv[4].strptr,
3520                                    CURLFORM_CONTENTSLENGTH,
3521                                    argv[4].strlength,
3522                                    CURLFORM_END );
3523       if ( curl_rc != CURLE_OK )
3524       {
3525          SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3526          SetCURLError( RxPackageGlobalData,  (CURLcode)curl_rc, curl_formadd_errors[rc] );
3527          return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3528       }
3529    }
3530    else if ( memcmpi( RxPackageGlobalData, "FILE", argv[1].strptr, argv[1].strlength ) == 0 )
3531    {
3532       /*
3533        * Check if we are using the array option
3534        */
3535       if ( argc == 5
3536       &&   argv[3].strptr[argv[3].strlength-1] == '.'
3537       &&   argv[4].strptr[argv[4].strlength-1] == '.' )
3538       {
3539          /*
3540           * arg[3] is array of contenttype, arg[4] is array of filenames
3541           */
3542          if ( GetRexxVariableInteger( RxPackageGlobalData, argv[3].strptr, &count, 0 ) == NULL )
3543          {
3544             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3545             return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3546          }
3547          num_buffers = 1 + (count * 2);
3548          /*
3549           * Get an array of curl_forms structures; two for each stem item
3550           */
3551          cf = (struct curl_forms *)malloc( num_buffers*sizeof(struct curl_forms) );
3552          if ( cf == NULL )
3553          {
3554             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3555             return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3556          }
3557          /*
3558           * Get an array of RXSTRINGs; one for each stem item
3559           */
3560          values = (RXSTRING *)malloc( count*sizeof(RXSTRING) );
3561          if ( values == NULL )
3562          {
3563             free( cf );
3564             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3565             return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3566          }
3567 
3568          for ( idx = 0, i = 0; i < count; i++ )
3569          {
3570             /*
3571              * Get the contenttype stem value
3572              */
3573             if ( GetRexxVariable( RxPackageGlobalData, argv[3].strptr, &values[i], i+1 ) == NULL )
3574             {
3575                free( cf );
3576                free( values );
3577                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3578                return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3579             }
3580             /*
3581              * If the contenttype value is empty, do not add the option
3582              */
3583             if ( values[i].strlength )
3584             {
3585                cf[idx].value = values[i].strptr;
3586                cf[idx].option = CURLFORM_CONTENTTYPE;
3587                InternalTrace( RxPackageGlobalData, "CurlFormAdd", "Setting Contenttype %d Option %d Value: [%s](%d)",
3588                               i, idx, cf[idx].value, cf[idx].option );
3589                idx++;
3590             }
3591             /*
3592              * Get the filename stem value
3593              */
3594             if ( GetRexxVariable( RxPackageGlobalData, argv[4].strptr, &values[i], i+1 ) == NULL )
3595             {
3596                free( cf );
3597                free( values );
3598                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3599                return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3600             }
3601             cf[idx].option = CURLFORM_FILE;
3602             cf[idx].value = values[i].strptr;
3603             InternalTrace( RxPackageGlobalData, "CurlFormAdd", "Setting Filename %d Option %d Value: [%s](%d)",
3604                            i, idx, cf[idx].value, cf[idx].option );
3605             idx++;
3606          }
3607          cf[idx].option = CURLFORM_END;
3608          cf[idx].value = NULL;
3609          InternalTrace( RxPackageGlobalData, "CurlFormAdd", "Executing curl_formadd. Name: [%s]%d",
3610                            argv[2].strptr, argv[2].strlength );
3611          rc = curl_rc = CURL_FORMADD( &RexxCURLData->HttpPostFirstPtrs[opt],
3612                                       &RexxCURLData->HttpPostLastPtrs[opt],
3613                                       CURLFORM_COPYNAME,
3614                                       argv[2].strptr,
3615                                       CURLFORM_NAMELENGTH,
3616                                       argv[2].strlength,
3617                                       CURLFORM_ARRAY,
3618                                       cf,
3619                                       CURLFORM_END );
3620          /*
3621           * Free the memory allocated in GetRexxVariable()
3622           */
3623          for ( i = 0 ; i < count ; i++ )
3624          {
3625             FREE_TSD( RxPackageGlobalData, values[i].strptr );
3626          }
3627          free( cf );
3628          if ( curl_rc != CURLE_OK )
3629          {
3630             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3631             SetCURLError( RxPackageGlobalData,  (CURLcode)curl_rc, curl_formadd_errors[rc] );
3632             return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3633          }
3634       }
3635       else
3636       {
3637          /*
3638           * We can have any number of pairs of options after the 3rd mandatory option
3639           */
3640          if ( argc % 2 == 0 )
3641          {
3642             return 1;
3643          }
3644          /*
3645           * Number of file pairs
3646           */
3647          count = ( argc - 3 ) / 2;
3648          num_buffers = 1 + (count * 2);
3649          /*
3650           * Get an array of curl_forms structures; one for each stem item
3651           */
3652          cf = (struct curl_forms *)malloc( num_buffers*sizeof(struct curl_forms) );
3653          if ( cf == NULL )
3654          {
3655             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3656             return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3657          }
3658          /*
3659           * Get an array of RXSTRINGs; one for each stem item
3660           */
3661          values = (RXSTRING *)malloc( count*sizeof(RXSTRING) );
3662          if ( values == NULL )
3663          {
3664             free( cf );
3665             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
3666             return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3667          }
3668          contenttype = 1;
3669          for ( idx = 0, i = 3; i < argc; i++ )
3670          {
3671             /*
3672              * If the contenttype value is empty, do not add the option
3673              */
3674             if ( contenttype )
3675             {
3676                if ( RXVALIDSTRING( argv[i] ) )
3677                {
3678                   cf[idx].value = argv[i].strptr;
3679                   cf[idx].option = CURLFORM_CONTENTTYPE;
3680                   InternalTrace( RxPackageGlobalData, "CurlFormAdd", "Setting Contenttype %d Option %d Value: [%s](%d)",
3681                                  i, idx, cf[idx].value, cf[idx].option );
3682                   idx++;
3683                }
3684                contenttype = 0;
3685             }
3686             else
3687             {
3688                cf[idx].option = CURLFORM_FILE;
3689                cf[idx].value = argv[i].strptr;
3690                InternalTrace( RxPackageGlobalData, "CurlFormAdd", "Setting Filename %d Option %d Value: [%s](%d)",
3691                               i, idx, cf[idx].value, cf[idx].option );
3692                idx++;
3693                contenttype = 1;
3694             }
3695          }
3696          cf[idx].option = CURLFORM_END;
3697          cf[idx].value = NULL;
3698          InternalTrace( RxPackageGlobalData, "CurlFormAdd", "Executing curl_formadd. Name: [%s]%d",
3699                            argv[2].strptr, argv[2].strlength );
3700          rc = curl_rc = CURL_FORMADD( &RexxCURLData->HttpPostFirstPtrs[opt],
3701                                       &RexxCURLData->HttpPostLastPtrs[opt],
3702                                       CURLFORM_COPYNAME,
3703                                       argv[2].strptr,
3704                                       CURLFORM_NAMELENGTH,
3705                                       argv[2].strlength,
3706                                       CURLFORM_ARRAY,
3707                                       cf,
3708                                       CURLFORM_END );
3709          /*
3710           * Free the memory allocated in GetRexxVariable()
3711           */
3712          for ( i = 0 ; i < count ; i++ )
3713          {
3714             FREE_TSD( RxPackageGlobalData, values[i].strptr );
3715          }
3716          free( cf );
3717          if ( curl_rc != CURLE_OK )
3718          {
3719             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3720             SetCURLError( RxPackageGlobalData,  (CURLcode)curl_rc, curl_formadd_errors[rc] );
3721             return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3722          }
3723       }
3724    }
3725    else
3726    {
3727       char buf[1024];
3728       sprintf( buf, "%s: %s", INTERR_INVALID_OPTION_STRING, argv[1].strptr );
3729       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_OPTION, buf );
3730       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3731    }
3732    return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3733 }
3734 
rxfunc(CurlPerform)3735 rxfunc( CurlPerform )
3736 {
3737    long curl;
3738    CURLcode rc;
3739    char value[20]; /* big enough for an int */
3740    int valuelen,i;
3741    REXXCURLDATA *RexxCURLData;
3742    /*
3743     * Get thread-safe-data
3744     */
3745    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
3746    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
3747    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
3748 
3749    if ( RexxCURLData->g_curl_error) ClearCURLError( RxPackageGlobalData );
3750    if ( RexxCURLData->g_rexxcurl_error) ClearIntError( RxPackageGlobalData );
3751    if ( my_checkparam( RxPackageGlobalData, name, argc, 1, 1 ) )
3752       return( 1 );
3753    if ( RxStrToLong( RxPackageGlobalData, &argv[0], &curl ) != 0 )
3754    {
3755       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_HANDLE, INTERR_INVALID_HANDLE_STRING );
3756       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3757    }
3758    /*
3759     * Set the CURLOPT_ERRORBUFFER here to ensure we get a string
3760     * error if something goes wrong.
3761     */
3762    strcpy( RexxCURLData->curl_error, "" );
3763    CURL_EASY_SETOPT( (CURL *)curl, CURLOPT_ERRORBUFFER, RexxCURLData->curl_error );
3764    InternalTrace( RxPackageGlobalData, "CurlPerform", "Set ERRORBUFFER OK" );
3765    RexxCURLData->g_curl_error = rc = CURL_EASY_PERFORM( (CURL *)curl );
3766    if ( rc != 0 )
3767    {
3768       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3769       SetCURLError( RxPackageGlobalData,  rc, (char *)RexxCURLData->curl_error );
3770    }
3771    InternalTrace( RxPackageGlobalData, "CurlPerform", "curl_easy_perform exited with %d", rc );
3772    /*
3773     * For those options that return their data in a stem, we need to set
3774     * the stem.0 value to the number of stem variables actually created.
3775     */
3776    if ( RexxCURLData->outstem_index )
3777    {
3778       InternalTrace( RxPackageGlobalData, "CurlPerform", "Using OUTSTEM" );
3779       outstem_create( RxPackageGlobalData );
3780       valuelen = sprintf( value, "%d", RexxCURLData->outstem_tail );
3781       create_rexx_compound( RxPackageGlobalData, RexxCURLData->StringPtrs[RexxCURLData->outstem_index], 0, value, valuelen );
3782       RexxCURLData->outstem_index = RexxCURLData->outstem_tail = RexxCURLData->outstem_strlength = 0;
3783       if ( RexxCURLData->outstem_strptr )
3784       {
3785          free( RexxCURLData->outstem_strptr );
3786          RexxCURLData->outstem_strptr = NULL;
3787          RexxCURLData->outstem_strlength = 0;
3788       }
3789       if ( RexxCURLData->outstem_line_terminator )
3790       {
3791          free( RexxCURLData->outstem_line_terminator );
3792          RexxCURLData->outstem_line_terminator = NULL;
3793       }
3794    }
3795    if ( RexxCURLData->headerstem_index )
3796    {
3797       InternalTrace( RxPackageGlobalData, "CurlPerform", "Using HEADERSTEM" );
3798       valuelen = sprintf( value, "%d", RexxCURLData->headerstem_tail );
3799       create_rexx_compound( RxPackageGlobalData, RexxCURLData->StringPtrs[RexxCURLData->headerstem_index], 0, value, valuelen );
3800       RexxCURLData->headerstem_index = RexxCURLData->headerstem_tail = 0;
3801    }
3802    /*
3803     * If OUTFILE or INFILE is used, close it here and set the FILE * to NULL
3804     */
3805    for ( i = 0; i < NUMBER_REXXCURL_OPTIONS; i++ )
3806    {
3807       if ( ( RexxCurlOptions[i].optiontype == RXCURLOPT_OUTFILE
3808          ||  RexxCurlOptions[i].optiontype == RXCURLOPT_INFILE )
3809       &&   RexxCURLData->FilePtrs[i] )
3810       {
3811          fclose( RexxCURLData->FilePtrs[i] );
3812          RexxCURLData->FilePtrs[i] = NULL;
3813       }
3814    }
3815    return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3816 }
3817 
rxfunc(CurlGetinfo)3818 rxfunc( CurlGetinfo )
3819 {
3820    ULONG rc = 0L;
3821    CURLcode curl_rc;
3822    long curl;
3823    int opt,suboption;
3824    int idx = 0;
3825    char *return_string = NULL;
3826    double return_double;
3827    long return_long;
3828    struct curl_slist *TmpSListPtrs = NULL;
3829    struct curl_slist *OrigSListPtrs=NULL;
3830 #if LIBCURL_VERSION_NUM >= 0x071301
3831    struct curl_certinfo *TmpCertInfoPtrs = NULL;
3832 #endif
3833    char value[20]; /* big enough for an int */
3834    int valuelen,i;
3835    REXXCURLDATA *RexxCURLData;
3836    /*
3837     * Get thread-safe-data
3838     */
3839    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
3840    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
3841    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
3842 
3843    if ( RexxCURLData->g_curl_error) ClearCURLError( RxPackageGlobalData );
3844    if ( RexxCURLData->g_rexxcurl_error) ClearIntError( RxPackageGlobalData );
3845    if ( my_checkparam( RxPackageGlobalData, name, argc, 2, 3 ) )
3846       return( 1 );
3847    if ( RxStrToLong( RxPackageGlobalData, &argv[0], &curl ) != 0 )
3848    {
3849       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_HANDLE, INTERR_INVALID_HANDLE_STRING );
3850       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3851    }
3852    opt = find_getinfo( RxPackageGlobalData, argv[1].strptr, argv[1].strlength );
3853    if ( opt == (-1) )
3854    {
3855       char buf[1024];
3856       sprintf( buf, "%s: %s", INTERR_INVALID_OPTION_STRING, argv[1].strptr );
3857       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_OPTION, buf );
3858       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
3859    }
3860    switch( RexxCurlGetinfos[opt].optiontype )
3861    {
3862       case RXCURLINFO_STRING:
3863          rc = curl_rc = CURL_EASY_GETINFO( (CURL *)curl, RexxCurlGetinfos[opt].number, &return_string );
3864          if ( curl_rc != CURLE_OK )
3865          {
3866             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3867             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3868             break;
3869          }
3870          return RxReturnString( RxPackageGlobalData, retstr, return_string );
3871          break;
3872       case RXCURLINFO_DOUBLE:
3873          rc = curl_rc = CURL_EASY_GETINFO( (CURL *)curl, RexxCurlGetinfos[opt].number, &return_double );
3874          if ( curl_rc != CURLE_OK )
3875          {
3876             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3877             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3878             break;
3879          }
3880          return RxReturnDouble( RxPackageGlobalData, retstr, return_double );
3881          break;
3882       case RXCURLINFO_LONG:
3883          rc = curl_rc = CURL_EASY_GETINFO( (CURL *)curl, RexxCurlGetinfos[opt].number, &return_long );
3884          if ( curl_rc != CURLE_OK )
3885          {
3886             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3887             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3888             break;
3889          }
3890          return RxReturnNumber( RxPackageGlobalData, retstr, return_long );
3891          break;
3892       case RXCURLINFO_LIST:
3893          if ( argc != 3 )
3894          {
3895             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_TOO_FEW_ARGS, INTERR_TOO_FEW_ARGS_STRING );
3896             break;
3897          }
3898          /*
3899           * Check that we have a stem
3900           */
3901          if ( argv[2].strptr[argv[2].strlength-1] != '.' )
3902          {
3903             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3904             break;
3905          }
3906          rc = curl_rc = CURL_EASY_GETINFO( (CURL *)curl, RexxCurlGetinfos[opt].number, &TmpSListPtrs );
3907          if ( curl_rc != CURLE_OK )
3908          {
3909             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3910             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3911             break;
3912          }
3913          OrigSListPtrs = TmpSListPtrs;
3914          for ( i = 1; TmpSListPtrs; i++, TmpSListPtrs=TmpSListPtrs->next )
3915          {
3916             create_rexx_compound( RxPackageGlobalData, argv[2].strptr, i, TmpSListPtrs->data, strlen( TmpSListPtrs->data ) );
3917          }
3918          valuelen = sprintf( value, "%d", i-1 );
3919          create_rexx_compound( RxPackageGlobalData, argv[2].strptr, 0, value, valuelen );
3920          if ( OrigSListPtrs )
3921          {
3922             CURL_SLIST_FREE_ALL( OrigSListPtrs );
3923          }
3924          return RxReturnNumber( RxPackageGlobalData, retstr, i-1 );
3925          break;
3926 #if LIBCURL_VERSION_NUM >= 0x071301
3927       case RXCURLINFO_CERTINFO:
3928          if ( argc != 3 )
3929          {
3930             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_TOO_FEW_ARGS, INTERR_TOO_FEW_ARGS_STRING );
3931             break;
3932          }
3933          /*
3934           * Check that we have a stem
3935           */
3936          if ( argv[2].strptr[argv[2].strlength-1] != '.' )
3937          {
3938             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_STEM, INTERR_INVALID_STEM_STRING );
3939             break;
3940          }
3941          rc = curl_rc = CURL_EASY_GETINFO( (CURL *)curl, RexxCurlGetinfos[opt].number, &TmpCertInfoPtrs );
3942          if ( curl_rc != CURLE_OK )
3943          {
3944             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3945             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3946             break;
3947          }
3948          if ( TmpCertInfoPtrs )
3949          {
3950             for ( i = 0; i < TmpCertInfoPtrs->num_of_certs; i++ )
3951             {
3952                TmpSListPtrs = TmpCertInfoPtrs->certinfo[i];
3953                for ( ; TmpSListPtrs; TmpSListPtrs=TmpSListPtrs->next )
3954                {
3955                   idx++;
3956                   create_rexx_compound( RxPackageGlobalData, argv[2].strptr, idx, TmpSListPtrs->data, strlen( TmpSListPtrs->data ) );
3957                }
3958                /* don't free the slist!! */
3959             }
3960          }
3961          valuelen = sprintf( value, "%d", idx );
3962          create_rexx_compound( RxPackageGlobalData, argv[2].strptr, 0, value, valuelen );
3963          /* don't free the TmpCertInfoPtrs */
3964          return RxReturnNumber( RxPackageGlobalData, retstr, idx );
3965          break;
3966 #endif
3967       case RXCURLINFO_BITMAP:
3968          suboption = 0;
3969          rc = curl_rc = CURL_EASY_GETINFO( (CURL *)curl, RexxCurlGetinfos[opt].number, &return_long );
3970          if ( curl_rc != CURLE_OK )
3971          {
3972             SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_CURL_ERROR, INTERR_CURL_ERROR_STRING );
3973             SetCURLError( RxPackageGlobalData,  curl_rc, curl_errors[rc] );
3974             break;
3975          }
3976          switch( RexxCurlGetinfos[opt].number )
3977          {
3978 #if LIBCURL_VERSION_NUM >= 0x070a08
3979             case CURLINFO_HTTPAUTH_AVAIL:
3980             case CURLINFO_PROXYAUTH_AVAIL:
3981                suboption = RXCURLOPT_BITMAP_AUTH;
3982                break;
3983 #endif
3984             default:
3985                break;
3986          }
3987          if ( suboption != 0 )
3988          {
3989             valuelen = 0;
3990             /*
3991              * Get the total length of our return string
3992              */
3993             for ( idx = 0; RexxCurlSubOptions[idx].name != NULL; idx++ )
3994             {
3995                if ( RexxCurlSubOptions[idx].optiontype == suboption
3996                &&   RexxCurlSubOptions[idx].newname == NULL
3997                &&   ( RexxCurlSubOptions[idx].number & return_long ) == RexxCurlSubOptions[idx].number )
3998                   valuelen = valuelen + 1 + strlen( RexxCurlSubOptions[idx].name );
3999             }
4000             /* allocate our return string */
4001             return_string = RexxAllocateMemory( valuelen + 1 );
4002             if ( return_string == NULL )
4003             {
4004                SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
4005                break;
4006             }
4007             /*
4008              * Append each value to our return string
4009              */
4010             strcpy( return_string, "" );
4011             for ( idx = 0; RexxCurlSubOptions[idx].name != NULL; idx++ )
4012             {
4013                if ( RexxCurlSubOptions[idx].optiontype == suboption
4014                &&   RexxCurlSubOptions[idx].newname == NULL
4015                &&   ( RexxCurlSubOptions[idx].number & return_long ) == RexxCurlSubOptions[idx].number )
4016                {
4017                   strcat( return_string, RexxCurlSubOptions[idx].name );
4018                   strcat( return_string, " " );
4019                }
4020             }
4021             return RxReturnStringAndFree( RxPackageGlobalData, retstr, return_string, 1 );
4022          }
4023          break;
4024       default:
4025          /* error */
4026          break;
4027    }
4028    return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
4029 }
4030 
rxfunc(CurlFormFree)4031 rxfunc( CurlFormFree )
4032 {
4033    long curl;
4034    int opt;
4035    REXXCURLDATA *RexxCURLData;
4036    /*
4037     * Get thread-safe-data
4038     */
4039    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
4040    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
4041    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
4042 
4043    if ( RexxCURLData->g_curl_error) ClearCURLError( RxPackageGlobalData );
4044    if ( RexxCURLData->g_rexxcurl_error) ClearIntError( RxPackageGlobalData );
4045    if ( my_checkparam( RxPackageGlobalData, name, argc, 1, 1 ) )
4046       return( 1 );
4047    if ( RxStrToLong( RxPackageGlobalData, &argv[0], &curl ) != 0 )
4048    {
4049       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_HANDLE, INTERR_INVALID_HANDLE_STRING );
4050       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
4051    }
4052    /*
4053     * Always look for HTTPPOSTFORM option
4054     */
4055    opt = find_option( RxPackageGlobalData, "HTTPPOSTFORM", 12 );
4056    if ( opt == (-1) )
4057    {
4058       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_OPTION, INTERR_INVALID_OPTION_STRING );
4059       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
4060    }
4061    if ( RexxCURLData->HttpPostFirstPtrs[opt] )
4062    {
4063       CURL_FORMFREE( RexxCURLData->HttpPostFirstPtrs[opt] );
4064    }
4065    RexxCURLData->HttpPostFirstPtrs[opt] = NULL;
4066    RexxCURLData->HttpPostLastPtrs[opt] = NULL;
4067    return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
4068 }
4069 
rxfunc(CurlEscape)4070 rxfunc( CurlEscape )
4071 {
4072    long curl;
4073    int valuelen;
4074    char *url, *return_string;
4075    REXXCURLDATA *RexxCURLData;
4076    /*
4077     * Get thread-safe-data
4078     */
4079    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
4080    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
4081    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
4082 
4083    if ( RexxCURLData->g_curl_error) ClearCURLError( RxPackageGlobalData );
4084    if ( RexxCURLData->g_rexxcurl_error) ClearIntError( RxPackageGlobalData );
4085    if ( my_checkparam( RxPackageGlobalData, name, argc, 2, 2 ) )
4086       return( 1 );
4087    if ( RxStrToLong( RxPackageGlobalData, &argv[0], &curl ) != 0 )
4088    {
4089       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_HANDLE, INTERR_INVALID_HANDLE_STRING );
4090       return RxReturnNumber( RxPackageGlobalData, retstr, INTERR_INVALID_HANDLE ) ;
4091    }
4092 
4093    url = CURL_EASY_ESCAPE( (CURL *)curl, (char *)RXSTRPTR( argv[1] ), RXSTRLEN( argv[1] ) );
4094    if ( url == NULL )
4095    {
4096       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
4097       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
4098    }
4099    valuelen = strlen( url );
4100    return_string = RexxAllocateMemory( valuelen + 1 );
4101    if ( return_string == NULL )
4102    {
4103       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
4104       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
4105    }
4106    strcpy( return_string, url );
4107    CURL_FREE( url );
4108    return RxReturnStringAndFree( RxPackageGlobalData, retstr, return_string, 1 ) ;
4109 }
4110 
rxfunc(CurlUnescape)4111 rxfunc( CurlUnescape )
4112 {
4113    long curl;
4114    int valuelen;
4115    char *url, *return_string;
4116    REXXCURLDATA *RexxCURLData;
4117    /*
4118     * Get thread-safe-data
4119     */
4120    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
4121    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
4122    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
4123 
4124    if ( RexxCURLData->g_curl_error) ClearCURLError( RxPackageGlobalData );
4125    if ( RexxCURLData->g_rexxcurl_error) ClearIntError( RxPackageGlobalData );
4126    if ( my_checkparam( RxPackageGlobalData, name, argc, 2, 2 ) )
4127       return( 1 );
4128    if ( RxStrToLong( RxPackageGlobalData, &argv[0], &curl ) != 0 )
4129    {
4130       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_HANDLE, INTERR_INVALID_HANDLE_STRING );
4131       return RxReturnNumber( RxPackageGlobalData, retstr, INTERR_INVALID_HANDLE ) ;
4132    }
4133 
4134    url = CURL_EASY_UNESCAPE( (CURL *)curl, (char *)RXSTRPTR( argv[1] ), RXSTRLEN( argv[1] ), &valuelen );
4135    if ( url == NULL )
4136    {
4137       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
4138       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
4139    }
4140    return_string = RexxAllocateMemory( valuelen + 1 );
4141    if ( return_string == NULL )
4142    {
4143       SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_NO_MEMORY, INTERR_NO_MEMORY_STRING );
4144       return RxReturnString( RxPackageGlobalData, retstr, "" ) ;
4145    }
4146    strcpy( return_string, url );
4147    CURL_FREE( url );
4148    return RxReturnStringAndFree( RxPackageGlobalData, retstr, return_string, 1 ) ;
4149 }
4150 
4151 /*
4152  * If an argument is passed, check if it is a valid function name
4153  * If no argument is passed, return all function names
4154  * Curlqueryfunction( var|stem, opt )
4155  * opt is R(registered), A(vailable)
4156  *
4157  * return 0 is successful - stem or func found
4158  * return 1 if func not found
4159  */
rxfunc(CurlQueryFunction)4160 rxfunc(CurlQueryFunction)
4161 {
4162    ULONG rc = 0L;
4163    int i,len,tmplen,idx;
4164    char *stem;
4165    char optionchar;
4166    char varname[255], value[10];
4167    char stem_name[255];
4168    REXXCURLDATA *RexxCURLData;
4169    /*
4170     * Get thread-safe-data
4171     */
4172    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
4173    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
4174    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
4175 
4176    if ( my_checkparam( RxPackageGlobalData, name, argc, 1, 2 ) )
4177       return( 1 );
4178 
4179    stem = RXSTRPTR(argv[0]);
4180    len = RXSTRLEN(argv[0]);
4181 
4182    if ( argc == 1 )
4183       optionchar = 'R';
4184    else
4185       optionchar = toupper( *argv[1].strptr );
4186 
4187    if ( stem[len-1] != '.' )
4188    {
4189       /*
4190        * Check that the specified function name is available/registered
4191        */
4192       rc = 1L; /* not found by default */
4193       for ( i = 0; RexxCURLFunctions[i].ExternalName != NULL; i++ )
4194       {
4195          tmplen = strlen( (char *)RexxCURLFunctions[i].ExternalName );
4196          if ( tmplen == len
4197          &&   memcmpi( RxPackageGlobalData, (char *)RexxCURLFunctions[i].ExternalName, stem, len ) == 0 )
4198          {
4199             /*
4200              * Function is available...
4201              */
4202             rc = 0L;
4203             if ( RexxQueryFunction( RexxCURLFunctions[i].InternalName )
4204             &&   optionchar == 'R' )
4205             {
4206                /*
4207                 * Function is not registered and we wanted a registered function
4208                 */
4209                rc = 1L;
4210             }
4211             break;
4212          }
4213       }
4214    }
4215    else
4216    {
4217       strcpy( stem_name, stem );
4218       make_upper( RxPackageGlobalData, stem_name );
4219       idx = 0;
4220       for ( i = 0; RexxCURLFunctions[i].ExternalName != NULL; i++ )
4221       {
4222          if ( RexxQueryFunction( RexxCURLFunctions[i].InternalName )
4223          &&   optionchar == 'R' )
4224          {
4225             /*
4226              * Function is not registered, and we wanted only registered functions
4227              */
4228             ;
4229          }
4230          else
4231          {
4232             idx++;
4233             len = sprintf( varname, "%s%u", stem_name, idx );
4234             if ( SetRexxVariable( RxPackageGlobalData, varname, len, (char *)RexxCURLFunctions[i].ExternalName, strlen( RexxCURLFunctions[i].ExternalName ) ) == 1 )
4235                return(1);
4236          }
4237       }
4238       i = sprintf( value, "%u", idx);
4239       len = sprintf(varname, "%s0", stem_name);
4240       rc = SetRexxVariable( RxPackageGlobalData, varname, len, value, i );
4241    }
4242    return RxReturnNumber( NULL, retstr, rc );
4243 }
4244 
rxfunc(CurlVariable)4245 rxfunc( CurlVariable )
4246 {
4247    RX_ULONG rc = 0L;
4248    char buf[250];
4249    REXXCURLDATA *RexxCURLData;
4250    /*
4251     * Get thread-safe-data
4252     */
4253    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
4254 
4255    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
4256 
4257    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
4258 
4259    if ( my_checkparam( RxPackageGlobalData, (char *)name, argc, 1, 2 ) )
4260       return( 1 );
4261    if ( RXSTRLEN( argv[0] ) == 9 && memcmpi( RxPackageGlobalData, "DEBUGFILE", RXSTRPTR( argv[0] ), RXSTRLEN( argv[0] ) ) == 0 )
4262    {
4263       if ( argc == 1 )
4264          return RxReturnString( RxPackageGlobalData, retstr, RxGetTraceFile( RxPackageGlobalData ) );
4265       else
4266       {
4267          rc = RxSetTraceFile( RxPackageGlobalData, (char *)RXSTRPTR( argv[1] ) );
4268          return RxReturnNumber( RxPackageGlobalData, retstr, rc );
4269       }
4270    }
4271    else if ( RXSTRLEN( argv[0] ) == 5 && memcmpi( RxPackageGlobalData, "DEBUG", RXSTRPTR( argv[0] ), RXSTRLEN( argv[0] ) ) == 0 )
4272    {
4273       if ( argc == 1 )
4274       {
4275          sprintf( buf, "%d", RxGetRunFlags( RxPackageGlobalData ) );
4276          return RxReturnString( RxPackageGlobalData, retstr, buf );
4277       }
4278       else
4279       {
4280          if ( RxStrToULong( RxPackageGlobalData, &argv[1], (RX_ULONG *)&rc ) == -1 )
4281             return RxReturnString( RxPackageGlobalData, retstr, "ERROR: Invalid DEBUG value. Cannot set variable; DEBUG" );
4282          RxSetRunFlags ( RxPackageGlobalData, rc );
4283          return RxReturnNumber( RxPackageGlobalData, retstr, 0 );
4284       }
4285    }
4286    else if ( RXSTRLEN( argv[0] ) == 7 && memcmpi( RxPackageGlobalData, "VERSION", RXSTRPTR( argv[0] ), RXSTRLEN( argv[0] ) ) == 0 )
4287    {
4288       if ( argc == 1 )
4289       {
4290          sprintf( buf, "%s %s %s %s", RxPackageName, REXXCURL_VERSION, REXXCURL_DATE, CURL_VERSION() );
4291          return RxReturnString( RxPackageGlobalData, retstr, buf );
4292       }
4293       else
4294          return RxReturnString( RxPackageGlobalData, retstr, "ERROR: Cannot set variable; VERSION" );
4295    }
4296    else if ( RXSTRLEN( argv[0] ) == 5 && memcmpi( RxPackageGlobalData, "ERROR", RXSTRPTR( argv[0] ), RXSTRLEN( argv[0] ) ) == 0 )
4297    {
4298       if ( argc == 1 )
4299       {
4300          return RxReturnString( RxPackageGlobalData, retstr, RexxCURLData->rexxcurl_error_prefix );
4301       }
4302       else
4303       {
4304          memcpy( RexxCURLData->rexxcurl_error_prefix, argv[1].strptr, argv[1].strlength );
4305          RexxCURLData->rexxcurl_error_prefix[argv[1].strlength] = '\0';
4306          return RxReturnString( RxPackageGlobalData, retstr, "" );
4307       }
4308    }
4309    else if ( RXSTRLEN(argv[0]) == 14 && memcmpi( RxPackageGlobalData, "CONSTANTPREFIX", RXSTRPTR(argv[0]), RXSTRLEN(argv[0]) ) == 0 )
4310    {
4311       if ( argc == 1 )
4312       {
4313          return RxReturnString( RxPackageGlobalData, retstr, RxGetConstantPrefix( RxPackageGlobalData ) );
4314       }
4315       else
4316       {
4317          rc = RxSetConstantPrefix( RxPackageGlobalData, (char *)argv[1].strptr );
4318          /*
4319           * Now we have a new prefix, we should reset all our constants...
4320           */
4321          SetPackageConstants( RxPackageGlobalData, RexxCURLConstants, 1 );
4322          /*
4323           * ...and our version info variables
4324           */
4325          RexxCURLSetVersionInfoConstants( RxPackageGlobalData );
4326          return RxReturnNumber( RxPackageGlobalData, retstr, rc );
4327       }
4328    }
4329    sprintf( buf, "%s %s", INTERR_INVALID_VARIABLE_STRING, argv[0].strptr );
4330    SetIntError( RxPackageGlobalData, __FILE__, __LINE__, INTERR_INVALID_VARIABLE, buf );
4331    return RxReturnString( RxPackageGlobalData, retstr, "" );
4332 }
4333 
4334 /*====== Routines for handling registration of functions ======*/
4335 
4336 
rxfunc(CurlLoadFuncs)4337 rxfunc( CurlLoadFuncs )
4338 {
4339    int rc = 0L;
4340 
4341    /*
4342     * Get thread-safe-data for DLL. EXE global data is not thread-safe
4343     */
4344    RxPackageGlobalDataDef *RxPackageGlobalData = GLOBAL_ENTRY_POINT();
4345    InitRxPackage( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, &rc );
4346    if ( !QueryRxFunction( RxPackageGlobalData, "CURLINIT" ) )
4347    {
4348       /*
4349        * Register all external functions
4350        */
4351       if ( !rc )
4352       {
4353          rc = RegisterRxFunctions( RxPackageGlobalData, RexxCURLFunctions, RxPackageName );
4354       }
4355    }
4356    rc = RexxCURLInitHandler( 0, 0, NULL );
4357    return RxReturnNumber( RxPackageGlobalData, retstr, rc );
4358 }
4359 
rxfunc(CurlDropFuncs)4360 rxfunc( CurlDropFuncs )
4361 {
4362    int rc=0;
4363    int unload=0;
4364    REXXCURLDATA *RexxCURLData;
4365    /*
4366     * Get thread-safe-data
4367     */
4368    RxPackageGlobalDataDef *RxPackageGlobalData = __rxpack_get_tsd();
4369 
4370    RxPackageGlobalData = FunctionPrologue( RxPackageGlobalData, RexxCURLInitialiser, RXPACKAGE_CONSTANT_PREFIX, (char*)name, argc, argv );
4371 
4372    RexxCURLData=(REXXCURLDATA *)RxPackageGlobalData->RXPACKAGE_tsd;
4373 
4374    if ( my_checkparam( RxPackageGlobalData, (char *)name, argc, 0, 1 ) )
4375       return( 1 );
4376    if ( argv[0].strlength == 6
4377    &&   memcmpi( RxPackageGlobalData, argv[0].strptr, "UNLOAD", 6 ) == 0 )
4378       unload = 1;
4379    (void)TermRxPackage( RxPackageGlobalData, RexxCURLTerminator, RexxCURLFunctions, RxPackageName, unload );
4380    return RxReturnNumber( NULL, retstr, rc );
4381 }
4382 
4383 
4384 
4385 /*
4386  * The following functions are used in rxpackage.c
4387  */
4388 
4389 /*-----------------------------------------------------------------------------
4390  * Print a usage message.
4391  *----------------------------------------------------------------------------*/
RexxCURLUsage(void)4392 void RexxCURLUsage
4393 
4394 #ifdef HAVE_PROTO
4395    (void)
4396 #else
4397    ()
4398 #endif
4399 
4400 {
4401    char buf[1024];
4402    (void)fprintf(stderr,
4403       "\nVersion: %s %s %s\nUsing: %s\n\nUsage:   %s [-h]\n         %s [-idvf<trace file>] [Rexx program name]\n\n",
4404       RxPackageName,
4405       REXXCURL_VERSION,
4406       REXXCURL_DATE,
4407       RxGetRexxInterpreterVersion( buf ),
4408       RxPackageName,
4409       RxPackageName);
4410 }
4411 
4412 
4413 #if defined(USE_REXX6000)
4414 /*
4415  * This function is used as the entry point for the REXX/6000
4416  * interpreter
4417  * If you change this table, don't forget to change the table at the
4418  * start of this file.
4419  */
InitFunc(RXFUNCBLOCK ** FuncBlock)4420 USHORT InitFunc( RXFUNCBLOCK **FuncBlock )
4421 {
4422    static RXFUNCBLOCK funcarray[] =
4423    {
4424       { NULL, NULL, NULL }
4425    } ;
4426    *FuncBlock = funcarray;
4427    return (USHORT)0;
4428 }
4429 #endif
4430