Re: SMPP data_sm implementation for MT messages
Alexander Malysh <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Michael, please read bellow carefully about how metadata should be formatted... Thanks, Alexander Malysh Am 22.07.2010 um 18:01 schrieb Michael Zervakis: > 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? > > > > > >> > > > > > > >> > >> > > > > > >> > >> > > > > > >> > > > > > > > > > > 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?...&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?...&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><meta-data>?smpp?my-data=Hello+World</meta-data></literal></para> > + <para>XML: DATA_SM</para> > + <para><literal><meta-data>?smpp_data_sm?my-data=Hello+World</meta-data></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