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