source: contrib/MailArchiver/sources/vendor/mime4j/apache-mime4j-0.7-SNAPSHOT-20110327.010440-17/core/src/main/java/org/apache/james/mime4j/util/MimeUtil.java @ 6785

Revision 6785, 13.0 KB checked in by rafaelraymundo, 12 years ago (diff)

Ticket #2946 - Liberado codigo do MailArchiver?. Documentação na subpasta DOCS.

Line 
1/****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one   *
3 * or more contributor license agreements.  See the NOTICE file *
4 * distributed with this work for additional information        *
5 * regarding copyright ownership.  The ASF licenses this file   *
6 * to you under the Apache License, Version 2.0 (the            *
7 * "License"); you may not use this file except in compliance   *
8 * with the License.  You may obtain a copy of the License at   *
9 *                                                              *
10 *   http://www.apache.org/licenses/LICENSE-2.0                 *
11 *                                                              *
12 * Unless required by applicable law or agreed to in writing,   *
13 * software distributed under the License is distributed on an  *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15 * KIND, either express or implied.  See the License for the    *
16 * specific language governing permissions and limitations      *
17 * under the License.                                           *
18 ****************************************************************/
19
20package org.apache.james.mime4j.util;
21
22import java.text.DateFormat;
23import java.text.FieldPosition;
24import java.text.SimpleDateFormat;
25import java.util.Date;
26import java.util.GregorianCalendar;
27import java.util.Locale;
28import java.util.Random;
29import java.util.TimeZone;
30
31/**
32 * A utility class, which provides some MIME related application logic.
33 */
34public final class MimeUtil {
35   
36    /**
37     * The <code>quoted-printable</code> encoding.
38     */
39    public static final String ENC_QUOTED_PRINTABLE = "quoted-printable";
40    /**
41     * The <code>binary</code> encoding.
42     */
43    public static final String ENC_BINARY = "binary";
44    /**
45     * The <code>base64</code> encoding.
46     */
47    public static final String ENC_BASE64 = "base64";
48    /**
49     * The <code>8bit</code> encoding.
50     */
51    public static final String ENC_8BIT = "8bit";
52    /**
53     * The <code>7bit</code> encoding.
54     */
55    public static final String ENC_7BIT = "7bit";
56
57    /** <code>MIME-Version</code> header name (lowercase) */
58    public static final String MIME_HEADER_MIME_VERSION = "mime-version";
59    /** <code>Content-ID</code> header name (lowercase) */
60    public static final String MIME_HEADER_CONTENT_ID = "content-id";
61    /** <code>Content-Description</code> header name (lowercase) */
62    public static final String MIME_HEADER_CONTENT_DESCRIPTION = "content-description";
63    /**
64     * <code>Content-Disposition</code> header name (lowercase).
65     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
66     */
67    public static final String MIME_HEADER_CONTENT_DISPOSITION = "content-disposition";
68    /**
69     * <code>Content-Disposition</code> filename parameter (lowercase).
70     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
71     */
72    public static final String PARAM_FILENAME = "filename";
73    /**
74     * <code>Content-Disposition</code> modification-date parameter (lowercase).
75     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
76     */
77    public static final String PARAM_MODIFICATION_DATE = "modification-date";
78    /**
79     * <code>Content-Disposition</code> creation-date parameter (lowercase).
80     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
81     */
82    public static final String PARAM_CREATION_DATE = "creation-date";
83    /**
84     * <code>Content-Disposition</code> read-date parameter (lowercase).
85     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
86     */
87    public static final String PARAM_READ_DATE = "read-date";
88    /**
89     * <code>Content-Disposition</code> size parameter (lowercase).
90     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
91     */
92    public static final String PARAM_SIZE = "size";
93    /**
94     * <code>Content-Langauge</code> header (lower case).
95     * See <a href='http://www.faqs.org/rfcs/rfc4646.html'>RFC4646</a>.
96     */
97    public static final String MIME_HEADER_LANGAUGE = "content-language";
98    /**
99     * <code>Content-Location</code> header (lower case).
100     * See <a href='http://www.faqs.org/rfcs/rfc2557.html'>RFC2557</a>.
101     */
102    public static final String MIME_HEADER_LOCATION = "content-location";
103    /**
104     * <code>Content-MD5</code> header (lower case).
105     * See <a href='http://www.faqs.org/rfcs/rfc1864.html'>RFC1864</a>.
106     */
107    public static final String MIME_HEADER_MD5 = "content-md5";
108
109    // used to create unique ids
110    private static final Random random = new Random();
111   
112    // used to create unique ids
113    private static int counter = 0;
114
115    private MimeUtil() {
116        // this is an utility class to be used statically.
117        // this constructor protect from instantiation.
118    }
119   
120    /**
121     * Returns, whether the given two MIME types are identical.
122     */
123    public static boolean isSameMimeType(String pType1, String pType2) {
124        return pType1 != null  &&  pType2 != null  &&  pType1.equalsIgnoreCase(pType2);
125    }
126
127    /**
128     * Returns true, if the given MIME type is that of a message.
129     */
130    public static boolean isMessage(String pMimeType) {
131        return pMimeType != null  &&  pMimeType.equalsIgnoreCase("message/rfc822");
132    }
133
134    /**
135     * Return true, if the given MIME type indicates a multipart entity.
136     */
137    public static boolean isMultipart(String pMimeType) {
138        return pMimeType != null  &&  pMimeType.toLowerCase().startsWith("multipart/");
139    }
140
141    /**
142     * Returns, whether the given transfer-encoding is "base64".
143     */
144    public static boolean isBase64Encoding(String pTransferEncoding) {
145        return ENC_BASE64.equalsIgnoreCase(pTransferEncoding);
146    }
147
148    /**
149     * Returns, whether the given transfer-encoding is "quoted-printable".
150     */
151    public static boolean isQuotedPrintableEncoded(String pTransferEncoding) {
152        return ENC_QUOTED_PRINTABLE.equalsIgnoreCase(pTransferEncoding);
153    }
154
155    /**
156     * Creates a new unique message boundary string that can be used as boundary
157     * parameter for the Content-Type header field of a message.
158     *
159     * @return a new unique message boundary string.
160     */
161    /* TODO - From rfc2045:
162     * Since the hyphen character ("-") may be represented as itself in the
163     * Quoted-Printable encoding, care must be taken, when encapsulating a
164     * quoted-printable encoded body inside one or more multipart entities,
165     * to ensure that the boundary delimiter does not appear anywhere in the
166     * encoded body.  (A good strategy is to choose a boundary that includes
167     * a character sequence such as "=_" which can never appear in a
168     * quoted-printable body.  See the definition of multipart messages in
169     * RFC 2046.)
170     */
171    public static String createUniqueBoundary() {
172        StringBuilder sb = new StringBuilder();
173        sb.append("-=Part.");
174        sb.append(Integer.toHexString(nextCounterValue()));
175        sb.append('.');
176        sb.append(Long.toHexString(random.nextLong()));
177        sb.append('.');
178        sb.append(Long.toHexString(System.currentTimeMillis()));
179        sb.append('.');
180        sb.append(Long.toHexString(random.nextLong()));
181        sb.append("=-");
182        return sb.toString();
183    }
184
185    /**
186     * Creates a new unique message identifier that can be used in message
187     * header field such as Message-ID or In-Reply-To. If the given host name is
188     * not <code>null</code> it will be used as suffix for the message ID
189     * (following an at sign).
190     *
191     * The resulting string is enclosed in angle brackets (&lt; and &gt;);
192     *
193     * @param hostName host name to be included in the message ID or
194     *            <code>null</code> if no host name should be included.
195     * @return a new unique message identifier.
196     */
197    public static String createUniqueMessageId(String hostName) {
198        StringBuilder sb = new StringBuilder("<Mime4j.");
199        sb.append(Integer.toHexString(nextCounterValue()));
200        sb.append('.');
201        sb.append(Long.toHexString(random.nextLong()));
202        sb.append('.');
203        sb.append(Long.toHexString(System.currentTimeMillis()));
204        if (hostName != null) {
205            sb.append('@');
206            sb.append(hostName);
207        }
208        sb.append('>');
209        return sb.toString();
210    }
211
212    /**
213     * Formats the specified date into a RFC 822 date-time string.
214     *
215     * @param date
216     *            date to be formatted into a string.
217     * @param zone
218     *            the time zone to use or <code>null</code> to use the default
219     *            time zone.
220     * @return the formatted time string.
221     */
222    public static String formatDate(Date date, TimeZone zone) {
223        DateFormat df = RFC822_DATE_FORMAT.get();
224
225        if (zone == null) {
226            df.setTimeZone(TimeZone.getDefault());
227        } else {
228            df.setTimeZone(zone);
229        }
230
231        return df.format(date);
232    }
233
234    /**
235     * Splits the specified string into a multiple-line representation with
236     * lines no longer than 76 characters (because the line might contain
237     * encoded words; see <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC
238     * 2047</a> section 2). If the string contains non-whitespace sequences
239     * longer than 76 characters a line break is inserted at the whitespace
240     * character following the sequence resulting in a line longer than 76
241     * characters.
242     *
243     * @param s
244     *            string to split.
245     * @param usedCharacters
246     *            number of characters already used up. Usually the number of
247     *            characters for header field name plus colon and one space.
248     * @return a multiple-line representation of the given string.
249     */
250    public static String fold(String s, int usedCharacters) {
251        final int maxCharacters = 76;
252
253        final int length = s.length();
254        if (usedCharacters + length <= maxCharacters)
255            return s;
256
257        StringBuilder sb = new StringBuilder();
258
259        int lastLineBreak = -usedCharacters;
260        int wspIdx = indexOfWsp(s, 0);
261        while (true) {
262            if (wspIdx == length) {
263                sb.append(s.substring(Math.max(0, lastLineBreak)));
264                return sb.toString();
265            }
266
267            int nextWspIdx = indexOfWsp(s, wspIdx + 1);
268
269            if (nextWspIdx - lastLineBreak > maxCharacters) {
270                sb.append(s.substring(Math.max(0, lastLineBreak), wspIdx));
271                sb.append("\r\n");
272                lastLineBreak = wspIdx;
273            }
274
275            wspIdx = nextWspIdx;
276        }
277    }
278
279    /**
280     * Unfold a multiple-line representation into a single line.
281     *
282     * @param s
283     *            string to unfold.
284     * @return unfolded string.
285     */
286    public static String unfold(String s) {
287        final int length = s.length();
288        for (int idx = 0; idx < length; idx++) {
289            char c = s.charAt(idx);
290            if (c == '\r' || c == '\n') {
291                return unfold0(s, idx);
292            }
293        }
294
295        return s;
296    }
297
298    private static String unfold0(String s, int crlfIdx) {
299        final int length = s.length();
300        StringBuilder sb = new StringBuilder(length);
301
302        if (crlfIdx > 0) {
303            sb.append(s.substring(0, crlfIdx));
304        }
305
306        for (int idx = crlfIdx + 1; idx < length; idx++) {
307            char c = s.charAt(idx);
308            if (c != '\r' && c != '\n') {
309                sb.append(c);
310            }
311        }
312
313        return sb.toString();
314    }
315
316    private static int indexOfWsp(String s, int fromIndex) {
317        final int len = s.length();
318        for (int index = fromIndex; index < len; index++) {
319            char c = s.charAt(index);
320            if (c == ' ' || c == '\t')
321                return index;
322        }
323        return len;
324    }
325
326    private static synchronized int nextCounterValue() {
327        return counter++;
328    }
329
330    private static final ThreadLocal<DateFormat> RFC822_DATE_FORMAT = new ThreadLocal<DateFormat>() {
331        @Override
332        protected DateFormat initialValue() {
333            return new Rfc822DateFormat();
334        }
335    };
336
337    private static final class Rfc822DateFormat extends SimpleDateFormat {
338        private static final long serialVersionUID = 1L;
339
340        public Rfc822DateFormat() {
341            super("EEE, d MMM yyyy HH:mm:ss ", Locale.US);
342        }
343
344        @Override
345        public StringBuffer format(Date date, StringBuffer toAppendTo,
346                FieldPosition pos) {
347            StringBuffer sb = super.format(date, toAppendTo, pos);
348
349            int zoneMillis = calendar.get(GregorianCalendar.ZONE_OFFSET);
350            int dstMillis = calendar.get(GregorianCalendar.DST_OFFSET);
351            int minutes = (zoneMillis + dstMillis) / 1000 / 60;
352
353            if (minutes < 0) {
354                sb.append('-');
355                minutes = -minutes;
356            } else {
357                sb.append('+');
358            }
359
360            sb.append(String.format("%02d%02d", minutes / 60, minutes % 60));
361
362            return sb;
363        }
364    }
365}
Note: See TracBrowser for help on using the repository browser.