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