/** * Splits an octet stream into the separate parts that would be the payloads of concatenated SMS * messages. * * @param messageBinary * @param sourcePort * @param destinationPort * @return Supplied byte[] split into parts. These parts should reconcatenate to form the original * byte array. Supplying a zero-length byte[] should return a single, empty part. */ public static byte[][] getPayloads(byte[] messageBinary, int sourcePort, int destinationPort) { if (messageBinary.length == 0) return new byte[][] {new byte[0]}; boolean isPorted = sourcePort > 0 || destinationPort > 0; int totalParts = getMessagesNeeded_8bit(messageBinary.length, isPorted); byte[][] payloadParts = new byte[totalParts][]; int udhLength = getUDHSize(true, isPorted, totalParts > 1); String encodedText = HexUtils.encode(messageBinary); for (int i = 0; i < payloadParts.length; i++) { payloadParts[i] = HexUtils.decode(extractPayload(encodedText, i + 1, udhLength)); } return payloadParts; }
/** * Generates the TPDUs for a UCS-2-encoded text message. The TPDUs are returned as hex-encoded * binary strings. * * @param messageText * @param smscNumber * @param recipientMsisdn * @param concatReferenceNumber Reference number to embed in multipart message parts' UDH * @param sourcePort * @param destinationPort * @param requestStatusReport * @param validityPeriod Validity period of this message, in hours. Maximum validity will be * requested if this is set to zero. * @param protocolIdentifier * @param dataCodingScheme * @return The PDUs to be sent for the message */ public static String[] generatePdus_ucs2( String messageText, String smscNumber, String recipientMsisdn, int concatReferenceNumber, int sourcePort, int destinationPort, boolean requestStatusReport, int validityPeriod, int protocolIdentifier, int dataCodingScheme) { boolean isPorted = sourcePort > 0 || destinationPort > 0; String[] messageParts = splitText_ucs2(messageText, isPorted); final int totalParts = messageParts.length; boolean isMultipart = totalParts > 1; boolean requiresUdh = isMultipart || isPorted; String[] pdus = new String[totalParts]; try { for (int partNumber = 1; partNumber <= totalParts; ++partNumber) { ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(encodeMsisdnAsAddressField(smscNumber, true)); // get the front byte, which identifies message content out.write(getByteZero(TP_MTI_MO_SUBMIT, requiresUdh, requestStatusReport)); // Message reference. Always zero here. /** [TP-MR: TP-Message-Reference] Parameter identifying the SMS-SUBMIT. */ out.write(0); // Add the recipient's MSISDN /** [TP-DA: TP-Destination-Address] Address of the destination SME. */ out.write(encodeMsisdnAsAddressField(recipientMsisdn, false)); /** * [TP-PID: TP-Protocol-Identifier] Parameter identifying the above layer protocol, if any. */ out.write(protocolIdentifier); /** * [TP-DCS: TP-Data-CodingScheme] Parameter identifying the coding scheme within the * TP-User-Data. */ out.write(dataCodingScheme); /** * [TP-VP: TP-Validity-Period] Parameter identifying the time from where the message is no * longer valid. Here, this is always relative. */ out.write(getRelativeVP(validityPeriod)); // Build the UD // First build the UDH /** * Total length of the udh, including the UDHL. Do not confuse with udhBytes.length, which * is the length of the UDH's content */ int udhTotalLength = getUDHSize(true, isPorted, isMultipart); byte[] encodedText = encodeUcs2Text(messageParts[partNumber - 1]); /** The length, in octets, of the user data, including the header. */ int dataLen = encodedText.length + udhTotalLength; /** [TP-UDL: TP-User-Data-Length] Length of the UD, specific to the encoding. */ out.write(dataLen); if (requiresUdh) { /** Now write the octet content of the UDH */ out.write( generateUDH( partNumber, totalParts, concatReferenceNumber, sourcePort, destinationPort)); } /** Add the MS to the PDU */ out.write(encodedText); pdus[partNumber - 1] = HexUtils.encode(out.toByteArray()); } return pdus; } catch (IOException ex) { throw new RuntimeException(ex); } }
/** * Generate PDUs for a text message encoded using {@link SmsMessageEncoding#GSM_7BIT}. * * @param messageText * @param smscNumber * @param recipientMsisdn * @param concatReferenceNumber * @param sourcePort * @param destinationPort * @param requestStatusReport * @param validityPeriod * @param protocolIdentifier * @param dataCodingScheme * @return An ordered list of PDUs encoded as hexadecimal strings which combine to recreate the * original text message. */ public static String[] generatePdus_gsm7bit( String messageText, String smscNumber, String recipientMsisdn, int concatReferenceNumber, int sourcePort, int destinationPort, boolean requestStatusReport, int validityPeriod, int protocolIdentifier, int dataCodingScheme) { boolean isPorted = sourcePort > 0 || destinationPort > 0; String[] messageParts = GsmAlphabet.splitText(messageText, isPorted); final int totalParts = messageParts.length; boolean isMultipart = totalParts > 1; boolean requiresUdh = isMultipart || isPorted; /** PDUs that make up this message, encoded as hexadecimal strings. */ String[] pdus = new String[totalParts]; try { for (int partNumber = 1; partNumber <= totalParts; ++partNumber) { ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(encodeMsisdnAsAddressField(smscNumber, true)); // get the front byte, which identifies message content out.write(getByteZero(TP_MTI_MO_SUBMIT, requiresUdh, requestStatusReport)); // Message reference. Always zero here. /** [TP-MR: TP-Message-Reference] Parameter identifying the SMS-SUBMIT. */ out.write(0); // Add the recipient's MSISDN /** [TP-DA: TP-Destination-Address] Address of the destination SME. */ out.write(encodeMsisdnAsAddressField(recipientMsisdn, false)); /** * [TP-PID: TP-Protocol-Identifier] Parameter identifying the above layer protocol, if any. */ out.write(protocolIdentifier); /** * [TP-DCS: TP-Data-CodingScheme] Parameter identifying the coding scheme within the * TP-User-Data. */ out.write(dataCodingScheme); /** * [TP-VP: TP-Validity-Period] Parameter identifying the time from where the message is no * longer valid. Here, this is always relative. */ out.write(getRelativeVP(validityPeriod)); // Build the UD // First build the UDH /** * Total length of the udh, including the UDHL. Do not confuse with udhBytes.length, which * is the length of the UDH's content */ int udhTotalLength = getUDHSize(true, isPorted, isMultipart); byte[] encodedMessageSeptets = GsmAlphabet.stringToBytes(messageParts[partNumber - 1]); /** Encode the message text using the standard 7-bit GSM alphabet. */ int skipBits = GsmAlphabet.calculateBitSkip(udhTotalLength); byte[] encodedMessageText = GsmAlphabet.septetStream2octetStream(encodedMessageSeptets, skipBits); /** * [TP-UDL: TP-User-Data-Length] Length of the UD, specific to the encoding. For a 7-bit GSM * charset message, this is the number of septets in the UD. */ int udLength = (int) Math.ceil( ((udhTotalLength * 8) + (encodedMessageSeptets.length * 7) + skipBits) / 7.0); out.write(udLength); if (requiresUdh) { /** Now write the octet content of the UDH */ out.write( generateUDH( partNumber, totalParts, concatReferenceNumber, sourcePort, destinationPort)); } out.write(encodedMessageText); pdus[partNumber - 1] = HexUtils.encode(out.toByteArray()); } return pdus; } catch (IOException ex) { throw new RuntimeException(ex); } }