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