Index: gw/wap_push_ota.c
===================================================================
RCS file: /home/cvs/gateway/gw/wap_push_ota.c,v
retrieving revision 1.17
diff -u -B -b -r1.17 wap_push_ota.c
--- gw/wap_push_ota.c	13 Feb 2003 10:32:01 -0000	1.17
+++ gw/wap_push_ota.c	5 Jun 2003 07:22:48 -0000
@@ -332,7 +332,8 @@
 }
 
 /*
- * Add push flag into push headers. Push flag is defined in otaa, p. 17-18.
+ * Add push flag into push headers. Push flag is defined in ota, p. 17-18.
+ * If there is no flags set, no Push-Flag header is added.
  */
 static List *add_push_flag(WAPEvent *e)
 {
@@ -377,9 +378,11 @@
     push_flag = 0;
     push_flag = push_flag | authenticated | trusted | last;
     
+    if (push_flag) {
     buf = octstr_format("%d", push_flag);
     http_header_add(headers, "Push-Flag", octstr_get_cstr(buf)); 
     octstr_destroy(buf);
+    }
 
     return headers;
 }
Index: gw/wap_push_pap_compiler.c
===================================================================
RCS file: /home/cvs/gateway/gw/wap_push_pap_compiler.c,v
retrieving revision 1.28
diff -u -B -b -r1.28 wap_push_pap_compiler.c
--- gw/wap_push_pap_compiler.c	28 Mar 2003 13:03:49 -0000	1.28
+++ gw/wap_push_pap_compiler.c	5 Jun 2003 07:22:48 -0000
@@ -757,8 +757,9 @@
     }
 
     if (i == NUM_ELEMENTS) {
+        debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown element:");
+        octstr_dump(name, 0);
         octstr_destroy(name);
-        debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown element");
         return -2;
     }
 
@@ -1444,8 +1445,14 @@
     if (octstr_get_char(*address, 0) == '/')
         octstr_delete(*address, 0, 1);
 
-    if ((pos = parse_ppg_specifier(address, pos)) < 0) {
-        warning(0, "illegal ppg specifier");
+/*
+ * WAP-209, chapter 8 states that addresses with telephone numbers
+ * should not have a ppg specifier. WAP-151 grammar, however, makes it
+ * mandatory. Best way to solve this contradiction seems to be regarding
+ * ppg specifier optional - MMSC is very important type of pi.
+ */
+    if (octstr_search_char(*address, '@', 0) >= 0) {
+        if ((pos = parse_ppg_specifier(address, pos)) < 0)
         return -2;
     }
 
@@ -1481,7 +1488,8 @@
 }
 
 /*
- * We are not interested of ppg specifier, but we must check its format.
+ * We are not interested of ppg specifier, but we must check its format,
+ * if we find it - it is optional.
  */
 static long parse_ppg_specifier(Octstr **address, long pos)
 {
@@ -1494,8 +1502,6 @@
 	    octstr_delete(*address, pos, 1);
             --pos;
         } else {
-            debug("wap.push.pap.compiler", 0, "PAP COMPILER: missing"
-                  " separator .");
 	    return -2;
         }
 
@@ -1511,8 +1517,6 @@
     }
 
     if (pos < 0) {
-       debug("wap.push.pap.compiler", 0, "PAP COMPILER: missing separator /"
-             " or @");
        return -2;
     }
 
Index: gw/wap_push_pap_mime.c
===================================================================
RCS file: /home/cvs/gateway/gw/wap_push_pap_mime.c,v
retrieving revision 1.5
diff -u -B -b -r1.5 wap_push_pap_mime.c
--- gw/wap_push_pap_mime.c	4 Sep 2002 09:05:06 -0000	1.5
+++ gw/wap_push_pap_mime.c	5 Jun 2003 07:22:48 -0000
@@ -2,7 +2,7 @@
  * Implementation of a gateway oriented mime parser for pap module. This 
  * parser follows proxy rules stated in Push Message, chapter 7.
  *
- * By Aarno Syvänen for Wiral Ltd
+ * By Aarno Syvänen for Wiral Ltd and Global Networks Inc.
  */
 
 #include "wap_push_pap_mime.h"
@@ -47,7 +47,7 @@
 			    long pos);
 static long pass_field_value(Octstr **body_part, Octstr **content_header, 
                              long pos);
-static void parse_epilogue(Octstr **mime_content);
+static int parse_epilogue(Octstr **mime_content);
 static int parse_tail(Octstr **multipart, Octstr *part_delimiter, 
                       long boundary_pos, long *next_part_pos);
 
@@ -103,8 +103,8 @@
         return 0;
     } else if (ret == 0) {
         gw_assert(*rdf_content == NULL);
+        if (octstr_len(mime_content) != 0)
         parse_epilogue(&mime_content);
-        gw_assert(octstr_len(mime_content) == 0);
         return 1;
     }
 
@@ -112,6 +112,7 @@
         warning(0, "erroneous capacity (rdf) headers");
         return 0;
     }
+    if (octstr_len(mime_content) != 0)
     parse_epilogue(&mime_content);
     gw_assert(octstr_len(mime_content) == 0);
     
@@ -141,6 +142,7 @@
     return c == '\t' || c == ' ';
 }
 
+/* These thingies we after normally have after delimiters. */
 static int parse_tail(Octstr **multipart, Octstr *delimiter, 
                       long boundary_pos, long *next_part_pos)
 {
@@ -153,6 +155,16 @@
     return 0;
 }
 
