Fw: SAR

<[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <012c01c28b5e$f3fce8a0$bc00a8c0@D>
hi !

     I downloaded the new CVS code and created this patch. Try it.





urs,
denzel.
cvs.patch (application/octet-stream, 59.3 KB)
Common subdirectories: wap/CVS and ../../gateway-cvs/wap/CVS
diff -ub wap/wap.c ../../gateway-cvs/wap/wap.c
--- wap/wap.c	Mon Nov 20 11:55:54 2000
+++ ../../gateway-cvs/wap/wap.c	Tue Oct 15 05:33:32 2002
@@ -10,11 +10,12 @@
 
 void wap_dispatch_datagram(WAPEvent *dgram)
 {
+    debug("wap.wap", 0, "XXXXXXX: wap_dispatch_datagram");
+
     gw_assert(dgram != NULL);
 
     if (dgram->type != T_DUnitdata_Ind) {
 	warning(0, "wap_dispatch_datagram got event of unexpected type.");
-	wap_event_dump(dgram);
 	wap_event_destroy(dgram);
         return;
     }
@@ -32,6 +33,9 @@
 	    WAPEvent *event;
 
 	    event = list_extract_first(events);
+	    debug("wap.wap", 0, "XXXXXXX: wap_dispatch_datagram <---------------");
+     	    wap_event_dump(event);
+
             if (wtp_event_is_for_responder(event))
                 wtp_resp_dispatch_event(event);
             else
diff -ub wap/wap_events.def ../../gateway-cvs/wap/wap_events.def
--- wap/wap_events.def	Tue Nov 12 05:34:53 2002
+++ ../../gateway-cvs/wap/wap_events.def	Sun Oct 27 23:12:03 2002
@@ -438,17 +438,6 @@
 	ADDRTUPLE(addr_tuple)
 	)
 
-WAPEVENT(RcvSegInvoke, "RcvSegInvoke",
-    OCTSTR(user_data)
-    INTEGER(tid)
-    INTEGER(rid)
-    INTEGER(no_cache_supported)
-    INTEGER(gtr)
-    INTEGER(ttr)
-    INTEGER(psn)
-    ADDRTUPLE(addr_tuple)
-    )
-
 WAPEVENT(RcvResult, "RcvResult",
 	OCTSTR(user_data)
 	INTEGER(tid)
@@ -469,11 +458,11 @@
 	INTEGER(tid)
 	INTEGER(tid_ok)
 	INTEGER(rid)
-    INTEGER(psn)
+	INTEGER(psnr)
 	ADDRTUPLE(addr_tuple)
 	)
 
-WAPEVENT(RcvNegativeAck, "RcvNack",
+WAPEVENT(RcvNack, "RcvNack",
     INTEGER(tid)
     INTEGER(rid)
     INTEGER(nmissing)
@@ -481,6 +470,16 @@
     ADDRTUPLE(addr_tuple)
     )
 
+WAPEVENT(RcvSegmInvoke, "RcvSegmInvoke",
+        OCTSTR(user_data)
+        INTEGER(tid)
+        INTEGER(gtr)
+        INTEGER(ttr)
+	INTEGER(psn)
+	INTEGER(rid)
+        ADDRTUPLE(addr_tuple)
+        )
+
 /*
  * Other events used by WTP layer.
  */
diff -ub wap/wsp_pdu.c ../../gateway-cvs/wap/wsp_pdu.c
--- wap/wsp_pdu.c	Mon Nov 20 11:55:54 2000
+++ ../../gateway-cvs/wap/wsp_pdu.c	Sun Oct 27 23:12:04 2002
@@ -123,6 +123,8 @@
 	WSP_PDU *pdu = NULL;
 	long bitpos = 0;
 
+	debug("wap.wsp", 0, "XXXXXXX: wsp_pdu_unpack");
+
 	gw_assert(data != NULL);
 
 	pdu = gw_malloc(sizeof(*pdu));
diff -ub wap/wsp_session.c ../../gateway-cvs/wap/wsp_session.c
--- wap/wsp_session.c	Tue May 14 04:05:08 2002
+++ ../../gateway-cvs/wap/wsp_session.c	Sun Oct 27 23:12:04 2002
@@ -167,6 +167,9 @@
 
 
 void wsp_session_dispatch_event(WAPEvent *event) {
+
+	debug("wap.wSp", 0, "XXXXXXX: wsp_session_dispatch_event");
+
 	wap_event_assert(event);
 	list_produce(queue, event);
 }
diff -ub wap/wtp.c ../../gateway-cvs/wap/wtp.c
--- wap/wtp.c	Tue Nov 12 05:34:53 2002
+++ ../../gateway-cvs/wap/wtp.c	Sun Oct 27 23:12:04 2002
@@ -26,11 +26,10 @@
 static int concatenated_message(Octstr *user_data);
 static int truncated_datagram(WAPEvent *event);
 static WAPEvent *unpack_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
-static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
 static WAPEvent *unpack_result(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
 static WAPEvent *unpack_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
-static WAPEvent *unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
 static WAPEvent *unpack_abort(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
+static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
 static WAPEvent *pack_error(WAPEvent *datagram);
 
 /******************************************************************************
@@ -47,6 +46,8 @@
      Octstr *data = NULL;
      long pdu_len;
 
+     debug("wap.wtp", 0, "XXXXXXX: wtp_unpack_wdp_datagram");
+
      gw_assert(datagram->type == T_DUnitdata_Ind);
 
      events = list_create();
@@ -99,13 +100,15 @@
 int wtp_event_is_for_responder(WAPEvent *event)
 {
 
+     debug("wap.wtp", 0, "XXXXXXX: wtp_event_is_for_responder");
+
      switch(event->type){
           
      case RcvInvoke:
          return event->u.RcvInvoke.tid < INITIATOR_TID_LIMIT;
 
-     case RcvSegInvoke:
-        return event->u.RcvSegInvoke.tid < INITIATOR_TID_LIMIT;
+     case RcvSegmInvoke:
+         return event->u.RcvSegmInvoke.tid < INITIATOR_TID_LIMIT;
 
      case RcvResult:
          return event->u.RcvResult.tid < INITIATOR_TID_LIMIT;
@@ -113,8 +116,8 @@
      case RcvAck:
         return event->u.RcvAck.tid < INITIATOR_TID_LIMIT;
 
-     case RcvNegativeAck:
-        return event->u.RcvNegativeAck.tid < INITIATOR_TID_LIMIT;
+     case RcvNack:
+	 return event->u.RcvNack.tid < INITIATOR_TID_LIMIT;
 
      case RcvAbort:
         return event->u.RcvAbort.tid < INITIATOR_TID_LIMIT;
@@ -137,6 +140,8 @@
  */
 static int truncated_datagram(WAPEvent *dgram)
 {
+    debug("wap.wtp", 0, "XXXXXXX: truncated_datagram");
+
     gw_assert(dgram->type == T_DUnitdata_Ind);
 
     if (octstr_len(dgram->u.T_DUnitdata_Ind.user_data) < 3) {
@@ -151,6 +156,8 @@
 {
     WAPEvent *event;
 
+    debug("wap.wtp", 0, "XXXXXXX: unpack_invoke");
+
     event = wap_event_create(RcvInvoke);
     event->u.RcvInvoke.user_data = 
         octstr_duplicate(pdu->u.Invoke.user_data);
@@ -168,28 +175,12 @@
     return event;
 }
 
-static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
-{
-    WAPEvent *event;
-
-    event = wap_event_create(RcvSegInvoke);
-    event->u.RcvSegInvoke.user_data = 
-        octstr_duplicate(pdu->u.Segmented_invoke.user_data);
-    event->u.RcvSegInvoke.tid = pdu->u.Segmented_invoke.tid;
-    event->u.RcvSegInvoke.rid = pdu->u.Segmented_invoke.rid;
-    event->u.RcvSegInvoke.no_cache_supported = 0;
-    event->u.RcvSegInvoke.gtr = pdu->u.Segmented_invoke.gtr;
-    event->u.RcvSegInvoke.ttr = pdu->u.Segmented_invoke.ttr;
-    event->u.RcvSegInvoke.psn = pdu->u.Segmented_invoke.psn;
-    event->u.RcvSegInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
-
-    return event;
-}
-
 static WAPEvent *unpack_result(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
 {
     WAPEvent *event;
 
+    debug("wap.wtp", 0, "XXXXXXX: unpack_result");
+
     event = wap_event_create(RcvResult);
     event->u.RcvResult.user_data = 
         octstr_duplicate(pdu->u.Result.user_data);
@@ -206,39 +197,42 @@
 {
     WAPEvent *event;
     WTP_TPI *tpi;
-    int	i, num_tpis;
+    int num_tpis, i;
+
+    debug("wap.wtp", 0, "XXXXXXX: unpack_ack");
 
     event = wap_event_create(RcvAck);
     event->u.RcvAck.tid = pdu->u.Ack.tid;
     event->u.RcvAck.tid_ok = pdu->u.Ack.tidverify;
     event->u.RcvAck.rid = pdu->u.Ack.rid;
-    event->u.RcvAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
 
-    /* Set default to 0 because Ack on 1 piece message has no tpi */
-    event->u.RcvAck.psn = 0;
+    if (pdu->u.Ack.con == 1) {
     num_tpis = list_len(pdu->options);
-
     for (i = 0; i < num_tpis; i++) {
         tpi = list_get(pdu->options, i);
-        if (tpi->type == TPI_PSN) {
-            event->u.RcvAck.psn = octstr_get_bits(tpi->data,0,8);
-            break;
+	
+	    if (tpi->type == 0x03)
+		event->u.RcvAck.psnr = octstr_get_char(tpi->data, 0);
         }
     }
 
+    event->u.RcvAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
+
     return event;
 }
 
-static WAPEvent *unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
+static WAPEvent *unpack_nack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
 {
     WAPEvent *event;
 
-    event = wap_event_create(RcvNegativeAck);
-    event->u.RcvNegativeAck.tid = pdu->u.Negative_ack.tid;
-    event->u.RcvNegativeAck.rid = pdu->u.Negative_ack.rid;
-    event->u.RcvNegativeAck.nmissing = pdu->u.Negative_ack.nmissing;
-    event->u.RcvNegativeAck.missing = octstr_duplicate(pdu->u.Negative_ack.missing);
-    event->u.RcvNegativeAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
+    debug("wap.wtp", 0, "XXXXXXX: unpack_nack");
+
+    event = wap_event_create(RcvNack);
+    event->u.RcvNack.tid = pdu->u.Negative_ack.tid;
+    event->u.RcvNack.rid = pdu->u.Negative_ack.rid;
+    event->u.RcvNack.nmissing = pdu->u.Negative_ack.nmissing;
+    event->u.RcvNack.missing =  octstr_duplicate(pdu->u.Negative_ack.missing);
+    event->u.RcvNack.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
     
     return event;
 }
@@ -247,6 +241,8 @@
 {
      WAPEvent *event;
 
+     debug("wap.wtp", 0, "XXXXXXX: unpack_abort");
+
      event = wap_event_create(RcvAbort);
      event->u.RcvAbort.tid = pdu->u.Abort.tid;
      event->u.RcvAbort.abort_type = pdu->u.Abort.abort_type;
@@ -256,10 +252,31 @@
      return event;
 }
 
+static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
+{
+    WAPEvent *event;
+
+    debug("wap.wtp", 0, "XXXXXXX: unpack_segmented_invoke");
+
+    event = wap_event_create(RcvSegmInvoke);
+
+    event->u.RcvSegmInvoke.tid = pdu->u.Segmented_invoke.tid;
+    event->u.RcvSegmInvoke.gtr = pdu->u.Segmented_invoke.gtr;
+    event->u.RcvSegmInvoke.ttr = pdu->u.Segmented_invoke.ttr;
+    event->u.RcvSegmInvoke.rid = pdu->u.Segmented_invoke.rid;
+    event->u.RcvSegmInvoke.psn = pdu->u.Segmented_invoke.psn;
+    event->u.RcvSegmInvoke.user_data = octstr_duplicate(pdu->u.Segmented_invoke.user_data);
+    event->u.RcvSegmInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
+
+    return event;
+}
+
 static WAPEvent *pack_error(WAPEvent *datagram)
 {
     WAPEvent *event;
 
+    debug("wap.wtp", 0, "XXXXXXX: pack_error");
+
     gw_assert(datagram->type == T_DUnitdata_Ind);
 
     event = wap_event_create(RcvErrorPDU);
@@ -288,6 +305,8 @@
     WAPEvent *event;
     Octstr *data;
 
+    debug("wap.wtp", 0, "XXXXXXX: unpack_wdp_datagram_real");
+
     gw_assert(datagram->type == T_DUnitdata_Ind);
 
     data = datagram->u.T_DUnitdata_Ind.user_data;
@@ -320,10 +339,6 @@
         }
         break;
 
-    case Segmented_invoke:
-        event = unpack_segmented_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
-        break;
-
     case Result:
         event = unpack_result(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
         /* if an WTP responder gets result, it would be an illegal pdu. */
@@ -339,12 +354,16 @@
         break;
 
     case Negative_ack:
-        event = unpack_negative_ack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);    
+	    event = unpack_nack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);    
         break;
 
 	case Abort:
 	    event = unpack_abort(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
         break;         
+
+	case Segmented_invoke:
+	    event = unpack_segmented_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
+	    break;
 
 	default:
 	    event = pack_error(datagram);
diff -ub wap/wtp.h ../../gateway-cvs/wap/wtp.h
--- wap/wtp.h	Tue Nov 12 05:34:53 2002
+++ ../../gateway-cvs/wap/wtp.h	Tue Oct 15 04:57:28 2002
@@ -25,7 +25,7 @@
  */
 enum {
     NUMBER_OF_ABORT_TYPES = 2,
-    NUMBER_OF_ABORT_REASONS  = 10,
+    NUMBER_OF_ABORT_REASONS  = 9,
     NUMBER_OF_TRANSACTION_CLASSES = 3
 };
 
@@ -82,8 +82,7 @@
     WTPVERSIONZERO = 0x06,
     CAPTEMPEXCEEDED = 0x07,
     NORESPONSE = 0x08,
-    MESSAGETOOLARGE = 0x09,
-    NOTIMPLEMENTEDESAR = 0x0A
+    MESSAGETOOLARGE = 0x09
 };    
 
 /*
@@ -109,15 +108,6 @@
 enum {
     INITIATOR_INDICATION = 0,
     RESPONDER_INDICATION = 1 
-};
-
-enum {
-    TPI_ERROR = 0,
-    TPI_INFO = 1,
-    TPI_OPTION = 2,
-    TPI_PSN = 3,
-    TPI_SDU_BOUNDARY = 4,
-    TPI_FRAME_BOUNDARY = 5
 };
 
 /*
diff -ub wap/wtp_init.c ../../gateway-cvs/wap/wtp_init.c
--- wap/wtp_init.c	Tue Mar 27 06:35:03 2001
+++ ../../gateway-cvs/wap/wtp_init.c	Sun Oct 27 23:12:05 2002
@@ -141,6 +141,8 @@
 
 void wtp_initiator_dispatch_event(WAPEvent *event) 
 {
+    debug("wap.wtp", 0, "XXXXXXX: wtp_initiator_dispatch_event");
+
     list_produce(queue, event);
 }
 
diff -ub wap/wtp_pack.c ../../gateway-cvs/wap/wtp_pack.c
--- wap/wtp_pack.c	Tue Nov 12 05:34:53 2002
+++ ../../gateway-cvs/wap/wtp_pack.c	Sun Oct 27 23:12:05 2002
@@ -27,9 +27,7 @@
     ERROR_DATA = 0x00,
     INFO_DATA = 0x01,
     OPTION = 0x02,
-    PACKET_SEQUENCE_NUMBER = 0x03,
-    SDU_BOUNDARY = 0x04,
-    FRAME_BOUNDARY = 0x05
+    PACKET_SEQUENCE_NUMBER = 0x03
 };
 
 /*****************************************************************************
@@ -108,48 +106,40 @@
     return dgram;
 }
 
-WAPEvent *wtp_pack_sar_result(WTPRespMachine *machine, int psn)
+WAPEvent *wtp_segm_pack_result(WTPRespMachine *machine, int psn, int gtr, int ttr)
 {
     WAPEvent *dgram = NULL;
     WTP_PDU *pdu = NULL;
-    Octstr *data = NULL;
-    int gtr, ttr;
+    Octstr *psntmp;
 
-    gw_assert(machine->sar && machine->sar->data);
+    debug("wap.wtp", 0, "XXXXXXX: wtp_segm_pack_result psn=%d gtr=%d ttr=%d list_len=%d segm_count=%d", psn, gtr, ttr, list_len(machine->segments), machine->segm_count);
 
-    if (psn > machine->sar->nsegm)
-        return dgram;
-
-    ttr = psn == machine->sar->nsegm ? 1 : 0;
-    gtr = ttr ? 0 : (psn+1)%SAR_GROUP_LEN ? 0 : 1;
-
-    if (gtr || ttr) 
-        machine->sar->tr = 1;
-
-    data = octstr_copy(machine->sar->data,psn*SAR_SEGM_SIZE,SAR_SEGM_SIZE);
+    gw_assert(psn < machine->segm_count);
 
-    if (!psn) {
+    if (psn == 0) {
         pdu = wtp_pdu_create(Result);
         pdu->u.Result.con = 0;
         pdu->u.Result.gtr = gtr;
         pdu->u.Result.ttr = ttr;
-        pdu->u.Result.rid = 0;
+        pdu->u.Result.rid = machine->rid;
         pdu->u.Result.tid = send_tid(machine->tid);
-        pdu->u.Result.user_data = data;
+        pdu->u.Result.user_data = octstr_duplicate(list_get(machine->segments, 0));
     } else {
         pdu = wtp_pdu_create(Segmented_result);
+        
         pdu->u.Segmented_result.con = 0;
+    
         pdu->u.Segmented_result.gtr = gtr;
         pdu->u.Segmented_result.ttr = ttr;
-        pdu->u.Segmented_result.rid = 0;
+        pdu->u.Segmented_result.rid = machine->rid;
         pdu->u.Segmented_result.tid = send_tid(machine->tid);
         pdu->u.Segmented_result.psn = psn;
-        pdu->u.Segmented_result.user_data = data;
+
+        pdu->u.Segmented_result.user_data = octstr_duplicate(list_get(machine->segments, psn));
     }
 
     dgram = wap_event_create(T_DUnitdata_Req);
-    dgram->u.T_DUnitdata_Req.addr_tuple =
-        wap_addr_tuple_duplicate(machine->addr_tuple);
+    dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(machine->addr_tuple);
     dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
     wtp_pdu_destroy(pdu);
 
@@ -199,30 +189,68 @@
     dgram = wap_event_create(T_DUnitdata_Req);
     dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address);
     dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
+    wtp_pdu_dump(pdu, 0);
     wtp_pdu_destroy(pdu);
 
     return dgram;
 }
 
-WAPEvent *wtp_pack_sar_ack(long ack_type, long tid, WAPAddrTuple *address, int psn)
+WAPEvent *wtp_pack_segmack(long ack_type, int rid_flag, long tid, int psnr, 
+                       WAPAddrTuple *address)
 {
     WAPEvent *dgram = NULL;
     WTP_PDU *pdu;
-    unsigned char cpsn;
+    Octstr *o_psnr = octstr_create("0");
     
-    sprintf(&cpsn, "%c", psn);
+    debug("wap.wtp", 0, "XXXXXXX: wtp_pack_segmack PSNR=%d", psnr);
 
     pdu = wtp_pdu_create(Ack);
     pdu->u.Ack.con = 1;
     pdu->u.Ack.tidverify = ack_type;
-    pdu->u.Ack.rid = 0;
+    pdu->u.Ack.rid = rid_flag;
     pdu->u.Ack.tid = send_tid(tid);
+    octstr_set_char(o_psnr, 0, psnr);
+    
+    wtp_pdu_append_tpi(pdu, 0x03, o_psnr);
+
+    dgram = wap_event_create(T_DUnitdata_Req);
+    dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address);
 
-    wtp_pdu_append_tpi(pdu, 3, octstr_create_from_data((char*) &cpsn, 1));
+    dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
+    wtp_pdu_dump(pdu, 0);
+    wtp_pdu_destroy(pdu);
+
+    return dgram;
+}
+
+
+WAPEvent *wtp_pack_segmnack(int rid_flag, long tid, List *nack_list, 
+                       WAPAddrTuple *address)
+{
+    WAPEvent *dgram = NULL;
+    WTP_PDU *pdu;
+    Octstr *o_psnr = octstr_create("");
+    int i;
+     
+    debug("wap.wtp", 0, "XXXXXXX: wtp_pack_segmnack");
+
+    pdu = wtp_pdu_create(Negative_ack);
+    pdu->u.Negative_ack.con = 0;
+    pdu->u.Negative_ack.rid = rid_flag;
+    pdu->u.Negative_ack.tid = send_tid(tid);
+    pdu->u.Negative_ack.nmissing = list_len(nack_list);
+
+    for (i=0; i<pdu->u.Negative_ack.nmissing; i++)
+    	octstr_append(o_psnr, list_get(nack_list, i));
+
+    if (pdu->u.Negative_ack.nmissing > 0)
+    	pdu->u.Negative_ack.missing = o_psnr;
 
     dgram = wap_event_create(T_DUnitdata_Req);
     dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address);
+    
     dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
+    wtp_pdu_dump(pdu, 0);
     wtp_pdu_destroy(pdu);
 
     return dgram;
diff -ub wap/wtp_pack.h ../../gateway-cvs/wap/wtp_pack.h
--- wap/wtp_pack.h	Tue Nov 12 05:34:53 2002
+++ ../../gateway-cvs/wap/wtp_pack.h	Sun Oct 27 23:12:05 2002
@@ -33,11 +33,9 @@
  */
 
 WAPEvent *wtp_pack_result(WTPRespMachine *resp_machine, WAPEvent *event); 
-
-/*
- * Same as above but for a segmented result.
- */
-WAPEvent *wtp_pack_sar_result(WTPRespMachine *resp_machine, int psn); 
+WAPEvent *wtp_segm_pack_result(WTPRespMachine *machine, int psn, int gtr, int ttr);
+WAPEvent *wtp_pack_segmack(long ack_type, int rid_flag, long tid, int psnr, WAPAddrTuple *address);
+WAPEvent *wtp_pack_segmnack(int rid_flag, long tid, List *nack_list, WAPAddrTuple *address);
 
 /*
  * Create a datagram event, having abort PDU as user data. Fetches SDU
@@ -58,11 +56,6 @@
 
 WAPEvent *wtp_pack_ack(long ack_type, int rid_flag, long tid, 
                        WAPAddrTuple *address);
-
-/*
- * Same as above but for a segmented ack
- */
-WAPEvent *wtp_pack_sar_ack(long ack_type, long tid, WAPAddrTuple *address, int psn);
 
 /*
  * Set or unset the retransmission indicator on a PDU that has already
diff -ub wap/wtp_pdu.c ../../gateway-cvs/wap/wtp_pdu.c
--- wap/wtp_pdu.c	Tue Nov 12 05:34:53 2002
+++ ../../gateway-cvs/wap/wtp_pdu.c	Tue Oct 15 05:05:16 2002
@@ -38,7 +38,7 @@
 #undef UINT
 #undef PDU
 	default:
-        warning(0, "Cannot create unknown WTP PDU type %d", pdu->type);
+		warning(0, "Cannot destroy unknown WTP PDU type %d", pdu->type);
 		break;
 	}
 
diff -ub wap/wtp_resp.c ../../gateway-cvs/wap/wtp_resp.c
--- wap/wtp_resp.c	Tue Nov 12 05:34:53 2002
+++ ../../gateway-cvs/wap/wtp_resp.c	Tue Nov  5 03:19:48 2002
@@ -49,6 +49,11 @@
  */
 static List *resp_queue = NULL;
 
+/*
+ * Indicator for forced WTP-SAR client kludge
+ */
+extern int wtp_forced_sar;
+
 /*****************************************************************************
  *
  * Prototypes of internal functions:
@@ -115,22 +120,10 @@
 static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason);
 static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm);
 static int erroneous_field_in(WAPEvent *event);
+static void handle_no_sar(WAPEvent *event);
 static void handle_wrong_version(WAPEvent *event);
 
 /*
- * SAR related functions.
- */
-static WAPEvent *assembly_sar_event (WTPRespMachine *machine, int last_psn);
-static int add_sar_transaction (WTPRespMachine *machine, Octstr *data, int psn);
-/* static int is_wanted_sar_data (void *a, void *b); */
-static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event);
-static void begin_sar_result(WTPRespMachine *machine, WAPEvent *event);
-static void continue_sar_result(WTPRespMachine *machine, WAPEvent *event);
-static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event);
-static void sar_info_destroy(void *sar_info);
-static void sardata_destroy(void *sardata);
-
-/*
  * Create a datagram with an Abort PDU and send it to the WDP layer.
  */
 static void send_abort(WTPRespMachine *machine, long type, long reason);
@@ -140,6 +133,13 @@
  */
 static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag);
 
+static void send_segm_ack(WTPRespMachine *machine, long ack_type, int rid_flag, int psnr);
+static Octstr *cat_segments(WTPRespMachine *machine);
+static void create_segments(WTPRespMachine *machine, Octstr *user_data);
+static void wtp_check_segments(WTPRespMachine *machine, int grp_psn, int ttr);
+static void wtp_send_segm(WTPRespMachine *machine);
+static void wtp_resend_segm(WTPRespMachine *machine, WAPEvent *event);
+static int wtp_check_group(WTPRespMachine *machine, int grp_psn);
 
 /******************************************************************************
  *
@@ -151,6 +151,8 @@
                    wap_dispatch_func_t *session_dispatch,
                    wap_dispatch_func_t *push_dispatch) 
 {
+    debug("wap.wtp", 0, "XXXXXXX: wtp_resp_init");
+
     resp_machines = list_create();
     resp_machine_id_counter = counter_create();
 
@@ -171,6 +173,8 @@
 
 void wtp_resp_shutdown(void) 
 {
+    debug("wap.wtp", 0, "XXXXXXX: wtp_resp_shutdown");
+
     gw_assert(resp_run_status == running);
     resp_run_status = terminating;
     list_remove_producer(resp_queue);
@@ -189,6 +193,7 @@
 
 void wtp_resp_dispatch_event(WAPEvent *event) 
 {
+    debug("wap.wtp", 0, "XXXXXXX: wtp_resp_dispatch_event");
     list_produce(resp_queue, event);
 }
 
@@ -204,16 +209,16 @@
     WTPRespMachine *sm;
     WAPEvent *e;
 
+    debug("wap.wtp", 0, "XXXXXXX: main_thread");
+
     while (resp_run_status == running && 
            (e = list_consume(resp_queue)) != NULL) {
-
         sm = resp_machine_find_or_create(e);
-        if (sm == NULL) {
+	if (sm == NULL)
             wap_event_destroy(e);
-        } else {
+	else
             resp_event_handle(sm, e);
         }
-    }
 }
 
 /*
@@ -221,6 +226,8 @@
  */
 static unsigned char *name_resp_state(int s)
 {
+    debug("wap.wtp", 0, "XXXXXXX: name_resp_state");
+
        switch (s) {
        #define STATE_NAME(state) case state: return #state;
        #define ROW(state, event, condition, action, new_state)
@@ -239,21 +246,6 @@
 static void resp_event_handle(WTPRespMachine *resp_machine, WAPEvent *event)
 {
     WAPEvent *wsp_event = NULL;
-    WAPEvent *e = NULL; /* For SAR acknowledgment */
-
-    /* 
-     * We don't feed sar packets into state machine 
-     * until we got the whole message 
-     */
-    if (process_sar_transaction(resp_machine,&event) == 0) {
-        debug("wap.wtp", 0, "SAR event received, wait for continue");
-        /* For removing state machine in case of incomplete sar */
-        start_timer_W(resp_machine);
-        if (event != NULL) {
-            wap_event_destroy(event);  
-        }
-        return;
-    }
 
     debug("wap.wtp", 0, "WTP: resp_machine %ld, state %s, event %s.", 
 	  resp_machine->mid, 
@@ -290,6 +282,8 @@
 {       
     WAPEvent *ab;
 
+    debug("wap.wtp", 0, "XXXXXXX: handle_wrong_version");
+
     if (event->type == RcvInvoke) {
         ab = wtp_pack_abort(PROVIDER, WTPVERSIONZERO, event->u.RcvInvoke.tid, 
                             event->u.RcvInvoke.addr_tuple);
@@ -298,11 +292,38 @@
 }
 
 /*
+ * This function will be removed when we have SAR
+ */
+static void handle_no_sar(WAPEvent *event)
+{
+    WAPEvent *ab;
+
+    debug("wap.wtp", 0, "XXXXXXX: handle_no_sar");
+
+    if (event->type == RcvInvoke) {
+        ab = wtp_pack_abort(PROVIDER, NOTIMPLEMENTEDSAR, 
+                            event->u.RcvInvoke.tid,
+                            event->u.RcvInvoke.addr_tuple);
+        dispatch_to_wdp(ab);
+    }
+}
+
+/*
  * Check for features 7 and 9 in WTP 10.2.
  */
 static int erroneous_field_in(WAPEvent *event)
 {
-    return event->type == RcvInvoke && event->u.RcvInvoke.version != 0;
+    /*
+     * If clients request WTP-SAR should we force to continue
+     * or act as be should do by telling the client to call back.
+     */
+    debug("wap.wtp", 0, "XXXXXXX: erroneous_field_in");
+
+    if (wtp_forced_sar) 
+        return 0;
+
+    return event->type == RcvInvoke && (event->u.RcvInvoke.version != 0 || 
+               !event->u.RcvInvoke.ttr || !event->u.RcvInvoke.gtr);
 }
 
 /*
@@ -311,12 +332,20 @@
  */
 static void handle_erroneous_field_in(WAPEvent *event)
 {
-    if (event->type == RcvInvoke) {
-        if (event->u.RcvInvoke.version != 0) {
+    debug("wap.wtp", 0, "XXXXXXX: handle_erroneous_field_in");
+
+    if (event->type == RcvInvoke){
+        if (event->u.RcvInvoke.version != 0){
             debug("wap.wtp_resp", 0, "WTP_RESP: wrong version, aborting"
                   "transaction");
             handle_wrong_version(event);
         }
+
+        if (!event->u.RcvInvoke.ttr || !event->u.RcvInvoke.gtr){
+            debug("wap.wtp_resp", 0, "WTP_RESP: no sar implemented," 
+                  "aborting transaction");
+            handle_no_sar(event);
+        }
     }
 }
 
@@ -338,6 +367,8 @@
     long tid, mid;
     WAPAddrTuple *tuple;
 
+    debug("wap.wtp", 0, "XXXXXXX: resp_machine_find_or_create");
+
     tid = -1;
     tuple = NULL;
     mid = -1;
@@ -354,9 +385,15 @@
             }
             break;
 
-        case RcvSegInvoke:
-            tid = event->u.RcvSegInvoke.tid;
-            tuple = event->u.RcvSegInvoke.addr_tuple;
+        case RcvSegmInvoke:
+            /* check if erroneous fields are given */
+            if (erroneous_field_in(event)) {
+                handle_erroneous_field_in(event);
+                return NULL;
+            } else {
+                tid = event->u.RcvSegmInvoke.tid;
+                tuple = event->u.RcvSegmInvoke.addr_tuple;
+            }
             break;
 
         case RcvAck:
@@ -364,9 +401,9 @@
             tuple = event->u.RcvAck.addr_tuple;
             break;
 
-        case RcvNegativeAck:
-            tid = event->u.RcvAck.tid;
-            tuple = event->u.RcvAck.addr_tuple;
+       case RcvNack:
+            tid = event->u.RcvNack.tid;
+            tuple = event->u.RcvNack.addr_tuple;
             break;
 
         case RcvAbort:
@@ -433,20 +470,6 @@
         case RcvInvoke:
             resp_machine = resp_machine_create(tuple, tid, 
                                                event->u.RcvInvoke.tcl);
-            /* if SAR requested */
-            if (!event->u.RcvInvoke.gtr || !event->u.RcvInvoke.ttr) {
-                resp_machine->sar = gw_malloc(sizeof(WTPSARData));
-                resp_machine->sar->nsegm = 0;
-                resp_machine->sar->csegm = 0;
-                resp_machine->sar->lsegm = 0;
-                resp_machine->sar->data = NULL;		
-            }
-
-            break;
-	    
-        case RcvSegInvoke:
-            info(0, "WTP_RESP: resp_machine_find_or_create:"
-                 " segmented invoke received, yet having no machine");
             break;
 
         /*
@@ -457,11 +480,6 @@
                  " ack received, yet having no machine");
             break;
 
-        case RcvNegativeAck: 
-            info(0, "WTP_RESP: resp_machine_find_or_create:"
-                 " negative ack received, yet having no machine");
-            break;
-
         case RcvAbort: 
             info(0, "WTP_RESP: resp_machine_find_or_create:"
                  " abort received, yet having no machine");
@@ -495,6 +513,8 @@
     machine_pattern *pat;
     WTPRespMachine *m;
 	
+    debug("wap.wtp", 0, "XXXXXXX: is_wanted_resp_machine");
+
     m = a;
     pat = b;
 
@@ -515,6 +535,8 @@
     machine_pattern pat;
     WTPRespMachine *m;
 	
+    debug("wap.wtp", 0, "XXXXXXX: resp_machine_find");
+
     pat.tuple = tuple;
     pat.tid = tid;
     pat.mid = mid;
@@ -529,6 +551,8 @@
 {
     WTPRespMachine *resp_machine;
 	
+    debug("wap.wtp", 0, "XXXXXXX: resp_machine_create");
+
     resp_machine = gw_malloc(sizeof(WTPRespMachine)); 
         
     #define ENUM(name) resp_machine->name = LISTEN;
@@ -536,8 +560,8 @@
     #define INTEGER(name) resp_machine->name = 0; 
     #define TIMER(name) resp_machine->name = gwtimer_create(resp_queue); 
     #define ADDRTUPLE(name) resp_machine->name = NULL; 
-    #define LIST(name) resp_machine->name = NULL;
-    #define SARDATA(name) resp_machine->name = NULL;
+    #define LIST(name) resp_machine->name = list_create();
+    #define DICT(name) resp_machine->name = dict_create(10, NULL);
     #define MACHINE(field) field
     #include "wtp_resp_machine.def"
 
@@ -563,6 +587,8 @@
 {
     WTPRespMachine *resp_machine;
 
+    debug("wap.wtp", 0, "XXXXXXX: resp_machine_destroy");
+
     resp_machine = p;
     debug("wap.wtp", 0, "WTP: Destroying WTPRespMachine %p (%ld)", 
 	  (void *) resp_machine, resp_machine->mid);
@@ -574,8 +600,8 @@
     #define INTEGER(name) resp_machine->name = 0; 
     #define TIMER(name) gwtimer_destroy(resp_machine->name); 
     #define ADDRTUPLE(name) wap_addr_tuple_destroy(resp_machine->name); 
-    #define LIST(name) list_destroy(resp_machine->name,sar_info_destroy);
-    #define SARDATA(name) sardata_destroy(resp_machine->name);
+    #define LIST(name) list_destroy(resp_machine->name, NULL);
+    #define DICT(name) dict_destroy(resp_machine->name);
     #define MACHINE(field) field
     #include "wtp_resp_machine.def"
     gw_free(resp_machine);
@@ -588,6 +614,8 @@
 {
     WAPEvent *event;
 	
+    debug("wap.wtp", 0, "XXXXXXX: create_tr_invoke_ind");
+
     event = wap_event_create(TR_Invoke_Ind);
     event->u.TR_Invoke_Ind.ack_type = sm->u_ack;
     event->u.TR_Invoke_Ind.user_data = octstr_duplicate(user_data);
@@ -606,6 +634,8 @@
 {
     WAPEvent *event;
 	
+    debug("wap.wtp", 0, "XXXXXXX: create_tr_result_cnf");
+
     event = wap_event_create(TR_Result_Cnf);
     event->u.TR_Result_Cnf.addr_tuple = 
 	wap_addr_tuple_duplicate(sm->addr_tuple);
@@ -620,6 +650,8 @@
 static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason) {
     WAPEvent *event;
 	
+    debug("wap.wtp", 0, "XXXXXXX: create_tr_abort_ind");
+
     event = wap_event_create(TR_Abort_Ind);
     event->u.TR_Abort_Ind.abort_code = abort_reason;
     event->u.TR_Abort_Ind.addr_tuple = 
@@ -637,6 +669,8 @@
 {
     WAPEvent *timer_event;
 
+    debug("wap.wtp", 0, "XXXXXXX: start_timer_A");
+
     timer_event = wap_event_create(TimerTO_A);
     timer_event->u.TimerTO_A.handle = machine->mid;
     gwtimer_start(machine->timer, L_A_WITH_USER_ACK, timer_event);
@@ -649,6 +683,8 @@
 {
     WAPEvent *timer_event;
 
+    debug("wap.wtp", 0, "XXXXXXX: start_timer_R");
+
     timer_event = wap_event_create(TimerTO_R);
     timer_event->u.TimerTO_R.handle = machine->mid;
     gwtimer_start(machine->timer, L_R_WITH_USER_ACK, timer_event);
@@ -661,6 +697,8 @@
 {
     WAPEvent *timer_event;
 
+    debug("wap.wtp", 0, "XXXXXXX: start_timer_W");
+
     timer_event = wap_event_create(TimerTO_W);
     timer_event->u.TimerTO_W.handle = machine->mid;
     gwtimer_start(machine->timer, W_WITH_USER_ACK, timer_event);
@@ -670,6 +708,8 @@
 {
     WAPEvent *e;
 
+    debug("wap.wtp", 0, "XXXXXXX: send_abort");
+
     e = wtp_pack_abort(type, reason, machine->tid, machine->addr_tuple);
     dispatch_to_wdp(e);
 }
@@ -678,252 +718,185 @@
 {
     WAPEvent *e;
 
+    debug("wap.wtp", 0, "XXXXXXX: send_ack");
+
     e = wtp_pack_ack(ack_type, rid_flag, machine->tid, machine->addr_tuple);
     dispatch_to_wdp(e);
 }
 
-/* 
- * Process incoming event, checking for WTP SAR 
- */
-static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event) 
+static void send_segm_ack(WTPRespMachine *machine, long ack_type, int rid_flag, int psnr)
 {
-    WAPEvent *e, *orig_event;
-    int psn;
+    WAPEvent *event;
   
-    orig_event = *event;
+    debug("wap.wtp", 0, "XXXXXXX: send_segm_ack PSNR=%d", psnr);
 
-    if (orig_event->type == RcvInvoke) { 
-        if (!orig_event->u.RcvInvoke.ttr || !orig_event->u.RcvInvoke.gtr) { /* SAR */
-            /* Ericcson set TTR flag even if we have the only part */
-            if (orig_event->u.RcvInvoke.ttr == 1) {
-                return 1; /* Not SAR although TTR flag was set */
-            } else {
-                /* save initial event */
-                machine->sar_invoke = wap_event_duplicate(orig_event);
+    event = wtp_pack_segmack(ack_type, rid_flag, machine->tid, psnr, machine->addr_tuple);
+    dispatch_to_wdp(event);
+}
 
-                /* save data into list with psn = 0 */
-                add_sar_transaction(machine, orig_event->u.RcvInvoke.user_data, 0);
 
-                if (orig_event->u.RcvInvoke.gtr == 1) { /* Need to acknowledge */
-                    e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid,
-                                         machine->addr_tuple, 0);
-                    dispatch_to_wdp(e);
-                }
-                return 0;
+static void wtp_check_segments(WTPRespMachine *machine, int grp_psn, int ttr)
+{
+    WAPEvent *event;
+    int i=0, nack_len;
+    List *nack_list;
+    Octstr *key;
+    Octstr *o_psnr = octstr_create("0");
+
+    debug("wap.wtp", 0, "XXXXXXX: wtp_check_segments");
+    
+    nack_list = list_create();
+    for (i=machine->last_ack_psn+1; i<grp_psn; i++) {
+    	key = octstr_format("%ld", i); 
+    	if (dict_get(machine->curr_grp_segm, key) == NULL) {
+    		octstr_set_char(o_psnr, 0, i);
+    		list_append(nack_list, octstr_duplicate(o_psnr));
+	}
+	octstr_destroy(key);
+    }
+    
+    nack_len = list_len(nack_list);
+    
+    if (nack_len == 0) {
+	for (i=machine->last_ack_psn+1; i<=grp_psn; i++) {
+	    key = octstr_format("%ld", i); 
+    	    debug("wap.wtp", 0, "************: add_segments %d", i);
+	    list_insert(machine->segments, i, octstr_duplicate(dict_get(machine->curr_grp_segm, key)));
+	    octstr_destroy(key);
+	    machine->segm_count++;
+	}
+	
+	if (ttr == 0) {
+	    event = wtp_pack_segmack(ACKNOWLEDGEMENT, machine->rid, machine->tid, grp_psn, machine->addr_tuple);
+	    machine->result = wap_event_duplicate(event);
+	    dispatch_to_wdp(event);
+	    machine->last_ack_psn = grp_psn;
+	    machine->ack_pdu_sent = 1;
             }
+	dict_destroy(machine->curr_grp_segm);
+	machine->curr_grp_segm = dict_create(10, NULL);
         } else {
-            return 1; /* Not SAR */
-        } 
+	event = wtp_pack_segmnack(machine->rid, machine->tid, nack_list, machine->addr_tuple);
+	machine->result = wap_event_duplicate(event);
+	dispatch_to_wdp(event);
     }
 
-    if (orig_event->type == RcvSegInvoke) {
-        add_sar_transaction(machine, orig_event->u.RcvSegInvoke.user_data, 
-                            orig_event->u.RcvSegInvoke.psn);
-
-        if (orig_event->u.RcvSegInvoke.gtr == 1) { /* Need to acknowledge */
-            e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid, machine->addr_tuple,
-                                 orig_event->u.RcvSegInvoke.psn);
-            dispatch_to_wdp(e);
-        }
-
-        if (orig_event->u.RcvSegInvoke.ttr == 1) { /* Need to feed to WSP */
-
-            /* Create assembled event */
-            psn = orig_event->u.RcvSegInvoke.psn;
-            wap_event_destroy(orig_event);
-      
-            *event = assembly_sar_event(machine,psn);
-
-            gw_assert(event != NULL);
-
-            return 1;
-        }
-        return 0;
-    }
-
-    /* Not SAR message */
-    return 1;
+    list_destroy(nack_list, NULL);
 }
 
-static int is_wanted_sar_data(void *a, void *b)
+
+static int wtp_check_group(WTPRespMachine *machine, int grp_psn)
 {
-    sar_info_t *s;
-    int *i;
+    int i=0;
+    int result=1;
+    Octstr *key;
 
-    s = a;
-    i = b;
+    debug("wap.wtp", 0, "XXXXXXX: wtp_check_group");
 
-    if (*i == s->sar_psn) {
-        return 1;
-    } else {
-        return 0;
+    for (i=machine->last_ack_psn+1; i<grp_psn; i++) {
+	key = octstr_format("%ld", i); 
+    	if (dict_get(machine->curr_grp_segm, key) == NULL) {
+    		result = 0;
+		octstr_destroy(key);
+    		break;
     }
-}
-
-/* 
- * Return 0 if transaction added suscessufully, 1 otherwise.
- */
-static int add_sar_transaction(WTPRespMachine *machine, Octstr *data, int psn) 
-{
-    sar_info_t *sar_info;
-
-    if (machine->sar_info == NULL) {
-        machine->sar_info = list_create();
+	octstr_destroy(key);
     }
 
-    if (list_search(machine->sar_info, &psn, is_wanted_sar_data) == NULL) {
-        sar_info = gw_malloc(sizeof(sar_info_t));
-        sar_info->sar_psn = psn;
-        sar_info->sar_data = octstr_duplicate(data);
-        list_append(machine->sar_info, sar_info);
-        return 0;
-    } else {
-        debug("wap.wtp", 0, "Duplicated psn found, ignore packet");
-        return 1;
-    } 
+    return result;
 }
 
-static WAPEvent *assembly_sar_event(WTPRespMachine *machine, int last_psn) 
-{
-    WAPEvent *e;
+static Octstr *cat_segments(WTPRespMachine *machine) {
+    Octstr *res = octstr_create("");
     int i;
-    sar_info_t *sar_info;
 
-    e = wap_event_duplicate(machine->sar_invoke);
+    debug("wap.wtp", 0, "XXXXXXX: cat_segments");
 
-    for (i = 1; i <= last_psn; i++) {
-        if ((sar_info = list_search(machine->sar_info, &i, is_wanted_sar_data)) != NULL) {
-            octstr_append(e->u.RcvInvoke.user_data,sar_info->sar_data);
-        } else {
-            debug("wap.wtp", 0, "Packet with psn %d not found", i);
-            return e;
-        }
+    for (i=0; i<machine->segm_count; i++) {
+    	octstr_append(res, list_get(machine->segments, i));
     }
 
-    return e;
+    return res;
 }
 
-static void sar_info_destroy(void *p) 
-{
-    sar_info_t *sar_info;
-
-    sar_info = p;
-  
-    octstr_destroy(sar_info->sar_data);
-    gw_free(sar_info);
-}
+static void create_segments(WTPRespMachine *machine, Octstr *user_data) {
+    int i, dataLen, segm_size = 900;
 
-static void sardata_destroy(void *p) 
-{
-    WTPSARData * sardata;
+    debug("wap.wtp", 0, "XXXXXXX: create_segments");
 
-    if (p) {
-        sardata = p;
-        octstr_destroy(sardata->data);
-        gw_free(sardata);
-    }
-}
+    list_destroy(machine->segments, NULL);
+    machine->last_ack_psn = -1;
 
-static void begin_sar_result(WTPRespMachine *resp_machine, WAPEvent *event) 
-{
-    WAPEvent *result;
-    WTPSARData *sar;
-    int psn;
+    machine->segments = list_create();
 
-    gw_assert(resp_machine->sar != NULL);
+    dataLen = octstr_len(user_data);
+    machine->segm_count = dataLen / segm_size;
 
-    sar = resp_machine->sar;
-    sar->data = octstr_duplicate(event->u.TR_Result_Req.user_data);
-    sar->nsegm = (octstr_len(sar->data)-1)/SAR_SEGM_SIZE;
-    sar->tr = sar->lsegm = 0;
-    sar->csegm = -1;
-
-    debug("wap.wtp", 0, "WTP: begin_sar_result(): data len = %lu", 
-          octstr_len(sar->data));
-
-    for (psn = 0; !sar->tr; psn++) {
-        result = wtp_pack_sar_result(resp_machine, psn);
-        if (sar->tr) 
-            resp_machine->result = wap_event_duplicate(result);
+    if (dataLen > (machine->segm_count * segm_size))
+    	machine->segm_count = machine->segm_count + 1;
 
-        debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
-        dispatch_to_wdp(result);
-        sar->lsegm = psn;
+    for (i=0; i<machine->segm_count; i++) {
+    	list_insert(machine->segments, i, octstr_copy_real(user_data, i * segm_size, segm_size));
     }
-
-    resp_machine->rid = 1;
 }
 
-static void continue_sar_result(WTPRespMachine *resp_machine, WAPEvent *event) 
-{
+static void wtp_send_segm(WTPRespMachine *machine) {
     WAPEvent *result;
-    WTPSARData *sar;
-    int psn;
+    int i, max_count, grp_size=3, gtr=0, ttr=0;
 
-    gw_assert(resp_machine->sar != NULL && event->type == RcvAck);
+    debug("wap.wtp", 0, "XXXXXXX: wtp_send_segm");
 
-    sar = resp_machine->sar;
-
-    debug("wap.wtp", 0, "WTP: continue_sar_result(): lsegm=%d, nsegm=%d, csegm=%d",
-          sar->lsegm, sar->nsegm, sar->csegm);
-
-    start_timer_R(resp_machine);
-
-    if (event->u.RcvAck.psn>sar->csegm) {
-        sar->csegm = event->u.RcvAck.psn;
+    i = machine->last_ack_psn + 1;
+    if ((i + grp_size + 1) >= machine->segm_count) {
+    	machine->ttr = 1;
+    	machine->gtr = 0;
+    	max_count = machine->segm_count - 1;
+    } else {
+    	machine->ttr = 0;
+    	machine->gtr = 1;
+    	max_count = i + grp_size;
     }
 
-    sar->tr = 0;
-    wap_event_destroy(resp_machine->result);
-    resp_machine->result = NULL;
+    for (; i<max_count; i++) {
+    	result = wtp_segm_pack_result(machine, i, 0, 0);
+    	wap_event_dump(result);
+     	dispatch_to_wdp(result);
+    }
 
-    for (psn = sar->csegm + 1; !sar->tr; psn++) {
-        result = wtp_pack_sar_result(resp_machine, psn);
-        if (sar->tr) 
-            resp_machine->result = wap_event_duplicate(result);
+    result = wtp_segm_pack_result(machine, i, machine->gtr, machine->ttr);
+    machine->result = wap_event_duplicate(result);
 
-        debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u",psn);
         dispatch_to_wdp(result);
-        sar->lsegm = psn;
-    }
+
+    machine->last_psn = i;
 }
 
-static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event)
-{
+static void wtp_resend_segm(WTPRespMachine *machine, WAPEvent *event) {
     WAPEvent *result;
-    WTPSARData *sar;
-    int	psn, i;
+    int i, nmissing, gtr=0, ttr=0, psnr=0;
 
-    gw_assert(resp_machine->sar != NULL && event->type == RcvNegativeAck);
+    debug("wap.wtp", 0, "XXXXXXX: wtp_resend_segm");
 
-    sar = resp_machine->sar;
+    nmissing = event->u.RcvNack.nmissing;
 
-    debug("wap.wtp", 0, "WTP: resend_sar_result(): lsegm=%d, nsegm=%d, csegm=%d",
-          sar->lsegm, sar->nsegm, sar->csegm);
+    for (i = 0; i < nmissing; i++) {
+    	psnr = octstr_get_char(event->u.RcvNack.missing, i);
 
-    start_timer_R(resp_machine);
-
-    if (event->u.RcvNegativeAck.nmissing) { 
-        /* if we have a list of missed packets */
-        for(i = 0; i < event->u.RcvNegativeAck.nmissing; i++) {
-            if ((psn = octstr_get_char(event->u.RcvNegativeAck.missing, i)) >= 0) {		
-                result = wtp_pack_sar_result(resp_machine, psn);
-                wtp_pack_set_rid(result, 1);
-                debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
-                dispatch_to_wdp(result);
-            }
-        }
+    	if (psnr == machine->last_psn) {
+    	    if (machine->ttr == 0) {
+    	    	gtr = 1;
+    	    	ttr = 0;
     } else { 
-        /* if we have to resend a whole group */
-        sar->tr = 0;
-        for (psn = sar->csegm+1; !sar->tr; psn++) {
-            result = wtp_pack_sar_result(resp_machine, psn);
-            wtp_pack_set_rid(result, 1);
-            debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
-            dispatch_to_wdp(result);
+    	    	gtr = 0;
+    	    	ttr = 1;
         }
     }
-}
 
+    	result = wtp_segm_pack_result(machine, psnr, gtr, ttr);
 
+    	if (i == (nmissing-1))
+    	    machine->result = wap_event_duplicate(result);
 
+     	dispatch_to_wdp(result);
+    }
+}
diff -ub wap/wtp_resp.h ../../gateway-cvs/wap/wtp_resp.h
--- wap/wtp_resp.h	Tue Nov 12 05:34:53 2002
+++ ../../gateway-cvs/wap/wtp_resp.h	Sun Oct 27 23:12:06 2002
@@ -13,32 +13,6 @@
 #include "wap_events.h"
 #include "timers.h"
 
-typedef struct sar_info_t {
-    int sar_psn;
-    Octstr *sar_data;
-} sar_info_t;
-
-
-/*
- * Structure to keep SAR data during transmission
- */
-typedef struct WTPSARData {
-    int nsegm;  /* number of the last segment, i.e. total number - 1 */
-    int csegm;  /* last segment confirmed by recipient */
-    int lsegm;  /* last sent segment */
-    int tr;		/* if current psn is gtr or ttr */
-    Octstr *data;
-} WTPSARData;
-
-
-/* 
- * Nokia wap gw uses the size of 576, but mobiles use 1,5K size, 
- * I will think later what is better to use
- */
-#define	SAR_SEGM_SIZE 576
-#define	SAR_GROUP_LEN 3
-
-
 /*
  * Responder machine states and responder WTP machine.
  * See file wtp_resp_state-decl.h for comments. Note that we must define macro
@@ -65,7 +39,7 @@
        #define ENUM(name) resp_states name;
        #define EVENT(name) WAPEvent *name;
        #define LIST(name) List *name;
-       #define SARDATA(name) WTPSARData *name;
+       #define DICT(name) Dict *name;
        #define MACHINE(field) field
        #include "wtp_resp_machine.def"
 };
diff -ub wap/wtp_resp_machine.def ../../gateway-cvs/wap/wtp_resp_machine.def
--- wap/wtp_resp_machine.def	Tue Nov 12 05:34:53 2002
+++ ../../gateway-cvs/wap/wtp_resp_machine.def	Sun Oct 27 23:12:06 2002
@@ -42,12 +42,12 @@
     #error "Macro TIMER is missing."
 #elif !defined(EVENT) 
     #error "Macro EVENT is missing."
-#elif !defined(LIST)
-    #error "Macro LIST is missing."
-#elif !defined(SARDATA)
-    #error "Macro SARDATA is missing."
 #elif !defined(ADDRTUPLE)
     #error "Macro ADDRTUPLE is missing."
+#elif !defined(LIST)
+    #error "Macro LIST is missing."
+#elif !defined(DICT)
+    #error "Macro DICT is missing."
 #endif
 
 MACHINE(ENUM(state)
@@ -61,15 +61,19 @@
                                       acknowledgement required) */ 
         INTEGER(rid)              /* retransmission flag, telling are we 
                                       resending the result */ 
+        INTEGER(gtr)
+        INTEGER(ttr)
+        INTEGER(last_ack_psn)
+        INTEGER(last_psn)
+        INTEGER(segm_count)
+        LIST(segments)
+        DICT(curr_grp_segm)
         EVENT(result)               /* packed result message - for resending */
         INTEGER(ack_pdu_sent)     /* are we resending the acknowledgement */
         TIMER(timer)              /* pointer to the timer of this machine timer
                                       in the global timers list */
         EVENT(invoke_indication) /* packed wsp invoke indication - for tid
                                          verification */
-        EVENT(sar_invoke)     /* initial invoke for SAR, accumulate user_data */
-        LIST(sar_info)
-        SARDATA(sar)              /* ! NULL if were we asked for SAR */
 	)
 
 #undef MACHINE
@@ -77,6 +81,6 @@
 #undef ENUM
 #undef TIMER
 #undef EVENT
-#undef LIST
-#undef SARDATA
 #undef ADDRTUPLE
+#undef LIST
+#undef DICT
diff -ub wap/wtp_resp_states.def ../../gateway-cvs/wap/wtp_resp_states.def
--- wap/wtp_resp_states.def	Tue Nov 12 05:34:53 2002
+++ ../../gateway-cvs/wap/wtp_resp_states.def	Mon Oct 28 01:20:10 2002
@@ -97,17 +97,20 @@
 STATE_NAME(RESULT_WAIT)
 STATE_NAME(RESULT_RESP_WAIT)
 STATE_NAME(WAIT_TIMEOUT_STATE)
+STATE_NAME(SEGMENT_WAIT)
+STATE_NAME(SEGMENT_ACK_WAIT)
 
 ROW(LISTEN,
     RcvInvoke,
     (event->u.RcvInvoke.tcl == 2 || event->u.RcvInvoke.tcl == 1) &&
+     event->u.RcvInvoke.ttr == 1 &&
      wtp_tid_is_valid(event, resp_machine) == ok,
     {
      resp_machine->u_ack = event->u.RcvInvoke.up_flag;
      resp_machine->tcl = event->u.RcvInvoke.tcl;
+     resp_machine->ttr = 1;
 
-     wsp_event = create_tr_invoke_ind(resp_machine, 
-         event->u.RcvInvoke.user_data);
+     wsp_event = create_tr_invoke_ind(resp_machine, event->u.RcvInvoke.user_data);
      if (resp_machine->tcl == 1)
          wsp_push_client_dispatch_event(wsp_event);
      else
@@ -119,6 +122,31 @@
     INVOKE_RESP_WAIT)
 
 /*
+ * Segmented Message Arrived
+ */
+ROW(LISTEN,
+    RcvInvoke,
+     event->u.RcvInvoke.tcl == 2 &&
+     event->u.RcvInvoke.ttr == 0 &&     
+     wtp_tid_is_valid(event, resp_machine) == ok,
+    {
+     resp_machine->u_ack = event->u.RcvInvoke.up_flag;
+     resp_machine->tcl = event->u.RcvInvoke.tcl;
+     resp_machine->gtr = event->u.RcvInvoke.gtr;
+     resp_machine->ttr = 0;
+     resp_machine->last_ack_psn = -1;
+     
+     dict_put(resp_machine->curr_grp_segm, octstr_create("0"), octstr_duplicate(event->u.RcvInvoke.user_data));
+
+     if (resp_machine->gtr == 1) {
+     	wtp_check_segments(resp_machine, 0, 0);
+     }
+
+     start_timer_A(resp_machine);
+    },
+    SEGMENT_WAIT)
+
+/*
  * We must here store event fields and wsp indication into the wtp responder 
  * state machine: if tid is valid, we will continue the transaction without a 
  * new event.
@@ -133,8 +161,20 @@
      
      resp_machine->u_ack = event->u.RcvInvoke.up_flag;
      resp_machine->tcl = event->u.RcvInvoke.tcl;
-     resp_machine->invoke_indication = create_tr_invoke_ind(resp_machine, 
-                                       event->u.RcvInvoke.user_data);
+     resp_machine->ttr = event->u.RcvInvoke.ttr;
+
+     if (resp_machine->ttr == 1) {
+     	resp_machine->invoke_indication = create_tr_invoke_ind(resp_machine, event->u.RcvInvoke.user_data);
+     } else {
+	dict_put(resp_machine->curr_grp_segm, octstr_create("0"), octstr_duplicate(event->u.RcvInvoke.user_data));
+	resp_machine->segm_count = 1;
+	
+	if (resp_machine->gtr == 1) {
+	    wtp_check_segments(resp_machine, 0, 0);
+	}
+     }
+     start_timer_A(resp_machine);
+
      debug("wap.wtp", 0, "WTP_STATE: generating invoke indication, tid being" 
            "invalid");
     },
@@ -147,9 +187,15 @@
     RcvInvoke,
     event->u.RcvInvoke.tcl == 0,
     {
+     resp_machine->tcl = event->u.RcvInvoke.tcl;
+     resp_machine->u_ack = event->u.RcvInvoke.up_flag;
+     resp_machine->gtr = event->u.RcvInvoke.gtr;
+     resp_machine->ttr = event->u.RcvInvoke.ttr;
+
      wsp_event = create_tr_invoke_ind(resp_machine, 
          event->u.RcvInvoke.user_data);
      wsp_session_dispatch_event(wsp_event);
+     
     },
     LISTEN)
 
@@ -165,12 +211,14 @@
     LISTEN)
 
 /*
- * Need to control SAR incomplete packets
+ * No user indication here: transaction is not yet started.
  */	
 ROW(LISTEN,
-    TimerTO_W,
+    RcvSegmInvoke,
     1,
-    {},
+    { 
+     send_abort(resp_machine, PROVIDER, PROTOERR);
+    },
     LISTEN)
 
 /*
@@ -181,6 +229,7 @@
 ROW(TIDOK_WAIT,
     RcvAck,
     (resp_machine->tcl == 2 || resp_machine->tcl == 1) && 
+     resp_machine->ttr == 1 && 
      event->u.RcvAck.tid_ok == 1,
     { 
      wsp_event = wap_event_duplicate(resp_machine->invoke_indication);
@@ -196,6 +245,23 @@
     },
     INVOKE_RESP_WAIT)
 
+ROW(TIDOK_WAIT,
+    RcvAck,
+     resp_machine->tcl == 2 &&
+     resp_machine->ttr == 0 && 
+     event->u.RcvAck.tid_ok == 1,
+    {
+     wtp_tid_set_by_machine(resp_machine, event->u.RcvAck.tid);
+
+     if (resp_machine->gtr == 1) {
+	send_segm_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid, 0); 
+	resp_machine->last_ack_psn = 0;
+	resp_machine->ack_pdu_sent = 1;
+	start_timer_A(resp_machine);
+     }
+    },
+    SEGMENT_WAIT)
+
 /*
  * When we get a negative answer to tid verification, we just abort trans-
  * action. Because wtp machines are destroyed when their state return to 
@@ -222,7 +288,9 @@
     RcvInvoke,
     event->u.RcvInvoke.rid == 1,
     { 
+     if (resp_machine->gtr == 1) {
      send_ack(resp_machine, TID_VERIFICATION, resp_machine->rid);
+     }
     },
     TIDOK_WAIT)
 
@@ -282,12 +350,9 @@
     },
     LISTEN)
 
-/*
- * non-SARed
- */
 ROW(INVOKE_RESP_WAIT,
     TR_Result_Req,
-    resp_machine->sar == NULL,
+    1,
     {
      WAPEvent *result;
 
@@ -304,24 +369,6 @@
     RESULT_RESP_WAIT)
 
 /*
- * SARed
- */
-ROW(INVOKE_RESP_WAIT,
-     TR_Result_Req,
-     resp_machine->sar != NULL,
-     {
-      WAPEvent *result;
-
-      resp_machine->rcr = 0;
-
-      start_timer_R(resp_machine);
-      wap_event_destroy(resp_machine->result);
-      resp_machine->rid = 0;
-      begin_sar_result(resp_machine, event);	
-     },
-     RESULT_RESP_WAIT)
-
-/*
  * Conditions below do not correspond wholly ones found from the spec. (If 
  * they does, user acknowledgement flag would never be used by the protocol, 
  * which cannot be the original intention.) 
@@ -396,12 +443,9 @@
     },
     LISTEN)
 
-/*
- * Non-SARed
- */
 ROW(RESULT_WAIT,
     TR_Result_Req,
-    resp_machine->sar == NULL,
+    octstr_len(event->u.TR_Result_Req.user_data) <= 900,
     {
      WAPEvent *result;
      resp_machine->rcr = 0;
@@ -417,23 +461,25 @@
     },
     RESULT_RESP_WAIT)
 
-/*
- * SARed
- */
 ROW(RESULT_WAIT,
     TR_Result_Req,
-    resp_machine->sar != NULL,
+    octstr_len(event->u.TR_Result_Req.user_data) > 900,
     {
      WAPEvent *result;
      resp_machine->rcr = 0;
 
-     start_timer_R(resp_machine);
-
      wap_event_destroy(resp_machine->result);
      resp_machine->rid = 0;
-     begin_sar_result(resp_machine, event);	
+     resp_machine->last_ack_psn = -1;
+     
+     create_segments(resp_machine, event->u.TR_Result_Req.user_data);
+     wtp_send_segm(resp_machine);
+
+     resp_machine->rid = 1;
+
+     start_timer_R(resp_machine);
     },
-    RESULT_RESP_WAIT)
+    SEGMENT_ACK_WAIT)
 
 ROW(RESULT_WAIT,
     RcvAbort,
@@ -466,6 +512,26 @@
     RESULT_WAIT)
 
 ROW(RESULT_WAIT,
+    RcvSegmInvoke,
+    event->u.RcvSegmInvoke.rid == 0,
+    { },
+    RESULT_WAIT)
+
+ROW(RESULT_WAIT,
+    RcvSegmInvoke,
+    event->u.RcvSegmInvoke.rid == 1 && resp_machine->ack_pdu_sent == 0,
+    { },
+    RESULT_WAIT)
+
+ROW(RESULT_WAIT,
+    RcvSegmInvoke,
+    event->u.RcvSegmInvoke.rid == 1 && resp_machine->ack_pdu_sent == 1,
+    {
+     /*send_segm_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid, event->u.RcvSegmInvoke.psn);*/
+    },
+    RESULT_WAIT)
+
+ROW(RESULT_WAIT,
     TR_Abort_Req,
     1,
     { 
@@ -522,12 +588,9 @@
     {},
     RESULT_WAIT)
 
-/*
- * Non-SARed
- */
 ROW(RESULT_RESP_WAIT,
     RcvAck,
-    resp_machine->sar == NULL || event->u.RcvAck.psn == resp_machine->sar->nsegm,
+    1,
     {
      wsp_event = create_tr_result_cnf(resp_machine);
      wsp_session_dispatch_event(wsp_event);
@@ -535,25 +598,6 @@
     LISTEN)
 
 /*
- * SARed
- */
-ROW(RESULT_RESP_WAIT,
-    RcvAck,
-    resp_machine->sar != NULL && event->u.RcvAck.psn != resp_machine->sar->nsegm,
-    {
-     continue_sar_result(resp_machine, event);	 
-    },
-    RESULT_RESP_WAIT)
-
-ROW(RESULT_RESP_WAIT,
-    RcvNegativeAck,
-    resp_machine->sar != NULL,
-    {
-     resend_sar_result(resp_machine, event);	 
-    },
-    RESULT_RESP_WAIT)
-
-/*
  * Specs does not tell what to do, when wtp responder receives invoke pdu and
  * its state is RESULT_RESP_WAIT. This can happen, however: event causing the 
  * transition RESULT_WAIT -> RESULT_RESP_WAIT is TR-Result.req, an internal 
@@ -566,6 +610,14 @@
     RESULT_RESP_WAIT)
 
 ROW(RESULT_RESP_WAIT,
+    RcvSegmInvoke,
+    1,
+    { 
+     dispatch_to_wdp(wap_event_duplicate(resp_machine->result));
+    },
+    RESULT_RESP_WAIT)
+
+ROW(RESULT_RESP_WAIT,
     RcvAbort,
     1,
     {
@@ -633,6 +685,20 @@
     WAIT_TIMEOUT_STATE)
 
 ROW(WAIT_TIMEOUT_STATE,
+    RcvSegmInvoke,
+    event->u.RcvSegmInvoke.rid == 0,
+    { },
+    WAIT_TIMEOUT_STATE)
+
+ROW(WAIT_TIMEOUT_STATE,
+    RcvSegmInvoke,
+    event->u.RcvInvoke.rid == 1,
+    {
+     /*send_segm_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid, event->u.RcvSegmInvoke.psn);*/
+    },
+    WAIT_TIMEOUT_STATE)
+
+ROW(WAIT_TIMEOUT_STATE,
     RcvErrorPDU,
     1,
     {
@@ -671,6 +737,256 @@
      send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
     },
     LISTEN)
+
+ROW(SEGMENT_WAIT,
+    RcvSegmInvoke,
+     event->u.RcvSegmInvoke.ttr == 0,
+    {
+     Octstr *key;
+
+     resp_machine->gtr = event->u.RcvSegmInvoke.gtr;
+
+     if (event->u.RcvSegmInvoke.gtr == 1)
+        resp_machine->last_psn = event->u.RcvSegmInvoke.psn;
+
+     resp_machine->rid = event->u.RcvSegmInvoke.rid;
+
+     key = octstr_format("%ld", event->u.RcvSegmInvoke.psn);
+     dict_put(resp_machine->curr_grp_segm, octstr_duplicate(key), octstr_duplicate(event->u.RcvSegmInvoke.user_data));
+
+     if ((event->u.RcvSegmInvoke.psn > resp_machine->last_ack_psn) && (event->u.RcvSegmInvoke.gtr == 1)) {
+        resp_machine->aec = 0;
+     	wtp_check_segments(resp_machine, event->u.RcvSegmInvoke.psn, 0);
+     }
+     octstr_destroy(key);
+
+     start_timer_A(resp_machine);
+    },
+    SEGMENT_WAIT)
+
+ROW(SEGMENT_WAIT,
+    RcvSegmInvoke,
+     event->u.RcvSegmInvoke.ttr == 1 && 
+     wtp_check_group(resp_machine, event->u.RcvSegmInvoke.psn) == 0,
+    {       
+     Octstr *key;
+
+     resp_machine->gtr = 0;
+     resp_machine->rid = event->u.RcvSegmInvoke.rid;
+     resp_machine->ttr = 1;
+     resp_machine->aec++;
+
+     key = octstr_format("%ld", event->u.RcvSegmInvoke.psn);
+     dict_put(resp_machine->curr_grp_segm, octstr_duplicate(key), octstr_duplicate(event->u.RcvSegmInvoke.user_data));
+     wtp_check_segments(resp_machine, event->u.RcvSegmInvoke.psn, 1);
+     octstr_destroy(key);
+
+     start_timer_A(resp_machine);
+    },      
+    SEGMENT_WAIT)
+
+ROW(SEGMENT_WAIT,
+    RcvSegmInvoke,
+     event->u.RcvSegmInvoke.ttr == 1 && 
+     wtp_check_group(resp_machine, event->u.RcvSegmInvoke.psn) == 1,
+    {       
+     Octstr *key;
+
+     resp_machine->gtr = 0;
+     resp_machine->rid = event->u.RcvSegmInvoke.rid;
+     resp_machine->ttr = 1;
+     resp_machine->aec = 0;
+
+     key = octstr_format("%ld", event->u.RcvSegmInvoke.psn);
+     dict_put(resp_machine->curr_grp_segm, octstr_duplicate(key), octstr_duplicate(event->u.RcvSegmInvoke.user_data));
+     wtp_check_segments(resp_machine, event->u.RcvSegmInvoke.psn, 1);
+
+     octstr_destroy(key);
+
+     wsp_event = create_tr_invoke_ind(resp_machine, cat_segments(resp_machine));
+     wsp_session_dispatch_event(wsp_event);
+
+     start_timer_A(resp_machine);
+    },      
+    INVOKE_RESP_WAIT)
+
+ROW(SEGMENT_WAIT,
+    TimerTO_R,
+    resp_machine->rcr < MAX_RCR,
+    { },
+    SEGMENT_WAIT)
+
+ROW(SEGMENT_WAIT,
+    TimerTO_R,
+    resp_machine->rcr == MAX_RCR,
+    { },
+    LISTEN)
+
+ROW(SEGMENT_WAIT,
+    TimerTO_A,
+    resp_machine->aec < AEC_MAX,
+    {
+     resp_machine->aec++;
+     resp_machine->rid = 1;
+
+     debug("wap.wtp", 0, "*******: last_psn=%d  last_ack_psn=%d", resp_machine->last_psn, resp_machine->last_ack_psn);
+     if (resp_machine->last_psn >= resp_machine->last_ack_psn) {
+     	wtp_check_segments(resp_machine, resp_machine->last_psn, resp_machine->ttr);
+     }
+
+     start_timer_A(resp_machine);
+
+    },
+    SEGMENT_WAIT)
+
+ROW(SEGMENT_WAIT,
+    TimerTO_A,
+    resp_machine->aec == AEC_MAX,
+    {
+     send_abort(resp_machine, USER, NORESPONSE);
+    },
+    LISTEN)
+
+ROW(SEGMENT_WAIT,
+    TR_Abort_Req,
+    1,
+    {
+     send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
+    },
+    LISTEN)
+
+ROW(SEGMENT_WAIT,
+    RcvErrorPDU,
+    1,
+    {
+     send_abort(resp_machine, PROVIDER, PROTOERR);
+    },
+    LISTEN)
+
+ROW(SEGMENT_WAIT,
+    RcvAbort,
+    1,
+    {
+    },
+    LISTEN)
+
+ROW(SEGMENT_ACK_WAIT,
+    RcvAck,
+    resp_machine->ttr == 0,
+    {
+     if (event->u.RcvAck.psnr == resp_machine->last_psn) {
+         resp_machine->rcr = 0;
+         resp_machine->rid = 0;
+         resp_machine->last_ack_psn = resp_machine->last_psn;
+
+         wap_event_destroy(resp_machine->result);
+         wtp_send_segm(resp_machine);
+
+         resp_machine->rid = 1;
+
+         start_timer_R(resp_machine);
+     }
+    },
+    SEGMENT_ACK_WAIT)
+
+ROW(SEGMENT_ACK_WAIT,
+    RcvAck,
+    resp_machine->ttr == 1 &&
+    event->u.RcvAck.psnr == resp_machine->last_psn,
+    { },
+    LISTEN)
+
+ROW(SEGMENT_ACK_WAIT,
+    RcvNack,
+    1,
+    {
+     resp_machine->rcr++;
+     resp_machine->rid = 1;
+
+     wap_event_destroy(resp_machine->result);
+     
+     if (event->u.RcvNack.nmissing == 0) {
+     	wtp_send_segm(resp_machine);
+     } else {
+     	wtp_resend_segm(resp_machine, event);
+     }
+     
+     start_timer_R(resp_machine);
+    },
+    SEGMENT_ACK_WAIT)
+
+ROW(SEGMENT_ACK_WAIT,
+    TimerTO_R,
+    resp_machine->rcr < MAX_RCR,
+    {
+     resp_machine->rcr++;
+     resp_machine->rid = 1;
+     
+     wap_event_destroy(resp_machine->result);
+     wtp_send_segm(resp_machine);
+     
+     /*dispatch_to_wdp(wap_event_duplicate(resp_machine->result));*/
+     
+     start_timer_R(resp_machine);
+    },
+    SEGMENT_ACK_WAIT)
+
+ROW(SEGMENT_ACK_WAIT,
+    TimerTO_R,
+    resp_machine->rcr == MAX_RCR,
+    {
+     send_abort(resp_machine, USER, NORESPONSE);
+     wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
+     wsp_session_dispatch_event(wsp_event);
+    },
+    LISTEN)
+
+ROW(SEGMENT_ACK_WAIT,
+    RcvResult,
+    1,
+    {
+     WAPEvent *result;
+     resp_machine->rcr = 0;
+     resp_machine->rid = 0;
+
+     start_timer_R(resp_machine);
+     wap_event_destroy(resp_machine->result);
+
+     result = wtp_pack_ack(ACKNOWLEDGEMENT, 0, resp_machine->tid, resp_machine->addr_tuple);
+     resp_machine->result = wap_event_duplicate(result);
+     dispatch_to_wdp(result);
+     resp_machine->rid = 1;
+    },
+    LISTEN)
+
+ROW(SEGMENT_ACK_WAIT,
+    RcvAbort,
+    1,
+    {
+     wsp_event = create_tr_abort_ind(resp_machine, event->u.RcvAbort.abort_reason);
+     wsp_session_dispatch_event(wsp_event);
+    },
+    LISTEN)
+
+ROW(SEGMENT_ACK_WAIT,
+    RcvInvoke,
+    1,
+    { },
+    SEGMENT_ACK_WAIT)
+
+ROW(SEGMENT_ACK_WAIT,
+    TR_Abort_Req,
+    1,
+    { 
+     send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
+    },
+    LISTEN)
+
+ROW(SEGMENT_ACK_WAIT,
+    RcvErrorPDU,
+    1,
+    {},
+    SEGMENT_ACK_WAIT)
 
 #undef ROW
 #undef STATE_NAME
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.