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