+/* But if we have no epilogue, we do not have crlf after close delimiter either.*/
+static int parse_short_tail(Octstr **multipart, Octstr *delimiter, long boundary_pos,
+                            long *next_part_pos)
+{
+    *next_part_pos = parse_transport_padding(*multipart,
+         boundary_pos + octstr_len(delimiter));
+
+    return 0;
+}
+
 /*
  * Boundary misses crlf here. This is intentional: Kannel header parsing pro-
  * cess drops this terminator.
@@ -200,18 +212,28 @@
 
 static long parse_transport_padding(Octstr *mime_content, long pos)
 {
-    while (islwspchar(octstr_get_char(mime_content, 0)))
+    while (islwspchar(octstr_get_char(mime_content, pos)))
         ++pos;
 
     return pos;
 }
 
+static long parse_close_delimiter(Octstr *close_delimiter, Octstr *mime_content,
+                                  long pos)
+{
+    if (octstr_ncompare(close_delimiter, mime_content, 
+                        octstr_len(close_delimiter)) != 0)
+        return -1;
+    pos += octstr_len(close_delimiter);
+
+    return pos;
+}
+
 /*
- * Splits the first body part away from the multipart message, if there is 
- * more than one left. A body part end with either with another body or with 
- * a close delimiter. If there is more than one body part left, we first split
- * the first one and then remove the stuff separating bodies from the remaind-
- * er. If there is none just remove the ending stuff.
+ * Splits the first body part away from the multipart message. A body part end with
+ * either with another body or with a close delimiter. We first split the body and
+ * then remove the separating stuff  from the remainder. If we have the last body
+ * part, we must parse all closing stuff. 
  * Returns 1, there is still another body part in the multipart message
  *         0, if there is none
  *         -1, when parsing error.
@@ -224,7 +246,8 @@
     long boundary_pos,          /* start of the boundary */
          close_delimiter_pos,   /* start of the close delimiter */
          end_pos,               /* end of the message */
-         next_part_pos;         /* start of the next part */
+         next_part_pos,         /* start of the next part */
+         epilogue_pos;          /* start of the epilogue */
  
     part_delimiter = make_part_delimiter(boundary);
     close_delimiter = make_close_delimiter(boundary);
@@ -235,17 +258,15 @@
 
     boundary_pos = octstr_search(*multipart, part_delimiter, 0);
     if (boundary_pos == close_delimiter_pos) {
-        if (parse_tail(multipart, close_delimiter, close_delimiter_pos,
-                       &end_pos) < 0) {
+        *body_part = octstr_create("");
+        octstr_split_by_pos(multipart, body_part, close_delimiter_pos);
+        if ((epilogue_pos = 
+                parse_close_delimiter(close_delimiter, *multipart, 0)) < 0)
             goto error;
-        } else {
-            octstr_delete(*multipart, close_delimiter_pos, 
-                          end_pos - close_delimiter_pos);
-            *body_part = octstr_duplicate(*multipart);
-            octstr_delete(*multipart, 0, end_pos);
+        epilogue_pos = parse_transport_padding(*multipart, epilogue_pos);
+        octstr_delete(*multipart, 0, epilogue_pos);
 	        goto last_part;
         }
-    }
 
     *body_part = octstr_create("");
     octstr_split_by_pos(multipart, body_part, boundary_pos);
@@ -727,13 +748,17 @@
     return pos;
 }
 
-static void parse_epilogue(Octstr **mime_content)
+/* This is actually CRLF epilogue. */
+static int parse_epilogue(Octstr **mime_content)
 {
+    long pos;
+
     if (octstr_len(*mime_content) == 0)
-        return;
+        return 0;
+    
+    if ((pos = parse_terminator(*mime_content, 0)) < 0)
+        return -1;
 
-    debug("wap.push.pap.mime", 0, "our epilogue was");
-    octstr_dump(*mime_content, 0);
     octstr_delete(*mime_content, 0, octstr_len(*mime_content));
 }
 
Index: gw/wap_push_ppg.c
===================================================================
RCS file: /home/cvs/gateway/gw/wap_push_ppg.c,v
retrieving revision 1.53
diff -u -B -b -r1.53 wap_push_ppg.c
--- gw/wap_push_ppg.c	20 Mar 2003 14:11:49 -0000	1.53
+++ gw/wap_push_ppg.c	5 Jun 2003 07:22:49 -0000
@@ -266,6 +266,7 @@
                              Octstr **boundary);
 static void change_header_value(List **push_headers, char *name, char *value);
 static void remove_mime_headers(List **push_headers);
