Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony;
     18 
     19 import android.util.Log;
     20 import com.android.internal.telephony.SmsHeader;
     21 import java.util.Arrays;
     22 
     23 import static android.telephony.SmsMessage.MessageClass;
     24 import android.provider.Telephony;
     25 
     26 /**
     27  * Base class declaring the specific methods and members for SmsMessage.
     28  * {@hide}
     29  */
     30 public abstract class SmsMessageBase {
     31     private static final String LOG_TAG = "SMS";
     32 
     33     /** {@hide} The address of the SMSC. May be null */
     34     protected String scAddress;
     35 
     36     /** {@hide} The address of the sender */
     37     protected SmsAddress originatingAddress;
     38 
     39     /** {@hide} The message body as a string. May be null if the message isn't text */
     40     protected String messageBody;
     41 
     42     /** {@hide} */
     43     protected String pseudoSubject;
     44 
     45     /** {@hide} Non-null if this is an email gateway message */
     46     protected String emailFrom;
     47 
     48     /** {@hide} Non-null if this is an email gateway message */
     49     protected String emailBody;
     50 
     51     /** {@hide} */
     52     protected boolean isEmail;
     53 
     54     /** {@hide} */
     55     protected long scTimeMillis;
     56 
     57     /** {@hide} The raw PDU of the message */
     58     protected byte[] mPdu;
     59 
     60     /** {@hide} The raw bytes for the user data section of the message */
     61     protected byte[] userData;
     62 
     63     /** {@hide} */
     64     protected SmsHeader userDataHeader;
     65 
     66     // "Message Waiting Indication Group"
     67     // 23.038 Section 4
     68     /** {@hide} */
     69     protected boolean isMwi;
     70 
     71     /** {@hide} */
     72     protected boolean mwiSense;
     73 
     74     /** {@hide} */
     75     protected boolean mwiDontStore;
     76 
     77     /**
     78      * Indicates status for messages stored on the ICC.
     79      */
     80     protected int statusOnIcc = -1;
     81 
     82     /**
     83      * Record index of message in the EF.
     84      */
     85     protected int indexOnIcc = -1;
     86 
     87     /** TP-Message-Reference - Message Reference of sent message. @hide */
     88     public int messageRef;
     89 
     90     /**
     91      * For a specific text string, this object describes protocol
     92      * properties of encoding it for transmission as message user
     93      * data.
     94      */
     95     public static class TextEncodingDetails {
     96         /**
     97          *The number of SMS's required to encode the text.
     98          */
     99         public int msgCount;
    100 
    101         /**
    102          * The number of code units consumed so far, where code units
    103          * are basically characters in the encoding -- for example,
    104          * septets for the standard ASCII and GSM encodings, and 16
    105          * bits for Unicode.
    106          */
    107         public int codeUnitCount;
    108 
    109         /**
    110          * How many code units are still available without spilling
    111          * into an additional message.
    112          */
    113         public int codeUnitsRemaining;
    114 
    115         /**
    116          * The encoding code unit size (specified using
    117          * android.telephony.SmsMessage ENCODING_*).
    118          */
    119         public int codeUnitSize;
    120 
    121         @Override
    122         public String toString() {
    123             return "TextEncodingDetails " +
    124                     "{ msgCount=" + msgCount +
    125                     ", codeUnitCount=" + codeUnitCount +
    126                     ", codeUnitsRemaining=" + codeUnitsRemaining +
    127                     ", codeUnitSize=" + codeUnitSize +
    128                     " }";
    129         }
    130     }
    131 
    132     // TODO(): This class is duplicated in SmsMessage.java. Refactor accordingly.
    133     public static abstract class SubmitPduBase  {
    134         public byte[] encodedScAddress; // Null if not applicable.
    135         public byte[] encodedMessage;
    136 
    137         public String toString() {
    138             return "SubmitPdu: encodedScAddress = "
    139                     + Arrays.toString(encodedScAddress)
    140                     + ", encodedMessage = "
    141                     + Arrays.toString(encodedMessage);
    142         }
    143     }
    144 
    145     /**
    146      * Returns the address of the SMS service center that relayed this message
    147      * or null if there is none.
    148      */
    149     public String getServiceCenterAddress() {
    150         return scAddress;
    151     }
    152 
    153     /**
    154      * Returns the originating address (sender) of this SMS message in String
    155      * form or null if unavailable
    156      */
    157     public String getOriginatingAddress() {
    158         if (originatingAddress == null) {
    159             return null;
    160         }
    161 
    162         return originatingAddress.getAddressString();
    163     }
    164 
    165     /**
    166      * Returns the originating address, or email from address if this message
    167      * was from an email gateway. Returns null if originating address
    168      * unavailable.
    169      */
    170     public String getDisplayOriginatingAddress() {
    171         if (isEmail) {
    172             return emailFrom;
    173         } else {
    174             return getOriginatingAddress();
    175         }
    176     }
    177 
    178     /**
    179      * Returns the message body as a String, if it exists and is text based.
    180      * @return message body is there is one, otherwise null
    181      */
    182     public String getMessageBody() {
    183         return messageBody;
    184     }
    185 
    186     /**
    187      * Returns the class of this message.
    188      */
    189     public abstract MessageClass getMessageClass();
    190 
    191     /**
    192      * Returns the message body, or email message body if this message was from
    193      * an email gateway. Returns null if message body unavailable.
    194      */
    195     public String getDisplayMessageBody() {
    196         if (isEmail) {
    197             return emailBody;
    198         } else {
    199             return getMessageBody();
    200         }
    201     }
    202 
    203     /**
    204      * Unofficial convention of a subject line enclosed in parens empty string
    205      * if not present
    206      */
    207     public String getPseudoSubject() {
    208         return pseudoSubject == null ? "" : pseudoSubject;
    209     }
    210 
    211     /**
    212      * Returns the service centre timestamp in currentTimeMillis() format
    213      */
    214     public long getTimestampMillis() {
    215         return scTimeMillis;
    216     }
    217 
    218     /**
    219      * Returns true if message is an email.
    220      *
    221      * @return true if this message came through an email gateway and email
    222      *         sender / subject / parsed body are available
    223      */
    224     public boolean isEmail() {
    225         return isEmail;
    226     }
    227 
    228     /**
    229      * @return if isEmail() is true, body of the email sent through the gateway.
    230      *         null otherwise
    231      */
    232     public String getEmailBody() {
    233         return emailBody;
    234     }
    235 
    236     /**
    237      * @return if isEmail() is true, email from address of email sent through
    238      *         the gateway. null otherwise
    239      */
    240     public String getEmailFrom() {
    241         return emailFrom;
    242     }
    243 
    244     /**
    245      * Get protocol identifier.
    246      */
    247     public abstract int getProtocolIdentifier();
    248 
    249     /**
    250      * See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
    251      * SMS
    252      */
    253     public abstract boolean isReplace();
    254 
    255     /**
    256      * Returns true for CPHS MWI toggle message.
    257      *
    258      * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section
    259      *         B.4.2
    260      */
    261     public abstract boolean isCphsMwiMessage();
    262 
    263     /**
    264      * returns true if this message is a CPHS voicemail / message waiting
    265      * indicator (MWI) clear message
    266      */
    267     public abstract boolean isMWIClearMessage();
    268 
    269     /**
    270      * returns true if this message is a CPHS voicemail / message waiting
    271      * indicator (MWI) set message
    272      */
    273     public abstract boolean isMWISetMessage();
    274 
    275     /**
    276      * returns true if this message is a "Message Waiting Indication Group:
    277      * Discard Message" notification and should not be stored.
    278      */
    279     public abstract boolean isMwiDontStore();
    280 
    281     /**
    282      * returns the user data section minus the user data header if one was
    283      * present.
    284      */
    285     public byte[] getUserData() {
    286         return userData;
    287     }
    288 
    289     /**
    290      * Returns an object representing the user data header
    291      *
    292      * {@hide}
    293      */
    294     public SmsHeader getUserDataHeader() {
    295         return userDataHeader;
    296     }
    297 
    298     /**
    299      * TODO(cleanup): The term PDU is used in a seemingly non-unique
    300      * manner -- for example, what is the difference between this byte
    301      * array and the contents of SubmitPdu objects.  Maybe a more
    302      * illustrative term would be appropriate.
    303      */
    304 
    305     /**
    306      * Returns the raw PDU for the message.
    307      */
    308     public byte[] getPdu() {
    309         return mPdu;
    310     }
    311 
    312     /**
    313      * For an SMS-STATUS-REPORT message, this returns the status field from
    314      * the status report.  This field indicates the status of a previously
    315      * submitted SMS, if requested.  See TS 23.040, 9.2.3.15 TP-Status for a
    316      * description of values.
    317      *
    318      * @return 0 indicates the previously sent message was received.
    319      *         See TS 23.040, 9.9.2.3.15 for a description of other possible
    320      *         values.
    321      */
    322     public abstract int getStatus();
    323 
    324     /**
    325      * Return true iff the message is a SMS-STATUS-REPORT message.
    326      */
    327     public abstract boolean isStatusReportMessage();
    328 
    329     /**
    330      * Returns true iff the <code>TP-Reply-Path</code> bit is set in
    331      * this message.
    332      */
    333     public abstract boolean isReplyPathPresent();
    334 
    335     /**
    336      * Returns the status of the message on the ICC (read, unread, sent, unsent).
    337      *
    338      * @return the status of the message on the ICC.  These are:
    339      *         SmsManager.STATUS_ON_ICC_FREE
    340      *         SmsManager.STATUS_ON_ICC_READ
    341      *         SmsManager.STATUS_ON_ICC_UNREAD
    342      *         SmsManager.STATUS_ON_ICC_SEND
    343      *         SmsManager.STATUS_ON_ICC_UNSENT
    344      */
    345     public int getStatusOnIcc() {
    346         return statusOnIcc;
    347     }
    348 
    349     /**
    350      * Returns the record index of the message on the ICC (1-based index).
    351      * @return the record index of the message on the ICC, or -1 if this
    352      *         SmsMessage was not created from a ICC SMS EF record.
    353      */
    354     public int getIndexOnIcc() {
    355         return indexOnIcc;
    356     }
    357 
    358     protected void parseMessageBody() {
    359         // originatingAddress could be null if this message is from a status
    360         // report.
    361         if (originatingAddress != null && originatingAddress.couldBeEmailGateway()) {
    362             extractEmailAddressFromMessageBody();
    363         }
    364     }
    365 
    366     /**
    367      * Try to parse this message as an email gateway message
    368      * There are two ways specified in TS 23.040 Section 3.8 :
    369      *  - SMS message "may have its TP-PID set for internet electronic mail - MT
    370      * SMS format: [<from-address><space>]<message> - "Depending on the
    371      * nature of the gateway, the destination/origination address is either
    372      * derived from the content of the SMS TP-OA or TP-DA field, or the
    373      * TP-OA/TP-DA field contains a generic gateway address and the to/from
    374      * address is added at the beginning as shown above." (which is supported here)
    375      * - Multiple addreses separated by commas, no spaces, Subject field delimited
    376      * by '()' or '##' and '#' Section 9.2.3.24.11 (which are NOT supported here)
    377      */
    378     protected void extractEmailAddressFromMessageBody() {
    379 
    380         /* Some carriers may use " /" delimiter as below
    381          *
    382          * 1. [x@y][ ]/[subject][ ]/[body]
    383          * -or-
    384          * 2. [x@y][ ]/[body]
    385          */
    386          String[] parts = messageBody.split("( /)|( )", 2);
    387          if (parts.length < 2) return;
    388          emailFrom = parts[0];
    389          emailBody = parts[1];
    390          isEmail = Telephony.Mms.isEmailAddress(emailFrom);
    391     }
    392 
    393 }
    394