SmsMessageBase.java revision fdf3b26ba78ed308f45a2c6f79a5f977663ac3c8
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
17package com.android.internal.telephony;
18
19import android.util.Log;
20import com.android.internal.telephony.SmsHeader;
21import java.util.Arrays;
22
23import static android.telephony.SmsMessage.MessageClass;
24import android.provider.Telephony;
25
26/**
27 * Base class declaring the specific methods and members for SmsMessage.
28 * {@hide}
29 */
30public 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