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