RE: SMPP data_sm implementation for MT messages

Michael Zervakis <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <[email protected]>
Hi ,


This is a proposed implementation for sending data_sm PDUs that also 
enforces SMPP requirement for having sm_length=0 when using 
message_payload TLV. To send a data_sm PDU the sendsms request should be 
like meta-data?smsc-type=smpp_data_sm?.
*msg_to_pdu() was replaced by two functions *msg_to_sm_pdu() and 
*msg_to_datasm_pdu() for submit_sm and data_sm() PDUs respectively and 
handle_pdu() got a new case for incoming data_sm_resp PDU.

 
BR,

Michael Zervakis

 

-----Original Message-----
From: Alexander Malysh [mailto:[email protected]] On Behalf Of 
Alexander Malysh
Sent: Friday, November 27, 2009 5:04 PM
To: Michael Zervakis
Cc: Kannel Devel; Alejandro Guerrieri
Subject: Re: SMPP data_sm implementation for MT messages

 

where do you have message_payload extracted to user?

 

that is simple:

 

MT(data_sm) -> sendsms?text=ABC&metadata=?smpp?pdu_type=data_sm... -> 
data_sm.message_payload=ABC

MT(submit_sm) -> sendsms?text=ABC... -> submit_sm.short_message=ABC

 

MO(data_sm) -> data_sm.message_payload=ABC -> 
receivesms?text=ABC&metadata=?smpp?pdu_type=data_sm

MO(submit_sm) -> submit_sm.short_message=ABC -> receivesms?text=ABC

 

If user set for MT 
text=ABC&metadata=?smpp?pdu_type=data_sm&message_payload=XXX then it's 
undefined and

we are free to choose which one to use and I would prefer to use text as 
message_payload...

 

Hope that's clear.

 

Thanks,

Alexander Malysh

 

Am 27.11.2009 um 15:21 schrieb Michael Zervakis:

 

 >

 > Let's assume that we follow Alex's recommendation 
"meta-data=?smpp?operation=data_sm&..." and if operation is omitted we 
use submit_sm as default.

 >

 >

 > We should clarify what should happen to "text=xxxx" if set and this 
should affect both submit_sm and data_sm operations as SMPP specs state 
that short_message and message_payload cannot coexist in a PDU 
(sm_length should be zero if message_payload is used). I can think of 
three cases here:

 >

 > 1) When "text" has a value and "message_payload" is not set. For 
submit_sm no need to change anything. For data_sm we append meta-data 
with message_payload and set the value of "text" to it (example: 
"text=XXXX&meta-data=?smpp?operation=data_sm").

 > 2) When both "text" and "message_payload" have values. For submit_sm 
operation "text" value is set to null (so "sm_length" is set to 0 and we 
don't break specs) and we use the provided "message_payload" value. For 
data_sm operation we simply ignore "text" value.

 >

 > 3) When "message_payload" has a value and "text" is not set. Normal 
case doesn't break specs.

 >

 >

 >

 >

 >

 >> -----Original Message-----

 >> From: Alexander Malysh [mailto:[email protected]] On Behalf Of

 > Alexander Malysh

 >> Sent: Friday, November 27, 2009 3:32 PM

 >> To: Michael Zervakis

 >> Cc: [email protected]; [email protected]

 >> Subject: Re: SMPP data_sm implementation for MT messages

 >

 >

 >> Hi,

 >

 >

 >> why not just use metadata=?smpp?operation=data_sm&... ?

 >

 >> then you can check in smsc_smpp whether submit_sm or data_sm should 
be used.

 >

 >

 >> Whether you have to use message_payload or short_message is

 > implementation details that

 >

 >> should not be exported to user interface.

 >

 >

 >> Thanks,

 >

 >> Alexander Malysh

 >

 >

 >> Am 27.11.2009 um 13:00 schrieb Michael Zervakis:

 >

 >

 >> > Data_sm PDU cannot contain a short_message field. Actually data_sm

 > contains only TLVs and instead of "short_message" field we should use 
