[FYI] ppg documentation

Aarno Syvänen <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <[email protected]>
Hi,

this diff contains new ppg documentation. In addition, ppg now
supports all well-known and reserved application ids, as
specified by Open Mobile Alliance (used to be wapforum).

Aarno
cvs.diff (application/octet-stream, 51 KB)
Index: doc/userguide/userguide.xml
===================================================================
RCS file: /home/cvs/gateway/doc/userguide/userguide.xml,v
retrieving revision 1.222
diff -u -B -b -r1.222 userguide.xml
--- doc/userguide/userguide.xml	3 Jun 2003 20:56:19 -0000	1.222
+++ doc/userguide/userguide.xml	12 Jun 2003 09:17:01 -0000
@@ -6364,7 +6364,8 @@
 <title>Setting up Push Proxy Gateway</title>
       <para>This chapter explains how to set up a push proxy gateway (PPG). 
        An example configuration file are given. A working push proxy gateway
-      is described. </para>
+      is described. Routing wap pushes to a certain smsc and asking for
+      <emphasis>SMS level</emphasis> delivery reports are described.</para>
 <sect1>
 <title>Configuring ppg core group, for push initiator (PI) interface</title>
      <para>PPG configuration group defines gateway's service interface.
@@ -6483,7 +6484,22 @@
         		 If no SMSC ID is given with the wappush HTTP request (see below), use
              this one as default route for all push messages.
      			 </entry></row>
-
+             <row><entry><literal>default-dlrc</literal></entry>
+             <entry><emphasis>string</emphasis></entry>
+             <entry valign="bottom">
+             If no dlr url is given with the wappush HTTP request (see below), use
+             this one as default route for all push messages.
+             </entry></row>
+             <row><entry><literal>ppg-smsbox-id</literal></entry>
+             <entry><emphasis>string</emphasis></entry>
+             <entry valign="bottom">
+             All ppg delivery reports are handled by this smsbox..
+             </entry></row>
+             <row><entry><literal>service-name</literal></entry>
+             <entry><emphasis>string</emphasis></entry>
+             <entry valign="bottom">
+             This is sms service name used by smsbox for wap push..
+             </entry></row>
              </tbody>
              </tgroup>
      </table>
@@ -6588,7 +6604,17 @@
      			 <entry valign="bottom">
         		 Allow only routing to a defined SMSC ID for this specific push user.
      			 </entry></row>
-
+             <row><entry><literal>dlr-url</literal></entry>
+             <entry><emphasis>string</emphasis></entry>
+             <entry valign="bottom">
+             If no dlr  is given with the wappush HTTP request (see below), use
+             this one as default route for this specific push user.
+             </entry></row>
+             <row><entry><literal>smsbox-id</literal></entry>
+             <entry><emphasis>string</emphasis></entry>
+             <entry valign="bottom">
+             Smsbox handling delivery reports fro this user.
+             </entry></row>
              </tbody>
              </tgroup>
       </table>
@@ -6644,11 +6670,12 @@
 no-coding = true
 send-url = http://host:port/path
 </programlisting>
-     <para>To set up smsbox. This group will eventually disappear, use here
-     only necessary configuration variables.</para>
+     <para>To set up smsbox. This is used for ppg delivery reports,
+     see later.</para>
 <programlisting>
 group = smsbox
 bearerbox-host = localhost
+smsbox-id = dlrbox
 </programlisting>
       <para>Kannel sources contain a sample push configuration file 
       <literal>gw/pushkannel.conf</literal>.</para>
@@ -6708,6 +6735,120 @@
        </para>
 </sect1>
      
