1/*
2 * Copyright (C) 2007 Esmertec AG.
3 * Copyright (C) 2007 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.messaging.mmslib.pdu;
19
20import android.util.SparseArray;
21
22import com.android.messaging.mmslib.InvalidHeaderValueException;
23
24import java.util.ArrayList;
25
26public class PduHeaders {
27    /**
28     * All pdu header fields.
29     */
30    public static final int BCC                             = 0x81;
31    public static final int CC                              = 0x82;
32    public static final int CONTENT_LOCATION                = 0x83;
33    public static final int CONTENT_TYPE                    = 0x84;
34    public static final int DATE                            = 0x85;
35    public static final int DELIVERY_REPORT                 = 0x86;
36    public static final int DELIVERY_TIME                   = 0x87;
37    public static final int EXPIRY                          = 0x88;
38    public static final int FROM                            = 0x89;
39    public static final int MESSAGE_CLASS                   = 0x8A;
40    public static final int MESSAGE_ID                      = 0x8B;
41    public static final int MESSAGE_TYPE                    = 0x8C;
42    public static final int MMS_VERSION                     = 0x8D;
43    public static final int MESSAGE_SIZE                    = 0x8E;
44    public static final int PRIORITY                        = 0x8F;
45
46    public static final int READ_REPLY                      = 0x90;
47    public static final int READ_REPORT                     = 0x90;
48    public static final int REPORT_ALLOWED                  = 0x91;
49    public static final int RESPONSE_STATUS                 = 0x92;
50    public static final int RESPONSE_TEXT                   = 0x93;
51    public static final int SENDER_VISIBILITY               = 0x94;
52    public static final int STATUS                          = 0x95;
53    public static final int SUBJECT                         = 0x96;
54    public static final int TO                              = 0x97;
55    public static final int TRANSACTION_ID                  = 0x98;
56    public static final int RETRIEVE_STATUS                 = 0x99;
57    public static final int RETRIEVE_TEXT                   = 0x9A;
58    public static final int READ_STATUS                     = 0x9B;
59    public static final int REPLY_CHARGING                  = 0x9C;
60    public static final int REPLY_CHARGING_DEADLINE         = 0x9D;
61    public static final int REPLY_CHARGING_ID               = 0x9E;
62    public static final int REPLY_CHARGING_SIZE             = 0x9F;
63
64    public static final int PREVIOUSLY_SENT_BY              = 0xA0;
65    public static final int PREVIOUSLY_SENT_DATE            = 0xA1;
66    public static final int STORE                           = 0xA2;
67    public static final int MM_STATE                        = 0xA3;
68    public static final int MM_FLAGS                        = 0xA4;
69    public static final int STORE_STATUS                    = 0xA5;
70    public static final int STORE_STATUS_TEXT               = 0xA6;
71    public static final int STORED                          = 0xA7;
72    public static final int ATTRIBUTES                      = 0xA8;
73    public static final int TOTALS                          = 0xA9;
74    public static final int MBOX_TOTALS                     = 0xAA;
75    public static final int QUOTAS                          = 0xAB;
76    public static final int MBOX_QUOTAS                     = 0xAC;
77    public static final int MESSAGE_COUNT                   = 0xAD;
78    public static final int CONTENT                         = 0xAE;
79    public static final int START                           = 0xAF;
80
81    public static final int ADDITIONAL_HEADERS              = 0xB0;
82    public static final int DISTRIBUTION_INDICATOR          = 0xB1;
83    public static final int ELEMENT_DESCRIPTOR              = 0xB2;
84    public static final int LIMIT                           = 0xB3;
85    public static final int RECOMMENDED_RETRIEVAL_MODE      = 0xB4;
86    public static final int RECOMMENDED_RETRIEVAL_MODE_TEXT = 0xB5;
87    public static final int STATUS_TEXT                     = 0xB6;
88    public static final int APPLIC_ID                       = 0xB7;
89    public static final int REPLY_APPLIC_ID                 = 0xB8;
90    public static final int AUX_APPLIC_ID                   = 0xB9;
91    public static final int CONTENT_CLASS                   = 0xBA;
92    public static final int DRM_CONTENT                     = 0xBB;
93    public static final int ADAPTATION_ALLOWED              = 0xBC;
94    public static final int REPLACE_ID                      = 0xBD;
95    public static final int CANCEL_ID                       = 0xBE;
96    public static final int CANCEL_STATUS                   = 0xBF;
97
98    /**
99     * X-Mms-Message-Type field types.
100     */
101    public static final int MESSAGE_TYPE_SEND_REQ           = 0x80;
102    public static final int MESSAGE_TYPE_SEND_CONF          = 0x81;
103    public static final int MESSAGE_TYPE_NOTIFICATION_IND   = 0x82;
104    public static final int MESSAGE_TYPE_NOTIFYRESP_IND     = 0x83;
105    public static final int MESSAGE_TYPE_RETRIEVE_CONF      = 0x84;
106    public static final int MESSAGE_TYPE_ACKNOWLEDGE_IND    = 0x85;
107    public static final int MESSAGE_TYPE_DELIVERY_IND       = 0x86;
108    public static final int MESSAGE_TYPE_READ_REC_IND       = 0x87;
109    public static final int MESSAGE_TYPE_READ_ORIG_IND      = 0x88;
110    public static final int MESSAGE_TYPE_FORWARD_REQ        = 0x89;
111    public static final int MESSAGE_TYPE_FORWARD_CONF       = 0x8A;
112    public static final int MESSAGE_TYPE_MBOX_STORE_REQ     = 0x8B;
113    public static final int MESSAGE_TYPE_MBOX_STORE_CONF    = 0x8C;
114    public static final int MESSAGE_TYPE_MBOX_VIEW_REQ      = 0x8D;
115    public static final int MESSAGE_TYPE_MBOX_VIEW_CONF     = 0x8E;
116    public static final int MESSAGE_TYPE_MBOX_UPLOAD_REQ    = 0x8F;
117    public static final int MESSAGE_TYPE_MBOX_UPLOAD_CONF   = 0x90;
118    public static final int MESSAGE_TYPE_MBOX_DELETE_REQ    = 0x91;
119    public static final int MESSAGE_TYPE_MBOX_DELETE_CONF   = 0x92;
120    public static final int MESSAGE_TYPE_MBOX_DESCR         = 0x93;
121    public static final int MESSAGE_TYPE_DELETE_REQ         = 0x94;
122    public static final int MESSAGE_TYPE_DELETE_CONF        = 0x95;
123    public static final int MESSAGE_TYPE_CANCEL_REQ         = 0x96;
124    public static final int MESSAGE_TYPE_CANCEL_CONF        = 0x97;
125
126    /**
127     * X-Mms-Delivery-Report |
128     * X-Mms-Read-Report |
129     * X-Mms-Report-Allowed |
130     * X-Mms-Sender-Visibility |
131     * X-Mms-Store |
132     * X-Mms-Stored |
133     * X-Mms-Totals |
134     * X-Mms-Quotas |
135     * X-Mms-Distribution-Indicator |
136     * X-Mms-DRM-Content |
137     * X-Mms-Adaptation-Allowed |
138     * field types.
139     */
140    public static final int VALUE_YES                       = 0x80;
141    public static final int VALUE_NO                        = 0x81;
142
143    /**
144     * Delivery-Time |
145     * Expiry and Reply-Charging-Deadline |
146     * field type components.
147     */
148    public static final int VALUE_ABSOLUTE_TOKEN            = 0x80;
149    public static final int VALUE_RELATIVE_TOKEN            = 0x81;
150
151    /**
152     * X-Mms-MMS-Version field types.
153     */
154    public static final int MMS_VERSION_1_3                 = ((1 << 4) | 3);
155    public static final int MMS_VERSION_1_2                 = ((1 << 4) | 2);
156    public static final int MMS_VERSION_1_1                 = ((1 << 4) | 1);
157    public static final int MMS_VERSION_1_0                 = ((1 << 4) | 0);
158
159    // Current version is 1.2.
160    public static final int CURRENT_MMS_VERSION             = MMS_VERSION_1_2;
161
162    /**
163     * From field type components.
164     */
165    public static final int FROM_ADDRESS_PRESENT_TOKEN      = 0x80;
166    public static final int FROM_INSERT_ADDRESS_TOKEN       = 0x81;
167
168    public static final String FROM_ADDRESS_PRESENT_TOKEN_STR = "address-present-token";
169
170    public static final String FROM_INSERT_ADDRESS_TOKEN_STR = "insert-address-token";
171
172    /**
173     * X-Mms-Status Field.
174     */
175    public static final int STATUS_EXPIRED                  = 0x80;
176    public static final int STATUS_RETRIEVED                = 0x81;
177    public static final int STATUS_REJECTED                 = 0x82;
178    public static final int STATUS_DEFERRED                 = 0x83;
179    public static final int STATUS_UNRECOGNIZED             = 0x84;
180    public static final int STATUS_INDETERMINATE            = 0x85;
181    public static final int STATUS_FORWARDED                = 0x86;
182    public static final int STATUS_UNREACHABLE              = 0x87;
183
184    /**
185     * MM-Flags field type components.
186     */
187    public static final int MM_FLAGS_ADD_TOKEN              = 0x80;
188    public static final int MM_FLAGS_REMOVE_TOKEN           = 0x81;
189    public static final int MM_FLAGS_FILTER_TOKEN           = 0x82;
190
191    /**
192     * X-Mms-Message-Class field types.
193     */
194    public static final int MESSAGE_CLASS_PERSONAL          = 0x80;
195    public static final int MESSAGE_CLASS_ADVERTISEMENT     = 0x81;
196    public static final int MESSAGE_CLASS_INFORMATIONAL     = 0x82;
197    public static final int MESSAGE_CLASS_AUTO              = 0x83;
198
199    public static final String MESSAGE_CLASS_PERSONAL_STR = "personal";
200
201    public static final String MESSAGE_CLASS_ADVERTISEMENT_STR = "advertisement";
202
203    public static final String MESSAGE_CLASS_INFORMATIONAL_STR = "informational";
204
205    public static final String MESSAGE_CLASS_AUTO_STR = "auto";
206
207    /**
208     * X-Mms-Priority field types.
209     */
210    public static final int PRIORITY_LOW                    = 0x80;
211    public static final int PRIORITY_NORMAL                 = 0x81;
212    public static final int PRIORITY_HIGH                   = 0x82;
213
214    /**
215     * X-Mms-Response-Status field types.
216     */
217    public static final int RESPONSE_STATUS_OK                   = 0x80;
218    public static final int RESPONSE_STATUS_ERROR_UNSPECIFIED    = 0x81;
219    public static final int RESPONSE_STATUS_ERROR_SERVICE_DENIED = 0x82;
220
221    public static final int RESPONSE_STATUS_ERROR_MESSAGE_FORMAT_CORRUPT     = 0x83;
222    public static final int RESPONSE_STATUS_ERROR_SENDING_ADDRESS_UNRESOLVED = 0x84;
223
224    public static final int RESPONSE_STATUS_ERROR_MESSAGE_NOT_FOUND    = 0x85;
225    public static final int RESPONSE_STATUS_ERROR_NETWORK_PROBLEM      = 0x86;
226    public static final int RESPONSE_STATUS_ERROR_CONTENT_NOT_ACCEPTED = 0x87;
227    public static final int RESPONSE_STATUS_ERROR_UNSUPPORTED_MESSAGE  = 0x88;
228    public static final int RESPONSE_STATUS_ERROR_TRANSIENT_FAILURE    = 0xC0;
229
230    public static final int RESPONSE_STATUS_ERROR_TRANSIENT_SENDNG_ADDRESS_UNRESOLVED = 0xC1;
231    public static final int RESPONSE_STATUS_ERROR_TRANSIENT_MESSAGE_NOT_FOUND         = 0xC2;
232    public static final int RESPONSE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM           = 0xC3;
233    public static final int RESPONSE_STATUS_ERROR_TRANSIENT_PARTIAL_SUCCESS           = 0xC4;
234
235    public static final int RESPONSE_STATUS_ERROR_PERMANENT_FAILURE
236            = 0xE0;
237    public static final int RESPONSE_STATUS_ERROR_PERMANENT_SERVICE_DENIED
238            = 0xE1;
239    public static final int RESPONSE_STATUS_ERROR_PERMANENT_MESSAGE_FORMAT_CORRUPT
240            = 0xE2;
241    public static final int RESPONSE_STATUS_ERROR_PERMANENT_SENDING_ADDRESS_UNRESOLVED
242            = 0xE3;
243    public static final int RESPONSE_STATUS_ERROR_PERMANENT_MESSAGE_NOT_FOUND
244            = 0xE4;
245    public static final int RESPONSE_STATUS_ERROR_PERMANENT_CONTENT_NOT_ACCEPTED
246            = 0xE5;
247    public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_LIMITATIONS_NOT_MET
248            = 0xE6;
249    public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_REQUEST_NOT_ACCEPTED
250            = 0xE7;
251    public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_FORWARDING_DENIED
252            = 0xE8;
253    public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_NOT_SUPPORTED
254            = 0xE9;
255    public static final int RESPONSE_STATUS_ERROR_PERMANENT_ADDRESS_HIDING_NOT_SUPPORTED
256            = 0xEA;
257    public static final int RESPONSE_STATUS_ERROR_PERMANENT_LACK_OF_PREPAID
258            = 0xEB;
259    public static final int RESPONSE_STATUS_ERROR_PERMANENT_END
260            = 0xFF;
261
262    /**
263     *  X-Mms-Retrieve-Status field types.
264     */
265    public static final int RETRIEVE_STATUS_OK                                  = 0x80;
266    public static final int RETRIEVE_STATUS_ERROR_TRANSIENT_FAILURE             = 0xC0;
267    public static final int RETRIEVE_STATUS_ERROR_TRANSIENT_MESSAGE_NOT_FOUND   = 0xC1;
268    public static final int RETRIEVE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM     = 0xC2;
269    public static final int RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE             = 0xE0;
270    public static final int RETRIEVE_STATUS_ERROR_PERMANENT_SERVICE_DENIED      = 0xE1;
271    public static final int RETRIEVE_STATUS_ERROR_PERMANENT_MESSAGE_NOT_FOUND   = 0xE2;
272    public static final int RETRIEVE_STATUS_ERROR_PERMANENT_CONTENT_UNSUPPORTED = 0xE3;
273    public static final int RETRIEVE_STATUS_ERROR_END                           = 0xFF;
274
275    /**
276     * X-Mms-Sender-Visibility field types.
277     */
278    public static final int SENDER_VISIBILITY_HIDE          = 0x80;
279    public static final int SENDER_VISIBILITY_SHOW          = 0x81;
280
281    /**
282     * X-Mms-Read-Status field types.
283     */
284    public static final int READ_STATUS_READ                        = 0x80;
285    public static final int READ_STATUS__DELETED_WITHOUT_BEING_READ = 0x81;
286
287    /**
288     * X-Mms-Cancel-Status field types.
289     */
290    public static final int CANCEL_STATUS_REQUEST_SUCCESSFULLY_RECEIVED = 0x80;
291    public static final int CANCEL_STATUS_REQUEST_CORRUPTED             = 0x81;
292
293    /**
294     * X-Mms-Reply-Charging field types.
295     */
296    public static final int REPLY_CHARGING_REQUESTED           = 0x80;
297    public static final int REPLY_CHARGING_REQUESTED_TEXT_ONLY = 0x81;
298    public static final int REPLY_CHARGING_ACCEPTED            = 0x82;
299    public static final int REPLY_CHARGING_ACCEPTED_TEXT_ONLY  = 0x83;
300
301    /**
302     * X-Mms-MM-State field types.
303     */
304    public static final int MM_STATE_DRAFT                  = 0x80;
305    public static final int MM_STATE_SENT                   = 0x81;
306    public static final int MM_STATE_NEW                    = 0x82;
307    public static final int MM_STATE_RETRIEVED              = 0x83;
308    public static final int MM_STATE_FORWARDED              = 0x84;
309
310    /**
311     * X-Mms-Recommended-Retrieval-Mode field types.
312     */
313    public static final int RECOMMENDED_RETRIEVAL_MODE_MANUAL = 0x80;
314
315    /**
316     * X-Mms-Content-Class field types.
317     */
318    public static final int CONTENT_CLASS_TEXT              = 0x80;
319    public static final int CONTENT_CLASS_IMAGE_BASIC       = 0x81;
320    public static final int CONTENT_CLASS_IMAGE_RICH        = 0x82;
321    public static final int CONTENT_CLASS_VIDEO_BASIC       = 0x83;
322    public static final int CONTENT_CLASS_VIDEO_RICH        = 0x84;
323    public static final int CONTENT_CLASS_MEGAPIXEL         = 0x85;
324    public static final int CONTENT_CLASS_CONTENT_BASIC     = 0x86;
325    public static final int CONTENT_CLASS_CONTENT_RICH      = 0x87;
326
327    /**
328     * X-Mms-Store-Status field types.
329     */
330    public static final int STORE_STATUS_SUCCESS                                = 0x80;
331    public static final int STORE_STATUS_ERROR_TRANSIENT_FAILURE                = 0xC0;
332    public static final int STORE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM        = 0xC1;
333    public static final int STORE_STATUS_ERROR_PERMANENT_FAILURE                = 0xE0;
334    public static final int STORE_STATUS_ERROR_PERMANENT_SERVICE_DENIED         = 0xE1;
335    public static final int STORE_STATUS_ERROR_PERMANENT_MESSAGE_FORMAT_CORRUPT = 0xE2;
336    public static final int STORE_STATUS_ERROR_PERMANENT_MESSAGE_NOT_FOUND      = 0xE3;
337    public static final int STORE_STATUS_ERROR_PERMANENT_MMBOX_FULL             = 0xE4;
338    public static final int STORE_STATUS_ERROR_END                              = 0xFF;
339
340    /**
341     * The map contains the value of all headers.
342     */
343    private SparseArray<Object> mHeaderMap = null;
344
345    /**
346     * Constructor of PduHeaders.
347     */
348    public PduHeaders() {
349        mHeaderMap = new SparseArray<Object>();
350    }
351
352    /**
353     * Get octet value by header field.
354     *
355     * @param field the field
356     * @return the octet value of the pdu header
357     * with specified header field. Return 0 if
358     * the value is not set.
359     */
360    protected int getOctet(int field) {
361        Integer octet = (Integer) mHeaderMap.get(field);
362        if (null == octet) {
363            return 0;
364        }
365
366        return octet;
367    }
368
369    /**
370     * Set octet value to pdu header by header field.
371     *
372     * @param value the value
373     * @param field the field
374     * @throws InvalidHeaderValueException if the value is invalid.
375     */
376    protected void setOctet(int value, int field)
377            throws InvalidHeaderValueException {
378        /**
379         * Check whether this field can be set for specific
380         * header and check validity of the field.
381         */
382        switch (field) {
383            case REPORT_ALLOWED:
384            case ADAPTATION_ALLOWED:
385            case DELIVERY_REPORT:
386            case DRM_CONTENT:
387            case DISTRIBUTION_INDICATOR:
388            case QUOTAS:
389            case READ_REPORT:
390            case STORE:
391            case STORED:
392            case TOTALS:
393            case SENDER_VISIBILITY:
394                if ((VALUE_YES != value) && (VALUE_NO != value)) {
395                    // Invalid value.
396                    throw new InvalidHeaderValueException("Invalid Octet value!");
397                }
398                break;
399            case READ_STATUS:
400                if ((READ_STATUS_READ != value) &&
401                        (READ_STATUS__DELETED_WITHOUT_BEING_READ != value)) {
402                    // Invalid value.
403                    throw new InvalidHeaderValueException("Invalid Octet value!");
404                }
405                break;
406            case CANCEL_STATUS:
407                if ((CANCEL_STATUS_REQUEST_SUCCESSFULLY_RECEIVED != value) &&
408                        (CANCEL_STATUS_REQUEST_CORRUPTED != value)) {
409                    // Invalid value.
410                    throw new InvalidHeaderValueException("Invalid Octet value!");
411                }
412                break;
413            case PRIORITY:
414                if ((value < PRIORITY_LOW) || (value > PRIORITY_HIGH)) {
415                    // Invalid value.
416                    throw new InvalidHeaderValueException("Invalid Octet value!");
417                }
418                break;
419            case STATUS:
420                if ((value < STATUS_EXPIRED) || (value > STATUS_UNREACHABLE)) {
421                    // Invalid value.
422                    throw new InvalidHeaderValueException("Invalid Octet value!");
423                }
424                break;
425            case REPLY_CHARGING:
426                if ((value < REPLY_CHARGING_REQUESTED)
427                        || (value > REPLY_CHARGING_ACCEPTED_TEXT_ONLY)) {
428                    // Invalid value.
429                    throw new InvalidHeaderValueException("Invalid Octet value!");
430                }
431                break;
432            case MM_STATE:
433                if ((value < MM_STATE_DRAFT) || (value > MM_STATE_FORWARDED)) {
434                    // Invalid value.
435                    throw new InvalidHeaderValueException("Invalid Octet value!");
436                }
437                break;
438            case RECOMMENDED_RETRIEVAL_MODE:
439                if (RECOMMENDED_RETRIEVAL_MODE_MANUAL != value) {
440                    // Invalid value.
441                    throw new InvalidHeaderValueException("Invalid Octet value!");
442                }
443                break;
444            case CONTENT_CLASS:
445                if ((value < CONTENT_CLASS_TEXT)
446                        || (value > CONTENT_CLASS_CONTENT_RICH)) {
447                    // Invalid value.
448                    throw new InvalidHeaderValueException("Invalid Octet value!");
449                }
450                break;
451            case RETRIEVE_STATUS:
452                // According to oma-ts-mms-enc-v1_3, section 7.3.50, we modify the invalid value.
453                if ((value > RETRIEVE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM) &&
454                        (value < RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE)) {
455                    value = RETRIEVE_STATUS_ERROR_TRANSIENT_FAILURE;
456                } else if ((value > RETRIEVE_STATUS_ERROR_PERMANENT_CONTENT_UNSUPPORTED) &&
457                        (value <= RETRIEVE_STATUS_ERROR_END)) {
458                    value = RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE;
459                } else if ((value < RETRIEVE_STATUS_OK) ||
460                        ((value > RETRIEVE_STATUS_OK) &&
461                                (value < RETRIEVE_STATUS_ERROR_TRANSIENT_FAILURE)) ||
462                        (value > RETRIEVE_STATUS_ERROR_END)) {
463                    value = RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE;
464                }
465                break;
466            case STORE_STATUS:
467                // According to oma-ts-mms-enc-v1_3, section 7.3.58, we modify the invalid value.
468                if ((value > STORE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM) &&
469                        (value < STORE_STATUS_ERROR_PERMANENT_FAILURE)) {
470                    value = STORE_STATUS_ERROR_TRANSIENT_FAILURE;
471                } else if ((value > STORE_STATUS_ERROR_PERMANENT_MMBOX_FULL) &&
472                        (value <= STORE_STATUS_ERROR_END)) {
473                    value = STORE_STATUS_ERROR_PERMANENT_FAILURE;
474                } else if ((value < STORE_STATUS_SUCCESS) ||
475                        ((value > STORE_STATUS_SUCCESS) &&
476                                (value < STORE_STATUS_ERROR_TRANSIENT_FAILURE)) ||
477                        (value > STORE_STATUS_ERROR_END)) {
478                    value = STORE_STATUS_ERROR_PERMANENT_FAILURE;
479                }
480                break;
481            case RESPONSE_STATUS:
482                // According to oma-ts-mms-enc-v1_3, section 7.3.48, we modify the invalid value.
483                if ((value > RESPONSE_STATUS_ERROR_TRANSIENT_PARTIAL_SUCCESS) &&
484                        (value < RESPONSE_STATUS_ERROR_PERMANENT_FAILURE)) {
485                    value = RESPONSE_STATUS_ERROR_TRANSIENT_FAILURE;
486                } else if (((value > RESPONSE_STATUS_ERROR_PERMANENT_LACK_OF_PREPAID) &&
487                        (value <= RESPONSE_STATUS_ERROR_PERMANENT_END)) ||
488                        (value < RESPONSE_STATUS_OK) ||
489                        ((value > RESPONSE_STATUS_ERROR_UNSUPPORTED_MESSAGE) &&
490                                (value < RESPONSE_STATUS_ERROR_TRANSIENT_FAILURE)) ||
491                        (value > RESPONSE_STATUS_ERROR_PERMANENT_END)) {
492                    value = RESPONSE_STATUS_ERROR_PERMANENT_FAILURE;
493                }
494                break;
495            case MMS_VERSION:
496                if ((value < MMS_VERSION_1_0) || (value > MMS_VERSION_1_3)) {
497                    value = CURRENT_MMS_VERSION; // Current version is the default value.
498                }
499                break;
500            case MESSAGE_TYPE:
501                if ((value < MESSAGE_TYPE_SEND_REQ) || (value > MESSAGE_TYPE_CANCEL_CONF)) {
502                    // Invalid value.
503                    throw new InvalidHeaderValueException("Invalid Octet value!");
504                }
505                break;
506            default:
507                // This header value should not be Octect.
508                throw new RuntimeException("Invalid header field!");
509        }
510        mHeaderMap.put(field, value);
511    }
512
513    /**
514     * Get TextString value by header field.
515     *
516     * @param field the field
517     * @return the TextString value of the pdu header
518     * with specified header field
519     */
520    protected byte[] getTextString(int field) {
521        return (byte[]) mHeaderMap.get(field);
522    }
523
524    /**
525     * Set TextString value to pdu header by header field.
526     *
527     * @param value the value
528     * @param field the field
529     * @return the TextString value of the pdu header
530     * with specified header field
531     * @throws NullPointerException if the value is null.
532     */
533    protected void setTextString(byte[] value, int field) {
534        /**
535         * Check whether this field can be set for specific
536         * header and check validity of the field.
537         */
538        if (null == value) {
539            throw new NullPointerException();
540        }
541
542        switch (field) {
543            case TRANSACTION_ID:
544            case REPLY_CHARGING_ID:
545            case AUX_APPLIC_ID:
546            case APPLIC_ID:
547            case REPLY_APPLIC_ID:
548            case MESSAGE_ID:
549            case REPLACE_ID:
550            case CANCEL_ID:
551            case CONTENT_LOCATION:
552            case MESSAGE_CLASS:
553            case CONTENT_TYPE:
554                break;
555            default:
556                // This header value should not be Text-String.
557                throw new RuntimeException("Invalid header field!");
558        }
559        mHeaderMap.put(field, value);
560    }
561
562    /**
563     * Get EncodedStringValue value by header field.
564     *
565     * @param field the field
566     * @return the EncodedStringValue value of the pdu header
567     * with specified header field
568     */
569    protected EncodedStringValue getEncodedStringValue(int field) {
570        return (EncodedStringValue) mHeaderMap.get(field);
571    }
572
573    /**
574     * Get TO, CC or BCC header value.
575     *
576     * @param field the field
577     * @return the EncodeStringValue array of the pdu header
578     * with specified header field
579     */
580    protected EncodedStringValue[] getEncodedStringValues(int field) {
581        ArrayList<EncodedStringValue> list =
582                (ArrayList<EncodedStringValue>) mHeaderMap.get(field);
583        if (null == list) {
584            return null;
585        }
586        EncodedStringValue[] values = new EncodedStringValue[list.size()];
587        return list.toArray(values);
588    }
589
590    /**
591     * Set EncodedStringValue value to pdu header by header field.
592     *
593     * @param value the value
594     * @param field the field
595     * @return the EncodedStringValue value of the pdu header
596     * with specified header field
597     * @throws NullPointerException if the value is null.
598     */
599    protected void setEncodedStringValue(EncodedStringValue value, int field) {
600        /**
601         * Check whether this field can be set for specific
602         * header and check validity of the field.
603         */
604        if (null == value) {
605            throw new NullPointerException();
606        }
607
608        switch (field) {
609            case SUBJECT:
610            case RECOMMENDED_RETRIEVAL_MODE_TEXT:
611            case RETRIEVE_TEXT:
612            case STATUS_TEXT:
613            case STORE_STATUS_TEXT:
614            case RESPONSE_TEXT:
615            case FROM:
616            case PREVIOUSLY_SENT_BY:
617            case MM_FLAGS:
618                break;
619            default:
620                // This header value should not be Encoded-String-Value.
621                throw new RuntimeException("Invalid header field!");
622        }
623
624        mHeaderMap.put(field, value);
625    }
626
627    /**
628     * Set TO, CC or BCC header value.
629     *
630     * @param value the value
631     * @param field the field
632     * @return the EncodedStringValue value array of the pdu header
633     * with specified header field
634     * @throws NullPointerException if the value is null.
635     */
636    protected void setEncodedStringValues(EncodedStringValue[] value, int field) {
637        /**
638         * Check whether this field can be set for specific
639         * header and check validity of the field.
640         */
641        if (null == value) {
642            throw new NullPointerException();
643        }
644
645        switch (field) {
646            case BCC:
647            case CC:
648            case TO:
649                break;
650            default:
651                // This header value should not be Encoded-String-Value.
652                throw new RuntimeException("Invalid header field!");
653        }
654
655        ArrayList<EncodedStringValue> list = new ArrayList<EncodedStringValue>();
656        for (int i = 0; i < value.length; i++) {
657            list.add(value[i]);
658        }
659        mHeaderMap.put(field, list);
660    }
661
662    /**
663     * Append one EncodedStringValue to another.
664     *
665     * @param value the EncodedStringValue to append
666     * @param field the field
667     * @throws NullPointerException if the value is null.
668     */
669    protected void appendEncodedStringValue(EncodedStringValue value,
670            int field) {
671        if (null == value) {
672            throw new NullPointerException();
673        }
674
675        switch (field) {
676            case BCC:
677            case CC:
678            case TO:
679                break;
680            default:
681                throw new RuntimeException("Invalid header field!");
682        }
683
684        ArrayList<EncodedStringValue> list =
685                (ArrayList<EncodedStringValue>) mHeaderMap.get(field);
686        if (null == list) {
687            list = new ArrayList<EncodedStringValue>();
688        }
689        list.add(value);
690        mHeaderMap.put(field, list);
691    }
692
693    /**
694     * Get LongInteger value by header field.
695     *
696     * @param field the field
697     * @return the LongInteger value of the pdu header
698     * with specified header field. if return -1, the
699     * field is not existed in pdu header.
700     */
701    protected long getLongInteger(int field) {
702        Long longInteger = (Long) mHeaderMap.get(field);
703        if (null == longInteger) {
704            return -1;
705        }
706
707        return longInteger.longValue();
708    }
709
710    /**
711     * Set LongInteger value to pdu header by header field.
712     *
713     * @param value the value
714     * @param field the field
715     */
716    protected void setLongInteger(long value, int field) {
717        /**
718         * Check whether this field can be set for specific
719         * header and check validity of the field.
720         */
721        switch (field) {
722            case DATE:
723            case REPLY_CHARGING_SIZE:
724            case MESSAGE_SIZE:
725            case MESSAGE_COUNT:
726            case START:
727            case LIMIT:
728            case DELIVERY_TIME:
729            case EXPIRY:
730            case REPLY_CHARGING_DEADLINE:
731            case PREVIOUSLY_SENT_DATE:
732                break;
733            default:
734                // This header value should not be LongInteger.
735                throw new RuntimeException("Invalid header field!");
736        }
737        mHeaderMap.put(field, value);
738    }
739
740    public boolean hasHeader(int field) {
741        return mHeaderMap.get(field, null) != null;
742    }
743}
744