wap_push_pap_compiler.c
资源名称:gateway-1.2.1 [点击查看]
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:60k
源码类别:
手机WAP编程
开发平台:
WINDOWS
- /*
- * wap_push_pap_compiler.c - implementation of wap_push_pap_compiler.h inter-
- * face (compiling pap documents to Kannel WAPEvents)
- *
- * This module implements PAP document DTD and status codes, defined in
- * WAP-164-PAP-19991108-a (called hereafter pap), chapter 9 and
- * PPG client addressing (it is. parsing client address of a pap document),
- * defined in
- * WAP-151-PPGService-19990816-a (ppg), chapter 7.
- *
- * In addition, Wapforum specification WAP-200-WDP-20001212-a (wdp) is re-
- * ferred.
- *
- * Compiler can be used by PI or PPG (it will handle all possible PAP DTD
- * elements). It checks that attribute values are legal and that an element
- * has only legal attributes, but does not otherwise validate PAP documents
- * against PAP DTD. (XML validation is quite another matter, of course.)
- * Client address is parsed out from the relevant PAP message attribute
- * containing lots of additional data, see ppg, 7.1. We do not yet support
- * user defined addresses.
- *
- * After compiling, some semantic analysing of the resulted event, and sett-
- * ing some defaults (however, relying on them is quite a bad policy). In
- * addition changing undefined values (any) to defined ones.
- *
- * By Aarno Syv鋘en for Wapit Ltd and for Wiral Ltd.
- */
- #include <libxml/xmlmemory.h>
- #include <libxml/parser.h>
- #include <libxml/tree.h>
- #include <libxml/debugXML.h>
- #include <libxml/encoding.h>
- #include <ctype.h>
- #include <string.h>
- #include "shared.h"
- #include "wap_push_pap_compiler.h"
- #include "wap_push_ppg.h"
- /****************************************************************************
- *
- * Global data structures
- *
- * Table for pap elements. These are defined in PAP, Chapter 9.
- */
- static char *pap_elements[] = {
- "pap",
- "push-message",
- "address",
- "quality-of-service",
- "push-response",
- "progress-note",
- "response-result",
- "cancel-message",
- "cancel-result",
- "cancel-response",
- "resultnotification-message",
- "resultnotification-response",
- "statusquery-message",
- "statusquery-response",
- "statusquery-result",
- "ccq-message",
- "ccq-response",
- "badmessage-response"
- };
- #define NUM_ELEMENTS sizeof(pap_elements)/sizeof(pap_elements[0])
- /*
- * Table for PAP attributes. These are defined in pap, Chapter 9.
- */
- struct pap_attributes_t {
- char *name;
- char *value;
- };
- typedef struct pap_attributes_t pap_attributes_t;
- static pap_attributes_t pap_attributes[] = {
- { "product-name", NULL },
- { "push-id", NULL },
- { "deliver-before-timestamp", NULL },
- { "deliver-after-timestamp", NULL },
- { "source-reference", NULL },
- { "progress-notes-requested", "true" },
- { "progress-notes-requested", "false" },
- { "ppg-notify-requested-to", NULL },
- { "address-value", NULL },
- { "priority", "high" },
- { "priority", "medium" },
- { "priority", "low" },
- { "delivery-method", "confirmed" },
- { "delivery-method", "preferconfirmed" },
- { "delivery-method", "unconfirmed" },
- { "delivery-method", "notspecified" },
- { "network", NULL },
- { "network-required", "true" },
- { "network-required", "false" },
- { "bearer", NULL },
- { "bearer-required", "true" },
- { "bearer-required", "false" },
- { "sender-address", NULL },
- { "sender-name", NULL },
- { "reply-time", NULL },
- { "stage", NULL },
- { "note", NULL },
- { "time", NULL },
- { "code", NULL },
- { "desc", NULL },
- { "received-time", NULL },
- { "event-time", NULL },
- { "message-state", NULL },
- { "query-id", NULL },
- { "app-id", NULL },
- { "bad-message-fragment", NULL}
- };
- #define NUM_ATTRIBUTES sizeof(pap_attributes)/sizeof(pap_attributes[0])
- /*
- * Status codes are defined in pap, chapter 9.13.
- */
- static int pap_codes[] = {
- PAP_ACCEPTED_FOR_PROCESSING,
- PAP_BAD_REQUEST,
- PAP_FORBIDDEN,
- PAP_ADDRESS_ERROR,
- PAP_CAPABILITIES_MISMATCH,
- PAP_DUPLICATE_PUSH_ID,
- PAP_TRANSFORMATION_FAILURE,
- PAP_REQUIRED_BEARER_NOT_AVAILABLE,
- PAP_ABORT_USERPND
- };
- #define NUM_CODES sizeof(pap_codes)/sizeof(pap_codes[0])
- /*
- * Possible bearer types. These are defined in wdp, appendix C.
- */
- static char *pap_bearer_types[] = {
- "Any",
- "USSD",
- "SMS",
- "GUTS/R-Data",
- "CSD",
- "Packet Data",
- "GPRS",
- "CDPD",
- "FLEX",
- "SDS",
- "ReFLEX",
- "MPAK",
- "GHOST/R_DATA"
- };
- #define NUM_BEARER_TYPES sizeof(pap_bearer_types)/sizeof(pap_bearer_types[0])
- /*
- * Possible network types. These are defined in wdp, appendix C.
- */
- static char *pap_network_types[] = {
- "Any",
- "GSM",
- "ANSI-136",
- "IS-95 CDMA",
- "AMPS",
- "PDC",
- "IDEN",
- "Paging network",
- "PHS",
- "TETRA",
- "Mobitex",
- };
- #define NUM_NETWORK_TYPES sizeof(pap_network_types)/
- sizeof(pap_network_types[0])
- /****************************************************************************
- *
- * Prototypes of internal functions. Note that suffix 'Ptr' means '*'.
- */
- static int parse_document(xmlDocPtr doc_p, WAPEvent **e);
- static int parse_node(xmlNodePtr node, WAPEvent **e, long *type_of_address,
- int *is_any);
- static int parse_element(xmlNodePtr node, WAPEvent **e,
- long *type_of_address, int *is_any);
- static int parse_attribute(Octstr *element_name, xmlAttrPtr attribute,
- WAPEvent **e, long *type_of_address, int *is_any);
- static int parse_attr_value(Octstr *element_name, Octstr *attr_name,
- Octstr *attr_value, WAPEvent **e,
- long *type_of_address, int *is_any);
- static int set_attribute_value(Octstr *element_name, Octstr *attr_value,
- Octstr *attr_name, WAPEvent **e);
- static int return_flag(Octstr *ros);
- static void wap_event_accept_or_create(Octstr *element_name, WAPEvent **e);
- static int parse_push_message_value(Octstr *attr_name, Octstr *attr_value,
- WAPEvent **e);
- static int parse_address_value(Octstr *attr_name, Octstr *attr_value,
- WAPEvent **e, long *type_of_address);
- static int parse_quality_of_service_value(Octstr *attr_name,
- Octstr *attr_value, WAPEvent **e,
- int *is_any);
- static int parse_push_response_value(Octstr *attr_name, Octstr *attr_value,
- WAPEvent **e);
- static int parse_progress_note_value(Octstr *attr_name, Octstr *attr_value,
- WAPEvent **e);
- static int parse_bad_message_response_value(Octstr *attr_name,
- Octstr *attr_value, WAPEvent **e);
- static int parse_response_result_value(Octstr *attr_name,
- Octstr *attr_value, WAPEvent **e);
- static int parse_code(Octstr *attr_value);
- static Octstr *parse_bearer(Octstr *attr_value);
- static Octstr *parse_network(Octstr *attr_value);
- static int parse_requirement(Octstr *attr_value);
- static int parse_priority(Octstr *attr_value);
- static int parse_delivery_method(Octstr *attr_value);
- static int parse_state(Octstr *attr_value);
- static int parse_address(Octstr **attr_value, long *type_of_address);
- static long parse_wappush_client_address(Octstr **address, long pos,
- long *type_of_address);
- static long parse_ppg_specifier(Octstr **address, long pos);
- static long parse_client_specifier(Octstr **address, long pos,
- long *type_of_address);
- static long parse_constant(const char *field_name, Octstr **address, long pos);
- static long parse_dom_fragment(Octstr **address, long pos);
- static long drop_character(Octstr **address, long pos);
- static long parse_type(Octstr **address, Octstr **type_value, long pos);
- static long parse_ext_qualifiers(Octstr **address, long pos,
- Octstr *type_value);
- static long parse_global_phone_number(Octstr **address, long pos);
- static long parse_ipv4(Octstr **address, long pos);
- static long parse_ipv6(Octstr **address, long pos);
- static long parse_escaped_value(Octstr **address, long pos);
- static Octstr *prepend_char(Octstr *address, unsigned char c);
- static int qualifiers(Octstr *address, long pos, Octstr *type);
- static long parse_qualifier_value(Octstr **address, long pos);
- static long parse_qualifier_keyword(Octstr **address, long pos);
- static long parse_ipv4_fragment(Octstr **address, long pos);
- static long parse_ipv6_fragment(Octstr **address, long pos);
- static int wina_bearer_identifier(Octstr *type_value);
- static int create_peek_window(Octstr **address, long *pos);
- static long rest_unescaped(Octstr **address, long pos);
- static int issafe(Octstr **address, long pos);
- static long accept_safe(Octstr **address, long pos);
- static long accept_escaped(Octstr **address, long pos);
- static long handle_two_terminators (Octstr **address, long pos,
- unsigned char comma, unsigned char point, unsigned char c,
- long fragment_parsed, long fragment_length);
- static int uses_gsm_msisdn_address(long bearer_required, Octstr *bearer);
- static int uses_ipv4_address(long bearer_required, Octstr *bearer);
- static int uses_ipv6_address(long bearer_required, Octstr *bearer);
- static int event_semantically_valid(WAPEvent *e, long type_of_address);
- static char *address_type(long type_of_address);
- static void set_defaults(WAPEvent **e, long type_of_address);
- static void set_bearer_defaults(WAPEvent **e, long type_of_address);
- static void set_network_defaults(WAPEvent **e, long type_of_address);
- static int set_anys(WAPEvent **e, long type_of_address, int is_any);
- static void set_any_value(int *is_any, Octstr *attr_name, Octstr *attr_value);
- /*
- * Macro for creating an octet string from a node content. This has two
- * versions for different libxml node content implementation methods.
- */
- #ifdef XML_USE_BUFFER_CONTENT
- #define create_octstr_from_node(node) (octstr_create(node->content->content))
- #else
- #define create_octstr_from_node(node) (octstr_create(node->content))
- #endif
- /****************************************************************************
- *
- * Compile PAP control document to a corresponding Kannel event. Checks vali-
- * dity of the document. The caller must initialize wap event to NULL. In add-
- * ition, it must free memory allocated by this function.
- *
- * After compiling, some semantic analysing of the resulted event.
- *
- * Note that entities in the DTD are parameter entities and they can appear
- * only in DTD (See site http://www.w3.org/TR/REC-xml, Chapter 4.1). So we do
- * not need to worry about them in the document itself.
- *
- * Returns 0, when success
- * -1, when a non-implemented pap feature is asked for
- * -2, when error
- * In addition, returns a newly created wap event corresponding the pap
- * control message, if success, wap event NULL otherwise.
- */
- int pap_compile(Octstr *pap_content, WAPEvent **e)
- {
- xmlDocPtr doc_p;
- size_t oslen;
- int ret;
- if (octstr_search_char(pap_content, ' ', 0) != -1) {
- warning(0, "PAP COMPILER: pap_compile: pap source contained a \0"
- " character");
- return -2;
- }
- octstr_strip_blanks(pap_content);
- oslen = octstr_len(pap_content);
- doc_p = xmlParseMemory(octstr_get_cstr(pap_content), oslen);
- if (doc_p == NULL) {
- goto error;
- }
- if ((ret = parse_document(doc_p, e)) < 0) {
- goto parserror;
- }
- xmlFreeDoc(doc_p);
- return 0;
- parserror:
- xmlFreeDoc(doc_p);
- wap_event_destroy(*e);
- *e = NULL;
- return ret;
- error:
- warning(0, "PAP COMPILER: pap_compile: parse error in pap source");
- xmlFreeDoc(doc_p);
- wap_event_destroy(*e);
- *e = NULL;
- return -2;
- }
- /****************************************************************************
- *
- * Implementation of internal functions
- *
- */
- enum {
- NEITHER = 0,
- BEARER_ANY = 1,
- NETWORK_ANY = 2,
- EITHER = 3,
- ERROR_ANY = 4
- };
- /*
- * Parse the document node of libxml syntax tree. FIXME: Add parsing of pap
- * version.
- * After parsing, some semantic analysing of the resulted event. Then set
- * a default network and bearer deduced from address type, if the correspond-
- * ing pap attribute is missing.
- *
- * Returns 0, when success
- * -1, when a non-implemented pap feature is requested
- * -2, when error
- * In addition, return a newly created wap event corresponding the pap
- * control message, if success, or partially parsed pap document, if not. Set
- * a field containing address type.
- */
- static int parse_document(xmlDocPtr doc_p, WAPEvent **e)
- {
- xmlNodePtr node;
- int ret,
- is_any; /* is bearer and/or network set any in qos
- attribute */
- long type_of_address;
- gw_assert(doc_p);
- node = xmlDocGetRootElement(doc_p);
- is_any = NEITHER;
- if ((ret = parse_node(node, e, &type_of_address, &is_any)) < 0)
- return ret;
- (*e)->u.Push_Message.address_type = type_of_address;
- if ((ret= event_semantically_valid(*e, type_of_address)) == 0) {
- warning(0, "wrong type of address for requested bearer");
- return -2;
- } else if (ret == -1) {
- info(0, "reverting to default bearer and network");
- set_defaults(e, type_of_address);
- return 0;
- }
- if (!set_anys(e, type_of_address, is_any)) {
- warning(0, "unable to handle any values in qos");
- return -2;
- } else {
- debug("wap.push.pap.compiler", 0, "using defaults instead of anys");
- }
- wap_event_assert(*e);
- return 0;
- }
- static int set_anys(WAPEvent **e, long type_of_address, int is_any)
- {
- switch (is_any) {
- case NEITHER:
- return 1;
- case BEARER_ANY:
- set_bearer_defaults(e, type_of_address);
- return 1;
- case NETWORK_ANY:
- set_network_defaults(e, type_of_address);
- return 1;
- case EITHER:
- set_defaults(e, type_of_address);
- return 1;
- default:
- return 0;
- }
- }
- /*
- * We actually use address_type field of a wap event for cotrolling the bearer
- * selection. Bearer and network filed are used for debugging purposes.
- */
- static void set_defaults(WAPEvent **e, long type_of_address)
- {
- set_bearer_defaults(e, type_of_address);
- set_network_defaults(e, type_of_address);
- }
- static void set_bearer_defaults(WAPEvent **e, long type_of_address)
- {
- gw_assert(type_of_address == ADDR_USER || type_of_address == ADDR_PLMN ||
- type_of_address == ADDR_IPV4 || type_of_address == ADDR_IPV6 ||
- type_of_address == ADDR_WINA);
- if ((*e)->type != Push_Message)
- return;
- (*e)->u.Push_Message.bearer_required = PAP_TRUE;
- octstr_destroy((*e)->u.Push_Message.bearer);
- switch (type_of_address) {
- case ADDR_PLMN:
- (*e)->u.Push_Message.bearer = octstr_format("%s", "SMS");
- break;
- case ADDR_IPV4:
- (*e)->u.Push_Message.bearer = octstr_format("%s", "CSD");
- break;
- case ADDR_IPV6:
- break;
- }
- }
- static void set_network_defaults(WAPEvent **e, long type_of_address)
- {
- gw_assert(type_of_address == ADDR_USER || type_of_address == ADDR_PLMN ||
- type_of_address == ADDR_IPV4 || type_of_address == ADDR_IPV6 ||
- type_of_address == ADDR_WINA);
- if ((*e)->type != Push_Message)
- return;
- (*e)->u.Push_Message.network_required = PAP_TRUE;
- octstr_destroy((*e)->u.Push_Message.network);
- switch (type_of_address) {
- case ADDR_PLMN:
- (*e)->u.Push_Message.network = octstr_format("%s", "GSM");
- break;
- case ADDR_IPV4:
- (*e)->u.Push_Message.network = octstr_format("%s", "GSM");
- break;
- case ADDR_IPV6:
- break;
- }
- }
- static char *address_type(long type_of_address)
- {
- switch(type_of_address) {
- case ADDR_USER:
- return "user defined address";
- case ADDR_PLMN:
- return "a phone number";
- case ADDR_IPV4:
- return "a IPv4 address";
- case ADDR_IPV6:
- return "a IPv6 address";
- case ADDR_WINA:
- return "a WINA accepted address";
- default:
- return "unknown address";
- }
- }
- /*
- * Do semantic analysis, when the event was Push_Message. Do not accept an IP
- * address, when a non-IP bearer is requested, and a phone number, when an IP
- * bearer is requested.
- * Return 0, when event is unacceptable
- * 1, when it is acceptable
- * -1, when there are no bearer or network specified
- */
- static int event_semantically_valid(WAPEvent *e, long type_of_address)
- {
- int ret;
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: doing semantic analysis"
- " for address type %s", address_type(type_of_address));
- if (e->type != Push_Message) {
- return 1;
- }
- if (e->u.Push_Message.network_required !=
- e->u.Push_Message.bearer_required) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: network-required and"
- " bearer-required must have same value");
- return 0;
- }
- if (type_of_address == ADDR_PLMN) {
- if ((ret = uses_gsm_msisdn_address(
- e->u.Push_Message.bearer_required,
- e->u.Push_Message.bearer)) == 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: bearer does"
- " not accept PLMN address");
- return 0;
- } else if (ret == -1) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: network or"
- "bearer missing, reverting to GSM+SMS");
- return -1;
- } else
- return 1;
- }
- if (type_of_address == ADDR_IPV4) {
- if ((ret = uses_ipv4_address(e->u.Push_Message.bearer_required,
- e->u.Push_Message.bearer)) == 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: bearer does"
- " not accept IPv4 address");
- return 0;
- } else if (ret == -1) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: network or"
- " bearer missing, reverting to GSM+CSD");
- return -1;
- } else
- return 1;
- }
- if (type_of_address == ADDR_IPV6) {
- if ((ret = uses_ipv6_address(e->u.Push_Message.bearer_required,
- e->u.Push_Message.bearer)) == 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: network or"
- " bearer does not accept IPv6 address");
- return 0;
- } else if (ret == -1) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: network or"
- " bearer missing, reverting Any+Any");
- return -1;
- } else
- return 1;
- }
- return 0;
- }
- /*
- * Bearers accepting IP addresses. These are defined in wdp, appendix c. Note
- * that when ipv6 bearers begin to appear, they must be added to the following
- * table. Currently none are specified.
- */
- static char *ip6_bearers[] = {
- "Any"
- };
- #define NUMBER_OF_IP6_BEARERS sizeof(ip6_bearers)/sizeof(ip6_bearers[0])
- static char *ip4_bearers[] = {
- "Any",
- "CSD",
- "Packet Data",
- "GPRS",
- "USSD"
- };
- #define NUMBER_OF_IP4_BEARERS sizeof(ip4_bearers)/sizeof(ip4_bearers[0])
- /*
- * Bearers accepting gsm msisdn addresses are defined in wdp, appendix c. We
- * add any, because Kannel PPG will change this to SMS.
- * Return -1, when there are no bearer defined
- * 0, when a bearer not accepting msisdn address is found
- * 1, when a bearer is accepting msisdn addresesses
- */
- static int uses_gsm_msisdn_address(long bearer_required, Octstr *bearer)
- {
- if (!bearer_required)
- return -1;
- if (!bearer)
- return 1;
- return (octstr_case_compare(bearer, octstr_imm("SMS")) == 0 ||
- octstr_case_compare(bearer, octstr_imm("GHOST/R_DATA")) == 0 ||
- octstr_case_compare(bearer, octstr_imm("Any")) == 0);
- }
- /*
- * Bearers accepting ipv4 addresses are defined in wdp, appendix c.
- * Return -1, when there are no bearer defined
- * 0, when a bearer not accepting ipv4 address is found
- * 1, when a bearer is accepting ipv4 addresesses
- */
- static int uses_ipv4_address(long bearer_required, Octstr *bearer)
- {
- long i;
- if (!bearer_required) {
- return -1;
- }
- if (!bearer)
- return -1;
- i = 0;
- while (i < NUMBER_OF_IP4_BEARERS) {
- if (octstr_case_compare(bearer, octstr_imm(ip4_bearers[i])) == 0) {
- return 1;
- }
- ++i;
- }
- return 0;
- }
- /*
- * Bearers accepting ipv6 addresses (currently *not* accepting) are defined in
- * wdp, appendix c.
- * Return -1, when there are no bearer defined
- * 0, when a bearer not accepting ipv6 address is found
- * 1, when a bearer is accepting ipv6 addresesses
- */
- static int uses_ipv6_address(long bearer_required, Octstr *bearer)
- {
- long i;
- if (!bearer_required)
- return -1;
- if (!bearer)
- return -1;
- i = 0;
- while (i < NUMBER_OF_IP6_BEARERS) {
- if (octstr_case_compare(bearer, octstr_imm(ip6_bearers[i])) == 0) {
- return 1;
- }
- ++i;
- }
- return 0;
- }
- /*
- * Parse node of the syntax tree. DTD, as defined in pap, chapter 9, contains
- * only elements (entities are restricted to DTDs).
- * The caller must initialize the value of is_any to 0.
- *
- * Output: a) a newly created wap event containing attributes from pap
- * document node, if success; partially parsed node, if not.
- * b) the type of of the client address
- * c) is bearer and/or network any
- * Returns 0, when success
- * -1, when a non-implemented feature is requested
- * -2, when error
- */
- static int parse_node(xmlNodePtr node, WAPEvent **e, long *type_of_address,
- int *is_any)
- {
- int ret;
- switch (node->type) {
- case XML_COMMENT_NODE: /* ignore text, comments and pi nodes */
- case XML_PI_NODE:
- case XML_TEXT_NODE:
- break;
- case XML_ELEMENT_NODE:
- if ((ret = parse_element(node, e, type_of_address, is_any)) < 0) {
- return ret;
- }
- break;
- default:
- warning(0, "PAP COMPILER: parse_node: Unknown XML node in PAP source");
- return -2;
- }
- if (node->children != NULL)
- if ((ret = parse_node(node->children, e, type_of_address,
- is_any)) < 0) {
- return ret;
- }
- if (node->next != NULL)
- if ((ret = parse_node(node->next, e, type_of_address, is_any)) < 0) {
- return ret;
- }
- return 0;
- }
- /*
- * Parse elements of a PAP source.
- *
- * Output: a) a newly created wap event containing attributes from the
- * element, if success; containing some unparsed attributes, if not.
- * b) the type of the client address
- * c) is bearer and/or network any
- * Returns 0, when success
- * -1, when a non-implemented feature is requested
- * -2, when error
- * In addition, return
- */
- static int parse_element(xmlNodePtr node, WAPEvent **e, long *type_of_address,
- int *is_any)
- {
- Octstr *name;
- xmlAttrPtr attribute;
- size_t i;
- int ret;
- name = octstr_create(node->name);
- if (octstr_len(name) == 0) {
- octstr_destroy(name);
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: element name length"
- " zero");
- return -2;
- }
- i = 0;
- while (i < NUM_ELEMENTS) {
- if (octstr_compare(name, octstr_imm(pap_elements[i])) == 0)
- break;
- ++i;
- }
- if (i == NUM_ELEMENTS) {
- octstr_destroy(name);
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown element");
- return -2;
- }
- if (node->properties != NULL) {
- attribute = node->properties;
- while (attribute != NULL) {
- if ((ret = parse_attribute(name, attribute, e,
- type_of_address, is_any)) < 0) {
- octstr_destroy(name);
- return ret;
- }
- attribute = attribute->next;
- }
- }
- octstr_destroy(name);
- return 0; /* If we reach this point, our node does not
- have any attributes left (or it had no
- attributes to start with). This is *not*
- an error. */
- }
- /*
- * Parse attribute updates corresponding fields of the wap event. Check that
- * both attribute name and value are papwise legal. If value is enumerated,
- * legal values are stored in the attributes table. Otherwise, call a separate
- * parsing function. If an attribute value is empty, use value "erroneous".
- *
- * Output: a) a newly created wap event containing parsed attribute from pap
- * source, if successfull, an uncomplete wap event otherwise.
- * b) the type of the client address
- * c) is bearer and/or network set any
- * Returns 0, when success
- * -1, when a non-implemented feature is requested
- * -2, when error
- */
- static int parse_attribute(Octstr *element_name, xmlAttrPtr attribute,
- WAPEvent **e, long *type_of_address, int *is_any)
- {
- Octstr *attr_name, *value, *nameos;
- size_t i;
- int ret;
- nameos = octstr_imm("erroneous");
- attr_name = octstr_create(attribute->name);
- if (attribute->children != NULL)
- value = create_octstr_from_node(attribute->children);
- else
- value = octstr_imm("erroneous");
- i = 0;
- while (i < NUM_ATTRIBUTES) {
- if (octstr_compare(attr_name, nameos =
- octstr_imm(pap_attributes[i].name)) == 0)
- break;
- ++i;
- }
- if (i == NUM_ATTRIBUTES) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown attribute");
- goto error;
- }
- /*
- * Parse an attribute (it is, check cdata is has for a value) that is *not* an
- * enumeration. Legal values are defined in pap, chapter 9.
- */
- if (pap_attributes[i].value == NULL) {
- ret = parse_attr_value(element_name, attr_name, value, e,
- type_of_address, is_any);
- if (ret == -2) {
- goto error;
- } else {
- goto parsed;
- }
- }
- while (octstr_compare(attr_name,
- nameos = octstr_imm(pap_attributes[i].name)) == 0) {
- if (octstr_compare(value, octstr_imm(pap_attributes[i].value)) == 0)
- break;
- ++i;
- }
- if (octstr_compare(attr_name, nameos) != 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown attribute"
- " value");
- goto error;
- }
- /*
- * Check that the value of the attribute is one enumerated for this attribute
- * in pap, chapter 9.
- */
- if (set_attribute_value(element_name, value, attr_name, e) == -1)
- goto error;
- octstr_destroy(attr_name);
- octstr_destroy(value);
- return 0;
- error:
- octstr_destroy(attr_name);
- octstr_destroy(value);
- return -2;
- parsed:
- octstr_destroy(attr_name);
- octstr_destroy(value);
- return ret;
- }
- /*
- * Value parsing functions return the newly created wap event containing
- * attribute value from pap source, if successfull; NULL otherwise . Value
- * types of attributes are defined in pap, chapter 9.
- */
- static int parse_push_message_value(Octstr *attr_name, Octstr *attr_value,
- WAPEvent **e)
- {
- Octstr *ros;
- ros = octstr_imm("erroneous");
- if (octstr_compare(attr_name, octstr_imm("push-id")) == 0) {
- octstr_destroy((**e).u.Push_Message.pi_push_id);
- (**e).u.Push_Message.pi_push_id = octstr_duplicate(attr_value);
- return 0;
- } else if (octstr_compare(attr_name,
- octstr_imm("deliver-before-timestamp")) == 0) {
- (**e).u.Push_Message.deliver_before_timestamp =
- (ros = parse_date(attr_value)) ?
- octstr_duplicate(attr_value) : octstr_imm("erroneous");
- return return_flag(ros);
- } else if (octstr_compare(attr_name,
- octstr_imm("deliver-after-timestamp")) == 0) {
- (**e).u.Push_Message.deliver_after_timestamp =
- (ros = parse_date(attr_value)) ?
- octstr_duplicate(attr_value) : octstr_imm("erroneous");
- return return_flag(ros);
- } else if (octstr_compare(attr_name,
- octstr_imm("source-reference")) == 0) {
- (**e).u.Push_Message.source_reference = octstr_duplicate(attr_value);
- return 0;
- } else if (octstr_compare(attr_name,
- octstr_imm("ppg-notify-requested-to")) == 0) {
- (**e).u.Push_Message.ppg_notify_requested_to =
- octstr_duplicate(attr_value);
- return 0;
- }
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown push message"
- " element attribute");
- return -2;
- }
- /*
- * When there is no legal address to be stored in field (either parsing was
- * unsuccessfull or an unimplemented address format was requested by the push
- * initiator) we use value "erroneous". This is necessary, because this a
- * mandatory field.
- *
- * Output a) a newly created wap event
- * b) the type of the client address
- */
- static int parse_address_value(Octstr *attr_name, Octstr *attr_value,
- WAPEvent **e, long *type_of_address)
- {
- int ret;
- ret = -2;
- if (octstr_compare(attr_name, octstr_imm("address-value")) == 0) {
- octstr_destroy((**e).u.Push_Message.address_value);
- (**e).u.Push_Message.address_value =
- (ret = parse_address(&attr_value, type_of_address)) > -1 ?
- octstr_duplicate(attr_value) : octstr_imm("erroneous");
- return ret;
- }
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown address element"
- " attribute");
- return -2;
- }
- static int parse_quality_of_service_value(Octstr *attr_name,
- Octstr *attr_value, WAPEvent **e,
- int *is_any)
- {
- Octstr *ros;
- ros = octstr_imm("erroneous");
- if (octstr_compare(attr_name, octstr_imm("network")) == 0) {
- (**e).u.Push_Message.network = (ros = parse_network(attr_value)) ?
- octstr_duplicate(attr_value) : octstr_imm("erroneous");
- set_any_value(is_any, attr_name, attr_value);
- return return_flag(ros);
- }
- if (octstr_compare(attr_name, octstr_imm("bearer")) == 0) {
- (**e).u.Push_Message.bearer = (ros = parse_bearer(attr_value)) ?
- octstr_duplicate(attr_value) : octstr_imm("erroneous");
- set_any_value(is_any, attr_name, attr_value);
- return return_flag(ros);
- }
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown quality of"
- " service attribute");
- return -2;
- }
- static void set_any_value(int *is_any, Octstr *attr_name, Octstr *attr_value)
- {
- switch (*is_any) {
- case NEITHER:
- if (octstr_compare(attr_name, octstr_imm("bearer")) == 0 &&
- octstr_case_compare(attr_value, octstr_imm("any")) == 0)
- *is_any = BEARER_ANY;
- else if (octstr_compare(attr_name, octstr_imm("network")) == 0 &&
- octstr_case_compare(attr_value, octstr_imm("any")) == 0)
- *is_any = NETWORK_ANY;
- return;
- case BEARER_ANY:
- if (octstr_compare(attr_name, octstr_imm("network")) == 0 &&
- octstr_case_compare(attr_value, octstr_imm("any")) == 0)
- *is_any = EITHER;
- return;
- case NETWORK_ANY:
- if (octstr_compare(attr_name, octstr_imm("bearer")) == 0 &&
- octstr_case_compare(attr_value, octstr_imm("any")) == 0)
- *is_any = EITHER;
- return;
- case EITHER:
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: problems with"
- " setting any");
- *is_any = ERROR_ANY;
- return;
- default:
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: wrong any value");
- *is_any = ERROR_ANY;
- return;
- }
- }
- static int parse_push_response_value(Octstr *attr_name, Octstr *attr_value,
- WAPEvent **e)
- {
- Octstr *ros;
- int ret;
- ret = -2;
- ros = octstr_imm("erroneous");
- if (octstr_compare(attr_name, octstr_imm("push-id")) == 0) {
- octstr_destroy((**e).u.Push_Response.pi_push_id);
- (**e).u.Push_Response.pi_push_id = octstr_duplicate(attr_value);
- return 0;
- } else if (octstr_compare(attr_name, octstr_imm("sender-address")) == 0) {
- (**e).u.Push_Response.sender_address = octstr_duplicate(attr_value);
- return 0;
- } else if (octstr_compare(attr_name, octstr_imm("reply-time")) == 0) {
- (**e).u.Push_Response.reply_time = (ros = parse_date(attr_value)) ?
- octstr_duplicate(attr_value) : NULL;
- return return_flag(ros);
- } else if (octstr_compare(attr_name, octstr_imm("sender-name")) == 0) {
- (**e).u.Push_Response.sender_name = octstr_duplicate(attr_value);
- return 0;
- }
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown push response"
- " element attribute");
- return -2;
- }
- static int parse_progress_note_value(Octstr *attr_name, Octstr *attr_value,
- WAPEvent **e)
- {
- Octstr *ros;
- int ret;
- ret = -2;
- ros = octstr_imm("erroneous");
- if (octstr_compare(attr_name, octstr_imm("stage")) == 0) {
- (**e).u.Progress_Note.stage =
- (ret = parse_state(attr_value)) ? ret : 0;
- return ret;
- } else if (octstr_compare(attr_name, octstr_imm("note")) == 0) {
- (**e).u.Progress_Note.note = octstr_duplicate(attr_value);
- return 0;
- } else if (octstr_compare(attr_name, octstr_imm("time")) == 0) {
- (**e).u.Progress_Note.time = (ros = parse_date(attr_value)) ?
- octstr_duplicate(attr_value) : octstr_imm("erroneous");
- return return_flag(ros);
- }
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown progress note"
- " element attribute");
- return -2;
- }
- static int parse_bad_message_response_value(Octstr *attr_name,
- Octstr *attr_value, WAPEvent **e)
- {
- if (octstr_compare(attr_name, octstr_imm("code")) == 0) {
- (**e).u.Bad_Message_Response.code = parse_code(attr_value);
- return 0;
- } else if (octstr_compare(attr_name, octstr_imm("desc")) == 0) {
- (**e).u.Bad_Message_Response.desc = octstr_duplicate(attr_value);
- return 0;
- } else if (octstr_compare(attr_name,
- octstr_imm("bad-message-fragment")) == 0) {
- (**e).u.Bad_Message_Response.bad_message_fragment =
- octstr_duplicate(attr_value);
- return 0;
- }
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown bad message"
- " response element attribute");
- return -2;
- }
- static int parse_response_result_value(Octstr *attr_name,
- Octstr *attr_value, WAPEvent **e)
- {
- if (octstr_compare(attr_name, octstr_imm("code")) == 0) {
- (**e).u.Push_Response.code = parse_code(attr_value);
- return 0;
- } else if (octstr_compare(attr_name, octstr_imm("desc")) == 0) {
- (**e).u.Push_Response.desc = octstr_duplicate(attr_value);
- return 0;
- }
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown response result"
- " attribute");
- return -2;
- }
- /*
- * Do not create multiple events. If *e points to NULL, we have not yet creat-
- * ed a wap event. Create a wap event mandatory fields set to error values
- * (these will be latter overwritten). This hack will disappear when we have
- * PAP validation.
- */
- static void wap_event_accept_or_create(Octstr *element_name, WAPEvent **e)
- {
- if (octstr_compare(element_name, octstr_imm("push-message")) == 0
- && *e == NULL) {
- *e = wap_event_create(Push_Message);
- (**e).u.Push_Message.pi_push_id = octstr_format("%s", "erroneous");
- (**e).u.Push_Message.address_value = octstr_format("%s", "erroneous");
- } else if (octstr_compare(element_name, octstr_imm("push-response")) == 0
- && *e == NULL) {
- *e = wap_event_create(Push_Response);
- (**e).u.Push_Response.pi_push_id = octstr_format("%s", "erroneous");
- } else if (octstr_compare(element_name, octstr_imm("progress-note")) == 0
- && *e == NULL) {
- *e = wap_event_create(Progress_Note);
- } else if (octstr_compare(element_name,
- octstr_imm("badmessage-response")) == 0 && *e == NULL) {
- *e = wap_event_create(Bad_Message_Response);
- }
- }
- static int return_flag(Octstr *ros)
- {
- if (ros) {
- return 0;
- } else {
- return -2;
- }
- }
- /*
- * Validates non-enumeration attributes and stores their value to a newly
- * created wap event e. (Even when attribute value parsing was not success-
- * full.) We do not accept NULL or empty attributes (if this kind of an
- * attribute is optional, we just drop it from the tokenised document).
- *
- * Output: a) a wap event, as created by subroutines
- * b) the type of the client address
- * c) is bearer or network set any
- * Returns 0, when success,
- * -1, when a non-implemented feature requested.
- * -2, when an error
- */
- static int parse_attr_value(Octstr *element_name, Octstr *attr_name,
- Octstr *attr_value, WAPEvent **e,
- long *type_of_address, int *is_any)
- {
- if (octstr_compare(attr_value, octstr_imm("erroneous")) == 0) {
- debug("wap.push.pap.compiler", 0, "unknown value for an attribute");
- return -2;
- }
- wap_event_accept_or_create(element_name, e);
- if (octstr_compare(element_name, octstr_imm("push-message")) == 0) {
- return parse_push_message_value(attr_name, attr_value, e);
- } else if (octstr_compare(element_name, octstr_imm("address")) == 0) {
- return parse_address_value(attr_name, attr_value, e, type_of_address);
- } else if (octstr_compare(element_name,
- octstr_imm("quality-of-service")) == 0) {
- return parse_quality_of_service_value(attr_name, attr_value, e,
- is_any);
- } else if (octstr_compare(element_name,
- octstr_imm("push-response")) == 0) {
- return parse_push_response_value(attr_name, attr_value, e);
- } else if (octstr_compare(element_name,
- octstr_imm("progress-note")) == 0) {
- return parse_progress_note_value(attr_name, attr_value, e);
- } else if (octstr_compare(element_name,
- octstr_imm("badmessage-response")) == 0) {
- return parse_bad_message_response_value(attr_name, attr_value, e);
- } else if (octstr_compare(element_name,
- octstr_imm("response-result")) == 0) {
- return parse_response_result_value(attr_name, attr_value, e);
- }
- return -2;
- }
- /*
- * Stores values of enumeration fields of a pap control message to wap event e.
- */
- static int set_attribute_value(Octstr *element_name, Octstr *attr_value,
- Octstr *attr_name, WAPEvent **e)
- {
- int ret;
- ret = -2;
- if (octstr_compare(element_name, octstr_imm("push-message")) == 0) {
- if (octstr_compare(attr_name,
- octstr_imm("progress-notes-requested")) == 0)
- (**e).u.Push_Message.progress_notes_requested =
- (ret = parse_requirement(attr_value)) >= 0 ? ret : 0;
- } else if (octstr_compare(element_name,
- octstr_imm("quality-of-service")) == 0) {
- if (octstr_compare(attr_name, octstr_imm("priority")) == 0)
- (**e).u.Push_Message.priority =
- (ret = parse_priority(attr_value)) >= 0 ? ret : 0;
- else if (octstr_compare(attr_name, octstr_imm("delivery-method")) == 0)
- (**e).u.Push_Message.delivery_method =
- (ret = parse_delivery_method(attr_value)) >= 0 ? ret : 0;
- else if (octstr_compare(attr_name,
- octstr_imm("network-required")) == 0)
- (**e).u.Push_Message.network_required =
- (ret = parse_requirement(attr_value)) >= 0 ? ret : 0;
- else if (octstr_compare(attr_name, octstr_imm("bearer-required")) == 0)
- (**e).u.Push_Message.bearer_required =
- (ret = parse_requirement(attr_value)) >= 0 ? ret : 0;
- }
- return ret;
- }
- /*
- * We must recognize status class and treat unrecognized codes as a x000 code,
- * as required by pap, 9.13, p 27.
- */
- static int parse_code(Octstr *attr_value)
- {
- long attr_as_number,
- len;
- size_t i;
- Octstr *ros;
- for (i = 0; i < NUM_CODES; i++) {
- ros = octstr_format("%d", pap_codes[i]);
- if (octstr_compare(attr_value, ros) == 0) {
- octstr_destroy(ros);
- return pap_codes[i];
- }
- octstr_destroy(ros);
- }
- warning(0, "PAP COMPILER: parse_code: no such return code, reversing to"
- " x000 code");
- len = octstr_parse_long(&attr_as_number, attr_value, 0, 10);
- if (attr_as_number >= PAP_OK && attr_as_number < PAP_BAD_REQUEST) {
- attr_as_number = PAP_OK;
- } else if (attr_as_number >= PAP_BAD_REQUEST &&
- attr_as_number < PAP_INTERNAL_SERVER_ERROR) {
- attr_as_number = PAP_BAD_REQUEST;
- } else if (attr_as_number >= PAP_INTERNAL_SERVER_ERROR &&
- attr_as_number < PAP_SERVICE_FAILURE) {
- attr_as_number = PAP_INTERNAL_SERVER_ERROR;
- } else if (attr_as_number >= PAP_SERVICE_FAILURE &&
- attr_as_number < PAP_CLIENT_ABORTED) {
- attr_as_number = PAP_SERVICE_FAILURE;
- } else {
- attr_as_number = PAP_CLIENT_ABORTED;
- }
- return attr_as_number;
- }
- static Octstr *parse_bearer(Octstr *attr_value)
- {
- size_t i;
- Octstr *ros;
- for (i = 0; i < NUM_BEARER_TYPES; i++) {
- if (octstr_case_compare(attr_value,
- ros = octstr_imm(pap_bearer_types[i])) == 0)
- return ros;
- }
- warning(0, "no such bearer");
- return NULL;
- }
- static Octstr *parse_network(Octstr *attr_value)
- {
- size_t i;
- Octstr *ros;
- for (i = 0; i < NUM_NETWORK_TYPES; i++) {
- if (octstr_case_compare(attr_value,
- ros = octstr_imm(pap_network_types[i])) == 0) {
- return ros;
- }
- }
- warning(0, "no such network");
- return NULL;
- }
- /*
- * Used for attributes accepting logical values.
- */
- static int parse_requirement(Octstr *attr_value)
- {
- long attr_as_number;
- attr_as_number = -2;
- if (octstr_case_compare(attr_value, octstr_imm("false")) == 0)
- attr_as_number = PAP_FALSE;
- else if (octstr_case_compare(attr_value, octstr_imm("true")) == 0)
- attr_as_number = PAP_TRUE;
- else
- warning(0, "in a requirement, value not a truth value");
- return attr_as_number;
- }
- /*
- * Priority is defined in pap, chapter 9.2.2.
- */
- static int parse_priority(Octstr *attr_value)
- {
- long attr_as_number;
- attr_as_number = -2;
- if (octstr_case_compare(attr_value, octstr_imm("high")) == 0)
- attr_as_number = PAP_HIGH;
- else if (octstr_case_compare(attr_value, octstr_imm("medium")) == 0)
- attr_as_number = PAP_MEDIUM;
- else if (octstr_case_compare(attr_value, octstr_imm("low")) == 0)
- attr_as_number = PAP_LOW;
- else
- warning(0, "illegal priority");
- return attr_as_number;
- }
- /*
- * Delivery-method is defined in pap, chapter 9.2.2.
- */
- static int parse_delivery_method(Octstr *attr_value)
- {
- long attr_as_number;
- attr_as_number = -2;
- if (octstr_case_compare(attr_value, octstr_imm("confirmed")) == 0)
- attr_as_number = PAP_CONFIRMED;
- else if (octstr_case_compare(attr_value,
- octstr_imm("preferconfirmed")) == 0)
- attr_as_number = PAP_PREFERCONFIRMED;
- else if (octstr_case_compare(attr_value, octstr_imm("unconfirmed")) == 0)
- attr_as_number = PAP_UNCONFIRMED;
- else if (octstr_case_compare(attr_value, octstr_imm("notspecified")) == 0)
- attr_as_number = PAP_NOT_SPECIFIED;
- else
- warning(0, "illegal delivery method");
- return attr_as_number;
- }
- /*
- * PAP states are defined in ppg, chapter 6.
- */
- static int parse_state(Octstr *attr_value)
- {
- long attr_as_number;
- attr_as_number = -2;
- if (octstr_case_compare(attr_value, octstr_imm("undeliverable")) == 0)
- attr_as_number = PAP_UNDELIVERABLE;
- else if (octstr_case_compare(attr_value, octstr_imm("pending")) == 0)
- attr_as_number = PAP_PENDING;
- else if (octstr_case_compare(attr_value, octstr_imm("expired")) == 0)
- attr_as_number = PAP_EXPIRED;
- else if (octstr_case_compare(attr_value, octstr_imm("delivered")) == 0)
- attr_as_number = PAP_DELIVERED;
- else if (octstr_case_compare(attr_value, octstr_imm("aborted")) == 0)
- attr_as_number = PAP_ABORTED;
- else if (octstr_case_compare(attr_value, octstr_imm("timeout")) == 0)
- attr_as_number = PAP_TIMEOUT;
- else if (octstr_case_compare(attr_value, octstr_imm("cancelled")) == 0)
- attr_as_number = PAP_CANCELLED;
- else
- warning(0, "illegal ppg state");
- return attr_as_number;
- }
- /*
- * Check legality of pap client address attribute and transform it to the
- * client address usable in Kannel wap address tuple data type. The grammar
- * for client address is specified in ppg, chapter 7.1.
- *
- * Output: the address type of the client address
- * Returns: 0, when success
- * -1, a non-implemented pap feature requested by pi
- * -2, address parsing error
- */
- static int parse_address(Octstr **address, long *type_of_address)
- {
- long pos;
- Octstr *copy;
- pos = octstr_len(*address) - 1;
- /*
- * Delete first separator, if there is one. This will help our parsing later.
- */
- if (octstr_get_char(*address, 0) == '/')
- octstr_delete(*address, 0, 1);
- if ((pos = parse_ppg_specifier(address, pos)) < 0) {
- warning(0, "illegal ppg specifier");
- return -2;
- }
- if ((pos = parse_wappush_client_address(address, pos,
- type_of_address)) == -2) {
- warning(0, "illegal client address");
- return -2;
- } else if (pos == -1) {
- warning(0, "unimplemented feature");
- return -1;
- }
- info(0, "client address was <%s>, accepted",
- octstr_get_cstr(copy = octstr_duplicate(*address)));
- octstr_destroy(copy);
- return pos;
- }
- /*
- * Output: the type of the client address
- */
- static long parse_wappush_client_address(Octstr **address, long pos,
- long *type_of_address)
- {
- if ((pos = parse_client_specifier(address, pos, type_of_address)) < 0) {
- return pos;
- }
- pos = parse_constant("WAPPUSH", address, pos);
- return pos;
- }
- /*
- * We are not interested of ppg specifier, but we must check its format.
- */
- static long parse_ppg_specifier(Octstr **address, long pos)
- {
- if (pos >= 0) {
- pos = parse_dom_fragment(address, pos);
- }
- while (octstr_get_char(*address, pos) != '@' && pos >= 0) {
- if (octstr_get_char(*address, pos) == '.') {
- octstr_delete(*address, pos, 1);
- --pos;
- } else {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: missing"
- " separator .");
- return -2;
- }
- pos = parse_dom_fragment(address, pos);
- }
- pos = drop_character(address, pos);
- if (octstr_get_char(*address, pos) == '/' && pos >= 0) {
- octstr_delete(*address, pos, 1);
- if (pos > 0)
- --pos;
- }
- if (pos < 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: missing separator /"
- " or @");
- return -2;
- }
- return pos;
- }
- /*
- * Output: the type of a client address.
- *
- * Return a negative value, when error, positive (the position of the parsing
- * cursor) otherwise.
- */
- static long parse_client_specifier(Octstr **address, long pos,
- long *type_of_address)
- {
- Octstr *type_value;
- type_value = octstr_create("");
- if ((pos = parse_type(address, &type_value, pos)) < 0) {
- goto parse_error;
- }
- pos = drop_character(address, pos);
- if ((pos = parse_constant("/TYPE", address, pos)) < 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: constant TYPE"
- " missing from the client address");
- goto parse_error;
- }
- if (octstr_case_compare(type_value, octstr_imm("USER")) == 0) {
- *type_of_address = ADDR_USER;
- goto not_implemented;
- }
- if ((pos = parse_ext_qualifiers(address, pos, type_value)) < 0) {
- goto parse_error;
- }
- if (octstr_case_compare(type_value, octstr_imm("PLMN")) == 0) {
- *type_of_address = ADDR_PLMN;
- pos = parse_global_phone_number(address, pos);
- }
- else if (octstr_case_compare(type_value, octstr_imm("IPv4")) == 0) {
- *type_of_address = ADDR_IPV4;
- pos = parse_ipv4(address, pos);
- }
- else if (octstr_case_compare(type_value, octstr_imm("IPv6")) == 0) {
- *type_of_address = ADDR_IPV6;
- pos = parse_ipv6(address, pos);
- }
- else if (wina_bearer_identifier(type_value)) {
- *type_of_address = ADDR_WINA;
- pos = parse_escaped_value(address, pos);
- }
- else {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: wrong address type"
- " in the client address");
- goto parse_error;
- }
- octstr_destroy(type_value);
- return pos;
- not_implemented:
- octstr_destroy(type_value);
- return -1;
- parse_error:
- octstr_destroy(type_value);
- return -2;
- }
- static long parse_constant(const char *field_name, Octstr **address, long pos)
- {
- size_t i,
- size;
- Octstr *nameos;
- nameos = octstr_format("%s", field_name);
- size = octstr_len(nameos);
- i = 0;
- while (octstr_get_char(*address, pos - i) ==
- octstr_get_char(nameos, size-1 - i) && i < size) {
- ++i;
- }
- while (octstr_get_char(*address, pos) !=
- octstr_get_char(nameos, 0) && pos >= 0) {
- pos = drop_character(address, pos);
- }
- pos = drop_character(address, pos);
- if (pos < 0 || i != size) {
- debug("wap.push.pap.compiler", 0, "parse_constant: unparsable"
- " constant %s", field_name);
- octstr_destroy(nameos);
- return -2;
- }
- octstr_destroy(nameos);
- return pos;
- }
- static long parse_dom_fragment(Octstr **address, long pos)
- {
- unsigned char c;
- if (pos >= 0) {
- if (isalnum(octstr_get_char(*address, pos))) {
- pos = drop_character(address, pos);
- } else
- return -2;
- }
- while ((c = octstr_get_char(*address, pos)) != '@' &&
- octstr_get_char(*address, pos) != '.' && pos >= 0) {
- if (isalnum(c) || c == '-') {
- pos = drop_character(address, pos);
- } else
- return -2;
- }
- return pos;
- }
- static long drop_character(Octstr **address, long pos)
- {
- if (pos >= 0) {
- octstr_delete(*address, pos, 1);
- if (pos > 0)
- --pos;
- }
- return pos;
- }
- static long parse_type(Octstr **address, Octstr **type_value, long pos)
- {
- unsigned char c;
- while ((c = octstr_get_char(*address, pos)) != '=' && pos >= 0) {
- *type_value = prepend_char(*type_value, c);
- pos = drop_character(address, pos);
- }
- if (pos < 0)
- return -2;
- return pos;
- }
- static long parse_ext_qualifiers(Octstr **address, long pos,
- Octstr *type)
- {
- int ret;
- while ((ret = qualifiers(*address, pos, type)) == 1) {
- if ((pos = parse_qualifier_value(address, pos)) < 0)
- return pos;
- if ((pos = parse_qualifier_keyword(address, pos)) < 0)
- return pos;
- }
- if (ret == 1) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: erroneous qualifiers"
- " in the client address");
- return -2;
- }
- return pos;
- }
- /*
- * According to ppg, chapter 7.1, global phone number starts with +. Phone
- * number is here an unique identifier, so if it does not conform the inter-
- * national format, we return an error. (Is up to bearerbox to transform it
- * to an usable phone number)
- */
- static long parse_global_phone_number(Octstr **address, long pos)
- {
- unsigned char c;
- while ((c = octstr_get_char(*address, pos)) != '+' && pos >= 0) {
- if (!isdigit(c) && c != '-' && c != '.') {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: wrong separator"
- " in a phone number (- and . allowed)");
- return -2;
- } else {
- --pos;
- }
- }
- if (pos == 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER:a phone number must"
- " start with +");
- return -2;
- }
- if (pos > 0)
- --pos;
- pos = drop_character(address, pos);
- return pos;
- }
- static long parse_ipv4(Octstr **address, long pos)
- {
- long i;
- if ((pos = parse_ipv4_fragment(address, pos)) < 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: wrong separator in a"
- " ipv4 address");
- return -2;
- }
- i = 1;
- while (i <= 3 && octstr_get_char(*address, pos) != '=' && pos >= 0) {
- pos = parse_ipv4_fragment(address, pos);
- ++i;
- }
- if (pos == 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: missing separator at"
- " beginning of a client address (=)");
- return -2;
- }
- return pos;
- }
- static long parse_ipv6(Octstr **address, long pos)
- {
- long i;
- if ((pos = parse_ipv6_fragment(address, pos)) < 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: wrong separator in a"
- " ipv6 address");
- return -2;
- }
- i = 1;
- while (i <= 7 && octstr_get_char(*address, pos) != '=' && pos >= 0) {
- pos = parse_ipv6_fragment(address, pos);
- ++i;
- }
- if (pos == 0) {
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: missing separator at"
- " beginning of a client address (=)");
- return -2;
- }
- return pos;
- }
- /*
- * WINA web page does not include address type identifiers. Following ones are
- * from wdp, Appendix C.
- */
- static char *bearer_address[] = {
- "GSM_MSISDN",
- "ANSI_136_MSISDN",
- "IS_637_MSISDN",
- "iDEN_MSISDN",
- "FLEX_MSISDN",
- "PHS_MSISDN",
- "GSM_Service_Code",
- "TETRA_ITSI",
- "TETRA_MSISDN",
- "ReFLEX_MSIDDN",
- "MAN",
- };
- static size_t bearer_address_size = sizeof(bearer_address) /
- sizeof(bearer_address[0]);
- static int wina_bearer_identifier(Octstr *type_value)
- {
- size_t i;
- i = 0;
- while (i < bearer_address_size) {
- if (octstr_case_compare(type_value,
- octstr_imm(bearer_address[i])) == 0)
- return 1;
- ++i;
- }
- debug("wap.push.pap.compiler", 0, "PAP COMPILER: a bearer not registered"
- " by wina");
- return 0;
- }
- /*
- * Note that we parse backwards. First we create a window of three characters
- * (representing a possible escaped character). If the first character of the
- * window is not escape, we handle the last character and move the window one
- * character backwards; if it is, we handle escaped sequence and create a new
- * window. If we cannot create a window, rest of characters are unescaped.
- */
- static long parse_escaped_value(Octstr **address, long pos)
- {
- int ret;
- if (create_peek_window(address, &pos) == 0)
- if ((pos = rest_unescaped(address, pos)) == -2)
- return -2;
- while (octstr_get_char(*address, pos) != '=' && pos >= 0) {
- if ((ret = issafe(address, pos)) == 1) {
- pos = accept_safe(address, pos);
- } else if (ret == 0) {
- if ((pos = accept_escaped(address, pos)) < 0)
- return -2;
- if (create_peek_window(address, &pos) == 0)
- if ((pos = rest_unescaped(address, pos)) == -2)
- return -2;
- }
- }
- pos = drop_character(address, pos);
- return pos;
- }
- static Octstr *prepend_char(Octstr *os, unsigned char c)
- {
- Octstr *tmp;
- tmp = octstr_format("%c", c);
- octstr_insert(os, tmp, 0);
- octstr_destroy(tmp);
- return os;
- }
- /*
- * Ext qualifiers contain /, ipv4 address contains . , ipv6 address contains :.
- * phone number contains + and escaped-value contain no specific tokens. Lastly
- * mentioned are for future extensions, but we must parse them.
- * Return 1, when qualifiers found
- * 0, when not
- * -1, when an error was found during the process
- */
- static int qualifiers(Octstr *address, long pos, Octstr *type)
- {
- unsigned char term,
- c;
- long i;
- i = pos;
- c = 'E';
- if (octstr_case_compare(type, octstr_imm("PLMN")) == 0)
- term = '+';
- else if (octstr_case_compare(type, octstr_imm("IPv4")) == 0)
- term = '.';
- else if (octstr_case_compare(type, octstr_imm("IPv6")) == 0)
- term = ':';
- else
- term = 'N';
- if (term != 'N') {
- while ((c = octstr_get_char(address, i)) != term && i != 0) {
- if (c == '/')
- return 1;
- --i;
- }
- if (i == 0)
- return 0;
- }
- if (term == 'N') {
- while (i != 0) {
- if (c == '/')
- return 1;
- --i;
- }
- }
- return 0;
- }
- static long parse_qualifier_value(Octstr **address, long pos)
- {
- unsigned char c;
- while ((c = octstr_get_char(*address, pos)) != '=' && pos >= 0) {
- if (c < 0x20 || (c > 0x2e && c < 0x30) || (c > 0x3c && c < 0x3e) ||
- c > 0x7e)
- return -2;
- pos = drop_character(address, pos);
- }
- pos = drop_character(address, pos);
- return pos;
- }
- static long parse_qualifier_keyword(Octstr **address, long pos)
- {
- unsigned char c;
- while ((c = octstr_get_char(*address, pos)) != '/') {
- if (isalnum(c) || c == '-') {
- pos = drop_character(address, pos);
- } else
- return -2;
- }
- pos = drop_character(address, pos);
- return pos;
- }
- static long parse_ipv4_fragment(Octstr **address, long pos)
- {
- long i;
- unsigned char c;
- i = 0;
- c = '=';
- if (isdigit(c = octstr_get_char(*address, pos)) && pos >= 0) {
- --pos;
- ++i;
- } else {
- debug("wap.push.pap.compiler", 0, "non-digit found in ip address,"
- " address unacceptable");
- return -2;
- }
- while (i <= 3 && ((c = octstr_get_char(*address, pos)) != '.' && c != '=')
- && pos >= 0) {
- if (isdigit(c)) {
- --pos;
- ++i;
- } else {
- debug("wap.push.pap.compiler", 0, "parse_ipv4_fragment: non-digit"
- " in ipv4 address, address unacceptable");
- return -2;
- }
- }
- pos = handle_two_terminators(address, pos, '.', '=', c, i, 3);
- return pos;
- }
- static long parse_ipv6_fragment(Octstr **address, long pos)
- {
- long i;
- unsigned char c;
- i = 0;
- if (isxdigit(octstr_get_char(*address, pos)) && pos >= 0) {
- --pos;
- ++i;
- } else {
- return -2;
- }
- c = '=';
- while (i <= 4 && ((c = octstr_get_char(*address, pos)) != ':' && c != '=')
- && pos >= 0) {
- if (isxdigit(c)) {
- --pos;
- ++i;
- } else {
- return -2;
- }
- }
- pos = handle_two_terminators(address, pos, ':', '=', c, i, 4);
- return pos;
- }
- /*
- * Return -1, it was impossible to create the window because of there is no
- * more enough characters left and 0 if OK.
- */
- static int create_peek_window(Octstr **address, long *pos)
- {
- long i;
- unsigned char c;
- i = 0;
- c = '=';
- while (i < 2 && (c = octstr_get_char(*address, *pos)) != '=') {
- if (*pos > 0)
- --*pos;
- ++i;
- }
- if (c == '=')
- return 0;
- return 1;
- }
- static long rest_unescaped(Octstr **address, long pos)
- {
- long i,
- ret;
- for (i = 2; i > 0; i--) {
- if ((ret = accept_safe(address, pos)) == -2)
- return -2;
- else if (ret == -1)
- return pos;
- }
- return pos;
- }
- static int issafe(Octstr **address, long pos)
- {
- if (octstr_get_char(*address, pos) == '%')
- return 0;
- else
- return 1;
- }
- static long accept_safe(Octstr **address, long pos)
- {
- unsigned char c;
- c = octstr_get_char(*address, pos);
- if ((isalnum(c) || c == '+' || c == '-' || c == '.' || c == '_') &&
- pos >= 0)
- --pos;
- else if (c == '=')
- return -1;
- else
- return -2;
- return pos;
- }
- static long accept_escaped(Octstr **address, long pos)
- {
- Octstr *temp;
- long i;
- unsigned char c;
- pos = drop_character(address, pos);
- temp = octstr_create("");
- for (i = 2; i > 0; i--) {
- c = octstr_get_char(*address, pos + i);
- temp = prepend_char(temp, c);
- pos = drop_character(address, pos + i);
- if (pos > 0)
- --pos;
- }
- if (octstr_hex_to_binary(temp) < 0) {
- octstr_destroy(temp);
- return -2;
- }
- octstr_insert(*address, temp, pos + 2); /* To the end of the window */
- octstr_destroy(temp);
- return pos + 1; /* The position preceding the
- inserted character */
- }
- /*
- * Point ends the string to be parsed, comma separates its fragments.
- */
- static long handle_two_terminators (Octstr **address, long pos,
- unsigned char comma, unsigned char point, unsigned char c,
- long fragment_parsed, long fragment_length)
- {
- if (fragment_parsed == fragment_length && c != comma && c != point)
- return -2;
- if (c == point)
- octstr_delete(*address, pos, 1);
- --pos;
- return pos;
- }