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