|  | 
 | Implementation notes: | 
 |  | 
 |   This is a true OS/400 implementation, not a PASE implementation (for PASE, | 
 | use AIX implementation). | 
 |  | 
 |   The biggest problem with OS/400 is EBCDIC. Libcurl implements an internal | 
 | conversion mechanism, but it has been designed for computers that have a | 
 | single native character set. OS/400 default native character set varies | 
 | depending on the country for which it has been localized. And more, a job | 
 | may dynamically alter its "native" character set. | 
 |   Several characters that do not have fixed code in EBCDIC variants are | 
 | used in libcurl strings. As a consequence, using the existing conversion | 
 | mechanism would have lead in a localized binary library - not portable across | 
 | countries. | 
 |   For this reason, and because libcurl was originally designed for ASCII based | 
 | operating systems, the current OS/400 implementation uses ASCII as internal | 
 | character set. This has been accomplished using the QADRT library and | 
 | include files, a C and system procedures ASCII wrapper library. See IBM QADRT | 
 | description for more information. | 
 |   This then results in libcurl being an ASCII library: any function string | 
 | argument is taken/returned in ASCII and a C/C++ calling program built around | 
 | QADRT may use libcurl functions as on any other platform. | 
 |   QADRT does not define ASCII wrappers for all C/system procedures: the | 
 | OS/400 configuration header file and an additional module (os400sys.c) define | 
 | some more of them, that are used by libcurl and that QADRT left out. | 
 |   To support all the different variants of EBCDIC, non-standard wrapper | 
 | procedures have been added to libcurl on OS/400: they provide an additional | 
 | CCSID (numeric Coded Character Set ID specific to OS/400) parameter for each | 
 | string argument. String values passed to callback procedures are NOT converted, | 
 | so text gathered this way is (probably !) ASCII. | 
 |  | 
 |   Another OS/400 problem comes from the fact that the last fixed argument of a | 
 | vararg procedure may not be of type char, unsigned char, short or unsigned | 
 | short. Enums that are internally implemented by the C compiler as one of these | 
 | types are also forbidden. Libcurl uses enums as vararg procedure tagfields... | 
 | Happily, there is a pragma forcing enums to type "int". The original libcurl | 
 | header files are thus altered during build process to use this pragma, in | 
 | order to force libcurl enums of being type int (the pragma disposition in use | 
 | before inclusion is restored before resuming the including unit compilation). | 
 |  | 
 |   Secure socket layer is provided by the IBM GSKit API: unlike other SSL | 
 | implementations, GSKit is based on "certificate stores" or keyrings | 
 | rather than individual certificate/key files. Certificate stores, as well as | 
 | "certificate labels" are managed by external IBM-defined applications. | 
 |   There are two ways to specify an SSL context: | 
 | - By an application identifier. | 
 | - By a keyring file pathname and (optionally) certificate label. | 
 |   To identify an SSL context by application identifier, use option | 
 | SETOPT_SSLCERT to specify the application identifier. | 
 |   To address an SSL context by keyring and certificate label, use CURLOPT_CAINFO | 
 | to set-up the keyring pathname, CURLOPT_SSLCERT to define the certificate label | 
 | (omitting it will cause the default certificate in keyring to be used) and | 
 | CURLOPT_KEYPASSWD to give the keyring password. If SSL is used without | 
 | defining any of these options, the default (i.e.: system) keyring is used for | 
 | server certificate validation. | 
 |  | 
 |   Non-standard EBCDIC wrapper prototypes are defined in an additional header | 
 | file: ccsidcurl.h. These should be self-explanatory to an OS/400-aware | 
 | designer. CCSID 0 can be used to select the current job's CCSID. | 
 |   Wrapper procedures with variable arguments are described below: | 
 |  | 
 | _ curl_easy_setopt_ccsid() | 
 |   Variable arguments are a string pointer and a CCSID (unsigned int) for | 
 | options: | 
 |         CURLOPT_ABSTRACT_UNIX_SOCKET | 
 |         CURLOPT_CAINFO | 
 |         CURLOPT_CAPATH | 
 |         CURLOPT_COOKIE | 
 |         CURLOPT_COOKIEFILE | 
 |         CURLOPT_COOKIEJAR | 
 |         CURLOPT_COOKIELIST | 
 |         CURLOPT_COPYPOSTFIELDS | 
 |         CURLOPT_CRLFILE | 
 |         CURLOPT_CUSTOMREQUEST | 
 |         CURLOPT_DEFAULT_PROTOCOL | 
 |         CURLOPT_DNS_SERVERS | 
 |         CURLOPT_EGDSOCKET | 
 |         CURLOPT_ENCODING | 
 |         CURLOPT_FTPPORT | 
 |         CURLOPT_FTP_ACCOUNT | 
 |         CURLOPT_FTP_ALTERNATIVE_TO_USER | 
 |         CURLOPT_INTERFACE | 
 |         CURLOPT_ISSUERCERT | 
 |         CURLOPT_KEYPASSWD | 
 |         CURLOPT_KRBLEVEL | 
 |         CURLOPT_LOGIN_OPTIONS | 
 |         CURLOPT_MAIL_AUTH | 
 |         CURLOPT_MAIL_FROM | 
 |         CURLOPT_NETRC_FILE | 
 |         CURLOPT_NOPROXY | 
 |         CURLOPT_PASSWORD | 
 |         CURLOPT_PINNEDPUBLICKEY | 
 |         CURLOPT_PRE_PROXY | 
 |         CURLOPT_PROXY | 
 |         CURLOPT_PROXYPASSWORD | 
 |         CURLOPT_PROXYUSERNAME | 
 |         CURLOPT_PROXYUSERPWD | 
 |         CURLOPT_PROXY_CAINFO | 
 |         CURLOPT_PROXY_CAPATH | 
 |         CURLOPT_PROXY_CRLFILE | 
 |         CURLOPT_PROXY_KEYPASSWD | 
 |         CURLOPT_PROXY_PINNEDPUBLICKEY | 
 |         CURLOPT_PROXY_SERVICE_NAME | 
 |         CURLOPT_PROXY_SSLCERT | 
 |         CURLOPT_PROXY_SSLCERTTYPE | 
 |         CURLOPT_PROXY_SSLKEY | 
 |         CURLOPT_PROXY_SSLKEYTYPE | 
 |         CURLOPT_PROXY_SSL_CIPHER_LIST | 
 |         CURLOPT_PROXY_TLSAUTH_PASSWORD | 
 |         CURLOPT_PROXY_TLSAUTH_TYPE | 
 |         CURLOPT_PROXY_TLSAUTH_USERNAME | 
 |         CURLOPT_RANDOM_FILE | 
 |         CURLOPT_RANGE | 
 |         CURLOPT_REFERER | 
 |         CURLOPT_RTSP_SESSION_UID | 
 |         CURLOPT_RTSP_STREAM_URI | 
 |         CURLOPT_RTSP_TRANSPORT | 
 |         CURLOPT_SERVICE_NAME | 
 |         CURLOPT_SOCKS5_GSSAPI_SERVICE | 
 |         CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 | 
 |         CURLOPT_SSH_KNOWNHOSTS | 
 |         CURLOPT_SSH_PRIVATE_KEYFILE | 
 |         CURLOPT_SSH_PUBLIC_KEYFILE | 
 |         CURLOPT_SSLCERT | 
 |         CURLOPT_SSLCERTTYPE | 
 |         CURLOPT_SSLENGINE | 
 |         CURLOPT_SSLKEY | 
 |         CURLOPT_SSLKEYTYPE | 
 |         CURLOPT_SSL_CIPHER_LIST | 
 |         CURLOPT_TLSAUTH_PASSWORD | 
 |         CURLOPT_TLSAUTH_TYPE | 
 |         CURLOPT_TLSAUTH_USERNAME | 
 |         CURLOPT_UNIX_SOCKET_PATH | 
 |         CURLOPT_URL | 
 |         CURLOPT_USERAGENT | 
 |         CURLOPT_USERNAME | 
 |         CURLOPT_USERPWD | 
 |         CURLOPT_XOAUTH2_BEARER | 
 |   Else it is the same as for curl_easy_setopt(). | 
 |   Note that CURLOPT_ERRORBUFFER is not in the list above, since it gives the | 
 | address of an (empty) character buffer, not the address of a string. | 
 | CURLOPT_POSTFIELDS stores the address of static binary data (of type void *) and | 
 | thus is not converted. If CURLOPT_COPYPOSTFIELDS is issued after | 
 | CURLOPT_POSTFIELDSIZE != -1, the data size is adjusted according to the | 
 | CCSID conversion result length. | 
 |  | 
 | _ curl_formadd_ccsid() | 
 |   In the variable argument list, string pointers should be followed by a (long) | 
 | CCSID for the following options: | 
 |         CURLFORM_FILENAME | 
 |         CURLFORM_CONTENTTYPE | 
 |         CURLFORM_BUFFER | 
 |         CURLFORM_FILE | 
 |         CURLFORM_FILECONTENT | 
 |         CURLFORM_COPYCONTENTS | 
 |         CURLFORM_COPYNAME | 
 |         CURLFORM_PTRNAME | 
 |   If taken from an argument array, an additional array entry must follow each | 
 | entry containing one of the above option. This additional entry holds the CCSID | 
 | in its value field, and the option field is meaningless. | 
 |   It is not possible to have a string pointer and its CCSID across a function | 
 | parameter/array boundary. | 
 |   Please note that CURLFORM_PTRCONTENTS and CURLFORM_BUFFERPTR are considered | 
 | unconvertible strings and thus are NOT followed by a CCSID. | 
 |  | 
 | _ curl_easy_getinfo_ccsid() | 
 |   The following options are followed by a 'char * *' and a CCSID. Unlike | 
 | curl_easy_getinfo(), the value returned in the pointer should be freed after | 
 | use: | 
 |         CURLINFO_EFFECTIVE_URL | 
 |         CURLINFO_CONTENT_TYPE | 
 |         CURLINFO_FTP_ENTRY_PATH | 
 |         CURLINFO_REDIRECT_URL | 
 |         CURLINFO_PRIMARY_IP | 
 |         CURLINFO_RTSP_SESSION_ID | 
 |         CURLINFO_LOCAL_IP | 
 |         CURLINFO_SCHEME | 
 |   Likewise, the following options are followed by a struct curl_slist * * and a | 
 | CCSID. | 
 |         CURLINFO_SSL_ENGINES | 
 |         CURLINFO_COOKIELIST | 
 | Lists returned should be released with curl_slist_free_all() after use. | 
 |   Option CURLINFO_CERTINFO is followed by a struct curl_certinfo * * and a | 
 | CCSID. Returned structures sould be free'ed using curl_certinfo_free_all() after | 
 | use. | 
 |   Other options are processed like in curl_easy_getinfo(). | 
 |  | 
 | _ curl_pushheader_bynum_cssid() and curl_pushheader_byname_ccsid() | 
 |   Although the prototypes are self-explanatory, the returned string pointer | 
 | should be freed after use, as opposite to the non-ccsid versions of these | 
 | procedures. | 
 |   Please note that HTTP2 is not (yet) implemented on OS/400, thus these | 
 | functions will always return NULL. | 
 |  | 
 |  | 
 |   Standard compilation environment does support neither autotools nor make; | 
 | in fact, very few common utilities are available. As a consequence, the | 
 | config-os400.h has been coded manually and the compilation scripts are | 
 | a set of shell scripts stored in subdirectory packages/OS400. | 
 |  | 
 |   The "curl" command and the test environment are currently not supported on | 
 | OS/400. | 
 |  | 
 |  | 
 | Protocols currently implemented on OS/400: | 
 | _ DICT | 
 | _ FILE | 
 | _ FTP | 
 | _ FTPS | 
 | _ FTP with secure transmission | 
 | _ GOPHER | 
 | _ HTTP | 
 | _ HTTPS | 
 | _ IMAP | 
 | _ IMAPS | 
 | _ IMAP with secure transmission | 
 | _ LDAP | 
 | _ POP3 | 
 | _ POP3S | 
 | _ POP3 with secure transmission | 
 | _ RTSP | 
 | _ SCP if libssh2 is enabled | 
 | _ SFTP if libssh2 is enabled | 
 | _ SMTP | 
 | _ SMTPS | 
 | _ SMTP with secure transmission | 
 | _ TELNET | 
 | _ TFTP | 
 |  | 
 |  | 
 |  | 
 | Compiling on OS/400: | 
 |  | 
 |   These instructions targets people who knows about OS/400, compiling, IFS and | 
 | archive extraction. Do not ask questions about these subjects if you're not | 
 | familiar with. | 
 |  | 
 | _ As a prerequisite, QADRT development environment must be installed. | 
 | _ If data compression has to be supported, ZLIB development environment must | 
 |   be installed. | 
 | _ Likewise, if SCP and SFTP protocols have to be compiled in, LIBSSH2 | 
 |   developent environment must be installed. | 
 | _ Install the curl source directory in IFS. | 
 | _ Enter shell (QSH) | 
 | _ Change current directory to the curl installation directory | 
 | _ Change current directory to ./packages/OS400 | 
 | _ Edit file iniscript.sh. You may want to change tunable configuration | 
 |   parameters, like debug info generation, optimisation level, listing option, | 
 |   target library, ZLIB/LIBSSH2 availability and location, etc. | 
 | _ Copy any file in the current directory to makelog (i.e.: | 
 |   cp initscript.sh makelog): this is intended to create the makelog file with | 
 |   an ASCII CCSID! | 
 | _ Enter the command "sh makefile.sh > makelog 2>&1' | 
 | _ Examine the makelog file to check for compilation errors. | 
 |  | 
 |   Leaving file initscript.sh unchanged, this will produce the following OS/400 | 
 | objects: | 
 | _ Library CURL. All other objects will be stored in this library. | 
 | _ Modules for all libcurl units. | 
 | _ Binding directory CURL_A, to be used at calling program link time for | 
 |   statically binding the modules (specify BNDSRVPGM(QADRTTS QGLDCLNT QGLDBRDR) | 
 |   when creating a program using CURL_A). | 
 | _ Service program CURL.<soname>, where <soname> is extracted from the | 
 |   lib/Makefile.am VERSION variable. To be used at calling program run-time | 
 |   when this program has dynamically bound curl at link time. | 
 | _ Binding directory CURL. To be used to dynamically bind libcurl when linking a | 
 |   calling program. | 
 | _ Source file H. It contains all the include members needed to compile a C/C++ | 
 |   module using libcurl, and an ILE/RPG /copy member for support in this | 
 |   language. | 
 | _ Standard C/C++ libcurl include members in file H. | 
 | _ CCSIDCURL member in file H. This defines the non-standard EBCDIC wrappers for | 
 |   C and C++. | 
 | _ CURL.INC member in file H. This defines everything needed by an ILE/RPG | 
 |   program using libcurl. | 
 | _ LIBxxx modules and programs. Although the test environment is not supported | 
 |   on OS/400, the libcurl test programs are compiled for manual tests. | 
 | _ IFS directory /curl/include/curl containing the C header files for IFS source | 
 |   C/C++ compilation and curl.inc.rpgle for IFS source ILE/RPG compilation. | 
 |  | 
 |  | 
 |  | 
 | Special programming consideration: | 
 |  | 
 | QADRT being used, the following points must be considered: | 
 | _ If static binding is used, service program QADRTTS must be linked too. | 
 | _ The EBCDIC CCSID used by QADRT is 37 by default, NOT THE JOB'S CCSID. If | 
 |   another EBCDIC CCSID is required, it must be set via a locale through a call | 
 |   to setlocale_a (QADRT's setlocale() ASCII wrapper) with category LC_ALL or | 
 |   LC_CTYPE, or by setting environment variable QADRT_ENV_LOCALE to the locale | 
 |   object path before executing the program. | 
 | _ Do not use original source include files unless you know what you are doing. | 
 |   Use the installed members instead (in /QSYS.LIB/CURL.LIB/H.FILE and | 
 |   /curl/include/curl). | 
 |  | 
 |  | 
 |  | 
 | ILE/RPG support: | 
 |  | 
 |   Since 95% of the OS/400 programmers use ILE/RPG exclusively, a definition | 
 |   /INCLUDE member is provided for this language. To include all libcurl | 
 |   definitions in an ILE/RPG module, line | 
 |  | 
 |      h bnddir('CURL/CURL') | 
 |  | 
 | must figure in the program header, and line | 
 |  | 
 |      d/include curl/h,curl.inc | 
 |  | 
 | in the global data section of the module's source code. | 
 |  | 
 |   No vararg procedure support exists in ILE/RPG: for this reason, the following | 
 | considerations apply: | 
 | _ Procedures curl_easy_setopt_long(), curl_easy_setopt_object(), | 
 |   curl_easy_setopt_function() and curl_easy_setopt_offset() are all alias | 
 |   prototypes to curl_easy_setopt(), but with different parameter lists. | 
 | _ Procedures curl_easy_getinfo_string(), curl_easy_getinfo_long(), | 
 |   curl_easy_getinfo_double() and curl_easy_getinfo_slist() are all alias | 
 |   prototypes to curl_easy_getinfo(), but with different parameter lists. | 
 | _ Procedures curl_multi_setopt_long(), curl_multi_setopt_object(), | 
 |   curl_multi_setopt_function() and curl_multi_setopt_offset() are all alias | 
 |   prototypes to curl_multi_setopt(), but with different parameter lists. | 
 | _ The prototype of procedure curl_formadd() allows specifying a pointer option | 
 |   and the CURLFORM_END option. This makes possible to use an option array | 
 |   without any additional definition. If some specific incompatible argument | 
 |   list is used in the ILE/RPG program, the latter must define a specialised | 
 |   alias. The same applies to curl_formadd_ccsid() too. | 
 |  | 
 |   Since RPG cannot cast a long to a pointer, procedure curl_form_long_value() | 
 | is provided for that purpose: this allows storing a long value in the curl_forms | 
 | array. |