+static void remove_link_headers(List **push_headers);
 
 /*
  * Communicating with pi.
@@ -374,6 +375,7 @@
          octstr_destroy(ppg_deny_ip);
          octstr_destroy(ppg_allow_ip);
          octstr_destroy(global_sender);
+         octstr_destroy(ppg_default_smsc);
 
          gwthread_join_every(http_read_thread);
 #ifdef HAVE_LIBSSL
@@ -693,6 +695,8 @@
         if (octstr_compare(url, ppg_url) != 0) {
             error(0,  "Request <%s> from <%s>: service not found", 
                   octstr_get_cstr(url), octstr_get_cstr(ip));
+            debug("wap.push.ppg", 0, "your configuration uses %s",
+                  octstr_get_cstr(ppg_url));           
             not_found = octstr_imm("Service not specified\n");
             http_send_reply(client, http_status, push_headers, not_found);
             goto ferror;
@@ -745,6 +749,7 @@
         
         http_remove_hop_headers(push_headers);
         remove_mime_headers(&push_headers);
+        remove_link_headers(&push_headers);
 
         if (!headers_acceptable(push_headers, &content_header)) {
 	        warning(0,  "PPG: Unparsable push headers, the request"
@@ -2670,7 +2675,23 @@
     "wta.ua", 
     "mms.ua", 
     "push.syncml", 
-    "loc.ua" 
+    "loc.ua",
+    "syncml.dm",
+    "drm.ua",
+    "emn.ua",
+    "wv.ua",
+    "x-wap-microsoft:localcontent.ua",
+    "x-wap-microsoft:IMclient.ua",
+    "x-wap-docomo:imode.mail.ua",
+    "x-wap-docomo:imode.mr.ua",
+    "x-wap-docomo:imode.mf.ua",
+    "x-motorola:location.ua",
+    "x-motorola:now.ua",
+    "x-motorola:otaprov.ua",
+    "x-motorola:browser.ua",
+    "x-motorola:splash.ua",
+    "x-wap-nai:mvsw.command",
+    "x-wap-openwave:iota.ua" 
 };
 
 #define NUMBER_OF_WINA_URIS sizeof(wina_uri)/sizeof(wina_uri[0])
@@ -2680,14 +2701,9 @@
  * First check do we a header with an app-encoding field and a coded value. 
  * If not, try to find push application id from table of wina approved values.
  * Return coded value value of application id in question, or an error code:
- *        -1, error
+ *        -1, no coded value (but defaults may be applied)
  *         0, * (meaning any application acceptable)
- *         1, push.sia
- *         2, wml.ua
- *         3, wta.ua 
- *         4, mms.ua
- *         5, push.syncml 
- *         6, loc.ua 
+ *         greater or equal as 1: code for this application id 
  */
 static long parse_appid_header(Octstr **appid_content)
 {
@@ -2844,12 +2860,21 @@
 
 /*
  * Some application level protocols may use MIME headers. This may cause problems
- * to them. 
+ * to them. (MIME version is a mandatory header).
  */
 static void remove_mime_headers(List **push_headers)
 {
     http_header_remove_all(*push_headers, "MIME-Version");
 }
+
+/*
+ * There are headers used only for HTTP POST pi->ppg. (For debugging, mainly.)
+ */
+static void remove_link_headers(List **push_headers)
+{
+    http_header_remove_all(*push_headers, "Host");
+}
+
 
 /*
  * Badmessage-response element is redefined in pap, implementation note, 
Index: gw/wapbox.c
===================================================================
RCS file: /home/cvs/gateway/gw/wapbox.c,v
retrieving revision 1.157
diff -u -B -b -r1.157 wapbox.c
--- gw/wapbox.c	27 Mar 2003 08:55:01 -0000	1.157
+++ gw/wapbox.c	5 Jun 2003 07:22:49 -0000
@@ -49,6 +49,10 @@
 int wsp_smart_errors = 0;
 Octstr *device_home = NULL;
 
+/* Controlling segmentation of sms messages sent by wapbox (push related).*/
+int concatenation = 1;
+long max_messages = 10;
+
 #ifdef HAVE_WTLS_OPENSSL
 RSA* private_key = NULL;
 X509* x509_cert = NULL;
@@ -176,6 +180,9 @@
      * error information instread of signaling using the HTTP reply codes
      */
     cfg_get_bool(&wsp_smart_errors, grp, octstr_imm("smart-errors"));
+    if (cfg_get_bool(&concatenation, grp, octstr_imm("concatenation")) < 0)
+        concatenation = 1;
+    cfg_get_integer(&max_messages, grp, octstr_imm("max-messages"));
 
     /* configure the 'wtls' group */
 #if (HAVE_WTLS_OPENSSL)
@@ -396,13 +403,13 @@
         } else {
 	    msg = pack_sms_datagram(dgram);
             msg_sequence = counter_increase(sequence_counter) & 0xff;
-            msg_len = octstr_len(msg->sms.msgdata);
-            max_msgs = (msg_len / MAX_SMS_OCTETS) + 1; 
-            sms_datagrams = sms_split(msg, NULL, NULL, NULL, NULL, 1, 
-                                      msg_sequence, max_msgs, MAX_SMS_OCTETS);
-
-            while ((part = list_extract_first(sms_datagrams)) != NULL)
+            /*msg_len = octstr_len(msg->sms.msgdata);
+            max_msgs = (msg_len / MAX_SMS_OCTETS) + 1;*/ 
+            sms_datagrams = sms_split(msg, NULL, NULL, NULL, NULL, concatenation, 
+                                      msg_sequence, max_messages, MAX_SMS_OCTETS);
+            while ((part = list_extract_first(sms_datagrams)) != NULL) {
 	            write_to_bearerbox(part);
+            }
 
             list_destroy(sms_datagrams, NULL);
             msg_destroy(msg);
Index: gwlib/cfg.def
===================================================================
RCS file: /home/cvs/gateway/gwlib/cfg.def,v
retrieving revision 1.85
diff -u -B -b -r1.85 cfg.def
--- gwlib/cfg.def	3 Apr 2003 12:18:18 -0000	1.85
+++ gwlib/cfg.def	5 Jun 2003 07:22:49 -0000
@@ -77,6 +77,8 @@
     OCTSTR(syslog-level)
     OCTSTR(smart-errors)
     OCTSTR(access-log)
+    OCTSTR(concatenation)
+    OCTSTR(max-messages)
 )
 
 
Index: gwlib/http.c
===================================================================
RCS file: /home/cvs/gateway/gwlib/http.c,v
retrieving revision 1.190
diff -u -B -b -r1.190 http.c
--- gwlib/http.c	3 Apr 2003 12:18:36 -0000	1.190
+++ gwlib/http.c	5 Jun 2003 07:22:49 -0000
@@ -2374,12 +2374,14 @@
         if (octstr_case_compare(current_name, name) == 0) {
             value = octstr_copy(os, colon + 1, octstr_len(os));
             octstr_strip_blanks(value);
+            octstr_destroy(current_name);
             return value;
         }
+        octstr_destroy(current_name);
         ++i;
     }
     
-    return value;
+    return NULL;
 }
 
 List *http_header_duplicate(List *headers)
