Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

wap_push_ppg.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * wap_push_ppg.c: General logic of a push proxy gateway.
00059  *
00060  * This module implements following WAP Forum specifications:
00061  *      WAP-151-PPGService-19990816-a (called afterwards PPG),
00062  *      WAP-164-PAP-19991108-a (PAP),
00063  *      WAP-164_100-PAP-20000218-a (PAP implementation note).
00064  * 
00065  * We refer following WAP Forum specifications:
00066  *      WAP-145-PushMessage-19990816-a (push message)
00067  *      WAP-200-WDP-20001212-a (WDP)
00068  *      WAP-203-WSP-20000504-a (WSP)
00069  *      WAP-189-PushOTA-20000217-a (OTA).
00070  *
00071  * In addition, RFCs 1521 and 2045 are referred.
00072  *
00073  * By Aarno SyväŠnen for Wapit Ltd, Wiral Ltd and Global Networks Inc. 
00074  */
00075 
00076 #include <time.h>
00077 #include <ctype.h>
00078 
00079 #include "wap_push_ppg.h"
00080 #include "wap/wap_events.h"
00081 #include "wap/wsp_caps.h"
00082 #include "wml_compiler.h"
00083 #include "wap-appl.h"
00084 #include "wap/wsp.h"
00085 #include "wap/wsp_strings.h"
00086 #include "wap_push_si_compiler.h"
00087 #include "wap_push_sl_compiler.h"
00088 #include "wap_push_pap_compiler.h"
00089 #include "wap_push_pap_mime.h"
00090 #include "wap_push_ppg_pushuser.h"
00091 
00092 enum {
00093     TIME_EXPIRED = 0,
00094     TIME_TOO_EARLY = 1,
00095     NO_CONSTRAINTS = 2
00096 };
00097 
00098 /*
00099  * Default values for configuration variables
00100  */
00101 enum {
00102     DEFAULT_HTTP_PORT = 8080,
00103     NO_HTTPS_PORT = -1,
00104     DEFAULT_NUMBER_OF_PUSHES = 100,
00105     PI_TRUSTED = 1,
00106     SSL_CONNECTION_OFF = 0,
00107     DEFAULT_NUMBER_OF_USERS = 1024,
00108     USER_CONFIGURATION_NOT_ADDED = 0
00109 };
00110 
00111 enum { USER_CONFIGURATION_ADDED = 1 };
00112 
00113 #define DEFAULT_PPG_URL "/wappush"
00114 
00115 /*****************************************************************************
00116  *
00117  * Internal data structures
00118  *
00119  * Give the status of the push ppg module:
00120  *
00121  *  limbo
00122  *      not running at all
00123  *  running
00124  *      operating normally
00125  *  terminating
00126  *      waiting for operations to terminate, returning to limbo
00127  */
00128 static enum {limbo, running, terminating} run_status = limbo;
00129 
00130 /*
00131  * The external event queue for this module
00132  */
00133 static List *ppg_queue = NULL;
00134 
00135 /*
00136  * The internal event queue for this module (allowing listening of many ports)
00137  */
00138 static List *pap_queue = NULL;
00139 
00140 /*
00141  * List of ppg session machines (it is, of currently active sessions)
00142  */
00143 static List *ppg_machines = NULL;
00144 
00145 /*
00146  * List of currently active unit pushes (we need a threadsafe storage for them,
00147  * because pushes can be cancelled and queried):
00148  */
00149 static List *ppg_unit_pushes = NULL;
00150 
00151 /*
00152  * Counter to store our internal push id.
00153  */
00154 static Counter *push_id_counter = NULL;
00155 
00156 /*
00157  * We need a mapping between HTTPClient structures, used by http library, and
00158  * push ids, used by ppg. 
00159  */
00160 static Dict *http_clients = NULL;
00161 
00162 /*
00163  * Mapping between urls used by pi and push ids used by ppg.
00164  */
00165 static Dict *urls = NULL;
00166 
00167 /*
00168  * Push content packed for compilers (wml, si, sl, co).
00169  */
00170 struct content {
00171     Octstr *body;
00172     Octstr *type;
00173     Octstr *charset;
00174 };
00175 
00176 static wap_dispatch_func_t *dispatch_to_ota;
00177 static wap_dispatch_func_t *dispatch_to_appl;
00178 
00179 /*
00180  * Configurable variables of ppg core group (for general configuration of a 
00181  * ppg), with some default values.
00182  */
00183 
00184 static Octstr *ppg_url = NULL ;
00185 static long ppg_port = DEFAULT_HTTP_PORT;
00186 
00187 #ifdef HAVE_LIBSSL
00188 static long ppg_ssl_port = NO_HTTPS_PORT;
00189 #endif
00190 
00191 static long number_of_pushes = DEFAULT_NUMBER_OF_PUSHES;
00192 static int trusted_pi = PI_TRUSTED;
00193 static long number_of_users = DEFAULT_NUMBER_OF_USERS;
00194 static Octstr *ppg_deny_ip = NULL;
00195 static Octstr *ppg_allow_ip = NULL; 
00196 static int user_configuration = USER_CONFIGURATION_NOT_ADDED;
00197 static Octstr *global_sender = NULL;
00198 static Octstr *ppg_default_smsc = NULL; 
00199 #ifdef HAVE_LIBSSL
00200 static Octstr *ssl_server_cert_file = NULL;
00201 static Octstr *ssl_server_key_file = NULL;
00202 #endif
00203 static Octstr *ppg_dlr_url = NULL;
00204 static Octstr *ppg_smsbox_id = NULL; 
00205 static Octstr *service_name = NULL;
00206 
00207 struct PAPEvent {
00208     HTTPClient *client;
00209     Octstr *ip; 
00210     Octstr *url;
00211     List *push_headers; 
00212     Octstr *mime_content;
00213     List *cgivars;
00214 };
00215 
00216 typedef struct PAPEvent PAPEvent;
00217 
00218 
00219 /*****************************************************************************
00220  *
00221  * Prototypes of internal functions
00222  *
00223  * Event handling
00224  */
00225 static void ota_read_thread(void *arg);
00226 static void http_read_thread(void *arg);
00227 
00228 #ifdef HAVE_LIBSSL
00229 static void https_read_thread(void *arg);
00230 #endif
00231 
00232 static void handle_internal_event(WAPEvent *e);
00233 static void pap_request_thread(void *arg);
00234 static int handle_push_message(HTTPClient **c, WAPEvent *ppg_event, int status);
00235 static PAPEvent *pap_event_create(Octstr *ip, Octstr *url, List *push_headers, 
00236                                   Octstr *mime_content, List *cgivars,
00237                                   HTTPClient *client);
00238 static void pap_event_destroy(PAPEvent *p);
00239 static void pap_event_destroy_item(void *p);
00240 static void pap_event_unpack(PAPEvent *p, Octstr **ip, Octstr **url, 
00241                              List **push_headers, Octstr **mime_content, 
00242                              List **cgivars, HTTPClient **client);
00243 
00244 /*
00245  * Constructors and destructors for machines.
00246  */
00247 static PPGSessionMachine *session_machine_create(WAPAddrTuple *tuple, 
00248                                                      WAPEvent *e);
00249 static void session_machine_destroy(void *p);
00250 static PPGPushMachine *push_machine_create(WAPEvent *e, 
00251     WAPAddrTuple *tuple);
00252 static void push_machine_destroy(void *pm);
00253 static void push_machines_list_destroy(List *pl);
00254 
00255 /*
00256  * Communicating other modules (ota and appl)
00257  */
00258 static void create_session(WAPEvent *e, PPGPushMachine *pm);
00259 static void request_confirmed_push(long last, PPGPushMachine *pm, 
00260                                    PPGSessionMachine *sm);
00261 static void request_unit_push(long last, PPGPushMachine *pm);
00262 static void request_push(long last, PPGPushMachine *sm);
00263 static int response_push_connection(WAPEvent *e, PPGSessionMachine *sm);
00264 static HTTPClient *response_push_message(PPGPushMachine *pm, long code, 
00265                                          int status);
00266 
00267 /*
00268  * Functions to find machines using various identifiers, and related help 
00269  * functions.
00270  */
00271 static PPGSessionMachine *session_find_using_pi_client_address(Octstr *addr);
00272 static PPGPushMachine *find_ppg_push_machine_using_pid(PPGSessionMachine *sm, 
00273                                                    long pid);
00274 static PPGPushMachine *find_ppg_push_machine_using_pi_push_id(
00275     PPGSessionMachine *sm, Octstr *pi_push_id);
00276 static PPGPushMachine *find_unit_ppg_push_machine_using_pi_push_id(
00277     Octstr *pi_push_id);
00278 static int push_has_pi_push_id(void *a, void *b);
00279 static int push_has_pid(void *a, void *b);
00280 static int session_has_pi_client_address(void *a, void *b);
00281 static int session_has_addr(void *a, void *b);
00282 static int session_has_sid(void *a, void *b);
00283 
00284 /*
00285  * Main logic of PPG.
00286  */
00287 static int check_capabilities(List *requested, List *assumed);
00288 static int transform_message(WAPEvent **e, WAPAddrTuple **tuple, 
00289                              List *push_headers, int connected, Octstr **type);
00290 static long check_x_wap_application_id_header(List **push_headers);
00291 static int pap_convert_content(struct content *content);
00292 static int pap_get_content(struct content *content);
00293 static int select_bearer_network(WAPEvent **e);
00294 static int delivery_time_constraints(WAPEvent *e, PPGPushMachine *pm);
00295 static void deliver_confirmed_push(long last, PPGPushMachine *pm, 
00296                                    PPGSessionMachine *sm);
00297 static PPGPushMachine *deliver_unit_push(long last, PPGPushMachine *pm,
00298     PPGSessionMachine *sm, int session_exists);
00299 static int store_push_data(PPGPushMachine **pm, PPGSessionMachine *sm, 
00300                            WAPEvent *e, WAPAddrTuple *tuple, int cless);
00301 static PPGPushMachine *update_push_data_with_attribute(PPGSessionMachine **sm, 
00302     PPGPushMachine *pm, long reason, long status);
00303 static void remove_push_data(PPGSessionMachine *sm, PPGPushMachine *pm, 
00304                              int cless);
00305 static void remove_session_data(PPGSessionMachine *sm, int status);
00306 static void remove_pushless_session(PPGSessionMachine *sm);
00307 static PPGSessionMachine *store_session_data(PPGSessionMachine *sm,
00308     WAPEvent *e, WAPAddrTuple *tuple, int *session_exists);
00309 static PPGSessionMachine *update_session_data_with_headers(
00310     PPGSessionMachine *sm, PPGPushMachine *pm);
00311 static void deliver_pending_pushes(PPGSessionMachine *sm, int last);
00312 static PPGPushMachine *abort_delivery(PPGSessionMachine *sm, int status);
00313 static PPGSessionMachine *update_session_data(PPGSessionMachine *sm, long sid,
00314                                               long port, List *caps);
00315 static int confirmation_requested(WAPEvent *e);
00316 static int cless_accepted(WAPEvent *e, PPGSessionMachine *sm);
00317 
00318 /*
00319  * Header functions
00320  */
00321 static int headers_acceptable(List *push_headers, Octstr **content_header);
00322 static int type_is(Octstr *content_header, char *required_type);
00323 static int get_mime_boundary(List *push_headers, Octstr *content_header, 
00324                              Octstr **boundary);
00325 static void change_header_value(List **push_headers, char *name, char *value);
00326 static void remove_mime_headers(List **push_headers);
00327 static void remove_link_headers(List **push_headers);
00328 static void remove_x_kannel_headers(List **push_headers);
00329 
00330 /*
00331  * Communicating with pi.
00332  */
00333 static void send_bad_message_response(HTTPClient **c, Octstr *body_fragment,
00334                                       int code, int status);
00335 static HTTPClient *send_push_response(WAPEvent *e, int status);
00336 static void send_to_pi(HTTPClient **c, Octstr *reply_body, int status);
00337 static void tell_fatal_error(HTTPClient **c, WAPEvent *e, Octstr *url, 
00338                              int status, int code);
00339 
00340 /*
00341  * PPG core authentication (not related to any particular user).
00342  */
00343 static int read_ppg_config(Cfg *cfg);
00344 static int ip_allowed_by_ppg(Octstr *ip);
00345 
00346 /*
00347  * Interface to various compilers
00348  */
00349 static Octstr *convert_wml_to_wmlc(struct content *content);
00350 static Octstr *convert_si_to_sic(struct content *content);
00351 static Octstr *convert_sl_to_slc(struct content *content);
00352 
00353 /*
00354  * Setting values for controlling sms level. (Pap control document enables 
00355  * some control, but not enough.)
00356  */
00357 
00358 static Octstr *set_smsc_id(List *headers, Octstr *username, int trusted_pi);
00359 static Octstr *set_dlr_url(List *headers, Octstr *username, int trusted_pi);
00360 static long set_dlr_mask(List *headers, Octstr *dlr_url);
00361 static Octstr *set_smsbox_id(List *headers, Octstr *username, int trusted_pi);
00362 static Octstr *set_service_name(void);
00363 
00364 /*
00365  * Various utility functions
00366  */
00367 static Octstr *set_time(void);
00368 static int deliver_before_test_cleared(Octstr *before, struct tm now);
00369 static int deliver_after_test_cleared(Octstr *after, struct tm now);
00370 static void session_machine_assert(PPGSessionMachine *sm);
00371 static void push_machine_assert(PPGPushMachine *pm);
00372 static Octstr *tell_ppg_name(void);
00373 static Octstr *describe_code(long code);
00374 static long ota_abort_to_pap(long reason);
00375 static int content_transformable(List *push_headers);
00376 static WAPAddrTuple *set_addr_tuple(Octstr *address, long cliport, long servport,
00377                                     long address_type, List *push_headers);
00378 static WAPAddrTuple *addr_tuple_change_cliport(WAPAddrTuple *tuple, long port);
00379 static void initialize_time_item_array(long time_data[], struct tm now);
00380 static int date_item_compare(Octstr *before, long time_data, long pos);
00381 static long parse_appid_header(Octstr **assigned_code);
00382 static Octstr *escape_fragment(Octstr *fragment);
00383 static int coriented_deliverable(long code);
00384 static int is_phone_number(long type_of_address);
00385 static void replace_octstr_char(Octstr *os1, Octstr *os2, long *pos);
00386 
00387 /*****************************************************************************
00388  *
00389  * EXTERNAL FUNCTIONS
00390  */
00391 
00392 enum {
00393     TYPE_HTTP = 0,
00394     TYPE_HTTPS = 1
00395 };
00396 
00397 void wap_push_ppg_init(wap_dispatch_func_t *ota_dispatch, 
00398                        wap_dispatch_func_t *appl_dispatch, Cfg *cfg)
00399 {
00400     user_configuration = read_ppg_config(cfg);
00401     if (user_configuration != USER_CONFIGURATION_NOT_ADDED) {
00402         ppg_queue = gwlist_create();
00403         gwlist_add_producer(ppg_queue);
00404         pap_queue = gwlist_create();
00405         gwlist_add_producer(pap_queue);
00406         push_id_counter = counter_create();
00407         ppg_machines = gwlist_create();
00408         ppg_unit_pushes = gwlist_create();
00409 
00410         dispatch_to_ota = ota_dispatch;
00411         dispatch_to_appl = appl_dispatch;
00412 
00413         http_open_port(ppg_port, TYPE_HTTP);
00414 #ifdef HAVE_LIBSSL
00415         if (ppg_ssl_port != NO_HTTPS_PORT)
00416             http_open_port(ppg_ssl_port, TYPE_HTTPS);
00417 #endif
00418         http_clients = dict_create(number_of_pushes, NULL);
00419         urls = dict_create(number_of_pushes, NULL);
00420 
00421         gw_assert(run_status == limbo);
00422         run_status = running;
00423         gwthread_create(ota_read_thread, NULL);
00424         gwthread_create(http_read_thread, NULL);
00425 #ifdef HAVE_LIBSSL
00426         if (ppg_ssl_port != NO_HTTPS_PORT) 
00427             gwthread_create(https_read_thread, NULL);
00428 #endif
00429         gwthread_create(pap_request_thread, NULL);
00430     }
00431 }
00432 
00433 void wap_push_ppg_shutdown(void)
00434 {
00435      if (user_configuration != USER_CONFIGURATION_NOT_ADDED) {
00436          gw_assert(run_status == running);
00437          run_status = terminating;
00438          gwlist_remove_producer(ppg_queue);
00439          gwlist_remove_producer(pap_queue);
00440          octstr_destroy(ppg_url);
00441          http_close_all_ports();
00442          dict_destroy(http_clients);
00443          dict_destroy(urls);
00444          wap_push_ppg_pushuser_list_destroy();
00445          octstr_destroy(ppg_deny_ip);
00446          octstr_destroy(ppg_allow_ip);
00447          octstr_destroy(global_sender);
00448          octstr_destroy(service_name);
00449          octstr_destroy(ppg_default_smsc);
00450 
00451          gwthread_join_every(http_read_thread);
00452 #ifdef HAVE_LIBSSL
00453          if (ppg_ssl_port != NO_HTTPS_PORT)
00454             gwthread_join_every(https_read_thread);
00455 #endif
00456          gwthread_join_every(ota_read_thread);
00457          gwthread_join_every(pap_request_thread);
00458 
00459          gwlist_destroy(ppg_queue, wap_event_destroy_item);
00460          gwlist_destroy(pap_queue, pap_event_destroy_item);
00461          counter_destroy(push_id_counter);
00462      
00463          debug("wap.push.ppg", 0, "PPG: %ld push session machines left.",
00464                gwlist_len(ppg_machines));
00465          gwlist_destroy(ppg_machines, session_machine_destroy);
00466 
00467          debug("wap_push_ppg", 0, "PPG: %ld unit pushes left", 
00468                gwlist_len(ppg_unit_pushes));
00469          gwlist_destroy(ppg_unit_pushes, push_machine_destroy);
00470      }
00471 }
00472 
00473 void wap_push_ppg_dispatch_event(WAPEvent *e)
00474 {
00475     gw_assert(run_status == running);
00476     gwlist_produce(ppg_queue, e);
00477 }
00478 
00479 /*
00480  * We cannot know port the client is using when it establish the connection.
00481  * However, we must link session creation with a pending push request. Only
00482  * data available is the client address, so we check it here.
00483  * Return non-NULL (pointer to the session machine found), if we have one.
00484  */
00485 PPGSessionMachine *wap_push_ppg_have_push_session_for(WAPAddrTuple *tuple)
00486 {
00487     PPGSessionMachine *sm;
00488 
00489     gw_assert(tuple);
00490     sm = gwlist_search(ppg_machines, tuple->remote->address, session_has_addr);
00491 
00492     return sm;
00493 }
00494 
00495 /*
00496  * Now initiators are identified by their session id. Return non-NULL (pointer
00497  * to the session machine found), if we have one. This function are used after 
00498  * wsp has indicated session establishment, giving us a session id.
00499  */
00500 PPGSessionMachine *wap_push_ppg_have_push_session_for_sid(long sid)
00501 {
00502     PPGSessionMachine *sm;
00503 
00504     gw_assert(sid >= 0);
00505     sm = gwlist_search(ppg_machines, &sid, session_has_sid);
00506 
00507     return sm;
00508 }
00509 
00510 /*****************************************************************************
00511  *
00512  * INTERNAL FUNCTIONS
00513  *
00514  * Read general ppg configuration and configuration specific for users (to the
00515  * list 'users').
00516  * Return 1 when an user ppg group is present, 0 otherwise (and panic
00517  * if we have not trusted ppg and no user groups).
00518  */
00519 
00520 static int read_ppg_config(Cfg *cfg)
00521 {
00522      CfgGroup *grp;
00523      List *list;
00524 
00525      if (cfg == NULL)
00526          return USER_CONFIGURATION_NOT_ADDED;
00527 
00528      grp = cfg_get_single_group(cfg, octstr_imm("ppg"));
00529      if ((ppg_url = cfg_get(grp, octstr_imm("ppg-url"))) == NULL)
00530          ppg_url = octstr_imm("/wappush");
00531      cfg_get_integer(&ppg_port, grp, octstr_imm("ppg-port"));
00532      cfg_get_integer(&number_of_pushes, grp, octstr_imm("concurrent-pushes"));
00533      cfg_get_bool(&trusted_pi, grp, octstr_imm("trusted-pi"));
00534      cfg_get_integer(&number_of_users, grp, octstr_imm("users"));
00535      ppg_deny_ip = cfg_get(grp, octstr_imm("ppg-deny-ip"));
00536      ppg_allow_ip = cfg_get(grp, octstr_imm("ppg-allow-ip"));
00537      if ((global_sender = cfg_get(grp, octstr_imm("global-sender"))) == NULL)
00538          global_sender = octstr_format("%s", "1234");
00539      ppg_default_smsc = cfg_get(grp, octstr_imm("default-smsc"));
00540      ppg_dlr_url = cfg_get(grp, octstr_imm("default-dlr-url"));
00541      ppg_smsbox_id = cfg_get(grp, octstr_imm("ppg-smsbox-id"));
00542      if ((service_name = cfg_get(grp, octstr_imm("service-name"))) == NULL)
00543          service_name = octstr_format("%s", "ppg");
00544    
00545 #ifdef HAVE_LIBSSL
00546      cfg_get_integer(&ppg_ssl_port, grp, octstr_imm("ppg-ssl-port"));
00547      ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file"));
00548      ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file"));
00549      if (ppg_ssl_port != NO_HTTPS_PORT) {
00550         if (ssl_server_cert_file == NULL || ssl_server_key_file == NULL) 
00551             panic(0, "cannot continue without server cert and/or key files");
00552         use_global_server_certkey_file(ssl_server_cert_file, ssl_server_key_file);
00553      }        
00554      octstr_destroy(ssl_server_cert_file);
00555      octstr_destroy(ssl_server_key_file);
00556 #endif
00557 
00558      /* If pi is trusted, ignore possible user groups. */
00559      if (trusted_pi) {
00560         cfg_destroy(cfg);
00561         return USER_CONFIGURATION_ADDED;
00562      }
00563 
00564      /* But if it is not, we cannot continue without user groups.*/
00565      if ((list = cfg_get_multi_group(cfg, octstr_imm("wap-push-user")))
00566               == NULL) {
00567          panic(0, "No user group but ppg not trusted, stopping");
00568          gwlist_destroy(list, NULL);
00569          cfg_destroy(cfg); 
00570          return USER_CONFIGURATION_NOT_ADDED;
00571      }
00572     
00573      if (!wap_push_ppg_pushuser_list_add(list, number_of_pushes, 
00574                                          number_of_users)) {
00575          panic(0, "unable to create users configuration list, exiting");
00576          return USER_CONFIGURATION_NOT_ADDED;     
00577      }  
00578 
00579      cfg_destroy(cfg); 
00580      return USER_CONFIGURATION_ADDED;
00581 }
00582 
00583 static int ip_allowed_by_ppg(Octstr *ip)
00584 {
00585     if (ip == NULL)
00586         return 0;    
00587 
00588     if (trusted_pi)
00589         return 1;
00590 
00591     if (ppg_deny_ip == NULL && ppg_allow_ip == NULL) {
00592         warning(0, "Your ppg core configuration lacks allowed and denied" 
00593                    " ip lists");
00594         return 1;
00595     }
00596 
00597     if (ppg_deny_ip)
00598         if (octstr_compare(ppg_deny_ip, octstr_imm("*.*.*.*")) == 0) {
00599             panic(0, "Your ppg core configuration deny all ips, exiting");
00600             return 0;
00601         }
00602 
00603     if (ppg_allow_ip)
00604         if (octstr_compare(ppg_allow_ip, octstr_imm("*.*.*.*")) == 0) {
00605             warning(0, "Your ppg core configuration allow all ips");
00606             return 1;
00607         }
00608 
00609     if (ppg_deny_ip)
00610         if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(ppg_deny_ip, ip, 
00611             octstr_imm(";"), octstr_imm("."))) {
00612             error(0, "ip found from denied list");
00613             return 0;
00614         }
00615 
00616     if (ppg_allow_ip)
00617         if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(ppg_allow_ip, ip, 
00618             octstr_imm(";"), octstr_imm("."))) {
00619             debug("wap.push.ppg.pushuser", 0, "PPG: ip_allowed_by_ppg: ip found"
00620                   " from allowed list");
00621             return 1;
00622         }
00623 
00624     warning(0, "did not found ip from any of core lists, deny it");
00625     return 0;
00626 }
00627 
00628 /*
00629  * Event handling functions
00630  */
00631 static void ota_read_thread (void *arg)
00632 {
00633     WAPEvent *e;
00634 
00635     while (run_status == running && (e = gwlist_consume(ppg_queue)) != NULL) {
00636         handle_internal_event(e);
00637     } 
00638 }
00639 
00640 /*
00641  * Pap event functions handle only copy pointers. They do not allocate memory.
00642  */
00643 static PAPEvent *pap_event_create(Octstr *ip, Octstr *url, List *push_headers, 
00644                                   Octstr *mime_content, List *cgivars,
00645                                   HTTPClient *client)
00646 {
00647     PAPEvent *p;
00648 
00649     p = gw_malloc(sizeof(PAPEvent));
00650     p->ip = ip;
00651     p->url = url;
00652     p->push_headers = push_headers;
00653     p->mime_content = mime_content;
00654     p->cgivars = cgivars;
00655     p->client = client;
00656 
00657     return p;
00658 }
00659 
00660 static void pap_event_destroy(PAPEvent *p)
00661 {
00662     if (p == NULL)
00663         return;
00664 
00665     gw_free(p);
00666 }
00667 
00668 static void pap_event_destroy_item(void *p)
00669 {
00670     pap_event_destroy(p);
00671 }
00672 
00673 static void pap_event_unpack(PAPEvent *p, Octstr **ip, Octstr **url, 
00674                              List **push_headers, Octstr **mime_content, 
00675                              List **cgivars, HTTPClient **client)
00676 {
00677     *ip = p->ip;
00678     *url = p->url;
00679     *push_headers = p->push_headers;
00680     *mime_content = p->mime_content;
00681     *cgivars = p->cgivars;
00682     *client = p->client;
00683 }
00684 
00685 static void http_read_thread(void *arg)
00686 {
00687     PAPEvent *p;
00688     Octstr *ip; 
00689     Octstr *url; 
00690     List *push_headers;
00691     Octstr *mime_content; 
00692     List *cgivars;
00693     HTTPClient *client;
00694 
00695     while (run_status == running) {
00696         client = http_accept_request(ppg_port, &ip, &url, &push_headers, 
00697                                      &mime_content, &cgivars);
00698         if (client == NULL) 
00699             break;
00700 
00701         p = pap_event_create(ip, url, push_headers, mime_content, cgivars,
00702                              client);
00703         gwlist_produce(pap_queue, p);
00704     }
00705 }
00706 
00707 #ifdef HAVE_LIBSSL
00708 static void https_read_thread(void *arg)
00709 {
00710     PAPEvent *p;
00711     Octstr *ip; 
00712     Octstr *url; 
00713     List *push_headers;
00714     Octstr *mime_content; 
00715     List *cgivars;
00716     HTTPClient *client;
00717 
00718     while (run_status == running) {
00719         client = http_accept_request(ppg_ssl_port, &ip, &url, &push_headers, 
00720                                      &mime_content, &cgivars); 
00721         if (client == NULL) 
00722         break;
00723         
00724         p = pap_event_create(ip, url, push_headers, mime_content, cgivars, 
00725                              client);
00726         gwlist_produce(pap_queue, p);
00727     }
00728 }
00729 #endif
00730 
00731 /*
00732  * Authorization failure as such causes a challenge to the client (as required 
00733  * by rfc 2617, chapter 1).
00734  * We store HTTPClient data structure corresponding a given push id, so that 
00735  * we can send responses to the rigth address.
00736  * Pap chapter 14.4.1 states that we must return http status 202 after we have 
00737  * accepted PAP message, even if it is unparsable. So only the non-existing 
00738  * service error and some authorisation failures are handled at HTTP level. 
00739  * When a phone number was unacceptable, we return a PAP level error, because
00740  * we cannot know this error before parsing the document.
00741  */
00742 
00743 static void pap_request_thread(void *arg)
00744 {
00745     WAPEvent *ppg_event;
00746     PAPEvent *p;
00747     size_t push_len;
00748     Octstr *pap_content = NULL;
00749     Octstr *push_data = NULL;
00750     Octstr *rdf_content = NULL;
00751     Octstr *mime_content = NULL;
00752     Octstr *plos = NULL;               /* a temporary variable*/
00753     Octstr *boundary = NULL;
00754     Octstr *content_header = NULL;     /* Content-Type MIME header */
00755     Octstr *url = NULL;
00756     Octstr *ip = NULL;
00757     Octstr *not_found = NULL;
00758     Octstr *username = NULL;
00759     int compiler_status,
00760         http_status;
00761     List *push_headers,                /* MIME headers themselves */
00762          *content_headers,             /* Headers from the content entity, see
00763                                           pap chapters 8.2, 13.1. Rfc 2045 
00764                                           grammar calls these MIME-part-hea-
00765                                           ders */
00766          *cgivars;
00767     HTTPClient *client;
00768     Octstr *dlr_url;
00769     
00770     http_status = 0;
00771     url = ip = mime_content = username = NULL;                
00772   
00773     while (run_status == running && (p = gwlist_consume(pap_queue)) != NULL) {
00774 
00775         http_status = HTTP_NOT_FOUND;
00776         pap_event_unpack(p, &ip, &url, &push_headers, &mime_content, 
00777                          &cgivars, &client);      
00778 
00779         if (octstr_compare(url, ppg_url) != 0) {
00780             error(0,  "Request <%s> from <%s>: service not found", 
00781                   octstr_get_cstr(url), octstr_get_cstr(ip));
00782             debug("wap.push.ppg", 0, "your configuration uses %s",
00783                   octstr_get_cstr(ppg_url));           
00784             not_found = octstr_imm("Service not specified\n");
00785             http_send_reply(client, http_status, push_headers, not_found);
00786             goto ferror;
00787         }
00788 
00789         http_status = HTTP_UNAUTHORIZED;
00790    
00791         if (!ip_allowed_by_ppg(ip)) {
00792             error(0,  "Request <%s> from <%s>: ip forbidden, closing the"
00793                   " client", octstr_get_cstr(url), octstr_get_cstr(ip));
00794             http_close_client(client);
00795             goto ferror; 
00796         }
00797 
00798         if (!trusted_pi && user_configuration) {
00799         if (!wap_push_ppg_pushuser_authenticate(client, cgivars, ip, 
00800                                                     push_headers, &username)) {
00801                  error(0,  "Request <%s> from <%s>: authorisation failure",
00802                        octstr_get_cstr(url), octstr_get_cstr(ip));
00803                  goto ferror;
00804             }
00805         } else {                        /* Jörg, this wont disappear again */
00806         username = octstr_imm("");
00807     }
00808 
00809         http_status = HTTP_ACCEPTED;
00810         info(0, "PPG: Accept request <%s> from <%s>", octstr_get_cstr(url), 
00811              octstr_get_cstr(ip));
00812         
00813         if (octstr_len(mime_content) == 0) {
00814         warning(0, "PPG: No MIME content received, the request"
00815                     " unacceptable");
00816             send_bad_message_response(&client, octstr_imm("No MIME content"), 
00817                                       PAP_BAD_REQUEST, http_status);
00818             if (client == NULL)
00819                 break;
00820             goto ferror;
00821         }
00822 
00823         if (!push_headers) {
00824             warning(0, "PPG: No push headers received , the request"
00825                     " unacceptable");
00826             send_bad_message_response(&client, octstr_imm("No push headers"), 
00827                                       PAP_BAD_REQUEST, http_status);
00828             if (client == NULL)
00829                 break;
00830             goto ferror;
00831         }
00832         octstr_destroy(ip);
00833         
00834         http_remove_hop_headers(push_headers);
00835         remove_mime_headers(&push_headers);
00836         remove_link_headers(&push_headers);
00837 
00838         if (!headers_acceptable(push_headers, &content_header)) {
00839             warning(0,  "PPG: Unparsable push headers, the request"
00840                     " unacceptable");
00841             send_bad_message_response(&client, content_header, PAP_BAD_REQUEST,
00842                                       http_status);
00843             if (client == NULL)
00844                 break;
00845             goto herror;
00846         }
00847         
00848         if (get_mime_boundary(push_headers, content_header, &boundary) == -1) {
00849             warning(0, "PPG: No MIME boundary, the request unacceptable");
00850             send_bad_message_response(&client, content_header, PAP_BAD_REQUEST,
00851                                       http_status);
00852             if (client == NULL) 
00853                 break;
00854             goto berror;
00855         }
00856 
00857         gw_assert(mime_content);
00858         if (!mime_parse(boundary, mime_content, &pap_content, &push_data, 
00859                         &content_headers, &rdf_content)) {
00860             send_bad_message_response(&client, mime_content, PAP_BAD_REQUEST,
00861                                       http_status);
00862             if (client == NULL)
00863                 break;
00864             warning(0, "PPG: unable to parse mime content, the request"
00865                     " unacceptable");
00866             goto clean;
00867         } else {
00868             debug("wap.push.ppg", 0, "PPG: http_read_thread: pap multipart"
00869                   " accepted");
00870         }
00871         
00872         push_len = octstr_len(push_data); 
00873         http_header_remove_all(push_headers, "Content-Type");
00874     http_append_headers(push_headers, content_headers);
00875         change_header_value(&push_headers, "Content-Length", 
00876             octstr_get_cstr(plos = octstr_format("%d", push_len)));
00877         octstr_destroy(plos);
00878         octstr_destroy(content_header);
00879     http_destroy_headers(content_headers);
00880 
00881         ppg_event = NULL;
00882         if ((compiler_status = pap_compile(pap_content, &ppg_event)) == -2) {
00883         send_bad_message_response(&client, pap_content, PAP_BAD_REQUEST,
00884                                        http_status);
00885             if (client == NULL)
00886             break;
00887             warning(0, "PPG: pap control entity erroneous, the request" 
00888                     " unacceptable");
00889             goto no_compile;
00890         } else if (compiler_status == -1) {
00891             send_bad_message_response(&client, pap_content, PAP_BAD_REQUEST,
00892                                       http_status);
00893             if (client == NULL)
00894             break;
00895             warning(0, "PPG: non implemented pap feature requested, the"
00896                     " request unacceptable");
00897             goto no_compile;
00898         } else {
00899         if (!dict_put_once(http_clients, 
00900             ppg_event->u.Push_Message.pi_push_id, client)) {
00901                 warning(0, "PPG: duplicate push id, the request unacceptable");
00902             tell_fatal_error(&client, ppg_event, url, http_status, 
00903                                  PAP_DUPLICATE_PUSH_ID);
00904                 if (client == NULL)
00905                 break;
00906                 goto not_acceptable;
00907         } 
00908 
00909             dict_put(urls, ppg_event->u.Push_Message.pi_push_id, url); 
00910  
00911             if (is_phone_number(ppg_event->u.Push_Message.address_type)) {
00912                 if (!trusted_pi && user_configuration && 
00913                         !wap_push_ppg_pushuser_client_phone_number_acceptable(
00914                         username, ppg_event->u.Push_Message.address_value)) {
00915                     tell_fatal_error(&client, ppg_event, url, http_status, 
00916                                     PAP_FORBIDDEN);
00917                     if (client == NULL)
00918                     break;
00919                     goto not_acceptable;
00920                 }   
00921             }        
00922             
00923             debug("wap.push.ppg", 0, "PPG: http_read_thread: pap control"
00924                   " entity compiled ok");
00925             ppg_event->u.Push_Message.push_data = octstr_duplicate(push_data);
00926             ppg_event->u.Push_Message.smsc_id = set_smsc_id(push_headers, username,
00927                                                             trusted_pi);
00928             dlr_url = set_dlr_url(push_headers, username, trusted_pi);
00929             ppg_event->u.Push_Message.dlr_url = dlr_url;
00930             ppg_event->u.Push_Message.dlr_mask = set_dlr_mask(push_headers, dlr_url);
00931             ppg_event->u.Push_Message.smsbox_id = set_smsbox_id(push_headers, username,
00932                                                                 trusted_pi);
00933             ppg_event->u.Push_Message.service_name = set_service_name();
00934             remove_x_kannel_headers(&push_headers);
00935             ppg_event->u.Push_Message.push_headers = http_header_duplicate(push_headers);
00936             
00937             if (!handle_push_message(&client, ppg_event, http_status)) {
00938             if (client == NULL)
00939             break;
00940                 goto no_transform;
00941             }
00942         }
00943 
00944         pap_event_destroy(p);
00945         http_destroy_headers(push_headers);
00946         http_destroy_cgiargs(cgivars);
00947         octstr_destroy(username);
00948         octstr_destroy(mime_content);
00949         octstr_destroy(pap_content);
00950         octstr_destroy(push_data);
00951         octstr_destroy(rdf_content);
00952         octstr_destroy(boundary);
00953         continue;
00954 
00955 no_transform:
00956         pap_event_destroy(p);
00957         http_destroy_headers(push_headers);
00958         http_destroy_cgiargs(cgivars);
00959         octstr_destroy(username);
00960         octstr_destroy(mime_content);
00961         octstr_destroy(pap_content);
00962         octstr_destroy(push_data);
00963         octstr_destroy(rdf_content);
00964         octstr_destroy(boundary);
00965         continue;
00966 
00967 no_compile:
00968         pap_event_destroy(p);
00969         http_destroy_headers(push_headers);
00970         http_destroy_cgiargs(cgivars);
00971         octstr_destroy(username);
00972         octstr_destroy(mime_content);
00973         octstr_destroy(push_data);
00974         octstr_destroy(rdf_content);
00975         octstr_destroy(boundary);
00976         octstr_destroy(url);
00977         continue;
00978 
00979 not_acceptable:
00980         pap_event_destroy(p);
00981         http_destroy_headers(push_headers);
00982         http_destroy_cgiargs(cgivars);
00983         octstr_destroy(username);
00984         octstr_destroy(mime_content);
00985         octstr_destroy(pap_content);
00986         octstr_destroy(push_data);
00987         octstr_destroy(rdf_content);
00988         octstr_destroy(boundary);
00989         octstr_destroy(url);
00990         continue;
00991 
00992 clean:
00993         pap_event_destroy(p);
00994         http_destroy_headers(push_headers);
00995         http_destroy_headers(content_headers);
00996         octstr_destroy(pap_content);
00997         octstr_destroy(push_data);
00998         octstr_destroy(rdf_content);
00999         octstr_destroy(content_header);
01000         octstr_destroy(boundary);
01001         octstr_destroy(url);
01002         continue;
01003 
01004 ferror:
01005         pap_event_destroy(p);
01006         http_destroy_headers(push_headers);
01007         http_destroy_cgiargs(cgivars);
01008         octstr_destroy(username);
01009         octstr_destroy(url);
01010         octstr_destroy(ip);
01011         octstr_destroy(mime_content);
01012         continue;
01013 
01014 herror:
01015         pap_event_destroy(p);
01016         http_destroy_headers(push_headers);
01017         http_destroy_cgiargs(cgivars);
01018         octstr_destroy(username);
01019         octstr_destroy(url);
01020         continue;
01021 
01022 berror:
01023         pap_event_destroy(p);
01024         http_destroy_headers(push_headers);
01025         http_destroy_cgiargs(cgivars);
01026         octstr_destroy(username);
01027         octstr_destroy(mime_content);
01028         octstr_destroy(content_header);
01029         octstr_destroy(boundary);
01030         octstr_destroy(url);
01031         continue;
01032     }
01033 }
01034 
01035 /*
01036  * Operations needed when push proxy gateway receives a new push message are 
01037  * defined in ppg Chapter 6. We create machines when error, too, because we 
01038  * must then have a reportable message error state.
01039  * Output: current HTTP Client state.
01040  * Return 1 if the push content was OK, 0 if it was not transformable.
01041  */
01042 
01043 static int handle_push_message(HTTPClient **c, WAPEvent *e, int status)
01044 {
01045     int cless,
01046         session_exists,
01047         bearer_supported,
01048         dummy,
01049         constraints,
01050         message_transformable,
01051         coriented_possible;
01052 
01053     long coded_appid_value;
01054 
01055     PPGPushMachine *pm;
01056     PPGSessionMachine *sm;
01057     WAPAddrTuple *tuple=NULL;
01058     Octstr *push_data=NULL;
01059     Octstr *cliaddr=NULL;
01060     Octstr *type=NULL;
01061 
01062     List *push_headers;
01063    
01064     push_data = e->u.Push_Message.push_data;
01065     push_headers = e->u.Push_Message.push_headers;
01066     cliaddr = e->u.Push_Message.address_value;
01067     session_exists = 0;
01068 
01069     sm = session_find_using_pi_client_address(cliaddr);
01070     coded_appid_value = check_x_wap_application_id_header(&push_headers);
01071     cless = cless_accepted(e, sm);
01072     message_transformable = transform_message(&e, &tuple, push_headers, cless, 
01073                                               &type);
01074 
01075     if (!sm && !cless) {
01076         sm = store_session_data(sm, e, tuple, &session_exists); 
01077     }
01078 
01079     if (!store_push_data(&pm, sm, e, tuple, cless)) {
01080         warning(0, "PPG: handle_push_message: duplicate push id");
01081         *c = response_push_message(pm, PAP_DUPLICATE_PUSH_ID, status);
01082         goto no_start;
01083     }
01084     
01085     if (!message_transformable) {
01086     pm = update_push_data_with_attribute(&sm, pm, 
01087         PAP_TRANSFORMATION_FAILURE, PAP_UNDELIVERABLE1);  
01088         if (tuple != NULL)   
01089         *c = response_push_message(pm, PAP_TRANSFORMATION_FAILURE, status);
01090         else
01091         *c = response_push_message(pm, PAP_ADDRESS_ERROR, status);
01092         goto no_transformation;
01093     }
01094     
01095     dummy = 0;
01096     pm = update_push_data_with_attribute(&sm, pm, dummy, PAP_PENDING);
01097     
01098     bearer_supported = select_bearer_network(&e);
01099     if (!bearer_supported) {
01100         pm = update_push_data_with_attribute(&sm, pm, dummy, 
01101             PAP_UNDELIVERABLE2);
01102         *c = response_push_message(pm, PAP_REQUIRED_BEARER_NOT_AVAILABLE, status);
01103         goto no_start;
01104     }
01105     
01106     if ((constraints = delivery_time_constraints(e, pm)) == TIME_EXPIRED) {
01107         pm = update_push_data_with_attribute(&sm, pm, PAP_FORBIDDEN, 
01108                                              PAP_EXPIRED);
01109         *c = response_push_message(pm, PAP_FORBIDDEN, status);
01110         goto no_start;
01111     }
01112 
01113 /*
01114  * If time is to early for delivering the push message, we do not remove push
01115  * data. We response PI here, so that "accepted for processing" means "no 
01116  * error messages to come".
01117  */ 
01118 
01119     *c = response_push_message(pm, PAP_ACCEPTED_FOR_PROCESSING, status);
01120     info(0, "PPG: handle_push_message: push message accepted for processing");
01121 
01122     if (constraints == TIME_TOO_EARLY)
01123         goto store_push;
01124 
01125     if (constraints == NO_CONSTRAINTS) {
01126     http_header_mark_transformation(pm->push_headers, pm->push_data, type);
01127         if (sm)
01128             sm = update_session_data_with_headers(sm, pm); 
01129 
01130         if (!confirmation_requested(e)) {
01131             pm = deliver_unit_push(NOT_LAST, pm, sm, session_exists);
01132             goto unit_push_delivered;
01133     } 
01134           
01135         if (session_exists) {
01136             deliver_confirmed_push(NOT_LAST, pm, sm);   
01137         } else { 
01138             coriented_possible = coriented_deliverable(coded_appid_value); 
01139         http_header_remove_all(e->u.Push_Message.push_headers, 
01140                                    "Content-Type");  
01141             if (coriented_possible) {
01142                 create_session(e, pm);
01143             } else {
01144                 warning(0, "PPG: handle_push_message: wrong app id for confirmed"
01145                         " push session creation");
01146                 *c = response_push_message(pm, PAP_BAD_REQUEST, status);
01147             }
01148         }
01149     }
01150 
01151     wap_addr_tuple_destroy(tuple);
01152     octstr_destroy(type);
01153     wap_event_destroy(e);
01154     return 1;
01155 
01156 unit_push_delivered:
01157     wap_addr_tuple_destroy(tuple);
01158     remove_push_data(sm, pm, cless);
01159     octstr_destroy(type);
01160     wap_event_destroy(e);
01161     return 1;
01162 
01163 store_push:
01164     wap_addr_tuple_destroy(tuple);
01165     octstr_destroy(type);
01166     wap_event_destroy(e);
01167     return 1;
01168 
01169 no_transformation:
01170     wap_addr_tuple_destroy(tuple);
01171     remove_push_data(sm, pm, cless);
01172     if (sm)
01173         remove_pushless_session(sm);
01174     wap_event_destroy(e);
01175     return 0;
01176 
01177 no_start:
01178     wap_addr_tuple_destroy(tuple);
01179     octstr_destroy(type);
01180     remove_push_data(sm, pm, cless);
01181     if (sm)
01182         remove_pushless_session(sm);
01183     wap_event_destroy(e);
01184     return 1;
01185 }
01186 
01187 /*
01188  * These events come from OTA layer
01189  */
01190 static void handle_internal_event(WAPEvent *e)
01191 {
01192     long sid,
01193          pid,
01194          reason,
01195          port;
01196     int http_status;
01197     PPGPushMachine *pm;
01198     PPGSessionMachine *sm;
01199     WAPAddrTuple *tuple;
01200     List *caps;
01201         
01202     http_status = HTTP_OK;
01203     switch (e->type) {
01204 /*
01205  * Pap, Chapter 11.1.3 states that if client is incapable, we should abort the
01206  * push and inform PI. We do this here.
01207  * In addition, we store session id used as an alias for address tuple and do
01208  * all pushes pending for this initiator (or abort them).
01209  */
01210     case Pom_Connect_Ind:
01211          debug("wap.push.ppg", 0, "PPG: handle_internal_event: connect"
01212                " indication from OTA");
01213          sid = e->u.Pom_Connect_Ind.session_id;
01214          tuple = e->u.Pom_Connect_Ind.addr_tuple;
01215          port = tuple->remote->port;
01216          caps = e->u.Pom_Connect_Ind.requested_capabilities;
01217 
01218          sm = wap_push_ppg_have_push_session_for(tuple);
01219          sm = update_session_data(sm, sid, port, caps);
01220         
01221          if (!response_push_connection(e, sm)) {
01222          pm = abort_delivery(sm, http_status);
01223              wap_event_destroy(e);
01224              return;
01225          }
01226 
01227 /* 
01228  * hard-coded until we have bearer control implemented
01229  */
01230          deliver_pending_pushes(sm, NOT_LAST);  
01231          wap_event_destroy(e);
01232     break;
01233 
01234     case Pom_Disconnect_Ind:
01235         debug("wap.push.ppg", 0, "PPG: handle_internal_event: disconnect"
01236               " indication from OTA");
01237         sm = wap_push_ppg_have_push_session_for_sid(
01238                  e->u.Pom_Disconnect_Ind.session_handle);
01239         remove_session_data(sm, http_status);
01240         wap_event_destroy(e);
01241     break;
01242 
01243 /*
01244  * Only the client can close a session. So we leave session open, even when 
01245  * there are no active pushes. Note that we do not store PAP attribute very
01246  * long time. Point is that result notification message, if asked, will rep-
01247  * ort this fact to PI, after which there is no need to store it any more.
01248  */
01249     case Po_ConfirmedPush_Cnf:
01250         debug("wap.push.ppg", 0, "PPG: handle_internal_event: push"
01251               " confirmation from OTA");
01252         sid = e->u.Po_ConfirmedPush_Cnf.session_handle;
01253         pid = e->u.Po_ConfirmedPush_Cnf.server_push_id;
01254 
01255         sm = wap_push_ppg_have_push_session_for_sid(sid);
01256         pm = find_ppg_push_machine_using_pid(sm, pid);
01257         pm = update_push_data_with_attribute(&sm, pm, PAP_CONFIRMED, 
01258                                              PAP_DELIVERED2);
01259         wap_event_destroy(e);
01260         remove_push_data(sm, pm, 0);
01261     break;
01262 
01263 /*
01264  * Again, PAP attribute will be reported to PI by using result notification.
01265  */
01266     case Po_PushAbort_Ind:
01267         debug("wap.push.ppg", 0, "PPG: handle_internal_event: abort"
01268               " indication from OTA");
01269         sid = e->u.Po_PushAbort_Ind.session_handle;
01270         pid = e->u.Po_PushAbort_Ind.push_id;
01271 
01272         sm = wap_push_ppg_have_push_session_for_sid(sid);
01273         pm = find_ppg_push_machine_using_pid(sm, pid);
01274         session_machine_assert(sm);
01275         push_machine_assert(pm);
01276         reason = e->u.Po_PushAbort_Ind.reason;
01277         pm = update_push_data_with_attribute(&sm, pm, reason, PAP_ABORTED);
01278         remove_session_data(sm, http_status);
01279         wap_event_destroy(e);
01280     break;
01281 
01282 /*
01283  * FIXME TRU: Add timeout (a mandatory feature!)
01284  */
01285     default:
01286         debug("wap.ppg", 0, "PPG: handle_internal_event: an unhandled event");
01287         wap_event_dump(e);
01288         wap_event_destroy(e);
01289     break;
01290     }
01291 }
01292 
01293 /*
01294  * Functions related to various ppg machine types.
01295  *
01296  * We do not set session id here: it is told to us by wsp.
01297  */
01298 static PPGSessionMachine *session_machine_create(WAPAddrTuple *tuple, 
01299                                                  WAPEvent *e)
01300 {
01301     PPGSessionMachine *m;
01302 
01303     gw_assert(e->type = Push_Message);
01304 
01305     m = gw_malloc(sizeof(PPGSessionMachine));
01306     
01307     #define INTEGER(name) m->name = 0;
01308     #define OCTSTR(name) m->name = NULL;
01309     #define ADDRTUPLE(name) m->name = NULL;
01310     #define PUSHMACHINES(name) m->name = gwlist_create();
01311     #define CAPABILITIES(name) m->name = NULL;
01312     #define MACHINE(fields) fields
01313     #include "wap_ppg_session_machine.def"
01314 
01315     m->pi_client_address = octstr_duplicate(e->u.Push_Message.address_value);
01316     m->addr_tuple = wap_addr_tuple_duplicate(tuple);
01317     m->assumed_capabilities = 
01318         wsp_cap_duplicate_list(e->u.Push_Message.pi_capabilities);
01319     m->preferconfirmed_value = PAP_CONFIRMED;    
01320 
01321     gwlist_append(ppg_machines, m);
01322     debug("wap.push.ppg", 0, "PPG: Created PPGSessionMachine %ld",
01323           m->session_id);
01324 
01325     return m;
01326 }
01327 
01328 static void session_machine_destroy(void *p)
01329 {
01330     PPGSessionMachine *sm;
01331 
01332     if (p == NULL)
01333         return;
01334 
01335     sm = p;
01336     debug("wap.push.ppg", 0, "PPG: destroying PPGSEssionMachine %ld", 
01337           sm->session_id);
01338     
01339     #define OCTSTR(name) octstr_destroy(sm->name);
01340     #define ADDRTUPLE(name) wap_addr_tuple_destroy(sm->name);
01341     #define INTEGER(name) sm->name = 0;
01342     #define PUSHMACHINES(name) push_machines_list_destroy(sm->name);
01343     #define CAPABILITIES(name) wsp_cap_destroy_list(sm->name);
01344     #define MACHINE(fields) fields
01345     #include "wap_ppg_session_machine.def"
01346     gw_free(sm);
01347 }
01348 
01349 /*
01350  * FIXME: PPG's trust policy (flags authenticated and trusted).
01351  * We return pointer to the created push machine and push id it uses.
01352  */
01353 static PPGPushMachine *push_machine_create(WAPEvent *e, WAPAddrTuple *tuple)
01354 {
01355     PPGPushMachine *m;
01356 
01357     m = gw_malloc(sizeof(PPGPushMachine));
01358 
01359     #define INTEGER(name) m->name = 0;
01360     #define OCTSTR(name) m->name = NULL;
01361     #define OPTIONAL_OCTSTR(name) m->name = NULL;
01362     #define ADDRTUPLE(name) m->name = NULL;
01363     #define CAPABILITIES m->name = NULL;
01364     #define HTTPHEADER(name) m->name = NULL;
01365     #define MACHINE(fields) fields
01366     #include "wap_ppg_push_machine.def"
01367 
01368     m->addr_tuple = wap_addr_tuple_duplicate(tuple);
01369     m->pi_push_id = octstr_duplicate(e->u.Push_Message.pi_push_id);
01370     m->push_id = counter_increase(push_id_counter);
01371     m->delivery_method = e->u.Push_Message.delivery_method;
01372     m->deliver_after_timestamp = 
01373         octstr_duplicate(e->u.Push_Message.deliver_after_timestamp);
01374     m->priority = e->u.Push_Message.priority;
01375     m->push_headers = http_header_duplicate(e->u.Push_Message.push_headers);
01376     m->push_data = octstr_duplicate(e->u.Push_Message.push_data);
01377 
01378     m->address_type = e->u.Push_Message.address_type;
01379     if (e->u.Push_Message.smsc_id != NULL)
01380         m->smsc_id = octstr_duplicate(e->u.Push_Message.smsc_id);
01381     else
01382         m->smsc_id = NULL;
01383     if (e->u.Push_Message.dlr_url != NULL)
01384         m->dlr_url = octstr_duplicate(e->u.Push_Message.dlr_url);                                 
01385     else
01386         m->dlr_url = NULL;
01387     m->dlr_mask = e->u.Push_Message.dlr_mask;
01388     if (e->u.Push_Message.smsbox_id != NULL)
01389         m->smsbox_id = octstr_duplicate(e->u.Push_Message.smsbox_id);
01390     else
01391         m->smsbox_id = NULL;
01392     m->service_name = octstr_duplicate(e->u.Push_Message.service_name);
01393 
01394     m->progress_notes_requested = e->u.Push_Message.progress_notes_requested;
01395     if (e->u.Push_Message.progress_notes_requested)
01396         m->ppg_notify_requested_to = 
01397             octstr_duplicate(e->u.Push_Message.ppg_notify_requested_to);
01398 
01399     debug("wap.push.ppg", 0, "PPG: push machine %ld created", m->push_id);
01400 
01401     return m;
01402 }
01403 
01404 /*
01405  * Contrary to the normal Kannel style, we do not remove from a list here. 
01406  * That is because we now have two different push lists.
01407  */
01408 static void push_machine_destroy(void *p)
01409 {
01410     PPGPushMachine *pm;
01411 
01412     if (p == NULL)
01413         return;
01414 
01415     pm = p;
01416 
01417     debug("wap.push.ppg", 0, "PPG: destroying push machine %ld", 
01418           pm->push_id); 
01419     #define OCTSTR(name) octstr_destroy(pm->name);
01420     #define OPTIONAL_OCTSTR(name) octstr_destroy(pm->name);
01421     #define INTEGER(name)
01422     #define ADDRTUPLE(name) wap_addr_tuple_destroy(pm->name);
01423     #define CAPABILITIES(name) wap_cap_destroy_list(pm->name);
01424     #define HTTPHEADER(name) http_destroy_headers(pm->name);
01425     #define MACHINE(fields) fields
01426     #include "wap_ppg_push_machine.def"
01427 
01428     gw_free(p);
01429 }
01430 
01431 static void push_machines_list_destroy(List *machines)
01432 {
01433     if (machines == NULL)
01434         return;
01435 
01436     gwlist_destroy(machines, push_machine_destroy);
01437 }
01438 
01439 static int session_has_addr(void *a, void *b)
01440 {
01441     Octstr *cliaddr;
01442     PPGSessionMachine *sm;
01443 
01444     cliaddr = b;
01445     sm = a;
01446     
01447     return octstr_compare(sm->addr_tuple->remote->address, cliaddr) == 0;
01448 }
01449 
01450 static int session_has_sid(void *a, void *b)
01451 {
01452      PPGSessionMachine *sm;
01453      long *sid;
01454 
01455      sid = b;
01456      sm = a;
01457 
01458      return *sid == sm->session_id;
01459 }
01460 
01461 /*
01462  * Here session machine address tuples have connection-oriented ports, because
01463  * these are used when establishing the connection an doing pushes. But session
01464  * creation request must be to the the connectionless push port of the client.
01465  * So we change ports here.
01466  */
01467 static void create_session(WAPEvent *e, PPGPushMachine *pm)
01468 {
01469     WAPEvent *ota_event;
01470     List *push_headers;
01471     Octstr *smsc_id;
01472     Octstr *dlr_url;
01473     Octstr *smsbox_id;
01474     Octstr *service_name;
01475 
01476     gw_assert(e->type == Push_Message);
01477     push_machine_assert(pm);
01478     
01479     push_headers = http_header_duplicate(e->u.Push_Message.push_headers);
01480     smsc_id = octstr_duplicate(e->u.Push_Message.smsc_id);
01481     dlr_url = octstr_duplicate(e->u.Push_Message.dlr_url);
01482     smsbox_id = octstr_duplicate(e->u.Push_Message.smsbox_id);
01483     service_name = octstr_duplicate(e->u.Push_Message.service_name);
01484 
01485     ota_event = wap_event_create(Pom_SessionRequest_Req);
01486     ota_event->u.Pom_SessionRequest_Req.addr_tuple =
01487         addr_tuple_change_cliport(pm->addr_tuple,
01488                                   CONNECTIONLESS_PUSH_CLIPORT);
01489     ota_event->u.Pom_SessionRequest_Req.push_headers = push_headers;
01490     ota_event->u.Pom_SessionRequest_Req.push_id = pm->push_id;
01491     ota_event->u.Pom_SessionRequest_Req.address_type = pm->address_type;
01492     if (smsc_id != NULL)
01493         ota_event->u.Pom_SessionRequest_Req.smsc_id = smsc_id;
01494     else
01495         ota_event->u.Pom_SessionRequest_Req.smsc_id = NULL;
01496     if (dlr_url != NULL)
01497         ota_event->u.Pom_SessionRequest_Req.dlr_url = dlr_url;                                    
01498     else
01499         ota_event->u.Pom_SessionRequest_Req.dlr_url = NULL;
01500     ota_event->u.Pom_SessionRequest_Req.dlr_mask = e->u.Push_Message.dlr_mask;
01501     if (smsbox_id != NULL)
01502         ota_event->u.Pom_SessionRequest_Req.smsbox_id = smsbox_id;
01503     else
01504         ota_event->u.Pom_SessionRequest_Req.smsbox_id = NULL;
01505     ota_event->u.Pom_SessionRequest_Req.service_name = service_name;
01506         
01507     dispatch_to_ota(ota_event);
01508 }
01509 
01510 /*
01511  * We store data to push machine, because it is possible that we do not have
01512  * a session when push request happens.
01513  */
01514 static void request_confirmed_push(long last, PPGPushMachine *pm, 
01515                                    PPGSessionMachine *sm)
01516 {
01517     WAPEvent *ota_event;
01518     List *push_headers;
01519 
01520     gw_assert(last == 0 || last == 1);
01521     push_machine_assert(pm);
01522     session_machine_assert(sm);
01523     
01524     push_headers = http_header_duplicate(pm->push_headers);
01525 
01526     ota_event = wap_event_create(Po_ConfirmedPush_Req);
01527     ota_event->u.Po_ConfirmedPush_Req.server_push_id = pm->push_id;
01528     ota_event->u.Po_ConfirmedPush_Req.push_headers = push_headers;
01529     ota_event->u.Po_ConfirmedPush_Req.authenticated = pm->authenticated;
01530     ota_event->u.Po_ConfirmedPush_Req.trusted = pm->trusted;
01531     ota_event->u.Po_ConfirmedPush_Req.last = last;
01532  
01533     if (pm->push_data != NULL)
01534         ota_event->u.Po_ConfirmedPush_Req.push_body = 
01535             octstr_duplicate(pm->push_data);
01536     else
01537         ota_event->u.Po_ConfirmedPush_Req.push_body = NULL;
01538 
01539     ota_event->u.Po_ConfirmedPush_Req.session_handle = sm->session_id;
01540     debug("wap.push.ota", 0, "PPG: confirmed push request to OTA");
01541     
01542     dispatch_to_ota(ota_event);
01543 }
01544 
01545 /*
01546  * There is to types of unit push requests: requesting ip services and sms 
01547  * services. Address type tells the difference.
01548  */
01549 static void request_unit_push(long last, PPGPushMachine *pm)
01550 {
01551     WAPEvent *ota_event;
01552     List *push_headers;
01553 
01554     gw_assert(last == 0 || last == 1);
01555     push_machine_assert(pm);
01556     
01557     push_headers = http_header_duplicate(pm->push_headers);
01558 
01559     ota_event = wap_event_create(Po_Unit_Push_Req);
01560     ota_event->u.Po_Unit_Push_Req.addr_tuple = 
01561         wap_addr_tuple_duplicate(pm->addr_tuple);
01562     ota_event->u.Po_Unit_Push_Req.push_id = pm->push_id;
01563     ota_event->u.Po_Unit_Push_Req.push_headers = push_headers;
01564     ota_event->u.Po_Unit_Push_Req.authenticated = pm->authenticated;
01565     ota_event->u.Po_Unit_Push_Req.trusted = pm->trusted;
01566     ota_event->u.Po_Unit_Push_Req.last = last;
01567 
01568     ota_event->u.Po_Unit_Push_Req.address_type = pm->address_type;
01569     if (pm->smsc_id != NULL)
01570         ota_event->u.Po_Unit_Push_Req.smsc_id = octstr_duplicate(pm->smsc_id);
01571     else
01572         ota_event->u.Po_Unit_Push_Req.smsc_id = NULL;
01573     if (pm->dlr_url != NULL)
01574         ota_event->u.Po_Unit_Push_Req.dlr_url = octstr_duplicate(pm->dlr_url);
01575     else
01576         ota_event->u.Po_Unit_Push_Req.dlr_url = NULL;
01577     ota_event->u.Po_Unit_Push_Req.dlr_mask = pm->dlr_mask;
01578     if (pm->smsbox_id != NULL)   
01579         ota_event->u.Po_Unit_Push_Req.smsbox_id = octstr_duplicate(pm->smsbox_id);
01580     else
01581         ota_event->u.Po_Unit_Push_Req.smsbox_id = NULL;
01582     if (pm->service_name != NULL)    
01583         ota_event->u.Po_Unit_Push_Req.service_name = octstr_duplicate(pm->service_name);
01584 
01585     ota_event->u.Po_Unit_Push_Req.push_body = octstr_duplicate(pm->push_data);
01586 
01587     dispatch_to_ota(ota_event);
01588     debug("wap.push.ppg", 0, "PPG: OTA request for unit push");
01589 }
01590 
01591 static void request_push(long last, PPGPushMachine *pm)
01592 {
01593     WAPEvent *ota_event;
01594     List *push_headers;
01595 
01596     gw_assert(last == 0 || last == 1);
01597     push_machine_assert(pm);
01598     
01599     push_headers = http_header_duplicate(pm->push_headers);
01600 
01601     ota_event = wap_event_create(Po_Push_Req);
01602     ota_event->u.Po_Push_Req.push_headers = push_headers;
01603     ota_event->u.Po_Push_Req.authenticated = pm->authenticated;
01604     ota_event->u.Po_Push_Req.trusted = pm->trusted;
01605     ota_event->u.Po_Push_Req.last = last;
01606 
01607     if (pm->push_data != NULL)
01608         ota_event->u.Po_Push_Req.push_body = 
01609             octstr_duplicate(pm->push_data);
01610     else
01611         ota_event->u.Po_Push_Req.push_body = NULL;        
01612 
01613     ota_event->u.Po_Push_Req.session_handle = pm->session_id;
01614     debug("wap.push.ppg", 0, "PPG: OTA request for push");
01615     
01616     dispatch_to_ota(ota_event);
01617 }
01618 
01619 
01620 /*
01621  * According to pap, Chapter 11, capabilities can be 
01622  *    
01623  *                a) queried by PI
01624  *                b) told to PI when a client is subscribing
01625  *                c) assumed
01626  *
01627  * In case c) we got capabilities from third part of the push message (other
01628  * cases PI knows what it is doing), and we check is the client capable to
01629  * handle the message.
01630  * Requested capabilities are client capabilities, assumed capabilities are
01631  * PI capabilities. If there is no assumed capabilities, PI knows client capab-
01632  * ilities by method a) or method b).
01633  * Returns 1, if the client is capable, 0 when it is not.
01634  */
01635 
01636 static int response_push_connection(WAPEvent *e, PPGSessionMachine *sm)
01637 {
01638     WAPEvent *appl_event;
01639 
01640     gw_assert(e->type == Pom_Connect_Ind);
01641 
01642     if (sm->assumed_capabilities != NULL && check_capabilities(
01643             e->u.Pom_Connect_Ind.requested_capabilities, 
01644             sm->assumed_capabilities) == 0)
01645        return 0;
01646 
01647     appl_event = wap_event_create(Pom_Connect_Res);
01648     appl_event->u.Pom_Connect_Res.negotiated_capabilities = 
01649         wsp_cap_duplicate_list(e->u.Pom_Connect_Ind.requested_capabilities);
01650     appl_event->u.Pom_Connect_Res.session_id = e->u.Pom_Connect_Ind.session_id;
01651 
01652     dispatch_to_appl(appl_event);
01653 
01654     return 1;
01655 }
01656 
01657 /*
01658  * Push response, from pap, Chapter 9.3. 
01659  * Inputs error code, in PAP format.
01660  * Return the current value of HTTPClient.
01661  */
01662 static HTTPClient *response_push_message(PPGPushMachine *pm, long code, int status)
01663 {
01664     WAPEvent *e;
01665     HTTPClient *c;
01666 
01667     push_machine_assert(pm);
01668 
01669     e = wap_event_create(Push_Response);
01670     e->u.Push_Response.pi_push_id = octstr_duplicate(pm->pi_push_id);
01671     e->u.Push_Response.sender_name = tell_ppg_name();
01672     e->u.Push_Response.reply_time = set_time();
01673     e->u.Push_Response.code = code;
01674     e->u.Push_Response.desc = describe_code(code);
01675 
01676     c = send_push_response(e, status);
01677 
01678     return c;
01679 }
01680 
01681 
01682 static int check_capabilities(List *requested, List *assumed)
01683 {
01684     int is_capable;
01685 
01686     is_capable = 1;
01687 
01688     return is_capable;
01689 }
01690 
01691 /*
01692  * Time of creation of the response (pap, chapter 9.3). We convert UNIX time 
01693  * to ISO8601, it is, YYYY-MM-DDThh:mm:ssZ, T and Z being literal strings (we
01694  * use gw_gmtime to turn UNIX time to broken time).
01695  */
01696 static Octstr *set_time(void)
01697 {
01698     Octstr *current_time;
01699     struct tm now;
01700 
01701     now = gw_gmtime(time(NULL));
01702     current_time = octstr_format("%04d-%02d-%02dT%02d:%02d:%02dZ", 
01703                                  now.tm_year + 1900, now.tm_mon + 1, 
01704                                  now.tm_mday, now.tm_hour, now.tm_min, 
01705                                  now.tm_sec);
01706 
01707     return current_time;
01708 }
01709 
01710 static void session_machine_assert(PPGSessionMachine *sm)
01711 {
01712     gw_assert(sm);
01713     gw_assert(sm->session_id >= 0);
01714     gw_assert(sm->addr_tuple);
01715     gw_assert(sm->pi_client_address);
01716 }
01717 
01718 static void push_machine_assert(PPGPushMachine *pm)
01719 {
01720     gw_assert(pm);
01721     gw_assert(pm->pi_push_id);
01722     gw_assert(pm->push_id >= 0);
01723     gw_assert(pm->session_id >= 0);
01724     gw_assert(pm->addr_tuple);
01725     gw_assert(pm->trusted == 1 || pm->trusted == 0);
01726     gw_assert(pm->authenticated  == 1 || pm->authenticated == 0);
01727 }
01728 
01729 /*
01730  * Message transformations performed by PPG are defined in ppg, 6.1.2.1. Ppg,
01731  * chapter 6.1.1, states that we MUST reject a push having an erroneous PAP
01732  * push message element. So we must validate it even when we do not compile
01733  * it.
01734  * If message content was not si or sl, we pass it without modifications.
01735  * We do not do any (formally optional, but phones may disagree) header 
01736  * conversions to the binary format here, these are responsibility of our OTA 
01737  * module (gw/wap_push_ota.c). 
01738  * FIXME: Remove all headers which default values are known to the client. 
01739  *
01740  * Return 
01741  *    a) message, either transformed or not (if there is no-transform cache 
01742  *       directive, wml code is erroneous or content was not si or sl.) 
01743  *    b) The transformed gw address. Use here global-sender, when the bearer
01744  *       is SMS (some SMS centers would require this).
01745  *    c) the transformed message content type
01746  *
01747  * Returned flag tells was the transformation (if any) successful or not. Error 
01748  * flag is returned when there is no push headers, there is no Content-Type header
01749  * or push content does not compile. We should have checked existence of push 
01750  * headers earlier, but let us be careful.
01751  */
01752 static int transform_message(WAPEvent **e, WAPAddrTuple **tuple, 
01753                              List *push_headers, int cless_accepted, Octstr **type)
01754 {
01755     int message_deliverable;
01756     struct content content;
01757     Octstr *cliaddr;
01758     long cliport,
01759          servport,
01760          address_type;
01761 
01762     gw_assert((**e).type == Push_Message);
01763     if ((**e).u.Push_Message.push_headers == NULL)
01764         goto herror;
01765 
01766     cliaddr = (**e).u.Push_Message.address_value;
01767     push_headers = (**e).u.Push_Message.push_headers;
01768 
01769     if (!cless_accepted) {
01770         cliport = CONNECTED_CLIPORT;
01771         servport = CONNECTED_SERVPORT;
01772     } else {
01773         cliport = CONNECTIONLESS_PUSH_CLIPORT;
01774         servport = CONNECTIONLESS_SERVPORT;
01775     }
01776     
01777     address_type = (**e).u.Push_Message.address_type;
01778     *tuple = set_addr_tuple(cliaddr, cliport, servport, address_type, push_headers);
01779 
01780     if (!content_transformable(push_headers)) 
01781         goto no_transform;
01782 
01783     content.charset = NULL;
01784     content.type = NULL;
01785 
01786     content.body = (**e).u.Push_Message.push_data; 
01787     if (content.body == NULL)
01788         goto no_transform;
01789 
01790     content.type = http_header_find_first(push_headers, "Content-Transfer-Encoding");
01791     if (content.type) {
01792     octstr_strip_blanks(content.type);
01793     debug("wap.push.ppg", 0, "PPG: Content-Transfer-Encoding is \"%s\"",
01794           octstr_get_cstr (content.type));
01795     message_deliverable = pap_get_content(&content);
01796     
01797         if (message_deliverable) {
01798         change_header_value(&push_headers, "Content-Transfer-Encoding", 
01799                                 "binary");
01800     } else {
01801         goto error;
01802     }
01803     }
01804 
01805     octstr_destroy(content.type);
01806     http_header_get_content_type(push_headers, &content.type, &content.charset);   
01807     message_deliverable = pap_convert_content(&content);
01808 
01809     if (content.type == NULL)
01810         goto error;
01811 
01812     if (message_deliverable) {
01813         *type = content.type;        
01814     } else {
01815         goto error;
01816     }
01817 
01818     (**e).u.Push_Message.push_data = content.body;
01819     octstr_destroy(content.charset);
01820 
01821     debug("wap.push.ppg", 0, "PPG: transform_message: push message content"
01822           " and headers valid");
01823     return 1;
01824 
01825 herror:
01826     warning(0, "PPG: transform_message: no push headers, cannot accept");
01827     octstr_destroy(content.type);
01828     return 0;
01829 
01830 error:
01831     warning(0, "PPG: transform_message: push content erroneous, cannot"
01832             " accept");
01833     octstr_destroy(content.type);
01834     octstr_destroy(content.charset);
01835     return 0;
01836 
01837 no_transform:
01838     warning(0, "PPG: transform_message: push content non transformable");
01839     return 1;
01840 }
01841 
01842 /*
01843  * Transform X-WAP-Application headers as per ppg 6.1.2.1. Note that missing
01844  * header means that wml.ua is assumed.
01845  * Return coded value (starting with 0), when the id was not wml.ua
01846  *        -1, when id was wml.ua (or no application id was present)
01847  *        -2, when error
01848  */
01849 static long check_x_wap_application_id_header(List **push_headers)
01850 {
01851     Octstr *appid_content;
01852     long coded_value;
01853     Octstr *cos;
01854     
01855     if (*push_headers == NULL)
01856         return -2;
01857 
01858     appid_content = http_header_find_first(*push_headers, 
01859         "X-WAP-Application-Id");
01860     
01861     if (appid_content == NULL) {
01862         octstr_destroy(appid_content);
01863         return -1;
01864     }
01865 
01866     if ((coded_value = parse_appid_header(&appid_content)) < 0) {
01867         octstr_destroy(appid_content);
01868         return -2;
01869     }
01870         
01871     if (coded_value == 2) {
01872         octstr_destroy(appid_content);
01873         http_header_remove_all(*push_headers, "X-WAP-Application-Id");
01874         return -1;
01875     }
01876 
01877     cos = octstr_format("%ld", coded_value);
01878     http_header_remove_all(*push_headers, "X-WAP-Application-Id");
01879     http_header_add(*push_headers, "X-WAP-Application-Id", octstr_get_cstr(cos));
01880     
01881     octstr_destroy(appid_content); 
01882     octstr_destroy(cos);
01883     
01884     return coded_value;  
01885 }
01886 
01887 /*
01888  * Check do we have a no-transform cache directive amongst the headers.
01889  */
01890 static int content_transformable(List *push_headers)
01891 {
01892     List *cache_directives;
01893     long i;
01894     Octstr *header_name, 
01895            *header_value;
01896 
01897     gw_assert(push_headers);
01898 
01899     cache_directives = http_header_find_all(push_headers, "Cache-Control");
01900     if (gwlist_len(cache_directives) == 0) {
01901         http_destroy_headers(cache_directives);
01902         return 1;
01903     }
01904 
01905     i = 0;
01906     while (i < gwlist_len(cache_directives)) {
01907         http_header_get(cache_directives, i, &header_name, &header_value);
01908         if (octstr_compare(header_value, octstr_imm("no-transform")) == 0) {
01909             http_destroy_headers(cache_directives);
01910             octstr_destroy(header_name);
01911             octstr_destroy(header_value);
01912         return 0;
01913         }
01914         ++i;
01915     }
01916 
01917     http_destroy_headers(cache_directives);
01918     octstr_destroy(header_name);
01919     octstr_destroy(header_value);
01920  
01921     return 1;
01922 }
01923 
01924 /*
01925  * Convert push content to compact binary format (this can be wmlc, sic, slc
01926  * or coc). Current status wml, sl and si compiled, others passed.
01927  */
01928 static Octstr *convert_wml_to_wmlc(struct content *content)
01929 {
01930     Octstr *wmlc;
01931 
01932     if (wml_compile(content->body, content->charset, &wmlc, NULL) == 0)
01933         return wmlc;
01934     warning(0, "PPG: wml compilation failed");
01935     return NULL;
01936 }
01937 
01938 static Octstr *convert_si_to_sic(struct content *content)
01939 {
01940     Octstr *sic;
01941 
01942     if (si_compile(content->body, content->charset, &sic) == 0)
01943         return sic;
01944     warning(0, "PPG: si compilation failed");
01945     return NULL;
01946 }
01947 
01948 static Octstr *convert_sl_to_slc(struct content *content)
01949 {
01950     Octstr *slc;
01951 
01952     if (sl_compile(content->body, content->charset, &slc) == 0)
01953         return slc;
01954     warning(0, "PPG: sl compilation failed");
01955     return NULL;
01956 }
01957 
01958 
01959 static Octstr *extract_base64(struct content *content)
01960 {
01961     Octstr *orig = octstr_duplicate(content->body);
01962     octstr_base64_to_binary(orig);
01963     return orig;
01964 }
01965 
01966 static struct {
01967     char *type;
01968     char *result_type;
01969     Octstr *(*convert) (struct content *);
01970 } converters[] = {
01971     { "text/vnd.wap.wml",
01972       "application/vnd.wap.wmlc",
01973       convert_wml_to_wmlc },
01974     { "text/vnd.wap.si",
01975       "application/vnd.wap.sic",
01976       convert_si_to_sic },
01977     { "text/vnd.wap.sl",
01978       "application/vnd.wap.slc",
01979       convert_sl_to_slc}
01980 };
01981 
01982 #define NUM_CONVERTERS ((long) (sizeof(converters) / sizeof(converters[0])))
01983 
01984 static struct {
01985     char *transfer_encoding;
01986     Octstr *(*extract) (struct content *);
01987 } extractors[] = {
01988     { "base64",
01989       extract_base64 }
01990 };
01991 
01992 #define NUM_EXTRACTORS ((long) (sizeof(extractors) / sizeof(extractors[0])))
01993 
01994 /*
01995  * Compile wap defined contents, accept others without modifications. Push
01996  * message 6.3 states that push content can be any MIME accepted content type.
01997  */
01998 static int pap_convert_content(struct content *content)
01999 {
02000     long i;
02001     Octstr *new_body;
02002 
02003     for (i = 0; i < NUM_CONVERTERS; i++) {
02004         if (octstr_compare(content->type, 
02005             octstr_imm(converters[i].type)) == 0) {
02006         new_body = converters[i].convert(content);
02007             if (new_body == NULL)
02008             return 0;
02009             octstr_destroy(content->body);
02010             content->body = new_body;
02011             octstr_destroy(content->type); 
02012             content->type = octstr_create(converters[i].result_type);
02013             return 1;
02014         }
02015     }
02016 
02017     return 1;
02018 }
02019 
02020 /*
02021  * MIME specifies a number of content transfer encodings.
02022  * This function tries to get the original version of the
02023  * content.
02024  */
02025 static int pap_get_content(struct content *content)
02026 {
02027     long i;
02028     Octstr *new_body;
02029 
02030     for (i = 0; i < NUM_EXTRACTORS; i++) {
02031         if (octstr_case_compare(content->type, 
02032             octstr_imm(extractors[i].transfer_encoding)) == 0) {
02033         
02034             new_body = extractors[i].extract(content);
02035             if (new_body == NULL)
02036             return 0;
02037             octstr_destroy(content->body);
02038             content->body = new_body;
02039         octstr_destroy(content->type);
02040         content->type = NULL;
02041             return 1;
02042         }
02043     }
02044 
02045     return 1;
02046 }
02047 
02048 /*
02049  * Bearer and network types are defined in wdp, Appendix C. Any means any net-
02050  * work supporting IPv4 or IPv6.
02051  */
02052 static char *bearers[] = {
02053    "Any",
02054    "SMS",
02055    "CSD",
02056    "GPRS",
02057    "Packet Data",
02058    "CDPD"
02059 };
02060 
02061 #define NUMBER_OF_BEARERS sizeof(bearers)/sizeof(bearers[0])
02062 
02063 static char *networks[] = {
02064     "Any", 
02065     "GSM",
02066     "IS-95 CDMA",
02067     "ANSI-136",
02068     "AMPS",
02069     "PDC",
02070     "IDEN", 
02071     "PHS",   
02072     "TETRA"
02073 };
02074 
02075 #define NUMBER_OF_NETWORKS sizeof(networks)/sizeof(networks[0])
02076 
02077 /*
02078  * We support networks using IP as a bearer and GSM using SMS as bearer, so we
02079  * must reject others. Default bearer is IP, it is (currently) not-SMS. After
02080  * the check we change meaning of the bearer_required-attribute: it will tell 
02081  * do we use WAP over SMS.
02082  */
02083 int select_bearer_network(WAPEvent **e)
02084 {
02085     Octstr *bearer,
02086            *network;
02087     int bearer_required,
02088         network_required;
02089     size_t i, 
02090            j;
02091 
02092     gw_assert((**e).type == Push_Message);
02093 
02094     bearer_required = (**e).u.Push_Message.bearer_required;
02095     network_required = (**e).u.Push_Message.network_required;
02096     bearer = octstr_imm("Any");
02097     network = octstr_imm("Any");
02098     
02099     if (!bearer_required || !network_required)
02100         return 1;
02101 
02102     if (bearer_required)
02103         bearer = (**e).u.Push_Message.bearer;
02104     if (network_required)
02105         network = (**e).u.Push_Message.network;
02106     
02107     for (i = 0; i < NUMBER_OF_NETWORKS ; ++i) {
02108         if (octstr_case_compare(bearer, octstr_imm(bearers[i])) == 0)
02109             break;
02110     }
02111     for (j = 0; j < NUMBER_OF_BEARERS ; ++j) {
02112         if (octstr_case_compare(bearer, octstr_imm(bearers[j])) == 0)
02113             break;
02114     }
02115     if (i == NUMBER_OF_NETWORKS || j == NUMBER_OF_BEARERS)
02116         return 0;
02117 
02118     return 1;
02119 }
02120 
02121 static int session_has_pi_client_address(void *a, void *b)
02122 {
02123     Octstr *caddr;
02124     PPGSessionMachine *sm;
02125 
02126     caddr = b;
02127     sm = a;
02128 
02129     return octstr_compare(caddr, sm->pi_client_address) == 0;
02130 }
02131 
02132 /*
02133  * PI client address is composed of a client specifier and a PPG specifier (see
02134  * ppg, chapter 7). So it is equivalent with gw address quadruplet.
02135  */
02136 PPGSessionMachine *session_find_using_pi_client_address(Octstr *caddr)
02137 {
02138     PPGSessionMachine *sm;
02139     
02140     sm = gwlist_search(ppg_machines, caddr, session_has_pi_client_address);
02141 
02142     return sm;
02143 }
02144 
02145 /*
02146  * Give PPG a human readable name.
02147  */
02148 static Octstr *tell_ppg_name(void)
02149 {
02150      return octstr_format("%S; WAP/1.3 (" GW_NAME "/%s)", get_official_name(), 
02151                           GW_VERSION);
02152 }
02153 
02154 /*
02155  * Delivery time constraints are a) deliver before and b) deliver after. It is
02156  * possible that service required is after some time and before other. So we 
02157  * test first condition a). Note that 'now' satisfy both constraints. 
02158  * Returns: 0 delivery time expired
02159  *          1 too early to send the message
02160  *          2 no constraints
02161  */
02162 static int delivery_time_constraints(WAPEvent *e, PPGPushMachine *pm)
02163 {
02164     Octstr *before,
02165            *after;
02166     struct tm now;
02167    
02168     gw_assert(e->type = Push_Message);
02169     
02170     before = e->u.Push_Message.deliver_before_timestamp;
02171     after = pm->deliver_after_timestamp;
02172     now = gw_gmtime(time(NULL));
02173 
02174     if (!deliver_before_test_cleared(before, now)) {
02175         info(0, "PPG: delivery deadline expired, dropping the push message");
02176         return 0;
02177     }
02178 
02179     if (!deliver_after_test_cleared(after, now)) {
02180         debug("wap.push.ppg", 0, "PPG: too early to push the message,"
02181               " waiting");
02182         return 1;
02183     }
02184 
02185     return 2;
02186 }
02187 
02188 /*
02189  * Give verbose description of the result code. Conversion table for descrip-
02190  * tion.
02191  */
02192 struct description_t {
02193     long reason;
02194     char *description;
02195 };
02196 
02197 typedef struct description_t description_t;
02198 
02199 static description_t pap_desc[] = {
02200     { PAP_OK, "The request succeeded"},
02201     { PAP_ACCEPTED_FOR_PROCESSING, "The request has been accepted for"
02202                                    " processing"},
02203     { PAP_BAD_REQUEST, "Not understood due to malformed syntax"},
02204     { PAP_FORBIDDEN, "Request was refused"},
02205     { PAP_ADDRESS_ERROR, "The client specified not recognised"},
02206     { PAP_CAPABILITIES_MISMATCH, "Capabilities assumed by PI were not"
02207                                  "  acceptable for the client specified"},
02208     { PAP_DUPLICATE_PUSH_ID, "Push id supplied was not unique"},
02209     { PAP_INTERNAL_SERVER_ERROR, "Server could not fulfill the request due"
02210                                  " to an internal error"},
02211     { PAP_TRANSFORMATION_FAILURE, "PPG was unable to perform a transformation"
02212                                   " of the message"},
02213     { PAP_REQUIRED_BEARER_NOT_AVAILABLE, "Required bearer not available"},
02214     { PAP_SERVICE_FAILURE, "The service failed. The client may re-attempt"
02215                            " the operation"},
02216     { PAP_CLIENT_ABORTED, "The client aborted the operation. No reason given"},
02217     { WSP_ABORT_USERREQ, "Wsp requested abort"},
02218     { WSP_ABORT_USERRFS, "Wsp refused push message. Do not try again"},
02219     { WSP_ABORT_USERPND, "Push message cannot be delivered to intended"
02220                          " destination by the wsp"},
02221     { WSP_ABORT_USERDCR, "Push message discarded due to resource shortage in"
02222                          " wsp"},
02223     { WSP_ABORT_USERDCU, "Content type of the push message cannot be"
02224                          " processed by the wsp"}
02225 };
02226 
02227 static size_t desc_tab_size = sizeof(pap_desc) / sizeof(pap_desc[0]);
02228     
02229 static Octstr *describe_code(long code)
02230 {
02231     Octstr *desc;
02232     size_t i;
02233 
02234     for (i = 0; i < desc_tab_size; i++) {
02235         if (pap_desc[i].reason == code) {
02236             desc = octstr_create(pap_desc[i].description);
02237             return desc;
02238         }
02239     }
02240 
02241     return octstr_imm("unknown PAP code");
02242 }
02243 
02244 /*
02245  * Remove push data from the list of connectionless pushes, if cless is true, 
02246  * otherwise from the list of pushes belonging to session machine sm.
02247  */
02248 static void remove_push_data(PPGSessionMachine *sm, PPGPushMachine *pm, 
02249                              int cless)
02250 {
02251     push_machine_assert(pm);
02252 
02253     if (cless) {
02254         gwlist_delete_equal(ppg_unit_pushes, pm);
02255     } else {
02256         session_machine_assert(sm);
02257         gwlist_delete_equal(sm->push_machines, pm);
02258     }
02259 
02260     push_machine_destroy(pm);
02261 }
02262 
02263 /*
02264  * If cless is true, store push to the list connectionless pushes, otherwise 
02265  * in the push list of the session machine sm.
02266  * We must create a push machine even when an error occurred, because this is
02267  * used for storing the relevant pap error state and other data for this push.
02268  * There should not be any duplicate push ids here (this is tested by http_
02269  * read_thread), but let us be carefull.
02270  * Return a pointer the push machine newly created and a flag telling was the
02271  * push id duplicate. 
02272  */
02273 static int store_push_data(PPGPushMachine **pm, PPGSessionMachine *sm, 
02274                            WAPEvent *e, WAPAddrTuple *tuple, int cless)
02275 { 
02276     Octstr *pi_push_id;  
02277     int duplicate_push_id;
02278     
02279     gw_assert(e->type == Push_Message);
02280 
02281     pi_push_id = e->u.Push_Message.pi_push_id;
02282 
02283     duplicate_push_id = 0;
02284     if (((!cless) && 
02285        (find_ppg_push_machine_using_pi_push_id(sm, pi_push_id) != NULL)) ||
02286        ((cless) && 
02287        (find_unit_ppg_push_machine_using_pi_push_id(pi_push_id) != NULL)))
02288        duplicate_push_id = 1;
02289 
02290     *pm = push_machine_create(e, tuple);
02291     
02292     if (duplicate_push_id)
02293         return !duplicate_push_id;
02294     
02295     if (!cless) {
02296        gwlist_append(sm->push_machines, *pm);
02297        debug("wap.push.ppg", 0, "PPG: store_push_data: push machine %ld"
02298              " appended to push list of sm machine %ld", (*pm)->push_id, 
02299              sm->session_id);
02300     } else {
02301        gwlist_append(ppg_unit_pushes, *pm);
02302        debug("wap.push.ppg", 0, "PPG: store_push_data: push machine %ld"
02303              " appended to unit push list", (*pm)->push_id);
02304     }
02305 
02306     return !duplicate_push_id;
02307 }
02308 
02309 /*
02310  * Deliver confirmed push. Note that if push is confirmed, PAP attribute is up-
02311  * dated only after an additional event (confirmation, abort or time-out). 
02312  */
02313 static void deliver_confirmed_push(long last, PPGPushMachine *pm, 
02314                                    PPGSessionMachine *sm)
02315 {
02316     request_confirmed_push(last, pm, sm);
02317 }
02318 
02319 /*
02320  * Ppg, chapter 6.1.2.2 , subchapter delivery, says that if push is unconform-
02321  * ed, we can use either Po-Unit-Push.req or Po-Push.req primitive. We use Po-
02322  * Push.req, if have an already established session (other words, sm != NULL).
02323  * In addition, update PAP attribute. Return pointer to the updated push mach-
02324  * ine.
02325  */
02326 static PPGPushMachine *deliver_unit_push(long last, PPGPushMachine *pm, 
02327     PPGSessionMachine *sm, int session_exists)
02328 {
02329     push_machine_assert(pm);
02330     
02331     if (!session_exists)
02332         request_unit_push(last, pm);
02333     else
02334         request_push(last, pm);
02335 
02336     pm = update_push_data_with_attribute(&sm, pm, PAP_UNCONFIRMED, 
02337                                          PAP_DELIVERED1);
02338     info(0, "PPG: unconfirmed push delivered to OTA");
02339 
02340     return pm;
02341 }
02342 
02343 /*
02344  * Deliver all pushes queued by session machine sm (it is, make a relevant OTA
02345  * request). Update PAP attribute, if push is unconfirmed.
02346  */
02347 static void deliver_pending_pushes(PPGSessionMachine *sm, int last)
02348 {
02349     PPGPushMachine *pm;    
02350     long i;
02351 
02352     session_machine_assert(sm);
02353     gw_assert(gwlist_len(sm->push_machines) > 0);
02354 
02355     i = 0;
02356     while (i < gwlist_len(sm->push_machines)) {
02357         pm = gwlist_get(sm->push_machines, i);
02358         push_machine_assert(pm);
02359 
02360         if (pm->delivery_method == PAP_UNCONFIRMED) {
02361             request_push(last, pm); 
02362             pm = update_push_data_with_attribute(&sm, pm, PAP_UNCONFIRMED, 
02363                  PAP_DELIVERED1);
02364             remove_push_data(sm, pm, sm == NULL);
02365         } else {
02366             request_confirmed_push(last, pm, sm);
02367             ++i;
02368         }
02369     }
02370 }     
02371 
02372 /*
02373  * Abort all pushes queued by session machine sm. In addition, update PAP
02374  * attribute and notify PI.
02375  */
02376 static PPGPushMachine *abort_delivery(PPGSessionMachine *sm, int status)
02377 {
02378     PPGPushMachine *pm;
02379     long reason,
02380          code;
02381 
02382     session_machine_assert(sm);
02383 
02384     pm = NULL;
02385     reason = PAP_ABORT_USERPND;
02386     code = PAP_CAPABILITIES_MISMATCH;
02387     
02388     while (gwlist_len(sm->push_machines) > 0) {
02389         pm = gwlist_get(sm->push_machines, 0);
02390         push_machine_assert(pm);
02391 
02392         pm = update_push_data_with_attribute(&sm, pm, reason, PAP_ABORTED);
02393         response_push_message(pm, code, status);
02394 
02395         remove_push_data(sm, pm, sm == NULL);
02396     }
02397 
02398     return pm;
02399 }
02400 
02401 /*
02402  * Remove a session, even if it have active pushes. These are aborted, and we
02403  * must inform PI about this. Client abort codes are defined in pap, 9.14.5,
02404  * which refers to wsp, Appendix A, table 35.
02405  */
02406 static void remove_session_data(PPGSessionMachine *sm, int status)
02407 {
02408     long code;
02409     PPGPushMachine *pm;
02410 
02411     session_machine_assert(sm);
02412 
02413     code = PAP_ABORT_USERPND;
02414     
02415     while (gwlist_len(sm->push_machines) > 0) {
02416         pm = gwlist_get(sm->push_machines, 0);
02417         response_push_message(pm, code, status);
02418         remove_push_data(sm, pm, sm == NULL);
02419     }
02420 
02421     gwlist_delete_equal(ppg_machines, sm);
02422     session_machine_destroy(sm);
02423 }
02424 
02425 /*
02426  * Remove session, if it has no active pushes.
02427  */
02428 static void remove_pushless_session(PPGSessionMachine *sm)
02429 {
02430     session_machine_assert(sm);
02431 
02432     if (gwlist_len(sm->push_machines) == 0) {
02433         gwlist_delete_equal(ppg_machines, sm);
02434         session_machine_destroy(sm);
02435     }
02436 }
02437 
02438 /*
02439  * If session machine not exist, create a session machine and store session 
02440  * data. If session exists, ignore. 
02441  * Return pointer to the session machine, and a flag did we have a session 
02442  * before executing this function. (Session data is needed to implement the 
02443  * PAP attribute. It does not mean that a session exists.)
02444  */
02445 static PPGSessionMachine *store_session_data(PPGSessionMachine *sm,
02446     WAPEvent *e, WAPAddrTuple *tuple, int *session_exists)
02447 {
02448     gw_assert(e->type == Push_Message);
02449 
02450     if (sm == NULL) {
02451         sm = session_machine_create(tuple, e);
02452         *session_exists = 0;
02453     } else
02454         *session_exists = 1;
02455     
02456     return sm;
02457 }
02458 
02459 static PPGSessionMachine *update_session_data_with_headers(
02460     PPGSessionMachine *sm, PPGPushMachine *pm)
02461 {
02462     gwlist_delete_matching(sm->push_machines, &pm->push_id, push_has_pid);
02463     gwlist_append(sm->push_machines, pm);
02464 
02465     return sm;
02466 }
02467 
02468 /*
02469  * Ppg 6.1.2.2, subchapter delivery, states that if the delivery method is not
02470  * confirmed or unconfirmed, PPG may select an implementation specific type of
02471  * the  primitive. We use an unconfirmed push, if QoS is notspecified, and 
02472  * confirmed one, when it is preferconfirmed (we do support confirmed push).
02473  */
02474 static int confirmation_requested(WAPEvent *e)
02475 {
02476     gw_assert(e->type = Push_Message);
02477 
02478     return e->u.Push_Message.delivery_method == PAP_CONFIRMED || 
02479            e->u.Push_Message.delivery_method == PAP_PREFERCONFIRMED;
02480 }
02481 
02482 static int push_has_pid(void *a, void *b)
02483 {
02484     long *pid;
02485     PPGPushMachine *pm;
02486 
02487     pid = b;
02488     pm = a;
02489     
02490     return *pid == pm->push_id;
02491 }
02492 
02493 static PPGPushMachine *find_ppg_push_machine_using_pid(PPGSessionMachine *sm, 
02494                                                    long pid)
02495 {
02496     PPGPushMachine *pm;
02497 
02498     gw_assert(pid >= 0);
02499     session_machine_assert(sm);
02500 
02501     pm = gwlist_search(sm->push_machines, &pid, push_has_pid);
02502 
02503     return pm;
02504 }
02505 
02506 static int push_has_pi_push_id(void *a, void *b)
02507 {
02508     Octstr *pi_push_id;
02509     PPGPushMachine *pm;
02510 
02511     pi_push_id = b;
02512     pm = a;
02513 
02514     return octstr_compare(pm->pi_push_id, pi_push_id) == 0;
02515 }
02516 
02517 static PPGPushMachine *find_ppg_push_machine_using_pi_push_id(
02518     PPGSessionMachine *sm, Octstr *pi_push_id)
02519 {
02520     PPGPushMachine *pm;
02521 
02522     gw_assert(pi_push_id);
02523     session_machine_assert(sm);
02524 
02525     pm = gwlist_search(sm->push_machines, pi_push_id, push_has_pi_push_id);
02526 
02527     return pm;
02528 }
02529 
02530 static PPGPushMachine *find_unit_ppg_push_machine_using_pi_push_id(
02531     Octstr *pi_push_id)
02532 {
02533     PPGPushMachine *pm;
02534 
02535     gw_assert(pi_push_id);
02536     pm = gwlist_search(ppg_unit_pushes, pi_push_id, push_has_pi_push_id);
02537 
02538     return pm;
02539 }
02540 
02541 /*
02542  * Store a new value of the push attribute into a push machine. It is to be 
02543  * found from the list of unit pushes, if connectionless push was asked 
02544  * (sm == NULL), otherwise from the the push list of the session machine sm. 
02545  * Returns updated push machine and session machine (this one has an updated
02546  * push machines list). 
02547  */
02548 static PPGPushMachine *update_push_data_with_attribute(PPGSessionMachine **sm, 
02549     PPGPushMachine *qm, long reason, long status)
02550 {
02551     push_machine_assert(qm);
02552    
02553     switch (status) {
02554     case PAP_UNDELIVERABLE1:
02555          qm->message_state = PAP_UNDELIVERABLE;
02556          qm->code = PAP_BAD_REQUEST;
02557     break;
02558 
02559     case PAP_UNDELIVERABLE2:
02560         qm->code = reason;
02561         qm->message_state = PAP_UNDELIVERABLE;
02562         qm->desc = describe_code(reason);
02563     break;
02564 
02565     case PAP_ABORTED:
02566         qm->message_state = status;
02567         qm->code = ota_abort_to_pap(reason);
02568         qm->event_time = set_time();
02569         qm->desc = describe_code(reason);
02570     break;
02571 
02572     case PAP_DELIVERED1:
02573         qm->message_state = PAP_DELIVERED;
02574         qm->delivery_method = PAP_UNCONFIRMED;
02575         qm->event_time = set_time();
02576     break;
02577 
02578     case PAP_DELIVERED2:
02579         qm->message_state = PAP_DELIVERED;
02580         qm->delivery_method = PAP_CONFIRMED;
02581         qm->event_time = set_time();
02582     break;
02583 
02584     case PAP_EXPIRED:
02585         qm->message_state = PAP_EXPIRED;
02586         qm->event_time = set_time();
02587         qm->desc = describe_code(reason);
02588     break;
02589 
02590     case PAP_PENDING:
02591         qm->message_state = PAP_PENDING;
02592     break;
02593 
02594     default:
02595         error(0, "WAP_PUSH_PPG: update_push_data_with_attribute: Non"
02596               " existing push machine status: %ld", status);
02597     break;
02598     }
02599 
02600     if (*sm != NULL){
02601         gwlist_delete_matching((**sm).push_machines, &qm->push_id, push_has_pid);
02602         gwlist_append((**sm).push_machines, qm);
02603         gwlist_delete_equal(ppg_machines, *sm);
02604         gwlist_append(ppg_machines, *sm);
02605     } else {
02606         gwlist_delete_matching(ppg_unit_pushes, &qm->push_id, push_has_pid);
02607         gwlist_append(ppg_unit_pushes, qm);
02608     }
02609 
02610     return qm;
02611 }
02612 
02613 /*
02614  * Store session id, client port and caps list received from application layer.
02615  */
02616 static PPGSessionMachine *update_session_data(PPGSessionMachine *m, 
02617                                               long sid, long port, List *caps)
02618 {
02619     session_machine_assert(m);
02620     gw_assert(sid >= 0);
02621 
02622     m->session_id = sid;
02623     m->addr_tuple->remote->port = port;
02624     m->client_capabilities = wsp_cap_duplicate_list(caps);
02625 
02626     gwlist_delete_equal(ppg_machines, m);
02627     gwlist_append(ppg_machines, m);
02628 
02629     return m;
02630 }
02631 
02632 /*
02633  * Convert OTA abort codes (ota 6.3.3) to corresponding PAP status codes. These
02634  * are defined in pap 9.14.5.
02635  */
02636 static long ota_abort_to_pap(long reason)
02637 {
02638     long offset;
02639 
02640     offset = reason - 0xEA;
02641     reason = 5026 + offset;
02642 
02643     return reason;
02644 }
02645 
02646 /*
02647  * Accept connectionless push when PI wants connectionless push and there is 
02648  * no sessions open.
02649  */
02650 static int cless_accepted(WAPEvent *e, PPGSessionMachine *sm)
02651 {
02652     gw_assert(e->type == Push_Message);
02653     return (e->u.Push_Message.delivery_method == PAP_UNCONFIRMED ||
02654            e->u.Push_Message.delivery_method == PAP_NOT_SPECIFIED) &&
02655            (sm == NULL);
02656 }
02657 
02658 /*
02659  * Application ids start with 0 and -1 means that default (wml.ua) was used.
02660  */
02661 static int coriented_deliverable(long appid_code)
02662 {
02663     return appid_code > -1;
02664 }
02665 
02666 /*
02667  * Compare PAP message timestamp, in PAP message format, and stored in octstr,
02668  * to gm (UTC) broken time. Return true, if before is after now, or if the 
02669  * service in question was not requested by PI. PAP time format is defined in 
02670  * pap, chapter 9.2.
02671  */
02672 
02673 static void initialize_time_item_array(long time_data[], struct tm now) 
02674 {
02675     time_data[0] = now.tm_year + 1900;
02676     time_data[1] = now.tm_mon + 1;
02677     time_data[2] = now.tm_mday;
02678     time_data[3] = now.tm_hour;
02679     time_data[4] = now.tm_min;
02680     time_data[5] = now.tm_sec;
02681 }
02682 
02683 static int date_item_compare(Octstr *condition, long time_data, long pos)
02684 {
02685     long data;
02686 
02687     if (octstr_parse_long(&data, condition, pos, 10) < 0) {
02688         return 0;
02689     }
02690     if (data < time_data) {
02691         return -1;
02692     }
02693     if (data > time_data) {
02694         return 1;
02695     }
02696 
02697     return 0;
02698 }
02699 
02700 /*
02701  * We do not accept timestamps equalling now. Return true, if the service was
02702  * not requested.
02703  */
02704 static int deliver_before_test_cleared(Octstr *before, struct tm now)
02705 {  
02706     long time_data[6];
02707     long j;
02708 
02709     if (before == NULL)
02710         return 1;
02711 
02712     initialize_time_item_array(time_data, now);
02713     if (date_item_compare(before, time_data[0], 0) == 1)
02714         return 1;
02715     if (date_item_compare(before, time_data[0], 0) == -1)
02716         return 0;
02717 
02718     for (j = 5; j < octstr_len(before); j += 3) {
02719         if (date_item_compare(before, time_data[(j-5)/3 + 1], j) == 1)
02720             return 1;
02721         if (date_item_compare(before, time_data[(j-5)/3 + 1], j) == -1)
02722             return 0;
02723     }
02724 
02725     return 0;
02726 }
02727 
02728 /* 
02729  * Ditto. Return true, if after is before now (or the service was not request-
02730  * ed). Do not accept timestamps equalling now.
02731  */
02732 static int deliver_after_test_cleared(Octstr *after, struct tm now)
02733 {
02734     long time_data[6];
02735     long j;
02736 
02737     if (after == NULL)
02738         return 1;
02739     
02740     initialize_time_item_array(time_data, now);
02741     if (date_item_compare(after, time_data[0], 0) == -1)
02742         return 1;
02743     if (date_item_compare(after, time_data[0], 0) == 1)
02744         return 0;
02745 
02746     for (j = 5; j < octstr_len(after); j += 3) {
02747         if (date_item_compare(after, time_data[(j-5)/3 + 1], j) == -1)
02748             return 1;
02749         if (date_item_compare(after, time_data[(j-5)/3 + 1], j) == 1)
02750             return 0;
02751     }
02752 
02753     return 0;
02754 }
02755 
02756 /*
02757  * We exchange here server and client addresses and ports, because our WDP,
02758  * written for pull, exchange them, too. Similarly server address INADDR_ANY is
02759  * used for compability reasons, when the bearer is ip. When it is SMS, the
02760  * server address is global-sender.
02761  */
02762 static WAPAddrTuple *set_addr_tuple(Octstr *address, long cliport, long servport, 
02763                                     long address_type, List *push_headers)
02764 {
02765     Octstr *cliaddr;
02766     Octstr *from = NULL;
02767     WAPAddrTuple *tuple;
02768     
02769     gw_assert(address);
02770 
02771     if (address_type == ADDR_PLMN) {
02772         from = http_header_value(push_headers, octstr_imm("X-Kannel-From"));
02773         cliaddr = from ? from : global_sender;
02774     } else {
02775         cliaddr = octstr_imm("0.0.0.0");
02776     }
02777 
02778     tuple = wap_addr_tuple_create(address, cliport, cliaddr, servport);
02779 
02780     octstr_destroy(from);
02781     http_header_remove_all(push_headers, "X-Kannel-From");
02782 
02783     return tuple;
02784 }
02785 
02786 /*
02787  * We are not interested about parsing URI fully - we check only does it cont-
02788  * ain application id reserved by WINA or the part containing assigned code. 
02789  * Otherwise (regardless of it being an URI or assigned code) we simply pass 
02790  * it forward. 
02791  * These are defined by WINA at http://www.openmobilealliance.org/tech/
02792  * omna/omna-push-app-id.htm. We recognize both well-known and registered
02793  * values. X-wap-application is not added, it is considired a default.
02794  */
02795 
02796 static char *wina_uri[] =
02797 {   "*",
02798     "push.sia",
02799     "wml.ua",
02800     "wta.ua", 
02801     "mms.ua", 
02802     "push.syncml", 
02803     "loc.ua",
02804     "syncml.dm",
02805     "drm.ua",
02806     "emn.ua",
02807     "wv.ua",
02808     "x-wap-microsoft:localcontent.ua",
02809     "x-wap-microsoft:IMclient.ua",
02810     "x-wap-docomo:imode.mail.ua",
02811     "x-wap-docomo:imode.mr.ua",
02812     "x-wap-docomo:imode.mf.ua",
02813     "x-motorola:location.ua",
02814     "x-motorola:now.ua",
02815     "x-motorola:otaprov.ua",
02816     "x-motorola:browser.ua",
02817     "x-motorola:splash.ua",
02818     "x-wap-nai:mvsw.command",
02819     "x-wap-openwave:iota.ua",
02820     "x-wap-docomo:imode.mail2.ua",
02821     "x-oma-nec:otaprov.ua",
02822     "x-oma-nokia:call.ua"
02823 };
02824 
02825 #define NUMBER_OF_WINA_URIS sizeof(wina_uri)/sizeof(wina_uri[0])
02826 
02827 /*
02828  * X-Wap-Application-Id header is defined in Push Message, chapter 6.2.2.1.
02829  * First check do we a header with an app-encoding field and a coded value. 
02830  * If not, try to find push application id from table of wina approved values.
02831  * Return coded value value of application id in question, or an error code:
02832  *        -1, no coded value (but defaults may be applied)
02833  *         0, * (meaning any application acceptable)
02834  *         greater or equal as 1: code for this application id 
02835  */
02836 static long parse_appid_header(Octstr **appid_content)
02837 {
02838     long pos,
02839          coded_value;
02840     size_t i;
02841 
02842     if ((pos = octstr_search(*appid_content, octstr_imm(";"), 0)) >= 0) {
02843         octstr_delete(*appid_content, pos, 
02844                       octstr_len(octstr_imm(";app-encoding=")));
02845         octstr_delete(*appid_content, 0, pos);         /* the URI part */
02846         return -1;
02847     } 
02848 
02849     i = 0;
02850     while (i < NUMBER_OF_WINA_URIS) {
02851         if ((pos = octstr_case_search(*appid_content, 
02852                 octstr_imm(wina_uri[i]), 0)) >= 0)
02853             break;
02854         ++i;
02855     }
02856 
02857     if (i == NUMBER_OF_WINA_URIS) {
02858         octstr_destroy(*appid_content);
02859         *appid_content = octstr_format("%ld", 2);      /* assigned number */
02860         return -1;                                     /* for wml ua */
02861     }
02862     
02863     octstr_delete(*appid_content, 0, pos);             /* again the URI */
02864     if ((coded_value = wsp_string_to_application_id(*appid_content)) >= 0) {
02865         octstr_destroy(*appid_content);
02866         *appid_content = octstr_format("%ld", coded_value);
02867         return coded_value;
02868     }
02869 
02870     return -1;
02871 }
02872 
02873 static WAPAddrTuple *addr_tuple_change_cliport(WAPAddrTuple *tuple, long port)
02874 {
02875     WAPAddrTuple *dubble;
02876 
02877     if (tuple == NULL)
02878         return NULL;
02879 
02880     dubble = wap_addr_tuple_create(tuple->remote->address,
02881                                    port,
02882                                    tuple->local->address,
02883                                    tuple->local->port);
02884 
02885     return dubble;
02886 }
02887 
02888 /*
02889  * Pi uses multipart/related content type when communicating with ppg. (see 
02890  * pap, Chapter 8) and subtype application/xml.
02891  * Check if push headers are acceptable according this rule. In addition, 
02892  * return the field value of Content-Type header, if any and error string if
02893  * none (this string is used by send_bad_message_response).
02894  */
02895 static int headers_acceptable(List *push_headers, Octstr **content_header)
02896 {
02897     gw_assert(push_headers);
02898     *content_header = http_header_find_first(push_headers, "Content-Type");
02899 
02900     if (*content_header == NULL) {
02901         *content_header = octstr_format("%s", "no content type header found");
02902         goto error;
02903     }
02904     
02905     if (!type_is(*content_header, "multipart/related")) {
02906         goto error;
02907     }
02908 
02909     if (!type_is(*content_header, "application/xml")) {
02910         goto error;
02911     }
02912 
02913     return 1;
02914 
02915 error:
02916     warning(0, "PPG: headers_acceptable: got unacceptable push headers");
02917     return 0;
02918 }
02919 
02920 /*
02921  * Content-Type header field is defined in rfc 1521, chapter 4. We are looking
02922  * after type multipart/related or "multipart/related" and parameter 
02923  * type=application/xml or type="application/xml", as required by pap, chapter
02924  * 8.
02925  */
02926 static int type_is(Octstr *content_header, char *name)
02927 {
02928     Octstr *quoted_type,
02929            *osname;
02930 
02931     osname = octstr_imm(name);
02932     if (octstr_case_search(content_header, osname, 0) >= 0)
02933         return 1;
02934 
02935     quoted_type = octstr_format("\"%S\"", osname);
02936 
02937     if (octstr_case_search(content_header, quoted_type, 0) >= 0) {
02938         octstr_destroy(quoted_type);
02939         return 1;
02940     }
02941 
02942     octstr_destroy(quoted_type);
02943     return 0;
02944 }
02945 
02946 /*
02947  * Again looking after a parameter, this time of type boundary=XXX or boundary=
02948  * "XXX".
02949  */
02950 static int get_mime_boundary(List *push_headers, Octstr *content_header, 
02951                              Octstr **boundary)
02952 {
02953     long pos;
02954     Octstr *bos;
02955     int c, quoted = 0;
02956     long bstart;
02957 
02958     pos = 0;
02959     if ((pos = octstr_case_search(content_header, 
02960                                   bos = octstr_imm("boundary="), 0)) < 0) {
02961         warning(0, "PPG: get_mime_boundary: no boundary specified");
02962         return -1;
02963     }
02964 
02965     pos += octstr_len(bos);
02966     if (octstr_get_char(content_header, pos) == '"') {
02967         ++pos;
02968         quoted = 1;
02969     }
02970     
02971     bstart = pos;
02972     while ((c = octstr_get_char(content_header, pos)) != -1) {
02973         if (c == ';' || (quoted && c == '"') || (!quoted && c == ' '))
02974              break;
02975         ++pos;
02976     }
02977     *boundary = octstr_copy(content_header, bstart, pos - bstart);
02978 
02979     return 0;
02980 }
02981 
02982 static void change_header_value(List **push_headers, char *name, char *value)
02983 {
02984     http_header_remove_all(*push_headers, name);
02985     http_header_add(*push_headers, name, value);
02986 }
02987 
02988 /*
02989  * Some application level protocols may use MIME headers. This may cause problems
02990  * to them. (MIME version is a mandatory header).
02991  */
02992 static void remove_mime_headers(List **push_headers)
02993 {
02994     http_header_remove_all(*push_headers, "MIME-Version");
02995 }
02996 
02997 /*
02998  * There are headers used only for HTTP POST pi->ppg. (For debugging, mainly.)
02999  */
03000 static void remove_link_headers(List **push_headers)
03001 {
03002     http_header_remove_all(*push_headers, "Host");
03003 }
03004 
03005 /*
03006  * X-Kannel headers are used to control Kannel ppg.
03007  */
03008 static void remove_x_kannel_headers(List **push_headers)
03009 {
03010     http_header_remove_all(*push_headers, "X-Kannel-SMSC");
03011     http_header_remove_all(*push_headers, "X-Kannel-DLR-Url");
03012     http_header_remove_all(*push_headers, "X-Kannel-DLR-Mask");
03013     http_header_remove_all(*push_headers, "X-Kannel-Smsbox-Id");
03014 }
03015 
03016 /*
03017  * Badmessage-response element is redefined in pap, implementation note, 
03018  * chapter 5. Do not add to the document a fragment being NULL or empty.
03019  * Return current status of HTTPClient.
03020  */
03021 static void send_bad_message_response(HTTPClient **c, Octstr *fragment, 
03022                                       int code, int status)
03023 {
03024     Octstr *reply_body;
03025 
03026     reply_body = octstr_format("%s", 
03027         "<?xml version=\"1.0\"?>"
03028         "<!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP 1.0//EN\""
03029                    " \"http://www.wapforum.org/DTD/pap_1.0.dtd\">"
03030         "<pap>"
03031              "<badmessage-response code=\"");
03032     octstr_format_append(reply_body, "%d", code);
03033     octstr_format_append(reply_body, "%s", "\""
03034                   " desc=\"");
03035     octstr_format_append(reply_body, "%s", "Not understood due to malformed"
03036                                            " syntax");
03037     octstr_format_append(reply_body, "%s", "\"");
03038 
03039     if (fragment != NULL && octstr_len(fragment) != 0) {
03040         octstr_format_append(reply_body, "%s", " bad-message-fragment=\"");
03041         octstr_format_append(reply_body, "%S", escape_fragment(fragment));
03042         octstr_format_append(reply_body, "%s", "\"");
03043     }
03044 
03045     octstr_format_append(reply_body, "%s", ">"
03046               "</badmessage-response>"
03047          "</pap>");
03048 
03049     debug("wap.push.ppg", 0, "PPG: send_bad_message_response: telling pi");
03050     send_to_pi(c, reply_body, status);
03051 
03052     octstr_destroy(fragment);
03053 }
03054 
03055 /*
03056  * Push response is defined in pap, chapter 9.3. Mapping between push ids and
03057  * http clients is done by using http_clients. We remove (push id, http client)
03058  * pair from the dictionary after the mapping has been done.
03059  * Return current status of HTTPClient.
03060  */
03061 static HTTPClient *send_push_response(WAPEvent *e, int status)
03062 {
03063     Octstr *reply_body,
03064            *url;
03065     HTTPClient *c;
03066 
03067     gw_assert(e->type == Push_Response);
03068     url = dict_get(urls, e->u.Push_Response.pi_push_id);
03069     dict_remove(urls, e->u.Push_Response.pi_push_id);
03070 
03071     reply_body = octstr_format("%s", 
03072         "<?xml version=\"1.0\"?>"
03073         "<!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP 1.0//EN\""
03074                    " \"http://www.wapforum.org/DTD/pap_1.0.dtd\">"
03075         "<pap>"
03076              "<push-response push-id=\"");
03077     octstr_format_append(reply_body, "%S", e->u.Push_Response.pi_push_id);
03078     octstr_format_append(reply_body, "%s", "\""); 
03079 
03080     if (e->u.Push_Response.sender_name != NULL) {
03081         octstr_format_append(reply_body, "%s",
03082                    " sender-name=\"");
03083         octstr_format_append(reply_body, "%S", 
03084             e->u.Push_Response.sender_name);
03085         octstr_format_append(reply_body, "%s", "\"");
03086     }
03087 
03088     if (e->u.Push_Response.reply_time != NULL) {
03089         octstr_format_append(reply_body, "%s",
03090                    " reply-time=\"");
03091         octstr_format_append(reply_body, "%S", 
03092             e->u.Push_Response.reply_time);
03093         octstr_format_append(reply_body, "%s", "\"");
03094     }
03095 
03096     if (url != NULL) {
03097         octstr_format_append(reply_body, "%s",
03098                    " sender-address=\"");
03099         octstr_format_append(reply_body, "%S", url);
03100         octstr_format_append(reply_body, "%s", "\"");
03101     }
03102 
03103     octstr_format_append(reply_body, "%s", ">"
03104              "<response-result code =\"");
03105     octstr_format_append(reply_body, "%d", e->u.Push_Response.code);
03106     octstr_format_append(reply_body, "%s", "\"");
03107 
03108     if (e->u.Push_Response.desc != NULL) {
03109         octstr_format_append(reply_body, "%s", " desc=\"");
03110         octstr_format_append(reply_body, "%S", e->u.Push_Response.desc);
03111         octstr_format_append(reply_body, "\"");
03112     }
03113     
03114     octstr_format_append(reply_body, "%s", ">"
03115               "</response-result>"
03116               "</push-response>"
03117           "</pap>");
03118 
03119     octstr_destroy(url);
03120 
03121     c = dict_get(http_clients, e->u.Push_Response.pi_push_id);
03122     dict_remove(http_clients, e->u.Push_Response.pi_push_id);
03123 
03124     debug("wap.push.ppg", 0, "PPG: send_push_response: telling pi");
03125     send_to_pi(&c, reply_body, status);
03126 
03127     wap_event_destroy(e);
03128     return c;
03129 }
03130 
03131 /*
03132  * Ppg notifies pi about duplicate push id by sending a push response document
03133  * to it. Note that we never put the push id to the dict in this case.
03134  * Return current c value.
03135  */
03136 static void tell_fatal_error(HTTPClient **c, WAPEvent *e, Octstr *url, 
03137                              int status, int code)
03138 {
03139     Octstr *reply_body,
03140            *dos,                      /* temporaries */
03141            *tos,
03142            *sos;
03143 
03144     gw_assert(e->type == Push_Message);
03145     reply_body = octstr_format("%s", 
03146         "<?xml version=\"1.0\"?>"
03147         "<!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP 1.0//EN\""
03148                    " \"http://www.wapforum.org/DTD/pap_1.0.dtd\">"
03149         "<pap>"
03150              "<push-response push-id=\"");
03151     octstr_format_append(reply_body, "%S", e->u.Push_Message.pi_push_id);
03152     octstr_format_append(reply_body, "%s", "\""); 
03153 
03154     octstr_format_append(reply_body, "%s",
03155                    " sender-name=\"");
03156     octstr_format_append(reply_body, "%S", tos = tell_ppg_name());
03157     octstr_format_append(reply_body, "%s", "\"");
03158 
03159     octstr_format_append(reply_body, "%s",
03160                    " reply-time=\"");
03161     octstr_format_append(reply_body, "%S", sos = set_time());
03162     octstr_format_append(reply_body, "%s", "\"");
03163 
03164     octstr_format_append(reply_body, "%s",
03165                    " sender-address=\"");
03166     octstr_format_append(reply_body, "%S", url);
03167     octstr_format_append(reply_body, "%s", "\"");
03168 
03169     octstr_format_append(reply_body, "%s", ">"
03170              "<response-result code =\"");
03171     octstr_format_append(reply_body, "%d", code);
03172     octstr_format_append(reply_body, "%s", "\"");
03173 
03174     octstr_format_append(reply_body, "%s", " desc=\"");
03175     octstr_format_append(reply_body, "%S", dos = describe_code(code));
03176     octstr_format_append(reply_body, "\"");
03177 
03178     octstr_format_append(reply_body, "%s", ">"
03179               "</response-result>"
03180               "</push-response>"
03181          "</pap>");
03182 
03183     debug("wap.push.ppg", 0, "PPG: tell_fatal_error: %s", octstr_get_cstr(dos));
03184     send_to_pi(c, reply_body, status);
03185 
03186     octstr_destroy(dos);
03187     octstr_destroy(tos);
03188     octstr_destroy(sos);
03189     wap_event_destroy(e);
03190 }
03191 
03192 /*
03193  * Does the HTTP reply to pi. Test has HTTPClient disappeared.
03194  * Return current c value.
03195  */
03196 static void send_to_pi(HTTPClient **c, Octstr *reply_body, int status) {
03197     List *reply_headers;
03198 
03199     reply_headers = http_create_empty_headers();
03200     http_header_add(reply_headers, "Content-Type", "application/xml");
03201 
03202     if (*c != NULL)
03203         http_send_reply(*c, status, reply_headers, reply_body);
03204 
03205     octstr_destroy(reply_body);
03206     http_destroy_headers(reply_headers);
03207 }
03208 
03209 /*
03210  * Escape characters not allowed in the value of an attribute. Pap does not 
03211  * define escape sequences for message fragments; try common xml ones.
03212  */
03213 
03214 static Octstr *escape_fragment(Octstr *fragment)
03215 {
03216     long i;
03217     int c;
03218 
03219     i = 0;
03220     while (i < octstr_len(fragment)) {
03221         if ((c = octstr_get_char(fragment, i)) == '"') {
03222             replace_octstr_char(fragment, octstr_imm("&quot;"), &i);
03223         } else if (c == '<') {
03224             replace_octstr_char(fragment, octstr_imm("&lt;"), &i);
03225         } else if (c == '>') {
03226             replace_octstr_char(fragment, octstr_imm("&gt;"), &i);
03227         } else if (c == '&') {
03228             replace_octstr_char(fragment, octstr_imm("&amp;"), &i);
03229         }
03230         ++i;
03231     }
03232 
03233     return fragment;
03234 }
03235 
03236 static int is_phone_number(long address_type)
03237 {
03238     return address_type == ADDR_PLMN;
03239 }
03240 
03241 static void replace_octstr_char(Octstr *os1, Octstr *os2, long *pos)
03242 {
03243     octstr_delete(os1, *pos, 1);
03244     octstr_insert(os1, os2, *pos);
03245     *pos += octstr_len(os2) - 1;
03246 }
03247 
03248 /* 
03249  * Check if we have an explicit routing information 
03250  *       a) first check x-kannel header
03251  *       b) then ppg user specific routing (if there is any groups; we have none,
03252  *          if pi is trusted)
03253  *       c) then global ppg routing
03254  *       d) if all these failed, return NULL
03255  */
03256 static Octstr *set_smsc_id(List *headers, Octstr *username, int trusted_pi)
03257 {
03258     Octstr *smsc_id = NULL;
03259 
03260     smsc_id = http_header_value(headers, octstr_imm("X-Kannel-SMSC"));
03261     if (smsc_id) {
03262         return smsc_id;
03263     }
03264 
03265     if (!trusted_pi)
03266         smsc_id = wap_push_ppg_pushuser_smsc_id_get(username);
03267 
03268     smsc_id = smsc_id ? 
03269         smsc_id : (ppg_default_smsc ? octstr_duplicate(ppg_default_smsc) : NULL);
03270 
03271     return smsc_id;
03272 }
03273 
03274 /* 
03275  * Checking for dlr url, using  following order:
03276  *       a) first check X-Kannel header  
03277  *       b) then ppg user specific dlr url (if there is any user group; if pi is
03278  *          trusted, there are none.)
03279  *       c) then global ppg dlr url
03280  *       d) if all these failed, return NULL
03281  */
03282 static Octstr *set_dlr_url(List *headers, Octstr *username, int trusted_pi)
03283 {
03284     Octstr *dlr_url = NULL;
03285 
03286     dlr_url = http_header_value(headers, octstr_imm("X-Kannel-DLR-Url"));
03287     if (dlr_url) {
03288         return dlr_url;
03289     }
03290 
03291     if (!trusted_pi)
03292         dlr_url = wap_push_ppg_pushuser_dlr_url_get(username);
03293 
03294     dlr_url = dlr_url ?
03295         dlr_url : (ppg_dlr_url ? octstr_duplicate(ppg_dlr_url) : NULL);
03296 
03297     return dlr_url;
03298 }
03299 
03300 /* 
03301  * Checking for dlr mask. Mask without dlr url is of course useless.
03302  * We reject (some) non-meaningfull values of dlr_mask. Value indic-
03303  * ating rejection is 0.
03304  */
03305 static long set_dlr_mask(List *headers, Octstr *dlr_url)
03306 {
03307     Octstr *dlrmaskos;
03308     long dlr_mask;
03309     long masklen;    
03310 
03311     if (dlr_url == NULL) {
03312         return 0; 
03313     }
03314 
03315     dlrmaskos = http_header_value(headers, octstr_imm("X-Kannel-DLR-Mask"));
03316     if (dlrmaskos == NULL) { 
03317         return 0;
03318     }
03319 
03320     if ((masklen = octstr_parse_long(&dlr_mask, dlrmaskos, 0, 10)) != -1 &&
03321              masklen == octstr_len(dlrmaskos) &&
03322              dlr_mask >= -1 && dlr_mask <= 31) {
03323          octstr_destroy(dlrmaskos);
03324          return dlr_mask;
03325     }
03326 
03327     warning(0, "unparsable dlr mask, rejected");
03328     octstr_destroy(dlrmaskos);
03329     return 0;
03330 }
03331 
03332 /*
03333  * Checking for dlr smsbox id, using  following order:
03334  *       a) first check X-Kannel header
03335  *       b) then ppg user specific smsbox id, if there is any group; if pi
03336  *          is trusted, there are none
03337  *       c) then global ppg smsbox id
03338  *       d) if all these failed, return NULL
03339  */
03340 
03341 static Octstr *set_smsbox_id(List *headers, Octstr *username, int trusted_pi)
03342 {
03343     Octstr *smsbox_id = NULL;
03344 
03345     smsbox_id = http_header_value(headers, octstr_imm("X-Kannel-Smsbox-Id"));
03346     if (smsbox_id != NULL) {
03347         return smsbox_id;
03348     }
03349 
03350     if (!trusted_pi)
03351         smsbox_id = wap_push_ppg_pushuser_smsbox_id_get(username);
03352 
03353     smsbox_id = smsbox_id ?
03354         smsbox_id : (ppg_smsbox_id ? octstr_duplicate(ppg_smsbox_id) : NULL);
03355 
03356     return smsbox_id;
03357 
03358 }
03359 
03360 /*
03361  * Service is ppg core group only configuration variable
03362  */ 
03363 static Octstr *set_service_name(void)
03364 {
03365     return octstr_duplicate(service_name);
03366 }
03367 
03368 
03369 
03370 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.