1/*
2 * Copyright (C) 2009 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.mms;
18
19import java.io.IOException;
20
21import org.xmlpull.v1.XmlPullParser;
22import org.xmlpull.v1.XmlPullParserException;
23
24import android.content.Context;
25import android.content.res.XmlResourceParser;
26import android.util.Log;
27
28import com.android.internal.telephony.TelephonyProperties;
29
30public class MmsConfig {
31    private static final String TAG = "MmsConfig";
32    private static final boolean DEBUG = true;
33    private static final boolean LOCAL_LOGV = false;
34
35    private static final String DEFAULT_HTTP_KEY_X_WAP_PROFILE = "x-wap-profile";
36    private static final String DEFAULT_USER_AGENT = "Android-Mms/2.0";
37
38    private static final int MAX_IMAGE_HEIGHT = 480;
39    private static final int MAX_IMAGE_WIDTH = 640;
40    private static final int MAX_TEXT_LENGTH = 2000;
41
42    /**
43     * Whether to hide MMS functionality from the user (i.e. SMS only).
44     */
45    private static boolean mTransIdEnabled = false;
46    private static int mMmsEnabled = 1;                         // default to true
47    private static int mMaxMessageSize = 300 * 1024;            // default to 300k max size
48    private static String mUserAgent = DEFAULT_USER_AGENT;
49    private static String mUaProfTagName = DEFAULT_HTTP_KEY_X_WAP_PROFILE;
50    private static String mUaProfUrl = null;
51    private static String mHttpParams = null;
52    private static String mHttpParamsLine1Key = null;
53    private static String mEmailGateway = null;
54    private static int mMaxImageHeight = MAX_IMAGE_HEIGHT;      // default value
55    private static int mMaxImageWidth = MAX_IMAGE_WIDTH;        // default value
56    private static int mRecipientLimit = Integer.MAX_VALUE;     // default value
57    private static int mDefaultSMSMessagesPerThread = 500;      // default value
58    private static int mDefaultMMSMessagesPerThread = 50;       // default value
59    private static int mMinMessageCountPerThread = 2;           // default value
60    private static int mMaxMessageCountPerThread = 5000;        // default value
61    private static int mHttpSocketTimeout = 60*1000;            // default to 1 min
62    private static int mMinimumSlideElementDuration = 7;        // default to 7 sec
63    private static boolean mNotifyWapMMSC = false;
64    private static boolean mAllowAttachAudio = true;
65
66    // If mEnableMultipartSMS is true, long sms messages are always sent as multi-part sms
67    // messages, with no checked limit on the number of segments.
68    // If mEnableMultipartSMS is false, then as soon as the user types a message longer
69    // than a single segment (i.e. 140 chars), then the message will turn into and be sent
70    // as an mms message. This feature exists for carriers that don't support multi-part sms's.
71    private static boolean mEnableMultipartSMS = true;
72
73    // If mEnableMultipartSMS is true and mSmsToMmsTextThreshold > 1, then multi-part SMS messages
74    // will be converted into a single mms message. For example, if the mms_config.xml file
75    // specifies <int name="smsToMmsTextThreshold">4</int>, then on the 5th sms segment, the
76    // message will be converted to an mms.
77    private static int mSmsToMmsTextThreshold = -1;
78
79    private static boolean mEnableSlideDuration = true;
80    private static boolean mEnableMMSReadReports = true;        // key: "enableMMSReadReports"
81    private static boolean mEnableSMSDeliveryReports = true;    // key: "enableSMSDeliveryReports"
82    private static boolean mEnableMMSDeliveryReports = true;    // key: "enableMMSDeliveryReports"
83    private static int mMaxTextLength = -1;
84
85    // This is the max amount of storage multiplied by mMaxMessageSize that we
86    // allow of unsent messages before blocking the user from sending any more
87    // MMS's.
88    private static int mMaxSizeScaleForPendingMmsAllowed = 4;       // default value
89
90    // Email gateway alias support, including the master switch and different rules
91    private static boolean mAliasEnabled = false;
92    private static int mAliasRuleMinChars = 2;
93    private static int mAliasRuleMaxChars = 48;
94
95    private static int mMaxSubjectLength = 40;  // maximum number of characters allowed for mms
96                                                // subject
97
98    // If mEnableGroupMms is true, a message with multiple recipients, regardless of contents,
99    // will be sent as a single MMS message with multiple "TO" fields set for each recipient.
100    // If mEnableGroupMms is false, the group MMS setting/preference will be hidden in the settings
101    // activity.
102    private static boolean mEnableGroupMms = true;
103
104    public static void init(Context context) {
105        if (LOCAL_LOGV) {
106            Log.v(TAG, "MmsConfig.init()");
107        }
108        // Always put the mnc/mcc in the log so we can tell which mms_config.xml was loaded.
109        Log.v(TAG, "mnc/mcc: " +
110                android.os.SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC));
111
112        loadMmsSettings(context);
113    }
114
115    public static int getSmsToMmsTextThreshold() {
116        return mSmsToMmsTextThreshold;
117    }
118
119    public static boolean getMmsEnabled() {
120        return mMmsEnabled == 1 ? true : false;
121    }
122
123    public static int getMaxMessageSize() {
124        if (LOCAL_LOGV) {
125            Log.v(TAG, "MmsConfig.getMaxMessageSize(): " + mMaxMessageSize);
126        }
127       return mMaxMessageSize;
128    }
129
130    /**
131     * This function returns the value of "enabledTransID" present in mms_config file.
132     * In case of single segment wap push message, this "enabledTransID" indicates whether
133     * TransactionID should be appended to URI or not.
134     */
135    public static boolean getTransIdEnabled() {
136        return mTransIdEnabled;
137    }
138
139    public static String getUserAgent() {
140        return mUserAgent;
141    }
142
143    public static String getUaProfTagName() {
144        return mUaProfTagName;
145    }
146
147    public static String getUaProfUrl() {
148        return mUaProfUrl;
149    }
150
151    public static String getHttpParams() {
152        return mHttpParams;
153    }
154
155    public static String getHttpParamsLine1Key() {
156        return mHttpParamsLine1Key;
157    }
158
159    public static String getEmailGateway() {
160        return mEmailGateway;
161    }
162
163    public static int getMaxImageHeight() {
164        return mMaxImageHeight;
165    }
166
167    public static int getMaxImageWidth() {
168        return mMaxImageWidth;
169    }
170
171    public static int getRecipientLimit() {
172        return mRecipientLimit;
173    }
174
175    public static int getMaxTextLimit() {
176        return mMaxTextLength > -1 ? mMaxTextLength : MAX_TEXT_LENGTH;
177    }
178
179    public static int getDefaultSMSMessagesPerThread() {
180        return mDefaultSMSMessagesPerThread;
181    }
182
183    public static int getDefaultMMSMessagesPerThread() {
184        return mDefaultMMSMessagesPerThread;
185    }
186
187    public static int getMinMessageCountPerThread() {
188        return mMinMessageCountPerThread;
189    }
190
191    public static int getMaxMessageCountPerThread() {
192        return mMaxMessageCountPerThread;
193    }
194
195    public static int getHttpSocketTimeout() {
196        return mHttpSocketTimeout;
197    }
198
199    public static int getMinimumSlideElementDuration() {
200        return mMinimumSlideElementDuration;
201    }
202
203    public static boolean getMultipartSmsEnabled() {
204        return mEnableMultipartSMS;
205    }
206
207    public static boolean getSlideDurationEnabled() {
208        return mEnableSlideDuration;
209    }
210
211    public static boolean getMMSReadReportsEnabled() {
212        return mEnableMMSReadReports;
213    }
214
215    public static boolean getSMSDeliveryReportsEnabled() {
216        return mEnableSMSDeliveryReports;
217    }
218
219    public static boolean getMMSDeliveryReportsEnabled() {
220        return mEnableMMSDeliveryReports;
221    }
222
223    public static boolean getNotifyWapMMSC() {
224        return mNotifyWapMMSC;
225    }
226
227    public static int getMaxSizeScaleForPendingMmsAllowed() {
228        return mMaxSizeScaleForPendingMmsAllowed;
229    }
230
231    public static boolean isAliasEnabled() {
232        return mAliasEnabled;
233    }
234
235    public static int getAliasMinChars() {
236        return mAliasRuleMinChars;
237    }
238
239    public static int getAliasMaxChars() {
240        return mAliasRuleMaxChars;
241    }
242
243    public static boolean getAllowAttachAudio() {
244        return mAllowAttachAudio;
245    }
246
247    public static int getMaxSubjectLength() {
248        return mMaxSubjectLength;
249    }
250
251    public static boolean getGroupMmsEnabled() {
252        return mEnableGroupMms;
253    }
254
255    public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException
256    {
257        int type;
258        while ((type=parser.next()) != parser.START_TAG
259                   && type != parser.END_DOCUMENT) {
260            ;
261        }
262
263        if (type != parser.START_TAG) {
264            throw new XmlPullParserException("No start tag found");
265        }
266
267        if (!parser.getName().equals(firstElementName)) {
268            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
269                    ", expected " + firstElementName);
270        }
271    }
272
273    public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException
274    {
275        int type;
276        while ((type=parser.next()) != parser.START_TAG
277                   && type != parser.END_DOCUMENT) {
278            ;
279        }
280    }
281
282    private static void loadMmsSettings(Context context) {
283        XmlResourceParser parser = context.getResources().getXml(R.xml.mms_config);
284
285        try {
286            beginDocument(parser, "mms_config");
287
288            while (true) {
289                nextElement(parser);
290                String tag = parser.getName();
291                if (tag == null) {
292                    break;
293                }
294                String name = parser.getAttributeName(0);
295                String value = parser.getAttributeValue(0);
296                String text = null;
297                if (parser.next() == XmlPullParser.TEXT) {
298                    text = parser.getText();
299                }
300
301                if (DEBUG) {
302                    Log.v(TAG, "tag: " + tag + " value: " + value + " - " +
303                            text);
304                }
305                if ("name".equalsIgnoreCase(name)) {
306                    if ("bool".equals(tag)) {
307                        // bool config tags go here
308                        if ("enabledMMS".equalsIgnoreCase(value)) {
309                            mMmsEnabled = "true".equalsIgnoreCase(text) ? 1 : 0;
310                        } else if ("enabledTransID".equalsIgnoreCase(value)) {
311                            mTransIdEnabled = "true".equalsIgnoreCase(text);
312                        } else if ("enabledNotifyWapMMSC".equalsIgnoreCase(value)) {
313                            mNotifyWapMMSC = "true".equalsIgnoreCase(text);
314                        } else if ("aliasEnabled".equalsIgnoreCase(value)) {
315                            mAliasEnabled = "true".equalsIgnoreCase(text);
316                        } else if ("allowAttachAudio".equalsIgnoreCase(value)) {
317                            mAllowAttachAudio = "true".equalsIgnoreCase(text);
318                        } else if ("enableMultipartSMS".equalsIgnoreCase(value)) {
319                            mEnableMultipartSMS = "true".equalsIgnoreCase(text);
320                        } else if ("enableSlideDuration".equalsIgnoreCase(value)) {
321                            mEnableSlideDuration = "true".equalsIgnoreCase(text);
322                        } else if ("enableMMSReadReports".equalsIgnoreCase(value)) {
323                            mEnableMMSReadReports = "true".equalsIgnoreCase(text);
324                        } else if ("enableSMSDeliveryReports".equalsIgnoreCase(value)) {
325                            mEnableSMSDeliveryReports = "true".equalsIgnoreCase(text);
326                        } else if ("enableMMSDeliveryReports".equalsIgnoreCase(value)) {
327                            mEnableMMSDeliveryReports = "true".equalsIgnoreCase(text);
328                        } else if ("enableGroupMms".equalsIgnoreCase(value)) {
329                            mEnableGroupMms = "true".equalsIgnoreCase(text);
330                        }
331                    } else if ("int".equals(tag)) {
332                        // int config tags go here
333                        if ("maxMessageSize".equalsIgnoreCase(value)) {
334                            mMaxMessageSize = Integer.parseInt(text);
335                        } else if ("maxImageHeight".equalsIgnoreCase(value)) {
336                            mMaxImageHeight = Integer.parseInt(text);
337                        } else if ("maxImageWidth".equalsIgnoreCase(value)) {
338                            mMaxImageWidth = Integer.parseInt(text);
339                        } else if ("defaultSMSMessagesPerThread".equalsIgnoreCase(value)) {
340                            mDefaultSMSMessagesPerThread = Integer.parseInt(text);
341                        } else if ("defaultMMSMessagesPerThread".equalsIgnoreCase(value)) {
342                            mDefaultMMSMessagesPerThread = Integer.parseInt(text);
343                        } else if ("minMessageCountPerThread".equalsIgnoreCase(value)) {
344                            mMinMessageCountPerThread = Integer.parseInt(text);
345                        } else if ("maxMessageCountPerThread".equalsIgnoreCase(value)) {
346                            mMaxMessageCountPerThread = Integer.parseInt(text);
347                        } else if ("recipientLimit".equalsIgnoreCase(value)) {
348                            mRecipientLimit = Integer.parseInt(text);
349                            if (mRecipientLimit < 0) {
350                                mRecipientLimit = Integer.MAX_VALUE;
351                            }
352                        } else if ("httpSocketTimeout".equalsIgnoreCase(value)) {
353                            mHttpSocketTimeout = Integer.parseInt(text);
354                        } else if ("minimumSlideElementDuration".equalsIgnoreCase(value)) {
355                            mMinimumSlideElementDuration = Integer.parseInt(text);
356                        } else if ("maxSizeScaleForPendingMmsAllowed".equalsIgnoreCase(value)) {
357                            mMaxSizeScaleForPendingMmsAllowed = Integer.parseInt(text);
358                        } else if ("aliasMinChars".equalsIgnoreCase(value)) {
359                            mAliasRuleMinChars = Integer.parseInt(text);
360                        } else if ("aliasMaxChars".equalsIgnoreCase(value)) {
361                            mAliasRuleMaxChars = Integer.parseInt(text);
362                        } else if ("smsToMmsTextThreshold".equalsIgnoreCase(value)) {
363                            mSmsToMmsTextThreshold = Integer.parseInt(text);
364                        } else if ("maxMessageTextSize".equalsIgnoreCase(value)) {
365                            mMaxTextLength = Integer.parseInt(text);
366                        } else if ("maxSubjectLength".equalsIgnoreCase(value)) {
367                            mMaxSubjectLength = Integer.parseInt(text);
368                        }
369                    } else if ("string".equals(tag)) {
370                        // string config tags go here
371                        if ("userAgent".equalsIgnoreCase(value)) {
372                            mUserAgent = text;
373                        } else if ("uaProfTagName".equalsIgnoreCase(value)) {
374                            mUaProfTagName = text;
375                        } else if ("uaProfUrl".equalsIgnoreCase(value)) {
376                            mUaProfUrl = text;
377                        } else if ("httpParams".equalsIgnoreCase(value)) {
378                            mHttpParams = text;
379                        } else if ("httpParamsLine1Key".equalsIgnoreCase(value)) {
380                            mHttpParamsLine1Key = text;
381                        } else if ("emailGatewayNumber".equalsIgnoreCase(value)) {
382                            mEmailGateway = text;
383                        }
384                    }
385                }
386            }
387        } catch (XmlPullParserException e) {
388            Log.e(TAG, "loadMmsSettings caught ", e);
389        } catch (NumberFormatException e) {
390            Log.e(TAG, "loadMmsSettings caught ", e);
391        } catch (IOException e) {
392            Log.e(TAG, "loadMmsSettings caught ", e);
393        } finally {
394            parser.close();
395        }
396
397        String errorStr = null;
398
399        if (getMmsEnabled() && mUaProfUrl == null) {
400            errorStr = "uaProfUrl";
401        }
402
403        if (errorStr != null) {
404            String err =
405                String.format("MmsConfig.loadMmsSettings mms_config.xml missing %s setting",
406                        errorStr);
407            Log.e(TAG, err);
408        }
409    }
410
411}
412