Index: test/test_ppg.c
===================================================================
RCS file: /home/cvs/gateway/test/test_ppg.c,v
retrieving revision 1.23
diff -u -B -b -r1.23 test_ppg.c
--- test/test_ppg.c	19 May 2003 07:37:52 -0000	1.23
+++ test/test_ppg.c	5 Jun 2003 07:22:50 -0000
@@ -27,15 +27,22 @@
            num_urls = 0,
            wait = 0,
            use_headers = 0,
-           use_config = 0;
+           use_config = 0,
+           accept_binary = 0, 
+           use_numeric = 0,
+           use_string = 0,
+           add_epilogue = 0,
+           add_preamble = 0;
 static double wait_seconds = 0.0;
 static Counter *counter = NULL;
 static char **push_data = NULL;
 static char *boundary = NULL;
 static Octstr *content_flag = NULL;
 static Octstr *appid_flag = NULL;
+static Octstr *appid_string = NULL;
 static Octstr *content_transfer_encoding = NULL;
 static Octstr *connection = NULL;
+static Octstr *delimiter = NULL;
 
 enum { SSL_CONNECTION_OFF = 0,
        DEFAULT_NUMBER_OF_RELOGS = 2};
@@ -90,43 +97,74 @@
     cfg_destroy(cfg);
 }
 
-static void add_push_application_id(List **push_headers, Octstr *appid_flag)
+static void add_delimiter(Octstr **content)
+{
+    if (octstr_compare(delimiter, octstr_imm("crlf")) == 0) {
+        octstr_format_append(*content, "%c", '\r');
+    }
+
+    octstr_format_append(*content, "%c", '\n');
+}
+
+static void add_push_application_id(List **push_headers, Octstr *appid_flag,
+                                    int use_string)
 {
-    if (octstr_compare(appid_flag, octstr_imm("any")) == 0)
+    if (use_string) {
+        list_append(*push_headers, appid_string);
+        return;
+    }
+
+    if (octstr_compare(appid_flag, octstr_imm("any")) == 0) {
+        if (!use_numeric)
         http_header_add(*push_headers, "X-WAP-Application-Id", 
                         "http://www.wiral.com:*");
-    else if (octstr_compare(appid_flag, octstr_imm("ua")) == 0)
+        else
+            http_header_add(*push_headers, "X-WAP-Application-Id", "0");
+    } else if (octstr_compare(appid_flag, octstr_imm("ua")) == 0) {
+        if (!use_numeric)
         http_header_add(*push_headers, "X-WAP-Application-Id", 
                         "http://www.wiral.com:wml.ua");
-    else if (octstr_compare(appid_flag, octstr_imm("mms")) == 0)
+        else
+            http_header_add(*push_headers, "X-WAP-Application-Id", "2");
+    } else if (octstr_compare(appid_flag, octstr_imm("mms")) == 0) {
+        if (!use_numeric)
         http_header_add(*push_headers, "X-WAP-Application-Id", 
                         "mms.ua");
-    else if (octstr_compare(appid_flag, octstr_imm("scrap")) == 0)
+        else
+            http_header_add(*push_headers, "X-WAP-Application-Id", "4");
+    } else if (octstr_compare(appid_flag, octstr_imm("scrap")) == 0) {
+        if (!use_numeric)
         http_header_add(*push_headers, "X-WAP-Application-Id", 
                         "no appid at all");
+        else
+            http_header_add(*push_headers, "X-WAP-Application-Id", 
+                            "this is not a numeric header");
+    }
 }
 
 static void add_content_type(Octstr *content_flag, Octstr **wap_content)
 {
     if (octstr_compare(content_flag, octstr_imm("wml")) == 0)
         *wap_content = octstr_format("%s", 
-            "Content-Type: text/vnd.wap.wml\r\n");
+            "Content-Type: text/vnd.wap.wml");
     else if (octstr_compare(content_flag, octstr_imm("si")) == 0)
 	    *wap_content = octstr_format("%s",
-            "Content-Type: text/vnd.wap.si\r\n");
+            "Content-Type: text/vnd.wap.si");
     else if (octstr_compare(content_flag, octstr_imm("sl")) == 0)
 	    *wap_content = octstr_format("%s",
-            "Content-Type: text/vnd.wap.sl\r\n");
+            "Content-Type: text/vnd.wap.sl");
     else if (octstr_compare(content_flag, octstr_imm("multipart")) == 0)
         *wap_content = octstr_format("%s",
             "Content-Type: multipart/related; boundary=fsahgwruijkfldsa\r\n");
     else if (octstr_compare(content_flag, octstr_imm("mms")) == 0) 
         *wap_content = octstr_format("%s", 
-            "Content-Type: application/vnd.wap.mms-message\r\n"); 
+            "Content-Type: application/vnd.wap.mms-message"); 
     else if (octstr_compare(content_flag, octstr_imm("scrap")) == 0)
-        *wap_content = octstr_format("%s", "no type at all\r\n"); 
+        *wap_content = octstr_format("%s", "no type at all"); 
     else if (octstr_compare(content_flag, octstr_imm("nil")) == 0)
         *wap_content = octstr_create("");
+    if (octstr_len(*wap_content) > 0)
+        add_delimiter(wap_content);
 }
 
 static void add_content_transfer_encoding_type(Octstr *content_flag, 
@@ -136,7 +174,9 @@
 	     return;
 
     if (octstr_compare(content_flag, octstr_imm("base64")) == 0)
-	    octstr_append_cstr(wap_content, "Content-transfer-encoding: base64\r\n");
+	octstr_append_cstr(wap_content, "Content-transfer-encoding: base64");
+
+    add_delimiter(&wap_content);
 }
 
 static void add_connection_header(Octstr *connection, Octstr *wap_content)
@@ -145,9 +185,11 @@
         return;
 
     if (octstr_compare(connection, octstr_imm("close")) == 0)
