Kannel: Open Source WAP and SMS gateway  svn-r5335
wap_push_ppg.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * wap_push_ppg.c: General logic of a push proxy gateway.
59  *
60  * This module implements following WAP Forum specifications:
61  * WAP-151-PPGService-19990816-a (called afterwards PPG),
62  * WAP-164-PAP-19991108-a (PAP),
63  * WAP-164_100-PAP-20000218-a (PAP implementation note).
64  *
65  * We refer following WAP Forum specifications:
66  * WAP-145-PushMessage-19990816-a (push message)
67  * WAP-200-WDP-20001212-a (WDP)
68  * WAP-203-WSP-20000504-a (WSP)
69  * WAP-189-PushOTA-20000217-a (OTA).
70  *
71  * In addition, RFCs 1521 and 2045 are referred.
72  *
73  * By Aarno Syv�nen for Wapit Ltd, Wiral Ltd and Global Networks Inc.
74  */
75 
76 #include <time.h>
77 #include <ctype.h>
78 
79 #include "wap_push_ppg.h"
80 #include "wap/wap_events.h"
81 #include "wap/wsp_caps.h"
82 #include "wml_compiler.h"
83 #include "wap-appl.h"
84 #include "wap/wsp.h"
85 #include "wap/wsp_strings.h"
86 #include "wap_push_si_compiler.h"
87 #include "wap_push_sl_compiler.h"
88 #include "wap_push_pap_compiler.h"
89 #include "wap_push_pap_mime.h"
90 #include "wap_push_ppg_pushuser.h"
91 
92 enum {
96 };
97 
98 /*
99  * Default values for configuration variables
100  */
101 enum {
109 };
110 
112 
113 #define DEFAULT_PPG_URL "/wappush"
114 
115 /*****************************************************************************
116  *
117  * Internal data structures
118  *
119  * Give the status of the push ppg module:
120  *
121  * limbo
122  * not running at all
123  * running
124  * operating normally
125  * terminating
126  * waiting for operations to terminate, returning to limbo
127  */
129 
130 /*
131  * The external event queue for this module
132  */
133 static List *ppg_queue = NULL;
134 
135 /*
136  * The internal event queue for this module (allowing listening of many ports)
137  */
138 static List *pap_queue = NULL;
139 
140 /*
141  * List of ppg session machines (it is, of currently active sessions)
142  */
143 static List *ppg_machines = NULL;
144 
145 /*
146  * List of currently active unit pushes (we need a threadsafe storage for them,
147  * because pushes can be cancelled and queried):
148  */
149 static List *ppg_unit_pushes = NULL;
150 
151 /*
152  * Counter to store our internal push id.
153  */
154 static Counter *push_id_counter = NULL;
155 
156 /*
157  * We need a mapping between HTTPClient structures, used by http library, and
158  * push ids, used by ppg.
159  */
160 static Dict *http_clients = NULL;
161 
162 /*
163  * Mapping between urls used by pi and push ids used by ppg.
164  */
165 static Dict *urls = NULL;
166 
167 /*
168  * Push content packed for compilers (wml, si, sl, co).
169  */
170 struct content {
171  Octstr *body;
172  Octstr *type;
173  Octstr *charset;
174 };
175 
178 
179 /*
180  * Configurable variables of ppg core group (for general configuration of a
181  * ppg), with some default values.
182  */
183 
184 static Octstr *ppg_url = NULL ;
186 
187 #ifdef HAVE_LIBSSL
188 static long ppg_ssl_port = NO_HTTPS_PORT;
189 #endif
190 
192 static int trusted_pi = PI_TRUSTED;
194 static Octstr *ppg_deny_ip = NULL;
195 static Octstr *ppg_allow_ip = NULL;
197 static Octstr *global_sender = NULL;
198 static Octstr *ppg_default_smsc = NULL;
199 #ifdef HAVE_LIBSSL
200 static Octstr *ssl_server_cert_file = NULL;
201 static Octstr *ssl_server_key_file = NULL;
202 #endif
203 static Octstr *ppg_dlr_url = NULL;
204 static Octstr *ppg_smsbox_id = NULL;
205 static Octstr *service_name = NULL;
206 
207 struct PAPEvent {
214 };
215 
216 typedef struct PAPEvent PAPEvent;
217 
218 
219 /*****************************************************************************
220  *
221  * Prototypes of internal functions
222  *
223  * Event handling
224  */
225 static void ota_read_thread(void *arg);
226 static void http_read_thread(void *arg);
227 
228 #ifdef HAVE_LIBSSL
229 static void https_read_thread(void *arg);
230 #endif
231 
232 static void handle_internal_event(WAPEvent *e);
233 static void pap_request_thread(void *arg);
234 static int handle_push_message(HTTPClient **c, WAPEvent *ppg_event, int status);
237  HTTPClient *client);
238 static void pap_event_destroy(PAPEvent *p);
239 static void pap_event_destroy_item(void *p);
240 static void pap_event_unpack(PAPEvent *p, Octstr **ip, Octstr **url,
243 
244 /*
245  * Constructors and destructors for machines.
246  */
248  WAPEvent *e);
249 static void session_machine_destroy(void *p);
251  WAPAddrTuple *tuple);
252 static void push_machine_destroy(void *pm);
253 static void push_machines_list_destroy(List *pl);
254 
255 /*
256  * Communicating other modules (ota and appl)
257  */
258 static void create_session(WAPEvent *e, PPGPushMachine *pm);
259 static void request_confirmed_push(long last, PPGPushMachine *pm,
260  PPGSessionMachine *sm);
261 static void request_unit_push(long last, PPGPushMachine *pm);
262 static void request_push(long last, PPGPushMachine *sm);
265  int status);
266 
267 /*
268  * Functions to find machines using various identifiers, and related help
269  * functions.
270  */
273  long pid);
275  PPGSessionMachine *sm, Octstr *pi_push_id);
277  Octstr *pi_push_id);
278 static int push_has_pi_push_id(void *a, void *b);
279 static int push_has_pid(void *a, void *b);
280 static int session_has_pi_client_address(void *a, void *b);
281 static int session_has_addr(void *a, void *b);
282 static int session_has_sid(void *a, void *b);
283 
284 /*
285  * Main logic of PPG.
286  */
287 static int check_capabilities(List *requested, List *assumed);
288 static int transform_message(WAPEvent **e, WAPAddrTuple **tuple,
289  List *push_headers, int connected, Octstr **type);
291 static int pap_convert_content(struct content *content);
292 static int pap_get_content(struct content *content);
293 static int select_bearer_network(WAPEvent **e);
295 static void deliver_confirmed_push(long last, PPGPushMachine *pm,
296  PPGSessionMachine *sm);
297 static PPGPushMachine *deliver_unit_push(long last, PPGPushMachine *pm,
298  PPGSessionMachine *sm, int session_exists);
299 static int store_push_data(PPGPushMachine **pm, PPGSessionMachine *sm,
300  WAPEvent *e, WAPAddrTuple *tuple, int cless);
302  PPGPushMachine *pm, long reason, long status);
304  int cless);
305 static void remove_session_data(PPGSessionMachine *sm, int status);
308  WAPEvent *e, WAPAddrTuple *tuple, int *session_exists);
311 static void deliver_pending_pushes(PPGSessionMachine *sm, int last);
314  long port, List *caps);
315 static int confirmation_requested(WAPEvent *e);
316 static int cless_accepted(WAPEvent *e, PPGSessionMachine *sm);
317 
318 /*
319  * Header functions
320  */
322 static int type_is(Octstr *content_header, char *required_type);
324  Octstr **boundary);
325 static void change_header_value(List **push_headers, char *name, char *value);
326 static void remove_mime_headers(List **push_headers);
327 static void remove_link_headers(List **push_headers);
329 
330 /*
331  * Communicating with pi.
332  */
333 static void send_bad_message_response(HTTPClient **c, Octstr *body_fragment,
334  int code, int status);
336 static void send_to_pi(HTTPClient **c, Octstr *reply_body, int status);
337 static void tell_fatal_error(HTTPClient **c, WAPEvent *e, Octstr *url,
338  int status, int code);
339 
340 /*
341  * PPG core authentication (not related to any particular user).
342  */
343 static int read_ppg_config(Cfg *cfg);
344 static int ip_allowed_by_ppg(Octstr *ip);
345 
346 /*
347  * Interface to various compilers
348  */
349 static Octstr *convert_wml_to_wmlc(struct content *content);
350 static Octstr *convert_si_to_sic(struct content *content);
351 static Octstr *convert_sl_to_slc(struct content *content);
352 
353 /*
354  * Setting values for controlling sms level. (Pap control document enables
355  * some control, but not enough.)
356  */
357 
358 static Octstr *set_smsc_id(List *headers, Octstr *username, int trusted_pi);
359 static Octstr *set_dlr_url(List *headers, Octstr *username, int trusted_pi);
360 static long set_dlr_mask(List *headers, Octstr *dlr_url);
361 static Octstr *set_smsbox_id(List *headers, Octstr *username, int trusted_pi);
362 static Octstr *set_service_name(void);
363 
364 /*
365  * Various utility functions
366  */
367 static Octstr *set_time(void);
368 static int deliver_before_test_cleared(Octstr *before, struct tm now);
369 static int deliver_after_test_cleared(Octstr *after, struct tm now);
371 static void push_machine_assert(PPGPushMachine *pm);
372 static Octstr *tell_ppg_name(void);
373 static Octstr *describe_code(long code);
374 static long ota_abort_to_pap(long reason);
376 static WAPAddrTuple *set_addr_tuple(Octstr *address, long cliport, long servport,
379 static void initialize_time_item_array(long time_data[], struct tm now);
380 static int date_item_compare(Octstr *before, long time_data, long pos);
381 static long parse_appid_header(Octstr **assigned_code);
382 static Octstr *escape_fragment(Octstr *fragment);
383 static int coriented_deliverable(long code);
384 static int is_phone_number(long type_of_address);
385 static void replace_octstr_char(Octstr *os1, Octstr *os2, long *pos);
386 
387 /*****************************************************************************
388  *
389  * EXTERNAL FUNCTIONS
390  */
391 
392 enum {
395 };
396 
398  wap_dispatch_func_t *appl_dispatch, Cfg *cfg)
399 {
409 
410  dispatch_to_ota = ota_dispatch;
411  dispatch_to_appl = appl_dispatch;
412 
414 #ifdef HAVE_LIBSSL
415  if (ppg_ssl_port != NO_HTTPS_PORT)
416  http_open_port(ppg_ssl_port, TYPE_HTTPS);
417 #endif
420 
425 #ifdef HAVE_LIBSSL
426  if (ppg_ssl_port != NO_HTTPS_PORT)
427  gwthread_create(https_read_thread, NULL);
428 #endif
430  }
431 }
432 
434 {
441  ppg_url = NULL;
453 
455 #ifdef HAVE_LIBSSL
456  if (ppg_ssl_port != NO_HTTPS_PORT)
457  gwthread_join_every(https_read_thread);
458 #endif
461 
465 
466  debug("wap.push.ppg", 0, "PPG: %ld push session machines left.",
469 
470  debug("wap_push_ppg", 0, "PPG: %ld unit pushes left",
473  }
474 }
475 
477 {
480 }
481 
482 /*
483  * We cannot know port the client is using when it establish the connection.
484  * However, we must link session creation with a pending push request. Only
485  * data available is the client address, so we check it here.
486  * Return non-NULL (pointer to the session machine found), if we have one.
487  */
489 {
490  PPGSessionMachine *sm;
491 
492  gw_assert(tuple);
494 
495  return sm;
496 }
497 
498 /*
499  * Now initiators are identified by their session id. Return non-NULL (pointer
500  * to the session machine found), if we have one. This function are used after
501  * wsp has indicated session establishment, giving us a session id.
502  */
504 {
505  PPGSessionMachine *sm;
506 
507  gw_assert(sid >= 0);
509 
510  return sm;
511 }
512 
513 /*****************************************************************************
514  *
515  * INTERNAL FUNCTIONS
516  *
517  * Read general ppg configuration and configuration specific for users (to the
518  * list 'users').
519  * Return 1 when an user ppg group is present, 0 otherwise (and panic
520  * if we have not trusted ppg and no user groups).
521  */
522 
523 static int read_ppg_config(Cfg *cfg)
524 {
525  CfgGroup *grp;
526  List *list;
527 
528  if (cfg == NULL)
530 
531  grp = cfg_get_single_group(cfg, octstr_imm("ppg"));
532  if ((ppg_url = cfg_get(grp, octstr_imm("ppg-url"))) == NULL)
533  ppg_url = octstr_imm("/wappush");
534  cfg_get_integer(&ppg_port, grp, octstr_imm("ppg-port"));
535  cfg_get_integer(&number_of_pushes, grp, octstr_imm("concurrent-pushes"));
536  cfg_get_bool(&trusted_pi, grp, octstr_imm("trusted-pi"));
537  cfg_get_integer(&number_of_users, grp, octstr_imm("users"));
538  ppg_deny_ip = cfg_get(grp, octstr_imm("ppg-deny-ip"));
539  ppg_allow_ip = cfg_get(grp, octstr_imm("ppg-allow-ip"));
540  if ((global_sender = cfg_get(grp, octstr_imm("global-sender"))) == NULL)
541  global_sender = octstr_format("%s", "1234");
542  ppg_default_smsc = cfg_get(grp, octstr_imm("default-smsc"));
543  ppg_dlr_url = cfg_get(grp, octstr_imm("default-dlr-url"));
544  ppg_smsbox_id = cfg_get(grp, octstr_imm("ppg-smsbox-id"));
545  if ((service_name = cfg_get(grp, octstr_imm("service-name"))) == NULL)
546  service_name = octstr_format("%s", "ppg");
547 
548 #ifdef HAVE_LIBSSL
549  cfg_get_integer(&ppg_ssl_port, grp, octstr_imm("ppg-ssl-port"));
550  ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file"));
551  ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file"));
552  if (ppg_ssl_port != NO_HTTPS_PORT) {
553  if (ssl_server_cert_file == NULL || ssl_server_key_file == NULL)
554  panic(0, "cannot continue without server cert and/or key files");
555  conn_use_global_server_certkey_file(ssl_server_cert_file, ssl_server_key_file);
556  }
557  octstr_destroy(ssl_server_cert_file);
558  octstr_destroy(ssl_server_key_file);
559 #endif
560 
561  /* If pi is trusted, ignore possible user groups. */
562  if (trusted_pi) {
563  cfg_destroy(cfg);
565  }
566 
567  /* But if it is not, we cannot continue without user groups.*/
568  if ((list = cfg_get_multi_group(cfg, octstr_imm("wap-push-user")))
569  == NULL) {
570  panic(0, "No user group but ppg not trusted, stopping");
571  gwlist_destroy(list, NULL);
572  cfg_destroy(cfg);
574  }
575 
577  number_of_users)) {
578  panic(0, "unable to create users configuration list, exiting");
580  }
581 
582  cfg_destroy(cfg);
584 }
585 
587 {
588  if (ip == NULL)
589  return 0;
590 
591  if (trusted_pi)
592  return 1;
593 
594  if (ppg_deny_ip == NULL && ppg_allow_ip == NULL) {
595  warning(0, "Your ppg core configuration lacks allowed and denied"
596  " ip lists");
597  return 1;
598  }
599 
600  if (ppg_deny_ip)
601  if (octstr_compare(ppg_deny_ip, octstr_imm("*.*.*.*")) == 0) {
602  panic(0, "Your ppg core configuration deny all ips, exiting");
603  return 0;
604  }
605 
606  if (ppg_allow_ip)
607  if (octstr_compare(ppg_allow_ip, octstr_imm("*.*.*.*")) == 0) {
608  warning(0, "Your ppg core configuration allow all ips");
609  return 1;
610  }
611 
612  if (ppg_deny_ip)
614  octstr_imm(";"), octstr_imm("."))) {
615  error(0, "ip found from denied list");
616  return 0;
617  }
618 
619  if (ppg_allow_ip)
621  octstr_imm(";"), octstr_imm("."))) {
622  debug("wap.push.ppg.pushuser", 0, "PPG: ip_allowed_by_ppg: ip found"
623  " from allowed list");
624  return 1;
625  }
626 
627  warning(0, "did not found ip from any of core lists, deny it");
628  return 0;
629 }
630 
631 /*
632  * Event handling functions
633  */
634 static void ota_read_thread (void *arg)
635 {
636  WAPEvent *e;
637 
638  while (run_status == running && (e = gwlist_consume(ppg_queue)) != NULL) {
640  }
641 }
642 
643 /*
644  * Pap event functions handle only copy pointers. They do not allocate memory.
645  */
649 {
650  PAPEvent *p;
651 
652  p = gw_malloc(sizeof(PAPEvent));
653  p->ip = ip;
654  p->url = url;
657  p->cgivars = cgivars;
658  p->client = client;
659 
660  return p;
661 }
662 
664 {
665  if (p == NULL)
666  return;
667 
668  gw_free(p);
669 }
670 
671 static void pap_event_destroy_item(void *p)
672 {
674 }
675 
676 static void pap_event_unpack(PAPEvent *p, Octstr **ip, Octstr **url,
679 {
680  *ip = p->ip;
681  *url = p->url;
684  *cgivars = p->cgivars;
685  *client = p->client;
686 }
687 
688 static void http_read_thread(void *arg)
689 {
690  PAPEvent *p;
691  Octstr *ip;
692  Octstr *url;
695  List *cgivars;
697 
698  while (run_status == running) {
700  &mime_content, &cgivars);
701  if (client == NULL)
702  break;
703 
705  client);
707  }
708 }
709 
710 #ifdef HAVE_LIBSSL
711 static void https_read_thread(void *arg)
712 {
713  PAPEvent *p;
714  Octstr *ip;
715  Octstr *url;
718  List *cgivars;
720 
721  while (run_status == running) {
722  client = http_accept_request(ppg_ssl_port, &ip, &url, &push_headers,
723  &mime_content, &cgivars);
724  if (client == NULL)
725  break;
726 
728  client);
730  }
731 }
732 #endif
733 
734 /*
735  * Authorization failure as such causes a challenge to the client (as required
736  * by rfc 2617, chapter 1).
737  * We store HTTPClient data structure corresponding a given push id, so that
738  * we can send responses to the rigth address.
739  * Pap chapter 14.4.1 states that we must return http status 202 after we have
740  * accepted PAP message, even if it is unparsable. So only the non-existing
741  * service error and some authorisation failures are handled at HTTP level.
742  * When a phone number was unacceptable, we return a PAP level error, because
743  * we cannot know this error before parsing the document.
744  */
745 
746 static void pap_request_thread(void *arg)
747 {
748  WAPEvent *ppg_event;
749  PAPEvent *p;
750  size_t push_len;
751  Octstr *pap_content = NULL;
752  Octstr *push_data = NULL;
753  Octstr *rdf_content = NULL;
754  Octstr *mime_content = NULL;
755  Octstr *plos = NULL; /* a temporary variable*/
756  Octstr *boundary = NULL;
757  Octstr *content_header = NULL; /* Content-Type MIME header */
758  Octstr *url = NULL;
759  Octstr *ip = NULL;
760  Octstr *not_found = NULL;
761  Octstr *username = NULL;
762  int compiler_status,
763  http_status;
764  List *push_headers, /* MIME headers themselves */
765  *content_headers, /* Headers from the content entity, see
766  pap chapters 8.2, 13.1. Rfc 2045
767  grammar calls these MIME-part-hea-
768  ders */
769  *cgivars;
771  Octstr *dlr_url;
772 
773  http_status = 0;
774  url = ip = mime_content = username = NULL;
775 
776  while (run_status == running && (p = gwlist_consume(pap_queue)) != NULL) {
777 
778  http_status = HTTP_NOT_FOUND;
780  &cgivars, &client);
781 
782  if (octstr_compare(url, ppg_url) != 0) {
783  error(0, "Request <%s> from <%s>: service not found",
785  debug("wap.push.ppg", 0, "your configuration uses %s",
787  not_found = octstr_imm("Service not specified\n");
788  http_send_reply(client, http_status, push_headers, not_found);
789  goto ferror;
790  }
791 
792  http_status = HTTP_UNAUTHORIZED;
793 
794  if (!ip_allowed_by_ppg(ip)) {
795  error(0, "Request <%s> from <%s>: ip forbidden, closing the"
796  " client", octstr_get_cstr(url), octstr_get_cstr(ip));
798  goto ferror;
799  }
800 
801  if (!trusted_pi && user_configuration) {
803  push_headers, &username)) {
804  error(0, "Request <%s> from <%s>: authorisation failure",
806  goto ferror;
807  }
808  } else { /* J�rg, this wont disappear again */
809  username = octstr_imm("");
810  }
811 
812  http_status = HTTP_ACCEPTED;
813  info(0, "PPG: Accept request <%s> from <%s>", octstr_get_cstr(url),
815 
816  if (octstr_len(mime_content) == 0) {
817  warning(0, "PPG: No MIME content received, the request"
818  " unacceptable");
819  send_bad_message_response(&client, octstr_imm("No MIME content"),
820  PAP_BAD_REQUEST, http_status);
821  if (client == NULL)
822  break;
823  goto ferror;
824  }
825 
826  if (!push_headers) {
827  warning(0, "PPG: No push headers received , the request"
828  " unacceptable");
829  send_bad_message_response(&client, octstr_imm("No push headers"),
830  PAP_BAD_REQUEST, http_status);
831  if (client == NULL)
832  break;
833  goto ferror;
834  }
836 
840 
842  warning(0, "PPG: Unparsable push headers, the request"
843  " unacceptable");
845  http_status);
846  if (client == NULL)
847  break;
848  goto herror;
849  }
850 
852  warning(0, "PPG: No MIME boundary, the request unacceptable");
854  http_status);
855  if (client == NULL)
856  break;
857  goto berror;
858  }
859 
861  if (!mime_parse(boundary, mime_content, &pap_content, &push_data,
862  &content_headers, &rdf_content)) {
864  http_status);
865  if (client == NULL)
866  break;
867  warning(0, "PPG: unable to parse mime content, the request"
868  " unacceptable");
869  goto clean;
870  } else {
871  debug("wap.push.ppg", 0, "PPG: http_read_thread: pap multipart"
872  " accepted");
873  }
874 
875  push_len = octstr_len(push_data);
876  http_header_remove_all(push_headers, "Content-Type");
877  http_append_headers(push_headers, content_headers);
878  change_header_value(&push_headers, "Content-Length",
879  octstr_get_cstr(plos = octstr_format("%d", push_len)));
880  octstr_destroy(plos);
882  http_destroy_headers(content_headers);
883 
884  ppg_event = NULL;
885  if ((compiler_status = pap_compile(pap_content, &ppg_event)) == -2) {
887  http_status);
888  if (client == NULL)
889  break;
890  warning(0, "PPG: pap control entity erroneous, the request"
891  " unacceptable");
892  goto no_compile;
893  } else if (compiler_status == -1) {
895  http_status);
896  if (client == NULL)
897  break;
898  warning(0, "PPG: non implemented pap feature requested, the"
899  " request unacceptable");
900  goto no_compile;
901  } else {
903  ppg_event->u.Push_Message.pi_push_id, client)) {
904  warning(0, "PPG: duplicate push id, the request unacceptable");
905  tell_fatal_error(&client, ppg_event, url, http_status,
907  if (client == NULL)
908  break;
909  goto not_acceptable;
910  }
911 
912  dict_put(urls, ppg_event->u.Push_Message.pi_push_id, url);
913 
914  if (is_phone_number(ppg_event->u.Push_Message.address_type)) {
915  if (!trusted_pi && user_configuration &&
917  username, ppg_event->u.Push_Message.address_value)) {
918  tell_fatal_error(&client, ppg_event, url, http_status,
919  PAP_FORBIDDEN);
920  if (client == NULL)
921  break;
922  goto not_acceptable;
923  }
924  }
925 
926  debug("wap.push.ppg", 0, "PPG: http_read_thread: pap control"
927  " entity compiled ok");
928  ppg_event->u.Push_Message.push_data = octstr_duplicate(push_data);
929  ppg_event->u.Push_Message.smsc_id = set_smsc_id(push_headers, username,
930  trusted_pi);
932  ppg_event->u.Push_Message.dlr_url = dlr_url;
933  ppg_event->u.Push_Message.dlr_mask = set_dlr_mask(push_headers, dlr_url);
934  ppg_event->u.Push_Message.smsbox_id = set_smsbox_id(push_headers, username,
935  trusted_pi);
936  ppg_event->u.Push_Message.service_name = set_service_name();
938  ppg_event->u.Push_Message.push_headers = http_header_duplicate(push_headers);
939 
940  if (!handle_push_message(&client, ppg_event, http_status)) {
941  if (client == NULL)
942  break;
943  goto no_transform;
944  }
945  }
946 
952  octstr_destroy(pap_content);
954  octstr_destroy(rdf_content);
956  boundary = rdf_content = push_data = pap_content = mime_content = username = NULL;
957  continue;
958 
959 no_transform:
965  octstr_destroy(pap_content);
967  octstr_destroy(rdf_content);
969  boundary = rdf_content = push_data = pap_content = mime_content = username = NULL;
970  continue;
971 
972 no_compile:
979  octstr_destroy(rdf_content);
982  url = boundary = rdf_content = push_data = mime_content = username = NULL;
983  continue;
984 
985 not_acceptable:
991  octstr_destroy(pap_content);
993  octstr_destroy(rdf_content);
996  url = boundary = rdf_content = push_data = pap_content = mime_content = username = NULL;
997  continue;
998 
999 clean:
1000  pap_event_destroy(p);
1002  http_destroy_headers(content_headers);
1003  octstr_destroy(pap_content);
1005  octstr_destroy(rdf_content);
1009  url = boundary = content_header = rdf_content = push_data = pap_content = NULL;
1010  continue;
1011 
1012 ferror:
1013  pap_event_destroy(p);
1018  octstr_destroy(ip);
1020  mime_content = ip = url = username = NULL;
1021  continue;
1022 
1023 herror:
1024  pap_event_destroy(p);
1029  url = username = NULL;
1030  continue;
1031 
1032 berror:
1033  pap_event_destroy(p);
1042  continue;
1043  }
1044 }
1045 
1046 /*
1047  * Operations needed when push proxy gateway receives a new push message are
1048  * defined in ppg Chapter 6. We create machines when error, too, because we
1049  * must then have a reportable message error state.
1050  * Output: current HTTP Client state.
1051  * Return 1 if the push content was OK, 0 if it was not transformable.
1052  */
1053 
1055 {
1056  int cless,
1057  session_exists,
1058  bearer_supported,
1059  dummy,
1060  constraints,
1061  message_transformable,
1062  coriented_possible;
1063 
1064  long coded_appid_value;
1065 
1066  PPGPushMachine *pm;
1067  PPGSessionMachine *sm;
1068  WAPAddrTuple *tuple=NULL;
1069  Octstr *cliaddr=NULL;
1070  Octstr *type=NULL;
1071 
1072  List *push_headers;
1073 
1074  push_headers = e->u.Push_Message.push_headers;
1075  cliaddr = e->u.Push_Message.address_value;
1076  session_exists = 0;
1077 
1079  coded_appid_value = check_x_wap_application_id_header(&push_headers);
1080  cless = cless_accepted(e, sm);
1081  message_transformable = transform_message(&e, &tuple, push_headers, cless,
1082  &type);
1083 
1084  if (!sm && !cless) {
1085  sm = store_session_data(sm, e, tuple, &session_exists);
1086  }
1087 
1088  if (!store_push_data(&pm, sm, e, tuple, cless)) {
1089  warning(0, "PPG: handle_push_message: duplicate push id");
1091  goto no_start;
1092  }
1093 
1094  if (!message_transformable) {
1095  pm = update_push_data_with_attribute(&sm, pm,
1097  if (tuple != NULL)
1099  else
1101  goto no_transformation;
1102  }
1103 
1104  dummy = 0;
1105  pm = update_push_data_with_attribute(&sm, pm, dummy, PAP_PENDING);
1106 
1107  bearer_supported = select_bearer_network(&e);
1108  if (!bearer_supported) {
1109  pm = update_push_data_with_attribute(&sm, pm, dummy,
1112  goto no_start;
1113  }
1114 
1115  if ((constraints = delivery_time_constraints(e, pm)) == TIME_EXPIRED) {
1117  PAP_EXPIRED);
1119  goto no_start;
1120  }
1121 
1122 /*
1123  * If time is to early for delivering the push message, we do not remove push
1124  * data. We response PI here, so that "accepted for processing" means "no
1125  * error messages to come".
1126  */
1127 
1129  info(0, "PPG: handle_push_message: push message accepted for processing");
1130 
1131  if (constraints == TIME_TOO_EARLY)
1132  goto store_push;
1133 
1134  if (constraints == NO_CONSTRAINTS) {
1135  http_header_mark_transformation(pm->push_headers, pm->push_data, type);
1136  if (sm)
1137  sm = update_session_data_with_headers(sm, pm);
1138 
1139  if (!confirmation_requested(e)) {
1140  pm = deliver_unit_push(NOT_LAST, pm, sm, session_exists);
1141  goto unit_push_delivered;
1142  }
1143 
1144  if (session_exists) {
1145  deliver_confirmed_push(NOT_LAST, pm, sm);
1146  } else {
1147  coriented_possible = coriented_deliverable(coded_appid_value);
1148  http_header_remove_all(e->u.Push_Message.push_headers,
1149  "Content-Type");
1150  if (coriented_possible) {
1151  create_session(e, pm);
1152  } else {
1153  warning(0, "PPG: handle_push_message: wrong app id for confirmed"
1154  " push session creation");
1156  }
1157  }
1158  }
1159 
1160  wap_addr_tuple_destroy(tuple);
1162  wap_event_destroy(e);
1163  return 1;
1164 
1165 unit_push_delivered:
1166  wap_addr_tuple_destroy(tuple);
1167  remove_push_data(sm, pm, cless);
1169  wap_event_destroy(e);
1170  return 1;
1171 
1172 store_push:
1173  wap_addr_tuple_destroy(tuple);
1175  wap_event_destroy(e);
1176  return 1;
1177 
1178 no_transformation:
1179  wap_addr_tuple_destroy(tuple);
1180  remove_push_data(sm, pm, cless);
1181  if (sm)
1183  wap_event_destroy(e);
1184  return 0;
1185 
1186 no_start:
1187  wap_addr_tuple_destroy(tuple);
1189  remove_push_data(sm, pm, cless);
1190  if (sm)
1192  wap_event_destroy(e);
1193  return 1;
1194 }
1195 
1196 /*
1197  * These events come from OTA layer
1198  */
1200 {
1201  long sid,
1202  pid,
1203  reason,
1204  port;
1205  int http_status;
1206  PPGPushMachine *pm;
1207  PPGSessionMachine *sm;
1208  WAPAddrTuple *tuple;
1209  List *caps;
1210 
1211  http_status = HTTP_OK;
1212  switch (e->type) {
1213 /*
1214  * Pap, Chapter 11.1.3 states that if client is incapable, we should abort the
1215  * push and inform PI. We do this here.
1216  * In addition, we store session id used as an alias for address tuple and do
1217  * all pushes pending for this initiator (or abort them).
1218  */
1219  case Pom_Connect_Ind:
1220  debug("wap.push.ppg", 0, "PPG: handle_internal_event: connect"
1221  " indication from OTA");
1222  sid = e->u.Pom_Connect_Ind.session_id;
1223  tuple = e->u.Pom_Connect_Ind.addr_tuple;
1224  port = tuple->remote->port;
1225  caps = e->u.Pom_Connect_Ind.requested_capabilities;
1226 
1228  sm = update_session_data(sm, sid, port, caps);
1229 
1230  if (!response_push_connection(e, sm)) {
1231  pm = abort_delivery(sm, http_status);
1232  wap_event_destroy(e);
1233  return;
1234  }
1235 
1236 /*
1237  * hard-coded until we have bearer control implemented
1238  */
1240  wap_event_destroy(e);
1241  break;
1242 
1243  case Pom_Disconnect_Ind:
1244  debug("wap.push.ppg", 0, "PPG: handle_internal_event: disconnect"
1245  " indication from OTA");
1247  e->u.Pom_Disconnect_Ind.session_handle);
1248  remove_session_data(sm, http_status);
1249  wap_event_destroy(e);
1250  break;
1251 
1252 /*
1253  * Only the client can close a session. So we leave session open, even when
1254  * there are no active pushes. Note that we do not store PAP attribute very
1255  * long time. Point is that result notification message, if asked, will rep-
1256  * ort this fact to PI, after which there is no need to store it any more.
1257  */
1258  case Po_ConfirmedPush_Cnf:
1259  debug("wap.push.ppg", 0, "PPG: handle_internal_event: push"
1260  " confirmation from OTA");
1261  sid = e->u.Po_ConfirmedPush_Cnf.session_handle;
1262  pid = e->u.Po_ConfirmedPush_Cnf.server_push_id;
1263 
1265  pm = find_ppg_push_machine_using_pid(sm, pid);
1267  PAP_DELIVERED2);
1268  wap_event_destroy(e);
1269  remove_push_data(sm, pm, 0);
1270  break;
1271 
1272 /*
1273  * Again, PAP attribute will be reported to PI by using result notification.
1274  */
1275  case Po_PushAbort_Ind:
1276  debug("wap.push.ppg", 0, "PPG: handle_internal_event: abort"
1277  " indication from OTA");
1278  sid = e->u.Po_PushAbort_Ind.session_handle;
1279  pid = e->u.Po_PushAbort_Ind.push_id;
1280 
1282  pm = find_ppg_push_machine_using_pid(sm, pid);
1284  push_machine_assert(pm);
1285  reason = e->u.Po_PushAbort_Ind.reason;
1286  pm = update_push_data_with_attribute(&sm, pm, reason, PAP_ABORTED);
1287  remove_session_data(sm, http_status);
1288  wap_event_destroy(e);
1289  break;
1290 
1291 /*
1292  * FIXME TRU: Add timeout (a mandatory feature!)
1293  */
1294  default:
1295  debug("wap.ppg", 0, "PPG: handle_internal_event: an unhandled event");
1296  wap_event_dump(e);
1297  wap_event_destroy(e);
1298  break;
1299  }
1300 }
1301 
1302 /*
1303  * Functions related to various ppg machine types.
1304  *
1305  * We do not set session id here: it is told to us by wsp.
1306  */
1308  WAPEvent *e)
1309 {
1310  PPGSessionMachine *m;
1311 
1312  gw_assert(e->type == Push_Message);
1313 
1314  m = gw_malloc(sizeof(PPGSessionMachine));
1315 
1316  #define INTEGER(name) m->name = 0;
1317  #define OCTSTR(name) m->name = NULL;
1318  #define ADDRTUPLE(name) m->name = NULL;
1319  #define PUSHMACHINES(name) m->name = gwlist_create();
1320  #define CAPABILITIES(name) m->name = NULL;
1321  #define MACHINE(fields) fields
1322  #include "wap_ppg_session_machine.def"
1323 
1324  m->pi_client_address = octstr_duplicate(e->u.Push_Message.address_value);
1325  m->addr_tuple = wap_addr_tuple_duplicate(tuple);
1326  m->assumed_capabilities =
1327  wsp_cap_duplicate_list(e->u.Push_Message.pi_capabilities);
1328  m->preferconfirmed_value = PAP_CONFIRMED;
1329 
1331  debug("wap.push.ppg", 0, "PPG: Created PPGSessionMachine %ld",
1332  m->session_id);
1333 
1334  return m;
1335 }
1336 
1337 static void session_machine_destroy(void *p)
1338 {
1339  PPGSessionMachine *sm;
1340 
1341  if (p == NULL)
1342  return;
1343 
1344  sm = p;
1345  debug("wap.push.ppg", 0, "PPG: destroying PPGSEssionMachine %ld",
1346  sm->session_id);
1347 
1348  #define OCTSTR(name) octstr_destroy(sm->name);
1349  #define ADDRTUPLE(name) wap_addr_tuple_destroy(sm->name);
1350  #define INTEGER(name) sm->name = 0;
1351  #define PUSHMACHINES(name) push_machines_list_destroy(sm->name);
1352  #define CAPABILITIES(name) wsp_cap_destroy_list(sm->name);
1353  #define MACHINE(fields) fields
1354  #include "wap_ppg_session_machine.def"
1355  gw_free(sm);
1356 }
1357 
1358 /*
1359  * FIXME: PPG's trust policy (flags authenticated and trusted).
1360  * We return pointer to the created push machine and push id it uses.
1361  */
1363 {
1364  PPGPushMachine *m;
1365 
1366  m = gw_malloc(sizeof(PPGPushMachine));
1367 
1368  #define INTEGER(name) m->name = 0;
1369  #define OCTSTR(name) m->name = NULL;
1370  #define OPTIONAL_OCTSTR(name) m->name = NULL;
1371  #define ADDRTUPLE(name) m->name = NULL;
1372  #define CAPABILITIES m->name = NULL;
1373  #define HTTPHEADER(name) m->name = NULL;
1374  #define MACHINE(fields) fields
1375  #include "wap_ppg_push_machine.def"
1376 
1377  m->addr_tuple = wap_addr_tuple_duplicate(tuple);
1378  m->pi_push_id = octstr_duplicate(e->u.Push_Message.pi_push_id);
1379  m->push_id = counter_increase(push_id_counter);
1380  m->delivery_method = e->u.Push_Message.delivery_method;
1381  m->deliver_after_timestamp =
1382  octstr_duplicate(e->u.Push_Message.deliver_after_timestamp);
1383  m->priority = e->u.Push_Message.priority;
1384  m->push_headers = http_header_duplicate(e->u.Push_Message.push_headers);
1385  m->push_data = octstr_duplicate(e->u.Push_Message.push_data);
1386 
1387  m->address_type = e->u.Push_Message.address_type;
1388  if (e->u.Push_Message.smsc_id != NULL)
1389  m->smsc_id = octstr_duplicate(e->u.Push_Message.smsc_id);
1390  else
1391  m->smsc_id = NULL;
1392  if (e->u.Push_Message.dlr_url != NULL)
1393  m->dlr_url = octstr_duplicate(e->u.Push_Message.dlr_url);
1394  else
1395  m->dlr_url = NULL;
1396  m->dlr_mask = e->u.Push_Message.dlr_mask;
1397  if (e->u.Push_Message.smsbox_id != NULL)
1398  m->smsbox_id = octstr_duplicate(e->u.Push_Message.smsbox_id);
1399  else
1400  m->smsbox_id = NULL;
1401  m->service_name = octstr_duplicate(e->u.Push_Message.service_name);
1402 
1403  m->progress_notes_requested = e->u.Push_Message.progress_notes_requested;
1404  if (e->u.Push_Message.progress_notes_requested)
1405  m->ppg_notify_requested_to =
1406  octstr_duplicate(e->u.Push_Message.ppg_notify_requested_to);
1407 
1408  debug("wap.push.ppg", 0, "PPG: push machine %ld created", m->push_id);
1409 
1410  return m;
1411 }
1412 
1413 /*
1414  * Contrary to the normal Kannel style, we do not remove from a list here.
1415  * That is because we now have two different push lists.
1416  */
1417 static void push_machine_destroy(void *p)
1418 {
1419  PPGPushMachine *pm;
1420 
1421  if (p == NULL)
1422  return;
1423 
1424  pm = p;
1425 
1426  debug("wap.push.ppg", 0, "PPG: destroying push machine %ld",
1427  pm->push_id);
1428  #define OCTSTR(name) octstr_destroy(pm->name);
1429  #define OPTIONAL_OCTSTR(name) octstr_destroy(pm->name);
1430  #define INTEGER(name)
1431  #define ADDRTUPLE(name) wap_addr_tuple_destroy(pm->name);
1432  #define CAPABILITIES(name) wap_cap_destroy_list(pm->name);
1433  #define HTTPHEADER(name) http_destroy_headers(pm->name);
1434  #define MACHINE(fields) fields
1435  #include "wap_ppg_push_machine.def"
1436 
1437  gw_free(p);
1438 }
1439 
1440 static void push_machines_list_destroy(List *machines)
1441 {
1442  if (machines == NULL)
1443  return;
1444 
1446 }
1447 
1448 static int session_has_addr(void *a, void *b)
1449 {
1450  Octstr *cliaddr;
1451  PPGSessionMachine *sm;
1452 
1453  cliaddr = b;
1454  sm = a;
1455 
1456  return octstr_compare(sm->addr_tuple->remote->address, cliaddr) == 0;
1457 }
1458 
1459 static int session_has_sid(void *a, void *b)
1460 {
1461  PPGSessionMachine *sm;
1462  long *sid;
1463 
1464  sid = b;
1465  sm = a;
1466 
1467  return *sid == sm->session_id;
1468 }
1469 
1470 /*
1471  * Here session machine address tuples have connection-oriented ports, because
1472  * these are used when establishing the connection an doing pushes. But session
1473  * creation request must be to the the connectionless push port of the client.
1474  * So we change ports here.
1475  */
1477 {
1478  WAPEvent *ota_event;
1479  List *push_headers;
1480  Octstr *smsc_id;
1481  Octstr *dlr_url;
1482  Octstr *smsbox_id;
1484 
1485  gw_assert(e->type == Push_Message);
1486  push_machine_assert(pm);
1487 
1488  push_headers = http_header_duplicate(e->u.Push_Message.push_headers);
1489  smsc_id = octstr_duplicate(e->u.Push_Message.smsc_id);
1490  dlr_url = octstr_duplicate(e->u.Push_Message.dlr_url);
1491  smsbox_id = octstr_duplicate(e->u.Push_Message.smsbox_id);
1492  service_name = octstr_duplicate(e->u.Push_Message.service_name);
1493 
1494  ota_event = wap_event_create(Pom_SessionRequest_Req);
1495  ota_event->u.Pom_SessionRequest_Req.addr_tuple =
1496  addr_tuple_change_cliport(pm->addr_tuple,
1498  ota_event->u.Pom_SessionRequest_Req.push_headers = push_headers;
1499  ota_event->u.Pom_SessionRequest_Req.push_id = pm->push_id;
1500  ota_event->u.Pom_SessionRequest_Req.address_type = pm->address_type;
1501  if (smsc_id != NULL)
1502  ota_event->u.Pom_SessionRequest_Req.smsc_id = smsc_id;
1503  else
1504  ota_event->u.Pom_SessionRequest_Req.smsc_id = NULL;
1505  if (dlr_url != NULL)
1506  ota_event->u.Pom_SessionRequest_Req.dlr_url = dlr_url;
1507  else
1508  ota_event->u.Pom_SessionRequest_Req.dlr_url = NULL;
1509  ota_event->u.Pom_SessionRequest_Req.dlr_mask = e->u.Push_Message.dlr_mask;
1510  if (smsbox_id != NULL)
1511  ota_event->u.Pom_SessionRequest_Req.smsbox_id = smsbox_id;
1512  else
1513  ota_event->u.Pom_SessionRequest_Req.smsbox_id = NULL;
1514  ota_event->u.Pom_SessionRequest_Req.service_name = service_name;
1515 
1516  dispatch_to_ota(ota_event);
1517 }
1518 
1519 /*
1520  * We store data to push machine, because it is possible that we do not have
1521  * a session when push request happens.
1522  */
1523 static void request_confirmed_push(long last, PPGPushMachine *pm,
1524  PPGSessionMachine *sm)
1525 {
1526  WAPEvent *ota_event;
1527  List *push_headers;
1528 
1529  gw_assert(last == 0 || last == 1);
1530  push_machine_assert(pm);
1532 
1533  push_headers = http_header_duplicate(pm->push_headers);
1534 
1535  ota_event = wap_event_create(Po_ConfirmedPush_Req);
1536  ota_event->u.Po_ConfirmedPush_Req.server_push_id = pm->push_id;
1537  ota_event->u.Po_ConfirmedPush_Req.push_headers = push_headers;
1538  ota_event->u.Po_ConfirmedPush_Req.authenticated = pm->authenticated;
1539  ota_event->u.Po_ConfirmedPush_Req.trusted = pm->trusted;
1540  ota_event->u.Po_ConfirmedPush_Req.last = last;
1541 
1542  if (pm->push_data != NULL)
1543  ota_event->u.Po_ConfirmedPush_Req.push_body =
1544  octstr_duplicate(pm->push_data);
1545  else
1546  ota_event->u.Po_ConfirmedPush_Req.push_body = NULL;
1547 
1548  ota_event->u.Po_ConfirmedPush_Req.session_handle = sm->session_id;
1549  debug("wap.push.ota", 0, "PPG: confirmed push request to OTA");
1550 
1551  dispatch_to_ota(ota_event);
1552 }
1553 
1554 /*
1555  * There is to types of unit push requests: requesting ip services and sms
1556  * services. Address type tells the difference.
1557  */
1558 static void request_unit_push(long last, PPGPushMachine *pm)
1559 {
1560  WAPEvent *ota_event;
1561  List *push_headers;
1562 
1563  gw_assert(last == 0 || last == 1);
1564  push_machine_assert(pm);
1565 
1566  push_headers = http_header_duplicate(pm->push_headers);
1567 
1568  ota_event = wap_event_create(Po_Unit_Push_Req);
1569  ota_event->u.Po_Unit_Push_Req.addr_tuple =
1570  wap_addr_tuple_duplicate(pm->addr_tuple);
1571  ota_event->u.Po_Unit_Push_Req.push_id = pm->push_id;
1572  ota_event->u.Po_Unit_Push_Req.push_headers = push_headers;
1573  ota_event->u.Po_Unit_Push_Req.authenticated = pm->authenticated;
1574  ota_event->u.Po_Unit_Push_Req.trusted = pm->trusted;
1575  ota_event->u.Po_Unit_Push_Req.last = last;
1576 
1577  ota_event->u.Po_Unit_Push_Req.address_type = pm->address_type;
1578  if (pm->smsc_id != NULL)
1579  ota_event->u.Po_Unit_Push_Req.smsc_id = octstr_duplicate(pm->smsc_id);
1580  else
1581  ota_event->u.Po_Unit_Push_Req.smsc_id = NULL;
1582  if (pm->dlr_url != NULL)
1583  ota_event->u.Po_Unit_Push_Req.dlr_url = octstr_duplicate(pm->dlr_url);
1584  else
1585  ota_event->u.Po_Unit_Push_Req.dlr_url = NULL;
1586  ota_event->u.Po_Unit_Push_Req.dlr_mask = pm->dlr_mask;
1587  if (pm->smsbox_id != NULL)
1588  ota_event->u.Po_Unit_Push_Req.smsbox_id = octstr_duplicate(pm->smsbox_id);
1589  else
1590  ota_event->u.Po_Unit_Push_Req.smsbox_id = NULL;
1591  if (pm->service_name != NULL)
1592  ota_event->u.Po_Unit_Push_Req.service_name = octstr_duplicate(pm->service_name);
1593 
1594  ota_event->u.Po_Unit_Push_Req.push_body = octstr_duplicate(pm->push_data);
1595 
1596  dispatch_to_ota(ota_event);
1597  debug("wap.push.ppg", 0, "PPG: OTA request for unit push");
1598 }
1599 
1600 static void request_push(long last, PPGPushMachine *pm)
1601 {
1602  WAPEvent *ota_event;
1603  List *push_headers;
1604 
1605  gw_assert(last == 0 || last == 1);
1606  push_machine_assert(pm);
1607 
1608  push_headers = http_header_duplicate(pm->push_headers);
1609 
1610  ota_event = wap_event_create(Po_Push_Req);
1611  ota_event->u.Po_Push_Req.push_headers = push_headers;
1612  ota_event->u.Po_Push_Req.authenticated = pm->authenticated;
1613  ota_event->u.Po_Push_Req.trusted = pm->trusted;
1614  ota_event->u.Po_Push_Req.last = last;
1615 
1616  if (pm->push_data != NULL)
1617  ota_event->u.Po_Push_Req.push_body =
1618  octstr_duplicate(pm->push_data);
1619  else
1620  ota_event->u.Po_Push_Req.push_body = NULL;
1621 
1622  ota_event->u.Po_Push_Req.session_handle = pm->session_id;
1623  debug("wap.push.ppg", 0, "PPG: OTA request for push");
1624 
1625  dispatch_to_ota(ota_event);
1626 }
1627 
1628 
1629 /*
1630  * According to pap, Chapter 11, capabilities can be
1631  *
1632  * a) queried by PI
1633  * b) told to PI when a client is subscribing
1634  * c) assumed
1635  *
1636  * In case c) we got capabilities from third part of the push message (other
1637  * cases PI knows what it is doing), and we check is the client capable to
1638  * handle the message.
1639  * Requested capabilities are client capabilities, assumed capabilities are
1640  * PI capabilities. If there is no assumed capabilities, PI knows client capab-
1641  * ilities by method a) or method b).
1642  * Returns 1, if the client is capable, 0 when it is not.
1643  */
1644 
1646 {
1647  WAPEvent *appl_event;
1648 
1649  gw_assert(e->type == Pom_Connect_Ind);
1650 
1651  if (sm->assumed_capabilities != NULL && check_capabilities(
1652  e->u.Pom_Connect_Ind.requested_capabilities,
1653  sm->assumed_capabilities) == 0)
1654  return 0;
1655 
1656  appl_event = wap_event_create(Pom_Connect_Res);
1657  appl_event->u.Pom_Connect_Res.negotiated_capabilities =
1658  wsp_cap_duplicate_list(e->u.Pom_Connect_Ind.requested_capabilities);
1659  appl_event->u.Pom_Connect_Res.session_id = e->u.Pom_Connect_Ind.session_id;
1660 
1661  dispatch_to_appl(appl_event);
1662 
1663  return 1;
1664 }
1665 
1666 /*
1667  * Push response, from pap, Chapter 9.3.
1668  * Inputs error code, in PAP format.
1669  * Return the current value of HTTPClient.
1670  */
1672 {
1673  WAPEvent *e;
1674  HTTPClient *c;
1675 
1676  push_machine_assert(pm);
1677 
1678  e = wap_event_create(Push_Response);
1679  e->u.Push_Response.pi_push_id = octstr_duplicate(pm->pi_push_id);
1680  e->u.Push_Response.sender_name = tell_ppg_name();
1681  e->u.Push_Response.reply_time = set_time();
1682  e->u.Push_Response.code = code;
1683  e->u.Push_Response.desc = describe_code(code);
1684 
1685  c = send_push_response(e, status);
1686 
1687  return c;
1688 }
1689 
1690 
1691 static int check_capabilities(List *requested, List *assumed)
1692 {
1693  int is_capable;
1694 
1695  is_capable = 1;
1696 
1697  return is_capable;
1698 }
1699 
1700 /*
1701  * Time of creation of the response (pap, chapter 9.3). We convert UNIX time
1702  * to ISO8601, it is, YYYY-MM-DDThh:mm:ssZ, T and Z being literal strings (we
1703  * use gw_gmtime to turn UNIX time to broken time).
1704  */
1705 static Octstr *set_time(void)
1706 {
1707  Octstr *current_time;
1708  struct tm now;
1709 
1710  now = gw_gmtime(time(NULL));
1711  current_time = octstr_format("%04d-%02d-%02dT%02d:%02d:%02dZ",
1712  now.tm_year + 1900, now.tm_mon + 1,
1713  now.tm_mday, now.tm_hour, now.tm_min,
1714  now.tm_sec);
1715 
1716  return current_time;
1717 }
1718 
1720 {
1721  gw_assert(sm);
1722  gw_assert(sm->session_id >= 0);
1723  gw_assert(sm->addr_tuple);
1724  gw_assert(sm->pi_client_address);
1725 }
1726 
1728 {
1729  gw_assert(pm);
1730  gw_assert(pm->pi_push_id);
1731  gw_assert(pm->push_id >= 0);
1732  gw_assert(pm->session_id >= 0);
1733  gw_assert(pm->addr_tuple);
1734  gw_assert(pm->trusted == 1 || pm->trusted == 0);
1735  gw_assert(pm->authenticated == 1 || pm->authenticated == 0);
1736 }
1737 
1738 /*
1739  * Message transformations performed by PPG are defined in ppg, 6.1.2.1. Ppg,
1740  * chapter 6.1.1, states that we MUST reject a push having an erroneous PAP
1741  * push message element. So we must validate it even when we do not compile
1742  * it.
1743  * If message content was not si or sl, we pass it without modifications.
1744  * We do not do any (formally optional, but phones may disagree) header
1745  * conversions to the binary format here, these are responsibility of our OTA
1746  * module (gw/wap_push_ota.c).
1747  * FIXME: Remove all headers which default values are known to the client.
1748  *
1749  * Return
1750  * a) message, either transformed or not (if there is no-transform cache
1751  * directive, wml code is erroneous or content was not si or sl.)
1752  * b) The transformed gw address. Use here global-sender, when the bearer
1753  * is SMS (some SMS centers would require this).
1754  * c) the transformed message content type
1755  *
1756  * Returned flag tells was the transformation (if any) successful or not. Error
1757  * flag is returned when there is no push headers, there is no Content-Type header
1758  * or push content does not compile. We should have checked existence of push
1759  * headers earlier, but let us be careful.
1760  */
1761 static int transform_message(WAPEvent **e, WAPAddrTuple **tuple,
1762  List *push_headers, int cless_accepted, Octstr **type)
1763 {
1764  int message_deliverable;
1765  struct content content;
1766  Octstr *cliaddr;
1767  long cliport,
1768  servport,
1769  address_type;
1770 
1771  gw_assert((**e).type == Push_Message);
1772  if ((**e).u.Push_Message.push_headers == NULL)
1773  goto herror;
1774 
1775  cliaddr = (**e).u.Push_Message.address_value;
1776  push_headers = (**e).u.Push_Message.push_headers;
1777 
1778  if (!cless_accepted) {
1779  cliport = CONNECTED_CLIPORT;
1780  servport = CONNECTED_SERVPORT;
1781  } else {
1782  cliport = CONNECTIONLESS_PUSH_CLIPORT;
1783  servport = CONNECTIONLESS_SERVPORT;
1784  }
1785 
1786  address_type = (**e).u.Push_Message.address_type;
1787  *tuple = set_addr_tuple(cliaddr, cliport, servport, address_type, push_headers);
1788 
1789  if (!content_transformable(push_headers))
1790  goto no_transform;
1791 
1792  content.charset = NULL;
1793  content.type = NULL;
1794 
1795  content.body = (**e).u.Push_Message.push_data;
1796  if (content.body == NULL)
1797  goto no_transform;
1798 
1799  content.type = http_header_find_first(push_headers, "Content-Transfer-Encoding");
1800  if (content.type) {
1802  debug("wap.push.ppg", 0, "PPG: Content-Transfer-Encoding is \"%s\"",
1804  message_deliverable = pap_get_content(&content);
1805 
1806  if (message_deliverable) {
1807  change_header_value(&push_headers, "Content-Transfer-Encoding",
1808  "binary");
1809  } else {
1810  goto error;
1811  }
1812  }
1813 
1816  message_deliverable = pap_convert_content(&content);
1817 
1818  if (content.type == NULL)
1819  goto error;
1820 
1821  if (message_deliverable) {
1822  *type = content.type;
1823  } else {
1824  goto error;
1825  }
1826 
1827  (**e).u.Push_Message.push_data = content.body;
1829 
1830  debug("wap.push.ppg", 0, "PPG: transform_message: push message content"
1831  " and headers valid");
1832  return 1;
1833 
1834 herror:
1835  warning(0, "PPG: transform_message: no push headers, cannot accept");
1837  return 0;
1838 
1839 error:
1840  warning(0, "PPG: transform_message: push content erroneous, cannot"
1841  " accept");
1844  return 0;
1845 
1846 no_transform:
1847  warning(0, "PPG: transform_message: push content non transformable");
1848  return 1;
1849 }
1850 
1851 /*
1852  * Transform X-WAP-Application headers as per ppg 6.1.2.1. Note that missing
1853  * header means that wml.ua is assumed.
1854  * Return coded value (starting with 0), when the id was not wml.ua
1855  * -1, when id was wml.ua (or no application id was present)
1856  * -2, when error
1857  */
1858 static long check_x_wap_application_id_header(List **push_headers)
1859 {
1860  Octstr *appid_content;
1861  long coded_value;
1862  Octstr *cos;
1863 
1864  if (*push_headers == NULL)
1865  return -2;
1866 
1867  appid_content = http_header_find_first(*push_headers,
1868  "X-WAP-Application-Id");
1869 
1870  if (appid_content == NULL) {
1871  octstr_destroy(appid_content);
1872  return -1;
1873  }
1874 
1875  if ((coded_value = parse_appid_header(&appid_content)) < 0) {
1876  octstr_destroy(appid_content);
1877  return -2;
1878  }
1879 
1880  if (coded_value == 2) {
1881  octstr_destroy(appid_content);
1882  http_header_remove_all(*push_headers, "X-WAP-Application-Id");
1883  return -1;
1884  }
1885 
1886  cos = octstr_format("%ld", coded_value);
1887  http_header_remove_all(*push_headers, "X-WAP-Application-Id");
1888  http_header_add(*push_headers, "X-WAP-Application-Id", octstr_get_cstr(cos));
1889 
1890  octstr_destroy(appid_content);
1891  octstr_destroy(cos);
1892 
1893  return coded_value;
1894 }
1895 
1896 /*
1897  * Check do we have a no-transform cache directive amongst the headers.
1898  */
1899 static int content_transformable(List *push_headers)
1900 {
1901  List *cache_directives;
1902  long i;
1903  Octstr *header_name,
1904  *header_value;
1905 
1906  gw_assert(push_headers);
1907 
1908  cache_directives = http_header_find_all(push_headers, "Cache-Control");
1909  if (gwlist_len(cache_directives) == 0) {
1910  http_destroy_headers(cache_directives);
1911  return 1;
1912  }
1913 
1914  i = 0;
1915  while (i < gwlist_len(cache_directives)) {
1916  http_header_get(cache_directives, i, &header_name, &header_value);
1917  if (octstr_compare(header_value, octstr_imm("no-transform")) == 0) {
1918  http_destroy_headers(cache_directives);
1919  octstr_destroy(header_name);
1920  octstr_destroy(header_value);
1921  return 0;
1922  }
1923  ++i;
1924  }
1925 
1926  http_destroy_headers(cache_directives);
1927  octstr_destroy(header_name);
1928  octstr_destroy(header_value);
1929 
1930  return 1;
1931 }
1932 
1933 /*
1934  * Convert push content to compact binary format (this can be wmlc, sic, slc
1935  * or coc). Current status wml, sl and si compiled, others passed.
1936  */
1938 {
1939  Octstr *wmlc;
1940 
1941  if (wml_compile(content->body, content->charset, &wmlc, NULL) == 0)
1942  return wmlc;
1943  warning(0, "PPG: wml compilation failed");
1944  return NULL;
1945 }
1946 
1948 {
1949  Octstr *sic;
1950 
1951  if (si_compile(content->body, content->charset, &sic) == 0)
1952  return sic;
1953  warning(0, "PPG: si compilation failed");
1954  return NULL;
1955 }
1956 
1958 {
1959  Octstr *slc;
1960 
1961  if (sl_compile(content->body, content->charset, &slc) == 0)
1962  return slc;
1963  warning(0, "PPG: sl compilation failed");
1964  return NULL;
1965 }
1966 
1967 
1969 {
1970  Octstr *orig = octstr_duplicate(content->body);
1972  return orig;
1973 }
1974 
1975 static struct {
1976  char *type;
1978  Octstr *(*convert) (struct content *);
1979 } converters[] = {
1980  { "text/vnd.wap.wml",
1981  "application/vnd.wap.wmlc",
1983  { "text/vnd.wap.si",
1984  "application/vnd.wap.sic",
1986  { "text/vnd.wap.sl",
1987  "application/vnd.wap.slc",
1989 };
1990 
1991 #define NUM_CONVERTERS ((long) (sizeof(converters) / sizeof(converters[0])))
1992 
1993 static struct {
1995  Octstr *(*extract) (struct content *);
1996 } extractors[] = {
1997  { "base64",
1998  extract_base64 }
1999 };
2000 
2001 #define NUM_EXTRACTORS ((long) (sizeof(extractors) / sizeof(extractors[0])))
2002 
2003 /*
2004  * Compile wap defined contents, accept others without modifications. Push
2005  * message 6.3 states that push content can be any MIME accepted content type.
2006  */
2008 {
2009  long i;
2010  Octstr *new_body;
2011 
2012  for (i = 0; i < NUM_CONVERTERS; i++) {
2013  if (octstr_compare(content->type,
2014  octstr_imm(converters[i].type)) == 0) {
2015  new_body = converters[i].convert(content);
2016  if (new_body == NULL)
2017  return 0;
2019  content->body = new_body;
2022  return 1;
2023  }
2024  }
2025 
2026  return 1;
2027 }
2028 
2029 /*
2030  * MIME specifies a number of content transfer encodings.
2031  * This function tries to get the original version of the
2032  * content.
2033  */
2034 static int pap_get_content(struct content *content)
2035 {
2036  long i;
2037  Octstr *new_body;
2038 
2039  for (i = 0; i < NUM_EXTRACTORS; i++) {
2042 
2043  new_body = extractors[i].extract(content);
2044  if (new_body == NULL)
2045  return 0;
2047  content->body = new_body;
2049  content->type = NULL;
2050  return 1;
2051  }
2052  }
2053 
2054  return 1;
2055 }
2056 
2057 /*
2058  * Bearer and network types are defined in wdp, Appendix C. Any means any net-
2059  * work supporting IPv4 or IPv6.
2060  */
2061 static char *bearers[] = {
2062  "Any",
2063  "SMS",
2064  "CSD",
2065  "GPRS",
2066  "Packet Data",
2067  "CDPD"
2068 };
2069 
2070 #define NUMBER_OF_BEARERS sizeof(bearers)/sizeof(bearers[0])
2071 
2072 static char *networks[] = {
2073  "Any",
2074  "GSM",
2075  "IS-95 CDMA",
2076  "ANSI-136",
2077  "AMPS",
2078  "PDC",
2079  "IDEN",
2080  "PHS",
2081  "TETRA"
2082 };
2083 
2084 #define NUMBER_OF_NETWORKS sizeof(networks)/sizeof(networks[0])
2085 
2086 /*
2087  * We support networks using IP as a bearer and GSM using SMS as bearer, so we
2088  * must reject others. Default bearer is IP, it is (currently) not-SMS. After
2089  * the check we change meaning of the bearer_required-attribute: it will tell
2090  * do we use WAP over SMS.
2091  */
2093 {
2094  Octstr *bearer,
2095  *network;
2096  int bearer_required,
2097  network_required;
2098  size_t i,
2099  j;
2100 
2101  gw_assert((**e).type == Push_Message);
2102 
2103  bearer_required = (**e).u.Push_Message.bearer_required;
2104  network_required = (**e).u.Push_Message.network_required;
2105  bearer = octstr_imm("Any");
2106  network = octstr_imm("Any");
2107 
2108  if (!bearer_required || !network_required)
2109  return 1;
2110 
2111  if (bearer_required)
2112  bearer = (**e).u.Push_Message.bearer;
2113  if (network_required)
2114  network = (**e).u.Push_Message.network;
2115 
2116  for (i = 0; i < NUMBER_OF_NETWORKS ; ++i) {
2117  if (octstr_case_compare(network, octstr_imm(networks[i])) == 0)
2118  break;
2119  }
2120  for (j = 0; j < NUMBER_OF_BEARERS ; ++j) {
2121  if (octstr_case_compare(bearer, octstr_imm(bearers[j])) == 0)
2122  break;
2123  }
2124  if (i == NUMBER_OF_NETWORKS || j == NUMBER_OF_BEARERS)
2125  return 0;
2126 
2127  return 1;
2128 }
2129 
2130 static int session_has_pi_client_address(void *a, void *b)
2131 {
2132  Octstr *caddr;
2133  PPGSessionMachine *sm;
2134 
2135  caddr = b;
2136  sm = a;
2137 
2138  return octstr_compare(caddr, sm->pi_client_address) == 0;
2139 }
2140 
2141 /*
2142  * PI client address is composed of a client specifier and a PPG specifier (see
2143  * ppg, chapter 7). So it is equivalent with gw address quadruplet.
2144  */
2146 {
2147  PPGSessionMachine *sm;
2148 
2150 
2151  return sm;
2152 }
2153 
2154 /*
2155  * Give PPG a human readable name.
2156  */
2157 static Octstr *tell_ppg_name(void)
2158 {
2159  return octstr_format("%S; WAP/1.3 (" GW_NAME "/%s)", get_official_name(),
2160  GW_VERSION);
2161 }
2162 
2163 /*
2164  * Delivery time constraints are a) deliver before and b) deliver after. It is
2165  * possible that service required is after some time and before other. So we
2166  * test first condition a). Note that 'now' satisfy both constraints.
2167  * Returns: 0 delivery time expired
2168  * 1 too early to send the message
2169  * 2 no constraints
2170  */
2172 {
2173  Octstr *before,
2174  *after;
2175  struct tm now;
2176 
2177  gw_assert(e->type == Push_Message);
2178 
2179  before = e->u.Push_Message.deliver_before_timestamp;
2180  after = pm->deliver_after_timestamp;
2181  now = gw_gmtime(time(NULL));
2182 
2183  if (!deliver_before_test_cleared(before, now)) {
2184  info(0, "PPG: delivery deadline expired, dropping the push message");
2185  return 0;
2186  }
2187 
2188  if (!deliver_after_test_cleared(after, now)) {
2189  debug("wap.push.ppg", 0, "PPG: too early to push the message,"
2190  " waiting");
2191  return 1;
2192  }
2193 
2194  return 2;
2195 }
2196 
2197 /*
2198  * Give verbose description of the result code. Conversion table for descrip-
2199  * tion.
2200  */
2202  long reason;
2204 };
2205 
2207 
2209  { PAP_OK, "The request succeeded"},
2210  { PAP_ACCEPTED_FOR_PROCESSING, "The request has been accepted for"
2211  " processing"},
2212  { PAP_BAD_REQUEST, "Not understood due to malformed syntax"},
2213  { PAP_FORBIDDEN, "Request was refused"},
2214  { PAP_ADDRESS_ERROR, "The client specified not recognised"},
2215  { PAP_CAPABILITIES_MISMATCH, "Capabilities assumed by PI were not"
2216  " acceptable for the client specified"},
2217  { PAP_DUPLICATE_PUSH_ID, "Push id supplied was not unique"},
2218  { PAP_INTERNAL_SERVER_ERROR, "Server could not fulfill the request due"
2219  " to an internal error"},
2220  { PAP_TRANSFORMATION_FAILURE, "PPG was unable to perform a transformation"
2221  " of the message"},
2222  { PAP_REQUIRED_BEARER_NOT_AVAILABLE, "Required bearer not available"},
2223  { PAP_SERVICE_FAILURE, "The service failed. The client may re-attempt"
2224  " the operation"},
2225  { PAP_CLIENT_ABORTED, "The client aborted the operation. No reason given"},
2226  { WSP_ABORT_USERREQ, "Wsp requested abort"},
2227  { WSP_ABORT_USERRFS, "Wsp refused push message. Do not try again"},
2228  { WSP_ABORT_USERPND, "Push message cannot be delivered to intended"
2229  " destination by the wsp"},
2230  { WSP_ABORT_USERDCR, "Push message discarded due to resource shortage in"
2231  " wsp"},
2232  { WSP_ABORT_USERDCU, "Content type of the push message cannot be"
2233  " processed by the wsp"}
2234 };
2235 
2236 static size_t desc_tab_size = sizeof(pap_desc) / sizeof(pap_desc[0]);
2237 
2239 {
2240  Octstr *desc;
2241  size_t i;
2242 
2243  for (i = 0; i < desc_tab_size; i++) {
2244  if (pap_desc[i].reason == code) {
2245  desc = octstr_create(pap_desc[i].description);
2246  return desc;
2247  }
2248  }
2249 
2250  return octstr_imm("unknown PAP code");
2251 }
2252 
2253 /*
2254  * Remove push data from the list of connectionless pushes, if cless is true,
2255  * otherwise from the list of pushes belonging to session machine sm.
2256  */
2258  int cless)
2259 {
2260  push_machine_assert(pm);
2261 
2262  if (cless) {
2264  } else {
2266  gwlist_delete_equal(sm->push_machines, pm);
2267  }
2268 
2270 }
2271 
2272 /*
2273  * If cless is true, store push to the list connectionless pushes, otherwise
2274  * in the push list of the session machine sm.
2275  * We must create a push machine even when an error occurred, because this is
2276  * used for storing the relevant pap error state and other data for this push.
2277  * There should not be any duplicate push ids here (this is tested by http_
2278  * read_thread), but let us be carefull.
2279  * Return a pointer the push machine newly created and a flag telling was the
2280  * push id duplicate.
2281  */
2283  WAPEvent *e, WAPAddrTuple *tuple, int cless)
2284 {
2285  Octstr *pi_push_id;
2286  int duplicate_push_id;
2287 
2288  gw_assert(e->type == Push_Message);
2289 
2290  pi_push_id = e->u.Push_Message.pi_push_id;
2291 
2292  duplicate_push_id = 0;
2293  if (((!cless) &&
2294  (find_ppg_push_machine_using_pi_push_id(sm, pi_push_id) != NULL)) ||
2295  ((cless) &&
2296  (find_unit_ppg_push_machine_using_pi_push_id(pi_push_id) != NULL)))
2297  duplicate_push_id = 1;
2298 
2299  *pm = push_machine_create(e, tuple);
2300 
2301  if (duplicate_push_id)
2302  return !duplicate_push_id;
2303 
2304  if (!cless) {
2305  gwlist_append(sm->push_machines, *pm);
2306  debug("wap.push.ppg", 0, "PPG: store_push_data: push machine %ld"
2307  " appended to push list of sm machine %ld", (*pm)->push_id,
2308  sm->session_id);
2309  } else {
2311  debug("wap.push.ppg", 0, "PPG: store_push_data: push machine %ld"
2312  " appended to unit push list", (*pm)->push_id);
2313  }
2314 
2315  return !duplicate_push_id;
2316 }
2317 
2318 /*
2319  * Deliver confirmed push. Note that if push is confirmed, PAP attribute is up-
2320  * dated only after an additional event (confirmation, abort or time-out).
2321  */
2322 static void deliver_confirmed_push(long last, PPGPushMachine *pm,
2323  PPGSessionMachine *sm)
2324 {
2325  request_confirmed_push(last, pm, sm);
2326 }
2327 
2328 /*
2329  * Ppg, chapter 6.1.2.2 , subchapter delivery, says that if push is unconform-
2330  * ed, we can use either Po-Unit-Push.req or Po-Push.req primitive. We use Po-
2331  * Push.req, if have an already established session (other words, sm != NULL).
2332  * In addition, update PAP attribute. Return pointer to the updated push mach-
2333  * ine.
2334  */
2336  PPGSessionMachine *sm, int session_exists)
2337 {
2338  push_machine_assert(pm);
2339 
2340  if (!session_exists)
2341  request_unit_push(last, pm);
2342  else
2343  request_push(last, pm);
2344 
2346  PAP_DELIVERED1);
2347  info(0, "PPG: unconfirmed push delivered to OTA");
2348 
2349  return pm;
2350 }
2351 
2352 /*
2353  * Deliver all pushes queued by session machine sm (it is, make a relevant OTA
2354  * request). Update PAP attribute, if push is unconfirmed.
2355  */
2356 static void deliver_pending_pushes(PPGSessionMachine *sm, int last)
2357 {
2358  PPGPushMachine *pm;
2359  long i;
2360 
2362  gw_assert(gwlist_len(sm->push_machines) > 0);
2363 
2364  i = 0;
2365  while (i < gwlist_len(sm->push_machines)) {
2366  pm = gwlist_get(sm->push_machines, i);
2367  push_machine_assert(pm);
2368 
2369  if (pm->delivery_method == PAP_UNCONFIRMED) {
2370  request_push(last, pm);
2372  PAP_DELIVERED1);
2373  remove_push_data(sm, pm, sm == NULL);
2374  } else {
2375  request_confirmed_push(last, pm, sm);
2376  ++i;
2377  }
2378  }
2379 }
2380 
2381 /*
2382  * Abort all pushes queued by session machine sm. In addition, update PAP
2383  * attribute and notify PI.
2384  */
2386 {
2387  PPGPushMachine *pm;
2388  long reason,
2389  code;
2390 
2392 
2393  pm = NULL;
2396 
2397  while (gwlist_len(sm->push_machines) > 0) {
2398  pm = gwlist_get(sm->push_machines, 0);
2399  push_machine_assert(pm);
2400 
2403 
2404  remove_push_data(sm, pm, sm == NULL);
2405  }
2406 
2407  return pm;
2408 }
2409 
2410 /*
2411  * Remove a session, even if it have active pushes. These are aborted, and we
2412  * must inform PI about this. Client abort codes are defined in pap, 9.14.5,
2413  * which refers to wsp, Appendix A, table 35.
2414  */
2416 {
2417  long code;
2418  PPGPushMachine *pm;
2419 
2421 
2423 
2424  while (gwlist_len(sm->push_machines) > 0) {
2425  pm = gwlist_get(sm->push_machines, 0);
2427  remove_push_data(sm, pm, sm == NULL);
2428  }
2429 
2432 }
2433 
2434 /*
2435  * Remove session, if it has no active pushes.
2436  */
2438 {
2440 
2441  if (gwlist_len(sm->push_machines) == 0) {
2444  }
2445 }
2446 
2447 /*
2448  * If session machine not exist, create a session machine and store session
2449  * data. If session exists, ignore.
2450  * Return pointer to the session machine, and a flag did we have a session
2451  * before executing this function. (Session data is needed to implement the
2452  * PAP attribute. It does not mean that a session exists.)
2453  */
2455  WAPEvent *e, WAPAddrTuple *tuple, int *session_exists)
2456 {
2457  gw_assert(e->type == Push_Message);
2458 
2459  if (sm == NULL) {
2460  sm = session_machine_create(tuple, e);
2461  *session_exists = 0;
2462  } else
2463  *session_exists = 1;
2464 
2465  return sm;
2466 }
2467 
2470 {
2471  gwlist_delete_matching(sm->push_machines, &pm->push_id, push_has_pid);
2472  gwlist_append(sm->push_machines, pm);
2473 
2474  return sm;
2475 }
2476 
2477 /*
2478  * Ppg 6.1.2.2, subchapter delivery, states that if the delivery method is not
2479  * confirmed or unconfirmed, PPG may select an implementation specific type of
2480  * the primitive. We use an unconfirmed push, if QoS is notspecified, and
2481  * confirmed one, when it is preferconfirmed (we do support confirmed push).
2482  */
2484 {
2485  gw_assert(e->type == Push_Message);
2486 
2487  return e->u.Push_Message.delivery_method == PAP_CONFIRMED ||
2488  e->u.Push_Message.delivery_method == PAP_PREFERCONFIRMED;
2489 }
2490 
2491 static int push_has_pid(void *a, void *b)
2492 {
2493  long *pid;
2494  PPGPushMachine *pm;
2495 
2496  pid = b;
2497  pm = a;
2498 
2499  return *pid == pm->push_id;
2500 }
2501 
2503  long pid)
2504 {
2505  PPGPushMachine *pm;
2506 
2507  gw_assert(pid >= 0);
2509 
2510  pm = gwlist_search(sm->push_machines, &pid, push_has_pid);
2511 
2512  return pm;
2513 }
2514 
2515 static int push_has_pi_push_id(void *a, void *b)
2516 {
2517  Octstr *pi_push_id;
2518  PPGPushMachine *pm;
2519 
2520  pi_push_id = b;
2521  pm = a;
2522 
2523  return octstr_compare(pm->pi_push_id, pi_push_id) == 0;
2524 }
2525 
2527  PPGSessionMachine *sm, Octstr *pi_push_id)
2528 {
2529  PPGPushMachine *pm;
2530 
2531  gw_assert(pi_push_id);
2533 
2534  pm = gwlist_search(sm->push_machines, pi_push_id, push_has_pi_push_id);
2535 
2536  return pm;
2537 }
2538 
2540  Octstr *pi_push_id)
2541 {
2542  PPGPushMachine *pm;
2543 
2544  gw_assert(pi_push_id);
2546 
2547  return pm;
2548 }
2549 
2550 /*
2551  * Store a new value of the push attribute into a push machine. It is to be
2552  * found from the list of unit pushes, if connectionless push was asked
2553  * (sm == NULL), otherwise from the the push list of the session machine sm.
2554  * Returns updated push machine and session machine (this one has an updated
2555  * push machines list).
2556  */
2558  PPGPushMachine *qm, long reason, long status)
2559 {
2560  push_machine_assert(qm);
2561 
2562  switch (status) {
2563  case PAP_UNDELIVERABLE1:
2564  qm->message_state = PAP_UNDELIVERABLE;
2565  qm->code = PAP_BAD_REQUEST;
2566  break;
2567 
2568  case PAP_UNDELIVERABLE2:
2569  qm->code = reason;
2570  qm->message_state = PAP_UNDELIVERABLE;
2571  qm->desc = describe_code(reason);
2572  break;
2573 
2574  case PAP_ABORTED:
2575  qm->message_state = status;
2576  qm->code = ota_abort_to_pap(reason);
2577  qm->event_time = set_time();
2578  qm->desc = describe_code(reason);
2579  break;
2580 
2581  case PAP_DELIVERED1:
2582  qm->message_state = PAP_DELIVERED;
2583  qm->delivery_method = PAP_UNCONFIRMED;
2584  qm->event_time = set_time();
2585  break;
2586 
2587  case PAP_DELIVERED2:
2588  qm->message_state = PAP_DELIVERED;
2589  qm->delivery_method = PAP_CONFIRMED;
2590  qm->event_time = set_time();
2591  break;
2592 
2593  case PAP_EXPIRED:
2594  qm->message_state = PAP_EXPIRED;
2595  qm->event_time = set_time();
2596  qm->desc = describe_code(reason);
2597  break;
2598 
2599  case PAP_PENDING:
2600  qm->message_state = PAP_PENDING;
2601  break;
2602 
2603  default:
2604  error(0, "WAP_PUSH_PPG: update_push_data_with_attribute: Non"
2605  " existing push machine status: %ld", status);
2606  break;
2607  }
2608 
2609  if (*sm != NULL){
2610  gwlist_delete_matching((**sm).push_machines, &qm->push_id, push_has_pid);
2611  gwlist_append((**sm).push_machines, qm);
2614  } else {
2617  }
2618 
2619  return qm;
2620 }
2621 
2622 /*
2623  * Store session id, client port and caps list received from application layer.
2624  */
2626  long sid, long port, List *caps)
2627 {
2629  gw_assert(sid >= 0);
2630 
2631  m->session_id = sid;
2632  m->addr_tuple->remote->port = port;
2633  m->client_capabilities = wsp_cap_duplicate_list(caps);
2634 
2637 
2638  return m;
2639 }
2640 
2641 /*
2642  * Convert OTA abort codes (ota 6.3.3) to corresponding PAP status codes. These
2643  * are defined in pap 9.14.5.
2644  */
2645 static long ota_abort_to_pap(long reason)
2646 {
2647  long offset;
2648 
2649  offset = reason - 0xEA;
2650  reason = 5026 + offset;
2651 
2652  return reason;
2653 }
2654 
2655 /*
2656  * Accept connectionless push when PI wants connectionless push and there is
2657  * no sessions open.
2658  */
2660 {
2661  gw_assert(e->type == Push_Message);
2662  return (e->u.Push_Message.delivery_method == PAP_UNCONFIRMED ||
2663  e->u.Push_Message.delivery_method == PAP_NOT_SPECIFIED) &&
2664  (sm == NULL);
2665 }
2666 
2667 /*
2668  * Application ids start with 0 and -1 means that default (wml.ua) was used.
2669  */
2670 static int coriented_deliverable(long appid_code)
2671 {
2672  return appid_code > -1;
2673 }
2674 
2675 /*
2676  * Compare PAP message timestamp, in PAP message format, and stored in octstr,
2677  * to gm (UTC) broken time. Return true, if before is after now, or if the
2678  * service in question was not requested by PI. PAP time format is defined in
2679  * pap, chapter 9.2.
2680  */
2681 
2682 static void initialize_time_item_array(long time_data[], struct tm now)
2683 {
2684  time_data[0] = now.tm_year + 1900;
2685  time_data[1] = now.tm_mon + 1;
2686  time_data[2] = now.tm_mday;
2687  time_data[3] = now.tm_hour;
2688  time_data[4] = now.tm_min;
2689  time_data[5] = now.tm_sec;
2690 }
2691 
2692 static int date_item_compare(Octstr *condition, long time_data, long pos)
2693 {
2694  long data;
2695 
2696  if (octstr_parse_long(&data, condition, pos, 10) < 0) {
2697  return 0;
2698  }
2699  if (data < time_data) {
2700  return -1;
2701  }
2702  if (data > time_data) {
2703  return 1;
2704  }
2705 
2706  return 0;
2707 }
2708 
2709 /*
2710  * We do not accept timestamps equalling now. Return true, if the service was
2711  * not requested.
2712  */
2713 static int deliver_before_test_cleared(Octstr *before, struct tm now)
2714 {
2715  long time_data[6];
2716  long j;
2717 
2718  if (before == NULL)
2719  return 1;
2720 
2721  initialize_time_item_array(time_data, now);
2722  if (date_item_compare(before, time_data[0], 0) == 1)
2723  return 1;
2724  if (date_item_compare(before, time_data[0], 0) == -1)
2725  return 0;
2726 
2727  for (j = 5; j < octstr_len(before); j += 3) {
2728  if (date_item_compare(before, time_data[(j-5)/3 + 1], j) == 1)
2729  return 1;
2730  if (date_item_compare(before, time_data[(j-5)/3 + 1], j) == -1)
2731  return 0;
2732  }
2733 
2734  return 0;
2735 }
2736 
2737 /*
2738  * Ditto. Return true, if after is before now (or the service was not request-
2739  * ed). Do not accept timestamps equalling now.
2740  */
2741 static int deliver_after_test_cleared(Octstr *after, struct tm now)
2742 {
2743  long time_data[6];
2744  long j;
2745 
2746  if (after == NULL)
2747  return 1;
2748 
2749  initialize_time_item_array(time_data, now);
2750  if (date_item_compare(after, time_data[0], 0) == -1)
2751  return 1;
2752  if (date_item_compare(after, time_data[0], 0) == 1)
2753  return 0;
2754 
2755  for (j = 5; j < octstr_len(after); j += 3) {
2756  if (date_item_compare(after, time_data[(j-5)/3 + 1], j) == -1)
2757  return 1;
2758  if (date_item_compare(after, time_data[(j-5)/3 + 1], j) == 1)
2759  return 0;
2760  }
2761 
2762  return 0;
2763 }
2764 
2765 /*
2766  * We exchange here server and client addresses and ports, because our WDP,
2767  * written for pull, exchange them, too. Similarly server address INADDR_ANY is
2768  * used for compability reasons, when the bearer is ip. When it is SMS, the
2769  * server address is global-sender.
2770  */
2771 static WAPAddrTuple *set_addr_tuple(Octstr *address, long cliport, long servport,
2772  long address_type, List *push_headers)
2773 {
2774  Octstr *cliaddr;
2775  Octstr *from = NULL;
2776  WAPAddrTuple *tuple;
2777 
2778  gw_assert(address);
2779 
2780  if (address_type == ADDR_PLMN) {
2781  from = http_header_value(push_headers, octstr_imm("X-Kannel-From"));
2782  cliaddr = from ? from : global_sender;
2783  } else {
2784  cliaddr = octstr_imm("0.0.0.0");
2785  }
2786 
2787  tuple = wap_addr_tuple_create(address, cliport, cliaddr, servport);
2788 
2790  http_header_remove_all(push_headers, "X-Kannel-From");
2791 
2792  return tuple;
2793 }
2794 
2795 /*
2796  * We are not interested about parsing URI fully - we check only does it cont-
2797  * ain application id reserved by WINA or the part containing assigned code.
2798  * Otherwise (regardless of it being an URI or assigned code) we simply pass
2799  * it forward.
2800  * These are defined by WINA at http://www.openmobilealliance.org/tech/
2801  * omna/omna-push-app-id.htm. We recognize both well-known and registered
2802  * values. X-wap-application is not added, it is considired a default.
2803  */
2804 
2805 static char *wina_uri[] =
2806 { "*",
2807  "push.sia",
2808  "wml.ua",
2809  "wta.ua",
2810  "mms.ua",
2811  "push.syncml",
2812  "loc.ua",
2813  "syncml.dm",
2814  "drm.ua",
2815  "emn.ua",
2816  "wv.ua",
2817  "x-wap-microsoft:localcontent.ua",
2818  "x-wap-microsoft:IMclient.ua",
2819  "x-wap-docomo:imode.mail.ua",
2820  "x-wap-docomo:imode.mr.ua",
2821  "x-wap-docomo:imode.mf.ua",
2822  "x-motorola:location.ua",
2823  "x-motorola:now.ua",
2824  "x-motorola:otaprov.ua",
2825  "x-motorola:browser.ua",
2826  "x-motorola:splash.ua",
2827  "x-wap-nai:mvsw.command",
2828  "x-wap-openwave:iota.ua",
2829  "x-wap-docomo:imode.mail2.ua",
2830  "x-oma-nec:otaprov.ua",
2831  "x-oma-nokia:call.ua"
2832 };
2833 
2834 #define NUMBER_OF_WINA_URIS sizeof(wina_uri)/sizeof(wina_uri[0])
2835 
2836 /*
2837  * X-Wap-Application-Id header is defined in Push Message, chapter 6.2.2.1.
2838  * First check do we a header with an app-encoding field and a coded value.
2839  * If not, try to find push application id from table of wina approved values.
2840  * Return coded value value of application id in question, or an error code:
2841  * -1, no coded value (but defaults may be applied)
2842  * 0, * (meaning any application acceptable)
2843  * greater or equal as 1: code for this application id
2844  */
2845 static long parse_appid_header(Octstr **appid_content)
2846 {
2847  long pos,
2848  coded_value;
2849  size_t i;
2850 
2851  if ((pos = octstr_search(*appid_content, octstr_imm(";"), 0)) >= 0) {
2852  octstr_delete(*appid_content, pos,
2853  octstr_len(octstr_imm(";app-encoding=")));
2854  octstr_delete(*appid_content, 0, pos); /* the URI part */
2855  return -1;
2856  }
2857 
2858  i = 0;
2859  while (i < NUMBER_OF_WINA_URIS) {
2860  if ((pos = octstr_case_search(*appid_content,
2861  octstr_imm(wina_uri[i]), 0)) >= 0)
2862  break;
2863  ++i;
2864  }
2865 
2866  if (i == NUMBER_OF_WINA_URIS) {
2867  octstr_destroy(*appid_content);
2868  *appid_content = octstr_format("%ld", 2); /* assigned number */
2869  return -1; /* for wml ua */
2870  }
2871 
2872  octstr_delete(*appid_content, 0, pos); /* again the URI */
2873  if ((coded_value = wsp_string_to_application_id(*appid_content)) >= 0) {
2874  octstr_destroy(*appid_content);
2875  *appid_content = octstr_format("%ld", coded_value);
2876  return coded_value;
2877  }
2878 
2879  return -1;
2880 }
2881 
2883 {
2884  WAPAddrTuple *dubble;
2885 
2886  if (tuple == NULL)
2887  return NULL;
2888 
2889  dubble = wap_addr_tuple_create(tuple->remote->address,
2890  port,
2891  tuple->local->address,
2892  tuple->local->port);
2893 
2894  return dubble;
2895 }
2896 
2897 /*
2898  * Pi uses multipart/related content type when communicating with ppg. (see
2899  * pap, Chapter 8) and subtype application/xml.
2900  * Check if push headers are acceptable according this rule. In addition,
2901  * return the field value of Content-Type header, if any and error string if
2902  * none (this string is used by send_bad_message_response).
2903  */
2904 static int headers_acceptable(List *push_headers, Octstr **content_header)
2905 {
2906  gw_assert(push_headers);
2907  *content_header = http_header_find_first(push_headers, "Content-Type");
2908 
2909  if (*content_header == NULL) {
2910  *content_header = octstr_format("%s", "no content type header found");
2911  goto error;
2912  }
2913 
2914  if (!type_is(*content_header, "multipart/related")) {
2915  goto error;
2916  }
2917 
2918  if (!type_is(*content_header, "application/xml")) {
2919  goto error;
2920  }
2921 
2922  return 1;
2923 
2924 error:
2925  warning(0, "PPG: headers_acceptable: got unacceptable push headers");
2926  return 0;
2927 }
2928 
2929 /*
2930  * Content-Type header field is defined in rfc 1521, chapter 4. We are looking
2931  * after type multipart/related or "multipart/related" and parameter
2932  * type=application/xml or type="application/xml", as required by pap, chapter
2933  * 8.
2934  */
2935 static int type_is(Octstr *content_header, char *name)
2936 {
2937  Octstr *quoted_type,
2938  *osname;
2939 
2940  osname = octstr_imm(name);
2941  if (octstr_case_search(content_header, osname, 0) >= 0)
2942  return 1;
2943 
2944  quoted_type = octstr_format("\"%S\"", osname);
2945 
2946  if (octstr_case_search(content_header, quoted_type, 0) >= 0) {
2947  octstr_destroy(quoted_type);
2948  return 1;
2949  }
2950 
2951  octstr_destroy(quoted_type);
2952  return 0;
2953 }
2954 
2955 /*
2956  * Again looking after a parameter, this time of type boundary=XXX or boundary=
2957  * "XXX".
2958  */
2959 static int get_mime_boundary(List *push_headers, Octstr *content_header,
2960  Octstr **boundary)
2961 {
2962  long pos;
2963  Octstr *bos;
2964  int c, quoted = 0;
2965  long bstart;
2966 
2967  pos = 0;
2968  if ((pos = octstr_case_search(content_header,
2969  bos = octstr_imm("boundary="), 0)) < 0) {
2970  warning(0, "PPG: get_mime_boundary: no boundary specified");
2971  return -1;
2972  }
2973 
2974  pos += octstr_len(bos);
2975  if (octstr_get_char(content_header, pos) == '"') {
2976  ++pos;
2977  quoted = 1;
2978  }
2979 
2980  bstart = pos;
2981  while ((c = octstr_get_char(content_header, pos)) != -1) {
2982  if (c == ';' || (quoted && c == '"') || (!quoted && c == ' '))
2983  break;
2984  ++pos;
2985  }
2986  *boundary = octstr_copy(content_header, bstart, pos - bstart);
2987 
2988  return 0;
2989 }
2990 
2991 static void change_header_value(List **push_headers, char *name, char *value)
2992 {
2993  http_header_remove_all(*push_headers, name);
2994  http_header_add(*push_headers, name, value);
2995 }
2996 
2997 /*
2998  * Some application level protocols may use MIME headers. This may cause problems
2999  * to them. (MIME version is a mandatory header).
3000  */
3001 static void remove_mime_headers(List **push_headers)
3002 {
3003  http_header_remove_all(*push_headers, "MIME-Version");
3004 }
3005 
3006 /*
3007  * There are headers used only for HTTP POST pi->ppg. (For debugging, mainly.)
3008  */
3009 static void remove_link_headers(List **push_headers)
3010 {
3011  http_header_remove_all(*push_headers, "Host");
3012 }
3013 
3014 /*
3015  * X-Kannel headers are used to control Kannel ppg.
3016  */
3017 static void remove_x_kannel_headers(List **push_headers)
3018 {
3019  http_header_remove_all(*push_headers, "X-Kannel-SMSC");
3020  http_header_remove_all(*push_headers, "X-Kannel-DLR-Url");
3021  http_header_remove_all(*push_headers, "X-Kannel-DLR-Mask");
3022  http_header_remove_all(*push_headers, "X-Kannel-Smsbox-Id");
3023 }
3024 
3025 /*
3026  * Badmessage-response element is redefined in pap, implementation note,
3027  * chapter 5. Do not add to the document a fragment being NULL or empty.
3028  * Return current status of HTTPClient.
3029  */
3030 static void send_bad_message_response(HTTPClient **c, Octstr *fragment,
3031  int code, int status)
3032 {
3033  Octstr *reply_body;
3034 
3035  reply_body = octstr_format("%s",
3036  "<?xml version=\"1.0\"?>"
3037  "<!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP 1.0//EN\""
3038  " \"http://www.wapforum.org/DTD/pap_1.0.dtd\">"
3039  "<pap>"
3040  "<badmessage-response code=\"");
3041  octstr_format_append(reply_body, "%d", code);
3042  octstr_format_append(reply_body, "%s", "\""
3043  " desc=\"");
3044  octstr_format_append(reply_body, "%s", "Not understood due to malformed"
3045  " syntax");
3046  octstr_format_append(reply_body, "%s", "\"");
3047 
3048  if (fragment != NULL && octstr_len(fragment) != 0) {
3049  octstr_format_append(reply_body, "%s", " bad-message-fragment=\"");
3050  octstr_format_append(reply_body, "%S", escape_fragment(fragment));
3051  octstr_format_append(reply_body, "%s", "\"");
3052  }
3053 
3054  octstr_format_append(reply_body, "%s", ">"
3055  "</badmessage-response>"
3056  "</pap>");
3057 
3058  debug("wap.push.ppg", 0, "PPG: send_bad_message_response: telling pi");
3059  send_to_pi(c, reply_body, status);
3060 
3061  octstr_destroy(fragment);
3062 }
3063 
3064 /*
3065  * Push response is defined in pap, chapter 9.3. Mapping between push ids and
3066  * http clients is done by using http_clients. We remove (push id, http client)
3067  * pair from the dictionary after the mapping has been done.
3068  * Return current status of HTTPClient.
3069  */
3071 {
3072  Octstr *reply_body,
3073  *url;
3074  HTTPClient *c;
3075 
3076  gw_assert(e->type == Push_Response);
3077  url = dict_get(urls, e->u.Push_Response.pi_push_id);
3078  dict_remove(urls, e->u.Push_Response.pi_push_id);
3079 
3080  reply_body = octstr_format("%s",
3081  "<?xml version=\"1.0\"?>"
3082  "<!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP 1.0//EN\""
3083  " \"http://www.wapforum.org/DTD/pap_1.0.dtd\">"
3084  "<pap>"
3085  "<push-response push-id=\"");
3086  octstr_format_append(reply_body, "%S", e->u.Push_Response.pi_push_id);
3087  octstr_format_append(reply_body, "%s", "\"");
3088 
3089  if (e->u.Push_Response.sender_name != NULL) {
3090  octstr_format_append(reply_body, "%s",
3091  " sender-name=\"");
3092  octstr_format_append(reply_body, "%S",
3093  e->u.Push_Response.sender_name);
3094  octstr_format_append(reply_body, "%s", "\"");
3095  }
3096 
3097  if (e->u.Push_Response.reply_time != NULL) {
3098  octstr_format_append(reply_body, "%s",
3099  " reply-time=\"");
3100  octstr_format_append(reply_body, "%S",
3101  e->u.Push_Response.reply_time);
3102  octstr_format_append(reply_body, "%s", "\"");
3103  }
3104 
3105  if (url != NULL) {
3106  octstr_format_append(reply_body, "%s",
3107  " sender-address=\"");
3108  octstr_format_append(reply_body, "%S", url);
3109  octstr_format_append(reply_body, "%s", "\"");
3110  }
3111 
3112  octstr_format_append(reply_body, "%s", ">"
3113  "<response-result code =\"");
3114  octstr_format_append(reply_body, "%d", e->u.Push_Response.code);
3115  octstr_format_append(reply_body, "%s", "\"");
3116 
3117  if (e->u.Push_Response.desc != NULL) {
3118  octstr_format_append(reply_body, "%s", " desc=\"");
3119  octstr_format_append(reply_body, "%S", e->u.Push_Response.desc);
3120  octstr_format_append(reply_body, "\"");
3121  }
3122 
3123  octstr_format_append(reply_body, "%s", ">"
3124  "</response-result>"
3125  "</push-response>"
3126  "</pap>");
3127 
3129 
3130  c = dict_get(http_clients, e->u.Push_Response.pi_push_id);
3131  dict_remove(http_clients, e->u.Push_Response.pi_push_id);
3132 
3133  debug("wap.push.ppg", 0, "PPG: send_push_response: telling pi");
3134  send_to_pi(&c, reply_body, status);
3135 
3136  wap_event_destroy(e);
3137  return c;
3138 }
3139 
3140 /*
3141  * Ppg notifies pi about duplicate push id by sending a push response document
3142  * to it. Note that we never put the push id to the dict in this case.
3143  * Return current c value.
3144  */
3146  int status, int code)
3147 {
3148  Octstr *reply_body,
3149  *dos, /* temporaries */
3150  *tos,
3151  *sos;
3152 
3153  gw_assert(e->type == Push_Message);
3154  reply_body = octstr_format("%s",
3155  "<?xml version=\"1.0\"?>"
3156  "<!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP 1.0//EN\""
3157  " \"http://www.wapforum.org/DTD/pap_1.0.dtd\">"
3158  "<pap>"
3159  "<push-response push-id=\"");
3160  octstr_format_append(reply_body, "%S", e->u.Push_Message.pi_push_id);
3161  octstr_format_append(reply_body, "%s", "\"");
3162 
3163  octstr_format_append(reply_body, "%s",
3164  " sender-name=\"");
3165  octstr_format_append(reply_body, "%S", tos = tell_ppg_name());
3166  octstr_format_append(reply_body, "%s", "\"");
3167 
3168  octstr_format_append(reply_body, "%s",
3169  " reply-time=\"");
3170  octstr_format_append(reply_body, "%S", sos = set_time());
3171  octstr_format_append(reply_body, "%s", "\"");
3172 
3173  octstr_format_append(reply_body, "%s",
3174  " sender-address=\"");
3175  octstr_format_append(reply_body, "%S", url);
3176  octstr_format_append(reply_body, "%s", "\"");
3177 
3178  octstr_format_append(reply_body, "%s", ">"
3179  "<response-result code =\"");
3180  octstr_format_append(reply_body, "%d", code);
3181  octstr_format_append(reply_body, "%s", "\"");
3182 
3183  octstr_format_append(reply_body, "%s", " desc=\"");
3184  octstr_format_append(reply_body, "%S", dos = describe_code(code));
3185  octstr_format_append(reply_body, "\"");
3186 
3187  octstr_format_append(reply_body, "%s", ">"
3188  "</response-result>"
3189  "</push-response>"
3190  "</pap>");
3191 
3192  debug("wap.push.ppg", 0, "PPG: tell_fatal_error: %s", octstr_get_cstr(dos));
3193  send_to_pi(c, reply_body, status);
3194 
3195  octstr_destroy(dos);
3196  octstr_destroy(tos);
3197  octstr_destroy(sos);
3198  wap_event_destroy(e);
3199 }
3200 
3201 /*
3202  * Does the HTTP reply to pi. Test has HTTPClient disappeared.
3203  * Return current c value.
3204  */
3205 static void send_to_pi(HTTPClient **c, Octstr *reply_body, int status) {
3206  List *reply_headers;
3207 
3208  reply_headers = http_create_empty_headers();
3209  http_header_add(reply_headers, "Content-Type", "application/xml");
3210 
3211  if (*c != NULL)
3212  http_send_reply(*c, status, reply_headers, reply_body);
3213 
3214  octstr_destroy(reply_body);
3215  http_destroy_headers(reply_headers);
3216 }
3217 
3218 /*
3219  * Escape characters not allowed in the value of an attribute. Pap does not
3220  * define escape sequences for message fragments; try common xml ones.
3221  */
3222 
3223 static Octstr *escape_fragment(Octstr *fragment)
3224 {
3225  long i;
3226  int c;
3227 
3228  i = 0;
3229  while (i < octstr_len(fragment)) {
3230  if ((c = octstr_get_char(fragment, i)) == '"') {
3231  replace_octstr_char(fragment, octstr_imm("&quot;"), &i);
3232  } else if (c == '<') {
3233  replace_octstr_char(fragment, octstr_imm("&lt;"), &i);
3234  } else if (c == '>') {
3235  replace_octstr_char(fragment, octstr_imm("&gt;"), &i);
3236  } else if (c == '&') {
3237  replace_octstr_char(fragment, octstr_imm("&amp;"), &i);
3238  }
3239  ++i;
3240  }
3241 
3242  return fragment;
3243 }
3244 
3246 {
3247  return address_type == ADDR_PLMN;
3248 }
3249 
3250 static void replace_octstr_char(Octstr *os1, Octstr *os2, long *pos)
3251 {
3252  octstr_delete(os1, *pos, 1);
3253  octstr_insert(os1, os2, *pos);
3254  *pos += octstr_len(os2) - 1;
3255 }
3256 
3257 /*
3258  * Check if we have an explicit routing information
3259  * a) first check x-kannel header
3260  * b) then ppg user specific routing (if there is any groups; we have none,
3261  * if pi is trusted)
3262  * c) then global ppg routing
3263  * d) if all these failed, return NULL
3264  */
3266 {
3267  Octstr *smsc_id = NULL;
3268 
3269  smsc_id = http_header_value(headers, octstr_imm("X-Kannel-SMSC"));
3270  if (smsc_id) {
3271  return smsc_id;
3272  }
3273 
3274  if (!trusted_pi)
3276 
3277  smsc_id = smsc_id ?
3279 
3280  return smsc_id;
3281 }
3282 
3283 /*
3284  * Checking for dlr url, using following order:
3285  * a) first check X-Kannel header
3286  * b) then ppg user specific dlr url (if there is any user group; if pi is
3287  * trusted, there are none.)
3288  * c) then global ppg dlr url
3289  * d) if all these failed, return NULL
3290  */
3292 {
3293  Octstr *dlr_url = NULL;
3294 
3295  dlr_url = http_header_value(headers, octstr_imm("X-Kannel-DLR-Url"));
3296  if (dlr_url) {
3297  return dlr_url;
3298  }
3299 
3300  if (!trusted_pi)
3302 
3303  dlr_url = dlr_url ?
3305 
3306  return dlr_url;
3307 }
3308 
3309 /*
3310  * Checking for dlr mask. Mask without dlr url is of course useless.
3311  * We reject (some) non-meaningfull values of dlr_mask. Value indic-
3312  * ating rejection is 0.
3313  */
3314 static long set_dlr_mask(List *headers, Octstr *dlr_url)
3315 {
3316  Octstr *dlrmaskos;
3317  long dlr_mask;
3318  long masklen;
3319 
3320  dlrmaskos = http_header_value(headers, octstr_imm("X-Kannel-DLR-Mask"));
3321  if (dlrmaskos == NULL) {
3322  return 0;
3323  }
3324 
3325  if ((masklen = octstr_parse_long(&dlr_mask, dlrmaskos, 0, 10)) != -1 &&
3326  masklen == octstr_len(dlrmaskos) &&
3327  dlr_mask >= -1 && dlr_mask <= 31) {
3328  octstr_destroy(dlrmaskos);
3329  return dlr_mask;
3330  }
3331 
3332  warning(0, "unparsable dlr mask, rejected");
3333  octstr_destroy(dlrmaskos);
3334  return 0;
3335 }
3336 
3337 /*
3338  * Checking for dlr smsbox id, using following order:
3339  * a) first check X-Kannel header
3340  * b) then ppg user specific smsbox id, if there is any group; if pi
3341  * is trusted, there are none
3342  * c) then global ppg smsbox id
3343  * d) if all these failed, return NULL
3344  */
3345 
3347 {
3348  Octstr *smsbox_id = NULL;
3349 
3350  smsbox_id = http_header_value(headers, octstr_imm("X-Kannel-Smsbox-Id"));
3351  if (smsbox_id != NULL) {
3352  return smsbox_id;
3353  }
3354 
3355  if (!trusted_pi)
3357 
3358  smsbox_id = smsbox_id ?
3360 
3361  return smsbox_id;
3362 
3363 }
3364 
3365 /*
3366  * Service is ppg core group only configuration variable
3367  */
3369 {
3371 }
3372 
3373 
3374 
3375 
Dict * dict_create(long size_hint, void(*destroy_value)(void *))
Definition: dict.c:192
static int headers_acceptable(List *push_headers, Octstr **content_header)
static Octstr * dlr_mask
Definition: test_ppg.c:106
static int confirmation_requested(WAPEvent *e)
void error(int err, const char *fmt,...)
Definition: log.c:648
static void remove_x_kannel_headers(List **push_headers)
void info(int err, const char *fmt,...)
Definition: log.c:672
static int is_phone_number(long type_of_address)
static Octstr * escape_fragment(Octstr *fragment)
static Octstr * service_name
Definition: wap_push_ppg.c:205
int sl_compile(Octstr *sl_doc, Octstr *charset, Octstr **sl_binary)
static int check_capabilities(List *requested, List *assumed)
Octstr * wap_push_ppg_pushuser_dlr_url_get(Octstr *username)
Definition: http.c:2014
static Octstr * ppg_default_smsc
Definition: wap_push_ppg.c:198
List * http_header_find_all(List *headers, char *name)
Definition: http.c:3115
static int cless_accepted(WAPEvent *e, PPGSessionMachine *sm)
void http_header_get(List *headers, long i, Octstr **name, Octstr **value)
Definition: http.c:2902
void * gwlist_search(List *list, void *pattern, int(*cmp)(void *, void *))
Definition: list.c:486
static int date_item_compare(Octstr *before, long time_data, long pos)
static char ** push_data
Definition: test_ppg.c:96
static long ota_abort_to_pap(long reason)
static Octstr * extract_base64(struct content *content)
List * push_headers
Definition: wap_push_ppg.c:211
static int read_ppg_config(Cfg *cfg)
Definition: wap_push_ppg.c:523
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2886
gw_assert(wtls_machine->packet_to_send !=NULL)
void dict_put(Dict *dict, Octstr *key, void *value)
Definition: dict.c:240
void counter_destroy(Counter *counter)
Definition: counter.c:110
void gwlist_append(List *list, void *item)
Definition: list.c:179
void http_close_client(HTTPClient *client)
Definition: http.c:2758
static Octstr * set_smsbox_id(List *headers, Octstr *username, int trusted_pi)
static void tell_fatal_error(HTTPClient **c, WAPEvent *e, Octstr *url, int status, int code)
static Counter * push_id_counter
Definition: wap_push_ppg.c:154
char * description
static int pap_get_content(struct content *content)
Octstr * wap_push_ppg_pushuser_smsc_id_get(Octstr *username)
struct tm gw_gmtime(time_t t)
Definition: protected.c:137
Octstr * wap_push_ppg_pushuser_smsbox_id_get(Octstr *username)
PPGSessionMachine * wap_push_ppg_have_push_session_for(WAPAddrTuple *tuple)
Definition: wap_push_ppg.c:488
static int transform_message(WAPEvent **e, WAPAddrTuple **tuple, List *push_headers, int connected, Octstr **type)
void gwlist_produce(List *list, void *item)
Definition: list.c:411
long gwlist_len(List *list)
Definition: list.c:166
static HTTPClient * send_push_response(WAPEvent *e, int status)
static void client(int port)
Definition: test_udp.c:77
static Octstr * describe_code(long code)
static int response_push_connection(WAPEvent *e, PPGSessionMachine *sm)
#define NUM_EXTRACTORS
static int push_has_pid(void *a, void *b)
void * gwlist_get(List *list, long pos)
Definition: list.c:292
static int content_transformable(List *push_headers)
static Octstr * ppg_url
Definition: wap_push_ppg.c:184
static struct @42 extractors[]
static void http_read_thread(void *arg)
Definition: wap_push_ppg.c:688
Octstr * ip
Definition: wap_push_ppg.c:209
static void deliver_confirmed_push(long last, PPGPushMachine *pm, PPGSessionMachine *sm)
int code
Definition: smsc_cimd2.c:346
static long parse_appid_header(Octstr **assigned_code)
static Octstr * convert_sl_to_slc(struct content *content)
Octstr * address
Definition: wap_addr.h:68
static long check_x_wap_application_id_header(List **push_headers)
static void remove_push_data(PPGSessionMachine *sm, PPGPushMachine *pm, int cless)
static char * boundary
Definition: test_ppg.c:97
long octstr_search(const Octstr *haystack, const Octstr *needle, long pos)
Definition: octstr.c:1070
#define cfg_get(grp, varname)
Definition: cfg.h:86
static void request_unit_push(long last, PPGPushMachine *pm)
char * description
Definition: ws.c:100
static char * bearers[]
static List * ppg_queue
Definition: wap_push_ppg.c:133
List * cgivars
Definition: wap_push_ppg.c:213
void http_header_get_content_type(List *headers, Octstr **type, Octstr **charset)
Definition: http.c:3225
static void request_confirmed_push(long last, PPGPushMachine *pm, PPGSessionMachine *sm)
int wap_push_ppg_pushuser_list_add(List *list, long number_of_pushes, long number_of_users)
static enum @39 run_status
static PPGPushMachine * find_unit_ppg_push_machine_using_pi_push_id(Octstr *pi_push_id)
static void remove_pushless_session(PPGSessionMachine *sm)
static void push_machine_assert(PPGPushMachine *pm)
static Cfg * cfg
Definition: opensmppbox.c:95
static PPGPushMachine * update_push_data_with_attribute(PPGSessionMachine **sm, PPGPushMachine *pm, long reason, long status)
void octstr_strip_blanks(Octstr *text)
Definition: octstr.c:1346
List * wsp_cap_duplicate_list(List *caps_list)
Definition: wsp_caps.c:125
static Octstr * ppg_dlr_url
Definition: wap_push_ppg.c:203
static List * ppg_unit_pushes
Definition: wap_push_ppg.c:149
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
void wap_event_dump(WAPEvent *event)
Definition: wap_events.c:181
void gwthread_join_every(gwthread_func_t *func)
int si_compile(Octstr *si_doc, Octstr *charset, Octstr **si_binary)
static int session_has_pi_client_address(void *a, void *b)
unsigned long counter_increase(Counter *counter)
Definition: counter.c:123
static Octstr * smsbox_id
Definition: smsbox.c:120
void http_header_mark_transformation(List *headers, Octstr *new_body, Octstr *new_type)
Definition: http.c:3203
WAPAddrTuple * wap_addr_tuple_duplicate(WAPAddrTuple *tuple)
Definition: wap_addr.c:125
static int user_configuration
Definition: wap_push_ppg.c:196
static void initialize_time_item_array(long time_data[], struct tm now)
Octstr * body
Definition: wap-appl.c:144
unsigned char * username
Definition: test_cimd2.c:99
static int select_bearer_network(WAPEvent **e)
void http_destroy_headers(List *headers)
Definition: http.c:2879
static int store_push_data(PPGPushMachine **pm, PPGSessionMachine *sm, WAPEvent *e, WAPAddrTuple *tuple, int cless)
static void remove_mime_headers(List **push_headers)
static PPGSessionMachine * session_find_using_pi_client_address(Octstr *addr)
static Octstr * content_header
Definition: test_ppg.c:101
static int port
Definition: fakesmsc.c:121
WAPAddr * local
Definition: wap_addr.h:74
static Octstr * from
Definition: mtbatch.c:95
static Octstr * tell_ppg_name(void)
void http_destroy_cgiargs(List *args)
Definition: http.c:2818
static Octstr * ppg_allow_ip
Definition: wap_push_ppg.c:195
static long number_of_users
Definition: wap_push_ppg.c:193
static int type_is(Octstr *content_header, char *required_type)
void http_append_headers(List *to, List *from)
Definition: http.c:3052
void http_send_reply(HTTPClient *client, int status, List *headers, Octstr *body)
Definition: http.c:2695
static struct @41 converters[]
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
static HTTPClient * response_push_message(PPGPushMachine *pm, long code, int status)
Definition: http.h:142
static Dict * urls
Definition: wap_push_ppg.c:165
Definition: cfg.c:164
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1303
static Dict * http_clients
Definition: wap_push_ppg.c:160
static Octstr * global_sender
Definition: wap_push_ppg.c:197
void * dict_remove(Dict *dict, Octstr *key)
Definition: dict.c:307
Counter * counter_create(void)
Definition: counter.c:94
void cfg_destroy(Cfg *cfg)
Definition: cfg.c:331
static void change_header_value(List **push_headers, char *name, char *value)
static void send_bad_message_response(HTTPClient **c, Octstr *body_fragment, int code, int status)
static Octstr * convert_si_to_sic(struct content *content)
static Octstr * dlr_url
Definition: test_ppg.c:107
static int pap_convert_content(struct content *content)
void * dict_get(Dict *dict, Octstr *key)
Definition: dict.c:286
HTTPClient * http_accept_request(int port, Octstr **client_ip, Octstr **url, List **headers, Octstr **body, List **cgivars)
Definition: http.c:2571
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1527
void gwlist_remove_producer(List *list)
Definition: list.c:401
Octstr * type
Definition: wap-appl.c:145
List * http_create_empty_headers(void)
Definition: http.c:2872
static long ppg_port
Definition: wap_push_ppg.c:185
int wap_push_ppg_pushuser_search_ip_from_wildcarded_list(Octstr *haystack, Octstr *needle, Octstr *gwlist_sep, Octstr *ip_sep)
static char * wina_uri[]
static PPGSessionMachine * store_session_data(PPGSessionMachine *sm, WAPEvent *e, WAPAddrTuple *tuple, int *session_exists)
void wap_event_destroy_item(void *event)
Definition: wap_events.c:130
static wap_dispatch_func_t * dispatch_to_ota
Definition: wap_push_ppg.c:176
static Octstr * set_service_name(void)
static Octstr * set_time(void)
Definition: dict.c:116
#define octstr_duplicate(ostr)
Definition: octstr.h:187
static Octstr * smsc_id
Definition: mtbatch.c:98
long octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos)
Definition: octstr.c:1102
List * cfg_get_multi_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:645
static void request_push(long last, PPGPushMachine *sm)
static int ip_allowed_by_ppg(Octstr *ip)
Definition: wap_push_ppg.c:586
int wap_push_ppg_pushuser_client_phone_number_acceptable(Octstr *username, Octstr *number)
static void pap_event_destroy(PAPEvent *p)
Definition: wap_push_ppg.c:663
#define http_header_find_first(headers, name)
Definition: http.h:603
long gwlist_delete_equal(List *list, void *item)
Definition: list.c:266
static WAPAddrTuple * addr_tuple_change_cliport(WAPAddrTuple *tuple, long port)
static Octstr * set_smsc_id(List *headers, Octstr *username, int trusted_pi)
void wap_push_ppg_init(wap_dispatch_func_t *ota_dispatch, wap_dispatch_func_t *appl_dispatch, Cfg *cfg)
Definition: wap_push_ppg.c:397
int wml_compile(Octstr *wml_text, Octstr *charset, Octstr **wml_binary, Octstr *version)
Definition: wml_compiler.c:360
static PPGPushMachine * push_machine_create(WAPEvent *e, WAPAddrTuple *tuple)
char * name
Definition: smsc_cimd2.c:212
int octstr_case_compare(const Octstr *os1, const Octstr *os2)
Definition: octstr.c:903
#define wap_event_create(type)
Definition: wap_events.h:107
static size_t desc_tab_size
static int session_has_sid(void *a, void *b)
void warning(int err, const char *fmt,...)
Definition: log.c:660
static PPGPushMachine * abort_delivery(PPGSessionMachine *sm, int status)
void http_remove_hop_headers(List *headers)
Definition: http.c:3161
void wap_push_ppg_pushuser_list_destroy(void)
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2464
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
void wap_addr_tuple_destroy(WAPAddrTuple *tuple)
Definition: wap_addr.c:108
static void pap_event_destroy_item(void *p)
Definition: wap_push_ppg.c:671
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
long port
Definition: wap_addr.h:70
static int delivery_time_constraints(WAPEvent *e, PPGPushMachine *pm)
static void session_machine_assert(PPGSessionMachine *sm)
static int deliver_before_test_cleared(Octstr *before, struct tm now)
static PPGPushMachine * find_ppg_push_machine_using_pid(PPGSessionMachine *sm, long pid)
Octstr * get_official_name(void)
Definition: socket.c:627
static long set_dlr_mask(List *headers, Octstr *dlr_url)
int wap_push_ppg_pushuser_authenticate(HTTPClient *c, List *cgivars, Octstr *ip, List *push_headers, Octstr **username)
static void ota_read_thread(void *arg)
Definition: wap_push_ppg.c:634
static void pap_event_unpack(PAPEvent *p, Octstr **ip, Octstr **url, List **push_headers, Octstr **mime_content, List **cgivars, HTTPClient **client)
Definition: wap_push_ppg.c:676
void octstr_base64_to_binary(Octstr *ostr)
Definition: octstr.c:663
int http_open_port(int port, int ssl)
Definition: http.c:2509
Octstr * mime_content
Definition: wap_push_ppg.c:212
static int session_has_addr(void *a, void *b)
WAPAddr * remote
Definition: wap_addr.h:74
static int coriented_deliverable(long code)
static int deliver_after_test_cleared(Octstr *after, struct tm now)
void http_close_all_ports(void)
Definition: http.c:2526
static long number_of_pushes
Definition: wap_push_ppg.c:191
Octstr * http_header_value(List *headers, Octstr *name)
Definition: http.c:2932
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
#define NUM_CONVERTERS
void dict_destroy(Dict *dict)
Definition: dict.c:215
long gwlist_delete_matching(List *list, void *pat, gwlist_item_matches_t *matches)
Definition: list.c:240
static PPGPushMachine * deliver_unit_push(long last, PPGPushMachine *pm, PPGSessionMachine *sm, int session_exists)
static void pap_request_thread(void *arg)
Definition: wap_push_ppg.c:746
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:759
Definition: octstr.c:118
static PAPEvent * pap_event_create(Octstr *ip, Octstr *url, List *push_headers, Octstr *mime_content, List *cgivars, HTTPClient *client)
Definition: wap_push_ppg.c:646
void * gwlist_consume(List *list)
Definition: list.c:427
static Octstr * convert_wml_to_wmlc(struct content *content)
Octstr * url
Definition: wap_push_ppg.c:210
#define NUMBER_OF_WINA_URIS
static void deliver_pending_pushes(PPGSessionMachine *sm, int last)
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:742
static description_t pap_desc[]
static Octstr * ppg_smsbox_id
Definition: wap_push_ppg.c:204
static void remove_session_data(PPGSessionMachine *sm, int status)
#define panic
Definition: log.h:87
char * transfer_encoding
void wap_push_ppg_shutdown(void)
Definition: wap_push_ppg.c:433
Octstr * charset
Definition: wap-appl.c:146
Definition: cfg.c:73
static void send_to_pi(HTTPClient **c, Octstr *reply_body, int status)
static int push_has_pi_push_id(void *a, void *b)
static void remove_link_headers(List **push_headers)
long http_header_remove_all(List *headers, char *name)
Definition: http.c:3135
WAPAddrTuple * wap_addr_tuple_create(Octstr *rmt_addr, long rmt_port, Octstr *lcl_addr, long lcl_port)
Definition: wap_addr.c:96
WAPEventName type
Definition: wap_events.h:88
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:749
void wap_push_ppg_dispatch_event(WAPEvent *e)
Definition: wap_push_ppg.c:476
static WAPAddrTuple * set_addr_tuple(Octstr *address, long cliport, long servport, long address_type, List *push_headers)
static void push_machine_destroy(void *pm)
void octstr_format_append(Octstr *os, const char *fmt,...)
Definition: octstr.c:2507
List * http_header_duplicate(List *headers)
Definition: http.c:2969
static void replace_octstr_char(Octstr *os1, Octstr *os2, long *pos)
static void create_session(WAPEvent *e, PPGPushMachine *pm)
static wap_dispatch_func_t * dispatch_to_appl
Definition: wap_push_ppg.c:177
#define gwlist_create()
Definition: list.h:136
static List * pap_queue
Definition: wap_push_ppg.c:138
int dict_put_once(Dict *dict, Octstr *key, void *value)
Definition: dict.c:271
static char * networks[]
static Octstr * ppg_deny_ip
Definition: wap_push_ppg.c:194
static int trusted_pi
Definition: wap_push_ppg.c:192
static Octstr * set_dlr_url(List *headers, Octstr *username, int trusted_pi)
static void session_machine_destroy(void *p)
CfgGroup * cfg_get_single_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:639
void gwlist_add_producer(List *list)
Definition: list.c:383
union WAPEvent::@87 u
static int get_mime_boundary(List *push_headers, Octstr *content_header, Octstr **boundary)
static PPGSessionMachine * update_session_data(PPGSessionMachine *sm, long sid, long port, List *caps)
static Octstr * url
Definition: test_xmlrpc.c:84
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:406
#define NUMBER_OF_BEARERS
#define NUMBER_OF_NETWORKS
static char * address_type(long type_of_address)
Definition: list.c:102
int mime_parse(Octstr *boundary, Octstr *mime_content, Octstr **pap_content, Octstr **push_data, List **content_headers, Octstr **rdf_content)
static PPGSessionMachine * session_machine_create(WAPAddrTuple *tuple, WAPEvent *e)
int pap_compile(Octstr *pap_content, WAPEvent **e)
HTTPClient * client
Definition: wap_push_ppg.c:208
static PPGPushMachine * find_ppg_push_machine_using_pi_push_id(PPGSessionMachine *sm, Octstr *pi_push_id)
static int handle_push_message(HTTPClient **c, WAPEvent *ppg_event, int status)
static List * ppg_machines
Definition: wap_push_ppg.c:143
void wap_event_destroy(WAPEvent *event)
Definition: wap_events.c:102
static PPGSessionMachine * update_session_data_with_headers(PPGSessionMachine *sm, PPGPushMachine *pm)
char * type
void wap_dispatch_func_t(WAPEvent *event)
Definition: wap.h:85
char * result_type
static void push_machines_list_destroy(List *pl)
PPGSessionMachine * wap_push_ppg_have_push_session_for_sid(long sid)
Definition: wap_push_ppg.c:503
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:871
static void handle_internal_event(WAPEvent *e)
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.