Home | History | Annotate | Download | only in OS400
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  *
     22  ***************************************************************************/
     23 
     24 /* CCSID API wrappers for OS/400. */
     25 
     26 #include <iconv.h>
     27 #include <string.h>
     28 #include <stdlib.h>
     29 #include <errno.h>
     30 #include <stdarg.h>
     31 
     32 #pragma enum(int)
     33 
     34 #include "curl.h"
     35 #include "mprintf.h"
     36 #include "slist.h"
     37 #include "urldata.h"
     38 #include "url.h"
     39 #include "setopt.h"
     40 #include "getinfo.h"
     41 #include "ccsidcurl.h"
     42 
     43 #include "os400sys.h"
     44 
     45 #ifndef SIZE_MAX
     46 #define SIZE_MAX        ((size_t) ~0)   /* Is unsigned on OS/400. */
     47 #endif
     48 
     49 
     50 #define ASCII_CCSID     819     /* Use ISO-8859-1 as ASCII. */
     51 #define NOCONV_CCSID    65535   /* No conversion. */
     52 #define ICONV_ID_SIZE   32      /* Size of iconv_open() code identifier. */
     53 #define ICONV_OPEN_ERROR(t)     ((t).return_value == -1)
     54 
     55 #define ALLOC_GRANULE   8       /* Alloc. granule for curl_formadd_ccsid(). */
     56 
     57 
     58 static void
     59 makeOS400IconvCode(char buf[ICONV_ID_SIZE], unsigned int ccsid)
     60 
     61 {
     62   /**
     63   *** Convert a CCSID to the corresponding IBM iconv_open() character
     64   ***  code identifier.
     65   ***  This code is specific to the OS400 implementation of the iconv library.
     66   ***  CCSID 65535 (no conversion) is replaced by the ASCII CCSID.
     67   ***  CCSID 0 is interpreted by the OS400 as the job's CCSID.
     68   **/
     69 
     70   ccsid &= 0xFFFF;
     71 
     72   if(ccsid == NOCONV_CCSID)
     73     ccsid = ASCII_CCSID;
     74 
     75   memset(buf, 0, ICONV_ID_SIZE);
     76   curl_msprintf(buf, "IBMCCSID%05u0000000", ccsid);
     77 }
     78 
     79 
     80 static iconv_t
     81 iconv_open_CCSID(unsigned int ccsidout, unsigned int ccsidin,
     82                                                         unsigned int cstr)
     83 
     84 {
     85   char fromcode[ICONV_ID_SIZE];
     86   char tocode[ICONV_ID_SIZE];
     87 
     88   /**
     89   ***  Like iconv_open(), but character codes are given as CCSIDs.
     90   ***  If `cstr' is non-zero, conversion is set up to stop whenever a
     91   ***   null character is encountered.
     92   ***  See iconv_open() IBM description in "National Language Support API".
     93   **/
     94 
     95   makeOS400IconvCode(fromcode, ccsidin);
     96   makeOS400IconvCode(tocode, ccsidout);
     97   memset(tocode + 13, 0, sizeof tocode - 13);   /* Dest. code id format. */
     98 
     99   if(cstr)
    100     fromcode[18] = '1';                         /* Set null-terminator flag. */
    101 
    102   return iconv_open(tocode, fromcode);
    103 }
    104 
    105 
    106 static int
    107 convert(char * d, size_t dlen, int dccsid,
    108         const char * s, int slen, int sccsid)
    109 
    110 {
    111   int i;
    112   iconv_t cd;
    113   size_t lslen;
    114 
    115   /**
    116   ***  Convert `sccsid'-coded `slen'-data bytes at `s' into `dccsid'-coded
    117   ***   data stored in the `dlen'-byte buffer at `d'.
    118   ***  If `slen' < 0, source string is null-terminated.
    119   ***  CCSID 65535 (no conversion) is replaced by the ASCII CCSID.
    120   ***  Return the converted destination byte count, or -1 if error.
    121   **/
    122 
    123   if(sccsid == 65535)
    124     sccsid = ASCII_CCSID;
    125 
    126   if(dccsid == 65535)
    127     dccsid = ASCII_CCSID;
    128 
    129   if(sccsid == dccsid) {
    130     lslen = slen >= 0? slen: strlen(s) + 1;
    131     i = lslen < dlen? lslen: dlen;
    132 
    133     if(s != d && i > 0)
    134       memcpy(d, s, i);
    135 
    136     return i;
    137     }
    138 
    139   if(slen < 0) {
    140     lslen = 0;
    141     cd = iconv_open_CCSID(dccsid, sccsid, 1);
    142     }
    143   else {
    144     lslen = (size_t) slen;
    145     cd = iconv_open_CCSID(dccsid, sccsid, 0);
    146     }
    147 
    148   if(ICONV_OPEN_ERROR(cd))
    149     return -1;
    150 
    151   i = dlen;
    152 
    153   if((int) iconv(cd, (char * *) &s, &lslen, &d, &dlen) < 0)
    154     i = -1;
    155   else
    156     i -= dlen;
    157 
    158   iconv_close(cd);
    159   return i;
    160 }
    161 
    162 
    163 static char *
    164 dynconvert(int dccsid, const char * s, int slen, int sccsid)
    165 
    166 {
    167   char * d;
    168   char * cp;
    169   size_t dlen;
    170   int l;
    171   static const char nullbyte = 0;
    172 
    173   /* Like convert, but the destination is allocated and returned. */
    174 
    175   dlen = (size_t) (slen < 0? strlen(s): slen) + 1;
    176   dlen *= MAX_CONV_EXPANSION;           /* Allow some expansion. */
    177   d = malloc(dlen);
    178 
    179   if(!d)
    180     return (char *) NULL;
    181 
    182   l = convert(d, dlen, dccsid, s, slen, sccsid);
    183 
    184   if(l < 0) {
    185     free(d);
    186     return (char *) NULL;
    187     }
    188 
    189   if(slen < 0) {
    190     /* Need to null-terminate even when source length is given.
    191        Since destination code size is unknown, use a conversion to generate
    192        terminator. */
    193 
    194     int l2 = convert(d + l, dlen - l, dccsid, &nullbyte, -1, ASCII_CCSID);
    195 
    196     if(l2 < 0) {
    197       free(d);
    198       return (char *) NULL;
    199       }
    200 
    201     l += l2;
    202     }
    203 
    204   if((size_t) l < dlen) {
    205     cp = realloc(d, l);         /* Shorten to minimum needed. */
    206 
    207     if(cp)
    208       d = cp;
    209     }
    210 
    211   return d;
    212 }
    213 
    214 
    215 static struct curl_slist *
    216 slist_convert(int dccsid, struct curl_slist * from, int sccsid)
    217 
    218 {
    219   struct curl_slist * to = (struct curl_slist *) NULL;
    220 
    221   for(; from; from = from->next) {
    222     struct curl_slist *nl;
    223     char * cp = dynconvert(dccsid, from->data, -1, sccsid);
    224 
    225     if(!cp) {
    226       curl_slist_free_all(to);
    227       return (struct curl_slist *) NULL;
    228     }
    229     nl = Curl_slist_append_nodup(to, cp);
    230     if(!nl) {
    231       curl_slist_free_all(to);
    232       free(cp);
    233       return NULL;
    234     }
    235     to = nl;
    236   }
    237   return to;
    238 }
    239 
    240 
    241 char *
    242 curl_version_ccsid(unsigned int ccsid)
    243 
    244 {
    245   int i;
    246   char * aversion;
    247   char * eversion;
    248 
    249   aversion = curl_version();
    250 
    251   if(!aversion)
    252     return aversion;
    253 
    254   i = strlen(aversion) + 1;
    255   i *= MAX_CONV_EXPANSION;
    256 
    257   if(!(eversion = Curl_thread_buffer(LK_CURL_VERSION, i)))
    258     return (char *) NULL;
    259 
    260   if(convert(eversion, i, ccsid, aversion, -1, ASCII_CCSID) < 0)
    261     return (char *) NULL;
    262 
    263   return eversion;
    264 }
    265 
    266 
    267 char *
    268 curl_easy_escape_ccsid(CURL * handle, const char * string, int length,
    269                        unsigned int sccsid, unsigned int dccsid)
    270 
    271 {
    272   char * s;
    273   char * d;
    274 
    275   if(!string) {
    276     errno = EINVAL;
    277     return (char *) NULL;
    278     }
    279 
    280   s = dynconvert(ASCII_CCSID, string, length? length: -1, sccsid);
    281 
    282   if(!s)
    283     return (char *) NULL;
    284 
    285   d = curl_easy_escape(handle, s, 0);
    286   free(s);
    287 
    288   if(!d)
    289     return (char *) NULL;
    290 
    291   s = dynconvert(dccsid, d, -1, ASCII_CCSID);
    292   free(d);
    293   return s;
    294 }
    295 
    296 
    297 char *
    298 curl_easy_unescape_ccsid(CURL * handle, const char * string, int length,
    299                          int * outlength,
    300                          unsigned int sccsid, unsigned int dccsid)
    301 
    302 {
    303   char * s;
    304   char * d;
    305 
    306   if(!string) {
    307     errno = EINVAL;
    308     return (char *) NULL;
    309     }
    310 
    311   s = dynconvert(ASCII_CCSID, string, length? length: -1, sccsid);
    312 
    313   if(!s)
    314     return (char *) NULL;
    315 
    316   d = curl_easy_unescape(handle, s, 0, outlength);
    317   free(s);
    318 
    319   if(!d)
    320     return (char *) NULL;
    321 
    322   s = dynconvert(dccsid, d, -1, ASCII_CCSID);
    323   free(d);
    324 
    325   if(s && outlength)
    326     *outlength = strlen(s);
    327 
    328   return s;
    329 }
    330 
    331 
    332 struct curl_slist *
    333 curl_slist_append_ccsid(struct curl_slist * list,
    334                         const char * data, unsigned int ccsid)
    335 
    336 {
    337   char * s;
    338 
    339   s = (char *) NULL;
    340 
    341   if(!data)
    342     return curl_slist_append(list, data);
    343 
    344   s = dynconvert(ASCII_CCSID, data, -1, ccsid);
    345 
    346   if(!s)
    347     return (struct curl_slist *) NULL;
    348 
    349   list = curl_slist_append(list, s);
    350   free(s);
    351   return list;
    352 }
    353 
    354 
    355 time_t
    356 curl_getdate_ccsid(const char * p, const time_t * unused, unsigned int ccsid)
    357 
    358 {
    359   char * s;
    360   time_t t;
    361 
    362   if(!p)
    363     return curl_getdate(p, unused);
    364 
    365   s = dynconvert(ASCII_CCSID, p, -1, ccsid);
    366 
    367   if(!s)
    368     return (time_t) -1;
    369 
    370   t = curl_getdate(s, unused);
    371   free(s);
    372   return t;
    373 }
    374 
    375 
    376 static int
    377 convert_version_info_string(const char * * stringp,
    378                             char * * bufp, int * left, unsigned int ccsid)
    379 
    380 {
    381   /* Helper for curl_version_info_ccsid(): convert a string if defined.
    382      Result is stored in the `*left'-byte buffer at `*bufp'.
    383      `*bufp' and `*left' are updated accordingly.
    384      Return 0 if ok, else -1. */
    385 
    386   if(*stringp) {
    387     int l = convert(*bufp, *left, ccsid, *stringp, -1, ASCII_CCSID);
    388 
    389     if(l <= 0)
    390       return -1;
    391 
    392     *stringp = *bufp;
    393     *bufp += l;
    394     *left -= l;
    395     }
    396 
    397   return 0;
    398 }
    399 
    400 
    401 curl_version_info_data *
    402 curl_version_info_ccsid(CURLversion stamp, unsigned int ccsid)
    403 
    404 {
    405   curl_version_info_data * p;
    406   char * cp;
    407   int n;
    408   int nproto;
    409   curl_version_info_data * id;
    410 
    411   /* The assertion below is possible, because although the second operand
    412      is an enum member, the first is a #define. In that case, the OS/400 C
    413      compiler seems to compare string values after substitution. */
    414 
    415 #if CURLVERSION_NOW != CURLVERSION_FOURTH
    416 #error curl_version_info_data structure has changed: upgrade this procedure.
    417 #endif
    418 
    419   /* If caller has been compiled with a new version, error. */
    420 
    421   if(stamp > CURLVERSION_NOW)
    422     return (curl_version_info_data *) NULL;
    423 
    424   p = curl_version_info(stamp);
    425 
    426   if(!p)
    427     return p;
    428 
    429   /* Measure thread space needed. */
    430 
    431   n = 0;
    432   nproto = 0;
    433 
    434   if(p->protocols) {
    435     while(p->protocols[nproto])
    436       n += strlen(p->protocols[nproto++]);
    437 
    438     n += nproto++;
    439     }
    440 
    441   if(p->version)
    442     n += strlen(p->version) + 1;
    443 
    444   if(p->host)
    445     n += strlen(p->host) + 1;
    446 
    447   if(p->ssl_version)
    448     n += strlen(p->ssl_version) + 1;
    449 
    450   if(p->libz_version)
    451     n += strlen(p->libz_version) + 1;
    452 
    453   if(p->ares)
    454     n += strlen(p->ares) + 1;
    455 
    456   if(p->libidn)
    457     n += strlen(p->libidn) + 1;
    458 
    459   if(p->libssh_version)
    460     n += strlen(p->libssh_version) + 1;
    461 
    462   /* Allocate thread space. */
    463 
    464   n *= MAX_CONV_EXPANSION;
    465 
    466   if(nproto)
    467     n += nproto * sizeof(const char *);
    468 
    469   cp = Curl_thread_buffer(LK_VERSION_INFO_DATA, n);
    470   id = (curl_version_info_data *) Curl_thread_buffer(LK_VERSION_INFO,
    471                                                      sizeof *id);
    472 
    473   if(!id || !cp)
    474     return (curl_version_info_data *) NULL;
    475 
    476   /* Copy data and convert strings. */
    477 
    478   memcpy((char *) id, (char *) p, sizeof *p);
    479 
    480   if(id->protocols) {
    481     int i = nproto * sizeof id->protocols[0];
    482 
    483     id->protocols = (const char * const *) cp;
    484     memcpy(cp, (char *) p->protocols, i);
    485     cp += i;
    486     n -= i;
    487 
    488     for(i = 0; id->protocols[i]; i++)
    489       if(convert_version_info_string(((const char * *) id->protocols) + i,
    490                                       &cp, &n, ccsid))
    491         return (curl_version_info_data *) NULL;
    492     }
    493 
    494   if(convert_version_info_string(&id->version, &cp, &n, ccsid))
    495     return (curl_version_info_data *) NULL;
    496 
    497   if(convert_version_info_string(&id->host, &cp, &n, ccsid))
    498     return (curl_version_info_data *) NULL;
    499 
    500   if(convert_version_info_string(&id->ssl_version, &cp, &n, ccsid))
    501     return (curl_version_info_data *) NULL;
    502 
    503   if(convert_version_info_string(&id->libz_version, &cp, &n, ccsid))
    504     return (curl_version_info_data *) NULL;
    505 
    506   if(convert_version_info_string(&id->ares, &cp, &n, ccsid))
    507     return (curl_version_info_data *) NULL;
    508 
    509   if(convert_version_info_string(&id->libidn, &cp, &n, ccsid))
    510     return (curl_version_info_data *) NULL;
    511 
    512   if(convert_version_info_string(&id->libssh_version, &cp, &n, ccsid))
    513     return (curl_version_info_data *) NULL;
    514 
    515   return id;
    516 }
    517 
    518 
    519 const char *
    520 curl_easy_strerror_ccsid(CURLcode error, unsigned int ccsid)
    521 
    522 {
    523   int i;
    524   const char * s;
    525   char * buf;
    526 
    527   s = curl_easy_strerror(error);
    528 
    529   if(!s)
    530     return s;
    531 
    532   i = MAX_CONV_EXPANSION * (strlen(s) + 1);
    533 
    534   if(!(buf = Curl_thread_buffer(LK_EASY_STRERROR, i)))
    535     return (const char *) NULL;
    536 
    537   if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
    538     return (const char *) NULL;
    539 
    540   return (const char *) buf;
    541 }
    542 
    543 
    544 const char *
    545 curl_share_strerror_ccsid(CURLSHcode error, unsigned int ccsid)
    546 
    547 {
    548   int i;
    549   const char * s;
    550   char * buf;
    551 
    552   s = curl_share_strerror(error);
    553 
    554   if(!s)
    555     return s;
    556 
    557   i = MAX_CONV_EXPANSION * (strlen(s) + 1);
    558 
    559   if(!(buf = Curl_thread_buffer(LK_SHARE_STRERROR, i)))
    560     return (const char *) NULL;
    561 
    562   if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
    563     return (const char *) NULL;
    564 
    565   return (const char *) buf;
    566 }
    567 
    568 
    569 const char *
    570 curl_multi_strerror_ccsid(CURLMcode error, unsigned int ccsid)
    571 
    572 {
    573   int i;
    574   const char * s;
    575   char * buf;
    576 
    577   s = curl_multi_strerror(error);
    578 
    579   if(!s)
    580     return s;
    581 
    582   i = MAX_CONV_EXPANSION * (strlen(s) + 1);
    583 
    584   if(!(buf = Curl_thread_buffer(LK_MULTI_STRERROR, i)))
    585     return (const char *) NULL;
    586 
    587   if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
    588     return (const char *) NULL;
    589 
    590   return (const char *) buf;
    591 }
    592 
    593 
    594 void
    595 curl_certinfo_free_all(struct curl_certinfo *info)
    596 
    597 {
    598   /* Free all memory used by certificate info. */
    599   if(info) {
    600     if(info->certinfo) {
    601       int i;
    602 
    603       for(i = 0; i < info->num_of_certs; i++)
    604         curl_slist_free_all(info->certinfo[i]);
    605       free((char *) info->certinfo);
    606     }
    607     free((char *) info);
    608   }
    609 }
    610 
    611 
    612 CURLcode
    613 curl_easy_getinfo_ccsid(CURL * curl, CURLINFO info, ...)
    614 
    615 {
    616   va_list arg;
    617   void * paramp;
    618   CURLcode ret;
    619   unsigned int ccsid;
    620   char * * cpp;
    621   struct Curl_easy * data;
    622   struct curl_slist * * slp;
    623   struct curl_certinfo * cipf;
    624   struct curl_certinfo * cipt;
    625 
    626   /* WARNING: unlike curl_easy_getinfo(), the strings returned by this
    627      procedure have to be free'ed. */
    628 
    629   data = (struct Curl_easy *) curl;
    630   va_start(arg, info);
    631   paramp = va_arg(arg, void *);
    632   ret = Curl_getinfo(data, info, paramp);
    633 
    634   if(ret == CURLE_OK)
    635     switch ((int) info & CURLINFO_TYPEMASK) {
    636 
    637     case CURLINFO_STRING:
    638       ccsid = va_arg(arg, unsigned int);
    639       cpp = (char * *) paramp;
    640 
    641       if(*cpp) {
    642         *cpp = dynconvert(ccsid, *cpp, -1, ASCII_CCSID);
    643 
    644         if(!*cpp)
    645           ret = CURLE_OUT_OF_MEMORY;
    646       }
    647 
    648       break;
    649 
    650     case CURLINFO_SLIST:
    651       ccsid = va_arg(arg, unsigned int);
    652       switch (info) {
    653       case CURLINFO_CERTINFO:
    654         cipf = *(struct curl_certinfo * *) paramp;
    655         if(cipf) {
    656           if(!(cipt = (struct curl_certinfo *) malloc(sizeof *cipt)))
    657             ret = CURLE_OUT_OF_MEMORY;
    658           else {
    659             cipt->certinfo = (struct curl_slist * *)
    660                              calloc(cipf->num_of_certs +
    661                                     1, sizeof(struct curl_slist *));
    662             if(!cipt->certinfo)
    663               ret = CURLE_OUT_OF_MEMORY;
    664             else {
    665               int i;
    666 
    667               cipt->num_of_certs = cipf->num_of_certs;
    668               for(i = 0; i < cipf->num_of_certs; i++)
    669                 if(cipf->certinfo[i])
    670                   if(!(cipt->certinfo[i] = slist_convert(ccsid,
    671                                                           cipf->certinfo[i],
    672                                                           ASCII_CCSID))) {
    673                     ret = CURLE_OUT_OF_MEMORY;
    674                     break;
    675                   }
    676               }
    677             }
    678 
    679           if(ret != CURLE_OK) {
    680             curl_certinfo_free_all(cipt);
    681             cipt = (struct curl_certinfo *) NULL;
    682           }
    683 
    684           *(struct curl_certinfo * *) paramp = cipt;
    685         }
    686 
    687         break;
    688 
    689       case CURLINFO_TLS_SESSION:
    690       case CURLINFO_TLS_SSL_PTR:
    691       case CURLINFO_SOCKET:
    692         break;
    693 
    694       default:
    695         slp = (struct curl_slist * *) paramp;
    696         if(*slp)
    697           if(!(*slp = slist_convert(ccsid, *slp, ASCII_CCSID)))
    698             ret = CURLE_OUT_OF_MEMORY;
    699         break;
    700       }
    701     }
    702 
    703   va_end(arg);
    704   return ret;
    705 }
    706 
    707 
    708 static int
    709 Curl_is_formadd_string(CURLformoption option)
    710 
    711 {
    712   switch (option) {
    713 
    714   case CURLFORM_FILENAME:
    715   case CURLFORM_CONTENTTYPE:
    716   case CURLFORM_BUFFER:
    717   case CURLFORM_FILE:
    718   case CURLFORM_FILECONTENT:
    719   case CURLFORM_COPYCONTENTS:
    720   case CURLFORM_COPYNAME:
    721     return 1;
    722   }
    723 
    724   return 0;
    725 }
    726 
    727 
    728 static void
    729 Curl_formadd_release_local(struct curl_forms * forms, int nargs, int skip)
    730 
    731 {
    732   while(nargs--)
    733     if(nargs != skip)
    734       if(Curl_is_formadd_string(forms[nargs].option))
    735         if(forms[nargs].value)
    736           free((char *) forms[nargs].value);
    737 
    738   free((char *) forms);
    739 }
    740 
    741 
    742 static int
    743 Curl_formadd_convert(struct curl_forms * forms,
    744                      int formx, int lengthx, unsigned int ccsid)
    745 
    746 {
    747   int l;
    748   char * cp;
    749   char * cp2;
    750 
    751   if(formx < 0 || !forms[formx].value)
    752     return 0;
    753 
    754   if(lengthx >= 0)
    755     l = (int) forms[lengthx].value;
    756   else
    757     l = strlen(forms[formx].value) + 1;
    758 
    759   cp = malloc(MAX_CONV_EXPANSION * l);
    760 
    761   if(!cp)
    762     return -1;
    763 
    764   l = convert(cp, MAX_CONV_EXPANSION * l, ASCII_CCSID,
    765               forms[formx].value, l, ccsid);
    766 
    767   if(l < 0) {
    768     free(cp);
    769     return -1;
    770     }
    771 
    772   cp2 = realloc(cp, l);         /* Shorten buffer to the string size. */
    773 
    774   if(cp2)
    775     cp = cp2;
    776 
    777   forms[formx].value = cp;
    778 
    779   if(lengthx >= 0)
    780     forms[lengthx].value = (char *) l;  /* Update length after conversion. */
    781 
    782   return l;
    783 }
    784 
    785 
    786 CURLFORMcode
    787 curl_formadd_ccsid(struct curl_httppost * * httppost,
    788                    struct curl_httppost * * last_post, ...)
    789 
    790 {
    791   va_list arg;
    792   CURLformoption option;
    793   CURLFORMcode result;
    794   struct curl_forms * forms;
    795   struct curl_forms * lforms;
    796   struct curl_forms * tforms;
    797   unsigned int lformlen;
    798   const char * value;
    799   unsigned int ccsid;
    800   int nargs;
    801   int namex;
    802   int namelengthx;
    803   int contentx;
    804   int lengthx;
    805   unsigned int contentccsid;
    806   unsigned int nameccsid;
    807 
    808   /* A single curl_formadd() call cannot be split in several calls to deal
    809      with all parameters: the original parameters are thus copied to a local
    810      curl_forms array and converted to ASCII when needed.
    811      CURLFORM_PTRNAME is processed as if it were CURLFORM_COPYNAME.
    812      CURLFORM_COPYNAME and CURLFORM_NAMELENGTH occurrence order in
    813      parameters is not defined; for this reason, the actual conversion is
    814      delayed to the end of parameter processing. The same applies to
    815      CURLFORM_COPYCONTENTS/CURLFORM_CONTENTSLENGTH, but these may appear
    816      several times in the parameter list; the problem resides here in knowing
    817      which CURLFORM_CONTENTSLENGTH applies to which CURLFORM_COPYCONTENTS and
    818      when we can be sure to have both info for conversion: end of parameter
    819      list is such a point, but CURLFORM_CONTENTTYPE is also used here as a
    820      natural separator between content data definitions; this seems to be
    821      in accordance with FormAdd() behavior. */
    822 
    823   /* Allocate the local curl_forms array. */
    824 
    825   lformlen = ALLOC_GRANULE;
    826   lforms = malloc(lformlen * sizeof *lforms);
    827 
    828   if(!lforms)
    829     return CURL_FORMADD_MEMORY;
    830 
    831   /* Process the arguments, copying them into local array, latching conversion
    832      indexes and converting when needed. */
    833 
    834   result = CURL_FORMADD_OK;
    835   nargs = 0;
    836   contentx = -1;
    837   lengthx = -1;
    838   namex = -1;
    839   namelengthx = -1;
    840   forms = (struct curl_forms *) NULL;
    841   va_start(arg, last_post);
    842 
    843   for(;;) {
    844     /* Make sure there is still room for an item in local array. */
    845 
    846     if(nargs >= lformlen) {
    847       lformlen += ALLOC_GRANULE;
    848       tforms = realloc(lforms, lformlen * sizeof *lforms);
    849 
    850       if(!tforms) {
    851         result = CURL_FORMADD_MEMORY;
    852         break;
    853         }
    854 
    855       lforms = tforms;
    856       }
    857 
    858     /* Get next option. */
    859 
    860     if(forms) {
    861       /* Get option from array. */
    862 
    863       option = forms->option;
    864       value = forms->value;
    865       forms++;
    866       }
    867     else {
    868       /* Get option from arguments. */
    869 
    870       option = va_arg(arg, CURLformoption);
    871 
    872       if(option == CURLFORM_END)
    873         break;
    874       }
    875 
    876     /* Dispatch by option. */
    877 
    878     switch (option) {
    879 
    880     case CURLFORM_END:
    881       forms = (struct curl_forms *) NULL;       /* Leave array mode. */
    882       continue;
    883 
    884     case CURLFORM_ARRAY:
    885       if(!forms) {
    886         forms = va_arg(arg, struct curl_forms *);
    887         continue;
    888         }
    889 
    890       result = CURL_FORMADD_ILLEGAL_ARRAY;
    891       break;
    892 
    893     case CURLFORM_COPYNAME:
    894       option = CURLFORM_PTRNAME;                /* Static for now. */
    895 
    896     case CURLFORM_PTRNAME:
    897       if(namex >= 0)
    898         result = CURL_FORMADD_OPTION_TWICE;
    899 
    900       namex = nargs;
    901 
    902       if(!forms) {
    903         value = va_arg(arg, char *);
    904         nameccsid = (unsigned int) va_arg(arg, long);
    905         }
    906       else {
    907         nameccsid = (unsigned int) forms->value;
    908         forms++;
    909         }
    910 
    911       break;
    912 
    913     case CURLFORM_COPYCONTENTS:
    914       if(contentx >= 0)
    915         result = CURL_FORMADD_OPTION_TWICE;
    916 
    917       contentx = nargs;
    918 
    919       if(!forms) {
    920         value = va_arg(arg, char *);
    921         contentccsid = (unsigned int) va_arg(arg, long);
    922         }
    923       else {
    924         contentccsid = (unsigned int) forms->value;
    925         forms++;
    926         }
    927 
    928       break;
    929 
    930     case CURLFORM_PTRCONTENTS:
    931     case CURLFORM_BUFFERPTR:
    932       if(!forms)
    933         value = va_arg(arg, char *);            /* No conversion. */
    934 
    935       break;
    936 
    937     case CURLFORM_CONTENTSLENGTH:
    938       lengthx = nargs;
    939 
    940       if(!forms)
    941         value = (char *) va_arg(arg, long);
    942 
    943       break;
    944 
    945     case CURLFORM_CONTENTLEN:
    946       lengthx = nargs;
    947 
    948       if(!forms)
    949         value = (char *) va_arg(arg, curl_off_t);
    950 
    951       break;
    952 
    953     case CURLFORM_NAMELENGTH:
    954       namelengthx = nargs;
    955 
    956       if(!forms)
    957         value = (char *) va_arg(arg, long);
    958 
    959       break;
    960 
    961     case CURLFORM_BUFFERLENGTH:
    962       if(!forms)
    963         value = (char *) va_arg(arg, long);
    964 
    965       break;
    966 
    967     case CURLFORM_CONTENTHEADER:
    968       if(!forms)
    969         value = (char *) va_arg(arg, struct curl_slist *);
    970 
    971       break;
    972 
    973     case CURLFORM_STREAM:
    974       if(!forms)
    975         value = (char *) va_arg(arg, void *);
    976 
    977       break;
    978 
    979     case CURLFORM_CONTENTTYPE:
    980       /* If a previous content has been encountered, convert it now. */
    981 
    982       if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) {
    983         result = CURL_FORMADD_MEMORY;
    984         break;
    985         }
    986 
    987       contentx = -1;
    988       lengthx = -1;
    989       /* Fall into default. */
    990 
    991     default:
    992       /* Must be a convertible string. */
    993 
    994       if(!Curl_is_formadd_string(option)) {
    995         result = CURL_FORMADD_UNKNOWN_OPTION;
    996         break;
    997         }
    998 
    999       if(!forms) {
   1000         value = va_arg(arg, char *);
   1001         ccsid = (unsigned int) va_arg(arg, long);
   1002         }
   1003       else {
   1004         ccsid = (unsigned int) forms->value;
   1005         forms++;
   1006         }
   1007 
   1008       /* Do the conversion. */
   1009 
   1010       lforms[nargs].value = value;
   1011 
   1012       if(Curl_formadd_convert(lforms, nargs, -1, ccsid) < 0) {
   1013         result = CURL_FORMADD_MEMORY;
   1014         break;
   1015         }
   1016 
   1017       value = lforms[nargs].value;
   1018       }
   1019 
   1020     if(result != CURL_FORMADD_OK)
   1021       break;
   1022 
   1023     lforms[nargs].value = value;
   1024     lforms[nargs++].option = option;
   1025     }
   1026 
   1027   va_end(arg);
   1028 
   1029   /* Convert the name and the last content, now that we know their lengths. */
   1030 
   1031   if(result == CURL_FORMADD_OK && namex >= 0) {
   1032     if(Curl_formadd_convert(lforms, namex, namelengthx, nameccsid) < 0)
   1033       result = CURL_FORMADD_MEMORY;
   1034     else
   1035       lforms[namex].option = CURLFORM_COPYNAME;         /* Force copy. */
   1036     }
   1037 
   1038   if(result == CURL_FORMADD_OK) {
   1039     if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0)
   1040       result = CURL_FORMADD_MEMORY;
   1041     else
   1042       contentx = -1;
   1043     }
   1044 
   1045   /* Do the formadd with our converted parameters. */
   1046 
   1047   if(result == CURL_FORMADD_OK) {
   1048     lforms[nargs].option = CURLFORM_END;
   1049     result = curl_formadd(httppost, last_post,
   1050                           CURLFORM_ARRAY, lforms, CURLFORM_END);
   1051     }
   1052 
   1053   /* Terminate. */
   1054 
   1055   Curl_formadd_release_local(lforms, nargs, contentx);
   1056   return result;
   1057 }
   1058 
   1059 
   1060 typedef struct {
   1061   curl_formget_callback append;
   1062   void *                arg;
   1063   unsigned int          ccsid;
   1064 }   cfcdata;
   1065 
   1066 
   1067 static size_t
   1068 Curl_formget_callback_ccsid(void * arg, const char * buf, size_t len)
   1069 
   1070 {
   1071   cfcdata * p;
   1072   char * b;
   1073   int l;
   1074   size_t ret;
   1075 
   1076   p = (cfcdata *) arg;
   1077 
   1078   if((long) len <= 0)
   1079     return (*p->append)(p->arg, buf, len);
   1080 
   1081   b = malloc(MAX_CONV_EXPANSION * len);
   1082 
   1083   if(!b)
   1084     return (size_t) -1;
   1085 
   1086   l = convert(b, MAX_CONV_EXPANSION * len, p->ccsid, buf, len, ASCII_CCSID);
   1087 
   1088   if(l < 0) {
   1089     free(b);
   1090     return (size_t) -1;
   1091     }
   1092 
   1093   ret = (*p->append)(p->arg, b, l);
   1094   free(b);
   1095   return ret == l? len: -1;
   1096 }
   1097 
   1098 
   1099 int
   1100 curl_formget_ccsid(struct curl_httppost * form, void * arg,
   1101                    curl_formget_callback append, unsigned int ccsid)
   1102 
   1103 {
   1104   cfcdata lcfc;
   1105 
   1106   lcfc.append = append;
   1107   lcfc.arg = arg;
   1108   lcfc.ccsid = ccsid;
   1109   return curl_formget(form, (void *) &lcfc, Curl_formget_callback_ccsid);
   1110 }
   1111 
   1112 
   1113 CURLcode
   1114 curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...)
   1115 
   1116 {
   1117   CURLcode result;
   1118   va_list arg;
   1119   struct Curl_easy * data;
   1120   char * s;
   1121   char * cp;
   1122   unsigned int ccsid;
   1123   curl_off_t pfsize;
   1124   static char testwarn = 1;
   1125 
   1126   /* Warns if this procedure has not been updated when the dupstring enum
   1127      changes.
   1128      We (try to) do it only once: there is no need to issue several times
   1129      the same message; but since threadsafeness is not handled here,
   1130      this may occur (and we don't care!). */
   1131 
   1132   if(testwarn) {
   1133     testwarn = 0;
   1134 
   1135     if(
   1136 #ifdef USE_ALTSVC
   1137        (int) STRING_LASTZEROTERMINATED != (int) STRING_ALTSVC + 1 ||
   1138 #else
   1139        (int) STRING_LASTZEROTERMINATED != (int) STRING_DOH + 1 ||
   1140 #endif
   1141        (int) STRING_LAST != (int) STRING_COPYPOSTFIELDS + 1)
   1142       curl_mfprintf(stderr,
   1143        "*** WARNING: curl_easy_setopt_ccsid() should be reworked ***\n");
   1144     }
   1145 
   1146   data = (struct Curl_easy *) curl;
   1147   va_start(arg, tag);
   1148 
   1149   switch (tag) {
   1150 
   1151   case CURLOPT_ABSTRACT_UNIX_SOCKET:
   1152   case CURLOPT_ALTSVC:
   1153   case CURLOPT_CAINFO:
   1154   case CURLOPT_CAPATH:
   1155   case CURLOPT_COOKIE:
   1156   case CURLOPT_COOKIEFILE:
   1157   case CURLOPT_COOKIEJAR:
   1158   case CURLOPT_COOKIELIST:
   1159   case CURLOPT_CRLFILE:
   1160   case CURLOPT_CUSTOMREQUEST:
   1161   case CURLOPT_DEFAULT_PROTOCOL:
   1162   case CURLOPT_DNS_SERVERS:
   1163   case CURLOPT_DOH_URL:
   1164   case CURLOPT_EGDSOCKET:
   1165   case CURLOPT_ENCODING:
   1166   case CURLOPT_FTPPORT:
   1167   case CURLOPT_FTP_ACCOUNT:
   1168   case CURLOPT_FTP_ALTERNATIVE_TO_USER:
   1169   case CURLOPT_INTERFACE:
   1170   case CURLOPT_ISSUERCERT:
   1171   case CURLOPT_KEYPASSWD:
   1172   case CURLOPT_KRBLEVEL:
   1173   case CURLOPT_LOGIN_OPTIONS:
   1174   case CURLOPT_MAIL_AUTH:
   1175   case CURLOPT_MAIL_FROM:
   1176   case CURLOPT_NETRC_FILE:
   1177   case CURLOPT_NOPROXY:
   1178   case CURLOPT_PASSWORD:
   1179   case CURLOPT_PINNEDPUBLICKEY:
   1180   case CURLOPT_PRE_PROXY:
   1181   case CURLOPT_PROXY:
   1182   case CURLOPT_PROXYPASSWORD:
   1183   case CURLOPT_PROXYUSERNAME:
   1184   case CURLOPT_PROXYUSERPWD:
   1185   case CURLOPT_PROXY_CAINFO:
   1186   case CURLOPT_PROXY_CAPATH:
   1187   case CURLOPT_PROXY_CRLFILE:
   1188   case CURLOPT_PROXY_KEYPASSWD:
   1189   case CURLOPT_PROXY_PINNEDPUBLICKEY:
   1190   case CURLOPT_PROXY_SERVICE_NAME:
   1191   case CURLOPT_PROXY_SSLCERT:
   1192   case CURLOPT_PROXY_SSLCERTTYPE:
   1193   case CURLOPT_PROXY_SSLKEY:
   1194   case CURLOPT_PROXY_SSLKEYTYPE:
   1195   case CURLOPT_PROXY_SSL_CIPHER_LIST:
   1196   case CURLOPT_PROXY_TLS13_CIPHERS:
   1197   case CURLOPT_PROXY_TLSAUTH_PASSWORD:
   1198   case CURLOPT_PROXY_TLSAUTH_TYPE:
   1199   case CURLOPT_PROXY_TLSAUTH_USERNAME:
   1200   case CURLOPT_RANDOM_FILE:
   1201   case CURLOPT_RANGE:
   1202   case CURLOPT_REFERER:
   1203   case CURLOPT_REQUEST_TARGET:
   1204   case CURLOPT_RTSP_SESSION_ID:
   1205   case CURLOPT_RTSP_STREAM_URI:
   1206   case CURLOPT_RTSP_TRANSPORT:
   1207   case CURLOPT_SERVICE_NAME:
   1208   case CURLOPT_SOCKS5_GSSAPI_SERVICE:
   1209   case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
   1210   case CURLOPT_SSH_KNOWNHOSTS:
   1211   case CURLOPT_SSH_PRIVATE_KEYFILE:
   1212   case CURLOPT_SSH_PUBLIC_KEYFILE:
   1213   case CURLOPT_SSLCERT:
   1214   case CURLOPT_SSLCERTTYPE:
   1215   case CURLOPT_SSLENGINE:
   1216   case CURLOPT_SSLKEY:
   1217   case CURLOPT_SSLKEYTYPE:
   1218   case CURLOPT_SSL_CIPHER_LIST:
   1219   case CURLOPT_TLS13_CIPHERS:
   1220   case CURLOPT_TLSAUTH_PASSWORD:
   1221   case CURLOPT_TLSAUTH_TYPE:
   1222   case CURLOPT_TLSAUTH_USERNAME:
   1223   case CURLOPT_UNIX_SOCKET_PATH:
   1224   case CURLOPT_URL:
   1225   case CURLOPT_USERAGENT:
   1226   case CURLOPT_USERNAME:
   1227   case CURLOPT_USERPWD:
   1228   case CURLOPT_XOAUTH2_BEARER:
   1229     s = va_arg(arg, char *);
   1230     ccsid = va_arg(arg, unsigned int);
   1231 
   1232     if(s) {
   1233       s = dynconvert(ASCII_CCSID, s, -1, ccsid);
   1234 
   1235       if(!s) {
   1236         result = CURLE_OUT_OF_MEMORY;
   1237         break;
   1238         }
   1239       }
   1240 
   1241     result = curl_easy_setopt(curl, tag, s);
   1242     free(s);
   1243     break;
   1244 
   1245   case CURLOPT_COPYPOSTFIELDS:
   1246     /* Special case: byte count may have been given by CURLOPT_POSTFIELDSIZE
   1247        prior to this call. In this case, convert the given byte count and
   1248        replace the length according to the conversion result. */
   1249     s = va_arg(arg, char *);
   1250     ccsid = va_arg(arg, unsigned int);
   1251 
   1252     pfsize = data->set.postfieldsize;
   1253 
   1254     if(!s || !pfsize || ccsid == NOCONV_CCSID || ccsid == ASCII_CCSID) {
   1255       result = curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, s);
   1256       break;
   1257       }
   1258 
   1259     if(pfsize == -1) {
   1260       /* Data is null-terminated. */
   1261       s = dynconvert(ASCII_CCSID, s, -1, ccsid);
   1262 
   1263       if(!s) {
   1264         result = CURLE_OUT_OF_MEMORY;
   1265         break;
   1266         }
   1267       }
   1268     else {
   1269       /* Data length specified. */
   1270       size_t len;
   1271 
   1272       if(pfsize < 0 || pfsize > SIZE_MAX) {
   1273         result = CURLE_OUT_OF_MEMORY;
   1274         break;
   1275         }
   1276 
   1277       len = pfsize;
   1278       pfsize = len * MAX_CONV_EXPANSION;
   1279 
   1280       if(pfsize > SIZE_MAX)
   1281         pfsize = SIZE_MAX;
   1282 
   1283       cp = malloc(pfsize);
   1284 
   1285       if(!cp) {
   1286         result = CURLE_OUT_OF_MEMORY;
   1287         break;
   1288         }
   1289 
   1290       pfsize = convert(cp, pfsize, ASCII_CCSID, s, len, ccsid);
   1291 
   1292       if(pfsize < 0) {
   1293         free(cp);
   1294         result = CURLE_OUT_OF_MEMORY;
   1295         break;
   1296         }
   1297 
   1298       data->set.postfieldsize = pfsize;         /* Replace data size. */
   1299       s = cp;
   1300       }
   1301 
   1302     result = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, s);
   1303     data->set.str[STRING_COPYPOSTFIELDS] = s;   /* Give to library. */
   1304     break;
   1305 
   1306   case CURLOPT_ERRORBUFFER:                     /* This is an output buffer. */
   1307   default:
   1308     result = Curl_vsetopt(data, tag, arg);
   1309     break;
   1310     }
   1311 
   1312   va_end(arg);
   1313   return result;
   1314 }
   1315 
   1316 
   1317 char *
   1318 curl_form_long_value(long value)
   1319 
   1320 {
   1321   /* ILE/RPG cannot cast an integer to a pointer. This procedure does it. */
   1322 
   1323   return (char *) value;
   1324 }
   1325 
   1326 
   1327 char *
   1328 curl_pushheader_bynum_cssid(struct curl_pushheaders *h,
   1329                             size_t num, unsigned int ccsid)
   1330 
   1331 {
   1332   char *d = (char *) NULL;
   1333   char *s = curl_pushheader_bynum(h, num);
   1334 
   1335   if(s)
   1336     d = dynconvert(ccsid, s, -1, ASCII_CCSID);
   1337 
   1338   return d;
   1339 }
   1340 
   1341 
   1342 char *
   1343 curl_pushheader_byname_ccsid(struct curl_pushheaders *h, const char *header,
   1344                              unsigned int ccsidin, unsigned int ccsidout)
   1345 
   1346 {
   1347   char *d = (char *) NULL;
   1348   char *s;
   1349 
   1350   if(header) {
   1351     header = dynconvert(ASCII_CCSID, header, -1, ccsidin);
   1352 
   1353     if(header) {
   1354       s = curl_pushheader_byname(h, header);
   1355       free((char *) header);
   1356 
   1357       if(s)
   1358         d = dynconvert(ccsidout, s, -1, ASCII_CCSID);
   1359     }
   1360   }
   1361 
   1362   return d;
   1363 }
   1364 
   1365 static CURLcode
   1366 mime_string_call(curl_mimepart *part, const char *string, unsigned int ccsid,
   1367                  CURLcode (*mimefunc)(curl_mimepart *part, const char *string))
   1368 
   1369 {
   1370   char *s = (char *) NULL;
   1371   CURLcode result;
   1372 
   1373   if(!string)
   1374     return mimefunc(part, string);
   1375   s = dynconvert(ASCII_CCSID, string, -1, ccsid);
   1376   if(!s)
   1377     return CURLE_OUT_OF_MEMORY;
   1378 
   1379   result = mimefunc(part, s);
   1380   free(s);
   1381   return result;
   1382 }
   1383 
   1384 CURLcode
   1385 curl_mime_name_ccsid(curl_mimepart *part, const char *name, unsigned int ccsid)
   1386 
   1387 {
   1388   return mime_string_call(part, name, ccsid, curl_mime_name);
   1389 }
   1390 
   1391 CURLcode
   1392 curl_mime_filename_ccsid(curl_mimepart *part,
   1393                          const char *filename, unsigned int ccsid)
   1394 
   1395 {
   1396   return mime_string_call(part, filename, ccsid, curl_mime_filename);
   1397 }
   1398 
   1399 CURLcode
   1400 curl_mime_type_ccsid(curl_mimepart *part,
   1401                      const char *mimetype, unsigned int ccsid)
   1402 
   1403 {
   1404   return mime_string_call(part, mimetype, ccsid, curl_mime_type);
   1405 }
   1406 
   1407 CURLcode
   1408 curl_mime_encoder_ccsid(curl_mimepart *part,
   1409                        const char *encoding, unsigned int ccsid)
   1410 
   1411 {
   1412   return mime_string_call(part, encoding, ccsid, curl_mime_encoder);
   1413 }
   1414 
   1415 CURLcode
   1416 curl_mime_filedata_ccsid(curl_mimepart *part,
   1417                          const char *filename, unsigned int ccsid)
   1418 
   1419 {
   1420   return mime_string_call(part, filename, ccsid, curl_mime_filedata);
   1421 }
   1422 
   1423 CURLcode
   1424 curl_mime_data_ccsid(curl_mimepart *part,
   1425                      const char *data, size_t datasize, unsigned int ccsid)
   1426 
   1427 {
   1428   char *s = (char *) NULL;
   1429   CURLcode result;
   1430 
   1431   if(!data)
   1432     return curl_mime_data(part, data, datasize);
   1433   s = dynconvert(ASCII_CCSID, data, datasize, ccsid);
   1434   if(!s)
   1435     return CURLE_OUT_OF_MEMORY;
   1436 
   1437   result = curl_mime_data(part, s, datasize);
   1438   free(s);
   1439   return result;
   1440 }
   1441 
   1442 CURLUcode
   1443 curl_url_get_ccsid(CURLU *handle, CURLUPart what, char **part,
   1444                    unsigned int flags, unsigned int ccsid)
   1445 
   1446 {
   1447   char *s = (char *)NULL;
   1448   CURLUcode result;
   1449 
   1450   if(!part)
   1451     return CURLUE_BAD_PARTPOINTER;
   1452 
   1453   *part = (char *)NULL;
   1454   result = curl_url_get(handle, what, &s, flags);
   1455   if(result == CURLUE_OK) {
   1456     if(s) {
   1457       *part = dynconvert(ccsid, s, -1, ASCII_CCSID);
   1458       if(!*part)
   1459         result = CURLUE_OUT_OF_MEMORY;
   1460     }
   1461   }
   1462   if(s)
   1463     free(s);
   1464   return result;
   1465 }
   1466 
   1467 CURLUcode
   1468 curl_url_set_ccsid(CURLU *handle, CURLUPart what, const char *part,
   1469                    unsigned int flags, unsigned int ccsid)
   1470 
   1471 {
   1472   char *s = (char *)NULL;
   1473   CURLUcode result;
   1474 
   1475   if(part) {
   1476     s = dynconvert(ASCII_CCSID, part, -1, ccsid);
   1477     if(!s)
   1478       return CURLUE_OUT_OF_MEMORY;
   1479   }
   1480   result = curl_url_set(handle, what, s, flags);
   1481   if(s)
   1482     free(s);
   1483   return result;
   1484 }
   1485