-        octstr_format_append(wap_content, "%s", "Connection: close\r\n");
+        octstr_format_append(wap_content, "%s", "Connection: close");
     else if (octstr_compare(connection, octstr_imm("keep-alive")) == 0) 
-        octstr_format_append(wap_content, "%s", "Connection: keep-alive\r\n");
+        octstr_format_append(wap_content, "%s", "Connection: keep-alive");
+
+    add_delimiter(&wap_content);
 }
 
 static void transfer_encode (Octstr *cte, Octstr *content)
@@ -180,12 +222,10 @@
     Octstr *part_delimiter;
 
     part_delimiter = octstr_create("");
-    octstr_format_append(part_delimiter, "%c", '\r');
-    octstr_format_append(part_delimiter, "%c", '\n');
+    add_delimiter(&part_delimiter);
     octstr_format_append(part_delimiter, "%s", "--");
     octstr_append(part_delimiter, boundary);
-    octstr_format_append(part_delimiter, "%c", '\r');
-    octstr_format_append(part_delimiter, "%c", '\n');
+    add_delimiter(&part_delimiter);
     
     return part_delimiter;
 }
@@ -195,14 +235,11 @@
     Octstr *close_delimiter;
 
     close_delimiter = octstr_create("");
-    octstr_format_append(close_delimiter, "%c", '\r');
-    octstr_format_append(close_delimiter, "%c", '\n');
+    add_delimiter(&close_delimiter);
     octstr_format_append(close_delimiter, "%s", "--");
     octstr_append(close_delimiter, boundary);
     octstr_format_append(close_delimiter, "%s", "--");
-    octstr_format_append(close_delimiter, "%c", '\r');
-    octstr_format_append(close_delimiter, "%c", '\n');
-    
+    /*add_delimiter(&close_delimiter);*/
 
     return close_delimiter;
 }
@@ -222,7 +259,7 @@
                         octstr_get_cstr(mos = make_multipart_value(boundary)));
     if (use_headers)
         http_add_basic_auth(push_headers, username, password);
-    add_push_application_id(&push_headers, appid_flag);
+    add_push_application_id(&push_headers, appid_flag, use_string);
 
     octstr_destroy(mos);
 
@@ -288,18 +325,30 @@
                                            wap_content);
         add_connection_header(connection, wap_content);
 
+        /* Read the content file. (To be pushed)*/
         if ((wap_file_content = 
                 octstr_read_file(octstr_get_cstr(content_file))) == NULL)
 	         panic(0, "Stopping");
+        if (accept_binary) {
+            octstr_delete_matching(wap_file_content, octstr_imm(" "));
+            octstr_delete_matching(wap_file_content, octstr_imm("\n"));
+            octstr_delete_matching(wap_file_content, octstr_imm("\r"));
+            if (!octstr_is_all_hex(wap_file_content))
+                panic(0, "non-hex chars in the content file, cannot continue");
+            octstr_hex_to_binary(wap_file_content);            
+        }
 
 	    transfer_encode (content_transfer_encoding, wap_file_content);
         octstr_append(wap_content, wap_file_content);
         octstr_destroy(wap_file_content);
 
-        pap_content = octstr_format("%s", "Content-Type: application/xml\r\n");
+        /* Read the control file. (To control pushing)*/
+        pap_content = octstr_format("%s", "Content-Type: application/xml");
+        add_delimiter(&pap_content);
         if ((pap_file_content = 
                 octstr_read_file(octstr_get_cstr(pap_file))) ==  NULL)
 	        panic(0, "Stopping");
+        
         octstr_append(pap_content, pap_file_content);
         octstr_destroy(pap_file_content);
 
@@ -307,14 +356,22 @@
 	        panic(0, "Cannot open the push content files");
 
         push_content = octstr_create("");
+        if (add_preamble)
+            octstr_append(push_content, octstr_imm("the parser should discard this"));
         octstr_append(push_content, 
             bpos = make_part_delimiter(octstr_imm(boundary)));
+        /*octstr_append(push_content, octstr_imm("\r\n"));*/ /* Do we accept an additional 
+                                                          * clrf ? */
         octstr_append(push_content, pap_content);
         octstr_append(push_content, bpos);
         octstr_destroy(bpos);
         octstr_append(push_content, wap_content);
         octstr_append(push_content, 
             bcos = make_close_delimiter(octstr_imm(boundary)));
+        if (add_epilogue) {
+            octstr_append(push_content, octstr_imm("\r\n"));
+            octstr_append(push_content, octstr_imm("the parser should discard this"));
+        }
         octstr_destroy(bcos);
         octstr_destroy(pap_content);
         octstr_destroy(wap_content);
@@ -574,6 +631,13 @@
     info(0, "-a application id");
     info(0, "Define the client application that will handle the push. Any,"); 
     info(0, "ua, mms, nil and scrap accepted, default ua.");
+    info(0, "-n");
+    info(0, "if set, use numeric appid values instead of string ones. For");
+    info(0, "instance, '4' instead of 'mms.ua'. Default is off.");
+    info(0, "-s string");
+    info(0, "supply application id as a plain string. For instance"); 
+    info(0, "-s x-wap-application-id:mms.ua equals -a ua. Default is");
+    info(0, "x-wap-application-id:mms.ua.");
     info(0, "-b");
     info(0, "If true, send username/password in headers. Default false");
     info(0, "-v number");
@@ -598,6 +662,17 @@
     info(0, "Default: read components from files");
     info(0, "-t");
     info(0, "number of threads, maximum 1024, default 1");
