1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2015, 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 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, 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 105 static int 106 convert(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 162 static char * 163 dynconvert(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 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 int 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 220 for(; from; from = from->next) { 221 char * cp = dynconvert(dccsid, from->data, -1, sccsid); 222 223 if(!cp) { 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 233 char * 234 curl_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 259 char * 260 curl_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, string, 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 289 char * 290 curl_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, string, 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 324 struct curl_slist * 325 curl_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 347 time_t 348 curl_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 368 static int 369 convert_version_info_string(const char * * stringp, 370 char * * bufp, int * left, unsigned int ccsid) 371 372 { 373 /* Helper for curl_version_info_ccsid(): convert a string if defined. 374 Result is stored in the `*left'-byte buffer at `*bufp'. 375 `*bufp' and `*left' are updated accordingly. 376 Return 0 if ok, else -1. */ 377 378 if(*stringp) { 379 int l = convert(*bufp, *left, ccsid, *stringp, -1, ASCII_CCSID); 380 381 if(l <= 0) 382 return -1; 383 384 *stringp = *bufp; 385 *bufp += l; 386 *left -= l; 387 } 388 389 return 0; 390 } 391 392 393 curl_version_info_data * 394 curl_version_info_ccsid(CURLversion stamp, unsigned int ccsid) 395 396 { 397 curl_version_info_data * p; 398 char * cp; 399 int n; 400 int nproto; 401 curl_version_info_data * id; 402 403 /* The assertion below is possible, because although the second operand 404 is an enum member, the first is a #define. In that case, the OS/400 C 405 compiler seems to compare string values after substitution. */ 406 407 #if CURLVERSION_NOW != CURLVERSION_FOURTH 408 #error curl_version_info_data structure has changed: upgrade this procedure. 409 #endif 410 411 /* If caller has been compiled with a new version, error. */ 412 413 if(stamp > CURLVERSION_NOW) 414 return (curl_version_info_data *) NULL; 415 416 p = curl_version_info(stamp); 417 418 if(!p) 419 return p; 420 421 /* Measure thread space needed. */ 422 423 n = 0; 424 nproto = 0; 425 426 if(p->protocols) { 427 while(p->protocols[nproto]) 428 n += strlen(p->protocols[nproto++]); 429 430 n += nproto++; 431 } 432 433 if(p->version) 434 n += strlen(p->version) + 1; 435 436 if(p->host) 437 n += strlen(p->host) + 1; 438 439 if(p->ssl_version) 440 n += strlen(p->ssl_version) + 1; 441 442 if(p->libz_version) 443 n += strlen(p->libz_version) + 1; 444 445 if(p->ares) 446 n += strlen(p->ares) + 1; 447 448 if(p->libidn) 449 n += strlen(p->libidn) + 1; 450 451 if(p->libssh_version) 452 n += strlen(p->libssh_version) + 1; 453 454 /* Allocate thread space. */ 455 456 n *= MAX_CONV_EXPANSION; 457 458 if(nproto) 459 n += nproto * sizeof(const char *); 460 461 cp = Curl_thread_buffer(LK_VERSION_INFO_DATA, n); 462 id = (curl_version_info_data *) Curl_thread_buffer(LK_VERSION_INFO, 463 sizeof *id); 464 465 if(!id || !cp) 466 return (curl_version_info_data *) NULL; 467 468 /* Copy data and convert strings. */ 469 470 memcpy((char *) id, (char *) p, sizeof *p); 471 472 if(id->protocols) { 473 int i = nproto * sizeof id->protocols[0]; 474 475 id->protocols = (const char * const *) cp; 476 memcpy(cp, (char *) p->protocols, i); 477 cp += i; 478 n -= i; 479 480 for(i = 0; id->protocols[i]; i++) 481 if(convert_version_info_string(((const char * *) id->protocols) + i, 482 &cp, &n, ccsid)) 483 return (curl_version_info_data *) NULL; 484 } 485 486 if(convert_version_info_string(&id->version, &cp, &n, ccsid)) 487 return (curl_version_info_data *) NULL; 488 489 if(convert_version_info_string(&id->host, &cp, &n, ccsid)) 490 return (curl_version_info_data *) NULL; 491 492 if(convert_version_info_string(&id->ssl_version, &cp, &n, ccsid)) 493 return (curl_version_info_data *) NULL; 494 495 if(convert_version_info_string(&id->libz_version, &cp, &n, ccsid)) 496 return (curl_version_info_data *) NULL; 497 498 if(convert_version_info_string(&id->ares, &cp, &n, ccsid)) 499 return (curl_version_info_data *) NULL; 500 501 if(convert_version_info_string(&id->libidn, &cp, &n, ccsid)) 502 return (curl_version_info_data *) NULL; 503 504 if(convert_version_info_string(&id->libssh_version, &cp, &n, ccsid)) 505 return (curl_version_info_data *) NULL; 506 507 return id; 508 } 509 510 511 const char * 512 curl_easy_strerror_ccsid(CURLcode error, unsigned int ccsid) 513 514 { 515 int i; 516 const char * s; 517 char * buf; 518 519 s = curl_easy_strerror(error); 520 521 if(!s) 522 return s; 523 524 i = MAX_CONV_EXPANSION * (strlen(s) + 1); 525 526 if(!(buf = Curl_thread_buffer(LK_EASY_STRERROR, i))) 527 return (const char *) NULL; 528 529 if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0) 530 return (const char *) NULL; 531 532 return (const char *) buf; 533 } 534 535 536 const char * 537 curl_share_strerror_ccsid(CURLSHcode error, unsigned int ccsid) 538 539 { 540 int i; 541 const char * s; 542 char * buf; 543 544 s = curl_share_strerror(error); 545 546 if(!s) 547 return s; 548 549 i = MAX_CONV_EXPANSION * (strlen(s) + 1); 550 551 if(!(buf = Curl_thread_buffer(LK_SHARE_STRERROR, i))) 552 return (const char *) NULL; 553 554 if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0) 555 return (const char *) NULL; 556 557 return (const char *) buf; 558 } 559 560 561 const char * 562 curl_multi_strerror_ccsid(CURLMcode error, unsigned int ccsid) 563 564 { 565 int i; 566 const char * s; 567 char * buf; 568 569 s = curl_multi_strerror(error); 570 571 if(!s) 572 return s; 573 574 i = MAX_CONV_EXPANSION * (strlen(s) + 1); 575 576 if(!(buf = Curl_thread_buffer(LK_MULTI_STRERROR, i))) 577 return (const char *) NULL; 578 579 if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0) 580 return (const char *) NULL; 581 582 return (const char *) buf; 583 } 584 585 586 void 587 curl_certinfo_free_all(struct curl_certinfo *info) 588 589 { 590 /* Free all memory used by certificate info. */ 591 if(info) { 592 if(info->certinfo) { 593 int i; 594 595 for(i = 0; i < info->num_of_certs; i++) 596 curl_slist_free_all(info->certinfo[i]); 597 free((char *) info->certinfo); 598 } 599 free((char *) info); 600 } 601 } 602 603 604 CURLcode 605 curl_easy_getinfo_ccsid(CURL * curl, CURLINFO info, ...) 606 607 { 608 va_list arg; 609 void * paramp; 610 CURLcode ret; 611 unsigned int ccsid; 612 char * * cpp; 613 struct SessionHandle * data; 614 struct curl_slist * * slp; 615 struct curl_certinfo * cipf; 616 struct curl_certinfo * cipt; 617 618 /* WARNING: unlike curl_easy_get_info(), the strings returned by this 619 procedure have to be free'ed. */ 620 621 data = (struct SessionHandle *) curl; 622 va_start(arg, info); 623 paramp = va_arg(arg, void *); 624 ret = Curl_getinfo(data, info, paramp); 625 626 if(ret == CURLE_OK) 627 switch ((int) info & CURLINFO_TYPEMASK) { 628 629 case CURLINFO_STRING: 630 ccsid = va_arg(arg, unsigned int); 631 cpp = (char * *) paramp; 632 633 if(*cpp) { 634 *cpp = dynconvert(ccsid, *cpp, -1, ASCII_CCSID); 635 636 if(!*cpp) 637 ret = CURLE_OUT_OF_MEMORY; 638 } 639 640 break; 641 642 case CURLINFO_SLIST: 643 ccsid = va_arg(arg, unsigned int); 644 switch (info) { 645 case CURLINFO_CERTINFO: 646 cipf = *(struct curl_certinfo * *) paramp; 647 if(cipf) { 648 if(!(cipt = (struct curl_certinfo *) malloc(sizeof *cipt))) 649 ret = CURLE_OUT_OF_MEMORY; 650 else { 651 cipt->certinfo = (struct curl_slist * *) 652 calloc(cipf->num_of_certs + 653 1, sizeof(struct curl_slist *)); 654 if(!cipt->certinfo) 655 ret = CURLE_OUT_OF_MEMORY; 656 else { 657 int i; 658 659 cipt->num_of_certs = cipf->num_of_certs; 660 for(i = 0; i < cipf->num_of_certs; i++) 661 if(cipf->certinfo[i]) 662 if(!(cipt->certinfo[i] = slist_convert(ccsid, 663 cipf->certinfo[i], 664 ASCII_CCSID))) { 665 ret = CURLE_OUT_OF_MEMORY; 666 break; 667 } 668 } 669 } 670 671 if(ret != CURLE_OK) { 672 curl_certinfo_free_all(cipt); 673 cipt = (struct curl_certinfo *) NULL; 674 } 675 676 *(struct curl_certinfo * *) paramp = cipt; 677 } 678 679 break; 680 681 case CURLINFO_TLS_SESSION: 682 break; 683 684 default: 685 slp = (struct curl_slist * *) paramp; 686 if(*slp) 687 if(!(*slp = slist_convert(ccsid, *slp, ASCII_CCSID))) 688 ret = CURLE_OUT_OF_MEMORY; 689 break; 690 } 691 } 692 693 va_end(arg); 694 return ret; 695 } 696 697 698 static int 699 Curl_is_formadd_string(CURLformoption option) 700 701 { 702 switch (option) { 703 704 case CURLFORM_FILENAME: 705 case CURLFORM_CONTENTTYPE: 706 case CURLFORM_BUFFER: 707 case CURLFORM_FILE: 708 case CURLFORM_FILECONTENT: 709 case CURLFORM_COPYCONTENTS: 710 case CURLFORM_COPYNAME: 711 return 1; 712 } 713 714 return 0; 715 } 716 717 718 static void 719 Curl_formadd_release_local(struct curl_forms * forms, int nargs, int skip) 720 721 { 722 while(nargs--) 723 if(nargs != skip) 724 if(Curl_is_formadd_string(forms[nargs].option)) 725 if(forms[nargs].value) 726 free((char *) forms[nargs].value); 727 728 free((char *) forms); 729 } 730 731 732 static int 733 Curl_formadd_convert(struct curl_forms * forms, 734 int formx, int lengthx, unsigned int ccsid) 735 736 { 737 int l; 738 char * cp; 739 char * cp2; 740 741 if(formx < 0 || !forms[formx].value) 742 return 0; 743 744 if(lengthx >= 0) 745 l = (int) forms[lengthx].value; 746 else 747 l = strlen(forms[formx].value) + 1; 748 749 cp = malloc(MAX_CONV_EXPANSION * l); 750 751 if(!cp) 752 return -1; 753 754 l = convert(cp, MAX_CONV_EXPANSION * l, ASCII_CCSID, 755 forms[formx].value, l, ccsid); 756 757 if(l < 0) { 758 free(cp); 759 return -1; 760 } 761 762 cp2 = realloc(cp, l); /* Shorten buffer to the string size. */ 763 764 if(cp2) 765 cp = cp2; 766 767 forms[formx].value = cp; 768 769 if(lengthx >= 0) 770 forms[lengthx].value = (char *) l; /* Update length after conversion. */ 771 772 return l; 773 } 774 775 776 CURLFORMcode 777 curl_formadd_ccsid(struct curl_httppost * * httppost, 778 struct curl_httppost * * last_post, ...) 779 780 { 781 va_list arg; 782 CURLformoption option; 783 CURLFORMcode result; 784 struct curl_forms * forms; 785 struct curl_forms * lforms; 786 struct curl_forms * tforms; 787 unsigned int lformlen; 788 const char * value; 789 unsigned int ccsid; 790 int nargs; 791 int namex; 792 int namelengthx; 793 int contentx; 794 int lengthx; 795 unsigned int contentccsid; 796 unsigned int nameccsid; 797 798 /* A single curl_formadd() call cannot be splitted in several calls to deal 799 with all parameters: the original parameters are thus copied to a local 800 curl_forms array and converted to ASCII when needed. 801 CURLFORM_PTRNAME is processed as if it were CURLFORM_COPYNAME. 802 CURLFORM_COPYNAME and CURLFORM_NAMELENGTH occurrence order in 803 parameters is not defined; for this reason, the actual conversion is 804 delayed to the end of parameter processing. The same applies to 805 CURLFORM_COPYCONTENTS/CURLFORM_CONTENTSLENGTH, but these may appear 806 several times in the parameter list; the problem resides here in knowing 807 which CURLFORM_CONTENTSLENGTH applies to which CURLFORM_COPYCONTENTS and 808 when we can be sure to have both info for conversion: end of parameter 809 list is such a point, but CURLFORM_CONTENTTYPE is also used here as a 810 natural separator between content data definitions; this seems to be 811 in accordance with FormAdd() behavior. */ 812 813 /* Allocate the local curl_forms array. */ 814 815 lformlen = ALLOC_GRANULE; 816 lforms = malloc(lformlen * sizeof *lforms); 817 818 if(!lforms) 819 return CURL_FORMADD_MEMORY; 820 821 /* Process the arguments, copying them into local array, latching conversion 822 indexes and converting when needed. */ 823 824 result = CURL_FORMADD_OK; 825 nargs = 0; 826 contentx = -1; 827 lengthx = -1; 828 namex = -1; 829 namelengthx = -1; 830 forms = (struct curl_forms *) NULL; 831 va_start(arg, last_post); 832 833 for(;;) { 834 /* Make sure there is still room for an item in local array. */ 835 836 if(nargs >= lformlen) { 837 lformlen += ALLOC_GRANULE; 838 tforms = realloc(lforms, lformlen * sizeof *lforms); 839 840 if(!tforms) { 841 result = CURL_FORMADD_MEMORY; 842 break; 843 } 844 845 lforms = tforms; 846 } 847 848 /* Get next option. */ 849 850 if(forms) { 851 /* Get option from array. */ 852 853 option = forms->option; 854 value = forms->value; 855 forms++; 856 } 857 else { 858 /* Get option from arguments. */ 859 860 option = va_arg(arg, CURLformoption); 861 862 if(option == CURLFORM_END) 863 break; 864 } 865 866 /* Dispatch by option. */ 867 868 switch (option) { 869 870 case CURLFORM_END: 871 forms = (struct curl_forms *) NULL; /* Leave array mode. */ 872 continue; 873 874 case CURLFORM_ARRAY: 875 if(!forms) { 876 forms = va_arg(arg, struct curl_forms *); 877 continue; 878 } 879 880 result = CURL_FORMADD_ILLEGAL_ARRAY; 881 break; 882 883 case CURLFORM_COPYNAME: 884 option = CURLFORM_PTRNAME; /* Static for now. */ 885 886 case CURLFORM_PTRNAME: 887 if(namex >= 0) 888 result = CURL_FORMADD_OPTION_TWICE; 889 890 namex = nargs; 891 892 if(!forms) { 893 value = va_arg(arg, char *); 894 nameccsid = (unsigned int) va_arg(arg, long); 895 } 896 else { 897 nameccsid = (unsigned int) forms->value; 898 forms++; 899 } 900 901 break; 902 903 case CURLFORM_COPYCONTENTS: 904 if(contentx >= 0) 905 result = CURL_FORMADD_OPTION_TWICE; 906 907 contentx = nargs; 908 909 if(!forms) { 910 value = va_arg(arg, char *); 911 contentccsid = (unsigned int) va_arg(arg, long); 912 } 913 else { 914 contentccsid = (unsigned int) forms->value; 915 forms++; 916 } 917 918 break; 919 920 case CURLFORM_PTRCONTENTS: 921 case CURLFORM_BUFFERPTR: 922 if(!forms) 923 value = va_arg(arg, char *); /* No conversion. */ 924 925 break; 926 927 case CURLFORM_CONTENTSLENGTH: 928 lengthx = nargs; 929 930 if(!forms) 931 value = (char *) va_arg(arg, long); 932 933 break; 934 935 case CURLFORM_NAMELENGTH: 936 namelengthx = nargs; 937 938 if(!forms) 939 value = (char *) va_arg(arg, long); 940 941 break; 942 943 case CURLFORM_BUFFERLENGTH: 944 if(!forms) 945 value = (char *) va_arg(arg, long); 946 947 break; 948 949 case CURLFORM_CONTENTHEADER: 950 if(!forms) 951 value = (char *) va_arg(arg, struct curl_slist *); 952 953 break; 954 955 case CURLFORM_STREAM: 956 if(!forms) 957 value = (char *) va_arg(arg, void *); 958 959 break; 960 961 case CURLFORM_CONTENTTYPE: 962 /* If a previous content has been encountered, convert it now. */ 963 964 if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) { 965 result = CURL_FORMADD_MEMORY; 966 break; 967 } 968 969 contentx = -1; 970 lengthx = -1; 971 /* Fall into default. */ 972 973 default: 974 /* Must be a convertible string. */ 975 976 if(!Curl_is_formadd_string(option)) { 977 result = CURL_FORMADD_UNKNOWN_OPTION; 978 break; 979 } 980 981 if(!forms) { 982 value = va_arg(arg, char *); 983 ccsid = (unsigned int) va_arg(arg, long); 984 } 985 else { 986 ccsid = (unsigned int) forms->value; 987 forms++; 988 } 989 990 /* Do the conversion. */ 991 992 lforms[nargs].value = value; 993 994 if(Curl_formadd_convert(lforms, nargs, -1, ccsid) < 0) { 995 result = CURL_FORMADD_MEMORY; 996 break; 997 } 998 999 value = lforms[nargs].value; 1000 } 1001 1002 if(result != CURL_FORMADD_OK) 1003 break; 1004 1005 lforms[nargs].value = value; 1006 lforms[nargs++].option = option; 1007 } 1008 1009 va_end(arg); 1010 1011 /* Convert the name and the last content, now that we know their lengths. */ 1012 1013 if(result == CURL_FORMADD_OK && namex >= 0) { 1014 if(Curl_formadd_convert(lforms, namex, namelengthx, nameccsid) < 0) 1015 result = CURL_FORMADD_MEMORY; 1016 else 1017 lforms[namex].option = CURLFORM_COPYNAME; /* Force copy. */ 1018 } 1019 1020 if(result == CURL_FORMADD_OK) { 1021 if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) 1022 result = CURL_FORMADD_MEMORY; 1023 else 1024 contentx = -1; 1025 } 1026 1027 /* Do the formadd with our converted parameters. */ 1028 1029 if(result == CURL_FORMADD_OK) { 1030 lforms[nargs].option = CURLFORM_END; 1031 result = curl_formadd(httppost, last_post, 1032 CURLFORM_ARRAY, lforms, CURLFORM_END); 1033 } 1034 1035 /* Terminate. */ 1036 1037 Curl_formadd_release_local(lforms, nargs, contentx); 1038 return result; 1039 } 1040 1041 1042 typedef struct { 1043 curl_formget_callback append; 1044 void * arg; 1045 unsigned int ccsid; 1046 } cfcdata; 1047 1048 1049 static size_t 1050 Curl_formget_callback_ccsid(void * arg, const char * buf, size_t len) 1051 1052 { 1053 cfcdata * p; 1054 char * b; 1055 int l; 1056 size_t ret; 1057 1058 p = (cfcdata *) arg; 1059 1060 if((long) len <= 0) 1061 return (*p->append)(p->arg, buf, len); 1062 1063 b = malloc(MAX_CONV_EXPANSION * len); 1064 1065 if(!b) 1066 return (size_t) -1; 1067 1068 l = convert(b, MAX_CONV_EXPANSION * len, p->ccsid, buf, len, ASCII_CCSID); 1069 1070 if(l < 0) { 1071 free(b); 1072 return (size_t) -1; 1073 } 1074 1075 ret = (*p->append)(p->arg, b, l); 1076 free(b); 1077 return ret == l? len: -1; 1078 } 1079 1080 1081 int 1082 curl_formget_ccsid(struct curl_httppost * form, void * arg, 1083 curl_formget_callback append, unsigned int ccsid) 1084 1085 { 1086 cfcdata lcfc; 1087 1088 lcfc.append = append; 1089 lcfc.arg = arg; 1090 lcfc.ccsid = ccsid; 1091 return curl_formget(form, (void *) &lcfc, Curl_formget_callback_ccsid); 1092 } 1093 1094 1095 CURLcode 1096 curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...) 1097 1098 { 1099 CURLcode result; 1100 va_list arg; 1101 struct SessionHandle * data; 1102 char * s; 1103 char * cp; 1104 unsigned int ccsid; 1105 curl_off_t pfsize; 1106 static char testwarn = 1; 1107 1108 /* Warns if this procedure has not been updated when the dupstring enum 1109 changes. 1110 We (try to) do it only once: there is no need to issue several times 1111 the same message; but since threadsafeness is not handled here, 1112 this may occur (and we don't care!). */ 1113 1114 if(testwarn) { 1115 testwarn = 0; 1116 1117 if((int) STRING_LASTZEROTERMINATED != (int) STRING_UNIX_SOCKET_PATH + 1 || 1118 (int) STRING_LAST != (int) STRING_COPYPOSTFIELDS + 1) 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_LOGIN_OPTIONS: 1147 case CURLOPT_MAIL_FROM: 1148 case CURLOPT_MAIL_AUTH: 1149 case CURLOPT_NETRC_FILE: 1150 case CURLOPT_NOPROXY: 1151 case CURLOPT_PASSWORD: 1152 case CURLOPT_PINNEDPUBLICKEY: 1153 case CURLOPT_PROXY: 1154 case CURLOPT_PROXYPASSWORD: 1155 case CURLOPT_PROXYUSERNAME: 1156 case CURLOPT_PROXYUSERPWD: 1157 case CURLOPT_PROXY_SERVICE_NAME: 1158 case CURLOPT_RANDOM_FILE: 1159 case CURLOPT_RANGE: 1160 case CURLOPT_REFERER: 1161 case CURLOPT_RTSP_SESSION_ID: 1162 case CURLOPT_RTSP_STREAM_URI: 1163 case CURLOPT_RTSP_TRANSPORT: 1164 case CURLOPT_SERVICE_NAME: 1165 case CURLOPT_SOCKS5_GSSAPI_SERVICE: 1166 case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: 1167 case CURLOPT_SSH_KNOWNHOSTS: 1168 case CURLOPT_SSH_PRIVATE_KEYFILE: 1169 case CURLOPT_SSH_PUBLIC_KEYFILE: 1170 case CURLOPT_SSLCERT: 1171 case CURLOPT_SSLCERTTYPE: 1172 case CURLOPT_SSL_CIPHER_LIST: 1173 case CURLOPT_SSLENGINE: 1174 case CURLOPT_SSLKEY: 1175 case CURLOPT_SSLKEYTYPE: 1176 case CURLOPT_TLSAUTH_PASSWORD: 1177 case CURLOPT_TLSAUTH_TYPE: 1178 case CURLOPT_TLSAUTH_USERNAME: 1179 case CURLOPT_UNIX_SOCKET_PATH: 1180 case CURLOPT_URL: 1181 case CURLOPT_USERAGENT: 1182 case CURLOPT_USERNAME: 1183 case CURLOPT_USERPWD: 1184 case CURLOPT_XOAUTH2_BEARER: 1185 s = va_arg(arg, char *); 1186 ccsid = va_arg(arg, unsigned int); 1187 1188 if(s) { 1189 s = dynconvert(ASCII_CCSID, s, -1, ccsid); 1190 1191 if(!s) { 1192 result = CURLE_OUT_OF_MEMORY; 1193 break; 1194 } 1195 } 1196 1197 result = curl_easy_setopt(curl, tag, s); 1198 free(s); 1199 break; 1200 1201 case CURLOPT_COPYPOSTFIELDS: 1202 /* Special case: byte count may have been given by CURLOPT_POSTFIELDSIZE 1203 prior to this call. In this case, convert the given byte count and 1204 replace the length according to the conversion result. */ 1205 s = va_arg(arg, char *); 1206 ccsid = va_arg(arg, unsigned int); 1207 1208 pfsize = data->set.postfieldsize; 1209 1210 if(!s || !pfsize || ccsid == NOCONV_CCSID || ccsid == ASCII_CCSID) { 1211 result = curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, s); 1212 break; 1213 } 1214 1215 if(pfsize == -1) { 1216 /* Data is null-terminated. */ 1217 s = dynconvert(ASCII_CCSID, s, -1, ccsid); 1218 1219 if(!s) { 1220 result = CURLE_OUT_OF_MEMORY; 1221 break; 1222 } 1223 } 1224 else { 1225 /* Data length specified. */ 1226 size_t len; 1227 1228 if(pfsize < 0 || pfsize > SIZE_MAX) { 1229 result = CURLE_OUT_OF_MEMORY; 1230 break; 1231 } 1232 1233 len = pfsize; 1234 pfsize = len * MAX_CONV_EXPANSION; 1235 1236 if(pfsize > SIZE_MAX) 1237 pfsize = SIZE_MAX; 1238 1239 cp = malloc(pfsize); 1240 1241 if(!cp) { 1242 result = CURLE_OUT_OF_MEMORY; 1243 break; 1244 } 1245 1246 pfsize = convert(cp, pfsize, ASCII_CCSID, s, len, ccsid); 1247 1248 if(pfsize < 0) { 1249 free(cp); 1250 result = CURLE_OUT_OF_MEMORY; 1251 break; 1252 } 1253 1254 data->set.postfieldsize = pfsize; /* Replace data size. */ 1255 s = cp; 1256 } 1257 1258 result = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, s); 1259 data->set.str[STRING_COPYPOSTFIELDS] = s; /* Give to library. */ 1260 break; 1261 1262 case CURLOPT_ERRORBUFFER: /* This is an output buffer. */ 1263 default: 1264 result = Curl_setopt(data, tag, arg); 1265 break; 1266 } 1267 1268 va_end(arg); 1269 return result; 1270 } 1271 1272 1273 char * 1274 curl_form_long_value(long value) 1275 1276 { 1277 /* ILE/RPG cannot cast an integer to a pointer. This procedure does it. */ 1278 1279 return (char *) value; 1280 } 1281