TLV "message_payload" to send text. As a result text=xxxx is obsolete 
when sending data_sm PDU. If we use data=xxxx what would be the value of 
data since all necessary data will be included in "meta-data=?smpp?"  ?

 >

 >> >

 >

 >> >

 >

 >> >> -----Original Message-----

 >

 >> >> From: Alejandro Guerrieri [mailto:[email protected]]

 >

 >> >> Sent: Friday, November 27, 2009 12:04 PM

 >

 >> >> To: Michael Zervakis

 >

 >> >> Cc: [email protected]

 >

 >> >> Subject: Re: SMPP data_sm implementation for MT messages

 >

 >> >

 >

 >> >

 >

 >> > >What about using "data=xxxx" instead of "text=xxxx" ?

 >

 >> >

 >

 >> > >--

 >

 >> >

 >

 >> > >Alejandro Guerrieri

 >

 >> >

 >

 >> > >[email protected]

 >

 >> >

 >

 >> > >

 >

 >> > >

 >

 >> > >

 >

 >> > >On 27/11/2009, at 10:00, Michael Zervakis wrote:

 >

 >> >

 >

 >> > >

 >

 >> > >> Data_sm can be used as an alternate of submit_sm when transmitting

 >

 >> > >> optional parameters (meta-data) and some carriers require the 
use of

 >

 >> > >> data_sm for MT charging applications.

 >

 >> >

 >

 >> > >> Since Kannel is not implementing this feature it's a good idea to

 >

 >> > >> start a discussion on how this could be implemented.

 >

 >> >

 >

 >> > >>

 >

 >> > >> First of all it's obvious that "static int send_messages()" at gw

 >

 >> >

 >

 >> > >> \smsc\smsc_smpp.c must be able to differentiate msgs that need 
to be

 >

 >> > >> sent as data_sm.

 >

 >> >

 >

 >> > >> I can think of two ways to achieve this:

 >

 >> >

 >

 >> > >> 1) Alter MSG definition to inlcude a new parameter that defines 
type

 >

 >> > >> of message Data or normal SMS

 >

 >> >

 >

 >> > >> Possible ways to use the new parameter could be the following

 >

 >> >

 >

 >> > >> /cgi-bin/sendsms?from=1111&to=2222&<new parameter>=data&meta-data=?

 >

 >> >

 >

 >> > >> smpp?key=value

 >

 >> >

 >

 >> > >> /cgi-bin/senddata?from=1111&to=2222&meta-data=?smpp?key=value

 >

 >> >

 >

 >> > >> 2) Leave MSG definition untouched and use meta-data to mark msg as

 >

 >> > >> data

 >

 >> >

 >

 >> > >> /cgi-bin/sendsms?from=1111&to=2222&meta-data=?smpp?<new

 >

 >> > >> parameter>=data&key=value

 >

 >> >

 >

 >> > >>

 >

 >> > >> Finally a new function has to be defined at gw\smsc\smsc_smpp.c to

 >

 >> > >> build data_sm pdu from msg for example "static SMPP_PDU

 >

 >> > >> *dmsg_to_pdu(SMPP *smpp, Msg *msg)"

 >

 >> >

 >

 >> > >> and function "static int handle_pdu()" at gw\smsc\smsc_smpp.c 
has to

 >

 >> > >> be modified to include a case for data_sm_resp PDU.

 >

 >> >

 >

 >> > >>

 >

 >> > >> Any comments?

 >

 >> >

 >

 >> > >>

 >

 >> > >>

 >

 >> >

 >

 >
data_sm.patch (text/plain, 19.6 KB)
Index: doc/userguide/userguide.xml
===================================================================
--- doc/userguide/userguide.xml	(revision 4833)
+++ doc/userguide/userguide.xml	(working copy)
@@ -9781,12 +9781,14 @@
         </sect3>
       </sect2>
       <sect2>
-        <title>MT Messages</title>
+        <title>MT Messages SUBMIT_SM or DATA_SM</title>
         <para>To send into an MT messages the <literal>meta-data</literal> parameter should be used.</para>
         
         <para>The format used to pass the data has 2 parts: The <literal>?smsc-type?</literal> (surrounded by question marks),