+    info(0, "-B");
+    info(0, "accept binary push content. Default: off.");
+    info(0, "Binary content consist of hex numbers. In addition, crs, lfs and");
+    info(0, "spaces are accepted, and ignored.");
+    info(0, "-d value");
+    info(0, "set delimiter to be used. Accepted values crlf and lf. Default crlf.");
+    info(0, "-E");
+    info(0, "If set, add a hardcoded epilogue (epilogue is to be discarded anyway).");
+    info(0, "Default off.");
+    info(0, "-p");
+    info(0, "If set, add hardcoded preamble. Default is off.");
 }
 
 int main(int argc, char **argv)
@@ -614,7 +689,7 @@
     gwlib_init();
     num_threads = 1;
 
-    while ((opt = getopt(argc, argv, "Hhbv:qr:t:c:a:i:e:k:")) != EOF) {
+    while ((opt = getopt(argc, argv, "HhBbnEpv:qr:t:c:a:i:e:k:d:s:")) != EOF) {
         switch(opt) {
 	    case 'v':
 	        log_set_output_level(atoi(optarg));
@@ -652,7 +727,7 @@
                     octstr_compare(content_flag, octstr_imm("mms")) != 0 &&
                     octstr_compare(content_flag, octstr_imm("scrap")) != 0 &&
                     octstr_compare(content_flag, 
-                    octstr_imm("multipart")) != 0){
+                    octstr_imm("multipart")) != 0) {
 		        octstr_destroy(content_flag);
 		        error(0, "TEST_PPG: Content type not known");
 		        help();
@@ -674,14 +749,21 @@
            }
 	    break;
 
+            case 'n':
+                use_numeric = 1;
+            break;
+
+            case 's':
+                appid_string = octstr_create(optarg);
+                use_string = 1;
+            break;
+
 	    case 'e':
 		    content_transfer_encoding = octstr_create(optarg);
-            if (octstr_compare(content_transfer_encoding, 
-                               octstr_imm("base64")) != 0) {
+                if (octstr_compare(content_transfer_encoding, octstr_imm("base64")) != 0) {
 		        octstr_destroy(content_transfer_encoding);
 		        error(0, "TEST_PPG: unknown content transfer" 
-                      " encoding \"%s\"",
-			          octstr_get_cstr(content_transfer_encoding));
+                      " encoding \"%s\"", octstr_get_cstr(content_transfer_encoding));
 		        help();
                 exit(1);
 		    }
@@ -690,8 +772,7 @@
 	    case 'k':
 	        connection = octstr_create(optarg);
             if (octstr_compare(connection, octstr_imm("close")) != 0 && 
-                    octstr_compare(connection, 
-                        octstr_imm("keep-alive")) != 0) {
+                        octstr_compare(connection, octstr_imm("keep-alive")) != 0) {
 		        octstr_destroy(connection);
 		        error(0, "TEST_PPG: Connection-header unacceptable");
 		        help();
@@ -707,6 +788,29 @@
 	        use_headers = 1;
 	    break;
 
+            case 'B':
+                accept_binary = 1;
+            break;
+
+            case 'd':
+                delimiter = octstr_create(optarg);
+                if (octstr_compare(delimiter, octstr_imm("crlf")) != 0 &&
+                        octstr_compare(delimiter, octstr_imm("lf")) != 0) {
+                    octstr_destroy(delimiter);
+                    error(0, "illegal d value");
+                    help();
+                    exit(1);
+                }
+            break;
+
+            case 'E':
+                add_epilogue = 1;
+            break;
+
+            case 'p':
+                add_preamble = 1;
+            break;
+
 	    case '?':
 	    default:
 	        error(0, "TEST_PPG: Invalid option %c", opt);
@@ -730,6 +834,12 @@
     if (appid_flag == NULL)
         appid_flag = octstr_imm("ua");
 
+    if (appid_string == NULL)
+        appid_string = octstr_imm("x-wap-application-id: wml.ua");
+
+    if (delimiter == NULL)
+        delimiter = octstr_imm("crlf");
+
     if (use_hardcoded) {
         username = octstr_imm("troo");
         password = octstr_imm("far");
@@ -792,6 +902,7 @@
     octstr_destroy(password);
     octstr_destroy(push_url);
     octstr_destroy(connection);
+    octstr_destroy(delimiter);;
     counter_destroy(counter);
     gwlib_shutdown();
 
Index: wap/wsp_headers.c
===================================================================
RCS file: /home/cvs/gateway/wap/wsp_headers.c,v
retrieving revision 1.6
diff -u -B -b -r1.6 wsp_headers.c
--- wap/wsp_headers.c	19 Oct 2002 10:07:39 -0000	1.6
+++ wap/wsp_headers.c	5 Jun 2003 07:22:50 -0000
@@ -250,7 +250,8 @@
     return convert_q_value(c);
 }
 
-/* Version-value is defined in 8.4.2.3 */
+/* Version-value is defined in 8.4.2.3. Encoding-Version uses coding
+ * defined in this chapter, see 8.4.2.70.  */
 static Octstr *unpack_version_value(long value)
 {
     Octstr *result;
@@ -269,6 +270,19 @@
     return result;
 }
 
+static Octstr *unpack_encoding_version(ParseContext *context)
+{
+    int ch;
+
+    ch = parse_get_char(context);
+    if (ch < 128) {
+        warning(0, "WSP: bad Encoding-Version value");
+        return NULL;
+    }
+
+    return unpack_version_value(((long) ch) - 128);
+}
+
 /* Called with the parse limit set to the end of the parameter data,
  * and decoded containing the unpacked header line so far.
  * Parameter is defined in 8.4.2.4. */
@@ -1155,6 +1169,10 @@
             decoded = unpack_disposition(context);
             break;
 
+        case WSP_HEADER_ENCODING_VERSION:
+            decoded = unpack_encoding_version(context);
+            break;
+
         default:
             if (headername) {
                 warning(0, "Did not expect value-length with "
@@ -1331,6 +1349,7 @@
 static int pack_transfer_encoding(Octstr *packet, Octstr *value);
 static int pack_uri(Octstr *packet, Octstr *value);
 static int pack_warning(Octstr *packet, Octstr *value);
+static int pack_version_value(Octstr *packet, Octstr *value);
 
 /* LIST is a comma-separated list such as is described in the "#rule"
  * entry of RFC2616 section 2.1. */
@@ -1396,10 +1415,11 @@
         { WSP_HEADER_WARNING, pack_warning, LIST },
         { WSP_HEADER_WWW_AUTHENTICATE, pack_challenge, BROKEN_LIST },
         { WSP_HEADER_CONTENT_DISPOSITION, pack_content_disposition, 0 },
-        { WSP_HEADER_PUSH_FLAG, pack_integer_string, 0},
-        { WSP_HEADER_X_WAP_CONTENT_URI, pack_uri, 0},
-        { WSP_HEADER_X_WAP_INITIATOR_URI, pack_uri, 0},
-        { WSP_HEADER_X_WAP_APPLICATION_ID, pack_integer_string, 0}
+        { WSP_HEADER_PUSH_FLAG, pack_integer_string, 0 },
+        { WSP_HEADER_X_WAP_CONTENT_URI, pack_uri, 0 },
+        { WSP_HEADER_X_WAP_INITIATOR_URI, pack_uri, 0 },
+        { WSP_HEADER_X_WAP_APPLICATION_ID, pack_integer_string, 0 },
+        { WSP_HEADER_ENCODING_VERSION, pack_version_value, 0 }
     };
 
 static Parameter *parm_create(Octstr *key, Octstr *value)
@@ -1743,7 +1763,7 @@
     return -1;
 }
 
-static void pack_version_value(Octstr *packed, Octstr *version)
+static int pack_version_value(Octstr *packed, Octstr *version)
 {
     long major, minor;
     long pos;
@@ -1763,10 +1783,11 @@
     }
 
     pack_short_integer(packed, major << 4 | minor);
-    return;
+    return 0;
 
 usetext:
     pack_text(packed, version);
+    return 0;
 }
 
 static int pack_constrained_value(Octstr *packed, Octstr *text, long value)
Index: wap/wsp_session.c
===================================================================
RCS file: /home/cvs/gateway/wap/wsp_session.c,v
retrieving revision 1.13
diff -u -B -b -r1.13 wsp_session.c
--- wap/wsp_session.c	14 May 2002 11:05:08 -0000	1.13
+++ wap/wsp_session.c	5 Jun 2003 07:22:50 -0000
@@ -87,6 +87,10 @@
 static unsigned long next_wsp_session_id(void);
 
 static List *make_capabilities_reply(WSPMachine *m);
+static List *make_reply_headers(WSPMachine *m);
+static int is_default_version(WSPMachine *m);
+static int is_higher_version(WSPMachine *m);
+static int is_lower_version(WSPMachine *m);
 static Octstr *make_connectreply_pdu(WSPMachine *m);
 static Octstr *make_resume_reply_pdu(WSPMachine *m, List *headers);
 static WSP_PDU *make_confirmedpush_pdu(WAPEvent *e);
@@ -946,11 +950,91 @@
 	return caps;
 }
 
