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 */
16package com.android.voicemail.impl.mail.internet;
17
18import com.android.voicemail.impl.mail.MessagingException;
19import java.io.BufferedWriter;
20import java.io.IOException;
21import java.io.OutputStream;
22import java.io.OutputStreamWriter;
23import java.util.ArrayList;
24
25public 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
50  public void clear() {
51    fields.clear();
52  }
53
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
62  public void addHeader(String name, String value) throws MessagingException {
63    fields.add(new Field(name, value));
64  }
65
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
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
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   */
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
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
130    public Field(String name, String value) {
131      this.name = name;
132      this.value = value;
133    }
134
135    @Override
136    public String toString() {
137      return name + "=" + value;
138    }
139  }
140
141  @Override
142  public String toString() {
143    return (fields == null) ? null : fields.toString();
144  }
145
146  public static final boolean arrayContains(Object[] a, Object o) {
147    int index = arrayIndex(a, o);
148    return (index >= 0);
149  }
150
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