-        which specify the kind of smsc receiving the data (at the moment only <literal>smpp</literal> is implemented) and then a set of key/value
-        pairs with the data to be transmitted. Extra smsc-types can be added surrounded by question marks and followed by the key/value pairs.</para>
+        which specify the kind of smsc receiving the data and then a set of key/value pairs with the data to be transmitted. 
+        Currently only SMPP is implemented with two possible values for <literal>?smsc-type?</literal>: <literal>smpp</literal> 
+        for SUBMIT_SM PDUs and <literal>smpp_data_sm</literal>) for DATA_SM PDUs.
+        Extra smsc-types can be added surrounded by question marks and followed by the key/value pairs.</para>
         
         <para>In other words,  the data should be coded using the following format, where URLENCODE() implies that the data between parentheses should
         be urlencoded:</para>
@@ -9800,14 +9802,26 @@
 
 	      <sect3>
 	        <title>Examples</title>
-	        <para>If we want to send the parameter "my-data" with value "Hello World" to an SMSC over SMPP, we'd use:</para>
+	        <para>If we want to send the parameter "my-data" with value "Hello World" to an SMSC over SMPP using SUBMIT_SM PDU, we'd use:</para>
 	        <para>sendsms get-url:</para>
 	        <para><literal>http://localhost:13013/cgi-bin/sendsms?...&amp;meta-data=%3Fsmpp%3Fmy-data%3DHello%2BWorld</literal></para>
+            <para>Similarly if we want to send the above using DATA_SM PDU, we'd use:</para>
+	        <para>sendsms get-url:</para>
+	        <para><literal>http://localhost:13013/cgi-bin/sendsms?...&amp;meta-data=%3Fsmpp_data_sm%3Fmy-data%3DHello%2BWorld</literal></para>
           <para>sendsms post:</para>
           <para>Send <literal>?smpp?my-data=Hello+World</literal> on the <literal>X-Kannel-Meta-Data</literal> header</para>
-          <para>XML:</para>
+          <para>XML: SUBMIT_SM</para>
           <para><literal>&lt;meta-data&gt;?smpp?my-data=Hello+World&lt;/meta-data&gt;</literal></para>
+          <para>XML: DATA_SM</para>
+          <para><literal>&lt;meta-data&gt;?smpp_data_sm?my-data=Hello+World&lt;/meta-data&gt;</literal></para>
 	      </sect3>
+
+          </sect3>
+            <title>SMPP TLV message_payload (0x0424)</title>
+            <para>SMPP message_payload TLV is an alternative to submit_sm short_message when sending messages longer than 255 octets.
+                  When sending submit_sm PDU with message_payload then short_message should be null. Kannel enforces this restriction 
+                  by ignoring supplied values for <literal>text</literal> if <literal>message_payload</literal> TLV is present.</para>
+          </sect3>
       </sect2>
     </sect1>
 </appendix>
Index: gw/smsc/smsc_smpp.c
===================================================================
--- gw/smsc/smsc_smpp.c	(revision 4833)
+++ gw/smsc/smsc_smpp.c	(working copy)
@@ -747,14 +747,12 @@
 }
 
 