+static int is_default_version(WSPMachine *m)
+{
+    Octstr *request_version;
+
+    request_version = http_header_value(m->http_headers, octstr_imm("Encoding-Version"));
+    if (request_version == NULL) {
+        return 1;
+    } else {
+        octstr_destroy(request_version);
+        return 0;
+    }
+}
+
+static int is_higher_version(WSPMachine *m)
+{
+    Octstr *request_version;
+
+    request_version = http_header_value(m->http_headers, octstr_imm("Encoding-Version"));
+    if (request_version && octstr_compare(request_version, octstr_imm("1.1")) != 0 &&
+            octstr_compare(request_version, octstr_imm("1.2")) != 0 &&
+            octstr_compare(request_version, octstr_imm("1.3")) != 0) {
+        octstr_destroy(request_version);
+        return 1;
+    } else {
+        octstr_destroy(request_version);
+        return 0;
+    }
+}
+
+static int is_lower_version(WSPMachine *m)
+{
+    Octstr *request_version;
+
+    request_version = http_header_value(m->http_headers, octstr_imm("Encoding-Version"));
+    if (request_version && (octstr_compare(request_version, octstr_imm("1.1")) == 0 ||
+            octstr_compare(request_version, octstr_imm("1.2")) == 0)) {
+        octstr_destroy(request_version);
+        return 1;        
+    } else {
+        octstr_destroy(request_version);
+        return 0;
+    }
+}
+
+static List *make_reply_headers(WSPMachine *m)
+{
+    List *headers;
+    Octstr *encoding_version;
+    Octstr *request_version;
+
+    /* Add all server wsp level hop-by-hop headers. Currently only 
+     * Encoding-Version, as defined by wsp, chapter 8.4.2.70. 
+     * What headers belong to which version is defined in appendix A,
+     * table 39.. 
+    encoding_version = request_version = NULL;
+     * Essentially, if the client sends us an Encoding-Version
+     * higher than ours (1.3) we send our version number to it,
+     * if it is lower, we left version number intact. */
+    /* First the case that we have no Encoding-Version header at all. 
+     * This case we must assume that the client supports version 1.2
+     * or lower. */
+    if (is_default_version(m)) {
+        encoding_version = octstr_create("1.2");
+    } else if (is_higher_version(m)) {
+        encoding_version = octstr_create("1.3");
+    } else if (is_lower_version(m)) {
+        request_version = http_header_value(m->http_headers, octstr_imm("Encoding-Version"));
+        encoding_version = octstr_duplicate(request_version);
+        octstr_destroy(request_version);
+    }  else {   
+        encoding_version = octstr_create("1.3");
+    }
+
+    headers = http_create_empty_headers();
+    http_header_add(headers, "Encoding-Version", octstr_get_cstr(encoding_version));
+    octstr_destroy(encoding_version);
+
+    return headers;
+}
 
 static Octstr *make_connectreply_pdu(WSPMachine *m) {
 	WSP_PDU *pdu;
 	Octstr *os;
 	List *caps;
+        List *reply_headers;
 	
 	pdu = wsp_pdu_create(ConnectReply);
 
@@ -959,7 +1043,10 @@
 	caps = make_capabilities_reply(m);
 	pdu->u.ConnectReply.capabilities = wsp_cap_pack_list(caps);
 	wsp_cap_destroy_list(caps);
-	pdu->u.ConnectReply.headers = NULL;
+
+        reply_headers = make_reply_headers(m);
+	pdu->u.ConnectReply.headers = wsp_headers_pack(reply_headers, 0);
+        http_destroy_headers(reply_headers);
 	
 	os = wsp_pdu_pack(pdu);
 	wsp_pdu_destroy(pdu);
Index: wap/wsp_strings.def
===================================================================
RCS file: /home/cvs/gateway/wap/wsp_strings.def,v
retrieving revision 1.6
diff -u -B -b -r1.6 wsp_strings.def
--- wap/wsp_strings.def	4 Sep 2002 09:16:31 -0000	1.6
+++ wap/wsp_strings.def	5 Jun 2003 07:22:50 -0000
@@ -109,7 +109,7 @@
 NSTRING("Encoding-Version", WSP_HEADER_ENCODING_VERSION)
 )
 
