/// <summary> /// Sends an SMS message synchronouslly, possibly splitting it on multiple PDUs /// using the specified segmentation & reassembly method. /// </summary> /// <param name="pdu">The pdu.</param> /// <param name="method">The method.</param> /// <returns>The list of messageIds assigned by remote party to each submitted PDU.</returns> public IEnumerable <string> Send(SmppSubmitSm pdu, SmppSarMethod method) { var requests = SmppUtil.SplitLongMessage(pdu, method, GetRandomByte()).Cast <SmppRequest>(); var responses = SendRequests(requests); if (responses.Any(x => (x is SmppGenericNackResp))) { var nack = responses.First(x => x is SmppGenericNackResp); var idx = responses.IndexWhere(x => x == nack); var req = requests.ElementAt(idx); var msg = string.Format("SMPP PDU was rejected by remote party. (error: {0})", nack.CommandStatus); throw new SmppRemoteException(msg, req, nack); } if (responses.Any(x => x.CommandStatus != 0)) { var res = responses.First(x => x.CommandStatus != 0); var idx = responses.IndexWhere(x => x == res); var req = requests.ElementAt(idx); var msg = string.Format("SMPP Request returned an error status. (code: {0})", res.CommandStatus); throw new SmppRemoteException(msg, req, res); } return(responses.OfType <SmppSubmitSmResp>().Select(x => x.MessageId).ToArray()); }
/// <summary> /// Apply segmentation over a message possibly splitting it on multiple SMPP PDUs. /// </summary> /// <remarks> /// Method may return the passed pdu (modified as needed) as result in case no splitting is required. /// </remarks> /// <param name="pdu">The base pdu to use.</param> /// <param name="method">The segmentation & reasembly method tu use when splitting the message.</param> /// <param name="correlationId">The correlation id to set to each message part.</param> /// <returns>The list of sequence numbers of PDUs sent</returns> public static IEnumerable <SmppSubmitSm> SplitLongMessage(SmppSubmitSm pdu, SmppSarMethod method, byte correlationId) { if (pdu == null) { throw new ArgumentNullException("pdu"); } var result = new List <SmppSubmitSm>(); var data = pdu.MessagePayload != null ? pdu.MessagePayload : pdu.ShortMessage; if (data != null && !(data is string || data is byte[])) { throw new ArgumentException("Short Message must be a string or byte array."); } var bytes = data is string?PduUtil.GetEncodedText(pdu.DataCoding, data as string) : data as byte[]; var maxSegmentLen = GetMaxSegmentLength(pdu.DataCoding, bytes.Length); // Remove/Reset data from PDU.. pdu.ShortMessage = pdu.MessagePayload = null; // Remove sequenceNumber. pdu.SequenceNumber = 0; // Remove UDH header (if set). pdu.EsmClass &= ((byte)~NetworkFeatures.UDHI); // Remove SMPP segmentation properties.. pdu.MoreMessagesToSend = null; pdu.NumberOfMessages = null; pdu.SarTotalSegments = null; pdu.SarMsgRefNumber = null; // Sending as payload means avoiding all the data splitting logic.. (which is great ;)) if (method == SmppSarMethod.SendAsPayload) { pdu.MessagePayload = data; return(new[] { pdu }); } // Else.. let's do segmentation and the other crappy stuff.. var udhref = method == SmppSarMethod.UserDataHeader ? new Nullable <byte>(correlationId) : null; var segments = SplitMessage(bytes, maxSegmentLen, udhref); var totalSegments = segments.Count(); var segno = 0; // If just one segment, send it w/o SAR parameters.. if (totalSegments < 2) { pdu.ShortMessage = data; return(new[] { pdu }); } // Ok, se we need segmentation, let's go ahead an use input PDU as template. var template = pdu.GetEncodedPdu(); // Well save results here.. var results = new List <SmppSubmitSm>(); foreach (var segment in segments) { var packet = new SmppSubmitSm(template); segno++; // Increase sequence number. packet.SequenceNumber = 0; // Remove sequenceNumber. packet.ShortMessage = segment; // Set current segment bytes as short message.. switch (method) { case SmppSarMethod.UserDataHeader: packet.EsmClass |= (byte)NetworkFeatures.UDHI; // Set UDH flag.. break; case SmppSarMethod.UseSmppSegmentation: packet.EsmClass &= ((byte)~NetworkFeatures.UDHI); // Remove UDH header (if set). // Fill-in SMPP segmentation fields.. packet.MoreMessagesToSend = segno != totalSegments; packet.NumberOfMessages = (byte)totalSegments; packet.SarTotalSegments = (byte)totalSegments; packet.SarMsgRefNumber = correlationId; packet.SarSegmentSeqnum = (byte)segno; break; } result.Add(packet); } return(result); }
/// <summary> /// Sends an SMS message synchronouslly, possibly splitting it on multiple PDUs /// using the specified segmentation & reassembly method. /// </summary> /// <param name="pdu">The pdu.</param> /// <param name="method">The method.</param> /// <returns>The list of messageIds assigned by remote party to each submitted PDU.</returns> public IEnumerable<string> Send(SmppSubmitSm pdu, SmppSarMethod method) { var requests = SmppUtil.SplitLongMessage(pdu, method, GetRandomByte()).Cast<SmppRequest>(); var responses = SendRequests(requests); if (responses.Any(x => (x is SmppGenericNackResp))) { var nack = responses.First(x => x is SmppGenericNackResp); var idx = responses.IndexWhere(x => x == nack); var req = requests.ElementAt(idx); var msg = string.Format("SMPP PDU was rejected by remote party. (error: {0})", nack.CommandStatus); throw new SmppRemoteException(msg, req, nack); } if (responses.Any(x => x.CommandStatus != 0)) { var res = responses.First(x => x.CommandStatus != 0); var idx = responses.IndexWhere(x => x == res); var req = requests.ElementAt(idx); var msg = string.Format("SMPP Request returned an error status. (code: {0})", res.CommandStatus); throw new SmppRemoteException(msg, req, res); } return responses.OfType<SmppSubmitSmResp>().Select(x => x.MessageId).ToArray(); }
/// <summary> /// Apply segmentation over a message possibly splitting it on multiple SMPP PDUs. /// </summary> /// <remarks> /// Method may return the passed pdu (modified as needed) as result in case no splitting is required. /// </remarks> /// <param name="pdu">The base pdu to use.</param> /// <param name="method">The segmentation & reasembly method tu use when splitting the message.</param> /// <param name="correlationId">The correlation id to set to each message part.</param> /// <returns>The list of sequence numbers of PDUs sent</returns> public static IEnumerable<SmppSubmitSm> SplitLongMessage(SmppSubmitSm pdu, SmppSarMethod method, byte correlationId) { if (pdu == null) throw new ArgumentNullException("pdu"); var result = new List<SmppSubmitSm>(); var data = pdu.MessagePayload != null ? pdu.MessagePayload : pdu.ShortMessage; if (data != null && !(data is string || data is byte[])) throw new ArgumentException("Short Message must be a string or byte array."); var bytes = data is string ? PduUtil.GetEncodedText(pdu.DataCoding, data as string) : data as byte[]; var maxSegmentLen = GetMaxSegmentLength(pdu.DataCoding, bytes.Length); // Remove/Reset data from PDU.. pdu.ShortMessage = pdu.MessagePayload = null; // Remove sequenceNumber. pdu.SequenceNumber = 0; // Remove UDH header (if set). pdu.EsmClass &= ((byte)~NetworkFeatures.UDHI); // Remove SMPP segmentation properties.. pdu.MoreMessagesToSend = null; pdu.NumberOfMessages = null; pdu.SarTotalSegments = null; pdu.SarMsgRefNumber = null; // Sending as payload means avoiding all the data splitting logic.. (which is great ;)) if (method == SmppSarMethod.SendAsPayload) { pdu.MessagePayload = data; return new[] { pdu }; } // Else.. let's do segmentation and the other crappy stuff.. var udhref = method == SmppSarMethod.UserDataHeader ? new Nullable<byte>(correlationId) : null; var segments = SplitMessage(bytes, maxSegmentLen, udhref); var totalSegments = segments.Count(); var segno = 0; // If just one segment, send it w/o SAR parameters.. if (totalSegments < 2) { pdu.ShortMessage = data; return new[] { pdu }; } // Ok, se we need segmentation, let's go ahead an use input PDU as template. var template = pdu.GetEncodedPdu(); // Well save results here.. var results = new List<SmppSubmitSm>(); foreach (var segment in segments) { var packet = new SmppSubmitSm(template); segno++; // Increase sequence number. packet.SequenceNumber = 0; // Remove sequenceNumber. packet.ShortMessage = segment; // Set current segment bytes as short message.. switch (method) { case SmppSarMethod.UserDataHeader: packet.EsmClass |= (byte)NetworkFeatures.UDHI; // Set UDH flag.. break; case SmppSarMethod.UseSmppSegmentation: packet.EsmClass &= ((byte)~NetworkFeatures.UDHI); // Remove UDH header (if set). // Fill-in SMPP segmentation fields.. packet.MoreMessagesToSend = segno != totalSegments; packet.NumberOfMessages = (byte)totalSegments; packet.SarTotalSegments = (byte)totalSegments; packet.SarMsgRefNumber = correlationId; packet.SarSegmentSeqnum = (byte)segno; break; } result.Add(packet); } return result; }