+<sect1>
+<title>Requesting SMS level delivery reports for WAP pushes</title>
+       <para>Push content is a normal binary SM, so you can ask delivery 
+       reports for them. These are useful for testing purposes (did the
+       phone get the content at all, or did it just reject it.) Another
+       use is create fallback services for phones not supporting displaying
+       a specific push content. (MMS one being perhaps currently most
+       obvious.) Generally speaking, this service is very similar to 
+       smsbox one. See chapter Delivery Reports for details.</para>
+
+       <para> For ppg sms delivery reports you will need a fully working 
+       smsbox. Add configuration variable <literal>smsbox-id<\literal> to
+       <literal>smsbox<\literal> group (it is necessary, because there
+       is no MT from any smsbox corresponding the delivery report 
+       bearerbox is receiving):<\para>
+
+<programlisting>
+       group = smsbox
+       smsbox-id = dlrbox
+       bearerbox-host = localhost
+       log-file = "/var/log/kannel/smsbox-core.log"
+       log-level = 0
+       access-log = "/var/log/kannel/smsbox-access.log"
+<\programlisting>
+
+       <para> Start smsbox normal way after updating the configuration
+       file. <\para>
+
+       <para> You must add to PPG configuration file two less obvious
+       variables: <literal>ppg-smsbox-id<\literal> and <literal>
+       service-name<\literal>. <literal>Ppg-smsbox-id<\literal> 
+       defines smsbox through which you want to route delivery reports,
+       <literal>service-name<\literal> makes possible for smsbox to
+       handle wap pushes as a separate sms service.<\para>
+
+       <para>Setting <literal>ppg-smsbox-id<\literal> will route all
+       ppg messages through same smsbox. You can route delivery 
+       reports of separate user through separate smsboxes, by using
+       configuration variable <literal>smsbox-id<\literal> in group
+       wap push user. Or you can use cgi variable <literal>smsbox-id
+      <\literal>. This means routing every message separately. <\para>
+
+       <para> You can supply dlr url and dlr mask as cgi variable, or
+       as a configuration variable in ppg user or ppg core group. (This
+       is order of precedence, too.) First one is valid for only one
+       message, second for a specific user, and third for every ppg
+       user. <\para>
+
+       <para> So following is a minimum ppg core group for sms delivery
+       reports:<\para>
+
+<programlisting>
+group = ppg
+ppg-url = /wappush
+ppg-port = 8080
+concurrent-pushes = 100
+trusted-pi = true
+users = 1024
+service-name = ppg
+ppg-smsbox-id = dlrbox
+<\programlisting>
+
+       <para>This you can use with following http post request (one
+       asking for all possible delivery reports):<\para>
+
+<screen><userinput>
+       http://193.53.0.56:8080/phplib/kannelgw.php?user=*deleted*&amp;
+       pass=*deleted*=to=%2B358408676001&amp;text=3D%02%06%17%AE%96localhost
+       %3A8080%00%AF%80%8D%CF%B4%80%02%05j%00E%C6%0C%03wap.iobox.fi%00%11%03
+       1%40wiral.com%00%07%0A%C3%07%19%99%06%25%15%23%15%10%C3%04+%02%060%01
+       %03Want+to+test+a+fetch%3F%00%01%01&amp;udh=%06%05%04%0B%84%23%F0&amp;
+       dlrmask=31&amp;dlrurl=http%3A%2F%2F193.53.0.56%2Fnotification-dlr%3F
+       smsc-id=%i%26status=%d%26answer=%A%26to=%P%26from=%p%26ts=%t
+<\userinput><\screen>
+
+       <para>Note that you can use all sms service escapes in dlrur, see
+       Parameters (Escape Codes) for details.<\para>
+
+       <para> If you want to set dlr url for a spesific user, you must set
+       configuration variable <literal>dlr-url<\literal>in <literal>
+       wap-push-user<\literal>, if for entire ppg, <literal>default-dlr-url
+       <\literal> in group <literal>ppg<\literal>. Value must naturally match
+       with one used in group smsc.<\para>
+</sect1>
+
+<sect1>
+<title>Routing WAP pushes to a specific smsc</title>
+       <para> This chapter explains how to route wap push to a spesific
+       smsc. </para>
+
+       <para> Smsc routing for wap pushes is similar to sms pushes. So,
+       firstly you must define configuration variable <literal>smsc-id
+       <\literal> in smsc group (or groups) in question. Say you used
+       value <literal>link0<\literal>. So you can issue a request:<\para>
+
+<screen><userinput>
+       http://193.53.0.56:8080/phplib/kannelgw.php?user=*deleted*&amp;
+       pass=*deleted*=to=%2B358408676001&amp;text=3D%02%06%17%AE%96localhost
+       %3A8080%00%AF%80%8D%CF%B4%80%02%05j%00E%C6%0C%03wap.iobox.fi%00%11%03
+       1%40wiral.com%00%07%0A%C3%07%19%99%06%25%15%23%15%10%C3%04+%02%060%01
+       %03Want+to+test+a+fetch%3F%00%01%01&amp;udh=%06%05%04%0B%84%23%F0&amp;
+       smsc=link0
+<\userinput><\screen>
+
+      <para> You can use configuration variables to route all messages of a
+      specific user or all ppg messages. Set <literal>default-smsc<\literal>
+      in group wap-push-user or in group ppg.<\para>
+
+      <para>Again precedence of various methods of setting the smsc is 
+      cgi variable, then configuration variable in group wap push user and
+      then in group ppg.<\para>
+
+</sect1>
+     
 </chapter>
 
 
