| /* |
| * Copyright (C) 2006 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.internal.telephony; |
| |
| import com.android.internal.util.HexDump; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * This class represents a SMS user data header. |
| * |
| */ |
| public class SmsHeader { |
| /** See TS 23.040 9.2.3.24 for description of this element ID. */ |
| public static final int CONCATENATED_8_BIT_REFERENCE = 0x00; |
| /** See TS 23.040 9.2.3.24 for description of this element ID. */ |
| public static final int SPECIAL_SMS_MESSAGE_INDICATION = 0x01; |
| /** See TS 23.040 9.2.3.24 for description of this element ID. */ |
| public static final int APPLICATION_PORT_ADDRESSING_8_BIT = 0x04; |
| /** See TS 23.040 9.2.3.24 for description of this element ID. */ |
| public static final int APPLICATION_PORT_ADDRESSING_16_BIT= 0x05; |
| /** See TS 23.040 9.2.3.24 for description of this element ID. */ |
| public static final int CONCATENATED_16_BIT_REFERENCE = 0x08; |
| |
| public static final int PORT_WAP_PUSH = 2948; |
| public static final int PORT_WAP_WSP = 9200; |
| |
| private byte[] m_data; |
| private ArrayList<Element> m_elements = new ArrayList<Element>(); |
| public int nbrOfHeaders; |
| |
| /** |
| * Creates an SmsHeader object from raw user data header bytes. |
| * |
| * @param data is user data header bytes |
| * @return an SmsHeader object |
| */ |
| public static SmsHeader parse(byte[] data) { |
| SmsHeader header = new SmsHeader(); |
| header.m_data = data; |
| |
| int index = 0; |
| header.nbrOfHeaders = 0; |
| while (index < data.length) { |
| int id = data[index++] & 0xff; |
| int length = data[index++] & 0xff; |
| byte[] elementData = new byte[length]; |
| System.arraycopy(data, index, elementData, 0, length); |
| header.add(new Element(id, elementData)); |
| index += length; |
| header.nbrOfHeaders++; |
| } |
| |
| return header; |
| } |
| |
| public SmsHeader() { } |
| |
| /** |
| * Returns the list of SmsHeader Elements that make up the header. |
| * |
| * @return the list of SmsHeader Elements. |
| */ |
| public ArrayList<Element> getElements() { |
| return m_elements; |
| } |
| |
| /** |
| * Add an element to the SmsHeader. |
| * |
| * @param element to add. |
| */ |
| public void add(Element element) { |
| m_elements.add(element); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder builder = new StringBuilder(); |
| |
| builder.append("UDH LENGTH: " + m_data.length + " octets"); |
| builder.append("UDH: "); |
| builder.append(HexDump.toHexString(m_data)); |
| builder.append("\n"); |
| |
| for (Element e : getElements()) { |
| builder.append(" 0x" + HexDump.toHexString((byte)e.getID()) + " - "); |
| switch (e.getID()) { |
| case CONCATENATED_8_BIT_REFERENCE: { |
| builder.append("Concatenated Short Message 8bit ref\n"); |
| byte[] data = e.getData(); |
| builder.append(" " + data.length + " (0x"); |
| builder.append(HexDump.toHexString((byte)data.length) |
| + ") Bytes - Information Element\n"); |
| builder.append(" " + data[0] + " : SM reference number\n"); |
| builder.append(" " + data[1] + " : number of messages\n"); |
| builder.append(" " + data[2] + " : this SM sequence number\n"); |
| break; |
| } |
| |
| case CONCATENATED_16_BIT_REFERENCE: { |
| builder.append("Concatenated Short Message 16bit ref\n"); |
| byte[] data = e.getData(); |
| builder.append(" " + data.length + " (0x"); |
| builder.append(HexDump.toHexString((byte)data.length) |
| + ") Bytes - Information Element\n"); |
| builder.append(" " + (data[0] & 0xff) * 256 + (data[1] & 0xff) |
| + " : SM reference number\n"); |
| builder.append(" " + data[2] + " : number of messages\n"); |
| builder.append(" " + data[3] + " : this SM sequence number\n"); |
| break; |
| } |
| |
| case APPLICATION_PORT_ADDRESSING_8_BIT: |
| { |
| builder.append("Application port addressing 8bit\n"); |
| byte[] data = e.getData(); |
| |
| builder.append(" " + data.length + " (0x"); |
| builder.append(HexDump.toHexString( |
| (byte)data.length) + ") Bytes - Information Element\n"); |
| |
| int source = (data[0] & 0xff); |
| builder.append(" " + source + " : DESTINATION port\n"); |
| |
| int dest = (data[1] & 0xff); |
| builder.append(" " + dest + " : SOURCE port\n"); |
| break; |
| } |
| |
| case APPLICATION_PORT_ADDRESSING_16_BIT: { |
| builder.append("Application port addressing 16bit\n"); |
| byte[] data = e.getData(); |
| |
| builder.append(" " + data.length + " (0x"); |
| builder.append(HexDump.toHexString((byte)data.length) |
| + ") Bytes - Information Element\n"); |
| |
| int source = (data[0] & 0xff) << 8; |
| source |= (data[1] & 0xff); |
| builder.append(" " + source + " : DESTINATION port\n"); |
| |
| int dest = (data[2] & 0xff) << 8; |
| dest |= (data[3] & 0xff); |
| builder.append(" " + dest + " : SOURCE port\n"); |
| break; |
| } |
| |
| default: { |
| builder.append("Unknown element\n"); |
| break; |
| } |
| } |
| } |
| |
| return builder.toString(); |
| } |
| |
| private int calcSize() { |
| int size = 1; // +1 for the UDHL field |
| for (Element e : m_elements) { |
| size += e.getData().length; |
| size += 2; // 1 byte ID, 1 byte length |
| } |
| |
| return size; |
| } |
| |
| /** |
| * Converts SmsHeader object to a byte array as specified in TS 23.040 9.2.3.24. |
| * @return Byte array representing the SmsHeader |
| */ |
| public byte[] toByteArray() { |
| if (m_elements.size() == 0) return null; |
| |
| if (m_data == null) { |
| int size = calcSize(); |
| int cur = 1; |
| m_data = new byte[size]; |
| |
| m_data[0] = (byte) (size-1); // UDHL does not include itself |
| |
| for (Element e : m_elements) { |
| int length = e.getData().length; |
| m_data[cur++] = (byte) e.getID(); |
| m_data[cur++] = (byte) length; |
| System.arraycopy(e.getData(), 0, m_data, cur, length); |
| cur += length; |
| } |
| } |
| |
| return m_data; |
| } |
| |
| /** |
| * A single Element in the SMS User Data Header. |
| * |
| * See TS 23.040 9.2.3.24. |
| * |
| */ |
| public static class Element { |
| private byte[] m_data; |
| private int m_id; |
| |
| public Element(int id, byte[] data) { |
| m_id = id; |
| m_data = data; |
| } |
| |
| /** |
| * Returns the Information Element Identifier for this element. |
| * |
| * @return the IE identifier. |
| */ |
| public int getID() { |
| return m_id; |
| } |
| |
| /** |
| * Returns the data portion of this element. |
| * |
| * @return element data. |
| */ |
| public byte[] getData() { |
| return m_data; |
| } |
| } |
| } |