wap-appl.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:41k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * gw/wap-appl.c - wapbox application layer and push ota indication, response
  3.  * and confirmation primitive implementation.
  4.  *
  5.  * This module implements indication and confirmation primitives of WAP-189-
  6.  * PushOTA-20000217-a (hereafter called ota). 
  7.  * In addition, WAP-200-WDP-20001212-a (wdp) is referred.
  8.  * Wapbox application layer is not a Wapforum protocol. 
  9.  *
  10.  * The application layer is reads events from its event queue, fetches the 
  11.  * corresponding URLs and feeds back events to the WSP layer (pull). 
  12.  *
  13.  * In addition, the layer forwards WSP events related to push to the module 
  14.  * wap_push_ppg and wsp, implementing indications, responses  and confirma-
  15.  * tions of ota.
  16.  *
  17.  * Note that push header encoding and decoding are divided two parts:
  18.  * first decoding and encoding numeric values and then packing these values
  19.  * into WSP format and unpacking them from WSP format. This module contains
  20.  * encoding part.
  21.  *
  22.  * Lars Wirzenius
  23.  */
  24. #include <string.h>
  25. #include "gwlib/gwlib.h"
  26. #include "wmlscript/ws.h"
  27. #include "xml_shared.h"
  28. #include "wml_compiler.h"
  29. #include "wap/wap.h"
  30. #include "wap-appl.h"
  31. #include "wap_push_ppg.h"
  32. #include "wap/wsp_strings.h"
  33. #include "wap/wsp_caps.h"
  34. #include "wap/wsp.h"
  35. #ifdef ENABLE_COOKIES
  36. #include "wap/cookies.h"
  37. #endif
  38. #include "wap-error.h"
  39. /*
  40.  * Give the status the module:
  41.  *
  42.  * limbo
  43.  * not running at all
  44.  * running
  45.  * operating normally
  46.  * terminating
  47.  * waiting for operations to terminate, returning to limbo
  48.  */
  49. static enum { limbo, running, terminating } run_status = limbo;
  50. /*
  51.  * The queue of incoming events.
  52.  */
  53. static List *queue = NULL;
  54. /*
  55.  * HTTP caller identifier for application layer.
  56.  */
  57. static HTTPCaller *caller = NULL;
  58. /*
  59.  * Number of currently running HTTP fetching threads.
  60.  */
  61. static Counter *fetches = NULL;
  62. /*
  63.  * Charsets supported by WML compiler, queried from wml_compiler.
  64.  */
  65. static List *charsets = NULL;
  66. struct content {
  67.     Octstr *body;
  68.     Octstr *type;
  69.     Octstr *charset;
  70.     Octstr *url;
  71. };
  72. /*
  73.  * A mapping from HTTP request identifiers to information about the request.
  74.  */
  75. struct request_data {
  76.     long client_SDU_size;
  77.     WAPEvent *event;
  78.     long session_id;
  79.     Octstr *url;
  80.     long x_wap_tod;
  81.     List *request_headers;
  82. };
  83. /*
  84.  * Indicator for WSP smart error messaging
  85.  */
  86. extern int wsp_smart_errors;
  87. /*
  88.  *
  89.  */
  90. static int have_ppg = 0;
  91. /*
  92.  * Private functions.
  93.  */
  94. static void main_thread(void *);
  95. static void start_fetch(WAPEvent *);
  96. static void return_replies_thread(void *);
  97. static void  dev_null(const char *data, size_t len, void *context);
  98. static Octstr *convert_wml_to_wmlc(struct content *content);
  99. static Octstr *convert_wmlscript_to_wmlscriptc(struct content *content);
  100. static void wsp_http_map_url(Octstr **osp);
  101. static List *negotiate_capabilities(List *req_caps);
  102. static struct {
  103.     char *type;
  104.     char *result_type;
  105.     Octstr *(*convert)(struct content *);
  106. } converters[] = {
  107.     { "text/vnd.wap.wml",
  108.       "application/vnd.wap.wmlc",
  109.       convert_wml_to_wmlc },
  110.     { "text/vnd.wap.wmlscript",
  111.       "application/vnd.wap.wmlscriptc",
  112.       convert_wmlscript_to_wmlscriptc },
  113. };
  114. #define NUM_CONVERTERS ((long)(sizeof(converters) / sizeof(converters[0])))
  115. /*
  116.  * Following functions implement indications and conformations part of Push
  117.  * OTA protocol.
  118.  */
  119. static void indicate_push_connection(WAPEvent *e);
  120. static void indicate_push_disconnect(WAPEvent *e);
  121. static void indicate_push_suspend(WAPEvent *e);
  122. static void indicate_push_resume(WAPEvent *e);
  123. static void confirm_push(WAPEvent *e);
  124. static void indicate_push_abort(WAPEvent *e);
  125. static void split_header_list(List **headers, List **new_headers, char *name);
  126. static void check_application_headers(List **headers, List **app_headers);
  127. static void decode_bearer_indication(List **headers, List **bearer_headers);
  128. static void response_push_connection(WAPEvent *e);
  129. /***********************************************************************
  130.  * The public interface to the application layer.
  131.  */
  132. void wap_appl_init(Cfg *cfg) 
  133. {
  134.     gw_assert(run_status == limbo);
  135.     queue = list_create();
  136.     fetches = counter_create();
  137.     list_add_producer(queue);
  138.     run_status = running;
  139.     charsets = wml_charsets();
  140.     caller = http_caller_create();
  141.     gwthread_create(main_thread, NULL);
  142.     gwthread_create(return_replies_thread, NULL);
  143.     if (cfg != NULL)
  144.         have_ppg = 1;
  145.     else
  146.         have_ppg = 0;
  147. }
  148. void wap_appl_shutdown(void) 
  149. {
  150.     gw_assert(run_status == running);
  151.     run_status = terminating;
  152.     
  153.     list_remove_producer(queue);
  154.     gwthread_join_every(main_thread);
  155.     
  156.     http_caller_signal_shutdown(caller);
  157.     gwthread_join_every(return_replies_thread);
  158.     
  159.     http_caller_destroy(caller);
  160.     list_destroy(queue, wap_event_destroy_item);
  161.     list_destroy(charsets, octstr_destroy_item);
  162.     counter_destroy(fetches);
  163. }
  164. void wap_appl_dispatch(WAPEvent *event) 
  165. {
  166.     gw_assert(run_status == running);
  167.     list_produce(queue, event);
  168. }
  169. long wap_appl_get_load(void) 
  170. {
  171.     gw_assert(run_status == running);
  172.     return counter_value(fetches) + list_len(queue);
  173. }
  174. /***********************************************************************
  175.  * Private functions.
  176.  */
  177. /*
  178.  * When we have a push event, create ota indication or confirmation and send 
  179.  * it to ppg module. 
  180.  * Because Accept-Application and Bearer-Indication are optional, we cannot 
  181.  * rely on them. We must ask ppg main module do we have an open push session 
  182.  * for this initiator. Push is identified by push id.
  183.  * If there is no ppg configured, do not refer to ppg's sessions' list.
  184.  */
  185. static void main_thread(void *arg) 
  186. {
  187.     WAPEvent *ind, *res;
  188.     long sid;
  189.     WAPAddrTuple *tuple;
  190.     
  191.     while (run_status == running && (ind = list_consume(queue)) != NULL) {
  192. switch (ind->type) {
  193. case S_MethodInvoke_Ind:
  194.     res = wap_event_create(S_MethodInvoke_Res);
  195.     res->u.S_MethodInvoke_Res.server_transaction_id =
  196.     ind->u.S_MethodInvoke_Ind.server_transaction_id;
  197.     res->u.S_MethodInvoke_Res.session_id =
  198.     ind->u.S_MethodInvoke_Ind.session_id;
  199.     wsp_session_dispatch_event(res);
  200.     start_fetch(ind);
  201.     break;
  202. case S_Unit_MethodInvoke_Ind:
  203.     start_fetch(ind);
  204.     break;
  205. case S_Connect_Ind:
  206.             tuple  = ind->u.S_Connect_Ind.addr_tuple;
  207.             if (have_ppg && wap_push_ppg_have_push_session_for(tuple)) {
  208.         indicate_push_connection(ind);
  209.             } else {
  210.         res = wap_event_create(S_Connect_Res);
  211.     /* FIXME: Not yet used by WSP layer */
  212.        res->u.S_Connect_Res.server_headers = NULL;
  213.        res->u.S_Connect_Res.negotiated_capabilities =
  214.            negotiate_capabilities(
  215.                ind->u.S_Connect_Ind.requested_capabilities);
  216.        res->u.S_Connect_Res.session_id = 
  217.                    ind->u.S_Connect_Ind.session_id;
  218.        wsp_session_dispatch_event(res);
  219.             }
  220.             wap_event_destroy(ind);
  221.             break;
  222. case S_Disconnect_Ind:
  223.     sid = ind->u.S_Disconnect_Ind.session_handle;
  224.             if (have_ppg && wap_push_ppg_have_push_session_for_sid(sid)) 
  225.                 indicate_push_disconnect(ind);
  226.     wap_event_destroy(ind);
  227.     break;
  228. case S_Suspend_Ind:
  229.     sid = ind->u.S_Suspend_Ind.session_id;
  230.             if (wap_push_ppg_have_push_session_for_sid(sid)) 
  231.                 indicate_push_suspend(ind);
  232.     wap_event_destroy(ind);
  233.     break;
  234. case S_Resume_Ind:
  235.     sid = ind->u.S_Resume_Ind.session_id;
  236.             if (have_ppg && wap_push_ppg_have_push_session_for_sid(sid)) 
  237.                 indicate_push_resume(ind);
  238.             else {
  239.         res = wap_event_create(S_Resume_Res);
  240.         res->u.S_Resume_Res.server_headers = NULL;
  241.         res->u.S_Resume_Res.session_id = 
  242.                     ind->u.S_Resume_Ind.session_id;
  243.         wsp_session_dispatch_event(res);
  244.         
  245.             }
  246.             wap_event_destroy(ind);
  247.     break;
  248. case S_MethodResult_Cnf:
  249.     wap_event_destroy(ind);
  250.     break;
  251.         case S_ConfirmedPush_Cnf:
  252.             confirm_push(ind);
  253.             wap_event_destroy(ind);
  254.     break;
  255. case S_MethodAbort_Ind:
  256.     /* XXX Interrupt the fetch thread somehow */
  257.     wap_event_destroy(ind);
  258.     break;
  259.         case S_PushAbort_Ind:
  260.             indicate_push_abort(ind);
  261.             wap_event_destroy(ind);
  262.     break;
  263.         case Pom_Connect_Res:
  264.     response_push_connection(ind);
  265.     wap_event_destroy(ind);
  266.     break;
  267. default:
  268.     panic(0, "APPL: Can't handle %s event", 
  269.        wap_event_name(ind->type));
  270.     break;
  271. }
  272.     }
  273. }
  274. static int convert_content(struct content *content) 
  275. {
  276.     Octstr *new_body;
  277.     int failed = 0;
  278.     int i;
  279.     
  280.     for (i = 0; i < NUM_CONVERTERS; i++) {
  281. if (octstr_str_compare(content->type, converters[i].type) == 0) {
  282.     new_body = converters[i].convert(content);
  283.     if (new_body != NULL) {
  284. octstr_destroy(content->body);
  285. content->body = new_body;
  286. octstr_destroy(content->type);
  287. content->type = octstr_create(
  288. converters[i].result_type);
  289. return 1;
  290.     }
  291.     failed = 1;
  292. }
  293.     }
  294.     
  295.     if (failed)
  296. return -1;
  297.     return 0;
  298. }
  299. /* Add a header identifying our gateway version */
  300. static void add_kannel_version(List *headers) 
  301. {
  302.     http_header_add(headers, "X-WAP-Gateway", GW_NAME "/" VERSION);
  303. }
  304. /* Add Accept-Charset: headers for stuff the WML compiler can
  305.  * convert to UTF-8. */
  306. /* XXX This is not really correct, since we will not be able
  307.  * to handle those charsets for all content types, just WML. */
  308. static void add_charset_headers(List *headers) 
  309. {
  310.     long i, len;
  311.     
  312.     gw_assert(charsets != NULL);
  313.     len = list_len(charsets);
  314.     for (i = 0; i < len; i++) {
  315. unsigned char *charset = octstr_get_cstr(list_get(charsets, i));
  316. if (!http_charset_accepted(headers, charset))
  317.     http_header_add(headers, "Accept-Charset", charset);
  318.     }
  319. }
  320. /* Add Accept: headers for stuff we can convert for the phone */
  321. static void add_accept_headers(List *headers) 
  322. {
  323.     int i;
  324.     
  325.     for (i = 0; i < NUM_CONVERTERS; i++) {
  326. if (http_type_accepted(headers, converters[i].result_type)
  327.     && !http_type_accepted(headers, converters[i].type)) {
  328.     http_header_add(headers, "Accept", converters[i].type);
  329. }
  330.     }
  331. }
  332. static void add_network_info(List *headers, WAPAddrTuple *addr_tuple) 
  333. {
  334.     if (octstr_len(addr_tuple->remote->address) > 0) {
  335. http_header_add(headers, "X_Network_Info", 
  336. octstr_get_cstr(addr_tuple->remote->address));
  337.     }
  338. }
  339. static void add_session_id(List *headers, long session_id) 
  340. {
  341.     if (session_id != -1) {
  342. char buf[40];
  343. sprintf(buf, "%ld", session_id);
  344. http_header_add(headers, "X-WAP-Session-ID", buf);
  345.     }
  346. }
  347. static void add_client_sdu_size(List *headers, long sdu_size) 
  348. {
  349.     if (sdu_size > 0) {
  350. Octstr *buf;
  351. buf = octstr_format("%ld", sdu_size);
  352. http_header_add(headers, "X-WAP-Client-SDU-Size", 
  353.           octstr_get_cstr(buf));
  354. octstr_destroy(buf);
  355.     }
  356. }
  357. static void add_via(List *headers) 
  358. {
  359.     Octstr *os;
  360.     
  361.     os = octstr_format("WAP/1.1 %S (" GW_NAME "/%s)", get_official_name(),
  362.        VERSION);
  363.     http_header_add(headers, "Via", octstr_get_cstr(os));
  364.     octstr_destroy(os);
  365. }
  366. /*
  367.  * Add an X-WAP.TOD header to the response headers.  It is defined in
  368.  * the "WAP Caching Model" specification.
  369.  * We generate it in textual form and let WSP header packing convert it
  370.  * to binary form.
  371.  */
  372. static void add_x_wap_tod(List *headers) 
  373. {
  374.     Octstr *gateway_time;
  375.     
  376.     gateway_time = date_format_http(time(NULL));
  377.     if (gateway_time == NULL) {
  378. warning(0, "Could not add X-WAP.TOD response header.");
  379. return;
  380.     }
  381.     
  382.     http_header_add(headers, "X-WAP.TOD", octstr_get_cstr(gateway_time));
  383.     octstr_destroy(gateway_time);
  384. }
  385. static void add_referer_url(List *headers, Octstr *url) 
  386. {
  387.     if (octstr_len(url) > 0) {
  388.    http_header_add(headers, "Referer", octstr_get_cstr(url));
  389.     }
  390. }
  391. static void set_referer_url(Octstr *url, WSPMachine *sm)
  392. {
  393. gw_assert(url != NULL);
  394. gw_assert(sm != NULL);
  395.     sm->referer_url = octstr_duplicate(url);
  396. }
  397. static Octstr *get_referer_url(const WSPMachine *sm)
  398. {
  399. gw_assert(sm != NULL);
  400.     return sm->referer_url;
  401. }
  402. /*
  403.  * Return the reply from an HTTP request to the phone via a WSP session.
  404.  */
  405. static void return_session_reply(long server_transaction_id, long status,
  406.                      List *headers, Octstr *body, 
  407.  long session_id)
  408. {
  409.     WAPEvent *e;
  410.     
  411.     e = wap_event_create(S_MethodResult_Req);
  412.     e->u.S_MethodResult_Req.server_transaction_id = server_transaction_id;
  413.     e->u.S_MethodResult_Req.status = status;
  414.     e->u.S_MethodResult_Req.response_headers = headers;
  415.     e->u.S_MethodResult_Req.response_body = body;
  416.     e->u.S_MethodResult_Req.session_id = session_id;
  417.     wsp_session_dispatch_event(e);
  418. }
  419. /*
  420.  * Return the reply from an HTTP request to the phone via connectionless
  421.  * WSP.
  422.  */
  423. static void return_unit_reply(WAPAddrTuple *tuple, long transaction_id,
  424.                      long status, List *headers, Octstr *body)
  425. {
  426.     WAPEvent *e;
  427.     e = wap_event_create(S_Unit_MethodResult_Req);
  428.     e->u.S_Unit_MethodResult_Req.addr_tuple = 
  429.      wap_addr_tuple_duplicate(tuple);
  430.     e->u.S_Unit_MethodResult_Req.transaction_id = transaction_id;
  431.     e->u.S_Unit_MethodResult_Req.status = status;
  432.     e->u.S_Unit_MethodResult_Req.response_headers = headers;
  433.     e->u.S_Unit_MethodResult_Req.response_body = body;
  434.     wsp_unit_dispatch_event(e);
  435. }
  436. /*
  437.  * Return an HTTP reply back to the phone.
  438.  */
  439. static void return_reply(int status, Octstr *content_body, List *headers,
  440.                 long sdu_size, WAPEvent *orig_event,
  441.                          long session_id, Octstr *url, int x_wap_tod,
  442.                          List *request_headers)
  443. {
  444.     struct content content;
  445.     int converted;
  446.     WSPMachine *sm;
  447.     content.url = url;
  448.     content.body = content_body;
  449.     if (status < 0) {
  450.         error(0, "WSP: http lookup failed, oops.");
  451.         content.charset = octstr_create("");
  452.         /* smart WSP error messaging?! */
  453.         if (wsp_smart_errors) {
  454.             Octstr *referer_url;
  455.             status = HTTP_OK;
  456.             content.type = octstr_create("text/vnd.wap.wml");
  457.             /*
  458.              * check if a referer for this URL exists and 
  459.              * get back to the previous page in this case
  460.              */
  461.             if ((referer_url = get_referer_url(find_session_machine_by_id(session_id)))) {
  462.                 content.body = error_requesting_back(url, referer_url);
  463.                 debug("wap.wsp",0,"WSP: returning smart error WML deck for referer URL");
  464.             } else {
  465.                 content.body = error_requesting(url);
  466.                 debug("wap.wsp",0,"WSP: returning smart error WML deck");
  467.             }
  468.             /* 
  469.              * if we did not connect at all there is no content in 
  470.              * the headers list, so create for the upcoming transformation
  471.              */
  472.             if (headers == NULL)
  473.                 headers = http_create_empty_headers();
  474.             converted = convert_content(&content);
  475.             if (converted == 1)
  476.                 http_header_mark_transformation(headers, content.body, content.type);
  477.         } else {
  478.             status = HTTP_BAD_GATEWAY;
  479.             content.type = octstr_create("text/plain");
  480.             content.charset = octstr_create("");
  481.             content.body = octstr_create("");
  482.         }
  483.     } else {
  484.         http_header_get_content_type(headers, &content.type, &content.charset);
  485.         alog("<%s> (%s, charset='%s') %d", 
  486.              octstr_get_cstr(url), octstr_get_cstr(content.type),
  487.              octstr_get_cstr(content.charset), status);
  488. #ifdef ENABLE_COOKIES
  489.         if (session_id != -1)
  490.             if (get_cookies(headers, find_session_machine_by_id(session_id)) == -1)
  491.                 error(0, "WSP: Failed to extract cookies");
  492. #endif
  493.         converted = convert_content(&content);
  494.         if (converted < 0) {
  495.             warning(0, "WSP: All converters for `%s' failed.",
  496.                     octstr_get_cstr(content.type));
  497.             /* Don't change status; just send the client what we did get. */
  498.         }
  499.         if (converted == 1) {
  500.             http_header_mark_transformation(headers, content.body, content.type);
  501.             /* 
  502.              * set referer URL to WSPMachine, but only if this was a converted
  503.              * content-type, like .wml
  504.              */
  505.             if (session_id != -1) {
  506.                 debug("wap.wsp.http",0,"WSP: Setting Referer URL to <%s>", 
  507.                       octstr_get_cstr(url));
  508.                 if ((sm = find_session_machine_by_id(session_id)) != NULL) {
  509.                     set_referer_url(url, sm);
  510.                 } else {
  511.                     error(0,"WSP: Failed to find session machine for ID %ld",
  512.                           session_id);
  513.                 }
  514.             }
  515.         }
  516.     }
  517.     if (headers == NULL)
  518.         headers = http_create_empty_headers();
  519.     http_remove_hop_headers(headers);
  520.     http_header_remove_all(headers, "X-WAP.TOD");
  521.     if (x_wap_tod)
  522.         add_x_wap_tod(headers);
  523.     if (content.body == NULL)
  524.         content.body = octstr_create("");
  525.     /*
  526.      * Deal with otherwise wap-aware servers that return text/html error
  527.      * messages if they report an error.
  528.      * (Normally we leave the content type alone even if the client doesn't
  529.      * claim to accept it, because the server might know better than the
  530.      * gateway.)
  531.      */
  532.     if (http_status_class(status) != HTTP_STATUS_SUCCESSFUL &&
  533.         !http_type_accepted(request_headers, octstr_get_cstr(content.type))) {
  534.         warning(0, "WSP: Content type <%s> not supported by client,"
  535.                    " deleting body.", octstr_get_cstr(content.type));
  536.         octstr_destroy(content.body);
  537.         content.body = octstr_create("");
  538.         octstr_destroy(content.type);
  539.         content.type = octstr_create("text/plain");
  540.         http_header_mark_transformation(headers, content.body, content.type);
  541.     }
  542.     /*
  543.      * If the response is too large to be sent to the client,
  544.      * suppress it and inform the client.
  545.      */
  546.     if (octstr_len(content.body) > sdu_size && sdu_size > 0) {
  547.         /*
  548.          * Only change the status if it indicated success.
  549.          * If it indicated an error, then that information is
  550.          * more useful to the client than our "Bad Gateway" would be.
  551.          * The too-large body is probably an error page in html.
  552.          */
  553.         if (http_status_class(status) == HTTP_STATUS_SUCCESSFUL)
  554.             status = HTTP_BAD_GATEWAY;
  555.         warning(0, "WSP: Entity at %s too large (size %ld B, limit %lu B)",
  556.                 octstr_get_cstr(url), octstr_len(content.body), sdu_size);
  557.         octstr_destroy(content.body);
  558.         content.body = octstr_create("");
  559.         http_header_mark_transformation(headers, content.body, content.type);
  560.     }
  561.     if (orig_event->type == S_MethodInvoke_Ind) {
  562.         return_session_reply(orig_event->u.S_MethodInvoke_Ind.server_transaction_id,
  563.                              status, headers, content.body, session_id);
  564.     } else {
  565.         return_unit_reply(orig_event->u.S_Unit_MethodInvoke_Ind.addr_tuple,
  566.                           orig_event->u.S_Unit_MethodInvoke_Ind.transaction_id,
  567.                           status, headers, content.body);
  568.     }
  569.     octstr_destroy(content.type); /* body was re-used above */
  570.     octstr_destroy(content.charset);
  571.     octstr_destroy(url);          /* same as content.url */
  572.     counter_decrease(fetches);
  573. }
  574. /*
  575.  * This thread receives replies from HTTP layer and sends them back to
  576.  * the phone.
  577.  */
  578. static void return_replies_thread(void *arg)
  579. {
  580.     Octstr *body;
  581.     struct request_data *p;
  582.     int status;
  583.     Octstr *final_url;
  584.     List *headers;
  585.     while (run_status == running) {
  586.         p = http_receive_result(caller, &status, &final_url, &headers, &body);
  587.         if (p == NULL)
  588.             break;
  589.         return_reply(status, body, headers, p->client_SDU_size,
  590.                      p->event, p->session_id, p->url, p->x_wap_tod,
  591.                      p->request_headers);
  592.         wap_event_destroy(p->event);
  593.         http_destroy_headers(p->request_headers);
  594.         gw_free(p);
  595.         octstr_destroy(final_url);
  596.     }
  597. }
  598. /*
  599.  * This WML deck is returned when the user asks for the URL "kannel:alive".
  600.  */
  601. #define HEALTH_DECK 
  602.     "<?xml version="1.0"?>" 
  603.     "<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD 1.1//EN" " 
  604.     ""http://www.wapforum.org/DTD/wml_1.1.xml">" 
  605.     "<wml><card id="health"><p>Ok</p></card></wml>"
  606. static void start_fetch(WAPEvent *event) 
  607. {
  608.     int ret;
  609.     long client_SDU_size; /* 0 means no limit */
  610.     Octstr *url;
  611.     Octstr *referer_url;
  612.     List *session_headers;
  613.     List *request_headers;
  614.     List *actual_headers;
  615.     List *resp_headers;
  616.     WAPAddrTuple *addr_tuple;
  617.     long session_id;
  618.     Octstr *content_body;
  619.     Octstr *method;     /* type of request, normally a get or a post */
  620.     Octstr *request_body;
  621.     int x_wap_tod;          /* X-WAP.TOD header was present in request */
  622.     Octstr *magic_url;
  623.     struct request_data *p;
  624.     
  625.     counter_increase(fetches);
  626.     
  627.     if (event->type == S_MethodInvoke_Ind) {
  628.         struct S_MethodInvoke_Ind *p;
  629.     
  630.         p = &event->u.S_MethodInvoke_Ind;
  631.         session_headers = p->session_headers;
  632.         request_headers = p->request_headers;
  633.         url = octstr_duplicate(p->request_uri);
  634.         addr_tuple = p->addr_tuple;
  635.         session_id = p->session_id;
  636.         client_SDU_size = p->client_SDU_size;
  637.         request_body = octstr_duplicate(p->request_body);
  638.         method = p->method;
  639.     } else {
  640.         struct S_Unit_MethodInvoke_Ind *p;
  641.         p = &event->u.S_Unit_MethodInvoke_Ind;
  642.         session_headers = NULL;
  643.         request_headers = p->request_headers;
  644.         url = octstr_duplicate(p->request_uri);
  645.         addr_tuple = p->addr_tuple;
  646.         session_id = -1;
  647.         client_SDU_size = 0; /* No limit */
  648.         request_body = octstr_duplicate(p->request_body);
  649.         method = p->method;
  650.     }
  651.     
  652.     wsp_http_map_url(&url);
  653.     
  654.     actual_headers = list_create();
  655.     
  656.     if (session_headers != NULL)
  657.         http_header_combine(actual_headers, session_headers);
  658.     if (request_headers != NULL)
  659.         http_header_combine(actual_headers, request_headers);
  660.     
  661.     http_remove_hop_headers(actual_headers);
  662.     x_wap_tod = http_header_remove_all(actual_headers, "X-WAP.TOD");
  663.     add_accept_headers(actual_headers);
  664.     add_charset_headers(actual_headers);
  665.     add_network_info(actual_headers, addr_tuple);
  666.     add_client_sdu_size(actual_headers, client_SDU_size);
  667.     add_via(actual_headers);
  668.     
  669. #ifdef ENABLE_COOKIES
  670.     if ((session_id != -1) && 
  671.         (set_cookies(actual_headers, find_session_machine_by_id(session_id)) == -1)) 
  672.         error(0, "WSP: Failed to add cookies");
  673. #endif
  674.     /* set referer URL to HTTP header from WSPMachine */
  675.     if (session_id != -1) {
  676.         if ((referer_url = get_referer_url(find_session_machine_by_id(session_id))) != NULL) {
  677.             add_referer_url(actual_headers, referer_url);
  678.         }
  679.     }
  680.     
  681.     add_kannel_version(actual_headers);
  682.     add_session_id(actual_headers, session_id);
  683.     
  684.     http_header_pack(actual_headers);
  685.     
  686.     magic_url = octstr_imm("kannel:alive");
  687.     if (octstr_str_compare(method, "GET")  == 0 &&
  688.         octstr_compare(url, magic_url) == 0) {
  689.         ret = HTTP_OK;
  690.         resp_headers = list_create();
  691.         http_header_add(resp_headers, "Content-Type", "text/vnd.wap.wml");
  692.         content_body = octstr_create(HEALTH_DECK);
  693.         octstr_destroy(request_body);
  694.         return_reply(ret, content_body, resp_headers, client_SDU_size,
  695.                      event, session_id, url, x_wap_tod, actual_headers);
  696.         wap_event_destroy(event);
  697.         http_destroy_headers(actual_headers);
  698.     } else if (octstr_str_compare(method, "GET") == 0 ||
  699.                octstr_str_compare(method, "POST") == 0 ||
  700.                octstr_str_compare(method, "HEAD") == 0) {
  701.         if (request_body != NULL && (octstr_str_compare(method, "GET") == 0 ||
  702.                                      octstr_str_compare(method, "HEAD") == 0)) {
  703.             octstr_destroy(request_body);
  704.             request_body = NULL;
  705.         }
  706.         p = gw_malloc(sizeof(*p));
  707.         p->client_SDU_size = client_SDU_size;
  708.         p->event = event;
  709.         p->session_id = session_id;
  710.         p->url = url;
  711.         p->x_wap_tod = x_wap_tod;
  712.         p->request_headers = actual_headers;
  713.         http_start_request(caller, http_name2method(method), url, actual_headers, 
  714.                            request_body, 0, p, NULL);
  715.         octstr_destroy(request_body);
  716.     } else {
  717.         error(0, "WSP: Method %s not supported.", octstr_get_cstr(method));
  718.         content_body = octstr_create("");
  719.         resp_headers = NULL;
  720.         ret = HTTP_NOT_IMPLEMENTED;
  721.         octstr_destroy(request_body);
  722.         return_reply(ret, content_body, resp_headers, client_SDU_size,
  723.                      event, session_id, url, x_wap_tod, actual_headers);
  724.         wap_event_destroy(event);
  725.         http_destroy_headers(actual_headers);
  726.     }
  727. }
  728. /* Shut up WMLScript compiler status/trace messages. */
  729. static void dev_null(const char *data, size_t len, void *context) 
  730. {
  731.     /* nothing */
  732. }
  733. static Octstr *convert_wml_to_wmlc(struct content *content) 
  734. {
  735.     Octstr *wmlc;
  736.     int ret;
  737.     
  738.     ret = wml_compile(content->body, content->charset, &wmlc);
  739.     if (ret == 0)
  740. return wmlc;
  741.     warning(0, "WSP: WML compilation failed.");
  742.     return NULL;
  743. }
  744. static Octstr *convert_wmlscript_to_wmlscriptc(struct content *content) 
  745. {
  746.     WsCompilerParams params;
  747.     WsCompilerPtr compiler;
  748.     WsResult result;
  749.     unsigned char *result_data;
  750.     size_t result_size;
  751.     Octstr *wmlscriptc;
  752.     
  753.     memset(&params, 0, sizeof(params));
  754.     params.use_latin1_strings = 0;
  755.     params.print_symbolic_assembler = 0;
  756.     params.print_assembler = 0;
  757.     params.meta_name_cb = NULL;
  758.     params.meta_name_cb_context = NULL;
  759.     params.meta_http_equiv_cb = NULL;
  760.     params.meta_http_equiv_cb_context = NULL;
  761.     params.stdout_cb = dev_null;
  762.     params.stderr_cb = dev_null;
  763.     
  764.     compiler = ws_create(&params);
  765.     if (compiler == NULL) {
  766. panic(0, "WSP: could not create WMLScript compiler");
  767. exit(1);
  768.     }
  769.     
  770.     result = ws_compile_data(compiler, 
  771.      octstr_get_cstr(content->url),
  772.      octstr_get_cstr(content->body),
  773.      octstr_len(content->body),
  774.      &result_data,
  775.      &result_size);
  776.     if (result != WS_OK) {
  777. warning(0, "WSP: WMLScript compilation failed: %s",
  778. ws_result_to_string(result));
  779. wmlscriptc = NULL;
  780.     } else {
  781. wmlscriptc = octstr_create_from_data(result_data, result_size);
  782.     }
  783.     
  784.     return wmlscriptc;
  785. }
  786. /* The interface for capability negotiation is a bit different from
  787.  * the negotiation at WSP level, to make it easier to program.
  788.  * The application layer gets a list of requested capabilities,
  789.  * basically a straight decoding of the WSP level capabilities.
  790.  * It replies with a list of all capabilities it wants to set or
  791.  * refuse.  (Refuse by setting cap->data to NULL).  Any capabilities
  792.  * it leaves out are considered "unknown; don't care".  The WSP layer
  793.  * will either process those itself, or refuse them.
  794.  *
  795.  * At the WSP level, not sending a reply to a capability means accepting
  796.  * what the client proposed.  If the application layer wants this to 
  797.  * happen, it should set cap->data to NULL and cap->accept to 1.
  798.  * (The WSP layer does not try to guess what kind of reply would be 
  799.  * identical to what the client proposed, because the format of the
  800.  * reply is often different from the format of the request, and this
  801.  * is likely to be true for unknown capabilities too.)
  802.  */
  803. static List *negotiate_capabilities(List *req_caps) 
  804. {
  805.     /* Currently we don't know or care about any capabilities,
  806.      * though it is likely that "Extended Methods" will be
  807.      * the first. */
  808.     return list_create();
  809. }
  810. /***********************************************************************
  811.  * The following code implements the map-url mechanism
  812.  */
  813. struct wsp_http_map {
  814. struct wsp_http_map *next;
  815. unsigned flags;
  816. #define WSP_HTTP_MAP_INPREFIX 0x0001 /* prefix-match incoming string */
  817. #define WSP_HTTP_MAP_OUTPREFIX 0x0002 /* prefix-replace outgoing string */
  818. #define WSP_HTTP_MAP_INOUTPREFIX 0x0003 /* combine the two for masking */
  819. char *in;
  820. int in_len;
  821. char *out;
  822. int out_len;
  823. };
  824. static struct wsp_http_map *wsp_http_map = 0;
  825. static struct wsp_http_map *wsp_http_map_last = 0;
  826. /*
  827.  * Add mapping for src URL to dst URL.
  828.  */
  829. static void wsp_http_map_url_do_config(char *src, char *dst)
  830. {
  831.     struct wsp_http_map *new_map;
  832.     int in_len = src ? strlen(src) : 0;
  833.     int out_len = dst ? strlen(dst) : 0;
  834.     
  835.     if (!in_len) {
  836. warning(0, "wsp_http_map_url_do_config: empty incoming string");
  837. return;
  838.     }
  839.     gw_assert(in_len > 0);
  840.     
  841.     new_map = gw_malloc(sizeof(*new_map));
  842.     new_map->next = NULL;
  843.     new_map->flags = 0;
  844.     
  845.     /* incoming string
  846.      * later, the incoming URL will be prefix-compared to new_map->in,
  847.      * using exactly new_map->in_len characters for comparison.
  848.      */
  849.     new_map->in = gw_strdup(src);
  850.     if (src[in_len-1] == '*') {
  851. new_map->flags |= WSP_HTTP_MAP_INPREFIX;
  852. in_len--; /* do not include `*' in comparison */
  853.     } else {
  854. in_len++; /* include  in comparisons */
  855.     }
  856.     new_map->in_len = in_len;
  857.     
  858.     /* replacement string
  859.      * later, when an incoming URL matches, it will be replaced
  860.      * or modified according to this string. If the replacement
  861.      * string ends with an asterisk, and the match string indicates
  862.      * a prefix match (also ends with an asterisk), the trailing
  863.      * part of the matching URL will be appended to the replacement
  864.      * string, i.e. we do a prefix replacement.
  865.      */
  866.     new_map->out = gw_strdup(dst);
  867.     if (dst[out_len-1] == '*') {
  868. new_map->flags |= WSP_HTTP_MAP_OUTPREFIX;
  869. out_len--; /* exclude `*' */
  870.     }
  871.     new_map->out_len = out_len;
  872.     
  873.     /* insert at tail of existing list */
  874.     if (wsp_http_map == NULL) {
  875. wsp_http_map = wsp_http_map_last = new_map;
  876.     } else {
  877. wsp_http_map_last->next = new_map;
  878. wsp_http_map_last = new_map;
  879.     }
  880. }
  881. /* Called during configuration read, once for each "map-url" statement.
  882.  * Interprets parameter value as a space-separated two-tuple of src and dst.
  883.  */
  884. void wsp_http_map_url_config(char *s)
  885. {
  886.     char *in, *out;
  887.     
  888.     s = gw_strdup(s);
  889.     in = strtok(s, " t");
  890.     if (!in) 
  891.      return;
  892.     out = strtok(NULL, " t");
  893.     if (!out) 
  894.      return;
  895.     wsp_http_map_url_do_config(in, out);
  896.     gw_free(s);
  897. }
  898. /* Called during configuration read, this adds a mapping for the source URL
  899.  * "DEVICE:home", to the given destination. The mapping is configured
  900.  * as an in/out prefix mapping.
  901.  */
  902. void wsp_http_map_url_config_device_home(char *to)
  903. {
  904.     int len;
  905.     char *newto = 0;
  906.     
  907.     if (!to)
  908. return;
  909.     len = strlen(to);
  910.     if (to[len] != '*') {
  911. newto = gw_malloc(len+2);
  912. strcpy(newto, to);
  913. newto[len] = '*';
  914. newto[len+1] = '';
  915. to = newto;
  916.     }
  917.     wsp_http_map_url_do_config("DEVICE:home*", to);
  918.     if (newto)
  919. gw_free(newto);
  920. }
  921. /* show mapping list at info level, after configuration is done. */
  922. void wsp_http_map_url_config_info(void)
  923. {
  924.     struct wsp_http_map *run;
  925.     
  926.     for (run = wsp_http_map; run; run = run->next) {
  927. char *s1 = (run->flags & WSP_HTTP_MAP_INPREFIX)  ? "*" : "";
  928. char *s2 = (run->flags & WSP_HTTP_MAP_OUTPREFIX) ? "*" : "";
  929. info(0, "map-url %.*s%s %.*s%s",
  930.      run->in_len, run->in, s1,
  931.      run->out_len, run->out, s2);
  932.     }
  933. }
  934. /* Search list of mappings for the given URL, returning the map structure. */
  935. static struct wsp_http_map *wsp_http_map_find(char *s)
  936. {
  937.     struct wsp_http_map *run;
  938.     
  939.     for (run = wsp_http_map; run; run = run->next)
  940.     if (0 == strncasecmp(s, run->in, run->in_len))
  941. break;
  942.     if (run) {
  943. debug("wap.wsp.http", 0, "WSP: found mapping for url <%s>", s);
  944.     }
  945.     return run;
  946. }
  947. /* 
  948.  * Maybe rewrite URL, if there is a mapping. This is where the runtime
  949.  * lookup comes in (called from further down this file, wsp_http.c)
  950.  */
  951. static void wsp_http_map_url(Octstr **osp)
  952. {
  953.     struct wsp_http_map *map;
  954.     Octstr *old = *osp;
  955.     char *oldstr = octstr_get_cstr(old);
  956.     
  957.     map = wsp_http_map_find(oldstr);
  958.     if (!map)
  959.         return;
  960.     *osp = octstr_create_from_data(map->out, map->out_len);
  961.     /* 
  962.      * If both prefix flags are set, append tail of incoming URL
  963.      * to outgoing URL.
  964.      */
  965.     if (WSP_HTTP_MAP_INOUTPREFIX == (map->flags & WSP_HTTP_MAP_INOUTPREFIX))
  966.         octstr_append_cstr(*osp, oldstr + map->in_len);
  967.     debug("wap.wsp.http", 0, "WSP: url <%s> mapped to <%s>",
  968.           oldstr, octstr_get_cstr(*osp));
  969.     octstr_destroy(old);
  970. }
  971. void wsp_http_map_destroy(void) 
  972. {
  973.     struct wsp_http_map *p, *q;
  974.     p = wsp_http_map;
  975.     
  976.     while (p != NULL) {
  977. q = p;
  978. if (q -> in) 
  979.     gw_free (q -> in);
  980. if (q -> out) 
  981.     gw_free (q -> out);
  982. p = q -> next;
  983. gw_free (q);
  984.     }
  985. }
  986. /*
  987.  * Ota submodule implements indications, responses and confirmations part of 
  988.  * ota.
  989.  */
  990. /*
  991.  * If Accept-Application is empty, add header indicating default application 
  992.  * wml ua (see ota 6.4.1). Otherwise decode application id (see http://www.
  993.  * wapforum.org/wina/push-app-id.htm). FIXME: capability negotiation (no-
  994.  * thing means default, if so negotiated).
  995.  * Function does not allocate memory neither for headers nor application_
  996.  * headers.
  997.  * Returns encoded application headers and input header list without them.
  998.  */
  999. static void check_application_headers(List **headers, 
  1000.                                       List **application_headers)
  1001. {
  1002.     List *inh;
  1003.     int i;
  1004.     Octstr *appid_name, *coded_octstr;
  1005.     char *appid_value, *coded_value;
  1006.     split_header_list(headers, &inh, "Accept-Application");
  1007.     
  1008.     if (*headers == NULL || list_len(inh) == 0) {
  1009.         http_header_add(*application_headers, "Accept-Application", "wml ua");
  1010.         debug("wap.appl.push", 0, "APPL: No push application, assuming wml"
  1011.               " ua");
  1012.         if (*headers != NULL)
  1013.             http_destroy_headers(inh);
  1014.         return;
  1015.     }
  1016.     i = 0;
  1017.     coded_value = NULL;
  1018.     appid_value = NULL;
  1019.     while (list_len(inh) > 0) {
  1020.         http_header_get(inh, i, &appid_name, &coded_octstr);
  1021.         /* Greatest value reserved by WINA is 0xFF00 0000*/
  1022.         coded_value = octstr_get_cstr(coded_octstr);
  1023.         if (coded_value != NULL)
  1024.    appid_value = wsp_application_id_to_cstr((long) coded_value);
  1025.         if (appid_value != NULL && coded_value != NULL)
  1026.             http_header_add(*application_headers, "Accept-Application", 
  1027.                             appid_value);
  1028.         else {
  1029.     error(0, "OTA: Unknown application is, skipping: ");
  1030.             octstr_dump(coded_octstr, 0);
  1031.         }
  1032.         i++;  
  1033.     }
  1034.    
  1035.     debug("wap.appl.push", 0, "application headers were");
  1036.     http_header_dump(*application_headers);
  1037.     http_destroy_headers(inh);
  1038.     octstr_destroy(appid_name);
  1039.     octstr_destroy(coded_octstr);
  1040. }
  1041. /*
  1042.  * Bearer-Indication field is defined in ota 6.4.1. 
  1043.  * Skip the header, if it is malformed or if there is more than one bearer 
  1044.  * indication.
  1045.  * Function does not allocate memory neither for headers nor bearer_headers.
  1046.  * Return encoded bearer indication header and input header list without it.
  1047.  */
  1048. static void decode_bearer_indication(List **headers, List **bearer_headers)
  1049. {
  1050.     List *inb;
  1051.     Octstr *name, *coded_octstr;
  1052.     char *value;
  1053.     unsigned char coded_value;
  1054.     if (*headers == NULL) {
  1055.         debug("wap.appl", 0, "APPL: no client headers, continuing");
  1056.         return;
  1057.     }
  1058.     split_header_list(headers, &inb, "Bearer-Indication");
  1059.     if (list_len(inb) == 0) {
  1060.         debug("wap.appl.push", 0, "APPL: No bearer indication headers,"
  1061.               " continuing");
  1062.         http_destroy_headers(inb);
  1063.         return;  
  1064.     }
  1065.     if (list_len(inb) > 1) {
  1066.         error(0, "APPL: To many bearer indication header(s), skipping"
  1067.               " them");
  1068.         http_destroy_headers(inb);
  1069.         return;
  1070.     }
  1071.     http_header_get(inb, 0, &name, &coded_octstr);
  1072.     http_destroy_headers(inb);
  1073.   /* Greatest assigned number for a bearer type is 0xff, see wdp, appendix C */
  1074.     coded_value = octstr_get_char(coded_octstr, 0);
  1075.     value = wsp_bearer_indication_to_cstr(coded_value);
  1076.     if (value != NULL && coded_value != 0) {
  1077.        http_header_add(*bearer_headers, "Bearer-Indication", value);
  1078.        debug("wap.appl.push", 0, "bearer indication header was");
  1079.        http_header_dump(*bearer_headers);
  1080.        return;
  1081.     } else {
  1082.        error(0, "APPL: Illegal bearer indication value, skipping");
  1083.        octstr_dump(coded_octstr, 0);
  1084.        http_destroy_headers(*bearer_headers);
  1085.        return;
  1086.     }
  1087. }
  1088. /*
  1089.  * Separate headers into two lists, one having all headers named "name" and
  1090.  * the other rest of them.
  1091.  */
  1092. static void split_header_list(List **headers, List **new_headers, char *name)
  1093. {
  1094.     if (*headers == NULL)
  1095.         return;
  1096.     *new_headers = http_header_find_all(*headers, name);
  1097.     http_header_remove_all(*headers, name);  
  1098. }
  1099. /*
  1100.  * Find headers Accept-Application and Bearer-Indication amongst push headers,
  1101.  * decode them and add them to their proper field. 
  1102.  */
  1103. static void indicate_push_connection(WAPEvent *e)
  1104. {
  1105.     WAPEvent *ppg_event;
  1106.     List *push_headers,
  1107.          *application_headers,
  1108.          *bearer_headers;
  1109.     push_headers = http_header_duplicate(e->u.S_Connect_Ind.client_headers);
  1110.     application_headers = http_create_empty_headers();
  1111.     bearer_headers = http_create_empty_headers();
  1112.     
  1113.     ppg_event = wap_event_create(Pom_Connect_Ind);
  1114.     ppg_event->u.Pom_Connect_Ind.addr_tuple = 
  1115.         wap_addr_tuple_duplicate(e->u.S_Connect_Ind.addr_tuple);
  1116.     ppg_event->u.Pom_Connect_Ind.requested_capabilities = 
  1117.         wsp_cap_duplicate_list(e->u.S_Connect_Ind.requested_capabilities);
  1118.     check_application_headers(&push_headers, &application_headers);
  1119.     ppg_event->u.Pom_Connect_Ind.accept_application = application_headers;
  1120.     decode_bearer_indication(&push_headers, &bearer_headers);
  1121.     if (list_len(bearer_headers) == 0) {
  1122.         http_destroy_headers(bearer_headers);
  1123.         ppg_event->u.Pom_Connect_Ind.bearer_indication = NULL;
  1124.     } else
  1125.         ppg_event->u.Pom_Connect_Ind.bearer_indication = bearer_headers;
  1126.     ppg_event->u.Pom_Connect_Ind.push_headers = push_headers;
  1127.     ppg_event->u.Pom_Connect_Ind.session_id = e->u.S_Connect_Ind.session_id;
  1128.     debug("wap.appl", 0, "APPL: making OTA connection indication to PPG");
  1129.     wap_push_ppg_dispatch_event(ppg_event);
  1130. }
  1131. static void indicate_push_disconnect(WAPEvent *e)
  1132. {
  1133.     WAPEvent *ppg_event;
  1134.     ppg_event = wap_event_create(Pom_Disconnect_Ind);
  1135.     ppg_event->u.Pom_Disconnect_Ind.reason_code = 
  1136.         e->u.S_Disconnect_Ind.reason_code;
  1137.     ppg_event->u.Pom_Disconnect_Ind.error_headers =
  1138.         octstr_duplicate(e->u.S_Disconnect_Ind.error_headers);
  1139.     ppg_event->u.Pom_Disconnect_Ind.error_body =
  1140.         octstr_duplicate(e->u.S_Disconnect_Ind.error_body);
  1141.     ppg_event->u.Pom_Disconnect_Ind.session_handle =
  1142.         e->u.S_Disconnect_Ind.session_handle;
  1143.     wap_push_ppg_dispatch_event(ppg_event);
  1144. }
  1145. /*
  1146.  * We do not implement acknowledgement headers
  1147.  */
  1148. static void confirm_push(WAPEvent *e)
  1149. {
  1150.     WAPEvent *ppg_event;
  1151.     ppg_event = wap_event_create(Po_ConfirmedPush_Cnf);
  1152.     ppg_event->u.Po_ConfirmedPush_Cnf.server_push_id = 
  1153.         e->u.S_ConfirmedPush_Cnf.server_push_id;
  1154.     ppg_event->u.Po_ConfirmedPush_Cnf.session_handle = 
  1155.          e->u.S_ConfirmedPush_Cnf.session_id;
  1156.     debug("wap.appl", 0, "OTA: confirming push for ppg");
  1157.     wap_push_ppg_dispatch_event(ppg_event);
  1158. }
  1159. static void indicate_push_abort(WAPEvent *e)
  1160. {
  1161.     WAPEvent *ppg_event;
  1162.     ppg_event = wap_event_create(Po_PushAbort_Ind);
  1163.     ppg_event->u.Po_PushAbort_Ind.push_id = e->u.S_PushAbort_Ind.push_id;
  1164.     ppg_event->u.Po_PushAbort_Ind.reason = e->u.S_PushAbort_Ind.reason;
  1165.     ppg_event->u.Po_PushAbort_Ind.session_handle = 
  1166.         e->u.S_PushAbort_Ind.session_id;
  1167.     debug("wap.push.ota", 0, "OTA: making push abort indication for ppg");
  1168.     wap_push_ppg_dispatch_event(ppg_event);
  1169. }
  1170. static void indicate_push_suspend(WAPEvent *e)
  1171. {
  1172.     WAPEvent *ppg_event;
  1173.     ppg_event = wap_event_create(Pom_Suspend_Ind);
  1174.     ppg_event->u.Pom_Suspend_Ind.reason = e->u.S_Suspend_Ind.reason;
  1175.     ppg_event->u.Pom_Suspend_Ind.session_id =  e->u.S_Suspend_Ind.session_id;
  1176.     wap_push_ppg_dispatch_event(ppg_event);
  1177. }
  1178. /*
  1179.  * Find Bearer-Indication amongst client headers, decode it and assign it to
  1180.  * a separate field in the event structure.
  1181.  */
  1182. static void indicate_push_resume(WAPEvent *e)
  1183. {
  1184.     WAPEvent *ppg_event;
  1185.     List *push_headers,
  1186.          *bearer_headers;
  1187.     push_headers = http_header_duplicate(e->u.S_Resume_Ind.client_headers);
  1188.     bearer_headers = http_create_empty_headers();
  1189.     
  1190.     ppg_event = wap_event_create(Pom_Resume_Ind);
  1191.     ppg_event->u.Pom_Resume_Ind.addr_tuple = wap_addr_tuple_duplicate(
  1192.         e->u.S_Resume_Ind.addr_tuple);
  1193.    
  1194.     decode_bearer_indication(&push_headers, &bearer_headers);
  1195.     if (list_len(bearer_headers) == 0) {
  1196.         http_destroy_headers(bearer_headers);
  1197.         ppg_event->u.Pom_Resume_Ind.bearer_indication = NULL;
  1198.     } else 
  1199.         ppg_event->u.Pom_Resume_Ind.bearer_indication = bearer_headers;
  1200.     ppg_event->u.Pom_Resume_Ind.client_headers = push_headers;
  1201.     ppg_event->u.Pom_Resume_Ind.session_id = e->u.S_Resume_Ind.session_id;
  1202.     wap_push_ppg_dispatch_event(ppg_event);
  1203. }
  1204. /*
  1205.  * Server headers are mentioned in table in ota 6.4.1, but none of the primit-
  1206.  * ives use them. They are optional in S_Connect_Res, so we do not use them.
  1207.  */
  1208. static void response_push_connection(WAPEvent *e)
  1209. {
  1210.     WAPEvent *wsp_event;
  1211.     gw_assert(e->type = Pom_Connect_Res);
  1212.     wsp_event = wap_event_create(S_Connect_Res);
  1213.     wsp_event->u.S_Connect_Res.session_id = e->u.Pom_Connect_Res.session_id;
  1214.     wsp_event->u.S_Connect_Res.negotiated_capabilities =
  1215.         wsp_cap_duplicate_list(e->u.Pom_Connect_Res.negotiated_capabilities);
  1216.     debug("wap.appl", 0, "APPL: making push connect response");
  1217.     wsp_session_dispatch_event(wsp_event);
  1218. }