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