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

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * wap_push_ppg.c: General logic of a push proxy gateway.
  3.  *
  4.  * This module implements following Wapforum specifications:
  5.  *      WAP-151-PPGService-19990816-a (called afterwards ppg),
  6.  *      WAP-164-PAP-19991108-a (pap),
  7.  *      WAP-164_100-PAP-20000218-a (pap implementation note).
  8.  * 
  9.  * We refer following Wapforum specifications:
  10.  *      WAP-145-PushMessage-19990816-a (push message)
  11.  *      WAP-200-WDP-20001212-a (wdp)
  12.  *      WAP-203-WSP-20000504-a (wsp)
  13.  *      WAP-189-PushOTA-20000217-a (ota).
  14.  *
  15.  * In addition, rfcs 1521 and 2045 are referred.
  16.  *
  17.  * By  Aarno Syv妌en for Wapit Ltd, Wiral Ltd and Global Networks Inc.
  18.  */
  19. #include <time.h>
  20. #include <ctype.h>
  21. #include "wap_push_ppg.h"
  22. #include "wap/wap_events.h"
  23. #include "wap/wsp_caps.h"
  24. #include "wml_compiler.h"
  25. #include "wap-appl.h"
  26. #include "wap/wsp.h"
  27. #include "wap/wsp_strings.h"
  28. #include "wap_push_si_compiler.h"
  29. #include "wap_push_sl_compiler.h"
  30. #include "wap_push_pap_compiler.h"
  31. #include "wap_push_pap_mime.h"
  32. #include "wap_push_ppg_pushuser.h"
  33. enum {
  34.     TIME_EXPIRED = 0,
  35.     TIME_TOO_EARLY = 1,
  36.     NO_CONSTRAINTS = 2
  37. };
  38. /*
  39.  * Default values for configuration variables
  40.  */
  41. enum {
  42.     DEFAULT_HTTP_PORT = 8080,
  43.     NO_HTTPS_PORT = -1,
  44.     DEFAULT_NUMBER_OF_PUSHES = 100,
  45.     PI_TRUSTED = 1,
  46.     SSL_CONNECTION_OFF = 0,
  47.     DEFAULT_NUMBER_OF_USERS = 1024,
  48.     USER_CONFIGURATION_NOT_ADDED = 0
  49. };
  50. enum { USER_CONFIGURATION_ADDED = 1 };
  51. #define DEFAULT_PPG_URL "/wappush"
  52. /*****************************************************************************
  53.  *
  54.  * Internal data structures
  55.  *
  56.  * Give the status of the push ppg module:
  57.  *
  58.  * limbo
  59.  * not running at all
  60.  * running
  61.  * operating normally
  62.  * terminating
  63.  * waiting for operations to terminate, returning to limbo
  64.  */
  65. static enum {limbo, running, terminating} run_status = limbo;
  66. /*
  67.  * The external event queue for this module
  68.  */
  69. static List *ppg_queue = NULL;
  70. /*
  71.  * The internal event queue for this module (allowing listening of many ports)
  72.  */
  73. static List *pap_queue = NULL;
  74. /*
  75.  * List of ppg session machines (it is, of currently active sessions)
  76.  */
  77. static List *ppg_machines = NULL;
  78. /*
  79.  * List of currently active unit pushes (we need a threadsafe storage for them,
  80.  * because pushes can be cancelled and queried):
  81.  */
  82. static List *ppg_unit_pushes = NULL;
  83. /*
  84.  * Counter to store our internal push id.
  85.  */
  86. static Counter *push_id_counter = NULL;
  87. /*
  88.  * We need a mapping between HTTPClient structures, used by http library, and
  89.  * push ids, used by ppg. 
  90.  */
  91. static Dict *http_clients = NULL;
  92. /*
  93.  * Mapping between urls used by pi and push ids used by ppg.
  94.  */
  95. static Dict *urls = NULL;
  96. /*
  97.  * Push content packed for compilers (wml, si, sl, co).
  98.  */
  99. struct content {
  100.     Octstr *body;
  101.     Octstr *type;
  102.     Octstr *charset;
  103. };
  104. static wap_dispatch_func_t *dispatch_to_ota;
  105. static wap_dispatch_func_t *dispatch_to_appl;
  106. /*
  107.  * Configurable variables of ppg core group (for general configuration of a 
  108.  * ppg), with some default values.
  109.  */
  110. static Octstr *ppg_url = NULL ;
  111. static long ppg_port = DEFAULT_HTTP_PORT;
  112. #ifdef HAVE_LIBSSL
  113. static long ppg_ssl_port = NO_HTTPS_PORT;
  114. #endif
  115. static long number_of_pushes = DEFAULT_NUMBER_OF_PUSHES;
  116. static int trusted_pi = PI_TRUSTED;
  117. static long number_of_users = DEFAULT_NUMBER_OF_USERS;
  118. static Octstr *ppg_deny_ip = NULL;
  119. static Octstr *ppg_allow_ip = NULL; 
  120. static int user_configuration = USER_CONFIGURATION_NOT_ADDED;
  121. static Octstr *global_sender = NULL;
  122. #ifdef HAVE_LIBSSL
  123. static Octstr *ssl_server_cert_file = NULL;
  124. static Octstr *ssl_server_key_file = NULL;
  125. #endif
  126. struct PAPEvent {
  127.     HTTPClient *client;
  128.     Octstr *ip; 
  129.     Octstr *url;
  130.     List *push_headers; 
  131.     Octstr *mime_content;
  132.     List *cgivars;
  133. };
  134. typedef struct PAPEvent PAPEvent;
  135. /*****************************************************************************
  136.  *
  137.  * Prototypes of internal functions
  138.  *
  139.  * Event handling
  140.  */
  141. static void ota_read_thread(void *arg);
  142. static void http_read_thread(void *arg);
  143. #ifdef HAVE_LIBSSL
  144. static void https_read_thread(void *arg);
  145. #endif
  146. static void handle_internal_event(WAPEvent *e);
  147. static void pap_request_thread(void *arg);
  148. static int handle_push_message(HTTPClient **c, WAPEvent *ppg_event, int status);
  149. static PAPEvent *pap_event_create(Octstr *ip, Octstr *url, List *push_headers, 
  150.                                   Octstr *mime_content, List *cgivars,
  151.                                   HTTPClient *client);
  152. static void pap_event_destroy(PAPEvent *p);
  153. static void pap_event_destroy_item(void *p);
  154. static void pap_event_unpack(PAPEvent *p, Octstr **ip, Octstr **url, 
  155.                              List **push_headers, Octstr **mime_content, 
  156.                              List **cgivars, HTTPClient **client);
  157. /*
  158.  * Constructors and destructors for machines.
  159.  */
  160. static PPGSessionMachine *session_machine_create(WAPAddrTuple *tuple, 
  161.                                                      WAPEvent *e);
  162. static void session_machine_destroy(void *p);
  163. static PPGPushMachine *push_machine_create(WAPEvent *e, 
  164.     WAPAddrTuple *tuple);
  165. static void push_machine_destroy(void *pm);
  166. static void push_machines_list_destroy(List *pl);
  167. /*
  168.  * Communicating other modules (ota and appl)
  169.  */
  170. static void create_session(WAPEvent *e, PPGPushMachine *pm);
  171. static void request_confirmed_push(long last, PPGPushMachine *pm, 
  172.                                    PPGSessionMachine *sm);
  173. static void request_unit_push(long last, PPGPushMachine *pm);
  174. static void request_push(long last, PPGPushMachine *sm);
  175. static int response_push_connection(WAPEvent *e, PPGSessionMachine *sm);
  176. static HTTPClient *response_push_message(PPGPushMachine *pm, long code, 
  177.                                          int status);
  178. /*
  179.  * Functions to find machines using various identifiers, and related help 
  180.  * functions.
  181.  */
  182. static PPGSessionMachine *session_find_using_pi_client_address(Octstr *addr);
  183. static PPGPushMachine *find_ppg_push_machine_using_pid(PPGSessionMachine *sm, 
  184.                                                    long pid);
  185. static PPGPushMachine *find_ppg_push_machine_using_pi_push_id(
  186.     PPGSessionMachine *sm, Octstr *pi_push_id);
  187. static PPGPushMachine *find_unit_ppg_push_machine_using_pi_push_id(
  188.     Octstr *pi_push_id);
  189. static int push_has_pi_push_id(void *a, void *b);
  190. static int push_has_pid(void *a, void *b);
  191. static int session_has_pi_client_address(void *a, void *b);
  192. static int session_has_addr(void *a, void *b);
  193. static int session_has_sid(void *a, void *b);
  194. /*
  195.  * Main logic of PPG.
  196.  */
  197. static int check_capabilities(List *requested, List *assumed);
  198. static int transform_message(WAPEvent **e, WAPAddrTuple **tuple, 
  199.                              List *push_headers, int connected, Octstr **type);
  200. static long check_x_wap_application_id_header(List **push_headers);
  201. static int pap_convert_content(struct content *content);
  202. static int pap_get_content(struct content *content);
  203. static int select_bearer_network(WAPEvent **e);
  204. static int delivery_time_constraints(WAPEvent *e, PPGPushMachine *pm);
  205. static void deliver_confirmed_push(long last, PPGPushMachine *pm, 
  206.                                    PPGSessionMachine *sm);
  207. static PPGPushMachine *deliver_unit_push(long last, PPGPushMachine *pm,
  208.     PPGSessionMachine *sm, int session_exists);
  209. static int store_push_data(PPGPushMachine **pm, PPGSessionMachine *sm, 
  210.                            WAPEvent *e, WAPAddrTuple *tuple, int cless);
  211. static PPGPushMachine *update_push_data_with_attribute(PPGSessionMachine **sm, 
  212.     PPGPushMachine *pm, long reason, long status);
  213. static void remove_push_data(PPGSessionMachine *sm, PPGPushMachine *pm, 
  214.                              int cless);
  215. static void remove_session_data(PPGSessionMachine *sm, int status);
  216. static void remove_pushless_session(PPGSessionMachine *sm);
  217. static PPGSessionMachine *store_session_data(PPGSessionMachine *sm,
  218.     WAPEvent *e, WAPAddrTuple *tuple, int *session_exists);
  219. static PPGSessionMachine *update_session_data_with_headers(
  220.     PPGSessionMachine *sm, PPGPushMachine *pm);
  221. static void deliver_pending_pushes(PPGSessionMachine *sm, int last);
  222. static PPGPushMachine *abort_delivery(PPGSessionMachine *sm, int status);
  223. static PPGSessionMachine *update_session_data(PPGSessionMachine *sm, long sid,
  224.                                               long port, List *caps);
  225. static int confirmation_requested(WAPEvent *e);
  226. static int cless_accepted(WAPEvent *e, PPGSessionMachine *sm);
  227. /*
  228.  * Header functions
  229.  */
  230. static int headers_acceptable(List *push_headers, Octstr **content_header);
  231. static int type_is(Octstr *content_header, char *required_type);
  232. static int get_mime_boundary(List *push_headers, Octstr *content_header, 
  233.                              Octstr **boundary);
  234. static void change_header_value(List **push_headers, char *name, char *value);
  235. static void remove_mime_headers(List **push_headers);
  236. /*
  237.  * Communicating with pi.
  238.  */
  239. static void send_bad_message_response(HTTPClient **c, Octstr *body_fragment,
  240.                                       int code, int status);
  241. static HTTPClient *send_push_response(WAPEvent *e, int status);
  242. static void send_to_pi(HTTPClient **c, Octstr *reply_body, int status);
  243. static void tell_fatal_error(HTTPClient **c, WAPEvent *e, Octstr *url, 
  244.                              int status, int code);
  245. /*
  246.  * PPG core authentication (not related to any particular user).
  247.  */
  248. static int read_ppg_config(Cfg *cfg);
  249. static int ip_allowed_by_ppg(Octstr *ip);
  250. /*
  251.  * Interface to various compilers
  252.  */
  253. static Octstr *convert_wml_to_wmlc(struct content *content);
  254. static Octstr *convert_si_to_sic(struct content *content);
  255. static Octstr *convert_sl_to_slc(struct content *content);
  256. /*
  257.  * Various utility functions
  258.  */
  259. static Octstr *set_time(void);
  260. static int deliver_before_test_cleared(Octstr *before, struct tm now);
  261. static int deliver_after_test_cleared(Octstr *after, struct tm now);
  262. static void session_machine_assert(PPGSessionMachine *sm);
  263. static void push_machine_assert(PPGPushMachine *pm);
  264. static Octstr *tell_ppg_name(void);
  265. static Octstr *describe_code(long code);
  266. static long ota_abort_to_pap(long reason);
  267. static int content_transformable(List *push_headers);
  268. static WAPAddrTuple *set_addr_tuple(Octstr *address, long cliport, 
  269.                                     long servport, long address_type);
  270. static WAPAddrTuple *addr_tuple_change_cliport(WAPAddrTuple *tuple, long port);
  271. static void initialize_time_item_array(long time_data[], struct tm now);
  272. static int date_item_compare(Octstr *before, long time_data, long pos);
  273. static long parse_appid_header(Octstr **assigned_code);
  274. static Octstr *escape_fragment(Octstr *fragment);
  275. static int coriented_deliverable(long code);
  276. static int is_phone_number(long type_of_address);
  277. static void replace_octstr_char(Octstr *os1, Octstr *os2, long *pos);
  278. /*****************************************************************************
  279.  *
  280.  * EXTERNAL FUNCTIONS
  281.  */
  282. enum {
  283.     TYPE_HTTP = 0,
  284.     TYPE_HTTPS = 1
  285. };
  286. void wap_push_ppg_init(wap_dispatch_func_t *ota_dispatch, 
  287.                        wap_dispatch_func_t *appl_dispatch, Cfg *cfg)
  288. {
  289.     user_configuration = read_ppg_config(cfg);
  290.     if (user_configuration != USER_CONFIGURATION_NOT_ADDED) {
  291.         ppg_queue = list_create();
  292.         list_add_producer(ppg_queue);
  293.         pap_queue = list_create();
  294.         list_add_producer(pap_queue);
  295.         push_id_counter = counter_create();
  296.         ppg_machines = list_create();
  297.         ppg_unit_pushes = list_create();
  298.         dispatch_to_ota = ota_dispatch;
  299.         dispatch_to_appl = appl_dispatch;
  300.         http_open_port(ppg_port, TYPE_HTTP);
  301. #ifdef HAVE_LIBSSL
  302.         if (ppg_ssl_port != NO_HTTPS_PORT)
  303.             http_open_port(ppg_ssl_port, TYPE_HTTPS);
  304. #endif
  305.         http_clients = dict_create(number_of_pushes, NULL);
  306.         urls = dict_create(number_of_pushes, NULL);
  307.         gw_assert(run_status == limbo);
  308.         run_status = running;
  309.         gwthread_create(ota_read_thread, NULL);
  310.         gwthread_create(http_read_thread, NULL);
  311. #ifdef HAVE_LIBSSL
  312.         if (ppg_ssl_port != NO_HTTPS_PORT) 
  313.             gwthread_create(https_read_thread, NULL);
  314. #endif
  315.         gwthread_create(pap_request_thread, NULL);
  316.     }
  317. }
  318. void wap_push_ppg_shutdown(void)
  319. {
  320.      if (user_configuration != USER_CONFIGURATION_NOT_ADDED) {
  321.          gw_assert(run_status == running);
  322.          run_status = terminating;
  323.          list_remove_producer(ppg_queue);
  324.          list_remove_producer(pap_queue);
  325.          octstr_destroy(ppg_url);
  326.          http_close_all_ports();
  327.          dict_destroy(http_clients);
  328.          dict_destroy(urls);
  329.          wap_push_ppg_pushuser_list_destroy();
  330.          octstr_destroy(ppg_deny_ip);
  331.          octstr_destroy(ppg_allow_ip);
  332.          octstr_destroy(global_sender);
  333.          gwthread_join_every(http_read_thread);
  334. #ifdef HAVE_LIBSSL
  335.          if (ppg_ssl_port != NO_HTTPS_PORT)
  336.             gwthread_join_every(https_read_thread);
  337. #endif
  338.          gwthread_join_every(ota_read_thread);
  339.          gwthread_join_every(pap_request_thread);
  340.          list_destroy(ppg_queue, wap_event_destroy_item);
  341.          list_destroy(pap_queue, pap_event_destroy_item);
  342.          counter_destroy(push_id_counter);
  343.      
  344.          debug("wap.push.ppg", 0, "PPG: %ld push session machines left.",
  345.                list_len(ppg_machines));
  346.          list_destroy(ppg_machines, session_machine_destroy);
  347.          debug("wap_push_ppg", 0, "PPG: %ld unit pushes left", 
  348.                list_len(ppg_unit_pushes));
  349.          list_destroy(ppg_unit_pushes, push_machine_destroy);
  350.      }
  351. }
  352. void wap_push_ppg_dispatch_event(WAPEvent *e)
  353. {
  354.     gw_assert(run_status == running);
  355.     list_produce(ppg_queue, e);
  356. }
  357. /*
  358.  * We cannot know port the client is using when it establish the connection.
  359.  * However, we must link session creation with a pending push request. Only
  360.  * data available is the client address, so we check it here.
  361.  * Return non-NULL (pointer to the session machine found), if we have one.
  362.  */
  363. PPGSessionMachine *wap_push_ppg_have_push_session_for(WAPAddrTuple *tuple)
  364. {
  365.     PPGSessionMachine *sm;
  366.     gw_assert(tuple);
  367.     sm = list_search(ppg_machines, tuple->remote->address, session_has_addr);
  368.     return sm;
  369. }
  370. /*
  371.  * Now initiators are identified by their session id. Return non-NULL (pointer
  372.  * to the session machine found), if we have one. This function are used after 
  373.  * wsp has indicated session establishment, giving us a session id.
  374.  */
  375. PPGSessionMachine *wap_push_ppg_have_push_session_for_sid(long sid)
  376. {
  377.     PPGSessionMachine *sm;
  378.     gw_assert(sid >= 0);
  379.     sm = list_search(ppg_machines, &sid, session_has_sid);
  380.     return sm;
  381. }
  382. /*****************************************************************************
  383.  *
  384.  * INTERNAL FUNCTIONS
  385.  *
  386.  * Read general ppg configuration and configuration specific for users (to the
  387.  * list 'users').
  388.  * Return 1 when an user configuration group is present, 0 otherwise.
  389.  */
  390. static int read_ppg_config(Cfg *cfg)
  391. {
  392.      CfgGroup *grp;
  393.      List *list;
  394.      if (cfg == NULL)
  395.          return USER_CONFIGURATION_NOT_ADDED;
  396.      grp = cfg_get_single_group(cfg, octstr_imm("ppg"));
  397.      if ((ppg_url = cfg_get(grp, octstr_imm("ppg-url"))) == NULL)
  398.          ppg_url = octstr_imm("/wappush");
  399.      cfg_get_integer(&ppg_port, grp, octstr_imm("ppg-port"));
  400.      cfg_get_integer(&number_of_pushes, grp, octstr_imm("concurrent-pushes"));
  401.      cfg_get_bool(&trusted_pi, grp, octstr_imm("trusted-pi"));
  402.      cfg_get_integer(&number_of_users, grp, octstr_imm("users"));
  403.      ppg_deny_ip = cfg_get(grp, octstr_imm("ppg-deny-ip"));
  404.      ppg_allow_ip = cfg_get(grp, octstr_imm("ppg-allow-ip"));
  405.      if ((global_sender = cfg_get(grp, octstr_imm("global-sender"))) == NULL)
  406.          global_sender = octstr_imm("1234");
  407. #ifdef HAVE_LIBSSL
  408.      cfg_get_integer(&ppg_ssl_port, grp, octstr_imm("ppg-ssl-port"));
  409.      ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file"));
  410.      ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file"));
  411.      if (ppg_ssl_port != NO_HTTPS_PORT) {
  412.         if (ssl_server_cert_file == NULL || ssl_server_key_file == NULL) 
  413.             panic(0, "cannot continue without server cert and/or key files");
  414.         use_global_server_certkey_file(ssl_server_cert_file, ssl_server_key_file);
  415.      }        
  416.      octstr_destroy(ssl_server_cert_file);
  417.      octstr_destroy(ssl_server_key_file);
  418. #endif
  419.      if ((list = cfg_get_multi_group(cfg, octstr_imm("wap-push-user")))
  420.               == NULL) {
  421.          info(0, "No configuration for any user, continuing without");
  422.          list_destroy(list, NULL);
  423.          cfg_destroy(cfg); 
  424.          return USER_CONFIGURATION_NOT_ADDED;
  425.      }
  426.     
  427.      if (!wap_push_ppg_pushuser_list_add(list, number_of_pushes, 
  428.                                          number_of_users)) {
  429.          panic(0, "unable to create users configuration list, exiting");
  430.          return USER_CONFIGURATION_NOT_ADDED;     
  431.      }  
  432.      cfg_destroy(cfg); 
  433.      return USER_CONFIGURATION_ADDED;
  434. }
  435. static int ip_allowed_by_ppg(Octstr *ip)
  436. {
  437.     if (ip == NULL)
  438.         return 0;    
  439.     if (trusted_pi)
  440.         return 1;
  441.     if (ppg_deny_ip == NULL && ppg_allow_ip == NULL) {
  442.         warning(0, "Your ppg core configuration lacks allowed and denied" 
  443.                    " ip lists");
  444.         return 1;
  445.     }
  446.     if (ppg_deny_ip)
  447.         if (octstr_compare(ppg_deny_ip, octstr_imm("*.*.*.*")) == 0) {
  448.             panic(0, "Your ppg core configuration deny all ips, exiting");
  449.             return 0;
  450.         }
  451.     if (ppg_allow_ip)
  452.         if (octstr_compare(ppg_allow_ip, octstr_imm("*.*.*.*")) == 0) {
  453.             warning(0, "Your ppg core configuration allow all ips");
  454.             return 1;
  455.         }
  456.     if (ppg_deny_ip)
  457.         if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(ppg_deny_ip, ip, 
  458.         octstr_imm(";"), octstr_imm("."))) {
  459.             error(0, "ip found from denied list");
  460.             return 0;
  461.         }
  462.     if (ppg_allow_ip)
  463.         if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(ppg_allow_ip, ip, 
  464.         octstr_imm(";"), octstr_imm("."))) {
  465.             debug("wap.push.ppg.pushuser", 0, "PPG: ip_allowed_by_ppg: ip found"
  466.                   " from allowed list");
  467.             return 1;
  468.         }
  469.     warning(0, "did not found ip from any of core lists, deny it");
  470.     return 0;
  471. }
  472. /*
  473.  * Event handling functions
  474.  */
  475. static void ota_read_thread (void *arg)
  476. {
  477.     WAPEvent *e;
  478.     while (run_status == running && (e = list_consume(ppg_queue)) != NULL) {
  479.         handle_internal_event(e);
  480.     } 
  481. }
  482. /*
  483.  * Pap event functions handle only copy pointers. They do not allocate memory.
  484.  */
  485. static PAPEvent *pap_event_create(Octstr *ip, Octstr *url, List *push_headers, 
  486.                                   Octstr *mime_content, List *cgivars,
  487.                                   HTTPClient *client)
  488. {
  489.     PAPEvent *p;
  490.     p = gw_malloc(sizeof(PAPEvent));
  491.     p->ip = ip;
  492.     p->url = url;
  493.     p->push_headers = push_headers;
  494.     p->mime_content = mime_content;
  495.     p->cgivars = cgivars;
  496.     p->client = client;
  497.     return p;
  498. }
  499. static void pap_event_destroy(PAPEvent *p)
  500. {
  501.     if (p == NULL)
  502.         return;
  503.     gw_free(p);
  504. }
  505. static void pap_event_destroy_item(void *p)
  506. {
  507.     pap_event_destroy(p);
  508. }
  509. static void pap_event_unpack(PAPEvent *p, Octstr **ip, Octstr **url, 
  510.                              List **push_headers, Octstr **mime_content, 
  511.                              List **cgivars, HTTPClient **client)
  512. {
  513.     *ip = p->ip;
  514.     *url = p->url;
  515.     *push_headers = p->push_headers;
  516.     *mime_content = p->mime_content;
  517.     *cgivars = p->cgivars;
  518.     *client = p->client;
  519. }
  520. static void http_read_thread(void *arg)
  521. {
  522.     PAPEvent *p;
  523.     Octstr *ip; 
  524.     Octstr *url; 
  525.     List *push_headers;
  526.     Octstr *mime_content; 
  527.     List *cgivars;
  528.     HTTPClient *client;
  529.     while (run_status == running) {
  530.         client = http_accept_request(ppg_port, &ip, &url, &push_headers, 
  531.                                      &mime_content, &cgivars);
  532.         if (client == NULL) 
  533.         break;
  534.         p = pap_event_create(ip, url, push_headers, mime_content, cgivars,
  535.                              client);
  536.         list_produce(pap_queue, p);
  537.     }
  538. }
  539. #ifdef HAVE_LIBSSL
  540. static void https_read_thread(void *arg)
  541. {
  542.     PAPEvent *p;
  543.     Octstr *ip; 
  544.     Octstr *url; 
  545.     List *push_headers;
  546.     Octstr *mime_content; 
  547.     List *cgivars;
  548.     HTTPClient *client;
  549.     while (run_status == running) {
  550.         client = http_accept_request(ppg_ssl_port, &ip, &url, &push_headers, 
  551.                                      &mime_content, &cgivars); 
  552.         if (client == NULL) 
  553.     break;
  554.         
  555.         p = pap_event_create(ip, url, push_headers, mime_content, cgivars, 
  556.                              client);
  557.         list_produce(pap_queue, p);
  558.     }
  559. }
  560. #endif
  561. /*
  562.  * Authorization failure as such causes a challenge to the client (as required 
  563.  * by rfc 2617, chapter 1).
  564.  * We store HTTPClient data structure corresponding a given push id, so that 
  565.  * we can send responses to the rigth address.
  566.  * Pap chapter 14.4.1 states that we must return http status 202 after we have 
  567.  * accepted PAP message, even if it is unparsable. So only the non-existing 
  568.  * service error and some authorisation failures are handled at HTTP level. 
  569.  * When a phone number was unacceptable, we return a PAP level error, because
  570.  * we cannot know this error before parsing the document.
  571.  */
  572. static void pap_request_thread(void *arg)
  573. {
  574.     WAPEvent *ppg_event;
  575.     PAPEvent *p;
  576.     size_t push_len;
  577.     Octstr *pap_content,
  578.            *push_data,
  579.            *rdf_content,
  580.            *mime_content,
  581.            *plos,                      /* a temporary variable*/
  582.            *boundary,
  583.            *content_header,            /* Content-Type MIME header */
  584.            *url,
  585.            *ip,
  586.            *not_found,
  587.            *username = NULL;
  588.     int compiler_status,
  589.         http_status;
  590.     List *push_headers,                /* MIME headers themselves */
  591.          *content_headers,             /* Headers from the content entity, see
  592.                                           pap chapters 8.2, 13.1. Rfc 2045 
  593.                                           grammar calls these MIME-part-hea-
  594.                                           ders */
  595.          *cgivars;
  596.     HTTPClient *client;
  597.     
  598.     http_status = 0;                
  599.   
  600.     while (run_status == running && (p = list_consume(pap_queue)) != NULL) {
  601.         http_status = HTTP_NOT_FOUND;
  602.         pap_event_unpack(p, &ip, &url, &push_headers, &mime_content, 
  603.                          &cgivars, &client);      
  604.         if (octstr_compare(url, ppg_url) != 0) {
  605.             error(0,  "Request <%s> from <%s>: service not found", 
  606.                   octstr_get_cstr(url), octstr_get_cstr(ip));
  607.             not_found = octstr_imm("Service not specifiedn");
  608.             http_send_reply(client, http_status, push_headers, not_found);
  609.             goto ferror;
  610.         }
  611.         http_status = HTTP_UNAUTHORIZED;
  612.    
  613.         if (!ip_allowed_by_ppg(ip)) {
  614.             error(0,  "Request <%s> from <%s>: ip forbidden, closing the"
  615.                   " client", octstr_get_cstr(url), octstr_get_cstr(ip));
  616.             http_close_client(client);
  617.             goto ferror; 
  618.         }
  619.         if (!trusted_pi && user_configuration) {
  620.         if (!wap_push_ppg_pushuser_authenticate(client, cgivars, ip, 
  621.                                                     push_headers, &username)) {
  622.              error(0,  "Request <%s> from <%s>: authorisation failure",
  623.                        octstr_get_cstr(url), octstr_get_cstr(ip));
  624.                  goto ferror;
  625.             }
  626.     } else {                        /* J鰎g, this wont disappear again */
  627.         username = octstr_imm("");
  628.     }
  629.         http_status = HTTP_ACCEPTED;
  630.         info(0, "PPG: Accept request <%s> from <%s>", octstr_get_cstr(url), 
  631.              octstr_get_cstr(ip));
  632.         
  633.         if (octstr_len(mime_content) == 0) {
  634.         warning(0, "PPG: No MIME content received, the request"
  635.                     " unacceptable");
  636.             send_bad_message_response(&client, octstr_imm("No MIME content"), 
  637.                                       PAP_BAD_REQUEST, http_status);
  638.             if (client == NULL)
  639.             break;
  640.             goto ferror;
  641.         }
  642.         if (!push_headers) {
  643.             warning(0, "PPG: No push headers received , the request"
  644.                     " unacceptable");
  645.             send_bad_message_response(&client, octstr_imm("No push headers"), 
  646.                                       PAP_BAD_REQUEST, http_status);
  647.             if (client == NULL)
  648.             break;
  649.             goto ferror;
  650.         }
  651.         octstr_destroy(ip);
  652.         
  653.         http_remove_hop_headers(push_headers);
  654.         remove_mime_headers(&push_headers);
  655.         if (!headers_acceptable(push_headers, &content_header)) {
  656.         warning(0,  "PPG: Unparsable push headers, the request"
  657.                     " unacceptable");
  658.             send_bad_message_response(&client, content_header, PAP_BAD_REQUEST,
  659.                                       http_status);
  660.             if (client == NULL)
  661.             break;
  662.         goto herror;
  663.         }
  664.         
  665.         if (get_mime_boundary(push_headers, content_header, &boundary) == -1) {
  666.         warning(0, "PPG: No MIME boundary, the request unacceptable");
  667.             send_bad_message_response(&client, content_header, PAP_BAD_REQUEST,
  668.                                       http_status);
  669.             if (client == NULL) 
  670.             break;
  671.         goto berror;
  672.         }
  673.         gw_assert(mime_content);
  674.         if (!mime_parse(boundary, mime_content, &pap_content, &push_data, 
  675.                         &content_headers, &rdf_content)) {
  676.             send_bad_message_response(&client, mime_content, PAP_BAD_REQUEST,
  677.                                       http_status);
  678.             if (client == NULL)
  679.             break;
  680.             warning(0, "PPG: unable to parse mime content, the request"
  681.                     " unacceptable");
  682.             goto clean;
  683.         } else {
  684.         debug("wap.push.ppg", 0, "PPG: http_read_thread: pap multipart"
  685.                   " accepted");
  686.         }
  687.         push_len = octstr_len(push_data); 
  688.         http_header_remove_all(push_headers, "Content-Type");
  689.     http_append_headers(push_headers, content_headers);
  690.         change_header_value(&push_headers, "Content-Length", 
  691.             octstr_get_cstr(plos = octstr_format("%d", push_len)));
  692.         octstr_destroy(plos);
  693.         octstr_destroy(content_header);
  694.     http_destroy_headers(content_headers);
  695.         ppg_event = NULL;
  696.         if ((compiler_status = pap_compile(pap_content, &ppg_event)) == -2) {
  697.          send_bad_message_response(&client, pap_content, PAP_BAD_REQUEST,
  698.                                        http_status);
  699.             if (client == NULL)
  700.             break;
  701.             warning(0, "PPG: pap control entity erroneous, the request" 
  702.                     " unacceptable");
  703.             goto no_compile;
  704.         } else if (compiler_status == -1) {
  705.             send_bad_message_response(&client, pap_content, PAP_BAD_REQUEST,
  706.                                       http_status);
  707.             if (client == NULL)
  708.             break;
  709.             warning(0, "PPG: non implemented pap feature requested, the"
  710.                     " request unacceptable");
  711.             goto no_compile;
  712.         } else {
  713.         if (!dict_put_once(http_clients, 
  714.         ppg_event->u.Push_Message.pi_push_id, client)) {
  715.                 warning(0, "PPG: duplicate push id, the request unacceptable");
  716.             tell_fatal_error(&client, ppg_event, url, http_status, 
  717.                                  PAP_DUPLICATE_PUSH_ID);
  718.                 if (client == NULL)
  719.                 break;
  720.                 goto not_acceptable;
  721.         } 
  722.             dict_put(urls, ppg_event->u.Push_Message.pi_push_id, url); 
  723.  
  724.             if (is_phone_number(ppg_event->u.Push_Message.address_type)) {
  725.                 if (!trusted_pi && user_configuration && 
  726.                         !wap_push_ppg_pushuser_client_phone_number_acceptable(
  727.                         username, ppg_event->u.Push_Message.address_value)) {
  728.                     tell_fatal_error(&client, ppg_event, url, http_status, 
  729.                                     PAP_FORBIDDEN);
  730.                     if (client == NULL)
  731.                     break;
  732.                 goto not_acceptable;
  733.             }   
  734.             }        
  735.             debug("wap.push.ppg", 0, "PPG: http_read_thread: pap control"
  736.                   " entity compiled ok");
  737.             ppg_event->u.Push_Message.push_headers = 
  738.                 http_header_duplicate(push_headers);
  739.             ppg_event->u.Push_Message.push_data = octstr_duplicate(push_data);
  740.             if (!handle_push_message(&client, ppg_event, http_status)) {
  741.             if (client == NULL)
  742.             break;
  743.                 goto no_transform;
  744.             }
  745.         }
  746.         pap_event_destroy(p);
  747.         http_destroy_headers(push_headers);
  748.         http_destroy_cgiargs(cgivars);
  749.         octstr_destroy(username);
  750.         octstr_destroy(mime_content);
  751.         octstr_destroy(pap_content);
  752.         octstr_destroy(push_data);
  753.         octstr_destroy(rdf_content);
  754.         octstr_destroy(boundary);
  755.         continue;
  756. no_transform:
  757.         pap_event_destroy(p);
  758.         http_destroy_headers(push_headers);
  759.         http_destroy_cgiargs(cgivars);
  760.         octstr_destroy(username);
  761.         octstr_destroy(mime_content);
  762.         octstr_destroy(pap_content);
  763.         octstr_destroy(push_data);
  764.         octstr_destroy(rdf_content);
  765.         octstr_destroy(boundary);
  766.         continue;
  767. no_compile:
  768.         pap_event_destroy(p);
  769.         http_destroy_headers(push_headers);
  770.         http_destroy_cgiargs(cgivars);
  771.         octstr_destroy(username);
  772.         octstr_destroy(mime_content);
  773.         octstr_destroy(push_data);
  774.         octstr_destroy(rdf_content);
  775.         octstr_destroy(boundary);
  776.         octstr_destroy(url);
  777.         continue;
  778. not_acceptable:
  779.         pap_event_destroy(p);
  780.         http_destroy_headers(push_headers);
  781.         http_destroy_cgiargs(cgivars);
  782.         octstr_destroy(username);
  783.         octstr_destroy(mime_content);
  784.         octstr_destroy(pap_content);
  785.         octstr_destroy(push_data);
  786.         octstr_destroy(rdf_content);
  787.         octstr_destroy(boundary);
  788.         octstr_destroy(url);
  789.         continue;
  790. clean:
  791.         pap_event_destroy(p);
  792.         http_destroy_headers(push_headers);
  793.         http_destroy_headers(content_headers);
  794.         octstr_destroy(pap_content);
  795.         octstr_destroy(push_data);
  796.         octstr_destroy(rdf_content);
  797.         octstr_destroy(content_header);
  798.         octstr_destroy(boundary);
  799.         octstr_destroy(url);
  800.         continue;
  801. ferror:
  802.         pap_event_destroy(p);
  803.         http_destroy_headers(push_headers);
  804.         http_destroy_cgiargs(cgivars);
  805.         octstr_destroy(username);
  806.         octstr_destroy(url);
  807.         octstr_destroy(ip);
  808.         octstr_destroy(mime_content);
  809.         continue;
  810. herror:
  811.         pap_event_destroy(p);
  812.         http_destroy_headers(push_headers);
  813.         http_destroy_cgiargs(cgivars);
  814.         octstr_destroy(username);
  815.         octstr_destroy(url);
  816.         continue;
  817. berror:
  818.         pap_event_destroy(p);
  819.         http_destroy_headers(push_headers);
  820.         http_destroy_cgiargs(cgivars);
  821.         octstr_destroy(username);
  822.         octstr_destroy(mime_content);
  823.         octstr_destroy(content_header);
  824.         octstr_destroy(boundary);
  825.         octstr_destroy(url);
  826.         continue;
  827.     }
  828. }
  829. /*
  830.  * Operations needed when push proxy gateway receives a new push message are 
  831.  * defined in ppg Chapter 6. We create machines when error, too, because we 
  832.  * must then have a reportable message error state.
  833.  * Output: current HTTP Client state.
  834.  * Return 1 if the push content was OK, 0 if it was not transformable.
  835.  */
  836. static int handle_push_message(HTTPClient **c, WAPEvent *e, int status)
  837. {
  838.     int cless,
  839.         session_exists,
  840.         bearer_supported,
  841.         dummy,
  842.         constraints,
  843.         message_transformable,
  844.         coriented_possible;
  845.     long coded_appid_value;
  846.     PPGPushMachine *pm;
  847.     PPGSessionMachine *sm;
  848.     WAPAddrTuple *tuple;
  849.     Octstr *push_data,
  850.            *cliaddr,
  851.            *type;
  852.     List *push_headers;
  853.    
  854.     push_data = e->u.Push_Message.push_data;
  855.     push_headers = e->u.Push_Message.push_headers;
  856.     cliaddr = e->u.Push_Message.address_value;
  857.     session_exists = 0;
  858.     sm = session_find_using_pi_client_address(cliaddr);
  859.     coded_appid_value = check_x_wap_application_id_header(&push_headers);
  860.     cless = cless_accepted(e, sm);
  861.     message_transformable = transform_message(&e, &tuple, push_headers, cless, 
  862.                                               &type);
  863.     if (!sm && !cless) {
  864.         sm = store_session_data(sm, e, tuple, &session_exists); 
  865.     }
  866.     if (!store_push_data(&pm, sm, e, tuple, cless)) {
  867.         warning(0, "PPG: handle_push_message: duplicate push id");
  868.         *c = response_push_message(pm, PAP_DUPLICATE_PUSH_ID, status);
  869.         goto no_start;
  870.     }
  871.     
  872.     if (!message_transformable) {
  873.     pm = update_push_data_with_attribute(&sm, pm, 
  874.             PAP_TRANSFORMATION_FAILURE, PAP_UNDELIVERABLE1);  
  875.         if (tuple != NULL)   
  876.         *c = response_push_message(pm, PAP_TRANSFORMATION_FAILURE, status);
  877.         else
  878.         *c = response_push_message(pm, PAP_ADDRESS_ERROR, status);
  879.         goto no_transformation;
  880.     }
  881.     
  882.     dummy = 0;
  883.     pm = update_push_data_with_attribute(&sm, pm, dummy, PAP_PENDING);
  884.     
  885.     bearer_supported = select_bearer_network(&e);
  886.     if (!bearer_supported) {
  887.         pm = update_push_data_with_attribute(&sm, pm, dummy, 
  888.             PAP_UNDELIVERABLE2);
  889.         *c = response_push_message(pm, PAP_REQUIRED_BEARER_NOT_AVAILABLE, status);
  890.     goto no_start;
  891.     }
  892.     
  893.     if ((constraints = delivery_time_constraints(e, pm)) == TIME_EXPIRED) {
  894.         pm = update_push_data_with_attribute(&sm, pm, PAP_FORBIDDEN, 
  895.                                              PAP_EXPIRED);
  896.         *c = response_push_message(pm, PAP_FORBIDDEN, status);
  897.     goto no_start;
  898.     }
  899. /*
  900.  * If time is to early for delivering the push message, we do not remove push
  901.  * data. We response PI here, so that "accepted for processing" means "no 
  902.  * error messages to come".
  903.  */ 
  904.     *c = response_push_message(pm, PAP_ACCEPTED_FOR_PROCESSING, status);
  905.     info(0, "PPG: handle_push_message: push message accepted for processing");
  906.     if (constraints == TIME_TOO_EARLY)
  907.     goto store_push;
  908.     if (constraints == NO_CONSTRAINTS) {
  909.     http_header_mark_transformation(pm->push_headers, pm->push_data, type);
  910.         if (sm)
  911.             sm = update_session_data_with_headers(sm, pm); 
  912.         if (!confirmation_requested(e)) {
  913.             pm = deliver_unit_push(NOT_LAST, pm, sm, session_exists);
  914.             goto unit_push_delivered;
  915.     } 
  916.       
  917.         if (session_exists) {
  918.             deliver_confirmed_push(NOT_LAST, pm, sm);   
  919.         } else { 
  920.             coriented_possible = coriented_deliverable(coded_appid_value); 
  921.         http_header_remove_all(e->u.Push_Message.push_headers, 
  922.                                    "Content-Type");  
  923.             if (coriented_possible) {
  924.                 create_session(e, pm);
  925.             } else {
  926.                 warning(0, "PPG: handle_push_message: wrong app id for confirmed"
  927.                         " push session creation");
  928.                 *c = response_push_message(pm, PAP_BAD_REQUEST, status);
  929.             }
  930.         }
  931.     }
  932.     wap_addr_tuple_destroy(tuple);
  933.     octstr_destroy(type);
  934.     wap_event_destroy(e);
  935.     return 1;
  936. unit_push_delivered:
  937.     wap_addr_tuple_destroy(tuple);
  938.     remove_push_data(sm, pm, cless);
  939.     octstr_destroy(type);
  940.     wap_event_destroy(e);
  941.     return 1;
  942. store_push:
  943.     wap_addr_tuple_destroy(tuple);
  944.     octstr_destroy(type);
  945.     wap_event_destroy(e);
  946.     return 1;
  947. no_transformation:
  948.     wap_addr_tuple_destroy(tuple);
  949.     remove_push_data(sm, pm, cless);
  950.     if (sm)
  951.         remove_pushless_session(sm);
  952.     wap_event_destroy(e);
  953.     return 0;
  954. no_start:
  955.     wap_addr_tuple_destroy(tuple);
  956.     octstr_destroy(type);
  957.     remove_push_data(sm, pm, cless);
  958.     if (sm)
  959.         remove_pushless_session(sm);
  960.     wap_event_destroy(e);
  961.     return 1;
  962. }
  963. /*
  964.  * These events come from OTA layer
  965.  */
  966. static void handle_internal_event(WAPEvent *e)
  967. {
  968.     long sid,
  969.          pid,
  970.          reason,
  971.          port;
  972.     int http_status;
  973.     PPGPushMachine *pm;
  974.     PPGSessionMachine *sm;
  975.     WAPAddrTuple *tuple;
  976.     List *caps;
  977.         
  978.     http_status = HTTP_OK;
  979.     switch (e->type) {
  980. /*
  981.  * Pap, Chapter 11.1.3 states that if client is incapable, we should abort the
  982.  * push and inform PI. We do this here.
  983.  * In addition, we store session id used as an alias for address tuple and do
  984.  * all pushes pending for this initiator (or abort them).
  985.  */
  986.     case Pom_Connect_Ind:
  987.          debug("wap.push.ppg", 0, "PPG: handle_internal_event: connect"
  988.                " indication from OTA");
  989.          sid = e->u.Pom_Connect_Ind.session_id;
  990.          tuple = e->u.Pom_Connect_Ind.addr_tuple;
  991.          port = tuple->remote->port;
  992.          caps = e->u.Pom_Connect_Ind.requested_capabilities;
  993.          sm = wap_push_ppg_have_push_session_for(tuple);
  994.          sm = update_session_data(sm, sid, port, caps);
  995.         
  996.          if (!response_push_connection(e, sm)) {
  997.      pm = abort_delivery(sm, http_status);
  998.              wap_event_destroy(e);
  999.              return;
  1000.          }
  1001. /* 
  1002.  * hard-coded until we have bearer control implemented
  1003.  */
  1004.          deliver_pending_pushes(sm, NOT_LAST);  
  1005.          wap_event_destroy(e);
  1006.     break;
  1007.     case Pom_Disconnect_Ind:
  1008.         debug("wap.push.ppg", 0, "PPG: handle_internal_event: disconnect"
  1009.               " indication from OTA");
  1010.         sm = wap_push_ppg_have_push_session_for_sid(
  1011.                  e->u.Pom_Disconnect_Ind.session_handle);
  1012.         remove_session_data(sm, http_status);
  1013.         wap_event_destroy(e);
  1014.     break;
  1015. /*
  1016.  * Only the client can close a session. So we leave session open, even when 
  1017.  * there are no active pushes. Note that we do not store PAP attribute very
  1018.  * long time. Point is that result notification message, if asked, will rep-
  1019.  * ort this fact to PI, after which there is no need to store it any more.
  1020.  */
  1021.     case Po_ConfirmedPush_Cnf:
  1022.         debug("wap.push.ppg", 0, "PPG: handle_internal_event: push"
  1023.               " confirmation from OTA");
  1024.         sid = e->u.Po_ConfirmedPush_Cnf.session_handle;
  1025.         pid = e->u.Po_ConfirmedPush_Cnf.server_push_id;
  1026.         sm = wap_push_ppg_have_push_session_for_sid(sid);
  1027.         pm = find_ppg_push_machine_using_pid(sm, pid);
  1028.         pm = update_push_data_with_attribute(&sm, pm, PAP_CONFIRMED, 
  1029.                                              PAP_DELIVERED2);
  1030.         wap_event_destroy(e);
  1031.         remove_push_data(sm, pm, 0);
  1032.     break;
  1033. /*
  1034.  * Again, PAP attribute will be reported to PI by using result notification.
  1035.  */
  1036.     case Po_PushAbort_Ind:
  1037.         debug("wap.push.ppg", 0, "PPG: handle_internal_event: abort"
  1038.               " indication from OTA");
  1039.         sid = e->u.Po_PushAbort_Ind.session_handle;
  1040.         pid = e->u.Po_PushAbort_Ind.push_id;
  1041.         sm = wap_push_ppg_have_push_session_for_sid(sid);
  1042.         pm = find_ppg_push_machine_using_pid(sm, pid);
  1043.         session_machine_assert(sm);
  1044.         push_machine_assert(pm);
  1045.         reason = e->u.Po_PushAbort_Ind.reason;
  1046.         pm = update_push_data_with_attribute(&sm, pm, reason, PAP_ABORTED);
  1047.         remove_session_data(sm, http_status);
  1048.         wap_event_destroy(e);
  1049.     break;
  1050. /*
  1051.  * FIXME TRU: Add timeout (a mandatory feature!)
  1052.  */
  1053.     default:
  1054.         debug("wap.ppg", 0, "PPG: handle_internal_event: an unhandled event");
  1055.         wap_event_dump(e);
  1056.         wap_event_destroy(e);
  1057.     break;
  1058.     }
  1059. }
  1060. /*
  1061.  * Functions related to various ppg machine types.
  1062.  *
  1063.  * We do not set session id here: it is told to us by wsp.
  1064.  */
  1065. static PPGSessionMachine *session_machine_create(WAPAddrTuple *tuple, 
  1066.                                                  WAPEvent *e)
  1067. {
  1068.     PPGSessionMachine *m;
  1069.     gw_assert(e->type = Push_Message);
  1070.     m = gw_malloc(sizeof(PPGSessionMachine));
  1071.     
  1072.     #define INTEGER(name) m->name = 0;
  1073.     #define OCTSTR(name) m->name = NULL;
  1074.     #define ADDRTUPLE(name) m->name = NULL;
  1075.     #define PUSHMACHINES(name) m->name = list_create();
  1076.     #define CAPABILITIES(name) m->name = NULL;
  1077.     #define MACHINE(fields) fields
  1078.     #include "wap_ppg_session_machine.def"
  1079.     m->pi_client_address = octstr_duplicate(e->u.Push_Message.address_value);
  1080.     m->addr_tuple = wap_addr_tuple_duplicate(tuple);
  1081.     m->assumed_capabilities = 
  1082.         wsp_cap_duplicate_list(e->u.Push_Message.pi_capabilities);
  1083.     m->preferconfirmed_value = PAP_CONFIRMED;    
  1084.     list_append(ppg_machines, m);
  1085.     debug("wap.push.ppg", 0, "PPG: Created PPGSessionMachine %ld",
  1086.           m->session_id);
  1087.     return m;
  1088. }
  1089. static void session_machine_destroy(void *p)
  1090. {
  1091.     PPGSessionMachine *sm;
  1092.     if (p == NULL)
  1093.         return;
  1094.     sm = p;
  1095.     debug("wap.push.ppg", 0, "PPG: destroying PPGSEssionMachine %ld", 
  1096.           sm->session_id);
  1097.     
  1098.     #define OCTSTR(name) octstr_destroy(sm->name);
  1099.     #define ADDRTUPLE(name) wap_addr_tuple_destroy(sm->name);
  1100.     #define INTEGER(name) sm->name = 0;
  1101.     #define PUSHMACHINES(name) push_machines_list_destroy(sm->name);
  1102.     #define CAPABILITIES(name) wsp_cap_destroy_list(sm->name);
  1103.     #define MACHINE(fields) fields
  1104.     #include "wap_ppg_session_machine.def"
  1105.     gw_free(sm);
  1106. }
  1107. /*
  1108.  * FIXME: PPG's trust policy (flags authenticated and trusted).
  1109.  * We return pointer to the created push machine and push id it uses.
  1110.  */
  1111. static PPGPushMachine *push_machine_create(WAPEvent *e, WAPAddrTuple *tuple)
  1112. {
  1113.     PPGPushMachine *m;
  1114.     m = gw_malloc(sizeof(PPGPushMachine));
  1115.     #define INTEGER(name) m->name = 0;
  1116.     #define OCTSTR(name) m->name = NULL;
  1117.     #define OPTIONAL_OCTSTR(name) m->name = NULL;
  1118.     #define ADDRTUPLE(name) m->name = NULL;
  1119.     #define CAPABILITIES m->name = NULL;
  1120.     #define HTTPHEADER(name) m->name = NULL;
  1121.     #define MACHINE(fields) fields
  1122.     #include "wap_ppg_push_machine.def"
  1123.     m->addr_tuple = wap_addr_tuple_duplicate(tuple);
  1124.     m->pi_push_id = octstr_duplicate(e->u.Push_Message.pi_push_id);
  1125.     m->push_id = counter_increase(push_id_counter);
  1126.     m->delivery_method = e->u.Push_Message.delivery_method;
  1127.     m->deliver_after_timestamp = 
  1128.         octstr_duplicate(e->u.Push_Message.deliver_after_timestamp);
  1129.     m->priority = e->u.Push_Message.priority;
  1130.     m->push_headers = http_header_duplicate(e->u.Push_Message.push_headers);
  1131.     m->push_data = octstr_duplicate(e->u.Push_Message.push_data);
  1132.     m->address_type = e->u.Push_Message.address_type;
  1133.     m->progress_notes_requested = e->u.Push_Message.progress_notes_requested;
  1134.     if (e->u.Push_Message.progress_notes_requested)
  1135.         m->ppg_notify_requested_to = 
  1136.             octstr_duplicate(e->u.Push_Message.ppg_notify_requested_to);
  1137.     debug("wap.push.ppg", 0, "PPG: push machine %ld created", m->push_id);
  1138.     return m;
  1139. }
  1140. /*
  1141.  * Contrary to the normal Kannel style, we do not remove from a list here. 
  1142.  * That is because we now have two different push lists.
  1143.  */
  1144. static void push_machine_destroy(void *p)
  1145. {
  1146.     PPGPushMachine *pm;
  1147.     if (p == NULL)
  1148.         return;
  1149.     pm = p;
  1150.     debug("wap.push.ppg", 0, "PPG: destroying push machine %ld", 
  1151.           pm->push_id); 
  1152.     #define OCTSTR(name) octstr_destroy(pm->name);
  1153.     #define OPTIONAL_OCTSTR(name) octstr_destroy(pm->name);
  1154.     #define INTEGER(name)
  1155.     #define ADDRTUPLE(name) wap_addr_tuple_destroy(pm->name);
  1156.     #define CAPABILITIES(name) wap_cap_destroy_list(pm->name);
  1157.     #define HTTPHEADER(name) http_destroy_headers(pm->name);
  1158.     #define MACHINE(fields) fields
  1159.     #include "wap_ppg_push_machine.def"
  1160.     gw_free(p);
  1161. }
  1162. static void push_machines_list_destroy(List *machines)
  1163. {
  1164.     if (machines == NULL)
  1165.         return;
  1166.     list_destroy(machines, push_machine_destroy);
  1167. }
  1168. static int session_has_addr(void *a, void *b)
  1169. {
  1170.     Octstr *cliaddr;
  1171.     PPGSessionMachine *sm;
  1172.     cliaddr = b;
  1173.     sm = a;
  1174.     
  1175.     return octstr_compare(sm->addr_tuple->remote->address, cliaddr) == 0;
  1176. }
  1177. static int session_has_sid(void *a, void *b)
  1178. {
  1179.      PPGSessionMachine *sm;
  1180.      long *sid;
  1181.      sid = b;
  1182.      sm = a;
  1183.      return *sid == sm->session_id;
  1184. }
  1185. /*
  1186.  * Here session machine address tuples have connection-oriented ports, because
  1187.  * these are used when establishing the connection an doing pushes. But session
  1188.  * creation request must be to the the connectionless push port of the client.
  1189.  * So we change ports here.
  1190.  */
  1191. static void create_session(WAPEvent *e, PPGPushMachine *pm)
  1192. {
  1193.     WAPEvent *ota_event;
  1194.     List *push_headers;
  1195.     gw_assert(e->type == Push_Message);
  1196.     push_machine_assert(pm);
  1197.     
  1198.     push_headers = http_header_duplicate(e->u.Push_Message.push_headers);
  1199.     ota_event = wap_event_create(Pom_SessionRequest_Req);
  1200.     ota_event->u.Pom_SessionRequest_Req.addr_tuple =
  1201.         addr_tuple_change_cliport(pm->addr_tuple,
  1202.                                   CONNECTIONLESS_PUSH_CLIPORT);
  1203.     ota_event->u.Pom_SessionRequest_Req.push_headers = push_headers;
  1204.     ota_event->u.Pom_SessionRequest_Req.push_id = pm->push_id;
  1205.     ota_event->u.Pom_SessionRequest_Req.address_type = pm->address_type;
  1206.      
  1207.     dispatch_to_ota(ota_event);
  1208. }
  1209. /*
  1210.  * We store data to push machine, because it is possible that we do not have
  1211.  * a session when push request happens.
  1212.  */
  1213. static void request_confirmed_push(long last, PPGPushMachine *pm, 
  1214.                                    PPGSessionMachine *sm)
  1215. {
  1216.     WAPEvent *ota_event;
  1217.     List *push_headers;
  1218.     gw_assert(last == 0 || last == 1);
  1219.     push_machine_assert(pm);
  1220.     session_machine_assert(sm);
  1221.     
  1222.     push_headers = http_header_duplicate(pm->push_headers);
  1223.     ota_event = wap_event_create(Po_ConfirmedPush_Req);
  1224.     ota_event->u.Po_ConfirmedPush_Req.server_push_id = pm->push_id;
  1225.     ota_event->u.Po_ConfirmedPush_Req.push_headers = push_headers;
  1226.     ota_event->u.Po_ConfirmedPush_Req.authenticated = pm->authenticated;
  1227.     ota_event->u.Po_ConfirmedPush_Req.trusted = pm->trusted;
  1228.     ota_event->u.Po_ConfirmedPush_Req.last = last;
  1229.  
  1230.     if (pm->push_data != NULL)
  1231.         ota_event->u.Po_ConfirmedPush_Req.push_body = 
  1232.             octstr_duplicate(pm->push_data);
  1233.     else
  1234.         ota_event->u.Po_ConfirmedPush_Req.push_body = NULL;
  1235.     ota_event->u.Po_ConfirmedPush_Req.session_handle = sm->session_id;
  1236.     debug("wap.push.ota", 0, "PPG: confirmed push request to OTA");
  1237.     
  1238.     dispatch_to_ota(ota_event);
  1239. }
  1240. /*
  1241.  * There is to types of unit push requests: requesting ip services and sms 
  1242.  * services. Address type tells the difference.
  1243.  */
  1244. static void request_unit_push(long last, PPGPushMachine *pm)
  1245. {
  1246.     WAPEvent *ota_event;
  1247.     List *push_headers;
  1248.     gw_assert(last == 0 || last == 1);
  1249.     push_machine_assert(pm);
  1250.     
  1251.     push_headers = http_header_duplicate(pm->push_headers);
  1252.     ota_event = wap_event_create(Po_Unit_Push_Req);
  1253.     ota_event->u.Po_Unit_Push_Req.addr_tuple = 
  1254.         wap_addr_tuple_duplicate(pm->addr_tuple);
  1255.     ota_event->u.Po_Unit_Push_Req.push_id = pm->push_id;
  1256.     ota_event->u.Po_Unit_Push_Req.push_headers = push_headers;
  1257.     ota_event->u.Po_Unit_Push_Req.authenticated = pm->authenticated;
  1258.     ota_event->u.Po_Unit_Push_Req.trusted = pm->trusted;
  1259.     ota_event->u.Po_Unit_Push_Req.last = last;
  1260.     ota_event->u.Po_Unit_Push_Req.address_type = pm->address_type;
  1261.     ota_event->u.Po_Unit_Push_Req.push_body = 
  1262.             octstr_duplicate(pm->push_data);
  1263.     dispatch_to_ota(ota_event);
  1264.     debug("wap.push.ppg", 0, "PPG: OTA request for unit push");
  1265. }
  1266. static void request_push(long last, PPGPushMachine *pm)
  1267. {
  1268.     WAPEvent *ota_event;
  1269.     List *push_headers;
  1270.     gw_assert(last == 0 || last == 1);
  1271.     push_machine_assert(pm);
  1272.     
  1273.     push_headers = http_header_duplicate(pm->push_headers);
  1274.     ota_event = wap_event_create(Po_Push_Req);
  1275.     ota_event->u.Po_Push_Req.push_headers = push_headers;
  1276.     ota_event->u.Po_Push_Req.authenticated = pm->authenticated;
  1277.     ota_event->u.Po_Push_Req.trusted = pm->trusted;
  1278.     ota_event->u.Po_Push_Req.last = last;
  1279.     if (pm->push_data != NULL)
  1280.         ota_event->u.Po_Push_Req.push_body = 
  1281.             octstr_duplicate(pm->push_data);
  1282.     else
  1283.         ota_event->u.Po_Push_Req.push_body = NULL;        
  1284.     ota_event->u.Po_Push_Req.session_handle = pm->session_id;
  1285.     debug("wap.push.ppg", 0, "PPG: OTA request for push");
  1286.     
  1287.     dispatch_to_ota(ota_event);
  1288. }
  1289. /*
  1290.  * According to pap, Chapter 11, capabilities can be 
  1291.  *    
  1292.  *                a) queried by PI
  1293.  *                b) told to PI when a client is subscribing
  1294.  *                c) assumed
  1295.  *
  1296.  * In case c) we got capabilities from third part of the push message (other
  1297.  * cases PI knows what it is doing), and we check is the client capable to
  1298.  * handle the message.
  1299.  * Requested capabilities are client capabilities, assumed capabilities are
  1300.  * PI capabilities. If there is no assumed capabilities, PI knows client capab-
  1301.  * ilities by method a) or method b).
  1302.  * Returns 1, if the client is capable, 0 when it is not.
  1303.  */
  1304. static int response_push_connection(WAPEvent *e, PPGSessionMachine *sm)
  1305. {
  1306.     WAPEvent *appl_event;
  1307.     gw_assert(e->type == Pom_Connect_Ind);
  1308.     if (sm->assumed_capabilities != NULL && check_capabilities(
  1309.             e->u.Pom_Connect_Ind.requested_capabilities, 
  1310.             sm->assumed_capabilities) == 0)
  1311.        return 0;
  1312.     appl_event = wap_event_create(Pom_Connect_Res);
  1313.     appl_event->u.Pom_Connect_Res.negotiated_capabilities = 
  1314.         wsp_cap_duplicate_list(e->u.Pom_Connect_Ind.requested_capabilities);
  1315.     appl_event->u.Pom_Connect_Res.session_id = e->u.Pom_Connect_Ind.session_id;
  1316.     dispatch_to_appl(appl_event);
  1317.     return 1;
  1318. }
  1319. /*
  1320.  * Push response, from pap, Chapter 9.3. 
  1321.  * Inputs error code, in PAP format.
  1322.  * Return the current value of HTTPClient.
  1323.  */
  1324. static HTTPClient *response_push_message(PPGPushMachine *pm, long code, int status)
  1325. {
  1326.     WAPEvent *e;
  1327.     HTTPClient *c;
  1328.     push_machine_assert(pm);
  1329.     e = wap_event_create(Push_Response);
  1330.     e->u.Push_Response.pi_push_id = octstr_duplicate(pm->pi_push_id);
  1331.     e->u.Push_Response.sender_name = tell_ppg_name();
  1332.     e->u.Push_Response.reply_time = set_time();
  1333.     e->u.Push_Response.code = code;
  1334.     e->u.Push_Response.desc = describe_code(code);
  1335.     c = send_push_response(e, status);
  1336.     return c;
  1337. }
  1338. static int check_capabilities(List *requested, List *assumed)
  1339. {
  1340.     int is_capable;
  1341.     is_capable = 1;
  1342.     return is_capable;
  1343. }
  1344. /*
  1345.  * Time of creation of the response (pap, chapter 9.3). We convert UNIX time 
  1346.  * to ISO8601, it is, YYYY-MM-DDThh:mm:ssZ, T and Z being literal strings (we
  1347.  * use gw_gmtime to turn UNIX time to broken time).
  1348.  */
  1349. static Octstr *set_time(void)
  1350. {
  1351.     Octstr *current_time;
  1352.     struct tm now;
  1353.     now = gw_gmtime(time(NULL));
  1354.     current_time = octstr_format("%04d-%02d-%02dT%02d:%02d:%02dZ", 
  1355.                                  now.tm_year + 1900, now.tm_mon + 1, 
  1356.                                  now.tm_mday, now.tm_hour, now.tm_min, 
  1357.                                  now.tm_sec);
  1358.     return current_time;
  1359. }
  1360. static void session_machine_assert(PPGSessionMachine *sm)
  1361. {
  1362.     gw_assert(sm);
  1363.     gw_assert(sm->session_id >= 0);
  1364.     gw_assert(sm->addr_tuple);
  1365.     gw_assert(sm->pi_client_address);
  1366. }
  1367. static void push_machine_assert(PPGPushMachine *pm)
  1368. {
  1369.     gw_assert(pm);
  1370.     gw_assert(pm->pi_push_id);
  1371.     gw_assert(pm->push_id >= 0);
  1372.     gw_assert(pm->session_id >= 0);
  1373.     gw_assert(pm->addr_tuple);
  1374.     gw_assert(pm->trusted == 1 || pm->trusted == 0);
  1375.     gw_assert(pm->authenticated  == 1 || pm->authenticated == 0);
  1376. }
  1377. /*
  1378.  * Message transformations performed by PPG are defined in ppg, 6.1.2.1. Ppg,
  1379.  * chapter 6.1.1, states that we MUST reject a push having an erroneous PAP
  1380.  * push message element. So we must validate it even when we do not compile
  1381.  * it.
  1382.  * We do not do any (formally optional, but phones may disagree) header 
  1383.  * conversions to the binary format here, these are responsibility of our OTA 
  1384.  * module (gw/wap_push_ota.c). 
  1385.  * FIXME: Remove all headers which default values are known to the client. 
  1386.  *
  1387.  * Return 
  1388.  *    a) message, either transformed or not (if there is no-transform cache 
  1389.  *       directive or wml code is erroneous) 
  1390.  *    b) The transformed gw address. Use here global-sender, when the bearer
  1391.  *       is SMS (some SMS centers would require this).
  1392.  *    c) the transformed message content type
  1393.  *
  1394.  * Returned flag tells was the transformation (if any) successfull or not. Error 
  1395.  * flag is returned when there is no push headers, there is no Content-Type header
  1396.  * or push content does not compile. We should have checked existence of push 
  1397.  * headers earlier, but let us be carefull.
  1398.  */
  1399. static int transform_message(WAPEvent **e, WAPAddrTuple **tuple, 
  1400.                              List *push_headers, int cless_accepted, Octstr **type)
  1401. {
  1402.     int message_deliverable;
  1403.     struct content content;
  1404.     Octstr *cliaddr;
  1405.     long cliport,
  1406.          servport,
  1407.          address_type;
  1408.     gw_assert((**e).type == Push_Message);
  1409.     if ((**e).u.Push_Message.push_headers == NULL)
  1410.         goto herror;
  1411.     cliaddr = (**e).u.Push_Message.address_value;
  1412.     push_headers = (**e).u.Push_Message.push_headers;
  1413.     if (!cless_accepted) {
  1414.         cliport = CONNECTED_CLIPORT;
  1415.         servport = CONNECTED_SERVPORT;
  1416.     } else {
  1417.         cliport = CONNECTIONLESS_PUSH_CLIPORT;
  1418.         servport = CONNECTIONLESS_SERVPORT;
  1419.     }
  1420.     
  1421.     address_type = (**e).u.Push_Message.address_type;
  1422.     *tuple = set_addr_tuple(cliaddr, cliport, servport, address_type);
  1423.     if (!content_transformable(push_headers)) 
  1424.         goto no_transform;
  1425.     content.body = (**e).u.Push_Message.push_data; 
  1426.     if (content.body == NULL)
  1427.         goto no_transform;
  1428.     content.type = http_header_find_first(push_headers, 
  1429.         "Content-Transfer-Encoding");
  1430.     if (content.type) {
  1431.     octstr_strip_blanks(content.type);
  1432.     debug("wap.push.ppg", 0, "PPG: Content-Transfer-Encoding is "%s"",
  1433.           octstr_get_cstr (content.type));
  1434.     message_deliverable = pap_get_content(&content);
  1435.     if (message_deliverable) {
  1436.         change_header_value(&push_headers, "Content-Transfer-Encoding", 
  1437.                                 "binary");
  1438.     } else {
  1439.         goto error;
  1440.     }
  1441.     }
  1442.     http_header_get_content_type(push_headers, &content.type,
  1443.                                  &content.charset);   
  1444.     message_deliverable = pap_convert_content(&content);
  1445.     if (content.type == NULL)
  1446.         goto error;
  1447.     if (message_deliverable) {
  1448.         *type = content.type;        
  1449.     } else {
  1450.         goto error;
  1451.     }
  1452.     (**e).u.Push_Message.push_data = content.body;
  1453.     octstr_destroy(content.charset);
  1454.     debug("wap.push.ppg", 0, "PPG: transform_message: push message content"
  1455.           " and headers valid");
  1456.     return 1;
  1457. herror:
  1458.     warning(0, "PPG: transform_message: no push headers, cannot accept");
  1459.     return 0;
  1460. error:
  1461.     warning(0, "PPG: transform_message: push content erroneous, cannot"
  1462.             " accept");
  1463.     octstr_destroy(content.type);
  1464.     octstr_destroy(content.charset);
  1465.     return 0;
  1466. no_transform:
  1467.     warning(0, "PPG: transform_message: push content non transformable");
  1468.     octstr_destroy(content.type);
  1469.     octstr_destroy(content.charset);
  1470.     return 1;
  1471. }
  1472. /*
  1473.  * Transform X-WAP-Application headers as per ppg 6.1.2.1. Note that missing
  1474.  * header means that wml.ua is assumed.
  1475.  * Return coded value (starting with 0), when the id was not wml.ua
  1476.  *        -1, when id was wml.ua (or no application id was present)
  1477.  *        -2, when error
  1478.  */
  1479. static long check_x_wap_application_id_header(List **push_headers)
  1480. {
  1481.     Octstr *appid_content;
  1482.     long coded_value;
  1483.     Octstr *cos;
  1484.     
  1485.     if (*push_headers == NULL)
  1486.         return -2;
  1487.     appid_content = http_header_find_first(*push_headers, 
  1488.         "X-WAP-Application-Id");
  1489.     
  1490.     if (appid_content == NULL) {
  1491.         octstr_destroy(appid_content);
  1492.         return -1;
  1493.     }
  1494.     if ((coded_value = parse_appid_header(&appid_content)) < 0) {
  1495.         octstr_destroy(appid_content);
  1496.         return -2;
  1497.     }
  1498.         
  1499.     if (coded_value == 2) {
  1500.         octstr_destroy(appid_content);
  1501.         http_header_remove_all(*push_headers, "X-WAP-Application-Id");
  1502.         return -1;
  1503.     }
  1504.     cos = octstr_format("%ld", coded_value);
  1505.     http_header_remove_all(*push_headers, "X-WAP-Application-Id");
  1506.     http_header_add(*push_headers, "X-WAP-Application-Id", octstr_get_cstr(cos));
  1507.     
  1508.     octstr_destroy(appid_content); 
  1509.     octstr_destroy(cos);
  1510.     
  1511.     return coded_value;  
  1512. }
  1513. /*
  1514.  * Check do we have a no-transform cache directive amongst the headers.
  1515.  */
  1516. static int content_transformable(List *push_headers)
  1517. {
  1518.     List *cache_directives;
  1519.     long i;
  1520.     Octstr *header_name, 
  1521.            *header_value;
  1522.     gw_assert(push_headers);
  1523.     cache_directives = http_header_find_all(push_headers, "Cache-Control");
  1524.     if (list_len(cache_directives) == 0) {
  1525.         http_destroy_headers(cache_directives);
  1526.         return 1;
  1527.     }
  1528.     i = 0;
  1529.     while (i < list_len(cache_directives)) {
  1530.         http_header_get(cache_directives, i, &header_name, &header_value);
  1531.         if (octstr_compare(header_value, octstr_imm("no-transform")) == 0) {
  1532.             http_destroy_headers(cache_directives);
  1533.             octstr_destroy(header_name);
  1534.             octstr_destroy(header_value);
  1535.     return 0;
  1536.         }
  1537.         ++i;
  1538.     }
  1539.     http_destroy_headers(cache_directives);
  1540.     octstr_destroy(header_name);
  1541.     octstr_destroy(header_value);
  1542.  
  1543.     return 1;
  1544. }
  1545. /*
  1546.  * Convert push content to compact binary format (this can be wmlc, sic, slc
  1547.  * or coc). Current status wml, sl and si compiled, others passed.
  1548.  */
  1549. static Octstr *convert_wml_to_wmlc(struct content *content)
  1550. {
  1551.     Octstr *wmlc;
  1552.     if (wml_compile(content->body, content->charset, &wmlc) == 0)
  1553.         return wmlc;
  1554.     warning(0, "PPG: wml compilation failed");
  1555.     return NULL;
  1556. }
  1557. static Octstr *convert_si_to_sic(struct content *content)
  1558. {
  1559.     Octstr *sic;
  1560.     if (si_compile(content->body, content->charset, &sic) == 0)
  1561.         return sic;
  1562.     warning(0, "PPG: si compilation failed");
  1563.     return NULL;
  1564. }
  1565. static Octstr *convert_sl_to_slc(struct content *content)
  1566. {
  1567.     Octstr *slc;
  1568.     if (sl_compile(content->body, content->charset, &slc) == 0)
  1569.         return slc;
  1570.     warning(0, "PPG: sl compilation failed");
  1571.     return NULL;
  1572. }
  1573. static Octstr *extract_base64(struct content *content)
  1574. {
  1575.     Octstr *orig = octstr_duplicate(content->body);
  1576.     octstr_base64_to_binary(orig);
  1577.     return orig;
  1578. }
  1579. static struct {
  1580.     char *type;
  1581.     char *result_type;
  1582.     Octstr *(*convert) (struct content *);
  1583. } converters[] = {
  1584.     { "text/vnd.wap.wml",
  1585.       "application/vnd.wap.wmlc",
  1586.       convert_wml_to_wmlc },
  1587.     { "text/vnd.wap.si",
  1588.       "application/vnd.wap.sic",
  1589.       convert_si_to_sic },
  1590.     { "text/vnd.wap.sl",
  1591.       "application/vnd.wap.slc",
  1592.       convert_sl_to_slc}
  1593. };
  1594. #define NUM_CONVERTERS ((long) (sizeof(converters) / sizeof(converters[0])))
  1595. static struct {
  1596.     char *transfer_encoding;
  1597.     Octstr *(*extract) (struct content *);
  1598. } extractors[] = {
  1599.     { "base64",
  1600.       extract_base64 }
  1601. };
  1602. #define NUM_EXTRACTORS ((long) (sizeof(extractors) / sizeof(extractors[0])))
  1603. /*
  1604.  * Compile wap defined contents, accept others without modifications. Push
  1605.  * message 6.3 states that push content can be any MIME accepted content type.
  1606.  */
  1607. static int pap_convert_content(struct content *content)
  1608. {
  1609.     long i;
  1610.     Octstr *new_body;
  1611.     for (i = 0; i < NUM_CONVERTERS; i++) {
  1612.         if (octstr_compare(content->type, 
  1613.             octstr_imm(converters[i].type)) == 0) {
  1614.         new_body = converters[i].convert(content);
  1615.             if (new_body == NULL)
  1616.             return 0;
  1617.             octstr_destroy(content->body);
  1618.             content->body = new_body;
  1619.             octstr_destroy(content->type); 
  1620.             content->type = octstr_create(converters[i].result_type);
  1621.             return 1;
  1622.         }
  1623.     }
  1624.     return 1;
  1625. }
  1626. /*
  1627.  * MIME specifies a number of content transfer encodings.
  1628.  * This function tries to get the original version of the
  1629.  * content.
  1630.  */
  1631. static int pap_get_content(struct content *content)
  1632. {
  1633.     long i;
  1634.     Octstr *new_body;
  1635.     for (i = 0; i < NUM_EXTRACTORS; i++) {
  1636.         if (octstr_case_compare(content->type, 
  1637.         octstr_imm(extractors[i].transfer_encoding)) == 0) {
  1638.     
  1639.         new_body = extractors[i].extract(content);
  1640.             if (new_body == NULL)
  1641.         return 0;
  1642.             octstr_destroy(content->body);
  1643.             content->body = new_body;
  1644.     octstr_destroy(content->type);
  1645.     content->type = NULL;
  1646.             return 1;
  1647.         }
  1648.     }
  1649.     return 1;
  1650. }
  1651. /*
  1652.  * Bearer and network types are defined in wdp, Appendix C. Any means any net-
  1653.  * work supporting IPv4 or IPv6.
  1654.  */
  1655. static char *bearers[] = {
  1656.    "Any",
  1657.    "SMS",
  1658.    "CSD",
  1659.    "GPRS",
  1660.    "Packet Data",
  1661.    "CDPD"
  1662. };
  1663. #define NUMBER_OF_BEARERS sizeof(bearers)/sizeof(bearers[0])
  1664. static char *networks[] = {
  1665.     "Any", 
  1666.     "GSM",
  1667.     "IS-95 CDMA",
  1668.     "ANSI-136",
  1669.     "AMPS",
  1670.     "PDC",
  1671.     "IDEN", 
  1672.     "PHS",   
  1673.     "TETRA"
  1674. };
  1675. #define NUMBER_OF_NETWORKS sizeof(networks)/sizeof(networks[0])
  1676. /*
  1677.  * We support networks using IP as a bearer and GSM using SMS as bearer, so we
  1678.  * must reject others. Default bearer is IP, it is (currently) not-SMS. After
  1679.  * the check we change meaning of the bearer_required-attribute: it will tell 
  1680.  * do we use WAP over SMS.
  1681.  */
  1682. int select_bearer_network(WAPEvent **e)
  1683. {
  1684.     Octstr *bearer,
  1685.            *network;
  1686.     int bearer_required,
  1687.         network_required;
  1688.     size_t i, 
  1689.            j;
  1690.     gw_assert((**e).type == Push_Message);
  1691.     bearer_required = (**e).u.Push_Message.bearer_required;
  1692.     network_required = (**e).u.Push_Message.network_required;
  1693.     bearer = octstr_imm("Any");
  1694.     network = octstr_imm("Any");
  1695.     
  1696.     if (!bearer_required || !network_required)
  1697.         return 1;
  1698.     if (bearer_required)
  1699.         bearer = (**e).u.Push_Message.bearer;
  1700.     if (network_required)
  1701.         network = (**e).u.Push_Message.network;
  1702.     
  1703.     for (i = 0; i < NUMBER_OF_NETWORKS ; ++i) {
  1704.         if (octstr_case_compare(bearer, octstr_imm(bearers[i])) == 0)
  1705.         break;
  1706.     }
  1707.     for (j = 0; j < NUMBER_OF_BEARERS ; ++j) {
  1708.         if (octstr_case_compare(bearer, octstr_imm(bearers[j])) == 0)
  1709.         break;
  1710.     }
  1711.     if (i == NUMBER_OF_NETWORKS || j == NUMBER_OF_BEARERS)
  1712.         return 0;
  1713.     return 1;
  1714. }
  1715. static int session_has_pi_client_address(void *a, void *b)
  1716. {
  1717.     Octstr *caddr;
  1718.     PPGSessionMachine *sm;
  1719.     caddr = b;
  1720.     sm = a;
  1721.     return octstr_compare(caddr, sm->pi_client_address) == 0;
  1722. }
  1723. /*
  1724.  * PI client address is composed of a client specifier and a PPG specifier (see
  1725.  * ppg, chapter 7). So it is equivalent with gw address quadruplet.
  1726.  */
  1727. PPGSessionMachine *session_find_using_pi_client_address(Octstr *caddr)
  1728. {
  1729.     PPGSessionMachine *sm;
  1730.     
  1731.     sm = list_search(ppg_machines, caddr, session_has_pi_client_address);
  1732.     return sm;
  1733. }
  1734. /*
  1735.  * Give PPG a human readable name.
  1736.  */
  1737. static Octstr *tell_ppg_name(void)
  1738. {
  1739.      return octstr_format("%S; WAP/1.3 (" GW_NAME "/%s)", get_official_name(), 
  1740.                           VERSION);
  1741. }
  1742. /*
  1743.  * Delivery time constraints are a) deliver before and b) deliver after. It is
  1744.  * possible that service required is after some time and before other. So we 
  1745.  * test first condition a). Note that 'now' satisfy both constraints. 
  1746.  * Returns: 0 delivery time expired
  1747.  *          1 too early to send the message
  1748.  *          2 no constraints
  1749.  */
  1750. static int delivery_time_constraints(WAPEvent *e, PPGPushMachine *pm)
  1751. {
  1752.     Octstr *before,
  1753.            *after;
  1754.     struct tm now;
  1755.    
  1756.     gw_assert(e->type = Push_Message);
  1757.     
  1758.     before = e->u.Push_Message.deliver_before_timestamp;
  1759.     after = pm->deliver_after_timestamp;
  1760.     now = gw_gmtime(time(NULL));
  1761.     if (!deliver_before_test_cleared(before, now)) {
  1762.         info(0, "PPG: delivery deadline expired, dropping the push message");
  1763.         return 0;
  1764.     }
  1765.     if (!deliver_after_test_cleared(after, now)) {
  1766.         debug("wap.push.ppg", 0, "PPG: too early to push the message,"
  1767.               " waiting");
  1768.         return 1;
  1769.     }
  1770.     return 2;
  1771. }
  1772. /*
  1773.  * Give verbose description of the result code. Conversion table for descrip-
  1774.  * tion.
  1775.  */
  1776. struct description_t {
  1777.     long reason;
  1778.     char *description;
  1779. };
  1780. typedef struct description_t description_t;
  1781. static description_t pap_desc[] = {
  1782.     { PAP_OK, "The request succeeded"},
  1783.     { PAP_ACCEPTED_FOR_PROCESSING, "The request has been accepted for"
  1784.                                    " processing"},
  1785.     { PAP_BAD_REQUEST, "Not understood due to malformed syntax"},
  1786.     { PAP_FORBIDDEN, "Request was refused"},
  1787.     { PAP_ADDRESS_ERROR, "The client specified not recognised"},
  1788.     { PAP_CAPABILITIES_MISMATCH, "Capabilities assumed by PI were not"
  1789.                                  "  acceptable for the client specified"},
  1790.     { PAP_DUPLICATE_PUSH_ID, "Push id supplied was not unique"},
  1791.     { PAP_INTERNAL_SERVER_ERROR, "Server could not fulfill the request due"
  1792.                                  " to an internal error"},
  1793.     { PAP_TRANSFORMATION_FAILURE, "PPG was unable to perform a transformation"
  1794.                                   " of the message"},
  1795.     { PAP_REQUIRED_BEARER_NOT_AVAILABLE, "Required bearer not available"},
  1796.     { PAP_SERVICE_FAILURE, "The service failed. The client may re-attempt"
  1797.                            " the operation"},
  1798.     { PAP_CLIENT_ABORTED, "The client aborted the operation. No reason given"},
  1799.     { WSP_ABORT_USERREQ, "Wsp requested abort"},
  1800.     { WSP_ABORT_USERRFS, "Wsp refused push message. Do not try again"},
  1801.     { WSP_ABORT_USERPND, "Push message cannot be delivered to intended"
  1802.                          " destination by the wsp"},
  1803.     { WSP_ABORT_USERDCR, "Push message discarded due to resource shortage in"
  1804.                          " wsp"},
  1805.     { WSP_ABORT_USERDCU, "Content type of the push message cannot be"
  1806.                          " processed by the wsp"}
  1807. };
  1808. static size_t desc_tab_size = sizeof(pap_desc) / sizeof(pap_desc[0]);
  1809.     
  1810. static Octstr *describe_code(long code)
  1811. {
  1812.     Octstr *desc;
  1813.     size_t i;
  1814.     for (i = 0; i < desc_tab_size; i++) {
  1815.         if (pap_desc[i].reason == code) {
  1816.             desc = octstr_create(pap_desc[i].description);
  1817.             return desc;
  1818.         }
  1819.     }
  1820.     return octstr_imm("unknown PAP code");
  1821. }
  1822. /*
  1823.  * Remove push data from the list of connectionless pushes, if cless is true, 
  1824.  * otherwise from the list of pushes belonging to session machine sm.
  1825.  */
  1826. static void remove_push_data(PPGSessionMachine *sm, PPGPushMachine *pm, 
  1827.                              int cless)
  1828. {
  1829.     push_machine_assert(pm);
  1830.     if (cless) {
  1831.         list_delete_equal(ppg_unit_pushes, pm);
  1832.     } else {
  1833.         session_machine_assert(sm);
  1834.         list_delete_equal(sm->push_machines, pm);
  1835.     }
  1836.     push_machine_destroy(pm);
  1837. }
  1838. /*
  1839.  * If cless is true, store push to the list connectionless pushes, otherwise 
  1840.  * in the push list of the session machine sm.
  1841.  * We must create a push machine even when an error occurred, because this is
  1842.  * used for storing the relevant pap error state and other data for this push.
  1843.  * There should not be any duplicate push ids here (this is tested by http_
  1844.  * read_thread), but let us be carefull.
  1845.  * Return a pointer the push machine newly created and a flag telling was the
  1846.  * push id duplicate. 
  1847.  */
  1848. static int store_push_data(PPGPushMachine **pm, PPGSessionMachine *sm, 
  1849.                            WAPEvent *e, WAPAddrTuple *tuple, int cless)
  1850.     Octstr *pi_push_id;  
  1851.     int duplicate_push_id;
  1852.     
  1853.     gw_assert(e->type == Push_Message);
  1854.     pi_push_id = e->u.Push_Message.pi_push_id;
  1855.     duplicate_push_id = 0;
  1856.     if (((!cless) && 
  1857.        (find_ppg_push_machine_using_pi_push_id(sm, pi_push_id) != NULL)) ||
  1858.        ((cless) && 
  1859.        (find_unit_ppg_push_machine_using_pi_push_id(pi_push_id) != NULL)))
  1860.        duplicate_push_id = 1;
  1861.     *pm = push_machine_create(e, tuple);
  1862.     
  1863.     if (duplicate_push_id)
  1864.         return !duplicate_push_id;
  1865.     
  1866.     if (!cless) {
  1867.        list_append(sm->push_machines, *pm);
  1868.        debug("wap.push.ppg", 0, "PPG: store_push_data: push machine %ld"
  1869.              " appended to push list of sm machine %ld", (*pm)->push_id, 
  1870.              sm->session_id);
  1871.     } else {
  1872.        list_append(ppg_unit_pushes, *pm);
  1873.        debug("wap.push.ppg", 0, "PPG: store_push_data: push machine %ld"
  1874.              " appended to unit push list", (*pm)->push_id);
  1875.     }
  1876.     return !duplicate_push_id;
  1877. }
  1878. /*
  1879.  * Deliver confirmed push. Note that if push is confirmed, PAP attribute is up-
  1880.  * dated only after an additional event (confirmation, abort or time-out). 
  1881.  */
  1882. static void deliver_confirmed_push(long last, PPGPushMachine *pm, 
  1883.                                    PPGSessionMachine *sm)
  1884. {
  1885.     request_confirmed_push(last, pm, sm);
  1886. }
  1887. /*
  1888.  * Ppg, chapter 6.1.2.2 , subchapter delivery, says that if push is unconform-
  1889.  * ed, we can use either Po-Unit-Push.req or Po-Push.req primitive. We use Po-
  1890.  * Push.req, if have an already established session (other words, sm != NULL).
  1891.  * In addition, update PAP attribute. Return pointer to the updated push mach-
  1892.  * ine.
  1893.  */
  1894. static PPGPushMachine *deliver_unit_push(long last, PPGPushMachine *pm, 
  1895.     PPGSessionMachine *sm, int session_exists)
  1896. {
  1897.     push_machine_assert(pm);
  1898.     
  1899.     if (!session_exists)
  1900.         request_unit_push(last, pm);
  1901.     else
  1902.         request_push(last, pm);
  1903.     pm = update_push_data_with_attribute(&sm, pm, PAP_UNCONFIRMED, 
  1904.                                          PAP_DELIVERED1);
  1905.     info(0, "PPG: unconfirmed push delivered to OTA");
  1906.     return pm;
  1907. }
  1908. /*
  1909.  * Deliver all pushes queued by session machine sm (it is, make a relevant OTA
  1910.  * request). Update PAP attribute, if push is unconfirmed.
  1911.  */
  1912. static void deliver_pending_pushes(PPGSessionMachine *sm, int last)
  1913. {
  1914.     PPGPushMachine *pm;    
  1915.     long i;
  1916.     session_machine_assert(sm);
  1917.     gw_assert(list_len(sm->push_machines) > 0);
  1918.     i = 0;
  1919.     while (i < list_len(sm->push_machines)) {
  1920.         pm = list_get(sm->push_machines, i);
  1921.         push_machine_assert(pm);
  1922.         if (pm->delivery_method == PAP_UNCONFIRMED) {
  1923.             request_push(last, pm); 
  1924.             pm = update_push_data_with_attribute(&sm, pm, PAP_UNCONFIRMED, 
  1925.                  PAP_DELIVERED1);
  1926.             remove_push_data(sm, pm, sm == NULL);
  1927.         } else {
  1928.         request_confirmed_push(last, pm, sm);
  1929.             ++i;
  1930.         }
  1931.     }
  1932. }     
  1933. /*
  1934.  * Abort all pushes queued by session machine sm. In addition, update PAP
  1935.  * attribute and notify PI.
  1936.  */
  1937. static PPGPushMachine *abort_delivery(PPGSessionMachine *sm, int status)
  1938. {
  1939.     PPGPushMachine *pm;
  1940.     long reason,
  1941.          code;
  1942.     session_machine_assert(sm);
  1943.     pm = NULL;
  1944.     reason = PAP_ABORT_USERPND;
  1945.     code = PAP_CAPABILITIES_MISMATCH;
  1946.     
  1947.     while (list_len(sm->push_machines) > 0) {
  1948.         pm = list_get(sm->push_machines, 0);
  1949.         push_machine_assert(pm);
  1950.         pm = update_push_data_with_attribute(&sm, pm, reason, PAP_ABORTED);
  1951.         response_push_message(pm, code, status);
  1952.         remove_push_data(sm, pm, sm == NULL);
  1953.     }
  1954.     return pm;
  1955. }
  1956. /*
  1957.  * Remove a session, even if it have active pushes. These are aborted, and we
  1958.  * must inform PI about this. Client abort codes are defined in pap, 9.14.5,
  1959.  * which refers to wsp, Appendix A, table 35.
  1960.  */
  1961. static void remove_session_data(PPGSessionMachine *sm, int status)
  1962. {
  1963.     long code;
  1964.     PPGPushMachine *pm;
  1965.     session_machine_assert(sm);
  1966.     code = PAP_ABORT_USERPND;
  1967.     
  1968.     while (list_len(sm->push_machines) > 0) {
  1969.         pm = list_get(sm->push_machines, 0);
  1970.         response_push_message(pm, code, status);
  1971.         remove_push_data(sm, pm, sm == NULL);
  1972.     }
  1973.     list_delete_equal(ppg_machines, sm);
  1974.     session_machine_destroy(sm);
  1975. }
  1976. /*
  1977.  * Remove session, if it has no active pushes.
  1978.  */
  1979. static void remove_pushless_session(PPGSessionMachine *sm)
  1980. {
  1981.     session_machine_assert(sm);
  1982.     if (list_len(sm->push_machines) == 0) {
  1983.         list_delete_equal(ppg_machines, sm);
  1984.         session_machine_destroy(sm);
  1985.     }
  1986. }
  1987. /*
  1988.  * If session machine not exist, create a session machine and store session 
  1989.  * data. If session exists, ignore. 
  1990.  * Return pointer to the session machine, and a flag did we have a session 
  1991.  * before executing this function. (Session data is needed to implement the 
  1992.  * PAP attribute. It does not mean that a session exists.)
  1993.  */
  1994. static PPGSessionMachine *store_session_data(PPGSessionMachine *sm,
  1995.     WAPEvent *e, WAPAddrTuple *tuple, int *session_exists)
  1996. {
  1997.     gw_assert(e->type == Push_Message);
  1998.     if (sm == NULL) {
  1999.         sm = session_machine_create(tuple, e);
  2000.         *session_exists = 0;
  2001.     } else
  2002.         *session_exists = 1;
  2003.     
  2004.     return sm;
  2005. }
  2006. static PPGSessionMachine *update_session_data_with_headers(
  2007.     PPGSessionMachine *sm, PPGPushMachine *pm)
  2008. {
  2009.     list_delete_matching(sm->push_machines, &pm->push_id, push_has_pid);
  2010.     list_append(sm->push_machines, pm);
  2011.     return sm;
  2012. }
  2013. /*
  2014.  * Ppg 6.1.2.2, subchapter delivery, states that if the delivery method is not
  2015.  * confirmed or unconfirmed, PPG may select an implementation specific type of
  2016.  * the  primitive. We use an unconfirmed push, if QoS is notspecified, and 
  2017.  * confirmed one, when it is preferconfirmed (we do support confirmed push).
  2018.  */
  2019. static int confirmation_requested(WAPEvent *e)
  2020. {
  2021.     gw_assert(e->type = Push_Message);
  2022.     return e->u.Push_Message.delivery_method == PAP_CONFIRMED || 
  2023.            e->u.Push_Message.delivery_method == PAP_PREFERCONFIRMED;
  2024. }
  2025. static int push_has_pid(void *a, void *b)
  2026. {
  2027.     long *pid;
  2028.     PPGPushMachine *pm;
  2029.     pid = b;
  2030.     pm = a;
  2031.     
  2032.     return *pid == pm->push_id;
  2033. }
  2034. static PPGPushMachine *find_ppg_push_machine_using_pid(PPGSessionMachine *sm, 
  2035.                                                    long pid)
  2036. {
  2037.     PPGPushMachine *pm;
  2038.     gw_assert(pid >= 0);
  2039.     session_machine_assert(sm);
  2040.     pm = list_search(sm->push_machines, &pid, push_has_pid);
  2041.     return pm;
  2042. }
  2043. static int push_has_pi_push_id(void *a, void *b)
  2044. {
  2045.     Octstr *pi_push_id;
  2046.     PPGPushMachine *pm;
  2047.     pi_push_id = b;
  2048.     pm = a;
  2049.     return octstr_compare(pm->pi_push_id, pi_push_id) == 0;
  2050. }
  2051. static PPGPushMachine *find_ppg_push_machine_using_pi_push_id(
  2052.     PPGSessionMachine *sm, Octstr *pi_push_id)
  2053. {
  2054.     PPGPushMachine *pm;
  2055.     gw_assert(pi_push_id);
  2056.     session_machine_assert(sm);
  2057.     pm = list_search(sm->push_machines, pi_push_id, push_has_pi_push_id);
  2058.     return pm;
  2059. }
  2060. static PPGPushMachine *find_unit_ppg_push_machine_using_pi_push_id(
  2061.     Octstr *pi_push_id)
  2062. {
  2063.     PPGPushMachine *pm;
  2064.     gw_assert(pi_push_id);
  2065.     pm = list_search(ppg_unit_pushes, pi_push_id, push_has_pi_push_id);
  2066.     return pm;
  2067. }
  2068. /*
  2069.  * Store a new value of the push attribute into a push machine. It is to be 
  2070.  * found from the list of unit pushes, if connectionless push was asked 
  2071.  * (sm == NULL), otherwise from the the push list of the session machine sm. 
  2072.  * Returns updated push machine and session machine (this one has an updated
  2073.  * push machines list). 
  2074.  */
  2075. static PPGPushMachine *update_push_data_with_attribute(PPGSessionMachine **sm, 
  2076.     PPGPushMachine *qm, long reason, long status)
  2077. {
  2078.     push_machine_assert(qm);
  2079.    
  2080.     switch (status) {
  2081.     case PAP_UNDELIVERABLE1:
  2082.          qm->message_state = PAP_UNDELIVERABLE;
  2083.          qm->code = PAP_BAD_REQUEST;
  2084.     break;
  2085.     case PAP_UNDELIVERABLE2:
  2086.         qm->code = reason;
  2087.         qm->message_state = PAP_UNDELIVERABLE;
  2088.         qm->desc = describe_code(reason);
  2089.     break;
  2090.     case PAP_ABORTED:
  2091.         qm->message_state = status;
  2092.         qm->code = ota_abort_to_pap(reason);
  2093.         qm->event_time = set_time();
  2094.         qm->desc = describe_code(reason);
  2095.     break;
  2096.     case PAP_DELIVERED1:
  2097.         qm->message_state = PAP_DELIVERED;
  2098.         qm->delivery_method = PAP_UNCONFIRMED;
  2099.         qm->event_time = set_time();
  2100.     break;
  2101.     case PAP_DELIVERED2:
  2102.         qm->message_state = PAP_DELIVERED;
  2103.         qm->delivery_method = PAP_CONFIRMED;
  2104.         qm->event_time = set_time();
  2105.     break;
  2106.     case PAP_EXPIRED:
  2107.         qm->message_state = PAP_EXPIRED;
  2108.         qm->event_time = set_time();
  2109.         qm->desc = describe_code(reason);
  2110.     break;
  2111.     case PAP_PENDING:
  2112.         qm->message_state = PAP_PENDING;
  2113.     break;
  2114.     default:
  2115.         error(0, "WAP_PUSH_PPG: update_push_data_with_attribute: Non"
  2116.               " existing push machine status: %ld", status);
  2117.     break;
  2118.     }
  2119.     if (*sm != NULL){
  2120.         list_delete_matching((**sm).push_machines, &qm->push_id, push_has_pid);
  2121.         list_append((**sm).push_machines, qm);
  2122.         list_delete_equal(ppg_machines, *sm);
  2123.         list_append(ppg_machines, *sm);
  2124.     } else {
  2125.         list_delete_matching(ppg_unit_pushes, &qm->push_id, push_has_pid);
  2126.         list_append(ppg_unit_pushes, qm);
  2127.     }
  2128.     return qm;
  2129. }
  2130. /*
  2131.  * Store session id, client port and caps list received from application layer.
  2132.  */
  2133. static PPGSessionMachine *update_session_data(PPGSessionMachine *m, 
  2134.                                               long sid, long port, List *caps)
  2135. {
  2136.     session_machine_assert(m);
  2137.     gw_assert(sid >= 0);
  2138.     m->session_id = sid;
  2139.     m->addr_tuple->remote->port = port;
  2140.     m->client_capabilities = wsp_cap_duplicate_list(caps);
  2141.     list_delete_equal(ppg_machines, m);
  2142.     list_append(ppg_machines, m);
  2143.     return m;
  2144. }
  2145. /*
  2146.  * Convert OTA abort codes (ota 6.3.3) to corresponding PAP status codes. These
  2147.  * are defined in pap 9.14.5.
  2148.  */
  2149. static long ota_abort_to_pap(long reason)
  2150. {
  2151.     long offset;
  2152.     offset = reason - 0xEA;
  2153.     reason = 5026 + offset;
  2154.     return reason;
  2155. }
  2156. /*
  2157.  * Accept connectionless push when PI wants connectionless push and there is 
  2158.  * no sessions open.
  2159.  */
  2160. static int cless_accepted(WAPEvent *e, PPGSessionMachine *sm)
  2161. {
  2162.     gw_assert(e->type == Push_Message);
  2163.     return (e->u.Push_Message.delivery_method == PAP_UNCONFIRMED ||
  2164.            e->u.Push_Message.delivery_method == PAP_NOT_SPECIFIED) &&
  2165.            (sm == NULL);
  2166. }
  2167. /*
  2168.  * Application ids start with 0 and -1 means that default (wml.ua) was used.
  2169.  */
  2170. static int coriented_deliverable(long appid_code)
  2171. {
  2172.     return appid_code > -1;
  2173. }
  2174. /*
  2175.  * Compare PAP message timestamp, in PAP message format, and stored in octstr,
  2176.  * to gm (UTC) broken time. Return true, if before is after now, or if the 
  2177.  * service in question was not requested by PI. PAP time format is defined in 
  2178.  * pap, chapter 9.2.
  2179.  */
  2180. static void initialize_time_item_array(long time_data[], struct tm now) 
  2181. {
  2182.     time_data[0] = now.tm_year + 1900;
  2183.     time_data[1] = now.tm_mon + 1;
  2184.     time_data[2] = now.tm_mday;
  2185.     time_data[3] = now.tm_hour;
  2186.     time_data[4] = now.tm_min;
  2187.     time_data[5] = now.tm_sec;
  2188. }
  2189. static int date_item_compare(Octstr *condition, long time_data, long pos)
  2190. {
  2191.     long data;
  2192.     if (octstr_parse_long(&data, condition, pos, 10) < 0) {
  2193.         return 0;
  2194.     }
  2195.     if (data < time_data) {
  2196.         return -1;
  2197.     }
  2198.     if (data > time_data) {
  2199.         return 1;
  2200.     }
  2201.     return 0;
  2202. }
  2203. /*
  2204.  * We do not accept timestamps equalling now. Return true, if the service was
  2205.  * not requested.
  2206.  */
  2207. static int deliver_before_test_cleared(Octstr *before, struct tm now)
  2208. {  
  2209.     long time_data[6];
  2210.     long j;
  2211.     if (before == NULL)
  2212.         return 1;
  2213.     initialize_time_item_array(time_data, now);
  2214.     if (date_item_compare(before, time_data[0], 0) == 1)
  2215.         return 1;
  2216.     if (date_item_compare(before, time_data[0], 0) == -1)
  2217.         return 0;
  2218.     for (j = 5; j < octstr_len(before); j += 3) {
  2219.         if (date_item_compare(before, time_data[(j-5)/3 + 1], j) == 1)
  2220.             return 1;
  2221.         if (date_item_compare(before, time_data[(j-5)/3 + 1], j) == -1)
  2222.             return 0;
  2223.     }
  2224.     return 0;
  2225. }
  2226. /* 
  2227.  * Ditto. Return true, if after is before now (or the service was not request-
  2228.  * ed). Do not accept timestamps equalling now.
  2229.  */
  2230. static int deliver_after_test_cleared(Octstr *after, struct tm now)
  2231. {
  2232.     long time_data[6];
  2233.     long j;
  2234.     if (after == NULL)
  2235.         return 1;
  2236.     
  2237.     initialize_time_item_array(time_data, now);
  2238.     if (date_item_compare(after, time_data[0], 0) == -1)
  2239.         return 1;
  2240.     if (date_item_compare(after, time_data[0], 0) == 1)
  2241.         return 0;
  2242.     for (j = 5; j < octstr_len(after); j += 3) {
  2243.         if (date_item_compare(after, time_data[(j-5)/3 + 1], j) == -1)
  2244.             return 1;
  2245.         if (date_item_compare(after, time_data[(j-5)/3 + 1], j) == 1)
  2246.             return 0;
  2247.     }
  2248.     return 0;
  2249. }
  2250. /*
  2251.  * We exchange here server and client addresses and ports, because our WDP,
  2252.  * written for pull, exchange them, too. Similarly server address INADDR_ANY is
  2253.  * used for compability reasons, when the bearer is ip. When it is SMS, the
  2254.  * server address is global-sender.
  2255.  */
  2256. static WAPAddrTuple *set_addr_tuple(Octstr *address, long cliport, 
  2257.                                     long servport, long address_type)
  2258. {
  2259.     Octstr *cliaddr;
  2260.     WAPAddrTuple *tuple;
  2261.     
  2262.     gw_assert(address);
  2263.     if (address_type == ADDR_PLMN)
  2264.         cliaddr = global_sender;
  2265.     else
  2266.         cliaddr = octstr_imm("0.0.0.0");
  2267.     tuple = wap_addr_tuple_create(address, cliport, cliaddr, servport);
  2268.     return tuple;
  2269. }
  2270. /*
  2271.  * We are not interested about parsing URI fully - we check only does it cont-
  2272.  * ain application id reserved by WINA or the part containing assigned code. 
  2273.  * Otherwise (regardless of it being an URI or assigned code) we simply pass 
  2274.  * it forward. 
  2275.  * These are defined by WINA at http://www.wapforum.org/wina/push-app-id.htm. 
  2276.  */
  2277. static char *wina_uri[] =
  2278. {   "*",
  2279.     "push.sia",
  2280.     "wml.ua",
  2281.     "wta.ua", 
  2282.     "mms.ua", 
  2283.     "push.syncml", 
  2284.     "loc.ua" 
  2285. };
  2286. #define NUMBER_OF_WINA_URIS sizeof(wina_uri)/sizeof(wina_uri[0])
  2287. /*
  2288.  * X-Wap-Application-Id header is defined in Push Message, chapter 6.2.2.1.
  2289.  * First check do we a header with an app-encoding field and a coded value. 
  2290.  * If not, try to find push application id from table of wina approved values.
  2291.  * Return coded value value of application id in question, or an error code:
  2292.  *        -1, error
  2293.  *         0, * (meaning any application acceptable)
  2294.  *         1, push.sia
  2295.  *         2, wml.ua
  2296.  *         3, wta.ua 
  2297.  *         4, mms.ua
  2298.  *         5, push.syncml 
  2299.  *         6, loc.ua 
  2300.  */
  2301. static long parse_appid_header(Octstr **appid_content)
  2302. {
  2303.     long pos,
  2304.          coded_value;
  2305.     size_t i;
  2306.     if ((pos = octstr_search(*appid_content, octstr_imm(";"), 0)) >= 0) {
  2307.         octstr_delete(*appid_content, pos, 
  2308.                       octstr_len(octstr_imm(";app-encoding=")));
  2309.         octstr_delete(*appid_content, 0, pos);         /* the URI part */
  2310.     return -1;
  2311.     } 
  2312.     i = 0;
  2313.     while (i < NUMBER_OF_WINA_URIS) {
  2314.         if ((pos = octstr_case_search(*appid_content, 
  2315.                 octstr_imm(wina_uri[i]), 0)) >= 0)
  2316.             break;
  2317.         ++i;
  2318.     }
  2319.     if (i == NUMBER_OF_WINA_URIS) {
  2320.         octstr_destroy(*appid_content);
  2321.         *appid_content = octstr_format("%ld", 2);      /* assigned number */
  2322.         return -1;                                     /* for wml ua */
  2323.     }
  2324.     
  2325.     octstr_delete(*appid_content, 0, pos);             /* again the URI */
  2326.     if ((coded_value = wsp_string_to_application_id(*appid_content)) >= 0) {
  2327.         octstr_destroy(*appid_content);
  2328.         *appid_content = octstr_format("%ld", coded_value);
  2329.         return coded_value;
  2330.     }
  2331.     return -1;
  2332. }
  2333. static WAPAddrTuple *addr_tuple_change_cliport(WAPAddrTuple *tuple, long port)
  2334. {
  2335.     WAPAddrTuple *dubble;
  2336.     if (tuple == NULL)
  2337.         return NULL;
  2338.     dubble = wap_addr_tuple_create(tuple->remote->address,
  2339.                                    port,
  2340.                                    tuple->local->address,
  2341.                                    tuple->local->port);
  2342.     return dubble;
  2343. }
  2344. /*
  2345.  * Pi uses multipart/related content type when communicating with ppg. (see 
  2346.  * pap, Chapter 8) and subtype application/xml.
  2347.  * Check if push headers are acceptable according this rule. In addition, 
  2348.  * return the field value of Content-Type header, if any and error string if
  2349.  * none (this string is used by send_bad_message_response).
  2350.  */
  2351. static int headers_acceptable(List *push_headers, Octstr **content_header)
  2352. {
  2353.     gw_assert(push_headers);
  2354.     *content_header = http_header_find_first(push_headers, "Content-Type");
  2355.     if (*content_header == NULL) {
  2356.         *content_header = octstr_format("%s", "no content type header found");
  2357.         goto error;
  2358.     }
  2359.     
  2360.     if (!type_is(*content_header, "multipart/related")) {
  2361.         goto error;
  2362.     }
  2363.     if (!type_is(*content_header, "application/xml")) {
  2364.         goto error;
  2365.     }
  2366.     return 1;
  2367. error:
  2368.     warning(0, "PPG: headers_acceptable: got unacceptable push headers");
  2369.     return 0;
  2370. }
  2371. /*
  2372.  * Content-Type header field is defined in rfc 1521, chapter 4. We are looking
  2373.  * after type multipart/related or "multipart/related" and parameter 
  2374.  * type=application/xml or type="application/xml", as required by pap, chapter
  2375.  * 8.
  2376.  */
  2377. static int type_is(Octstr *content_header, char *name)
  2378. {
  2379.     Octstr *quoted_type,
  2380.            *osname;
  2381.     osname = octstr_imm(name);
  2382.     if (octstr_case_search(content_header, osname, 0) >= 0)
  2383.         return 1;
  2384.     quoted_type = octstr_create("");
  2385.     octstr_format_append(quoted_type, "%c", '"');
  2386.     octstr_append(quoted_type, osname);
  2387.     octstr_format_append(quoted_type, "%c", '"');
  2388.     if (octstr_case_search(content_header, quoted_type, 0) >= 0) {
  2389.         octstr_destroy(quoted_type);
  2390.         return 1;
  2391.     }
  2392.     octstr_destroy(quoted_type);
  2393.     return 0;
  2394. }
  2395. /*
  2396.  * Again looking after a parameter, this time of type boundary=XXX or boundary=
  2397.  * "XXX".
  2398.  */
  2399. static int get_mime_boundary(List *push_headers, Octstr *content_header, 
  2400.                              Octstr **boundary)
  2401. {
  2402.     long pos;
  2403.     Octstr *bos;
  2404.     int c, quoted = 0;
  2405.     pos = 0;
  2406.     if ((pos = octstr_case_search(content_header, 
  2407.                                   bos = octstr_imm("boundary="), 0)) < 0) {
  2408.         warning(0, "PPG: get_mime_boundary: no boundary specified");
  2409.         return -1;
  2410.     }
  2411.     pos += octstr_len(bos);
  2412.     if (octstr_get_char(content_header, pos) == '"') {
  2413.         ++pos;
  2414.         quoted = 1;
  2415.     }
  2416.     *boundary = octstr_create("");
  2417.     while ((c = octstr_get_char(content_header, pos)) != -1) {
  2418.         if (c == ';' || (quoted && c == '"') || (!quoted && c == ' '))
  2419.                 break;
  2420.             octstr_format_append(*boundary, "%c", c);
  2421.         ++pos;
  2422.     }
  2423.     return 0;
  2424. }
  2425. static void change_header_value(List **push_headers, char *name, char *value)
  2426. {
  2427.     http_header_remove_all(*push_headers, name);
  2428.     http_header_add(*push_headers, name, value);
  2429. }
  2430. /*
  2431.  * Some application level protocols may use MIME headers. This may cause problems
  2432.  * to them. 
  2433.  */
  2434. static void remove_mime_headers(List **push_headers)
  2435. {
  2436.     http_header_remove_all(*push_headers, "MIME-Version");
  2437. }
  2438. /*
  2439.  * Badmessage-response element is redefined in pap, implementation note, 
  2440.  * chapter 5. Do not add to the document a fragment being NULL or empty.
  2441.  * Return current status of HTTPClient.
  2442.  */
  2443. static void send_bad_message_response(HTTPClient **c, Octstr *fragment, 
  2444.                                       int code, int status)
  2445. {
  2446.     Octstr *reply_body;
  2447.     reply_body = octstr_format("%s", 
  2448.         "<?xml version="1.0"?>"
  2449.         "<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 1.0//EN""
  2450.                    " "http://www.wapforum.org/DTD/pap_1.0.dtd">"
  2451.         "<pap>"
  2452.              "<badmessage-response code="");
  2453.     octstr_format_append(reply_body, "%d", code);
  2454.     octstr_format_append(reply_body, "%s", """
  2455.                   " desc="");
  2456.     octstr_format_append(reply_body, "%s", "Not understood due to malformed"
  2457.                                            " syntax");
  2458.     octstr_format_append(reply_body, "%s", """);
  2459.     if (fragment != NULL && octstr_len(fragment) != 0) {
  2460.         octstr_format_append(reply_body, "%s", " bad-message-fragment="");
  2461.         octstr_format_append(reply_body, "%S", escape_fragment(fragment));
  2462.         octstr_format_append(reply_body, "%s", """);
  2463.     }
  2464.     octstr_format_append(reply_body, "%s", ">"
  2465.               "</badmessage-response>"
  2466.          "</pap>");
  2467.     debug("wap.push.ppg", 0, "PPG: send_bad_message_response: telling pi");
  2468.     send_to_pi(c, reply_body, status);
  2469.     octstr_destroy(fragment);
  2470. }
  2471. /*
  2472.  * Push response is defined in pap, chapter 9.3. Mapping between push ids and
  2473.  * http clients is done by using http_clients. We remove (push id, http client)
  2474.  * pair from the dictionary after the mapping has been done.
  2475.  * Return current status of HTTPClient.
  2476.  */
  2477. static HTTPClient *send_push_response(WAPEvent *e, int status)
  2478. {
  2479.     Octstr *reply_body,
  2480.            *url;
  2481.     HTTPClient *c;
  2482.     gw_assert(e->type == Push_Response);
  2483.     url = dict_get(urls, e->u.Push_Response.pi_push_id);
  2484.     dict_remove(urls, e->u.Push_Response.pi_push_id);
  2485.     reply_body = octstr_format("%s", 
  2486.         "<?xml version="1.0"?>"
  2487.         "<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 1.0//EN""
  2488.                    " "http://www.wapforum.org/DTD/pap_1.0.dtd">"
  2489.         "<pap>"
  2490.              "<push-response push-id="");
  2491.     octstr_format_append(reply_body, "%S", e->u.Push_Response.pi_push_id);
  2492.     octstr_format_append(reply_body, "%s", """); 
  2493.     if (e->u.Push_Response.sender_name != NULL) {
  2494.         octstr_format_append(reply_body, "%s",
  2495.                    " sender-name="");
  2496.         octstr_format_append(reply_body, "%S", 
  2497.             e->u.Push_Response.sender_name);
  2498.         octstr_format_append(reply_body, "%s", """);
  2499.     }
  2500.     if (e->u.Push_Response.reply_time != NULL) {
  2501.         octstr_format_append(reply_body, "%s",
  2502.                    " reply-time="");
  2503.         octstr_format_append(reply_body, "%S", 
  2504.             e->u.Push_Response.reply_time);
  2505.         octstr_format_append(reply_body, "%s", """);
  2506.     }
  2507.     if (url != NULL) {
  2508.         octstr_format_append(reply_body, "%s",
  2509.                    " sender-address="");
  2510.         octstr_format_append(reply_body, "%S", url);
  2511.         octstr_format_append(reply_body, "%s", """);
  2512.     }
  2513.     octstr_format_append(reply_body, "%s", ">"
  2514.      "</push-response>"
  2515.              "<response-result code ="");
  2516.     octstr_format_append(reply_body, "%d", e->u.Push_Response.code);
  2517.     octstr_format_append(reply_body, "%s", """);
  2518.     if (e->u.Push_Response.desc != NULL) {
  2519.         octstr_format_append(reply_body, "%s", " desc="");
  2520.         octstr_format_append(reply_body, "%S", e->u.Push_Response.desc);
  2521.         octstr_format_append(reply_body, """);
  2522.     }
  2523.     
  2524.     octstr_format_append(reply_body, "%s", ">"
  2525.               "</response-result>"
  2526.          "</pap>");
  2527.     octstr_destroy(url);
  2528.     c = dict_get(http_clients, e->u.Push_Response.pi_push_id);
  2529.     dict_remove(http_clients, e->u.Push_Response.pi_push_id);
  2530.     debug("wap.push.ppg", 0, "PPG: send_push_response: telling pi");
  2531.     send_to_pi(&c, reply_body, status);
  2532.     wap_event_destroy(e);
  2533.     return c;
  2534. }
  2535. /*
  2536.  * Ppg notifies pi about duplicate push id by sending a push response document
  2537.  * to it. Note that we never put the push id to the dict in this case.
  2538.  * Return current c value.
  2539.  */
  2540. static void tell_fatal_error(HTTPClient **c, WAPEvent *e, Octstr *url, 
  2541.                              int status, int code)
  2542. {
  2543.     Octstr *reply_body,
  2544.            *dos,                      /* temporaries */
  2545.            *tos,
  2546.            *sos;
  2547.     gw_assert(e->type == Push_Message);
  2548.     reply_body = octstr_format("%s", 
  2549.         "<?xml version="1.0"?>"
  2550.         "<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 1.0//EN""
  2551.                    " "http://www.wapforum.org/DTD/pap_1.0.dtd">"
  2552.         "<pap>"
  2553.              "<push-response push-id="");
  2554.     octstr_format_append(reply_body, "%S", e->u.Push_Message.pi_push_id);
  2555.     octstr_format_append(reply_body, "%s", """); 
  2556.     octstr_format_append(reply_body, "%s",
  2557.                    " sender-name="");
  2558.     octstr_format_append(reply_body, "%S", tos = tell_ppg_name());
  2559.     octstr_format_append(reply_body, "%s", """);
  2560.     octstr_format_append(reply_body, "%s",
  2561.                    " reply-time="");
  2562.     octstr_format_append(reply_body, "%S", sos = set_time());
  2563.     octstr_format_append(reply_body, "%s", """);
  2564.     octstr_format_append(reply_body, "%s",
  2565.                    " sender-address="");
  2566.     octstr_format_append(reply_body, "%S", url);
  2567.     octstr_format_append(reply_body, "%s", """);
  2568.     octstr_format_append(reply_body, "%s", ">"
  2569.      "</push-response>"
  2570.              "<response-result code ="");
  2571.     octstr_format_append(reply_body, "%d", code);
  2572.     octstr_format_append(reply_body, "%s", """);
  2573.     octstr_format_append(reply_body, "%s", " desc="");
  2574.     octstr_format_append(reply_body, "%S", dos = describe_code(code));
  2575.     octstr_format_append(reply_body, """);
  2576.     octstr_format_append(reply_body, "%s", ">"
  2577.               "</response-result>"
  2578.          "</pap>");
  2579.     debug("wap.push.ppg", 0, "PPG: tell_fatal_error: %s", octstr_get_cstr(dos));
  2580.     send_to_pi(c, reply_body, status);
  2581.     octstr_destroy(dos);
  2582.     octstr_destroy(tos);
  2583.     octstr_destroy(sos);
  2584.     wap_event_destroy(e);
  2585. }
  2586. /*
  2587.  * Does the HTTP reply to pi. Test has HTTPClient disappeared.
  2588.  * Return current c value.
  2589.  */
  2590. static void send_to_pi(HTTPClient **c, Octstr *reply_body, int status) {
  2591.     List *reply_headers;
  2592.     reply_headers = http_create_empty_headers();
  2593.     http_header_add(reply_headers, "Content-Type", "application/xml");
  2594.     if (*c != NULL)
  2595.         http_send_reply(*c, status, reply_headers, reply_body);
  2596.     octstr_destroy(reply_body);
  2597.     http_destroy_headers(reply_headers);
  2598. }
  2599. /*
  2600.  * Escape characters not allowed in the value of an attribute. Pap does not 
  2601.  * define escape sequences for message fragments; try common xml ones.
  2602.  */
  2603. static Octstr *escape_fragment(Octstr *fragment)
  2604. {
  2605.     long i;
  2606.     int c;
  2607.     i = 0;
  2608.     while (i < octstr_len(fragment)) {
  2609.         if ((c = octstr_get_char(fragment, i)) == '"') {
  2610.             replace_octstr_char(fragment, octstr_imm("&quot;"), &i);
  2611.         } else if (c == '<') {
  2612.             replace_octstr_char(fragment, octstr_imm("&lt;"), &i);
  2613.         } else if (c == '>') {
  2614.             replace_octstr_char(fragment, octstr_imm("&gt;"), &i);
  2615.         } else if (c == '&') {
  2616.             replace_octstr_char(fragment, octstr_imm("&amp;"), &i);
  2617.         }
  2618.         ++i;
  2619.     }
  2620.     return fragment;
  2621. }
  2622. static int is_phone_number(long address_type)
  2623. {
  2624.     return address_type == ADDR_PLMN;
  2625. }
  2626. static void replace_octstr_char(Octstr *os1, Octstr *os2, long *pos)
  2627. {
  2628.     octstr_delete(os1, *pos, 1);
  2629.     octstr_insert(os1, os2, *pos);
  2630.     *pos += octstr_len(os2) - 1;
  2631. }