SmsMessageBase.java revision daccacb865947c00f277f1823333e2fbf91e652a
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;
24
25/**
26 * Base class declaring the specific methods and members for SmsMessage.
27 * {@hide}
28 */
29public 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    public static abstract class SubmitPduBase  {
122        public byte[] encodedScAddress; // Null if not applicable.
123        public byte[] encodedMessage;
124
125        public String toString() {
126            return "SubmitPdu: encodedScAddress = "
127                    + Arrays.toString(encodedScAddress)
128                    + ", encodedMessage = "
129                    + Arrays.toString(encodedMessage);
130        }
131    }
132
133    /**
134     * Returns the address of the SMS service center that relayed this message
135     * or null if there is none.
136     */
137    public String getServiceCenterAddress() {
138        return scAddress;
139    }
140
141    /**
142     * Returns the originating address (sender) of this SMS message in String
143     * form or null if unavailable
144     */
145    public String getOriginatingAddress() {
146        if (originatingAddress == null) {
147            return null;
148        }
149
150        return originatingAddress.getAddressString();
151    }
152
153    /**
154     * Returns the originating address, or email from address if this message
155     * was from an email gateway. Returns null if originating address
156     * unavailable.
157     */
158    public String getDisplayOriginatingAddress() {
159        if (isEmail) {
160            return emailFrom;
161        } else {
162            return getOriginatingAddress();
163        }
164    }
165
166    /**
167     * Returns the message body as a String, if it exists and is text based.
168     * @return message body is there is one, otherwise null
169     */
170    public String getMessageBody() {
171        return messageBody;
172    }
173
174    /**
175     * Returns the class of this message.
176     */
177    public abstract MessageClass getMessageClass();
178
179    /**
180     * Returns the message body, or email message body if this message was from
181     * an email gateway. Returns null if message body unavailable.
182     */
183    public String getDisplayMessageBody() {
184        if (isEmail) {
185            return emailBody;
186        } else {
187            return getMessageBody();
188        }
189    }
190
191    /**
192     * Unofficial convention of a subject line enclosed in parens empty string
193     * if not present
194     */
195    public String getPseudoSubject() {
196        return pseudoSubject == null ? "" : pseudoSubject;
197    }
198
199    /**
200     * Returns the service centre timestamp in currentTimeMillis() format
201     */
202    public long getTimestampMillis() {
203        return scTimeMillis;
204    }
205
206    /**
207     * Returns true if message is an email.
208     *
209     * @return true if this message came through an email gateway and email
210     *         sender / subject / parsed body are available
211     */
212    public boolean isEmail() {
213        return isEmail;
214    }
215
216    /**
217     * @return if isEmail() is true, body of the email sent through the gateway.
218     *         null otherwise
219     */
220    public String getEmailBody() {
221        return emailBody;
222    }
223
224    /**
225     * @return if isEmail() is true, email from address of email sent through
226     *         the gateway. null otherwise
227     */
228    public String getEmailFrom() {
229        return emailFrom;
230    }
231
232    /**
233     * Get protocol identifier.
234     */
235    public abstract int getProtocolIdentifier();
236
237    /**
238     * See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
239     * SMS
240     */
241    public abstract boolean isReplace();
242
243    /**
244     * Returns true for CPHS MWI toggle message.
245     *
246     * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section
247     *         B.4.2
248     */
249    public abstract boolean isCphsMwiMessage();
250
251    /**
252     * returns true if this message is a CPHS voicemail / message waiting
253     * indicator (MWI) clear message
254     */
255    public abstract boolean isMWIClearMessage();
256
257    /**
258     * returns true if this message is a CPHS voicemail / message waiting
259     * indicator (MWI) set message
260     */
261    public abstract boolean isMWISetMessage();
262
263    /**
264     * returns true if this message is a "Message Waiting Indication Group:
265     * Discard Message" notification and should not be stored.
266     */
267    public abstract boolean isMwiDontStore();
268
269    /**
270     * returns the user data section minus the user data header if one was
271     * present.
272     */
273    public byte[] getUserData() {
274        return userData;
275    }
276
277    /**
278     * Returns an object representing the user data header
279     *
280     * {@hide}
281     */
282    public SmsHeader getUserDataHeader() {
283        return userDataHeader;
284    }
285
286    /**
287     * TODO(cleanup): The term PDU is used in a seemingly non-unique
288     * manner -- for example, what is the difference between this byte
289     * array and the contents of SubmitPdu objects.  Maybe a more
290     * illustrative term would be appropriate.
291     */
292
293    /**
294     * Returns the raw PDU for the message.
295     */
296    public byte[] getPdu() {
297        return mPdu;
298    }
299
300    /**
301     * For an SMS-STATUS-REPORT message, this returns the status field from
302     * the status report.  This field indicates the status of a previously
303     * submitted SMS, if requested.  See TS 23.040, 9.2.3.15 TP-Status for a
304     * description of values.
305     *
306     * @return 0 indicates the previously sent message was received.
307     *         See TS 23.040, 9.9.2.3.15 for a description of other possible
308     *         values.
309     */
310    public abstract int getStatus();
311
312    /**
313     * Return true iff the message is a SMS-STATUS-REPORT message.
314     */
315    public abstract boolean isStatusReportMessage();
316
317    /**
318     * Returns true iff the <code>TP-Reply-Path</code> bit is set in
319     * this message.
320     */
321    public abstract boolean isReplyPathPresent();
322
323    /**
324     * Returns the status of the message on the ICC (read, unread, sent, unsent).
325     *
326     * @return the status of the message on the ICC.  These are:
327     *         SmsManager.STATUS_ON_ICC_FREE
328     *         SmsManager.STATUS_ON_ICC_READ
329     *         SmsManager.STATUS_ON_ICC_UNREAD
330     *         SmsManager.STATUS_ON_ICC_SEND
331     *         SmsManager.STATUS_ON_ICC_UNSENT
332     */
333    public int getStatusOnIcc() {
334        return statusOnIcc;
335    }
336
337    /**
338     * Returns the record index of the message on the ICC (1-based index).
339     * @return the record index of the message on the ICC, or -1 if this
340     *         SmsMessage was not created from a ICC SMS EF record.
341     */
342    public int getIndexOnIcc() {
343        return indexOnIcc;
344    }
345
346    protected void parseMessageBody() {
347        // originatingAddress could be null if this message is from a status
348        // report.
349        if (originatingAddress != null && originatingAddress.couldBeEmailGateway()) {
350            extractEmailAddressFromMessageBody();
351        }
352    }
353
354    /**
355     * Try to parse this message as an email gateway message
356     * There are two ways specified in TS 23.040 Section 3.8 :
357     *  - SMS message "may have its TP-PID set for internet electronic mail - MT
358     * SMS format: [<from-address><space>]<message> - "Depending on the
359     * nature of the gateway, the destination/origination address is either
360     * derived from the content of the SMS TP-OA or TP-DA field, or the
361     * TP-OA/TP-DA field contains a generic gateway address and the to/from
362     * address is added at the beginning as shown above." (which is supported here)
363     * - Multiple addreses separated by commas, no spaces, Subject field delimited
364     * by '()' or '##' and '#' Section 9.2.3.24.11 (which are NOT supported here)
365     */
366    protected void extractEmailAddressFromMessageBody() {
367
368        /* Some carriers may use " /" delimiter as below
369         *
370         * 1. [x@y][ ]/[subject][ ]/[body]
371         * -or-
372         * 2. [x@y][ ]/[body]
373         */
374         String[] parts = messageBody.split("( /)|( )", 3);
375         if (parts.length < 2 || parts[0].indexOf('@') == -1) return;
376         emailFrom = parts[0];
377         if (parts.length == 3) {
378             pseudoSubject = parts[1];
379             emailBody = parts[2];
380         } else {
381             pseudoSubject = null;
382             emailBody = parts[1];
383         }
384         isEmail = true;
385    }
386
387}
388