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