@@ -7249,6 +7390,35 @@
              <entry valign="bottom">
              Use <emphasis>number</emphasis> threads instead of default
              <literal>1</literal>.
+             </entry></row>
+             <row><entry><literal>-s</literal></entry>
+             <entry><emphasis>string</emphasis></entry>
+             <entry valign="bottom">
+             Use <literal>string<\literal> as a X-WAP-Application-Id
+             header (You must supply whole header).
+             </entry></row>
+             <row><entry><literal>-B</literal></entry>
+             <entry><emphasis>boolean</emphasis></entry>
+             <entry valign="bottom">
+             If set, accept binary content. Default is off.
+             <literal>1</literal>.
+             </entry></row>
+             <row><entry><literal>-d</literal></entry>
+             <entry><emphasis>enumerated string</emphasis></entry>
+             <entry valign="bottom">
+             Set delimiter to be used. Acceptable values are crlf anf
+             lf. Default is <literal>crlf<\literal>.
+             </entry></row>
+             <row><entry><literal>-p</literal></entry>
+             <entry><emphasis>boolean</emphasis></entry>
+             <entry valign="bottom">
+             If set, add an preamble (hardcoded one). Default
+             is off.
+             </entry></row>
+             <row><entry><literal>-E</literal></entry>
+             <entry><emphasis>boolean</emphasis></entry>
+             <entry valign="bottom">
+             if set, add an epilogue (hardcoded). Default is off.
              </entry></row>
              </tbody>
              </tgroup>
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	12 Jun 2003 09:17:01 -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	12 Jun 2003 09:17:02 -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	12 Jun 2003 09:17:02 -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	12 Jun 2003 09:17:02 -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"
@@ -2660,7 +2665,9 @@
  * ain application id reserved by WINA or the part containing assigned code. 
  * Otherwise (regardless of it being an URI or assigned code) we simply pass 
  * it forward. 
- * These are defined by WINA at http://www.wapforum.org/wina/push-app-id.htm. 
+ * These are defined by WINA at http://www.openmobilealliance.org/tech/
+ * omna/omna-push-app-id.htm. We recognize both well-known and registered
+ * values. X-wap-application is not added, it is considired a default.
  */
 
 static char *wina_uri[] =
@@ -2670,7 +2677,26 @@
     "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",
+    "x-wap-docomo:imode.mail2.ua",
+    "x-oma-nec:otaprov.ua",
+    "x-oma-nokia:call.ua"
 };
 
 #define NUMBER_OF_WINA_URIS sizeof(wina_uri)/sizeof(wina_uri[0])
@@ -2680,14 +2706,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 +2865,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	12 Jun 2003 09:17:02 -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	12 Jun 2003 09:17:03 -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	12 Jun 2003 09:17:03 -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	12 Jun 2003 09:17:03 -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	12 Jun 2003 09:17:04 -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	12 Jun 2003 09:17:04 -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	12 Jun 2003 09:17:04 -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) */
@@ -454,8 +454,9 @@
 )
 
 /*
- * Well known push application ids, from http://www.wapforum.org/wina/
- * push-app-id.htm.
+ * Well known and reserver push application ids, from http://www.openmobile-
+ * alliance.org/omna/omna-push-app-id.htm. Note that id strings does not contain
+ * x-wap-application, this being default.
  */
 NUMBERED(application_id,
 ASSIGN("*", 0x00)
@@ -465,6 +466,25 @@
 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)
+ASSIGN("x-wap-docomo: imode.mail2.ua", 0x9000)
+ASSIGN("x-oma-nec: otaprov.ua", 0x9001)
+ASSIGN("x-oma-nokia: call.ua", 0x9002)
 )
 
 /**** 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	12 Jun 2003 09:17:04 -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);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.