-static SMPP_PDU *msg_to_pdu(SMPP *smpp, Msg *msg)
+static SMPP_PDU *msg_to_sm_pdu(SMPP_PDU *pdu, Msg *msg, SMPP *smpp)
 {
-    SMPP_PDU *pdu;
+
     int validity;
-
-    pdu = smpp_pdu_create(submit_sm,
-    	    	    	  counter_increase(smpp->message_id_counter));
-
+
+
     pdu->u.submit_sm.source_addr = octstr_duplicate(msg->sms.sender);
     pdu->u.submit_sm.destination_addr = octstr_duplicate(msg->sms.receiver);
 
@@ -876,9 +874,41 @@
     /*
      * set data segments and length
      */
-
-    pdu->u.submit_sm.short_message = octstr_duplicate(msg->sms.msgdata);
-
+    
+    /* 
+     If a message contains both msg_data and meta_data and within meta_data is contained the tlv message_payload
+     then ignore smg_data field forward message's meta_data and print a warning message
+     */ 
+    
+    
+    if((octstr_len(msg->sms.msgdata)) && (octstr_len(msg->sms.meta_data)))
+    {   
+        debug("bb.sms.smpp", 0, "msg->sms.msgdata = [%s] and msg->sms.meta_data !=[%s]", octstr_get_cstr(msg->sms.msgdata),octstr_get_cstr(msg->sms.meta_data));
+        
+        if(octstr_search(msg->sms.meta_data, octstr_imm("message_payload"),0)!=-1) 
+        {
+            pdu->u.submit_sm.short_message == NULL; 
+            pdu->u.submit_sm.sm_length = 0;
+            warning(0, "SMPP[%s]: Ignoring msg->sms.msgdata = [%s] because msg->sms.meta_data(message_payload)= [%s] TLV message_payload was found ",
+                    octstr_get_cstr(smpp->conn->id),octstr_get_cstr(msg->sms.msgdata),octstr_get_cstr(msg->sms.meta_data));
+            
+        }
+        else
+        {
+            pdu->u.submit_sm.short_message = octstr_duplicate(msg->sms.msgdata);
+            pdu->u.submit_sm.sm_length = octstr_len(pdu->u.submit_sm.short_message);
+            
+        }
+    }
+    else
+    {
+        pdu->u.submit_sm.short_message = octstr_duplicate(msg->sms.msgdata);
+        pdu->u.submit_sm.sm_length = octstr_len(pdu->u.submit_sm.short_message);
+        
+    } 
+    
+    /*pdu->u.submit_sm.short_message = octstr_duplicate(msg->sms.msgdata);*/
+    
     /*
      * only re-encoding if using default smsc charset that is defined via
      * alt-charset in smsc group and if MT is not binary
@@ -908,9 +938,9 @@
     if (octstr_len(msg->sms.udhdata)) {
         octstr_insert(pdu->u.submit_sm.short_message, msg->sms.udhdata, 0);
     }
-
-    pdu->u.submit_sm.sm_length = octstr_len(pdu->u.submit_sm.short_message);
-
+
     /*
      * check for validity and defered settings
      * were message value has higher priiority then smsc config group value
@@ -958,6 +988,228 @@
 }
 
 
+/* Function to create a data_sm pdu
+ 
+ Pdu fields:
+ 
+ (common to both sumbit_sm and data_sm)
+ 1. command length
+ 2. command id
+ 3. command status
+ 4. sequence number
+ 5. service type
+ 6. source_addr_ton
+ 7. source_addr_npi
+ 8. source_addr
+ 9. dest_addr_ton
+ 10. dest_addr_npi
+ 11.destnation_addr
+ 12. esm_class
+ 13. registered_delivery
+ 14. data_coding
+ 15. Optional TLVs
+ 
+ */
+
+static SMPP_PDU *msg_to_datasm_pdu(SMPP_PDU *pdu, Msg *msg, SMPP *smpp)
+{
+
+
+    pdu->u.data_sm.source_addr = octstr_duplicate(msg->sms.sender);
+
+    pdu->u.data_sm.destination_addr = octstr_duplicate(msg->sms.receiver);
+
+
+    /* Set the service type of the outgoing message. We'll use the config
+     * directive as default and 'binfo' as specific parameter. */
+    pdu->u.data_sm.service_type = octstr_len(msg->sms.binfo) ?
+    octstr_duplicate(msg->sms.binfo) : octstr_duplicate(smpp->service_type);
+
+
+
+    /* Check for manual override of source ton and npi values */
+    if(smpp->source_addr_ton > -1 && smpp->source_addr_npi > -1) {
+        pdu->u.data_sm.source_addr_ton = smpp->source_addr_ton;
+        pdu->u.data_sm.source_addr_npi = smpp->source_addr_npi;
+        debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced source addr ton = %d, source add npi = %d",
+              octstr_get_cstr(smpp->conn->id), smpp->source_addr_ton,
+              smpp->source_addr_npi);
+    } else {
+        /* setup default values */
+        pdu->u.data_sm.source_addr_ton = GSM_ADDR_TON_NATIONAL; /* national */
+        pdu->u.data_sm.source_addr_npi = GSM_ADDR_NPI_E164; /* ISDN number plan */
+    }
+
+    if (pdu->u.data_sm.source_addr && smpp->autodetect_addr) {
+        /* lets see if its international or alphanumeric sender */
+        if (octstr_get_char(pdu->u.data_sm.source_addr, 0) == '+') {
+            if (!octstr_check_range(pdu->u.data_sm.source_addr, 1, 256, gw_isdigit)) {
+                pdu->u.data_sm.source_addr_ton = GSM_ADDR_TON_ALPHANUMERIC; /* alphanum */
+                pdu->u.data_sm.source_addr_npi = GSM_ADDR_NPI_UNKNOWN;    /* short code */
+                if (smpp->alt_addr_charset) {
+                    if (octstr_str_case_compare(smpp->alt_addr_charset, "gsm") == 0) {
+                        /* @ would break PDU if converted into GSM*/
+                        octstr_replace(pdu->u.data_sm.source_addr, octstr_imm("@"), octstr_imm("?"));
+                        charset_utf8_to_gsm(pdu->u.data_sm.source_addr);
+                    } else if (charset_convert(pdu->u.data_sm.source_addr, SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset)) != 0)
+                        error(0, "Failed to convert source_addr from charset <%s> to <%s>, will send as is.",
+                              SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset));
+                }
+            } else {
+                /* numeric sender address with + in front -> international (remove the +) */
+                octstr_delete(pdu->u.data_sm.source_addr, 0, 1);
+                pdu->u.data_sm.source_addr_ton = GSM_ADDR_TON_INTERNATIONAL;
+            }
+        } else {
+            if (!octstr_check_range(pdu->u.submit_sm.source_addr,0, 256, gw_isdigit)) {
+                pdu->u.data_sm.source_addr_ton = GSM_ADDR_TON_ALPHANUMERIC;
+                pdu->u.data_sm.source_addr_npi = GSM_ADDR_NPI_UNKNOWN;
+                if (smpp->alt_addr_charset) {
+                    if (octstr_str_case_compare(smpp->alt_addr_charset, "gsm") == 0) {
+                        /* @ would break PDU if converted into GSM */
+                        octstr_replace(pdu->u.data_sm.source_addr, octstr_imm("@"), octstr_imm("?"));
+                        charset_utf8_to_gsm(pdu->u.data_sm.source_addr);
+                    } else if (charset_convert(pdu->u.data_sm.source_addr, SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset)) != 0)
+                        error(0, "Failed to convert source_addr from charset <%s> to <%s>, will send as is.",
+                              SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset));
+                }
+            }
+        }
+    }
+
+
+    /* Check for manual override of destination ton and npi values */
+    if (smpp->dest_addr_ton > -1 && smpp->dest_addr_npi > -1) {
+        pdu->u.data_sm.dest_addr_ton = smpp->dest_addr_ton;
+        pdu->u.data_sm.dest_addr_npi = smpp->dest_addr_npi;
+        debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced dest addr ton = %d, dest add npi = %d",
+              octstr_get_cstr(smpp->conn->id), smpp->dest_addr_ton,
+              smpp->dest_addr_npi);
+    } else {
+        pdu->u.data_sm.dest_addr_ton = GSM_ADDR_TON_NATIONAL; /* national */
+        pdu->u.data_sm.dest_addr_npi = GSM_ADDR_NPI_E164; /* ISDN number plan */
+    }
+
+    /*
+     * if its a international number starting with +, lets remove the
+     * '+' and set number type to international instead
+     */
+    if (octstr_get_char(pdu->u.data_sm.destination_addr,0) == '+') {
+        octstr_delete(pdu->u.data_sm.destination_addr, 0,1);
+        pdu->u.data_sm.dest_addr_ton = GSM_ADDR_TON_INTERNATIONAL;
+    }
+    
+    /* check length of src/dst address */
+    if (octstr_len(pdu->u.data_sm.destination_addr) > 20 ||
+        octstr_len(pdu->u.data_sm.source_addr) > 20) {
+        smpp_pdu_destroy(pdu);
+        return NULL;
+    }
+
+    /*
+     * set the data coding scheme (DCS) field
+     * check if we have a forced value for this from the smsc-group.
+     * Note: if message class is set, then we _must_ force alt_dcs otherwise
+     * dcs has reserved values (e.g. mclass=2, dcs=0x11). We check MWI flag
+     * first here, because MWI and MCLASS can not be set at the same time and
+     * function fields_to_dcs check MWI first, so we have no need to force alt_dcs
+     * if MWI is set.
+     */
+    if (msg->sms.mwi == MWI_UNDEF && msg->sms.mclass != MC_UNDEF)
+        pdu->u.data_sm.data_coding = fields_to_dcs(msg, 1); /* force alt_dcs */
+    else
+        pdu->u.data_sm.data_coding = fields_to_dcs(msg,
+                                                   (msg->sms.alt_dcs != SMS_PARAM_UNDEFINED ?
+                                                    msg->sms.alt_dcs : smpp->conn->alt_dcs));
+
+
+    /*
+     * set the esm_class field
+     * default is store and forward, plus udh and rpi if requested
+     */
+    pdu->u.data_sm.esm_class = ESM_CLASS_SUBMIT_STORE_AND_FORWARD_MODE;
+    if (octstr_len(msg->sms.udhdata))
+        pdu->u.data_sm.esm_class = pdu->u.submit_sm.esm_class |
+        ESM_CLASS_SUBMIT_UDH_INDICATOR;
+    if (msg->sms.rpi > 0)
+        pdu->u.data_sm.esm_class = pdu->u.submit_sm.esm_class |
+        ESM_CLASS_SUBMIT_RPI;
+
+
+    /* ask for the delivery reports if needed */
+    if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
+        pdu->u.data_sm.registered_delivery = 1;
+    else if (DLR_IS_FAIL(msg->sms.dlr_mask) && !DLR_IS_SUCCESS(msg->sms.dlr_mask))
+        pdu->u.data_sm.registered_delivery = 2;
+
+    if (DLR_IS_INTERMEDIATE(msg->sms.dlr_mask))
+        pdu->u.data_sm.registered_delivery += 16;
+
+
+
+    /* set more messages to send */
+    if (smpp->version > 0x33 && msg->sms.msg_left > 0)
+        pdu->u.data_sm.more_messages_to_send = 1;
+
+    dict_destroy(pdu->u.data_sm.tlv);
+
+    /* search within meta_data group for smpp_data_sm */
+    pdu->u.data_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp_data_sm");
+
+    /*pdu->u.data_sm.data_coding = 1;*/
+
+
+    return pdu; 
+}
+
+
+
+/* Procedure for deternining the type of pdu to build :
+ 1. Submit_sm message will be build by the msg_to_pdu when the field meta_data is empty 
+ or when within the meta_data mesage field there is not a string of the form "pdu_type=data_sm". 
+ 2. Else when the meta_data is not empty and contains a string of the form "pdu_type=data_sm" the 
+ pdu that is going to be build will be a data_sm pdu.
+ */
+
+static SMPP_PDU *msg_to_pdu(SMPP *smpp, Msg *msg)
+{
+    SMPP_PDU *pdu;
+    unsigned long pdu_type =0;
+    
+    /* make sure we are not searching within a null string */
+    if(octstr_len(msg->sms.meta_data) == 0)
+    {    
+        pdu_type = submit_sm;
+        debug("bb.sms.smpp", 0, "msg_to_pdu : pdu_type = submit_sm");
+    }    
+    else if(octstr_search(msg->sms.meta_data, octstr_imm("?smpp_data_sm?"),0)==-1)
+    {
+        pdu_type = submit_sm;      
+        debug("bb.sms.smpp", 0, "msg_to_pdu : pdu_type = submit_sm");
+    }
+    else 
+    {        
+        pdu_type = data_sm;    
+        debug("bb.sms.smpp", 0, "msg_to_pdu : pdu_type = data_sm");
+    }
+
+
+    /* kltsa : 07/07/2010 : submit_sm will now passed as parameter pdu_type */
+    pdu = smpp_pdu_create(pdu_type,counter_increase(smpp->message_id_counter));
+
+    switch (pdu_type) 
+    {
+        case data_sm  : pdu = msg_to_datasm_pdu(pdu,msg,smpp);
+            break;/*add other cases here*/
+        default: pdu = msg_to_sm_pdu(pdu,msg,smpp);
+            break;
+    }
+
+    return pdu;
+}    
+
+
+
 static int send_enquire_link(SMPP *smpp, Connection *conn, long *last_sent)
 {
     SMPP_PDU *pdu;
@@ -1073,7 +1325,21 @@
         /* check for write errors */
         if (send_pdu(conn, smpp->conn->id, pdu) == 0) {
             struct smpp_msg *smpp_msg = smpp_msg_create(msg);
-            os = octstr_format("%ld", pdu->u.submit_sm.sequence_number);
+
+            /* Check for sequence number errors depending on pdu type */
+            if(pdu->type == submit_sm)
+            {
+                os = octstr_format("%ld", pdu->u.submit_sm.sequence_number);
+                debug("bb.sms.smpp", 0, "send_messages : pdu->type = submit_sm");
+            }
+            else if(pdu->type == data_sm)
+            {
+                os = octstr_format("%ld", pdu->u.data_sm.sequence_number);
+                debug("bb.sms.smpp", 0, "send_messages : pdu->type = data_sm");
+            }
+            else
+                error(0, "send_messages : :unknown pdu type = [%lu]!\n",pdu->type);
+
             dict_put(smpp->sent_msgs, os, smpp_msg);
             smpp_pdu_destroy(pdu);
             octstr_destroy(os);
@@ -1504,9 +1770,72 @@
                 msg->sms.smsc_id = octstr_duplicate(smpp->conn->id);
                 reason =  bb_smscconn_receive(smpp->conn, msg);
                 resp->u.data_sm_resp.command_status = smscconn_failure_reason_to_smpp_status(reason);
-           }
-           break;
-
+            }
+            break;
+        case data_sm_resp:
+            os = octstr_format("%ld", pdu->u.data_sm_resp.sequence_number);
+            smpp_msg = dict_remove(smpp->sent_msgs, os);
+            octstr_destroy(os);
+            if (smpp_msg == NULL) {
+                warning(0, "SMPP[%s]: SMSC sent data_sm_resp "
+                        "with wrong sequence number 0x%08lx",
+                        octstr_get_cstr(smpp->conn->id),
+                        pdu->u.data_sm_resp.sequence_number);
+                break;
+            }
+            msg = smpp_msg->msg;
+            smpp_msg_destroy(smpp_msg, 0);
+            if (pdu->u.data_sm_resp.command_status != 0) {
+                error(0, "SMPP[%s]: SMSC returned error code 0x%08lx (%s) "
+                      "in response to data_sm.",
+                      octstr_get_cstr(smpp->conn->id),
+                      pdu->u.data_sm_resp.command_status,
+                      smpp_error_to_string(pdu->u.data_sm_resp.command_status));
+                reason = smpp_status_to_smscconn_failure_reason(
+                                                                pdu->u.data_sm_resp.command_status);
+
+                /*
+                 * check to see if we got a "throttling error", in which case we'll just
+                 * sleep for a while
+                 */
+                if (pdu->u.data_sm_resp.command_status == SMPP_ESME_RTHROTTLED)
+                    time(&(smpp->throttling_err_time));
+                else
+                    smpp->throttling_err_time = 0;
+
+                bb_smscconn_send_failed(smpp->conn, msg, reason, octstr_format("0x%08lx/%s", pdu->u.data_sm_resp.command_status,
+                                                                               smpp_error_to_string(pdu->u.data_sm_resp.command_status)));
+                --(*pending_submits);
+            } else {
+                Octstr *tmp;
+
+                /* check if msg_id is C string, decimal or hex for this SMSC */
+                if (smpp->smpp_msg_id_type == -1) {
+                    /* the default, C string */
+                    tmp = octstr_duplicate(pdu->u.data_sm_resp.message_id);
+                } else {
+                    if ((smpp->smpp_msg_id_type & 0x01) ||
+                        (!octstr_check_range(pdu->u.data_sm_resp.message_id, 0,
+                                             octstr_len(pdu->u.data_sm_resp.message_id), gw_isdigit))) {
+                        tmp = octstr_format("%llu", strtoll(  /* hex */
+                                                            octstr_get_cstr(pdu->u.data_sm_resp.message_id), NULL, 16));
+                    } else {
+                        tmp = octstr_format("%llu", strtoll(  /* decimal */
+                                                            octstr_get_cstr(pdu->u.data_sm_resp.message_id), NULL, 10));
+                    }
+                }
+
+                /* SMSC ACK.. now we have the message id. */
+                if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask))
+                    dlr_add(smpp->conn->id, tmp, msg);
+
+                octstr_destroy(tmp);
+                bb_smscconn_sent(smpp->conn, msg, NULL);
+                --(*pending_submits);
+            } /* end if for SMSC ACK */
+            break;
+
         case deliver_sm:
 	       /*
             * If SMSCConn stopped then send temp. error code
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.