Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
wap-appl.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * gw/wap-appl.c - wapbox application layer and push ota indication, response
59  * and confirmation primitive implementation.
60  *
61  * This module implements various indication and confirmation primitives and
62  * protocol mappings as defined in:
63  *
64  * WAP-189-PushOTA-20000217-a (hereafter called ota)
65  * WAP-200-WDP-20001212-a (wdp)
66  * WAP-248-UAProf-20011020-a (UAProf)
67  *
68  * Wapbox application layer itself is not a WAP Forum protocol.
69  *
70  * The application layer is reads events from its event queue, fetches the
71  * corresponding URLs and feeds back events to the WSP layer (pull).
72  *
73  * In addition, the layer forwards WSP events related to push to the module
74  * wap_push_ppg and wsp, implementing indications, responses and confirma-
75  * tions of ota.
76  *
77  * Note that push header encoding and decoding are divided two parts:
78  * first decoding and encoding numeric values and then packing these values
79  * into WSP format and unpacking them from WSP format. This module contains
80  * encoding part.
81  *
82  * Lars Wirzenius
83  */
84 
85 #include <string.h>
86 
87 #include "gwlib/gwlib.h"
88 #include "wmlscript/ws.h"
89 #include "xml_shared.h"
90 #include "wml_compiler.h"
91 #include "mime_decompiler.h"
92 #include "wap/wap.h"
93 #include "wap-appl.h"
94 #include "wap_push_ppg.h"
95 #include "wap/wsp_strings.h"
96 #include "wap/wsp_caps.h"
97 #include "wap/wsp.h"
98 #ifdef ENABLE_COOKIES
99 #include "wap/cookies.h"
100 #endif
101 #include "radius/radius_acct.h"
102 #include "wap-error.h"
103 #include "wap-maps.h"
104 
105 #define ENABLE_NOT_ACCEPTED
106 
107 /*
108  * Give the status the module:
109  *
110  * limbo
111  * not running at all
112  * running
113  * operating normally
114  * terminating
115  * waiting for operations to terminate, returning to limbo
116  */
118 
119 
120 /*
121  * The queue of incoming events.
122  */
123 static List *queue = NULL;
124 
125 
126 /*
127  * HTTP caller identifier for application layer.
128  */
129 static HTTPCaller *caller = NULL;
130 
131 
132 /*
133  * Number of currently running HTTP fetching threads.
134  */
135 static Counter *fetches = NULL;
136 
137 
138 /*
139  * Charsets supported by WML compiler, queried from wml_compiler.
140  */
141 static List *charsets = NULL;
142 
143 struct content {
149 };
150 
151 
152 /*
153  * A mapping from HTTP request identifiers to information about the request.
154  */
155 struct request_data {
161  long x_wap_tod;
164 };
165 
166 
167 /*
168  * WSP smart error messaging
169  */
170 extern int wsp_smart_errors;
171 extern Octstr *device_home;
172 
173 /*
174  * Defines if PPG is running in wapbox instance
175  */
176 static int have_ppg = 0;
177 
178 /*
179  * Private functions.
180  */
181 
182 static void main_thread(void *);
183 static void start_fetch(WAPEvent *);
184 static void return_replies_thread(void *);
185 
186 static void dev_null(const char *data, size_t len, void *context);
187 
188 static Octstr *convert_wml_to_wmlc(struct content *content);
190 /* DAVI: To-Do static Octstr *convert_multipart_mixed(struct content *content); */
192 /* DAVI: To-Do static Octstr *deconvert_mms_message(struct content *content); */
193 static List *negotiate_capabilities(List *req_caps);
194 
195 static struct {
196  char *type;
197  char *result_type;
198  Octstr *(*convert)(struct content *);
199 } converters[] = {
200  { "text/vnd.wap.wml",
201  "application/vnd.wap.wmlc",
203  { "text/vnd.wap.wmlscript",
204  "application/vnd.wap.wmlscriptc",
206 /* DAVI: To-Do
207  { "multipart/mixed",
208  "application/vnd.wap.multipart.mixed",
209  convert_multipart_mixed },
210 */
211 };
212 #define NUM_CONVERTERS ((long)(sizeof(converters) / sizeof(converters[0])))
213 
214 static struct {
215  char *type;
216  char *result_type;
217  Octstr *(*deconvert)(struct content *);
218 } deconverters[] = {
219  { "application/vnd.wap.multipart.form-data",
220  "multipart/form-data; boundary=kannel_boundary",
222 /* DAVI: To-Do
223  { "application/vnd.wap.mms-message",
224  "multipart/related; type=application/smil; boundary=kannel_boundary; start=<t0>",
225  deconvert_mms_message },
226 */
227 };
228 #define NUM_DECONVERTERS ((long)(sizeof(deconverters) / sizeof(deconverters[0])))
229 
230 /*
231  * Following functions implement indications and conformations part of Push
232  * OTA protocol.
233  */
234 static void indicate_push_connection(WAPEvent *e);
235 static void indicate_push_disconnect(WAPEvent *e);
236 static void indicate_push_suspend(WAPEvent *e);
237 static void indicate_push_resume(WAPEvent *e);
238 static void confirm_push(WAPEvent *e);
239 static void indicate_push_abort(WAPEvent *e);
240 static void split_header_list(List **headers, List **new_headers, char *name);
241 static void check_application_headers(List **headers, List **app_headers);
242 static void decode_bearer_indication(List **headers, List **bearer_headers);
243 static void response_push_connection(WAPEvent *e);
244 
245 /***********************************************************************
246  * The public interface to the application layer.
247  */
248 
250 {
252  queue = gwlist_create();
253  fetches = counter_create();
254  gwlist_add_producer(queue);
256  charsets = wml_charsets();
257  caller = http_caller_create();
260 
261  if (cfg != NULL)
262  have_ppg = 1;
263  else
264  have_ppg = 0;
265 }
266 
267 
268 void wap_appl_shutdown(void)
269 {
272 
273  gwlist_remove_producer(queue);
275 
278 
279  wap_map_destroy();
281  http_caller_destroy(caller);
284  counter_destroy(fetches);
285 }
286 
287 
289 {
291  gwlist_produce(queue, event);
292 }
293 
294 
295 long wap_appl_get_load(void)
296 {
298  return counter_value(fetches) + gwlist_len(queue);
299 }
300 
301 
302 /***********************************************************************
303  * Private functions.
304  */
305 
306 /*
307  * When we have a push event, create ota indication or confirmation and send
308  * it to ppg module.
309  * Because Accept-Application and Bearer-Indication are optional, we cannot
310  * rely on them. We must ask ppg main module do we have an open push session
311  * for this initiator. Push is identified by push id.
312  * If there is no ppg configured, do not refer to ppg's sessions' list.
313  */
314 static void main_thread(void *arg)
315 {
316  WAPEvent *ind, *res;
317  long sid;
318  WAPAddrTuple *tuple;
319 
320  while (run_status == running && (ind = gwlist_consume(queue)) != NULL) {
321  switch (ind->type) {
322  case S_MethodInvoke_Ind:
323  res = wap_event_create(S_MethodInvoke_Res);
324  res->u.S_MethodInvoke_Res.server_transaction_id =
325  ind->u.S_MethodInvoke_Ind.server_transaction_id;
326  res->u.S_MethodInvoke_Res.session_id =
327  ind->u.S_MethodInvoke_Ind.session_id;
329  start_fetch(ind);
330  break;
331 
332  case S_Unit_MethodInvoke_Ind:
333  start_fetch(ind);
334  break;
335 
336  case S_Connect_Ind:
337  tuple = ind->u.S_Connect_Ind.addr_tuple;
340  } else {
341  res = wap_event_create(S_Connect_Res);
342  /* FIXME: Not yet used by WSP layer */
343  res->u.S_Connect_Res.server_headers = NULL;
344  res->u.S_Connect_Res.negotiated_capabilities =
345  negotiate_capabilities(ind->u.S_Connect_Ind.requested_capabilities);
346  res->u.S_Connect_Res.session_id =
347  ind->u.S_Connect_Ind.session_id;
349  }
350  wap_event_destroy(ind);
351  break;
352 
353  case S_Disconnect_Ind:
354  sid = ind->u.S_Disconnect_Ind.session_handle;
357  wap_event_destroy(ind);
358  break;
359 
360  case S_Suspend_Ind:
361  sid = ind->u.S_Suspend_Ind.session_id;
364  wap_event_destroy(ind);
365  break;
366 
367  case S_Resume_Ind:
368  sid = ind->u.S_Resume_Ind.session_id;
371  } else {
372  res = wap_event_create(S_Resume_Res);
373  res->u.S_Resume_Res.server_headers = NULL;
374  res->u.S_Resume_Res.session_id = ind->u.S_Resume_Ind.session_id;
376  }
377  wap_event_destroy(ind);
378  break;
379 
380  case S_MethodResult_Cnf:
381  wap_event_destroy(ind);
382  break;
383 
384  case S_ConfirmedPush_Cnf:
385  confirm_push(ind);
386  wap_event_destroy(ind);
387  break;
388 
389  case S_MethodAbort_Ind:
390  /* XXX Interrupt the fetch thread somehow */
391  wap_event_destroy(ind);
392  break;
393 
394  case S_PushAbort_Ind:
395  indicate_push_abort(ind);
396  wap_event_destroy(ind);
397  break;
398 
399  case Pom_Connect_Res:
401  wap_event_destroy(ind);
402  break;
403 
404  default:
405  panic(0, "WAP-APPL: Can't handle %s event",
406  wap_event_name(ind->type));
407  break;
408  } /* switch */
409  } /* while */
410 }
411 
412 
413 /*
414  * Tries to convert or compile a specific content-type to
415  * it's complementing one. It does not convert if the client has explicitely
416  * told us via Accept: header that a specific type is supported.
417  * Returns 1 if an convertion has been successfull,
418  * -1 if an convertion failed and 0 if no convertion routine
419  * was maching this content-type
420  */
421 static int convert_content(struct content *content, List *request_headers,
422  int allow_empty)
423 {
424  Octstr *new_body;
425  int failed = 0;
426  int i;
427 
428  for (i = 0; i < NUM_CONVERTERS; i++) {
429  if (octstr_str_compare(content->type, converters[i].type) == 0 &&
430  !http_type_accepted(request_headers, octstr_get_cstr(content->type))) {
431  debug("wap.convert",0,"WSP: Converting from <%s> to <%s>",
432  octstr_get_cstr(content->type), converters[i].result_type);
433  /*
434  * Note: if request is HEAD, body is empty and we still need to adapt
435  * content-type but we don't need to convert a 0 bytes body
436  */
437  if (allow_empty && octstr_len(content->body) == 0)
438  return 1;
439 
440  new_body = converters[i].convert(content);
441  if (new_body != NULL) {
442  long s = octstr_len(content->body);
443  octstr_destroy(content->body);
444  octstr_destroy(content->type);
445  content->body = new_body;
446  content->type = octstr_create(converters[i].result_type);
447  debug("wap.convert",0,"WSP: Content-type is "
448  "now <%s>, size %ld bytes (before: %ld bytes), content body is:",
449  converters[i].result_type, octstr_len(new_body), s);
450  octstr_dump(new_body, 0);
451  return 1;
452  }
453  debug("wap.convert",0,"WSP: Content convertion failed!");
454  failed = 1;
455  }
456  }
457 
458  return (failed ? -1 : 0);
459 }
460 
461 
462 /*
463  * Tries to deconvert or decompile a specific content-type to
464  * it's complementing one.
465  * Returns 1 if an deconvertion has been successfull,
466  * -1 if an deconvertion failed and 0 if no deconvertion routine
467  * was maching this content-type
468  */
469 static int deconvert_content(struct content *content)
470 {
471  Octstr *new_body;
472  int failed = 0;
473  int i;
474 
475  debug("wap.deconvert",0,"WSP deconvert: Trying to deconvert:");
476  octstr_dump(content->body, 0);
477  for (i = 0; i < NUM_DECONVERTERS; i++) {
478  if (octstr_str_compare(content->type, deconverters[i].type) == 0) {
479  debug("wap.deconvert",0,"WSP: Deconverting from <%s> to <%s>",
480  octstr_get_cstr(content->type),
481  deconverters[i].result_type);
482  new_body = deconverters[i].deconvert(content);
483  if (new_body != NULL) {
484  long s = octstr_len(content->body);
485  octstr_destroy(content->body);
486  octstr_destroy(content->type);
487  content->body = new_body;
489  debug("wap.convert",0,"WSP: Content-type is "
490  "now <%s>, size %ld bytes (before: %ld bytes), content body is:",
491  deconverters[i].result_type, octstr_len(new_body), s);
492  octstr_dump(new_body, 0);
493  return 1;
494  }
495  debug("wap.deconvert",0,"WSP: Content convertion failed!");
496  failed = 1;
497  }
498  }
499 
500  return (failed ? -1 : 0);
501 }
502 
503 
504 /* Add a header identifying our gateway version */
505 static void add_kannel_version(List *headers)
506 {
507  http_header_add(headers, "X-WAP-Gateway", GW_NAME "/" GW_VERSION);
508 }
509 
510 
511 /* Add Accept-Charset: headers for stuff the WML compiler can
512  * convert to UTF-8. */
513 /* XXX This is not really correct, since we will not be able
514  * to handle those charsets for all content types, just WML/XHTML. */
515 static void add_charset_headers(List *headers)
516 {
517  if (!http_charset_accepted(headers, "utf-8"))
518  http_header_add(headers, "Accept-Charset", "utf-8");
519 }
520 
521 
522 /* Add Accept: headers for stuff we can convert for the phone */
523 static void add_accept_headers(List *headers)
524 {
525  int i;
526 
527  for (i = 0; i < NUM_CONVERTERS; i++) {
528  if (http_type_accepted(headers, "*/*") || (
530  && !http_type_accepted(headers, converters[i].type))) {
531  http_header_add(headers, "Accept", converters[i].type);
532  }
533  }
534 }
535 
536 
537 /* Add X-WAP-Network-Client-IP: header to proxy client IP to HTTP server */
539 {
540  if (octstr_len(addr_tuple->remote->address) > 0) {
541  http_header_add(headers, "X-WAP-Network-Client-IP",
542  octstr_get_cstr(addr_tuple->remote->address));
543  }
544 }
545 
546 
547 /* Add X-WAP-Session-ID: header to request */
548 static void add_session_id(List *headers, long session_id)
549 {
550  if (session_id != -1) {
551  char buf[40];
552  sprintf(buf, "%ld", session_id);
553  http_header_add(headers, "X-WAP-Session-ID", buf);
554  }
555 }
556 
557 
558 /* Add X-WAP-Client-SDU-Size: to provide information on client capabilities */
559 static void add_client_sdu_size(List *headers, long sdu_size)
560 {
561  if (sdu_size > 0) {
562  Octstr *buf;
563 
564  buf = octstr_format("%ld", sdu_size);
565  http_header_add(headers, "X-WAP-Client-SDU-Size", octstr_get_cstr(buf));
566  octstr_destroy(buf);
567  }
568 }
569 
570 /* Add proxy Via: header to request with our Kannel version */
571 static void add_via(List *headers)
572 {
573  Octstr *os;
574  Octstr *version;
575 
576  version = http_header_value(headers, octstr_imm("Encoding-Version"));
577  os = octstr_format("WAP/%s %S (" GW_NAME "/%s)",
578  (version ? octstr_get_cstr(version) : "1.1"),
579  get_official_name(), GW_VERSION);
580  http_header_add(headers, "Via", octstr_get_cstr(os));
581  octstr_destroy(os);
582  octstr_destroy(version);
583 }
584 
585 
586 /*
587  * Add an X-WAP.TOD header to the response headers. It is defined in
588  * the "WAP Caching Model" specification.
589  * We generate it in textual form and let WSP header packing convert it
590  * to binary form.
591  */
592 static void add_x_wap_tod(List *headers)
593 {
594  Octstr *gateway_time;
595 
596  gateway_time = date_format_http(time(NULL));
597  if (gateway_time == NULL) {
598  warning(0, "Could not add X-WAP.TOD response header.");
599  return;
600  }
601 
602  http_header_add(headers, "X-WAP.TOD", octstr_get_cstr(gateway_time));
603  octstr_destroy(gateway_time);
604 }
605 
606 
607 /* Add MSISDN provisioning information to HTTP header */
608 static void add_msisdn(List *headers, WAPAddrTuple *addr_tuple,
609  Octstr *send_msisdn_header)
610 {
611  Octstr *msisdn = NULL;
612  Octstr *value = NULL;
613 
614  if (send_msisdn_header == NULL || octstr_len(send_msisdn_header) == 0)
615  return;
616 
617  /*
618  * Security considerations. If there are headers with the header name we
619  * use to pass on the MSISDN number, then remove them.
620  */
621  if ((value = http_header_value(headers, send_msisdn_header)) != NULL) {
622  warning(0, "MSISDN header <%s> already present on request, "
623  "header value=<%s>", octstr_get_cstr(send_msisdn_header),
624  octstr_get_cstr(value));
625  http_header_remove_all(headers, octstr_get_cstr(send_msisdn_header));
626  }
627 
628  /*
629  * XXX Add generic msisdn provisioning cleanly in here!
630  * See revision 1.89 for Bruno's try.
631  */
632 
633  /* We do not accept NULL values to be added to the HTTP header */
634  if ((msisdn = radius_acct_get_msisdn(addr_tuple->remote->address)) != NULL) {
635  http_header_add(headers, octstr_get_cstr(send_msisdn_header), octstr_get_cstr(msisdn));
636  }
637 
638  octstr_destroy(value);
639  octstr_destroy(msisdn);
640 }
641 
642 
643 /*
644  * Map WSP UAProf headers 'Profile', 'Profile-Diff' to W-HTTP headers
645  * 'X-WAP-Profile', 'X-WAP-Profile-Diff' according to WAP-248-UAProf-20011020-a,
646  * section 9.2.3.3.
647  */
648 /*
649 static void map_uaprof_headers(List *headers)
650 {
651  Octstr *os;
652  Octstr *version;
653 
654  version = http_header_value(headers, octstr_imm("Encoding-Version"));
655  os = octstr_format("WAP/%s %S (" GW_NAME "/%s)",
656  (version ? octstr_get_cstr(version) : "1.1"),
657  get_official_name(), GW_VERSION);
658  http_header_add(headers, "Via", octstr_get_cstr(os));
659  octstr_destroy(os);
660  octstr_destroy(version);
661 }
662 */
663 
664 
665 /* XXX DAVI: Disabled in cvs revision 1.81 for Opengroup tests
666 static void add_referer_url(List *headers, Octstr *url)
667 {
668  if (octstr_len(url) > 0) {
669  http_header_add(headers, "Referer", octstr_get_cstr(url));
670  }
671 }
672 */
673 
674 
676 {
677  gw_assert(url != NULL);
678  gw_assert(sm != NULL);
679 
680  octstr_destroy(sm->referer_url);
681  sm->referer_url = octstr_duplicate(url);
682 }
683 
684 
686 {
687  return sm ? sm->referer_url : NULL;
688 }
689 
690 
691 /*
692  * Return the reply from an HTTP request to the phone via a WSP session.
693  */
694 static void return_session_reply(long server_transaction_id, long status,
695  List *headers, Octstr *body, long session_id)
696 {
697  WAPEvent *e;
698 
699  e = wap_event_create(S_MethodResult_Req);
700  e->u.S_MethodResult_Req.server_transaction_id = server_transaction_id;
701  e->u.S_MethodResult_Req.status = status;
702  e->u.S_MethodResult_Req.response_headers = headers;
703  e->u.S_MethodResult_Req.response_body = body;
704  e->u.S_MethodResult_Req.session_id = session_id;
706 }
707 
708 
709 /*
710  * Return the reply from an HTTP request to the phone via connectionless
711  * WSP.
712  */
713 static void return_unit_reply(WAPAddrTuple *tuple, long transaction_id,
714  long status, List *headers, Octstr *body)
715 {
716  WAPEvent *e;
717 
718  e = wap_event_create(S_Unit_MethodResult_Req);
719  e->u.S_Unit_MethodResult_Req.addr_tuple =
721  e->u.S_Unit_MethodResult_Req.transaction_id = transaction_id;
722  e->u.S_Unit_MethodResult_Req.status = status;
723  e->u.S_Unit_MethodResult_Req.response_headers = headers;
724  e->u.S_Unit_MethodResult_Req.response_body = body;
726 }
727 
728 
729 static void normalize_charset(struct content * content, List* device_headers)
730 {
731  Octstr* charset;
732 
733  if ((charset = find_charset_encoding(content->body)) == NULL) {
734  if (octstr_len(content->charset) > 0) {
735  charset = octstr_duplicate(content->charset);
736  } else {
737  charset = octstr_imm("UTF-8");
738  }
739  }
740 
741  debug("wap-appl",0,"Normalizing charset from %s", octstr_get_cstr(charset));
742 
743  if (octstr_case_compare(charset, octstr_imm("UTF-8")) != 0 &&
744  !http_charset_accepted(device_headers, octstr_get_cstr(charset))) {
745  if (!http_charset_accepted(device_headers, "UTF-8")) {
746  warning(0, "WSP: Device doesn't support charset <%s> neither UTF-8",
747  octstr_get_cstr(charset));
748  } else {
749  debug("wsp",0,"Converting wml/xhtml from charset <%s> to UTF-8",
750  octstr_get_cstr(charset));
751  if (charset_convert(content->body,
752  octstr_get_cstr(charset), "UTF-8") >= 0) {
753  octstr_destroy(content->charset);
754  content->charset = octstr_create("UTF-8");
755  }
756  }
757  }
758  octstr_destroy(charset);
759 }
760 
761 /*
762  * Return an HTTP reply back to the phone.
763  */
764 static void return_reply(int status, Octstr *content_body, List *headers,
765  long sdu_size, WAPEvent *orig_event, long session_id,
766  Octstr *method, Octstr *url, int x_wap_tod,
767  List *request_headers, Octstr *msisdn)
768 {
769  struct content content;
770  int converted;
771  WSPMachine *sm;
772  List *device_headers, *t_headers;
774  Octstr *ua, *server;
775 
776  content.url = url;
777  content.body = content_body;
778  content.version = content.type = content.charset = NULL;
779  server = ua = NULL;
780 
781  /* Get session machine for this session. If this was a connection-less
782  * request be obviously will not find any session machine entry. */
783  sm = find_session_machine_by_id(session_id);
784 
785  device_headers = gwlist_create();
786 
787  /* ensure we pass only the original headers to the convertion routine */
788  t_headers = (orig_event->type == S_MethodInvoke_Ind) ?
789  orig_event->u.S_MethodInvoke_Ind.session_headers :
790  NULL;
791  if (t_headers != NULL) http_header_combine(device_headers, t_headers);
792  t_headers = (orig_event->type == S_MethodInvoke_Ind) ?
793  orig_event->u.S_MethodInvoke_Ind.request_headers :
794  orig_event->u.S_Unit_MethodInvoke_Ind.request_headers;
795  if (t_headers != NULL) http_header_combine(device_headers, t_headers);
796 
797  /*
798  * We are acting as a proxy. Hence ensure we log a correct HTTP response
799  * code to our access-log file to allow identification of failed proxying
800  * requests in the main accesss-log.
801  */
802  /* get client IP and User-Agent identifier */
803  addr_tuple = (orig_event->type == S_MethodInvoke_Ind) ?
804  orig_event->u.S_MethodInvoke_Ind.addr_tuple :
805  orig_event->u.S_Unit_MethodInvoke_Ind.addr_tuple;
806  ua = http_header_value(request_headers, octstr_imm("User-Agent"));
807 
808  if (headers != NULL) {
809  /* get response content type and Server identifier */
810  http_header_get_content_type(headers, &content.type, &content.charset);
811  server = http_header_value(headers, octstr_imm("Server"));
812  }
813 
814  /* log the access */
815  /* XXX make this configurable in the future */
816  alog("%s %s %s <%s> (%s, charset='%s') %ld %d <%s> <%s>",
817  octstr_get_cstr(addr_tuple->remote->address),
818  msisdn ? octstr_get_cstr(msisdn) : "-",
819  octstr_get_cstr(method), octstr_get_cstr(url),
820  content.type ? octstr_get_cstr(content.type) : "",
821  content.charset ? octstr_get_cstr(content.charset) : "",
822  octstr_len(content.body), status < 0 ? HTTP_BAD_GATEWAY : status,
823  ua ? octstr_get_cstr(ua) : "",
824  server ? octstr_get_cstr(server) : "");
825 
826  octstr_destroy(ua);
827  octstr_destroy(server);
828 
829 
830  if (status < 0) {
831  error(0, "WSP: HTTP lookup failed, oops.");
832  /* smart WSP error messaging?! */
833  if (wsp_smart_errors) {
834  Octstr *referer_url;
835  status = HTTP_OK;
836  content.type = octstr_create("text/vnd.wap.wml");
837  content.charset = octstr_create("");
838  /*
839  * check if a referer for this URL exists and
840  * get back to the previous page in this case
841  */
842  if ((referer_url = get_referer_url(find_session_machine_by_id(session_id)))) {
843  content.body = error_requesting_back(url, referer_url);
844  debug("wap.wsp",0,"WSP: returning smart error WML deck for referer URL");
845  }
846  /*
847  * if there is no referer to retun to, check if we have a
848  * device-home defined and return to that, otherwise simply
849  * drop an error wml deck.
850  */
851  else if (device_home != NULL) {
852  content.body = error_requesting_back(url, device_home);
853  debug("wap.wsp",0,"WSP: returning smart error WML deck for device-home URL");
854  } else {
855  content.body = error_requesting(url);
856  debug("wap.wsp",0,"WSP: returning smart error WML deck");
857  }
858 
859  /*
860  * if we did not connect at all there is no content in
861  * the headers list, so create for the upcoming transformation
862  */
863  if (headers == NULL)
864  headers = http_create_empty_headers();
865 
866  converted = convert_content(&content, device_headers, 0);
867  if (converted == 1)
868  http_header_mark_transformation(headers, content.body, content.type);
869 
870  } else {
871  /* no WSP smart error messaging */
872  status = HTTP_BAD_GATEWAY;
873  content.type = octstr_create("text/plain");
874  content.charset = octstr_create("");
875  content.body = octstr_create("");
876  }
877 
878  } else {
879  /* received response by HTTP server */
880 
881 #ifdef ENABLE_COOKIES
882  if (session_id != -1)
883  if (get_cookies(headers, find_session_machine_by_id(session_id)) == -1)
884  error(0, "WSP: Failed to extract cookies");
885 #endif
886 
887  /*
888  * XXX why do we transcode charsets on the content body here?!
889  * Why is this not in the scope of the HTTP server, rather
890  * then doing this inside Kannel?! st.
891  */
892 
893  /*
894  * Adapts content body's charset to device.
895  * If device doesn't support body's charset but supports UTF-8, this
896  * block tries to convert body to UTF-8.
897  * (This is required for Sharp GX20 for example)
898  */
899  if (octstr_search(content.type, octstr_imm("text/vnd.wap.wml"), 0) >= 0 ||
900  octstr_search(content.type, octstr_imm("application/xhtml+xml"), 0) >= 0 ||
901  octstr_search(content.type, octstr_imm("application/vnd.wap.xhtml+xml"), 0) >= 0) {
902 
903  normalize_charset(&content, device_headers);
904  }
905 
906  /* set WBXML Encoding-Version for wml->wmlc conversion */
907  if (sm != NULL) {
908  content.version = http_header_value(sm->http_headers,
909  octstr_imm("Encoding-Version"));
910  } else {
911  content.version = NULL;
912  }
913 
914  /* convert content-type by our own converter table */
915  converted = convert_content(&content, device_headers,
916  octstr_compare(method, octstr_imm("HEAD")) == 0);
917  if (converted < 0) {
918  warning(0, "WSP: All converters for `%s' at `%s' failed.",
919  octstr_get_cstr(content.type), octstr_get_cstr(url));
920 
921  /*
922  * Don't change status; just send the client what we did get.
923  * Or if smart error messages are configured, send a wmlc deck
924  * with accurate information.
925  */
926  if (wsp_smart_errors) {
927  octstr_destroy(content.body);
928  octstr_destroy(content.charset);
929  content.body = error_converting(url, content.type);
930  content.charset = octstr_create("UTF-8");
931 
932  debug("wap.wsp",0,"WSP: returning smart error WML deck for failed converters");
933 
934  converted = convert_content(&content, device_headers, 0);
935  if (converted == 1)
936  http_header_mark_transformation(headers, content.body, content.type);
937 
938  }
939  }
940  else if (converted == 1) {
941  http_header_mark_transformation(headers, content.body, content.type);
942 
943  /*
944  * set referer URL to WSPMachine, but only if this was a converted
945  * content-type, like .wml
946  */
947  if (session_id != -1) {
948  debug("wap.wsp.http",0,"WSP: Setting Referer URL to <%s>",
949  octstr_get_cstr(url));
950  if ((sm = find_session_machine_by_id(session_id)) != NULL) {
951  set_referer_url(url, sm);
952  } else {
953  error(0,"WSP: Failed to find session machine for ID %ld",
954  session_id);
955  }
956  }
957  }
958 
959  /* if converted == 0 then we pass the content wihtout modification */
960  }
961 
962  if (headers == NULL)
963  headers = http_create_empty_headers();
964  http_remove_hop_headers(headers);
965  http_header_remove_all(headers, "X-WAP.TOD");
966  if (x_wap_tod)
967  add_x_wap_tod(headers);
968 
969  if (content.body == NULL)
970  content.body = octstr_create("");
971 
972  /*
973  * Deal with otherwise wap-aware servers that return text/html error
974  * messages if they report an error.
975  * (Normally we leave the content type alone even if the client doesn't
976  * claim to accept it, because the server might know better than the
977  * gateway.)
978  */
979  if (http_status_class(status) != HTTP_STATUS_SUCCESSFUL &&
980  !http_type_accepted(request_headers, octstr_get_cstr(content.type))) {
981  warning(0, "WSP: Content type <%s> not supported by client,"
982  " deleting body.", octstr_get_cstr(content.type));
983  octstr_destroy(content.body);
984  content.body = octstr_create("");
985  octstr_destroy(content.type);
986  content.type = octstr_create("text/plain");
987  http_header_mark_transformation(headers, content.body, content.type);
988  }
989  /* remove body if request method was HEAD, we act strictly here */
990  else if (octstr_compare(method, octstr_imm("HEAD")) == 0) {
991  octstr_destroy(content.body);
992  content.body = octstr_create("");
993  /* change to text/plain if received content-type is not accepted */
994  if (!http_type_accepted(request_headers, "*/*") &&
995  !http_type_accepted(request_headers, octstr_get_cstr(content.type))) {
996  octstr_destroy(content.type);
997  content.type = octstr_create("text/plain");
998  }
999  debug("wsp",0,"WSP: HEAD request, removing body, content-type is now <%s>",
1000  octstr_get_cstr(content.type));
1001  http_header_mark_transformation(headers, content.body, content.type);
1002  }
1003 
1004 #ifdef ENABLE_NOT_ACCEPTED
1005  /* Returns HTTP response 406 if content-type is not supported by device */
1006  else if (request_headers && content.type &&
1007  !http_type_accepted(request_headers, octstr_get_cstr(content.type)) &&
1008  !http_type_accepted(request_headers, "*/*")) {
1009  warning(0, "WSP: content-type <%s> not supported",
1010  octstr_get_cstr(content.type));
1011  status = HTTP_NOT_ACCEPTABLE;
1012  octstr_destroy(content.type);
1013  content.type = octstr_create("text/plain");
1014  octstr_destroy(content.charset);
1015  octstr_destroy(content.body);
1016  content.charset = octstr_create("");
1017  content.body = octstr_create("");
1018  http_header_mark_transformation(headers, content.body, content.type);
1019  }
1020 #endif
1021 
1022  /*
1023  * If the response is too large to be sent to the client,
1024  * suppress it and inform the client.
1025  */
1026  if (octstr_len(content.body) > sdu_size && sdu_size > 0) {
1027  /*
1028  * Only change the status if it indicated success.
1029  * If it indicated an error, then that information is
1030  * more useful to the client than our "Bad Gateway" would be.
1031  * The too-large body is probably an error page in html.
1032  */
1033  /* XXX add WSP smart messaging here too */
1035  status = HTTP_BAD_GATEWAY;
1036  warning(0, "WSP: Entity at %s too large (size %ld B, limit %lu B)",
1037  octstr_get_cstr(url), octstr_len(content.body), sdu_size);
1038  octstr_destroy(content.body);
1039  content.body = octstr_create("");
1040  http_header_mark_transformation(headers, content.body, content.type);
1041  }
1042 
1043  if (orig_event->type == S_MethodInvoke_Ind) {
1044  return_session_reply(orig_event->u.S_MethodInvoke_Ind.server_transaction_id,
1045  status, headers, content.body, session_id);
1046  } else {
1047  return_unit_reply(orig_event->u.S_Unit_MethodInvoke_Ind.addr_tuple,
1048  orig_event->u.S_Unit_MethodInvoke_Ind.transaction_id,
1049  status, headers, content.body);
1050  }
1051 
1052  octstr_destroy(content.version); /* body was re-used above */
1053  octstr_destroy(content.type); /* body was re-used above */
1054  octstr_destroy(content.charset);
1055  octstr_destroy(url); /* same as content.url */
1056  http_destroy_headers(device_headers);
1057 
1058  counter_decrease(fetches);
1059 }
1060 
1061 
1062 /*
1063  * This thread receives replies from HTTP layer and sends them back to
1064  * the phone.
1065  */
1066 static void return_replies_thread(void *arg)
1067 {
1068  Octstr *body;
1069  struct request_data *p;
1070  int status;
1071  Octstr *final_url;
1072  List *headers;
1073 
1074  while (run_status == running) {
1075 
1076  p = http_receive_result(caller, &status, &final_url, &headers, &body);
1077  if (p == NULL)
1078  break;
1079 
1080  return_reply(status, body, headers, p->client_SDU_size,
1081  p->event, p->session_id, p->method, p->url, p->x_wap_tod,
1082  p->request_headers, p->msisdn);
1083 
1086  octstr_destroy(p->msisdn);
1087  gw_free(p);
1088  octstr_destroy(final_url);
1089  }
1090 }
1091 
1092 
1093 /*
1094  * This WML deck is returned when the user asks for the magic
1095  * URL "kannel:alive".
1096  */
1097 #define HEALTH_DECK \
1098  "<?xml version=\"1.0\"?>" \
1099  "<!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD 1.1//EN\" " \
1100  "\"http://www.wapforum.org/DTD/wml_1.1.xml\">" \
1101  "<wml><card id=\"health\"><p>Ok</p></card></wml>"
1102 
1104 {
1105  int ret;
1106  long client_SDU_size; /* 0 means no limit */
1107  Octstr *url;
1108  List *session_headers;
1110  List *actual_headers;
1111  List *resp_headers;
1113  long session_id;
1114  Octstr *content_body;
1115  Octstr *method; /* type of request, normally a get or a post */
1116  Octstr *request_body;
1117  int x_wap_tod; /* X-WAP.TOD header was present in request */
1118  Octstr *magic_url;
1119  struct request_data *p;
1120  Octstr *send_msisdn_query, *send_msisdn_header, *send_msisdn_format;
1121  int accept_cookies;
1122  Octstr *msisdn;
1123 
1124  counter_increase(fetches);
1125 
1126  if (event->type == S_MethodInvoke_Ind) {
1127  struct S_MethodInvoke_Ind *p;
1128 
1129  /* WSP, connection orientated */
1130  p = &event->u.S_MethodInvoke_Ind;
1131  session_headers = p->session_headers;
1132  request_headers = p->request_headers;
1133  url = octstr_duplicate(p->request_uri);
1134  addr_tuple = p->addr_tuple;
1135  session_id = p->session_id;
1136  client_SDU_size = p->client_SDU_size;
1137  request_body = octstr_duplicate(p->request_body);
1138  method = p->method;
1139  } else {
1140  struct S_Unit_MethodInvoke_Ind *p;
1141 
1142  /* WDP, non orientated */
1143  p = &event->u.S_Unit_MethodInvoke_Ind;
1144  session_headers = NULL;
1145  request_headers = p->request_headers;
1146  url = octstr_duplicate(p->request_uri);
1147  addr_tuple = p->addr_tuple;
1148  session_id = -1;
1149  client_SDU_size = 0; /* No limit */
1150  request_body = octstr_duplicate(p->request_body);
1151  method = p->method;
1152  }
1153 
1154  msisdn = radius_acct_get_msisdn(addr_tuple->remote->address);
1155  info(0, "Fetching URL <%s> for MSISDN <%s>, IP <%s:%ld>", octstr_get_cstr(url),
1156  msisdn ? octstr_get_cstr(msisdn) : "",
1157  addr_tuple->remote->address ? octstr_get_cstr(addr_tuple->remote->address) : "",
1158  addr_tuple->remote->port);
1159 
1160  /*
1161  * XXX this URL mapping needs to be rebuild! st.
1162  */
1163 
1164  /* try to rewrite URL */
1165  wap_map_url(&url, &send_msisdn_query, &send_msisdn_header,
1166  &send_msisdn_format, &accept_cookies);
1167  /* if no mapping found, then use our RADIUS acct proxy header */
1168  if (send_msisdn_header == NULL)
1169  send_msisdn_header = octstr_create("X-WAP-Network-Client-MSISDN");
1170 
1171  actual_headers = gwlist_create();
1172 
1173  if (session_headers != NULL)
1174  http_header_combine(actual_headers, session_headers);
1175  if (request_headers != NULL)
1176  http_header_combine(actual_headers, request_headers);
1177 
1178  x_wap_tod = http_header_remove_all(actual_headers, "X-WAP.TOD");
1179  add_accept_headers(actual_headers);
1180  add_charset_headers(actual_headers);
1181  add_network_info(actual_headers, addr_tuple);
1182  add_client_sdu_size(actual_headers, client_SDU_size);
1183  add_via(actual_headers);
1184 
1185 #ifdef ENABLE_COOKIES
1186  /* DAVI: to finish - accept_cookies -1,
1187  * use global accept-cookies, 0 = no, 1 = yes ? */
1188  if (accept_cookies != 0 && (session_id != -1) &&
1189  /* DAVI (set_cookies(url, actual_headers,
1190  find_session_machine_by_id(session_id)) == -1)) */
1191  (set_cookies(actual_headers, find_session_machine_by_id(session_id)) == -1))
1192  error(0, "WSP: Failed to add cookies");
1193 #endif
1194 
1195  /* set referer URL to HTTP header from WSPMachine */
1196  /*
1197  * XXX This makes Open Group's test suite wml/events/tasks/go/5 failing,
1198  * which requires that device is *not* sending referer, but Kannel drops
1199  * it in. We have to remove this for now.
1200  */
1201  /*
1202  if (session_id != -1) {
1203  if ((referer_url = get_referer_url(find_session_machine_by_id(session_id))) != NULL) {
1204  add_referer_url(actual_headers, referer_url);
1205  }
1206  }
1207  */
1208 
1209  add_kannel_version(actual_headers);
1210  add_session_id(actual_headers, session_id);
1211 
1212  add_msisdn(actual_headers, addr_tuple, send_msisdn_header);
1213  octstr_destroy(send_msisdn_query);
1214  octstr_destroy(send_msisdn_header);
1215  octstr_destroy(send_msisdn_format);
1216 
1217  http_remove_hop_headers(actual_headers);
1218  http_header_pack(actual_headers);
1219 
1220  magic_url = octstr_imm("kannel:alive");
1221 
1222  /* check if this request is a call for our magic URL */
1223  if (octstr_str_compare(method, "GET") == 0 &&
1224  octstr_compare(url, magic_url) == 0) {
1225  ret = HTTP_OK;
1226  resp_headers = gwlist_create();
1227  http_header_add(resp_headers, "Content-Type", "text/vnd.wap.wml");
1228  content_body = octstr_create(HEALTH_DECK);
1229  octstr_destroy(request_body);
1230  return_reply(ret, content_body, resp_headers, client_SDU_size,
1231  event, session_id, method, url, x_wap_tod, actual_headers,
1232  msisdn);
1233  wap_event_destroy(event);
1234  http_destroy_headers(actual_headers);
1235  octstr_destroy(msisdn);
1236  }
1237  /* otherwise it should be a GET, POST or HEAD request type */
1238  else if (octstr_str_compare(method, "GET") == 0 ||
1239  octstr_str_compare(method, "POST") == 0 ||
1240  octstr_str_compare(method, "HEAD") == 0) {
1241 
1242  /* we don't allow a body within a GET or HEAD request */
1243  if (request_body != NULL && (octstr_str_compare(method, "GET") == 0 ||
1244  octstr_str_compare(method, "HEAD") == 0)) {
1245  octstr_destroy(request_body);
1246  request_body = NULL;
1247  }
1248 
1249  /*
1250  * Call deconvert_content() here for transformations of binary
1251  * encoded POST requests from the client into plain text decoded
1252  * POST requests for the HTTP server.
1253  * Mainly this is used for multipart/form-data transmissions,
1254  * including MMS on-the-fly message decoding.
1255  * When we are doing mms, the phone POSTs contents and acknowled-
1256  * gements. In this case, we dont do not deconvert anything.
1257  */
1258  if (octstr_str_compare(method, "POST") == 0 && request_body &&
1259  octstr_len(request_body)) {
1260  struct content content;
1261  int converted;
1262 
1263  http_header_get_content_type(actual_headers, &content.type,
1264  &content.charset);
1265  content.body = request_body;
1266  converted = deconvert_content(&content);
1267  if (converted == 1)
1268  http_header_mark_transformation(actual_headers, content.body,
1269  content.type);
1270  request_body = content.body;
1271  octstr_destroy(content.type);
1272  octstr_destroy(content.charset);
1273  }
1274 
1275  /* struct that is used for the HTTP response identifier */
1276  p = gw_malloc(sizeof(*p));
1277  p->client_SDU_size = client_SDU_size;
1278  p->event = event;
1279  p->session_id = session_id;
1280  p->method = method;
1281  p->url = url;
1282  p->x_wap_tod = x_wap_tod;
1283  p->request_headers = actual_headers;
1284  p->msisdn = msisdn;
1285 
1286  /* issue the request to the HTTP server */
1287  http_start_request(caller, http_name2method(method), url, actual_headers,
1288  request_body, 0, p, NULL);
1289 
1290  octstr_destroy(request_body);
1291  }
1292  /* we don't support the WSP/HTTP method the client asked us */
1293  else {
1294  error(0, "WSP: Method %s not supported.", octstr_get_cstr(method));
1295  content_body = octstr_create("");
1296  resp_headers = http_create_empty_headers();
1297  ret = HTTP_NOT_IMPLEMENTED;
1298  octstr_destroy(request_body);
1299  return_reply(ret, content_body, resp_headers, client_SDU_size,
1300  event, session_id, method, url, x_wap_tod, actual_headers,
1301  msisdn);
1302  wap_event_destroy(event);
1303  http_destroy_headers(actual_headers);
1304  octstr_destroy(msisdn);
1305  }
1306 }
1307 
1308 
1309 /* Shut up WMLScript compiler status/trace messages. */
1310 static void dev_null(const char *data, size_t len, void *context)
1311 {
1312  /* nothing */
1313 }
1314 
1315 
1317 {
1318  Octstr *wmlc;
1319  int ret;
1320 
1321  /* content->charset is passed from the HTTP header parsing */
1322  ret = wml_compile(content->body, content->charset, &wmlc,
1323  content->version);
1324 
1325  /* wmlc is created implicitely in wml_compile() */
1326  if (ret == 0)
1327  return wmlc;
1328 
1329  octstr_destroy(wmlc);
1330  warning(0, "WSP: WML compilation failed.");
1331  return NULL;
1332 }
1333 
1334 
1336 {
1337  WsCompilerParams params;
1338  WsCompilerPtr compiler;
1339  WsResult result;
1340  unsigned char *result_data;
1341  size_t result_size;
1342  Octstr *wmlscriptc;
1343 
1344  memset(&params, 0, sizeof(params));
1345  params.use_latin1_strings = 0;
1346  params.print_symbolic_assembler = 0;
1347  params.print_assembler = 0;
1348  params.meta_name_cb = NULL;
1349  params.meta_name_cb_context = NULL;
1350  params.meta_http_equiv_cb = NULL;
1351  params.meta_http_equiv_cb_context = NULL;
1352  params.stdout_cb = dev_null;
1353  params.stderr_cb = dev_null;
1354 
1355  compiler = ws_create(&params);
1356  if (compiler == NULL) {
1357  panic(0, "WSP: could not create WMLScript compiler");
1358  }
1359 
1360  result = ws_compile_data(compiler, octstr_get_cstr(content->url),
1361  (unsigned char *)octstr_get_cstr(content->body),
1362  octstr_len(content->body),
1363  &result_data, &result_size);
1364  if (result != WS_OK) {
1365  warning(0, "WSP: WMLScript compilation failed: %s",
1366  ws_result_to_string(result));
1367  wmlscriptc = NULL;
1368  } else {
1369  wmlscriptc = octstr_create_from_data((char *)result_data, result_size);
1370  }
1371 
1372  return wmlscriptc;
1373 }
1374 
1375 
1376 /*
1377  * XXX There's a big bug in http_get_content_type that
1378  * assumes that header parameter is charset without looking at
1379  * parameter key. Good!. I'll use its value to catch boundary
1380  * value for now
1381  * ie. "Content-Type: (foo/bar);something=(value)" it gets value
1382  * without caring about what is "something"
1383  */
1384 
1385 /* DAVI: To-Do
1386 static Octstr *convert_multipart_mixed(struct content *content)
1387 {
1388  Octstr *result = NULL;
1389 
1390  debug("wap.wsp.multipart.mixed", 0, "WSP.Multipart.Mixed, boundary=[%s]",
1391  octstr_get_cstr(content->charset));
1392 
1393  result = octstr_duplicate(content->body);
1394  return result;
1395 }
1396 */
1397 
1398 
1400 {
1401  Octstr *mime;
1402 
1403  if ((mime_decompile(content->body, &mime)) == 0)
1404  return mime;
1405 
1406  return NULL;
1407 }
1408 
1409 /* DAVI: To-Do
1410 static Octstr *deconvert_mms_message(struct content *content)
1411 {
1412  Octstr *mime;
1413 
1414  if ((mms_decompile(content->body, &mime)) == 0)
1415  return mime;
1416 
1417  return NULL;
1418 }
1419 */
1420 
1421 
1422 /* The interface for capability negotiation is a bit different from
1423  * the negotiation at WSP level, to make it easier to program.
1424  * The application layer gets a list of requested capabilities,
1425  * basically a straight decoding of the WSP level capabilities.
1426  * It replies with a list of all capabilities it wants to set or
1427  * refuse. (Refuse by setting cap->data to NULL). Any capabilities
1428  * it leaves out are considered "unknown; don't care". The WSP layer
1429  * will either process those itself, or refuse them.
1430  *
1431  * At the WSP level, not sending a reply to a capability means accepting
1432  * what the client proposed. If the application layer wants this to
1433  * happen, it should set cap->data to NULL and cap->accept to 1.
1434  * (The WSP layer does not try to guess what kind of reply would be
1435  * identical to what the client proposed, because the format of the
1436  * reply is often different from the format of the request, and this
1437  * is likely to be true for unknown capabilities too.)
1438  */
1439 static List *negotiate_capabilities(List *req_caps)
1440 {
1441  /* Currently we don't know or care about any capabilities,
1442  * though it is likely that "Extended Methods" will be
1443  * the first. */
1444  return gwlist_create();
1445 }
1446 
1447 
1448 /*
1449  * Ota submodule implements indications, responses and confirmations part of
1450  * ota.
1451  */
1452 
1453 /*
1454  * If Accept-Application is empty, add header indicating default application
1455  * wml ua (see ota 6.4.1). Otherwise decode application id (see http://www.
1456  * wapforum.org/wina/push-app-id.htm). FIXME: capability negotiation (no-
1457  * thing means default, if so negotiated).
1458  * Function does not allocate memory neither for headers nor application_
1459  * headers.
1460  * Returns encoded application headers and input header list without them.
1461  */
1462 static void check_application_headers(List **headers,
1463  List **application_headers)
1464 {
1465  List *inh = NULL;
1466  int i;
1467  long len;
1468  Octstr *appid_name, *coded_octstr;
1469  char *appid_value, *coded_value;
1470 
1471  split_header_list(headers, &inh, "Accept-Application");
1472 
1473  if (*headers == NULL || gwlist_len(inh) == 0) {
1474  http_header_add(*application_headers, "Accept-Application", "wml ua");
1475  debug("wap.appl.push", 0, "APPL: No push application, assuming wml"
1476  " ua");
1477  if (*headers != NULL)
1478  http_destroy_headers(inh);
1479  return;
1480  }
1481 
1482  i = 0;
1483  len = gwlist_len(inh);
1484  coded_value = NULL;
1485  appid_value = NULL;
1486 
1487  while (i < len) {
1488  http_header_get(inh, i, &appid_name, &coded_octstr);
1489 
1490  /* Greatest value reserved by WINA is 0xFF00 0000*/
1491  coded_value = octstr_get_cstr(coded_octstr);
1492  if (coded_value != NULL)
1493  appid_value = (char *)wsp_application_id_to_cstr((long) coded_value);
1494 
1495  if (appid_value != NULL && coded_value != NULL)
1496  http_header_add(*application_headers, "Accept-Application",
1497  appid_value);
1498  else {
1499  error(0, "OTA: Unknown application is, skipping: ");
1500  octstr_dump(coded_octstr, 0, GW_ERROR);
1501  }
1502 
1503  i++;
1504  }
1505 
1506  debug("wap.appl.push", 0, "application headers were");
1507  http_header_dump(*application_headers);
1508 
1509  http_destroy_headers(inh);
1510  octstr_destroy(appid_name);
1511  octstr_destroy(coded_octstr);
1512 }
1513 
1514 
1515 /*
1516  * Bearer-Indication field is defined in ota 6.4.1.
1517  * Skip the header, if it is malformed or if there is more than one bearer
1518  * indication.
1519  * Function does not allocate memory neither for headers nor bearer_headers.
1520  * Return encoded bearer indication header and input header list without it.
1521  */
1522 static void decode_bearer_indication(List **headers, List **bearer_headers)
1523 {
1524  List *inb;
1525  Octstr *name, *coded_octstr;
1526  char *value;
1527  unsigned char coded_value;
1528 
1529  if (*headers == NULL) {
1530  debug("wap.appl", 0, "APPL: no client headers, continuing");
1531  return;
1532  }
1533 
1534  split_header_list(headers, &inb, "Bearer-Indication");
1535 
1536  if (gwlist_len(inb) == 0) {
1537  debug("wap.appl.push", 0, "APPL: No bearer indication headers,"
1538  " continuing");
1539  http_destroy_headers(inb);
1540  return;
1541  }
1542 
1543  if (gwlist_len(inb) > 1) {
1544  error(0, "APPL: To many bearer indication header(s), skipping"
1545  " them");
1546  http_destroy_headers(inb);
1547  return;
1548  }
1549 
1550  http_header_get(inb, 0, &name, &coded_octstr);
1551  http_destroy_headers(inb);
1552 
1553  /* Greatest assigned number for a bearer type is 0xff, see wdp, appendix C */
1554  coded_value = octstr_get_char(coded_octstr, 0);
1555  value = (char *)wsp_bearer_indication_to_cstr(coded_value);
1556 
1557  if (value != NULL && coded_value != 0) {
1558  http_header_add(*bearer_headers, "Bearer-Indication", value);
1559  debug("wap.appl.push", 0, "bearer indication header was");
1560  http_header_dump(*bearer_headers);
1561  return;
1562  } else {
1563  error(0, "APPL: Illegal bearer indication value, skipping:");
1564  octstr_dump(coded_octstr, 0, GW_ERROR);
1565  http_destroy_headers(*bearer_headers);
1566  return;
1567  }
1568 }
1569 
1570 
1571 /*
1572  * Separate headers into two lists, one having all headers named "name" and
1573  * the other rest of them.
1574  */
1575 static void split_header_list(List **headers, List **new_headers, char *name)
1576 {
1577  if (*headers == NULL)
1578  return;
1579 
1580  *new_headers = http_header_find_all(*headers, name);
1581  http_header_remove_all(*headers, name);
1582 }
1583 
1584 
1585 /*
1586  * Find headers Accept-Application and Bearer-Indication amongst push headers,
1587  * decode them and add them to their proper field.
1588  */
1590 {
1591  WAPEvent *ppg_event;
1592  List *push_headers, *application_headers, *bearer_headers;
1593 
1594  push_headers = http_header_duplicate(e->u.S_Connect_Ind.client_headers);
1595  application_headers = http_create_empty_headers();
1596  bearer_headers = http_create_empty_headers();
1597 
1598  ppg_event = wap_event_create(Pom_Connect_Ind);
1599  ppg_event->u.Pom_Connect_Ind.addr_tuple =
1600  wap_addr_tuple_duplicate(e->u.S_Connect_Ind.addr_tuple);
1601  ppg_event->u.Pom_Connect_Ind.requested_capabilities =
1602  wsp_cap_duplicate_list(e->u.S_Connect_Ind.requested_capabilities);
1603 
1604  check_application_headers(&push_headers, &application_headers);
1605  ppg_event->u.Pom_Connect_Ind.accept_application = application_headers;
1606 
1607  decode_bearer_indication(&push_headers, &bearer_headers);
1608 
1609  if (gwlist_len(bearer_headers) == 0) {
1610  http_destroy_headers(bearer_headers);
1611  ppg_event->u.Pom_Connect_Ind.bearer_indication = NULL;
1612  } else
1613  ppg_event->u.Pom_Connect_Ind.bearer_indication = bearer_headers;
1614 
1615  ppg_event->u.Pom_Connect_Ind.push_headers = push_headers;
1616  ppg_event->u.Pom_Connect_Ind.session_id = e->u.S_Connect_Ind.session_id;
1617  debug("wap.appl", 0, "APPL: making OTA connection indication to PPG");
1618 
1619  wap_push_ppg_dispatch_event(ppg_event);
1620 }
1621 
1622 
1624 {
1625  WAPEvent *ppg_event;
1626 
1627  ppg_event = wap_event_create(Pom_Disconnect_Ind);
1628  ppg_event->u.Pom_Disconnect_Ind.reason_code =
1629  e->u.S_Disconnect_Ind.reason_code;
1630  ppg_event->u.Pom_Disconnect_Ind.error_headers =
1631  octstr_duplicate(e->u.S_Disconnect_Ind.error_headers);
1632  ppg_event->u.Pom_Disconnect_Ind.error_body =
1633  octstr_duplicate(e->u.S_Disconnect_Ind.error_body);
1634  ppg_event->u.Pom_Disconnect_Ind.session_handle =
1635  e->u.S_Disconnect_Ind.session_handle;
1636 
1637  wap_push_ppg_dispatch_event(ppg_event);
1638 }
1639 
1640 
1641 /*
1642  * We do not implement acknowledgement headers
1643  */
1644 static void confirm_push(WAPEvent *e)
1645 {
1646  WAPEvent *ppg_event;
1647 
1648  ppg_event = wap_event_create(Po_ConfirmedPush_Cnf);
1649  ppg_event->u.Po_ConfirmedPush_Cnf.server_push_id =
1650  e->u.S_ConfirmedPush_Cnf.server_push_id;
1651  ppg_event->u.Po_ConfirmedPush_Cnf.session_handle =
1652  e->u.S_ConfirmedPush_Cnf.session_id;
1653 
1654  debug("wap.appl", 0, "OTA: confirming push for ppg");
1655  wap_push_ppg_dispatch_event(ppg_event);
1656 }
1657 
1658 
1660 {
1661  WAPEvent *ppg_event;
1662 
1663  ppg_event = wap_event_create(Po_PushAbort_Ind);
1664  ppg_event->u.Po_PushAbort_Ind.push_id = e->u.S_PushAbort_Ind.push_id;
1665  ppg_event->u.Po_PushAbort_Ind.reason = e->u.S_PushAbort_Ind.reason;
1666  ppg_event->u.Po_PushAbort_Ind.session_handle =
1667  e->u.S_PushAbort_Ind.session_id;
1668 
1669  debug("wap.push.ota", 0, "OTA: making push abort indication for ppg");
1670  wap_push_ppg_dispatch_event(ppg_event);
1671 }
1672 
1673 
1675 {
1676  WAPEvent *ppg_event;
1677 
1678  ppg_event = wap_event_create(Pom_Suspend_Ind);
1679  ppg_event->u.Pom_Suspend_Ind.reason = e->u.S_Suspend_Ind.reason;
1680  ppg_event->u.Pom_Suspend_Ind.session_id = e->u.S_Suspend_Ind.session_id;
1681 
1682  wap_push_ppg_dispatch_event(ppg_event);
1683 }
1684 
1685 
1686 /*
1687  * Find Bearer-Indication amongst client headers, decode it and assign it to
1688  * a separate field in the event structure.
1689  */
1691 {
1692  WAPEvent *ppg_event;
1693  List *push_headers, *bearer_headers;
1694 
1695  push_headers = http_header_duplicate(e->u.S_Resume_Ind.client_headers);
1696  bearer_headers = http_create_empty_headers();
1697 
1698  ppg_event = wap_event_create(Pom_Resume_Ind);
1699  ppg_event->u.Pom_Resume_Ind.addr_tuple = wap_addr_tuple_duplicate(
1700  e->u.S_Resume_Ind.addr_tuple);
1701 
1702  decode_bearer_indication(&push_headers, &bearer_headers);
1703 
1704  if (gwlist_len(bearer_headers) == 0) {
1705  http_destroy_headers(bearer_headers);
1706  ppg_event->u.Pom_Resume_Ind.bearer_indication = NULL;
1707  } else
1708  ppg_event->u.Pom_Resume_Ind.bearer_indication = bearer_headers;
1709 
1710  ppg_event->u.Pom_Resume_Ind.client_headers = push_headers;
1711  ppg_event->u.Pom_Resume_Ind.session_id = e->u.S_Resume_Ind.session_id;
1712 
1713  wap_push_ppg_dispatch_event(ppg_event);
1714 }
1715 
1716 
1717 /*
1718  * Server headers are mentioned in table in ota 6.4.1, but none of the primit-
1719  * ives use them. They are optional in S_Connect_Res, so we do not use them.
1720  */
1722 {
1723  WAPEvent *wsp_event;
1724 
1725  gw_assert(e->type = Pom_Connect_Res);
1726 
1727  wsp_event = wap_event_create(S_Connect_Res);
1728  wsp_event->u.S_Connect_Res.session_id = e->u.Pom_Connect_Res.session_id;
1729  wsp_event->u.S_Connect_Res.negotiated_capabilities =
1730  wsp_cap_duplicate_list(e->u.Pom_Connect_Res.negotiated_capabilities);
1731  debug("wap.appl", 0, "APPL: making push connect response");
1732 
1733  wsp_session_dispatch_event(wsp_event);
1734 }
1735 
int get_cookies(List *headers, const WSPMachine *sm)
Definition: cookies.c:111
static void return_replies_thread(void *)
Definition: wap-appl.c:1066
static void indicate_push_connection(WAPEvent *e)
Definition: wap-appl.c:1589
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
Octstr * radius_acct_get_msisdn(Octstr *client_ip)
Definition: radius_acct.c:363
static void add_session_id(List *headers, long session_id)
Definition: wap-appl.c:548
Octstr * error_requesting_back(Octstr *url, Octstr *referer)
Definition: wap-error.c:67
List * http_header_find_all(List *headers, char *name)
Definition: http.c:3092
void http_header_get(List *headers, long i, Octstr **name, Octstr **value)
Definition: http.c:2879
static Counter * fetches
Definition: wap-appl.c:135
List * wml_charsets(void)
Definition: xml_shared.c:262
static void return_unit_reply(WAPAddrTuple *tuple, long transaction_id, long status, List *headers, Octstr *body)
Definition: wap-appl.c:713
static void add_charset_headers(List *headers)
Definition: wap-appl.c:515
unsigned int print_symbolic_assembler
Definition: ws.h:154
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2863
static void normalize_charset(struct content *content, List *device_headers)
Definition: wap-appl.c:729
Definition: parse.c:65
void http_caller_signal_shutdown(HTTPCaller *caller)
Definition: http.c:913
void counter_destroy(Counter *counter)
Definition: counter.c:110
static void main_thread(void *)
Definition: wap-appl.c:314
PPGSessionMachine * wap_push_ppg_have_push_session_for(WAPAddrTuple *tuple)
Definition: wap_push_ppg.c:488
void gwlist_produce(List *list, void *item)
Definition: list.c:411
static int have_ppg
Definition: wap-appl.c:176
long gwlist_len(List *list)
Definition: list.c:166
static void indicate_push_suspend(WAPEvent *e)
Definition: wap-appl.c:1674
static void start_fetch(WAPEvent *)
Definition: wap-appl.c:1103
void http_header_combine(List *old_headers, List *new_headers)
Definition: http.c:3045
static void indicate_push_resume(WAPEvent *e)
Definition: wap-appl.c:1690
static Octstr * get_referer_url(const WSPMachine *sm)
Definition: wap-appl.c:685
Octstr * msisdn
Definition: wap-appl.c:163
Octstr * address
Definition: wap_addr.h:68
long octstr_search(const Octstr *haystack, const Octstr *needle, long pos)
Definition: octstr.c:1068
Octstr * error_converting(Octstr *url, Octstr *type)
Definition: wap-error.c:109
WsCompilerPtr ws_create(WsCompilerParams *params)
Definition: ws.c:135
Octstr * method
Definition: wap-appl.c:159
static void add_via(List *headers)
Definition: wap-appl.c:571
void http_header_get_content_type(List *headers, Octstr **type, Octstr **charset)
Definition: http.c:3202
unsigned int use_latin1_strings
Definition: ws.h:109
#define NUM_DECONVERTERS
Definition: wap-appl.c:228
static Octstr * convert_wml_to_wmlc(struct content *content)
Definition: wap-appl.c:1316
unsigned long counter_decrease(Counter *counter)
Definition: counter.c:155
int http_name2method(Octstr *method)
Definition: http.c:3633
List * wsp_cap_duplicate_list(List *caps_list)
Definition: wsp_caps.c:125
int mime_decompile(Octstr *binary_mime, Octstr **mime)
WsResult
Definition: ws.h:203
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static void indicate_push_abort(WAPEvent *e)
Definition: wap-appl.c:1659
void gwthread_join_every(gwthread_func_t *func)
static int deconvert_content(struct content *content)
Definition: wap-appl.c:469
unsigned long counter_increase(Counter *counter)
Definition: counter.c:123
Octstr * charset
Definition: test_ota.c:68
void http_header_mark_transformation(List *headers, Octstr *new_body, Octstr *new_type)
Definition: http.c:3180
WAPAddrTuple * wap_addr_tuple_duplicate(WAPAddrTuple *tuple)
Definition: wap_addr.c:125
static void add_accept_headers(List *headers)
Definition: wap-appl.c:523
Octstr * version
Definition: wap-appl.c:148
Octstr * body
Definition: wap-appl.c:144
static struct @30 converters[]
void wsp_unit_dispatch_event(WAPEvent *event)
Definition: wsp_unit.c:124
static void add_kannel_version(List *headers)
Definition: wap-appl.c:505
Octstr * error_requesting(Octstr *url)
Definition: wap-error.c:89
void http_destroy_headers(List *headers)
Definition: http.c:2856
long session_id
Definition: wap-appl.c:158
void wap_appl_shutdown(void)
Definition: wap-appl.c:268
static void return_reply(int status, Octstr *content_body, List *headers, long sdu_size, WAPEvent *orig_event, long session_id, Octstr *method, Octstr *url, int x_wap_tod, List *request_headers, Octstr *msisdn)
Definition: wap-appl.c:764
void http_start_request(HTTPCaller *caller, int method, Octstr *url, List *headers, Octstr *body, int follow, void *id, Octstr *certkeyfile)
Definition: http.c:1745
List * request_headers
Definition: wap-appl.c:162
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
Definition: http.h:142
Definition: cfg.c:164
static void add_x_wap_tod(List *headers)
Definition: wap-appl.c:592
Counter * counter_create(void)
Definition: counter.c:94
WsResult ws_compile_data(WsCompilerPtr compiler, const char *input_name, const unsigned char *input, size_t input_len, unsigned char **output_return, size_t *output_len_return)
Definition: ws.c:206
static Octstr * deconvert_multipart_formdata(struct content *content)
Definition: wap-appl.c:1399
Definition: ws.h:206
void gwlist_remove_producer(List *list)
Definition: list.c:401
#define HEALTH_DECK
Definition: wap-appl.c:1097
static void response_push_connection(WAPEvent *e)
Definition: wap-appl.c:1721
Octstr * type
Definition: wap-appl.c:145
WSPMachine * find_session_machine_by_id(int)
Definition: wsp_session.c:1434
static Octstr * convert_wmlscript_to_wmlscriptc(struct content *content)
Definition: wap-appl.c:1335
List * http_create_empty_headers(void)
Definition: http.c:2849
void wap_event_destroy_item(void *event)
Definition: wap_events.c:130
static enum @29 run_status
static void add_client_sdu_size(List *headers, long sdu_size)
Definition: wap-appl.c:559
void http_header_pack(List *headers)
Definition: http.c:2969
unsigned int print_assembler
Definition: ws.h:157
#define octstr_duplicate(ostr)
Definition: octstr.h:187
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
void wap_map_user_destroy(void)
Definition: wap-maps.c:174
int http_status_class(int code)
Definition: http.c:3621
const char * wap_event_name(WAPEventName type)
Definition: wap_events.c:169
void * meta_name_cb_context
Definition: ws.h:174
int wml_compile(Octstr *wml_text, Octstr *charset, Octstr **wml_binary, Octstr *version)
Definition: wml_compiler.c:360
WsPragmaMetaProc meta_name_cb
Definition: ws.h:173
char * name
Definition: smsc_cimd2.c:212
int octstr_case_compare(const Octstr *os1, const Octstr *os2)
Definition: octstr.c:901
#define wap_event_create(type)
Definition: wap_events.h:107
void warning(int err, const char *fmt,...)
Definition: log.c:624
static void split_header_list(List **headers, List **new_headers, char *name)
Definition: wap-appl.c:1575
void http_remove_hop_headers(List *headers)
Definition: http.c:3138
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define gwthread_create(func, arg)
Definition: gwthread.h:90
static int method
Definition: test_http.c:76
#define octstr_create(cstr)
Definition: octstr.h:125
long port
Definition: wap_addr.h:70
void octstr_destroy_item(void *os)
Definition: octstr.c:334
unsigned long counter_value(Counter *counter)
Definition: counter.c:145
gw_assert(wtls_machine->packet_to_send!=NULL)
Octstr * get_official_name(void)
Definition: socket.c:627
#define NUM_CONVERTERS
Definition: wap-appl.c:212
static void set_referer_url(Octstr *url, WSPMachine *sm)
Definition: wap-appl.c:675
Definition: log.h:69
Octstr * url
Definition: wap-appl.c:147
static void confirm_push(WAPEvent *e)
Definition: wap-appl.c:1644
WsIOProc stdout_cb
Definition: ws.h:164
WAPAddr * remote
Definition: wap_addr.h:74
char * type
Definition: wap-appl.c:196
#define http_receive_result(caller, status, final_url, headers, body)
Definition: http.h:383
static Cfg * cfg
Definition: smsbox.c:115
void wap_map_destroy(void)
Definition: wap-maps.c:152
Octstr * http_header_value(List *headers, Octstr *name)
Definition: http.c:2909
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
void wsp_session_dispatch_event(WAPEvent *event)
Definition: wsp_session.c:228
Definition: octstr.c:118
void * gwlist_consume(List *list)
Definition: list.c:427
static List * negotiate_capabilities(List *req_caps)
Definition: wap-appl.c:1439
void alog(const char *fmt,...)
Definition: accesslog.c:206
static int convert_content(struct content *content, List *request_headers, int allow_empty)
Definition: wap-appl.c:421
WsPragmaMetaProc meta_http_equiv_cb
Definition: ws.h:178
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
const char * ws_result_to_string(WsResult result)
Definition: ws.c:234
long wap_appl_get_load(void)
Definition: wap-appl.c:295
static struct @31 deconverters[]
Octstr * find_charset_encoding(Octstr *document)
Definition: xml_shared.c:145
long x_wap_tod
Definition: wap-appl.c:161
#define panic
Definition: log.h:87
void * meta_http_equiv_cb_context
Definition: ws.h:179
WAPEvent * event
Definition: wap-appl.c:157
Octstr * charset
Definition: wap-appl.c:146
int octstr_str_compare(const Octstr *ostr, const char *str)
Definition: octstr.c:971
long http_header_remove_all(List *headers, char *name)
Definition: http.c:3112
WAPEventName type
Definition: wap_events.h:88
int wsp_smart_errors
Definition: wapbox.c:111
static void return_session_reply(long server_transaction_id, long status, List *headers, Octstr *body, long session_id)
Definition: wap-appl.c:694
void wap_push_ppg_dispatch_event(WAPEvent *e)
Definition: wap_push_ppg.c:476
HTTPCaller * http_caller_create(void)
Definition: http.c:897
int http_charset_accepted(List *headers, char *charset)
Definition: http.c:3486
List * http_header_duplicate(List *headers)
Definition: http.c:2946
int set_cookies(List *headers, WSPMachine *sm)
Definition: cookies.c:162
char * result_type
Definition: wap-appl.c:197
static void add_network_info(List *headers, WAPAddrTuple *addr_tuple)
Definition: wap-appl.c:538
static void dev_null(const char *data, size_t len, void *context)
Definition: wap-appl.c:1310
#define gwlist_create()
Definition: list.h:136
void wap_appl_init(Cfg *cfg)
Definition: wap-appl.c:249
static void server(int lport, int pport)
Octstr * date_format_http(unsigned long unixtime)
Definition: date.c:89
WsIOProc stderr_cb
Definition: ws.h:168
long client_SDU_size
Definition: wap-appl.c:156
void http_caller_destroy(HTTPCaller *caller)
Definition: http.c:907
static HTTPCaller * caller
Definition: wap-appl.c:129
static void indicate_push_disconnect(WAPEvent *e)
Definition: wap-appl.c:1623
Octstr * url
Definition: wap-appl.c:160
static List * queue
Definition: wap-appl.c:123
int http_type_accepted(List *headers, char *type)
Definition: http.c:3480
static void add_msisdn(List *headers, WAPAddrTuple *addr_tuple, Octstr *send_msisdn_header)
Definition: wap-appl.c:608
static List * charsets
Definition: wap-appl.c:141
void gwlist_add_producer(List *list)
Definition: list.c:383
union WAPEvent::@87 u
Octstr * device_home
Definition: wapbox.c:112
static Octstr * url
Definition: test_xmlrpc.c:84
static void check_application_headers(List **headers, List **app_headers)
Definition: wap-appl.c:1462
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
#define octstr_create_from_data(data, len)
Definition: octstr.h:134
Definition: list.c:102
void http_header_dump(List *headers)
Definition: http.c:3404
alert u SEC_Terminate_Req addr_tuple
void wap_event_destroy(WAPEvent *event)
Definition: wap_events.c:102
void wap_appl_dispatch(WAPEvent *event)
Definition: wap-appl.c:288
int charset_convert(Octstr *string, char *charset_from, char *charset_to)
Definition: charset.c:589
PPGSessionMachine * wap_push_ppg_have_push_session_for_sid(long sid)
Definition: wap_push_ppg.c:503
static void decode_bearer_indication(List **headers, List **bearer_headers)
Definition: wap-appl.c:1522
void wap_map_url(Octstr **osp, Octstr **send_msisdn_query, Octstr **send_msisdn_header, Octstr **send_msisdn_format, int *accept_cookies)
Definition: wap-maps.c:208
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:869
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.