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 
17 package com.android.emailcommon.internet;
18 
19 import com.android.emailcommon.mail.MessagingException;
20 
21 import java.io.BufferedWriter;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.OutputStreamWriter;
25 import java.util.ArrayList;
26 
27 public class MimeHeader {
28     /**
29      * Application specific header that contains Store specific information about an attachment.
30      * In IMAP this contains the IMAP BODYSTRUCTURE part id so that the ImapStore can later
31      * retrieve the attachment at will from the server.
32      * The info is recorded from this header on LocalStore.appendMessage and is put back
33      * into the MIME data by LocalStore.fetch.
34      */
35     public static final String HEADER_ANDROID_ATTACHMENT_STORE_DATA = "X-Android-Attachment-StoreData";
36 
37     public static final String HEADER_CONTENT_TYPE = "Content-Type";
38     public static final String HEADER_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
39     public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
40     public static final String HEADER_CONTENT_ID = "Content-ID";
41 
42     /**
43      * Fields that should be omitted when writing the header using writeTo()
44      */
45     private static final String[] WRITE_OMIT_FIELDS = {
46 //        HEADER_ANDROID_ATTACHMENT_DOWNLOADED,
47 //        HEADER_ANDROID_ATTACHMENT_ID,
48         HEADER_ANDROID_ATTACHMENT_STORE_DATA
49     };
50 
51     protected final ArrayList<Field> mFields = new ArrayList<Field>();
52 
clear()53     public void clear() {
54         mFields.clear();
55     }
56 
getFirstHeader(String name)57     public String getFirstHeader(String name) throws MessagingException {
58         String[] header = getHeader(name);
59         if (header == null) {
60             return null;
61         }
62         return header[0];
63     }
64 
addHeader(String name, String value)65     public void addHeader(String name, String value) throws MessagingException {
66         mFields.add(new Field(name, value));
67     }
68 
setHeader(String name, String value)69     public void setHeader(String name, String value) throws MessagingException {
70         if (name == null || value == null) {
71             return;
72         }
73         removeHeader(name);
74         addHeader(name, value);
75     }
76 
getHeader(String name)77     public String[] getHeader(String name) throws MessagingException {
78         ArrayList<String> values = new ArrayList<String>();
79         for (Field field : mFields) {
80             if (field.name.equalsIgnoreCase(name)) {
81                 values.add(field.value);
82             }
83         }
84         if (values.size() == 0) {
85             return null;
86         }
87         return values.toArray(new String[] {});
88     }
89 
removeHeader(String name)90     public void removeHeader(String name) throws MessagingException {
91         ArrayList<Field> removeFields = new ArrayList<Field>();
92         for (Field field : mFields) {
93             if (field.name.equalsIgnoreCase(name)) {
94                 removeFields.add(field);
95             }
96         }
97         mFields.removeAll(removeFields);
98     }
99 
100     /**
101      * Write header into String
102      *
103      * @return CR-NL separated header string except the headers in writeOmitFields
104      * null if header is empty
105      */
writeToString()106     public String writeToString() {
107         if (mFields.size() == 0) {
108             return null;
109         }
110         StringBuilder builder = new StringBuilder();
111         for (Field field : mFields) {
112             if (!arrayContains(WRITE_OMIT_FIELDS, field.name)) {
113                 builder.append(field.name + ": " + field.value + "\r\n");
114             }
115         }
116         return builder.toString();
117     }
118 
writeTo(OutputStream out)119     public void writeTo(OutputStream out) throws IOException, MessagingException {
120         BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
121         for (Field field : mFields) {
122             if (!arrayContains(WRITE_OMIT_FIELDS, field.name)) {
123                 writer.write(field.name + ": " + field.value + "\r\n");
124             }
125         }
126         writer.flush();
127     }
128 
129     private static class Field {
130         final String name;
131         final String value;
132 
Field(String name, String value)133         public Field(String name, String value) {
134             this.name = name;
135             this.value = value;
136         }
137 
138         @Override
toString()139         public String toString() {
140             return name + "=" + value;
141         }
142     }
143 
144     @Override
toString()145     public String toString() {
146         return (mFields == null) ? null : mFields.toString();
147     }
148 
arrayContains(Object[] a, Object o)149     public final static boolean arrayContains(Object[] a, Object o) {
150         int index = arrayIndex(a, o);
151         return (index >= 0);
152     }
153 
arrayIndex(Object[] a, Object o)154     public final static int arrayIndex(Object[] a, Object o) {
155         for (int i = 0, count = a.length; i < count; i++) {
156             if (a[i].equals(o)) {
157                 return i;
158             }
159         }
160         return -1;
161     }
162 }
163