Optimize length check
[TortoiseGit.git] / ext / CrashServer / external / gsoap-win32-2.8.0 / stdsoap2.cpp
blobf01d0695bbe5aab8e020c28a94c5fae07086a06b
1 /*
2 stdsoap2.c[pp] 2.8.0
4 gSOAP runtime engine
6 gSOAP XML Web services tools
7 Copyright (C) 2000-2010, Robert van Engelen, Genivia Inc., All Rights Reserved.
8 This part of the software is released under ONE of the following licenses:
9 GPL, or the gSOAP public license, or Genivia's license for commercial use.
10 --------------------------------------------------------------------------------
11 Contributors:
13 Wind River Systems Inc., for the following additions under gSOAP public license:
14 - vxWorks compatible
15 --------------------------------------------------------------------------------
16 gSOAP public license.
18 The contents of this file are subject to the gSOAP Public License Version 1.3
19 (the "License"); you may not use this file except in compliance with the
20 License. You may obtain a copy of the License at
21 http://www.cs.fsu.edu/~engelen/soaplicense.html
22 Software distributed under the License is distributed on an "AS IS" basis,
23 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
24 for the specific language governing rights and limitations under the License.
26 The Initial Developer of the Original Code is Robert A. van Engelen.
27 Copyright (C) 2000-2010, Robert van Engelen, Genivia Inc., All Rights Reserved.
28 --------------------------------------------------------------------------------
29 GPL license.
31 This program is free software; you can redistribute it and/or modify it under
32 the terms of the GNU General Public License as published by the Free Software
33 Foundation; either version 2 of the License, or (at your option) any later
34 version.
36 This program is distributed in the hope that it will be useful, but WITHOUT ANY
37 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
38 PARTICULAR PURPOSE. See the GNU General Public License for more details.
40 You should have received a copy of the GNU General Public License along with
41 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
42 Place, Suite 330, Boston, MA 02111-1307 USA
44 Author contact information:
45 engelen@genivia.com / engelen@acm.org
47 This program is released under the GPL with the additional exemption that
48 compiling, linking, and/or using OpenSSL is allowed.
49 --------------------------------------------------------------------------------
50 A commercial use license is available from Genivia, Inc., contact@genivia.com
51 --------------------------------------------------------------------------------
53 Installation note:
55 Win32 build needs winsock.dll (Visual C++ "wsock32.lib")
56 To do this in Visual C++ 6.0, go to "Project", "settings", select the "Link"
57 tab (the project file needs to be selected in the file view) and add
58 "wsock32.lib" to the "Object/library modules" entry
60 On Mac OS X with gcc (GCC) 3.1 20020420 (prerelease) you MUST compile with
61 -fstack_check when using -O2 because gcc 3.1 has a bug that smashes the stack
62 when locally allocated data exceeds 64K.
66 #ifdef AS400
67 # pragma convert(819) /* EBCDIC to ASCII */
68 #endif
70 #include "stdsoap2.h"
72 #ifdef __BORLANDC__
73 # pragma warn -8060
74 #else
75 # ifdef WIN32
76 # ifdef UNDER_CE
77 # pragma comment(lib, "winsock.lib")
78 # else
79 # pragma comment(lib, "wsock32.lib")
80 # endif
81 # pragma warning(disable : 4996) /* disable deprecation warnings */
82 # endif
83 #endif
85 #ifdef __cplusplus
86 SOAP_SOURCE_STAMP("@(#) stdsoap2.cpp ver 2.8.0 2010-09-20 00:00:00 GMT")
87 extern "C" {
88 #else
89 SOAP_SOURCE_STAMP("@(#) stdsoap2.c ver 2.8.0 2010-09-20 00:00:00 GMT")
90 #endif
92 /* 8bit character representing unknown/nonrepresentable character data (e.g. not supported by current locale with multibyte support enabled) */
93 #ifndef SOAP_UNKNOWN_CHAR
94 #define SOAP_UNKNOWN_CHAR (127)
95 #endif
97 /* EOF=-1 */
98 #define SOAP_LT (soap_wchar)(-2) /* XML character '<' */
99 #define SOAP_TT (soap_wchar)(-3) /* XML character '</' */
100 #define SOAP_GT (soap_wchar)(-4) /* XML character '>' */
101 #define SOAP_QT (soap_wchar)(-5) /* XML character '"' */
102 #define SOAP_AP (soap_wchar)(-6) /* XML character ''' */
104 #define soap_blank(c) ((c) >= 0 && (c) <= 32)
105 #define soap_notblank(c) ((c) > 32)
107 #if defined(WIN32) && !defined(UNDER_CE)
108 #define soap_hash_ptr(p) ((PtrToUlong(p) >> 3) & (SOAP_PTRHASH - 1))
109 #else
110 #define soap_hash_ptr(p) ((size_t)(((unsigned long)(p) >> 3) & (SOAP_PTRHASH-1)))
111 #endif
113 #if !defined(WITH_LEAN) || defined(SOAP_DEBUG)
114 static void soap_init_logs(struct soap*);
115 #endif
116 #ifdef SOAP_DEBUG
117 static void soap_close_logfile(struct soap*, int);
118 static void soap_set_logfile(struct soap*, int, const char*);
119 #endif
121 #ifdef SOAP_MEM_DEBUG
122 static void soap_init_mht(struct soap*);
123 static void soap_free_mht(struct soap*);
124 static void soap_track_unlink(struct soap*, const void*);
125 #endif
127 #ifndef PALM_2
128 static int soap_set_error(struct soap*, const char*, const char*, const char*, const char*, int);
129 static int soap_copy_fault(struct soap*, const char*, const char*, const char*, const char*);
130 static int soap_getattrval(struct soap*, char*, size_t, soap_wchar);
131 #endif
133 #ifndef PALM_1
134 static void soap_free_ns(struct soap *soap);
135 static soap_wchar soap_char(struct soap*);
136 static soap_wchar soap_get_pi(struct soap*);
137 static int soap_isxdigit(int);
138 static void *fplugin(struct soap*, const char*);
139 static size_t soap_count_attachments(struct soap *soap);
140 static int soap_try_connect_command(struct soap*, int http_command, const char *endpoint, const char *action);
141 #ifndef WITH_NOIDREF
142 static void soap_update_ptrs(struct soap*, char*, char*, char*, char*);
143 static int soap_has_copies(struct soap*, const char*, const char*);
144 static void soap_init_iht(struct soap*);
145 static void soap_free_iht(struct soap*);
146 static void soap_init_pht(struct soap*);
147 static void soap_free_pht(struct soap*);
148 #endif
149 #endif
151 #ifndef WITH_LEAN
152 static const char *soap_set_validation_fault(struct soap*, const char*, const char*);
153 static int soap_isnumeric(struct soap*, const char*);
154 static struct soap_nlist *soap_push_ns(struct soap *soap, const char *id, const char *ns, short utilized);
155 static void soap_utilize_ns(struct soap *soap, const char *tag, size_t n);
156 #endif
158 #ifndef WITH_LEANER
159 #ifndef PALM_1
160 static struct soap_multipart *soap_new_multipart(struct soap*, struct soap_multipart**, struct soap_multipart**, char*, size_t);
161 static int soap_putdimefield(struct soap*, const char*, size_t);
162 static char *soap_getdimefield(struct soap*, size_t);
163 static void soap_select_mime_boundary(struct soap*);
164 static int soap_valid_mime_boundary(struct soap*);
165 static void soap_resolve_attachment(struct soap*, struct soap_multipart*);
166 #endif
167 #endif
169 #ifdef WITH_GZIP
170 static int soap_getgziphdr(struct soap*);
171 #endif
173 #ifdef WITH_OPENSSL
174 # ifndef SOAP_SSL_RSA_BITS
175 # define SOAP_SSL_RSA_BITS 2048
176 # endif
177 static int soap_ssl_init_done = 0;
178 static int ssl_auth_init(struct soap*);
179 static int ssl_verify_callback(int, X509_STORE_CTX*);
180 static int ssl_verify_callback_allow_expired_certificate(int, X509_STORE_CTX*);
181 static int ssl_password(char*, int, int, void *);
182 #endif
184 #ifdef WITH_GNUTLS
185 # ifndef SOAP_SSL_RSA_BITS
186 # define SOAP_SSL_RSA_BITS 2048
187 # endif
188 static int soap_ssl_init_done = 0;
189 static const char *ssl_verify(struct soap *soap, const char *host);
190 # if defined(HAVE_PTHREAD_H)
191 # include <pthread.h>
192 /* make GNUTLS thread safe with pthreads */
193 GCRY_THREAD_OPTION_PTHREAD_IMPL;
194 # elif defined(HAVE_PTH_H)
195 #include <pth.h>
196 /* make GNUTLS thread safe with PTH */
197 GCRY_THREAD_OPTION_PTH_IMPL;
198 # endif
199 #endif
201 #if !defined(WITH_NOHTTP) || !defined(WITH_LEANER)
202 #ifndef PALM_1
203 static const char *soap_decode(char*, size_t, const char*, const char*);
204 #endif
205 #endif
207 #ifndef WITH_NOHTTP
208 #ifndef PALM_1
209 static soap_wchar soap_getchunkchar(struct soap*);
210 static const char *http_error(struct soap*, int);
211 static int http_put(struct soap*);
212 static int http_get(struct soap*);
213 static int http_405(struct soap*);
214 static int http_post(struct soap*, const char*, const char*, int, const char*, const char*, size_t);
215 static int http_send_header(struct soap*, const char*);
216 static int http_post_header(struct soap*, const char*, const char*);
217 static int http_response(struct soap*, int, size_t);
218 static int http_parse(struct soap*);
219 static int http_parse_header(struct soap*, const char*, const char*);
220 #endif
221 #endif
223 #ifndef WITH_NOIO
225 #ifndef PALM_1
226 static int fsend(struct soap*, const char*, size_t);
227 static size_t frecv(struct soap*, char*, size_t);
228 static int tcp_init(struct soap*);
229 static const char *tcp_error(struct soap*);
230 #ifndef WITH_IPV6
231 static int tcp_gethost(struct soap*, const char *addr, struct in_addr *inaddr);
232 #endif
233 static SOAP_SOCKET tcp_connect(struct soap*, const char *endpoint, const char *host, int port);
234 static SOAP_SOCKET tcp_accept(struct soap*, SOAP_SOCKET, struct sockaddr*, int*);
235 static int tcp_select(struct soap*, SOAP_SOCKET, int, int);
236 static int tcp_disconnect(struct soap*);
237 static int tcp_closesocket(struct soap*, SOAP_SOCKET);
238 static int tcp_shutdownsocket(struct soap*, SOAP_SOCKET, int);
239 static const char *soap_strerror(struct soap*);
240 #endif
242 #define SOAP_TCP_SELECT_RCV 0x1
243 #define SOAP_TCP_SELECT_SND 0x2
244 #define SOAP_TCP_SELECT_ERR 0x4
245 #define SOAP_TCP_SELECT_ALL 0x7
247 #if defined(WIN32)
248 #define SOAP_SOCKBLOCK(fd) \
249 { u_long blocking = 0; \
250 ioctlsocket(fd, FIONBIO, &blocking); \
252 #define SOAP_SOCKNONBLOCK(fd) \
253 { u_long nonblocking = 1; \
254 ioctlsocket(fd, FIONBIO, &nonblocking); \
256 #elif defined(VXWORKS)
257 #define SOAP_SOCKBLOCK(fd) \
258 { u_long blocking = 0; \
259 ioctl(fd, FIONBIO, (int)(&blocking)); \
261 #define SOAP_SOCKNONBLOCK(fd) \
262 { u_long nonblocking = 1; \
263 ioctl(fd, FIONBIO, (int)(&nonblocking)); \
265 #elif defined(PALM)
266 #define SOAP_SOCKBLOCK(fd) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0)&~O_NONBLOCK);
267 #define SOAP_SOCKNONBLOCK(fd) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0)|O_NONBLOCK);
268 #elif defined(SYMBIAN)
269 #define SOAP_SOCKBLOCK(fd) \
270 { long blocking = 0; \
271 ioctl(fd, 0/*FIONBIO*/, &blocking); \
273 #define SOAP_SOCKNONBLOCK(fd) \
274 { long nonblocking = 1; \
275 ioctl(fd, 0/*FIONBIO*/, &nonblocking); \
277 #else
278 #define SOAP_SOCKBLOCK(fd) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)&~O_NONBLOCK);
279 #define SOAP_SOCKNONBLOCK(fd) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)|O_NONBLOCK);
280 #endif
282 #endif
284 #if defined(PALM) && !defined(PALM_2)
285 unsigned short errno;
286 #endif
288 #ifndef PALM_1
289 static const char soap_env1[42] = "http://schemas.xmlsoap.org/soap/envelope/";
290 static const char soap_enc1[42] = "http://schemas.xmlsoap.org/soap/encoding/";
291 static const char soap_env2[40] = "http://www.w3.org/2003/05/soap-envelope";
292 static const char soap_enc2[40] = "http://www.w3.org/2003/05/soap-encoding";
293 static const char soap_rpc[35] = "http://www.w3.org/2003/05/soap-rpc";
294 #endif
296 #ifndef PALM_1
297 const struct soap_double_nan soap_double_nan = {0xFFFFFFFF, 0xFFFFFFFF};
298 static const char soap_base64o[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
299 static const char soap_base64i[81] = "\76XXX\77\64\65\66\67\70\71\72\73\74\75XXXXXXX\00\01\02\03\04\05\06\07\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31XXXXXX\32\33\34\35\36\37\40\41\42\43\44\45\46\47\50\51\52\53\54\55\56\57\60\61\62\63";
300 #endif
302 #ifndef WITH_LEAN
303 static const char soap_indent[11] = "\n\t\t\t\t\t\t\t\t\t";
304 /* Alternative indentation form for SOAP_XML_INDENT:
305 static const char soap_indent[21] = "\n ";
307 #endif
309 #ifndef SOAP_CANARY
310 # define SOAP_CANARY (0xC0DE)
311 #endif
313 static const char soap_padding[4] = "\0\0\0";
314 #define SOAP_STR_PADDING (soap_padding)
315 #define SOAP_STR_EOS (soap_padding)
316 #define SOAP_NON_NULL (soap_padding)
318 #ifndef WITH_LEAN
319 static const struct soap_code_map html_entity_codes[] = /* entities for XHTML parsing */
320 { { 160, "nbsp" },
321 { 161, "iexcl" },
322 { 162, "cent" },
323 { 163, "pound" },
324 { 164, "curren" },
325 { 165, "yen" },
326 { 166, "brvbar" },
327 { 167, "sect" },
328 { 168, "uml" },
329 { 169, "copy" },
330 { 170, "ordf" },
331 { 171, "laquo" },
332 { 172, "not" },
333 { 173, "shy" },
334 { 174, "reg" },
335 { 175, "macr" },
336 { 176, "deg" },
337 { 177, "plusmn" },
338 { 178, "sup2" },
339 { 179, "sup3" },
340 { 180, "acute" },
341 { 181, "micro" },
342 { 182, "para" },
343 { 183, "middot" },
344 { 184, "cedil" },
345 { 185, "sup1" },
346 { 186, "ordm" },
347 { 187, "raquo" },
348 { 188, "frac14" },
349 { 189, "frac12" },
350 { 190, "frac34" },
351 { 191, "iquest" },
352 { 192, "Agrave" },
353 { 193, "Aacute" },
354 { 194, "Acirc" },
355 { 195, "Atilde" },
356 { 196, "Auml" },
357 { 197, "Aring" },
358 { 198, "AElig" },
359 { 199, "Ccedil" },
360 { 200, "Egrave" },
361 { 201, "Eacute" },
362 { 202, "Ecirc" },
363 { 203, "Euml" },
364 { 204, "Igrave" },
365 { 205, "Iacute" },
366 { 206, "Icirc" },
367 { 207, "Iuml" },
368 { 208, "ETH" },
369 { 209, "Ntilde" },
370 { 210, "Ograve" },
371 { 211, "Oacute" },
372 { 212, "Ocirc" },
373 { 213, "Otilde" },
374 { 214, "Ouml" },
375 { 215, "times" },
376 { 216, "Oslash" },
377 { 217, "Ugrave" },
378 { 218, "Uacute" },
379 { 219, "Ucirc" },
380 { 220, "Uuml" },
381 { 221, "Yacute" },
382 { 222, "THORN" },
383 { 223, "szlig" },
384 { 224, "agrave" },
385 { 225, "aacute" },
386 { 226, "acirc" },
387 { 227, "atilde" },
388 { 228, "auml" },
389 { 229, "aring" },
390 { 230, "aelig" },
391 { 231, "ccedil" },
392 { 232, "egrave" },
393 { 233, "eacute" },
394 { 234, "ecirc" },
395 { 235, "euml" },
396 { 236, "igrave" },
397 { 237, "iacute" },
398 { 238, "icirc" },
399 { 239, "iuml" },
400 { 240, "eth" },
401 { 241, "ntilde" },
402 { 242, "ograve" },
403 { 243, "oacute" },
404 { 244, "ocirc" },
405 { 245, "otilde" },
406 { 246, "ouml" },
407 { 247, "divide" },
408 { 248, "oslash" },
409 { 249, "ugrave" },
410 { 250, "uacute" },
411 { 251, "ucirc" },
412 { 252, "uuml" },
413 { 253, "yacute" },
414 { 254, "thorn" },
415 { 255, "yuml" },
416 { 0, NULL }
418 #endif
420 #ifndef WITH_NOIO
421 #ifndef WITH_LEAN
422 static const struct soap_code_map h_error_codes[] =
424 #ifdef HOST_NOT_FOUND
425 { HOST_NOT_FOUND, "Host not found" },
426 #endif
427 #ifdef TRY_AGAIN
428 { TRY_AGAIN, "Try Again" },
429 #endif
430 #ifdef NO_RECOVERY
431 { NO_RECOVERY, "No Recovery" },
432 #endif
433 #ifdef NO_DATA
434 { NO_DATA, "No Data" },
435 #endif
436 #ifdef NO_ADDRESS
437 { NO_ADDRESS, "No Address" },
438 #endif
439 { 0, NULL }
441 #endif
442 #endif
444 #ifndef WITH_NOHTTP
445 #ifndef WITH_LEAN
446 static const struct soap_code_map h_http_error_codes[] =
447 { { 200, "OK" },
448 { 201, "Created" },
449 { 202, "Accepted" },
450 { 203, "Non-Authoritative Information" },
451 { 204, "No Content" },
452 { 205, "Reset Content" },
453 { 206, "Partial Content" },
454 { 300, "Multiple Choices" },
455 { 301, "Moved Permanently" },
456 { 302, "Found" },
457 { 303, "See Other" },
458 { 304, "Not Modified" },
459 { 305, "Use Proxy" },
460 { 307, "Temporary Redirect" },
461 { 400, "Bad Request" },
462 { 401, "Unauthorized" },
463 { 402, "Payment Required" },
464 { 403, "Forbidden" },
465 { 404, "Not Found" },
466 { 405, "Method Not Allowed" },
467 { 406, "Not Acceptable" },
468 { 407, "Proxy Authentication Required" },
469 { 408, "Request Time-out" },
470 { 409, "Conflict" },
471 { 410, "Gone" },
472 { 411, "Length Required" },
473 { 412, "Precondition Failed" },
474 { 413, "Request Entity Too Large" },
475 { 414, "Request-URI Too Large" },
476 { 415, "Unsupported Media Type" },
477 { 416, "Requested range not satisfiable" },
478 { 417, "Expectation Failed" },
479 { 500, "Internal Server Error" },
480 { 501, "Not Implemented" },
481 { 502, "Bad Gateway" },
482 { 503, "Service Unavailable" },
483 { 504, "Gateway Time-out" },
484 { 505, "HTTP Version not supported" },
485 { 0, NULL }
487 #endif
488 #endif
490 #ifdef WITH_OPENSSL
491 static const struct soap_code_map h_ssl_error_codes[] =
493 #define _SSL_ERROR(e) { e, #e }
494 _SSL_ERROR(SSL_ERROR_SSL),
495 _SSL_ERROR(SSL_ERROR_ZERO_RETURN),
496 _SSL_ERROR(SSL_ERROR_WANT_READ),
497 _SSL_ERROR(SSL_ERROR_WANT_WRITE),
498 _SSL_ERROR(SSL_ERROR_WANT_CONNECT),
499 _SSL_ERROR(SSL_ERROR_WANT_X509_LOOKUP),
500 _SSL_ERROR(SSL_ERROR_SYSCALL),
501 { 0, NULL }
503 #endif
505 #ifndef WITH_LEANER
506 static const struct soap_code_map mime_codes[] =
507 { { SOAP_MIME_7BIT, "7bit" },
508 { SOAP_MIME_8BIT, "8bit" },
509 { SOAP_MIME_BINARY, "binary" },
510 { SOAP_MIME_QUOTED_PRINTABLE, "quoted-printable" },
511 { SOAP_MIME_BASE64, "base64" },
512 { SOAP_MIME_IETF_TOKEN, "ietf-token" },
513 { SOAP_MIME_X_TOKEN, "x-token" },
514 { 0, NULL }
516 #endif
518 #ifdef WIN32
519 static int tcp_done = 0;
520 #endif
522 #if defined(HP_UX) && defined(HAVE_GETHOSTBYNAME_R)
523 extern int h_errno;
524 #endif
526 /******************************************************************************/
527 #ifndef WITH_NOIO
528 #ifndef PALM_1
529 static int
530 fsend(struct soap *soap, const char *s, size_t n)
531 { register int nwritten, err;
532 #if defined(__cplusplus) && !defined(WITH_LEAN) && !defined(WITH_COMPAT)
533 if (soap->os)
534 { soap->os->write(s, (std::streamsize)n);
535 if (soap->os->good())
536 return SOAP_OK;
537 soap->errnum = 0;
538 return SOAP_EOF;
540 #endif
541 while (n)
542 { if (soap_valid_socket(soap->socket))
544 if (soap->send_timeout)
545 { for (;;)
546 { register int r;
547 #ifdef WITH_OPENSSL
548 if (soap->ssl)
549 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_ALL, soap->send_timeout);
550 else
551 #endif
552 #ifdef WITH_GNUTLS
553 if (soap->session)
554 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_ALL, soap->send_timeout);
555 else
556 #endif
557 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, soap->send_timeout);
558 if (r > 0)
559 break;
560 if (!r)
561 return SOAP_EOF;
562 err = soap->errnum;
563 if (!err)
564 return soap->error;
565 if (err != SOAP_EINTR && err != SOAP_EAGAIN && err != SOAP_EWOULDBLOCK)
566 return SOAP_EOF;
569 #ifdef WITH_OPENSSL
570 if (soap->ssl)
571 nwritten = SSL_write(soap->ssl, s, (int)n);
572 else if (soap->bio)
573 nwritten = BIO_write(soap->bio, s, (int)n);
574 else
575 #endif
576 #ifdef WITH_GNUTLS
577 if (soap->session)
578 nwritten = gnutls_record_send(soap->session, s, n);
579 else
580 #endif
581 #ifndef WITH_LEAN
582 if ((soap->omode & SOAP_IO_UDP))
583 { if (soap->peerlen)
584 nwritten = sendto(soap->socket, (char*)s, (SOAP_WINSOCKINT)n, soap->socket_flags, (struct sockaddr*)&soap->peer, (SOAP_WINSOCKINT)soap->peerlen);
585 else
586 nwritten = send(soap->socket, s, (SOAP_WINSOCKINT)n, soap->socket_flags);
587 /* retry and back-off algorithm */
588 /* TODO: this is not very clear from specs so verify and limit conditions under which we should loop (e.g. ENOBUFS) */
589 if (nwritten < 0)
590 { int udp_repeat;
591 int udp_delay;
592 if ((soap->connect_flags & SO_BROADCAST))
593 udp_repeat = 3; /* SOAP-over-UDP MULTICAST_UDP_REPEAT - 1 */
594 else
595 udp_repeat = 1; /* SOAP-over-UDP UNICAST_UDP_REPEAT - 1 */
596 udp_delay = (soap_random % 201) + 50; /* UDP_MIN_DELAY .. UDP_MAX_DELAY */
598 { tcp_select(soap, soap->socket, SOAP_TCP_SELECT_ERR, -1000 * udp_delay);
599 if (soap->peerlen)
600 nwritten = sendto(soap->socket, (char*)s, (SOAP_WINSOCKINT)n, soap->socket_flags, (struct sockaddr*)&soap->peer, (SOAP_WINSOCKINT)soap->peerlen);
601 else
602 nwritten = send(soap->socket, s, (SOAP_WINSOCKINT)n, soap->socket_flags);
603 udp_delay <<= 1;
604 if (udp_delay > 500) /* UDP_UPPER_DELAY */
605 udp_delay = 500;
607 while (nwritten < 0 && --udp_repeat > 0);
610 else
611 #endif
612 #if !defined(PALM) && !defined(AS400)
613 nwritten = send(soap->socket, s, (int)n, soap->socket_flags);
614 #else
615 nwritten = send(soap->socket, (void*)s, n, soap->socket_flags);
616 #endif
617 if (nwritten <= 0)
619 register int r = 0;
620 err = soap_socket_errno(soap->socket);
621 #ifdef WITH_OPENSSL
622 if (soap->ssl && (r = SSL_get_error(soap->ssl, nwritten)) != SSL_ERROR_NONE && r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE)
623 { soap->errnum = err;
624 return SOAP_EOF;
626 #endif
627 #ifdef WITH_GNUTLS
628 if (soap->session)
629 { if (nwritten == GNUTLS_E_INTERRUPTED)
630 err = SOAP_EINTR;
631 else if (nwritten == GNUTLS_E_AGAIN)
632 err = SOAP_EAGAIN;
634 #endif
635 if (err == SOAP_EWOULDBLOCK || err == SOAP_EAGAIN)
637 #if defined(WITH_OPENSSL)
638 if (soap->ssl && r == SSL_ERROR_WANT_READ)
639 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, soap->send_timeout ? soap->send_timeout : -10000);
640 else
641 #elif defined(WITH_GNUTLS)
642 if (soap->session && !gnutls_record_get_direction(soap->session))
643 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, soap->send_timeout ? soap->send_timeout : -10000);
644 else
645 #endif
646 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, soap->send_timeout ? soap->send_timeout : -10000);
647 if (!r && soap->send_timeout)
648 return SOAP_EOF;
649 if (r < 0 && soap->errnum != SOAP_EINTR)
650 return SOAP_EOF;
652 else if (err && err != SOAP_EINTR)
653 { soap->errnum = err;
654 return SOAP_EOF;
656 nwritten = 0; /* and call write() again */
659 else
661 #ifdef WITH_FASTCGI
662 nwritten = fwrite((void*)s, 1, n, stdout);
663 fflush(stdout);
664 #else
665 #ifdef UNDER_CE
666 nwritten = fwrite(s, 1, n, soap->sendfd);
667 #else
668 #ifdef VXWORKS
669 #ifdef WMW_RPM_IO
670 if (soap->rpmreqid)
671 nwritten = (httpBlockPut(soap->rpmreqid, (char*)s, n) == 0) ? n : -1;
672 else
673 #endif
674 nwritten = fwrite(s, sizeof(char), n, fdopen(soap->sendfd, "w"));
675 #else
676 #ifdef WIN32
677 nwritten = _write(soap->sendfd, s, (unsigned int)n);
678 #else
679 nwritten = write(soap->sendfd, s, (unsigned int)n);
680 #endif
681 #endif
682 #endif
683 #endif
684 if (nwritten <= 0)
686 #ifndef WITH_FASTCGI
687 err = soap_errno;
688 #else
689 err = EOF;
690 #endif
691 if (err && err != SOAP_EINTR && err != SOAP_EWOULDBLOCK && err != SOAP_EAGAIN)
692 { soap->errnum = err;
693 return SOAP_EOF;
695 nwritten = 0; /* and call write() again */
698 n -= nwritten;
699 s += nwritten;
701 return SOAP_OK;
703 #endif
704 #endif
706 /******************************************************************************/
707 #ifndef PALM_1
708 SOAP_FMAC1
710 SOAP_FMAC2
711 soap_send_raw(struct soap *soap, const char *s, size_t n)
712 { if (!n)
713 return SOAP_OK;
714 if (soap->mode & SOAP_IO_LENGTH)
715 { soap->count += n;
716 #ifndef WITH_LEANER
717 if (soap->fpreparesend && (soap->mode & SOAP_IO) != SOAP_IO_STORE)
718 return soap->error = soap->fpreparesend(soap, s, n);
719 #endif
720 return SOAP_OK;
722 if (soap->mode & SOAP_IO)
723 { register size_t i = SOAP_BUFLEN - soap->bufidx;
724 while (n >= i)
725 { memcpy(soap->buf + soap->bufidx, s, i);
726 soap->bufidx = SOAP_BUFLEN;
727 if (soap_flush(soap))
728 return soap->error;
729 s += i;
730 n -= i;
731 i = SOAP_BUFLEN;
733 memcpy(soap->buf + soap->bufidx, s, n);
734 soap->bufidx += n;
735 return SOAP_OK;
737 return soap_flush_raw(soap, s, n);
739 #endif
741 /******************************************************************************/
742 #ifndef PALM_1
743 SOAP_FMAC1
745 SOAP_FMAC2
746 soap_flush(struct soap *soap)
747 { register size_t n = soap->bufidx;
748 if (n)
750 #ifndef WITH_LEANER
751 if ((soap->mode & SOAP_IO) == SOAP_IO_STORE)
752 { register int r;
753 if (soap->fpreparesend && (r = soap->fpreparesend(soap, soap->buf, n)))
754 return soap->error = r;
756 #endif
757 soap->bufidx = 0;
758 #ifdef WITH_ZLIB
759 if (soap->mode & SOAP_ENC_ZLIB)
760 { soap->d_stream->next_in = (Byte*)soap->buf;
761 soap->d_stream->avail_in = (unsigned int)n;
762 #ifdef WITH_GZIP
763 soap->z_crc = crc32(soap->z_crc, (Byte*)soap->buf, (unsigned int)n);
764 #endif
766 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Deflating %u bytes\n", soap->d_stream->avail_in));
767 if (deflate(soap->d_stream, Z_NO_FLUSH) != Z_OK)
768 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unable to deflate: %s\n", soap->d_stream->msg?soap->d_stream->msg:SOAP_STR_EOS));
769 return soap->error = SOAP_ZLIB_ERROR;
771 if (!soap->d_stream->avail_out)
772 { if (soap_flush_raw(soap, soap->z_buf, SOAP_BUFLEN))
773 return soap->error;
774 soap->d_stream->next_out = (Byte*)soap->z_buf;
775 soap->d_stream->avail_out = SOAP_BUFLEN;
777 } while (soap->d_stream->avail_in);
779 else
780 #endif
781 return soap_flush_raw(soap, soap->buf, n);
783 return SOAP_OK;
785 #endif
787 /******************************************************************************/
788 #ifndef PALM_1
789 SOAP_FMAC1
791 SOAP_FMAC2
792 soap_flush_raw(struct soap *soap, const char *s, size_t n)
793 { if ((soap->mode & SOAP_IO) == SOAP_IO_STORE)
794 { register char *t;
795 if (!(t = (char*)soap_push_block(soap, NULL, n)))
796 return soap->error = SOAP_EOM;
797 memcpy(t, s, n);
798 return SOAP_OK;
800 #ifndef WITH_LEANER
801 if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK)
802 { char t[16];
803 sprintf(t, "\r\n%lX\r\n" + (soap->chunksize ? 0 : 2), (unsigned long)n);
804 DBGMSG(SENT, t, strlen(t));
805 if ((soap->error = soap->fsend(soap, t, strlen(t))))
806 return soap->error;
807 soap->chunksize += n;
809 DBGMSG(SENT, s, n);
810 #endif
811 return soap->error = soap->fsend(soap, s, n);
813 #endif
815 /******************************************************************************/
816 #ifndef PALM_1
817 SOAP_FMAC1
819 SOAP_FMAC2
820 soap_send(struct soap *soap, const char *s)
821 { if (s)
822 return soap_send_raw(soap, s, strlen(s));
823 return SOAP_OK;
825 #endif
827 /******************************************************************************/
828 #ifndef WITH_LEANER
829 #ifndef PALM_1
830 SOAP_FMAC1
832 SOAP_FMAC2
833 soap_send2(struct soap *soap, const char *s1, const char *s2)
834 { if (soap_send(soap, s1))
835 return soap->error;
836 return soap_send(soap, s2);
838 #endif
839 #endif
841 /******************************************************************************/
842 #ifndef WITH_LEANER
843 #ifndef PALM_1
844 SOAP_FMAC1
846 SOAP_FMAC2
847 soap_send3(struct soap *soap, const char *s1, const char *s2, const char *s3)
848 { if (soap_send(soap, s1)
849 || soap_send(soap, s2))
850 return soap->error;
851 return soap_send(soap, s3);
853 #endif
854 #endif
856 /******************************************************************************/
857 #ifndef WITH_NOIO
858 #ifndef PALM_1
859 static size_t
860 frecv(struct soap *soap, char *s, size_t n)
861 { register int r;
862 register int retries = 100; /* max 100 retries with non-blocking sockets */
863 soap->errnum = 0;
864 #if defined(__cplusplus) && !defined(WITH_LEAN) && !defined(WITH_COMPAT)
865 if (soap->is)
866 { if (soap->is->good())
867 return soap->is->read(s, (std::streamsize)n).gcount();
868 return 0;
870 #endif
871 if (soap_valid_socket(soap->socket))
872 { for (;;)
874 #ifdef WITH_OPENSSL
875 register int err = 0;
876 #endif
877 #ifdef WITH_OPENSSL
878 if (soap->recv_timeout && !soap->ssl) /* SSL: sockets are nonblocking */
879 #else
880 if (soap->recv_timeout)
881 #endif
882 { for (;;)
883 { r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, soap->recv_timeout);
884 if (r > 0)
885 break;
886 if (!r)
887 return 0;
888 r = soap->errnum;
889 if (r != SOAP_EINTR && r != SOAP_EAGAIN && r != SOAP_EWOULDBLOCK)
890 return 0;
893 #ifdef WITH_OPENSSL
894 if (soap->ssl)
895 { r = SSL_read(soap->ssl, s, (int)n);
896 if (r > 0)
897 return (size_t)r;
898 err = SSL_get_error(soap->ssl, r);
899 if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE)
900 return 0;
902 else if (soap->bio)
903 { r = BIO_read(soap->bio, s, (int)n);
904 if (r > 0)
905 return (size_t)r;
906 return 0;
908 else
909 #endif
910 #ifdef WITH_GNUTLS
911 if (soap->session)
912 { r = (int)gnutls_record_recv(soap->session, s, n);
913 if (r >= 0)
914 return (size_t)r;
916 else
917 #endif
919 #ifndef WITH_LEAN
920 if ((soap->omode & SOAP_IO_UDP))
921 { SOAP_SOCKLEN_T k = (SOAP_SOCKLEN_T)sizeof(soap->peer);
922 memset((void*)&soap->peer, 0, sizeof(soap->peer));
923 r = recvfrom(soap->socket, s, (SOAP_WINSOCKINT)n, soap->socket_flags, (struct sockaddr*)&soap->peer, &k); /* portability note: see SOAP_SOCKLEN_T definition in stdsoap2.h */
924 soap->peerlen = (size_t)k;
925 #ifndef WITH_IPV6
926 soap->ip = ntohl(soap->peer.sin_addr.s_addr);
927 #endif
929 else
930 #endif
931 r = recv(soap->socket, s, (int)n, soap->socket_flags);
932 #ifdef PALM
933 /* CycleSyncDisplay(curStatusMsg); */
934 #endif
935 if (r >= 0)
936 return (size_t)r;
937 r = soap_socket_errno(soap->socket);
938 if (r != SOAP_EINTR && r != SOAP_EAGAIN && r != SOAP_EWOULDBLOCK)
939 { soap->errnum = r;
940 return 0;
943 #if defined(WITH_OPENSSL)
944 if (soap->ssl && err == SSL_ERROR_WANT_WRITE)
945 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, soap->recv_timeout ? soap->recv_timeout : 5);
946 else
947 #elif defined(WITH_GNUTLS)
948 if (soap->session && gnutls_record_get_direction(soap->session))
949 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, soap->recv_timeout ? soap->recv_timeout : 5);
950 else
951 #endif
952 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, soap->recv_timeout ? soap->recv_timeout : 5);
953 if (!r && soap->recv_timeout)
954 return 0;
955 if (r < 0)
956 { r = soap->errnum;
957 if (r != SOAP_EINTR && r != SOAP_EAGAIN && r != SOAP_EWOULDBLOCK)
958 return 0;
960 if (retries-- <= 0)
961 return 0;
962 #ifdef PALM
963 r = soap_socket_errno(soap->socket);
964 if (r != SOAP_EINTR && retries-- <= 0)
965 { soap->errnum = r;
966 return 0;
968 #endif
971 #ifdef WITH_FASTCGI
972 return fread(s, 1, n, stdin);
973 #else
974 #ifdef UNDER_CE
975 return fread(s, 1, n, soap->recvfd);
976 #else
977 #ifdef WMW_RPM_IO
978 if (soap->rpmreqid)
979 r = httpBlockRead(soap->rpmreqid, s, n);
980 else
981 #endif
982 #ifdef WIN32
983 r = _read(soap->recvfd, s, (unsigned int)n);
984 #else
985 r = read(soap->recvfd, s, (unsigned int)n);
986 #endif
987 if (r >= 0)
988 return (size_t)r;
989 soap->errnum = soap_errno;
990 return 0;
991 #endif
992 #endif
994 #endif
995 #endif
997 /******************************************************************************/
998 #ifndef WITH_NOHTTP
999 #ifndef PALM_1
1000 static soap_wchar
1001 soap_getchunkchar(struct soap *soap)
1002 { if (soap->bufidx < soap->buflen)
1003 return soap->buf[soap->bufidx++];
1004 soap->bufidx = 0;
1005 soap->buflen = soap->chunkbuflen = soap->frecv(soap, soap->buf, SOAP_BUFLEN);
1006 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes from socket %d\n", (unsigned int)soap->buflen, soap->socket));
1007 DBGMSG(RECV, soap->buf, soap->buflen);
1008 if (soap->buflen)
1009 return soap->buf[soap->bufidx++];
1010 return EOF;
1012 #endif
1013 #endif
1015 /******************************************************************************/
1016 #ifndef PALM_1
1017 static int
1018 soap_isxdigit(int c)
1019 { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
1021 #endif
1023 /******************************************************************************/
1024 #ifndef PALM_1
1025 SOAP_FMAC1
1027 SOAP_FMAC2
1028 soap_recv_raw(struct soap *soap)
1029 { register size_t ret;
1030 #if !defined(WITH_LEANER) || defined(WITH_ZLIB)
1031 register int r;
1032 #endif
1033 #ifdef WITH_ZLIB
1034 if (soap->mode & SOAP_ENC_ZLIB)
1035 { if (soap->d_stream->next_out == Z_NULL)
1036 return EOF;
1037 if (soap->d_stream->avail_in || !soap->d_stream->avail_out)
1038 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflating\n"));
1039 soap->d_stream->next_out = (Byte*)soap->buf;
1040 soap->d_stream->avail_out = SOAP_BUFLEN;
1041 r = inflate(soap->d_stream, Z_NO_FLUSH);
1042 if (r == Z_NEED_DICT && soap->z_dict)
1043 r = inflateSetDictionary(soap->d_stream, (const Bytef*)soap->z_dict, soap->z_dict_len);
1044 if (r == Z_OK || r == Z_STREAM_END)
1045 { soap->bufidx = 0;
1046 ret = soap->buflen = SOAP_BUFLEN - soap->d_stream->avail_out;
1047 if (soap->zlib_in == SOAP_ZLIB_GZIP)
1048 soap->z_crc = crc32(soap->z_crc, (Byte*)soap->buf, (unsigned int)ret);
1049 if (r == Z_STREAM_END)
1050 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflated %lu->%lu bytes\n", soap->d_stream->total_in, soap->d_stream->total_out));
1051 soap->z_ratio_in = (float)soap->d_stream->total_in / (float)soap->d_stream->total_out;
1052 soap->d_stream->next_out = Z_NULL;
1054 if (ret)
1055 { soap->count += ret;
1056 DBGLOG(RECV, SOAP_MESSAGE(fdebug, "\n---- decompressed ----\n"));
1057 DBGMSG(RECV, soap->buf, ret);
1058 DBGLOG(RECV, SOAP_MESSAGE(fdebug, "\n----\n"));
1059 #ifndef WITH_LEANER
1060 if (soap->fpreparerecv && (r = soap->fpreparerecv(soap, soap->buf, ret)))
1061 return soap->error = r;
1062 #endif
1063 return SOAP_OK;
1066 else if (r != Z_BUF_ERROR)
1067 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflate error: %s\n", soap->d_stream->msg?soap->d_stream->msg:SOAP_STR_EOS));
1068 soap->d_stream->next_out = Z_NULL;
1069 soap->error = SOAP_ZLIB_ERROR;
1070 return EOF;
1073 zlib_again:
1074 if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK && !soap->chunksize)
1075 { memcpy(soap->buf, soap->z_buf, SOAP_BUFLEN);
1076 soap->buflen = soap->z_buflen;
1078 DBGLOG(RECV, SOAP_MESSAGE(fdebug, "\n---- compressed ----\n"));
1080 #endif
1081 #ifndef WITH_NOHTTP
1082 if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK) /* read HTTP chunked transfer */
1083 { for (;;)
1084 { register soap_wchar c;
1085 char *t, tmp[8];
1086 if (soap->chunksize)
1087 { soap->buflen = ret = soap->frecv(soap, soap->buf, soap->chunksize > SOAP_BUFLEN ? SOAP_BUFLEN : soap->chunksize);
1088 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Getting chunk: read %u bytes\n", (unsigned int)ret));
1089 DBGMSG(RECV, soap->buf, ret);
1090 soap->bufidx = 0;
1091 soap->chunksize -= ret;
1092 break;
1094 t = tmp;
1095 if (!soap->chunkbuflen)
1096 { soap->chunkbuflen = ret = soap->frecv(soap, soap->buf, SOAP_BUFLEN);
1097 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes (chunked) from socket %d\n", (unsigned int)ret, soap->socket));
1098 DBGMSG(RECV, soap->buf, ret);
1099 soap->bufidx = 0;
1100 if (!ret)
1101 return soap->ahead = EOF;
1103 else
1104 soap->bufidx = soap->buflen;
1105 soap->buflen = soap->chunkbuflen;
1106 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Getting chunk size (idx=%u len=%u)\n", (unsigned int)soap->bufidx, (unsigned int)soap->buflen));
1107 while (!soap_isxdigit((int)(c = soap_getchunkchar(soap))))
1108 { if ((int)c == EOF)
1109 return soap->ahead = EOF;
1112 *t++ = (char)c;
1113 while (soap_isxdigit((int)(c = soap_getchunkchar(soap))) && t - tmp < 7);
1114 while ((int)c != EOF && c != '\n')
1115 c = soap_getchunkchar(soap);
1116 if ((int)c == EOF)
1117 return soap->ahead = EOF;
1118 *t = '\0';
1119 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Chunk size = %s (hex)\n", tmp));
1120 soap->chunksize = soap_strtoul(tmp, &t, 16);
1121 if (!soap->chunksize)
1122 { soap->chunkbuflen = 0;
1123 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End of chunked message\n"));
1124 while ((int)c != EOF && c != '\n')
1125 c = soap_getchunkchar(soap);
1126 ret = 0;
1127 soap->ahead = EOF;
1128 break;
1130 soap->buflen = soap->bufidx + soap->chunksize;
1131 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Moving buf len to idx=%u len=%u (%s)\n", (unsigned int)soap->bufidx, (unsigned int)soap->buflen, tmp));
1132 if (soap->buflen > soap->chunkbuflen)
1133 { soap->buflen = soap->chunkbuflen;
1134 soap->chunksize -= soap->buflen - soap->bufidx;
1135 soap->chunkbuflen = 0;
1136 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Passed end of buffer for chunked HTTP (%u bytes left)\n", (unsigned int)(soap->buflen - soap->bufidx)));
1138 else if (soap->chunkbuflen)
1139 soap->chunksize = 0;
1140 ret = soap->buflen - soap->bufidx;
1141 if (ret)
1142 break;
1145 else
1146 #endif
1147 { soap->bufidx = 0;
1148 soap->buflen = ret = soap->frecv(soap, soap->buf, SOAP_BUFLEN);
1149 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes from socket %d\n", (unsigned int)ret, soap->socket));
1150 DBGMSG(RECV, soap->buf, ret);
1152 #ifdef WITH_ZLIB
1153 if (soap->mode & SOAP_ENC_ZLIB)
1154 { memcpy(soap->z_buf, soap->buf, SOAP_BUFLEN);
1155 soap->d_stream->next_in = (Byte*)(soap->z_buf + soap->bufidx);
1156 soap->d_stream->avail_in = (unsigned int)ret;
1157 soap->d_stream->next_out = (Byte*)soap->buf;
1158 soap->d_stream->avail_out = SOAP_BUFLEN;
1159 r = inflate(soap->d_stream, Z_NO_FLUSH);
1160 if (r == Z_NEED_DICT && soap->z_dict)
1161 r = inflateSetDictionary(soap->d_stream, (const Bytef*)soap->z_dict, soap->z_dict_len);
1162 if (r == Z_OK || r == Z_STREAM_END)
1163 { soap->bufidx = 0;
1164 soap->z_buflen = soap->buflen;
1165 soap->buflen = SOAP_BUFLEN - soap->d_stream->avail_out;
1166 if (soap->zlib_in == SOAP_ZLIB_GZIP)
1167 soap->z_crc = crc32(soap->z_crc, (Byte*)soap->buf, (unsigned int)soap->buflen);
1168 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflated %u bytes\n", (unsigned int)soap->buflen));
1169 if (ret && !soap->buflen && r != Z_STREAM_END)
1170 goto zlib_again;
1171 ret = soap->buflen;
1172 if (r == Z_STREAM_END)
1173 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflated total %lu->%lu bytes\n", soap->d_stream->total_in, soap->d_stream->total_out));
1174 soap->z_ratio_in = (float)soap->d_stream->total_in / (float)soap->d_stream->total_out;
1175 soap->d_stream->next_out = Z_NULL;
1177 DBGLOG(RECV, SOAP_MESSAGE(fdebug, "\n---- decompressed ----\n"));
1178 DBGMSG(RECV, soap->buf, ret);
1179 #ifndef WITH_LEANER
1180 if (soap->fpreparerecv && (r = soap->fpreparerecv(soap, soap->buf, ret)))
1181 return soap->error = r;
1182 #endif
1184 else
1185 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unable to inflate: (%d) %s\n", r, soap->d_stream->msg?soap->d_stream->msg:SOAP_STR_EOS));
1186 soap->d_stream->next_out = Z_NULL;
1187 soap->error = SOAP_ZLIB_ERROR;
1188 return EOF;
1191 #endif
1192 #ifndef WITH_LEANER
1193 if (soap->fpreparerecv
1194 #ifdef WITH_ZLIB
1195 && soap->zlib_in == SOAP_ZLIB_NONE
1196 #endif
1197 && (r = soap->fpreparerecv(soap, soap->buf + soap->bufidx, ret)))
1198 return soap->error = r;
1199 #endif
1200 soap->count += ret;
1201 return !ret;
1203 #endif
1205 /******************************************************************************/
1206 #ifndef PALM_1
1207 SOAP_FMAC1
1209 SOAP_FMAC2
1210 soap_recv(struct soap *soap)
1212 #ifndef WITH_LEANER
1213 if (soap->mode & SOAP_ENC_DIME)
1214 { if (soap->dime.buflen)
1215 { char *s;
1216 int i;
1217 unsigned char tmp[12];
1218 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DIME hdr for chunked DIME is in buffer\n"));
1219 soap->count += soap->dime.buflen - soap->buflen;
1220 soap->buflen = soap->dime.buflen;
1221 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Skip padding (%ld bytes)\n", -(long)soap->dime.size&3));
1222 for (i = -(long)soap->dime.size&3; i > 0; i--)
1223 { soap->bufidx++;
1224 if (soap->bufidx >= soap->buflen)
1225 if (soap_recv_raw(soap))
1226 return EOF;
1228 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get DIME hdr for next chunk\n"));
1229 s = (char*)tmp;
1230 for (i = 12; i > 0; i--)
1231 { *s++ = soap->buf[soap->bufidx++];
1232 if (soap->bufidx >= soap->buflen)
1233 if (soap_recv_raw(soap))
1234 return EOF;
1236 soap->dime.flags = tmp[0] & 0x7;
1237 soap->dime.size = ((size_t)tmp[8] << 24) | ((size_t)tmp[9] << 16) | ((size_t)tmp[10] << 8) | ((size_t)tmp[11]);
1238 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get DIME chunk (%u bytes)\n", (unsigned int)soap->dime.size));
1239 if (soap->dime.flags & SOAP_DIME_CF)
1240 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "More chunking\n"));
1241 soap->dime.chunksize = soap->dime.size;
1242 if (soap->buflen - soap->bufidx >= soap->dime.size)
1243 { soap->dime.buflen = soap->buflen;
1244 soap->buflen = soap->bufidx + soap->dime.chunksize;
1246 else
1247 soap->dime.chunksize -= soap->buflen - soap->bufidx;
1249 else
1250 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Last chunk\n"));
1251 soap->dime.buflen = 0;
1252 soap->dime.chunksize = 0;
1254 soap->count = soap->buflen - soap->bufidx;
1255 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "%u bytes remaining\n", (unsigned int)soap->count));
1256 return SOAP_OK;
1258 if (soap->dime.chunksize)
1259 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get next DIME hdr for chunked DIME (%u bytes chunk)\n", (unsigned int)soap->dime.chunksize));
1260 if (soap_recv_raw(soap))
1261 return EOF;
1262 if (soap->buflen - soap->bufidx >= soap->dime.chunksize)
1263 { soap->dime.buflen = soap->buflen;
1264 soap->count -= soap->buflen - soap->bufidx - soap->dime.chunksize;
1265 soap->buflen = soap->bufidx + soap->dime.chunksize;
1267 else
1268 soap->dime.chunksize -= soap->buflen - soap->bufidx;
1269 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "%lu bytes remaining, count=%u\n", (unsigned long)(soap->buflen-soap->bufidx), (unsigned int)soap->count));
1270 return SOAP_OK;
1273 #endif
1274 return soap_recv_raw(soap);
1276 #endif
1278 /******************************************************************************/
1279 #ifndef PALM_1
1280 SOAP_FMAC1
1281 soap_wchar
1282 SOAP_FMAC2
1283 soap_getchar(struct soap *soap)
1284 { register soap_wchar c;
1285 c = soap->ahead;
1286 if (c)
1287 { if (c != EOF)
1288 soap->ahead = 0;
1289 return c;
1291 return soap_get1(soap);
1293 #endif
1295 /******************************************************************************/
1296 #ifndef PALM_1
1297 SOAP_FMAC1
1298 const struct soap_code_map*
1299 SOAP_FMAC2
1300 soap_code(const struct soap_code_map *code_map, const char *str)
1301 { if (code_map && str)
1302 { while (code_map->string)
1303 { if (!strcmp(str, code_map->string)) /* case sensitive */
1304 return code_map;
1305 code_map++;
1308 return NULL;
1310 #endif
1312 /******************************************************************************/
1313 #ifndef PALM_1
1314 SOAP_FMAC1
1315 long
1316 SOAP_FMAC2
1317 soap_code_int(const struct soap_code_map *code_map, const char *str, long other)
1318 { if (code_map)
1319 { while (code_map->string)
1320 { if (!soap_tag_cmp(str, code_map->string)) /* case insensitive */
1321 return code_map->code;
1322 code_map++;
1325 return other;
1327 #endif
1329 /******************************************************************************/
1330 #ifndef PALM_1
1331 SOAP_FMAC1
1332 const char*
1333 SOAP_FMAC2
1334 soap_code_str(const struct soap_code_map *code_map, long code)
1335 { if (!code_map)
1336 return NULL;
1337 while (code_map->code != code && code_map->string)
1338 code_map++;
1339 return code_map->string;
1341 #endif
1343 /******************************************************************************/
1344 #ifndef PALM_1
1345 SOAP_FMAC1
1346 long
1347 SOAP_FMAC2
1348 soap_code_bits(const struct soap_code_map *code_map, const char *str)
1349 { register long bits = 0;
1350 if (code_map)
1351 { while (str && *str)
1352 { const struct soap_code_map *p;
1353 for (p = code_map; p->string; p++)
1354 { register size_t n = strlen(p->string);
1355 if (!strncmp(p->string, str, n) && soap_blank((soap_wchar)str[n]))
1356 { bits |= p->code;
1357 str += n;
1358 while (*str > 0 && *str <= 32)
1359 str++;
1360 break;
1363 if (!p->string)
1364 return 0;
1367 return bits;
1369 #endif
1371 /******************************************************************************/
1372 #ifndef PALM_1
1373 SOAP_FMAC1
1374 const char*
1375 SOAP_FMAC2
1376 soap_code_list(struct soap *soap, const struct soap_code_map *code_map, long code)
1377 { register char *t = soap->tmpbuf;
1378 if (code_map)
1379 { while (code_map->string)
1380 { if (code_map->code & code)
1381 { register const char *s = code_map->string;
1382 if (t != soap->tmpbuf)
1383 *t++ = ' ';
1384 while (*s && t < soap->tmpbuf + sizeof(soap->tmpbuf) - 1)
1385 *t++ = *s++;
1386 if (t == soap->tmpbuf + sizeof(soap->tmpbuf) - 1)
1387 break;
1389 code_map++;
1392 *t = '\0';
1393 return soap->tmpbuf;
1395 #endif
1397 /******************************************************************************/
1398 #ifndef PALM_1
1399 static soap_wchar
1400 soap_char(struct soap *soap)
1401 { char tmp[8];
1402 register int i;
1403 register soap_wchar c;
1404 register char *s = tmp;
1405 for (i = 0; i < 7; i++)
1406 { c = soap_get1(soap);
1407 if (c == ';' || (int)c == EOF)
1408 break;
1409 *s++ = (char)c;
1411 *s = '\0';
1412 if (*tmp == '#')
1413 { if (tmp[1] == 'x' || tmp[1] == 'X')
1414 return (soap_wchar)soap_strtol(tmp + 2, NULL, 16);
1415 return (soap_wchar)soap_strtol(tmp + 1, NULL, 10);
1417 if (!strcmp(tmp, "lt"))
1418 return '<';
1419 if (!strcmp(tmp, "gt"))
1420 return '>';
1421 if (!strcmp(tmp, "amp"))
1422 return '&';
1423 if (!strcmp(tmp, "quot"))
1424 return '"';
1425 if (!strcmp(tmp, "apos"))
1426 return '\'';
1427 #ifndef WITH_LEAN
1428 return (soap_wchar)soap_code_int(html_entity_codes, tmp, SOAP_UNKNOWN_CHAR);
1429 #else
1430 return SOAP_UNKNOWN_CHAR; /* use this to represent unknown code */
1431 #endif
1433 #endif
1435 /******************************************************************************/
1436 #ifdef WITH_LEAN
1437 #ifndef PALM_1
1438 soap_wchar
1439 soap_get0(struct soap *soap)
1440 { if (soap->bufidx >= soap->buflen && soap_recv(soap))
1441 return EOF;
1442 return (unsigned char)soap->buf[soap->bufidx];
1444 #endif
1445 #endif
1447 /******************************************************************************/
1448 #ifdef WITH_LEAN
1449 #ifndef PALM_1
1450 soap_wchar
1451 soap_get1(struct soap *soap)
1452 { if (soap->bufidx >= soap->buflen && soap_recv(soap))
1453 return EOF;
1454 return (unsigned char)soap->buf[soap->bufidx++];
1456 #endif
1457 #endif
1459 /******************************************************************************/
1460 #ifndef PALM_1
1461 SOAP_FMAC1
1462 soap_wchar
1463 SOAP_FMAC2
1464 soap_get(struct soap *soap)
1465 { register soap_wchar c;
1466 c = soap->ahead;
1467 if (c)
1468 { if ((int)c != EOF)
1469 soap->ahead = 0;
1471 else
1472 c = soap_get1(soap);
1473 while ((int)c != EOF)
1474 { if (soap->cdata)
1475 { if (c == ']')
1476 { c = soap_get1(soap);
1477 if (c == ']')
1478 { c = soap_get0(soap);
1479 if (c == '>')
1480 { soap->cdata = 0;
1481 soap_get1(soap);
1482 c = soap_get1(soap);
1484 else
1485 { soap_unget(soap, ']');
1486 return ']';
1489 else
1490 { soap_revget1(soap);
1491 return ']';
1494 else
1495 return c;
1497 switch (c)
1498 { case '<':
1499 do c = soap_get1(soap);
1500 while (soap_blank(c));
1501 if (c == '!' || c == '?' || c == '%')
1502 { register int k = 1;
1503 if (c == '!')
1504 { c = soap_get1(soap);
1505 if (c == '[')
1506 { do c = soap_get1(soap);
1507 while ((int)c != EOF && c != '[');
1508 if ((int)c == EOF)
1509 break;
1510 soap->cdata = 1;
1511 c = soap_get1(soap);
1512 continue;
1514 if (c == '-' && (c = soap_get1(soap)) == '-')
1515 { do
1516 { c = soap_get1(soap);
1517 if (c == '-' && (c = soap_get1(soap)) == '-')
1518 break;
1519 } while ((int)c != EOF);
1522 else if (c == '?')
1523 c = soap_get_pi(soap);
1524 while ((int)c != EOF)
1525 { if (c == '<')
1526 k++;
1527 else if (c == '>')
1528 { if (--k <= 0)
1529 break;
1531 c = soap_get1(soap);
1533 if ((int)c == EOF)
1534 break;
1535 c = soap_get1(soap);
1536 continue;
1538 if (c == '/')
1539 return SOAP_TT;
1540 soap_revget1(soap);
1541 return SOAP_LT;
1542 case '>':
1543 return SOAP_GT;
1544 case '"':
1545 return SOAP_QT;
1546 case '\'':
1547 return SOAP_AP;
1548 case '&':
1549 return soap_char(soap) | 0x80000000;
1551 break;
1553 return c;
1555 #endif
1557 /******************************************************************************/
1558 #ifndef PALM_1
1559 static soap_wchar
1560 soap_get_pi(struct soap *soap)
1561 { char buf[64];
1562 register char *s = buf;
1563 register int i = sizeof(buf);
1564 register soap_wchar c = soap_getchar(soap);
1565 /* This is a quick way to parse XML PI and we could use a callback instead to
1566 * enable applications to intercept processing instructions */
1567 while ((int)c != EOF && c != '?')
1568 { if (--i > 0)
1569 { if (soap_blank(c))
1570 c = ' ';
1571 *s++ = (char)c;
1573 c = soap_getchar(soap);
1575 *s = '\0';
1576 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "XML PI <?%s?>\n", buf));
1577 if (!strncmp(buf, "xml ", 4))
1578 { s = strstr(buf, " encoding=");
1579 if (s && s[10])
1580 { if (!soap_tag_cmp(s + 11, "iso-8859-1*")
1581 || !soap_tag_cmp(s + 11, "latin1*"))
1582 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Switching to latin1 encoding\n"));
1583 soap->mode |= SOAP_ENC_LATIN;
1585 else if (!soap_tag_cmp(s + 11, "utf-8*"))
1586 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Switching to utf-8 encoding\n"));
1587 soap->mode &= ~SOAP_ENC_LATIN;
1591 if ((int)c != EOF)
1592 c = soap_getchar(soap);
1593 return c;
1595 #endif
1597 /******************************************************************************/
1598 #ifndef WITH_LEANER
1599 #ifndef PALM_1
1600 SOAP_FMAC1
1602 SOAP_FMAC2
1603 soap_move(struct soap *soap, long n)
1604 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Moving %ld bytes forward\n", (long)n));
1605 for (; n > 0; n--)
1606 if ((int)soap_getchar(soap) == EOF)
1607 return SOAP_EOF;
1608 return SOAP_OK;
1610 #endif
1611 #endif
1613 /******************************************************************************/
1614 #ifndef WITH_LEANER
1615 #ifndef PALM_1
1616 SOAP_FMAC1
1617 size_t
1618 SOAP_FMAC2
1619 soap_tell(struct soap *soap)
1620 { return soap->count - soap->buflen + soap->bufidx - (soap->ahead != 0);
1622 #endif
1623 #endif
1625 /******************************************************************************/
1626 #ifndef PALM_1
1627 SOAP_FMAC1
1629 SOAP_FMAC2
1630 soap_pututf8(struct soap *soap, register unsigned long c)
1631 { char tmp[16];
1632 if (c < 0x80 && c > 0)
1633 { *tmp = (char)c;
1634 return soap_send_raw(soap, tmp, 1);
1636 #ifndef WITH_LEAN
1637 if (c >= 0x80)
1638 { register char *t = tmp;
1639 if (c < 0x0800)
1640 *t++ = (char)(0xC0 | ((c >> 6) & 0x1F));
1641 else
1642 { if (c < 0x010000)
1643 *t++ = (char)(0xE0 | ((c >> 12) & 0x0F));
1644 else
1645 { if (c < 0x200000)
1646 *t++ = (char)(0xF0 | ((c >> 18) & 0x07));
1647 else
1648 { if (c < 0x04000000)
1649 *t++ = (char)(0xF8 | ((c >> 24) & 0x03));
1650 else
1651 { *t++ = (char)(0xFC | ((c >> 30) & 0x01));
1652 *t++ = (char)(0x80 | ((c >> 24) & 0x3F));
1654 *t++ = (char)(0x80 | ((c >> 18) & 0x3F));
1656 *t++ = (char)(0x80 | ((c >> 12) & 0x3F));
1658 *t++ = (char)(0x80 | ((c >> 6) & 0x3F));
1660 *t++ = (char)(0x80 | (c & 0x3F));
1661 *t = '\0';
1663 #else
1664 sprintf(tmp, "&#%lu;", c);
1665 #endif
1666 return soap_send(soap, tmp);
1668 #endif
1670 /******************************************************************************/
1671 #ifndef PALM_1
1672 SOAP_FMAC1
1673 soap_wchar
1674 SOAP_FMAC2
1675 soap_getutf8(struct soap *soap)
1676 { register soap_wchar c, c1, c2, c3, c4;
1677 c = soap->ahead;
1678 if (c > 0x7F)
1679 { soap->ahead = 0;
1680 return c;
1682 c = soap_get(soap);
1683 if (c < 0x80 || (soap->mode & SOAP_ENC_LATIN))
1684 return c;
1685 c1 = soap_get1(soap);
1686 if (c1 < 0x80)
1687 { soap_revget1(soap); /* doesn't look like this is UTF8 */
1688 return c;
1690 c1 &= 0x3F;
1691 if (c < 0xE0)
1692 return ((soap_wchar)(c & 0x1F) << 6) | c1;
1693 c2 = (soap_wchar)soap_get1(soap) & 0x3F;
1694 if (c < 0xF0)
1695 return ((soap_wchar)(c & 0x0F) << 12) | (c1 << 6) | c2;
1696 c3 = (soap_wchar)soap_get1(soap) & 0x3F;
1697 if (c < 0xF8)
1698 return ((soap_wchar)(c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3;
1699 c4 = (soap_wchar)soap_get1(soap) & 0x3F;
1700 if (c < 0xFC)
1701 return ((soap_wchar)(c & 0x03) << 24) | (c1 << 18) | (c2 << 12) | (c3 << 6) | c4;
1702 return ((soap_wchar)(c & 0x01) << 30) | (c1 << 24) | (c2 << 18) | (c3 << 12) | (c4 << 6) | (soap_wchar)(soap_get1(soap) & 0x3F);
1704 #endif
1706 /******************************************************************************/
1707 #ifndef PALM_1
1708 SOAP_FMAC1
1710 SOAP_FMAC2
1711 soap_puthex(struct soap *soap, const unsigned char *s, int n)
1712 { char d[2];
1713 register int i;
1714 #ifdef WITH_DOM
1715 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
1716 { if (!(soap->dom->data = soap_s2hex(soap, s, NULL, n)))
1717 return soap->error;
1718 return SOAP_OK;
1720 #endif
1721 for (i = 0; i < n; i++)
1722 { register int m = *s++;
1723 d[0] = (char)((m >> 4) + (m > 159 ? '7' : '0'));
1724 m &= 0x0F;
1725 d[1] = (char)(m + (m > 9 ? '7' : '0'));
1726 if (soap_send_raw(soap, d, 2))
1727 return soap->error;
1729 return SOAP_OK;
1731 #endif
1733 /******************************************************************************/
1734 #ifndef PALM_1
1735 SOAP_FMAC1
1736 unsigned char*
1737 SOAP_FMAC2
1738 soap_gethex(struct soap *soap, int *n)
1740 #ifdef WITH_DOM
1741 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
1742 { soap->dom->data = soap_string_in(soap, 0, -1, -1);
1743 return (unsigned char*)soap_hex2s(soap, soap->dom->data, NULL, 0, n);
1745 #endif
1746 #ifdef WITH_FAST
1747 soap->labidx = 0;
1748 for (;;)
1749 { register char *s;
1750 register size_t i, k;
1751 if (soap_append_lab(soap, NULL, 0))
1752 return NULL;
1753 s = soap->labbuf + soap->labidx;
1754 k = soap->lablen - soap->labidx;
1755 soap->labidx = soap->lablen;
1756 for (i = 0; i < k; i++)
1757 { register char d1, d2;
1758 register soap_wchar c;
1759 c = soap_get(soap);
1760 if (soap_isxdigit(c))
1761 { d1 = (char)c;
1762 c = soap_get(soap);
1763 if (soap_isxdigit(c))
1764 d2 = (char)c;
1765 else
1766 { soap->error = SOAP_TYPE;
1767 return NULL;
1770 else
1771 { unsigned char *p;
1772 soap_unget(soap, c);
1773 if (n)
1774 *n = (int)(soap->lablen + i - k);
1775 p = (unsigned char*)soap_malloc(soap, soap->lablen + i - k);
1776 if (p)
1777 memcpy(p, soap->labbuf, soap->lablen + i - k);
1778 return p;
1780 *s++ = ((d1 >= 'A' ? (d1 & 0x7) + 9 : d1 - '0') << 4) + (d2 >= 'A' ? (d2 & 0x7) + 9 : d2 - '0');
1783 #else
1784 if (soap_new_block(soap) == NULL)
1785 return NULL;
1786 for (;;)
1787 { register int i;
1788 register char *s = (char*)soap_push_block(soap, NULL, SOAP_BLKLEN);
1789 if (!s)
1790 { soap_end_block(soap, NULL);
1791 return NULL;
1793 for (i = 0; i < SOAP_BLKLEN; i++)
1794 { register char d1, d2;
1795 register soap_wchar c = soap_get(soap);
1796 if (soap_isxdigit(c))
1797 { d1 = (char)c;
1798 c = soap_get(soap);
1799 if (soap_isxdigit(c))
1800 d2 = (char)c;
1801 else
1802 { soap_end_block(soap, NULL);
1803 soap->error = SOAP_TYPE;
1804 return NULL;
1807 else
1808 { unsigned char *p;
1809 soap_unget(soap, c);
1810 if (n)
1811 *n = (int)soap_size_block(soap, NULL, i);
1812 p = (unsigned char*)soap_save_block(soap, NULL, 0);
1813 return p;
1815 *s++ = ((d1 >= 'A' ? (d1 & 0x7) + 9 : d1 - '0') << 4) + (d2 >= 'A' ? (d2 & 0x7) + 9 : d2 - '0');
1818 #endif
1820 #endif
1822 /******************************************************************************/
1823 #ifndef PALM_1
1824 SOAP_FMAC1
1826 SOAP_FMAC2
1827 soap_putbase64(struct soap *soap, const unsigned char *s, int n)
1828 { register int i;
1829 register unsigned long m;
1830 char d[4];
1831 if (!s)
1832 return SOAP_OK;
1833 #ifdef WITH_DOM
1834 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
1835 { if (!(soap->dom->data = soap_s2base64(soap, s, NULL, n)))
1836 return soap->error;
1837 return SOAP_OK;
1839 #endif
1840 for (; n > 2; n -= 3, s += 3)
1841 { m = s[0];
1842 m = (m << 8) | s[1];
1843 m = (m << 8) | s[2];
1844 for (i = 4; i > 0; m >>= 6)
1845 d[--i] = soap_base64o[m & 0x3F];
1846 if (soap_send_raw(soap, d, 4))
1847 return soap->error;
1849 if (n > 0)
1850 { m = 0;
1851 for (i = 0; i < n; i++)
1852 m = (m << 8) | *s++;
1853 for (; i < 3; i++)
1854 m <<= 8;
1855 for (i++; i > 0; m >>= 6)
1856 d[--i] = soap_base64o[m & 0x3F];
1857 for (i = 3; i > n; i--)
1858 d[i] = '=';
1859 if (soap_send_raw(soap, d, 4))
1860 return soap->error;
1862 return SOAP_OK;
1864 #endif
1866 /******************************************************************************/
1867 #ifndef PALM_1
1868 SOAP_FMAC1
1869 unsigned char*
1870 SOAP_FMAC2
1871 soap_getbase64(struct soap *soap, int *n, int malloc_flag)
1873 #ifdef WITH_DOM
1874 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
1875 { soap->dom->data = soap_string_in(soap, 0, -1, -1);
1876 return (unsigned char*)soap_base642s(soap, soap->dom->data, NULL, 0, n);
1878 #endif
1879 #ifdef WITH_FAST
1880 soap->labidx = 0;
1881 for (;;)
1882 { register size_t i, k;
1883 register char *s;
1884 if (soap_append_lab(soap, NULL, 2))
1885 return NULL;
1886 s = soap->labbuf + soap->labidx;
1887 k = soap->lablen - soap->labidx;
1888 soap->labidx = 3 * (soap->lablen / 3);
1889 if (!s)
1890 return NULL;
1891 if (k > 2)
1892 { for (i = 0; i < k - 2; i += 3)
1893 { register unsigned long m = 0;
1894 register int j = 0;
1896 { register soap_wchar c = soap_get(soap);
1897 if (c == '=' || c < 0)
1898 { unsigned char *p;
1899 switch (j)
1900 { case 2:
1901 *s++ = (char)((m >> 4) & 0xFF);
1902 i++;
1903 break;
1904 case 3:
1905 *s++ = (char)((m >> 10) & 0xFF);
1906 *s++ = (char)((m >> 2) & 0xFF);
1907 i += 2;
1909 if (n)
1910 *n = (int)(soap->lablen + i - k);
1911 p = (unsigned char*)soap_malloc(soap, soap->lablen + i - k);
1912 if (p)
1913 memcpy(p, soap->labbuf, soap->lablen + i - k);
1914 if (c >= 0)
1915 { while ((int)((c = soap_get(soap)) != EOF) && c != SOAP_LT && c != SOAP_TT)
1918 soap_unget(soap, c);
1919 return p;
1921 c -= '+';
1922 if (c >= 0 && c <= 79)
1923 { register int b = soap_base64i[c];
1924 if (b >= 64)
1925 { soap->error = SOAP_TYPE;
1926 return NULL;
1928 m = (m << 6) + b;
1929 j++;
1931 else if (!soap_blank(c + '+'))
1932 { soap->error = SOAP_TYPE;
1933 return NULL;
1935 } while (j < 4);
1936 *s++ = (char)((m >> 16) & 0xFF);
1937 *s++ = (char)((m >> 8) & 0xFF);
1938 *s++ = (char)(m & 0xFF);
1942 #else
1943 if (soap_new_block(soap) == NULL)
1944 return NULL;
1945 for (;;)
1946 { register int i;
1947 register char *s = (char*)soap_push_block(soap, NULL, 3 * SOAP_BLKLEN); /* must be multiple of 3 */
1948 if (!s)
1949 { soap_end_block(soap, NULL);
1950 return NULL;
1952 for (i = 0; i < SOAP_BLKLEN; i++)
1953 { register unsigned long m = 0;
1954 register int j = 0;
1956 { register soap_wchar c = soap_get(soap);
1957 if (c == '=' || c < 0)
1958 { unsigned char *p;
1959 i *= 3;
1960 switch (j)
1961 { case 2:
1962 *s++ = (char)((m >> 4) & 0xFF);
1963 i++;
1964 break;
1965 case 3:
1966 *s++ = (char)((m >> 10) & 0xFF);
1967 *s++ = (char)((m >> 2) & 0xFF);
1968 i += 2;
1970 if (n)
1971 *n = (int)soap_size_block(soap, NULL, i);
1972 p = (unsigned char*)soap_save_block(soap, NULL, 0);
1973 if (c >= 0)
1974 { while ((int)((c = soap_get(soap)) != EOF) && c != SOAP_LT && c != SOAP_TT)
1977 soap_unget(soap, c);
1978 return p;
1980 c -= '+';
1981 if (c >= 0 && c <= 79)
1982 { int b = soap_base64i[c];
1983 if (b >= 64)
1984 { soap->error = SOAP_TYPE;
1985 return NULL;
1987 m = (m << 6) + b;
1988 j++;
1990 else if (!soap_blank(c))
1991 { soap->error = SOAP_TYPE;
1992 return NULL;
1994 } while (j < 4);
1995 *s++ = (char)((m >> 16) & 0xFF);
1996 *s++ = (char)((m >> 8) & 0xFF);
1997 *s++ = (char)(m & 0xFF);
2000 #endif
2002 #endif
2004 /******************************************************************************/
2005 #ifndef WITH_LEANER
2006 #ifndef PALM_1
2007 SOAP_FMAC1
2009 SOAP_FMAC2
2010 soap_xop_forward(struct soap *soap, unsigned char **ptr, int *size, char **id, char **type, char **options)
2011 { /* Check MTOM xop:Include element (within hex/base64Binary) */
2012 /* TODO: this code to be obsoleted with new import/xop.h conventions */
2013 int body = soap->body; /* should save type too? */
2014 if (!soap_peek_element(soap))
2015 { if (!soap_element_begin_in(soap, "xop:Include", 0, NULL) && *soap->href)
2016 { if (soap_dime_forward(soap, ptr, size, id, type, options))
2017 return soap->error;
2019 if (soap->body && soap_element_end_in(soap, NULL))
2020 return soap->error;
2022 soap->body = body;
2023 return SOAP_OK;
2025 #endif
2026 #endif
2028 /******************************************************************************/
2029 #ifndef WITH_LEANER
2030 #ifndef PALM_1
2031 SOAP_FMAC1
2033 SOAP_FMAC2
2034 soap_dime_forward(struct soap *soap, unsigned char **ptr, int *size, char **id, char **type, char **options)
2035 { struct soap_xlist *xp;
2036 *ptr = NULL;
2037 *size = 0;
2038 *id = NULL;
2039 *type = NULL;
2040 *options = NULL;
2041 if (!*soap->href)
2042 return SOAP_OK;
2043 *id = soap_strdup(soap, soap->href);
2044 xp = (struct soap_xlist*)SOAP_MALLOC(soap, sizeof(struct soap_xlist));
2045 if (!xp)
2046 return soap->error = SOAP_EOM;
2047 xp->next = soap->xlist;
2048 xp->ptr = ptr;
2049 xp->size = size;
2050 xp->id = *id;
2051 xp->type = type;
2052 xp->options = options;
2053 soap->xlist = xp;
2054 return SOAP_OK;
2056 #endif
2057 #endif
2059 /******************************************************************************/
2060 #ifndef PALM_1
2061 SOAP_FMAC1
2062 char *
2063 SOAP_FMAC2
2064 soap_strdup(struct soap *soap, const char *s)
2065 { char *t = NULL;
2066 if (s && (t = (char*)soap_malloc(soap, strlen(s) + 1)))
2067 strcpy(t, s);
2068 return t;
2070 #endif
2072 /******************************************************************************/
2073 #ifndef PALM_1
2074 SOAP_FMAC1
2075 wchar_t *
2076 SOAP_FMAC2
2077 soap_wstrdup(struct soap *soap, const wchar_t *s)
2078 { wchar_t *t = NULL;
2079 if (s)
2080 { size_t n = 0;
2081 while (s[n])
2082 n++;
2083 if ((t = (wchar_t*)soap_malloc(soap, sizeof(wchar_t)*(n+1))))
2084 memcpy(t, s, sizeof(wchar_t)*(n+1));
2086 return t;
2088 #endif
2090 /******************************************************************************/
2091 #ifndef PALM_1
2092 SOAP_FMAC1
2093 struct soap_blist*
2094 SOAP_FMAC2
2095 soap_new_block(struct soap *soap)
2096 { struct soap_blist *p;
2097 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "New block sequence (prev=%p)\n", soap->blist));
2098 if (!(p = (struct soap_blist*)SOAP_MALLOC(soap, sizeof(struct soap_blist))))
2099 { soap->error = SOAP_EOM;
2100 return NULL;
2102 p->next = soap->blist;
2103 p->ptr = NULL;
2104 p->size = 0;
2105 soap->blist = p;
2106 return p;
2108 #endif
2110 /******************************************************************************/
2111 #ifndef PALM_1
2112 SOAP_FMAC1
2113 void*
2114 SOAP_FMAC2
2115 soap_push_block(struct soap *soap, struct soap_blist *b, size_t n)
2116 { char *p;
2117 if (!b)
2118 b = soap->blist;
2119 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Push block of %u bytes (%u bytes total)\n", (unsigned int)n, (unsigned int)b->size + (unsigned int)n));
2120 if (!(p = (char*)SOAP_MALLOC(soap, n + sizeof(char*) + sizeof(size_t))))
2121 { soap->error = SOAP_EOM;
2122 return NULL;
2124 *(char**)p = b->ptr;
2125 *(size_t*)(p + sizeof(char*)) = n;
2126 b->ptr = p;
2127 b->size += n;
2128 return p + sizeof(char*) + sizeof(size_t);
2130 #endif
2132 /******************************************************************************/
2133 #ifndef PALM_1
2134 SOAP_FMAC1
2135 void
2136 SOAP_FMAC2
2137 soap_pop_block(struct soap *soap, struct soap_blist *b)
2138 { char *p;
2139 if (!b)
2140 b = soap->blist;
2141 if (!b->ptr)
2142 return;
2143 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Pop block\n"));
2144 p = b->ptr;
2145 b->size -= *(size_t*)(p + sizeof(char*));
2146 b->ptr = *(char**)p;
2147 SOAP_FREE(soap, p);
2149 #endif
2151 /******************************************************************************/
2152 #ifndef WITH_NOIDREF
2153 #ifndef PALM_1
2154 static void
2155 soap_update_ptrs(struct soap *soap, char *start, char *end, char *p1, char *p2)
2156 { int i;
2157 register struct soap_ilist *ip = NULL;
2158 register struct soap_flist *fp = NULL;
2159 #ifndef WITH_LEANER
2160 register struct soap_xlist *xp = NULL;
2161 #endif
2162 register void *p, **q;
2163 for (i = 0; i < SOAP_IDHASH; i++)
2164 { for (ip = soap->iht[i]; ip; ip = ip->next)
2165 { if (ip->ptr && (char*)ip->ptr >= start && (char*)ip->ptr < end)
2166 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Update id='%s' %p -> %p\n", ip->id, ip->ptr, (char*)ip->ptr + (p1-p2)));
2167 ip->ptr = (char*)ip->ptr + (p1-p2);
2169 for (q = &ip->link; q; q = (void**)p)
2170 { p = *q;
2171 if (p && (char*)p >= start && (char*)p < end)
2172 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Link update id='%s' %p\n", ip->id, p));
2173 *q = (char*)p + (p1-p2);
2176 for (q = &ip->copy; q; q = (void**)p)
2177 { p = *q;
2178 if (p && (char*)p >= start && (char*)p < end)
2179 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy chain update id='%s' %p\n", ip->id, p));
2180 *q = (char*)p + (p1-p2);
2183 for (fp = ip->flist; fp; fp = fp->next)
2184 { if ((char*)fp->ptr >= start && (char*)fp->ptr < end)
2185 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy list update id='%s' %p\n", ip->id, fp));
2186 fp->ptr = (char*)fp->ptr + (p1-p2);
2191 #ifndef WITH_LEANER
2192 for (xp = soap->xlist; xp; xp = xp->next)
2193 { if (xp->ptr && (char*)xp->ptr >= start && (char*)xp->ptr < end)
2194 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Update id='%s' %p -> %p\n", xp->id?xp->id:SOAP_STR_EOS, xp->ptr, (char*)xp->ptr + (p1-p2)));
2195 xp->ptr = (unsigned char**)((char*)xp->ptr + (p1-p2));
2196 xp->size = (int*)((char*)xp->size + (p1-p2));
2197 xp->type = (char**)((char*)xp->type + (p1-p2));
2198 xp->options = (char**)((char*)xp->options + (p1-p2));
2201 #endif
2203 #endif
2204 #endif
2206 /******************************************************************************/
2207 #ifndef WITH_NOIDREF
2208 #ifndef PALM_1
2209 static int
2210 soap_has_copies(struct soap *soap, register const char *start, register const char *end)
2211 { register int i;
2212 register struct soap_ilist *ip = NULL;
2213 register struct soap_flist *fp = NULL;
2214 register const char *p;
2215 for (i = 0; i < SOAP_IDHASH; i++)
2216 { for (ip = soap->iht[i]; ip; ip = ip->next)
2217 { for (p = (const char*)ip->copy; p; p = *(const char**)p)
2218 if (p >= start && p < end)
2219 return SOAP_ERR;
2220 for (fp = ip->flist; fp; fp = fp->next)
2221 if ((const char*)fp->ptr >= start && (const char*)fp->ptr < end)
2222 return SOAP_ERR;
2225 return SOAP_OK;
2227 #endif
2228 #endif
2230 /******************************************************************************/
2231 #ifndef WITH_NOIDREF
2232 #ifndef PALM_1
2233 SOAP_FMAC1
2235 SOAP_FMAC2
2236 soap_resolve(struct soap *soap)
2237 { register int i;
2238 register struct soap_ilist *ip = NULL;
2239 register struct soap_flist *fp = NULL;
2240 short flag;
2241 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolving forwarded data\n"));
2242 for (i = 0; i < SOAP_IDHASH; i++)
2243 { for (ip = soap->iht[i]; ip; ip = ip->next)
2244 { if (ip->ptr)
2245 { register void *p, **q, *r;
2246 q = (void**)ip->link;
2247 ip->link = NULL;
2248 r = ip->ptr;
2249 DBGLOG(TEST, if (q) SOAP_MESSAGE(fdebug, "Traversing link chain to resolve id='%s'\n", ip->id));
2250 while (q)
2251 { p = *q;
2252 *q = r;
2253 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "... link %p -> %p\n", q, r));
2254 q = (void**)p;
2257 else if (*ip->id == '#')
2258 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Missing data for id='%s'\n", ip->id));
2259 strcpy(soap->id, ip->id + 1);
2260 return soap->error = SOAP_MISSING_ID;
2265 { flag = 0;
2266 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolution phase\n"));
2267 for (i = 0; i < SOAP_IDHASH; i++)
2268 { for (ip = soap->iht[i]; ip; ip = ip->next)
2269 { if (ip->ptr && !soap_has_copies(soap, (const char*)ip->ptr, (const char*)ip->ptr + ip->size))
2270 { if (ip->copy)
2271 { register void *p, **q = (void**)ip->copy;
2272 DBGLOG(TEST, if (q) SOAP_MESSAGE(fdebug, "Traversing copy chain to resolve id='%s'\n", ip->id));
2273 ip->copy = NULL;
2275 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "... copy %p -> %p (%u bytes)\n", ip->ptr, q, (unsigned int)ip->size));
2276 p = *q;
2277 memcpy(q, ip->ptr, ip->size);
2278 q = (void**)p;
2279 } while (q);
2280 flag = 1;
2282 for (fp = ip->flist; fp; fp = ip->flist)
2283 { register unsigned int k = fp->level;
2284 register void *p = ip->ptr;
2285 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolving forwarded data type=%d location=%p level=%u,%u id='%s'\n", ip->type, p, ip->level, fp->level, ip->id));
2286 while (ip->level < k)
2287 { register void **q = (void**)soap_malloc(soap, sizeof(void*));
2288 if (!q)
2289 return soap->error;
2290 *q = p;
2291 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Descending one level, new location=%p holds=%p...\n", q, *q));
2292 p = (void*)q;
2293 k--;
2295 if (fp->fcopy)
2296 fp->fcopy(soap, ip->type, fp->type, fp->ptr, fp->len, p, ip->size);
2297 else
2298 soap_fcopy(soap, ip->type, fp->type, fp->ptr, fp->len, p, ip->size);
2299 ip->flist = fp->next;
2300 SOAP_FREE(soap, fp);
2301 flag = 1;
2306 } while (flag);
2307 #ifdef SOAP_DEBUG
2308 for (i = 0; i < SOAP_IDHASH; i++)
2309 { for (ip = soap->iht[i]; ip; ip = ip->next)
2310 { if (ip->copy || ip->flist)
2311 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolution error: forwarded data for id='%s' could not be propagated, please report this problem to the developers\n", ip->id));
2315 #endif
2316 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolution done\n"));
2317 return SOAP_OK;
2319 #endif
2320 #endif
2322 /******************************************************************************/
2323 #ifndef PALM_1
2324 SOAP_FMAC1
2325 size_t
2326 SOAP_FMAC2
2327 soap_size_block(struct soap *soap, struct soap_blist *b, size_t n)
2328 { if (!b)
2329 b = soap->blist;
2330 if (b->ptr)
2331 { b->size -= *(size_t*)(b->ptr + sizeof(char*)) - n;
2332 *(size_t*)(b->ptr + sizeof(char*)) = n;
2334 return b->size;
2336 #endif
2338 /******************************************************************************/
2339 #ifndef PALM_1
2340 SOAP_FMAC1
2341 char*
2342 SOAP_FMAC2
2343 soap_first_block(struct soap *soap, struct soap_blist *b)
2344 { char *p, *q, *r;
2345 if (!b)
2346 b = soap->blist;
2347 p = b->ptr;
2348 if (!p)
2349 return NULL;
2350 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "First block\n"));
2351 r = NULL;
2353 { q = *(char**)p;
2354 *(char**)p = r;
2355 r = p;
2356 p = q;
2357 } while (p);
2358 b->ptr = r;
2359 return r + sizeof(char*) + sizeof(size_t);
2361 #endif
2363 /******************************************************************************/
2364 #ifndef PALM_1
2365 SOAP_FMAC1
2366 char*
2367 SOAP_FMAC2
2368 soap_next_block(struct soap *soap, struct soap_blist *b)
2369 { char *p;
2370 if (!b)
2371 b = soap->blist;
2372 p = b->ptr;
2373 if (p)
2374 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Next block\n"));
2375 b->ptr = *(char**)p;
2376 SOAP_FREE(soap, p);
2377 if (b->ptr)
2378 return b->ptr + sizeof(char*) + sizeof(size_t);
2380 return NULL;
2382 #endif
2384 /******************************************************************************/
2385 #ifndef PALM_1
2386 SOAP_FMAC1
2387 size_t
2388 SOAP_FMAC2
2389 soap_block_size(struct soap *soap, struct soap_blist *b)
2390 { if (!b)
2391 b = soap->blist;
2392 return *(size_t*)(b->ptr + sizeof(char*));
2394 #endif
2396 /******************************************************************************/
2397 #ifndef PALM_1
2398 SOAP_FMAC1
2399 void
2400 SOAP_FMAC2
2401 soap_end_block(struct soap *soap, struct soap_blist *b)
2402 { char *p, *q;
2403 if (!b)
2404 b = soap->blist;
2405 if (b)
2406 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End of block sequence, free all remaining blocks\n"));
2407 for (p = b->ptr; p; p = q)
2408 { q = *(char**)p;
2409 SOAP_FREE(soap, p);
2411 if (soap->blist == b)
2412 soap->blist = b->next;
2413 else
2414 { struct soap_blist *bp;
2415 for (bp = soap->blist; bp; bp = bp->next)
2416 { if (bp->next == b)
2417 { bp->next = b->next;
2418 break;
2422 SOAP_FREE(soap, b);
2424 DBGLOG(TEST, if (soap->blist) SOAP_MESSAGE(fdebug, "Restore previous block sequence\n"));
2426 #endif
2428 /******************************************************************************/
2429 #ifndef PALM_1
2430 SOAP_FMAC1
2431 char*
2432 SOAP_FMAC2
2433 soap_save_block(struct soap *soap, struct soap_blist *b, char *p, int flag)
2434 { register size_t n;
2435 register char *q, *s;
2436 if (!b)
2437 b = soap->blist;
2438 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Save all blocks in contiguous memory space of %u bytes (%p->%p)\n", (unsigned int)b->size, b->ptr, p));
2439 if (b->size)
2440 { if (!p)
2441 p = (char*)soap_malloc(soap, b->size);
2442 if (p)
2443 { for (s = p, q = soap_first_block(soap, b); q; q = soap_next_block(soap, b))
2444 { n = soap_block_size(soap, b);
2445 #ifndef WITH_NOIDREF
2446 if (flag)
2447 soap_update_ptrs(soap, q, q + n, s, q);
2448 #endif
2449 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy %u bytes from %p to %p\n", (unsigned int)n, q, s));
2450 memcpy(s, q, n);
2451 s += n;
2454 else
2455 soap->error = SOAP_EOM;
2457 soap_end_block(soap, b);
2458 return p;
2460 #endif
2462 /******************************************************************************/
2463 #ifndef PALM_2
2464 SOAP_FMAC1
2465 char *
2466 SOAP_FMAC2
2467 soap_putsize(struct soap *soap, const char *type, int size)
2468 { return soap_putsizes(soap, type, &size, 1);
2470 #endif
2472 /******************************************************************************/
2473 #ifndef PALM_2
2474 SOAP_FMAC1
2475 char *
2476 SOAP_FMAC2
2477 soap_putsizes(struct soap *soap, const char *type, const int *size, int dim)
2478 { return soap_putsizesoffsets(soap, type, size, NULL, dim);
2480 #endif
2482 /******************************************************************************/
2483 #ifndef PALM_2
2484 SOAP_FMAC1
2485 char *
2486 SOAP_FMAC2
2487 soap_putsizesoffsets(struct soap *soap, const char *type, const int *size, const int *offset, int dim)
2488 { int i;
2489 if (!type)
2490 return NULL;
2491 if (soap->version == 2)
2492 { sprintf(soap->type, "%s[%d", type, size[0]);
2493 for (i = 1; i < dim; i++)
2494 sprintf(soap->type + strlen(soap->type), " %d", size[i]);
2496 else
2497 { if (offset)
2498 { sprintf(soap->type, "%s[%d", type, size[0] + offset[0]);
2499 for (i = 1; i < dim; i++)
2500 sprintf(soap->type + strlen(soap->type), ",%d", size[i] + offset[i]);
2502 else
2503 { sprintf(soap->type, "%s[%d", type, size[0]);
2504 for (i = 1; i < dim; i++)
2505 sprintf(soap->type + strlen(soap->type), ",%d", size[i]);
2507 strcat(soap->type, "]");
2509 return soap->type;
2511 #endif
2513 /******************************************************************************/
2514 #ifndef PALM_2
2515 SOAP_FMAC1
2516 char *
2517 SOAP_FMAC2
2518 soap_putoffset(struct soap *soap, int offset)
2519 { return soap_putoffsets(soap, &offset, 1);
2521 #endif
2523 /******************************************************************************/
2524 #ifndef PALM_2
2525 SOAP_FMAC1
2526 char *
2527 SOAP_FMAC2
2528 soap_putoffsets(struct soap *soap, const int *offset, int dim)
2529 { register int i;
2530 sprintf(soap->arrayOffset, "[%d", offset[0]);
2531 for (i = 1; i < dim; i++)
2532 sprintf(soap->arrayOffset + strlen(soap->arrayOffset), ",%d", offset[i]);
2533 strcat(soap->arrayOffset, "]");
2534 return soap->arrayOffset;
2536 #endif
2538 /******************************************************************************/
2539 #ifndef PALM_2
2540 SOAP_FMAC1
2542 SOAP_FMAC2
2543 soap_size(const int *size, int dim)
2544 { register int i, n = size[0];
2545 for (i = 1; i < dim; i++)
2546 n *= size[i];
2547 return n;
2549 #endif
2551 /******************************************************************************/
2552 #ifndef PALM_2
2553 SOAP_FMAC1
2555 SOAP_FMAC2
2556 soap_getoffsets(const char *attr, const int *size, int *offset, int dim)
2557 { register int i, j = 0;
2558 if (offset)
2559 for (i = 0; i < dim && attr && *attr; i++)
2560 { attr++;
2561 j *= size[i];
2562 j += offset[i] = (int)soap_strtol(attr, NULL, 10);
2563 attr = strchr(attr, ',');
2565 else
2566 for (i = 0; i < dim && attr && *attr; i++)
2567 { attr++;
2568 j *= size[i];
2569 j += (int)soap_strtol(attr, NULL, 10);
2570 attr = strchr(attr, ',');
2572 return j;
2574 #endif
2576 /******************************************************************************/
2577 #ifndef PALM_2
2578 SOAP_FMAC1
2580 SOAP_FMAC2
2581 soap_getsize(const char *attr1, const char *attr2, int *j)
2582 { register int n, k;
2583 char *s;
2584 *j = 0;
2585 if (!*attr1)
2586 return -1;
2587 if (*attr1 == '[')
2588 attr1++;
2589 n = 1;
2590 for (;;)
2591 { k = (int)soap_strtol(attr1, &s, 10);
2592 n *= k;
2593 if (k < 0 || n > SOAP_MAXARRAYSIZE || s == attr1)
2594 return -1;
2595 attr1 = strchr(s, ',');
2596 if (!attr1)
2597 attr1 = strchr(s, ' ');
2598 if (attr2 && *attr2)
2599 { attr2++;
2600 *j *= k;
2601 k = (int)soap_strtol(attr2, &s, 10);
2602 *j += k;
2603 if (k < 0)
2604 return -1;
2605 attr2 = s;
2607 if (!attr1)
2608 break;
2609 attr1++;
2611 return n - *j;
2613 #endif
2615 /******************************************************************************/
2616 #ifndef PALM_2
2617 SOAP_FMAC1
2619 SOAP_FMAC2
2620 soap_getsizes(const char *attr, int *size, int dim)
2621 { register int i, k, n;
2622 if (!*attr)
2623 return -1;
2624 i = (int)strlen(attr);
2625 n = 1;
2627 { for (i = i-1; i >= 0; i--)
2628 if (attr[i] == '[' || attr[i] == ',' || attr[i] == ' ')
2629 break;
2630 k = (int)soap_strtol(attr + i + 1, NULL, 10);
2631 n *= size[--dim] = k;
2632 if (k < 0 || n > SOAP_MAXARRAYSIZE)
2633 return -1;
2634 } while (i >= 0 && attr[i] != '[');
2635 return n;
2637 #endif
2639 /******************************************************************************/
2640 #ifndef PALM_2
2641 SOAP_FMAC1
2643 SOAP_FMAC2
2644 soap_getposition(const char *attr, int *pos)
2645 { register int i, n;
2646 if (!*attr)
2647 return -1;
2648 n = 0;
2649 i = 1;
2651 { pos[n++] = (int)soap_strtol(attr + i, NULL, 10);
2652 while (attr[i] && attr[i] != ',' && attr[i] != ']')
2653 i++;
2654 if (attr[i] == ',')
2655 i++;
2656 } while (n < SOAP_MAXDIMS && attr[i] && attr[i] != ']');
2657 return n;
2659 #endif
2661 /******************************************************************************/
2662 #ifndef PALM_2
2663 SOAP_FMAC1
2664 struct soap_nlist *
2665 SOAP_FMAC2
2666 soap_push_namespace(struct soap *soap, const char *id, const char *ns)
2667 { register struct soap_nlist *np;
2668 register struct Namespace *p;
2669 register short i = -1;
2670 register size_t n, k;
2671 n = strlen(id);
2672 k = strlen(ns) + 1;
2673 p = soap->local_namespaces;
2674 if (p)
2675 { for (i = 0; p->id; p++, i++)
2676 { if (p->ns && !strcmp(ns, p->ns))
2677 { if (p->out)
2678 { SOAP_FREE(soap, p->out);
2679 p->out = NULL;
2681 break;
2683 if (p->out)
2684 { if (!strcmp(ns, p->out))
2685 break;
2687 else if (p->in)
2688 { if (!soap_tag_cmp(ns, p->in))
2689 { if ((p->out = (char*)SOAP_MALLOC(soap, k)))
2690 strcpy(p->out, ns);
2691 break;
2695 if (!p || !p->id)
2696 i = -1;
2698 if (i >= 0)
2699 k = 0;
2700 np = (struct soap_nlist*)SOAP_MALLOC(soap, sizeof(struct soap_nlist) + n + k);
2701 if (!np)
2702 { soap->error = SOAP_EOM;
2703 return NULL;
2705 np->next = soap->nlist;
2706 soap->nlist = np;
2707 np->level = soap->level;
2708 np->index = i;
2709 strcpy(np->id, id);
2710 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Push namespace binding (level=%u) '%s' '%s'\n", soap->level, id, ns));
2711 if (i < 0)
2712 { np->ns = strcpy(np->id + n + 1, ns);
2713 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Push NOT OK: no match found for '%s' in namespace mapping table (added to stack anyway)\n", ns));
2715 else
2716 { np->ns = NULL;
2717 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Push OK ('%s' matches '%s' in namespace table)\n", id, p->id));
2719 return np;
2721 #endif
2723 /******************************************************************************/
2724 #ifndef PALM_2
2725 SOAP_FMAC1
2726 void
2727 SOAP_FMAC2
2728 soap_pop_namespace(struct soap *soap)
2729 { register struct soap_nlist *np, *nq;
2730 for (np = soap->nlist; np && np->level >= soap->level; np = nq)
2731 { nq = np->next;
2732 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Pop namespace binding (level=%u) '%s'\n", soap->level, np->id));
2733 SOAP_FREE(soap, np);
2735 soap->nlist = np;
2737 #endif
2739 /******************************************************************************/
2740 #ifndef PALM_2
2741 SOAP_FMAC1
2743 SOAP_FMAC2
2744 soap_match_namespace(struct soap *soap, const char *id1, const char *id2, size_t n1, size_t n2)
2745 { register struct soap_nlist *np = soap->nlist;
2746 const char *s;
2747 while (np && (strncmp(np->id, id1, n1) || np->id[n1]))
2748 np = np->next;
2749 if (np)
2750 { if (!(soap->mode & SOAP_XML_IGNORENS))
2751 if (np->index < 0
2752 || ((s = soap->local_namespaces[np->index].id) && (strncmp(s, id2, n2) || (s[n2] && s[n2] != '_'))))
2753 return SOAP_NAMESPACE;
2754 return SOAP_OK;
2756 if (n1 == 0)
2757 return (soap->mode & SOAP_XML_IGNORENS) ? SOAP_OK : SOAP_NAMESPACE;
2758 if ((n1 == 3 && n1 == n2 && !strncmp(id1, "xml", 3) && !strncmp(id1, id2, 3))
2759 || (soap->mode & SOAP_XML_IGNORENS))
2760 return SOAP_OK;
2761 return soap->error = SOAP_SYNTAX_ERROR;
2763 #endif
2765 /******************************************************************************/
2766 #ifndef PALM_2
2767 SOAP_FMAC1
2768 const char*
2769 SOAP_FMAC2
2770 soap_current_namespace(struct soap *soap, const char *tag)
2771 { register struct soap_nlist *np;
2772 register const char *s;
2773 if (!tag || !strncmp(tag, "xml", 3))
2774 return NULL;
2775 np = soap->nlist;
2776 if (!(s = strchr(tag, ':')))
2777 { while (np && *np->id) /* find default namespace, if present */
2778 np = np->next;
2780 else
2781 { while (np && (strncmp(np->id, tag, s - tag) || np->id[s - tag]))
2782 np = np->next;
2783 if (!np)
2784 soap->error = SOAP_NAMESPACE;
2786 if (np)
2787 { if (np->index >= 0)
2788 return soap->namespaces[np->index].ns;
2789 if (np->ns)
2790 return soap_strdup(soap, np->ns);
2792 return NULL;
2794 #endif
2796 /******************************************************************************/
2797 #ifndef PALM_2
2798 SOAP_FMAC1
2800 SOAP_FMAC2
2801 soap_tag_cmp(const char *s, const char *t)
2802 { for (;;)
2803 { register int c1 = *s;
2804 register int c2 = *t;
2805 if (!c1 || c1 == '"')
2806 break;
2807 if (c2 != '-')
2808 { if (c1 != c2)
2809 { if (c1 >= 'A' && c1 <= 'Z')
2810 c1 += 'a' - 'A';
2811 if (c2 >= 'A' && c2 <= 'Z')
2812 c2 += 'a' - 'A';
2814 if (c1 != c2)
2815 { if (c2 != '*')
2816 return 1;
2817 c2 = *++t;
2818 if (!c2)
2819 return 0;
2820 if (c2 >= 'A' && c2 <= 'Z')
2821 c2 += 'a' - 'A';
2822 for (;;)
2823 { c1 = *s;
2824 if (!c1 || c1 == '"')
2825 break;
2826 if (c1 >= 'A' && c1 <= 'Z')
2827 c1 += 'a' - 'A';
2828 if (c1 == c2 && !soap_tag_cmp(s + 1, t + 1))
2829 return 0;
2830 s++;
2832 break;
2835 s++;
2836 t++;
2838 if (*t == '*' && !t[1])
2839 return 0;
2840 return *t;
2842 #endif
2844 /******************************************************************************/
2845 #ifndef PALM_2
2846 SOAP_FMAC1
2848 SOAP_FMAC2
2849 soap_match_tag(struct soap *soap, const char *tag1, const char *tag2)
2850 { register const char *s, *t;
2851 register int err;
2852 if (!tag1 || !tag2 || !*tag2)
2853 return SOAP_OK;
2854 s = strchr(tag1, ':');
2855 t = strchr(tag2, ':');
2856 if (t)
2857 { if (s)
2858 { if (t[1] && SOAP_STRCMP(s + 1, t + 1))
2859 return SOAP_TAG_MISMATCH;
2860 if (t != tag2 && (err = soap_match_namespace(soap, tag1, tag2, s - tag1, t - tag2)))
2861 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Tags '%s' and '%s' match but namespaces differ\n", tag1, tag2));
2862 if (err == SOAP_NAMESPACE)
2863 return SOAP_TAG_MISMATCH;
2864 return err;
2867 else if (SOAP_STRCMP(tag1, t + 1))
2868 { return SOAP_TAG_MISMATCH;
2870 else if (t != tag2 && (err = soap_match_namespace(soap, tag1, tag2, 0, t - tag2)))
2871 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Tags '%s' and '%s' match but namespaces differ\n", tag1, tag2));
2872 if (err == SOAP_NAMESPACE)
2873 return SOAP_TAG_MISMATCH;
2874 return err;
2876 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Tags and (default) namespaces match: '%s' '%s'\n", tag1, tag2));
2877 return SOAP_OK;
2879 if (s)
2880 { if (SOAP_STRCMP(s + 1, tag2))
2881 return SOAP_TAG_MISMATCH;
2883 else if (SOAP_STRCMP(tag1, tag2))
2884 return SOAP_TAG_MISMATCH;
2885 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Tags match: '%s' '%s'\n", tag1, tag2));
2886 return SOAP_OK;
2888 #endif
2890 /******************************************************************************/
2891 #ifndef PALM_2
2892 SOAP_FMAC1
2894 SOAP_FMAC2
2895 soap_match_array(struct soap *soap, const char *type)
2896 { if (*soap->arrayType)
2897 if (soap_match_tag(soap, soap->arrayType, type)
2898 && soap_match_tag(soap, soap->arrayType, "xsd:anyType")
2899 && soap_match_tag(soap, soap->arrayType, "xsd:ur-type")
2901 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array type mismatch: '%s' '%s'\n", soap->arrayType, type));
2902 return SOAP_TAG_MISMATCH;
2904 return SOAP_OK;
2906 #endif
2908 /******************************************************************************\
2910 * SSL/TLS
2912 \******************************************************************************/
2914 /******************************************************************************/
2915 #ifdef WITH_OPENSSL
2916 #ifndef PALM_2
2917 SOAP_FMAC1
2919 SOAP_FMAC2
2920 soap_rand()
2921 { unsigned char buf[4];
2922 if (!soap_ssl_init_done)
2923 soap_ssl_init();
2924 RAND_pseudo_bytes(buf, 4);
2925 return *(int*)buf;
2927 #endif
2928 #endif
2930 /******************************************************************************/
2931 #if defined(WITH_OPENSSL) || defined(WITH_GNUTLS)
2932 #ifndef PALM_2
2933 SOAP_FMAC1
2935 SOAP_FMAC2
2936 soap_ssl_server_context(struct soap *soap, unsigned short flags, const char *keyfile, const char *password, const char *cafile, const char *capath, const char *dhfile, const char *randfile, const char *sid)
2937 { int err;
2938 soap->keyfile = keyfile;
2939 soap->password = password;
2940 soap->cafile = cafile;
2941 soap->capath = capath;
2942 soap->crlfile = NULL;
2943 #ifdef WITH_OPENSSL
2944 soap->dhfile = dhfile;
2945 soap->randfile = randfile;
2946 #endif
2947 soap->ssl_flags = flags | (dhfile == NULL ? SOAP_SSL_RSA : 0);
2948 #ifdef WITH_GNUTLS
2949 if (dhfile)
2950 { char *s;
2951 int n = (int)soap_strtoul(dhfile, &s, 10);
2952 if (!soap->dh_params)
2953 gnutls_dh_params_init(&soap->dh_params);
2954 /* if dhfile is numeric, treat it as a key length to generate DH params which can take a while */
2955 if (n >= 512 && s && *s == '\0')
2956 gnutls_dh_params_generate2(soap->dh_params, (unsigned int)n);
2957 else
2958 { unsigned int dparams_len;
2959 unsigned char dparams_buf[1024];
2960 FILE *fd = fopen(dhfile, "r");
2961 if (!fd)
2962 return soap_set_receiver_error(soap, "SSL/TLS error", "Invalid DH file", SOAP_SSL_ERROR);
2963 dparams_len = (unsigned int)fread(dparams_buf, 1, sizeof(dparams_buf), fd);
2964 fclose(fd);
2965 gnutls_datum_t dparams = { dparams_buf, dparams_len };
2966 if (gnutls_dh_params_import_pkcs3(soap->dh_params, &dparams, GNUTLS_X509_FMT_PEM))
2967 return soap_set_receiver_error(soap, "SSL/TLS error", "Invalid DH file", SOAP_SSL_ERROR);
2970 else
2971 { if (!soap->rsa_params)
2972 gnutls_rsa_params_init(&soap->rsa_params);
2973 gnutls_rsa_params_generate2(soap->rsa_params, SOAP_SSL_RSA_BITS);
2975 if (soap->session)
2976 { gnutls_deinit(soap->session);
2977 soap->session = NULL;
2979 if (soap->xcred)
2980 { gnutls_certificate_free_credentials(soap->xcred);
2981 soap->xcred = NULL;
2983 #endif
2984 err = soap->fsslauth(soap);
2985 #ifdef WITH_OPENSSL
2986 if (!err)
2987 { if (sid)
2988 SSL_CTX_set_session_id_context(soap->ctx, (unsigned char*)sid, (unsigned int)strlen(sid));
2989 else
2990 SSL_CTX_set_session_cache_mode(soap->ctx, SSL_SESS_CACHE_OFF);
2992 #endif
2993 return err;
2995 #endif
2996 #endif
2998 /******************************************************************************/
2999 #if defined(WITH_OPENSSL) || defined(WITH_GNUTLS)
3000 #ifndef PALM_2
3001 SOAP_FMAC1
3003 SOAP_FMAC2
3004 soap_ssl_client_context(struct soap *soap, unsigned short flags, const char *keyfile, const char *password, const char *cafile, const char *capath, const char *randfile)
3005 { soap->keyfile = keyfile;
3006 soap->password = password;
3007 soap->cafile = cafile;
3008 soap->capath = capath;
3009 soap->ssl_flags = SOAP_SSL_CLIENT | flags;
3010 #ifdef WITH_OPENSSL
3011 soap->dhfile = NULL;
3012 soap->randfile = randfile;
3013 soap->fsslverify = (flags & SOAP_SSL_ALLOW_EXPIRED_CERTIFICATE) == 0 ? ssl_verify_callback : ssl_verify_callback_allow_expired_certificate;
3014 #endif
3015 #ifdef WITH_GNUTLS
3016 if (soap->session)
3017 { gnutls_deinit(soap->session);
3018 soap->session = NULL;
3020 if (soap->xcred)
3021 { gnutls_certificate_free_credentials(soap->xcred);
3022 soap->xcred = NULL;
3024 #endif
3025 return soap->fsslauth(soap);
3027 #endif
3028 #endif
3030 /******************************************************************************/
3031 #if defined(WITH_OPENSSL) || defined(WITH_GNUTLS)
3032 #ifndef PALM_2
3033 SOAP_FMAC1
3034 void
3035 SOAP_FMAC2
3036 soap_ssl_init()
3037 { /* Note: for MT systems, the main program MUST call soap_ssl_init() before any threads are started */
3038 if (!soap_ssl_init_done)
3039 { soap_ssl_init_done = 1;
3040 #ifdef WITH_OPENSSL
3041 SSL_library_init();
3042 #ifndef WITH_LEAN
3043 SSL_load_error_strings();
3044 #endif
3045 if (!RAND_load_file("/dev/urandom", 1024))
3046 { char buf[1024];
3047 RAND_seed(buf, sizeof(buf));
3048 while (!RAND_status())
3049 { int r = rand();
3050 RAND_seed(&r, sizeof(int));
3053 #endif
3054 #ifdef WITH_GNUTLS
3055 # if defined(HAVE_PTHREAD_H)
3056 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
3057 # elif defined(HAVE_PTH_H)
3058 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
3059 # endif
3060 gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
3061 gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
3062 gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); /* libgcrypt init done */
3063 gnutls_global_init();
3064 #endif
3067 #endif
3068 #endif
3070 /******************************************************************************/
3071 #if defined(WITH_OPENSSL) || defined(WITH_GNUTLS)
3072 #ifndef PALM_1
3073 SOAP_FMAC1
3074 const char *
3075 SOAP_FMAC2
3076 soap_ssl_error(struct soap *soap, int ret)
3078 #ifdef WITH_OPENSSL
3079 int err = SSL_get_error(soap->ssl, ret);
3080 const char *msg = soap_code_str(h_ssl_error_codes, err);
3081 if (msg)
3082 strcpy(soap->msgbuf, msg);
3083 else
3084 return ERR_error_string(err, soap->msgbuf);
3085 if (ERR_peek_error())
3086 { unsigned long r;
3087 strcat(soap->msgbuf, "\n");
3088 while ((r = ERR_get_error()))
3089 ERR_error_string_n(r, soap->msgbuf + strlen(soap->msgbuf), sizeof(soap->msgbuf) - strlen(soap->msgbuf));
3091 else
3092 { switch (ret)
3093 { case 0:
3094 strcpy(soap->msgbuf, "EOF was observed that violates the protocol. The client probably provided invalid authentication information.");
3095 break;
3096 case -1:
3097 sprintf(soap->msgbuf, "Error observed by underlying BIO: %s", strerror(errno));
3098 break;
3101 return soap->msgbuf;
3102 #endif
3103 #ifdef WITH_GNUTLS
3104 return gnutls_strerror(ret);
3105 #endif
3107 #endif
3108 #endif
3110 /******************************************************************************/
3111 #if defined(WITH_OPENSSL) || defined(WITH_GNUTLS)
3112 #ifndef PALM_1
3113 static int
3114 ssl_auth_init(struct soap *soap)
3116 #ifdef WITH_OPENSSL
3117 long flags;
3118 int mode;
3119 if (!soap_ssl_init_done)
3120 soap_ssl_init();
3121 ERR_clear_error();
3122 if (!soap->ctx)
3123 { if (!(soap->ctx = SSL_CTX_new(SSLv23_method())))
3124 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't setup context", SOAP_SSL_ERROR);
3125 /* The following alters the behavior of SSL read/write: */
3126 #if 0
3127 SSL_CTX_set_mode(soap->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY);
3128 #endif
3130 if (soap->randfile)
3131 { if (!RAND_load_file(soap->randfile, -1))
3132 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't load randomness", SOAP_SSL_ERROR);
3134 if (soap->cafile || soap->capath)
3135 { if (!SSL_CTX_load_verify_locations(soap->ctx, soap->cafile, soap->capath))
3136 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CA file", SOAP_SSL_ERROR);
3137 if (soap->cafile && (soap->ssl_flags & SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION))
3138 SSL_CTX_set_client_CA_list(soap->ctx, SSL_load_client_CA_file(soap->cafile));
3140 if (!(soap->ssl_flags & SOAP_SSL_NO_DEFAULT_CA_PATH))
3141 { if (!SSL_CTX_set_default_verify_paths(soap->ctx))
3142 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read default CA file and/or directory", SOAP_SSL_ERROR);
3144 /* This code assumes a typical scenario, see alternative code below */
3145 if (soap->keyfile)
3146 { if (!SSL_CTX_use_certificate_chain_file(soap->ctx, soap->keyfile))
3147 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read certificate key file", SOAP_SSL_ERROR);
3148 if (soap->password)
3149 { SSL_CTX_set_default_passwd_cb_userdata(soap->ctx, (void*)soap->password);
3150 SSL_CTX_set_default_passwd_cb(soap->ctx, ssl_password);
3152 if (!SSL_CTX_use_PrivateKey_file(soap->ctx, soap->keyfile, SSL_FILETYPE_PEM))
3153 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read key file", SOAP_SSL_ERROR);
3155 /* Suggested alternative approach to check the key file for certs (cafile=NULL):*/
3156 #if 0
3157 if (soap->password)
3158 { SSL_CTX_set_default_passwd_cb_userdata(soap->ctx, (void*)soap->password);
3159 SSL_CTX_set_default_passwd_cb(soap->ctx, ssl_password);
3161 if (!soap->cafile || !SSL_CTX_use_certificate_chain_file(soap->ctx, soap->cafile))
3162 { if (soap->keyfile)
3163 { if (!SSL_CTX_use_certificate_chain_file(soap->ctx, soap->keyfile))
3164 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read certificate or key file", SOAP_SSL_ERROR);
3165 if (!SSL_CTX_use_PrivateKey_file(soap->ctx, soap->keyfile, SSL_FILETYPE_PEM))
3166 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read key file", SOAP_SSL_ERROR);
3169 #endif
3170 if ((soap->ssl_flags & SOAP_SSL_RSA))
3171 { RSA *rsa = RSA_generate_key(SOAP_SSL_RSA_BITS, RSA_F4, NULL, NULL);
3172 if (!SSL_CTX_set_tmp_rsa(soap->ctx, rsa))
3173 { if (rsa)
3174 RSA_free(rsa);
3175 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't set RSA key", SOAP_SSL_ERROR);
3177 RSA_free(rsa);
3179 else if (soap->dhfile)
3180 { DH *dh = 0;
3181 char *s;
3182 int n = (int)soap_strtoul(soap->dhfile, &s, 10);
3183 /* if dhfile is numeric, treat it as a key length to generate DH params which can take a while */
3184 if (n >= 512 && s && *s == '\0')
3185 dh = DH_generate_parameters(n, 2/*or 5*/, NULL, NULL);
3186 else
3187 { BIO *bio;
3188 bio = BIO_new_file(soap->dhfile, "r");
3189 if (!bio)
3190 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read DH file", SOAP_SSL_ERROR);
3191 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
3192 BIO_free(bio);
3194 if (!dh || DH_check(dh, &n) != 1 || SSL_CTX_set_tmp_dh(soap->ctx, dh) < 0)
3195 { if (dh)
3196 DH_free(dh);
3197 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't set DH parameters", SOAP_SSL_ERROR);
3199 DH_free(dh);
3201 flags = (SSL_OP_ALL | SSL_OP_NO_SSLv2);
3202 if ((soap->ssl_flags & SOAP_SSLv3))
3203 flags |= SSL_OP_NO_TLSv1;
3204 if ((soap->ssl_flags & SOAP_TLSv1))
3205 flags |= SSL_OP_NO_SSLv3;
3206 #ifdef SSL_OP_NO_TICKET
3207 /* TLS extension is enabled by default in OPENSSL v0.9.8k
3208 Disable it by adding SSL_OP_NO_TICKET */
3209 flags |= SSL_OP_NO_TICKET;
3210 #endif
3211 SSL_CTX_set_options(soap->ctx, flags);
3212 if ((soap->ssl_flags & SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION))
3213 mode = (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
3214 else if ((soap->ssl_flags & SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION))
3215 mode = SSL_VERIFY_PEER;
3216 else
3217 mode = SSL_VERIFY_NONE;
3218 SSL_CTX_set_verify(soap->ctx, mode, soap->fsslverify);
3219 #if (OPENSSL_VERSION_NUMBER < 0x00905100L)
3220 SSL_CTX_set_verify_depth(soap->ctx, 1);
3221 #else
3222 SSL_CTX_set_verify_depth(soap->ctx, 9);
3223 #endif
3224 #endif
3225 #ifdef WITH_GNUTLS
3226 int ret;
3227 if (!soap_ssl_init_done)
3228 soap_ssl_init();
3229 if (!soap->xcred)
3230 { gnutls_certificate_allocate_credentials(&soap->xcred);
3231 if (soap->cafile)
3232 { if (gnutls_certificate_set_x509_trust_file(soap->xcred, soap->cafile, GNUTLS_X509_FMT_PEM) < 0)
3233 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CA file", SOAP_SSL_ERROR);
3235 if (soap->crlfile)
3236 { if (gnutls_certificate_set_x509_crl_file(soap->xcred, soap->crlfile, GNUTLS_X509_FMT_PEM) < 0)
3237 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read CRL file", SOAP_SSL_ERROR);
3239 if (soap->keyfile)
3240 { if (gnutls_certificate_set_x509_key_file(soap->xcred, soap->keyfile, soap->keyfile, GNUTLS_X509_FMT_PEM) < 0) /* TODO: GNUTLS need to concat cert and key in single key file */
3241 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't read key file", SOAP_SSL_ERROR);
3244 if ((soap->ssl_flags & SOAP_SSL_CLIENT))
3245 { gnutls_init(&soap->session, GNUTLS_CLIENT);
3246 if (soap->cafile || soap->crlfile || soap->keyfile)
3247 { ret = gnutls_priority_set_direct(soap->session, "PERFORMANCE", NULL);
3248 if (ret < 0)
3249 return soap_set_receiver_error(soap, soap_ssl_error(soap, ret), "SSL/TLS set priority error", SOAP_SSL_ERROR);
3250 gnutls_credentials_set(soap->session, GNUTLS_CRD_CERTIFICATE, soap->xcred);
3252 else
3253 { if (!soap->acred)
3254 gnutls_anon_allocate_client_credentials(&soap->acred);
3255 gnutls_init(&soap->session, GNUTLS_CLIENT);
3256 gnutls_priority_set_direct(soap->session, "PERFORMANCE:+ANON-DH:!ARCFOUR-128", NULL);
3257 gnutls_credentials_set(soap->session, GNUTLS_CRD_ANON, soap->acred);
3260 else
3261 { if (!soap->keyfile)
3262 return soap_set_receiver_error(soap, "SSL/TLS error", "No key file: anonymous server authentication not supported in this release", SOAP_SSL_ERROR);
3263 if ((soap->ssl_flags & SOAP_SSL_RSA) && soap->rsa_params)
3264 gnutls_certificate_set_rsa_export_params(soap->xcred, soap->rsa_params);
3265 else if (soap->dh_params)
3266 gnutls_certificate_set_dh_params(soap->xcred, soap->dh_params);
3267 if (!soap->cache)
3268 gnutls_priority_init(&soap->cache, "NORMAL", NULL);
3269 gnutls_init(&soap->session, GNUTLS_SERVER);
3270 gnutls_priority_set(soap->session, soap->cache);
3271 gnutls_credentials_set(soap->session, GNUTLS_CRD_CERTIFICATE, soap->xcred);
3272 if ((soap->ssl_flags & SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION))
3273 gnutls_certificate_server_set_request(soap->session, GNUTLS_CERT_REQUEST);
3274 gnutls_session_enable_compatibility_mode(soap->session);
3275 if ((soap->ssl_flags & SOAP_TLSv1))
3276 { int protocol_priority[] = { GNUTLS_TLS1_0, 0 };
3277 if (gnutls_protocol_set_priority(soap->session, protocol_priority) != GNUTLS_E_SUCCESS)
3278 return soap_set_receiver_error(soap, "SSL/TLS error", "Can't set TLS v1.0 protocol", SOAP_SSL_ERROR);
3281 #endif
3282 return SOAP_OK;
3284 #endif
3285 #endif
3287 /******************************************************************************/
3288 #ifdef WITH_OPENSSL
3289 #ifndef PALM_1
3290 static int
3291 ssl_password(char *buf, int num, int rwflag, void *userdata)
3292 { if (num < (int)strlen((char*)userdata) + 1)
3293 return 0;
3294 return (int)strlen(strcpy(buf, (char*)userdata));
3296 #endif
3297 #endif
3299 /******************************************************************************/
3300 #ifdef WITH_OPENSSL
3301 #ifndef PALM_1
3302 static int
3303 ssl_verify_callback(int ok, X509_STORE_CTX *store)
3305 #ifdef SOAP_DEBUG
3306 if (!ok)
3307 { char data[256];
3308 X509 *cert = X509_STORE_CTX_get_current_cert(store);
3309 fprintf(stderr, "SSL verify error or warning with certificate at depth %d: %s\n", X509_STORE_CTX_get_error_depth(store), X509_verify_cert_error_string(X509_STORE_CTX_get_error(store)));
3310 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof(data));
3311 fprintf(stderr, "certificate issuer %s\n", data);
3312 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof(data));
3313 fprintf(stderr, "certificate subject %s\n", data);
3315 #endif
3316 /* Note: return 1 to continue, but unsafe progress will be terminated by OpenSSL */
3317 return ok;
3319 #endif
3320 #endif
3322 /******************************************************************************/
3323 #ifdef WITH_OPENSSL
3324 #ifndef PALM_1
3325 static int
3326 ssl_verify_callback_allow_expired_certificate(int ok, X509_STORE_CTX *store)
3327 { ok = ssl_verify_callback(ok, store);
3328 if (ok == 0 && X509_STORE_CTX_get_error(store) == X509_V_ERR_CERT_HAS_EXPIRED)
3330 #ifdef SOAP_DEBUG
3331 fprintf(stderr, "ignoring certificate expiration\n");
3332 #endif
3333 X509_STORE_CTX_set_error(store, X509_V_OK);
3334 ok = 1;
3336 /* Note: return 1 to continue, but unsafe progress will be terminated by SSL */
3337 return ok;
3339 #endif
3340 #endif
3342 /******************************************************************************/
3343 #ifdef WITH_GNUTLS
3344 static const char *
3345 ssl_verify(struct soap *soap, const char *host)
3346 { unsigned int status;
3347 const char *err = NULL;
3348 int r = gnutls_certificate_verify_peers2(soap->session, &status);
3349 if (r < 0)
3350 err = "Certificate verify error";
3351 else if ((status & GNUTLS_CERT_INVALID))
3352 err = "The certificate is not trusted";
3353 else if ((status & GNUTLS_CERT_SIGNER_NOT_FOUND))
3354 err = "The certificate hasn't got a known issuer";
3355 else if ((status & GNUTLS_CERT_REVOKED))
3356 err = "The certificate has been revoked";
3357 else if (gnutls_certificate_type_get(soap->session) == GNUTLS_CRT_X509)
3358 { gnutls_x509_crt_t cert;
3359 const gnutls_datum_t *cert_list;
3360 unsigned int cert_list_size;
3361 if (gnutls_x509_crt_init(&cert) < 0)
3362 err = "Could not get X509 certificates";
3363 else if ((cert_list = gnutls_certificate_get_peers(soap->session, &cert_list_size)) == NULL)
3364 err = "Could not get X509 certificates";
3365 else if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
3366 err = "Error parsing X509 certificate";
3367 else if (!(soap->ssl_flags & SOAP_SSL_ALLOW_EXPIRED_CERTIFICATE) && gnutls_x509_crt_get_expiration_time(cert) < time(NULL))
3368 err = "The certificate has expired";
3369 else if (!(soap->ssl_flags & SOAP_SSL_ALLOW_EXPIRED_CERTIFICATE) && gnutls_x509_crt_get_activation_time(cert) > time(NULL))
3370 err = "The certificate is not yet activated";
3371 else if (host && !(soap->ssl_flags & SOAP_SSL_SKIP_HOST_CHECK))
3372 { if (!gnutls_x509_crt_check_hostname(cert, host))
3373 err = "Certificate host name mismatch";
3375 gnutls_x509_crt_deinit(cert);
3377 return err;
3379 #endif
3381 /******************************************************************************/
3382 #if defined(WITH_OPENSSL) || defined(WITH_GNUTLS)
3383 #ifndef WITH_NOIO
3384 #ifndef PALM_1
3385 SOAP_FMAC1
3387 SOAP_FMAC2
3388 soap_ssl_accept(struct soap *soap)
3389 { SOAP_SOCKET fd = soap->socket;
3390 #ifdef WITH_OPENSSL
3391 BIO *bio;
3392 int retries, r, s;
3393 if (!soap_valid_socket(fd))
3394 return soap_set_receiver_error(soap, "SSL/TLS error", "No socket in soap_ssl_accept()", SOAP_SSL_ERROR);
3395 soap->ssl_flags &= ~SOAP_SSL_CLIENT;
3396 if (!soap->ctx && (soap->error = soap->fsslauth(soap)))
3397 return soap->error;
3398 if (!soap->ssl)
3399 { soap->ssl = SSL_new(soap->ctx);
3400 if (!soap->ssl)
3401 return soap_set_receiver_error(soap, "SSL/TLS error", "SSL_new() failed in soap_ssl_accept()", SOAP_SSL_ERROR);
3403 else
3404 SSL_clear(soap->ssl);
3405 bio = BIO_new_socket((int)fd, BIO_NOCLOSE);
3406 SSL_set_bio(soap->ssl, bio, bio);
3407 /* Set SSL sockets to non-blocking */
3408 retries = 0;
3409 if (soap->accept_timeout)
3410 { SOAP_SOCKNONBLOCK(fd)
3411 retries = 10*soap->accept_timeout;
3413 if (retries <= 0)
3414 retries = 100; /* timeout: 10 sec retries, 100 times 0.1 sec */
3415 while ((r = SSL_accept(soap->ssl)) <= 0)
3416 { int err;
3417 if (retries-- <= 0)
3418 break;
3419 err = SSL_get_error(soap->ssl, r);
3420 if (err == SSL_ERROR_WANT_ACCEPT || err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
3421 { if (err == SSL_ERROR_WANT_READ)
3422 s = tcp_select(soap, fd, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, -100000);
3423 else
3424 s = tcp_select(soap, fd, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, -100000);
3425 if (s < 0 && soap->errnum != SOAP_EINTR)
3426 break;
3428 else
3429 { soap->errnum = soap_socket_errno(fd);
3430 break;
3433 if (r <= 0)
3434 { soap_set_receiver_error(soap, soap_ssl_error(soap, r), "SSL_accept() failed in soap_ssl_accept()", SOAP_SSL_ERROR);
3435 soap_closesock(soap);
3436 return SOAP_SSL_ERROR;
3438 if ((soap->ssl_flags & SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION))
3439 { X509 *peer;
3440 int err;
3441 if ((err = SSL_get_verify_result(soap->ssl)) != X509_V_OK)
3442 { soap_closesock(soap);
3443 return soap_set_sender_error(soap, X509_verify_cert_error_string(err), "SSL certificate presented by peer cannot be verified in soap_ssl_accept()", SOAP_SSL_ERROR);
3445 peer = SSL_get_peer_certificate(soap->ssl);
3446 if (!peer)
3447 { soap_closesock(soap);
3448 return soap_set_sender_error(soap, "SSL/TLS error", "No SSL certificate was presented by the peer in soap_ssl_accept()", SOAP_SSL_ERROR);
3450 X509_free(peer);
3452 #endif
3453 #ifdef WITH_GNUTLS
3454 int retries = 0, r;
3455 if (!soap_valid_socket(fd))
3456 return soap_set_receiver_error(soap, "SSL/TLS error", "No socket in soap_ssl_accept()", SOAP_SSL_ERROR);
3457 soap->ssl_flags &= ~SOAP_SSL_CLIENT;
3458 if (!soap->session && (soap->error = soap->fsslauth(soap)))
3459 { soap_closesock(soap);
3460 return soap->error;
3462 gnutls_transport_set_ptr(soap->session, (gnutls_transport_ptr_t)(long)fd);
3463 /* Set SSL sockets to non-blocking */
3464 if (soap->accept_timeout)
3465 { SOAP_SOCKNONBLOCK(fd)
3466 retries = 10*soap->accept_timeout;
3468 if (retries <= 0)
3469 retries = 100; /* timeout: 10 sec retries, 100 times 0.1 sec */
3470 while ((r = gnutls_handshake(soap->session)))
3471 { int s;
3472 /* GNUTLS repeat handhake when GNUTLS_E_AGAIN */
3473 if (retries-- <= 0)
3474 break;
3475 if (r == GNUTLS_E_AGAIN || r == GNUTLS_E_INTERRUPTED)
3476 { if (!gnutls_record_get_direction(soap->session))
3477 s = tcp_select(soap, fd, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, -100000);
3478 else
3479 s = tcp_select(soap, fd, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, -100000);
3480 if (s < 0 && soap->errnum != SOAP_EINTR)
3481 break;
3483 else
3484 { soap->errnum = soap_socket_errno(fd);
3485 break;
3488 if (r)
3489 { soap_closesock(soap);
3490 return soap_set_receiver_error(soap, soap_ssl_error(soap, r), "SSL/TLS handshake failed", SOAP_SSL_ERROR);
3492 if ((soap->ssl_flags & SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION))
3493 { const char *err = ssl_verify(soap, NULL);
3494 if (err)
3495 { soap_closesock(soap);
3496 return soap_set_receiver_error(soap, "SSL/TLS error", err, SOAP_SSL_ERROR);
3499 #endif
3500 if (soap->recv_timeout || soap->send_timeout)
3501 SOAP_SOCKNONBLOCK(fd)
3502 else
3503 SOAP_SOCKBLOCK(fd)
3504 soap->imode |= SOAP_ENC_SSL;
3505 soap->omode |= SOAP_ENC_SSL;
3506 return SOAP_OK;
3508 #endif
3509 #endif
3510 #endif
3512 /******************************************************************************\
3514 * TCP/UDP [SSL/TLS] IPv4 and IPv6
3516 \******************************************************************************/
3518 /******************************************************************************/
3519 #ifndef WITH_NOIO
3520 #ifndef PALM_1
3521 static int
3522 tcp_init(struct soap *soap)
3523 { soap->errmode = 1;
3524 #ifdef WIN32
3525 if (tcp_done)
3526 return 0;
3527 else
3528 { WSADATA w;
3529 if (WSAStartup(MAKEWORD(1, 1), &w))
3530 return -1;
3531 tcp_done = 1;
3533 #endif
3534 return 0;
3536 #endif
3537 #endif
3539 /******************************************************************************/
3540 #ifndef WITH_NOIO
3541 #ifndef PALM_1
3542 static const char*
3543 tcp_error(struct soap *soap)
3544 { register const char *msg = NULL;
3545 switch (soap->errmode)
3546 { case 0:
3547 msg = soap_strerror(soap);
3548 break;
3549 case 1:
3550 msg = "WSAStartup failed";
3551 break;
3552 case 2:
3554 #ifndef WITH_LEAN
3555 msg = soap_code_str(h_error_codes, soap->errnum);
3556 if (!msg)
3557 #endif
3558 { sprintf(soap->msgbuf, "TCP/UDP IP error %d", soap->errnum);
3559 msg = soap->msgbuf;
3563 return msg;
3565 #endif
3566 #endif
3568 /******************************************************************************/
3569 #ifndef WITH_IPV6
3570 #ifndef WITH_NOIO
3571 #ifndef PALM_1
3572 static int
3573 tcp_gethost(struct soap *soap, const char *addr, struct in_addr *inaddr)
3574 { soap_int32 iadd = -1;
3575 struct hostent hostent, *host = &hostent;
3576 #ifdef VXWORKS
3577 int hostint;
3578 /* inet_addr(), and hostGetByName() expect "char *"; addr is a "const char *". */
3579 iadd = inet_addr((char*)addr);
3580 #else
3581 #if defined(_AIX43) || ((defined(TRU64) || defined(HP_UX)) && defined(HAVE_GETHOSTBYNAME_R))
3582 struct hostent_data ht_data;
3583 #endif
3584 #ifdef AS400
3585 iadd = inet_addr((void*)addr);
3586 #else
3587 iadd = inet_addr(addr);
3588 #endif
3589 #endif
3590 if (iadd != -1)
3591 { memcpy(inaddr, &iadd, sizeof(iadd));
3592 return SOAP_OK;
3594 #if defined(__GLIBC__) || (defined(HAVE_GETHOSTBYNAME_R) && (defined(FREEBSD) || defined(__FreeBSD__)))
3595 if (gethostbyname_r(addr, &hostent, soap->buf, SOAP_BUFLEN, &host, &soap->errnum) < 0)
3596 host = NULL;
3597 #elif defined(_AIX43) || ((defined(TRU64) || defined(HP_UX)) && defined(HAVE_GETHOSTBYNAME_R))
3598 memset((void*)&ht_data, 0, sizeof(ht_data));
3599 if (gethostbyname_r(addr, &hostent, &ht_data) < 0)
3600 { host = NULL;
3601 soap->errnum = h_errno;
3603 #elif defined(HAVE_GETHOSTBYNAME_R)
3604 host = gethostbyname_r(addr, &hostent, soap->buf, SOAP_BUFLEN, &soap->errnum);
3605 #elif defined(VXWORKS)
3606 /* If the DNS resolver library resolvLib has been configured in the vxWorks
3607 * image, a query for the host IP address is sent to the DNS server, if the
3608 * name was not found in the local host table. */
3609 hostint = hostGetByName((char*)addr);
3610 if (hostint == ERROR)
3611 { host = NULL;
3612 soap->errnum = soap_errno;
3614 #else
3615 #ifdef AS400
3616 if (!(host = gethostbyname((void*)addr)))
3617 soap->errnum = h_errno;
3618 #else
3619 if (!(host = gethostbyname(addr)))
3620 soap->errnum = h_errno;
3621 #endif
3622 #endif
3623 if (!host)
3624 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Host name not found\n"));
3625 return SOAP_ERR;
3627 #ifdef VXWORKS
3628 inaddr->s_addr = hostint;
3629 #else
3630 memcpy(inaddr, host->h_addr, host->h_length);
3631 #endif
3632 return SOAP_OK;
3634 #endif
3635 #endif
3636 #endif
3638 /******************************************************************************/
3639 #ifndef WITH_NOIO
3640 #ifndef PALM_1
3641 static SOAP_SOCKET
3642 tcp_connect(struct soap *soap, const char *endpoint, const char *host, int port)
3644 #ifdef WITH_IPV6
3645 struct addrinfo hints, *res, *ressave;
3646 #endif
3647 SOAP_SOCKET fd;
3648 int err = 0;
3649 #ifndef WITH_LEAN
3650 #ifndef WITH_WIN32
3651 int len = SOAP_BUFLEN;
3652 #else
3653 int len = SOAP_BUFLEN + 1; /* speeds up windows xfer */
3654 #endif
3655 int set = 1;
3656 #endif
3657 #if !defined(WITH_LEAN) || defined(WITH_OPENSSL) || defined(WITH_GNUTLS)
3658 int retries;
3659 #endif
3660 if (soap_valid_socket(soap->socket))
3661 soap->fclosesocket(soap, soap->socket);
3662 soap->socket = SOAP_INVALID_SOCKET;
3663 if (tcp_init(soap))
3664 { soap->errnum = 0;
3665 soap_set_sender_error(soap, tcp_error(soap), "TCP init failed in tcp_connect()", SOAP_TCP_ERROR);
3666 return SOAP_INVALID_SOCKET;
3668 soap->errmode = 0;
3669 #ifdef WITH_IPV6
3670 memset((void*)&hints, 0, sizeof(hints));
3671 hints.ai_family = PF_UNSPEC;
3672 #ifndef WITH_LEAN
3673 if ((soap->omode & SOAP_IO_UDP))
3674 hints.ai_socktype = SOCK_DGRAM;
3675 else
3676 #endif
3677 hints.ai_socktype = SOCK_STREAM;
3678 soap->errmode = 2;
3679 if (soap->proxy_host)
3680 err = getaddrinfo(soap->proxy_host, soap_int2s(soap, soap->proxy_port), &hints, &res);
3681 else
3682 err = getaddrinfo(host, soap_int2s(soap, port), &hints, &res);
3683 if (err)
3684 { soap_set_sender_error(soap, SOAP_GAI_STRERROR(err), "getaddrinfo failed in tcp_connect()", SOAP_TCP_ERROR);
3685 return SOAP_INVALID_SOCKET;
3687 ressave = res;
3688 again:
3689 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
3690 soap->errmode = 0;
3691 #else
3692 #ifndef WITH_LEAN
3693 again:
3694 #endif
3695 #ifndef WITH_LEAN
3696 if ((soap->omode & SOAP_IO_UDP))
3697 fd = socket(AF_INET, SOCK_DGRAM, 0);
3698 else
3699 #endif
3700 fd = socket(AF_INET, SOCK_STREAM, 0);
3701 #endif
3702 if (!soap_valid_socket(fd))
3704 #ifdef WITH_IPV6
3705 if (res->ai_next)
3706 { res = res->ai_next;
3707 goto again;
3709 #endif
3710 soap->errnum = soap_socket_errno(fd);
3711 soap_set_sender_error(soap, tcp_error(soap), "socket failed in tcp_connect()", SOAP_TCP_ERROR);
3712 #ifdef WITH_IPV6
3713 freeaddrinfo(ressave);
3714 #endif
3715 return SOAP_INVALID_SOCKET;
3717 #ifdef SOCKET_CLOSE_ON_EXEC
3718 #ifdef WIN32
3719 #ifndef UNDER_CE
3720 SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0);
3721 #endif
3722 #else
3723 fcntl(fd, F_SETFD, 1);
3724 #endif
3725 #endif
3726 #ifndef WITH_LEAN
3727 if (soap->connect_flags == SO_LINGER)
3728 { struct linger linger;
3729 memset((void*)&linger, 0, sizeof(linger));
3730 linger.l_onoff = 1;
3731 linger.l_linger = soap->linger_time;
3732 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(struct linger)))
3733 { soap->errnum = soap_socket_errno(fd);
3734 soap_set_sender_error(soap, tcp_error(soap), "setsockopt SO_LINGER failed in tcp_connect()", SOAP_TCP_ERROR);
3735 soap->fclosesocket(soap, fd);
3736 #ifdef WITH_IPV6
3737 freeaddrinfo(ressave);
3738 #endif
3739 return SOAP_INVALID_SOCKET;
3742 else if (soap->connect_flags && setsockopt(fd, SOL_SOCKET, soap->connect_flags, (char*)&set, sizeof(int)))
3743 { soap->errnum = soap_socket_errno(fd);
3744 soap_set_sender_error(soap, tcp_error(soap), "setsockopt failed in tcp_connect()", SOAP_TCP_ERROR);
3745 soap->fclosesocket(soap, fd);
3746 #ifdef WITH_IPV6
3747 freeaddrinfo(ressave);
3748 #endif
3749 return SOAP_INVALID_SOCKET;
3751 if ((soap->keep_alive || soap->tcp_keep_alive) && setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&set, sizeof(int)))
3752 { soap->errnum = soap_socket_errno(fd);
3753 soap_set_sender_error(soap, tcp_error(soap), "setsockopt SO_KEEPALIVE failed in tcp_connect()", SOAP_TCP_ERROR);
3754 soap->fclosesocket(soap, fd);
3755 #ifdef WITH_IPV6
3756 freeaddrinfo(ressave);
3757 #endif
3758 return SOAP_INVALID_SOCKET;
3760 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int)))
3761 { soap->errnum = soap_socket_errno(fd);
3762 soap_set_sender_error(soap, tcp_error(soap), "setsockopt SO_SNDBUF failed in tcp_connect()", SOAP_TCP_ERROR);
3763 soap->fclosesocket(soap, fd);
3764 #ifdef WITH_IPV6
3765 freeaddrinfo(ressave);
3766 #endif
3767 return SOAP_INVALID_SOCKET;
3769 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int)))
3770 { soap->errnum = soap_socket_errno(fd);
3771 soap_set_sender_error(soap, tcp_error(soap), "setsockopt SO_RCVBUF failed in tcp_connect()", SOAP_TCP_ERROR);
3772 soap->fclosesocket(soap, fd);
3773 #ifdef WITH_IPV6
3774 freeaddrinfo(ressave);
3775 #endif
3776 return SOAP_INVALID_SOCKET;
3778 #ifdef TCP_KEEPIDLE
3779 if (soap->tcp_keep_idle && setsockopt((SOAP_SOCKET)fd, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&(soap->tcp_keep_idle), sizeof(int)))
3780 { soap->errnum = soap_socket_errno(fd);
3781 soap_set_sender_error(soap, tcp_error(soap), "setsockopt TCP_KEEPIDLE failed in tcp_connect()", SOAP_TCP_ERROR);
3782 soap->fclosesocket(soap, (SOAP_SOCKET)fd);
3783 #ifdef WITH_IPV6
3784 freeaddrinfo(ressave);
3785 #endif
3786 return SOAP_INVALID_SOCKET;
3788 #endif
3789 #ifdef TCP_KEEPINTVL
3790 if (soap->tcp_keep_intvl && setsockopt((SOAP_SOCKET)fd, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&(soap->tcp_keep_intvl), sizeof(int)))
3791 { soap->errnum = soap_socket_errno(fd);
3792 soap_set_sender_error(soap, tcp_error(soap), "setsockopt TCP_KEEPINTVL failed in tcp_connect()", SOAP_TCP_ERROR);
3793 soap->fclosesocket(soap, (SOAP_SOCKET)fd);
3794 #ifdef WITH_IPV6
3795 freeaddrinfo(ressave);
3796 #endif
3797 return SOAP_INVALID_SOCKET;
3799 #endif
3800 #ifdef TCP_KEEPCNT
3801 if (soap->tcp_keep_cnt && setsockopt((SOAP_SOCKET)fd, IPPROTO_TCP, TCP_KEEPCNT, (char*)&(soap->tcp_keep_cnt), sizeof(int)))
3802 { soap->errnum = soap_socket_errno(fd);
3803 soap_set_sender_error(soap, tcp_error(soap), "setsockopt TCP_KEEPCNT failed in tcp_connect()", SOAP_TCP_ERROR);
3804 soap->fclosesocket(soap, (SOAP_SOCKET)fd);
3805 #ifdef WITH_IPV6
3806 freeaddrinfo(ressave);
3807 #endif
3808 return SOAP_INVALID_SOCKET;
3810 #endif
3811 #ifdef TCP_NODELAY
3812 if (!(soap->omode & SOAP_IO_UDP) && setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&set, sizeof(int)))
3813 { soap->errnum = soap_socket_errno(fd);
3814 soap_set_sender_error(soap, tcp_error(soap), "setsockopt TCP_NODELAY failed in tcp_connect()", SOAP_TCP_ERROR);
3815 soap->fclosesocket(soap, fd);
3816 #ifdef WITH_IPV6
3817 freeaddrinfo(ressave);
3818 #endif
3819 return SOAP_INVALID_SOCKET;
3821 #endif
3822 #ifdef WITH_IPV6
3823 if ((soap->omode & SOAP_IO_UDP) && soap->ipv6_multicast_if)
3824 { struct sockaddr_in6 *in6addr = (struct sockaddr_in6*)res->ai_addr;
3825 in6addr->sin6_scope_id = soap->ipv6_multicast_if;
3827 #endif
3828 #ifdef IP_MULTICAST_TTL
3829 if ((soap->omode & SOAP_IO_UDP) && soap->ipv4_multicast_if && !soap->ipv6_multicast_if)
3830 { if (soap->ipv4_multicast_ttl > 0)
3831 { char ttl = (char)(soap->ipv4_multicast_ttl);
3832 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl)))
3833 { soap->errnum = soap_socket_errno(fd);
3834 soap_set_sender_error(soap, tcp_error(soap), "setsockopt IP_MULTICAST_TTL failed in tcp_connect()", SOAP_TCP_ERROR);
3835 soap->fclosesocket(soap, fd);
3836 return SOAP_INVALID_SOCKET;
3839 #ifndef WINDOWS
3840 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char*)soap->ipv4_multicast_if, sizeof(struct in_addr)))
3841 { soap->errnum = soap_socket_errno(fd);
3842 soap_set_sender_error(soap, tcp_error(soap), "setsockopt IP_MULTICAST_IF failed in tcp_connect()", SOAP_TCP_ERROR);
3843 soap->fclosesocket(soap, fd);
3844 return SOAP_INVALID_SOCKET;
3846 #else
3847 #ifndef IP_MULTICAST_IF
3848 #define IP_MULTICAST_IF 2
3849 #endif
3850 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char*)soap->ipv4_multicast_if, sizeof(struct in_addr)))
3851 { soap->errnum = soap_socket_errno(fd);
3852 soap_set_sender_error(soap, tcp_error(soap), "setsockopt IP_MULTICAST_IF failed in tcp_connect()", SOAP_TCP_ERROR);
3853 soap->fclosesocket(soap, fd);
3854 return SOAP_INVALID_SOCKET;
3856 #endif
3858 #endif
3859 #endif
3860 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Opening socket %d to host='%s' port=%d\n", fd, host, port));
3861 #ifndef WITH_IPV6
3862 soap->peerlen = sizeof(soap->peer);
3863 memset((void*)&soap->peer, 0, sizeof(soap->peer));
3864 soap->peer.sin_family = AF_INET;
3865 soap->errmode = 2;
3866 if (soap->proxy_host)
3867 { if (soap->fresolve(soap, soap->proxy_host, &soap->peer.sin_addr))
3868 { soap_set_sender_error(soap, tcp_error(soap), "get proxy host by name failed in tcp_connect()", SOAP_TCP_ERROR);
3869 soap->fclosesocket(soap, fd);
3870 return SOAP_INVALID_SOCKET;
3872 soap->peer.sin_port = htons((short)soap->proxy_port);
3874 else
3875 { if (soap->fresolve(soap, host, &soap->peer.sin_addr))
3876 { soap_set_sender_error(soap, tcp_error(soap), "get host by name failed in tcp_connect()", SOAP_TCP_ERROR);
3877 soap->fclosesocket(soap, fd);
3878 return SOAP_INVALID_SOCKET;
3880 soap->peer.sin_port = htons((short)port);
3882 soap->errmode = 0;
3883 #ifndef WITH_LEAN
3884 if ((soap->omode & SOAP_IO_UDP))
3885 return fd;
3886 #endif
3887 #else
3888 if ((soap->omode & SOAP_IO_UDP))
3889 { memcpy(&soap->peer, res->ai_addr, res->ai_addrlen);
3890 soap->peerlen = res->ai_addrlen;
3891 freeaddrinfo(ressave);
3892 return fd;
3894 #endif
3895 #ifndef WITH_LEAN
3896 if (soap->connect_timeout)
3897 SOAP_SOCKNONBLOCK(fd)
3898 else
3899 SOAP_SOCKBLOCK(fd)
3900 retries = 10;
3901 #endif
3902 for (;;)
3904 #ifdef WITH_IPV6
3905 if (connect(fd, res->ai_addr, (int)res->ai_addrlen))
3906 #else
3907 if (connect(fd, (struct sockaddr*)&soap->peer, sizeof(soap->peer)))
3908 #endif
3909 { err = soap_socket_errno(fd);
3910 #ifndef WITH_LEAN
3911 if (err == SOAP_EADDRINUSE)
3912 { soap->fclosesocket(soap, fd);
3913 if (retries-- > 0)
3914 goto again;
3916 else if (soap->connect_timeout && (err == SOAP_EINPROGRESS || err == SOAP_EAGAIN || err == SOAP_EWOULDBLOCK))
3918 SOAP_SOCKLEN_T k;
3919 for (;;)
3920 { register int r;
3921 r = tcp_select(soap, fd, SOAP_TCP_SELECT_SND, soap->connect_timeout);
3922 if (r > 0)
3923 break;
3924 if (!r)
3925 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Connect timeout\n"));
3926 soap_set_sender_error(soap, "Timeout", "connect failed in tcp_connect()", SOAP_TCP_ERROR);
3927 soap->fclosesocket(soap, fd);
3928 #ifdef WITH_IPV6
3929 freeaddrinfo(ressave);
3930 #endif
3931 return SOAP_INVALID_SOCKET;
3933 r = soap->errnum;
3934 if (r != SOAP_EINTR)
3935 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not connect to host\n"));
3936 soap_set_sender_error(soap, tcp_error(soap), "connect failed in tcp_connect()", SOAP_TCP_ERROR);
3937 soap->fclosesocket(soap, fd);
3938 #ifdef WITH_IPV6
3939 freeaddrinfo(ressave);
3940 #endif
3941 return SOAP_INVALID_SOCKET;
3944 k = (SOAP_SOCKLEN_T)sizeof(soap->errnum);
3945 if (!getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&soap->errnum, &k) && !soap->errnum) /* portability note: see SOAP_SOCKLEN_T definition in stdsoap2.h */
3946 break;
3947 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not connect to host\n"));
3948 if (!soap->errnum)
3949 soap->errnum = soap_socket_errno(fd);
3950 soap_set_sender_error(soap, tcp_error(soap), "connect failed in tcp_connect()", SOAP_TCP_ERROR);
3951 soap->fclosesocket(soap, fd);
3952 #ifdef WITH_IPV6
3953 freeaddrinfo(ressave);
3954 #endif
3955 return SOAP_INVALID_SOCKET;
3957 #endif
3958 #ifdef WITH_IPV6
3959 if (res->ai_next)
3960 { res = res->ai_next;
3961 soap->fclosesocket(soap, fd);
3962 goto again;
3964 #endif
3965 if (err && err != SOAP_EINTR)
3966 { soap->errnum = err;
3967 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not connect to host\n"));
3968 soap_set_sender_error(soap, tcp_error(soap), "connect failed in tcp_connect()", SOAP_TCP_ERROR);
3969 soap->fclosesocket(soap, fd);
3970 #ifdef WITH_IPV6
3971 freeaddrinfo(ressave);
3972 #endif
3973 return SOAP_INVALID_SOCKET;
3976 else
3977 break;
3979 #ifdef WITH_IPV6
3980 soap->peerlen = 0; /* IPv6: already connected so use send() */
3981 freeaddrinfo(ressave);
3982 #endif
3983 soap->socket = fd;
3984 soap->imode &= ~SOAP_ENC_SSL;
3985 soap->omode &= ~SOAP_ENC_SSL;
3986 if (!soap_tag_cmp(endpoint, "https:*"))
3988 #if defined(WITH_OPENSSL) || defined(WITH_GNUTLS)
3989 #ifdef WITH_OPENSSL
3990 BIO *bio;
3991 #endif
3992 int r;
3993 if (soap->proxy_host)
3994 { soap_mode m = soap->mode; /* preserve settings */
3995 soap_mode om = soap->omode; /* make sure we only parse HTTP */
3996 size_t n = soap->count; /* save the content length */
3997 const char *userid, *passwd;
3998 soap->omode &= ~SOAP_ENC; /* mask IO and ENC */
3999 soap->omode |= SOAP_IO_BUFFER;
4000 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Connecting to %s proxy server\n", soap->proxy_http_version));
4001 sprintf(soap->tmpbuf, "CONNECT %s:%d HTTP/%s", host, port, soap->proxy_http_version);
4002 if (soap_begin_send(soap)
4003 || (soap->error = soap->fposthdr(soap, soap->tmpbuf, NULL)))
4004 { soap->fclosesocket(soap, fd);
4005 return SOAP_INVALID_SOCKET;
4007 #ifndef WITH_LEAN
4008 if (soap->proxy_userid && soap->proxy_passwd && strlen(soap->proxy_userid) + strlen(soap->proxy_passwd) < 761)
4009 { sprintf(soap->tmpbuf + 262, "%s:%s", soap->proxy_userid, soap->proxy_passwd);
4010 strcpy(soap->tmpbuf, "Basic ");
4011 soap_s2base64(soap, (const unsigned char*)(soap->tmpbuf + 262), soap->tmpbuf + 6, (int)strlen(soap->tmpbuf + 262));
4012 if ((soap->error = soap->fposthdr(soap, "Proxy-Authorization", soap->tmpbuf)))
4013 { soap->fclosesocket(soap, fd);
4014 return soap->error;
4017 #endif
4018 if ((soap->error = soap->fposthdr(soap, NULL, NULL))
4019 || soap_flush(soap))
4020 { soap->fclosesocket(soap, fd);
4021 return SOAP_INVALID_SOCKET;
4023 soap->omode = om;
4024 om = soap->imode;
4025 soap->imode &= ~SOAP_ENC; /* mask IO and ENC */
4026 userid = soap->userid; /* preserve */
4027 passwd = soap->passwd; /* preserve */
4028 if ((soap->error = soap->fparse(soap)))
4029 { soap->fclosesocket(soap, fd);
4030 return SOAP_INVALID_SOCKET;
4032 soap->userid = userid; /* restore */
4033 soap->passwd = passwd; /* restore */
4034 soap->imode = om; /* restore */
4035 soap->count = n; /* restore */
4036 if (soap_begin_send(soap))
4037 { soap->fclosesocket(soap, fd);
4038 return SOAP_INVALID_SOCKET;
4040 if (endpoint)
4041 strncpy(soap->endpoint, endpoint, sizeof(soap->endpoint)-1); /* restore */
4042 soap->mode = m;
4044 #ifdef WITH_OPENSSL
4045 soap->ssl_flags |= SOAP_SSL_CLIENT;
4046 if (!soap->ctx && (soap->error = soap->fsslauth(soap)))
4047 { soap->fclosesocket(soap, fd);
4048 return SOAP_INVALID_SOCKET;
4050 if (!soap->ssl)
4051 { soap->ssl = SSL_new(soap->ctx);
4052 if (!soap->ssl)
4053 { soap->fclosesocket(soap, fd);
4054 soap->error = SOAP_SSL_ERROR;
4055 return SOAP_INVALID_SOCKET;
4058 else
4059 SSL_clear(soap->ssl);
4060 if (soap->session)
4061 { if (!strcmp(soap->session_host, host) && soap->session_port == port)
4062 SSL_set_session(soap->ssl, soap->session);
4063 SSL_SESSION_free(soap->session);
4064 soap->session = NULL;
4066 soap->imode |= SOAP_ENC_SSL;
4067 soap->omode |= SOAP_ENC_SSL;
4068 bio = BIO_new_socket((int)fd, BIO_NOCLOSE);
4069 SSL_set_bio(soap->ssl, bio, bio);
4070 /* Connect timeout: set SSL sockets to non-blocking */
4071 retries = 0;
4072 if (soap->connect_timeout)
4073 { SOAP_SOCKNONBLOCK(fd)
4074 retries = 10*soap->connect_timeout;
4076 else
4077 SOAP_SOCKBLOCK(fd)
4078 if (retries <= 0)
4079 retries = 100; /* timeout: 10 sec retries, 100 times 0.1 sec */
4080 /* Try connecting until success or timeout (when nonblocking) */
4082 { if ((r = SSL_connect(soap->ssl)) <= 0)
4083 { int err = SSL_get_error(soap->ssl, r);
4084 if (err == SSL_ERROR_WANT_CONNECT || err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
4085 { register int s;
4086 if (err == SSL_ERROR_WANT_READ)
4087 s = tcp_select(soap, fd, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, -100000);
4088 else
4089 s = tcp_select(soap, fd, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, -100000);
4090 if (s < 0 && soap->errnum != SOAP_EINTR)
4091 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "SSL_connect/select error in tcp_connect\n"));
4092 soap_set_sender_error(soap, soap_ssl_error(soap, r), "SSL_connect failed in tcp_connect()", SOAP_TCP_ERROR);
4093 soap->fclosesocket(soap, fd);
4094 return SOAP_INVALID_SOCKET;
4096 if (s == 0 && retries-- <= 0)
4097 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "SSL/TLS connect timeout\n"));
4098 soap_set_sender_error(soap, "Timeout", "SSL_connect failed in tcp_connect()", SOAP_TCP_ERROR);
4099 soap->fclosesocket(soap, fd);
4100 return SOAP_INVALID_SOCKET;
4103 else
4104 { soap_set_sender_error(soap, soap_ssl_error(soap, r), "SSL_connect error in tcp_connect()", SOAP_SSL_ERROR);
4105 soap->fclosesocket(soap, fd);
4106 return SOAP_INVALID_SOCKET;
4109 } while (!SSL_is_init_finished(soap->ssl));
4110 /* Set SSL sockets to nonblocking */
4111 SOAP_SOCKNONBLOCK(fd)
4112 /* Check server credentials when required */
4113 if ((soap->ssl_flags & SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION))
4114 { int err;
4115 if ((err = SSL_get_verify_result(soap->ssl)) != X509_V_OK)
4116 { soap_set_sender_error(soap, X509_verify_cert_error_string(err), "SSL/TLS certificate presented by peer cannot be verified in tcp_connect()", SOAP_SSL_ERROR);
4117 soap->fclosesocket(soap, fd);
4118 return SOAP_INVALID_SOCKET;
4120 if (!(soap->ssl_flags & SOAP_SSL_SKIP_HOST_CHECK))
4121 { X509_NAME *subj;
4122 int ext_count;
4123 int ok = 0;
4124 X509 *peer;
4125 peer = SSL_get_peer_certificate(soap->ssl);
4126 if (!peer)
4127 { soap_set_sender_error(soap, "SSL/TLS error", "No SSL/TLS certificate was presented by the peer in tcp_connect()", SOAP_SSL_ERROR);
4128 soap->fclosesocket(soap, fd);
4129 return SOAP_INVALID_SOCKET;
4131 ext_count = X509_get_ext_count(peer);
4132 if (ext_count > 0)
4133 { int i;
4134 for (i = 0; i < ext_count; i++)
4135 { X509_EXTENSION *ext = X509_get_ext(peer, i);
4136 const char *ext_str = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
4137 if (ext_str && !strcmp(ext_str, "subjectAltName"))
4138 { X509V3_EXT_METHOD *meth = (X509V3_EXT_METHOD*)X509V3_EXT_get(ext);
4139 void *ext_data;
4140 #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
4141 const unsigned char *data;
4142 #else
4143 unsigned char *data;
4144 #endif
4145 STACK_OF(CONF_VALUE) *val;
4146 int j;
4147 if (!meth)
4148 break;
4149 data = ext->value->data;
4150 #if (OPENSSL_VERSION_NUMBER > 0x00907000L)
4151 if (meth->it)
4152 ext_data = ASN1_item_d2i(NULL, &data, ext->value->length, ASN1_ITEM_ptr(meth->it));
4153 else
4154 { /* OpenSSL not perfectly portable at this point (?):
4155 Some compilers appear to prefer
4156 meth->d2i(NULL, (const unsigned char**)&data, ...
4157 and others prefer
4158 meth->d2i(NULL, &data, ext->value->length);
4160 ext_data = meth->d2i(NULL, &data, ext->value->length);
4162 #else
4163 ext_data = meth->d2i(NULL, &data, ext->value->length);
4164 #endif
4165 if (ext_data)
4166 { val = meth->i2v(meth, ext_data, NULL);
4167 if (val)
4168 { for (j = 0; j < sk_CONF_VALUE_num(val); j++)
4169 { CONF_VALUE *nval = sk_CONF_VALUE_value(val, j);
4170 if (nval && !strcmp(nval->name, "DNS") && !strcmp(nval->value, host))
4171 { ok = 1;
4172 break;
4175 sk_CONF_VALUE_pop_free(val, X509V3_conf_free);
4177 #if (OPENSSL_VERSION_NUMBER > 0x00907000L)
4178 if (meth->it)
4179 ASN1_item_free((ASN1_VALUE*)ext_data, ASN1_ITEM_ptr(meth->it));
4180 else
4181 meth->ext_free(ext_data);
4182 #else
4183 meth->ext_free(ext_data);
4184 #endif
4187 if (ok)
4188 break;
4191 if (!ok && (subj = X509_get_subject_name(peer)))
4192 { int i = -1;
4194 { ASN1_STRING *name;
4195 i = X509_NAME_get_index_by_NID(subj, NID_commonName, i);
4196 if (i == -1)
4197 break;
4198 name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subj, i));
4199 if (name)
4200 { if (!soap_tag_cmp(host, (const char*)M_ASN1_STRING_data(name)))
4201 ok = 1;
4202 else
4203 { unsigned char *tmp = NULL;
4204 ASN1_STRING_to_UTF8(&tmp, name);
4205 if (tmp)
4206 { if (!soap_tag_cmp(host, (const char*)tmp))
4207 ok = 1;
4208 OPENSSL_free(tmp);
4212 } while (!ok);
4214 X509_free(peer);
4215 if (!ok)
4216 { soap_set_sender_error(soap, "SSL/TLS error", "SSL/TLS certificate host name mismatch in tcp_connect()", SOAP_SSL_ERROR);
4217 soap->fclosesocket(soap, fd);
4218 return SOAP_INVALID_SOCKET;
4222 #endif
4223 #ifdef WITH_GNUTLS
4224 soap->ssl_flags |= SOAP_SSL_CLIENT;
4225 if (!soap->session && (soap->error = soap->fsslauth(soap)))
4226 { soap->fclosesocket(soap, fd);
4227 return SOAP_INVALID_SOCKET;
4229 gnutls_transport_set_ptr(soap->session, (gnutls_transport_ptr_t)(long)fd);
4230 /* Set SSL sockets to non-blocking */
4231 if (soap->connect_timeout)
4232 { SOAP_SOCKNONBLOCK(fd)
4233 retries = 10*soap->connect_timeout;
4235 else
4236 SOAP_SOCKBLOCK(fd)
4237 if (retries <= 0)
4238 retries = 100; /* timeout: 10 sec retries, 100 times 0.1 sec */
4239 while ((r = gnutls_handshake(soap->session)))
4240 { int s;
4241 /* GNUTLS repeat handhake when GNUTLS_E_AGAIN */
4242 if (retries-- <= 0)
4243 break;
4244 if (r == GNUTLS_E_AGAIN || r == GNUTLS_E_INTERRUPTED)
4245 { if (!gnutls_record_get_direction(soap->session))
4246 s = tcp_select(soap, fd, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, -100000);
4247 else
4248 s = tcp_select(soap, fd, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, -100000);
4249 if (s < 0 && soap->errnum != SOAP_EINTR)
4250 break;
4252 else
4253 { soap->errnum = soap_socket_errno(fd);
4254 break;
4257 if (r)
4258 { soap_set_sender_error(soap, soap_ssl_error(soap, r), "SSL/TLS handshake failed", SOAP_SSL_ERROR);
4259 soap->fclosesocket(soap, fd);
4260 return SOAP_INVALID_SOCKET;
4262 if ((soap->ssl_flags & SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION))
4263 { const char *err = ssl_verify(soap, host);
4264 if (err)
4265 { soap->fclosesocket(soap, fd);
4266 soap->error = soap_set_sender_error(soap, "SSL/TLS error", err, SOAP_SSL_ERROR);
4267 return SOAP_INVALID_SOCKET;
4270 #endif
4271 #else
4272 soap->fclosesocket(soap, fd);
4273 soap->error = SOAP_SSL_ERROR;
4274 return SOAP_INVALID_SOCKET;
4275 #endif
4277 if (soap->recv_timeout || soap->send_timeout)
4278 SOAP_SOCKNONBLOCK(fd)
4279 else
4280 SOAP_SOCKBLOCK(fd)
4281 return fd;
4283 #endif
4284 #endif
4286 /******************************************************************************/
4287 #ifndef WITH_NOIO
4288 #ifndef PALM_1
4289 static int
4290 tcp_select(struct soap *soap, SOAP_SOCKET s, int flags, int timeout)
4291 { register int r;
4292 struct timeval tv;
4293 fd_set fd[3], *rfd, *sfd, *efd;
4294 soap->errnum = 0;
4295 #ifndef WIN32
4296 /* if fd max set size exceeded, use poll() when available */
4297 #if defined(__QNX__) || defined(QNX) /* select() is not MT safe on some QNX */
4298 if (1)
4299 #else
4300 if ((int)s >= (int)FD_SETSIZE)
4301 #endif
4302 #ifdef HAVE_POLL
4303 { struct pollfd pollfd;
4304 int retries = 0;
4305 pollfd.fd = (int)s;
4306 pollfd.events = 0;
4307 if (flags & SOAP_TCP_SELECT_RCV)
4308 pollfd.events |= POLLIN;
4309 if (flags & SOAP_TCP_SELECT_SND)
4310 pollfd.events |= POLLOUT;
4311 if (flags & SOAP_TCP_SELECT_ERR)
4312 pollfd.events |= POLLERR;
4313 if (timeout < 0)
4314 timeout /= -1000; /* -usec -> ms */
4315 else if (timeout <= 1000000) /* avoid overflow */
4316 timeout *= 1000; /* sec -> ms */
4317 else
4318 { retries = timeout / 1000000;
4319 timeout = 1000000000;
4321 do r = poll(&pollfd, 1, timeout);
4322 while (r == 0 && retries--);
4323 if (r > 0)
4324 { r = 0;
4325 if ((flags & SOAP_TCP_SELECT_RCV) && (pollfd.revents & POLLIN))
4326 r |= SOAP_TCP_SELECT_RCV;
4327 if ((flags & SOAP_TCP_SELECT_SND) && (pollfd.revents & POLLOUT))
4328 r |= SOAP_TCP_SELECT_SND;
4329 if ((flags & SOAP_TCP_SELECT_ERR) && (pollfd.revents & POLLERR))
4330 r |= SOAP_TCP_SELECT_ERR;
4332 else if (r < 0)
4333 soap->errnum = soap_socket_errno(s);
4334 return r;
4336 #else
4337 { soap->error = SOAP_FD_EXCEEDED;
4338 return -1;
4340 #endif
4341 #endif
4342 rfd = sfd = efd = NULL;
4343 if (flags & SOAP_TCP_SELECT_RCV)
4344 { rfd = &fd[0];
4345 FD_ZERO(rfd);
4346 FD_SET(s, rfd);
4348 if (flags & SOAP_TCP_SELECT_SND)
4349 { sfd = &fd[1];
4350 FD_ZERO(sfd);
4351 FD_SET(s, sfd);
4353 if (flags & SOAP_TCP_SELECT_ERR)
4354 { efd = &fd[2];
4355 FD_ZERO(efd);
4356 FD_SET(s, efd);
4358 if (timeout >= 0)
4359 { tv.tv_sec = timeout;
4360 tv.tv_usec = 0;
4362 else
4363 { tv.tv_sec = -timeout / 1000000;
4364 tv.tv_usec = -timeout % 1000000;
4366 r = select((int)s + 1, rfd, sfd, efd, &tv);
4367 if (r > 0)
4368 { r = 0;
4369 if ((flags & SOAP_TCP_SELECT_RCV) && FD_ISSET(s, rfd))
4370 r |= SOAP_TCP_SELECT_RCV;
4371 if ((flags & SOAP_TCP_SELECT_SND) && FD_ISSET(s, sfd))
4372 r |= SOAP_TCP_SELECT_SND;
4373 if ((flags & SOAP_TCP_SELECT_ERR) && FD_ISSET(s, efd))
4374 r |= SOAP_TCP_SELECT_ERR;
4376 else if (r < 0)
4377 soap->errnum = soap_socket_errno(s);
4378 return r;
4380 #endif
4381 #endif
4383 /******************************************************************************/
4384 #ifndef WITH_NOIO
4385 #ifndef PALM_1
4386 static SOAP_SOCKET
4387 tcp_accept(struct soap *soap, SOAP_SOCKET s, struct sockaddr *a, int *n)
4388 { SOAP_SOCKET fd;
4389 fd = accept(s, a, (SOAP_SOCKLEN_T*)n); /* portability note: see SOAP_SOCKLEN_T definition in stdsoap2.h */
4390 #ifdef SOCKET_CLOSE_ON_EXEC
4391 #ifdef WIN32
4392 #ifndef UNDER_CE
4393 SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0);
4394 #endif
4395 #else
4396 fcntl(fd, F_SETFD, FD_CLOEXEC);
4397 #endif
4398 #endif
4399 return fd;
4401 #endif
4402 #endif
4404 /******************************************************************************/
4405 #ifndef WITH_NOIO
4406 #ifndef PALM_1
4407 static int
4408 tcp_disconnect(struct soap *soap)
4410 #ifdef WITH_OPENSSL
4411 if (soap->ssl)
4412 { int r, s = 0;
4413 if (soap->session)
4414 { SSL_SESSION_free(soap->session);
4415 soap->session = NULL;
4417 if (*soap->host)
4418 { soap->session = SSL_get1_session(soap->ssl);
4419 if (soap->session)
4420 { strcpy(soap->session_host, soap->host);
4421 soap->session_port = soap->port;
4424 r = SSL_shutdown(soap->ssl);
4425 /* SSL shutdown does not work when reads are pending */
4426 while (SSL_want_read(soap->ssl))
4427 { SSL_read(soap->ssl, NULL, 0);
4428 if (soap_socket_errno(soap->socket) != SOAP_EAGAIN)
4429 { r = SSL_shutdown(soap->ssl);
4430 break;
4433 if (r == 0)
4434 { if (soap_valid_socket(soap->socket))
4435 { if (!soap->fshutdownsocket(soap, soap->socket, SOAP_SHUT_WR))
4437 #ifndef WITH_LEAN
4439 wait up to 10 seconds for close_notify to be sent by peer (if peer not
4440 present, this avoids calling SSL_shutdown() which has a lengthy return
4441 timeout)
4443 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, 10);
4444 if (r <= 0 && soap->errnum != SOAP_EINTR)
4445 { soap->errnum = 0;
4446 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Connection lost...\n"));
4447 soap->fclosesocket(soap, soap->socket);
4448 soap->socket = SOAP_INVALID_SOCKET;
4449 ERR_remove_state(0);
4450 return SOAP_OK;
4452 #else
4453 r = SSL_shutdown(soap->ssl);
4454 #endif
4458 if (r != 1)
4459 { s = ERR_get_error();
4460 if (s)
4461 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Shutdown failed: %d\n", SSL_get_error(soap->ssl, r)));
4462 if (soap_valid_socket(soap->socket) && !(soap->omode & SOAP_IO_UDP))
4463 { soap->fclosesocket(soap, soap->socket);
4464 soap->socket = SOAP_INVALID_SOCKET;
4468 SSL_free(soap->ssl);
4469 soap->ssl = NULL;
4470 if (s)
4471 return SOAP_SSL_ERROR;
4472 ERR_remove_state(0);
4474 #endif
4475 #ifdef WITH_GNUTLS
4476 if (soap->session)
4477 { gnutls_bye(soap->session, GNUTLS_SHUT_RDWR);
4478 gnutls_deinit(soap->session);
4479 soap->session = NULL;
4481 #endif
4482 if (soap_valid_socket(soap->socket) && !(soap->omode & SOAP_IO_UDP))
4483 { soap->fshutdownsocket(soap, soap->socket, SOAP_SHUT_RDWR);
4484 soap->fclosesocket(soap, soap->socket);
4485 soap->socket = SOAP_INVALID_SOCKET;
4487 return SOAP_OK;
4489 #endif
4490 #endif
4492 /******************************************************************************/
4493 #ifndef WITH_NOIO
4494 #ifndef PALM_1
4495 static int
4496 tcp_closesocket(struct soap *soap, SOAP_SOCKET fd)
4497 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Close socket %d\n", (int)fd));
4498 return soap_closesocket(fd);
4500 #endif
4501 #endif
4503 /******************************************************************************/
4504 #ifndef WITH_NOIO
4505 #ifndef PALM_1
4506 static int
4507 tcp_shutdownsocket(struct soap *soap, SOAP_SOCKET fd, int how)
4508 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Shutdown socket %d how=%d\n", (int)fd, how));
4509 return shutdown(fd, how);
4511 #endif
4512 #endif
4514 /******************************************************************************/
4515 #ifndef WITH_NOIO
4516 #ifndef PALM_1
4517 SOAP_FMAC1
4518 SOAP_SOCKET
4519 SOAP_FMAC2
4520 soap_bind(struct soap *soap, const char *host, int port, int backlog)
4522 #ifdef WITH_IPV6
4523 struct addrinfo *addrinfo = NULL;
4524 struct addrinfo hints;
4525 struct addrinfo res;
4526 int err;
4527 #ifdef WITH_NO_IPV6_V6ONLY
4528 int unset = 0;
4529 #endif
4530 #endif
4531 #ifndef WITH_LEAN
4532 #ifndef WITH_WIN32
4533 int len = SOAP_BUFLEN;
4534 #else
4535 int len = SOAP_BUFLEN + 1; /* speeds up windows xfer */
4536 #endif
4537 int set = 1;
4538 #endif
4539 if (soap_valid_socket(soap->master))
4540 { soap->fclosesocket(soap, soap->master);
4541 soap->master = SOAP_INVALID_SOCKET;
4543 soap->socket = SOAP_INVALID_SOCKET;
4544 soap->errmode = 1;
4545 if (tcp_init(soap))
4546 { soap_set_receiver_error(soap, tcp_error(soap), "TCP init failed in soap_bind()", SOAP_TCP_ERROR);
4547 return SOAP_INVALID_SOCKET;
4549 #ifdef WITH_IPV6
4550 memset((void*)&hints, 0, sizeof(hints));
4551 hints.ai_family = PF_UNSPEC;
4552 #ifndef WITH_LEAN
4553 if ((soap->omode & SOAP_IO_UDP))
4554 hints.ai_socktype = SOCK_DGRAM;
4555 else
4556 #endif
4557 hints.ai_socktype = SOCK_STREAM;
4558 hints.ai_flags = AI_PASSIVE;
4559 soap->errmode = 2;
4560 err = getaddrinfo(host, soap_int2s(soap, port), &hints, &addrinfo);
4561 if (err || !addrinfo)
4562 { soap_set_receiver_error(soap, SOAP_GAI_STRERROR(err), "getaddrinfo failed in soap_bind()", SOAP_TCP_ERROR);
4563 return SOAP_INVALID_SOCKET;
4565 res = *addrinfo;
4566 memcpy(&soap->peer, addrinfo->ai_addr, addrinfo->ai_addrlen);
4567 soap->peerlen = addrinfo->ai_addrlen;
4568 res.ai_addr = (struct sockaddr*)&soap->peer;
4569 res.ai_addrlen = soap->peerlen;
4570 freeaddrinfo(addrinfo);
4571 soap->master = (int)socket(res.ai_family, res.ai_socktype, res.ai_protocol);
4572 #else
4573 #ifndef WITH_LEAN
4574 if ((soap->omode & SOAP_IO_UDP))
4575 soap->master = (int)socket(AF_INET, SOCK_DGRAM, 0);
4576 else
4577 #endif
4578 soap->master = (int)socket(AF_INET, SOCK_STREAM, 0);
4579 #endif
4580 soap->errmode = 0;
4581 if (!soap_valid_socket(soap->master))
4582 { soap->errnum = soap_socket_errno(soap->master);
4583 soap_set_receiver_error(soap, tcp_error(soap), "socket failed in soap_bind()", SOAP_TCP_ERROR);
4584 return SOAP_INVALID_SOCKET;
4586 #ifndef WITH_LEAN
4587 if ((soap->omode & SOAP_IO_UDP))
4588 soap->socket = soap->master;
4589 #endif
4590 #ifdef SOCKET_CLOSE_ON_EXEC
4591 #ifdef WIN32
4592 #ifndef UNDER_CE
4593 SetHandleInformation((HANDLE)soap->master, HANDLE_FLAG_INHERIT, 0);
4594 #endif
4595 #else
4596 fcntl(soap->master, F_SETFD, 1);
4597 #endif
4598 #endif
4599 #ifndef WITH_LEAN
4600 if (soap->bind_flags && setsockopt(soap->master, SOL_SOCKET, soap->bind_flags, (char*)&set, sizeof(int)))
4601 { soap->errnum = soap_socket_errno(soap->master);
4602 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt failed in soap_bind()", SOAP_TCP_ERROR);
4603 return SOAP_INVALID_SOCKET;
4605 if (((soap->imode | soap->omode) & SOAP_IO_KEEPALIVE) && setsockopt(soap->master, SOL_SOCKET, SO_KEEPALIVE, (char*)&set, sizeof(int)))
4606 { soap->errnum = soap_socket_errno(soap->master);
4607 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt SO_KEEPALIVE failed in soap_bind()", SOAP_TCP_ERROR);
4608 return SOAP_INVALID_SOCKET;
4610 if (setsockopt(soap->master, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int)))
4611 { soap->errnum = soap_socket_errno(soap->master);
4612 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt SO_SNDBUF failed in soap_bind()", SOAP_TCP_ERROR);
4613 return SOAP_INVALID_SOCKET;
4615 if (setsockopt(soap->master, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int)))
4616 { soap->errnum = soap_socket_errno(soap->master);
4617 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt SO_RCVBUF failed in soap_bind()", SOAP_TCP_ERROR);
4618 return SOAP_INVALID_SOCKET;
4620 #ifdef TCP_NODELAY
4621 if (!(soap->omode & SOAP_IO_UDP) && setsockopt(soap->master, IPPROTO_TCP, TCP_NODELAY, (char*)&set, sizeof(int)))
4622 { soap->errnum = soap_socket_errno(soap->master);
4623 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt TCP_NODELAY failed in soap_bind()", SOAP_TCP_ERROR);
4624 return SOAP_INVALID_SOCKET;
4626 #endif
4627 #endif
4628 #ifdef WITH_IPV6
4629 #ifdef WITH_IPV6_V6ONLY
4630 if (setsockopt(soap->master, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&set, sizeof(int)))
4631 { soap->errnum = soap_socket_errno(soap->master);
4632 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt IPV6_V6ONLY failed in soap_bind()", SOAP_TCP_ERROR);
4633 return SOAP_INVALID_SOCKET;
4635 #endif
4636 #ifdef WITH_NO_IPV6_V6ONLY
4637 if (setsockopt(soap->master, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&unset, sizeof(int)))
4638 { soap->errnum = soap_socket_errno(soap->master);
4639 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt IPV6_V6ONLY failed in soap_bind()", SOAP_TCP_ERROR);
4640 return SOAP_INVALID_SOCKET;
4642 #endif
4643 soap->errmode = 0;
4644 if (bind(soap->master, res.ai_addr, (int)res.ai_addrlen))
4645 { soap->errnum = soap_socket_errno(soap->master);
4646 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not bind to host\n"));
4647 soap_closesock(soap);
4648 soap_set_receiver_error(soap, tcp_error(soap), "bind failed in soap_bind()", SOAP_TCP_ERROR);
4649 return SOAP_INVALID_SOCKET;
4651 #else
4652 soap->peerlen = sizeof(soap->peer);
4653 memset((void*)&soap->peer, 0, sizeof(soap->peer));
4654 soap->peer.sin_family = AF_INET;
4655 soap->errmode = 2;
4656 if (host)
4657 { if (soap->fresolve(soap, host, &soap->peer.sin_addr))
4658 { soap_set_receiver_error(soap, tcp_error(soap), "get host by name failed in soap_bind()", SOAP_TCP_ERROR);
4659 return SOAP_INVALID_SOCKET;
4662 else
4663 soap->peer.sin_addr.s_addr = htonl(INADDR_ANY);
4664 soap->peer.sin_port = htons((short)port);
4665 soap->errmode = 0;
4666 if (bind(soap->master, (struct sockaddr*)&soap->peer, (int)soap->peerlen))
4667 { soap->errnum = soap_socket_errno(soap->master);
4668 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not bind to host\n"));
4669 soap_closesock(soap);
4670 soap_set_receiver_error(soap, tcp_error(soap), "bind failed in soap_bind()", SOAP_TCP_ERROR);
4671 return SOAP_INVALID_SOCKET;
4673 #endif
4674 if (!(soap->omode & SOAP_IO_UDP) && listen(soap->master, backlog))
4675 { soap->errnum = soap_socket_errno(soap->master);
4676 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not bind to host\n"));
4677 soap_closesock(soap);
4678 soap_set_receiver_error(soap, tcp_error(soap), "listen failed in soap_bind()", SOAP_TCP_ERROR);
4679 return SOAP_INVALID_SOCKET;
4681 return soap->master;
4683 #endif
4684 #endif
4686 /******************************************************************************/
4687 #ifndef WITH_NOIO
4688 #ifndef PALM_1
4689 SOAP_FMAC1
4691 SOAP_FMAC2
4692 soap_poll(struct soap *soap)
4694 #ifndef WITH_LEAN
4695 register int r;
4696 if (soap_valid_socket(soap->socket))
4697 { r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_ALL, 0);
4698 if (r > 0 && (r & SOAP_TCP_SELECT_ERR))
4699 r = -1;
4701 else if (soap_valid_socket(soap->master))
4702 r = tcp_select(soap, soap->master, SOAP_TCP_SELECT_SND, 0);
4703 else
4704 return SOAP_OK; /* OK when no socket! */
4705 if (r > 0)
4707 #ifdef WITH_OPENSSL
4708 if (soap->imode & SOAP_ENC_SSL)
4710 if (soap_valid_socket(soap->socket)
4711 && (r & SOAP_TCP_SELECT_SND)
4712 && (!(r & SOAP_TCP_SELECT_RCV)
4713 || SSL_peek(soap->ssl, soap->tmpbuf, 1) > 0))
4714 return SOAP_OK;
4716 else
4717 #endif
4718 if (soap_valid_socket(soap->socket)
4719 && (r & SOAP_TCP_SELECT_SND)
4720 && (!(r & SOAP_TCP_SELECT_RCV)
4721 || recv(soap->socket, soap->tmpbuf, 1, MSG_PEEK) > 0))
4722 return SOAP_OK;
4724 else if (r < 0)
4725 { if ((soap_valid_socket(soap->master) || soap_valid_socket(soap->socket)) && soap_socket_errno(soap->master) != SOAP_EINTR)
4726 { soap_set_receiver_error(soap, tcp_error(soap), "select failed in soap_poll()", SOAP_TCP_ERROR);
4727 return soap->error = SOAP_TCP_ERROR;
4730 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Polling: other end down on socket=%d select=%d\n", soap->socket, r));
4731 return SOAP_EOF;
4732 #else
4733 return SOAP_OK;
4734 #endif
4736 #endif
4737 #endif
4739 /******************************************************************************/
4740 #ifndef WITH_NOIO
4741 #ifndef PALM_1
4742 SOAP_FMAC1
4743 SOAP_SOCKET
4744 SOAP_FMAC2
4745 soap_accept(struct soap *soap)
4746 { int n = (int)sizeof(soap->peer);
4747 #ifndef WITH_LEAN
4748 #ifndef WITH_WIN32
4749 int len = SOAP_BUFLEN;
4750 #else
4751 int len = SOAP_BUFLEN + 1; /* speeds up windows xfer */
4752 #endif
4753 int set = 1;
4754 #endif
4755 soap->error = SOAP_OK;
4756 #ifndef WITH_LEAN
4757 if ((soap->omode & SOAP_IO_UDP))
4758 return soap->socket = soap->master;
4759 #endif
4760 memset((void*)&soap->peer, 0, sizeof(soap->peer));
4761 soap->socket = SOAP_INVALID_SOCKET;
4762 soap->errmode = 0;
4763 soap->keep_alive = 0;
4764 if (soap_valid_socket(soap->master))
4765 { register int err;
4766 for (;;)
4767 { if (soap->accept_timeout || soap->send_timeout || soap->recv_timeout)
4768 { for (;;)
4769 { register int r;
4770 r = tcp_select(soap, soap->master, SOAP_TCP_SELECT_ALL, soap->accept_timeout ? soap->accept_timeout : 60);
4771 if (r > 0)
4772 break;
4773 if (!r && soap->accept_timeout)
4774 { soap_set_receiver_error(soap, "Timeout", "accept failed in soap_accept()", SOAP_TCP_ERROR);
4775 return SOAP_INVALID_SOCKET;
4777 if (r < 0)
4778 { r = soap->errnum;
4779 if (r != SOAP_EINTR)
4780 { soap_closesock(soap);
4781 soap_set_sender_error(soap, tcp_error(soap), "accept failed in soap_accept()", SOAP_TCP_ERROR);
4782 return SOAP_INVALID_SOCKET;
4787 if (soap->accept_timeout)
4788 SOAP_SOCKNONBLOCK(soap->master)
4789 else
4790 SOAP_SOCKBLOCK(soap->master)
4791 soap->socket = soap->faccept(soap, soap->master, (struct sockaddr*)&soap->peer, &n);
4792 soap->peerlen = (size_t)n;
4793 if (soap_valid_socket(soap->socket))
4795 #ifdef WITH_IPV6
4796 /* Use soap->host to store the numeric form of the remote host */
4797 getnameinfo((struct sockaddr*)&soap->peer, n, soap->host, sizeof(soap->host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
4798 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Accept socket %d from %s\n", soap->socket, soap->host));
4799 soap->ip = 0; /* info stored in soap->peer and soap->host */
4800 soap->port = 0; /* info stored in soap->peer and soap->host */
4801 #else
4802 soap->ip = ntohl(soap->peer.sin_addr.s_addr);
4803 soap->port = (int)ntohs(soap->peer.sin_port); /* does not return port number on some systems */
4804 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Accept socket %d at port %d from IP %d.%d.%d.%d\n", soap->socket, soap->port, (int)(soap->ip>>24)&0xFF, (int)(soap->ip>>16)&0xFF, (int)(soap->ip>>8)&0xFF, (int)soap->ip&0xFF));
4805 #endif
4806 #ifndef WITH_LEAN
4807 if (soap->accept_flags == SO_LINGER)
4808 { struct linger linger;
4809 memset((void*)&linger, 0, sizeof(linger));
4810 linger.l_onoff = 1;
4811 linger.l_linger = soap->linger_time;
4812 if (setsockopt(soap->socket, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(struct linger)))
4813 { soap->errnum = soap_socket_errno(soap->socket);
4814 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt SO_LINGER failed in soap_accept()", SOAP_TCP_ERROR);
4815 soap_closesock(soap);
4816 return SOAP_INVALID_SOCKET;
4819 else if (soap->accept_flags && setsockopt(soap->socket, SOL_SOCKET, soap->accept_flags, (char*)&set, sizeof(int)))
4820 { soap->errnum = soap_socket_errno(soap->socket);
4821 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt failed in soap_accept()", SOAP_TCP_ERROR);
4822 soap_closesock(soap);
4823 return SOAP_INVALID_SOCKET;
4825 if (((soap->imode | soap->omode) & SOAP_IO_KEEPALIVE) && setsockopt(soap->socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&set, sizeof(int)))
4826 { soap->errnum = soap_socket_errno(soap->socket);
4827 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt SO_KEEPALIVE failed in soap_accept()", SOAP_TCP_ERROR);
4828 soap_closesock(soap);
4829 return SOAP_INVALID_SOCKET;
4831 if (setsockopt(soap->socket, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int)))
4832 { soap->errnum = soap_socket_errno(soap->socket);
4833 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt SO_SNDBUF failed in soap_accept()", SOAP_TCP_ERROR);
4834 soap_closesock(soap);
4835 return SOAP_INVALID_SOCKET;
4837 if (setsockopt(soap->socket, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int)))
4838 { soap->errnum = soap_socket_errno(soap->socket);
4839 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt SO_RCVBUF failed in soap_accept()", SOAP_TCP_ERROR);
4840 soap_closesock(soap);
4841 return SOAP_INVALID_SOCKET;
4843 #ifdef TCP_NODELAY
4844 if (!(soap->omode & SOAP_IO_UDP) && setsockopt(soap->socket, IPPROTO_TCP, TCP_NODELAY, (char*)&set, sizeof(int)))
4845 { soap->errnum = soap_socket_errno(soap->socket);
4846 soap_set_receiver_error(soap, tcp_error(soap), "setsockopt TCP_NODELAY failed in soap_accept()", SOAP_TCP_ERROR);
4847 soap_closesock(soap);
4848 return SOAP_INVALID_SOCKET;
4850 #endif
4851 #endif
4852 soap->keep_alive = (((soap->imode | soap->omode) & SOAP_IO_KEEPALIVE) != 0);
4853 if (soap->send_timeout || soap->recv_timeout)
4854 SOAP_SOCKNONBLOCK(soap->socket)
4855 else
4856 SOAP_SOCKBLOCK(soap->socket)
4857 return soap->socket;
4859 err = soap_socket_errno(soap->socket);
4860 if (err != 0 && err != SOAP_EINTR && err != SOAP_EAGAIN && err != SOAP_EWOULDBLOCK)
4861 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Accept failed from %s\n", soap->host));
4862 soap->errnum = err;
4863 soap_set_receiver_error(soap, tcp_error(soap), "accept failed in soap_accept()", SOAP_TCP_ERROR);
4864 soap_closesock(soap);
4865 return SOAP_INVALID_SOCKET;
4869 else
4870 { soap->errnum = 0;
4871 soap_set_receiver_error(soap, tcp_error(soap), "no master socket in soap_accept()", SOAP_TCP_ERROR);
4872 return SOAP_INVALID_SOCKET;
4875 #endif
4876 #endif
4878 /******************************************************************************/
4879 #ifndef PALM_1
4880 SOAP_FMAC1
4882 SOAP_FMAC2
4883 soap_closesock(struct soap *soap)
4884 { register int status = soap->error;
4885 #ifndef WITH_LEANER
4886 if (status) /* close on error: attachment state is not to be trusted */
4887 { soap->mime.first = NULL;
4888 soap->mime.last = NULL;
4889 soap->dime.first = NULL;
4890 soap->dime.last = NULL;
4892 #endif
4893 if (soap->fdisconnect && (soap->error = soap->fdisconnect(soap)))
4894 return soap->error;
4895 if (status == SOAP_EOF || status == SOAP_TCP_ERROR || status == SOAP_SSL_ERROR || !soap->keep_alive)
4896 { if (soap->fclose && (soap->error = soap->fclose(soap)))
4897 return soap->error;
4898 soap->keep_alive = 0;
4900 #ifdef WITH_ZLIB
4901 if (soap->zlib_state == SOAP_ZLIB_DEFLATE)
4902 deflateEnd(soap->d_stream);
4903 else if (soap->zlib_state == SOAP_ZLIB_INFLATE)
4904 inflateEnd(soap->d_stream);
4905 soap->zlib_state = SOAP_ZLIB_NONE;
4906 #endif
4907 return soap->error = status;
4909 #endif
4911 /******************************************************************************/
4912 #ifndef WITH_NOIO
4913 #ifndef PALM_2
4914 SOAP_FMAC1
4915 void
4916 SOAP_FMAC2
4917 soap_cleanup(struct soap *soap)
4918 { soap_done(soap);
4919 #ifdef WIN32
4920 if (!tcp_done)
4921 return;
4922 tcp_done = 0;
4923 WSACleanup();
4924 #endif
4926 #endif
4927 #endif
4929 /******************************************************************************/
4930 #ifndef PALM_1
4931 SOAP_FMAC1
4932 void
4933 SOAP_FMAC2
4934 soap_done(struct soap *soap)
4936 #ifdef SOAP_DEBUG
4937 int i;
4938 #endif
4939 if (soap_check_state(soap))
4940 return;
4941 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Done with context\n"));
4942 soap_free_temp(soap);
4943 while (soap->clist)
4944 { struct soap_clist *p = soap->clist->next;
4945 SOAP_FREE(soap, soap->clist);
4946 soap->clist = p;
4948 if (soap->state == SOAP_INIT)
4949 soap->omode &= ~SOAP_IO_UDP; /* to force close the socket */
4950 soap->keep_alive = 0; /* to force close the socket */
4951 soap_closesock(soap);
4952 #ifdef WITH_COOKIES
4953 soap_free_cookies(soap);
4954 #endif
4955 while (soap->plugins)
4956 { register struct soap_plugin *p = soap->plugins->next;
4957 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Removing plugin '%s'\n", soap->plugins->id));
4958 if (soap->plugins->fcopy || soap->state == SOAP_INIT)
4959 soap->plugins->fdelete(soap, soap->plugins);
4960 SOAP_FREE(soap, soap->plugins);
4961 soap->plugins = p;
4963 soap->fplugin = fplugin;
4964 soap->fmalloc = NULL;
4965 #ifndef WITH_NOHTTP
4966 soap->fpost = http_post;
4967 soap->fput = http_put;
4968 soap->fget = http_get;
4969 soap->fdel = http_405;
4970 soap->fopt = http_405;
4971 soap->fhead = http_405;
4972 soap->fform = NULL;
4973 soap->fposthdr = http_post_header;
4974 soap->fresponse = http_response;
4975 soap->fparse = http_parse;
4976 soap->fparsehdr = http_parse_header;
4977 #endif
4978 soap->fheader = NULL;
4979 #ifndef WITH_NOIO
4980 #ifndef WITH_IPV6
4981 soap->fresolve = tcp_gethost;
4982 #else
4983 soap->fresolve = NULL;
4984 #endif
4985 soap->faccept = tcp_accept;
4986 soap->fopen = tcp_connect;
4987 soap->fclose = tcp_disconnect;
4988 soap->fclosesocket = tcp_closesocket;
4989 soap->fshutdownsocket = tcp_shutdownsocket;
4990 soap->fsend = fsend;
4991 soap->frecv = frecv;
4992 soap->fpoll = soap_poll;
4993 #else
4994 soap->fopen = NULL;
4995 soap->fclose = NULL;
4996 soap->fpoll = NULL;
4997 #endif
4998 #ifndef WITH_LEANER
4999 soap->fprepareinitsend = NULL;
5000 soap->fprepareinitrecv = NULL;
5001 soap->fpreparesend = NULL;
5002 soap->fpreparerecv = NULL;
5003 soap->fpreparefinalsend = NULL;
5004 soap->fpreparefinalrecv = NULL;
5005 #endif
5006 soap->fseterror = NULL;
5007 soap->fignore = NULL;
5008 soap->fserveloop = NULL;
5009 #ifdef WITH_OPENSSL
5010 if (soap->session)
5011 { SSL_SESSION_free(soap->session);
5012 soap->session = NULL;
5014 #endif
5015 if (soap->state == SOAP_INIT)
5016 { if (soap_valid_socket(soap->master))
5017 { soap->fclosesocket(soap, soap->master);
5018 soap->master = SOAP_INVALID_SOCKET;
5021 #ifdef WITH_OPENSSL
5022 if (soap->ssl)
5023 { SSL_free(soap->ssl);
5024 soap->ssl = NULL;
5026 if (soap->state == SOAP_INIT)
5027 { if (soap->ctx)
5028 { SSL_CTX_free(soap->ctx);
5029 soap->ctx = NULL;
5032 ERR_remove_state(0);
5033 #endif
5034 #ifdef WITH_GNUTLS
5035 if (soap->state == SOAP_INIT)
5036 { if (soap->xcred)
5037 { gnutls_certificate_free_credentials(soap->xcred);
5038 soap->xcred = NULL;
5040 if (soap->acred)
5041 { gnutls_anon_free_client_credentials(soap->acred);
5042 soap->acred = NULL;
5044 if (soap->cache)
5045 { gnutls_priority_deinit(soap->cache);
5046 soap->cache = NULL;
5048 if (soap->dh_params)
5049 { gnutls_dh_params_deinit(soap->dh_params);
5050 soap->dh_params = NULL;
5052 if (soap->rsa_params)
5053 { gnutls_rsa_params_deinit(soap->rsa_params);
5054 soap->rsa_params = NULL;
5057 if (soap->session)
5058 { gnutls_deinit(soap->session);
5059 soap->session = NULL;
5061 #endif
5062 #ifdef WITH_C_LOCALE
5063 freelocale(soap->c_locale);
5064 #endif
5065 #ifdef WITH_ZLIB
5066 if (soap->d_stream)
5067 { SOAP_FREE(soap, (void*)soap->d_stream);
5068 soap->d_stream = NULL;
5070 if (soap->z_buf)
5071 { SOAP_FREE(soap, (void*)soap->z_buf);
5072 soap->z_buf = NULL;
5074 #endif
5075 #ifdef SOAP_DEBUG
5076 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free logfiles\n"));
5077 for (i = 0; i < SOAP_MAXLOGS; i++)
5078 { if (soap->logfile[i])
5079 { SOAP_FREE(soap, (void*)soap->logfile[i]);
5080 soap->logfile[i] = NULL;
5082 soap_close_logfile(soap, i);
5084 soap->state = SOAP_NONE;
5085 #endif
5086 #ifdef SOAP_MEM_DEBUG
5087 soap_free_mht(soap);
5088 #endif
5090 #endif
5092 /******************************************************************************\
5094 * HTTP
5096 \******************************************************************************/
5098 /******************************************************************************/
5099 #ifndef WITH_NOHTTP
5100 #ifndef PALM_1
5102 http_parse(struct soap *soap)
5103 { char header[SOAP_HDRLEN], *s;
5104 unsigned short httpcmd = 0, status = 0;
5105 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Waiting for HTTP request/response...\n"));
5106 *soap->endpoint = '\0';
5107 soap->length = 0;
5108 soap->userid = NULL;
5109 soap->passwd = NULL;
5110 soap->action = NULL;
5111 soap->authrealm = NULL;
5112 soap->proxy_from = NULL;
5113 soap->http_content = NULL;
5114 soap->status = 0;
5116 { if (soap_getline(soap, soap->msgbuf, sizeof(soap->msgbuf)))
5117 { if (soap->error == SOAP_EOF)
5118 return SOAP_EOF;
5119 return soap->error = 414;
5121 if ((s = strchr(soap->msgbuf, ' ')))
5122 { soap->status = (unsigned short)soap_strtoul(s, &s, 10);
5123 if (!soap_blank((soap_wchar)*s))
5124 soap->status = 0;
5126 else
5127 soap->status = 0;
5128 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "HTTP status: %s\n", soap->msgbuf));
5129 for (;;)
5130 { if (soap_getline(soap, header, SOAP_HDRLEN))
5131 { if (soap->error == SOAP_EOF)
5132 { soap->error = SOAP_OK;
5133 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "EOF in HTTP header, continue anyway\n"));
5134 break;
5136 return soap->error;
5138 if (!*header)
5139 break;
5140 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "HTTP header: %s\n", header));
5141 s = strchr(header, ':');
5142 if (s)
5143 { char *t;
5144 *s = '\0';
5145 do s++;
5146 while (*s && *s <= 32);
5147 if (*s == '"')
5148 s++;
5149 t = s + strlen(s) - 1;
5150 while (t > s && *t <= 32)
5151 t--;
5152 if (t >= s && *t == '"')
5153 t--;
5154 t[1] = '\0';
5155 if ((soap->error = soap->fparsehdr(soap, header, s)))
5156 { if (soap->error < SOAP_STOP)
5157 return soap->error;
5158 status = soap->error;
5159 soap->error = SOAP_OK;
5163 } while (soap->status == 100);
5164 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Finished HTTP header parsing, status = %d\n", soap->status));
5165 s = strstr(soap->msgbuf, "HTTP/");
5166 if (s && s[7] != '1')
5167 { if (soap->keep_alive == 1)
5168 soap->keep_alive = 0;
5169 if (soap->status == 0 && (soap->omode & SOAP_IO) == SOAP_IO_CHUNK) /* soap->status == 0 for HTTP request */
5170 { soap->imode |= SOAP_IO_CHUNK;
5171 soap->omode = (soap->omode & ~SOAP_IO) | SOAP_IO_STORE;
5174 if (soap->keep_alive < 0)
5175 soap->keep_alive = 1;
5176 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Keep alive connection = %d\n", soap->keep_alive));
5177 if (soap->status == 0)
5178 { size_t l = 0;
5179 if (s)
5180 { if (!strncmp(soap->msgbuf, "POST ", l = 5))
5181 httpcmd = 1;
5182 else if (!strncmp(soap->msgbuf, "PUT ", l = 4))
5183 httpcmd = 2;
5184 else if (!strncmp(soap->msgbuf, "GET ", l = 4))
5185 httpcmd = 3;
5186 else if (!strncmp(soap->msgbuf, "DELETE ", l = 7))
5187 httpcmd = 4;
5188 else if (!strncmp(soap->msgbuf, "OPTIONS ", l = 8))
5189 httpcmd = 5;
5190 else if (!strncmp(soap->msgbuf, "HEAD ", l = 5))
5191 httpcmd = 6;
5193 if (s && httpcmd)
5194 { size_t m = strlen(soap->endpoint);
5195 size_t n = m + (s - soap->msgbuf) - l - 1;
5196 if (m > n)
5197 m = n;
5198 if (n >= sizeof(soap->endpoint))
5199 n = sizeof(soap->endpoint) - 1;
5200 strncpy(soap->path, soap->msgbuf + l, n - m);
5201 soap->path[n - m] = '\0';
5202 strcat(soap->endpoint, soap->path);
5203 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Target endpoint='%s'\n", soap->endpoint));
5204 if (httpcmd > 1)
5205 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "HTTP %s handler\n", soap->msgbuf));
5206 switch (httpcmd)
5207 { case 2: soap->error = soap->fput(soap); break;
5208 case 3: soap->error = soap->fget(soap); break;
5209 case 4: soap->error = soap->fdel(soap); break;
5210 case 5: soap->error = soap->fopt(soap); break;
5211 case 6: soap->error = soap->fhead(soap); break;
5212 default: soap->error = 405; break;
5214 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "HTTP handler return = %d\n", soap->error));
5215 if (soap->error == SOAP_OK)
5216 soap->error = SOAP_STOP; /* prevents further processing */
5217 return soap->error;
5219 if (status)
5220 return soap->error = status;
5222 else if (status)
5223 return soap->error = status;
5224 else if (s)
5225 return soap->error = 405;
5227 /* Status OK (HTTP 200) */
5228 if (soap->status == 0 || soap->status == 200)
5229 return SOAP_OK;
5230 /* Status 201 (Created), 202 (Accepted), ... and HTTP 400 and 500 errors
5231 may not have a body. When content length, content type, or chunking is
5232 used assume there is a message to parse, either XML or HTTP.
5234 if (soap->length > 0 || (soap->http_content && soap->recv_timeout) || (soap->imode & SOAP_IO) == SOAP_IO_CHUNK)
5235 { if (((soap->status > 200 && soap->status <= 299) || soap->status == 400 || soap->status == 500))
5236 return SOAP_OK;
5237 /* force close afterwards in soap_closesock() */
5238 soap->keep_alive = 0;
5239 #ifndef WITH_LEAN
5240 /* read HTTP body for error details */
5241 s = soap_get_http_body(soap);
5242 if (s)
5243 return soap_set_receiver_error(soap, soap->msgbuf, s, soap->status);
5244 #endif
5246 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "HTTP error %d\n", soap->status));
5247 return soap_set_receiver_error(soap, "HTTP Error", soap->msgbuf, soap->status);
5249 #endif
5250 #endif
5252 /******************************************************************************/
5253 #ifndef WITH_NOHTTP
5254 #ifndef PALM_1
5255 static int
5256 http_parse_header(struct soap *soap, const char *key, const char *val)
5257 { if (!soap_tag_cmp(key, "Host"))
5259 #if defined(WITH_OPENSSL) || defined(WITH_GNUTLS)
5260 if (soap->imode & SOAP_ENC_SSL)
5261 strcpy(soap->endpoint, "https://");
5262 else
5263 #endif
5264 strcpy(soap->endpoint, "http://");
5265 strncat(soap->endpoint, val, sizeof(soap->endpoint) - 8);
5266 soap->endpoint[sizeof(soap->endpoint) - 1] = '\0';
5268 #ifndef WITH_LEANER
5269 else if (!soap_tag_cmp(key, "Content-Type"))
5270 { const char *action;
5271 soap->http_content = soap_strdup(soap, val);
5272 if (soap_get_header_attribute(soap, val, "application/dime"))
5273 soap->imode |= SOAP_ENC_DIME;
5274 else if (soap_get_header_attribute(soap, val, "multipart/related")
5275 || soap_get_header_attribute(soap, val, "multipart/form-data"))
5276 { soap->mime.boundary = soap_strdup(soap, soap_get_header_attribute(soap, val, "boundary"));
5277 soap->mime.start = soap_strdup(soap, soap_get_header_attribute(soap, val, "start"));
5278 soap->imode |= SOAP_ENC_MIME;
5280 action = soap_get_header_attribute(soap, val, "action");
5281 if (action)
5282 { if (*action == '"')
5283 { soap->action = soap_strdup(soap, action + 1);
5284 soap->action[strlen(soap->action) - 1] = '\0';
5286 else
5287 soap->action = soap_strdup(soap, action);
5290 #endif
5291 else if (!soap_tag_cmp(key, "Content-Length"))
5292 { soap->length = soap_strtoul(val, NULL, 10);
5294 else if (!soap_tag_cmp(key, "Content-Encoding"))
5295 { if (!soap_tag_cmp(val, "deflate"))
5296 #ifdef WITH_ZLIB
5297 soap->zlib_in = SOAP_ZLIB_DEFLATE;
5298 #else
5299 return SOAP_ZLIB_ERROR;
5300 #endif
5301 else if (!soap_tag_cmp(val, "gzip"))
5302 #ifdef WITH_GZIP
5303 soap->zlib_in = SOAP_ZLIB_GZIP;
5304 #else
5305 return SOAP_ZLIB_ERROR;
5306 #endif
5308 #ifdef WITH_ZLIB
5309 else if (!soap_tag_cmp(key, "Accept-Encoding"))
5311 #ifdef WITH_GZIP
5312 if (strchr(val, '*') || soap_get_header_attribute(soap, val, "gzip"))
5313 soap->zlib_out = SOAP_ZLIB_GZIP;
5314 else
5315 #endif
5316 if (strchr(val, '*') || soap_get_header_attribute(soap, val, "deflate"))
5317 soap->zlib_out = SOAP_ZLIB_DEFLATE;
5318 else
5319 soap->zlib_out = SOAP_ZLIB_NONE;
5321 #endif
5322 else if (!soap_tag_cmp(key, "Transfer-Encoding"))
5323 { soap->imode &= ~SOAP_IO;
5324 if (!soap_tag_cmp(val, "chunked"))
5325 soap->imode |= SOAP_IO_CHUNK;
5327 else if (!soap_tag_cmp(key, "Connection"))
5328 { if (!soap_tag_cmp(val, "keep-alive"))
5329 soap->keep_alive = -soap->keep_alive;
5330 else if (!soap_tag_cmp(val, "close"))
5331 soap->keep_alive = 0;
5333 #ifndef WITH_LEAN
5334 else if (!soap_tag_cmp(key, "Authorization"))
5335 { if (!soap_tag_cmp(val, "Basic *"))
5336 { int n;
5337 char *s;
5338 soap_base642s(soap, val + 6, soap->tmpbuf, sizeof(soap->tmpbuf) - 1, &n);
5339 soap->tmpbuf[n] = '\0';
5340 if ((s = strchr(soap->tmpbuf, ':')))
5341 { *s = '\0';
5342 soap->userid = soap_strdup(soap, soap->tmpbuf);
5343 soap->passwd = soap_strdup(soap, s + 1);
5347 else if (!soap_tag_cmp(key, "WWW-Authenticate"))
5348 { soap->authrealm = soap_strdup(soap, soap_get_header_attribute(soap, val + 6, "realm"));
5350 else if (!soap_tag_cmp(key, "Expect"))
5351 { if (!soap_tag_cmp(val, "100-continue"))
5352 { if ((soap->error = soap->fposthdr(soap, "HTTP/1.1 100 Continue", NULL))
5353 || (soap->error = soap->fposthdr(soap, NULL, NULL)))
5354 return soap->error;
5357 #endif
5358 else if (!soap_tag_cmp(key, "SOAPAction"))
5359 { if (*val == '"')
5360 { soap->action = soap_strdup(soap, val + 1);
5361 soap->action[strlen(soap->action) - 1] = '\0';
5363 else
5364 soap->action = soap_strdup(soap, val);
5366 else if (!soap_tag_cmp(key, "Location"))
5367 { strncpy(soap->endpoint, val, sizeof(soap->endpoint));
5368 soap->endpoint[sizeof(soap->endpoint) - 1] = '\0';
5370 else if (!soap_tag_cmp(key, "X-Forwarded-For"))
5371 { soap->proxy_from = soap_strdup(soap, val);
5373 #ifdef WITH_COOKIES
5374 else if (!soap_tag_cmp(key, "Cookie")
5375 || !soap_tag_cmp(key, "Cookie2")
5376 || !soap_tag_cmp(key, "Set-Cookie")
5377 || !soap_tag_cmp(key, "Set-Cookie2"))
5378 { soap_getcookies(soap, val);
5380 #endif
5381 return SOAP_OK;
5383 #endif
5384 #endif
5386 /******************************************************************************/
5387 #if !defined(WITH_NOHTTP) || !defined(WITH_LEANER)
5388 #ifndef PALM_1
5389 SOAP_FMAC1
5390 const char*
5391 SOAP_FMAC2
5392 soap_get_header_attribute(struct soap *soap, const char *line, const char *key)
5393 { register const char *s = line;
5394 if (s)
5395 { while (*s)
5396 { register short flag;
5397 s = soap_decode_key(soap->tmpbuf, sizeof(soap->tmpbuf), s);
5398 flag = soap_tag_cmp(soap->tmpbuf, key);
5399 s = soap_decode_val(soap->tmpbuf, sizeof(soap->tmpbuf), s);
5400 if (!flag)
5401 return soap->tmpbuf;
5404 return NULL;
5406 #endif
5407 #endif
5409 /******************************************************************************/
5410 #if !defined(WITH_NOHTTP) || !defined(WITH_LEANER)
5411 #ifndef PALM_1
5412 SOAP_FMAC1
5413 const char*
5414 SOAP_FMAC2
5415 soap_decode_key(char *buf, size_t len, const char *val)
5416 { return soap_decode(buf, len, val, "=,;");
5418 #endif
5419 #endif
5421 /******************************************************************************/
5422 #if !defined(WITH_NOHTTP) || !defined(WITH_LEANER)
5423 #ifndef PALM_1
5424 SOAP_FMAC1
5425 const char*
5426 SOAP_FMAC2
5427 soap_decode_val(char *buf, size_t len, const char *val)
5428 { if (*val != '=')
5429 { *buf = '\0';
5430 return val;
5432 return soap_decode(buf, len, val + 1, ",;");
5434 #endif
5435 #endif
5437 /******************************************************************************/
5438 #if !defined(WITH_NOHTTP) || !defined(WITH_LEANER)
5439 #ifndef PALM_1
5440 static const char*
5441 soap_decode(char *buf, size_t len, const char *val, const char *sep)
5442 { const char *s;
5443 char *t = buf;
5444 for (s = val; *s; s++)
5445 if (*s != ' ' && *s != '\t' && !strchr(sep, *s))
5446 break;
5447 if (*s == '"')
5448 { s++;
5449 while (*s && *s != '"' && --len)
5450 *t++ = *s++;
5452 else
5453 { while (*s && !soap_blank((soap_wchar)*s) && !strchr(sep, *s) && --len)
5454 { if (*s == '%')
5455 { *t++ = ((s[1] >= 'A' ? (s[1] & 0x7) + 9 : s[1] - '0') << 4)
5456 + (s[2] >= 'A' ? (s[2] & 0x7) + 9 : s[2] - '0');
5457 s += 3;
5459 else
5460 *t++ = *s++;
5463 *t = '\0';
5464 while (*s && !strchr(sep, *s))
5465 s++;
5466 return s;
5468 #endif
5469 #endif
5471 /******************************************************************************/
5472 #ifndef WITH_NOHTTP
5473 #ifndef PALM_1
5474 static const char*
5475 http_error(struct soap *soap, int status)
5476 { register const char *msg = SOAP_STR_EOS;
5477 #ifndef WITH_LEAN
5478 msg = soap_code_str(h_http_error_codes, status);
5479 if (!msg)
5480 msg = SOAP_STR_EOS;
5481 #endif
5482 return msg;
5484 #endif
5485 #endif
5487 /******************************************************************************/
5488 #ifndef WITH_NOHTTP
5489 #ifndef PALM_1
5490 static int
5491 http_put(struct soap *soap)
5492 { return http_parse(soap);
5494 #endif
5495 #endif
5496 /******************************************************************************/
5498 #ifndef WITH_NOHTTP
5499 #ifndef PALM_1
5500 static int
5501 http_get(struct soap *soap)
5502 { return SOAP_GET_METHOD;
5504 #endif
5505 #endif
5507 /******************************************************************************/
5508 #ifndef WITH_NOHTTP
5509 #ifndef PALM_1
5510 static int
5511 http_405(struct soap *soap)
5512 { return 405;
5514 #endif
5515 #endif
5517 /******************************************************************************/
5518 #ifndef WITH_NOHTTP
5519 #ifndef PALM_1
5520 static int
5521 http_post(struct soap *soap, const char *endpoint, const char *host, int port, const char *path, const char *action, size_t count)
5522 { register const char *s;
5523 register int err;
5524 if (soap->status == SOAP_GET)
5525 s = "GET";
5526 else
5527 s = "POST";
5528 #ifdef PALM
5529 if (!endpoint || (soap_tag_cmp(endpoint, "http:*") && soap_tag_cmp(endpoint, "https:*") && strncmp(endpoint, "httpg:", 6)) && strncmp(endpoint, "_beam:", 6) && strncmp(endpoint, "_local:", 7) && strncmp(endpoint, "_btobex:", 8))
5530 #else
5531 if (!endpoint || (soap_tag_cmp(endpoint, "http:*") && soap_tag_cmp(endpoint, "https:*") && strncmp(endpoint, "httpg:", 6)))
5532 #endif
5533 return SOAP_OK;
5534 if (strlen(endpoint) + strlen(soap->http_version) > sizeof(soap->tmpbuf) - 80)
5535 return soap->error = SOAP_EOM;
5536 if (soap->proxy_host && soap_tag_cmp(endpoint, "https:*"))
5537 sprintf(soap->tmpbuf, "%s %s HTTP/%s", s, endpoint, soap->http_version);
5538 else
5539 sprintf(soap->tmpbuf, "%s /%s HTTP/%s", s, (*path == '/' ? path + 1 : path), soap->http_version);
5540 if ((err = soap->fposthdr(soap, soap->tmpbuf, NULL)))
5541 return err;
5542 #ifdef WITH_OPENSSL
5543 if ((soap->ssl && soap->port != 443) || (!soap->ssl && soap->port != 80))
5544 sprintf(soap->tmpbuf, "%s:%d", host, port);
5545 else
5546 strcpy(soap->tmpbuf, host);
5547 #else
5548 if (port != 80)
5549 sprintf(soap->tmpbuf, "%s:%d", host, port);
5550 else
5551 strcpy(soap->tmpbuf, host);
5552 #endif
5553 if ((err = soap->fposthdr(soap, "Host", soap->tmpbuf))
5554 || (err = soap->fposthdr(soap, "User-Agent", "gSOAP/2.7"))
5555 || (err = soap_puthttphdr(soap, SOAP_OK, count)))
5556 return err;
5557 #ifdef WITH_ZLIB
5558 #ifdef WITH_GZIP
5559 if ((err = soap->fposthdr(soap, "Accept-Encoding", "gzip, deflate")))
5560 #else
5561 if ((err = soap->fposthdr(soap, "Accept-Encoding", "deflate")))
5562 #endif
5563 return err;
5564 #endif
5565 #ifndef WITH_LEAN
5566 if (soap->userid && soap->passwd && strlen(soap->userid) + strlen(soap->passwd) < 761)
5567 { sprintf(soap->tmpbuf + 262, "%s:%s", soap->userid, soap->passwd);
5568 strcpy(soap->tmpbuf, "Basic ");
5569 soap_s2base64(soap, (const unsigned char*)(soap->tmpbuf + 262), soap->tmpbuf + 6, (int)strlen(soap->tmpbuf + 262));
5570 if ((err = soap->fposthdr(soap, "Authorization", soap->tmpbuf)))
5571 return err;
5573 if (soap->proxy_userid && soap->proxy_passwd && strlen(soap->proxy_userid) + strlen(soap->proxy_passwd) < 761)
5574 { sprintf(soap->tmpbuf + 262, "%s:%s", soap->proxy_userid, soap->proxy_passwd);
5575 strcpy(soap->tmpbuf, "Basic ");
5576 soap_s2base64(soap, (const unsigned char*)(soap->tmpbuf + 262), soap->tmpbuf + 6, (int)strlen(soap->tmpbuf + 262));
5577 if ((err = soap->fposthdr(soap, "Proxy-Authorization", soap->tmpbuf)))
5578 return err;
5580 #endif
5581 #ifdef WITH_COOKIES
5582 #ifdef WITH_OPENSSL
5583 if (soap_putcookies(soap, host, path, soap->ssl != NULL))
5584 return soap->error;
5585 #else
5586 if (soap_putcookies(soap, host, path, 0))
5587 return soap->error;
5588 #endif
5589 #endif
5590 if (soap->status != SOAP_GET && (soap->version == 1 || (action && *action)))
5591 { sprintf(soap->tmpbuf, "\"%s\"", action && strlen(action) < sizeof(soap->tmpbuf) - 3 ? action : SOAP_STR_EOS);
5592 if ((err = soap->fposthdr(soap, "SOAPAction", soap->tmpbuf)))
5593 return err;
5595 return soap->fposthdr(soap, NULL, NULL);
5597 #endif
5598 #endif
5600 /******************************************************************************/
5601 #ifndef WITH_NOHTTP
5602 #ifndef PALM_1
5603 static int
5604 http_send_header(struct soap *soap, const char *s)
5605 { register const char *t;
5607 { t = strchr(s, '\n'); /* disallow \n in HTTP headers */
5608 if (!t)
5609 t = s + strlen(s);
5610 if (soap_send_raw(soap, s, t - s))
5611 return soap->error;
5612 s = t + 1;
5613 } while (*t);
5614 return SOAP_OK;
5616 #endif
5617 #endif
5619 /******************************************************************************/
5620 #ifndef WITH_NOHTTP
5621 #ifndef PALM_1
5622 static int
5623 http_post_header(struct soap *soap, const char *key, const char *val)
5624 { if (key)
5625 { if (http_send_header(soap, key))
5626 return soap->error;
5627 if (val && (soap_send_raw(soap, ": ", 2) || http_send_header(soap, val)))
5628 return soap->error;
5630 return soap_send_raw(soap, "\r\n", 2);
5632 #endif
5633 #endif
5635 /******************************************************************************/
5636 #ifndef WITH_NOHTTP
5637 #ifndef PALM_1
5638 static int
5639 http_response(struct soap *soap, int status, size_t count)
5640 { register int err;
5641 #ifdef WMW_RPM_IO
5642 if (soap->rpmreqid)
5643 httpOutputEnable(soap->rpmreqid);
5644 #endif
5645 if (strlen(soap->http_version) > 4)
5646 return soap->error = SOAP_EOM;
5647 if (!status || status == SOAP_HTML || status == SOAP_FILE)
5648 { const char *s;
5649 if (count || ((soap->omode & SOAP_IO) == SOAP_IO_CHUNK))
5650 s = "200 OK";
5651 else
5652 s = "202 ACCEPTED";
5653 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Status = %s\n", s));
5654 #ifdef WMW_RPM_IO
5655 if (soap->rpmreqid || soap_valid_socket(soap->master) || soap_valid_socket(soap->socket)) /* RPM behaves as if standalone */
5656 #else
5657 if (soap_valid_socket(soap->master) || soap_valid_socket(soap->socket)) /* standalone application (socket) or CGI (stdin/out)? */
5658 #endif
5659 { sprintf(soap->tmpbuf, "HTTP/%s %s", soap->http_version, s);
5660 if ((err = soap->fposthdr(soap, soap->tmpbuf, NULL)))
5661 return err;
5663 else if ((err = soap->fposthdr(soap, "Status", s))) /* CGI header */
5664 return err;
5666 else if (status >= 200 && status < 600)
5667 { sprintf(soap->tmpbuf, "HTTP/%s %d %s", soap->http_version, status, http_error(soap, status));
5668 if ((err = soap->fposthdr(soap, soap->tmpbuf, NULL)))
5669 return err;
5670 #ifndef WITH_LEAN
5671 if (status == 401)
5672 { sprintf(soap->tmpbuf, "Basic realm=\"%s\"", (soap->authrealm && strlen(soap->authrealm) < sizeof(soap->tmpbuf) - 14) ? soap->authrealm : "gSOAP Web Service");
5673 if ((err = soap->fposthdr(soap, "WWW-Authenticate", soap->tmpbuf)))
5674 return err;
5676 else if ((status >= 301 && status <= 303) || status == 307)
5677 { if ((err = soap->fposthdr(soap, "Location", soap->endpoint)))
5678 return err;
5680 #endif
5682 else
5683 { const char *s = *soap_faultcode(soap);
5684 if (status >= SOAP_GET_METHOD && status <= SOAP_HTTP_METHOD)
5685 s = "405 Method Not Allowed";
5686 else if (soap->version == 2 && (!s || !strcmp(s, "SOAP-ENV:Sender")))
5687 s = "400 Bad Request";
5688 else
5689 s = "500 Internal Server Error";
5690 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Error %s (status=%d)\n", s, status));
5691 #ifdef WMW_RPM_IO
5692 if (soap->rpmreqid || soap_valid_socket(soap->master) || soap_valid_socket(soap->socket)) /* RPM behaves as if standalone */
5693 #else
5694 if (soap_valid_socket(soap->master) || soap_valid_socket(soap->socket)) /* standalone application */
5695 #endif
5696 { sprintf(soap->tmpbuf, "HTTP/%s %s", soap->http_version, s);
5697 if ((err = soap->fposthdr(soap, soap->tmpbuf, NULL)))
5698 return err;
5700 else if ((err = soap->fposthdr(soap, "Status", s))) /* CGI */
5701 return err;
5703 if ((err = soap->fposthdr(soap, "Server", "gSOAP/2.7"))
5704 || (err = soap_puthttphdr(soap, status, count)))
5705 return err;
5706 #ifdef WITH_COOKIES
5707 if (soap_putsetcookies(soap))
5708 return soap->error;
5709 #endif
5710 return soap->fposthdr(soap, NULL, NULL);
5712 #endif
5713 #endif
5715 /******************************************************************************/
5716 #ifndef PALM_1
5717 SOAP_FMAC1
5719 SOAP_FMAC2
5720 soap_response(struct soap *soap, int status)
5721 { register size_t count;
5722 if (!(soap->omode & (SOAP_ENC_XML | SOAP_IO_STORE /* this tests for chunking too */))
5723 && (status == SOAP_HTML || status == SOAP_FILE))
5724 soap->omode = (soap->omode & ~SOAP_IO) | SOAP_IO_STORE;
5725 soap->status = status;
5726 count = soap_count_attachments(soap);
5727 if (soap_begin_send(soap))
5728 return soap->error;
5729 #ifndef WITH_NOHTTP
5730 if ((soap->mode & SOAP_IO) != SOAP_IO_STORE && !(soap->mode & SOAP_ENC_XML))
5731 { register int n = soap->mode;
5732 soap->mode &= ~(SOAP_IO | SOAP_ENC_ZLIB);
5733 if ((n & SOAP_IO) != SOAP_IO_FLUSH)
5734 soap->mode |= SOAP_IO_BUFFER;
5735 if ((soap->error = soap->fresponse(soap, status, count)))
5736 return soap->error;
5737 #ifndef WITH_LEANER
5738 if ((n & SOAP_IO) == SOAP_IO_CHUNK)
5739 { if (soap_flush(soap))
5740 return soap->error;
5742 #endif
5743 soap->mode = n;
5745 #endif
5746 return SOAP_OK;
5748 #endif
5750 /******************************************************************************\
5752 * HTTP Cookies
5754 \******************************************************************************/
5756 #ifdef WITH_COOKIES
5757 /******************************************************************************/
5758 SOAP_FMAC1
5759 size_t
5760 SOAP_FMAC2
5761 soap_encode_cookie(const char *s, char *t, size_t len)
5762 { register int c;
5763 register size_t n = len;
5764 while ((c = *s++) && --n > 0)
5765 { if (c > ' ' && c < 128 && !strchr("()<>@,;:\\\"/[]?={}#!$&'*+", c))
5766 *t++ = c;
5767 else if (n > 2)
5768 { *t++ = '%';
5769 *t++ = (c >> 4) + (c > 159 ? '7' : '0');
5770 c &= 0xF;
5771 *t++ = c + (c > 9 ? '7' : '0');
5772 n -= 2;
5774 else
5775 break;
5777 *t = '\0';
5778 return len - n;
5781 /******************************************************************************/
5782 SOAP_FMAC1
5783 struct soap_cookie*
5784 SOAP_FMAC2
5785 soap_cookie(struct soap *soap, const char *name, const char *domain, const char *path)
5786 { struct soap_cookie *p;
5787 if (!domain)
5788 domain = soap->cookie_domain;
5789 if (!path)
5790 path = soap->cookie_path;
5791 if (!path)
5792 path = SOAP_STR_EOS;
5793 else if (*path == '/')
5794 path++;
5795 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Search cookie %s domain=%s path=%s\n", name, domain?domain:"(null)", path?path:"(null)"));
5796 for (p = soap->cookies; p; p = p->next)
5797 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Cookie in database: %s=%s domain=%s path=%s env=%hd\n", p->name, p->value?p->value:"(null)", p->domain?p->domain:"(null)", p->path?p->path:"(null)", p->env));
5798 if (!strcmp(p->name, name)
5799 && p->domain
5800 && p->path
5801 && !strcmp(p->domain, domain)
5802 && (!*p->path || !strncmp(p->path, path, strlen(p->path))))
5803 break;
5805 return p;
5808 /******************************************************************************/
5809 SOAP_FMAC1
5810 struct soap_cookie*
5811 SOAP_FMAC2
5812 soap_set_cookie(struct soap *soap, const char *name, const char *value, const char *domain, const char *path)
5813 { struct soap_cookie **p, *q;
5814 int n;
5815 if (!domain)
5816 domain = soap->cookie_domain;
5817 if (!path)
5818 path = soap->cookie_path;
5819 if (!path)
5820 path = SOAP_STR_EOS;
5821 else if (*path == '/')
5822 path++;
5823 q = soap_cookie(soap, name, domain, path);
5824 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Set %scookie: %s=%s domain=%s path=%s\n", q ? SOAP_STR_EOS : "new ", name, value?value:"(null)", domain?domain:"(null)", path?path:"(null)"));
5825 if (!q)
5826 { if ((q = (struct soap_cookie*)SOAP_MALLOC(soap, sizeof(struct soap_cookie))))
5827 { if ((q->name = (char*)SOAP_MALLOC(soap, strlen(name)+1)))
5828 strcpy(q->name, name);
5829 q->value = NULL;
5830 q->domain = NULL;
5831 q->path = NULL;
5832 q->expire = 0;
5833 q->maxage = -1;
5834 q->version = 1;
5835 q->secure = 0;
5836 q->modified = 0;
5837 for (p = &soap->cookies, n = soap->cookie_max; *p && n; p = &(*p)->next, n--)
5838 if (!strcmp((*p)->name, name) && (*p)->path && path && strcmp((*p)->path, path) < 0)
5839 break;
5840 if (n)
5841 { q->next = *p;
5842 *p = q;
5844 else
5845 { SOAP_FREE(soap, q->name);
5846 SOAP_FREE(soap, q);
5847 q = NULL;
5851 else
5852 q->modified = 1;
5853 if (q)
5854 { if (q->value)
5855 { if (!value || strcmp(value, q->value))
5856 { SOAP_FREE(soap, q->value);
5857 q->value = NULL;
5860 if (value && *value && !q->value && (q->value = (char*)SOAP_MALLOC(soap, strlen(value)+1)))
5861 strcpy(q->value, value);
5862 if (q->domain)
5863 { if (!domain || strcmp(domain, q->domain))
5864 { SOAP_FREE(soap, q->domain);
5865 q->domain = NULL;
5868 if (domain && !q->domain && (q->domain = (char*)SOAP_MALLOC(soap, strlen(domain)+1)))
5869 strcpy(q->domain, domain);
5870 if (q->path)
5871 { if (!path || strncmp(path, q->path, strlen(q->path)))
5872 { SOAP_FREE(soap, q->path);
5873 q->path = NULL;
5876 if (path && !q->path && (q->path = (char*)SOAP_MALLOC(soap, strlen(path)+1)))
5877 strcpy(q->path, path);
5878 q->session = 1;
5879 q->env = 0;
5881 return q;
5884 /******************************************************************************/
5885 SOAP_FMAC1
5886 void
5887 SOAP_FMAC2
5888 soap_clr_cookie(struct soap *soap, const char *name, const char *domain, const char *path)
5889 { struct soap_cookie **p, *q;
5890 if (!domain)
5891 domain = soap->cookie_domain;
5892 if (!domain)
5893 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Error in clear cookie %s: cookie domain not set\n", name?name:"(null)"));
5894 return;
5896 if (!path)
5897 path = soap->cookie_path;
5898 if (!path)
5899 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Error in clear cookie %s: cookie path not set\n", name?name:"(null)"));
5900 return;
5902 if (*path == '/')
5903 path++;
5904 for (p = &soap->cookies, q = *p; q; q = *p)
5905 { if (!strcmp(q->name, name) && !strcmp(q->domain, domain) && !strncmp(q->path, path, strlen(q->path)))
5906 { if (q->value)
5907 SOAP_FREE(soap, q->value);
5908 if (q->domain)
5909 SOAP_FREE(soap, q->domain);
5910 if (q->path)
5911 SOAP_FREE(soap, q->path);
5912 *p = q->next;
5913 SOAP_FREE(soap, q);
5915 else
5916 p = &q->next;
5920 /******************************************************************************/
5921 SOAP_FMAC1
5922 char *
5923 SOAP_FMAC2
5924 soap_cookie_value(struct soap *soap, const char *name, const char *domain, const char *path)
5925 { struct soap_cookie *p;
5926 if ((p = soap_cookie(soap, name, domain, path)))
5927 return p->value;
5928 return NULL;
5931 /******************************************************************************/
5932 SOAP_FMAC1
5933 char *
5934 SOAP_FMAC2
5935 soap_env_cookie_value(struct soap *soap, const char *name, const char *domain, const char *path)
5936 { struct soap_cookie *p;
5937 if ((p = soap_cookie(soap, name, domain, path)) && p->env)
5938 return p->value;
5939 return NULL;
5942 /******************************************************************************/
5943 SOAP_FMAC1
5944 time_t
5945 SOAP_FMAC2
5946 soap_cookie_expire(struct soap *soap, const char *name, const char *domain, const char *path)
5947 { struct soap_cookie *p;
5948 if ((p = soap_cookie(soap, name, domain, path)))
5949 return p->expire;
5950 return -1;
5953 /******************************************************************************/
5954 SOAP_FMAC1
5956 SOAP_FMAC2
5957 soap_set_cookie_expire(struct soap *soap, const char *name, long expire, const char *domain, const char *path)
5958 { struct soap_cookie *p;
5959 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Set cookie expiration max-age %ld: %s domain=%s path=%s\n", expire, name, domain?domain:"(null)", path?path:"(null)"));
5960 if ((p = soap_cookie(soap, name, domain, path)))
5961 { p->maxage = expire;
5962 p->modified = 1;
5963 return SOAP_OK;
5965 return SOAP_ERR;
5968 /******************************************************************************/
5969 SOAP_FMAC1
5971 SOAP_FMAC2
5972 soap_set_cookie_session(struct soap *soap, const char *name, const char *domain, const char *path)
5973 { struct soap_cookie *p;
5974 if ((p = soap_cookie(soap, name, domain, path)))
5975 { p->session = 1;
5976 p->modified = 1;
5977 return SOAP_OK;
5979 return SOAP_ERR;
5982 /******************************************************************************/
5983 SOAP_FMAC1
5985 SOAP_FMAC2
5986 soap_clr_cookie_session(struct soap *soap, const char *name, const char *domain, const char *path)
5987 { struct soap_cookie *p;
5988 if ((p = soap_cookie(soap, name, domain, path)))
5989 { p->session = 0;
5990 p->modified = 1;
5991 return SOAP_OK;
5993 return SOAP_ERR;
5996 /******************************************************************************/
5997 SOAP_FMAC1
5999 SOAP_FMAC2
6000 soap_putsetcookies(struct soap *soap)
6001 { struct soap_cookie *p;
6002 char *s, tmp[4096];
6003 const char *t;
6004 for (p = soap->cookies; p; p = p->next)
6006 if (p->modified
6007 #ifdef WITH_OPENSSL
6008 || (!p->env && !soap->ssl == !p->secure)
6009 #endif
6011 { s = tmp;
6012 if (p->name)
6013 s += soap_encode_cookie(p->name, s, tmp-s+4064);
6014 if (p->value && *p->value)
6015 { *s++ = '=';
6016 s += soap_encode_cookie(p->value, s, tmp-s+4064);
6018 if (p->domain && (int)strlen(p->domain) < tmp-s+4064)
6019 { strcpy(s, ";Domain=");
6020 strcat(s, p->domain);
6022 else if (soap->cookie_domain && (int)strlen(soap->cookie_domain) < tmp-s+4064)
6023 { strcpy(s, ";Domain=");
6024 strcat(s, soap->cookie_domain);
6026 strcat(s, ";Path=/");
6027 s += strlen(s);
6028 if (p->path)
6029 t = p->path;
6030 else
6031 t = soap->cookie_path;
6032 if (t)
6033 { if (*t == '/')
6034 t++;
6035 if ((int)strlen(t) < tmp-s+4064)
6036 { if (strchr(t, '%')) /* already URL encoded? */
6037 { strcpy(s, t);
6038 s += strlen(s);
6040 else
6041 s += soap_encode_cookie(t, s, tmp-s+4064);
6044 if (p->version > 0 && s-tmp < 4060)
6045 { sprintf(s, ";Version=%u", p->version);
6046 s += strlen(s);
6048 if (p->maxage >= 0 && s-tmp < 4060)
6049 { sprintf(s, ";Max-Age=%ld", p->maxage);
6050 s += strlen(s);
6052 if (s-tmp < 4073
6053 && (p->secure
6054 #ifdef WITH_OPENSSL
6055 || soap->ssl
6056 #endif
6058 strcpy(s, ";Secure");
6059 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Set-Cookie: %s\n", tmp));
6060 if ((soap->error = soap->fposthdr(soap, "Set-Cookie", tmp)))
6061 return soap->error;
6064 return SOAP_OK;
6067 /******************************************************************************/
6068 SOAP_FMAC1
6070 SOAP_FMAC2
6071 soap_putcookies(struct soap *soap, const char *domain, const char *path, int secure)
6072 { struct soap_cookie **p, *q;
6073 unsigned int version = 0;
6074 time_t now = time(NULL);
6075 char *s, tmp[4096];
6076 p = &soap->cookies;
6077 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Sending cookies for domain=%s path=%s\n", domain, path));
6078 if (*path == '/')
6079 path++;
6080 while ((q = *p))
6081 { if (q->expire && now > q->expire)
6082 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Cookie %s expired\n", q->name));
6083 SOAP_FREE(soap, q->name);
6084 if (q->value)
6085 SOAP_FREE(soap, q->value);
6086 if (q->domain)
6087 SOAP_FREE(soap, q->domain);
6088 if (q->path)
6089 SOAP_FREE(soap, q->path);
6090 *p = q->next;
6091 SOAP_FREE(soap, q);
6093 else
6094 { int flag;
6095 char *t = q->domain;
6096 size_t n = 0;
6097 if (!t)
6098 flag = 1;
6099 else
6100 { const char *r = strchr(t, ':');
6101 if (r)
6102 n = r - t;
6103 else
6104 n = strlen(t);
6105 flag = !strncmp(t, domain, n);
6107 /* domain-level cookies, cannot compile when WITH_NOIO set */
6108 #ifndef WITH_NOIO
6109 if (!flag)
6110 { struct hostent *hostent = gethostbyname((char*)domain);
6111 if (hostent)
6112 { const char *r = strchr(hostent->h_name, '.');
6113 if (!r)
6114 r = hostent->h_name;
6115 flag = !strncmp(t, r, n);
6118 #endif
6119 if (flag
6120 && (!q->path || !strncmp(q->path, path, strlen(q->path)))
6121 && (!q->secure || secure))
6122 { s = tmp;
6123 if (q->version != version)
6124 { sprintf(s, "$Version=%u;", q->version);
6125 version = q->version;
6127 if (q->name)
6128 s += soap_encode_cookie(q->name, s, tmp-s+4080);
6129 if (q->value && *q->value)
6130 { *s++ = '=';
6131 s += soap_encode_cookie(q->value, s, tmp-s+4080);
6133 if (q->path && *q->path && (int)strlen(q->path) < tmp-s+4080)
6134 { sprintf(s, ";$Path=\"/%s\"", (*q->path == '/' ? q->path + 1 : q->path));
6135 s += strlen(s);
6137 if (q->domain && (int)strlen(q->domain) < tmp-s+4080)
6138 sprintf(s, ";$Domain=\"%s\"", q->domain);
6139 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Cookie: %s\n", tmp));
6140 if ((soap->error = soap->fposthdr(soap, "Cookie", tmp)))
6141 return soap->error;
6143 p = &q->next;
6146 return SOAP_OK;
6149 /******************************************************************************/
6150 SOAP_FMAC1
6151 void
6152 SOAP_FMAC2
6153 soap_getcookies(struct soap *soap, const char *val)
6154 { struct soap_cookie *p = NULL, *q;
6155 const char *s;
6156 char *t, tmp[4096]; /* cookie size is up to 4096 bytes [RFC2109] */
6157 char *domain = NULL;
6158 char *path = NULL;
6159 unsigned int version = 0;
6160 time_t now = time(NULL);
6161 if (!val)
6162 return;
6163 s = val;
6164 while (*s)
6165 { s = soap_decode_key(tmp, sizeof(tmp), s);
6166 if (!soap_tag_cmp(tmp, "$Version"))
6167 { if ((s = soap_decode_val(tmp, sizeof(tmp), s)))
6168 { if (p)
6169 p->version = (int)soap_strtol(tmp, NULL, 10);
6170 else
6171 version = (int)soap_strtol(tmp, NULL, 10);
6174 else if (!soap_tag_cmp(tmp, "$Path"))
6175 { s = soap_decode_val(tmp, sizeof(tmp), s);
6176 if (*tmp)
6177 { if ((t = (char*)SOAP_MALLOC(soap, strlen(tmp)+1)))
6178 strcpy(t, tmp);
6180 else
6181 t = NULL;
6182 if (p)
6183 { if (p->path)
6184 SOAP_FREE(soap, p->path);
6185 p->path = t;
6187 else
6188 { if (path)
6189 SOAP_FREE(soap, path);
6190 path = t;
6193 else if (!soap_tag_cmp(tmp, "$Domain"))
6194 { s = soap_decode_val(tmp, sizeof(tmp), s);
6195 if (*tmp)
6196 { if ((t = (char*)SOAP_MALLOC(soap, strlen(tmp)+1)))
6197 strcpy(t, tmp);
6199 else
6200 t = NULL;
6201 if (p)
6202 { if (p->domain)
6203 SOAP_FREE(soap, p->domain);
6204 p->domain = t;
6206 else
6207 { if (domain)
6208 SOAP_FREE(soap, domain);
6209 domain = t;
6212 else if (p && !soap_tag_cmp(tmp, "Path"))
6213 { if (p->path)
6214 SOAP_FREE(soap, p->path);
6215 s = soap_decode_val(tmp, sizeof(tmp), s);
6216 if (*tmp)
6217 { if ((p->path = (char*)SOAP_MALLOC(soap, strlen(tmp)+1)))
6218 strcpy(p->path, tmp);
6220 else
6221 p->path = NULL;
6223 else if (p && !soap_tag_cmp(tmp, "Domain"))
6224 { if (p->domain)
6225 SOAP_FREE(soap, p->domain);
6226 s = soap_decode_val(tmp, sizeof(tmp), s);
6227 if (*tmp)
6228 { if ((p->domain = (char*)SOAP_MALLOC(soap, strlen(tmp)+1)))
6229 strcpy(p->domain, tmp);
6231 else
6232 p->domain = NULL;
6234 else if (p && !soap_tag_cmp(tmp, "Version"))
6235 { s = soap_decode_val(tmp, sizeof(tmp), s);
6236 p->version = (unsigned int)soap_strtoul(tmp, NULL, 10);
6238 else if (p && !soap_tag_cmp(tmp, "Max-Age"))
6239 { s = soap_decode_val(tmp, sizeof(tmp), s);
6240 p->expire = now + soap_strtol(tmp, NULL, 10);
6242 else if (p && !soap_tag_cmp(tmp, "Expires"))
6243 { struct tm T;
6244 char a[3];
6245 static const char mns[] = "anebarprayunulugepctovec";
6246 s = soap_decode_val(tmp, sizeof(tmp), s);
6247 if (strlen(tmp) > 20)
6248 { memset((void*)&T, 0, sizeof(T));
6249 a[0] = tmp[4];
6250 a[1] = tmp[5];
6251 a[2] = '\0';
6252 T.tm_mday = (int)soap_strtol(a, NULL, 10);
6253 a[0] = tmp[8];
6254 a[1] = tmp[9];
6255 T.tm_mon = (int)(strstr(mns, a) - mns) / 2;
6256 a[0] = tmp[11];
6257 a[1] = tmp[12];
6258 T.tm_year = 100 + (int)soap_strtol(a, NULL, 10);
6259 a[0] = tmp[13];
6260 a[1] = tmp[14];
6261 T.tm_hour = (int)soap_strtol(a, NULL, 10);
6262 a[0] = tmp[16];
6263 a[1] = tmp[17];
6264 T.tm_min = (int)soap_strtol(a, NULL, 10);
6265 a[0] = tmp[19];
6266 a[1] = tmp[20];
6267 T.tm_sec = (int)soap_strtol(a, NULL, 10);
6268 p->expire = soap_timegm(&T);
6271 else if (p && !soap_tag_cmp(tmp, "Secure"))
6272 p->secure = 1;
6273 else
6274 { if (p)
6275 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Got environment cookie %s=%s domain=%s path=%s expire=%ld secure=%d\n", p->name, p->value?p->value:"(null)", p->domain?p->domain:"(null)", p->path?p->path:"(null)", p->expire, p->secure));
6276 if ((q = soap_set_cookie(soap, p->name, p->value, p->domain, p->path)))
6277 { q->version = p->version;
6278 q->expire = p->expire;
6279 q->secure = p->secure;
6280 q->env = 1;
6282 if (p->name)
6283 SOAP_FREE(soap, p->name);
6284 if (p->value)
6285 SOAP_FREE(soap, p->value);
6286 if (p->domain)
6287 SOAP_FREE(soap, p->domain);
6288 if (p->path)
6289 SOAP_FREE(soap, p->path);
6290 SOAP_FREE(soap, p);
6292 if ((p = (struct soap_cookie*)SOAP_MALLOC(soap, sizeof(struct soap_cookie))))
6293 { p->name = (char*)SOAP_MALLOC(soap, strlen(tmp)+1);
6294 strcpy(p->name, tmp);
6295 s = soap_decode_val(tmp, sizeof(tmp), s);
6296 if (*tmp)
6297 { p->value = (char*)SOAP_MALLOC(soap, strlen(tmp)+1);
6298 strcpy(p->value, tmp);
6300 else
6301 p->value = NULL;
6302 if (domain)
6303 p->domain = domain;
6304 else if (*soap->host)
6305 { p->domain = (char*)SOAP_MALLOC(soap, strlen(soap->host)+1);
6306 strcpy(p->domain, soap->host);
6308 else
6309 p->domain = NULL;
6310 if (path)
6311 p->path = path;
6312 else if (soap->path && *soap->path)
6313 { p->path = (char*)SOAP_MALLOC(soap, strlen(soap->path)+1);
6314 strcpy(p->path, soap->path);
6316 else
6317 { p->path = (char*)SOAP_MALLOC(soap, 2);
6318 strcpy(p->path, "/");
6320 p->expire = 0;
6321 p->secure = 0;
6322 p->version = version;
6326 if (p)
6327 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Got environment cookie %s=%s domain=%s path=%s expire=%ld secure=%d\n", p->name, p->value?p->value:"(null)", p->domain?p->domain:"(null)", p->path?p->path:"(null)", p->expire, p->secure));
6328 if ((q = soap_set_cookie(soap, p->name, p->value, p->domain, p->path)))
6329 { q->version = p->version;
6330 q->expire = p->expire;
6331 q->secure = p->secure;
6332 q->env = 1;
6334 if (p->name)
6335 SOAP_FREE(soap, p->name);
6336 if (p->value)
6337 SOAP_FREE(soap, p->value);
6338 if (p->domain)
6339 SOAP_FREE(soap, p->domain);
6340 if (p->path)
6341 SOAP_FREE(soap, p->path);
6342 SOAP_FREE(soap, p);
6344 if (domain)
6345 SOAP_FREE(soap, domain);
6346 if (path)
6347 SOAP_FREE(soap, path);
6350 /******************************************************************************/
6351 SOAP_FMAC1
6353 SOAP_FMAC2
6354 soap_getenv_cookies(struct soap *soap)
6355 { struct soap_cookie *p;
6356 const char *s;
6357 char key[4096], val[4096]; /* cookie size is up to 4096 bytes [RFC2109] */
6358 if (!(s = getenv("HTTP_COOKIE")))
6359 return SOAP_ERR;
6361 { s = soap_decode_key(key, sizeof(key), s);
6362 s = soap_decode_val(val, sizeof(val), s);
6363 p = soap_set_cookie(soap, key, val, NULL, NULL);
6364 if (p)
6365 p->env = 1;
6366 } while (*s);
6367 return SOAP_OK;
6370 /******************************************************************************/
6371 SOAP_FMAC1
6372 struct soap_cookie*
6373 SOAP_FMAC2
6374 soap_copy_cookies(struct soap *copy, const struct soap *soap)
6375 { struct soap_cookie *p, **q, *r;
6376 q = &r;
6377 for (p = soap->cookies; p; p = p->next)
6378 { if (!(*q = (struct soap_cookie*)SOAP_MALLOC(copy, sizeof(struct soap_cookie))))
6379 return r;
6380 **q = *p;
6381 if (p->name)
6382 { if (((*q)->name = (char*)SOAP_MALLOC(copy, strlen(p->name)+1)))
6383 strcpy((*q)->name, p->name);
6385 if (p->value)
6386 { if (((*q)->value = (char*)SOAP_MALLOC(copy, strlen(p->value)+1)))
6387 strcpy((*q)->value, p->value);
6389 if (p->domain)
6390 { if (((*q)->domain = (char*)SOAP_MALLOC(copy, strlen(p->domain)+1)))
6391 strcpy((*q)->domain, p->domain);
6393 if (p->path)
6394 { if (((*q)->path = (char*)SOAP_MALLOC(copy, strlen(p->path)+1)))
6395 strcpy((*q)->path, p->path);
6397 q = &(*q)->next;
6399 *q = NULL;
6400 return r;
6403 /******************************************************************************/
6404 SOAP_FMAC1
6405 void
6406 SOAP_FMAC2
6407 soap_free_cookies(struct soap *soap)
6408 { struct soap_cookie *p;
6409 for (p = soap->cookies; p; p = soap->cookies)
6410 { soap->cookies = p->next;
6411 SOAP_FREE(soap, p->name);
6412 if (p->value)
6413 SOAP_FREE(soap, p->value);
6414 if (p->domain)
6415 SOAP_FREE(soap, p->domain);
6416 if (p->path)
6417 SOAP_FREE(soap, p->path);
6418 SOAP_FREE(soap, p);
6422 /******************************************************************************/
6423 #endif /* WITH_COOKIES */
6425 /******************************************************************************/
6426 #ifndef WITH_NOIDREF
6427 #ifndef PALM_2
6428 SOAP_FMAC1
6429 size_t
6430 SOAP_FMAC2
6431 soap_hash(register const char *s)
6432 { register size_t h = 0;
6433 while (*s)
6434 h = 65599*h + *s++;
6435 return h % SOAP_IDHASH;
6437 #endif
6438 #endif
6440 /******************************************************************************/
6441 #ifndef WITH_NOIDREF
6442 #ifndef PALM_1
6443 static void
6444 soap_init_pht(struct soap *soap)
6445 { register int i;
6446 soap->pblk = NULL;
6447 soap->pidx = 0;
6448 for (i = 0; i < (int)SOAP_PTRHASH; i++)
6449 soap->pht[i] = NULL;
6451 #endif
6452 #endif
6454 /******************************************************************************/
6455 #ifndef PALM_1
6456 SOAP_FMAC1
6457 struct soap*
6458 SOAP_FMAC2
6459 soap_new1(soap_mode mode)
6460 { return soap_new2(mode, mode);
6462 #endif
6464 /******************************************************************************/
6465 #ifndef PALM_1
6466 SOAP_FMAC1
6467 struct soap*
6468 SOAP_FMAC2
6469 soap_new()
6470 { return soap_new2(SOAP_IO_DEFAULT, SOAP_IO_DEFAULT);
6472 #endif
6474 /******************************************************************************/
6475 #ifndef PALM_1
6476 SOAP_FMAC1
6477 struct soap*
6478 SOAP_FMAC2
6479 soap_new2(soap_mode imode, soap_mode omode)
6480 { struct soap *soap = (struct soap*)malloc(sizeof(struct soap));
6481 if (soap)
6482 soap_init2(soap, imode, omode);
6483 return soap;
6485 #endif
6487 /******************************************************************************/
6488 #ifndef PALM_1
6489 SOAP_FMAC1
6490 void
6491 SOAP_FMAC2
6492 soap_free(struct soap *soap)
6493 { soap_done(soap);
6494 free(soap);
6496 #endif
6498 /******************************************************************************/
6499 #ifndef PALM_1
6500 SOAP_FMAC1
6501 void
6502 SOAP_FMAC2
6503 soap_del(struct soap *soap)
6504 { free(soap);
6506 #endif
6508 /******************************************************************************/
6509 #ifndef WITH_NOIDREF
6510 #ifndef PALM_1
6511 static void
6512 soap_free_pht(struct soap *soap)
6513 { register struct soap_pblk *pb, *next;
6514 register int i;
6515 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free pointer hashtable\n"));
6516 for (pb = soap->pblk; pb; pb = next)
6517 { next = pb->next;
6518 SOAP_FREE(soap, pb);
6520 soap->pblk = NULL;
6521 soap->pidx = 0;
6522 for (i = 0; i < (int)SOAP_PTRHASH; i++)
6523 soap->pht[i] = NULL;
6525 #endif
6526 #endif
6528 /******************************************************************************/
6529 #ifndef WITH_NOIDREF
6530 #ifndef PALM_2
6531 SOAP_FMAC1
6533 SOAP_FMAC2
6534 soap_embed(struct soap *soap, const void *p, const struct soap_array *a, int n, const char *tag, int type)
6535 { register int i;
6536 struct soap_plist *pp;
6537 if (soap->version == 2)
6538 soap->encoding = 1;
6539 if (a)
6540 i = soap_array_pointer_lookup(soap, p, a, n, type, &pp);
6541 else
6542 i = soap_pointer_lookup(soap, p, type, &pp);
6543 if (i)
6544 { if (soap_is_embedded(soap, pp)
6545 || soap_is_single(soap, pp))
6546 return 0;
6547 soap_set_embedded(soap, pp);
6549 return i;
6551 #endif
6552 #endif
6554 /******************************************************************************/
6555 #ifndef WITH_NOIDREF
6556 #ifndef PALM_2
6557 SOAP_FMAC1
6559 SOAP_FMAC2
6560 soap_pointer_lookup(struct soap *soap, const void *p, int type, struct soap_plist **ppp)
6561 { register struct soap_plist *pp;
6562 *ppp = NULL;
6563 if (p)
6564 { for (pp = soap->pht[soap_hash_ptr(p)]; pp; pp = pp->next)
6565 { if (pp->ptr == p && pp->type == type)
6566 { *ppp = pp;
6567 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Lookup location=%p type=%d id=%d\n", p, type, pp->id));
6568 return pp->id;
6572 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Lookup location=%p type=%d: not found\n", p, type));
6573 return 0;
6575 #endif
6576 #endif
6578 /******************************************************************************/
6579 #ifndef WITH_NOIDREF
6580 #ifndef PALM_2
6581 SOAP_FMAC1
6583 SOAP_FMAC2
6584 soap_pointer_enter(struct soap *soap, const void *p, const struct soap_array *a, int n, int type, struct soap_plist **ppp)
6585 { register size_t h;
6586 register struct soap_plist *pp;
6587 if (!soap->pblk || soap->pidx >= SOAP_PTRBLK)
6588 { register struct soap_pblk *pb = (struct soap_pblk*)SOAP_MALLOC(soap, sizeof(struct soap_pblk));
6589 if (!pb)
6590 { soap->error = SOAP_EOM;
6591 return 0;
6593 pb->next = soap->pblk;
6594 soap->pblk = pb;
6595 soap->pidx = 0;
6597 *ppp = pp = &soap->pblk->plist[soap->pidx++];
6598 if (a)
6599 h = soap_hash_ptr(a->__ptr);
6600 else
6601 h = soap_hash_ptr(p);
6602 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Pointer enter location=%p array=%p size=%d dim=%d type=%d id=%d\n", p, a?a->__ptr:NULL, a?a->__size:0, n, type, soap->idnum+1));
6603 pp->next = soap->pht[h];
6604 pp->type = type;
6605 pp->mark1 = 0;
6606 pp->mark2 = 0;
6607 pp->ptr = p;
6608 pp->array = a;
6609 soap->pht[h] = pp;
6610 pp->id = ++soap->idnum;
6611 return pp->id;
6613 #endif
6614 #endif
6616 /******************************************************************************/
6617 #ifndef WITH_NOIDREF
6618 #ifndef PALM_2
6619 SOAP_FMAC1
6621 SOAP_FMAC2
6622 soap_array_pointer_lookup(struct soap *soap, const void *p, const struct soap_array *a, int n, int type, struct soap_plist **ppp)
6623 { register struct soap_plist *pp;
6624 *ppp = NULL;
6625 if (!p || !a->__ptr)
6626 return 0;
6627 for (pp = soap->pht[soap_hash_ptr(a->__ptr)]; pp; pp = pp->next)
6628 { if (pp->type == type && pp->array && pp->array->__ptr == a->__ptr)
6629 { register int i;
6630 for (i = 0; i < n; i++)
6631 if (((const int*)&pp->array->__size)[i] != ((const int*)&a->__size)[i])
6632 break;
6633 if (i == n)
6634 { *ppp = pp;
6635 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array lookup location=%p type=%d id=%d\n", a->__ptr, type, pp->id));
6636 return pp->id;
6640 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array lookup location=%p type=%d: not found\n", a->__ptr, type));
6641 return 0;
6643 #endif
6644 #endif
6646 /******************************************************************************/
6647 #ifndef PALM_1
6648 SOAP_FMAC1
6650 SOAP_FMAC2
6651 soap_begin_count(struct soap *soap)
6652 { soap_free_ns(soap);
6653 #ifndef WITH_LEANER
6654 if ((soap->mode & SOAP_ENC_DIME) || (soap->omode & SOAP_ENC_DIME))
6655 soap->mode = soap->omode | SOAP_IO_LENGTH | SOAP_ENC_DIME;
6656 else
6657 #endif
6658 { soap->mode = soap->omode;
6659 if ((soap->mode & SOAP_IO_UDP))
6660 soap->mode |= SOAP_ENC_XML;
6661 if ((soap->mode & SOAP_IO) == SOAP_IO_STORE
6662 || (((soap->mode & SOAP_IO) == SOAP_IO_CHUNK || (soap->mode & SOAP_ENC_XML))
6663 #ifndef WITH_LEANER
6664 && !soap->fpreparesend
6665 #endif
6667 soap->mode &= ~SOAP_IO_LENGTH;
6668 else
6669 soap->mode |= SOAP_IO_LENGTH;
6671 #ifdef WITH_ZLIB
6672 if ((soap->mode & SOAP_ENC_ZLIB) && (soap->mode & SOAP_IO) == SOAP_IO_FLUSH)
6673 { if (!(soap->mode & SOAP_ENC_DIME))
6674 soap->mode &= ~SOAP_IO_LENGTH;
6675 if (soap->mode & SOAP_ENC_XML)
6676 soap->mode |= SOAP_IO_BUFFER;
6677 else
6678 soap->mode |= SOAP_IO_STORE;
6680 #endif
6681 if (!soap->encodingStyle && !(soap->mode & SOAP_XML_GRAPH))
6682 soap->mode |= SOAP_XML_TREE;
6683 #ifndef WITH_LEANER
6684 if ((soap->mode & SOAP_ENC_MTOM) && (soap->mode & SOAP_ENC_DIME))
6685 soap->mode |= SOAP_ENC_MIME;
6686 else if (!(soap->mode & SOAP_ENC_MIME))
6687 soap->mode &= ~SOAP_ENC_MTOM;
6688 if (soap->mode & SOAP_ENC_MIME)
6689 soap_select_mime_boundary(soap);
6690 soap->dime.list = soap->dime.last; /* keep track of last DIME attachment */
6691 #endif
6692 soap->count = 0;
6693 soap->ns = 0;
6694 soap->null = 0;
6695 soap->position = 0;
6696 soap->mustUnderstand = 0;
6697 soap->encoding = 0;
6698 soap->part = SOAP_BEGIN;
6699 soap->idnum = 0;
6700 soap_clr_attr(soap);
6701 soap_set_local_namespaces(soap);
6702 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Begin count phase (socket=%d mode=0x%x count=%lu)\n", soap->socket, (unsigned int)soap->mode, (unsigned long)soap->count));
6703 #ifndef WITH_LEANER
6704 soap->dime.count = 0; /* count # of attachments */
6705 soap->dime.size = 0; /* accumulate total size of attachments */
6706 if (soap->fprepareinitsend && (soap->mode & SOAP_IO) != SOAP_IO_STORE)
6707 return soap->error = soap->fprepareinitsend(soap);
6708 #endif
6709 return SOAP_OK;
6711 #endif
6713 /******************************************************************************/
6714 #ifndef PALM_1
6715 SOAP_FMAC1
6717 SOAP_FMAC2
6718 soap_end_count(struct soap *soap)
6719 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End of count phase\n"));
6720 #ifndef WITH_LEANER
6721 if (soap->fpreparefinalsend && (soap->mode & SOAP_IO_LENGTH))
6722 return soap->error = soap->fpreparefinalsend(soap);
6723 #endif
6724 return SOAP_OK;
6726 #endif
6728 /******************************************************************************/
6729 #ifndef PALM_1
6730 SOAP_FMAC1
6732 SOAP_FMAC2
6733 soap_begin_send(struct soap *soap)
6734 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Initializing for output\n"));
6735 soap_free_ns(soap);
6736 soap->error = SOAP_OK;
6737 soap->mode = soap->omode | (soap->mode & (SOAP_IO_LENGTH | SOAP_ENC_DIME));
6738 #ifdef WITH_ZLIB
6739 if ((soap->mode & SOAP_ENC_ZLIB) && (soap->mode & SOAP_IO) == SOAP_IO_FLUSH)
6740 { if (soap->mode & SOAP_ENC_XML)
6741 soap->mode |= SOAP_IO_BUFFER;
6742 else
6743 soap->mode |= SOAP_IO_STORE;
6745 #endif
6746 #ifndef WITH_LEAN
6747 if ((soap->mode & SOAP_IO_UDP))
6748 { soap->mode |= SOAP_ENC_XML;
6749 if (soap->count > SOAP_BUFLEN)
6750 return soap->error = SOAP_UDP_ERROR;
6752 #endif
6753 if ((soap->mode & SOAP_IO) == SOAP_IO_FLUSH && soap_valid_socket(soap->socket))
6754 { if (soap->count || (soap->mode & SOAP_IO_LENGTH) || (soap->mode & SOAP_ENC_XML))
6755 soap->mode |= SOAP_IO_BUFFER;
6756 else
6757 soap->mode |= SOAP_IO_STORE;
6759 soap->mode &= ~SOAP_IO_LENGTH;
6760 if ((soap->mode & SOAP_IO) == SOAP_IO_STORE)
6761 if (soap_new_block(soap) == NULL)
6762 return soap->error;
6763 if (!(soap->mode & SOAP_IO_KEEPALIVE))
6764 soap->keep_alive = 0;
6765 if (!soap->encodingStyle && !(soap->mode & SOAP_XML_GRAPH))
6766 soap->mode |= SOAP_XML_TREE;
6767 #ifndef WITH_LEANER
6768 if ((soap->mode & SOAP_ENC_MTOM) && (soap->mode & SOAP_ENC_DIME))
6769 { soap->mode |= SOAP_ENC_MIME;
6770 soap->mode &= ~SOAP_ENC_DIME;
6772 else if (!(soap->mode & SOAP_ENC_MIME))
6773 soap->mode &= ~SOAP_ENC_MTOM;
6774 if (soap->mode & SOAP_ENC_MIME)
6775 soap_select_mime_boundary(soap);
6776 #ifdef WIN32
6777 #ifndef UNDER_CE
6778 #ifndef WITH_FASTCGI
6779 if (!soap_valid_socket(soap->socket)) /* Set win32 stdout or soap->sendfd to BINARY, e.g. to support DIME */
6780 #ifdef __BORLANDC__
6781 setmode(soap->sendfd, _O_BINARY);
6782 #else
6783 _setmode(soap->sendfd, _O_BINARY);
6784 #endif
6785 #endif
6786 #endif
6787 #endif
6788 #endif
6789 if (soap->mode & SOAP_IO)
6790 { soap->bufidx = 0;
6791 soap->buflen = 0;
6793 soap->chunksize = 0;
6794 soap->ns = 0;
6795 soap->null = 0;
6796 soap->position = 0;
6797 soap->mustUnderstand = 0;
6798 soap->encoding = 0;
6799 soap->idnum = 0;
6800 soap->level = 0;
6801 soap_clr_attr(soap);
6802 soap_set_local_namespaces(soap);
6803 #ifdef WITH_ZLIB
6804 soap->z_ratio_out = 1.0;
6805 if ((soap->mode & SOAP_ENC_ZLIB) && soap->zlib_state != SOAP_ZLIB_DEFLATE)
6806 { if (!soap->z_buf)
6807 soap->z_buf = (char*)SOAP_MALLOC(soap, SOAP_BUFLEN);
6808 soap->d_stream->next_out = (Byte*)soap->z_buf;
6809 soap->d_stream->avail_out = SOAP_BUFLEN;
6810 #ifdef WITH_GZIP
6811 if (soap->zlib_out != SOAP_ZLIB_DEFLATE)
6812 { memcpy(soap->z_buf, "\37\213\10\0\0\0\0\0\0\377", 10);
6813 soap->d_stream->next_out = (Byte*)soap->z_buf + 10;
6814 soap->d_stream->avail_out = SOAP_BUFLEN - 10;
6815 soap->z_crc = crc32(0L, NULL, 0);
6816 soap->zlib_out = SOAP_ZLIB_GZIP;
6817 if (soap->z_dict)
6818 *((Byte*)soap->z_buf + 2) = 0xff;
6819 if (deflateInit2(soap->d_stream, soap->z_level, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK)
6820 return soap->error = SOAP_ZLIB_ERROR;
6822 else
6823 #endif
6824 if (deflateInit(soap->d_stream, soap->z_level) != Z_OK)
6825 return soap->error = SOAP_ZLIB_ERROR;
6826 if (soap->z_dict)
6827 { if (deflateSetDictionary(soap->d_stream, (const Bytef*)soap->z_dict, soap->z_dict_len) != Z_OK)
6828 return soap->error = SOAP_ZLIB_ERROR;
6830 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Deflate initialized\n"));
6831 soap->zlib_state = SOAP_ZLIB_DEFLATE;
6833 #endif
6834 #ifdef WITH_OPENSSL
6835 if (soap->ssl)
6836 ERR_clear_error();
6837 #endif
6838 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Begin send phase (socket=%d mode=0x%x count=%lu)\n", soap->socket, soap->mode, (unsigned long)soap->count));
6839 soap->part = SOAP_BEGIN;
6840 #ifndef WITH_LEANER
6841 if (soap->fprepareinitsend && (soap->mode & SOAP_IO) == SOAP_IO_STORE)
6842 soap->fprepareinitsend(soap);
6843 #endif
6844 return SOAP_OK;
6846 #endif
6848 /******************************************************************************/
6849 #ifndef WITH_NOIDREF
6850 #ifndef PALM_2
6851 SOAP_FMAC1
6852 void
6853 SOAP_FMAC2
6854 soap_embedded(struct soap *soap, const void *p, int t)
6855 { struct soap_plist *pp;
6856 if (soap_pointer_lookup(soap, p, t, &pp))
6857 { pp->mark1 = 1;
6858 pp->mark2 = 1;
6859 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Embedded %p type=%d mark set to 1\n", p, t));
6862 #endif
6863 #endif
6865 /******************************************************************************/
6866 #ifndef WITH_NOIDREF
6867 #ifndef PALM_2
6868 SOAP_FMAC1
6870 SOAP_FMAC2
6871 soap_reference(struct soap *soap, const void *p, int t)
6872 { struct soap_plist *pp;
6873 if (!p || (soap->mode & SOAP_XML_TREE))
6874 return 1;
6875 if (soap_pointer_lookup(soap, p, t, &pp))
6876 { if (pp->mark1 == 0)
6877 { pp->mark1 = 2;
6878 pp->mark2 = 2;
6881 else if (soap_pointer_enter(soap, p, NULL, 0, t, &pp))
6882 { pp->mark1 = 0;
6883 pp->mark2 = 0;
6885 else
6886 return 1;
6887 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Reference %p type=%d (%d %d)\n", p, t, (int)pp->mark1, (int)pp->mark2));
6888 return pp->mark1;
6890 #endif
6891 #endif
6893 /******************************************************************************/
6894 #ifndef WITH_NOIDREF
6895 #ifndef PALM_2
6896 SOAP_FMAC1
6898 SOAP_FMAC2
6899 soap_array_reference(struct soap *soap, const void *p, const struct soap_array *a, int n, int t)
6900 { register int i;
6901 struct soap_plist *pp;
6902 if (!p || !a->__ptr)
6903 return 1;
6904 i = soap_array_pointer_lookup(soap, p, a, n, t, &pp);
6905 if (i)
6906 { if (pp->mark1 == 0)
6907 { pp->mark1 = 2;
6908 pp->mark2 = 2;
6911 else if (!soap_pointer_enter(soap, p, a, n, t, &pp))
6912 return 1;
6913 else
6914 { pp->mark1 = 0;
6915 pp->mark2 = 0;
6917 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array reference %p ptr=%p dim=%d type=%d (%d %d)\n", p, a->__ptr, n, t, (int)pp->mark1, (int)pp->mark2));
6918 return pp->mark1;
6920 #endif
6921 #endif
6923 /******************************************************************************/
6924 #ifndef WITH_NOIDREF
6925 #ifndef PALM_2
6926 SOAP_FMAC1
6928 SOAP_FMAC2
6929 soap_embedded_id(struct soap *soap, int id, const void *p, int t)
6930 { struct soap_plist *pp = NULL;
6931 if (soap->mode & SOAP_XML_TREE)
6932 return id;
6933 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Embedded_id %p type=%d id=%d\n", p, t, id));
6934 if (soap->version == 1 && soap->encodingStyle && !(soap->mode & SOAP_XML_GRAPH) && soap->part != SOAP_IN_HEADER)
6935 { if (id < 0)
6936 { id = soap_pointer_lookup(soap, p, t, &pp);
6937 if (id)
6938 { if (soap->mode & SOAP_IO_LENGTH)
6939 pp->mark1 = 2;
6940 else
6941 pp->mark2 = 2;
6942 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Embedded_id multiref id=%d %p type=%d = (%d %d)\n", id, p, t, (int)pp->mark1, (int)pp->mark2));
6944 return -1;
6946 return id;
6948 if (id < 0)
6949 id = soap_pointer_lookup(soap, p, t, &pp);
6950 else if (id && !soap_pointer_lookup(soap, p, t, &pp))
6951 return 0;
6952 if (id && pp)
6953 { if (soap->mode & SOAP_IO_LENGTH)
6954 pp->mark1 = 1;
6955 else
6956 pp->mark2 = 1;
6957 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Embedded_id embedded ref id=%d %p type=%d = (%d %d)\n", id, p, t, (int)pp->mark1, (int)pp->mark2));
6959 return id;
6961 #endif
6962 #endif
6964 /******************************************************************************/
6965 #ifndef WITH_NOIDREF
6966 #ifndef PALM_2
6967 SOAP_FMAC1
6969 SOAP_FMAC2
6970 soap_is_embedded(struct soap *soap, struct soap_plist *pp)
6971 { if (!pp)
6972 return 0;
6973 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Is embedded? %d %d\n", (int)pp->mark1, (int)pp->mark2));
6974 if (soap->version == 1 && soap->encodingStyle && !(soap->mode & SOAP_XML_GRAPH) && soap->part != SOAP_IN_HEADER)
6975 { if (soap->mode & SOAP_IO_LENGTH)
6976 return pp->mark1 != 0;
6977 return pp->mark2 != 0;
6979 if (soap->mode & SOAP_IO_LENGTH)
6980 return pp->mark1 == 1;
6981 return pp->mark2 == 1;
6983 #endif
6984 #endif
6986 /******************************************************************************/
6987 #ifndef WITH_NOIDREF
6988 #ifndef PALM_2
6989 SOAP_FMAC1
6991 SOAP_FMAC2
6992 soap_is_single(struct soap *soap, struct soap_plist *pp)
6993 { if (soap->part == SOAP_IN_HEADER)
6994 return 1;
6995 if (!pp)
6996 return 0;
6997 if (soap->mode & SOAP_IO_LENGTH)
6998 return pp->mark1 == 0;
6999 return pp->mark2 == 0;
7001 #endif
7002 #endif
7004 /******************************************************************************/
7005 #ifndef WITH_NOIDREF
7006 #ifndef PALM_2
7007 SOAP_FMAC1
7008 void
7009 SOAP_FMAC2
7010 soap_set_embedded(struct soap *soap, struct soap_plist *pp)
7011 { if (!pp)
7012 return;
7013 if (soap->mode & SOAP_IO_LENGTH)
7014 pp->mark1 = 1;
7015 else
7016 pp->mark2 = 1;
7018 #endif
7019 #endif
7021 /******************************************************************************/
7022 #ifndef WITH_LEANER
7023 #ifndef PALM_1
7024 SOAP_FMAC1
7026 SOAP_FMAC2
7027 soap_attachment(struct soap *soap, const char *tag, int id, const void *p, const struct soap_array *a, const char *aid, const char *atype, const char *aoptions, int n, const char *type, int t)
7029 #ifndef WITH_NOIDREF
7030 struct soap_plist *pp;
7031 int i;
7032 if (!p || !a->__ptr || (!aid && !atype))
7033 return soap_element_id(soap, tag, id, p, a, n, type, t);
7034 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Attachment tag='%s' id='%s' (%d) type='%s'\n", tag, aid?aid:SOAP_STR_EOS, id, atype?atype:SOAP_STR_EOS));
7035 i = soap_array_pointer_lookup(soap, p, a, n, t, &pp);
7036 if (!i)
7037 { i = soap_pointer_enter(soap, p, a, n, t, &pp);
7038 if (!i)
7039 { soap->error = SOAP_EOM;
7040 return -1;
7043 if (id <= 0)
7044 id = i;
7045 if (!aid)
7046 { sprintf(soap->tmpbuf, soap->dime_id_format, id);
7047 aid = soap_strdup(soap, soap->tmpbuf);
7049 /* Add MTOM xop:Include element when necessary */
7050 /* TODO: this code to be obsoleted with new import/xop.h conventions */
7051 if ((soap->mode & SOAP_ENC_MTOM) && strcmp(tag, "xop:Include"))
7052 { if (soap_element_begin_out(soap, tag, 0, type)
7053 || soap_element_href(soap, "xop:Include", 0, "xmlns:xop=\"http://www.w3.org/2004/08/xop/include\" href", aid)
7054 || soap_element_end_out(soap, tag))
7055 return soap->error;
7057 else if (soap_element_href(soap, tag, 0, "href", aid))
7058 return soap->error;
7059 if (soap->mode & SOAP_IO_LENGTH)
7060 { if (pp->mark1 != 3)
7061 { struct soap_multipart *content;
7062 if (soap->mode & SOAP_ENC_MTOM)
7063 content = soap_new_multipart(soap, &soap->mime.first, &soap->mime.last, (char*)a->__ptr, a->__size);
7064 else
7065 content = soap_new_multipart(soap, &soap->dime.first, &soap->dime.last, (char*)a->__ptr, a->__size);
7066 if (!content)
7067 { soap->error = SOAP_EOM;
7068 return -1;
7070 if (!strncmp(aid, "cid:", 4)) /* RFC 2111 */
7071 { if (soap->mode & SOAP_ENC_MTOM)
7072 { char *s = (char*)soap_malloc(soap, strlen(aid) - 1);
7073 if (s)
7074 { *s = '<';
7075 strcpy(s + 1, aid + 4);
7076 strcat(s, ">");
7077 content->id = s;
7080 else
7081 content->id = aid + 4;
7083 else
7084 content->id = aid;
7085 content->type = atype;
7086 content->options = aoptions;
7087 content->encoding = SOAP_MIME_BINARY;
7088 pp->mark1 = 3;
7091 else
7092 pp->mark2 = 3;
7093 #endif
7094 return -1;
7096 #endif
7097 #endif
7099 /******************************************************************************/
7100 #ifndef WITH_NOIDREF
7101 #ifndef PALM_1
7102 static void
7103 soap_init_iht(struct soap *soap)
7104 { register int i;
7105 for (i = 0; i < SOAP_IDHASH; i++)
7106 soap->iht[i] = NULL;
7108 #endif
7109 #endif
7111 /******************************************************************************/
7112 #ifndef WITH_NOIDREF
7113 #ifndef PALM_1
7114 static void
7115 soap_free_iht(struct soap *soap)
7116 { register int i;
7117 register struct soap_ilist *ip = NULL, *p = NULL;
7118 register struct soap_flist *fp = NULL, *fq = NULL;
7119 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free ID hashtable\n"));
7120 for (i = 0; i < SOAP_IDHASH; i++)
7121 { for (ip = soap->iht[i]; ip; ip = p)
7122 { for (fp = ip->flist; fp; fp = fq)
7123 { fq = fp->next;
7124 SOAP_FREE(soap, fp);
7126 p = ip->next;
7127 SOAP_FREE(soap, ip);
7129 soap->iht[i] = NULL;
7132 #endif
7133 #endif
7135 /******************************************************************************/
7136 #ifndef WITH_NOIDREF
7137 #ifndef PALM_2
7138 SOAP_FMAC1
7139 struct soap_ilist *
7140 SOAP_FMAC2
7141 soap_lookup(struct soap *soap, const char *id)
7142 { register struct soap_ilist *ip = NULL;
7143 for (ip = soap->iht[soap_hash(id)]; ip; ip = ip->next)
7144 if (!strcmp(ip->id, id))
7145 return ip;
7146 return NULL;
7148 #endif
7149 #endif
7151 /******************************************************************************/
7152 #ifndef WITH_NOIDREF
7153 #ifndef PALM_2
7154 SOAP_FMAC1
7155 struct soap_ilist *
7156 SOAP_FMAC2
7157 soap_enter(struct soap *soap, const char *id)
7158 { register size_t h;
7159 register struct soap_ilist *ip;
7160 ip = (struct soap_ilist*)SOAP_MALLOC(soap, sizeof(struct soap_ilist) + strlen(id));
7161 if (ip)
7162 { h = soap_hash(id);
7163 strcpy(ip->id, id);
7164 ip->next = soap->iht[h];
7165 soap->iht[h] = ip;
7167 return ip;
7169 #endif
7170 #endif
7172 /******************************************************************************/
7173 #ifndef PALM_2
7174 SOAP_FMAC1
7175 void*
7176 SOAP_FMAC2
7177 soap_malloc(struct soap *soap, size_t n)
7178 { register char *p;
7179 if (!n)
7180 return (void*)SOAP_NON_NULL;
7181 if (!soap)
7182 return SOAP_MALLOC(soap, n);
7183 if (soap->fmalloc)
7184 p = (char*)soap->fmalloc(soap, n);
7185 else
7186 { n += sizeof(short);
7187 n += (-(long)n) & (sizeof(void*)-1); /* align at 4-, 8- or 16-byte boundary */
7188 if (!(p = (char*)SOAP_MALLOC(soap, n + sizeof(void*) + sizeof(size_t))))
7189 { soap->error = SOAP_EOM;
7190 return NULL;
7192 /* set the canary to detect corruption */
7193 *(unsigned short*)(p + n - sizeof(unsigned short)) = (unsigned short)SOAP_CANARY;
7194 /* keep chain of alloced cells for destruction */
7195 *(void**)(p + n) = soap->alist;
7196 *(size_t*)(p + n + sizeof(void*)) = n;
7197 soap->alist = p + n;
7199 soap->alloced = 1;
7200 return p;
7202 #endif
7204 /******************************************************************************/
7205 #ifdef SOAP_MEM_DEBUG
7206 static void
7207 soap_init_mht(struct soap *soap)
7208 { register int i;
7209 for (i = 0; i < (int)SOAP_PTRHASH; i++)
7210 soap->mht[i] = NULL;
7212 #endif
7214 /******************************************************************************/
7215 #ifdef SOAP_MEM_DEBUG
7216 static void
7217 soap_free_mht(struct soap *soap)
7218 { register int i;
7219 register struct soap_mlist *mp, *mq;
7220 for (i = 0; i < (int)SOAP_PTRHASH; i++)
7221 { for (mp = soap->mht[i]; mp; mp = mq)
7222 { mq = mp->next;
7223 if (mp->live)
7224 fprintf(stderr, "%s(%d): malloc() = %p not freed (memory leak or forgot to call soap_end()?)\n", mp->file, mp->line, mp->ptr);
7225 free(mp);
7227 soap->mht[i] = NULL;
7230 #endif
7232 /******************************************************************************/
7233 #ifdef SOAP_MEM_DEBUG
7234 SOAP_FMAC1
7235 void*
7236 SOAP_FMAC2
7237 soap_track_malloc(struct soap *soap, const char *file, int line, size_t size)
7238 { register void *p = malloc(size);
7239 if (soap)
7240 { register size_t h = soap_hash_ptr(p);
7241 register struct soap_mlist *mp = (struct soap_mlist*)malloc(sizeof(struct soap_mlist));
7242 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "%s(%d): malloc(%lu) = %p\n", file, line, (unsigned long)size, p));
7243 mp->next = soap->mht[h];
7244 mp->ptr = p;
7245 mp->file = file;
7246 mp->line = line;
7247 mp->live = 1;
7248 soap->mht[h] = mp;
7250 return p;
7252 #endif
7254 /******************************************************************************/
7255 #ifdef SOAP_MEM_DEBUG
7256 SOAP_FMAC1
7257 void
7258 SOAP_FMAC2
7259 soap_track_free(struct soap *soap, const char *file, int line, void *p)
7260 { register size_t h = soap_hash_ptr(p);
7261 register struct soap_mlist *mp;
7262 for (mp = soap->mht[h]; mp; mp = mp->next)
7263 if (mp->ptr == p)
7264 break;
7265 if (mp)
7266 { if (mp->live)
7267 { free(p);
7268 if (soap->fdebug[SOAP_INDEX_TEST])
7269 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "%s(%d): free(%p)\n", file, line, p));
7271 mp->live = 0;
7273 else
7274 fprintf(stderr, "%s(%d): free(%p) double free of pointer malloced at %s(%d)\n", file, line, p, mp->file, mp->line);
7276 else
7277 fprintf(stderr, "%s(%d): free(%p) pointer not malloced\n", file, line, p);
7279 #endif
7281 /******************************************************************************/
7282 #ifdef SOAP_MEM_DEBUG
7283 static void
7284 soap_track_unlink(struct soap *soap, const void *p)
7285 { register size_t h = soap_hash_ptr(p);
7286 register struct soap_mlist *mp;
7287 for (mp = soap->mht[h]; mp; mp = mp->next)
7288 if (mp->ptr == p)
7289 break;
7290 if (mp)
7291 mp->live = 0;
7293 #endif
7295 /******************************************************************************/
7296 #ifndef PALM_2
7297 SOAP_FMAC1
7298 void
7299 SOAP_FMAC2
7300 soap_dealloc(struct soap *soap, void *p)
7301 { if (soap_check_state(soap))
7302 return;
7303 if (p)
7304 { register char **q;
7305 for (q = (char**)&soap->alist; *q; q = *(char***)q)
7307 if (*(unsigned short*)(char*)(*q - sizeof(unsigned short)) != (unsigned short)SOAP_CANARY)
7309 #ifdef SOAP_MEM_DEBUG
7310 fprintf(stderr, "Data corruption in dynamic allocation (see logs)\n");
7311 #endif
7312 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Data corruption:\n"));
7313 DBGHEX(TEST, *q - 200, 200);
7314 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n"));
7315 soap->error = SOAP_MOE;
7316 return;
7318 if (p == (void*)(*q - *(size_t*)(*q + sizeof(void*))))
7319 { *q = **(char***)q;
7320 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Freed data at %p\n", p));
7321 SOAP_FREE(soap, p);
7322 return;
7325 soap_delete(soap, p);
7327 else
7328 { register char *q;
7329 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free all soap_malloc() data\n"));
7330 while (soap->alist)
7331 { q = (char*)soap->alist;
7332 if (*(unsigned short*)(char*)(q - sizeof(unsigned short)) != (unsigned short)SOAP_CANARY)
7334 #ifdef SOAP_MEM_DEBUG
7335 fprintf(stderr, "Data corruption in dynamic allocation (see logs)\n");
7336 #endif
7337 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Data corruption:\n"));
7338 DBGHEX(TEST, q - 200, 200);
7339 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n"));
7340 soap->error = SOAP_MOE;
7341 return;
7343 soap->alist = *(void**)q;
7344 q -= *(size_t*)(q + sizeof(void*));
7345 SOAP_FREE(soap, q);
7347 /* we must assume these were deallocated: */
7348 soap->action = NULL;
7349 soap->fault = NULL;
7350 soap->header = NULL;
7351 soap->userid = NULL;
7352 soap->passwd = NULL;
7353 soap->authrealm = NULL;
7354 soap->http_content = NULL;
7355 #ifndef WITH_LEANER
7356 soap_clr_mime(soap);
7357 #endif
7360 #endif
7362 /******************************************************************************/
7363 #ifndef PALM_2
7364 SOAP_FMAC1
7365 void
7366 SOAP_FMAC2
7367 soap_delete(struct soap *soap, void *p)
7368 { register struct soap_clist **cp;
7369 if (soap_check_state(soap))
7370 return;
7371 cp = &soap->clist;
7372 if (p)
7373 { while (*cp)
7374 { if (p == (*cp)->ptr)
7375 { register struct soap_clist *q = *cp;
7376 *cp = q->next;
7377 if (q->fdelete(q))
7378 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not dealloc data %p: deletion callback failed for object type %d\n", q->ptr, q->type));
7379 #ifdef SOAP_MEM_DEBUG
7380 fprintf(stderr, "new(object type = %d) = %p not freed: deletion callback failed\n", q->type, q->ptr);
7381 #endif
7383 SOAP_FREE(soap, q);
7384 return;
7386 cp = &(*cp)->next;
7388 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not dealloc data %p: address not in list\n", p));
7390 else
7391 { while (*cp)
7392 { register struct soap_clist *q = *cp;
7393 *cp = q->next;
7394 if (q->fdelete(q))
7395 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not dealloc data %p: deletion callback failed for object type %d\n", q->ptr, q->type));
7396 #ifdef SOAP_MEM_DEBUG
7397 fprintf(stderr, "new(object type = %d) = %p not freed: deletion callback failed\n", q->type, q->ptr);
7398 #endif
7400 SOAP_FREE(soap, q);
7403 soap->fault = NULL; /* this was possibly deallocated */
7404 soap->header = NULL; /* this was possibly deallocated */
7406 #endif
7408 /******************************************************************************/
7409 #ifndef PALM_2
7410 SOAP_FMAC1
7411 void
7412 SOAP_FMAC2
7413 soap_delegate_deletion(struct soap *soap, struct soap *soap_to)
7414 { register struct soap_clist *cp;
7415 register char **q;
7416 #ifdef SOAP_MEM_DEBUG
7417 register void *p;
7418 register struct soap_mlist **mp, *mq;
7419 size_t h;
7420 #endif
7421 for (q = (char**)&soap->alist; *q; q = *(char***)q)
7423 if (*(unsigned short*)(char*)(*q - sizeof(unsigned short)) != (unsigned short)SOAP_CANARY)
7425 #ifdef SOAP_MEM_DEBUG
7426 fprintf(stderr, "Data corruption in dynamic allocation (see logs)\n");
7427 #endif
7428 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Data corruption:\n"));
7429 DBGHEX(TEST, *q - 200, 200);
7430 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n"));
7431 soap->error = SOAP_MOE;
7432 return;
7434 #ifdef SOAP_MEM_DEBUG
7435 p = (void*)(*q - *(size_t*)(*q + sizeof(void*)));
7436 h = soap_hash_ptr(p);
7437 for (mp = &soap->mht[h]; *mp; mp = &(*mp)->next)
7438 { if ((*mp)->ptr == p)
7439 { mq = *mp;
7440 *mp = mq->next;
7441 mq->next = soap_to->mht[h];
7442 soap_to->mht[h] = mq;
7443 break;
7446 #endif
7448 *q = (char*)soap_to->alist;
7449 soap_to->alist = soap->alist;
7450 soap->alist = NULL;
7451 cp = soap_to->clist;
7452 if (cp)
7453 { while (cp->next)
7454 cp = cp->next;
7455 cp->next = soap->clist;
7457 else
7458 soap_to->clist = soap->clist;
7459 soap->clist = NULL;
7461 #endif
7463 /******************************************************************************/
7464 #ifndef PALM_2
7465 SOAP_FMAC1
7466 struct soap_clist *
7467 SOAP_FMAC2
7468 soap_link(struct soap *soap, void *p, int t, int n, int (*fdelete)(struct soap_clist*))
7469 { register struct soap_clist *cp;
7470 if ((cp = (struct soap_clist*)SOAP_MALLOC(soap, sizeof(struct soap_clist))))
7471 { cp->next = soap->clist;
7472 cp->type = t;
7473 cp->size = n;
7474 cp->ptr = p;
7475 cp->fdelete = fdelete;
7476 soap->clist = cp;
7478 return cp;
7480 #endif
7482 /******************************************************************************/
7483 #ifndef PALM_2
7484 SOAP_FMAC1
7485 void
7486 SOAP_FMAC2
7487 soap_unlink(struct soap *soap, const void *p)
7488 { register char **q;
7489 register struct soap_clist **cp;
7490 if (!soap || !p)
7491 return;
7492 for (q = (char**)&soap->alist; *q; q = *(char***)q)
7493 { if (p == (void*)(*q - *(size_t*)(*q + sizeof(void*))))
7494 { *q = **(char***)q;
7495 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unlinked data %p\n", p));
7496 #ifdef SOAP_MEM_DEBUG
7497 soap_track_unlink(soap, p);
7498 #endif
7499 return;
7502 for (cp = &soap->clist; *cp; cp = &(*cp)->next)
7503 { if (p == (*cp)->ptr)
7504 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unlinked class instance %p\n", p));
7505 q = (char**)*cp;
7506 *cp = (*cp)->next;
7507 SOAP_FREE(soap, q);
7508 return;
7512 #endif
7514 /******************************************************************************/
7515 #ifndef WITH_NOIDREF
7516 #ifndef PALM_2
7517 SOAP_FMAC1
7519 SOAP_FMAC2
7520 soap_lookup_type(struct soap *soap, const char *id)
7521 { register struct soap_ilist *ip;
7522 if (id && *id)
7523 { ip = soap_lookup(soap, id);
7524 if (ip)
7525 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Lookup id='%s' type=%d\n", id, ip->type));
7526 return ip->type;
7529 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "lookup type id='%s' NOT FOUND! Need to get it from xsi:type\n", id));
7530 return 0;
7532 #endif
7533 #endif
7535 /******************************************************************************/
7536 #ifndef WITH_NOIDREF
7537 #ifndef PALM_2
7538 SOAP_FMAC1
7539 void*
7540 SOAP_FMAC2
7541 soap_id_lookup(struct soap *soap, const char *id, void **p, int t, size_t n, unsigned int k)
7542 { struct soap_ilist *ip;
7543 void **q;
7544 if (!p || !id || !*id)
7545 return p;
7546 ip = soap_lookup(soap, id); /* lookup pointer to hash table entry for string id */
7547 if (!ip)
7548 { if (!(ip = soap_enter(soap, id))) /* new hash table entry for string id */
7549 return NULL;
7550 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarding first href='%s' type=%d %p (%u bytes)\n", id, t, p, (unsigned int)n));
7551 ip->type = t;
7552 ip->size = n;
7553 ip->link = p;
7554 ip->copy = NULL;
7555 ip->flist = NULL;
7556 ip->ptr = NULL;
7557 ip->level = k;
7558 *p = NULL;
7560 else if (ip->ptr)
7561 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolved href='%s' type=%d location=%p (%u bytes)\n", id, t, ip->ptr, (unsigned int)n));
7562 if (ip->type != t)
7563 { strcpy(soap->id, id);
7564 soap->error = SOAP_HREF;
7565 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Type incompatibility: href='%s' id-type=%d href-type=%d\n", id, ip->type, t));
7566 return NULL;
7568 while (ip->level < k)
7569 { q = (void**)soap_malloc(soap, sizeof(void*));
7570 if (!q)
7571 return NULL;
7572 *p = (void*)q;
7573 p = q;
7574 k--;
7575 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Descending one level...\n"));
7577 *p = ip->ptr;
7579 else if (ip->level > k)
7580 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolving level %u pointers to href='%s'\n", ip->level, id));
7581 while (ip->level > k)
7582 { void *s, **r = &ip->link;
7583 q = (void**)ip->link;
7584 while (q)
7585 { *r = (void*)soap_malloc(soap, sizeof(void*));
7586 if (!*r)
7587 return NULL;
7588 s = *q;
7589 *q = *r;
7590 r = (void**)*r;
7591 q = (void**)s;
7593 *r = NULL;
7594 ip->size = n;
7595 ip->copy = NULL;
7596 ip->level = ip->level - 1;
7597 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Descending one level...\n"));
7599 q = (void**)ip->link;
7600 ip->link = p;
7601 *p = (void*)q;
7603 else
7604 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarded href='%s' type=%d location=%p (%u bytes)\n", id, t, p, (unsigned int)n));
7605 while (ip->level < k)
7606 { q = (void**)soap_malloc(soap, sizeof(void*));
7607 if (!q)
7608 return NULL;
7609 *p = q;
7610 p = q;
7611 k--;
7612 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Descending one level...\n"));
7614 q = (void**)ip->link;
7615 ip->link = p;
7616 *p = (void*)q;
7618 return p;
7620 #endif
7621 #endif
7623 /******************************************************************************/
7624 #ifndef WITH_NOIDREF
7625 #ifndef PALM_2
7626 SOAP_FMAC1
7627 void*
7628 SOAP_FMAC2
7629 soap_id_forward(struct soap *soap, const char *href, void *p, size_t len, int st, int tt, size_t n, unsigned int k, void (*fcopy)(struct soap*, int, int, void*, size_t, const void*, size_t))
7630 { struct soap_ilist *ip;
7631 if (!p || !href || !*href)
7632 return p;
7633 ip = soap_lookup(soap, href); /* lookup pointer to hash table entry for string id */
7634 if (!ip)
7635 { if (!(ip = soap_enter(soap, href))) /* new hash table entry for string id */
7636 return NULL;
7637 ip->type = st;
7638 ip->size = n;
7639 ip->link = NULL;
7640 ip->copy = NULL;
7641 ip->ptr = NULL;
7642 ip->level = 0;
7643 ip->flist = NULL;
7644 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "New entry href='%s' type=%d size=%lu level=%d location=%p\n", href, st, (unsigned long)n, k, p));
7646 else if (ip->type != st || (ip->level == k && ip->size != n))
7647 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Type incompatibility id='%s' expect type=%d size=%lu level=%u got type=%d size=%lu\n", href, ip->type, (unsigned long)ip->size, k, st, (unsigned long)n));
7648 strcpy(soap->id, href);
7649 soap->error = SOAP_HREF;
7650 return NULL;
7652 if (fcopy || n < sizeof(void*) || *href != '#')
7653 { register struct soap_flist *fp = (struct soap_flist*)SOAP_MALLOC(soap, sizeof(struct soap_flist));
7654 if (!fp)
7655 { soap->error = SOAP_EOM;
7656 return NULL;
7658 fp->next = ip->flist;
7659 fp->type = tt;
7660 fp->ptr = p;
7661 fp->level = k;
7662 fp->len = len;
7663 if (fcopy)
7664 fp->fcopy = fcopy;
7665 else
7666 fp->fcopy = soap_fcopy;
7667 ip->flist = fp;
7668 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarding type=%d (target type=%d) size=%lu location=%p level=%u len=%lu href='%s'\n", st, tt, (unsigned long)n, p, k, (unsigned long)len, href));
7670 else
7671 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarding copying address %p for type=%d href='%s'\n", p, st, href));
7672 *(void**)p = ip->copy;
7673 ip->copy = p;
7675 return p;
7677 #endif
7678 #endif
7680 /******************************************************************************/
7681 #ifndef PALM_2
7682 SOAP_FMAC1
7683 void*
7684 SOAP_FMAC2
7685 soap_id_enter(struct soap *soap, const char *id, void *p, int t, size_t n, unsigned int k, const char *type, const char *arrayType, void *(*finstantiate)(struct soap*, int, const char*, const char*, size_t*))
7687 #ifndef WITH_NOIDREF
7688 struct soap_ilist *ip;
7689 #endif
7690 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Enter id='%s' type=%d loc=%p size=%lu level=%u\n", id, t, p, (unsigned long)n, k));
7691 soap->alloced = 0;
7692 if (!p)
7693 { if (finstantiate)
7694 p = finstantiate(soap, t, type, arrayType, &n);
7695 else
7696 p = soap_malloc(soap, n);
7697 if (p)
7698 soap->alloced = 1;
7700 #ifndef WITH_NOIDREF
7701 if (!id || !*id)
7702 #endif
7703 return p;
7704 #ifndef WITH_NOIDREF
7705 ip = soap_lookup(soap, id); /* lookup pointer to hash table entry for string id */
7706 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Lookup entry id='%s for location=%p'\n", id, p));
7707 if (!ip)
7708 { if (!(ip = soap_enter(soap, id))) /* new hash table entry for string id */
7709 return NULL;
7710 ip->type = t;
7711 ip->link = NULL;
7712 ip->copy = NULL;
7713 ip->flist = NULL;
7714 ip->size = n;
7715 ip->ptr = p;
7716 ip->level = k;
7717 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "New entry id='%s' type=%d size=%lu level=%u location=%p\n", id, t, (unsigned long)n, k, p));
7719 else if ((ip->type != t || (ip->level == k && ip->size != n)) && (ip->copy || ip->flist))
7720 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Type incompatibility id='%s' expect type=%d size=%lu level=%u got type=%d size=%lu\n", id, ip->type, (unsigned long)ip->size, k, t, (unsigned long)n));
7721 strcpy(soap->id, id);
7722 soap->error = SOAP_HREF;
7723 return NULL;
7725 else if (ip->ptr)
7726 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Multiply defined id='%s'\n", id));
7727 strcpy(soap->id, id);
7728 soap->error = SOAP_DUPLICATE_ID;
7729 return NULL;
7731 else
7732 { ip->size = n;
7733 ip->ptr = p;
7734 ip->level = k;
7735 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Update entry id='%s' type=%d location=%p size=%lu level=%u\n", id, t, p, (unsigned long)n, k));
7737 return ip->ptr;
7738 #endif
7740 #endif
7742 /******************************************************************************/
7743 #ifndef PALM_2
7744 SOAP_FMAC1
7745 void
7746 SOAP_FMAC2
7747 soap_fcopy(struct soap *soap, int st, int tt, void *p, size_t len, const void *q, size_t n)
7748 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Copying data type=%d (target type=%d) %p -> %p (%lu bytes)\n", st, tt, q, p, (unsigned long)n));
7749 memcpy(p, q, n);
7751 #endif
7753 /******************************************************************************/
7754 #ifndef PALM_1
7755 SOAP_FMAC1
7757 SOAP_FMAC2
7758 soap_end_send(struct soap *soap)
7760 #ifndef WITH_LEANER
7761 int err;
7762 if (soap->dime.list)
7763 { /* SOAP body referenced attachments must appear first */
7764 soap->dime.last->next = soap->dime.first;
7765 soap->dime.first = soap->dime.list->next;
7766 soap->dime.list->next = NULL;
7767 soap->dime.last = soap->dime.list;
7769 if (!(err = soap_putdime(soap)))
7770 err = soap_putmime(soap);
7771 soap->mime.list = NULL;
7772 soap->mime.first = NULL;
7773 soap->mime.last = NULL;
7774 soap->dime.list = NULL;
7775 soap->dime.first = NULL;
7776 soap->dime.last = NULL;
7777 if (err)
7778 return err;
7779 #endif
7780 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End send\n"));
7781 if (soap->mode & SOAP_IO) /* need to flush the remaining data in buffer */
7782 { if (soap_flush(soap))
7783 #ifdef WITH_ZLIB
7784 { if (soap->mode & SOAP_ENC_ZLIB && soap->zlib_state == SOAP_ZLIB_DEFLATE)
7785 { soap->zlib_state = SOAP_ZLIB_NONE;
7786 deflateEnd(soap->d_stream);
7788 return soap->error;
7790 #else
7791 return soap->error;
7792 #endif
7793 #ifdef WITH_ZLIB
7794 if (soap->mode & SOAP_ENC_ZLIB)
7795 { int r;
7796 soap->d_stream->avail_in = 0;
7798 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Deflating remainder\n"));
7799 r = deflate(soap->d_stream, Z_FINISH);
7800 if (soap->d_stream->avail_out != SOAP_BUFLEN)
7801 { if (soap_flush_raw(soap, soap->z_buf, SOAP_BUFLEN - soap->d_stream->avail_out))
7802 { soap->zlib_state = SOAP_ZLIB_NONE;
7803 deflateEnd(soap->d_stream);
7804 return soap->error;
7806 soap->d_stream->next_out = (Byte*)soap->z_buf;
7807 soap->d_stream->avail_out = SOAP_BUFLEN;
7809 } while (r == Z_OK);
7810 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Deflated total %lu->%lu bytes\n", soap->d_stream->total_in, soap->d_stream->total_out));
7811 soap->z_ratio_out = (float)soap->d_stream->total_out / (float)soap->d_stream->total_in;
7812 soap->mode &= ~SOAP_ENC_ZLIB;
7813 soap->zlib_state = SOAP_ZLIB_NONE;
7814 if (deflateEnd(soap->d_stream) != Z_OK || r != Z_STREAM_END)
7815 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unable to end deflate: %s\n", soap->d_stream->msg?soap->d_stream->msg:SOAP_STR_EOS));
7816 return soap->error = SOAP_ZLIB_ERROR;
7818 #ifdef WITH_GZIP
7819 if (soap->zlib_out != SOAP_ZLIB_DEFLATE)
7820 { soap->z_buf[0] = soap->z_crc & 0xFF;
7821 soap->z_buf[1] = (soap->z_crc >> 8) & 0xFF;
7822 soap->z_buf[2] = (soap->z_crc >> 16) & 0xFF;
7823 soap->z_buf[3] = (soap->z_crc >> 24) & 0xFF;
7824 soap->z_buf[4] = soap->d_stream->total_in & 0xFF;
7825 soap->z_buf[5] = (soap->d_stream->total_in >> 8) & 0xFF;
7826 soap->z_buf[6] = (soap->d_stream->total_in >> 16) & 0xFF;
7827 soap->z_buf[7] = (soap->d_stream->total_in >> 24) & 0xFF;
7828 if (soap_flush_raw(soap, soap->z_buf, 8))
7829 return soap->error;
7830 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "gzip crc32=%lu\n", (unsigned long)soap->z_crc));
7832 #endif
7834 #endif
7835 if ((soap->mode & SOAP_IO) == SOAP_IO_STORE)
7836 { char *p;
7837 #ifndef WITH_NOHTTP
7838 if (!(soap->mode & SOAP_ENC_XML))
7839 { soap->mode--;
7840 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Sending buffered message of length %u\n", (unsigned int)soap->blist->size));
7841 if (soap->status >= SOAP_POST)
7842 soap->error = soap->fpost(soap, soap->endpoint, soap->host, soap->port, soap->path, soap->action, soap->blist->size);
7843 else if (soap->status != SOAP_STOP)
7844 soap->error = soap->fresponse(soap, soap->status, soap->blist->size);
7845 if (soap->error || soap_flush(soap))
7846 return soap->error;
7847 soap->mode++;
7849 #endif
7850 for (p = soap_first_block(soap, NULL); p; p = soap_next_block(soap, NULL))
7851 { DBGMSG(SENT, p, soap_block_size(soap, NULL));
7852 if ((soap->error = soap->fsend(soap, p, soap_block_size(soap, NULL))))
7853 { soap_end_block(soap, NULL);
7854 return soap->error;
7857 soap_end_block(soap, NULL);
7859 #ifndef WITH_LEANER
7860 else if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK)
7861 { DBGMSG(SENT, "\r\n0\r\n\r\n", 7);
7862 if ((soap->error = soap->fsend(soap, "\r\n0\r\n\r\n", 7)))
7863 return soap->error;
7865 #endif
7867 #ifdef WITH_TCPFIN
7868 #ifdef WITH_OPENSSL
7869 if (!soap->ssl && soap_valid_socket(soap->socket) && !soap->keep_alive && !(soap->omode & SOAP_IO_UDP))
7870 soap->fshutdownsocket(soap, soap->socket, SOAP_SHUT_WR); /* Send TCP FIN */
7871 #else
7872 if (soap_valid_socket(soap->socket) && !soap->keep_alive && !(soap->omode & SOAP_IO_UDP))
7873 soap->fshutdownsocket(soap, soap->socket, SOAP_SHUT_WR); /* Send TCP FIN */
7874 #endif
7875 #endif
7876 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End of send phase\n"));
7877 soap->omode &= ~SOAP_XML_SEC;
7878 soap->count = 0;
7879 soap->part = SOAP_END;
7880 return SOAP_OK;
7882 #endif
7884 /******************************************************************************/
7885 #ifndef PALM_1
7886 SOAP_FMAC1
7888 SOAP_FMAC2
7889 soap_end_recv(struct soap *soap)
7890 { soap->part = SOAP_END;
7891 #ifndef WITH_LEAN
7892 soap->wsuid = NULL; /* reset before next send */
7893 soap->c14nexclude = NULL; /* reset before next send */
7894 #endif
7895 #ifndef WITH_LEANER
7896 if ((soap->mode & SOAP_ENC_DIME) && soap_getdime(soap))
7897 { soap->dime.first = NULL;
7898 soap->dime.last = NULL;
7899 return soap->error;
7901 soap->dime.list = soap->dime.first;
7902 soap->dime.first = NULL;
7903 soap->dime.last = NULL;
7904 /* Check if MIME attachments and mime-post-check flag is set, if so call soap_resolve() and return */
7905 if (soap->mode & SOAP_ENC_MIME)
7907 if (soap->mode & SOAP_MIME_POSTCHECK)
7908 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Post checking MIME attachments\n"));
7909 if (!soap->keep_alive)
7910 soap->keep_alive = -1;
7911 #ifndef WITH_NOIDREF
7912 soap_resolve(soap);
7913 #endif
7914 return SOAP_OK;
7916 if (soap_getmime(soap))
7917 return soap->error;
7919 soap->mime.list = soap->mime.first;
7920 soap->mime.first = NULL;
7921 soap->mime.last = NULL;
7922 soap->mime.boundary = NULL;
7923 if (soap->xlist)
7924 { struct soap_multipart *content;
7925 for (content = soap->mime.list; content; content = content->next)
7926 soap_resolve_attachment(soap, content);
7928 #endif
7929 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "End of receive message ok\n"));
7930 #ifdef WITH_ZLIB
7931 if (soap->mode & SOAP_ENC_ZLIB)
7932 { /* Make sure end of compressed content is reached */
7933 while (soap->d_stream->next_out != Z_NULL)
7934 if ((int)soap_get1(soap) == EOF)
7935 break;
7936 soap->mode &= ~SOAP_ENC_ZLIB;
7937 memcpy(soap->buf, soap->z_buf, SOAP_BUFLEN);
7938 soap->bufidx = (char*)soap->d_stream->next_in - soap->z_buf;
7939 soap->buflen = soap->z_buflen;
7940 soap->zlib_state = SOAP_ZLIB_NONE;
7941 if (inflateEnd(soap->d_stream) != Z_OK)
7942 return soap->error = SOAP_ZLIB_ERROR;
7943 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Inflate end ok\n"));
7944 #ifdef WITH_GZIP
7945 if (soap->zlib_in == SOAP_ZLIB_GZIP)
7946 { soap_wchar c;
7947 short i;
7948 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Inflate gzip crc check\n"));
7949 for (i = 0; i < 8; i++)
7950 { if ((int)(c = soap_get1(soap)) == EOF)
7951 return soap->error = SOAP_EOF;
7952 soap->z_buf[i] = (char)c;
7954 if (soap->z_crc != ((uLong)(unsigned char)soap->z_buf[0] | ((uLong)(unsigned char)soap->z_buf[1] << 8) | ((uLong)(unsigned char)soap->z_buf[2] << 16) | ((uLong)(unsigned char)soap->z_buf[3] << 24)))
7955 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Gzip error: crc check failed, message corrupted? (crc32=%lu)\n", (unsigned long)soap->z_crc));
7956 return soap->error = SOAP_ZLIB_ERROR;
7958 if (soap->d_stream->total_out != ((uLong)(unsigned char)soap->z_buf[4] | ((uLong)(unsigned char)soap->z_buf[5] << 8) | ((uLong)(unsigned char)soap->z_buf[6] << 16) | ((uLong)(unsigned char)soap->z_buf[7] << 24)))
7959 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Gzip error: incorrect message length\n"));
7960 return soap->error = SOAP_ZLIB_ERROR;
7963 soap->zlib_in = SOAP_ZLIB_NONE;
7964 #endif
7966 #endif
7967 if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK)
7968 while ((int)soap_getchar(soap) != EOF) /* advance to last chunk */
7970 #ifndef WITH_NOIDREF
7971 if (soap_resolve(soap))
7972 return soap->error;
7973 #endif
7974 #ifndef WITH_LEANER
7975 if (soap->xlist)
7976 { if (soap->mode & SOAP_ENC_MTOM)
7977 return soap->error = SOAP_MIME_HREF;
7978 return soap->error = SOAP_DIME_HREF;
7980 #endif
7981 soap_free_ns(soap);
7982 #ifndef WITH_LEANER
7983 if (soap->fpreparefinalrecv)
7984 return soap->error = soap->fpreparefinalrecv(soap);
7985 #endif
7986 return SOAP_OK;
7988 #endif
7990 /******************************************************************************/
7991 #ifndef PALM_1
7992 SOAP_FMAC1
7993 void
7994 SOAP_FMAC2
7995 soap_free_temp(struct soap *soap)
7996 { register struct soap_attribute *tp, *tq;
7997 register struct Namespace *ns;
7998 soap_free_ns(soap);
7999 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free any remaining temp blocks\n"));
8000 while (soap->blist)
8001 soap_end_block(soap, NULL);
8002 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free attribute storage\n"));
8003 for (tp = soap->attributes; tp; tp = tq)
8004 { tq = tp->next;
8005 if (tp->value)
8006 SOAP_FREE(soap, tp->value);
8007 SOAP_FREE(soap, tp);
8009 soap->attributes = NULL;
8010 #ifdef WITH_FAST
8011 if (soap->labbuf)
8012 SOAP_FREE(soap, soap->labbuf);
8013 soap->labbuf = NULL;
8014 soap->lablen = 0;
8015 soap->labidx = 0;
8016 #endif
8017 ns = soap->local_namespaces;
8018 if (ns)
8019 { for (; ns->id; ns++)
8020 { if (ns->out)
8021 { if (soap->encodingStyle == ns->out)
8022 soap->encodingStyle = SOAP_STR_EOS;
8023 SOAP_FREE(soap, ns->out);
8024 ns->out = NULL;
8026 if (soap->encodingStyle == ns->ns)
8027 soap->encodingStyle = SOAP_STR_EOS;
8029 SOAP_FREE(soap, soap->local_namespaces);
8030 soap->local_namespaces = NULL;
8032 #ifndef WITH_LEANER
8033 while (soap->xlist)
8034 { struct soap_xlist *xp = soap->xlist->next;
8035 SOAP_FREE(soap, soap->xlist);
8036 soap->xlist = xp;
8038 #endif
8039 #ifndef WITH_NOIDREF
8040 soap_free_pht(soap);
8041 soap_free_iht(soap);
8042 #endif
8044 #endif
8046 /******************************************************************************/
8047 #ifndef PALM_1
8048 static void
8049 soap_free_ns(struct soap *soap)
8050 { register struct soap_nlist *np, *nq;
8051 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free namespace stack\n"));
8052 for (np = soap->nlist; np; np = nq)
8053 { nq = np->next;
8054 SOAP_FREE(soap, np);
8056 soap->nlist = NULL;
8058 #endif
8060 /******************************************************************************/
8061 #ifndef PALM_1
8062 #if !defined(WITH_LEAN) || defined(SOAP_DEBUG)
8063 static void
8064 soap_init_logs(struct soap *soap)
8065 { int i;
8066 for (i = 0; i < SOAP_MAXLOGS; i++)
8067 { soap->logfile[i] = NULL;
8068 soap->fdebug[i] = NULL;
8071 #endif
8072 #endif
8074 /******************************************************************************/
8075 #if !defined(WITH_LEAN) || defined(SOAP_DEBUG)
8076 SOAP_FMAC1
8077 void
8078 SOAP_FMAC2
8079 soap_open_logfile(struct soap *soap, int i)
8080 { if (soap->logfile[i])
8081 soap->fdebug[i] = fopen(soap->logfile[i], i < 2 ? "ab" : "a");
8083 #endif
8085 /******************************************************************************/
8086 #ifdef SOAP_DEBUG
8087 static void
8088 soap_close_logfile(struct soap *soap, int i)
8089 { if (soap->fdebug[i])
8090 { fclose(soap->fdebug[i]);
8091 soap->fdebug[i] = NULL;
8094 #endif
8096 /******************************************************************************/
8097 #ifdef SOAP_DEBUG
8098 SOAP_FMAC1
8099 void
8100 SOAP_FMAC2
8101 soap_close_logfiles(struct soap *soap)
8102 { int i;
8103 for (i = 0; i < SOAP_MAXLOGS; i++)
8104 soap_close_logfile(soap, i);
8106 #endif
8108 /******************************************************************************/
8109 #ifdef SOAP_DEBUG
8110 static void
8111 soap_set_logfile(struct soap *soap, int i, const char *logfile)
8112 { const char *s;
8113 char *t = NULL;
8114 soap_close_logfile(soap, i);
8115 s = soap->logfile[i];
8116 soap->logfile[i] = logfile;
8117 if (s)
8118 SOAP_FREE(soap, (void*)s);
8119 if (logfile)
8120 if ((t = (char*)SOAP_MALLOC(soap, strlen(logfile) + 1)))
8121 strcpy(t, logfile);
8122 soap->logfile[i] = t;
8124 #endif
8126 /******************************************************************************/
8127 #ifdef SOAP_DEBUG
8128 SOAP_FMAC1
8129 void
8130 SOAP_FMAC2
8131 soap_set_recv_logfile(struct soap *soap, const char *logfile)
8132 { soap_set_logfile(soap, SOAP_INDEX_RECV, logfile);
8134 #endif
8136 /******************************************************************************/
8137 #ifdef SOAP_DEBUG
8138 SOAP_FMAC1
8139 void
8140 SOAP_FMAC2
8141 soap_set_sent_logfile(struct soap *soap, const char *logfile)
8142 { soap_set_logfile(soap, SOAP_INDEX_SENT, logfile);
8144 #endif
8146 /******************************************************************************/
8147 #ifdef SOAP_DEBUG
8148 SOAP_FMAC1
8149 void
8150 SOAP_FMAC2
8151 soap_set_test_logfile(struct soap *soap, const char *logfile)
8152 { soap_set_logfile(soap, SOAP_INDEX_TEST, logfile);
8154 #endif
8156 /******************************************************************************/
8157 #ifndef PALM_1
8158 SOAP_FMAC1
8159 struct soap*
8160 SOAP_FMAC2
8161 soap_copy(const struct soap *soap)
8162 { return soap_copy_context((struct soap*)malloc(sizeof(struct soap)), soap);
8164 #endif
8166 /******************************************************************************/
8167 #ifndef PALM_1
8168 SOAP_FMAC1
8169 struct soap*
8170 SOAP_FMAC2
8171 soap_copy_context(struct soap *copy, const struct soap *soap)
8172 { if (soap_check_state(soap))
8173 return NULL;
8174 if (copy)
8175 { register struct soap_plugin *p = NULL;
8176 #ifdef __cplusplus
8177 *copy = *soap;
8178 #else
8179 memcpy(copy, soap, sizeof(struct soap));
8180 #endif
8181 copy->state = SOAP_COPY;
8182 copy->error = SOAP_OK;
8183 copy->userid = NULL;
8184 copy->passwd = NULL;
8185 copy->nlist = NULL;
8186 copy->blist = NULL;
8187 copy->clist = NULL;
8188 copy->alist = NULL;
8189 copy->attributes = NULL;
8190 copy->labbuf = NULL;
8191 copy->lablen = 0;
8192 copy->labidx = 0;
8193 #ifdef SOAP_MEM_DEBUG
8194 soap_init_mht(copy);
8195 #endif
8196 #if !defined(WITH_LEAN) || defined(SOAP_DEBUG)
8197 soap_init_logs(copy);
8198 #endif
8199 #ifdef SOAP_DEBUG
8200 soap_set_test_logfile(copy, soap->logfile[SOAP_INDEX_TEST]);
8201 soap_set_sent_logfile(copy, soap->logfile[SOAP_INDEX_SENT]);
8202 soap_set_recv_logfile(copy, soap->logfile[SOAP_INDEX_RECV]);
8203 #endif
8204 #ifdef WITH_C_LOCALE
8205 copy->c_locale = duplocale(soap->c_locale);
8206 #else
8207 copy->c_locale = NULL;
8208 #endif
8209 #ifdef WITH_OPENSSL
8210 copy->bio = NULL;
8211 copy->ssl = NULL;
8212 copy->session = NULL;
8213 #endif
8214 #ifdef WITH_GNUTLS
8215 copy->session = NULL;
8216 #endif
8217 #ifdef WITH_ZLIB
8218 copy->d_stream = (z_stream*)SOAP_MALLOC(copy, sizeof(z_stream));
8219 copy->d_stream->zalloc = Z_NULL;
8220 copy->d_stream->zfree = Z_NULL;
8221 copy->d_stream->opaque = Z_NULL;
8222 copy->z_buf = NULL;
8223 #endif
8224 copy->local_namespaces = NULL;
8225 #ifndef WITH_NOIDREF
8226 soap_init_iht(copy);
8227 soap_init_pht(copy);
8228 #endif
8229 copy->header = NULL;
8230 copy->fault = NULL;
8231 copy->action = NULL;
8232 #ifndef WITH_LEAN
8233 #ifdef WITH_COOKIES
8234 copy->cookies = soap_copy_cookies(copy, soap);
8235 #else
8236 copy->cookies = NULL;
8237 #endif
8238 #endif
8239 copy->plugins = NULL;
8240 for (p = soap->plugins; p; p = p->next)
8241 { register struct soap_plugin *q = (struct soap_plugin*)SOAP_MALLOC(copy, sizeof(struct soap_plugin));
8242 if (!q)
8243 return NULL;
8244 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copying plugin '%s'\n", p->id));
8245 *q = *p;
8246 if (p->fcopy && p->fcopy(copy, q, p))
8247 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not copy plugin '%s'\n", p->id));
8248 SOAP_FREE(copy, q);
8249 return NULL;
8251 q->next = copy->plugins;
8252 copy->plugins = q;
8255 return copy;
8257 #endif
8259 /******************************************************************************/
8260 #ifndef PALM_1
8261 SOAP_FMAC1
8262 void
8263 SOAP_FMAC2
8264 soap_copy_stream(struct soap *copy, struct soap *soap)
8265 { copy->mode = soap->mode;
8266 copy->imode = soap->imode;
8267 copy->omode = soap->omode;
8268 copy->socket = soap->socket;
8269 copy->recv_timeout = soap->recv_timeout;
8270 copy->send_timeout = soap->send_timeout;
8271 #if defined(__cplusplus) && !defined(WITH_LEAN)
8272 copy->os = soap->os;
8273 copy->is = soap->is;
8274 #endif
8275 copy->sendfd = soap->sendfd;
8276 copy->recvfd = soap->recvfd;
8277 copy->bufidx = soap->bufidx;
8278 copy->buflen = soap->buflen;
8279 copy->ahead = soap->ahead;
8280 copy->cdata = soap->cdata;
8281 copy->chunksize = soap->chunksize;
8282 copy->chunkbuflen = soap->chunkbuflen;
8283 copy->keep_alive = soap->keep_alive;
8284 copy->tcp_keep_alive = soap->tcp_keep_alive;
8285 copy->tcp_keep_idle = soap->tcp_keep_idle;
8286 copy->tcp_keep_intvl = soap->tcp_keep_intvl;
8287 copy->tcp_keep_cnt = soap->tcp_keep_cnt;
8288 copy->max_keep_alive = soap->max_keep_alive;
8289 #ifndef WITH_NOIO
8290 copy->peer = soap->peer;
8291 copy->peerlen = soap->peerlen;
8292 #endif
8293 #ifdef WITH_OPENSSL
8294 copy->bio = soap->bio;
8295 copy->ssl = soap->ssl;
8296 copy->ctx = soap->ctx;
8297 #endif
8298 #ifdef WITH_GNUTLS
8299 copy->session = soap->session; /* TODO: GNUTLS provides a dup? */
8300 #endif
8301 #ifdef WITH_ZLIB
8302 copy->zlib_state = soap->zlib_state;
8303 copy->zlib_in = soap->zlib_in;
8304 copy->zlib_out = soap->zlib_out;
8305 copy->d_stream = (z_stream*)SOAP_MALLOC(copy, sizeof(z_stream));
8306 memcpy(copy->d_stream, soap->d_stream, sizeof(z_stream));
8307 copy->z_crc = soap->z_crc;
8308 copy->z_ratio_in = soap->z_ratio_in;
8309 copy->z_ratio_out = soap->z_ratio_out;
8310 copy->z_buf = NULL;
8311 copy->z_buflen = soap->z_buflen;
8312 copy->z_level = soap->z_level;
8313 if (soap->z_buf && soap->zlib_state != SOAP_ZLIB_NONE)
8314 { copy->z_buf = (char*)SOAP_MALLOC(copy, SOAP_BUFLEN);
8315 memcpy(copy->z_buf, soap->z_buf, sizeof(soap->z_buf));
8317 copy->z_dict = soap->z_dict;
8318 copy->z_dict_len = soap->z_dict_len;
8319 #endif
8320 memcpy(copy->buf, soap->buf, sizeof(soap->buf));
8322 #endif
8324 /******************************************************************************/
8325 #ifndef PALM_1
8326 SOAP_FMAC1
8327 void
8328 SOAP_FMAC2
8329 soap_free_stream(struct soap *soap)
8330 { soap->socket = SOAP_INVALID_SOCKET;
8331 #ifdef WITH_OPENSSL
8332 soap->bio = NULL;
8333 soap->ssl = NULL;
8334 #endif
8335 #ifdef WITH_GNUTLS
8336 soap->xcred = NULL;
8337 soap->acred = NULL;
8338 soap->cache = NULL;
8339 soap->session = NULL; /* TODO: GNUTLS free (when dupped)? */
8340 soap->dh_params = NULL;
8341 soap->rsa_params = NULL;
8342 #endif
8343 #ifdef WITH_ZLIB
8344 if (soap->d_stream)
8345 SOAP_FREE(soap, soap->d_stream);
8346 soap->d_stream = NULL;
8347 if (soap->z_buf)
8348 SOAP_FREE(soap, soap->z_buf);
8349 soap->z_buf = NULL;
8350 #endif
8352 #endif
8354 /******************************************************************************/
8355 #ifndef PALM_1
8356 SOAP_FMAC1
8357 void
8358 SOAP_FMAC2
8359 soap_init(struct soap *soap)
8360 { soap->state = SOAP_INIT;
8361 #ifdef SOAP_MEM_DEBUG
8362 soap_init_mht(soap);
8363 #endif
8364 #if !defined(WITH_LEAN) || defined(SOAP_DEBUG)
8365 soap_init_logs(soap);
8366 #endif
8367 #ifdef SOAP_DEBUG
8368 soap_set_test_logfile(soap, "TEST.log");
8369 soap_set_sent_logfile(soap, "SENT.log");
8370 soap_set_recv_logfile(soap, "RECV.log");
8371 #endif
8372 soap->version = 0;
8373 soap_imode(soap, SOAP_IO_DEFAULT);
8374 soap_omode(soap, SOAP_IO_DEFAULT);
8375 soap->plugins = NULL;
8376 soap->user = NULL;
8377 soap->userid = NULL;
8378 soap->passwd = NULL;
8379 #ifndef WITH_NOHTTP
8380 soap->fpost = http_post;
8381 soap->fput = http_put;
8382 soap->fget = http_get;
8383 soap->fdel = http_405;
8384 soap->fopt = http_405;
8385 soap->fhead = http_405;
8386 soap->fform = NULL;
8387 soap->fposthdr = http_post_header;
8388 soap->fresponse = http_response;
8389 soap->fparse = http_parse;
8390 soap->fparsehdr = http_parse_header;
8391 #endif
8392 soap->fheader = NULL;
8393 soap->fconnect = NULL;
8394 soap->fdisconnect = NULL;
8395 #ifndef WITH_NOIO
8396 soap->ipv6_multicast_if = 0;
8397 soap->ipv4_multicast_if = NULL;
8398 #ifndef WITH_IPV6
8399 soap->fresolve = tcp_gethost;
8400 #else
8401 soap->fresolve = NULL;
8402 #endif
8403 soap->faccept = tcp_accept;
8404 soap->fopen = tcp_connect;
8405 soap->fclose = tcp_disconnect;
8406 soap->fclosesocket = tcp_closesocket;
8407 soap->fshutdownsocket = tcp_shutdownsocket;
8408 soap->fsend = fsend;
8409 soap->frecv = frecv;
8410 soap->fpoll = soap_poll;
8411 #else
8412 soap->fopen = NULL;
8413 soap->fclose = NULL;
8414 soap->fpoll = NULL;
8415 #endif
8416 soap->fseterror = NULL;
8417 soap->fignore = NULL;
8418 soap->fserveloop = NULL;
8419 soap->fplugin = fplugin;
8420 soap->fmalloc = NULL;
8421 #ifndef WITH_LEANER
8422 soap->fprepareinitsend = NULL;
8423 soap->fprepareinitrecv = NULL;
8424 soap->fpreparesend = NULL;
8425 soap->fpreparerecv = NULL;
8426 soap->fpreparefinalsend = NULL;
8427 soap->fpreparefinalrecv = NULL;
8428 soap->fdimereadopen = NULL;
8429 soap->fdimewriteopen = NULL;
8430 soap->fdimereadclose = NULL;
8431 soap->fdimewriteclose = NULL;
8432 soap->fdimeread = NULL;
8433 soap->fdimewrite = NULL;
8434 soap->fmimereadopen = NULL;
8435 soap->fmimewriteopen = NULL;
8436 soap->fmimereadclose = NULL;
8437 soap->fmimewriteclose = NULL;
8438 soap->fmimeread = NULL;
8439 soap->fmimewrite = NULL;
8440 #endif
8441 soap->float_format = "%.9G"; /* Alternative: use "%G" */
8442 soap->double_format = "%.17lG"; /* Alternative: use "%lG" */
8443 soap->dime_id_format = "cid:id%d"; /* default DIME id format */
8444 soap->http_version = "1.1";
8445 soap->proxy_http_version = "1.0";
8446 soap->http_content = NULL;
8447 soap->actor = NULL;
8448 soap->lang = "en";
8449 soap->keep_alive = 0;
8450 soap->tcp_keep_alive = 0;
8451 soap->tcp_keep_idle = 0;
8452 soap->tcp_keep_intvl = 0;
8453 soap->tcp_keep_cnt = 0;
8454 soap->max_keep_alive = SOAP_MAXKEEPALIVE;
8455 soap->recv_timeout = 0;
8456 soap->send_timeout = 0;
8457 soap->connect_timeout = 0;
8458 soap->accept_timeout = 0;
8459 soap->socket_flags = 0;
8460 soap->connect_flags = 0;
8461 soap->bind_flags = 0;
8462 soap->accept_flags = 0;
8463 soap->linger_time = 0;
8464 soap->ip = 0;
8465 soap->labbuf = NULL;
8466 soap->lablen = 0;
8467 soap->labidx = 0;
8468 soap->encodingStyle = SOAP_STR_EOS;
8469 #ifndef WITH_NONAMESPACES
8470 soap->namespaces = namespaces;
8471 #else
8472 soap->namespaces = NULL;
8473 #endif
8474 soap->local_namespaces = NULL;
8475 soap->nlist = NULL;
8476 soap->blist = NULL;
8477 soap->clist = NULL;
8478 soap->alist = NULL;
8479 soap->attributes = NULL;
8480 soap->header = NULL;
8481 soap->fault = NULL;
8482 soap->master = SOAP_INVALID_SOCKET;
8483 soap->socket = SOAP_INVALID_SOCKET;
8484 soap->os = NULL;
8485 soap->is = NULL;
8486 #ifndef WITH_LEANER
8487 soap->dom = NULL;
8488 soap->dime.list = NULL;
8489 soap->dime.first = NULL;
8490 soap->dime.last = NULL;
8491 soap->mime.list = NULL;
8492 soap->mime.first = NULL;
8493 soap->mime.last = NULL;
8494 soap->mime.boundary = NULL;
8495 soap->mime.start = NULL;
8496 soap->xlist = NULL;
8497 #endif
8498 #ifndef UNDER_CE
8499 soap->recvfd = 0;
8500 soap->sendfd = 1;
8501 #else
8502 soap->recvfd = stdin;
8503 soap->sendfd = stdout;
8504 #endif
8505 soap->host[0] = '\0';
8506 soap->port = 0;
8507 soap->action = NULL;
8508 soap->proxy_host = NULL;
8509 soap->proxy_port = 8080;
8510 soap->proxy_userid = NULL;
8511 soap->proxy_passwd = NULL;
8512 soap->authrealm = NULL;
8513 soap->prolog = NULL;
8514 #ifdef WITH_ZLIB
8515 soap->zlib_state = SOAP_ZLIB_NONE;
8516 soap->zlib_in = SOAP_ZLIB_NONE;
8517 soap->zlib_out = SOAP_ZLIB_NONE;
8518 soap->d_stream = (z_stream*)SOAP_MALLOC(soap, sizeof(z_stream));
8519 soap->d_stream->zalloc = Z_NULL;
8520 soap->d_stream->zfree = Z_NULL;
8521 soap->d_stream->opaque = Z_NULL;
8522 soap->z_buf = NULL;
8523 soap->z_level = 6;
8524 soap->z_dict = NULL;
8525 soap->z_dict_len = 0;
8526 #endif
8527 #ifndef WITH_LEAN
8528 soap->wsuid = NULL;
8529 soap->c14nexclude = NULL;
8530 soap->cookies = NULL;
8531 soap->cookie_domain = NULL;
8532 soap->cookie_path = NULL;
8533 soap->cookie_max = 32;
8534 #endif
8535 #ifdef WMW_RPM_IO
8536 soap->rpmreqid = NULL;
8537 #endif
8538 #ifdef PALM
8539 palmNetLibOpen();
8540 #endif
8541 #ifndef WITH_NOIDREF
8542 soap_init_iht(soap);
8543 soap_init_pht(soap);
8544 #endif
8545 #ifdef WITH_OPENSSL
8546 if (!soap_ssl_init_done)
8547 soap_ssl_init();
8548 soap->fsslauth = ssl_auth_init;
8549 soap->fsslverify = ssl_verify_callback;
8550 soap->bio = NULL;
8551 soap->ssl = NULL;
8552 soap->ctx = NULL;
8553 soap->session = NULL;
8554 soap->ssl_flags = SOAP_SSL_DEFAULT;
8555 soap->keyfile = NULL;
8556 soap->password = NULL;
8557 soap->cafile = NULL;
8558 soap->capath = NULL;
8559 soap->crlfile = NULL;
8560 soap->dhfile = NULL;
8561 soap->randfile = NULL;
8562 #endif
8563 #ifdef WITH_GNUTLS
8564 if (!soap_ssl_init_done)
8565 soap_ssl_init();
8566 soap->fsslauth = ssl_auth_init;
8567 soap->fsslverify = NULL;
8568 soap->xcred = NULL;
8569 soap->acred = NULL;
8570 soap->cache = NULL;
8571 soap->session = NULL;
8572 soap->ssl_flags = SOAP_SSL_DEFAULT;
8573 soap->keyfile = NULL;
8574 soap->password = NULL;
8575 soap->cafile = NULL;
8576 soap->capath = NULL;
8577 soap->crlfile = NULL;
8578 soap->dh_params = NULL;
8579 soap->rsa_params = NULL;
8580 #endif
8581 #ifdef WITH_C_LOCALE
8582 soap->c_locale = newlocale(LC_ALL_MASK, "C", NULL);
8583 #else
8584 soap->c_locale = NULL;
8585 #endif
8586 soap->buflen = 0;
8587 soap->bufidx = 0;
8588 #ifndef WITH_LEANER
8589 soap->dime.chunksize = 0;
8590 soap->dime.buflen = 0;
8591 #endif
8592 soap->null = 0;
8593 soap->position = 0;
8594 soap->encoding = 0;
8595 soap->mustUnderstand = 0;
8596 soap->ns = 0;
8597 soap->part = SOAP_END;
8598 soap->alloced = 0;
8599 soap->count = 0;
8600 soap->length = 0;
8601 soap->cdata = 0;
8602 soap->peeked = 0;
8603 soap->ahead = 0;
8604 soap->idnum = 0;
8605 soap->level = 0;
8606 soap->endpoint[0] = '\0';
8607 soap->error = SOAP_OK;
8609 #endif
8611 /******************************************************************************/
8612 #ifndef PALM_1
8613 SOAP_FMAC1
8614 void
8615 SOAP_FMAC2
8616 soap_init1(struct soap *soap, soap_mode mode)
8617 { soap_init2(soap, mode, mode);
8619 #endif
8621 /******************************************************************************/
8622 #ifndef PALM_1
8623 SOAP_FMAC1
8624 void
8625 SOAP_FMAC2
8626 soap_init2(struct soap *soap, soap_mode imode, soap_mode omode)
8627 { soap_init(soap);
8628 soap_imode(soap, imode);
8629 soap_omode(soap, omode);
8631 #endif
8633 /******************************************************************************/
8634 #ifndef PALM_2
8635 SOAP_FMAC1
8636 void
8637 SOAP_FMAC2
8638 soap_begin(struct soap *soap)
8639 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Reinitializing context\n"));
8640 if (!soap->keep_alive)
8641 { soap->buflen = 0;
8642 soap->bufidx = 0;
8644 soap->keep_alive = (((soap->imode | soap->omode) & SOAP_IO_KEEPALIVE) != 0);
8645 soap->null = 0;
8646 soap->position = 0;
8647 soap->encoding = 0;
8648 soap->mustUnderstand = 0;
8649 soap->mode = 0;
8650 soap->ns = 0;
8651 soap->part = SOAP_END;
8652 soap->alloced = 0;
8653 soap->count = 0;
8654 soap->length = 0;
8655 soap->cdata = 0;
8656 soap->error = SOAP_OK;
8657 soap->peeked = 0;
8658 soap->ahead = 0;
8659 soap->idnum = 0;
8660 soap->level = 0;
8661 soap->endpoint[0] = '\0';
8662 #ifndef WITH_LEANER
8663 soap->dime.chunksize = 0;
8664 soap->dime.buflen = 0;
8665 #endif
8666 soap_free_temp(soap);
8668 #endif
8670 /******************************************************************************/
8671 #ifndef PALM_2
8672 SOAP_FMAC1
8673 void
8674 SOAP_FMAC2
8675 soap_end(struct soap *soap)
8676 { if (soap_check_state(soap))
8677 return;
8678 soap_free_temp(soap);
8679 soap_dealloc(soap, NULL);
8680 while (soap->clist)
8681 { register struct soap_clist *cp = soap->clist->next;
8682 SOAP_FREE(soap, soap->clist);
8683 soap->clist = cp;
8685 soap_closesock(soap);
8686 #ifdef SOAP_DEBUG
8687 soap_close_logfiles(soap);
8688 #endif
8689 #ifdef PALM
8690 palmNetLibClose();
8691 #endif
8693 #endif
8695 /******************************************************************************/
8696 #ifndef PALM_1
8697 SOAP_FMAC1
8699 SOAP_FMAC2
8700 soap_set_namespaces(struct soap *soap, const struct Namespace *p)
8701 { register struct Namespace *ns = soap->local_namespaces;
8702 register struct soap_nlist *np, *nq, *nr;
8703 register unsigned int level = soap->level;
8704 soap->namespaces = p;
8705 soap->local_namespaces = NULL;
8706 soap_set_local_namespaces(soap);
8707 /* reverse the namespace list */
8708 np = soap->nlist;
8709 soap->nlist = NULL;
8710 if (np)
8711 { nq = np->next;
8712 np->next = NULL;
8713 while (nq)
8714 { nr = nq->next;
8715 nq->next = np;
8716 np = nq;
8717 nq = nr;
8720 /* then push on new stack */
8721 while (np)
8722 { register const char *s;
8723 soap->level = np->level; /* preserve element nesting level */
8724 s = np->ns;
8725 if (!s && np->index >= 0 && ns)
8726 { s = ns[np->index].out;
8727 if (!s)
8728 s = ns[np->index].ns;
8730 if (s && soap_push_namespace(soap, np->id, s) == NULL)
8731 return soap->error;
8732 nq = np;
8733 np = np->next;
8734 SOAP_FREE(soap, nq);
8736 if (ns)
8737 { register int i;
8738 for (i = 0; ns[i].id; i++)
8739 { if (ns[i].out)
8740 { SOAP_FREE(soap, ns[i].out);
8741 ns[i].out = NULL;
8744 SOAP_FREE(soap, ns);
8746 soap->level = level; /* restore level */
8747 return SOAP_OK;
8749 #endif
8751 /******************************************************************************/
8752 #ifndef PALM_1
8753 SOAP_FMAC1
8754 void
8755 SOAP_FMAC2
8756 soap_set_local_namespaces(struct soap *soap)
8757 { if (soap->namespaces && !soap->local_namespaces)
8758 { register const struct Namespace *ns1;
8759 register struct Namespace *ns2;
8760 register size_t n = 1;
8761 for (ns1 = soap->namespaces; ns1->id; ns1++)
8762 n++;
8763 n *= sizeof(struct Namespace);
8764 ns2 = (struct Namespace*)SOAP_MALLOC(soap, n);
8765 if (ns2)
8766 { memcpy(ns2, soap->namespaces, n);
8767 if (ns2[0].ns)
8768 { if (!strcmp(ns2[0].ns, soap_env1))
8769 soap->version = 1;
8770 else
8771 soap->version = 2;
8773 soap->local_namespaces = ns2;
8777 #endif
8779 /******************************************************************************/
8780 #ifndef WITH_LEAN
8781 #ifndef PALM_1
8782 SOAP_FMAC1
8783 const char *
8784 SOAP_FMAC2
8785 soap_tagsearch(const char *big, const char *little)
8786 { if (little)
8787 { register size_t n = strlen(little);
8788 register const char *s = big;
8789 while (s)
8790 { register const char *t = s;
8791 register size_t i;
8792 for (i = 0; i < n; i++, t++)
8793 { if (*t != little[i])
8794 break;
8796 if (*t == '\0' || *t == ' ')
8797 { if (i == n || (i && little[i-1] == ':'))
8798 return s;
8800 s = strchr(t, ' ');
8801 if (s)
8802 s++;
8805 return NULL;
8807 #endif
8808 #endif
8810 /******************************************************************************/
8811 #ifndef WITH_LEAN
8812 #ifndef PALM_1
8813 SOAP_FMAC1
8814 struct soap_nlist *
8815 SOAP_FMAC2
8816 soap_lookup_ns(struct soap *soap, const char *tag, size_t n)
8817 { register struct soap_nlist *np;
8818 for (np = soap->nlist; np; np = np->next)
8819 { if (!strncmp(np->id, tag, n) && !np->id[n])
8820 return np;
8822 return NULL;
8824 #endif
8825 #endif
8827 /******************************************************************************/
8828 #ifndef WITH_LEAN
8829 static struct soap_nlist *
8830 soap_push_ns(struct soap *soap, const char *id, const char *ns, short utilized)
8831 { register struct soap_nlist *np;
8832 size_t n, k;
8833 if (soap_tagsearch(soap->c14nexclude, id))
8834 return NULL;
8835 if (!utilized)
8836 { for (np = soap->nlist; np; np = np->next)
8837 { if (!strcmp(np->id, id) && (!np->ns || !strcmp(np->ns, ns)))
8838 break;
8840 if (np)
8841 { if ((np->level < soap->level || !np->ns) && np->index == 1)
8842 utilized = 1;
8843 else
8844 return NULL;
8847 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Adding namespace binding (level=%u) '%s' '%s' utilized=%d\n", soap->level, id, ns?ns:"(null)", utilized));
8848 n = strlen(id);
8849 if (ns)
8850 k = strlen(ns);
8851 else
8852 k = 0;
8853 np = (struct soap_nlist*)SOAP_MALLOC(soap, sizeof(struct soap_nlist) + n + k + 1);
8854 if (!np)
8855 { soap->error = SOAP_EOM;
8856 return NULL;
8858 np->next = soap->nlist;
8859 soap->nlist = np;
8860 strcpy(np->id, id);
8861 if (ns)
8862 np->ns = strcpy(np->id + n + 1, ns);
8863 else
8864 np->ns = NULL;
8865 np->level = soap->level;
8866 np->index = utilized;
8867 return np;
8869 #endif
8871 /******************************************************************************/
8872 #ifndef WITH_LEAN
8873 static void
8874 soap_utilize_ns(struct soap *soap, const char *tag, size_t n)
8875 { register struct soap_nlist *np = soap_lookup_ns(soap, tag, n);
8876 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Utilizing namespace of '%s'\n", tag));
8877 if (np)
8878 { if (np->index == 0)
8879 soap_push_ns(soap, np->id, np->ns, 1);
8881 else if (strncmp(tag, "xml", 3))
8882 { strncpy(soap->tmpbuf, tag, n);
8883 soap->tmpbuf[n] = '\0';
8884 soap_push_ns(soap, soap->tmpbuf, NULL, 1);
8887 #endif
8889 /******************************************************************************/
8890 #ifndef PALM_2
8891 SOAP_FMAC1
8893 SOAP_FMAC2
8894 soap_element(struct soap *soap, const char *tag, int id, const char *type)
8896 #ifndef WITH_LEAN
8897 register const char *s;
8898 #endif
8899 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Element begin tag='%s' id='%d' type='%s'\n", tag, id, type?type:SOAP_STR_EOS));
8900 #ifdef WITH_DOM
8901 #ifndef WITH_LEAN
8902 if (soap->wsuid && soap_tagsearch(soap->wsuid, tag))
8903 { size_t i;
8904 for (s = tag, i = 0; *s && i < sizeof(soap->tag); s++, i++)
8905 soap->tag[i] = *s == ':' ? '-' : *s;
8906 soap->tag[sizeof(soap->tag) - 1] = '\0';
8907 if (soap_set_attr(soap, "wsu:Id", soap->tag, 1))
8908 return soap->error;
8910 #endif
8911 if (soap->part == SOAP_BEGIN_SECURITY && (soap->mode & SOAP_XML_CANONICAL) && !(soap->mode & SOAP_DOM_ASIS))
8912 { register struct soap_nlist *np;
8913 /* wsu:Id found: clear xmlns renderings, so re-emit them for exc-c14n */
8914 for (np = soap->nlist; np; np = np->next)
8915 { if (np->index == 2)
8916 np->index = 0;
8919 if (soap->mode & SOAP_XML_DOM)
8920 { register struct soap_dom_element *elt = (struct soap_dom_element*)soap_malloc(soap, sizeof(struct soap_dom_element));
8921 if (!elt)
8922 return soap->error;
8923 elt->soap = soap;
8924 elt->next = NULL;
8925 elt->prnt = soap->dom;
8926 elt->name = soap_strdup(soap, tag);
8927 elt->elts = NULL;
8928 elt->atts = NULL;
8929 elt->nstr = NULL;
8930 elt->data = NULL;
8931 elt->wide = NULL;
8932 elt->node = NULL;
8933 elt->type = 0;
8934 elt->head = NULL;
8935 elt->tail = NULL;
8936 if (soap->dom)
8937 { struct soap_dom_element *p = soap->dom->elts;
8938 if (p)
8939 { while (p->next)
8940 p = p->next;
8941 p->next = elt;
8943 else
8944 soap->dom->elts = elt;
8946 soap->dom = elt;
8948 else
8950 #endif
8951 soap->level++;
8952 #ifndef WITH_LEAN
8953 if (!soap->ns)
8954 { if (!(soap->mode & SOAP_XML_CANONICAL)
8955 && soap_send(soap, soap->prolog ? soap->prolog : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"))
8956 return soap->error;
8958 else if (soap->mode & SOAP_XML_INDENT)
8959 { if (soap->ns == 1 && soap_send_raw(soap, soap_indent, soap->level < sizeof(soap_indent) ? soap->level : sizeof(soap_indent) - 1))
8960 return soap->error;
8961 soap->body = 1;
8963 if ((soap->mode & SOAP_XML_DEFAULTNS) && (s = strchr(tag, ':')))
8964 { struct Namespace *ns = soap->local_namespaces;
8965 size_t n = s - tag;
8966 if (soap_send_raw(soap, "<", 1)
8967 || soap_send(soap, s + 1))
8968 return soap->error;
8969 if (soap->nlist && !strncmp(soap->nlist->id, tag, n) && !soap->nlist->id[n])
8970 ns = NULL;
8971 for (; ns && ns->id; ns++)
8972 { if (*ns->id && (ns->out || ns->ns) && !strncmp(ns->id, tag, n) && !ns->id[n])
8973 { soap_push_ns(soap, ns->id, ns->out ? ns->out : ns->ns, 0);
8974 if (soap_attribute(soap, "xmlns", ns->out ? ns->out : ns->ns))
8975 return soap->error;
8976 break;
8980 else
8981 #endif
8982 if (soap_send_raw(soap, "<", 1)
8983 || soap_send(soap, tag))
8984 return soap->error;
8985 #ifdef WITH_DOM
8987 #endif
8988 if (!soap->ns)
8989 { struct Namespace *ns;
8990 int k = -1;
8991 #ifndef WITH_LEAN
8992 if ((soap->mode & SOAP_XML_DEFAULTNS))
8993 k = 4; /* only produce the first four required entries */
8994 #endif
8995 for (ns = soap->local_namespaces; ns && ns->id && k; ns++, k--)
8996 { if (*ns->id && (ns->out || ns->ns))
8997 { sprintf(soap->tmpbuf, "xmlns:%s", ns->id);
8998 if (soap_attribute(soap, soap->tmpbuf, ns->out ? ns->out : ns->ns))
8999 return soap->error;
9003 soap->ns = 1; /* namespace table control: ns = 0 or 2 to start, then 1 to stop dumping the table */
9004 #ifndef WITH_LEAN
9005 if (soap->mode & SOAP_XML_CANONICAL)
9006 { const char *t = strchr(tag, ':');
9007 if (t)
9008 soap_utilize_ns(soap, tag, t - tag);
9010 #endif
9011 if (id > 0)
9012 { sprintf(soap->tmpbuf, "_%d", id);
9013 if (soap_attribute(soap, "id", soap->tmpbuf))
9014 return soap->error;
9016 if (type && *type && (!(soap->mode & SOAP_XML_SEC) || soap->part == SOAP_IN_BODY))
9017 { if (soap_attribute(soap, "xsi:type", type))
9018 return soap->error;
9019 #ifndef WITH_LEAN
9020 if (soap->mode & SOAP_XML_CANONICAL)
9021 { const char *t = strchr(type, ':');
9022 if (t)
9023 soap_utilize_ns(soap, type, t - type);
9025 #endif
9027 if (soap->null && soap->position > 0)
9028 { register int i;
9029 sprintf(soap->tmpbuf, "[%d", soap->positions[0]);
9030 for (i = 1; i < soap->position; i++)
9031 sprintf(soap->tmpbuf + strlen(soap->tmpbuf), ",%d", soap->positions[i]);
9032 strcat(soap->tmpbuf, "]");
9033 if (soap_attribute(soap, "SOAP-ENC:position", soap->tmpbuf))
9034 return soap->error;
9036 if (soap->mustUnderstand)
9037 { if (soap->actor && *soap->actor)
9038 { if (soap_attribute(soap, soap->version == 2 ? "SOAP-ENV:role" : "SOAP-ENV:actor", soap->actor))
9039 return soap->error;
9041 if (soap_attribute(soap, "SOAP-ENV:mustUnderstand", soap->version == 2 ? "true" : "1"))
9042 return soap->error;
9043 soap->mustUnderstand = 0;
9045 if (soap->encoding)
9046 { if (soap->encodingStyle && soap->local_namespaces)
9047 { if (!*soap->encodingStyle)
9048 { if (soap->local_namespaces[1].out)
9049 soap->encodingStyle = soap->local_namespaces[1].out;
9050 else
9051 soap->encodingStyle = soap->local_namespaces[1].ns;
9053 if (soap->encodingStyle && soap_attribute(soap, "SOAP-ENV:encodingStyle", soap->encodingStyle))
9054 return soap->error;
9056 soap->encoding = 0;
9058 soap->null = 0;
9059 soap->position = 0;
9060 if (soap->part == SOAP_BEGIN_SECURITY && (soap->mode & SOAP_XML_CANONICAL))
9061 soap->part = SOAP_IN_SECURITY;
9062 return SOAP_OK;
9064 #endif
9066 /******************************************************************************/
9067 #ifndef PALM_2
9068 SOAP_FMAC1
9070 SOAP_FMAC2
9071 soap_element_begin_out(struct soap *soap, const char *tag, int id, const char *type)
9072 { if (*tag == '-')
9073 return SOAP_OK;
9074 if (soap_element(soap, tag, id, type))
9075 return soap->error;
9076 return soap_element_start_end_out(soap, NULL);
9078 #endif
9080 /******************************************************************************/
9081 #ifndef PALM_2
9082 #ifndef HAVE_STRRCHR
9083 SOAP_FMAC1
9084 char*
9085 SOAP_FMAC2
9086 soap_strrchr(const char *s, int t)
9087 { register char *r = NULL;
9088 while (*s)
9089 if (*s++ == t)
9090 r = (char*)s - 1;
9091 return r;
9093 #endif
9094 #endif
9096 /******************************************************************************/
9097 #ifndef PALM_2
9098 #ifndef HAVE_STRTOL
9099 SOAP_FMAC1
9100 long
9101 SOAP_FMAC2
9102 soap_strtol(const char *s, char **t, int b)
9103 { register long n = 0;
9104 register int c;
9105 while (*s > 0 && *s <= 32)
9106 s++;
9107 if (b == 10)
9108 { short neg = 0;
9109 if (*s == '-')
9110 { s++;
9111 neg = 1;
9113 else if (*s == '+')
9114 s++;
9115 while ((c = *s) && c >= '0' && c <= '9')
9116 { if (n >= 214748364 && (n > 214748364 || c >= '8'))
9117 break;
9118 n *= 10;
9119 n += c - '0';
9120 s++;
9122 if (neg)
9123 n = -n;
9125 else /* assume b == 16 and value is always positive */
9126 { while ((c = *s))
9127 { if (c >= '0' && c <= '9')
9128 c -= '0';
9129 else if (c >= 'A' && c <= 'F')
9130 c -= 'A' - 10;
9131 else if (c >= 'a' && c <= 'f')
9132 c -= 'a' - 10;
9133 if (n > 0x07FFFFFF)
9134 break;
9135 n <<= 4;
9136 n += c;
9137 s++;
9140 if (t)
9141 *t = (char*)s;
9142 return n;
9144 #endif
9145 #endif
9147 /******************************************************************************/
9148 #ifndef PALM_2
9149 #ifndef HAVE_STRTOUL
9150 SOAP_FMAC1
9151 unsigned long
9152 SOAP_FMAC2
9153 soap_strtoul(const char *s, char **t, int b)
9154 { unsigned long n = 0;
9155 register int c;
9156 while (*s > 0 && *s <= 32)
9157 s++;
9158 if (b == 10)
9159 { if (*s == '+')
9160 s++;
9161 while ((c = *s) && c >= '0' && c <= '9')
9162 { if (n >= 429496729 && (n > 429496729 || c >= '6'))
9163 break;
9164 n *= 10;
9165 n += c - '0';
9166 s++;
9169 else /* b == 16 */
9170 { while ((c = *s))
9171 { if (c >= '0' && c <= '9')
9172 c -= '0';
9173 else if (c >= 'A' && c <= 'F')
9174 c -= 'A' - 10;
9175 else if (c >= 'a' && c <= 'f')
9176 c -= 'a' - 10;
9177 if (n > 0x0FFFFFFF)
9178 break;
9179 n <<= 4;
9180 n += c;
9181 s++;
9184 if (t)
9185 *t = (char*)s;
9186 return n;
9188 #endif
9189 #endif
9191 /******************************************************************************/
9192 #ifndef PALM_1
9193 SOAP_FMAC1
9195 SOAP_FMAC2
9196 soap_array_begin_out(struct soap *soap, const char *tag, int id, const char *type, const char *offset)
9197 { if (!type || !*type)
9198 return soap_element_begin_out(soap, tag, id, NULL);
9199 if (soap_element(soap, tag, id, "SOAP-ENC:Array"))
9200 return soap->error;
9201 if (soap->version == 2)
9202 { const char *s;
9203 s = soap_strrchr(type, '[');
9204 if ((size_t)(s - type) < sizeof(soap->tmpbuf))
9205 { strncpy(soap->tmpbuf, type, s - type);
9206 soap->tmpbuf[s - type] = '\0';
9207 if (soap_attribute(soap, "SOAP-ENC:itemType", soap->tmpbuf))
9208 return soap->error;
9209 if (s && (soap_attribute(soap, "SOAP-ENC:arraySize", s + 1)))
9210 return soap->error;
9213 else
9214 { if (offset && soap_attribute(soap, "SOAP-ENC:offset", offset))
9215 return soap->error;
9216 if (soap_attribute(soap, "SOAP-ENC:arrayType", type))
9217 return soap->error;
9219 #ifndef WITH_LEAN
9220 if ((soap->mode & SOAP_XML_CANONICAL))
9221 { const char *s = strchr(type, ':');
9222 if (s)
9223 soap_utilize_ns(soap, type, s - type);
9225 #endif
9226 return soap_element_start_end_out(soap, NULL);
9228 #endif
9230 /******************************************************************************/
9231 #ifndef PALM_1
9232 SOAP_FMAC1
9234 SOAP_FMAC2
9235 soap_element_start_end_out(struct soap *soap, const char *tag)
9236 { register struct soap_attribute *tp;
9237 #ifndef WITH_LEAN
9238 if (soap->mode & SOAP_XML_CANONICAL)
9239 { struct soap_nlist *np;
9240 for (tp = soap->attributes; tp; tp = tp->next)
9241 { if (tp->visible && tp->name)
9242 { const char *s = strchr(tp->name, ':');
9243 if (s)
9244 soap_utilize_ns(soap, tp->name, s - tp->name);
9247 for (np = soap->nlist; np; np = np->next)
9248 { if (np->index == 1 && np->ns)
9249 { sprintf(soap->tmpbuf, "xmlns:%s", np->id);
9250 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Enabling utilized binding (level=%u) %s='%s'\n", np->level, soap->tmpbuf, np->ns));
9251 soap_set_attr(soap, soap->tmpbuf, np->ns, 1);
9252 np->index = 2;
9256 #endif
9257 #ifdef WITH_DOM
9258 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
9259 { register struct soap_dom_attribute **att;
9260 att = &soap->dom->atts;
9261 for (tp = soap->attributes; tp; tp = tp->next)
9262 { if (tp->visible)
9263 { *att = (struct soap_dom_attribute*)soap_malloc(soap, sizeof(struct soap_dom_attribute));
9264 if (!*att)
9265 return soap->error;
9266 (*att)->next = NULL;
9267 (*att)->nstr = NULL;
9268 (*att)->name = soap_strdup(soap, tp->name);
9269 (*att)->data = soap_strdup(soap, tp->value);
9270 (*att)->wide = NULL;
9271 (*att)->soap = soap;
9272 att = &(*att)->next;
9273 tp->visible = 0;
9276 return SOAP_OK;
9278 #endif
9279 for (tp = soap->attributes; tp; tp = tp->next)
9280 { if (tp->visible)
9282 #ifndef WITH_LEAN
9283 const char *s;
9284 if ((soap->mode & SOAP_XML_DEFAULTNS) && (s = strchr(tp->name, ':')))
9285 { size_t n = s - tp->name;
9286 if (soap->nlist && !strncmp(soap->nlist->id, tp->name, n) && !soap->nlist->id[n])
9287 s++;
9288 else
9289 s = tp->name;
9290 if (soap_send(soap, " ") || soap_send(soap, s))
9291 return soap->error;
9293 else
9294 #endif
9295 if (soap_send(soap, " ") || soap_send(soap, tp->name))
9296 return soap->error;
9297 if (tp->visible == 2 && tp->value)
9298 if (soap_send_raw(soap, "=\"", 2)
9299 || soap_string_out(soap, tp->value, tp->flag)
9300 || soap_send_raw(soap, "\"", 1))
9301 return soap->error;
9302 tp->visible = 0;
9305 if (tag)
9307 #ifndef WITH_LEAN
9308 if (soap->mode & SOAP_XML_CANONICAL)
9309 { if (soap_send_raw(soap, ">", 1)
9310 || soap_element_end_out(soap, tag))
9311 return soap->error;
9312 return SOAP_OK;
9314 #endif
9315 soap->level--; /* decrement level just before /> */
9316 return soap_send_raw(soap, "/>", 2);
9318 return soap_send_raw(soap, ">", 1);
9320 #endif
9322 /******************************************************************************/
9323 #ifndef PALM_1
9324 SOAP_FMAC1
9326 SOAP_FMAC2
9327 soap_element_end_out(struct soap *soap, const char *tag)
9329 #ifndef WITH_LEAN
9330 const char *s;
9331 #endif
9332 if (*tag == '-')
9333 return SOAP_OK;
9334 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Element ending tag='%s'\n", tag));
9335 #ifdef WITH_DOM
9336 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
9337 { if (soap->dom->prnt)
9338 soap->dom = soap->dom->prnt;
9339 return SOAP_OK;
9341 #endif
9342 #ifndef WITH_LEAN
9343 if (soap->mode & SOAP_XML_CANONICAL)
9344 soap_pop_namespace(soap);
9345 if (soap->mode & SOAP_XML_INDENT)
9346 { if (!soap->body)
9347 { if (soap_send_raw(soap, soap_indent, soap->level < sizeof(soap_indent) ? soap->level : sizeof(soap_indent) - 1))
9348 return soap->error;
9350 soap->body = 0;
9352 if ((soap->mode & SOAP_XML_DEFAULTNS) && (s = strchr(tag, ':')))
9353 { soap_pop_namespace(soap);
9354 tag = s + 1;
9356 #endif
9357 if (soap_send_raw(soap, "</", 2)
9358 || soap_send(soap, tag))
9359 return soap->error;
9360 soap->level--; /* decrement level just before > */
9361 return soap_send_raw(soap, ">", 1);
9363 #endif
9365 /******************************************************************************/
9366 #ifndef PALM_1
9367 SOAP_FMAC1
9369 SOAP_FMAC2
9370 soap_element_ref(struct soap *soap, const char *tag, int id, int href)
9371 { register int n = 0;
9372 const char *s = "href";
9373 if (soap->version == 2)
9374 { s = "SOAP-ENC:ref";
9375 n = 1;
9377 sprintf(soap->href, "#_%d", href);
9378 return soap_element_href(soap, tag, id, s, soap->href + n);
9380 #endif
9382 /******************************************************************************/
9383 #ifndef PALM_1
9384 SOAP_FMAC1
9386 SOAP_FMAC2
9387 soap_element_href(struct soap *soap, const char *tag, int id, const char *ref, const char *val)
9388 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Element '%s' reference %s='%s'\n", tag, ref, val));
9389 if (soap_element(soap, tag, id, NULL)
9390 || soap_attribute(soap, ref, val)
9391 || soap_element_start_end_out(soap, tag))
9392 return soap->error;
9393 return SOAP_OK;
9395 #endif
9397 /******************************************************************************/
9398 #ifndef PALM_1
9399 SOAP_FMAC1
9401 SOAP_FMAC2
9402 soap_element_null(struct soap *soap, const char *tag, int id, const char *type)
9403 { struct soap_attribute *tp = NULL;
9404 for (tp = soap->attributes; tp; tp = tp->next)
9405 if (tp->visible)
9406 break;
9407 if (tp || (soap->version == 2 && soap->position > 0) || id > 0 || (soap->mode & SOAP_XML_NIL))
9408 { if (soap_element(soap, tag, id, type)
9409 || (!tp && soap_attribute(soap, "xsi:nil", "true")))
9410 return soap->error;
9411 return soap_element_start_end_out(soap, tag);
9413 soap->null = 1;
9414 soap->position = 0;
9415 soap->mustUnderstand = 0;
9416 return SOAP_OK;
9418 #endif
9420 /******************************************************************************/
9421 #ifndef PALM_1
9422 SOAP_FMAC1
9424 SOAP_FMAC2
9425 soap_element_nil(struct soap *soap, const char *tag)
9426 { if (soap_element(soap, tag, -1, NULL)
9427 || soap_attribute(soap, "xsi:nil", "true"))
9428 return soap->error;
9429 return soap_element_start_end_out(soap, tag);
9431 #endif
9433 /******************************************************************************/
9434 #ifndef PALM_1
9435 SOAP_FMAC1
9437 SOAP_FMAC2
9438 soap_element_id(struct soap *soap, const char *tag, int id, const void *p, const struct soap_array *a, int n, const char *type, int t)
9439 { if (!p)
9440 { soap_element_null(soap, tag, id, type);
9441 return -1;
9443 #ifndef WITH_NOIDREF
9444 if (soap->mode & SOAP_XML_TREE)
9445 return 0;
9446 if (id < 0)
9447 { struct soap_plist *pp;
9448 if (a)
9449 id = soap_array_pointer_lookup(soap, p, a, n, t, &pp);
9450 else
9451 id = soap_pointer_lookup(soap, p, t, &pp);
9452 if (id)
9453 { if (soap_is_embedded(soap, pp))
9454 { soap_element_ref(soap, tag, 0, id);
9455 return -1;
9457 if (soap_is_single(soap, pp))
9458 return 0;
9459 soap_set_embedded(soap, pp);
9462 return id;
9463 #else
9464 return 0;
9465 #endif
9467 #endif
9469 /******************************************************************************/
9470 #ifndef PALM_1
9471 SOAP_FMAC1
9473 SOAP_FMAC2
9474 soap_element_result(struct soap *soap, const char *tag)
9475 { if (soap->version == 2 && soap->encodingStyle)
9476 { if (soap_element(soap, "SOAP-RPC:result", 0, NULL)
9477 || soap_attribute(soap, "xmlns:SOAP-RPC", soap_rpc)
9478 || soap_element_start_end_out(soap, NULL)
9479 || soap_string_out(soap, tag, 0)
9480 || soap_element_end_out(soap, "SOAP-RPC:result"))
9481 return soap->error;
9483 return SOAP_OK;
9485 #endif
9487 /******************************************************************************/
9488 #ifndef PALM_1
9489 SOAP_FMAC1
9490 void
9491 SOAP_FMAC2
9492 soap_check_result(struct soap *soap, const char *tag)
9493 { if (soap->version == 2 && soap->encodingStyle)
9494 { soap_instring(soap, ":result", NULL, NULL, 0, 2, -1, -1);
9495 /* just ignore content for compliance reasons, but should compare tag to element's QName value? */
9498 #endif
9500 /******************************************************************************/
9501 #ifndef PALM_2
9502 SOAP_FMAC1
9504 SOAP_FMAC2
9505 soap_attribute(struct soap *soap, const char *name, const char *value)
9507 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Attribute '%s'='%s'\n", name, value));
9508 #ifdef WITH_DOM
9509 if ((soap->mode & SOAP_XML_DOM) && !(soap->mode & SOAP_XML_CANONICAL) && soap->dom)
9510 { register struct soap_dom_attribute *a = (struct soap_dom_attribute*)soap_malloc(soap, sizeof(struct soap_dom_attribute));
9511 if (!a)
9512 return soap->error;
9513 a->next = soap->dom->atts;
9514 a->nstr = NULL;
9515 a->name = soap_strdup(soap, name);
9516 a->data = soap_strdup(soap, value);
9517 a->wide = NULL;
9518 a->soap = soap;
9519 soap->dom->atts = a;
9520 return SOAP_OK;
9522 #endif
9523 #ifndef WITH_LEAN
9524 if (soap->mode & SOAP_XML_CANONICAL)
9525 { /* TODO: consider using this code to handle default namespace bindings
9526 if (!strncmp(name, "xmlns", 5) && (name[5] == ':' || name[5] == '\0'))
9527 { if (name[5] == ':')
9528 soap_push_ns(soap, name + 6, value, 0);
9529 else
9530 soap_push_ns(soap, "", value, 0);
9533 if (!strncmp(name, "xmlns:", 6))
9534 soap_push_ns(soap, name + 6, value, 0);
9535 else if (soap_set_attr(soap, name, value, 1))
9536 return soap->error;
9538 else
9539 #endif
9540 { if (soap_send(soap, " ") || soap_send(soap, name))
9541 return soap->error;
9542 if (value)
9543 if (soap_send_raw(soap, "=\"", 2)
9544 || soap_string_out(soap, value, 1)
9545 || soap_send_raw(soap, "\"", 1))
9546 return soap->error;
9548 return SOAP_OK;
9550 #endif
9552 /******************************************************************************/
9553 #ifndef PALM_2
9554 SOAP_FMAC1
9556 SOAP_FMAC2
9557 soap_element_begin_in(struct soap *soap, const char *tag, int nillable, const char *type)
9558 { if (!soap_peek_element(soap))
9559 { if (soap->other)
9560 return soap->error = SOAP_TAG_MISMATCH;
9561 if (tag && *tag == '-')
9562 return SOAP_OK;
9563 if (!(soap->error = soap_match_tag(soap, soap->tag, tag)))
9564 { soap->peeked = 0;
9565 if (type && *soap->type && soap_match_tag(soap, soap->type, type))
9566 return soap->error = SOAP_TYPE;
9567 if (!nillable && soap->null && (soap->mode & SOAP_XML_STRICT))
9568 return soap->error = SOAP_NULL;
9569 if (soap->body)
9570 soap->level++;
9571 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Begin element found (level=%u) '%s'='%s'\n", soap->level, soap->tag, tag?tag:SOAP_STR_EOS ));
9574 else if (soap->error == SOAP_NO_TAG && tag && *tag == '-')
9575 soap->error = SOAP_OK;
9576 return soap->error;
9578 #endif
9580 /******************************************************************************/
9581 #ifndef PALM_2
9582 SOAP_FMAC1
9584 SOAP_FMAC2
9585 soap_element_end_in(struct soap *soap, const char *tag)
9586 { register soap_wchar c;
9587 register char *s;
9588 register int n = 0;
9589 if (tag && *tag == '-')
9590 return SOAP_OK;
9591 if (soap->error == SOAP_NO_TAG)
9592 soap->error = SOAP_OK;
9593 #ifdef WITH_DOM
9594 /* this whitespace or mixed content is significant for DOM */
9595 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
9596 { if (!soap->peeked && !soap_string_in(soap, 3, -1, -1))
9597 return soap->error;
9598 if (soap->dom->prnt)
9599 soap->dom = soap->dom->prnt;
9601 #endif
9602 if (soap->peeked)
9603 { if (*soap->tag)
9604 n++;
9605 soap->peeked = 0;
9608 { while (((c = soap_get(soap)) != SOAP_TT))
9609 { if ((int)c == EOF)
9610 return soap->error = SOAP_EOF;
9611 if (c == SOAP_LT)
9612 n++;
9613 else if (c == '/')
9614 { c = soap_get(soap);
9615 if (c == SOAP_GT)
9616 n--;
9617 else
9618 soap_unget(soap, c);
9621 } while (n--);
9622 s = soap->tag;
9623 n = sizeof(soap->tag);
9624 while (soap_notblank(c = soap_get(soap)))
9625 { if (--n > 0)
9626 *s++ = (char)c;
9628 *s = '\0';
9629 if ((int)c == EOF)
9630 return soap->error = SOAP_EOF;
9631 while (soap_blank(c))
9632 c = soap_get(soap);
9633 if (c != SOAP_GT)
9634 return soap->error = SOAP_SYNTAX_ERROR;
9635 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End element found (level=%u) '%s'='%s'\n", soap->level, soap->tag, tag?tag:SOAP_STR_EOS));
9636 #ifndef WITH_LEAN
9637 if (tag && (soap->mode & SOAP_XML_STRICT))
9638 { soap_pop_namespace(soap);
9639 if (soap_match_tag(soap, soap->tag, tag))
9640 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End element tag name does not match\n"));
9641 return soap->error = SOAP_SYNTAX_ERROR;
9644 #endif
9645 soap->level--;
9646 return SOAP_OK;
9648 #endif
9650 /******************************************************************************/
9651 #ifndef PALM_2
9652 SOAP_FMAC1
9653 const char *
9654 SOAP_FMAC2
9655 soap_attr_value(struct soap *soap, const char *name, int flag)
9656 { register struct soap_attribute *tp;
9657 if (*name == '-')
9658 return SOAP_STR_EOS;
9659 for (tp = soap->attributes; tp; tp = tp->next)
9660 { if (tp->visible && !soap_match_tag(soap, tp->name, name))
9661 break;
9663 if (tp)
9664 { if (flag == 2 && (soap->mode & SOAP_XML_STRICT))
9665 soap->error = SOAP_PROHIBITED;
9666 else
9667 return tp->value;
9669 else if (flag == 1 && (soap->mode & SOAP_XML_STRICT))
9670 soap->error = SOAP_REQUIRED;
9671 else
9672 soap->error = SOAP_OK;
9673 return NULL;
9675 #endif
9677 /******************************************************************************/
9678 #ifndef PALM_2
9679 SOAP_FMAC1
9681 SOAP_FMAC2
9682 soap_set_attr(struct soap *soap, const char *name, const char *value, int flag)
9683 { register struct soap_attribute *tp;
9684 if (*name == '-')
9685 return SOAP_OK;
9686 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Set attribute %s='%s'\n", name, value?value:SOAP_STR_EOS));
9687 for (tp = soap->attributes; tp; tp = tp->next)
9688 { if (!strcmp(tp->name, name))
9689 break;
9691 if (!tp)
9692 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Allocate attribute %s\n", name));
9693 if (!(tp = (struct soap_attribute*)SOAP_MALLOC(soap, sizeof(struct soap_attribute) + strlen(name))))
9694 return soap->error = SOAP_EOM;
9695 tp->ns = NULL;
9696 #ifndef WITH_LEAN
9697 if ((soap->mode & SOAP_XML_CANONICAL))
9698 { struct soap_attribute **tpp = &soap->attributes;
9699 const char *s = strchr(name, ':');
9700 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inserting attribute %s for c14n\n", name))
9701 if (!strncmp(name, "xmlns", 5))
9702 { for (; *tpp; tpp = &(*tpp)->next)
9703 if (strncmp((*tpp)->name, "xmlns", 5) || strcmp((*tpp)->name + 5, name + 5) > 0)
9704 break;
9706 else if (!s)
9707 { for (; *tpp; tpp = &(*tpp)->next)
9708 if (strncmp((*tpp)->name, "xmlns", 5) && ((*tpp)->ns || strcmp((*tpp)->name, name) > 0))
9709 break;
9711 else
9712 { int k;
9713 for (; *tpp; tpp = &(*tpp)->next)
9714 { if (!strncmp((*tpp)->name, "xmlns:", 6) && !strncmp((*tpp)->name + 6, name, s - name) && !(*tpp)->name[6 + s - name])
9715 { if (!tp->ns)
9716 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Canonicalization: prefix %s=%p (%s)\n", name, (*tpp)->ns, (*tpp)->ns));
9717 tp->ns = (*tpp)->ns;
9720 else if (strncmp((*tpp)->name, "xmlns", 5) && (*tpp)->ns && tp->ns && ((k = strcmp((*tpp)->ns, tp->ns)) > 0 || (!k && strcmp((*tpp)->name, name) > 0)))
9721 break;
9724 tp->next = *tpp;
9725 *tpp = tp;
9727 else
9728 #endif
9729 { tp->next = soap->attributes;
9730 soap->attributes = tp;
9732 strcpy(tp->name, name);
9733 tp->value = NULL;
9735 else if (tp->visible)
9736 { return SOAP_OK;
9738 else if (value && tp->value && tp->size <= strlen(value))
9739 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free attribute value of %s (free %p)\n", name, tp->value));
9740 SOAP_FREE(soap, tp->value);
9741 tp->value = NULL;
9742 tp->ns = NULL;
9744 if (value)
9745 { if (!tp->value)
9746 { tp->size = strlen(value) + 1;
9747 if (!(tp->value = (char*)SOAP_MALLOC(soap, tp->size)))
9748 return soap->error = SOAP_EOM;
9749 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Allocate attribute value for %s (%p)\n", tp->name, tp->value));
9751 strcpy(tp->value, value);
9752 if (!strncmp(tp->name, "xmlns:", 6))
9753 tp->ns = tp->value;
9754 tp->visible = 2;
9755 tp->flag = flag;
9756 #ifndef WITH_LEAN
9757 if (soap->part != SOAP_IN_SECURITY && !strcmp(name, "wsu:Id"))
9758 { soap->part = SOAP_BEGIN_SECURITY;
9759 strncpy(soap->id, value, sizeof(soap->id));
9760 soap->id[sizeof(soap->id)-1] = '\0';
9762 #endif
9764 else
9765 tp->visible = 1;
9766 return SOAP_OK;
9768 #endif
9770 /******************************************************************************/
9771 #ifndef PALM_2
9772 SOAP_FMAC1
9773 void
9774 SOAP_FMAC2
9775 soap_clr_attr(struct soap *soap)
9776 { register struct soap_attribute *tp;
9777 #ifndef WITH_LEAN
9778 if ((soap->mode & SOAP_XML_CANONICAL))
9779 { while (soap->attributes)
9780 { tp = soap->attributes->next;
9781 if (soap->attributes->value)
9782 SOAP_FREE(soap, soap->attributes->value);
9783 SOAP_FREE(soap, soap->attributes);
9784 soap->attributes = tp;
9787 else
9788 #endif
9789 { for (tp = soap->attributes; tp; tp = tp->next)
9790 tp->visible = 0;
9793 #endif
9795 /******************************************************************************/
9796 #ifndef PALM_2
9797 static int
9798 soap_getattrval(struct soap *soap, char *s, size_t n, soap_wchar d)
9799 { register size_t i;
9800 for (i = 0; i < n; i++)
9801 { register soap_wchar c = soap_get(soap);
9802 switch (c)
9804 case SOAP_TT:
9805 *s++ = '<';
9806 soap_unget(soap, '/');
9807 break;
9808 case SOAP_LT:
9809 *s++ = '<';
9810 break;
9811 case SOAP_GT:
9812 if (d == ' ')
9813 { soap_unget(soap, c);
9814 *s = '\0';
9815 return SOAP_OK;
9817 *s++ = '>';
9818 break;
9819 case SOAP_QT:
9820 if (c == d)
9821 { *s = '\0';
9822 return SOAP_OK;
9824 *s++ = '"';
9825 break;
9826 case SOAP_AP:
9827 if (c == d)
9828 { *s = '\0';
9829 return SOAP_OK;
9831 *s++ = '\'';
9832 break;
9833 case '\t':
9834 case '\n':
9835 case '\r':
9836 case ' ':
9837 case '/':
9838 if (d == ' ')
9839 { soap_unget(soap, c);
9840 *s = '\0';
9841 return SOAP_OK;
9843 default:
9844 if ((int)c == EOF)
9845 return soap->error = SOAP_EOF;
9846 *s++ = (char)c;
9849 return soap->error = SOAP_EOM;
9851 #endif
9853 /******************************************************************************/
9854 #ifdef WITH_FAST
9855 #ifndef PALM_2
9856 SOAP_FMAC1
9858 SOAP_FMAC2
9859 soap_store_lab(struct soap *soap, const char *s, size_t n)
9860 { soap->labidx = 0;
9861 return soap_append_lab(soap, s, n);
9863 #endif
9864 #endif
9866 /******************************************************************************/
9867 #ifdef WITH_FAST
9868 #ifndef PALM_2
9869 SOAP_FMAC1
9871 SOAP_FMAC2
9872 soap_append_lab(struct soap *soap, const char *s, size_t n)
9873 { if (soap->labidx + n >= soap->lablen)
9874 { register char *t = soap->labbuf;
9875 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Enlarging look-aside buffer to append data, old size=%lu", (unsigned long)soap->lablen));
9876 if (soap->lablen == 0)
9877 soap->lablen = SOAP_LABLEN;
9878 while (soap->labidx + n >= soap->lablen)
9879 soap->lablen <<= 1;
9880 DBGLOG(TEST, SOAP_MESSAGE(fdebug, ", new size=%lu\n", (unsigned long)soap->lablen));
9881 soap->labbuf = (char*)SOAP_MALLOC(soap, soap->lablen);
9882 if (!soap->labbuf)
9883 { if (t)
9884 SOAP_FREE(soap, t);
9885 return soap->error = SOAP_EOM;
9887 if (t)
9888 { memcpy(soap->labbuf, t, soap->labidx);
9889 SOAP_FREE(soap, t);
9892 if (s)
9893 { memcpy(soap->labbuf + soap->labidx, s, n);
9894 soap->labidx += n;
9896 return SOAP_OK;
9898 #endif
9899 #endif
9901 /******************************************************************************/
9902 #ifndef PALM_2
9903 SOAP_FMAC1
9905 SOAP_FMAC2
9906 soap_peek_element(struct soap *soap)
9908 #ifdef WITH_DOM
9909 register struct soap_dom_attribute **att = NULL;
9910 register char *lead = NULL;
9911 #endif
9912 register struct soap_attribute *tp, *tq = NULL;
9913 register const char *t;
9914 register char *s;
9915 register soap_wchar c;
9916 register int i;
9917 if (soap->peeked)
9918 { if (!*soap->tag)
9919 return soap->error = SOAP_NO_TAG;
9920 return SOAP_OK;
9922 soap->peeked = 1;
9923 soap->id[0] = '\0';
9924 soap->href[0] = '\0';
9925 soap->type[0] = '\0';
9926 soap->arrayType[0] = '\0';
9927 soap->arraySize[0] = '\0';
9928 soap->arrayOffset[0] = '\0';
9929 soap->other = 0;
9930 soap->root = -1;
9931 soap->position = 0;
9932 soap->null = 0;
9933 soap->mustUnderstand = 0;
9934 /* skip BOM */
9935 if ((c = soap_getchar(soap)) != 0xEF || (c = soap_get1(soap)) != 0xBB || (c = soap_get1(soap)) != 0xBF)
9936 soap_unget(soap, c);
9937 c = soap_get(soap);
9938 #ifdef WITH_DOM
9939 /* whitespace leading to tag is not insignificant for DOM */
9940 if (soap_blank(c))
9941 { soap->labidx = 0;
9943 { if (soap_append_lab(soap, NULL, 0))
9944 return soap->error;
9945 s = soap->labbuf + soap->labidx;
9946 i = soap->lablen - soap->labidx;
9947 soap->labidx = soap->lablen;
9948 while (soap_blank(c) && i--)
9949 { *s++ = c;
9950 c = soap_get(soap);
9953 while (soap_blank(c));
9954 *s = '\0';
9955 lead = soap->labbuf;
9957 #else
9958 /* skip space */
9959 while (soap_blank(c))
9960 c = soap_get(soap);
9961 #endif
9962 if (c != SOAP_LT)
9963 { *soap->tag = '\0';
9964 if ((int)c == EOF)
9965 return soap->error = SOAP_EOF;
9966 soap_unget(soap, c);
9967 #ifdef WITH_DOM
9968 /* whitespace leading to end tag is significant for DOM */
9969 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
9970 { if (lead && *lead)
9971 soap->dom->tail = soap_strdup(soap, lead);
9972 else
9973 soap->dom->tail = (char*)SOAP_STR_EOS;
9975 #endif
9976 return soap->error = SOAP_NO_TAG;
9978 s = soap->tag;
9979 do c = soap_get1(soap);
9980 while (soap_blank(c));
9981 i = sizeof(soap->tag);
9982 while (c != '>' && c != '/' && soap_notblank(c) && (int)c != EOF)
9983 { if (--i > 0)
9984 *s++ = (char)c;
9985 c = soap_get1(soap);
9987 while (soap_blank(c))
9988 c = soap_get1(soap);
9989 *s = '\0';
9990 #ifdef WITH_DOM
9991 if (soap->mode & SOAP_XML_DOM)
9992 { register struct soap_dom_element *elt;
9993 elt = (struct soap_dom_element*)soap_malloc(soap, sizeof(struct soap_dom_element));
9994 if (!elt)
9995 return soap->error;
9996 elt->next = NULL;
9997 elt->nstr = NULL;
9998 elt->name = soap_strdup(soap, soap->tag);
9999 elt->prnt = soap->dom;
10000 elt->elts = NULL;
10001 elt->atts = NULL;
10002 elt->data = NULL;
10003 elt->wide = NULL;
10004 elt->type = 0;
10005 elt->node = NULL;
10006 elt->head = soap_strdup(soap, lead);
10007 elt->tail = NULL;
10008 elt->soap = soap;
10009 if (soap->dom)
10010 { struct soap_dom_element *p = soap->dom->elts;
10011 if (p)
10012 { while (p->next)
10013 p = p->next;
10014 p->next = elt;
10016 else
10017 soap->dom->elts = elt;
10019 soap->dom = elt;
10020 att = &elt->atts;
10022 #endif
10023 soap_pop_namespace(soap);
10024 for (tp = soap->attributes; tp; tp = tp->next)
10025 tp->visible = 0;
10026 while ((int)c != EOF && c != '>' && c != '/')
10027 { s = soap->tmpbuf;
10028 i = sizeof(soap->tmpbuf);
10029 while (c != '=' && c != '>' && c != '/' && soap_notblank(c) && (int)c != EOF)
10030 { if (--i > 0)
10031 *s++ = (char)c;
10032 c = soap_get1(soap);
10034 *s = '\0';
10035 if (i == sizeof(soap->tmpbuf))
10036 return soap->error = SOAP_SYNTAX_ERROR;
10037 #ifdef WITH_DOM
10038 /* add attribute name to dom */
10039 if (att)
10040 { *att = (struct soap_dom_attribute*)soap_malloc(soap, sizeof(struct soap_dom_attribute));
10041 if (!*att)
10042 return soap->error;
10043 (*att)->next = NULL;
10044 (*att)->nstr = NULL;
10045 (*att)->name = soap_strdup(soap, soap->tmpbuf);
10046 (*att)->data = NULL;
10047 (*att)->wide = NULL;
10048 (*att)->soap = soap;
10050 #endif
10051 if (!strncmp(soap->tmpbuf, "xmlns", 5))
10052 { if (soap->tmpbuf[5] == ':')
10053 t = soap->tmpbuf + 6;
10054 else if (soap->tmpbuf[5])
10055 t = NULL;
10056 else
10057 t = SOAP_STR_EOS;
10059 else
10060 t = NULL;
10061 tq = NULL;
10062 for (tp = soap->attributes; tp; tq = tp, tp = tp->next)
10063 { if (!SOAP_STRCMP(tp->name, soap->tmpbuf))
10064 break;
10066 if (!tp)
10067 { tp = (struct soap_attribute*)SOAP_MALLOC(soap, sizeof(struct soap_attribute) + strlen(soap->tmpbuf));
10068 if (!tp)
10069 return soap->error = SOAP_EOM;
10070 strcpy(tp->name, soap->tmpbuf);
10071 tp->value = NULL;
10072 tp->size = 0;
10073 /* if attribute name is qualified, append it to the end of the list */
10074 if (tq && strchr(soap->tmpbuf, ':'))
10075 { tq->next = tp;
10076 tp->next = NULL;
10078 else
10079 { tp->next = soap->attributes;
10080 soap->attributes = tp;
10083 while (soap_blank(c))
10084 c = soap_get1(soap);
10085 if (c == '=')
10086 { do c = soap_getutf8(soap);
10087 while (soap_blank(c));
10088 if (c != SOAP_QT && c != SOAP_AP)
10089 { soap_unget(soap, c);
10090 c = ' '; /* blank delimiter */
10092 if (soap_getattrval(soap, tp->value, tp->size, c))
10094 #ifdef WITH_FAST
10095 if (soap->error != SOAP_EOM)
10096 return soap->error;
10097 soap->error = SOAP_OK;
10098 if (soap_store_lab(soap, tp->value, tp->size))
10099 return soap->error;
10100 if (tp->value)
10101 SOAP_FREE(soap, tp->value);
10102 for (;;)
10103 { if (soap_getattrval(soap, soap->labbuf + soap->labidx, soap->lablen - soap->labidx, c))
10104 { if (soap->error != SOAP_EOM)
10105 return soap->error;
10106 soap->error = SOAP_OK;
10107 soap->labidx = soap->lablen;
10108 if (soap_append_lab(soap, NULL, 0))
10109 return soap->error;
10111 else
10112 break;
10114 if (soap->labidx)
10115 tp->size = soap->lablen;
10116 else
10117 { tp->size = strlen(soap->labbuf) + 1;
10118 if (tp->size < SOAP_LABLEN)
10119 tp->size = SOAP_LABLEN;
10121 if (!(tp->value = (char*)SOAP_MALLOC(soap, tp->size)))
10122 return soap->error = SOAP_EOM;
10123 strcpy(tp->value, soap->labbuf);
10124 #else
10125 size_t n;
10126 if (soap->error != SOAP_EOM)
10127 return soap->error;
10128 soap->error = SOAP_OK;
10129 if (soap_new_block(soap) == NULL)
10130 return soap->error;
10131 for (;;)
10132 { if (!(s = (char*)soap_push_block(soap, NULL, SOAP_BLKLEN)))
10133 return soap->error;
10134 if (soap_getattrval(soap, s, SOAP_BLKLEN, c))
10135 { if (soap->error != SOAP_EOM)
10136 return soap->error;
10137 soap->error = SOAP_OK;
10139 else
10140 break;
10142 n = tp->size + soap->blist->size;
10143 if (!(s = (char*)SOAP_MALLOC(soap, n)))
10144 return soap->error = SOAP_EOM;
10145 if (tp->value)
10146 { memcpy(s, tp->value, tp->size);
10147 SOAP_FREE(soap, tp->value);
10149 soap_save_block(soap, NULL, s + tp->size, 0);
10150 tp->value = s;
10151 tp->size = n;
10152 #endif
10154 do c = soap_get1(soap);
10155 while (soap_blank(c));
10156 tp->visible = 2; /* seen this attribute w/ value */
10157 #ifdef WITH_DOM
10158 if (att)
10159 (*att)->data = soap_strdup(soap, tp->value);
10160 #endif
10162 else
10163 tp->visible = 1; /* seen this attribute w/o value */
10164 #ifdef WITH_DOM
10165 if (att)
10166 att = &(*att)->next;
10167 #endif
10168 if (t && tp->value)
10169 { if (soap_push_namespace(soap, t, tp->value) == NULL)
10170 return soap->error;
10173 #ifdef WITH_DOM
10174 if (att)
10175 { soap->dom->nstr = soap_current_namespace(soap, soap->tag);
10176 for (att = &soap->dom->atts; *att; att = &(*att)->next)
10177 (*att)->nstr = soap_current_namespace(soap, (*att)->name);
10179 #endif
10180 if ((int)c == EOF)
10181 return soap->error = SOAP_EOF;
10182 if (!(soap->body = (c != '/')))
10183 do c = soap_get1(soap);
10184 while (soap_blank(c));
10185 #ifdef WITH_DOM
10186 if (soap->mode & SOAP_XML_DOM)
10187 { if (!soap->body && soap->dom->prnt)
10188 soap->dom = soap->dom->prnt;
10190 #endif
10191 for (tp = soap->attributes; tp; tp = tp->next)
10192 { if (tp->visible && tp->value)
10194 #ifndef WITH_NOIDREF
10195 if (!strcmp(tp->name, "id"))
10196 { if ((soap->version > 0 && !(soap->mode & SOAP_XML_TREE))
10197 || (soap->mode & SOAP_XML_GRAPH))
10198 { *soap->id = '#';
10199 strncpy(soap->id + 1, tp->value, sizeof(soap->id) - 2);
10200 soap->id[sizeof(soap->id)-1] = '\0';
10203 else if (!strcmp(tp->name, "href"))
10204 { if (soap->version == 1
10205 || (soap->mode & SOAP_XML_GRAPH)
10206 || (soap->mode & SOAP_ENC_MTOM)
10207 || (soap->mode & SOAP_ENC_DIME))
10208 { strncpy(soap->href, tp->value, sizeof(soap->href) - 1);
10209 soap->href[sizeof(soap->href)-1] = '\0';
10212 else
10213 #endif
10214 if (!soap_match_tag(soap, tp->name, "xsi:type"))
10215 { strncpy(soap->type, tp->value, sizeof(soap->type) - 1);
10216 soap->type[sizeof(soap->type)-1] = '\0';
10218 else if ((!soap_match_tag(soap, tp->name, "xsi:null")
10219 || !soap_match_tag(soap, tp->name, "xsi:nil"))
10220 && (!strcmp(tp->value, "1")
10221 || !strcmp(tp->value, "true")))
10222 { soap->null = 1;
10224 else if (soap->version == 1)
10225 { if (!soap_match_tag(soap, tp->name, "SOAP-ENC:arrayType"))
10226 { s = soap_strrchr(tp->value, '[');
10227 if (s && (size_t)(s - tp->value) < sizeof(soap->arrayType))
10228 { strncpy(soap->arrayType, tp->value, s - tp->value);
10229 soap->arrayType[s - tp->value] = '\0';
10230 strncpy(soap->arraySize, s, sizeof(soap->arraySize) - 1);
10232 else
10233 strncpy(soap->arrayType, tp->value, sizeof(soap->arrayType) - 1);
10234 soap->arraySize[sizeof(soap->arrayType)-1] = '\0';
10235 soap->arrayType[sizeof(soap->arrayType)-1] = '\0';
10237 else if (!soap_match_tag(soap, tp->name, "SOAP-ENC:offset"))
10238 strncpy(soap->arrayOffset, tp->value, sizeof(soap->arrayOffset));
10239 else if (!soap_match_tag(soap, tp->name, "SOAP-ENC:position"))
10240 soap->position = soap_getposition(tp->value, soap->positions);
10241 else if (!soap_match_tag(soap, tp->name, "SOAP-ENC:root"))
10242 soap->root = ((!strcmp(tp->value, "1") || !strcmp(tp->value, "true")));
10243 else if (!soap_match_tag(soap, tp->name, "SOAP-ENV:mustUnderstand")
10244 && (!strcmp(tp->value, "1") || !strcmp(tp->value, "true")))
10245 soap->mustUnderstand = 1;
10246 else if (!soap_match_tag(soap, tp->name, "SOAP-ENV:actor"))
10247 { if ((!soap->actor || strcmp(soap->actor, tp->value))
10248 && strcmp(tp->value, "http://schemas.xmlsoap.org/soap/actor/next"))
10249 soap->other = 1;
10252 else if (soap->version == 2)
10254 #ifndef WITH_NOIDREF
10255 if (!strcmp(tp->name, "ref")
10256 || !soap_match_tag(soap, tp->name, "SOAP-ENC:ref"))
10257 { *soap->href = '#';
10258 strncpy(soap->href + 1, tp->value, sizeof(soap->href) - 2);
10259 soap->href[sizeof(soap->href)-1] = '\0';
10261 else
10262 #endif
10263 if (!soap_match_tag(soap, tp->name, "SOAP-ENC:itemType"))
10264 strncpy(soap->arrayType, tp->value, sizeof(soap->arrayType) - 1);
10265 else if (!soap_match_tag(soap, tp->name, "SOAP-ENC:arraySize"))
10266 strncpy(soap->arraySize, tp->value, sizeof(soap->arraySize) - 1);
10267 else if (!soap_match_tag(soap, tp->name, "SOAP-ENV:mustUnderstand")
10268 && (!strcmp(tp->value, "1") || !strcmp(tp->value, "true")))
10269 soap->mustUnderstand = 1;
10270 else if (!soap_match_tag(soap, tp->name, "SOAP-ENV:role"))
10271 { if ((!soap->actor || strcmp(soap->actor, tp->value))
10272 && strcmp(tp->value, "http://www.w3.org/2003/05/soap-envelope/role/next"))
10273 soap->other = 1;
10276 else
10277 { if (!soap_match_tag(soap, tp->name, "wsdl:required") && !strcmp(tp->value, "true"))
10278 soap->mustUnderstand = 1;
10282 return soap->error = SOAP_OK;
10284 #endif
10286 /******************************************************************************/
10287 #ifndef PALM_2
10288 SOAP_FMAC1
10289 void
10290 SOAP_FMAC2
10291 soap_retry(struct soap *soap)
10292 { soap->error = SOAP_OK;
10293 soap_revert(soap);
10295 #endif
10297 /******************************************************************************/
10298 #ifndef PALM_2
10299 SOAP_FMAC1
10300 void
10301 SOAP_FMAC2
10302 soap_revert(struct soap *soap)
10303 { if (!soap->peeked)
10304 { soap->peeked = 1;
10305 if (soap->body)
10306 soap->level--;
10308 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Reverting to last element '%s' (level=%u)\n", soap->tag, soap->level));
10310 #endif
10312 /******************************************************************************/
10313 #ifndef PALM_2
10314 SOAP_FMAC1
10316 SOAP_FMAC2
10317 soap_string_out(struct soap *soap, const char *s, int flag)
10318 { register const char *t;
10319 register soap_wchar c;
10320 register soap_wchar mask = (soap_wchar)0xFFFFFF80UL;
10321 #ifdef WITH_DOM
10322 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
10323 { soap->dom->data = soap_strdup(soap, s);
10324 return SOAP_OK;
10326 #endif
10327 if (flag == 2 || soap->mode & SOAP_C_UTFSTRING)
10328 mask = 0;
10329 t = s;
10330 while ((c = *t++))
10331 { switch (c)
10333 case 0x09:
10334 if (flag)
10335 { if (soap_send_raw(soap, s, t - s - 1) || soap_send_raw(soap, "&#x9;", 5))
10336 return soap->error;
10337 s = t;
10339 break;
10340 case 0x0A:
10341 if (flag || !(soap->mode & SOAP_XML_CANONICAL))
10342 { if (soap_send_raw(soap, s, t - s - 1) || soap_send_raw(soap, "&#xA;", 5))
10343 return soap->error;
10344 s = t;
10346 break;
10347 case 0x0D:
10348 if (soap_send_raw(soap, s, t - s - 1) || soap_send_raw(soap, "&#xD;", 5))
10349 return soap->error;
10350 s = t;
10351 break;
10352 case '&':
10353 if (soap_send_raw(soap, s, t - s - 1) || soap_send_raw(soap, "&amp;", 5))
10354 return soap->error;
10355 s = t;
10356 break;
10357 case '<':
10358 if (soap_send_raw(soap, s, t - s - 1) || soap_send_raw(soap, "&lt;", 4))
10359 return soap->error;
10360 s = t;
10361 break;
10362 case '>':
10363 if (!flag)
10364 { if (soap_send_raw(soap, s, t - s - 1) || soap_send_raw(soap, "&gt;", 4))
10365 return soap->error;
10366 s = t;
10368 break;
10369 case '"':
10370 if (flag)
10371 { if (soap_send_raw(soap, s, t - s - 1) || soap_send_raw(soap, "&quot;", 6))
10372 return soap->error;
10373 s = t;
10375 break;
10376 default:
10377 #ifndef WITH_LEANER
10378 #ifdef HAVE_MBTOWC
10379 if (soap->mode & SOAP_C_MBSTRING)
10380 { wchar_t wc;
10381 register int m = mbtowc(&wc, t - 1, MB_CUR_MAX);
10382 if (m > 0 && wc != c)
10383 { if (soap_send_raw(soap, s, t - s - 1) || soap_pututf8(soap, wc))
10384 return soap->error;
10385 s = t += m - 1;
10386 continue;
10389 #endif
10390 #endif
10391 #ifndef WITH_NOSTRINGTOUTF8
10392 if ((c & mask) || !(c & 0xFFFFFFE0UL))
10393 { if (soap_send_raw(soap, s, t - s - 1) || soap_pututf8(soap, (unsigned char)c))
10394 return soap->error;
10395 s = t;
10397 #endif
10400 return soap_send_raw(soap, s, t - s - 1);
10402 #endif
10404 /******************************************************************************/
10405 #ifndef PALM_2
10406 SOAP_FMAC1
10407 char *
10408 SOAP_FMAC2
10409 soap_string_in(struct soap *soap, int flag, long minlen, long maxlen)
10410 { register char *s;
10411 char *t = NULL;
10412 register size_t i;
10413 register long l = 0;
10414 register int n = 0, f = 0, m = 0;
10415 register soap_wchar c;
10416 #if !defined(WITH_LEANER) && defined(HAVE_WCTOMB)
10417 char buf[MB_LEN_MAX > 8 ? MB_LEN_MAX : 8];
10418 #else
10419 char buf[8];
10420 #endif
10421 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Reading string content, flag=%d\n", flag));
10422 if (soap->peeked && *soap->tag)
10424 #ifndef WITH_LEAN
10425 struct soap_attribute *tp;
10426 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "String content includes tag '%s' and attributes\n", soap->tag));
10427 t = soap->tmpbuf;
10428 *t = '<';
10429 t[sizeof(soap->tmpbuf)-1] = '\0';
10430 strncpy(t + 1, soap->tag, sizeof(soap->tmpbuf) - 2);
10431 t += strlen(t);
10432 for (tp = soap->attributes; tp; tp = tp->next)
10433 { if (tp->visible)
10434 { if (t >= soap->tmpbuf + sizeof(soap->tmpbuf) - 2)
10435 break;
10436 *t++ = ' ';
10437 strcpy(t, tp->name);
10438 t += strlen(t);
10439 if (t >= soap->tmpbuf + sizeof(soap->tmpbuf) - 2)
10440 break; /* too many or large attribute values */
10441 if (tp->value)
10442 { *t++ = '=';
10443 *t++ = '"';
10444 strcpy(t, tp->value);
10445 t += strlen(t);
10446 *t++ = '"';
10450 if (!soap->body)
10451 *t++ = '/';
10452 *t++ = '>';
10453 *t = '\0';
10454 t = soap->tmpbuf;
10455 m = (int)strlen(soap->tmpbuf);
10456 #endif
10457 if (soap->body)
10458 n = 1;
10459 f = 1;
10460 soap->peeked = 0;
10462 #ifdef WITH_CDATA
10463 if (!flag)
10464 { register int state = 0;
10465 #ifdef WITH_FAST
10466 soap->labidx = 0; /* use look-aside buffer */
10467 #else
10468 if (soap_new_block(soap) == NULL)
10469 return NULL;
10470 #endif
10471 for (;;)
10473 #ifdef WITH_FAST
10474 register size_t k;
10475 if (soap_append_lab(soap, NULL, 0)) /* allocate more space in look-aside buffer if necessary */
10476 return NULL;
10477 s = soap->labbuf + soap->labidx; /* space to populate */
10478 k = soap->lablen - soap->labidx; /* number of bytes available */
10479 soap->labidx = soap->lablen; /* claim this space */
10480 #else
10481 register size_t k = SOAP_BLKLEN;
10482 if (!(s = (char*)soap_push_block(soap, NULL, k)))
10483 return NULL;
10484 #endif
10485 for (i = 0; i < k; i++)
10486 { if (m > 0)
10487 { *s++ = *t++; /* copy multibyte characters */
10488 m--;
10489 continue;
10491 c = soap_getchar(soap);
10492 if ((int)c == EOF)
10493 goto end;
10494 if (c >= 0x80 && state != 1 && !(soap->mode & SOAP_ENC_LATIN))
10495 { soap_unget(soap, c);
10496 c = soap_getutf8(soap);
10497 if (soap->mode & SOAP_C_UTFSTRING)
10498 { c &= 0x7FFFFFFF;
10499 t = buf;
10500 if (c < 0x0800)
10501 *t++ = (char)(0xC0 | ((c >> 6) & 0x1F));
10502 else
10503 { if (c < 0x010000)
10504 *t++ = (char)(0xE0 | ((c >> 12) & 0x0F));
10505 else
10506 { if (c < 0x200000)
10507 *t++ = (char)(0xF0 | ((c >> 18) & 0x07));
10508 else
10509 { if (c < 0x04000000)
10510 *t++ = (char)(0xF8 | ((c >> 24) & 0x03));
10511 else
10512 { *t++ = (char)(0xFC | ((c >> 30) & 0x01));
10513 *t++ = (char)(0x80 | ((c >> 24) & 0x3F));
10515 *t++ = (char)(0x80 | ((c >> 18) & 0x3F));
10517 *t++ = (char)(0x80 | ((c >> 12) & 0x3F));
10519 *t++ = (char)(0x80 | ((c >> 6) & 0x3F));
10521 *t++ = (char)(0x80 | (c & 0x3F));
10522 m = (int)(t - buf) - 1;
10523 t = buf;
10524 *s++ = *t++;
10525 continue;
10528 switch (state)
10529 { case 1:
10530 if (c == ']')
10531 state = 4;
10532 *s++ = c;
10533 continue;
10534 case 2:
10535 if (c == '-')
10536 state = 6;
10537 *s++ = c;
10538 continue;
10539 case 3:
10540 if (c == '?')
10541 state = 8;
10542 *s++ = c;
10543 continue;
10544 /* CDATA */
10545 case 4:
10546 if (c == ']')
10547 state = 5;
10548 else
10549 state = 1;
10550 *s++ = c;
10551 continue;
10552 case 5:
10553 if (c == '>')
10554 state = 0;
10555 else
10556 state = 1;
10557 *s++ = c;
10558 continue;
10559 /* comment */
10560 case 6:
10561 if (c == '-')
10562 state = 7;
10563 else
10564 state = 2;
10565 *s++ = c;
10566 continue;
10567 case 7:
10568 if (c == '>')
10569 state = 0;
10570 else
10571 state = 2;
10572 *s++ = c;
10573 continue;
10574 /* PI */
10575 case 8:
10576 if (c == '>')
10577 state = 0;
10578 else
10579 state = 3;
10580 *s++ = c;
10581 continue;
10583 switch (c)
10585 case SOAP_TT:
10586 if (n == 0)
10587 goto end;
10588 n--;
10589 *s++ = '<';
10590 t = (char*)"/";
10591 m = 1;
10592 break;
10593 case SOAP_LT:
10594 if (f && n == 0)
10595 goto end;
10596 n++;
10597 *s++ = '<';
10598 break;
10599 case '/':
10600 if (n > 0)
10601 { c = soap_getchar(soap);
10602 if (c == '>')
10603 n--;
10604 soap_unget(soap, c);
10606 *s++ = '/';
10607 break;
10608 case '<':
10609 c = soap_getchar(soap);
10610 if (c == '/')
10611 { if (n == 0)
10612 { c = SOAP_TT;
10613 goto end;
10615 n--;
10617 else if (c == '!')
10618 { c = soap_getchar(soap);
10619 if (c == '[')
10620 { do c = soap_getchar(soap);
10621 while ((int)c != EOF && c != '[');
10622 if ((int)c == EOF)
10623 goto end;
10624 t = (char*)"![CDATA[";
10625 m = 8;
10626 state = 1;
10628 else if (c == '-')
10629 { if ((c = soap_getchar(soap)) == '-')
10630 state = 2;
10631 t = (char*)"!-";
10632 m = 2;
10633 soap_unget(soap, c);
10635 else
10636 { t = (char*)"!";
10637 m = 1;
10638 soap_unget(soap, c);
10640 *s++ = '<';
10641 break;
10643 else if (c == '?')
10644 state = 3;
10645 else if (f && n == 0)
10646 { soap_revget1(soap);
10647 c = '<';
10648 goto end;
10650 else
10651 n++;
10652 soap_unget(soap, c);
10653 *s++ = '<';
10654 break;
10655 case '>':
10656 *s++ = '>';
10657 break;
10658 case '"':
10659 *s++ = '"';
10660 break;
10661 default:
10662 #ifndef WITH_LEANER
10663 #ifdef HAVE_WCTOMB
10664 if (soap->mode & SOAP_C_MBSTRING)
10665 { m = wctomb(buf, c & 0x7FFFFFFF);
10666 if (m >= 1 && m <= (int)MB_CUR_MAX)
10667 { t = buf;
10668 *s++ = *t++;
10669 m--;
10671 else
10672 { *s++ = SOAP_UNKNOWN_CHAR;
10673 m = 0;
10676 else
10677 #endif
10678 #endif
10679 *s++ = (char)(c & 0xFF);
10681 l++;
10682 if (maxlen >= 0 && l > maxlen)
10683 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "String too long: maxlen=%ld\n", maxlen));
10684 soap->error = SOAP_LENGTH;
10685 return NULL;
10690 #endif
10691 #ifdef WITH_FAST
10692 soap->labidx = 0; /* use look-aside buffer */
10693 #else
10694 if (soap_new_block(soap) == NULL)
10695 return NULL;
10696 #endif
10697 for (;;)
10699 #ifdef WITH_FAST
10700 register size_t k;
10701 if (soap_append_lab(soap, NULL, 0)) /* allocate more space in look-aside buffer if necessary */
10702 return NULL;
10703 s = soap->labbuf + soap->labidx; /* space to populate */
10704 k = soap->lablen - soap->labidx; /* number of bytes available */
10705 soap->labidx = soap->lablen; /* claim this space */
10706 #else
10707 register size_t k = SOAP_BLKLEN;
10708 if (!(s = (char*)soap_push_block(soap, NULL, k)))
10709 return NULL;
10710 #endif
10711 for (i = 0; i < k; i++)
10712 { if (m > 0)
10713 { *s++ = *t++; /* copy multibyte characters */
10714 m--;
10715 continue;
10717 if (soap->mode & SOAP_C_UTFSTRING)
10718 { if (((c = soap_get(soap)) & 0x80000000) && c >= -0x7FFFFF80 && c < SOAP_AP)
10719 { c &= 0x7FFFFFFF;
10720 t = buf;
10721 if (c < 0x0800)
10722 *t++ = (char)(0xC0 | ((c >> 6) & 0x1F));
10723 else
10724 { if (c < 0x010000)
10725 *t++ = (char)(0xE0 | ((c >> 12) & 0x0F));
10726 else
10727 { if (c < 0x200000)
10728 *t++ = (char)(0xF0 | ((c >> 18) & 0x07));
10729 else
10730 { if (c < 0x04000000)
10731 *t++ = (char)(0xF8 | ((c >> 24) & 0x03));
10732 else
10733 { *t++ = (char)(0xFC | ((c >> 30) & 0x01));
10734 *t++ = (char)(0x80 | ((c >> 24) & 0x3F));
10736 *t++ = (char)(0x80 | ((c >> 18) & 0x3F));
10738 *t++ = (char)(0x80 | ((c >> 12) & 0x3F));
10740 *t++ = (char)(0x80 | ((c >> 6) & 0x3F));
10742 *t++ = (char)(0x80 | (c & 0x3F));
10743 m = (int)(t - buf) - 1;
10744 t = buf;
10745 *s++ = *t++;
10746 continue;
10749 else
10750 c = soap_getutf8(soap);
10751 switch (c)
10753 case SOAP_TT:
10754 if (n == 0)
10755 goto end;
10756 n--;
10757 *s++ = '<';
10758 t = (char*)"/";
10759 m = 1;
10760 break;
10761 case SOAP_LT:
10762 if (f && n == 0)
10763 goto end;
10764 n++;
10765 *s++ = '<';
10766 break;
10767 case SOAP_GT:
10768 *s++ = '>';
10769 break;
10770 case SOAP_QT:
10771 *s++ = '"';
10772 break;
10773 case SOAP_AP:
10774 *s++ = '\'';
10775 break;
10776 case '/':
10777 if (n > 0)
10778 { c = soap_get(soap);
10779 if (c == SOAP_GT)
10780 n--;
10781 soap_unget(soap, c);
10783 *s++ = '/';
10784 break;
10785 case (soap_wchar)('<' | 0x80000000):
10786 if (flag)
10787 *s++ = '<';
10788 else
10789 { *s++ = '&';
10790 t = (char*)"lt;";
10791 m = 3;
10793 break;
10794 case (soap_wchar)('>' | 0x80000000):
10795 if (flag)
10796 *s++ = '>';
10797 else
10798 { *s++ = '&';
10799 t = (char*)"gt;";
10800 m = 3;
10802 break;
10803 case (soap_wchar)('&' | 0x80000000):
10804 if (flag)
10805 *s++ = '&';
10806 else
10807 { *s++ = '&';
10808 t = (char*)"amp;";
10809 m = 4;
10811 break;
10812 case (soap_wchar)('"' | 0x80000000):
10813 if (flag)
10814 *s++ = '"';
10815 else
10816 { *s++ = '&';
10817 t = (char*)"quot;";
10818 m = 5;
10820 break;
10821 case (soap_wchar)('\'' | 0x80000000):
10822 if (flag)
10823 *s++ = '\'';
10824 else
10825 { *s++ = '&';
10826 t = (char*)"apos;";
10827 m = 5;
10829 break;
10830 default:
10831 if ((int)c == EOF)
10832 goto end;
10833 #ifndef WITH_LEANER
10834 #ifdef HAVE_WCTOMB
10835 if (soap->mode & SOAP_C_MBSTRING)
10836 { m = wctomb(buf, c & 0x7FFFFFFF);
10837 if (m >= 1 && m <= (int)MB_CUR_MAX)
10838 { t = buf;
10839 *s++ = *t++;
10840 m--;
10842 else
10843 { *s++ = SOAP_UNKNOWN_CHAR;
10844 m = 0;
10847 else
10848 #endif
10849 #endif
10850 *s++ = (char)(c & 0xFF);
10852 l++;
10853 if (maxlen >= 0 && l > maxlen)
10854 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "String too long: maxlen=%ld\n", maxlen));
10855 soap->error = SOAP_LENGTH;
10856 return NULL;
10860 end:
10861 soap_unget(soap, c);
10862 *s = '\0';
10863 #ifdef WITH_FAST
10864 t = soap_strdup(soap, soap->labbuf);
10865 #else
10866 soap_size_block(soap, NULL, i+1);
10867 t = soap_save_block(soap, NULL, 0);
10868 #endif
10869 if (l < minlen)
10870 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "String too short: %ld chars, minlen=%ld\n", l, minlen));
10871 soap->error = SOAP_LENGTH;
10872 return NULL;
10874 #ifdef WITH_DOM
10875 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
10876 { if (flag == 3)
10877 soap->dom->tail = t;
10878 else
10879 soap->dom->data = t;
10881 #endif
10882 if (flag == 2)
10883 if (soap_s2QName(soap, t, &t, minlen, maxlen))
10884 return NULL;
10885 return t;
10887 #endif
10889 /******************************************************************************/
10890 #ifndef WITH_LEANER
10891 #ifndef PALM_2
10892 SOAP_FMAC1
10894 SOAP_FMAC2
10895 soap_wstring_out(struct soap *soap, const wchar_t *s, int flag)
10896 { const char *t;
10897 char tmp;
10898 register soap_wchar c;
10899 #ifdef WITH_DOM
10900 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
10901 { wchar_t *r = (wchar_t*)s;
10902 int n = 1;
10903 while (*r++)
10904 n++;
10905 soap->dom->wide = r = (wchar_t*)soap_malloc(soap, n * sizeof(wchar_t));
10906 while (n--)
10907 *r++ = *s++;
10908 return SOAP_OK;
10910 #endif
10911 while ((c = *s++))
10912 { switch (c)
10914 case 0x09:
10915 if (flag)
10916 t = "&#x9;";
10917 else
10918 t = "\t";
10919 break;
10920 case 0x0A:
10921 if (flag || !(soap->mode & SOAP_XML_CANONICAL))
10922 t = "&#xA;";
10923 else
10924 t = "\n";
10925 break;
10926 case 0x0D:
10927 t = "&#xD;";
10928 break;
10929 case '&':
10930 t = "&amp;";
10931 break;
10932 case '<':
10933 t = "&lt;";
10934 break;
10935 case '>':
10936 if (flag)
10937 t = ">";
10938 else
10939 t = "&gt;";
10940 break;
10941 case '"':
10942 if (flag)
10943 t = "&quot;";
10944 else
10945 t = "\"";
10946 break;
10947 default:
10948 if (c >= 0x20 && c < 0x80)
10949 { tmp = (char)c;
10950 if (soap_send_raw(soap, &tmp, 1))
10951 return soap->error;
10953 else /* check UTF16 encoding when wchar_t is too small to hold UCS */
10954 { if (sizeof(wchar_t) < 4 && (c & 0xD800) == 0xD800)
10955 { /* http://unicode.org/faq/utf_bom.html#utf16-2 */
10956 if ((*s & 0xD800) == 0xD800)
10957 c = (c << 10) + *s++ + 0x10000 - (0xD800 << 10) - 0xDC00;
10958 else
10959 c = 0xFFFD; /* Malformed */
10961 if (soap_pututf8(soap, (unsigned long)c))
10962 return soap->error;
10964 continue;
10966 if (soap_send(soap, t))
10967 return soap->error;
10969 return SOAP_OK;
10971 #endif
10972 #endif
10974 /******************************************************************************/
10975 #ifndef WITH_LEANER
10976 #ifndef PALM_2
10977 SOAP_FMAC1
10978 wchar_t *
10979 SOAP_FMAC2
10980 soap_wstring_in(struct soap *soap, int flag, long minlen, long maxlen)
10981 { wchar_t *s;
10982 register int i, n = 0, f = 0;
10983 register long l = 0;
10984 register soap_wchar c;
10985 char *t = NULL;
10986 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Reading wide string content\n"));
10987 if (soap->peeked)
10988 { if (*soap->tag)
10990 #ifndef WITH_LEAN
10991 struct soap_attribute *tp;
10992 t = soap->tmpbuf;
10993 *t = '<';
10994 t[sizeof(soap->tmpbuf)-1] = '\0';
10995 strncpy(t + 1, soap->tag, sizeof(soap->tmpbuf) - 2);
10996 t += strlen(t);
10997 for (tp = soap->attributes; tp; tp = tp->next)
10998 { if (tp->visible)
10999 { if (t >= soap->tmpbuf + sizeof(soap->tmpbuf) - 2)
11000 break;
11001 *t++ = ' ';
11002 strcpy(t, tp->name);
11003 t += strlen(t);
11004 if (t >= soap->tmpbuf + sizeof(soap->tmpbuf) - 2)
11005 break;
11006 if (tp->value)
11007 { *t++ = '=';
11008 *t++ = '"';
11009 strcpy(t, tp->value);
11010 t += strlen(t);
11011 *t++ = '"';
11015 if (!soap->body)
11016 *t++ = '/';
11017 *t++ = '>';
11018 *t = '\0';
11019 t = soap->tmpbuf;
11020 #endif
11021 if (soap->body)
11022 n = 1;
11023 f = 1;
11024 soap->peeked = 0;
11027 if (soap_new_block(soap) == NULL)
11028 return NULL;
11029 for (;;)
11030 { if (!(s = (wchar_t*)soap_push_block(soap, NULL, sizeof(wchar_t)*SOAP_BLKLEN)))
11031 return NULL;
11032 for (i = 0; i < SOAP_BLKLEN; i++)
11033 { if (t)
11034 { *s++ = (wchar_t)*t++;
11035 if (!*t)
11036 t = NULL;
11037 continue;
11039 c = soap_getutf8(soap);
11040 switch (c)
11042 case SOAP_TT:
11043 if (n == 0)
11044 goto end;
11045 n--;
11046 *s++ = '<';
11047 soap_unget(soap, '/');
11048 break;
11049 case SOAP_LT:
11050 if (f && n == 0)
11051 goto end;
11052 n++;
11053 *s++ = '<';
11054 break;
11055 case SOAP_GT:
11056 *s++ = '>';
11057 break;
11058 case SOAP_QT:
11059 *s++ = '"';
11060 break;
11061 case SOAP_AP:
11062 *s++ = '\'';
11063 break;
11064 case '/':
11065 if (n > 0)
11066 { c = soap_getutf8(soap);
11067 if (c == SOAP_GT)
11068 n--;
11069 soap_unget(soap, c);
11071 *s++ = '/';
11072 break;
11073 case '<':
11074 if (flag)
11075 *s++ = (soap_wchar)'<';
11076 else
11077 { *s++ = (soap_wchar)'&';
11078 t = (char*)"lt;";
11080 break;
11081 case '>':
11082 if (flag)
11083 *s++ = (soap_wchar)'>';
11084 else
11085 { *s++ = (soap_wchar)'&';
11086 t = (char*)"gt;";
11088 break;
11089 case '"':
11090 if (flag)
11091 *s++ = (soap_wchar)'"';
11092 else
11093 { *s++ = (soap_wchar)'&';
11094 t = (char*)"quot;";
11096 break;
11097 default:
11098 if ((int)c == EOF)
11099 goto end;
11100 if (sizeof(wchar_t) < 4 && c > 0xFFFF)
11101 { wchar_t c1, c2;
11102 /* http://unicode.org/faq/utf_bom.html#utf16-2 */
11103 c1 = 0xD800 - (0x10000 >> 10) + (c >> 10);
11104 c2 = 0xDC00 + (c & 0x3FF);
11105 c = c1;
11106 soap_unget(soap, c2);
11108 *s++ = (wchar_t)c & 0x7FFFFFFF;
11110 l++;
11111 if (maxlen >= 0 && l > maxlen)
11112 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "String too long: maxlen=%ld\n", maxlen));
11113 soap->error = SOAP_LENGTH;
11114 return NULL;
11118 end:
11119 soap_unget(soap, c);
11120 *s = '\0';
11121 soap_size_block(soap, NULL, sizeof(wchar_t) * (i + 1));
11122 if (l < minlen)
11123 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "String too short: %ld chars, minlen=%ld\n", l, minlen));
11124 soap->error = SOAP_LENGTH;
11125 return NULL;
11127 s = (wchar_t*)soap_save_block(soap, NULL, NULL, 0);
11128 #ifdef WITH_DOM
11129 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
11130 soap->dom->wide = s;
11131 #endif
11132 return s;
11134 #endif
11135 #endif
11137 /******************************************************************************/
11138 #ifndef PALM_2
11139 SOAP_FMAC1
11140 const char*
11141 SOAP_FMAC2
11142 soap_int2s(struct soap *soap, int n)
11143 { return soap_long2s(soap, (long)n);
11145 #endif
11147 /******************************************************************************/
11148 #ifndef PALM_2
11149 SOAP_FMAC1
11151 SOAP_FMAC2
11152 soap_outint(struct soap *soap, const char *tag, int id, const int *p, const char *type, int n)
11153 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
11154 || soap_string_out(soap, soap_long2s(soap, (long)*p), 0))
11155 return soap->error;
11156 return soap_element_end_out(soap, tag);
11158 #endif
11160 /******************************************************************************/
11161 #ifndef PALM_2
11162 SOAP_FMAC1
11164 SOAP_FMAC2
11165 soap_s2int(struct soap *soap, const char *s, int *p)
11166 { if (s)
11167 { char *r;
11168 #ifndef WITH_NOIO
11169 #ifndef WITH_LEAN
11170 soap_reset_errno;
11171 #endif
11172 #endif
11173 *p = (int)soap_strtol(s, &r, 10);
11174 if ((s == r && (soap->mode & SOAP_XML_STRICT)) || *r
11175 #ifndef WITH_NOIO
11176 #ifndef WITH_LEAN
11177 || soap_errno == SOAP_ERANGE
11178 #endif
11179 #endif
11181 soap->error = SOAP_TYPE;
11183 return soap->error;
11185 #endif
11187 /******************************************************************************/
11188 #ifndef PALM_2
11189 SOAP_FMAC1
11190 int *
11191 SOAP_FMAC2
11192 soap_inint(struct soap *soap, const char *tag, int *p, const char *type, int t)
11193 { if (soap_element_begin_in(soap, tag, 0, NULL))
11194 return NULL;
11195 #ifndef WITH_LEAN
11196 if (*soap->type
11197 && soap_match_tag(soap, soap->type, type)
11198 && soap_match_tag(soap, soap->type, ":int")
11199 && soap_match_tag(soap, soap->type, ":short")
11200 && soap_match_tag(soap, soap->type, ":byte"))
11201 { soap->error = SOAP_TYPE;
11202 soap_revert(soap);
11203 return NULL;
11205 #endif
11206 p = (int*)soap_id_enter(soap, soap->id, p, t, sizeof(int), 0, NULL, NULL, NULL);
11207 if (*soap->href)
11208 p = (int*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(int), 0, NULL);
11209 else if (p)
11210 { if (soap_s2int(soap, soap_value(soap), p))
11211 return NULL;
11213 if (soap->body && soap_element_end_in(soap, tag))
11214 return NULL;
11215 return p;
11217 #endif
11219 /******************************************************************************/
11220 #ifndef PALM_2
11221 SOAP_FMAC1
11222 const char*
11223 SOAP_FMAC2
11224 soap_long2s(struct soap *soap, long n)
11225 { sprintf(soap->tmpbuf, "%ld", n);
11226 return soap->tmpbuf;
11228 #endif
11230 /******************************************************************************/
11231 #ifndef PALM_2
11232 SOAP_FMAC1
11234 SOAP_FMAC2
11235 soap_outlong(struct soap *soap, const char *tag, int id, const long *p, const char *type, int n)
11236 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
11237 || soap_string_out(soap, soap_long2s(soap, *p), 0))
11238 return soap->error;
11239 return soap_element_end_out(soap, tag);
11241 #endif
11243 /******************************************************************************/
11244 #ifndef PALM_2
11245 SOAP_FMAC1
11247 SOAP_FMAC2
11248 soap_s2long(struct soap *soap, const char *s, long *p)
11249 { if (s)
11250 { char *r;
11251 #ifndef WITH_NOIO
11252 #ifndef WITH_LEAN
11253 soap_reset_errno;
11254 #endif
11255 #endif
11256 *p = soap_strtol(s, &r, 10);
11257 if ((s == r && (soap->mode & SOAP_XML_STRICT)) || *r
11258 #ifndef WITH_NOIO
11259 #ifndef WITH_LEAN
11260 || soap_errno == SOAP_ERANGE
11261 #endif
11262 #endif
11264 soap->error = SOAP_TYPE;
11266 return soap->error;
11268 #endif
11270 /******************************************************************************/
11271 #ifndef PALM_2
11272 SOAP_FMAC1
11273 long *
11274 SOAP_FMAC2
11275 soap_inlong(struct soap *soap, const char *tag, long *p, const char *type, int t)
11276 { if (soap_element_begin_in(soap, tag, 0, NULL))
11277 return NULL;
11278 #ifndef WITH_LEAN
11279 if (*soap->type
11280 && soap_match_tag(soap, soap->type, type)
11281 && soap_match_tag(soap, soap->type, ":int")
11282 && soap_match_tag(soap, soap->type, ":short")
11283 && soap_match_tag(soap, soap->type, ":byte"))
11284 { soap->error = SOAP_TYPE;
11285 soap_revert(soap);
11286 return NULL;
11288 #endif
11289 p = (long*)soap_id_enter(soap, soap->id, p, t, sizeof(long), 0, NULL, NULL, NULL);
11290 if (*soap->href)
11291 p = (long*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(long), 0, NULL);
11292 else if (p)
11293 { if (soap_s2long(soap, soap_value(soap), p))
11294 return NULL;
11296 if (soap->body && soap_element_end_in(soap, tag))
11297 return NULL;
11298 return p;
11300 #endif
11302 /******************************************************************************/
11303 #ifndef WITH_LEAN
11304 SOAP_FMAC1
11305 const char*
11306 SOAP_FMAC2
11307 soap_LONG642s(struct soap *soap, LONG64 n)
11308 { sprintf(soap->tmpbuf, SOAP_LONG_FORMAT, n);
11309 return soap->tmpbuf;
11311 #endif
11313 /******************************************************************************/
11314 #ifndef WITH_LEAN
11315 SOAP_FMAC1
11317 SOAP_FMAC2
11318 soap_outLONG64(struct soap *soap, const char *tag, int id, const LONG64 *p, const char *type, int n)
11319 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
11320 || soap_string_out(soap, soap_LONG642s(soap, *p), 0))
11321 return soap->error;
11322 return soap_element_end_out(soap, tag);
11324 #endif
11326 /******************************************************************************/
11327 #ifndef WITH_LEAN
11328 SOAP_FMAC1
11330 SOAP_FMAC2
11331 soap_s2LONG64(struct soap *soap, const char *s, LONG64 *p)
11332 { if (s)
11334 #ifdef HAVE_STRTOLL
11335 char *r;
11336 #ifndef WITH_NOIO
11337 #ifndef WITH_LEAN
11338 soap_reset_errno;
11339 #endif
11340 #endif
11341 *p = strtoll(s, &r, 10);
11342 if ((s == r && (soap->mode & SOAP_XML_STRICT)) || *r
11343 #ifndef WITH_NOIO
11344 #ifndef WITH_LEAN
11345 || soap_errno == SOAP_ERANGE
11346 #endif
11347 #endif
11349 #else
11350 # ifdef HAVE_SSCANF
11351 if (sscanf(s, SOAP_LONG_FORMAT, p) != 1)
11352 # endif
11353 #endif
11354 soap->error = SOAP_TYPE;
11356 return soap->error;
11358 #endif
11360 /******************************************************************************/
11361 #ifndef WITH_LEAN
11362 SOAP_FMAC1
11363 LONG64 *
11364 SOAP_FMAC2
11365 soap_inLONG64(struct soap *soap, const char *tag, LONG64 *p, const char *type, int t)
11366 { if (soap_element_begin_in(soap, tag, 0, NULL))
11367 return NULL;
11368 #ifndef WITH_LEAN
11369 if (*soap->type
11370 && soap_match_tag(soap, soap->type, type)
11371 && soap_match_tag(soap, soap->type, ":integer")
11372 && soap_match_tag(soap, soap->type, ":positiveInteger")
11373 && soap_match_tag(soap, soap->type, ":negativeInteger")
11374 && soap_match_tag(soap, soap->type, ":nonPositiveInteger")
11375 && soap_match_tag(soap, soap->type, ":nonNegativeInteger")
11376 && soap_match_tag(soap, soap->type, ":long")
11377 && soap_match_tag(soap, soap->type, ":int")
11378 && soap_match_tag(soap, soap->type, ":short")
11379 && soap_match_tag(soap, soap->type, ":byte"))
11380 { soap->error = SOAP_TYPE;
11381 soap_revert(soap);
11382 return NULL;
11384 #endif
11385 p = (LONG64*)soap_id_enter(soap, soap->id, p, t, sizeof(LONG64), 0, NULL, NULL, NULL);
11386 if (*soap->href)
11387 p = (LONG64*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(LONG64), 0, NULL);
11388 else if (p)
11389 { if (soap_s2LONG64(soap, soap_value(soap), p))
11390 return NULL;
11392 if (soap->body && soap_element_end_in(soap, tag))
11393 return NULL;
11394 return p;
11396 #endif
11398 /******************************************************************************/
11399 #ifndef PALM_2
11400 SOAP_FMAC1
11401 const char*
11402 SOAP_FMAC2
11403 soap_byte2s(struct soap *soap, char n)
11404 { return soap_long2s(soap, (long)n);
11406 #endif
11408 /******************************************************************************/
11409 #ifndef PALM_2
11410 SOAP_FMAC1
11412 SOAP_FMAC2
11413 soap_outbyte(struct soap *soap, const char *tag, int id, const char *p, const char *type, int n)
11414 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
11415 || soap_string_out(soap, soap_long2s(soap, (long)*p), 0))
11416 return soap->error;
11417 return soap_element_end_out(soap, tag);
11419 #endif
11421 /******************************************************************************/
11422 #ifndef PALM_2
11423 SOAP_FMAC1
11425 SOAP_FMAC2
11426 soap_s2byte(struct soap *soap, const char *s, char *p)
11427 { if (s)
11428 { long n;
11429 char *r;
11430 n = soap_strtol(s, &r, 10);
11431 if (s == r || *r || n < -128 || n > 127)
11432 soap->error = SOAP_TYPE;
11433 *p = (char)n;
11435 return soap->error;
11437 #endif
11439 /******************************************************************************/
11440 #ifndef PALM_2
11441 SOAP_FMAC1
11442 char *
11443 SOAP_FMAC2
11444 soap_inbyte(struct soap *soap, const char *tag, char *p, const char *type, int t)
11445 { if (soap_element_begin_in(soap, tag, 0, NULL))
11446 return NULL;
11447 #ifndef WITH_LEAN
11448 if (*soap->type
11449 && soap_match_tag(soap, soap->type, type)
11450 && soap_match_tag(soap, soap->type, ":byte"))
11451 { soap->error = SOAP_TYPE;
11452 soap_revert(soap);
11453 return NULL;
11455 #endif
11456 p = (char*)soap_id_enter(soap, soap->id, p, t, sizeof(char), 0, NULL, NULL, NULL);
11457 if (*soap->href)
11458 p = (char*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(char), 0, NULL);
11459 else if (p)
11460 { if (soap_s2byte(soap, soap_value(soap), p))
11461 return NULL;
11463 if (soap->body && soap_element_end_in(soap, tag))
11464 return NULL;
11465 return p;
11467 #endif
11469 /******************************************************************************/
11470 #ifndef PALM_2
11471 SOAP_FMAC1
11472 const char*
11473 SOAP_FMAC2
11474 soap_short2s(struct soap *soap, short n)
11475 { return soap_long2s(soap, (long)n);
11477 #endif
11479 /******************************************************************************/
11480 #ifndef PALM_2
11481 SOAP_FMAC1
11483 SOAP_FMAC2
11484 soap_outshort(struct soap *soap, const char *tag, int id, const short *p, const char *type, int n)
11485 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
11486 || soap_string_out(soap, soap_long2s(soap, (long)*p), 0))
11487 return soap->error;
11488 return soap_element_end_out(soap, tag);
11490 #endif
11492 /******************************************************************************/
11493 #ifndef PALM_2
11494 SOAP_FMAC1
11496 SOAP_FMAC2
11497 soap_s2short(struct soap *soap, const char *s, short *p)
11498 { if (s)
11499 { long n;
11500 char *r;
11501 n = soap_strtol(s, &r, 10);
11502 if (s == r || *r || n < -32768 || n > 32767)
11503 soap->error = SOAP_TYPE;
11504 *p = (short)n;
11506 return soap->error;
11508 #endif
11510 /******************************************************************************/
11511 #ifndef PALM_2
11512 SOAP_FMAC1
11513 short *
11514 SOAP_FMAC2
11515 soap_inshort(struct soap *soap, const char *tag, short *p, const char *type, int t)
11516 { if (soap_element_begin_in(soap, tag, 0, NULL))
11517 return NULL;
11518 #ifndef WITH_LEAN
11519 if (*soap->type
11520 && soap_match_tag(soap, soap->type, type)
11521 && soap_match_tag(soap, soap->type, ":short")
11522 && soap_match_tag(soap, soap->type, ":byte"))
11523 { soap->error = SOAP_TYPE;
11524 soap_revert(soap);
11525 return NULL;
11527 #endif
11528 p = (short*)soap_id_enter(soap, soap->id, p, t, sizeof(short), 0, NULL, NULL, NULL);
11529 if (*soap->href)
11530 p = (short*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(short), 0, NULL);
11531 else if (p)
11532 { if (soap_s2short(soap, soap_value(soap), p))
11533 return NULL;
11535 if (soap->body && soap_element_end_in(soap, tag))
11536 return NULL;
11537 return p;
11539 #endif
11541 /******************************************************************************/
11542 #ifndef PALM_2
11543 SOAP_FMAC1
11544 const char*
11545 SOAP_FMAC2
11546 soap_float2s(struct soap *soap, float n)
11547 { char *s;
11548 if (soap_isnan((double)n))
11549 return "NaN";
11550 if (soap_ispinff(n))
11551 return "INF";
11552 if (soap_isninff(n))
11553 return "-INF";
11554 s = soap->tmpbuf;
11555 #if defined(HAVE_SPRINTF_L)
11556 sprintf_l(s, soap->c_locale, soap->float_format, n);
11557 #else
11558 sprintf(s, soap->float_format, n);
11559 s = strchr(s, ','); /* convert decimal comma to DP */
11560 if (s)
11561 *s = '.';
11562 #endif
11563 return soap->tmpbuf;
11565 #endif
11567 /******************************************************************************/
11568 #ifndef PALM_2
11569 SOAP_FMAC1
11571 SOAP_FMAC2
11572 soap_outfloat(struct soap *soap, const char *tag, int id, const float *p, const char *type, int n)
11573 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
11574 || soap_string_out(soap, soap_float2s(soap, *p), 0))
11575 return soap->error;
11576 return soap_element_end_out(soap, tag);
11578 #endif
11580 /******************************************************************************/
11581 #ifndef PALM_2
11582 SOAP_FMAC1
11584 SOAP_FMAC2
11585 soap_s2float(struct soap *soap, const char *s, float *p)
11586 { if (s)
11587 { if (!*s)
11588 return soap->error = SOAP_TYPE;
11589 if (!soap_tag_cmp(s, "INF"))
11590 *p = FLT_PINFTY;
11591 else if (!soap_tag_cmp(s, "+INF"))
11592 *p = FLT_PINFTY;
11593 else if (!soap_tag_cmp(s, "-INF"))
11594 *p = FLT_NINFTY;
11595 else if (!soap_tag_cmp(s, "NaN"))
11596 *p = FLT_NAN;
11597 else
11599 /* On some systems strtof requires -std=c99 or does not even link: so we try to use strtod first */
11600 #if defined(HAVE_STRTOD_L)
11601 char *r;
11602 *p = (float)strtod_l(s, &r, soap->c_locale);
11603 if (*r)
11604 #elif defined(HAVE_STRTOD)
11605 char *r;
11606 *p = (float)strtod(s, &r);
11607 if (*r)
11608 #elif defined(HAVE_STRTOF_L)
11609 char *r;
11610 *p = strtof_l((char*)s, &r, soap->c_locale);
11611 if (*r)
11612 #elif defined(HAVE_STRTOF)
11613 char *r;
11614 *p = strtof((char*)s, &r);
11615 if (*r)
11616 #endif
11618 #if defined(HAVE_SSCANF_L) && !defined(HAVE_STRTOF_L) && !defined(HAVE_STRTOD_L)
11619 if (sscanf_l(s, soap->c_locale, "%g", p) != 1)
11620 soap->error = SOAP_TYPE;
11621 #elif defined(HAVE_SSCANF)
11622 if (sscanf(s, "%g", p) != 1)
11623 soap->error = SOAP_TYPE;
11624 #else
11625 soap->error = SOAP_TYPE;
11626 #endif
11630 return soap->error;
11632 #endif
11634 /******************************************************************************/
11635 #ifndef WITH_LEAN
11636 static int soap_isnumeric(struct soap *soap, const char *type)
11637 { if (soap_match_tag(soap, soap->type, type)
11638 && soap_match_tag(soap, soap->type, ":float")
11639 && soap_match_tag(soap, soap->type, ":double")
11640 && soap_match_tag(soap, soap->type, ":decimal")
11641 && soap_match_tag(soap, soap->type, ":integer")
11642 && soap_match_tag(soap, soap->type, ":positiveInteger")
11643 && soap_match_tag(soap, soap->type, ":negativeInteger")
11644 && soap_match_tag(soap, soap->type, ":nonPositiveInteger")
11645 && soap_match_tag(soap, soap->type, ":nonNegativeInteger")
11646 && soap_match_tag(soap, soap->type, ":long")
11647 && soap_match_tag(soap, soap->type, ":int")
11648 && soap_match_tag(soap, soap->type, ":short")
11649 && soap_match_tag(soap, soap->type, ":byte")
11650 && soap_match_tag(soap, soap->type, ":unsignedLong")
11651 && soap_match_tag(soap, soap->type, ":unsignedInt")
11652 && soap_match_tag(soap, soap->type, ":unsignedShort")
11653 && soap_match_tag(soap, soap->type, ":unsignedByte"))
11654 { soap->error = SOAP_TYPE;
11655 soap_revert(soap);
11656 return SOAP_ERR;
11658 return SOAP_OK;
11660 #endif
11662 /******************************************************************************/
11663 #ifndef PALM_2
11664 SOAP_FMAC1
11665 float *
11666 SOAP_FMAC2
11667 soap_infloat(struct soap *soap, const char *tag, float *p, const char *type, int t)
11668 { if (soap_element_begin_in(soap, tag, 0, NULL))
11669 return NULL;
11670 #ifndef WITH_LEAN
11671 if (*soap->type != '\0' && soap_isnumeric(soap, type))
11672 return NULL;
11673 #endif
11674 p = (float*)soap_id_enter(soap, soap->id, p, t, sizeof(float), 0, NULL, NULL, NULL);
11675 if (*soap->href)
11676 p = (float*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(float), 0, NULL);
11677 else if (p)
11678 { if (soap_s2float(soap, soap_value(soap), p))
11679 return NULL;
11681 if (soap->body && soap_element_end_in(soap, tag))
11682 return NULL;
11683 return p;
11685 #endif
11687 /******************************************************************************/
11688 #ifndef PALM_2
11689 SOAP_FMAC1
11690 const char*
11691 SOAP_FMAC2
11692 soap_double2s(struct soap *soap, double n)
11693 { char *s;
11694 if (soap_isnan(n))
11695 return "NaN";
11696 if (soap_ispinfd(n))
11697 return "INF";
11698 if (soap_isninfd(n))
11699 return "-INF";
11700 s = soap->tmpbuf;
11701 #if defined(HAVE_SPRINTF_L)
11702 sprintf_l(s, soap->c_locale, soap->double_format, n);
11703 #else
11704 sprintf(s, soap->double_format, n);
11705 s = strchr(s, ','); /* convert decimal comma to DP */
11706 if (s)
11707 *s = '.';
11708 #endif
11709 return soap->tmpbuf;
11711 #endif
11713 /******************************************************************************/
11714 #ifndef PALM_2
11715 SOAP_FMAC1
11717 SOAP_FMAC2
11718 soap_outdouble(struct soap *soap, const char *tag, int id, const double *p, const char *type, int n)
11719 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
11720 || soap_string_out(soap, soap_double2s(soap, *p), 0))
11721 return soap->error;
11722 return soap_element_end_out(soap, tag);
11724 #endif
11726 /******************************************************************************/
11727 #ifndef PALM_2
11728 SOAP_FMAC1
11730 SOAP_FMAC2
11731 soap_s2double(struct soap *soap, const char *s, double *p)
11732 { if (s)
11733 { if (!*s)
11734 return soap->error = SOAP_TYPE;
11735 if (!soap_tag_cmp(s, "INF"))
11736 *p = DBL_PINFTY;
11737 else if (!soap_tag_cmp(s, "+INF"))
11738 *p = DBL_PINFTY;
11739 else if (!soap_tag_cmp(s, "-INF"))
11740 *p = DBL_NINFTY;
11741 else if (!soap_tag_cmp(s, "NaN"))
11742 *p = DBL_NAN;
11743 else
11745 #if defined(HAVE_STRTOD_L)
11746 char *r;
11747 *p = strtod_l(s, &r, soap->c_locale);
11748 if (*r)
11749 #elif defined(HAVE_STRTOD)
11750 char *r;
11751 *p = strtod(s, &r);
11752 if (*r)
11753 #endif
11755 #if defined(HAVE_SSCANF_L) && !defined(HAVE_STRTOF_L) && !defined(HAVE_STRTOD_L)
11756 if (sscanf_l(s, soap->c_locale, "%lg", p) != 1)
11757 soap->error = SOAP_TYPE;
11758 #elif defined(HAVE_SSCANF)
11759 if (sscanf(s, "%lg", p) != 1)
11760 soap->error = SOAP_TYPE;
11761 #else
11762 soap->error = SOAP_TYPE;
11763 #endif
11767 return soap->error;
11769 #endif
11771 /******************************************************************************/
11772 #ifndef PALM_2
11773 SOAP_FMAC1
11774 double *
11775 SOAP_FMAC2
11776 soap_indouble(struct soap *soap, const char *tag, double *p, const char *type, int t)
11777 { if (soap_element_begin_in(soap, tag, 0, NULL))
11778 return NULL;
11779 #ifndef WITH_LEAN
11780 if (*soap->type != '\0' && soap_isnumeric(soap, type))
11781 return NULL;
11782 #endif
11783 p = (double*)soap_id_enter(soap, soap->id, p, t, sizeof(double), 0, NULL, NULL, NULL);
11784 if (*soap->href)
11785 p = (double*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(double), 0, NULL);
11786 else if (p)
11787 { if (soap_s2double(soap, soap_value(soap), p))
11788 return NULL;
11790 if (soap->body && soap_element_end_in(soap, tag))
11791 return NULL;
11792 return p;
11794 #endif
11796 /******************************************************************************/
11797 #ifndef PALM_2
11798 SOAP_FMAC1
11799 const char*
11800 SOAP_FMAC2
11801 soap_unsignedByte2s(struct soap *soap, unsigned char n)
11802 { return soap_unsignedLong2s(soap, (unsigned long)n);
11804 #endif
11806 /******************************************************************************/
11807 #ifndef PALM_2
11808 SOAP_FMAC1
11810 SOAP_FMAC2
11811 soap_outunsignedByte(struct soap *soap, const char *tag, int id, const unsigned char *p, const char *type, int n)
11812 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
11813 || soap_string_out(soap, soap_unsignedLong2s(soap, (unsigned long)*p), 0))
11814 return soap->error;
11815 return soap_element_end_out(soap, tag);
11817 #endif
11819 /******************************************************************************/
11820 #ifndef PALM_2
11821 SOAP_FMAC1
11823 SOAP_FMAC2
11824 soap_s2unsignedByte(struct soap *soap, const char *s, unsigned char *p)
11825 { if (s)
11826 { unsigned long n;
11827 char *r;
11828 n = soap_strtoul(s, &r, 10);
11829 if (s == r || *r || n > 255)
11830 soap->error = SOAP_TYPE;
11831 *p = (unsigned char)n;
11833 return soap->error;
11835 #endif
11837 /******************************************************************************/
11838 #ifndef PALM_2
11839 SOAP_FMAC1
11840 unsigned char *
11841 SOAP_FMAC2
11842 soap_inunsignedByte(struct soap *soap, const char *tag, unsigned char *p, const char *type, int t)
11843 { if (soap_element_begin_in(soap, tag, 0, NULL))
11844 return NULL;
11845 #ifndef WITH_LEAN
11846 if (*soap->type
11847 && soap_match_tag(soap, soap->type, type)
11848 && soap_match_tag(soap, soap->type, ":unsignedByte"))
11849 { soap->error = SOAP_TYPE;
11850 soap_revert(soap);
11851 return NULL;
11853 #endif
11854 p = (unsigned char*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned char), 0, NULL, NULL, NULL);
11855 if (*soap->href)
11856 p = (unsigned char*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(unsigned char), 0, NULL);
11857 else if (p)
11858 { if (soap_s2unsignedByte(soap, soap_value(soap), p))
11859 return NULL;
11861 if (soap->body && soap_element_end_in(soap, tag))
11862 return NULL;
11863 return p;
11865 #endif
11867 /******************************************************************************/
11868 #ifndef PALM_2
11869 SOAP_FMAC1
11870 const char*
11871 SOAP_FMAC2
11872 soap_unsignedShort2s(struct soap *soap, unsigned short n)
11873 { return soap_unsignedLong2s(soap, (unsigned long)n);
11875 #endif
11877 /******************************************************************************/
11878 #ifndef PALM_2
11879 SOAP_FMAC1
11881 SOAP_FMAC2
11882 soap_outunsignedShort(struct soap *soap, const char *tag, int id, const unsigned short *p, const char *type, int n)
11883 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
11884 || soap_string_out(soap, soap_unsignedLong2s(soap, (unsigned long)*p), 0))
11885 return soap->error;
11886 return soap_element_end_out(soap, tag);
11888 #endif
11890 /******************************************************************************/
11891 #ifndef PALM_2
11892 SOAP_FMAC1
11894 SOAP_FMAC2
11895 soap_s2unsignedShort(struct soap *soap, const char *s, unsigned short *p)
11896 { if (s)
11897 { unsigned long n;
11898 char *r;
11899 n = soap_strtoul(s, &r, 10);
11900 if (s == r || *r || n > 65535)
11901 soap->error = SOAP_TYPE;
11902 *p = (unsigned short)n;
11904 return soap->error;
11906 #endif
11908 /******************************************************************************/
11909 #ifndef PALM_2
11910 SOAP_FMAC1
11911 unsigned short *
11912 SOAP_FMAC2
11913 soap_inunsignedShort(struct soap *soap, const char *tag, unsigned short *p, const char *type, int t)
11914 { if (soap_element_begin_in(soap, tag, 0, NULL))
11915 return NULL;
11916 #ifndef WITH_LEAN
11917 if (*soap->type
11918 && soap_match_tag(soap, soap->type, type)
11919 && soap_match_tag(soap, soap->type, ":unsignedShort")
11920 && soap_match_tag(soap, soap->type, ":unsignedByte"))
11921 { soap->error = SOAP_TYPE;
11922 soap_revert(soap);
11923 return NULL;
11925 #endif
11926 p = (unsigned short*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned short), 0, NULL, NULL, NULL);
11927 if (*soap->href)
11928 p = (unsigned short*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(unsigned short), 0, NULL);
11929 else if (p)
11930 { if (soap_s2unsignedShort(soap, soap_value(soap), p))
11931 return NULL;
11933 if (soap->body && soap_element_end_in(soap, tag))
11934 return NULL;
11935 return p;
11937 #endif
11939 /******************************************************************************/
11940 #ifndef PALM_2
11941 SOAP_FMAC1
11942 const char*
11943 SOAP_FMAC2
11944 soap_unsignedInt2s(struct soap *soap, unsigned int n)
11945 { return soap_unsignedLong2s(soap, (unsigned long)n);
11947 #endif
11949 /******************************************************************************/
11950 #ifndef PALM_2
11951 SOAP_FMAC1
11953 SOAP_FMAC2
11954 soap_outunsignedInt(struct soap *soap, const char *tag, int id, const unsigned int *p, const char *type, int n)
11955 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
11956 || soap_string_out(soap, soap_unsignedLong2s(soap, (unsigned long)*p), 0))
11957 return soap->error;
11958 return soap_element_end_out(soap, tag);
11960 #endif
11962 /******************************************************************************/
11963 #ifndef PALM_2
11964 SOAP_FMAC1
11966 SOAP_FMAC2
11967 soap_s2unsignedInt(struct soap *soap, const char *s, unsigned int *p)
11968 { if (s)
11969 { char *r;
11970 #ifndef WITH_NOIO
11971 #ifndef WITH_LEAN
11972 soap_reset_errno;
11973 #endif
11974 #endif
11975 *p = (unsigned int)soap_strtoul(s, &r, 10);
11976 if ((s == r && (soap->mode & SOAP_XML_STRICT)) || *r
11977 #ifndef WITH_NOIO
11978 #ifndef WITH_LEAN
11979 || soap_errno == SOAP_ERANGE
11980 #endif
11981 #endif
11983 soap->error = SOAP_TYPE;
11985 return soap->error;
11987 #endif
11989 /******************************************************************************/
11990 #ifndef PALM_2
11991 SOAP_FMAC1
11992 unsigned int *
11993 SOAP_FMAC2
11994 soap_inunsignedInt(struct soap *soap, const char *tag, unsigned int *p, const char *type, int t)
11995 { if (soap_element_begin_in(soap, tag, 0, NULL))
11996 return NULL;
11997 #ifndef WITH_LEAN
11998 if (*soap->type
11999 && soap_match_tag(soap, soap->type, type)
12000 && soap_match_tag(soap, soap->type, ":unsignedInt")
12001 && soap_match_tag(soap, soap->type, ":unsignedShort")
12002 && soap_match_tag(soap, soap->type, ":unsignedByte"))
12003 { soap->error = SOAP_TYPE;
12004 soap_revert(soap);
12005 return NULL;
12007 #endif
12008 p = (unsigned int*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned int), 0, NULL, NULL, NULL);
12009 if (*soap->href)
12010 p = (unsigned int*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(unsigned int), 0, NULL);
12011 else if (p)
12012 { if (soap_s2unsignedInt(soap, soap_value(soap), p))
12013 return NULL;
12015 if (soap->body && soap_element_end_in(soap, tag))
12016 return NULL;
12017 return p;
12019 #endif
12021 /******************************************************************************/
12022 #ifndef PALM_2
12023 SOAP_FMAC1
12024 const char*
12025 SOAP_FMAC2
12026 soap_unsignedLong2s(struct soap *soap, unsigned long n)
12027 { sprintf(soap->tmpbuf, "%lu", n);
12028 return soap->tmpbuf;
12030 #endif
12032 /******************************************************************************/
12033 #ifndef PALM_2
12034 SOAP_FMAC1
12036 SOAP_FMAC2
12037 soap_outunsignedLong(struct soap *soap, const char *tag, int id, const unsigned long *p, const char *type, int n)
12038 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
12039 || soap_string_out(soap, soap_unsignedLong2s(soap, *p), 0))
12040 return soap->error;
12041 return soap_element_end_out(soap, tag);
12043 #endif
12045 /******************************************************************************/
12046 #ifndef PALM_2
12047 SOAP_FMAC1
12049 SOAP_FMAC2
12050 soap_s2unsignedLong(struct soap *soap, const char *s, unsigned long *p)
12051 { if (s)
12052 { char *r;
12053 #ifndef WITH_NOIO
12054 #ifndef WITH_LEAN
12055 soap_reset_errno;
12056 #endif
12057 #endif
12058 *p = soap_strtoul(s, &r, 10);
12059 if ((s == r && (soap->mode & SOAP_XML_STRICT)) || *r
12060 #ifndef WITH_NOIO
12061 #ifndef WITH_LEAN
12062 || soap_errno == SOAP_ERANGE
12063 #endif
12064 #endif
12066 soap->error = SOAP_TYPE;
12068 return soap->error;
12070 #endif
12072 /******************************************************************************/
12073 #ifndef PALM_2
12074 SOAP_FMAC1
12075 unsigned long *
12076 SOAP_FMAC2
12077 soap_inunsignedLong(struct soap *soap, const char *tag, unsigned long *p, const char *type, int t)
12078 { if (soap_element_begin_in(soap, tag, 0, NULL))
12079 return NULL;
12080 #ifndef WITH_LEAN
12081 if (*soap->type
12082 && soap_match_tag(soap, soap->type, type)
12083 && soap_match_tag(soap, soap->type, ":unsignedInt")
12084 && soap_match_tag(soap, soap->type, ":unsignedShort")
12085 && soap_match_tag(soap, soap->type, ":unsignedByte"))
12086 { soap->error = SOAP_TYPE;
12087 soap_revert(soap);
12088 return NULL;
12090 #endif
12091 p = (unsigned long*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned long), 0, NULL, NULL, NULL);
12092 if (*soap->href)
12093 p = (unsigned long*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(unsigned long), 0, NULL);
12094 else if (p)
12095 { if (soap_s2unsignedLong(soap, soap_value(soap), p))
12096 return NULL;
12098 if (soap->body && soap_element_end_in(soap, tag))
12099 return NULL;
12100 return p;
12102 #endif
12104 /******************************************************************************/
12105 #ifndef WITH_LEAN
12106 SOAP_FMAC1
12107 const char*
12108 SOAP_FMAC2
12109 soap_ULONG642s(struct soap *soap, ULONG64 n)
12110 { sprintf(soap->tmpbuf, SOAP_ULONG_FORMAT, n);
12111 return soap->tmpbuf;
12113 #endif
12115 /******************************************************************************/
12116 #ifndef WITH_LEAN
12117 SOAP_FMAC1
12119 SOAP_FMAC2
12120 soap_outULONG64(struct soap *soap, const char *tag, int id, const ULONG64 *p, const char *type, int n)
12121 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
12122 || soap_string_out(soap, soap_ULONG642s(soap, *p), 0))
12123 return soap->error;
12124 return soap_element_end_out(soap, tag);
12126 #endif
12128 /******************************************************************************/
12129 #ifndef WITH_LEAN
12130 SOAP_FMAC1
12132 SOAP_FMAC2
12133 soap_s2ULONG64(struct soap *soap, const char *s, ULONG64 *p)
12134 { if (s)
12136 #ifdef HAVE_STRTOULL
12137 char *r;
12138 #ifndef WITH_NOIO
12139 #ifndef WITH_LEAN
12140 soap_reset_errno;
12141 #endif
12142 #endif
12143 *p = strtoull(s, &r, 10);
12144 if ((s == r && (soap->mode & SOAP_XML_STRICT)) || *r
12145 #ifndef WITH_NOIO
12146 #ifndef WITH_LEAN
12147 || soap_errno == SOAP_ERANGE
12148 #endif
12149 #endif
12151 #else
12152 #ifdef HAVE_SSCANF
12153 if (sscanf(s, SOAP_ULONG_FORMAT, p) != 1)
12154 #endif
12155 #endif
12156 soap->error = SOAP_TYPE;
12158 return soap->error;
12160 #endif
12162 /******************************************************************************/
12163 #ifndef WITH_LEAN
12164 SOAP_FMAC1
12165 ULONG64 *
12166 SOAP_FMAC2
12167 soap_inULONG64(struct soap *soap, const char *tag, ULONG64 *p, const char *type, int t)
12168 { if (soap_element_begin_in(soap, tag, 0, NULL))
12169 return NULL;
12170 if (*soap->type
12171 && soap_match_tag(soap, soap->type, type)
12172 && soap_match_tag(soap, soap->type, ":positiveInteger")
12173 && soap_match_tag(soap, soap->type, ":nonNegativeInteger")
12174 && soap_match_tag(soap, soap->type, ":unsignedLong")
12175 && soap_match_tag(soap, soap->type, ":unsignedInt")
12176 && soap_match_tag(soap, soap->type, ":unsignedShort")
12177 && soap_match_tag(soap, soap->type, ":unsignedByte"))
12178 { soap->error = SOAP_TYPE;
12179 soap_revert(soap);
12180 return NULL;
12182 p = (ULONG64*)soap_id_enter(soap, soap->id, p, t, sizeof(ULONG64), 0, NULL, NULL, NULL);
12183 if (*soap->href)
12184 p = (ULONG64*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(ULONG64), 0, NULL);
12185 else if (p)
12186 { if (soap_s2ULONG64(soap, soap_value(soap), p))
12187 return NULL;
12189 if (soap->body && soap_element_end_in(soap, tag))
12190 return NULL;
12191 return p;
12193 #endif
12195 /******************************************************************************/
12196 #ifndef PALM_2
12197 SOAP_FMAC1
12199 SOAP_FMAC2
12200 soap_s2string(struct soap *soap, const char *s, char **t, long minlen, long maxlen)
12201 { if (s)
12202 { long l = (long)strlen(s);
12203 if ((maxlen >= 0 && l > maxlen) || l < minlen)
12204 return soap->error = SOAP_LENGTH;
12205 if (!(*t = soap_strdup(soap, s)))
12206 return soap->error = SOAP_EOM;
12207 if (!(soap->mode & (SOAP_ENC_LATIN | SOAP_C_UTFSTRING)))
12208 { char *r = *t;
12209 /* remove non-ASCII chars */
12210 for (s = *t; *s; s++)
12211 if (!(*s & 0x80))
12212 *r++ = *s;
12213 *r = '\0';
12216 return soap->error;
12218 #endif
12220 /******************************************************************************/
12221 #ifndef PALM_2
12222 SOAP_FMAC1
12224 SOAP_FMAC2
12225 soap_s2QName(struct soap *soap, const char *s, char **t, long minlen, long maxlen)
12226 { if (s)
12227 { long l = (long)strlen(s);
12228 if ((maxlen >= 0 && l > maxlen) || l < minlen)
12229 return soap->error = SOAP_LENGTH;
12230 soap->labidx = 0;
12231 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Normalized namespace(s) of QNames '%s'", s));
12232 /* convert (by prefix normalize prefix) all QNames in s */
12233 for (;;)
12234 { size_t n;
12235 struct soap_nlist *np;
12236 register const char *p;
12237 /* skip blanks */
12238 while (*s && soap_blank((soap_wchar)*s))
12239 s++;
12240 if (!*s)
12241 break;
12242 /* find next QName */
12243 n = 1;
12244 while (s[n] && !soap_blank(s[n]))
12245 n++;
12246 np = soap->nlist;
12247 /* if there is no namespace stack, or prefix is "xml" then copy string */
12248 if (!np || !strncmp(s, "xml:", 4))
12249 { soap_append_lab(soap, s, n);
12251 else /* we normalize the QName by replacing its prefix */
12252 { const char *q;
12253 for (p = s; *p && p < s + n; p++)
12254 if (*p == ':')
12255 break;
12256 if (*p == ':')
12257 { size_t k = p - s;
12258 while (np && (strncmp(np->id, s, k) || np->id[k]))
12259 np = np->next;
12260 p++;
12262 else
12263 { while (np && *np->id)
12264 np = np->next;
12265 p = s;
12267 /* replace prefix */
12268 if (np)
12269 { if (np->index >= 0 && soap->local_namespaces && (q = soap->local_namespaces[np->index].id))
12270 { size_t k = strlen(q);
12271 if (q[k-1] != '_')
12272 soap_append_lab(soap, q, k);
12273 else
12274 { soap_append_lab(soap, "\"", 1);
12275 soap_append_lab(soap, soap->local_namespaces[np->index].ns, strlen(soap->local_namespaces[np->index].ns));
12276 soap_append_lab(soap, "\"", 1);
12279 else if (np->ns)
12280 { soap_append_lab(soap, "\"", 1);
12281 soap_append_lab(soap, np->ns, strlen(np->ns));
12282 soap_append_lab(soap, "\"", 1);
12284 else
12285 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\nNamespace prefix of '%s' not defined (index=%d, URI=%s)\n", s, np->index, np->ns?np->ns:SOAP_STR_EOS));
12286 return soap->error = SOAP_NAMESPACE;
12289 else if (s[n]) /* no namespace, part of string */
12290 { soap_append_lab(soap, s, n);
12292 else /* no namespace: assume "" namespace */
12293 { soap_append_lab(soap, "\"\"", 2);
12295 soap_append_lab(soap, ":", 1);
12296 soap_append_lab(soap, p, n - (p-s));
12298 /* advance to next and add spacing */
12299 s += n;
12300 if (*s)
12301 soap_append_lab(soap, " ", 1);
12303 soap_append_lab(soap, SOAP_STR_EOS, 1);
12304 *t = soap_strdup(soap, soap->labbuf);
12305 DBGLOG(TEST, SOAP_MESSAGE(fdebug, " into '%s'\n", *t));
12307 return soap->error;
12309 #endif
12311 /******************************************************************************/
12312 #ifndef PALM_2
12313 SOAP_FMAC1
12314 const char*
12315 SOAP_FMAC2
12316 soap_QName2s(struct soap *soap, const char *s)
12317 { const char *t = NULL;
12318 if (s)
12319 { soap->labidx = 0;
12320 for (;;)
12321 { size_t n;
12322 /* skip blanks */
12323 while (*s && soap_blank((soap_wchar)*s))
12324 s++;
12325 if (!*s)
12326 break;
12327 /* find next QName */
12328 n = 1;
12329 while (s[n] && !soap_blank((soap_wchar)s[n]))
12330 n++;
12331 /* normal prefix: pass string as is */
12332 if (*s != '"')
12333 { soap_append_lab(soap, s, n);
12334 #ifndef WITH_LEAN
12335 if ((soap->mode & SOAP_XML_CANONICAL))
12336 { const char *r = strchr(s, ':');
12337 if (r)
12338 soap_utilize_ns(soap, s, r - s);
12340 #endif
12342 else /* URL-based string prefix */
12343 { const char *q;
12344 s++;
12345 q = strchr(s, '"');
12346 if (q)
12347 { struct Namespace *p = soap->local_namespaces;
12348 if (p)
12349 { for (; p->id; p++)
12350 { if (p->ns)
12351 if (!soap_tag_cmp(s, p->ns))
12352 break;
12353 if (p->in)
12354 if (!soap_tag_cmp(s, p->in))
12355 break;
12358 /* URL is in the namespace table? */
12359 if (p && p->id)
12360 { soap_append_lab(soap, p->id, strlen(p->id));
12362 else /* not in namespace table: create xmlns binding */
12363 { char *r = soap_strdup(soap, s);
12364 r[q-s] = '\0';
12365 sprintf(soap->tmpbuf, "xmlns:_%d", soap->idnum++);
12366 soap_set_attr(soap, soap->tmpbuf, r, 1);
12367 soap_append_lab(soap, soap->tmpbuf + 6, strlen(soap->tmpbuf + 6));
12369 soap_append_lab(soap, q + 1, n - (q-s) - 1);
12372 /* advance to next and add spacing */
12373 s += n;
12374 if (*s)
12375 soap_append_lab(soap, " ", 1);
12377 soap_append_lab(soap, SOAP_STR_EOS, 1);
12378 t = soap_strdup(soap, soap->labbuf);
12380 return t;
12382 #endif
12384 /******************************************************************************/
12385 #ifndef WITH_LEAN
12386 SOAP_FMAC1
12388 SOAP_FMAC2
12389 soap_s2wchar(struct soap *soap, const char *s, wchar_t **t, long minlen, long maxlen)
12390 { if (s)
12391 { long l;
12392 wchar_t *r;
12393 *t = r = (wchar_t*)soap_malloc(soap, sizeof(wchar_t) * (strlen(s) + 1));
12394 if (!r)
12395 return soap->error = SOAP_EOM;
12396 if (soap->mode & SOAP_ENC_LATIN)
12397 { while (*s)
12398 *r++ = (wchar_t)*s++;
12400 else
12401 { /* Convert UTF8 to wchar */
12402 while (*s)
12403 { register soap_wchar c, c1, c2, c3, c4;
12404 c = (unsigned char)*s++;
12405 if (c < 0x80)
12406 *r++ = (wchar_t)c;
12407 else
12408 { c1 = (soap_wchar)*s++ & 0x3F;
12409 if (c < 0xE0)
12410 *r++ = (wchar_t)(((soap_wchar)(c & 0x1F) << 6) | c1);
12411 else
12412 { c2 = (soap_wchar)*s++ & 0x3F;
12413 if (c < 0xF0)
12414 *r++ = (wchar_t)(((soap_wchar)(c & 0x0F) << 12) | (c1 << 6) | c2);
12415 else
12416 { c3 = (soap_wchar)*s++ & 0x3F;
12417 if (c < 0xF8)
12418 *r++ = (wchar_t)(((soap_wchar)(c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3);
12419 else
12420 { c4 = (soap_wchar)*s++ & 0x3F;
12421 if (c < 0xFC)
12422 *r++ = (wchar_t)(((soap_wchar)(c & 0x03) << 24) | (c1 << 18) | (c2 << 12) | (c3 << 6) | c4);
12423 else
12424 *r++ = (wchar_t)(((soap_wchar)(c & 0x01) << 30) | (c1 << 24) | (c2 << 18) | (c3 << 12) | (c4 << 6) | (soap_wchar)(*s++ & 0x3F));
12431 *r = L'\0';
12432 l = (long)(r - *t);
12433 if ((maxlen >= 0 && l > maxlen) || l < minlen)
12434 return soap->error = SOAP_LENGTH;
12436 return soap->error;
12438 #endif
12440 /******************************************************************************/
12441 #ifndef WITH_LEAN
12442 SOAP_FMAC1
12443 const char*
12444 SOAP_FMAC2
12445 soap_wchar2s(struct soap *soap, const wchar_t *s)
12446 { register soap_wchar c;
12447 register char *r, *t;
12448 const wchar_t *q = s;
12449 size_t n = 0;
12450 while ((c = *q++))
12451 { if (c > 0 && c < 0x80)
12452 n++;
12453 else
12454 n += 6;
12456 r = t = (char*)soap_malloc(soap, n + 1);
12457 if (r)
12458 { /* Convert wchar to UTF8 */
12459 while ((c = *s++))
12460 { if (c > 0 && c < 0x80)
12461 *t++ = (char)c;
12462 else
12463 { if (c < 0x0800)
12464 *t++ = (char)(0xC0 | ((c >> 6) & 0x1F));
12465 else
12466 { if (c < 0x010000)
12467 *t++ = (char)(0xE0 | ((c >> 12) & 0x0F));
12468 else
12469 { if (c < 0x200000)
12470 *t++ = (char)(0xF0 | ((c >> 18) & 0x07));
12471 else
12472 { if (c < 0x04000000)
12473 *t++ = (char)(0xF8 | ((c >> 24) & 0x03));
12474 else
12475 { *t++ = (char)(0xFC | ((c >> 30) & 0x01));
12476 *t++ = (char)(0x80 | ((c >> 24) & 0x3F));
12478 *t++ = (char)(0x80 | ((c >> 18) & 0x3F));
12480 *t++ = (char)(0x80 | ((c >> 12) & 0x3F));
12482 *t++ = (char)(0x80 | ((c >> 6) & 0x3F));
12484 *t++ = (char)(0x80 | (c & 0x3F));
12487 *t = '\0';
12489 return r;
12491 #endif
12493 /******************************************************************************/
12494 #ifndef PALM_2
12495 SOAP_FMAC1
12497 SOAP_FMAC2
12498 soap_outstring(struct soap *soap, const char *tag, int id, char *const*p, const char *type, int n)
12499 { id = soap_element_id(soap, tag, id, *p, NULL, 0, type, n);
12500 if (id < 0)
12501 return soap->error;
12502 if (!**p && (soap->mode & SOAP_C_NILSTRING))
12503 return soap_element_null(soap, tag, id, type);
12504 if (soap_element_begin_out(soap, tag, id, type)
12505 || soap_string_out(soap, *p, 0)
12506 || soap_element_end_out(soap, tag))
12507 return soap->error;
12508 return SOAP_OK;
12510 #endif
12512 /******************************************************************************/
12513 #ifndef PALM_2
12514 SOAP_FMAC1
12515 char **
12516 SOAP_FMAC2
12517 soap_instring(struct soap *soap, const char *tag, char **p, const char *type, int t, int flag, long minlen, long maxlen)
12518 { if (soap_element_begin_in(soap, tag, 1, NULL))
12519 { if (!tag || *tag != '-' || soap->error != SOAP_NO_TAG)
12520 return NULL;
12521 soap->error = SOAP_OK;
12523 if (!p)
12524 { if (!(p = (char**)soap_malloc(soap, sizeof(char*))))
12525 return NULL;
12527 if (soap->null)
12528 *p = NULL;
12529 else if (soap->body)
12530 { *p = soap_string_in(soap, flag, minlen, maxlen);
12531 if (!*p || !(char*)soap_id_enter(soap, soap->id, *p, t, sizeof(char*), 0, NULL, NULL, NULL))
12532 return NULL;
12533 if (!**p && tag && *tag == '-')
12534 { soap->error = SOAP_NO_TAG;
12535 return NULL;
12538 else if (tag && *tag == '-')
12539 { soap->error = SOAP_NO_TAG;
12540 return NULL;
12542 else if (!*soap->href && minlen > 0)
12543 { soap->error = SOAP_LENGTH;
12544 return NULL;
12546 else
12547 *p = soap_strdup(soap, SOAP_STR_EOS);
12548 if (*soap->href)
12549 p = (char**)soap_id_lookup(soap, soap->href, (void**)p, t, sizeof(char**), 0);
12550 if (soap->body && soap_element_end_in(soap, tag))
12551 return NULL;
12552 return p;
12554 #endif
12556 /******************************************************************************/
12557 #ifndef WITH_LEANER
12558 #ifndef PALM_2
12559 SOAP_FMAC1
12561 SOAP_FMAC2
12562 soap_outwstring(struct soap *soap, const char *tag, int id, wchar_t *const*p, const char *type, int n)
12563 { id = soap_element_id(soap, tag, id, *p, NULL, 0, type, n);
12564 if (id < 0)
12565 return soap->error;
12566 if (!**p && (soap->mode & SOAP_C_NILSTRING))
12567 return soap_element_null(soap, tag, id, type);
12568 if (soap_element_begin_out(soap, tag, id, type)
12569 || soap_wstring_out(soap, *p, 0)
12570 || soap_element_end_out(soap, tag))
12571 return soap->error;
12572 return SOAP_OK;
12574 #endif
12575 #endif
12577 /******************************************************************************/
12578 #ifndef WITH_LEANER
12579 #ifndef PALM_2
12580 SOAP_FMAC1
12581 wchar_t **
12582 SOAP_FMAC2
12583 soap_inwstring(struct soap *soap, const char *tag, wchar_t **p, const char *type, int t, long minlen, long maxlen)
12584 { if (soap_element_begin_in(soap, tag, 1, NULL))
12585 { if (!tag || *tag != '-' || soap->error != SOAP_NO_TAG)
12586 return NULL;
12587 soap->error = SOAP_OK;
12589 if (!p)
12590 { if (!(p = (wchar_t**)soap_malloc(soap, sizeof(wchar_t*))))
12591 return NULL;
12593 if (soap->body)
12594 { *p = soap_wstring_in(soap, 1, minlen, maxlen);
12595 if (!*p || !(wchar_t*)soap_id_enter(soap, soap->id, *p, t, sizeof(wchar_t*), 0, NULL, NULL, NULL))
12596 return NULL;
12597 if (!**p && tag && *tag == '-')
12598 { soap->error = SOAP_NO_TAG;
12599 return NULL;
12602 else if (tag && *tag == '-')
12603 { soap->error = SOAP_NO_TAG;
12604 return NULL;
12606 else if (soap->null)
12607 *p = NULL;
12608 else
12609 *p = soap_wstrdup(soap, (wchar_t*)SOAP_STR_EOS);
12610 if (*soap->href)
12611 p = (wchar_t**)soap_id_lookup(soap, soap->href, (void**)p, t, sizeof(wchar_t**), 0);
12612 if (soap->body && soap_element_end_in(soap, tag))
12613 return NULL;
12614 return p;
12616 #endif
12617 #endif
12619 /******************************************************************************/
12620 #ifndef WITH_LEAN
12621 SOAP_FMAC1
12622 time_t
12623 SOAP_FMAC2
12624 soap_timegm(struct tm *T)
12626 #if defined(HAVE_TIMEGM)
12627 return timegm(T);
12628 #else
12629 time_t t, g, z;
12630 struct tm tm;
12631 t = mktime(T);
12632 if (t == (time_t)-1)
12633 return (time_t)-1;
12634 #ifdef HAVE_GMTIME_R
12635 gmtime_r(&t, &tm);
12636 #else
12637 tm = *gmtime(&t);
12638 #endif
12639 tm.tm_isdst = 0;
12640 g = mktime(&tm);
12641 if (g == (time_t)-1)
12642 return (time_t)-1;
12643 z = g - t;
12644 return t - z;
12645 #endif
12647 #endif
12649 /******************************************************************************/
12650 #ifndef WITH_LEAN
12651 SOAP_FMAC1
12652 const char*
12653 SOAP_FMAC2
12654 soap_dateTime2s(struct soap *soap, time_t n)
12655 { struct tm T, *pT = &T;
12656 #if defined(HAVE_GMTIME_R)
12657 if (gmtime_r(&n, pT))
12658 strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%SZ", pT);
12659 #elif defined(HAVE_GMTIME)
12660 if ((pT = gmtime(&n)))
12661 strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%SZ", pT);
12662 #elif defined(HAVE_GETTIMEOFDAY)
12663 struct timezone tz;
12664 memset((void*)&tz, 0, sizeof(tz));
12665 #if defined(HAVE_LOCALTIME_R)
12666 if (localtime_r(&n, pT))
12667 { struct timeval tv;
12668 gettimeofday(&tv, &tz);
12669 strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%S", pT);
12670 sprintf(soap->tmpbuf + strlen(soap->tmpbuf), "%+03d:%02d", -tz.tz_minuteswest/60+(pT->tm_isdst!=0), abs(tz.tz_minuteswest)%60);
12672 #else
12673 if ((pT = localtime(&n)))
12674 { struct timeval tv;
12675 gettimeofday(&tv, &tz);
12676 strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%S", pT);
12677 sprintf(soap->tmpbuf + strlen(soap->tmpbuf), "%+03d:%02d", -tz.tz_minuteswest/60+(pT->tm_isdst!=0), abs(tz.tz_minuteswest)%60);
12679 #endif
12680 #elif defined(HAVE_FTIME)
12681 struct timeb t;
12682 memset((void*)&t, 0, sizeof(t));
12683 #if defined(HAVE_LOCALTIME_R)
12684 if (localtime_r(&n, pT))
12686 #ifdef __BORLANDC__
12687 ::ftime(&t);
12688 #else
12689 ftime(&t);
12690 #endif
12691 strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%S", pT);
12692 sprintf(soap->tmpbuf + strlen(soap->tmpbuf), "%+03d:%02d", -t.timezone/60+(pT->tm_isdst!=0), abs(t.timezone)%60);
12694 #else
12695 if ((pT = localtime(&n)))
12697 #ifdef __BORLANDC__
12698 ::ftime(&t);
12699 #else
12700 ftime(&t);
12701 #endif
12702 strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%S", pT);
12703 sprintf(soap->tmpbuf + strlen(soap->tmpbuf), "%+03d:%02d", -t.timezone/60+(pT->tm_isdst!=0), abs(t.timezone)%60);
12705 #endif
12706 #elif defined(HAVE_LOCALTIME_R)
12707 if (localtime_r(&n, pT))
12708 strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%S", pT);
12709 #else
12710 if ((pT = localtime(&n)))
12711 strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%S", pT);
12712 #endif
12713 else
12714 strcpy(soap->tmpbuf, "1969-12-31T23:59:59Z");
12715 return soap->tmpbuf;
12717 #endif
12719 /******************************************************************************/
12720 #ifndef WITH_LEAN
12721 SOAP_FMAC1
12723 SOAP_FMAC2
12724 soap_outdateTime(struct soap *soap, const char *tag, int id, const time_t *p, const char *type, int n)
12725 { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type)
12726 || soap_string_out(soap, soap_dateTime2s(soap, *p), 0))
12727 return soap->error;
12728 return soap_element_end_out(soap, tag);
12730 #endif
12732 /******************************************************************************/
12733 #ifndef WITH_LEAN
12734 SOAP_FMAC1
12736 SOAP_FMAC2
12737 soap_s2dateTime(struct soap *soap, const char *s, time_t *p)
12738 { if (s)
12739 { char zone[32];
12740 struct tm T;
12741 const char *t;
12742 *zone = '\0';
12743 memset((void*)&T, 0, sizeof(T));
12744 if (strchr(s, '-'))
12745 t = "%d-%d-%dT%d:%d:%d%31s";
12746 else if (strchr(s, ':'))
12747 t = "%4d%2d%2dT%d:%d:%d%31s";
12748 else /* parse non-XSD-standard alternative ISO 8601 format */
12749 t = "%4d%2d%2dT%2d%2d%2d%31s";
12750 if (sscanf(s, t, &T.tm_year, &T.tm_mon, &T.tm_mday, &T.tm_hour, &T.tm_min, &T.tm_sec, zone) < 6)
12751 return soap->error = SOAP_TYPE;
12752 if (T.tm_year == 1)
12753 T.tm_year = 70;
12754 else
12755 T.tm_year -= 1900;
12756 T.tm_mon--;
12757 if (*zone == '.')
12758 { for (s = zone + 1; *s; s++)
12759 if (*s < '0' || *s > '9')
12760 break;
12762 else
12763 s = zone;
12764 if (*s)
12766 #ifndef WITH_NOZONE
12767 if (*s == '+' || *s == '-')
12768 { int h = 0, m = 0;
12769 if (s[3] == ':')
12770 { /* +hh:mm */
12771 sscanf(s, "%d:%d", &h, &m);
12772 if (h < 0)
12773 m = -m;
12775 else /* +hhmm */
12776 { m = (int)soap_strtol(s, NULL, 10);
12777 h = m / 100;
12778 m = m % 100;
12780 T.tm_min -= m;
12781 T.tm_hour -= h;
12782 /* put hour and min in range */
12783 T.tm_hour += T.tm_min / 60;
12784 T.tm_min %= 60;
12785 if (T.tm_min < 0)
12786 { T.tm_min += 60;
12787 T.tm_hour--;
12789 T.tm_mday += T.tm_hour / 24;
12790 T.tm_hour %= 24;
12791 if (T.tm_hour < 0)
12792 { T.tm_hour += 24;
12793 T.tm_mday--;
12795 /* note: day of the month may be out of range, timegm() handles it */
12797 #endif
12798 *p = soap_timegm(&T);
12800 else /* no UTC or timezone, so assume we got a localtime */
12801 { T.tm_isdst = -1;
12802 *p = mktime(&T);
12805 return soap->error;
12807 #endif
12809 /******************************************************************************/
12810 #ifndef WITH_LEAN
12811 SOAP_FMAC1
12812 time_t *
12813 SOAP_FMAC2
12814 soap_indateTime(struct soap *soap, const char *tag, time_t *p, const char *type, int t)
12815 { if (soap_element_begin_in(soap, tag, 0, NULL))
12816 return NULL;
12817 if (*soap->type
12818 && soap_match_tag(soap, soap->type, type)
12819 && soap_match_tag(soap, soap->type, ":dateTime"))
12820 { soap->error = SOAP_TYPE;
12821 soap_revert(soap);
12822 return NULL;
12824 p = (time_t*)soap_id_enter(soap, soap->id, p, t, sizeof(time_t), 0, NULL, NULL, NULL);
12825 if (*soap->href)
12826 p = (time_t*)soap_id_forward(soap, soap->href, p, 0, t, 0, sizeof(time_t), 0, NULL);
12827 else if (p)
12828 { if (soap_s2dateTime(soap, soap_value(soap), p))
12829 return NULL;
12831 if (soap->body && soap_element_end_in(soap, tag))
12832 return NULL;
12833 return p;
12835 #endif
12837 /******************************************************************************/
12838 #ifndef PALM_2
12839 SOAP_FMAC1
12841 SOAP_FMAC2
12842 soap_outliteral(struct soap *soap, const char *tag, char *const*p, const char *type)
12843 { int i;
12844 const char *t = NULL;
12845 if (tag && *tag != '-')
12846 { if (soap->local_namespaces && (t = strchr(tag, ':')))
12847 { strncpy(soap->tmpbuf, tag, t-tag);
12848 soap->tmpbuf[t-tag] = '\0';
12849 for (i = 0; soap->local_namespaces[i].id; i++)
12850 if (!strcmp(soap->tmpbuf, soap->local_namespaces[i].id))
12851 break;
12852 t++;
12853 if (soap_element(soap, t, 0, type)
12854 || soap_attribute(soap, "xmlns", soap->local_namespaces[i].ns ? soap->local_namespaces[i].ns : SOAP_STR_EOS)
12855 || soap_element_start_end_out(soap, NULL))
12856 return soap->error;
12858 else
12859 { t = tag;
12860 if (soap_element_begin_out(soap, t, 0, type))
12861 return soap->error;
12864 if (p && *p)
12865 { if (soap_send(soap, *p))
12866 return soap->error;
12868 if (t)
12869 return soap_element_end_out(soap, t);
12870 return SOAP_OK;
12872 #endif
12874 /******************************************************************************/
12875 #ifndef PALM_2
12876 SOAP_FMAC1
12877 char **
12878 SOAP_FMAC2
12879 soap_inliteral(struct soap *soap, const char *tag, char **p)
12880 { if (soap_element_begin_in(soap, tag, 1, NULL))
12881 { if (soap->error != SOAP_NO_TAG || soap_unget(soap, soap_get(soap)) == SOAP_TT)
12882 return NULL;
12883 soap->error = SOAP_OK;
12885 if (!p)
12886 { if (!(p = (char**)soap_malloc(soap, sizeof(char*))))
12887 return NULL;
12889 if (soap->body || (tag && *tag == '-'))
12890 { *p = soap_string_in(soap, 0, -1, -1);
12891 if (!*p)
12892 return NULL;
12893 if (!**p && tag && *tag == '-')
12894 { soap->error = SOAP_NO_TAG;
12895 return NULL;
12898 else if (soap->null)
12899 *p = NULL;
12900 else
12901 *p = soap_strdup(soap, SOAP_STR_EOS);
12902 if (soap->body && soap_element_end_in(soap, tag))
12903 return NULL;
12904 return p;
12906 #endif
12908 /******************************************************************************/
12909 #ifndef WITH_LEANER
12910 #ifndef PALM_2
12911 SOAP_FMAC1
12913 SOAP_FMAC2
12914 soap_outwliteral(struct soap *soap, const char *tag, wchar_t *const*p, const char *type)
12915 { int i;
12916 const char *t = NULL;
12917 if (tag && *tag != '-')
12918 { if (soap->local_namespaces && (t = strchr(tag, ':')))
12919 { strncpy(soap->tmpbuf, tag, t-tag);
12920 soap->tmpbuf[t-tag] = '\0';
12921 for (i = 0; soap->local_namespaces[i].id; i++)
12922 if (!strcmp(soap->tmpbuf, soap->local_namespaces[i].id))
12923 break;
12924 t++;
12925 if (soap_element(soap, t, 0, type)
12926 || soap_attribute(soap, "xmlns", soap->local_namespaces[i].ns ? soap->local_namespaces[i].ns : SOAP_STR_EOS)
12927 || soap_element_start_end_out(soap, NULL))
12928 return soap->error;
12930 else
12931 { t = tag;
12932 if (soap_element_begin_out(soap, t, 0, type))
12933 return soap->error;
12935 if (soap_send(soap, soap->tmpbuf))
12936 return soap->error;
12938 if (p)
12939 { wchar_t c;
12940 const wchar_t *s = *p;
12941 while ((c = *s++))
12942 { if (soap_pututf8(soap, (unsigned long)c))
12943 return soap->error;
12946 if (t)
12947 return soap_element_end_out(soap, t);
12948 return SOAP_OK;
12950 #endif
12951 #endif
12953 /******************************************************************************/
12954 #ifndef WITH_LEANER
12955 #ifndef PALM_2
12956 SOAP_FMAC1
12957 wchar_t **
12958 SOAP_FMAC2
12959 soap_inwliteral(struct soap *soap, const char *tag, wchar_t **p)
12960 { if (soap_element_begin_in(soap, tag, 1, NULL))
12961 { if (soap->error != SOAP_NO_TAG || soap_unget(soap, soap_get(soap)) == SOAP_TT)
12962 return NULL;
12963 soap->error = SOAP_OK;
12965 if (!p)
12966 { if (!(p = (wchar_t**)soap_malloc(soap, sizeof(wchar_t*))))
12967 return NULL;
12969 if (soap->body)
12970 { *p = soap_wstring_in(soap, 0, -1, -1);
12971 if (!*p)
12972 return NULL;
12973 if (!**p && tag && *tag == '-')
12974 { soap->error = SOAP_NO_TAG;
12975 return NULL;
12978 else if (tag && *tag == '-')
12979 { soap->error = SOAP_NO_TAG;
12980 return NULL;
12982 else if (soap->null)
12983 *p = NULL;
12984 else
12985 *p = soap_wstrdup(soap, (wchar_t*)SOAP_STR_EOS);
12986 if (soap->body && soap_element_end_in(soap, tag))
12987 return NULL;
12988 return p;
12990 #endif
12991 #endif
12993 /******************************************************************************/
12994 #ifndef PALM_2
12995 SOAP_FMAC1
12996 const char *
12997 SOAP_FMAC2
12998 soap_value(struct soap *soap)
12999 { register size_t i;
13000 register soap_wchar c = 0;
13001 register char *s = soap->tmpbuf;
13002 if (!soap->body)
13003 return SOAP_STR_EOS;
13004 do c = soap_get(soap);
13005 while (soap_blank(c));
13006 for (i = 0; i < sizeof(soap->tmpbuf) - 1; i++)
13007 { if (c == SOAP_TT || c == SOAP_LT || (int)c == EOF)
13008 break;
13009 *s++ = (char)c;
13010 c = soap_get(soap);
13012 for (s--; i > 0; i--, s--)
13013 { if (!soap_blank((soap_wchar)*s))
13014 break;
13016 s[1] = '\0';
13017 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Element content value='%s'\n", soap->tmpbuf));
13018 if (c == SOAP_TT || c == SOAP_LT || (int)c == EOF)
13019 soap_unget(soap, c);
13020 else if (soap->mode & SOAP_XML_STRICT)
13021 { soap->error = SOAP_LENGTH;
13022 return NULL;
13024 #ifdef WITH_DOM
13025 if ((soap->mode & SOAP_XML_DOM) && soap->dom)
13026 soap->dom->data = soap_strdup(soap, soap->tmpbuf);
13027 #endif
13028 return soap->tmpbuf; /* return non-null pointer */
13030 #endif
13032 /******************************************************************************/
13033 #if !defined(WITH_LEANER) || !defined(WITH_NOHTTP)
13034 #ifndef PALM_2
13035 SOAP_FMAC1
13037 SOAP_FMAC2
13038 soap_getline(struct soap *soap, char *s, int len)
13039 { int i = len;
13040 soap_wchar c = 0;
13041 for (;;)
13042 { while (--i > 0)
13043 { c = soap_getchar(soap);
13044 if (c == '\r' || c == '\n')
13045 break;
13046 if ((int)c == EOF)
13047 return soap->error = SOAP_EOF;
13048 *s++ = (char)c;
13050 if (c != '\n')
13051 c = soap_getchar(soap); /* got \r or something else, now get \n */
13052 if (c == '\n')
13053 { *s = '\0';
13054 if (i+1 == len) /* empty line: end of HTTP/MIME header */
13055 break;
13056 c = soap_get0(soap);
13057 if (c != ' ' && c != '\t') /* HTTP line continuation? */
13058 break;
13060 else if ((int)c == EOF)
13061 return soap->error = SOAP_EOF;
13062 if (i < 0)
13063 return soap->error = SOAP_HDR;
13065 return SOAP_OK;
13067 #endif
13068 #endif
13070 /******************************************************************************/
13071 #ifndef PALM_1
13072 static size_t
13073 soap_count_attachments(struct soap *soap)
13075 #ifndef WITH_LEANER
13076 register struct soap_multipart *content;
13077 register size_t count = soap->count;
13078 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Calculating the message size with attachments, current count=%lu\n", (unsigned long)count));
13079 if ((soap->mode & SOAP_ENC_DIME) && !(soap->mode & SOAP_ENC_MTOM))
13080 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Calculating the size of DIME attachments\n"));
13081 for (content = soap->dime.first; content; content = content->next)
13082 { count += 12 + ((content->size+3)&(~3));
13083 if (content->id)
13084 count += ((strlen(content->id)+3)&(~3));
13085 if (content->type)
13086 count += ((strlen(content->type)+3)&(~3));
13087 if (content->options)
13088 count += ((((unsigned char)content->options[2] << 8) | ((unsigned char)content->options[3]))+7)&(~3);
13089 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Size of DIME attachment content is %lu bytes\n", (unsigned long)content->size));
13092 if ((soap->mode & SOAP_ENC_MIME) && soap->mime.boundary)
13093 { register size_t n = strlen(soap->mime.boundary);
13094 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Calculating the size of MIME attachments\n"));
13095 for (content = soap->mime.first; content; content = content->next)
13096 { register const char *s;
13097 /* count \r\n--boundary\r\n */
13098 count += 6 + n;
13099 /* count Content-Type: ...\r\n */
13100 if (content->type)
13101 count += 16 + strlen(content->type);
13102 /* count Content-Transfer-Encoding: ...\r\n */
13103 s = soap_code_str(mime_codes, content->encoding);
13104 if (s)
13105 count += 29 + strlen(s);
13106 /* count Content-ID: ...\r\n */
13107 if (content->id)
13108 count += 14 + strlen(content->id);
13109 /* count Content-Location: ...\r\n */
13110 if (content->location)
13111 count += 20 + strlen(content->location);
13112 /* count Content-Description: ...\r\n */
13113 if (content->description)
13114 count += 23 + strlen(content->description);
13115 /* count \r\n...content */
13116 count += 2 + content->size;
13117 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Size of MIME attachment content is %lu bytes\n", (unsigned long)content->size));
13119 /* count \r\n--boundary-- */
13120 count += 6 + n;
13122 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "New count is %lu bytes\n", (unsigned long)count));
13123 return count;
13124 #else
13125 return soap->count;
13126 #endif
13128 #endif
13130 /******************************************************************************/
13131 #ifndef WITH_LEANER
13132 #ifndef PALM_1
13133 static int
13134 soap_putdimefield(struct soap *soap, const char *s, size_t n)
13135 { if (soap_send_raw(soap, s, n))
13136 return soap->error;
13137 return soap_send_raw(soap, SOAP_STR_PADDING, -(long)n&3);
13139 #endif
13140 #endif
13142 /******************************************************************************/
13143 #ifndef WITH_LEANER
13144 #ifndef PALM_1
13145 SOAP_FMAC1
13146 char *
13147 SOAP_FMAC2
13148 soap_dime_option(struct soap *soap, unsigned short optype, const char *option)
13149 { size_t n;
13150 char *s = NULL;
13151 if (option)
13152 { n = strlen(option);
13153 s = (char*)soap_malloc(soap, n + 5);
13154 if (s)
13155 { s[0] = (char)(optype >> 8);
13156 s[1] = (char)(optype & 0xFF);
13157 s[2] = (char)(n >> 8);
13158 s[3] = (char)(n & 0xFF);
13159 strcpy(s + 4, option);
13162 return s;
13164 #endif
13165 #endif
13167 /******************************************************************************/
13168 #ifndef WITH_LEANER
13169 #ifndef PALM_1
13170 SOAP_FMAC1
13172 SOAP_FMAC2
13173 soap_putdimehdr(struct soap *soap)
13174 { unsigned char tmp[12];
13175 size_t optlen = 0, idlen = 0, typelen = 0;
13176 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Put DIME header id='%s'\n", soap->dime.id?soap->dime.id:SOAP_STR_EOS));
13177 if (soap->dime.options)
13178 optlen = (((unsigned char)soap->dime.options[2] << 8) | ((unsigned char)soap->dime.options[3])) + 4;
13179 if (soap->dime.id)
13180 { idlen = strlen(soap->dime.id);
13181 if (idlen > 0x0000FFFF)
13182 idlen = 0x0000FFFF;
13184 if (soap->dime.type)
13185 { typelen = strlen(soap->dime.type);
13186 if (typelen > 0x0000FFFF)
13187 typelen = 0x0000FFFF;
13189 tmp[0] = SOAP_DIME_VERSION | (soap->dime.flags & 0x7);
13190 tmp[1] = soap->dime.flags & 0xF0;
13191 tmp[2] = (char)(optlen >> 8);
13192 tmp[3] = (char)(optlen & 0xFF);
13193 tmp[4] = (char)(idlen >> 8);
13194 tmp[5] = (char)(idlen & 0xFF);
13195 tmp[6] = (char)(typelen >> 8);
13196 tmp[7] = (char)(typelen & 0xFF);
13197 tmp[8] = (char)(soap->dime.size >> 24);
13198 tmp[9] = (char)((soap->dime.size >> 16) & 0xFF);
13199 tmp[10] = (char)((soap->dime.size >> 8) & 0xFF);
13200 tmp[11] = (char)(soap->dime.size & 0xFF);
13201 if (soap_send_raw(soap, (char*)tmp, 12)
13202 || soap_putdimefield(soap, soap->dime.options, optlen)
13203 || soap_putdimefield(soap, soap->dime.id, idlen)
13204 || soap_putdimefield(soap, soap->dime.type, typelen))
13205 return soap->error;
13206 return SOAP_OK;
13208 #endif
13209 #endif
13211 /******************************************************************************/
13212 #ifndef WITH_LEANER
13213 #ifndef PALM_1
13214 SOAP_FMAC1
13216 SOAP_FMAC2
13217 soap_putdime(struct soap *soap)
13218 { struct soap_multipart *content;
13219 if (!(soap->mode & SOAP_ENC_DIME))
13220 return SOAP_OK;
13221 for (content = soap->dime.first; content; content = content->next)
13222 { void *handle;
13223 soap->dime.size = content->size;
13224 soap->dime.id = content->id;
13225 soap->dime.type = content->type;
13226 soap->dime.options = content->options;
13227 soap->dime.flags = SOAP_DIME_VERSION | SOAP_DIME_MEDIA;
13228 if (soap->fdimereadopen && ((handle = soap->fdimereadopen(soap, (void*)content->ptr, content->id, content->type, content->options)) || soap->error))
13229 { size_t size = content->size;
13230 if (!handle)
13231 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fdimereadopen failed\n"));
13232 return soap->error;
13234 if (!size && ((soap->mode & SOAP_ENC_XML) || (soap->mode & SOAP_IO) == SOAP_IO_CHUNK || (soap->mode & SOAP_IO) == SOAP_IO_STORE))
13235 { size_t chunksize = sizeof(soap->tmpbuf);
13236 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Chunked streaming DIME\n"));
13238 { size = soap->fdimeread(soap, handle, soap->tmpbuf, chunksize);
13239 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fdimeread returned %lu bytes\n", (unsigned long)size));
13240 if (size < chunksize)
13241 { soap->dime.flags &= ~SOAP_DIME_CF;
13242 if (!content->next)
13243 soap->dime.flags |= SOAP_DIME_ME;
13245 else
13246 soap->dime.flags |= SOAP_DIME_CF;
13247 soap->dime.size = size;
13248 if (soap_putdimehdr(soap)
13249 || soap_putdimefield(soap, soap->tmpbuf, size))
13250 break;
13251 if (soap->dime.id)
13252 { soap->dime.flags &= ~(SOAP_DIME_MB | SOAP_DIME_MEDIA);
13253 soap->dime.id = NULL;
13254 soap->dime.type = NULL;
13255 soap->dime.options = NULL;
13257 } while (size >= chunksize);
13259 else
13260 { if (!content->next)
13261 soap->dime.flags |= SOAP_DIME_ME;
13262 if (soap_putdimehdr(soap))
13263 return soap->error;
13265 { size_t bufsize;
13266 if (size < sizeof(soap->tmpbuf))
13267 bufsize = size;
13268 else
13269 bufsize = sizeof(soap->tmpbuf);
13270 if (!(bufsize = soap->fdimeread(soap, handle, soap->tmpbuf, bufsize)))
13271 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fdimeread failed: insufficient data (%lu bytes remaining from %lu bytes)\n", (unsigned long)size, (unsigned long)content->size));
13272 soap->error = SOAP_EOF;
13273 break;
13275 if (soap_send_raw(soap, soap->tmpbuf, bufsize))
13276 break;
13277 size -= bufsize;
13278 } while (size);
13279 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fdimereadclose\n"));
13280 soap_send_raw(soap, SOAP_STR_PADDING, -(long)soap->dime.size&3);
13282 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fdimereadclose\n"));
13283 if (soap->fdimereadclose)
13284 soap->fdimereadclose(soap, handle);
13286 else
13287 { if (!content->next)
13288 soap->dime.flags |= SOAP_DIME_ME;
13289 if (soap_putdimehdr(soap)
13290 || soap_putdimefield(soap, (char*)content->ptr, content->size))
13291 return soap->error;
13294 return SOAP_OK;
13296 #endif
13297 #endif
13299 /******************************************************************************/
13300 #ifndef WITH_LEANER
13301 #ifndef PALM_1
13302 static char *
13303 soap_getdimefield(struct soap *soap, size_t n)
13304 { register soap_wchar c;
13305 register size_t i;
13306 register char *s;
13307 register char *p = NULL;
13308 if (n)
13309 { p = (char*)soap_malloc(soap, n + 1);
13310 if (p)
13311 { s = p;
13312 for (i = n; i > 0; i--)
13313 { if ((int)(c = soap_get1(soap)) == EOF)
13314 { soap->error = SOAP_EOF;
13315 return NULL;
13317 *s++ = (char)c;
13319 *s = '\0';
13320 if ((soap->error = soap_move(soap, -(long)n&3)))
13321 return NULL;
13323 else
13324 soap->error = SOAP_EOM;
13326 return p;
13328 #endif
13329 #endif
13331 /******************************************************************************/
13332 #ifndef WITH_LEANER
13333 #ifndef PALM_1
13334 SOAP_FMAC1
13336 SOAP_FMAC2
13337 soap_getdimehdr(struct soap *soap)
13338 { register soap_wchar c;
13339 register char *s;
13340 register int i;
13341 unsigned char tmp[12];
13342 size_t optlen, idlen, typelen;
13343 if (!(soap->mode & SOAP_ENC_DIME))
13344 return soap->error = SOAP_DIME_END;
13345 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get DIME header\n"));
13346 if (soap->dime.buflen || soap->dime.chunksize)
13347 { if (soap_move(soap, (long)(soap->dime.size - soap_tell(soap))))
13348 return soap->error = SOAP_EOF;
13349 soap_unget(soap, soap_getchar(soap)); /* skip padding and get hdr */
13350 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "... From chunked\n"));
13351 return SOAP_OK;
13353 s = (char*)tmp;
13354 for (i = 12; i > 0; i--)
13355 { if ((int)(c = soap_getchar(soap)) == EOF)
13356 return soap->error = SOAP_EOF;
13357 *s++ = (char)c;
13359 if ((tmp[0] & 0xF8) != SOAP_DIME_VERSION)
13360 return soap->error = SOAP_DIME_MISMATCH;
13361 soap->dime.flags = (tmp[0] & 0x7) | (tmp[1] & 0xF0);
13362 optlen = (tmp[2] << 8) | tmp[3];
13363 idlen = (tmp[4] << 8) | tmp[5];
13364 typelen = (tmp[6] << 8) | tmp[7];
13365 soap->dime.size = (tmp[8] << 24) | (tmp[9] << 16) | (tmp[10] << 8) | tmp[11];
13366 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DIME size=%lu flags=0x%X\n", (unsigned long)soap->dime.size, soap->dime.flags));
13367 if (!(soap->dime.options = soap_getdimefield(soap, optlen)) && soap->error)
13368 return soap->error;
13369 if (!(soap->dime.id = soap_getdimefield(soap, idlen)) && soap->error)
13370 return soap->error;
13371 if (!(soap->dime.type = soap_getdimefield(soap, typelen)) && soap->error)
13372 return soap->error;
13373 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DIME id=%s, type=%s, options=%s\n", soap->dime.id?soap->dime.id:SOAP_STR_EOS, soap->dime.type?soap->dime.type:"", soap->dime.options?soap->dime.options+4:SOAP_STR_EOS));
13374 if (soap->dime.flags & SOAP_DIME_ME)
13375 soap->mode &= ~SOAP_ENC_DIME;
13376 return SOAP_OK;
13378 #endif
13379 #endif
13381 /******************************************************************************/
13382 #ifndef WITH_LEANER
13383 #ifndef PALM_1
13384 SOAP_FMAC1
13386 SOAP_FMAC2
13387 soap_getdime(struct soap *soap)
13388 { while (soap->dime.flags & SOAP_DIME_CF)
13389 { if (soap_getdimehdr(soap))
13390 return soap->error;
13391 if (soap_move(soap, (long)soap->dime.size))
13392 return soap->error = SOAP_EOF;
13394 if (soap_move(soap, (long)(((soap->dime.size+3)&(~3))-soap_tell(soap))))
13395 return soap->error = SOAP_EOF;
13396 for (;;)
13397 { register struct soap_multipart *content;
13398 if (soap_getdimehdr(soap))
13399 break;
13400 if (soap->fdimewriteopen && ((soap->dime.ptr = (char*)soap->fdimewriteopen(soap, soap->dime.id, soap->dime.type, soap->dime.options)) || soap->error))
13401 { const char *id, *type, *options;
13402 size_t size, n;
13403 if (!soap->dime.ptr)
13404 return soap->error;
13405 id = soap->dime.id;
13406 type = soap->dime.type;
13407 options = soap->dime.options;
13408 for (;;)
13409 { size = soap->dime.size;
13410 for (;;)
13411 { n = soap->buflen - soap->bufidx;
13412 if (size < n)
13413 n = size;
13414 if ((soap->error = soap->fdimewrite(soap, (void*)soap->dime.ptr, soap->buf + soap->bufidx, n)))
13415 break;
13416 size -= n;
13417 if (!size)
13418 { soap->bufidx += n;
13419 break;
13421 if (soap_recv(soap))
13422 { soap->error = SOAP_EOF;
13423 goto end;
13426 if (soap_move(soap, -(long)soap->dime.size&3))
13427 { soap->error = SOAP_EOF;
13428 break;
13430 if (!(soap->dime.flags & SOAP_DIME_CF))
13431 break;
13432 if (soap_getdimehdr(soap))
13433 break;
13435 end:
13436 if (soap->fdimewriteclose)
13437 soap->fdimewriteclose(soap, (void*)soap->dime.ptr);
13438 soap->dime.size = 0;
13439 soap->dime.id = id;
13440 soap->dime.type = type;
13441 soap->dime.options = options;
13443 else if (soap->dime.flags & SOAP_DIME_CF)
13444 { const char *id, *type, *options;
13445 id = soap->dime.id;
13446 type = soap->dime.type;
13447 options = soap->dime.options;
13448 if (soap_new_block(soap) == NULL)
13449 return SOAP_EOM;
13450 for (;;)
13451 { register soap_wchar c;
13452 register size_t i;
13453 register char *s;
13454 s = (char*)soap_push_block(soap, NULL, soap->dime.size);
13455 if (!s)
13456 return soap->error = SOAP_EOM;
13457 for (i = soap->dime.size; i > 0; i--)
13458 { if ((int)(c = soap_get1(soap)) == EOF)
13459 return soap->error = SOAP_EOF;
13460 *s++ = (char)c;
13462 if (soap_move(soap, -(long)soap->dime.size&3))
13463 return soap->error = SOAP_EOF;
13464 if (!(soap->dime.flags & SOAP_DIME_CF))
13465 break;
13466 if (soap_getdimehdr(soap))
13467 return soap->error;
13469 soap->dime.size = soap->blist->size++; /* allocate one more for '\0' */
13470 if (!(soap->dime.ptr = soap_save_block(soap, NULL, NULL, 0)))
13471 return soap->error;
13472 soap->dime.ptr[soap->dime.size] = '\0'; /* force 0-terminated */
13473 soap->dime.id = id;
13474 soap->dime.type = type;
13475 soap->dime.options = options;
13477 else
13478 soap->dime.ptr = soap_getdimefield(soap, soap->dime.size);
13479 content = soap_new_multipart(soap, &soap->dime.first, &soap->dime.last, soap->dime.ptr, soap->dime.size);
13480 if (!content)
13481 return soap->error = SOAP_EOM;
13482 content->id = soap->dime.id;
13483 content->type = soap->dime.type;
13484 content->options = soap->dime.options;
13485 if (soap->error)
13486 return soap->error;
13487 soap_resolve_attachment(soap, content);
13489 if (soap->error != SOAP_DIME_END)
13490 return soap->error;
13491 return soap->error = SOAP_OK;
13493 #endif
13494 #endif
13496 /******************************************************************************/
13497 #ifndef WITH_LEANER
13498 #ifndef PALM_1
13499 SOAP_FMAC1
13501 SOAP_FMAC2
13502 soap_getmimehdr(struct soap *soap)
13503 { struct soap_multipart *content;
13505 { if (soap_getline(soap, soap->msgbuf, sizeof(soap->msgbuf)))
13506 return soap->error;
13508 while (!*soap->msgbuf);
13509 if (soap->msgbuf[0] == '-' && soap->msgbuf[1] == '-')
13510 { char *s = soap->msgbuf + strlen(soap->msgbuf) - 1;
13511 /* remove white space */
13512 while (soap_blank((soap_wchar)*s))
13513 s--;
13514 s[1] = '\0';
13515 if (soap->mime.boundary)
13516 { if (strcmp(soap->msgbuf + 2, soap->mime.boundary))
13517 return soap->error = SOAP_MIME_ERROR;
13519 else
13520 soap->mime.boundary = soap_strdup(soap, soap->msgbuf + 2);
13521 if (soap_getline(soap, soap->msgbuf, sizeof(soap->msgbuf)))
13522 return soap->error;
13524 if (soap_set_mime_attachment(soap, NULL, 0, SOAP_MIME_NONE, NULL, NULL, NULL, NULL))
13525 return soap->error = SOAP_EOM;
13526 content = soap->mime.last;
13527 for (;;)
13528 { register char *key = soap->msgbuf;
13529 register char *val;
13530 if (!*key)
13531 break;
13532 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "MIME header: %s\n", key));
13533 val = strchr(soap->msgbuf, ':');
13534 if (val)
13535 { *val = '\0';
13536 do val++;
13537 while (*val && *val <= 32);
13538 if (!soap_tag_cmp(key, "Content-ID"))
13539 content->id = soap_strdup(soap, val);
13540 else if (!soap_tag_cmp(key, "Content-Location"))
13541 content->location = soap_strdup(soap, val);
13542 else if (!soap_tag_cmp(key, "Content-Disposition"))
13543 content->id = soap_strdup(soap, soap_get_header_attribute(soap, val, "name"));
13544 else if (!soap_tag_cmp(key, "Content-Type"))
13545 content->type = soap_strdup(soap, val);
13546 else if (!soap_tag_cmp(key, "Content-Description"))
13547 content->description = soap_strdup(soap, val);
13548 else if (!soap_tag_cmp(key, "Content-Transfer-Encoding"))
13549 content->encoding = (enum soap_mime_encoding)soap_code_int(mime_codes, val, (long)SOAP_MIME_NONE);
13551 if (soap_getline(soap, key, sizeof(soap->msgbuf)))
13552 return soap->error;
13554 return SOAP_OK;
13556 #endif
13557 #endif
13559 /******************************************************************************/
13560 #ifndef WITH_LEANER
13561 #ifndef PALM_1
13562 SOAP_FMAC1
13564 SOAP_FMAC2
13565 soap_getmime(struct soap *soap)
13566 { while (soap_get_mime_attachment(soap, NULL))
13568 return soap->error;
13570 #endif
13571 #endif
13573 /******************************************************************************/
13574 #ifndef WITH_LEANER
13575 #ifndef PALM_1
13576 SOAP_FMAC1
13577 void
13578 SOAP_FMAC2
13579 soap_post_check_mime_attachments(struct soap *soap)
13580 { soap->imode |= SOAP_MIME_POSTCHECK;
13582 #endif
13583 #endif
13585 /******************************************************************************/
13586 #ifndef WITH_LEANER
13587 #ifndef PALM_1
13588 SOAP_FMAC1
13590 SOAP_FMAC2
13591 soap_check_mime_attachments(struct soap *soap)
13592 { if (soap->mode & SOAP_MIME_POSTCHECK)
13593 return soap_get_mime_attachment(soap, NULL) != NULL;
13594 return SOAP_OK;
13596 #endif
13597 #endif
13599 /******************************************************************************/
13600 #ifndef WITH_LEANER
13601 #ifndef PALM_1
13602 SOAP_FMAC1
13603 struct soap_multipart *
13604 SOAP_FMAC2
13605 soap_get_mime_attachment(struct soap *soap, void *handle)
13606 { register soap_wchar c = 0;
13607 register size_t i, m = 0;
13608 register char *s, *t = NULL;
13609 register struct soap_multipart *content;
13610 register short flag = 0;
13611 if (!(soap->mode & SOAP_ENC_MIME))
13612 return NULL;
13613 content = soap->mime.last;
13614 if (!content)
13615 { if (soap_getmimehdr(soap))
13616 return NULL;
13617 content = soap->mime.last;
13619 else if (content != soap->mime.first)
13620 { if (soap->fmimewriteopen && ((content->ptr = (char*)soap->fmimewriteopen(soap, (void*)handle, content->id, content->type, content->description, content->encoding)) || soap->error))
13621 { if (!content->ptr)
13622 return NULL;
13625 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Parsing MIME content id=%s type=%s\n", content->id?content->id:SOAP_STR_EOS, content->type?content->type:SOAP_STR_EOS));
13626 if (!content->ptr && soap_new_block(soap) == NULL)
13627 { soap->error = SOAP_EOM;
13628 return NULL;
13630 for (;;)
13631 { if (content->ptr)
13632 s = soap->tmpbuf;
13633 else if (!(s = (char*)soap_push_block(soap, NULL, sizeof(soap->tmpbuf))))
13634 { soap->error = SOAP_EOM;
13635 return NULL;
13637 for (i = 0; i < sizeof(soap->tmpbuf); i++)
13638 { if (m > 0)
13639 { *s++ = *t++;
13640 m--;
13642 else
13643 { if (!flag)
13644 { c = soap_get1(soap);
13645 if ((int)c == EOF)
13646 { soap->error = SOAP_EOF;
13647 return NULL;
13650 if (flag || c == '\r')
13651 { t = soap->msgbuf;
13652 memset(t, 0, sizeof(soap->msgbuf));
13653 strcpy(t, "\n--");
13654 if (soap->mime.boundary)
13655 strncat(t, soap->mime.boundary, sizeof(soap->msgbuf)-4);
13656 do c = soap_getchar(soap);
13657 while (c == *t++);
13658 if ((int)c == EOF)
13659 { soap->error = SOAP_EOF;
13660 return NULL;
13662 if (!*--t)
13663 goto end;
13664 *t = (char)c;
13665 flag = (c == '\r');
13666 m = t - soap->msgbuf + 1 - flag;
13667 t = soap->msgbuf;
13668 c = '\r';
13670 *s++ = (char)c;
13673 if (content->ptr && soap->fmimewrite)
13674 { if ((soap->error = soap->fmimewrite(soap, (void*)content->ptr, soap->tmpbuf, i)))
13675 break;
13678 end:
13679 *s = '\0'; /* force 0-terminated */
13680 if (content->ptr)
13681 { if (!soap->error && soap->fmimewrite)
13682 soap->error = soap->fmimewrite(soap, (void*)content->ptr, soap->tmpbuf, i);
13683 if (soap->fmimewriteclose)
13684 soap->fmimewriteclose(soap, (void*)content->ptr);
13685 if (soap->error)
13686 return NULL;
13688 else
13689 { content->size = soap_size_block(soap, NULL, i+1)-1;
13690 content->ptr = soap_save_block(soap, NULL, NULL, 0);
13692 soap_resolve_attachment(soap, content);
13693 if (c == '-' && soap_getchar(soap) == '-')
13694 { soap->mode &= ~SOAP_ENC_MIME;
13695 if ((soap->mode & SOAP_MIME_POSTCHECK) && soap_end_recv(soap))
13696 { if (soap->keep_alive < 0)
13697 soap->keep_alive = 0;
13698 soap_closesock(soap);
13699 return NULL;
13702 else
13703 { while (c != '\r' && (int)c != EOF && soap_blank(c))
13704 c = soap_getchar(soap);
13705 if (c != '\r' || soap_getchar(soap) != '\n')
13706 { soap->error = SOAP_MIME_ERROR;
13707 return NULL;
13709 if (soap_getmimehdr(soap))
13710 return NULL;
13712 return content;
13714 #endif
13715 #endif
13717 /******************************************************************************/
13718 #ifndef WITH_LEANER
13719 #ifndef PALM_1
13720 SOAP_FMAC1
13722 SOAP_FMAC2
13723 soap_match_cid(struct soap *soap, const char *s, const char *t)
13724 { register size_t n;
13725 if (!s)
13726 return 1;
13727 if (!strcmp(s, t))
13728 return 0;
13729 if (!strncmp(s, "cid:", 4))
13730 s += 4;
13731 n = strlen(t);
13732 if (*t == '<')
13733 { t++;
13734 n -= 2;
13736 if (!strncmp(s, t, n) && !s[n])
13737 return 0;
13738 soap_decode(soap->tmpbuf, sizeof(soap->tmpbuf), s, SOAP_STR_EOS);
13739 if (!strncmp(soap->tmpbuf, t, n) && !soap->tmpbuf[n])
13740 return 0;
13741 return 1;
13743 #endif
13744 #endif
13746 /******************************************************************************/
13747 #ifndef WITH_LEANER
13748 #ifndef PALM_1
13749 static void
13750 soap_resolve_attachment(struct soap *soap, struct soap_multipart *content)
13751 { if (content->id)
13752 { register struct soap_xlist **xp = &soap->xlist;
13753 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolving attachment data for id=%s\n", content->id));
13754 while (*xp)
13755 { register struct soap_xlist *xq = *xp;
13756 if (!soap_match_cid(soap, xq->id, content->id))
13757 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Found matching attachment %s for content id=%s\n", xq->id, content->id));
13758 *xp = xq->next;
13759 *xq->ptr = (unsigned char*)content->ptr;
13760 *xq->size = (int)content->size;
13761 *xq->type = (char*)content->type;
13762 if (content->options)
13763 *xq->options = (char*)content->options;
13764 else
13765 *xq->options = (char*)content->description;
13766 SOAP_FREE(soap, xq);
13768 else
13769 xp = &(*xp)->next;
13773 #endif
13774 #endif
13776 /******************************************************************************/
13777 #ifndef WITH_LEANER
13778 #ifndef PALM_1
13779 SOAP_FMAC1
13781 SOAP_FMAC2
13782 soap_putmimehdr(struct soap *soap, struct soap_multipart *content)
13783 { const char *s;
13784 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "MIME attachment type=%s\n", content->type?content->type:SOAP_STR_EOS));
13785 if (soap_send3(soap, "\r\n--", soap->mime.boundary, "\r\n"))
13786 return soap->error;
13787 if (content->type && soap_send3(soap, "Content-Type: ", content->type, "\r\n"))
13788 return soap->error;
13789 s = soap_code_str(mime_codes, content->encoding);
13790 if (s && soap_send3(soap, "Content-Transfer-Encoding: ", s, "\r\n"))
13791 return soap->error;
13792 if (content->id && soap_send3(soap, "Content-ID: ", content->id, "\r\n"))
13793 return soap->error;
13794 if (content->location && soap_send3(soap, "Content-Location: ", content->location, "\r\n"))
13795 return soap->error;
13796 if (content->description && soap_send3(soap, "Content-Description: ", content->description, "\r\n"))
13797 return soap->error;
13798 return soap_send_raw(soap, "\r\n", 2);
13800 #endif
13801 #endif
13803 /******************************************************************************/
13804 #ifndef WITH_LEANER
13805 #ifndef PALM_1
13806 SOAP_FMAC1
13808 SOAP_FMAC2
13809 soap_putmime(struct soap *soap)
13810 { struct soap_multipart *content;
13811 if (!(soap->mode & SOAP_ENC_MIME) || !soap->mime.boundary)
13812 return SOAP_OK;
13813 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Sending MIME attachments\n"));
13814 for (content = soap->mime.first; content; content = content->next)
13815 { void *handle;
13816 if (soap->fmimereadopen && ((handle = soap->fmimereadopen(soap, (void*)content->ptr, content->id, content->type, content->description)) || soap->error))
13817 { size_t size = content->size;
13818 if (!handle)
13819 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fmimereadopen failed\n"));
13820 return soap->error;
13822 if (soap_putmimehdr(soap, content))
13823 return soap->error;
13824 if (!size)
13825 { if ((soap->mode & SOAP_ENC_XML) || (soap->mode & SOAP_IO) == SOAP_IO_CHUNK || (soap->mode & SOAP_IO) == SOAP_IO_STORE)
13826 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Chunked streaming MIME\n"));
13828 { size = soap->fmimeread(soap, handle, soap->tmpbuf, sizeof(soap->tmpbuf));
13829 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fmimeread returned %lu bytes\n", (unsigned long)size));
13830 if (soap_send_raw(soap, soap->tmpbuf, size))
13831 break;
13832 } while (size);
13834 else
13835 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Error: cannot chunk streaming MIME (no HTTP chunking)\n"));
13838 else
13839 { do
13840 { size_t bufsize;
13841 if (size < sizeof(soap->tmpbuf))
13842 bufsize = size;
13843 else
13844 bufsize = sizeof(soap->tmpbuf);
13845 if (!(bufsize = soap->fmimeread(soap, handle, soap->tmpbuf, bufsize)))
13846 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "fmimeread failed: insufficient data (%lu bytes remaining from %lu bytes)\n", (unsigned long)size, (unsigned long)content->size));
13847 soap->error = SOAP_EOF;
13848 break;
13850 if (soap_send_raw(soap, soap->tmpbuf, bufsize))
13851 break;
13852 size -= bufsize;
13853 } while (size);
13855 if (soap->fmimereadclose)
13856 soap->fmimereadclose(soap, handle);
13858 else
13859 { if (soap_putmimehdr(soap, content)
13860 || soap_send_raw(soap, content->ptr, content->size))
13861 return soap->error;
13864 return soap_send3(soap, "\r\n--", soap->mime.boundary, "--");
13866 #endif
13867 #endif
13869 /******************************************************************************/
13870 #ifndef WITH_LEANER
13871 #ifndef PALM_1
13872 SOAP_FMAC1
13873 void
13874 SOAP_FMAC2
13875 soap_set_dime(struct soap *soap)
13876 { soap->omode |= SOAP_ENC_DIME;
13877 soap->dime.first = NULL;
13878 soap->dime.last = NULL;
13880 #endif
13881 #endif
13883 /******************************************************************************/
13884 #ifndef WITH_LEANER
13885 #ifndef PALM_1
13886 SOAP_FMAC1
13887 void
13888 SOAP_FMAC2
13889 soap_set_mime(struct soap *soap, const char *boundary, const char *start)
13890 { soap->omode |= SOAP_ENC_MIME;
13891 soap->mime.first = NULL;
13892 soap->mime.last = NULL;
13893 soap->mime.boundary = soap_strdup(soap, boundary);
13894 soap->mime.start = soap_strdup(soap, start);
13896 #endif
13897 #endif
13899 /******************************************************************************/
13900 #ifndef WITH_LEANER
13901 #ifndef PALM_1
13902 SOAP_FMAC1
13903 void
13904 SOAP_FMAC2
13905 soap_clr_dime(struct soap *soap)
13906 { soap->omode &= ~SOAP_ENC_DIME;
13907 soap->dime.first = NULL;
13908 soap->dime.last = NULL;
13910 #endif
13911 #endif
13913 /******************************************************************************/
13914 #ifndef WITH_LEANER
13915 #ifndef PALM_1
13916 SOAP_FMAC1
13917 void
13918 SOAP_FMAC2
13919 soap_clr_mime(struct soap *soap)
13920 { soap->omode &= ~SOAP_ENC_MIME;
13921 soap->mime.first = NULL;
13922 soap->mime.last = NULL;
13923 soap->mime.boundary = NULL;
13924 soap->mime.start = NULL;
13926 #endif
13927 #endif
13929 /******************************************************************************/
13930 #ifndef WITH_LEANER
13931 #ifndef PALM_1
13932 static struct soap_multipart*
13933 soap_new_multipart(struct soap *soap, struct soap_multipart **first, struct soap_multipart **last, char *ptr, size_t size)
13934 { struct soap_multipart *content;
13935 content = (struct soap_multipart*)soap_malloc(soap, sizeof(struct soap_multipart));
13936 if (content)
13937 { content->next = NULL;
13938 content->ptr = ptr;
13939 content->size = size;
13940 content->id = NULL;
13941 content->type = NULL;
13942 content->options = NULL;
13943 content->encoding = SOAP_MIME_NONE;
13944 content->location = NULL;
13945 content->description = NULL;
13946 if (!*first)
13947 *first = content;
13948 if (*last)
13949 (*last)->next = content;
13950 *last = content;
13952 return content;
13954 #endif
13955 #endif
13957 /******************************************************************************/
13958 #ifndef WITH_LEANER
13959 #ifndef PALM_1
13960 SOAP_FMAC1
13962 SOAP_FMAC2
13963 soap_set_dime_attachment(struct soap *soap, char *ptr, size_t size, const char *type, const char *id, unsigned short optype, const char *option)
13964 { struct soap_multipart *content = soap_new_multipart(soap, &soap->dime.first, &soap->dime.last, ptr, size);
13965 if (!content)
13966 return SOAP_EOM;
13967 content->id = soap_strdup(soap, id);
13968 content->type = soap_strdup(soap, type);
13969 content->options = soap_dime_option(soap, optype, option);
13970 return SOAP_OK;
13972 #endif
13973 #endif
13975 /******************************************************************************/
13976 #ifndef WITH_LEANER
13977 #ifndef PALM_1
13978 SOAP_FMAC1
13980 SOAP_FMAC2
13981 soap_set_mime_attachment(struct soap *soap, char *ptr, size_t size, enum soap_mime_encoding encoding, const char *type, const char *id, const char *location, const char *description)
13982 { struct soap_multipart *content = soap_new_multipart(soap, &soap->mime.first, &soap->mime.last, ptr, size);
13983 if (!content)
13984 return SOAP_EOM;
13985 content->id = soap_strdup(soap, id);
13986 content->type = soap_strdup(soap, type);
13987 content->encoding = encoding;
13988 content->location = soap_strdup(soap, location);
13989 content->description = soap_strdup(soap, description);
13990 return SOAP_OK;
13992 #endif
13993 #endif
13995 /******************************************************************************/
13996 #ifndef WITH_LEANER
13997 #ifndef PALM_1
13998 SOAP_FMAC1
13999 struct soap_multipart*
14000 SOAP_FMAC2
14001 soap_next_multipart(struct soap_multipart *content)
14002 { if (content)
14003 return content->next;
14004 return NULL;
14006 #endif
14007 #endif
14009 /******************************************************************************/
14010 #ifndef WITH_LEANER
14011 #ifndef PALM_1
14012 static void
14013 soap_select_mime_boundary(struct soap *soap)
14014 { while (!soap->mime.boundary || soap_valid_mime_boundary(soap))
14015 { register char *s = soap->mime.boundary;
14016 register size_t n = 0;
14017 if (s)
14018 n = strlen(s);
14019 if (n < 16)
14020 { n = 64;
14021 s = soap->mime.boundary = (char*)soap_malloc(soap, n + 1);
14022 if (!s)
14023 return;
14025 strcpy(s, "==");
14026 s += 2;
14027 n -= 4;
14028 while (n)
14029 { *s++ = soap_base64o[soap_random & 0x3F];
14030 n--;
14032 strcpy(s, "==");
14034 if (!soap->mime.start)
14035 soap->mime.start = "<SOAP-ENV:Envelope>";
14037 #endif
14038 #endif
14040 /******************************************************************************/
14041 #ifndef WITH_LEANER
14042 #ifndef PALM_1
14043 static int
14044 soap_valid_mime_boundary(struct soap *soap)
14045 { register struct soap_multipart *content;
14046 register size_t k;
14047 if (soap->fmimeread)
14048 return SOAP_OK;
14049 k = strlen(soap->mime.boundary);
14050 for (content = soap->mime.first; content; content = content->next)
14051 { if (content->ptr && content->size >= k)
14052 { register const char *p = (const char*)content->ptr;
14053 register size_t i;
14054 for (i = 0; i < content->size - k; i++, p++)
14055 { if (!strncmp(p, soap->mime.boundary, k))
14056 return SOAP_ERR;
14060 return SOAP_OK;
14062 #endif
14063 #endif
14065 /******************************************************************************/
14066 #ifdef WITH_GZIP
14067 #ifndef PALM_1
14068 static int
14069 soap_getgziphdr(struct soap *soap)
14070 { int i;
14071 soap_wchar c = 0, f = 0;
14072 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get gzip header\n"));
14073 for (i = 0; i < 9; i++)
14074 { if ((int)(c = soap_get1(soap) == EOF))
14075 return soap->error = SOAP_EOF;
14076 if (i == 1 && c == 8)
14077 soap->z_dict = 0;
14078 if (i == 2)
14079 f = c;
14081 if (f & 0x04) /* FEXTRA */
14082 { for (i = soap_get1(soap) | (soap_get1(soap) << 8); i; i--)
14083 { if ((int)soap_get1(soap) == EOF)
14084 return soap->error = SOAP_EOF;
14087 if (f & 0x08) /* skip FNAME */
14088 { do
14089 c = soap_get1(soap);
14090 while (c && (int)c != EOF);
14092 if ((int)c != EOF && (f & 0x10)) /* skip FCOMMENT */
14093 { do
14094 c = soap_get1(soap);
14095 while (c && (int)c != EOF);
14097 if ((int)c != EOF && (f & 0x02)) /* skip FHCRC (CRC32 is used) */
14098 { if ((int)(c = soap_get1(soap)) != EOF)
14099 c = soap_get1(soap);
14101 if ((int)c == EOF)
14102 return soap->error = SOAP_EOF;
14103 return SOAP_OK;
14105 #endif
14106 #endif
14108 /******************************************************************************/
14109 #ifndef PALM_1
14110 SOAP_FMAC1
14112 SOAP_FMAC2
14113 soap_begin_recv(struct soap *soap)
14114 { soap_wchar c;
14115 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Initializing for input\n"));
14116 soap->error = SOAP_OK;
14117 soap_free_temp(soap);
14118 soap_set_local_namespaces(soap);
14119 soap->version = 0; /* don't assume we're parsing SOAP content by default */
14120 #ifndef WITH_NOIDREF
14121 soap_free_iht(soap);
14122 #endif
14123 if ((soap->imode & SOAP_IO) == SOAP_IO_CHUNK)
14124 soap->omode |= SOAP_IO_CHUNK;
14125 soap->imode &= ~(SOAP_IO | SOAP_ENC_MIME);
14126 soap->mode = soap->imode;
14127 if (!soap->keep_alive)
14128 { soap->buflen = 0;
14129 soap->bufidx = 0;
14131 if (!(soap->mode & SOAP_IO_KEEPALIVE))
14132 soap->keep_alive = 0;
14133 soap->ahead = 0;
14134 soap->peeked = 0;
14135 soap->level = 0;
14136 soap->part = SOAP_BEGIN;
14137 soap->alloced = 0;
14138 soap->count = 0;
14139 soap->length = 0;
14140 soap->cdata = 0;
14141 *soap->endpoint = '\0';
14142 soap->action = NULL;
14143 soap->header = NULL;
14144 soap->fault = NULL;
14145 soap->status = 0;
14146 #ifndef WITH_LEANER
14147 soap->dom = NULL;
14148 soap->dime.chunksize = 0;
14149 soap->dime.buflen = 0;
14150 soap->dime.list = NULL;
14151 soap->dime.first = NULL;
14152 soap->dime.last = NULL;
14153 soap->mime.list = NULL;
14154 soap->mime.first = NULL;
14155 soap->mime.last = NULL;
14156 soap->mime.boundary = NULL;
14157 soap->mime.start = NULL;
14158 #endif
14159 #ifdef WIN32
14160 #ifndef UNDER_CE
14161 #ifndef WITH_FASTCGI
14162 if (!soap_valid_socket(soap->socket))
14163 #ifdef __BORLANDC__
14164 setmode(soap->recvfd, _O_BINARY);
14165 #else
14166 _setmode(soap->recvfd, _O_BINARY);
14167 #endif
14168 #endif
14169 #endif
14170 #endif
14171 #ifdef WITH_ZLIB
14172 soap->mode &= ~SOAP_ENC_ZLIB;
14173 soap->zlib_in = SOAP_ZLIB_NONE;
14174 soap->zlib_out = SOAP_ZLIB_NONE;
14175 soap->d_stream->next_in = Z_NULL;
14176 soap->d_stream->avail_in = 0;
14177 soap->d_stream->next_out = (Byte*)soap->buf;
14178 soap->d_stream->avail_out = SOAP_BUFLEN;
14179 soap->z_ratio_in = 1.0;
14180 #endif
14181 #ifdef WITH_OPENSSL
14182 if (soap->ssl)
14183 ERR_clear_error();
14184 #endif
14185 #ifndef WITH_LEANER
14186 if (soap->fprepareinitrecv && (soap->error = soap->fprepareinitrecv(soap)))
14187 return soap->error;
14188 #endif
14189 c = soap_getchar(soap);
14190 #ifdef WITH_GZIP
14191 if (c == 0x1F)
14192 { if (soap_getgziphdr(soap))
14193 return soap->error;
14194 if (inflateInit2(soap->d_stream, -MAX_WBITS) != Z_OK)
14195 return soap->error = SOAP_ZLIB_ERROR;
14196 if (soap->z_dict)
14197 { if (inflateSetDictionary(soap->d_stream, (const Bytef*)soap->z_dict, soap->z_dict_len) != Z_OK)
14198 return soap->error = SOAP_ZLIB_ERROR;
14200 soap->zlib_state = SOAP_ZLIB_INFLATE;
14201 soap->mode |= SOAP_ENC_ZLIB;
14202 soap->zlib_in = SOAP_ZLIB_GZIP;
14203 soap->z_crc = crc32(0L, NULL, 0);
14204 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "gzip initialized\n"));
14205 if (!soap->z_buf)
14206 soap->z_buf = (char*)SOAP_MALLOC(soap, SOAP_BUFLEN);
14207 memcpy(soap->z_buf, soap->buf, SOAP_BUFLEN);
14208 /* should not chunk over plain transport, so why bother to check? */
14209 /* if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK) */
14210 /* soap->z_buflen = soap->bufidx; */
14211 /* else */
14212 soap->d_stream->next_in = (Byte*)(soap->z_buf + soap->bufidx);
14213 soap->d_stream->avail_in = soap->buflen - soap->bufidx;
14214 soap->z_buflen = soap->buflen;
14215 soap->buflen = soap->bufidx;
14216 c = ' ';
14218 #endif
14219 while (soap_blank(c))
14220 c = soap_getchar(soap);
14221 #ifndef WITH_LEANER
14222 if (c == '-' && soap_get0(soap) == '-')
14223 soap->mode |= SOAP_ENC_MIME;
14224 else if ((c & 0xFFFC) == (SOAP_DIME_VERSION | SOAP_DIME_MB) && (soap_get0(soap) & 0xFFF0) == 0x20)
14225 soap->mode |= SOAP_ENC_DIME;
14226 else
14227 #endif
14228 { /* skip BOM */
14229 if (c == 0xEF && (c = soap_getchar(soap)) == 0xBB && (c = soap_getchar(soap)) == 0xBF)
14230 c = soap_getchar(soap);
14231 /* skip space */
14232 while (soap_blank(c))
14233 c = soap_getchar(soap);
14235 if ((int)c == EOF)
14236 return soap->error = SOAP_EOF;
14237 soap_unget(soap, c);
14238 #ifndef WITH_NOHTTP
14239 /* if not XML or MIME/DIME/ZLIB, assume HTTP header */
14240 if (c != '<' && !(soap->mode & (SOAP_ENC_MIME | SOAP_ENC_DIME | SOAP_ENC_ZLIB)))
14241 { soap_mode m = soap->imode;
14242 soap->mode &= ~SOAP_IO;
14243 soap->error = soap->fparse(soap);
14244 if (soap->error && soap->error < SOAP_STOP)
14245 { soap->keep_alive = 0; /* force close later */
14246 return soap->error;
14248 if (soap->error == SOAP_STOP)
14249 return soap->error;
14250 soap->mode = soap->imode; /* if imode is changed, effectuate */
14251 soap->imode = m; /* restore imode */
14252 #ifdef WITH_ZLIB
14253 soap->mode &= ~SOAP_ENC_ZLIB;
14254 #endif
14255 if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK)
14256 { soap->chunkbuflen = soap->buflen;
14257 soap->buflen = soap->bufidx;
14258 soap->chunksize = 0;
14260 /* Note: fparse should not use soap_unget to push back last char */
14261 if (soap_get0(soap) == (int)EOF)
14262 { if (soap->status == 200)
14263 return soap->error = SOAP_NO_DATA; /* HTTP OK: always expect data */
14264 return soap->error = soap->status;
14266 #ifdef WITH_ZLIB
14267 if (soap->zlib_in != SOAP_ZLIB_NONE)
14269 #ifdef WITH_GZIP
14270 if (soap->zlib_in != SOAP_ZLIB_DEFLATE)
14271 { c = soap_get1(soap);
14272 if (c == 0x1F)
14273 { if (soap_getgziphdr(soap))
14274 return soap->error;
14275 if (inflateInit2(soap->d_stream, -MAX_WBITS) != Z_OK)
14276 return soap->error = SOAP_ZLIB_ERROR;
14277 soap->z_crc = crc32(0L, NULL, 0);
14278 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "gzip initialized\n"));
14280 else
14281 { soap_revget1(soap);
14282 if (inflateInit(soap->d_stream) != Z_OK)
14283 return soap->error = SOAP_ZLIB_ERROR;
14284 soap->zlib_in = SOAP_ZLIB_DEFLATE;
14287 else
14288 #endif
14289 if (inflateInit(soap->d_stream) != Z_OK)
14290 return soap->error = SOAP_ZLIB_ERROR;
14291 if (soap->z_dict)
14292 { if (inflateSetDictionary(soap->d_stream, (const Bytef*)soap->z_dict, soap->z_dict_len) != Z_OK)
14293 return soap->error = SOAP_ZLIB_ERROR;
14295 soap->zlib_state = SOAP_ZLIB_INFLATE;
14296 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflate initialized\n"));
14297 soap->mode |= SOAP_ENC_ZLIB;
14298 if (!soap->z_buf)
14299 soap->z_buf = (char*)SOAP_MALLOC(soap, SOAP_BUFLEN);
14300 memcpy(soap->z_buf, soap->buf, SOAP_BUFLEN);
14301 soap->d_stream->next_in = (Byte*)(soap->z_buf + soap->bufidx);
14302 soap->d_stream->avail_in = soap->buflen - soap->bufidx;
14303 soap->z_buflen = soap->buflen;
14304 soap->buflen = soap->bufidx;
14306 #endif
14307 #ifndef WITH_LEANER
14308 if (soap->fpreparerecv && (soap->mode & SOAP_IO) != SOAP_IO_CHUNK && soap->buflen > soap->bufidx)
14309 { int r;
14310 if ((r = soap->fpreparerecv(soap, soap->buf + soap->bufidx, soap->buflen - soap->bufidx)))
14311 return soap->error = r;
14313 #endif
14314 if (soap->error)
14315 { if (soap->error == SOAP_FORM && soap->fform)
14316 { soap->error = soap->fform(soap);
14317 if (soap->error == SOAP_OK)
14318 soap->error = SOAP_STOP; /* prevents further processing */
14320 return soap->error;
14323 #endif
14324 #ifndef WITH_LEANER
14325 if (soap->mode & SOAP_ENC_MIME)
14326 { do /* skip preamble */
14327 { if ((int)(c = soap_getchar(soap)) == EOF)
14328 return soap->error = SOAP_EOF;
14329 } while (c != '-' || soap_get0(soap) != '-');
14330 soap_unget(soap, c);
14331 if (soap_getmimehdr(soap))
14332 return soap->error;
14333 if (soap->mime.start)
14334 { do
14335 { if (!soap->mime.last->id)
14336 break;
14337 if (!soap_match_cid(soap, soap->mime.start, soap->mime.last->id))
14338 break;
14339 } while (soap_get_mime_attachment(soap, NULL));
14341 if (soap_get_header_attribute(soap, soap->mime.first->type, "application/dime"))
14342 soap->mode |= SOAP_ENC_DIME;
14344 if (soap->mode & SOAP_ENC_DIME)
14345 { if (soap_getdimehdr(soap))
14346 return soap->error;
14347 if (soap->dime.flags & SOAP_DIME_CF)
14348 { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Chunked DIME SOAP message\n"));
14349 soap->dime.chunksize = soap->dime.size;
14350 if (soap->buflen - soap->bufidx >= soap->dime.chunksize)
14351 { soap->dime.buflen = soap->buflen;
14352 soap->buflen = soap->bufidx + soap->dime.chunksize;
14354 else
14355 soap->dime.chunksize -= soap->buflen - soap->bufidx;
14357 soap->count = soap->buflen - soap->bufidx;
14359 #endif
14360 return SOAP_OK;
14362 #endif
14364 /******************************************************************************/
14365 #ifndef PALM_2
14366 SOAP_FMAC1
14368 SOAP_FMAC2
14369 soap_envelope_begin_out(struct soap *soap)
14371 #ifndef WITH_LEANER
14372 size_t n = 0;
14373 if ((soap->mode & SOAP_ENC_MIME) && soap->mime.boundary && soap->mime.start && strlen(soap->mime.boundary) + strlen(soap->mime.start) < sizeof(soap->tmpbuf) - 80 )
14374 { const char *s;
14375 if ((soap->mode & SOAP_ENC_DIME) && !(soap->mode & SOAP_ENC_MTOM))
14376 s = "application/dime";
14377 else if (soap->version == 2)
14378 { if (soap->mode & SOAP_ENC_MTOM)
14379 s = "application/xop+xml; charset=utf-8; type=\"application/soap+xml\"";
14380 else
14381 s = "application/soap+xml; charset=utf-8";
14383 else if (soap->mode & SOAP_ENC_MTOM)
14384 s = "application/xop+xml; charset=utf-8; type=\"text/xml\"";
14385 else
14386 s = "text/xml; charset=utf-8";
14387 sprintf(soap->tmpbuf, "--%s\r\nContent-Type: %s\r\nContent-Transfer-Encoding: binary\r\nContent-ID: %s\r\n\r\n", soap->mime.boundary, s, soap->mime.start);
14388 n = strlen(soap->tmpbuf);
14389 if (soap_send_raw(soap, soap->tmpbuf, n))
14390 return soap->error;
14392 if (soap->mode & SOAP_IO_LENGTH)
14393 soap->dime.size = soap->count; /* DIME in MIME correction */
14394 if (!(soap->mode & SOAP_IO_LENGTH) && (soap->mode & SOAP_ENC_DIME))
14395 { if (soap_putdimehdr(soap))
14396 return soap->error;
14398 #endif
14399 soap->part = SOAP_IN_ENVELOPE;
14400 return soap_element_begin_out(soap, "SOAP-ENV:Envelope", 0, NULL);
14402 #endif
14404 /******************************************************************************/
14405 #ifndef PALM_2
14406 SOAP_FMAC1
14408 SOAP_FMAC2
14409 soap_envelope_end_out(struct soap *soap)
14410 { if (soap_element_end_out(soap, "SOAP-ENV:Envelope") || ((soap->mode & SOAP_XML_INDENT) && soap_send_raw(soap, "\r\n", 2)))
14411 return soap->error;
14412 #ifndef WITH_LEANER
14413 if ((soap->mode & SOAP_IO_LENGTH) && (soap->mode & SOAP_ENC_DIME) && !(soap->mode & SOAP_ENC_MTOM))
14414 { soap->dime.size = soap->count - soap->dime.size; /* DIME in MIME correction */
14415 sprintf(soap->id, soap->dime_id_format, 0);
14416 soap->dime.id = soap->id;
14417 if (soap->local_namespaces)
14418 { if (soap->local_namespaces[0].out)
14419 soap->dime.type = (char*)soap->local_namespaces[0].out;
14420 else
14421 soap->dime.type = (char*)soap->local_namespaces[0].ns;
14423 soap->dime.options = NULL;
14424 soap->dime.flags = SOAP_DIME_MB | SOAP_DIME_ABSURI;
14425 if (!soap->dime.first)
14426 soap->dime.flags |= SOAP_DIME_ME;
14427 soap->count += 12 + ((strlen(soap->dime.id)+3)&(~3)) + (soap->dime.type ? ((strlen(soap->dime.type)+3)&(~3)) : 0);
14429 if ((soap->mode & SOAP_ENC_DIME) && !(soap->mode & SOAP_ENC_MTOM))
14430 return soap_send_raw(soap, SOAP_STR_PADDING, -(long)soap->dime.size&3);
14431 #endif
14432 soap->part = SOAP_END_ENVELOPE;
14433 return SOAP_OK;
14435 #endif
14437 /******************************************************************************/
14438 #ifndef WITH_LEAN
14439 #ifndef PALM_1
14440 SOAP_FMAC1
14441 char*
14442 SOAP_FMAC2
14443 soap_get_http_body(struct soap *soap)
14445 #ifndef WITH_LEAN
14446 register size_t l = 0, n = 0;
14447 register char *s;
14448 /* get HTML body of HTTP error content */
14449 if (!(soap->mode & SOAP_ENC_ZLIB) && (soap->mode & SOAP_IO) != SOAP_IO_CHUNK)
14450 { n = soap->length;
14451 if (!n)
14452 return NULL;
14454 #ifdef WITH_FAST
14455 soap->labidx = 0; /* use look-aside buffer */
14456 #else
14457 if (soap_new_block(soap) == NULL)
14458 return NULL;
14459 #endif
14460 for (;;)
14462 #ifdef WITH_FAST
14463 register size_t i, k;
14464 if (soap_append_lab(soap, NULL, 0)) /* allocate more space in look-aside buffer if necessary */
14465 return NULL;
14466 s = soap->labbuf + soap->labidx; /* space to populate */
14467 k = soap->lablen - soap->labidx; /* number of bytes available */
14468 soap->labidx = soap->lablen; /* claim this space */
14469 #else
14470 register size_t i, k = SOAP_BLKLEN;
14471 if (!(s = (char*)soap_push_block(soap, NULL, k)))
14472 return NULL;
14473 #endif
14474 for (i = 0; i < k; i++)
14475 { register soap_wchar c = soap_getchar(soap);
14476 if ((int)c == EOF)
14477 goto end;
14478 *s++ = (char)(c & 0xFF);
14479 l++;
14480 if (n > 0 && l >= n)
14481 goto end;
14484 end:
14485 *s = '\0';
14486 #ifdef WITH_FAST
14487 s = soap_strdup(soap, soap->labbuf);
14488 #else
14489 soap_size_block(soap, NULL, i+1);
14490 s = soap_save_block(soap, NULL, 0);
14491 #endif
14492 return s;
14493 #else
14494 return NULL;
14495 #endif
14497 #endif
14498 #endif
14500 /******************************************************************************/
14501 #ifndef PALM_1
14502 SOAP_FMAC1
14504 SOAP_FMAC2
14505 soap_envelope_begin_in(struct soap *soap)
14506 { register struct Namespace *p;
14507 soap->part = SOAP_IN_ENVELOPE;
14508 if (soap_element_begin_in(soap, "SOAP-ENV:Envelope", 0, NULL))
14509 { if (soap->error == SOAP_TAG_MISMATCH
14510 && !soap_element_begin_in(soap, "Envelope", 0, NULL))
14511 soap->error = SOAP_VERSIONMISMATCH;
14512 else if (soap->status)
14513 soap->error = soap->status;
14514 return soap->error;
14516 p = soap->local_namespaces;
14517 if (p)
14518 { const char *ns = p[0].out;
14519 if (!ns)
14520 ns = p[0].ns;
14521 if (!strcmp(ns, soap_env1))
14522 { soap->version = 1; /* make sure we use SOAP 1.1 */
14523 if (p[1].out)
14524 SOAP_FREE(soap, p[1].out);
14525 if ((p[1].out = (char*)SOAP_MALLOC(soap, sizeof(soap_enc1))))
14526 strcpy(p[1].out, soap_enc1);
14528 else if (!strcmp(ns, soap_env2))
14529 { soap->version = 2; /* make sure we use SOAP 1.2 */
14530 if (p[1].out)
14531 SOAP_FREE(soap, p[1].out);
14532 if ((p[1].out = (char*)SOAP_MALLOC(soap, sizeof(soap_enc2))))
14533 strcpy(p[1].out, soap_enc2);
14536 return SOAP_OK;
14538 #endif
14540 /******************************************************************************/
14541 #ifndef PALM_1
14542 SOAP_FMAC1
14544 SOAP_FMAC2
14545 soap_envelope_end_in(struct soap *soap)
14546 { soap->part = SOAP_END_ENVELOPE;
14547 return soap_element_end_in(soap, "SOAP-ENV:Envelope");
14549 #endif
14551 /******************************************************************************/
14552 #ifndef PALM_2
14553 SOAP_FMAC1
14555 SOAP_FMAC2
14556 soap_body_begin_out(struct soap *soap)
14557 { soap->part = SOAP_IN_BODY;
14558 if (soap->version == 1)
14559 soap->encoding = 1;
14560 #ifndef WITH_LEAN
14561 if ((soap->mode & SOAP_XML_SEC) && soap_set_attr(soap, "wsu:Id", "Body", 1))
14562 return soap->error;
14563 #endif
14564 if (soap_element(soap, "SOAP-ENV:Body", 0, NULL))
14565 return soap->error;
14566 return soap_element_start_end_out(soap, NULL);
14568 #endif
14570 /******************************************************************************/
14571 #ifndef PALM_2
14572 SOAP_FMAC1
14574 SOAP_FMAC2
14575 soap_body_end_out(struct soap *soap)
14576 { if (soap_element_end_out(soap, "SOAP-ENV:Body"))
14577 return soap->error;
14578 soap->part = SOAP_END_BODY;
14579 return SOAP_OK;
14581 #endif
14583 /******************************************************************************/
14584 #ifndef PALM_2
14585 SOAP_FMAC1
14587 SOAP_FMAC2
14588 soap_body_begin_in(struct soap *soap)
14589 { soap->part = SOAP_IN_BODY;
14590 if (soap_element_begin_in(soap, "SOAP-ENV:Body", 0, NULL))
14591 return soap->error;
14592 if (!soap->body)
14593 soap->part = SOAP_NO_BODY;
14594 return SOAP_OK;
14596 #endif
14598 /******************************************************************************/
14599 #ifndef PALM_2
14600 SOAP_FMAC1
14602 SOAP_FMAC2
14603 soap_body_end_in(struct soap *soap)
14604 { if (soap->part == SOAP_NO_BODY)
14605 return soap->error = SOAP_OK;
14606 soap->part = SOAP_END_BODY;
14607 return soap_element_end_in(soap, "SOAP-ENV:Body");
14609 #endif
14611 /******************************************************************************/
14612 #ifndef PALM_2
14613 SOAP_FMAC1
14615 SOAP_FMAC2
14616 soap_recv_header(struct soap *soap)
14617 { if (soap_getheader(soap) && soap->error == SOAP_TAG_MISMATCH)
14618 soap->error = SOAP_OK;
14619 if (soap->error == SOAP_OK && soap->fheader)
14620 soap->error = soap->fheader(soap);
14621 return soap->error;
14623 #endif
14625 /******************************************************************************/
14626 #ifndef PALM_1
14627 SOAP_FMAC1
14628 void
14629 SOAP_FMAC2
14630 soap_set_endpoint(struct soap *soap, const char *endpoint)
14631 { register const char *s;
14632 register size_t i, n;
14633 soap->endpoint[0] = '\0';
14634 soap->host[0] = '\0';
14635 soap->path[0] = '/';
14636 soap->path[1] = '\0';
14637 soap->port = 80;
14638 if (!endpoint || !*endpoint)
14639 return;
14640 #ifdef WITH_OPENSSL
14641 if (!soap_tag_cmp(endpoint, "https:*"))
14642 soap->port = 443;
14643 #endif
14644 strncpy(soap->endpoint, endpoint, sizeof(soap->endpoint) - 1);
14645 soap->endpoint[sizeof(soap->endpoint) - 1] = '\0';
14646 s = strchr(endpoint, ':');
14647 if (s && s[1] == '/' && s[2] == '/')
14648 s += 3;
14649 else
14650 s = endpoint;
14651 n = strlen(s);
14652 if (n >= sizeof(soap->host))
14653 n = sizeof(soap->host) - 1;
14654 #ifdef WITH_IPV6
14655 if (s[0] == '[')
14656 { s++;
14657 for (i = 0; i < n; i++)
14658 { if (s[i] == ']')
14659 { s++;
14660 --n;
14661 break;
14663 soap->host[i] = s[i];
14666 else
14667 { for (i = 0; i < n; i++)
14668 { soap->host[i] = s[i];
14669 if (s[i] == '/' || s[i] == ':')
14670 break;
14673 #else
14674 for (i = 0; i < n; i++)
14675 { soap->host[i] = s[i];
14676 if (s[i] == '/' || s[i] == ':')
14677 break;
14679 #endif
14680 soap->host[i] = '\0';
14681 if (s[i] == ':')
14682 { soap->port = (int)soap_strtol(s + i + 1, NULL, 10);
14683 for (i++; i < n; i++)
14684 if (s[i] == '/')
14685 break;
14687 if (i < n && s[i])
14688 { strncpy(soap->path, s + i, sizeof(soap->path));
14689 soap->path[sizeof(soap->path) - 1] = '\0';
14692 #endif
14694 /******************************************************************************/
14695 #ifndef PALM_1
14696 SOAP_FMAC1
14698 SOAP_FMAC2
14699 soap_connect(struct soap *soap, const char *endpoint, const char *action)
14700 { return soap_connect_command(soap, SOAP_POST, endpoint, action);
14702 #endif
14704 /******************************************************************************/
14705 #ifndef PALM_1
14706 SOAP_FMAC1
14708 SOAP_FMAC2
14709 soap_connect_command(struct soap *soap, int http_command, const char *endpoints, const char *action)
14710 { char *endpoint;
14711 const char *s;
14712 if (endpoints && (s = strchr(endpoints, ' ')))
14713 { endpoint = (char*)SOAP_MALLOC(soap, strlen(endpoints) + 1);
14714 for (;;)
14715 { strncpy(endpoint, endpoints, s - endpoints);
14716 endpoint[s - endpoints] = '\0';
14717 if (soap_try_connect_command(soap, http_command, endpoint, action) != SOAP_TCP_ERROR)
14718 break;
14719 if (!*s)
14720 break;
14721 soap->error = SOAP_OK;
14722 while (*s == ' ')
14723 s++;
14724 endpoints = s;
14725 s = strchr(endpoints, ' ');
14726 if (!s)
14727 s = endpoints + strlen(endpoints);
14729 SOAP_FREE(soap, endpoint);
14731 else
14732 soap_try_connect_command(soap, http_command, endpoints, action);
14733 return soap->error;
14735 #endif
14737 /******************************************************************************/
14738 #ifndef PALM_1
14739 static int
14740 soap_try_connect_command(struct soap *soap, int http_command, const char *endpoint, const char *action)
14741 { char host[sizeof(soap->host)];
14742 int port;
14743 size_t count;
14744 soap->error = SOAP_OK;
14745 strcpy(host, soap->host); /* save previous host name: if != then reconnect */
14746 port = soap->port; /* save previous port to compare */
14747 soap->status = http_command;
14748 soap_set_endpoint(soap, endpoint);
14749 #ifndef WITH_LEANER
14750 if (soap->fconnect)
14751 { if ((soap->error = soap->fconnect(soap, endpoint, soap->host, soap->port)))
14752 return soap->error;
14754 else
14755 #endif
14756 if (soap->fopen && *soap->host)
14757 { if (!soap->keep_alive || !soap_valid_socket(soap->socket) || strcmp(soap->host, host) || soap->port != port || !soap->fpoll || soap->fpoll(soap))
14758 { soap->keep_alive = 0; /* to force close */
14759 soap->omode &= ~SOAP_IO_UDP; /* to force close */
14760 soap_closesock(soap);
14761 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Connect/reconnect to host='%s' path='%s' port=%d\n", soap->host, soap->path, soap->port));
14762 #ifndef WITH_LEAN
14763 if (!strncmp(endpoint, "soap.udp:", 9))
14764 soap->omode |= SOAP_IO_UDP;
14765 #endif
14766 soap->socket = soap->fopen(soap, endpoint, soap->host, soap->port);
14767 if (soap->error)
14768 return soap->error;
14769 soap->keep_alive = ((soap->omode & SOAP_IO_KEEPALIVE) != 0);
14772 count = soap_count_attachments(soap);
14773 if (soap_begin_send(soap))
14774 return soap->error;
14775 if (http_command == SOAP_GET)
14776 { soap->mode &= ~SOAP_IO;
14777 soap->mode |= SOAP_IO_BUFFER;
14779 #ifndef WITH_NOHTTP
14780 soap->action = soap_strdup(soap, action);
14781 if ((soap->mode & SOAP_IO) != SOAP_IO_STORE && !(soap->mode & SOAP_ENC_XML) && endpoint)
14782 { unsigned int k = soap->mode;
14783 soap->mode &= ~(SOAP_IO | SOAP_ENC_ZLIB);
14784 if ((k & SOAP_IO) != SOAP_IO_FLUSH)
14785 soap->mode |= SOAP_IO_BUFFER;
14786 if ((soap->error = soap->fpost(soap, endpoint, soap->host, soap->port, soap->path, action, count)))
14787 return soap->error;
14788 #ifndef WITH_LEANER
14789 if ((k & SOAP_IO) == SOAP_IO_CHUNK)
14790 { if (soap_flush(soap))
14791 return soap->error;
14793 #endif
14794 soap->mode = k;
14796 if (http_command == SOAP_GET)
14797 return soap_end_send(soap);
14798 #endif
14799 return SOAP_OK;
14801 #endif
14803 /******************************************************************************/
14804 #ifndef WITH_LEAN
14805 SOAP_FMAC1
14806 char*
14807 SOAP_FMAC2
14808 soap_s2base64(struct soap *soap, const unsigned char *s, char *t, int n)
14809 { register int i;
14810 register unsigned long m;
14811 register char *p;
14812 if (!t)
14813 t = (char*)soap_malloc(soap, (n + 2) / 3 * 4 + 1);
14814 if (!t)
14815 return NULL;
14816 p = t;
14817 t[0] = '\0';
14818 if (!s)
14819 return p;
14820 for (; n > 2; n -= 3, s += 3)
14821 { m = s[0];
14822 m = (m << 8) | s[1];
14823 m = (m << 8) | s[2];
14824 for (i = 4; i > 0; m >>= 6)
14825 t[--i] = soap_base64o[m & 0x3F];
14826 t += 4;
14828 t[0] = '\0';
14829 if (n > 0)
14830 { m = 0;
14831 for (i = 0; i < n; i++)
14832 m = (m << 8) | *s++;
14833 for (; i < 3; i++)
14834 m <<= 8;
14835 for (i++; i > 0; m >>= 6)
14836 t[--i] = soap_base64o[m & 0x3F];
14837 for (i = 3; i > n; i--)
14838 t[i] = '=';
14839 t[4] = '\0';
14841 return p;
14843 #endif
14845 /******************************************************************************/
14846 #ifndef WITH_LEAN
14847 SOAP_FMAC1
14848 const char*
14849 SOAP_FMAC2
14850 soap_base642s(struct soap *soap, const char *s, char *t, size_t l, int *n)
14851 { register int i, j, c;
14852 register unsigned long m;
14853 register const char *p;
14854 if (!s || !*s)
14855 { if (n)
14856 *n = 0;
14857 if (soap->error)
14858 return NULL;
14859 return SOAP_NON_NULL;
14861 if (!t)
14862 { l = (strlen(s) + 3) / 4 * 3;
14863 t = (char*)soap_malloc(soap, l);
14865 if (!t)
14866 return NULL;
14867 p = t;
14868 if (n)
14869 *n = 0;
14870 for (;;)
14871 { for (i = 0; i < SOAP_BLKLEN; i++)
14872 { m = 0;
14873 j = 0;
14874 while (j < 4)
14875 { c = *s++;
14876 if (c == '=' || !c)
14877 { i *= 3;
14878 switch (j)
14879 { case 2:
14880 *t++ = (char)((m >> 4) & 0xFF);
14881 i++;
14882 break;
14883 case 3:
14884 *t++ = (char)((m >> 10) & 0xFF);
14885 *t++ = (char)((m >> 2) & 0xFF);
14886 i += 2;
14888 if (n)
14889 *n += i;
14890 return p;
14892 c -= '+';
14893 if (c >= 0 && c <= 79)
14894 { int b = soap_base64i[c];
14895 if (b >= 64)
14896 { soap->error = SOAP_TYPE;
14897 return NULL;
14899 m = (m << 6) + b;
14900 j++;
14902 else if (!soap_blank(c + '+'))
14903 { soap->error = SOAP_TYPE;
14904 return NULL;
14907 *t++ = (char)((m >> 16) & 0xFF);
14908 *t++ = (char)((m >> 8) & 0xFF);
14909 *t++ = (char)(m & 0xFF);
14910 if (l < 3)
14911 { if (n)
14912 *n += i;
14913 return p;
14915 l -= 3;
14917 if (n)
14918 *n += 3 * SOAP_BLKLEN;
14921 #endif
14923 /******************************************************************************/
14924 #ifndef WITH_LEAN
14925 SOAP_FMAC1
14926 char*
14927 SOAP_FMAC2
14928 soap_s2hex(struct soap *soap, const unsigned char *s, char *t, int n)
14929 { register char *p;
14930 if (!t)
14931 t = (char*)soap_malloc(soap, 2 * n + 1);
14932 if (!t)
14933 return NULL;
14934 p = t;
14935 t[0] = '\0';
14936 if (s)
14937 { for (; n > 0; n--)
14938 { register int m = *s++;
14939 *t++ = (char)((m >> 4) + (m > 159 ? 'a' - 10 : '0'));
14940 m &= 0x0F;
14941 *t++ = (char)(m + (m > 9 ? 'a' - 10 : '0'));
14944 *t++ = '\0';
14945 return p;
14947 #endif
14949 /******************************************************************************/
14950 #ifndef WITH_LEAN
14951 SOAP_FMAC1
14952 const char*
14953 SOAP_FMAC2
14954 soap_hex2s(struct soap *soap, const char *s, char *t, size_t l, int *n)
14955 { register const char *p;
14956 if (!s || !*s)
14957 { if (n)
14958 *n = 0;
14959 if (soap->error)
14960 return NULL;
14961 return SOAP_NON_NULL;
14963 if (!t)
14964 { l = strlen(s) / 2;
14965 t = (char*)soap_malloc(soap, l);
14967 if (!t)
14968 return NULL;
14969 p = t;
14970 while (l)
14971 { register int d1, d2;
14972 d1 = *s++;
14973 if (!d1)
14974 break;
14975 d2 = *s++;
14976 if (!d2)
14977 break;
14978 *t++ = ((d1 >= 'A' ? (d1 & 0x7) + 9 : d1 - '0') << 4) + (d2 >= 'A' ? (d2 & 0x7) + 9 : d2 - '0');
14979 l--;
14981 if (n)
14982 *n = (int)(t - p);
14983 return p;
14985 #endif
14987 /******************************************************************************/
14988 #ifndef WITH_NOHTTP
14989 #ifndef PALM_1
14990 SOAP_FMAC1
14992 SOAP_FMAC2
14993 soap_puthttphdr(struct soap *soap, int status, size_t count)
14994 { if (soap->status != SOAP_GET)
14995 { register const char *s = "text/xml; charset=utf-8";
14996 register int err = SOAP_OK;
14997 #ifndef WITH_LEANER
14998 register const char *r = NULL;
14999 #endif
15000 if ((status == SOAP_FILE || soap->status == SOAP_POST_FILE) && soap->http_content)
15001 s = soap->http_content;
15002 else if (status == SOAP_HTML)
15003 s = "text/html; charset=utf-8";
15004 else if (count || ((soap->omode & SOAP_IO) == SOAP_IO_CHUNK))
15005 { if (soap->version == 2)
15006 s = "application/soap+xml; charset=utf-8";
15008 #ifndef WITH_LEANER
15009 if (soap->mode & (SOAP_ENC_DIME | SOAP_ENC_MTOM))
15010 { if (soap->mode & SOAP_ENC_MTOM)
15011 { if (soap->version == 2)
15012 r = "application/soap+xml";
15013 else
15014 r = "text/xml";
15015 s = "application/xop+xml";
15017 else
15018 s = "application/dime";
15020 if ((soap->mode & SOAP_ENC_MIME) && soap->mime.boundary && strlen(soap->mime.boundary) + strlen(soap->mime.start ? soap->mime.start : SOAP_STR_EOS) < sizeof(soap->tmpbuf) - 80)
15021 { register const char *t = strchr(s, ';');
15022 sprintf(soap->tmpbuf, "multipart/related; charset=utf-8; boundary=\"%s\"; type=\"", soap->mime.boundary);
15023 if (t)
15024 { strncat(soap->tmpbuf, s, t - s);
15025 soap->tmpbuf[sizeof(soap->tmpbuf)-1] = '\0';
15027 else
15028 strcat(soap->tmpbuf, s);
15029 if (soap->mime.start)
15030 { strcat(soap->tmpbuf, "\"; start=\"");
15031 strcat(soap->tmpbuf, soap->mime.start);
15033 strcat(soap->tmpbuf, "\"");
15034 if (r)
15035 { strcat(soap->tmpbuf, "; start-info=\"");
15036 strcat(soap->tmpbuf, r);
15037 strcat(soap->tmpbuf, "\"");
15039 s = soap->tmpbuf;
15041 else if (status == SOAP_OK && soap->action && strlen(soap->action) < sizeof(soap->tmpbuf) - 80)
15042 { sprintf(soap->tmpbuf, "%s; action=\"%s\"", s, soap->action);
15043 s = soap->tmpbuf;
15045 #endif
15046 if (s && (err = soap->fposthdr(soap, "Content-Type", s)))
15047 return err;
15048 #ifdef WITH_ZLIB
15049 if ((soap->omode & SOAP_ENC_ZLIB))
15051 #ifdef WITH_GZIP
15052 err = soap->fposthdr(soap, "Content-Encoding", soap->zlib_out == SOAP_ZLIB_DEFLATE ? "deflate" : "gzip");
15053 #else
15054 err = soap->fposthdr(soap, "Content-Encoding", "deflate");
15055 #endif
15056 if (err)
15057 return err;
15059 #endif
15060 #ifndef WITH_LEANER
15061 if ((soap->omode & SOAP_IO) == SOAP_IO_CHUNK)
15062 err = soap->fposthdr(soap, "Transfer-Encoding", "chunked");
15063 else
15064 #endif
15065 if (s)
15066 { sprintf(soap->tmpbuf, "%lu", (unsigned long)count);
15067 err = soap->fposthdr(soap, "Content-Length", soap->tmpbuf);
15069 if (err)
15070 return err;
15072 return soap->fposthdr(soap, "Connection", soap->keep_alive ? "keep-alive" : "close");
15074 #endif
15075 #endif
15077 /******************************************************************************/
15078 #ifndef WITH_LEAN
15079 static const char*
15080 soap_set_validation_fault(struct soap *soap, const char *s, const char *t)
15081 { if (*soap->tag)
15082 sprintf(soap->msgbuf, "Validation constraint violation: %s%s in element '%s'", s, t?t:SOAP_STR_EOS, soap->tag);
15083 else
15084 sprintf(soap->msgbuf, "Validation constraint violation: %s%s", s, t?t:SOAP_STR_EOS);
15085 return soap->msgbuf;
15087 #endif
15089 /******************************************************************************/
15090 #ifndef PALM_1
15091 SOAP_FMAC1
15092 void
15093 SOAP_FMAC2
15094 soap_set_fault(struct soap *soap)
15095 { const char **c = soap_faultcode(soap);
15096 const char **s = soap_faultstring(soap);
15097 if (soap->fseterror)
15098 soap->fseterror(soap, c, s);
15099 if (!*c)
15100 { if (soap->version == 2)
15101 *c = "SOAP-ENV:Sender";
15102 else
15103 *c = "SOAP-ENV:Client";
15105 if (*s)
15106 return;
15107 switch (soap->error)
15109 #ifndef WITH_LEAN
15110 case SOAP_CLI_FAULT:
15111 *s = "Client fault";
15112 break;
15113 case SOAP_SVR_FAULT:
15114 *s = "Server fault";
15115 break;
15116 case SOAP_TAG_MISMATCH:
15117 *s = soap_set_validation_fault(soap, "tag name or namespace mismatch", NULL);
15118 break;
15119 case SOAP_TYPE:
15120 *s = soap_set_validation_fault(soap, "data type mismatch ", soap->type);
15121 break;
15122 case SOAP_SYNTAX_ERROR:
15123 *s = "Well-formedness violation";
15124 break;
15125 case SOAP_NO_TAG:
15126 *s = "No XML root element";
15127 break;
15128 case SOAP_MUSTUNDERSTAND:
15129 *c = "SOAP-ENV:MustUnderstand";
15130 sprintf(soap->msgbuf, "The data in element '%s' must be understood but cannot be handled", soap->tag);
15131 *s = soap->msgbuf;
15132 break;
15133 case SOAP_VERSIONMISMATCH:
15134 *c = "SOAP-ENV:VersionMismatch";
15135 *s = "Invalid SOAP message or SOAP version mismatch";
15136 break;
15137 case SOAP_DATAENCODINGUNKNOWN:
15138 *c = "SOAP-ENV:DataEncodingUnknown";
15139 *s = "Unsupported SOAP data encoding";
15140 break;
15141 case SOAP_NAMESPACE:
15142 *s = soap_set_validation_fault(soap, "namespace error", NULL);
15143 break;
15144 case SOAP_USER_ERROR:
15145 *s = "User error";
15146 break;
15147 case SOAP_FATAL_ERROR:
15148 *s = "Fatal error";
15149 break;
15150 case SOAP_NO_METHOD:
15151 sprintf(soap->msgbuf, "Method '%s' not implemented: method name or namespace not recognized", soap->tag);
15152 *s = soap->msgbuf;
15153 break;
15154 case SOAP_NO_DATA:
15155 *s = "Data required for operation";
15156 break;
15157 case SOAP_GET_METHOD:
15158 *s = "HTTP GET method not implemented";
15159 break;
15160 case SOAP_PUT_METHOD:
15161 *s = "HTTP PUT method not implemented";
15162 break;
15163 case SOAP_HTTP_METHOD:
15164 *s = "HTTP method not implemented";
15165 break;
15166 case SOAP_EOM:
15167 *s = "Out of memory";
15168 break;
15169 case SOAP_MOE:
15170 *s = "Memory overflow or memory corruption error";
15171 break;
15172 case SOAP_HDR:
15173 *s = "Header line too long";
15174 break;
15175 case SOAP_IOB:
15176 *s = "Array index out of bounds";
15177 break;
15178 case SOAP_NULL:
15179 *s = soap_set_validation_fault(soap, "nil not allowed", NULL);
15180 break;
15181 case SOAP_DUPLICATE_ID:
15182 *s = soap_set_validation_fault(soap, "multiple definitions of id ", soap->id);
15183 if (soap->version == 2)
15184 *soap_faultsubcode(soap) = "SOAP-ENC:DuplicateID";
15185 break;
15186 case SOAP_MISSING_ID:
15187 *s = soap_set_validation_fault(soap, "missing id for ref ", soap->id);
15188 if (soap->version == 2)
15189 *soap_faultsubcode(soap) = "SOAP-ENC:MissingID";
15190 break;
15191 case SOAP_HREF:
15192 *s = soap_set_validation_fault(soap, "incompatible object type ref/id pair ", soap->id);
15193 break;
15194 case SOAP_FAULT:
15195 break;
15196 #ifndef WITH_NOIO
15197 case SOAP_UDP_ERROR:
15198 *s = "Message too large for UDP packet";
15199 break;
15200 case SOAP_TCP_ERROR:
15201 *s = tcp_error(soap);
15202 break;
15203 #endif
15204 case SOAP_HTTP_ERROR:
15205 *s = "An HTTP processing error occurred";
15206 break;
15207 case SOAP_SSL_ERROR:
15208 #ifdef WITH_OPENSSL
15209 *s = "SSL/TLS error";
15210 #else
15211 *s = "OpenSSL not installed: recompile with -DWITH_OPENSSL";
15212 #endif
15213 break;
15214 case SOAP_PLUGIN_ERROR:
15215 *s = "Plugin registry error";
15216 break;
15217 case SOAP_DIME_ERROR:
15218 *s = "DIME format error";
15219 break;
15220 case SOAP_DIME_HREF:
15221 *s = "DIME href to missing attachment";
15222 break;
15223 case SOAP_DIME_MISMATCH:
15224 *s = "DIME version/transmission error";
15225 break;
15226 case SOAP_DIME_END:
15227 *s = "End of DIME error";
15228 break;
15229 case SOAP_MIME_ERROR:
15230 *s = "MIME format error";
15231 break;
15232 case SOAP_MIME_HREF:
15233 *s = "MIME href to missing attachment";
15234 break;
15235 case SOAP_MIME_END:
15236 *s = "End of MIME error";
15237 break;
15238 case SOAP_ZLIB_ERROR:
15239 #ifdef WITH_ZLIB
15240 sprintf(soap->msgbuf, "Zlib/gzip error: '%s'", soap->d_stream->msg?soap->d_stream->msg:SOAP_STR_EOS);
15241 *s = soap->msgbuf;
15242 #else
15243 *s = "Zlib/gzip not installed for (de)compression: recompile with -DWITH_GZIP";
15244 #endif
15245 break;
15246 case SOAP_REQUIRED:
15247 *s = soap_set_validation_fault(soap, "missing required attribute", NULL);
15248 break;
15249 case SOAP_PROHIBITED:
15250 *s = soap_set_validation_fault(soap, "prohibited attribute present", NULL);
15251 break;
15252 case SOAP_OCCURS:
15253 *s = soap_set_validation_fault(soap, "occurrence violation", NULL);
15254 break;
15255 case SOAP_LENGTH:
15256 *s = soap_set_validation_fault(soap, "content range or length violation", NULL);
15257 break;
15258 case SOAP_FD_EXCEEDED:
15259 *s = "Maximum number of open connections was reached (no define HAVE_POLL): increase FD_SETSIZE";
15260 break;
15261 case SOAP_STOP:
15262 *s = "Stopped: no response to be sent or received (informative)";
15263 break;
15264 #endif
15265 case SOAP_EOF:
15266 #ifndef WITH_NOIO
15267 strcpy(soap->msgbuf, soap_strerror(soap));
15268 #ifndef WITH_LEAN
15269 if (strlen(soap->msgbuf) + 25 < sizeof(soap->msgbuf))
15270 { memmove(soap->msgbuf + 25, soap->msgbuf, strlen(soap->msgbuf) + 1);
15271 memcpy(soap->msgbuf, "End of file or no input: ", 25);
15273 #endif
15274 *s = soap->msgbuf;
15275 break;
15276 #else
15277 *s = "End of file or no input";
15278 break;
15279 #endif
15280 default:
15281 #ifndef WITH_NOHTTP
15282 #ifndef WITH_LEAN
15283 if (soap->error > 200 && soap->error < 600)
15284 { sprintf(soap->msgbuf, "HTTP Error: %d %s", soap->error, http_error(soap, soap->error));
15285 *s = soap->msgbuf;
15287 else
15288 #endif
15289 #endif
15290 { sprintf(soap->msgbuf, "Error %d", soap->error);
15291 *s = soap->msgbuf;
15295 #endif
15297 /******************************************************************************/
15298 #ifndef PALM_1
15299 SOAP_FMAC1
15301 SOAP_FMAC2
15302 soap_send_fault(struct soap *soap)
15303 { register int status = soap->error;
15304 if (status == SOAP_STOP)
15305 return soap_closesock(soap);
15306 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Sending back fault struct for error code %d\n", soap->error));
15307 soap->keep_alive = 0; /* to terminate connection */
15308 soap_set_fault(soap);
15309 if (soap->error < 200 && soap->error != SOAP_FAULT)
15310 soap->header = NULL;
15311 if (status != SOAP_EOF || (!soap->recv_timeout && !soap->send_timeout))
15312 { int r = 1;
15313 #ifndef WITH_NOIO
15314 if (soap->fpoll && soap->fpoll(soap))
15315 r = 0;
15316 #ifndef WITH_LEAN
15317 else if (soap_valid_socket(soap->socket))
15318 { r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_SND, 0);
15319 if (r > 0)
15320 { if (!(r & SOAP_TCP_SELECT_SND)
15321 || ((r & SOAP_TCP_SELECT_RCV)
15322 && recv(soap->socket, soap->tmpbuf, 1, MSG_PEEK) < 0))
15323 r = 0;
15326 #endif
15327 #endif
15328 if (r > 0)
15329 { soap->error = SOAP_OK;
15330 soap_serializeheader(soap);
15331 soap_serializefault(soap);
15332 soap_begin_count(soap);
15333 if (soap->mode & SOAP_IO_LENGTH)
15334 { soap_envelope_begin_out(soap);
15335 soap_putheader(soap);
15336 soap_body_begin_out(soap);
15337 soap_putfault(soap);
15338 soap_body_end_out(soap);
15339 soap_envelope_end_out(soap);
15341 soap_end_count(soap);
15342 if (soap_response(soap, status)
15343 || soap_envelope_begin_out(soap)
15344 || soap_putheader(soap)
15345 || soap_body_begin_out(soap)
15346 || soap_putfault(soap)
15347 || soap_body_end_out(soap)
15348 || soap_envelope_end_out(soap))
15349 return soap_closesock(soap);
15350 soap_end_send(soap);
15353 soap->error = status;
15354 return soap_closesock(soap);
15356 #endif
15358 /******************************************************************************/
15359 #ifndef PALM_1
15360 SOAP_FMAC1
15362 SOAP_FMAC2
15363 soap_recv_fault(struct soap *soap, int check)
15364 { register int status = soap->error;
15365 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Check if receiving SOAP Fault\n"));
15366 if (!check)
15367 { /* try getfault when no tag or tag mismatched at level 2, otherwise ret */
15368 if (soap->error != SOAP_NO_TAG
15369 && (soap->error != SOAP_TAG_MISMATCH || soap->level != 2))
15370 return soap->error;
15372 soap->error = SOAP_OK;
15373 if (soap_getfault(soap))
15374 { /* check flag set: check if SOAP Fault is present, if not just return */
15375 if (check && soap->error == SOAP_TAG_MISMATCH && soap->level == 2)
15376 return soap->error = SOAP_OK;
15377 DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Error: soap_get_soapfault() failed. Is this a SOAP message at all?\n"));
15378 *soap_faultcode(soap) = (soap->version == 2 ? "SOAP-ENV:Sender" : "SOAP-ENV:Client");
15379 soap->error = status;
15380 soap_set_fault(soap);
15382 else
15383 { register const char *s = *soap_faultcode(soap);
15384 if (!soap_match_tag(soap, s, "SOAP-ENV:Server") || !soap_match_tag(soap, s, "SOAP-ENV:Receiver"))
15385 status = SOAP_SVR_FAULT;
15386 else if (!soap_match_tag(soap, s, "SOAP-ENV:Client") || !soap_match_tag(soap, s, "SOAP-ENV:Sender"))
15387 status = SOAP_CLI_FAULT;
15388 else if (!soap_match_tag(soap, s, "SOAP-ENV:MustUnderstand"))
15389 status = SOAP_MUSTUNDERSTAND;
15390 else if (!soap_match_tag(soap, s, "SOAP-ENV:VersionMismatch"))
15391 status = SOAP_VERSIONMISMATCH;
15392 else
15393 { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Received SOAP Fault code %s\n", s));
15394 status = SOAP_FAULT;
15396 if (!soap_body_end_in(soap))
15397 soap_envelope_end_in(soap);
15399 soap_end_recv(soap);
15400 soap->error = status;
15401 return soap_closesock(soap);
15403 #endif
15405 /******************************************************************************/
15406 #ifndef WITH_NOHTTP
15407 #ifndef PALM_1
15408 SOAP_FMAC1
15410 SOAP_FMAC2
15411 soap_send_empty_response(struct soap *soap, int httpstatuscode)
15412 { register soap_mode m = soap->omode;
15413 soap->count = 0;
15414 if ((m & SOAP_IO) == SOAP_IO_CHUNK)
15415 soap->omode = (m & ~SOAP_IO) | SOAP_IO_BUFFER;
15416 if (soap_response(soap, httpstatuscode) || soap_end_send(soap))
15417 { soap->omode = m;
15418 return soap_closesock(soap);
15420 soap->omode = m;
15421 return soap->error = SOAP_STOP; /* stops the server's response */
15423 #endif
15424 #endif
15426 /******************************************************************************/
15427 #ifndef WITH_NOHTTP
15428 #ifndef PALM_1
15429 SOAP_FMAC1
15431 SOAP_FMAC2
15432 soap_recv_empty_response(struct soap *soap)
15433 { if (!soap_begin_recv(soap))
15434 soap_end_recv(soap);
15435 else if (soap->error == SOAP_NO_DATA || soap->error == 202)
15436 soap->error = SOAP_OK;
15437 return soap_closesock(soap);
15439 #endif
15440 #endif
15442 /******************************************************************************/
15443 #ifndef WITH_NOIO
15444 #ifndef PALM_1
15445 static const char*
15446 soap_strerror(struct soap *soap)
15447 { register int err = soap->errnum;
15448 if (err)
15450 #ifndef WIN32
15451 # ifdef HAVE_STRERROR_R
15452 strerror_r(err, soap->msgbuf, sizeof(soap->msgbuf));
15453 # else
15454 return strerror(err);
15455 # endif
15456 #else
15457 #ifndef UNDER_CE
15458 DWORD len;
15459 *soap->msgbuf = '\0';
15460 len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)soap->msgbuf, (DWORD)sizeof(soap->msgbuf), NULL);
15461 #else
15462 DWORD i, len;
15463 *soap->msgbuf = '\0';
15464 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, (LPTSTR)soap->msgbuf, (DWORD)(sizeof(soap->msgbuf)/sizeof(TCHAR)), NULL);
15465 for (i = 0; i <= len; i++)
15466 { if (((TCHAR*)soap->msgbuf)[i] < 0x80)
15467 soap->msgbuf[i] = (char)((TCHAR*)soap->msgbuf)[i];
15468 else
15469 soap->msgbuf[i] = '?';
15471 #endif
15472 #endif
15474 else
15475 { char *s = soap->msgbuf;
15476 #ifndef WITH_LEAN
15477 int rt = soap->recv_timeout, st = soap->send_timeout;
15478 int ru = ' ', su = ' ';
15479 #endif
15480 strcpy(s, "Operation interrupted or timed out");
15481 #ifndef WITH_LEAN
15482 if (rt < 0)
15483 { rt = -rt;
15484 ru = 'u';
15486 if (st < 0)
15487 { st = -st;
15488 su = 'u';
15490 if (rt)
15491 sprintf(s + strlen(s), " (%d%cs receive delay)", rt, ru);
15492 if (st)
15493 sprintf(s + strlen(s), " (%d%cs send delay)", st, su);
15494 #endif
15496 return soap->msgbuf;
15498 #endif
15499 #endif
15501 /******************************************************************************/
15502 #ifndef PALM_2
15503 static int
15504 soap_set_error(struct soap *soap, const char *faultcode, const char *faultsubcodeQName, const char *faultstring, const char *faultdetailXML, int soaperror)
15505 { *soap_faultcode(soap) = faultcode;
15506 if (faultsubcodeQName)
15507 *soap_faultsubcode(soap) = faultsubcodeQName;
15508 *soap_faultstring(soap) = faultstring;
15509 if (faultdetailXML && *faultdetailXML)
15510 { register const char **s = soap_faultdetail(soap);
15511 if (s)
15512 *s = faultdetailXML;
15514 return soap->error = soaperror;
15516 #endif
15518 /******************************************************************************/
15519 #ifndef PALM_2
15520 SOAP_FMAC1
15522 SOAP_FMAC2
15523 soap_set_sender_error(struct soap *soap, const char *faultstring, const char *faultdetailXML, int soaperror)
15524 { return soap_set_error(soap, soap->version == 2 ? "SOAP-ENV:Sender" : "SOAP-ENV:Client", NULL, faultstring, faultdetailXML, soaperror);
15526 #endif
15528 /******************************************************************************/
15529 #ifndef PALM_2
15530 SOAP_FMAC1
15532 SOAP_FMAC2
15533 soap_set_receiver_error(struct soap *soap, const char *faultstring, const char *faultdetailXML, int soaperror)
15534 { return soap_set_error(soap, soap->version == 2 ? "SOAP-ENV:Receiver" : "SOAP-ENV:Server", NULL, faultstring, faultdetailXML, soaperror);
15536 #endif
15538 /******************************************************************************/
15539 #ifndef PALM_2
15540 static int
15541 soap_copy_fault(struct soap *soap, const char *faultcode, const char *faultsubcodeQName, const char *faultstring, const char *faultdetailXML)
15542 { char *r = NULL, *s = NULL, *t = NULL;
15543 if (faultsubcodeQName)
15544 r = soap_strdup(soap, faultsubcodeQName);
15545 if (faultstring)
15546 s = soap_strdup(soap, faultstring);
15547 if (faultdetailXML)
15548 t = soap_strdup(soap, faultdetailXML);
15549 return soap_set_error(soap, faultcode, r, s, t, SOAP_FAULT);
15551 #endif
15553 /******************************************************************************/
15554 #ifndef PALM_2
15555 SOAP_FMAC1
15557 SOAP_FMAC2
15558 soap_sender_fault(struct soap *soap, const char *faultstring, const char *faultdetailXML)
15559 { return soap_sender_fault_subcode(soap, NULL, faultstring, faultdetailXML);
15561 #endif
15563 /******************************************************************************/
15564 #ifndef PALM_2
15565 SOAP_FMAC1
15567 SOAP_FMAC2
15568 soap_sender_fault_subcode(struct soap *soap, const char *faultsubcodeQName, const char *faultstring, const char *faultdetailXML)
15569 { return soap_copy_fault(soap, soap->version == 2 ? "SOAP-ENV:Sender" : "SOAP-ENV:Client", faultsubcodeQName, faultstring, faultdetailXML);
15571 #endif
15573 /******************************************************************************/
15574 #ifndef PALM_2
15575 SOAP_FMAC1
15577 SOAP_FMAC2
15578 soap_receiver_fault(struct soap *soap, const char *faultstring, const char *faultdetailXML)
15579 { return soap_receiver_fault_subcode(soap, NULL, faultstring, faultdetailXML);
15581 #endif
15583 /******************************************************************************/
15584 #ifndef PALM_2
15585 SOAP_FMAC1
15587 SOAP_FMAC2
15588 soap_receiver_fault_subcode(struct soap *soap, const char *faultsubcodeQName, const char *faultstring, const char *faultdetailXML)
15589 { return soap_copy_fault(soap, soap->version == 2 ? "SOAP-ENV:Receiver" : "SOAP-ENV:Server", faultsubcodeQName, faultstring, faultdetailXML);
15591 #endif
15593 /******************************************************************************/
15594 #ifndef PALM_2
15595 #ifndef WITH_NOSTDLIB
15596 SOAP_FMAC1
15597 void
15598 SOAP_FMAC2
15599 soap_print_fault(struct soap *soap, FILE *fd)
15600 { if (soap_check_state(soap))
15601 fprintf(fd, "Error: soap struct state not initialized\n");
15602 else if (soap->error)
15603 { const char *c, *v = NULL, *s, **d;
15604 d = soap_faultcode(soap);
15605 if (!*d)
15606 soap_set_fault(soap);
15607 c = *d;
15608 if (soap->version == 2)
15609 v = *soap_faultsubcode(soap);
15610 s = *soap_faultstring(soap);
15611 d = soap_faultdetail(soap);
15612 fprintf(fd, "%s%d fault: %s [%s]\n\"%s\"\nDetail: %s\n", soap->version ? "SOAP 1." : "Error ", soap->version ? (int)soap->version : soap->error, c, v ? v : "no subcode", s ? s : "[no reason]", d && *d ? *d : "[no detail]");
15615 #endif
15616 #endif
15618 /******************************************************************************/
15619 #ifdef __cplusplus
15620 #ifndef WITH_LEAN
15621 #ifndef WITH_NOSTDLIB
15622 SOAP_FMAC1
15623 void
15624 SOAP_FMAC2
15625 soap_stream_fault(struct soap *soap, std::ostream& os)
15626 { if (soap_check_state(soap))
15627 os << "Error: soap struct state not initialized\n";
15628 else if (soap->error)
15629 { const char *c, *v = NULL, *s, **d;
15630 d = soap_faultcode(soap);
15631 if (!*d)
15632 soap_set_fault(soap);
15633 c = *d;
15634 if (soap->version == 2)
15635 v = *soap_faultsubcode(soap);
15636 s = *soap_faultstring(soap);
15637 d = soap_faultdetail(soap);
15638 os << (soap->version ? "SOAP 1." : "Error ")
15639 << (soap->version ? (int)soap->version : soap->error)
15640 << " fault: " << c
15641 << "[" << (v ? v : "no subcode") << "]"
15642 << std::endl
15643 << "\"" << (s ? s : "[no reason]") << "\""
15644 << std::endl
15645 << "Detail: " << (d && *d ? *d : "[no detail]")
15646 << std::endl;
15649 #endif
15650 #endif
15651 #endif
15653 /******************************************************************************/
15654 #ifndef WITH_LEAN
15655 #ifndef WITH_NOSTDLIB
15656 SOAP_FMAC1
15657 char*
15658 SOAP_FMAC2
15659 soap_sprint_fault(struct soap *soap, char *buf, size_t len)
15660 { if (soap_check_state(soap))
15661 strncpy(buf, "Error: soap struct not initialized", len);
15662 else if (soap->error)
15663 { const char *c, *v = NULL, *s, **d;
15664 d = soap_faultcode(soap);
15665 if (!*d)
15666 soap_set_fault(soap);
15667 c = *d;
15668 if (soap->version == 2)
15669 v = *soap_faultsubcode(soap);
15670 s = *soap_faultstring(soap);
15671 d = soap_faultdetail(soap);
15672 #ifdef HAVE_SNPRINTF
15673 # ifdef WIN32
15674 _snprintf
15675 # else
15676 snprintf
15677 # endif
15678 (buf, len, "%s%d fault: %s [%s]\n\"%s\"\nDetail: %s\n", soap->version ? "SOAP 1." : "Error ", soap->version ? (int)soap->version : soap->error, c, v ? v : "no subcode", s ? s : "[no reason]", d && *d ? *d : "[no detail]");
15679 #else
15680 if (len > 40 + (v ? strlen(v) : 0) + (s ? strlen(s) : 0) + (d && *d ? strlen(*d) : 0))
15681 sprintf(buf, "%s%d fault: %s [%s]\n\"%s\"\nDetail: %s\n", soap->version ? "SOAP 1." : "Error ", soap->version ? (int)soap->version : soap->error, c, v ? v : "no subcode", s ? s : "[no reason]", d && *d ? *d : "[no detail]");
15682 else if (len > 40)
15683 sprintf(buf, "%s%d fault: %s\n", soap->version ? "SOAP 1." : "Error ", soap->version ? (int)soap->version : soap->error, c);
15684 else
15685 buf[0] = '\0';
15686 #endif
15688 return buf;
15690 #endif
15691 #endif
15693 /******************************************************************************/
15694 #ifndef PALM_1
15695 #ifndef WITH_NOSTDLIB
15696 SOAP_FMAC1
15697 void
15698 SOAP_FMAC2
15699 soap_print_fault_location(struct soap *soap, FILE *fd)
15701 #ifndef WITH_LEAN
15702 int i, j, c1, c2;
15703 if (soap->error && soap->error != SOAP_STOP && soap->bufidx <= soap->buflen && soap->buflen > 0 && soap->buflen <= SOAP_BUFLEN)
15704 { i = (int)soap->bufidx - 1;
15705 if (i <= 0)
15706 i = 0;
15707 c1 = soap->buf[i];
15708 soap->buf[i] = '\0';
15709 if ((int)soap->buflen >= i + 1024)
15710 j = i + 1023;
15711 else
15712 j = (int)soap->buflen - 1;
15713 c2 = soap->buf[j];
15714 soap->buf[j] = '\0';
15715 fprintf(fd, "%s%c\n<!-- ** HERE ** -->\n", soap->buf, c1);
15716 if (soap->bufidx < soap->buflen)
15717 fprintf(fd, "%s\n", soap->buf + soap->bufidx);
15718 soap->buf[i] = c1;
15719 soap->buf[j] = c2;
15721 #endif
15723 #endif
15724 #endif
15726 /******************************************************************************/
15727 #ifndef PALM_1
15728 SOAP_FMAC1
15730 SOAP_FMAC2
15731 soap_register_plugin_arg(struct soap *soap, int (*fcreate)(struct soap*, struct soap_plugin*, void*), void *arg)
15732 { register struct soap_plugin *p;
15733 register int r;
15734 if (!(p = (struct soap_plugin*)SOAP_MALLOC(soap, sizeof(struct soap_plugin))))
15735 return soap->error = SOAP_EOM;
15736 p->id = NULL;
15737 p->data = NULL;
15738 p->fcopy = NULL;
15739 p->fdelete = NULL;
15740 r = fcreate(soap, p, arg);
15741 if (!r && p->fdelete)
15742 { p->next = soap->plugins;
15743 soap->plugins = p;
15744 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Registered '%s' plugin\n", p->id));
15745 return SOAP_OK;
15747 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not register plugin '%s': plugin returned error %d (or fdelete callback not set)\n", p->id?p->id:"?", r));
15748 SOAP_FREE(soap, p);
15749 return r;
15751 #endif
15753 /******************************************************************************/
15754 #ifndef PALM_1
15755 static void *
15756 fplugin(struct soap *soap, const char *id)
15757 { register struct soap_plugin *p;
15758 for (p = soap->plugins; p; p = p->next)
15759 if (p->id == id || !strcmp(p->id, id))
15760 return p->data;
15761 return NULL;
15763 #endif
15765 /******************************************************************************/
15766 #ifndef PALM_2
15767 SOAP_FMAC1
15768 void *
15769 SOAP_FMAC2
15770 soap_lookup_plugin(struct soap *soap, const char *id)
15771 { return soap->fplugin(soap, id);
15773 #endif
15775 /******************************************************************************/
15776 #ifdef __cplusplus
15778 #endif
15780 /******************************************************************************\
15782 * C++ soap struct methods
15784 \******************************************************************************/
15786 #ifdef __cplusplus
15787 soap::soap()
15788 { soap_init(this);
15790 #endif
15792 /******************************************************************************/
15793 #ifdef __cplusplus
15794 soap::soap(soap_mode m)
15795 { soap_init1(this, m);
15797 #endif
15799 /******************************************************************************/
15800 #ifdef __cplusplus
15801 soap::soap(soap_mode im, soap_mode om)
15802 { soap_init2(this, im, om);
15804 #endif
15806 /******************************************************************************/
15807 #ifdef __cplusplus
15808 soap::soap(const struct soap& soap)
15809 { soap_copy_context(this, &soap);
15811 #endif
15813 /******************************************************************************/
15814 #ifdef __cplusplus
15815 soap::~soap()
15816 { soap_destroy(this);
15817 soap_end(this);
15818 soap_done(this);
15820 #endif
15822 /******************************************************************************/