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