-/* Table 40. Content Type Assignments */
+/* Table 40. Content Type Assignments. Only to wsp version 1.3. */
 LINEAR(content_type,
 STRING("*/*")
 STRING("text/*")
@@ -166,14 +166,14 @@
 STRING("application/vnd.wap.sia")
 STRING("text/vnd.wap.connectivity-xml")
 STRING("application/vnd.wap.connectivity-wbxml")
-STRING("application/pkcs7-mime")
+/*STRING("application/pkcs7-mime")
 STRING("application/vnd.wap.hashed-certificate")
 STRING("application/vnd.wap.signed-certificate")
 STRING("application/vnd.wap.cert-response")
 STRING("application/xhtml+xml")
 STRING("application/wml+xml")
 STRING("text/css")
-STRING("application/vnd.wap.mms-message") 
+STRING("application/vnd.wap.mms-message")*/ 
 )
 
 /* Table 42, Character Set Assignment (partial) */
@@ -465,6 +465,22 @@
 ASSIGN("mms.ua", 0x04) 
 ASSIGN("push.syncml", 0x05) 
 ASSIGN("loc.ua", 0x06) 
+ASSIGN("syncml.dm", 0x07)
+ASSIGN("drm.ua", 0x08)
+ASSIGN("emn.ua", 0x09)
+ASSIGN("wv.ua", 0x0A)
+ASSIGN("x-wap-microsoft:localcontent.ua", 0x8000)
+ASSIGN("x-wap-microsoft:IMclient.ua", 0x8001)
+ASSIGN("x-wap-docomo:imode.mail.ua", 0x8002)
+ASSIGN("x-wap-docomo:imode.mr.ua", 0x8003)
+ASSIGN("x-wap-docomo:imode.mf.ua", 0x8004)
+ASSIGN("x-motorola:location.ua", 0x8005)
+ASSIGN("x-motorola:now.ua", 0x8006)
+ASSIGN("x-motorola:otaprov.ua", 0x8007)
+ASSIGN("x-motorola:browser.ua", 0x8008)
+ASSIGN("x-motorola:splash.ua", 0x8009)
+ASSIGN("x-wap-nai:mvsw.command", 0x800B)
+ASSIGN("x-wap-openvawe:iota.ua", 0x8010)
 )
 
 /**** More preprocessor magic ****/
Index: wap/wsp_unit.c
===================================================================
RCS file: /home/cvs/gateway/wap/wsp_unit.c,v
retrieving revision 1.12
diff -u -B -b -r1.12 wsp_unit.c
--- wap/wsp_unit.c	13 Feb 2003 10:34:09 -0000	1.12
+++ wap/wsp_unit.c	5 Jun 2003 07:22:50 -0000
@@ -192,7 +192,10 @@
 
 /*
  * We do not set TUnitData.ind's SMS-specific fields here, because we do not
- * support sending results to the phone over SMS.
+ * support sending results to the phone over SMS. Wsp, chapter 8.4.1 states
+ * that "that each peer entity is always associated with an encoding version.".
+ * So we add Encoding-Version when we are sending something to the client.
+ * (This includes push, which is not directly mentioned in chapter 8.4.2.70). 
  */
 static WAPEvent *pack_into_result_datagram(WAPEvent *event) {
 	WAPEvent *datagram;
@@ -204,6 +207,8 @@
 	gw_assert(event->type == S_Unit_MethodResult_Req);
 	p = &event->u.S_Unit_MethodResult_Req;
 
+        http_header_add(p->response_headers, "Encoding-Version", "1.3");
+
 	pdu = wsp_pdu_create(Reply);
 	pdu->u.Reply.status = wsp_convert_http_status_to_wsp_status(p->status);
 	pdu->u.Reply.headers = wsp_headers_pack(p->response_headers, 1);
@@ -236,6 +241,10 @@
 
         gw_assert(event->type == S_Unit_Push_Req);
         debug("wap.wsp.unit", 0, "WSP_UNIT: Connectionless push accepted");
+
+        http_header_add(event->u.S_Unit_Push_Req.push_headers, 
+                        "Encoding-Version", "1.3");
+
         pdu = wsp_pdu_create(Push);
 	pdu->u.Push.headers = wsp_headers_pack(
             event->u.S_Unit_Push_Req.push_headers, 1);
