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