hashCode
58 | * method that preserves the general contract of
59 | * equals and hashCode - objects that
60 | * compare as equal must have the same hashCode.
61 | *
62 | * @param address Address object
63 | */
64 | @Override
65 | public abstract boolean equals(Object address);
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/java/org/simplejavamail/outlookmessageparser/OutlookMessageParserTest.java:
--------------------------------------------------------------------------------
1 | package org.simplejavamail.outlookmessageparser;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.simplejavamail.outlookmessageparser.model.OutlookMessage;
5 |
6 | import static org.assertj.core.api.Assertions.assertThat;
7 |
8 | public class OutlookMessageParserTest {
9 |
10 | private static final String HEADERS = "Date: Sun, 5 Mar 2017 12:11:31 +0100\n"
11 | + "Reply-To: lollypop-replyto byte to this output stream.
53 | * @param c the byte.
54 | * @exception IOException if an I/O error occurs.
55 | */
56 | @Override
57 | public void write(int c) throws IOException {
58 | c = c & 0xff; // Turn off the MSB.
59 | if (c == ' ')
60 | output('_', false);
61 | else if (c < 040 || c >= 0177 || specials.indexOf(c) >= 0)
62 | // Encoding required.
63 | output(c, true);
64 | else // No encoding required
65 | output(c, false);
66 | }
67 |
68 | /**
69 | * Returns the length of the encoded version of this byte array.
70 | *
71 | * @param b the byte array
72 | * @param encodingWord true if encoding words, false if encoding text
73 | * @return the length
74 | */
75 | public static int encodedLength(byte[] b, boolean encodingWord) {
76 | int len = 0;
77 | String specials = encodingWord ? WORD_SPECIALS: TEXT_SPECIALS;
78 | for (int i = 0; i < b.length; i++) {
79 | int c = b[i] & 0xff; // Mask off MSB
80 | if (c < 040 || c >= 0177 || specials.indexOf(c) >= 0)
81 | // needs encoding
82 | len += 3; // Q-encoding is 1 -> 3 conversion
83 | else
84 | len++;
85 | }
86 | return len;
87 | }
88 |
89 | /**** begin TEST program ***
90 | public static void main(String argv[]) throws Exception {
91 | FileInputStream infile = new FileInputStream(argv[0]);
92 | QEncoderStream encoder = new QEncoderStream(System.out);
93 | int c;
94 |
95 | while ((c = infile.read()) != -1)
96 | encoder.write(c);
97 | encoder.close();
98 | }
99 | *** end TEST program ***/
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/org/simplejavamail/com/sun/mail/util/PropUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License v. 2.0, which is available at
6 | * http://www.eclipse.org/legal/epl-2.0.
7 | *
8 | * This Source Code may also be made available under the following Secondary
9 | * Licenses when the conditions for such availability set forth in the
10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11 | * version 2 with the GNU Classpath Exception, which is available at
12 | * https://www.gnu.org/software/classpath/license.html.
13 | *
14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15 | */
16 |
17 | package org.simplejavamail.com.sun.mail.util;
18 |
19 | import java.util.*;
20 |
21 | /**
22 | * Utilities to make it easier to get property values.
23 | * Properties can be strings or type-specific value objects.
24 | *
25 | * @author Bill Shannon
26 | */
27 | public class PropUtil {
28 |
29 | // No one should instantiate this class.
30 | private PropUtil() {
31 | }
32 |
33 | /**
34 | * Get an integer valued property.
35 | *
36 | * @param props the properties
37 | * @param name the property name
38 | * @param def default value if property not found
39 | * @return the property value
40 | */
41 | public static int getIntProperty(Properties props, String name, int def) {
42 | return getInt(getProp(props, name), def);
43 | }
44 |
45 | /**
46 | * Get a boolean valued property.
47 | *
48 | * @param props the properties
49 | * @param name the property name
50 | * @param def default value if property not found
51 | * @return the property value
52 | */
53 | public static boolean getBooleanProperty(Properties props,
54 | String name, boolean def) {
55 | return getBoolean(getProp(props, name), def);
56 | }
57 |
58 | /**
59 | * Get a boolean valued System property.
60 | *
61 | * @param name the property name
62 | * @param def default value if property not found
63 | * @return the property value
64 | */
65 | public static boolean getBooleanSystemProperty(String name, boolean def) {
66 | try {
67 | return getBoolean(getProp(System.getProperties(), name), def);
68 | } catch (SecurityException sex) {
69 | // fall through...
70 | }
71 |
72 | /*
73 | * If we can't get the entire System Properties object because
74 | * of a SecurityException, just ask for the specific property.
75 | */
76 | try {
77 | String value = System.getProperty(name);
78 | if (value == null)
79 | return def;
80 | if (def)
81 | return !value.equalsIgnoreCase("false");
82 | else
83 | return value.equalsIgnoreCase("true");
84 | } catch (SecurityException sex) {
85 | return def;
86 | }
87 | }
88 |
89 | /**
90 | * Get the value of the specified property.
91 | * If the "get" method returns null, use the getProperty method,
92 | * which might cascade to a default Properties object.
93 | */
94 | private static Object getProp(Properties props, String name) {
95 | Object val = props.get(name);
96 | if (val != null)
97 | return val;
98 | else
99 | return props.getProperty(name);
100 | }
101 |
102 | /**
103 | * Interpret the value object as an integer,
104 | * returning def if unable.
105 | */
106 | private static int getInt(Object value, int def) {
107 | if (value == null)
108 | return def;
109 | if (value instanceof String) {
110 | try {
111 | String s = (String)value;
112 | if (s.startsWith("0x"))
113 | return Integer.parseInt(s.substring(2), 16);
114 | else
115 | return Integer.parseInt(s);
116 | } catch (NumberFormatException nfex) { }
117 | }
118 | if (value instanceof Integer)
119 | return ((Integer)value).intValue();
120 | return def;
121 | }
122 |
123 | /**
124 | * Interpret the value object as a boolean,
125 | * returning def if unable.
126 | */
127 | private static boolean getBoolean(Object value, boolean def) {
128 | if (value == null)
129 | return def;
130 | if (value instanceof String) {
131 | /*
132 | * If the default is true, only "false" turns it off.
133 | * If the default is false, only "true" turns it on.
134 | */
135 | if (def)
136 | return !((String)value).equalsIgnoreCase("false");
137 | else
138 | return ((String)value).equalsIgnoreCase("true");
139 | }
140 | if (value instanceof Boolean)
141 | return ((Boolean)value).booleanValue();
142 | return def;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/main/java/org/simplejavamail/jakarta/mail/MessagingException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License v. 2.0, which is available at
6 | * http://www.eclipse.org/legal/epl-2.0.
7 | *
8 | * This Source Code may also be made available under the following Secondary
9 | * Licenses when the conditions for such availability set forth in the
10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11 | * version 2 with the GNU Classpath Exception, which is available at
12 | * https://www.gnu.org/software/classpath/license.html.
13 | *
14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15 | */
16 |
17 | package org.simplejavamail.jakarta.mail;
18 |
19 | import java.lang.*;
20 |
21 | /**
22 | * The base class for all exceptions thrown by the Messaging classes
23 | *
24 | * @author John Mani
25 | * @author Bill Shannon
26 | */
27 |
28 | public class MessagingException extends Exception {
29 |
30 | /**
31 | * The next exception in the chain.
32 | *
33 | * @serial
34 | */
35 | private Exception next;
36 |
37 | private static final long serialVersionUID = -7569192289819959253L;
38 |
39 | /**
40 | * Constructs a MessagingException with no detail message.
41 | */
42 | public MessagingException() {
43 | super();
44 | initCause(null); // prevent anyone else from setting it
45 | }
46 |
47 | /**
48 | * Constructs a MessagingException with the specified detail message.
49 | *
50 | * @param s the detail message
51 | */
52 | public MessagingException(String s) {
53 | super(s);
54 | initCause(null); // prevent anyone else from setting it
55 | }
56 |
57 | /**
58 | * Constructs a MessagingException with the specified
59 | * Exception and detail message. The specified exception is chained
60 | * to this exception.
61 | *
62 | * @param s the detail message
63 | * @param e the embedded exception
64 | * @see #getNextException
65 | * @see #setNextException
66 | * @see #getCause
67 | */
68 | public MessagingException(String s, Exception e) {
69 | super(s);
70 | next = e;
71 | initCause(null); // prevent anyone else from setting it
72 | }
73 |
74 | /**
75 | * Get the next exception chained to this one. If the
76 | * next exception is a MessagingException, the chain
77 | * may extend further.
78 | *
79 | * @return next Exception, null if none.
80 | */
81 | public synchronized Exception getNextException() {
82 | return next;
83 | }
84 |
85 | /**
86 | * Overrides the getCause method of Throwable
87 | * to return the next exception in the chain of nested exceptions.
88 | *
89 | * @return next Exception, null if none.
90 | */
91 | @Override
92 | public synchronized Throwable getCause() {
93 | return next;
94 | }
95 |
96 | /**
97 | * Add an exception to the end of the chain. If the end
98 | * is not a MessagingException, this
99 | * exception cannot be added to the end.
100 | *
101 | * @param ex the new end of the Exception chain
102 | * @return true if this Exception
103 | * was added, false otherwise.
104 | */
105 | public synchronized boolean setNextException(Exception ex) {
106 | Exception theEnd = this;
107 | while (theEnd instanceof MessagingException &&
108 | ((MessagingException)theEnd).next != null) {
109 | theEnd = ((MessagingException)theEnd).next;
110 | }
111 | // If the end is a MessagingException, we can add this
112 | // exception to the chain.
113 | if (theEnd instanceof MessagingException) {
114 | ((MessagingException)theEnd).next = ex;
115 | return true;
116 | } else
117 | return false;
118 | }
119 |
120 | /**
121 | * Override toString method to provide information on
122 | * nested exceptions.
123 | */
124 | @Override
125 | public synchronized String toString() {
126 | String s = super.toString();
127 | Exception n = next;
128 | if (n == null)
129 | return s;
130 | StringBuilder sb = new StringBuilder(s == null ? "" : s);
131 | while (n != null) {
132 | sb.append(";\n nested exception is:\n\t");
133 | if (n instanceof MessagingException) {
134 | MessagingException mex = (MessagingException)n;
135 | sb.append(mex.superToString());
136 | n = mex.next;
137 | } else {
138 | sb.append(n.toString());
139 | n = null;
140 | }
141 | }
142 | return sb.toString();
143 | }
144 |
145 | /**
146 | * Return the "toString" information for this exception,
147 | * without any information on nested exceptions.
148 | */
149 | private final String superToString() {
150 | return super.toString();
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/properties-list1.txt:
--------------------------------------------------------------------------------
1 | This first partial list explains some of the properties we recognize or ignore
2 |
3 | (source: https://github.com/mvz/email-outlook-message-perl/blob/master/lib/Email/Outlook/Message/Base.pm)
4 |
5 | {
6 | # Envelope properties
7 | '0002' => "Alternate Recipient Allowed",
8 | '000B' => "Conversation Key",
9 | '0017' => "Importance", #TODO: Use this.
10 | '001A' => "Message Class",
11 | '0023' => "Originator Delivery Report Requested",
12 | '0026' => "Priority", #TODO: Use this.
13 | '0029' => "Read Receipt Requested", #TODO: Use this.
14 | '0036' => "Sensitivity", # As assessed by the Sender
15 | '003B' => "Sent Representing Search Key",
16 | '003D' => "Subject Prefix",
17 | '003F' => "Received By EntryId",
18 | '0040' => "Received By Name",
19 | # TODO: These two fields are part of the Sender field.
20 | '0041' => "Sent Representing EntryId",
21 | '0042' => "Sent Representing Name",
22 | '0043' => "Received Representing EntryId",
23 | '0044' => "Received Representing Name",
24 | '0046' => "Read Receipt EntryId",
25 | '0051' => "Received By Search Key",
26 | '0052' => "Received Representing Search Key",
27 | '0053' => "Read Receipt Search Key",
28 | # TODO: These two fields are part of the Sender field.
29 | '0064' => "Sent Representing Address Type",
30 | '0065' => "Sent Representing Email Address",
31 | '0070' => "Conversation Topic",
32 | '0071' => "Conversation Index",
33 | '0075' => "Received By Address Type",
34 | '0076' => "Received By Email Address",
35 | '0077' => "Received Representing Address Type",
36 | '0078' => "Received Representing Email Address",
37 | '007F' => "TNEF Correlation Key",
38 | # Recipient properties
39 | '0C15' => "Recipient Type",
40 | # Sender properties
41 | '0C19' => "Sender Entry Id",
42 | '0C1D' => "Sender Search Key",
43 | '0C1E' => "Sender Address Type",
44 | # Non-transmittable properties
45 | '0E02' => "Display Bcc",
46 | '0E06' => "Message Delivery Time",
47 | '0E07' => "Message Flags",
48 | '0E0A' => "Sent Mail EntryId",
49 | '0E0F' => "Responsibility",
50 | '0E1B' => "Has Attachments",
51 | '0E1D' => "Normalized Subject",
52 | '0E1F' => "RTF In Sync",
53 | '0E20' => "Attachment Size",
54 | '0E21' => "Attachment Number",
55 | '0E23' => "Internet Article Number",
56 | '0E27' => "Security Descriptor",
57 | '0E79' => "Trust Sender",
58 | '0FF4' => "Access",
59 | '0FF6' => "Instance Key",
60 | '0FF7' => "Access Level",
61 | '0FF9' => "Record Key",
62 | '0FFE' => "Object Type",
63 | '0FFF' => "EntryId",
64 | # Content properties
65 | '1006' => "RTF Sync Body CRC",
66 | '1007' => "RTF Sync Body Count",
67 | '1008' => "RTF Sync Body Tag",
68 | '1010' => "RTF Sync Prefix Count",
69 | '1011' => "RTF Sync Trailing Count",
70 | '1046' => "Original Message ID",
71 | '1080' => "Icon Index",
72 | '1081' => "Last Verb Executed",
73 | '1082' => "Last Verb Execution Time",
74 | '10F3' => "URL Component Name",
75 | '10F4' => "Attribute Hidden",
76 | '10F5' => "Attribute System",
77 | '10F6' => "Attribute Read Only",
78 | # 'Common property'
79 | '3000' => "Row Id",
80 | '3001' => "Display Name",
81 | '3002' => "Address Type",
82 | '3007' => "Creation Time",
83 | '3008' => "Last Modification Time",
84 | '300B' => "Search Key",
85 | # Message store info
86 | '340D' => "Store Support Mask",
87 | '3414' => "Message Store Provider",
88 | # Attachment properties
89 | '3702' => "Attachment Encoding",
90 | '3703' => "Attachment Extension",
91 | # TODO: Use the following to distinguish between nested msg and other OLE
92 | # stores.
93 | '3705' => "Attachment Method",
94 | '3709' => "Attachment Rendering", # Icon as WMF
95 | '370A' => "Tag identifying application that supplied the attachment",
96 | '370B' => "Attachment Rendering Position",
97 | '3713' => "Attachment Content Location", #TODO: Use this?
98 | # 3900 -- 39FF: 'Address book'
99 | '3900' => "Address Book Display Type",
100 | '39FF' => "Address Book 7 Bit Display Name",
101 | # Mail User Object
102 | '3A00' => "Account",
103 | '3A20' => "Transmittable Display Name",
104 | '3A40' => "Send Rich Info",
105 | '3FDE' => "Internet Code Page", # TODO: Perhaps use this.
106 | # 'Display table properties'
107 | '3FF8' => "Creator Name",
108 | '3FF9' => "Creator EntryId",
109 | '3FFA' => "Last Modifier Name",
110 | '3FFB' => "Last Modifier EntryId",
111 | '3FFD' => "Message Code Page",
112 | # 'Transport-defined envelope property'
113 | '4019' => "Sender Flags",
114 | '401A' => "Sent Representing Flags",
115 | '401B' => "Received By Flags",
116 | '401C' => "Received Representing Flags",
117 | '4029' => "Read Receipt Address Type",
118 | '402A' => "Read Receipt Email Address",
119 | '402B' => "Read Receipt Name",
120 | '5FF6' => "Recipient Display Name",
121 | '5FF7' => "Recipient EntryId",
122 | '5FFD' => "Recipient Flags",
123 | '5FFF' => "Recipient Track Status",
124 | # 'Provider-defined internal non-transmittable property'
125 | '664A' => "Has Named Properties",
126 | '6740' => "Sent Mail Server EntryId",
--------------------------------------------------------------------------------
/src/main/java/org/simplejavamail/outlookmessageparser/model/OutlookFileAttachment.java:
--------------------------------------------------------------------------------
1 | package org.simplejavamail.outlookmessageparser.model;
2 |
3 | /**
4 | * Implementation of the {@link OutlookAttachment} interface that represents a file attachment. It contains some useful information (as long as it is available
5 | * in the .msg file) like the attachment name, its size, etc.
6 | */
7 | public class OutlookFileAttachment implements OutlookAttachment {
8 |
9 | /**
10 | * The (by Outlook) shortened filename of the attachment.
11 | */
12 | private String filename;
13 | /**
14 | * The full filename of the attachment.
15 | */
16 | private String longFilename;
17 | /**
18 | * Mime type of the attachment
19 | */
20 | private String mimeTag;
21 | /**
22 | * CID of the attachment
23 | */
24 | private String contentId;
25 | /**
26 | * The extension of the attachment (may not be set).
27 | */
28 | private String extension;
29 | /**
30 | * The attachment itself as a byte array.
31 | */
32 | private byte[] data;
33 | /**
34 | * The size of the attachment.
35 | */
36 | private long size = -1;
37 |
38 | /**
39 | * Sets the property specified by the name parameter. Unknown names are ignored.
40 | */
41 | public void setProperty(final OutlookMessageProperty msgProp) {
42 | final String name = msgProp.getClazz();
43 | final Object value = msgProp.getData();
44 |
45 | if (name != null && value != null) {
46 | switch (name) {
47 | case "3701":
48 | setSize(msgProp.getSize());
49 | setData((byte[]) value);
50 | break;
51 | case "3704":
52 | setFilename((String) value);
53 | break;
54 | case "3707":
55 | setLongFilename((String) value);
56 | break;
57 | case "370e":
58 | setMimeTag((String) value);
59 | break;
60 | case "3703":
61 | setExtension((String) value);
62 | break;
63 | case "3712":
64 | setContentId((String) value);
65 | break;
66 | default:
67 | // property to ignore, for full list see properties-list.txt
68 | }
69 | }
70 | }
71 |
72 | public void checkSmimeFilename() {
73 | if (this.filename == null && this.mimeTag != null) {
74 | if (this.mimeTag.contains("multipart/signed")) {
75 | if (!this.mimeTag.contains("protocol") || this.mimeTag.contains("protocol=\"application/pkcs7-signature\"")) {
76 | this.filename = "smime.p7s";
77 | }
78 | }
79 | }
80 | }
81 |
82 | public void checkMimeTag() {
83 | if (this.mimeTag == null || this.mimeTag.length() == 0) {
84 | if (this.filename != null && this.filename.length() > 0) {
85 | this.mimeTag = MimeType.getContentType(this.filename);
86 | } else if (this.longFilename != null && this.longFilename.length() > 0) {
87 | this.mimeTag = MimeType.getContentType(this.longFilename);
88 | }
89 | }
90 | }
91 |
92 | @Override
93 | public String toString() {
94 | return (longFilename != null) ? longFilename : filename;
95 | }
96 |
97 | /**
98 | * Bean getter for {@link #contentId}.
99 | */
100 | @SuppressWarnings("ElementOnlyUsedFromTestCode")
101 | public String getContentId() {
102 | return contentId;
103 | }
104 |
105 | /**
106 | * Bean setter for {@link #contentId}.
107 | */
108 | void setContentId(final String contentId) {
109 | this.contentId = contentId;
110 | }
111 |
112 | /**
113 | * Bean getter for {@link #extension}.
114 | */
115 | @SuppressWarnings("ElementOnlyUsedFromTestCode")
116 | public String getExtension() {
117 | return extension;
118 | }
119 |
120 | /**
121 | * Bean setter for {@link #extension}.
122 | */
123 | void setExtension(final String extension) {
124 | this.extension = extension;
125 | }
126 |
127 | /**
128 | * Bean getter for {@link #filename}.
129 | */
130 | @SuppressWarnings("ElementOnlyUsedFromTestCode")
131 | public String getFilename() {
132 | return filename;
133 | }
134 |
135 | /**
136 | * Bean setter for {@link #filename}.
137 | */
138 | void setFilename(final String filename) {
139 | this.filename = filename;
140 | }
141 |
142 | /**
143 | * Bean getter for {@link #longFilename}.
144 | */
145 | public String getLongFilename() {
146 | return longFilename;
147 | }
148 |
149 | /**
150 | * Bean setter for {@link #longFilename}.
151 | */
152 | void setLongFilename(final String longFilename) {
153 | this.longFilename = longFilename;
154 | }
155 |
156 | /**
157 | * Bean getter for {@link #mimeTag}.
158 | */
159 | @SuppressWarnings("ElementOnlyUsedFromTestCode")
160 | public String getMimeTag() {
161 | return mimeTag;
162 | }
163 |
164 | /**
165 | * Bean setter for {@link #mimeTag}.
166 | */
167 | void setMimeTag(final String mimeTag) {
168 | this.mimeTag = mimeTag;
169 | }
170 |
171 | /**
172 | * Bean getter for {@link #data}.
173 | */
174 | @SuppressWarnings("ElementOnlyUsedFromTestCode")
175 | public byte[] getData() {
176 | return data.clone();
177 | }
178 |
179 | /**
180 | * Bean setter for {@link #data}.
181 | */
182 | void setData(final byte[] data) {
183 | this.data = data;
184 | }
185 |
186 | /**
187 | * Bean getter for {@link #size}.
188 | */
189 | public long getSize() {
190 | return size;
191 | }
192 |
193 | /**
194 | * Bean setter for {@link #size}.
195 | */
196 | void setSize(final long size) {
197 | this.size = size;
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/RELEASE.txt:
--------------------------------------------------------------------------------
1 | v1.14.0 - v1.14.1
2 |
3 | - 1.14.1 (08-06-2024): #64: [Bug] Parsing lists to HTML has double bullet points
4 | - 1.14.0 (25-05-2024): #80: RTF converted to HTML doesn't always detect charset properly
5 |
6 |
7 | v1.13.0 - v1.13.4
8 |
9 | - 1.13.4 (04-May-2024): bumped apache poi to 5.2.5 and managed commons-io to 2.16.1
10 | - 1.13.3 (04-May-2024): bumped angus-activation from 2.0.2 to 2.0.3
11 | - 1.13.2 (05-April-2024): #73: Don't overwrite existing address, but do retain X500 address if available
12 | - 1.13.1 (04-April-2024): #73: Further improve X500 addresses detection
13 | - 1.13.0 (18-January-2024): #71: Update to latest Jakarta+Angus dependencies
14 |
15 |
16 | v1.12.0 (10-December-2023)
17 |
18 | - #70: [Enhancement] ignore recipients with null-address
19 |
20 |
21 | v1.11.0 - v1.11.1
22 |
23 | - 1.11.1 (08-December-2023): #69: Enhancement: instead of ignoring them completely, only ignore for embedded images
24 | - 1.11.0 (08-December-2023): #69: Enhancement: ignore attachment with missing content
25 |
26 |
27 | v1.10.0 - v1.10.2
28 |
29 | - 1.10.2 (03-December-2023): #68: Improved heuristics for X500 Names
30 | - 1.10.1 (24-October-2023): #67: Fixed "Adding possibility to parse X500 Names"
31 | - 1.10.0 (24-October-2023): #67: Adding possibility to parse X500 Names (don't use this version)
32 |
33 |
34 | v1.9.0 - v1.9.7
35 |
36 | - 1.9.6 (18-July-2022): #57: Same, but now with Collection values to support duplicate headers
37 | - 1.9.5 (18-July-2022): #57: Headers should be more accessible, rather than just a big string of text
38 | - 1.9.x - a bunch of dependency fixes and tries apparently, my release train was not so smooth here, sorry
39 | - 1.9.0 (13-May-2021): #55: CVE issue: Update Apache POI and POI Scratchpad
40 |
41 |
42 | v1.8.0 - v1.8.1
43 |
44 | - v1.8.1 (31-January-2022): #41: OutlookMessage.getPropertyValue() should be public
45 | - v1.8.0 (31-January-2022): #52: Adjust dependencies and make Java 9+ friendly
46 | - v1.8.0 (31-January-2022): #45: Bump commons-io from 2.6 to 2.7
47 |
48 |
49 | v1.7.10 - v1.7.13 (17-November-2021)
50 |
51 | - #49: bugfix solved by improved charset handling
52 | - #46: bugfix Rare NPE case of producing empty nested outlook attachment when there should be no attachments
53 | - #43: bugfix getFromEmailFromHeaders cannot handle "quoted-name-with@at-sign"
54 | - some minor code improvements
55 |
56 |
57 | v1.7.9 (10-October-2020)
58 |
59 | - #28/#36: bugfix NumberFormatException on parsing .msg files
60 |
61 |
62 | v1.7.8 (4-August-2020)
63 |
64 | - #35: Clarify permission to publish project using Apache v2 license
65 |
66 |
67 | v1.7.0 - v1.7.7 (9-January-2020 - 17-July-2020)
68 |
69 | - v1.7.7 - #34: Wrong encoding for bodyHTML
70 | - v1.7.5 - #31: Bugfix for attachments with special characters in the name
71 | - v1.7.4 - #27: Same as 1.7.3, but now also for chinese senders
72 | - v1.7.3 - #27: When from name/address are not available (unsent emails), these fields are filled with binary garbage
73 | - v1.7.2 - #26: To email address is not handled properly when name is omitted
74 | - v1.7.1 - #25: NPE on ClientSubmitTime when original message has not been sent yet
75 | - v1.7.1 - #23: Bug: __nameid_ directory should not be parsed (and causing invalid HTML body)
76 | - v1.7.0 - #18: Upgrade Apache POI 3.9 -> 4.x
77 |
78 | Note: Apache POI requires minimum Java 8
79 |
80 |
81 | v1.6.0 (8-January-2020)
82 |
83 | - #21: Multiple TO recipients are not handles properly
84 |
85 |
86 | v1.5.0 (18-December-2019)
87 |
88 | - #20: CC and BCC recipients are not parsed properly
89 | - #19: Use real Outlook ContentId Attribute to resolve CID Attachments
90 |
91 |
92 | v1.4.1 (22-October-2019)
93 |
94 | - #17: Fixed encoding error for UTF-8's Windows legacy name (cp)65001
95 |
96 |
97 | v1.4.0 (13-October-2019)
98 |
99 | - #9: Replaced the RFC to HTML converter with a brand new RFC-compliant convert! (thanks to @fadeyev!)
100 |
101 |
102 | v1.3.0 (4-October-2019)
103 |
104 | - #14: Dependency problem with Java9+, missing Jakarta Activation Framework
105 | - #13: HTML start tags with extra space not handled correctly
106 | - #11: SimpleRTF2HTMLConverter inserts too many DataInputStream.readLine(). Expected use is to read
31 | * lines as String objects from an IMAP/SMTP/etc. stream.
32 | *
33 | * This class also supports UTF-8 data by calling the appropriate
34 | * constructor. Or, if the System property mail.mime.allowutf8
35 | * is set to true, an attempt will be made to interpret the data as UTF-8,
36 | * falling back to treating it as an 8-bit charset if that fails.
37 | * 38 | * LineInputStream is implemented as a FilterInputStream, so one can just 39 | * wrap it around any input stream and read bytes from this filter. 40 | * 41 | * @author John Mani 42 | * @author Bill Shannon 43 | */ 44 | 45 | public class LineInputStream extends FilterInputStream { 46 | 47 | private boolean allowutf8; 48 | private byte[] lineBuffer = null; // reusable byte buffer 49 | private CharsetDecoder decoder; 50 | 51 | private static boolean defaultutf8 = 52 | PropUtil.getBooleanSystemProperty("mail.mime.allowutf8", false); 53 | private static int MAX_INCR = 1024*1024; // 1MB 54 | 55 | public LineInputStream(InputStream in) { 56 | this(in, false); 57 | } 58 | 59 | /** 60 | * @param in the InputStream 61 | * @param allowutf8 allow UTF-8 characters? 62 | * @since JavaMail 1.6 63 | */ 64 | public LineInputStream(InputStream in, boolean allowutf8) { 65 | super(in); 66 | this.allowutf8 = allowutf8; 67 | if (!allowutf8 && defaultutf8) { 68 | decoder = StandardCharsets.UTF_8.newDecoder(); 69 | decoder.onMalformedInput(CodingErrorAction.REPORT); 70 | decoder.onUnmappableCharacter(CodingErrorAction.REPORT); 71 | } 72 | } 73 | 74 | /** 75 | * Read a line containing only ASCII characters from the input 76 | * stream. A line is terminated by a CR or NL or CR-NL sequence. 77 | * A common error is a CR-CR-NL sequence, which will also terminate 78 | * a line. 79 | * The line terminator is not returned as part of the returned 80 | * String. Returns null if no data is available.
81 | *
82 | * This class is similar to the deprecated
83 | *
24 | *
25 | * This class handles folded headers (ie headers with embedded
26 | * CRLF SPACE sequences). The folds are removed in the returned
27 | * tokens.
28 | *
29 | * @author John Mani
30 | * @author Bill Shannon
31 | */
32 |
33 | public class HeaderTokenizer {
34 |
35 | /**
36 | * The Token class represents tokens returned by the
37 | * HeaderTokenizer.
38 | */
39 | public static class Token {
40 |
41 | private int type;
42 | private String value;
43 |
44 | /**
45 | * Token type indicating an ATOM.
46 | */
47 | public static final int ATOM = -1;
48 |
49 | /**
50 | * Token type indicating a quoted string. The value
51 | * field contains the string without the quotes.
52 | */
53 | public static final int QUOTEDSTRING = -2;
54 |
55 | /**
56 | * Token type indicating a comment. The value field
57 | * contains the comment string without the comment
58 | * start and end symbols.
59 | */
60 | public static final int COMMENT = -3;
61 |
62 | /**
63 | * Token type indicating end of input.
64 | */
65 | public static final int EOF = -4;
66 |
67 | /**
68 | * Constructor.
69 | * @param type Token type
70 | * @param value Token value
71 | */
72 | public Token(int type, String value) {
73 | this.type = type;
74 | this.value = value;
75 | }
76 |
77 | /**
78 | * Return the type of the token. If the token represents a
79 | * delimiter or a control character, the type is that character
80 | * itself, converted to an integer. Otherwise, it's value is
81 | * one of the following:
82 | *
176 | *
177 | * Clients sit in a loop calling next() to parse successive
178 | * tokens until an EOF Token is returned.
179 | *
180 | * @return the next Token
181 | * @exception ParseException if the parse fails
182 | */
183 | public Token next() throws ParseException {
184 | return next('\0', false);
185 | }
186 |
187 | /**
188 | * Parses the next token from this String.
189 | * If endOfAtom is not NUL, the token extends until the
190 | * endOfAtom character is seen, or to the end of the header.
191 | * This method is useful when parsing headers that don't
192 | * obey the MIME specification, e.g., by failing to quote
193 | * parameter values that contain spaces.
194 | *
195 | * @param endOfAtom if not NUL, character marking end of token
196 | * @return the next Token
197 | * @exception ParseException if the parse fails
198 | * @since JavaMail 1.5
199 | */
200 | public Token next(char endOfAtom) throws ParseException {
201 | return next(endOfAtom, false);
202 | }
203 |
204 | /**
205 | * Parses the next token from this String.
206 | * endOfAtom is handled as above. If keepEscapes is true,
207 | * any backslash escapes are preserved in the returned string.
208 | * This method is useful when parsing headers that don't
209 | * obey the MIME specification, e.g., by failing to escape
210 | * backslashes in the filename parameter.
211 | *
212 | * @param endOfAtom if not NUL, character marking end of token
213 | * @param keepEscapes keep all backslashes in returned string?
214 | * @return the next Token
215 | * @exception ParseException if the parse fails
216 | * @since JavaMail 1.5
217 | */
218 | public Token next(char endOfAtom, boolean keepEscapes)
219 | throws ParseException {
220 | Token tk;
221 |
222 | currentPos = nextPos; // setup currentPos
223 | tk = getNext(endOfAtom, keepEscapes);
224 | nextPos = peekPos = currentPos; // update currentPos and peekPos
225 | return tk;
226 | }
227 |
228 | /**
229 | * Peek at the next token, without actually removing the token
230 | * from the parse stream. Invoking this method multiple times
231 | * will return successive tokens, until
233 | *
234 | * @return the next Token
235 | * @exception ParseException if the parse fails
236 | */
237 | public Token peek() throws ParseException {
238 | Token tk;
239 |
240 | currentPos = peekPos; // setup currentPos
241 | tk = getNext('\0', false);
242 | peekPos = currentPos; // update peekPos
243 | return tk;
244 | }
245 |
246 | /**
247 | * Return the rest of the Header.
248 | *
249 | * @return String rest of header. null is returned if we are
250 | * already at end of header
251 | */
252 | public String getRemainder() {
253 | if (nextPos >= string.length())
254 | return null;
255 | return string.substring(nextPos);
256 | }
257 |
258 | /*
259 | * Return the next token starting from 'currentPos'. After the
260 | * parse, 'currentPos' is updated to point to the start of the
261 | * next token.
262 | */
263 | private Token getNext(char endOfAtom, boolean keepEscapes)
264 | throws ParseException {
265 | // If we're already at end of string, return EOF
266 | if (currentPos >= maxPos)
267 | return EOFToken;
268 |
269 | // Skip white-space, position currentPos beyond the space
270 | if (skipWhiteSpace() == Token.EOF)
271 | return EOFToken;
272 |
273 | char c;
274 | int start;
275 | boolean filter = false;
276 |
277 | c = string.charAt(currentPos);
278 |
279 | // Check or Skip comments and position currentPos
280 | // beyond the comment
281 | while (c == '(') {
282 | // Parsing comment ..
283 | int nesting;
284 | for (start = ++currentPos, nesting = 1;
285 | nesting > 0 && currentPos < maxPos;
286 | currentPos++) {
287 | c = string.charAt(currentPos);
288 | if (c == '\\') { // Escape sequence
289 | currentPos++; // skip the escaped character
290 | filter = true;
291 | } else if (c == '\r')
292 | filter = true;
293 | else if (c == '(')
294 | nesting++;
295 | else if (c == ')')
296 | nesting--;
297 | }
298 | if (nesting != 0)
299 | throw new ParseException("Unbalanced comments");
300 |
301 | if (!skipComments) {
302 | // Return the comment, if we are asked to.
303 | // Note that the comment start & end markers are ignored.
304 | String s;
305 | if (filter) // need to go thru the token again.
306 | s = filterToken(string, start, currentPos-1, keepEscapes);
307 | else
308 | s = string.substring(start,currentPos-1);
309 |
310 | return new Token(Token.COMMENT, s);
311 | }
312 |
313 | // Skip any whitespace after the comment.
314 | if (skipWhiteSpace() == Token.EOF)
315 | return EOFToken;
316 | c = string.charAt(currentPos);
317 | }
318 |
319 | // Check for quoted-string and position currentPos
320 | // beyond the terminating quote
321 | if (c == '"') {
322 | currentPos++; // skip initial quote
323 | return collectString('"', keepEscapes);
324 | }
325 |
326 | // Check for SPECIAL or CTL
327 | if (c < 040 || c >= 0177 || delimiters.indexOf(c) >= 0) {
328 | if (endOfAtom > 0 && c != endOfAtom) {
329 | // not expecting a special character here,
330 | // pretend it's a quoted string
331 | return collectString(endOfAtom, keepEscapes);
332 | }
333 | currentPos++; // re-position currentPos
334 | char ch[] = new char[1];
335 | ch[0] = c;
336 | return new Token((int)c, new String(ch));
337 | }
338 |
339 | // Check for ATOM
340 | for (start = currentPos; currentPos < maxPos; currentPos++) {
341 | c = string.charAt(currentPos);
342 | // ATOM is delimited by either SPACE, CTL, "(", <">
343 | // or the specified SPECIALS
344 | if (c < 040 || c >= 0177 || c == '(' || c == ' ' ||
345 | c == '"' || delimiters.indexOf(c) >= 0) {
346 | if (endOfAtom > 0 && c != endOfAtom) {
347 | // not the expected atom after all;
348 | // back up and pretend it's a quoted string
349 | currentPos = start;
350 | return collectString(endOfAtom, keepEscapes);
351 | }
352 | break;
353 | }
354 | }
355 | return new Token(Token.ATOM, string.substring(start, currentPos));
356 | }
357 |
358 | private Token collectString(char eos, boolean keepEscapes)
359 | throws ParseException {
360 | int start;
361 | boolean filter = false;
362 | for (start = currentPos; currentPos < maxPos; currentPos++) {
363 | char c = string.charAt(currentPos);
364 | if (c == '\\') { // Escape sequence
365 | currentPos++;
366 | filter = true;
367 | } else if (c == '\r')
368 | filter = true;
369 | else if (c == eos) {
370 | currentPos++;
371 | String s;
372 |
373 | if (filter)
374 | s = filterToken(string, start, currentPos-1, keepEscapes);
375 | else
376 | s = string.substring(start, currentPos-1);
377 |
378 | if (c != '"') { // not a real quoted string
379 | s = trimWhiteSpace(s);
380 | currentPos--; // back up before the eos char
381 | }
382 |
383 | return new Token(Token.QUOTEDSTRING, s);
384 | }
385 | }
386 |
387 | // ran off the end of the string
388 |
389 | // if we're looking for a matching quote, that's an error
390 | if (eos == '"')
391 | throw new ParseException("Unbalanced quoted string");
392 |
393 | // otherwise, just return whatever's left
394 | String s;
395 | if (filter)
396 | s = filterToken(string, start, currentPos, keepEscapes);
397 | else
398 | s = string.substring(start, currentPos);
399 | s = trimWhiteSpace(s);
400 | return new Token(Token.QUOTEDSTRING, s);
401 | }
402 |
403 | // Skip SPACE, HT, CR and NL
404 | private int skipWhiteSpace() {
405 | char c;
406 | for (; currentPos < maxPos; currentPos++)
407 | if (((c = string.charAt(currentPos)) != ' ') &&
408 | (c != '\t') && (c != '\r') && (c != '\n'))
409 | return currentPos;
410 | return Token.EOF;
411 | }
412 |
413 | // Trim SPACE, HT, CR and NL from end of string
414 | private static String trimWhiteSpace(String s) {
415 | char c;
416 | int i;
417 | for (i = s.length() - 1; i >= 0; i--) {
418 | if (((c = s.charAt(i)) != ' ') &&
419 | (c != '\t') && (c != '\r') && (c != '\n'))
420 | break;
421 | }
422 | if (i <= 0)
423 | return "";
424 | else
425 | return s.substring(0, i + 1);
426 | }
427 |
428 | /* Process escape sequences and embedded LWSPs from a comment or
429 | * quoted string.
430 | */
431 | private static String filterToken(String s, int start, int end,
432 | boolean keepEscapes) {
433 | StringBuilder sb = new StringBuilder();
434 | char c;
435 | boolean gotEscape = false;
436 | boolean gotCR = false;
437 |
438 | for (int i = start; i < end; i++) {
439 | c = s.charAt(i);
440 | if (c == '\n' && gotCR) {
441 | // This LF is part of an unescaped
442 | // CRLF sequence (i.e, LWSP). Skip it.
443 | gotCR = false;
444 | continue;
445 | }
446 |
447 | gotCR = false;
448 | if (!gotEscape) {
449 | // Previous character was NOT '\'
450 | if (c == '\\') // skip this character
451 | gotEscape = true;
452 | else if (c == '\r') // skip this character
453 | gotCR = true;
454 | else // append this character
455 | sb.append(c);
456 | } else {
457 | // Previous character was '\'. So no need to
458 | // bother with any special processing, just
459 | // append this character. If keepEscapes is
460 | // set, keep the backslash. IE6 fails to escape
461 | // backslashes in quoted strings in HTTP headers,
462 | // e.g., in the filename parameter.
463 | if (keepEscapes)
464 | sb.append('\\');
465 | sb.append(c);
466 | gotEscape = false;
467 | }
468 | }
469 | return sb.toString();
470 | }
471 | }
472 |
--------------------------------------------------------------------------------
/properties-list2.txt:
--------------------------------------------------------------------------------
1 | This second partial list explains some of the properties we recognize or ignore
2 |
3 | (source: https://github.com/JoshData/convert-outlook-msg-file/blob/master/outlookmsgfile.py)
4 |
5 | # from mapitags.h via https://github.com/mvz/email-outlook-message-perl/blob/master/mapitags.h
6 | property_tags = {
7 | 0x01: ('ACKNOWLEDGEMENT_MODE', 'I4'),
8 | 0x02: ('ALTERNATE_RECIPIENT_ALLOWED', 'BOOLEAN'),
9 | 0x03: ('AUTHORIZING_USERS', 'BINARY'),
10 | # Comment on an automatically forwarded message
11 | 0x04: ('AUTO_FORWARD_COMMENT', 'STRING'),
12 | # Whether a message has been automatically forwarded
13 | 0x05: ('AUTO_FORWARDED', 'BOOLEAN'),
14 | 0x06: ('CONTENT_CONFIDENTIALITY_ALGORITHM_ID', 'BINARY'),
15 | 0x07: ('CONTENT_CORRELATOR', 'BINARY'),
16 | 0x08: ('CONTENT_IDENTIFIER', 'STRING'),
17 | # MIME content length
18 | 0x09: ('CONTENT_LENGTH', 'I4'),
19 | 0x0A: ('CONTENT_RETURN_REQUESTED', 'BOOLEAN'),
20 | 0x0B: ('CONVERSATION_KEY', 'BINARY'),
21 | 0x0C: ('CONVERSION_EITS', 'BINARY'),
22 | 0x0D: ('CONVERSION_WITH_LOSS_PROHIBITED', 'BOOLEAN'),
23 | 0x0E: ('CONVERTED_EITS', 'BINARY'),
24 | # Time to deliver for delayed delivery messages
25 | 0x0F: ('DEFERRED_DELIVERY_TIME', 'SYSTIME'),
26 | 0x10: ('DELIVER_TIME', 'SYSTIME'),
27 | # Reason a message was discarded
28 | 0x11: ('DISCARD_REASON', 'I4'),
29 | 0x12: ('DISCLOSURE_OF_RECIPIENTS', 'BOOLEAN'),
30 | 0x13: ('DL_EXPANSION_HISTORY', 'BINARY'),
31 | 0x14: ('DL_EXPANSION_PROHIBITED', 'BOOLEAN'),
32 | 0x15: ('EXPIRY_TIME', 'SYSTIME'),
33 | 0x16: ('IMPLICIT_CONVERSION_PROHIBITED', 'BOOLEAN'),
34 | # Message importance
35 | 0x17: ('IMPORTANCE', 'I4'),
36 | 0x18: ('IPM_ID', 'BINARY'),
37 | 0x19: ('LATEST_DELIVERY_TIME', 'SYSTIME'),
38 | 0x1A: ('MESSAGE_CLASS', 'STRING'),
39 | 0x1B: ('MESSAGE_DELIVERY_ID', 'BINARY'),
40 | 0x1E: ('MESSAGE_SECURITY_LABEL', 'BINARY'),
41 | 0x1F: ('OBSOLETED_IPMS', 'BINARY'),
42 | # Person a message was originally for
43 | 0x20: ('ORIGINALLY_INTENDED_RECIPIENT_NAME', 'BINARY'),
44 | 0x21: ('ORIGINAL_EITS', 'BINARY'),
45 | 0x22: ('ORIGINATOR_CERTIFICATE', 'BINARY'),
46 | 0x23: ('ORIGINATOR_DELIVERY_REPORT_REQUESTED', 'BOOLEAN'),
47 | # Address of the message sender
48 | 0x24: ('ORIGINATOR_RETURN_ADDRESS', 'BINARY'),
49 | 0x25: ('PARENT_KEY', 'BINARY'),
50 | 0x26: ('PRIORITY', 'I4'),
51 | 0x27: ('ORIGIN_CHECK', 'BINARY'),
52 | 0x28: ('PROOF_OF_SUBMISSION_REQUESTED', 'BOOLEAN'),
53 | # Whether a read receipt is desired
54 | 0x29: ('READ_RECEIPT_REQUESTED', 'BOOLEAN'),
55 | # Time a message was received
56 | 0x2A: ('RECEIPT_TIME', 'SYSTIME'),
57 | 0x2B: ('RECIPIENT_REASSIGNMENT_PROHIBITED', 'BOOLEAN'),
58 | 0x2C: ('REDIRECTION_HISTORY', 'BINARY'),
59 | 0x2D: ('RELATED_IPMS', 'BINARY'),
60 | # Sensitivity of the original message
61 | 0x2E: ('ORIGINAL_SENSITIVITY', 'I4'),
62 | 0x2F: ('LANGUAGES', 'STRING'),
63 | 0x30: ('REPLY_TIME', 'SYSTIME'),
64 | 0x31: ('REPORT_TAG', 'BINARY'),
65 | 0x32: ('REPORT_TIME', 'SYSTIME'),
66 | 0x33: ('RETURNED_IPM', 'BOOLEAN'),
67 | 0x34: ('SECURITY', 'I4'),
68 | 0x35: ('INCOMPLETE_COPY', 'BOOLEAN'),
69 | 0x36: ('SENSITIVITY', 'I4'),
70 | # The message subject
71 | 0x37: ('SUBJECT', 'STRING'),
72 | 0x38: ('SUBJECT_IPM', 'BINARY'),
73 | 0x39: ('CLIENT_SUBMIT_TIME', 'SYSTIME'),
74 | 0x3A: ('REPORT_NAME', 'STRING'),
75 | 0x3B: ('SENT_REPRESENTING_SEARCH_KEY', 'BINARY'),
76 | 0x3C: ('X400_CONTENT_TYPE', 'BINARY'),
77 | 0x3D: ('SUBJECT_PREFIX', 'STRING'),
78 | 0x3E: ('NON_RECEIPT_REASON', 'I4'),
79 | 0x3F: ('RECEIVED_BY_ENTRYID', 'BINARY'),
80 | # Received by: entry
81 | 0x40: ('RECEIVED_BY_NAME', 'STRING'),
82 | 0x41: ('SENT_REPRESENTING_ENTRYID', 'BINARY'),
83 | 0x42: ('SENT_REPRESENTING_NAME', 'STRING'),
84 | 0x43: ('RCVD_REPRESENTING_ENTRYID', 'BINARY'),
85 | 0x44: ('RCVD_REPRESENTING_NAME', 'STRING'),
86 | 0x45: ('REPORT_ENTRYID', 'BINARY'),
87 | 0x46: ('READ_RECEIPT_ENTRYID', 'BINARY'),
88 | 0x47: ('MESSAGE_SUBMISSION_ID', 'BINARY'),
89 | 0x48: ('PROVIDER_SUBMIT_TIME', 'SYSTIME'),
90 | # Subject of the original message
91 | 0x49: ('ORIGINAL_SUBJECT', 'STRING'),
92 | 0x4A: ('DISC_VAL', 'BOOLEAN'),
93 | 0x4B: ('ORIG_MESSAGE_CLASS', 'STRING'),
94 | 0x4C: ('ORIGINAL_AUTHOR_ENTRYID', 'BINARY'),
95 | # Author of the original message
96 | 0x4D: ('ORIGINAL_AUTHOR_NAME', 'STRING'),
97 | # Time the original message was submitted
98 | 0x4E: ('ORIGINAL_SUBMIT_TIME', 'SYSTIME'),
99 | 0x4F: ('REPLY_RECIPIENT_ENTRIES', 'BINARY'),
100 | 0x50: ('REPLY_RECIPIENT_NAMES', 'STRING'),
101 | 0x51: ('RECEIVED_BY_SEARCH_KEY', 'BINARY'),
102 | 0x52: ('RCVD_REPRESENTING_SEARCH_KEY', 'BINARY'),
103 | 0x53: ('READ_RECEIPT_SEARCH_KEY', 'BINARY'),
104 | 0x54: ('REPORT_SEARCH_KEY', 'BINARY'),
105 | 0x55: ('ORIGINAL_DELIVERY_TIME', 'SYSTIME'),
106 | 0x56: ('ORIGINAL_AUTHOR_SEARCH_KEY', 'BINARY'),
107 | 0x57: ('MESSAGE_TO_ME', 'BOOLEAN'),
108 | 0x58: ('MESSAGE_CC_ME', 'BOOLEAN'),
109 | 0x59: ('MESSAGE_RECIP_ME', 'BOOLEAN'),
110 | # Sender of the original message
111 | 0x5A: ('ORIGINAL_SENDER_NAME', 'STRING'),
112 | 0x5B: ('ORIGINAL_SENDER_ENTRYID', 'BINARY'),
113 | 0x5C: ('ORIGINAL_SENDER_SEARCH_KEY', 'BINARY'),
114 | 0x5D: ('ORIGINAL_SENT_REPRESENTING_NAME', 'STRING'),
115 | 0x5E: ('ORIGINAL_SENT_REPRESENTING_ENTRYID', 'BINARY'),
116 | 0x5F: ('ORIGINAL_SENT_REPRESENTING_SEARCH_KEY', 'BINARY'),
117 | 0x60: ('START_DATE', 'SYSTIME'),
118 | 0x61: ('END_DATE', 'SYSTIME'),
119 | 0x62: ('OWNER_APPT_ID', 'I4'),
120 | # Whether a response to the message is desired
121 | 0x63: ('RESPONSE_REQUESTED', 'BOOLEAN'),
122 | 0x64: ('SENT_REPRESENTING_ADDRTYPE', 'STRING'),
123 | 0x65: ('SENT_REPRESENTING_EMAIL_ADDRESS', 'STRING'),
124 | 0x66: ('ORIGINAL_SENDER_ADDRTYPE', 'STRING'),
125 | # Email of the original message sender
126 | 0x67: ('ORIGINAL_SENDER_EMAIL_ADDRESS', 'STRING'),
127 | 0x68: ('ORIGINAL_SENT_REPRESENTING_ADDRTYPE', 'STRING'),
128 | 0x69: ('ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS', 'STRING'),
129 | 0x70: ('CONVERSATION_TOPIC', 'STRING'),
130 | 0x71: ('CONVERSATION_INDEX', 'BINARY'),
131 | 0x72: ('ORIGINAL_DISPLAY_BCC', 'STRING'),
132 | 0x73: ('ORIGINAL_DISPLAY_CC', 'STRING'),
133 | 0x74: ('ORIGINAL_DISPLAY_TO', 'STRING'),
134 | 0x75: ('RECEIVED_BY_ADDRTYPE', 'STRING'),
135 | 0x76: ('RECEIVED_BY_EMAIL_ADDRESS', 'STRING'),
136 | 0x77: ('RCVD_REPRESENTING_ADDRTYPE', 'STRING'),
137 | 0x78: ('RCVD_REPRESENTING_EMAIL_ADDRESS', 'STRING'),
138 | 0x79: ('ORIGINAL_AUTHOR_ADDRTYPE', 'STRING'),
139 | 0x7A: ('ORIGINAL_AUTHOR_EMAIL_ADDRESS', 'STRING'),
140 | 0x7B: ('ORIGINALLY_INTENDED_RECIP_ADDRTYPE', 'STRING'),
141 | 0x7C: ('ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS', 'STRING'),
142 | 0x7D: ('TRANSPORT_MESSAGE_HEADERS', 'STRING'),
143 | 0x7E: ('DELEGATION', 'BINARY'),
144 | 0x7F: ('TNEF_CORRELATION_KEY', 'BINARY'),
145 | 0x1000: ('BODY', 'STRING'),
146 | 0x1001: ('REPORT_TEXT', 'STRING'),
147 | 0x1002: ('ORIGINATOR_AND_DL_EXPANSION_HISTORY', 'BINARY'),
148 | 0x1003: ('REPORTING_DL_NAME', 'BINARY'),
149 | 0x1004: ('REPORTING_MTA_CERTIFICATE', 'BINARY'),
150 | 0x1006: ('RTF_SYNC_BODY_CRC', 'I4'),
151 | 0x1007: ('RTF_SYNC_BODY_COUNT', 'I4'),
152 | 0x1008: ('RTF_SYNC_BODY_TAG', 'STRING'),
153 | 0x1009: ('RTF_COMPRESSED', 'BINARY'),
154 | 0x1010: ('RTF_SYNC_PREFIX_COUNT', 'I4'),
155 | 0x1011: ('RTF_SYNC_TRAILING_COUNT', 'I4'),
156 | 0x1012: ('ORIGINALLY_INTENDED_RECIP_ENTRYID', 'BINARY'),
157 | 0x0C00: ('CONTENT_INTEGRITY_CHECK', 'BINARY'),
158 | 0x0C01: ('EXPLICIT_CONVERSION', 'I4'),
159 | 0x0C02: ('IPM_RETURN_REQUESTED', 'BOOLEAN'),
160 | 0x0C03: ('MESSAGE_TOKEN', 'BINARY'),
161 | 0x0C04: ('NDR_REASON_CODE', 'I4'),
162 | 0x0C05: ('NDR_DIAG_CODE', 'I4'),
163 | 0x0C06: ('NON_RECEIPT_NOTIFICATION_REQUESTED', 'BOOLEAN'),
164 | 0x0C07: ('DELIVERY_POINT', 'I4'),
165 | 0x0C08: ('ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED', 'BOOLEAN'),
166 | 0x0C09: ('ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT', 'BINARY'),
167 | 0x0C0A: ('PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY', 'BOOLEAN'),
168 | 0x0C0B: ('PHYSICAL_DELIVERY_MODE', 'I4'),
169 | 0x0C0C: ('PHYSICAL_DELIVERY_REPORT_REQUEST', 'I4'),
170 | 0x0C0D: ('PHYSICAL_FORWARDING_ADDRESS', 'BINARY'),
171 | 0x0C0E: ('PHYSICAL_FORWARDING_ADDRESS_REQUESTED', 'BOOLEAN'),
172 | 0x0C0F: ('PHYSICAL_FORWARDING_PROHIBITED', 'BOOLEAN'),
173 | 0x0C10: ('PHYSICAL_RENDITION_ATTRIBUTES', 'BINARY'),
174 | 0x0C11: ('PROOF_OF_DELIVERY', 'BINARY'),
175 | 0x0C12: ('PROOF_OF_DELIVERY_REQUESTED', 'BOOLEAN'),
176 | 0x0C13: ('RECIPIENT_CERTIFICATE', 'BINARY'),
177 | 0x0C14: ('RECIPIENT_NUMBER_FOR_ADVICE', 'STRING'),
178 | 0x0C15: ('RECIPIENT_TYPE', 'I4'),
179 | 0x0C16: ('REGISTERED_MAIL_TYPE', 'I4'),
180 | 0x0C17: ('REPLY_REQUESTED', 'BOOLEAN'),
181 | 0x0C18: ('REQUESTED_DELIVERY_METHOD', 'I4'),
182 | 0x0C19: ('SENDER_ENTRYID', 'BINARY'),
183 | 0x0C1A: ('SENDER_NAME', 'STRING'),
184 | 0x0C1B: ('SUPPLEMENTARY_INFO', 'STRING'),
185 | 0x0C1C: ('TYPE_OF_MTS_USER', 'I4'),
186 | 0x0C1D: ('SENDER_SEARCH_KEY', 'BINARY'),
187 | 0x0C1E: ('SENDER_ADDRTYPE', 'STRING'),
188 | 0x0C1F: ('SENDER_EMAIL_ADDRESS', 'STRING'),
189 | 0x0E00: ('CURRENT_VERSION', 'I8'),
190 | 0x0E01: ('DELETE_AFTER_SUBMIT', 'BOOLEAN'),
191 | 0x0E02: ('DISPLAY_BCC', 'STRING'),
192 | 0x0E03: ('DISPLAY_CC', 'STRING'),
193 | 0x0E04: ('DISPLAY_TO', 'STRING'),
194 | 0x0E05: ('PARENT_DISPLAY', 'STRING'),
195 | 0x0E06: ('MESSAGE_DELIVERY_TIME', 'SYSTIME'),
196 | 0x0E07: ('MESSAGE_FLAGS', 'I4'),
197 | 0x0E08: ('MESSAGE_SIZE', 'I4'),
198 | 0x0E09: ('PARENT_ENTRYID', 'BINARY'),
199 | 0x0E0A: ('SENTMAIL_ENTRYID', 'BINARY'),
200 | 0x0E0C: ('CORRELATE', 'BOOLEAN'),
201 | 0x0E0D: ('CORRELATE_MTSID', 'BINARY'),
202 | 0x0E0E: ('DISCRETE_VALUES', 'BOOLEAN'),
203 | 0x0E0F: ('RESPONSIBILITY', 'BOOLEAN'),
204 | 0x0E10: ('SPOOLER_STATUS', 'I4'),
205 | 0x0E11: ('TRANSPORT_STATUS', 'I4'),
206 | 0x0E12: ('MESSAGE_RECIPIENTS', 'OBJECT'),
207 | 0x0E13: ('MESSAGE_ATTACHMENTS', 'OBJECT'),
208 | 0x0E14: ('SUBMIT_FLAGS', 'I4'),
209 | 0x0E15: ('RECIPIENT_STATUS', 'I4'),
210 | 0x0E16: ('TRANSPORT_KEY', 'I4'),
211 | 0x0E17: ('MSG_STATUS', 'I4'),
212 | 0x0E18: ('MESSAGE_DOWNLOAD_TIME', 'I4'),
213 | 0x0E19: ('CREATION_VERSION', 'I8'),
214 | 0x0E1A: ('MODIFY_VERSION', 'I8'),
215 | 0x0E1B: ('HASATTACH', 'BOOLEAN'),
216 | 0x0E1D: ('NORMALIZED_SUBJECT', 'STRING'),
217 | 0x0E1F: ('RTF_IN_SYNC', 'BOOLEAN'),
218 | 0x0E20: ('ATTACH_SIZE', 'I4'),
219 | 0x0E21: ('ATTACH_NUM', 'I4'),
220 | 0x0E22: ('PREPROCESS', 'BOOLEAN'),
221 | 0x0E25: ('ORIGINATING_MTA_CERTIFICATE', 'BINARY'),
222 | 0x0E26: ('PROOF_OF_SUBMISSION', 'BINARY'),
223 | # A unique identifier for editing the properties of a MAPI object
224 | 0x0FFF: ('ENTRYID', 'BINARY'),
225 | # The type of an object
226 | 0x0FFE: ('OBJECT_TYPE', 'I4'),
227 | 0x0FFD: ('ICON', 'BINARY'),
228 | 0x0FFC: ('MINI_ICON', 'BINARY'),
229 | 0x0FFB: ('STORE_ENTRYID', 'BINARY'),
230 | 0x0FFA: ('STORE_RECORD_KEY', 'BINARY'),
231 | # Binary identifer for an individual object
232 | 0x0FF9: ('RECORD_KEY', 'BINARY'),
233 | 0x0FF8: ('MAPPING_SIGNATURE', 'BINARY'),
234 | 0x0FF7: ('ACCESS_LEVEL', 'I4'),
235 | # The primary key of a column in a table
236 | 0x0FF6: ('INSTANCE_KEY', 'BINARY'),
237 | 0x0FF5: ('ROW_TYPE', 'I4'),
238 | 0x0FF4: ('ACCESS', 'I4'),
239 | 0x3000: ('ROWID', 'I4'),
240 | # The name to display for a given MAPI object
241 | 0x3001: ('DISPLAY_NAME', 'STRING'),
242 | 0x3002: ('ADDRTYPE', 'STRING'),
243 | # An email address
244 | 0x3003: ('EMAIL_ADDRESS', 'STRING'),
245 | # A comment field
246 | 0x3004: ('COMMENT', 'STRING'),
247 | 0x3005: ('DEPTH', 'I4'),
248 | # Provider-defined display name for a service provider
249 | 0x3006: ('PROVIDER_DISPLAY', 'STRING'),
250 | # The time an object was created
251 | 0x3007: ('CREATION_TIME', 'SYSTIME'),
252 | # The time an object was last modified
253 | 0x3008: ('LAST_MODIFICATION_TIME', 'SYSTIME'),
254 | # Flags describing a service provider, message service, or status object
255 | 0x3009: ('RESOURCE_FLAGS', 'I4'),
256 | # The name of a provider dll, minus any "32" suffix and ".dll"
257 | 0x300A: ('PROVIDER_DLL_NAME', 'STRING'),
258 | 0x300B: ('SEARCH_KEY', 'BINARY'),
259 | 0x300C: ('PROVIDER_UID', 'BINARY'),
260 | 0x300D: ('PROVIDER_ORDINAL', 'I4'),
261 | 0x3301: ('FORM_VERSION', 'STRING'),
262 | 0x3302: ('FORM_CLSID', 'CLSID'),
263 | 0x3303: ('FORM_CONTACT_NAME', 'STRING'),
264 | 0x3304: ('FORM_CATEGORY', 'STRING'),
265 | 0x3305: ('FORM_CATEGORY_SUB', 'STRING'),
266 | 0x3306: ('FORM_HOST_MAP', 'MV_LONG'),
267 | 0x3307: ('FORM_HIDDEN', 'BOOLEAN'),
268 | 0x3308: ('FORM_DESIGNER_NAME', 'STRING'),
269 | 0x3309: ('FORM_DESIGNER_GUID', 'CLSID'),
270 | 0x330A: ('FORM_MESSAGE_BEHAVIOR', 'I4'),
271 | # Is this row the default message store?
272 | 0x3400: ('DEFAULT_STORE', 'BOOLEAN'),
273 | 0x340D: ('STORE_SUPPORT_MASK', 'I4'),
274 | 0x340E: ('STORE_STATE', 'I4'),
275 | 0x3410: ('IPM_SUBTREE_SEARCH_KEY', 'BINARY'),
276 | 0x3411: ('IPM_OUTBOX_SEARCH_KEY', 'BINARY'),
277 | 0x3412: ('IPM_WASTEBASKET_SEARCH_KEY', 'BINARY'),
278 | 0x3413: ('IPM_SENTMAIL_SEARCH_KEY', 'BINARY'),
279 | # Provder-defined message store type
280 | 0x3414: ('MDB_PROVIDER', 'BINARY'),
281 | 0x3415: ('RECEIVE_FOLDER_SETTINGS', 'OBJECT'),
282 | 0x35DF: ('VALID_FOLDER_MASK', 'I4'),
283 | 0x35E0: ('IPM_SUBTREE_ENTRYID', 'BINARY'),
284 | 0x35E2: ('IPM_OUTBOX_ENTRYID', 'BINARY'),
285 | 0x35E3: ('IPM_WASTEBASKET_ENTRYID', 'BINARY'),
286 | 0x35E4: ('IPM_SENTMAIL_ENTRYID', 'BINARY'),
287 | 0x35E5: ('VIEWS_ENTRYID', 'BINARY'),
288 | 0x35E6: ('COMMON_VIEWS_ENTRYID', 'BINARY'),
289 | 0x35E7: ('FINDER_ENTRYID', 'BINARY'),
290 | 0x3600: ('CONTAINER_FLAGS', 'I4'),
291 | 0x3601: ('FOLDER_TYPE', 'I4'),
292 | 0x3602: ('CONTENT_COUNT', 'I4'),
293 | 0x3603: ('CONTENT_UNREAD', 'I4'),
294 | 0x3604: ('CREATE_TEMPLATES', 'OBJECT'),
295 | 0x3605: ('DETAILS_TABLE', 'OBJECT'),
296 | 0x3607: ('SEARCH', 'OBJECT'),
297 | 0x3609: ('SELECTABLE', 'BOOLEAN'),
298 | 0x360A: ('SUBFOLDERS', 'BOOLEAN'),
299 | 0x360B: ('STATUS', 'I4'),
300 | 0x360C: ('ANR', 'STRING'),
301 | 0x360D: ('CONTENTS_SORT_ORDER', 'MV_LONG'),
302 | 0x360E: ('CONTAINER_HIERARCHY', 'OBJECT'),
303 | 0x360F: ('CONTAINER_CONTENTS', 'OBJECT'),
304 | 0x3610: ('FOLDER_ASSOCIATED_CONTENTS', 'OBJECT'),
305 | 0x3611: ('DEF_CREATE_DL', 'BINARY'),
306 | 0x3612: ('DEF_CREATE_MAILUSER', 'BINARY'),
307 | 0x3613: ('CONTAINER_CLASS', 'STRING'),
308 | 0x3614: ('CONTAINER_MODIFY_VERSION', 'I8'),
309 | 0x3615: ('AB_PROVIDER_ID', 'BINARY'),
310 | 0x3616: ('DEFAULT_VIEW_ENTRYID', 'BINARY'),
311 | 0x3617: ('ASSOC_CONTENT_COUNT', 'I4'),
312 | 0x3700: ('ATTACHMENT_X400_PARAMETERS', 'BINARY'),
313 | 0x3701: ('ATTACH_DATA_OBJ', 'OBJECT'),
314 | 0x3701: ('ATTACH_DATA_BIN', 'BINARY'),
315 | 0x3702: ('ATTACH_ENCODING', 'BINARY'),
316 | 0x3703: ('ATTACH_EXTENSION', 'STRING'),
317 | 0x3704: ('ATTACH_FILENAME', 'STRING'),
318 | 0x3705: ('ATTACH_METHOD', 'I4'),
319 | 0x3707: ('ATTACH_LONG_FILENAME', 'STRING'),
320 | 0x3708: ('ATTACH_PATHNAME', 'STRING'),
321 | 0x370A: ('ATTACH_TAG', 'BINARY'),
322 | 0x370B: ('RENDERING_POSITION', 'I4'),
323 | 0x370C: ('ATTACH_TRANSPORT_NAME', 'STRING'),
324 | 0x370D: ('ATTACH_LONG_PATHNAME', 'STRING'),
325 | 0x370E: ('ATTACH_MIME_TAG', 'STRING'),
326 | 0x370F: ('ATTACH_ADDITIONAL_INFO', 'BINARY'),
327 | 0x3900: ('DISPLAY_TYPE', 'I4'),
328 | 0x3902: ('TEMPLATEID', 'BINARY'),
329 | 0x3904: ('PRIMARY_CAPABILITY', 'BINARY'),
330 | 0x39FF: ('7BIT_DISPLAY_NAME', 'STRING'),
331 | 0x3A00: ('ACCOUNT', 'STRING'),
332 | 0x3A01: ('ALTERNATE_RECIPIENT', 'BINARY'),
333 | 0x3A02: ('CALLBACK_TELEPHONE_NUMBER', 'STRING'),
334 | 0x3A03: ('CONVERSION_PROHIBITED', 'BOOLEAN'),
335 | 0x3A04: ('DISCLOSE_RECIPIENTS', 'BOOLEAN'),
336 | 0x3A05: ('GENERATION', 'STRING'),
337 | 0x3A06: ('GIVEN_NAME', 'STRING'),
338 | 0x3A07: ('GOVERNMENT_ID_NUMBER', 'STRING'),
339 | 0x3A08: ('BUSINESS_TELEPHONE_NUMBER', 'STRING'),
340 | 0x3A09: ('HOME_TELEPHONE_NUMBER', 'STRING'),
341 | 0x3A0A: ('INITIALS', 'STRING'),
342 | 0x3A0B: ('KEYWORD', 'STRING'),
343 | 0x3A0C: ('LANGUAGE', 'STRING'),
344 | 0x3A0D: ('LOCATION', 'STRING'),
345 | 0x3A0E: ('MAIL_PERMISSION', 'BOOLEAN'),
346 | 0x3A0F: ('MHS_COMMON_NAME', 'STRING'),
347 | 0x3A10: ('ORGANIZATIONAL_ID_NUMBER', 'STRING'),
348 | 0x3A11: ('SURNAME', 'STRING'),
349 | 0x3A12: ('ORIGINAL_ENTRYID', 'BINARY'),
350 | 0x3A13: ('ORIGINAL_DISPLAY_NAME', 'STRING'),
351 | 0x3A14: ('ORIGINAL_SEARCH_KEY', 'BINARY'),
352 | 0x3A15: ('POSTAL_ADDRESS', 'STRING'),
353 | 0x3A16: ('COMPANY_NAME', 'STRING'),
354 | 0x3A17: ('TITLE', 'STRING'),
355 | 0x3A18: ('DEPARTMENT_NAME', 'STRING'),
356 | 0x3A19: ('OFFICE_LOCATION', 'STRING'),
357 | 0x3A1A: ('PRIMARY_TELEPHONE_NUMBER', 'STRING'),
358 | 0x3A1B: ('BUSINESS2_TELEPHONE_NUMBER', 'STRING'),
359 | 0x3A1C: ('MOBILE_TELEPHONE_NUMBER', 'STRING'),
360 | 0x3A1D: ('RADIO_TELEPHONE_NUMBER', 'STRING'),
361 | 0x3A1E: ('CAR_TELEPHONE_NUMBER', 'STRING'),
362 | 0x3A1F: ('OTHER_TELEPHONE_NUMBER', 'STRING'),
363 | 0x3A20: ('TRANSMITABLE_DISPLAY_NAME', 'STRING'),
364 | 0x3A21: ('PAGER_TELEPHONE_NUMBER', 'STRING'),
365 | 0x3A22: ('USER_CERTIFICATE', 'BINARY'),
366 | 0x3A23: ('PRIMARY_FAX_NUMBER', 'STRING'),
367 | 0x3A24: ('BUSINESS_FAX_NUMBER', 'STRING'),
368 | 0x3A25: ('HOME_FAX_NUMBER', 'STRING'),
369 | 0x3A26: ('COUNTRY', 'STRING'),
370 | 0x3A27: ('LOCALITY', 'STRING'),
371 | 0x3A28: ('STATE_OR_PROVINCE', 'STRING'),
372 | 0x3A29: ('STREET_ADDRESS', 'STRING'),
373 | 0x3A2A: ('POSTAL_CODE', 'STRING'),
374 | 0x3A2B: ('POST_OFFICE_BOX', 'STRING'),
375 | 0x3A2C: ('TELEX_NUMBER', 'STRING'),
376 | 0x3A2D: ('ISDN_NUMBER', 'STRING'),
377 | 0x3A2E: ('ASSISTANT_TELEPHONE_NUMBER', 'STRING'),
378 | 0x3A2F: ('HOME2_TELEPHONE_NUMBER', 'STRING'),
379 | 0x3A30: ('ASSISTANT', 'STRING'),
380 | 0x3A40: ('SEND_RICH_INFO', 'BOOLEAN'),
381 | 0x3A41: ('WEDDING_ANNIVERSARY', 'SYSTIME'),
382 | 0x3A42: ('BIRTHDAY', 'SYSTIME'),
383 | 0x3A43: ('HOBBIES', 'STRING'),
384 | 0x3A44: ('MIDDLE_NAME', 'STRING'),
385 | 0x3A45: ('DISPLAY_NAME_PREFIX', 'STRING'),
386 | 0x3A46: ('PROFESSION', 'STRING'),
387 | 0x3A47: ('PREFERRED_BY_NAME', 'STRING'),
388 | 0x3A48: ('SPOUSE_NAME', 'STRING'),
389 | 0x3A49: ('COMPUTER_NETWORK_NAME', 'STRING'),
390 | 0x3A4A: ('CUSTOMER_ID', 'STRING'),
391 | 0x3A4B: ('TTYTDD_PHONE_NUMBER', 'STRING'),
392 | 0x3A4C: ('FTP_SITE', 'STRING'),
393 | 0x3A4D: ('GENDER', 'I2'),
394 | 0x3A4E: ('MANAGER_NAME', 'STRING'),
395 | 0x3A4F: ('NICKNAME', 'STRING'),
396 | 0x3A50: ('PERSONAL_HOME_PAGE', 'STRING'),
397 | 0x3A51: ('BUSINESS_HOME_PAGE', 'STRING'),
398 | 0x3A52: ('CONTACT_VERSION', 'CLSID'),
399 | 0x3A53: ('CONTACT_ENTRYIDS', 'MV_BINARY'),
400 | 0x3A54: ('CONTACT_ADDRTYPES', 'MV_STRING'),
401 | 0x3A55: ('CONTACT_DEFAULT_ADDRESS_INDEX', 'I4'),
402 | 0x3A56: ('CONTACT_EMAIL_ADDRESSES', 'MV_STRING'),
403 | 0x3A57: ('COMPANY_MAIN_PHONE_NUMBER', 'STRING'),
404 | 0x3A58: ('CHILDRENS_NAMES', 'MV_STRING'),
405 | 0x3A59: ('HOME_ADDRESS_CITY', 'STRING'),
406 | 0x3A5A: ('HOME_ADDRESS_COUNTRY', 'STRING'),
407 | 0x3A5B: ('HOME_ADDRESS_POSTAL_CODE', 'STRING'),
408 | 0x3A5C: ('HOME_ADDRESS_STATE_OR_PROVINCE', 'STRING'),
409 | 0x3A5D: ('HOME_ADDRESS_STREET', 'STRING'),
410 | 0x3A5E: ('HOME_ADDRESS_POST_OFFICE_BOX', 'STRING'),
411 | 0x3A5F: ('OTHER_ADDRESS_CITY', 'STRING'),
412 | 0x3A60: ('OTHER_ADDRESS_COUNTRY', 'STRING'),
413 | 0x3A61: ('OTHER_ADDRESS_POSTAL_CODE', 'STRING'),
414 | 0x3A62: ('OTHER_ADDRESS_STATE_OR_PROVINCE', 'STRING'),
415 | 0x3A63: ('OTHER_ADDRESS_STREET', 'STRING'),
416 | 0x3A64: ('OTHER_ADDRESS_POST_OFFICE_BOX', 'STRING'),
417 | 0x3D00: ('STORE_PROVIDERS', 'BINARY'),
418 | 0x3D01: ('AB_PROVIDERS', 'BINARY'),
419 | 0x3D02: ('TRANSPORT_PROVIDERS', 'BINARY'),
420 | 0x3D04: ('DEFAULT_PROFILE', 'BOOLEAN'),
421 | 0x3D05: ('AB_SEARCH_PATH', 'MV_BINARY'),
422 | 0x3D06: ('AB_DEFAULT_DIR', 'BINARY'),
423 | 0x3D07: ('AB_DEFAULT_PAB', 'BINARY'),
424 | 0x3D09: ('SERVICE_NAME', 'STRING'),
425 | 0x3D0A: ('SERVICE_DLL_NAME', 'STRING'),
426 | 0x3D0B: ('SERVICE_ENTRY_NAME', 'STRING'),
427 | 0x3D0C: ('SERVICE_UID', 'BINARY'),
428 | 0x3D0D: ('SERVICE_EXTRA_UIDS', 'BINARY'),
429 | 0x3D0E: ('SERVICES', 'BINARY'),
430 | 0x3D0F: ('SERVICE_SUPPORT_FILES', 'MV_STRING'),
431 | 0x3D10: ('SERVICE_DELETE_FILES', 'MV_STRING'),
432 | 0x3D11: ('AB_SEARCH_PATH_UPDATE', 'BINARY'),
433 | 0x3D12: ('PROFILE_NAME', 'STRING'),
434 | 0x3E00: ('IDENTITY_DISPLAY', 'STRING'),
435 | 0x3E01: ('IDENTITY_ENTRYID', 'BINARY'),
436 | 0x3E02: ('RESOURCE_METHODS', 'I4'),
437 | # Service provider type
438 | 0x3E03: ('RESOURCE_TYPE', 'I4'),
439 | 0x3E04: ('STATUS_CODE', 'I4'),
440 | 0x3E05: ('IDENTITY_SEARCH_KEY', 'BINARY'),
441 | 0x3E06: ('OWN_STORE_ENTRYID', 'BINARY'),
442 | 0x3E07: ('RESOURCE_PATH', 'STRING'),
443 | 0x3E08: ('STATUS_STRING', 'STRING'),
444 | 0x3E09: ('X400_DEFERRED_DELIVERY_CANCEL', 'BOOLEAN'),
445 | 0x3E0A: ('HEADER_FOLDER_ENTRYID', 'BINARY'),
446 | 0x3E0B: ('REMOTE_PROGRESS', 'I4'),
447 | 0x3E0C: ('REMOTE_PROGRESS_TEXT', 'STRING'),
448 | 0x3E0D: ('REMOTE_VALIDATE_OK', 'BOOLEAN'),
449 | 0x3F00: ('CONTROL_FLAGS', 'I4'),
450 | 0x3F01: ('CONTROL_STRUCTURE', 'BINARY'),
451 | 0x3F02: ('CONTROL_TYPE', 'I4'),
452 | 0x3F03: ('DELTAX', 'I4'),
453 | 0x3F04: ('DELTAY', 'I4'),
454 | 0x3F05: ('XPOS', 'I4'),
455 | 0x3F06: ('YPOS', 'I4'),
456 | 0x3F07: ('CONTROL_ID', 'BINARY'),
457 | 0x3F08: ('INITIAL_DETAILS_PANE', 'I4'),
458 | }
--------------------------------------------------------------------------------
/src/main/java/org/simplejavamail/jakarta/mail/internet/InternetHeaders.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License v. 2.0, which is available at
6 | * http://www.eclipse.org/legal/epl-2.0.
7 | *
8 | * This Source Code may also be made available under the following Secondary
9 | * Licenses when the conditions for such availability set forth in the
10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11 | * version 2 with the GNU Classpath Exception, which is available at
12 | * https://www.gnu.org/software/classpath/license.html.
13 | *
14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15 | */
16 |
17 | package org.simplejavamail.jakarta.mail.internet;
18 |
19 | import org.simplejavamail.com.sun.mail.util.LineInputStream;
20 | import org.simplejavamail.com.sun.mail.util.PropUtil;
21 | import org.simplejavamail.jakarta.mail.*;
22 |
23 | import java.io.*;
24 | import java.util.*;
25 |
26 | /**
27 | * InternetHeaders is a utility class that manages RFC822 style
28 | * headers. Given an RFC822 format message stream, it reads lines
29 | * until the blank line that indicates end of header. The input stream
30 | * is positioned at the start of the body. The lines are stored
31 | * within the object and can be extracted as either Strings or
32 | * {@link org.simplejavamail.jakarta.mail.Header} objects.
33 | *
34 | * This class is mostly intended for service providers. MimeMessage
35 | * and MimeBody use this class for holding their headers.
36 | *
37 | *
38 | *
39 | * RFC822 and MIME header fields must contain only
40 | * US-ASCII characters. If a header contains non US-ASCII characters,
41 | * it must be encoded as per the rules in RFC 2047. The MimeUtility
42 | * class provided in this package can be used to to achieve this.
43 | * Callers of the
50 | *
51 | * The current implementation supports the System property
52 | *
69 | *
70 | * An InternetHeader object with a null value is used as a placeholder
71 | * for headers of that name, to preserve the order of headers.
72 | * A placeholder InternetHeader object with a name of ":" marks
73 | * the location in the list of headers where new headers are
74 | * added by default.
75 | *
76 | * @since JavaMail 1.4
77 | */
78 | protected static final class InternetHeader extends Header {
79 | /*
80 | * Note that the value field from the superclass
81 | * isn't used in this class. We extract the value
82 | * from the line field as needed. We store the line
83 | * rather than just the value to ensure that we can
84 | * get back the exact original line, with the original
85 | * whitespace, etc.
86 | */
87 | String line; // the entire RFC822 header "line",
88 | // or null if placeholder
89 |
90 | /**
91 | * Constructor that takes a line and splits out
92 | * the header name.
93 | *
94 | * @param l the header line
95 | */
96 | public InternetHeader(String l) {
97 | super("", ""); // XXX - we'll change it later
98 | int i = l.indexOf(':');
99 | if (i < 0) {
100 | // should never happen
101 | name = l.trim();
102 | } else {
103 | name = l.substring(0, i).trim();
104 | }
105 | line = l;
106 | }
107 |
108 | /**
109 | * Constructor that takes a header name and value.
110 | *
111 | * @param n the name of the header
112 | * @param v the value of the header
113 | */
114 | public InternetHeader(String n, String v) {
115 | super(n, "");
116 | if (v != null)
117 | line = n + ": " + v;
118 | else
119 | line = null;
120 | }
121 |
122 | /**
123 | * Return the "value" part of the header line.
124 | */
125 | @Override
126 | public String getValue() {
127 | int i = line.indexOf(':');
128 | if (i < 0)
129 | return line;
130 | // skip whitespace after ':'
131 | int j;
132 | for (j = i + 1; j < line.length(); j++) {
133 | char c = line.charAt(j);
134 | if (!(c == ' ' || c == '\t' || c == '\r' || c == '\n'))
135 | break;
136 | }
137 | return line.substring(j);
138 | }
139 | }
140 |
141 | /*
142 | * The enumeration object used to enumerate an
143 | * InternetHeaders object. Can return
144 | * either a String or a Header object.
145 | */
146 | static class MatchEnum {
147 | private Iterator
323 | *
324 | * For efficiency, wrap a BufferedInputStream around the actual
325 | * input stream and pass it as the parameter.
326 | *
327 | * No placeholder entries are inserted; the original order of
328 | * the headers is preserved.
329 | *
330 | * @param is RFC822 input stream
331 | * @exception MessagingException for any I/O error reading the stream
332 | */
333 | public InternetHeaders(InputStream is) throws MessagingException {
334 | this(is, false);
335 | }
336 |
337 | /**
338 | * Read and parse the given RFC822 message stream till the
339 | * blank line separating the header from the body. The input
340 | * stream is left positioned at the start of the body. The
341 | * header lines are stored internally.
342 | *
343 | * For efficiency, wrap a BufferedInputStream around the actual
344 | * input stream and pass it as the parameter.
345 | *
346 | * No placeholder entries are inserted; the original order of
347 | * the headers is preserved.
348 | *
349 | * @param is RFC822 input stream
350 | * @param allowutf8 if UTF-8 encoded headers are allowed
351 | * @exception MessagingException for any I/O error reading the stream
352 | * @since JavaMail 1.6
353 | */
354 | public InternetHeaders(InputStream is, boolean allowutf8)
355 | throws MessagingException {
356 | headers = new ArrayList<>(40);
357 | load(is, allowutf8);
358 | }
359 |
360 | /**
361 | * Read and parse the given RFC822 message stream till the
362 | * blank line separating the header from the body. Store the
363 | * header lines inside this InternetHeaders object. The order
364 | * of header lines is preserved.
365 | *
366 | * Note that the header lines are added into this InternetHeaders
367 | * object, so any existing headers in this object will not be
368 | * affected. Headers are added to the end of the existing list
369 | * of headers, in order.
370 | *
371 | * @param is RFC822 input stream
372 | * @exception MessagingException for any I/O error reading the stream
373 | */
374 | public void load(InputStream is) throws MessagingException {
375 | load(is, false);
376 | }
377 |
378 | /**
379 | * Read and parse the given RFC822 message stream till the
380 | * blank line separating the header from the body. Store the
381 | * header lines inside this InternetHeaders object. The order
382 | * of header lines is preserved.
383 | *
384 | * Note that the header lines are added into this InternetHeaders
385 | * object, so any existing headers in this object will not be
386 | * affected. Headers are added to the end of the existing list
387 | * of headers, in order.
388 | *
389 | * @param is RFC822 input stream
390 | * @param allowutf8 if UTF-8 encoded headers are allowed
391 | * @exception MessagingException for any I/O error reading the stream
392 | * @since JavaMail 1.6
393 | */
394 | public void load(InputStream is, boolean allowutf8)
395 | throws MessagingException {
396 | // Read header lines until a blank line. It is valid
397 | // to have BodyParts with no header lines.
398 | String line;
399 | LineInputStream lis = new LineInputStream(is, allowutf8);
400 | String prevline = null; // the previous header line, as a string
401 | // a buffer to accumulate the header in, when we know it's needed
402 | StringBuilder lineBuffer = new StringBuilder();
403 |
404 | try {
405 | // if the first line being read is a continuation line,
406 | // we ignore it if it's otherwise empty or we treat it as
407 | // a non-continuation line if it has non-whitespace content
408 | boolean first = true;
409 | do {
410 | line = lis.readLine();
411 | if (line != null &&
412 | (line.startsWith(" ") || line.startsWith("\t"))) {
413 | // continuation of header
414 | if (prevline != null) {
415 | lineBuffer.append(prevline);
416 | prevline = null;
417 | }
418 | if (first) {
419 | String lt = line.trim();
420 | if (lt.length() > 0)
421 | lineBuffer.append(lt);
422 | } else {
423 | if (lineBuffer.length() > 0)
424 | lineBuffer.append("\r\n");
425 | lineBuffer.append(line);
426 | }
427 | } else {
428 | // new header
429 | if (prevline != null)
430 | addHeaderLine(prevline);
431 | else if (lineBuffer.length() > 0) {
432 | // store previous header first
433 | addHeaderLine(lineBuffer.toString());
434 | lineBuffer.setLength(0);
435 | }
436 | prevline = line;
437 | }
438 | first = false;
439 | } while (line != null && !isEmpty(line));
440 | } catch (IOException ioex) {
441 | throw new MessagingException("Error in input stream", ioex);
442 | }
443 | }
444 |
445 | /**
446 | * Is this line an empty (blank) line?
447 | */
448 | private static final boolean isEmpty(String line) {
449 | return line.length() == 0 ||
450 | (ignoreWhitespaceLines && line.trim().length() == 0);
451 | }
452 |
453 | /**
454 | * Return all the values for the specified header. The
455 | * values are String objects. Returns
513 | *
514 | * Note that RFC822 headers can only contain US-ASCII characters
515 | *
516 | * @param name header name
517 | * @param value header value
518 | */
519 | public void setHeader(String name, String value) {
520 | boolean found = false;
521 |
522 | for (int i = 0; i < headers.size(); i++) {
523 | InternetHeader h = headers.get(i);
524 | if (name.equalsIgnoreCase(h.getName())) {
525 | if (!found) {
526 | int j;
527 | if (h.line != null && (j = h.line.indexOf(':')) >= 0) {
528 | h.line = h.line.substring(0, j + 1) + " " + value;
529 | // preserves capitalization, spacing
530 | } else {
531 | h.line = name + ": " + value;
532 | }
533 | found = true;
534 | } else {
535 | headers.remove(i);
536 | i--; // have to look at i again
537 | }
538 | }
539 | }
540 |
541 | if (!found) {
542 | addHeader(name, value);
543 | }
544 | }
545 |
546 | /**
547 | * Add a header with the specified name and value to the header list.
548 | *
549 | * The current implementation knows about the preferred order of most
550 | * well-known headers and will insert headers in that order. In
551 | * addition, it knows that
555 | *
556 | * Note that RFC822 headers can only contain US-ASCII characters.
557 | *
558 | * @param name header name
559 | * @param value header value
560 | */
561 | public void addHeader(String name, String value) {
562 | int pos = headers.size();
563 | boolean addReverse =
564 | name.equalsIgnoreCase("Received") ||
565 | name.equalsIgnoreCase("Return-Path");
566 | if (addReverse)
567 | pos = 0;
568 | for (int i = headers.size() - 1; i >= 0; i--) {
569 | InternetHeader h = headers.get(i);
570 | if (name.equalsIgnoreCase(h.getName())) {
571 | if (addReverse) {
572 | pos = i;
573 | } else {
574 | headers.add(i + 1, new InternetHeader(name, value));
575 | return;
576 | }
577 | }
578 | // marker for default place to add new headers
579 | if (!addReverse && h.getName().equals(":"))
580 | pos = i;
581 | }
582 | headers.add(pos, new InternetHeader(name, value));
583 | }
584 |
585 | /**
586 | * Remove all header entries that match the given name
587 | * @param name header name
588 | */
589 | public void removeHeader(String name) {
590 | for (int i = 0; i < headers.size(); i++) {
591 | InternetHeader h = headers.get(i);
592 | if (name.equalsIgnoreCase(h.getName())) {
593 | h.line = null;
594 | //headers.remove(i);
595 | //i--; // have to look at i again
596 | }
597 | }
598 | }
599 |
600 | /**
601 | * Return all the headers as an Enumeration of
602 | * {@link org.simplejavamail.jakarta.mail.Header} objects.
603 | *
604 | * @return Enumeration of Header objects
605 | */
606 | public Enumeration
635 | *
636 | * Note that RFC822 headers can only contain US-ASCII characters
637 | *
638 | * @param line raw RFC822 header line
639 | */
640 | public void addHeaderLine(String line) {
641 | try {
642 | char c = line.charAt(0);
643 | if (c == ' ' || c == '\t') {
644 | InternetHeader h = headers.get(headers.size() - 1);
645 | h.line += "\r\n" + line;
646 | } else
647 | headers.add(new InternetHeader(line));
648 | } catch (StringIndexOutOfBoundsException e) {
649 | // line is empty, ignore it
650 | return;
651 | } catch (NoSuchElementException e) {
652 | // XXX - list is empty?
653 | }
654 | }
655 |
656 | /**
657 | * Return all the header lines as an Enumeration of Strings.
658 | *
659 | * @return Enumeration of Strings of all header lines
660 | */
661 | public EnumerationDataInputStream.readLine()
84 | *
85 | * @return the line
86 | * @exception IOException for I/O errors
87 | */
88 | @SuppressWarnings("deprecation") // for old String constructor
89 | public String readLine() throws IOException {
90 | //InputStream in = this.in;
91 | byte[] buf = lineBuffer;
92 |
93 | if (buf == null)
94 | buf = lineBuffer = new byte[128];
95 |
96 | int c1;
97 | int room = buf.length;
98 | int offset = 0;
99 |
100 | while ((c1 = in.read()) != -1) {
101 | if (c1 == '\n') // Got NL, outa here.
102 | break;
103 | else if (c1 == '\r') {
104 | // Got CR, is the next char NL ?
105 | boolean twoCRs = false;
106 | if (in.markSupported())
107 | in.mark(2);
108 | int c2 = in.read();
109 | if (c2 == '\r') { // discard extraneous CR
110 | twoCRs = true;
111 | c2 = in.read();
112 | }
113 | if (c2 != '\n') {
114 | /*
115 | * If the stream supports it (which we hope will always
116 | * be the case), reset to after the first CR. Otherwise,
117 | * we wrap a PushbackInputStream around the stream so we
118 | * can unread the characters we don't need. The only
119 | * problem with that is that the caller might stop
120 | * reading from this LineInputStream, throw it away,
121 | * and then start reading from the underlying stream.
122 | * If that happens, the pushed back characters will be
123 | * lost forever.
124 | */
125 | if (in.markSupported())
126 | in.reset();
127 | else {
128 | if (!(in instanceof PushbackInputStream))
129 | in /*= this.in*/ = new PushbackInputStream(in, 2);
130 | if (c2 != -1)
131 | ((PushbackInputStream)in).unread(c2);
132 | if (twoCRs)
133 | ((PushbackInputStream)in).unread('\r');
134 | }
135 | }
136 | break; // outa here.
137 | }
138 |
139 | // Not CR, NL or CR-NL ...
140 | // .. Insert the byte into our byte buffer
141 | if (--room < 0) { // No room, need to grow.
142 | if (buf.length < MAX_INCR)
143 | buf = new byte[buf.length * 2];
144 | else
145 | buf = new byte[buf.length + MAX_INCR];
146 | room = buf.length - offset - 1;
147 | System.arraycopy(lineBuffer, 0, buf, 0, offset);
148 | lineBuffer = buf;
149 | }
150 | buf[offset++] = (byte)c1;
151 | }
152 |
153 | if ((c1 == -1) && (offset == 0))
154 | return null;
155 |
156 | if (allowutf8)
157 | return new String(buf, 0, offset, StandardCharsets.UTF_8);
158 | else {
159 | if (defaultutf8) {
160 | // try to decode it as UTF-8
161 | try {
162 | return decoder.decode(ByteBuffer.wrap(buf, 0, offset)).
163 | toString();
164 | } catch (CharacterCodingException cex) {
165 | // looks like it's not valid UTF-8 data,
166 | // fall through and treat it as an 8-bit charset
167 | }
168 | }
169 | return new String(buf, 0, 0, offset);
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/main/java/org/simplejavamail/com/sun/mail/util/QPEncoderStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License v. 2.0, which is available at
6 | * http://www.eclipse.org/legal/epl-2.0.
7 | *
8 | * This Source Code may also be made available under the following Secondary
9 | * Licenses when the conditions for such availability set forth in the
10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11 | * version 2 with the GNU Classpath Exception, which is available at
12 | * https://www.gnu.org/software/classpath/license.html.
13 | *
14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15 | */
16 |
17 | package org.simplejavamail.com.sun.mail.util;
18 |
19 | import java.io.*;
20 |
21 | /**
22 | * This class implements a Quoted Printable Encoder. It is implemented as
23 | * a FilterOutputStream, so one can just wrap this class around
24 | * any output stream and write bytes into this filter. The Encoding
25 | * is done as the bytes are written out.
26 | *
27 | * @author John Mani
28 | */
29 |
30 | public class QPEncoderStream extends FilterOutputStream {
31 | private int count = 0; // number of bytes that have been output
32 | private int bytesPerLine; // number of bytes per line
33 | private boolean gotSpace = false;
34 | private boolean gotCR = false;
35 |
36 | /**
37 | * Create a QP encoder that encodes the specified input stream
38 | * @param out the output stream
39 | * @param bytesPerLine the number of bytes per line. The encoder
40 | * inserts a CRLF sequence after this many number
41 | * of bytes.
42 | */
43 | public QPEncoderStream(OutputStream out, int bytesPerLine) {
44 | super(out);
45 | // Subtract 1 to account for the '=' in the soft-return
46 | // at the end of a line
47 | this.bytesPerLine = bytesPerLine - 1;
48 | }
49 |
50 | /**
51 | * Create a QP encoder that encodes the specified input stream.
52 | * Inserts the CRLF sequence after outputting 76 bytes.
53 | * @param out the output stream
54 | */
55 | public QPEncoderStream(OutputStream out) {
56 | this(out, 76);
57 | }
58 |
59 | /**
60 | * Encodes len bytes from the specified
61 | * byte array starting at offset off to
62 | * this output stream.
63 | *
64 | * @param b the data.
65 | * @param off the start offset in the data.
66 | * @param len the number of bytes to write.
67 | * @exception IOException if an I/O error occurs.
68 | */
69 | @Override
70 | public void write(byte[] b, int off, int len) throws IOException {
71 | for (int i = 0; i < len; i++)
72 | write(b[off + i]);
73 | }
74 |
75 | /**
76 | * Encodes b.length bytes to this output stream.
77 | * @param b the data to be written.
78 | * @exception IOException if an I/O error occurs.
79 | */
80 | @Override
81 | public void write(byte[] b) throws IOException {
82 | write(b, 0, b.length);
83 | }
84 |
85 | /**
86 | * Encodes the specified byte to this output stream.
87 | * @param c the byte.
88 | * @exception IOException if an I/O error occurs.
89 | */
90 | @Override
91 | public void write(int c) throws IOException {
92 | c = c & 0xff; // Turn off the MSB.
93 | if (gotSpace) { // previous character was
tags
127 | - [#10](https://github.com/bbottema/outlook-message-parser/issues/10) Embedded images with DOS-like names are classified as attachments
128 | - [#9](https://github.com/bbottema/outlook-message-parser/issues/9) SimpleRTF2HTMLConverter removes some valid tags during conversion
129 |
130 |
131 | v1.2.1 (12-May-2019)
132 |
133 | - Ignore non S/MIME related content types when extracting S/MIME metadata
134 | - Added toString and equals methods to the S/MIME data classes
135 |
136 |
137 | v1.1.21 (4-May-2019)
138 |
139 | - Upgraded mediatype recognition based on file extension for incomplete attachments
140 | - Added / improved support for public S/MIME meta data
141 |
142 |
143 | v1.1.20 (14-April-2019)
144 |
145 | - [#7](https://github.com/bbottema/outlook-message-parser/issues/7) Fix missing S/MIME header details that are needed to determine the type of S/MIME application
146 |
147 |
148 | v1.1.19 (10-April-2019)
149 |
150 | - Log rtf compression error, but otherwise ignore it and keep going and extract what we can.
151 |
152 |
153 | v1.1.18 (5-April-2019)
154 |
155 | - [#6](https://github.com/bbottema/outlook-message-parser/issues/6) Missing mimeTag for attachments should be guessed based on file extension
156 |
157 |
158 | v1.1.17 (19-August-2018)
159 |
160 | - [#3](https://github.com/bbottema/simple-java-mail/issues/3) implemented robust support for character sets / code pages in RTF to HTML
161 | conversion (fixes chinese support #3)
162 | - fixed bug where too much text was cleaned up as part of superfluous RTF cleanup step when converting to HTML
163 | - Performance boost in the RTF -> HTML converter
164 |
165 |
166 | v1.1.16 (~28-Februari-2017)
167 |
168 | - First Maven deployment, continuing version number from 1.1.15 of msgparser (https://github.com/bbottema/msgparser)
169 |
170 |
171 | v1.16
172 | - Added support for replyTo name and address
173 | - cleaned up code (1st wave)
--------------------------------------------------------------------------------
/src/main/java/org/simplejavamail/com/sun/mail/util/BASE64EncoderStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License v. 2.0, which is available at
6 | * http://www.eclipse.org/legal/epl-2.0.
7 | *
8 | * This Source Code may also be made available under the following Secondary
9 | * Licenses when the conditions for such availability set forth in the
10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11 | * version 2 with the GNU Classpath Exception, which is available at
12 | * https://www.gnu.org/software/classpath/license.html.
13 | *
14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15 | */
16 |
17 | package org.simplejavamail.com.sun.mail.util;
18 |
19 | import java.io.*;
20 |
21 | /**
22 | * This class implements a BASE64 encoder. It is implemented as
23 | * a FilterOutputStream, so one can just wrap this class around
24 | * any output stream and write bytes into this filter. The encoding
25 | * is done as the bytes are written out.
26 | *
27 | * @author John Mani
28 | * @author Bill Shannon
29 | */
30 |
31 | public class BASE64EncoderStream extends FilterOutputStream {
32 | private byte[] buffer; // cache of bytes that are yet to be encoded
33 | private int bufsize = 0; // size of the cache
34 | private byte[] outbuf; // line size output buffer
35 | private int count = 0; // number of bytes that have been output
36 | private int bytesPerLine; // number of bytes per line
37 | private int lineLimit; // number of input bytes to output bytesPerLine
38 | private boolean noCRLF = false;
39 |
40 | private static byte[] newline = new byte[] { '\r', '\n' };
41 |
42 | /**
43 | * Create a BASE64 encoder that encodes the specified output stream.
44 | *
45 | * @param out the output stream
46 | * @param bytesPerLine number of bytes per line. The encoder inserts
47 | * a CRLF sequence after the specified number of bytes,
48 | * unless bytesPerLine is Integer.MAX_VALUE, in which
49 | * case no CRLF is inserted. bytesPerLine is rounded
50 | * down to a multiple of 4.
51 | */
52 | public BASE64EncoderStream(OutputStream out, int bytesPerLine) {
53 | super(out);
54 | buffer = new byte[3];
55 | if (bytesPerLine == Integer.MAX_VALUE || bytesPerLine < 4) {
56 | noCRLF = true;
57 | bytesPerLine = 76;
58 | }
59 | bytesPerLine = (bytesPerLine / 4) * 4; // Rounded down to 4n
60 | this.bytesPerLine = bytesPerLine; // save it
61 | lineLimit = bytesPerLine / 4 * 3;
62 |
63 | if (noCRLF) {
64 | outbuf = new byte[bytesPerLine];
65 | } else {
66 | outbuf = new byte[bytesPerLine + 2];
67 | outbuf[bytesPerLine] = (byte)'\r';
68 | outbuf[bytesPerLine + 1] = (byte)'\n';
69 | }
70 | }
71 |
72 | /**
73 | * Create a BASE64 encoder that encodes the specified input stream.
74 | * Inserts the CRLF sequence after outputting 76 bytes.
75 | *
76 | * @param out the output stream
77 | */
78 | public BASE64EncoderStream(OutputStream out) {
79 | this(out, 76);
80 | }
81 |
82 | /**
83 | * Encodes len bytes from the specified
84 | * byte array starting at offset off to
85 | * this output stream.
86 | *
87 | * @param b the data.
88 | * @param off the start offset in the data.
89 | * @param len the number of bytes to write.
90 | * @exception IOException if an I/O error occurs.
91 | */
92 | @Override
93 | public synchronized void write(byte[] b, int off, int len)
94 | throws IOException {
95 | int end = off + len;
96 |
97 | // finish off incomplete coding unit
98 | while (bufsize != 0 && off < end)
99 | write(b[off++]);
100 |
101 | // finish off line
102 | int blen = ((bytesPerLine - count) / 4) * 3;
103 | if (off + blen <= end) {
104 | // number of bytes that will be produced in outbuf
105 | int outlen = encodedSize(blen);
106 | if (!noCRLF) {
107 | outbuf[outlen++] = (byte)'\r';
108 | outbuf[outlen++] = (byte)'\n';
109 | }
110 | out.write(encode(b, off, blen, outbuf), 0, outlen);
111 | off += blen;
112 | count = 0;
113 | }
114 |
115 | // do bulk encoding a line at a time.
116 | for (; off + lineLimit <= end; off += lineLimit)
117 | out.write(encode(b, off, lineLimit, outbuf));
118 |
119 | // handle remaining partial line
120 | if (off + 3 <= end) {
121 | blen = end - off;
122 | blen = (blen / 3) * 3; // round down
123 | // number of bytes that will be produced in outbuf
124 | int outlen = encodedSize(blen);
125 | out.write(encode(b, off, blen, outbuf), 0, outlen);
126 | off += blen;
127 | count += outlen;
128 | }
129 |
130 | // start next coding unit
131 | for (; off < end; off++)
132 | write(b[off]);
133 | }
134 |
135 | /**
136 | * Encodes b.length bytes to this output stream.
137 | *
138 | * @param b the data to be written.
139 | * @exception IOException if an I/O error occurs.
140 | */
141 | @Override
142 | public void write(byte[] b) throws IOException {
143 | write(b, 0, b.length);
144 | }
145 |
146 | /**
147 | * Encodes the specified byte to this output stream.
148 | *
149 | * @param c the byte.
150 | * @exception IOException if an I/O error occurs.
151 | */
152 | @Override
153 | public synchronized void write(int c) throws IOException {
154 | buffer[bufsize++] = (byte)c;
155 | if (bufsize == 3) { // Encoding unit = 3 bytes
156 | encode();
157 | bufsize = 0;
158 | }
159 | }
160 |
161 | /**
162 | * Flushes this output stream and forces any buffered output bytes
163 | * to be encoded out to the stream.
164 | *
165 | * @exception IOException if an I/O error occurs.
166 | */
167 | @Override
168 | public synchronized void flush() throws IOException {
169 | if (bufsize > 0) { // If there's unencoded characters in the buffer ..
170 | encode(); // .. encode them
171 | bufsize = 0;
172 | }
173 | out.flush();
174 | }
175 |
176 | /**
177 | * Forces any buffered output bytes to be encoded out to the stream
178 | * and closes this output stream
179 | */
180 | @Override
181 | public synchronized void close() throws IOException {
182 | flush();
183 | if (count > 0 && !noCRLF) {
184 | out.write(newline);
185 | out.flush();
186 | }
187 | out.close();
188 | }
189 |
190 | /** This array maps the characters to their 6 bit values */
191 | private final static char pem_array[] = {
192 | 'A','B','C','D','E','F','G','H', // 0
193 | 'I','J','K','L','M','N','O','P', // 1
194 | 'Q','R','S','T','U','V','W','X', // 2
195 | 'Y','Z','a','b','c','d','e','f', // 3
196 | 'g','h','i','j','k','l','m','n', // 4
197 | 'o','p','q','r','s','t','u','v', // 5
198 | 'w','x','y','z','0','1','2','3', // 6
199 | '4','5','6','7','8','9','+','/' // 7
200 | };
201 |
202 | /**
203 | * Encode the data stored in buffer.
204 | * Uses outbuf to store the encoded
205 | * data before writing.
206 | *
207 | * @exception IOException if an I/O error occurs.
208 | */
209 | private void encode() throws IOException {
210 | int osize = encodedSize(bufsize);
211 | out.write(encode(buffer, 0, bufsize, outbuf), 0, osize);
212 | // increment count
213 | count += osize;
214 | // If writing out this encoded unit caused overflow,
215 | // start a new line.
216 | if (count >= bytesPerLine) {
217 | if (!noCRLF)
218 | out.write(newline);
219 | count = 0;
220 | }
221 | }
222 |
223 | /**
224 | * Base64 encode a byte array. No line breaks are inserted.
225 | * This method is suitable for short strings, such as those
226 | * in the IMAP AUTHENTICATE protocol, but not to encode the
227 | * entire content of a MIME part.
228 | *
229 | * @param inbuf the byte array
230 | * @return the encoded byte array
231 | */
232 | public static byte[] encode(byte[] inbuf) {
233 | if (inbuf.length == 0)
234 | return inbuf;
235 | return encode(inbuf, 0, inbuf.length, null);
236 | }
237 |
238 | /**
239 | * Internal use only version of encode. Allow specifying which
240 | * part of the input buffer to encode. If outbuf is non-null,
241 | * it's used as is. Otherwise, a new output buffer is allocated.
242 | */
243 | private static byte[] encode(byte[] inbuf, int off, int size,
244 | byte[] outbuf) {
245 | if (outbuf == null)
246 | outbuf = new byte[encodedSize(size)];
247 | int inpos, outpos;
248 | int val;
249 | for (inpos = off, outpos = 0; size >= 3; size -= 3, outpos += 4) {
250 | val = inbuf[inpos++] & 0xff;
251 | val <<= 8;
252 | val |= inbuf[inpos++] & 0xff;
253 | val <<= 8;
254 | val |= inbuf[inpos++] & 0xff;
255 | outbuf[outpos+3] = (byte)pem_array[val & 0x3f];
256 | val >>= 6;
257 | outbuf[outpos+2] = (byte)pem_array[val & 0x3f];
258 | val >>= 6;
259 | outbuf[outpos+1] = (byte)pem_array[val & 0x3f];
260 | val >>= 6;
261 | outbuf[outpos+0] = (byte)pem_array[val & 0x3f];
262 | }
263 | // done with groups of three, finish up any odd bytes left
264 | if (size == 1) {
265 | val = inbuf[inpos++] & 0xff;
266 | val <<= 4;
267 | outbuf[outpos+3] = (byte)'='; // pad character;
268 | outbuf[outpos+2] = (byte)'='; // pad character;
269 | outbuf[outpos+1] = (byte)pem_array[val & 0x3f];
270 | val >>= 6;
271 | outbuf[outpos+0] = (byte)pem_array[val & 0x3f];
272 | } else if (size == 2) {
273 | val = inbuf[inpos++] & 0xff;
274 | val <<= 8;
275 | val |= inbuf[inpos++] & 0xff;
276 | val <<= 2;
277 | outbuf[outpos+3] = (byte)'='; // pad character;
278 | outbuf[outpos+2] = (byte)pem_array[val & 0x3f];
279 | val >>= 6;
280 | outbuf[outpos+1] = (byte)pem_array[val & 0x3f];
281 | val >>= 6;
282 | outbuf[outpos+0] = (byte)pem_array[val & 0x3f];
283 | }
284 | return outbuf;
285 | }
286 |
287 | /**
288 | * Return the corresponding encoded size for the given number
289 | * of bytes, not including any CRLF.
290 | */
291 | private static int encodedSize(int size) {
292 | return ((size + 2) / 3) * 4;
293 | }
294 |
295 | /*** begin TEST program
296 | public static void main(String argv[]) throws Exception {
297 | FileInputStream infile = new FileInputStream(argv[0]);
298 | BASE64EncoderStream encoder = new BASE64EncoderStream(System.out);
299 | int c;
300 |
301 | while ((c = infile.read()) != -1)
302 | encoder.write(c);
303 | encoder.close();
304 | }
305 | *** end TEST program **/
306 | }
307 |
--------------------------------------------------------------------------------
/LICENSE-2.0.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
--------------------------------------------------------------------------------
/src/main/resources/mimetypes.txt:
--------------------------------------------------------------------------------
1 | xgl/movie xmz
2 | xgl/drawing xgz
3 | x-world/x-vrt vrt
4 | x-world/x-vrml wrl vrml wrz
5 | x-world/x-svr svr
6 | x-world/x-3dmf qd3d qd3 3dmf 3dm
7 | x-music/x-midi midi mid
8 | x-conference/x-cooltalk ice
9 | www/mime mime
10 | windows/metafile wmf
11 | video/x-sgi-movie movie mv
12 | video/x-scm scm
13 | video/x-qtc qtc
14 | video/x-msvideo avi
15 | video/x-ms-asf-plugin asx
16 | video/x-ms-asf asf asx
17 | video/x-mpeq2a mp2
18 | video/x-mpeg mp3 mp2
19 | video/x-motion-jpeg mjpg
20 | video/x-isvideo isu
21 | video/x-gl gl
22 | video/x-generic mp4 wmv swf dvd mov mpeg osp ogv
23 | video/x-fli fli
24 | video/x-dv dif dv
25 | video/x-dl dl
26 | video/x-atomic3d-feature fmf
27 | video/x-amt-showrun xsr
28 | video/x-amt-demorun xdr
29 | video/vosaic vos
30 | video/vnd.vivo viv vivo
31 | video/vnd.rn-realvideo rv
32 | video/vivo viv vivo
33 | video/vdo vdo
34 | video/quicktime qt mov moov
35 | video/msvideo avi
36 | video/mpeg m2v mp3 mpv m1v mpe mpg mpegv mpeg vbs mp2 mpa
37 | video/gl gl
38 | video/fli fli
39 | video/dl dl
40 | video/avs-video avs
41 | video/avi avi
42 | video/animaflex afl
43 | text/xml xml XML osm
44 | text/x-vcalendar vcs
45 | text/x-uuencode uu uue
46 | text/x-uil uil
47 | text/x-tex tex
48 | text/x-tcl tcl
49 | text/x-sql sql
50 | text/x-speech spc talk
51 | text/x-sgml sgml sgm
52 | text/x-setext etx
53 | text/x-server-parsed-html ssi shtml
54 | text/x-script.zsh zsh
55 | text/x-script.tcsh tcsh
56 | text/x-script.tcl tcl
57 | text/x-script.sh sh
58 | text/x-script.scheme scm
59 | text/x-script.rexx rexx
60 | text/x-script.phyton py
61 | text/x-script.perl-module pm
62 | text/x-script.perl pl
63 | text/x-script.lisp lsp
64 | text/x-script.ksh ksh
65 | text/x-script.guile scm
66 | text/x-script.elisp el
67 | text/x-script.csh csh
68 | text/x-script hlb
69 | text/x-python py
70 | text/x-po pot po
71 | text/x-pascal p pas
72 | text/x-m m
73 | text/x-log log
74 | text/x-la-asf lsx
75 | text/x-java-source java jav
76 | text/x-java java
77 | text/x-h hh h
78 | text/x-fortran f f77 for f90
79 | text/x-csrc c
80 | text/x-component htc
81 | text/x-c++src cpp c++
82 | text/x-c++hdr h
83 | text/x-c cc cpp c
84 | text/x-bibtex bib
85 | text/x-audiosoft-intra aip
86 | text/x-asm s asm
87 | text/webviewhtml htt
88 | text/vnd.wap.wmlscript wmls
89 | text/vnd.wap.wml wml
90 | text/vnd.rn-realtext rt
91 | text/vnd.fmi.flexstor flx
92 | text/vnd.abc abc
93 | text/uri-list uni uris unis uri
94 | text/tab-separated-values tab tsv
95 | text/sgml sgml sgm
96 | text/scriplet wsc
97 | text/rtf rtf
98 | text/richtext rt rtf rtx
99 | text/plain com hh c++ def log sdml for conf TEXT lst TXT java text jav mar cc cxx c f g h idc list m txt f90 pl
100 | text/pascal pas
101 | text/mcf mcf
102 | text/javascript js
103 | text/html htm HTM htmls acgi html HTML shtml htx
104 | text/ecmascript js
105 | text/csv csv
106 | text/css css
107 | text/asp asp
108 | paleovu/x-pv pvu
109 | music/x-karaoke kar
110 | music/crescendo midi mid
111 | multipart/x-zip zip
112 | multipart/x-ustar ustar
113 | multipart/x-gzip gzip
114 | model/x-pov pov
115 | model/vrml wrl vrml wrz
116 | model/vnd.dwf dwf
117 | model/iges igs iges
118 | message/rfc822 mime mht mhtml
119 | image/xpm xpm
120 | image/xbm xbm
121 | image/x-xwindowdump xwd
122 | image/x-xwd xwd
123 | image/x-xpixmap xpm pm
124 | image/x-xbm xbm
125 | image/x-xbitmap xbm
126 | image/x-windows-bmp bmp
127 | image/x-tiff tif tiff
128 | image/x-rgb rgb
129 | image/x-quicktime qtif qti qif
130 | image/x-portable-pixmap ppm
131 | image/x-portable-greymap pgm
132 | image/x-portable-graymap pgm
133 | image/x-portable-bitmap pbm
134 | image/x-portable-anymap pnm
135 | image/x-pict pct
136 | image/x-pcx pcx
137 | image/x-niff niff nif
138 | image/x-jps jps
139 | image/x-jg art
140 | image/x-icon ico
141 | image/x-generic jpg tif wmf tiff bmp xpm png jpeg emf
142 | image/x-eps eps
143 | image/x-dwg svf dxf dwg
144 | image/x-cmu-raster ras
145 | image/vnd.xiff xif
146 | image/vnd.wap.wbmp wbmp
147 | image/vnd.rn-realpix rp
148 | image/vnd.rn-realflash rf
149 | image/vnd.net-fpx fpx
150 | image/vnd.fpx fpx
151 | image/vnd.dwg svf dxf dwg
152 | image/vasa mcf
153 | image/tiff tif tiff
154 | image/svg+xml svgz svg
155 | image/png x-png png PNG
156 | image/pjpeg jpg jfif jpeg jpe
157 | image/pict pic pict
158 | image/naplps naplps nap
159 | image/jutvision jut
160 | image/jpeg jpg JPG jfif jpeg jfif-tbnl jpe
161 | image/ief iefs ief
162 | image/gif gif GIF
163 | image/g3fax g3
164 | image/florian flo turbot
165 | image/fif fif
166 | image/cmu-raster ras rast
167 | image/bmp bmp bm
168 | i-world/i-vrml ivr
169 | drawing/x-dwf dwf (old)
170 | chemical/x-pdb xyz pdb
171 | audio/xm xm
172 | audio/x-wav wav
173 | audio/x-voc voc
174 | audio/x-vnd.audioexplosion.mjuicemediafile mjf
175 | audio/x-twinvq-plugin vql vqe
176 | audio/x-twinvq vqf
177 | audio/x-realaudio ra
178 | audio/x-psid sid
179 | audio/x-pn-realaudio-plugin rmp rpm ra
180 | audio/x-pn-realaudio rmm rmp rm ra ram
181 | audio/x-nspaudio lma la
182 | audio/x-mpequrl m3u
183 | audio/x-mpeg-3 mp3
184 | audio/x-mpeg mpg mpeg mp2
185 | audio/x-mod mod
186 | audio/x-midi midi mid
187 | audio/x-mid midi mid
188 | audio/x-liveaudio lam
189 | audio/x-jam jam
190 | audio/x-gsm gsm gsd
191 | audio/x-generic mp3 wma wav ogg
192 | audio/x-au au
193 | audio/x-aiff aiff aifc aif
194 | audio/x-aifc aifc
195 | audio/x-adpcm snd
196 | audio/wav wav
197 | audio/voxware vox
198 | audio/voc voc
199 | audio/vnd.qcelp qcp
200 | audio/tsplayer tsp
201 | audio/tsp-audio tsi
202 | audio/s3m s3m
203 | audio/nspaudio lma la
204 | audio/mpeg3 mp3
205 | audio/mpeg mp3 mpg mpeg3 m2a mp2 mpga mpa
206 | audio/mod mod
207 | audio/midi midi mid kar
208 | audio/mid rmi
209 | audio/make.my.funk pfunk
210 | audio/make pfunk funk my
211 | audio/it it
212 | audio/basic au snd
213 | audio/aiff aiff aifc aif
214 | audio/ac3 ac3
215 | application/zip zip
216 | application/xml xml
217 | application/x-zip-compressed zip
218 | application/x-x509-user-cert crt
219 | application/x-x509-ca-cert der cer crt
220 | application/x-wri wri
221 | application/x-wpwin wpd
222 | application/x-world wrl svr
223 | application/x-wintalk wtk
224 | application/x-winhelp hlp
225 | application/x-wais-source src wsrc
226 | application/x-vrml vrml
227 | application/x-vnd.oasis.opendocument.spreadsheet ods
228 | application/x-vnd.ls-xpix xpix
229 | application/x-vnd.audioexplosion.mzz mzz
230 | application/x-visio vsd vst vsw
231 | application/x-ustar ustar
232 | application/x-troff-msvideo avi
233 | application/x-troff-ms ms
234 | application/x-troff-me me
235 | application/x-troff-man man
236 | application/x-troff t roff tr
237 | application/x-trash autosave
238 | application/x-texinfo texi texinfo
239 | application/x-tex tex
240 | application/x-tcl tcl
241 | application/x-tbook tbk sbk
242 | application/x-tar tar
243 | application/x-sv4crc sv4crc
244 | application/x-sv4cpio sv4cpio
245 | application/x-stuffit sit
246 | application/x-sprite spr sprite
247 | application/x-sit sit
248 | application/x-shockwave-flash swf
249 | application/x-shellscript sh
250 | application/x-sharedlib o
251 | application/x-shar shar sh
252 | application/x-sh sh
253 | application/x-seelogo sl
254 | application/x-sea sea
255 | application/x-sdp sdp
256 | application/x-rtf rtf
257 | application/x-rpm rpm
258 | application/x-qpro wb1
259 | application/x-project mpt mpc mpv mpx
260 | application/x-portable-anymap pnm
261 | application/x-pointplus css
262 | application/x-pkcs7-signature p7a
263 | application/x-pkcs7-mime p7m p7c
264 | application/x-pkcs7-certreqresp p7r
265 | application/x-pkcs7-certificates spc
266 | application/x-pkcs12 p12
267 | application/x-pkcs10 p10
268 | application/x-pixclscript plx
269 | application/x-php php
270 | application/x-perl pl
271 | application/x-pcl pcl
272 | application/x-pagemaker pm4 pm5
273 | application/x-omcregerator omcr
274 | application/x-omcdatamaker omcd
275 | application/x-omc omc
276 | application/x-nokia-9000-communicator-add-on-software aos
277 | application/x-newton-compatible-pkg pkg
278 | application/x-netcdf cdf nc
279 | application/x-navistyle stl
280 | application/x-navimap map
281 | application/x-navidoc nvd
282 | application/x-navi-animation ani
283 | application/x-mspowerpoint ppt
284 | application/x-msexcel xlw xla xls
285 | application/x-ms-dos-executable msi exe
286 | application/x-mplayer2 asx
287 | application/x-mix-transfer nix
288 | application/x-mif mif
289 | application/x-midi midi mid
290 | application/x-meme mm
291 | application/x-mathcad mcd
292 | application/x-magic-cap-package-1.0 mc$
293 | application/x-macbinary bin
294 | application/x-mac-binhex40 hqx
295 | application/x-lzx lzx
296 | application/x-lzh lzh
297 | application/x-lotusscreencam scm
298 | application/x-lotus wq1
299 | application/x-livescreen ivy
300 | application/x-lisp lsp
301 | application/x-lha lha
302 | application/x-latex ltx latex
303 | application/x-ksh ksh
304 | application/x-koan skm skp skd skt
305 | application/x-javascript js
306 | application/x-java-commerce jcm
307 | application/x-java-class class
308 | application/x-java-archive jar
309 | application/x-java-applet class
310 | application/x-ip2 ip
311 | application/x-inventor iv
312 | application/x-internett-signup ins
313 | application/x-ima ima
314 | application/x-httpd-imap imap
315 | application/x-helpfile help hlp
316 | application/x-hdf hdf
317 | application/x-gzip gz gzip
318 | application/x-gtar gtar
319 | application/x-gss gss
320 | application/x-gsp gsp
321 | application/x-freelance pre
322 | application/x-frame mif
323 | application/x-font-ttf ttf TTF
324 | application/x-font-otf otf OTF
325 | application/x-excel xld xlt xlw xlv xlk xlm xll xla xlc xls xlb
326 | application/x-esrehber es
327 | application/x-envoy evy env
328 | application/x-elc elc
329 | application/x-dvi dvi
330 | application/x-director dcr dir dxr
331 | application/x-deepv deepv
332 | application/x-deb deb
333 | application/x-csh csh
334 | application/x-cpt cpt
335 | application/x-cpio cpio
336 | application/x-conference nsc
337 | application/x-compressed zip gz tgz z
338 | application/x-compress zip rar gz tar z
339 | application/x-compactpro cpt
340 | application/x-cocoa cco
341 | application/x-cmu-raster ras
342 | application/x-chat chat cha
343 | application/x-cdlink vcd
344 | application/x-cdf cdf
345 | application/x-cd-image iso
346 | application/x-bzip2 bz2 boz
347 | application/x-bzip bz
348 | application/x-bytecode.python pyc
349 | application/x-bytecode.elisp elisp) (compiled elc
350 | application/x-bsh shar sh bsh
351 | application/x-blender blend
352 | application/x-binhex40 hqx
353 | application/x-binary bin
354 | application/x-bcpio bcpio
355 | application/x-awk awk
356 | application/x-authorware-seg aas
357 | application/x-authorware-map aam
358 | application/x-authorware-bin aab
359 | application/x-aim aim
360 | application/x-123 wk1
361 | application/wordperfect6.1 w61
362 | application/wordperfect6.0 w60 wp5
363 | application/wordperfect wp wpd wp6 wp5
364 | application/vocaltec-media-file vmf
365 | application/vocaltec-media-desc vmd
366 | application/vnd.xara web
367 | application/vnd.wap.wmlscriptc wmlsc
368 | application/vnd.wap.wmlc wmlc
369 | application/vnd.rn-realplayer rnx
370 | application/vnd.rn-realmedia rm
371 | application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
372 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
373 | application/vnd.oasis.text odt
374 | application/vnd.oasis.spreadsheet ods
375 | application/vnd.oasis.presentation odp
376 | application/vnd.oasis.opendocument.text odt
377 | application/vnd.oasis.database odb
378 | application/vnd.nokia.ringing-tone rng
379 | application/vnd.nokia.configuration-message ncm
380 | application/vnd.ms-project mpp
381 | application/vnd.ms-powerpoint ppa pptx pps pwz pot ppt pptm
382 | application/vnd.ms-pki.stl stl
383 | application/vnd.ms-pki.seccat cat
384 | application/vnd.ms-pki.pko pko
385 | application/vnd.ms-pki.certstore sst
386 | application/vnd.ms-excel xlsx xlw xlsm xlm xll xlc xls XLS xlb
387 | application/vnd.hp-pcl pcl
388 | application/vnd.hp-hpgl hgl hpgl hpg
389 | application/vnd.fdf fdf
390 | application/vda vda
391 | application/toolbook tbk
392 | application/streamingmedia ssm
393 | application/step step stp
394 | application/sounder sdr
395 | application/solids sol
396 | application/smil smil smi
397 | application/sla stl
398 | application/set set
399 | application/sea sea
400 | application/sdp sdp
401 | application/rtf rtf rtx
402 | application/rss+xml rss
403 | application/ringing-tones rng
404 | application/pro_eng prt part
405 | application/powerpoint ppt
406 | application/postscript ps ai eps
407 | application/plain text
408 | application/pkix-crl crl
409 | application/pkix-cert cer crt
410 | application/pkcs7-signature p7s
411 | application/pkcs7-mime p7m p7c
412 | application/pkcs10 p10
413 | application/pkcs-crl crl
414 | application/pkcs-12 p12
415 | application/pdf pdf
416 | application/oda oda
417 | application/octet-stream com psd uu a lha bin lzx o arc exe arj dump lzh zoo lhx saveme
418 | application/netmc mcp
419 | application/mswrite wri
420 | application/msword dot doc w6w wiz docm word docx
421 | application/mspowerpoint pps pot ppt ppz
422 | application/mime aps
423 | application/mcad mcd
424 | application/mbedlet mbd
425 | application/marc mrc
426 | application/macbinary bin
427 | application/mac-compactpro cpt
428 | application/mac-binhex40 hqx
429 | application/mac-binhex hqx
430 | application/mac-binary bin
431 | application/lzx lzx
432 | application/lha lha
433 | application/javascript js
434 | application/java-byte-code class
435 | application/java class
436 | application/inf inf
437 | application/iges igs iges
438 | application/i-deas unv
439 | application/hta hta
440 | application/hlp hlp
441 | application/groupwise vew
442 | application/gnutar tgz
443 | application/futuresplash spl
444 | application/freeloader frl
445 | application/fractals fif
446 | application/excel xld xlt xlw xlv xl xlk xlm xll xla xlc xls xlb
447 | application/envoy evy
448 | application/ecmascript js
449 | application/dxf dxf
450 | application/dsptype tsp
451 | application/drafting drw
452 | application/commonground dp
453 | application/clariscad ccad
454 | application/cdf cdf
455 | application/book boo book
456 | application/binhex4 hqx
457 | application/binhex hqx
458 | application/base64 mm mme
459 | application/arj arj
460 | application/acad dwg
--------------------------------------------------------------------------------
/src/main/java/org/simplejavamail/com/sun/mail/util/MailLogger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License v. 2.0, which is available at
6 | * http://www.eclipse.org/legal/epl-2.0.
7 | *
8 | * This Source Code may also be made available under the following Secondary
9 | * Licenses when the conditions for such availability set forth in the
10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11 | * version 2 with the GNU Classpath Exception, which is available at
12 | * https://www.gnu.org/software/classpath/license.html.
13 | *
14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15 | */
16 |
17 | package org.simplejavamail.com.sun.mail.util;
18 |
19 | import java.io.PrintStream;
20 | import java.text.MessageFormat;
21 | import java.util.logging.Level;
22 | import java.util.logging.Logger;
23 |
24 | /**
25 | * A simplified logger used by Jakarta Mail to handle logging to a
26 | * PrintStream and logging through a java.util.logging.Logger.
27 | * If debug is set, messages are written to the PrintStream and
28 | * prefixed by the specified prefix (which is not included in
29 | * Logger messages).
30 | * Messages are logged by the Logger based on the configuration
31 | * of the logging system.
32 | */
33 |
34 | /*
35 | * It would be so much simpler to just subclass Logger and override
36 | * the log(LogRecord) method, as the javadocs suggest, but that doesn't
37 | * work because Logger makes the decision about whether to log the message
38 | * or not before calling the log(LogRecord) method. Instead, we just
39 | * provide the few log methods we need here.
40 | */
41 |
42 | public final class MailLogger {
43 | /**
44 | * For log messages.
45 | */
46 | private final Logger logger;
47 | /**
48 | * For debug output.
49 | */
50 | private final String prefix;
51 | /**
52 | * Produce debug output?
53 | */
54 | private final boolean debug;
55 | /**
56 | * Stream for debug output.
57 | */
58 | private final PrintStream out;
59 |
60 | /**
61 | * Construct a new MailLogger using the specified Logger name,
62 | * debug prefix (e.g., "DEBUG"), debug flag, and PrintStream.
63 | *
64 | * @param name the Logger name
65 | * @param prefix the prefix for debug output, or null for none
66 | * @param debug if true, write to PrintStream
67 | * @param out the PrintStream to write to
68 | */
69 | public MailLogger(String name, String prefix, boolean debug,
70 | PrintStream out) {
71 | logger = Logger.getLogger(name);
72 | this.prefix = prefix;
73 | this.debug = debug;
74 | this.out = out != null ? out : System.out;
75 | }
76 |
77 | /**
78 | * Construct a new MailLogger using the specified class' package
79 | * name as the Logger name,
80 | * debug prefix (e.g., "DEBUG"), debug flag, and PrintStream.
81 | *
82 | * @param clazz the Logger name is the package name of this class
83 | * @param prefix the prefix for debug output, or null for none
84 | * @param debug if true, write to PrintStream
85 | * @param out the PrintStream to write to
86 | */
87 | public MailLogger(Class> clazz, String prefix, boolean debug,
88 | PrintStream out) {
89 | String name = packageOf(clazz);
90 | logger = Logger.getLogger(name);
91 | this.prefix = prefix;
92 | this.debug = debug;
93 | this.out = out != null ? out : System.out;
94 | }
95 |
96 | /**
97 | * Construct a new MailLogger using the specified class' package
98 | * name combined with the specified subname as the Logger name,
99 | * debug prefix (e.g., "DEBUG"), debug flag, and PrintStream.
100 | *
101 | * @param clazz the Logger name is the package name of this class
102 | * @param subname the Logger name relative to this Logger name
103 | * @param prefix the prefix for debug output, or null for none
104 | * @param debug if true, write to PrintStream
105 | * @param out the PrintStream to write to
106 | */
107 | public MailLogger(Class> clazz, String subname, String prefix, boolean debug,
108 | PrintStream out) {
109 | String name = packageOf(clazz) + "." + subname;
110 | logger = Logger.getLogger(name);
111 | this.prefix = prefix;
112 | this.debug = debug;
113 | this.out = out != null ? out : System.out;
114 | }
115 |
116 | /**
117 | * Create a MailLogger that uses a Logger with the specified name
118 | * and prefix. The new MailLogger uses the same debug flag and
119 | * PrintStream as this MailLogger.
120 | *
121 | * @param name the Logger name
122 | * @param prefix the prefix for debug output, or null for none
123 | * @return a MailLogger for the given name and prefix.
124 | */
125 | public MailLogger getLogger(String name, String prefix) {
126 | return new MailLogger(name, prefix, debug, out);
127 | }
128 |
129 | /**
130 | * Create a MailLogger using the specified class' package
131 | * name as the Logger name and the specified prefix.
132 | * The new MailLogger uses the same debug flag and
133 | * PrintStream as this MailLogger.
134 | *
135 | * @param clazz the Logger name is the package name of this class
136 | * @param prefix the prefix for debug output, or null for none
137 | * @return a MailLogger for the given name and prefix.
138 | */
139 | public MailLogger getLogger(Class> clazz, String prefix) {
140 | return new MailLogger(clazz, prefix, debug, out);
141 | }
142 |
143 | /**
144 | * Create a MailLogger that uses a Logger whose name is composed
145 | * of this MailLogger's name plus the specified sub-name, separated
146 | * by a dot. The new MailLogger uses the new prefix for debug output.
147 | * This is used primarily by the protocol trace code that wants a
148 | * different prefix (none).
149 | *
150 | * @param subname the Logger name relative to this Logger name
151 | * @param prefix the prefix for debug output, or null for none
152 | * @return a MailLogger for the given name and prefix.
153 | */
154 | public MailLogger getSubLogger(String subname, String prefix) {
155 | return new MailLogger(logger.getName() + "." + subname, prefix,
156 | debug, out);
157 | }
158 |
159 | /**
160 | * Create a MailLogger that uses a Logger whose name is composed
161 | * of this MailLogger's name plus the specified sub-name, separated
162 | * by a dot. The new MailLogger uses the new prefix for debug output.
163 | * This is used primarily by the protocol trace code that wants a
164 | * different prefix (none).
165 | *
166 | * @param subname the Logger name relative to this Logger name
167 | * @param prefix the prefix for debug output, or null for none
168 | * @param debug the debug flag for the sub-logger
169 | * @return a MailLogger for the given name and prefix.
170 | */
171 | public MailLogger getSubLogger(String subname, String prefix,
172 | boolean debug) {
173 | return new MailLogger(logger.getName() + "." + subname, prefix,
174 | debug, out);
175 | }
176 |
177 | /**
178 | * Log the message at the specified level.
179 | * @param level the log level.
180 | * @param msg the message.
181 | */
182 | public void log(Level level, String msg) {
183 | ifDebugOut(msg);
184 | if (logger.isLoggable(level)) {
185 | final StackTraceElement frame = inferCaller();
186 | logger.logp(level, frame.getClassName(), frame.getMethodName(), msg);
187 | }
188 | }
189 |
190 | /**
191 | * Log the message at the specified level.
192 | * @param level the log level.
193 | * @param msg the message.
194 | * @param param1 the additional parameter.
195 | */
196 | public void log(Level level, String msg, Object param1) {
197 | if (debug) {
198 | msg = MessageFormat.format(msg, new Object[] { param1 });
199 | debugOut(msg);
200 | }
201 |
202 | if (logger.isLoggable(level)) {
203 | final StackTraceElement frame = inferCaller();
204 | logger.logp(level, frame.getClassName(), frame.getMethodName(), msg, param1);
205 | }
206 | }
207 |
208 | /**
209 | * Log the message at the specified level.
210 | * @param level the log level.
211 | * @param msg the message.
212 | * @param params the message parameters.
213 | */
214 | public void log(Level level, String msg, Object... params) {
215 | if (debug) {
216 | msg = MessageFormat.format(msg, params);
217 | debugOut(msg);
218 | }
219 |
220 | if (logger.isLoggable(level)) {
221 | final StackTraceElement frame = inferCaller();
222 | logger.logp(level, frame.getClassName(), frame.getMethodName(), msg, params);
223 | }
224 | }
225 |
226 | /**
227 | * Log the message at the specified level using a format string.
228 | * @param level the log level.
229 | * @param msg the message format string.
230 | * @param params the message parameters.
231 | *
232 | * @since JavaMail 1.5.4
233 | */
234 | public void logf(Level level, String msg, Object... params) {
235 | msg = String.format(msg, params);
236 | ifDebugOut(msg);
237 | logger.log(level, msg);
238 | }
239 |
240 | /**
241 | * Log the message at the specified level.
242 | * @param level the log level.
243 | * @param msg the message.
244 | * @param thrown the throwable to log.
245 | */
246 | public void log(Level level, String msg, Throwable thrown) {
247 | if (debug) {
248 | if (thrown != null) {
249 | debugOut(msg + ", THROW: ");
250 | thrown.printStackTrace(out);
251 | } else {
252 | debugOut(msg);
253 | }
254 | }
255 |
256 | if (logger.isLoggable(level)) {
257 | final StackTraceElement frame = inferCaller();
258 | logger.logp(level, frame.getClassName(), frame.getMethodName(), msg, thrown);
259 | }
260 | }
261 |
262 | /**
263 | * Log a message at the CONFIG level.
264 | * @param msg the message.
265 | */
266 | public void config(String msg) {
267 | log(Level.CONFIG, msg);
268 | }
269 |
270 | /**
271 | * Log a message at the FINE level.
272 | * @param msg the message.
273 | */
274 | public void fine(String msg) {
275 | log(Level.FINE, msg);
276 | }
277 |
278 | /**
279 | * Log a message at the FINER level.
280 | * @param msg the message.
281 | */
282 | public void finer(String msg) {
283 | log(Level.FINER, msg);
284 | }
285 |
286 | /**
287 | * Log a message at the FINEST level.
288 | * @param msg the message.
289 | */
290 | public void finest(String msg) {
291 | log(Level.FINEST, msg);
292 | }
293 |
294 | /**
295 | * If "debug" is set, or our embedded Logger is loggable at the
296 | * given level, return true.
297 | * @param level the log level.
298 | * @return true if loggable.
299 | */
300 | public boolean isLoggable(Level level) {
301 | return debug || logger.isLoggable(level);
302 | }
303 |
304 | /**
305 | * Common code to conditionally log debug statements.
306 | * @param msg the message to log.
307 | */
308 | private void ifDebugOut(String msg) {
309 | if (debug)
310 | debugOut(msg);
311 | }
312 |
313 | /**
314 | * Common formatting for debug output.
315 | * @param msg the message to log.
316 | */
317 | private void debugOut(String msg) {
318 | if (prefix != null)
319 | out.println(prefix + ": " + msg);
320 | else
321 | out.println(msg);
322 | }
323 |
324 | /**
325 | * Return the package name of the class.
326 | * Sometimes there will be no Package object for the class,
327 | * e.g., if the class loader hasn't created one (see Class.getPackage()).
328 | * @param clazz the class source.
329 | * @return the package name or an empty string.
330 | */
331 | private String packageOf(Class> clazz) {
332 | Package p = clazz.getPackage();
333 | if (p != null)
334 | return p.getName(); // hopefully the common case
335 | String cname = clazz.getName();
336 | int i = cname.lastIndexOf('.');
337 | if (i > 0)
338 | return cname.substring(0, i);
339 | // no package name, now what?
340 | return "";
341 | }
342 |
343 | /**
344 | * A disadvantage of not being able to use Logger directly in Jakarta Mail
345 | * code is that the "source class" information that Logger guesses will
346 | * always refer to this class instead of our caller. This method
347 | * duplicates what Logger does to try to find *our* caller, so that
348 | * Logger doesn't have to do it (and get the wrong answer), and because
349 | * our caller is what's wanted.
350 | * @return StackTraceElement that logged the message. Treat as read-only.
351 | */
352 | private StackTraceElement inferCaller() {
353 | // Get the stack trace.
354 | StackTraceElement stack[] = (new Throwable()).getStackTrace();
355 | // First, search back to a method in the Logger class.
356 | int ix = 0;
357 | while (ix < stack.length) {
358 | StackTraceElement frame = stack[ix];
359 | String cname = frame.getClassName();
360 | if (isLoggerImplFrame(cname)) {
361 | break;
362 | }
363 | ix++;
364 | }
365 | // Now search for the first frame before the "Logger" class.
366 | while (ix < stack.length) {
367 | StackTraceElement frame = stack[ix];
368 | String cname = frame.getClassName();
369 | if (!isLoggerImplFrame(cname)) {
370 | // We've found the relevant frame.
371 | return frame;
372 | }
373 | ix++;
374 | }
375 | // We haven't found a suitable frame, so just punt. This is
376 | // OK as we are only committed to making a "best effort" here.
377 | return new StackTraceElement(MailLogger.class.getName(), "log",
378 | MailLogger.class.getName(), -1);
379 | }
380 |
381 | /**
382 | * Frames to ignore as part of the MailLogger to JUL bridge.
383 | * @param cname the class name.
384 | * @return true if the class name is part of the MailLogger bridge.
385 | */
386 | private boolean isLoggerImplFrame(String cname) {
387 | return MailLogger.class.getName().equals(cname);
388 | }
389 | }
390 |
--------------------------------------------------------------------------------
/src/main/java/org/simplejavamail/jakarta/mail/internet/HeaderTokenizer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License v. 2.0, which is available at
6 | * http://www.eclipse.org/legal/epl-2.0.
7 | *
8 | * This Source Code may also be made available under the following Secondary
9 | * Licenses when the conditions for such availability set forth in the
10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11 | * version 2 with the GNU Classpath Exception, which is available at
12 | * https://www.gnu.org/software/classpath/license.html.
13 | *
14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15 | */
16 |
17 | package org.simplejavamail.jakarta.mail.internet;
18 |
19 | import java.util.*;
20 |
21 | /**
22 | * This class tokenizes RFC822 and MIME headers into the basic
23 | * symbols specified by RFC822 and MIME.
83 | *
92 | *
93 | * @return the token type
94 | */
95 | public int getType() {
96 | return type;
97 | }
98 |
99 | /**
100 | * Returns the value of the token just read. When the current
101 | * token is a quoted string, this field contains the body of the
102 | * string, without the quotes. When the current token is a comment,
103 | * this field contains the body of the comment.
104 | *
105 | * @return token value
106 | */
107 | public String getValue() {
108 | return value;
109 | }
110 | }
111 |
112 | private String string; // the string to be tokenized
113 | private boolean skipComments; // should comments be skipped ?
114 | private String delimiters; // delimiter string
115 | private int currentPos; // current parse position
116 | private int maxPos; // string length
117 | private int nextPos; // track start of next Token for next()
118 | private int peekPos; // track start of next Token for peek()
119 |
120 | /**
121 | * RFC822 specials
122 | */
123 | public final static String RFC822 = "()<>@,;:\\\"\t .[]";
124 |
125 | /**
126 | * MIME specials
127 | */
128 | public final static String MIME = "()<>@,;:\\\"\t []/?=";
129 |
130 | // The EOF Token
131 | private final static Token EOFToken = new Token(Token.EOF, null);
132 |
133 | /**
134 | * Constructor that takes a rfc822 style header.
135 | *
136 | * @param header The rfc822 header to be tokenized
137 | * @param delimiters Set of delimiter characters
138 | * to be used to delimit ATOMS. These
139 | * are usually ATOM A sequence of ASCII characters
84 | * delimited by either SPACE, CTL, "(", <"> or the
85 | * specified SPECIALS
86 | * QUOTEDSTRING A sequence of ASCII characters
87 | * within quotes
88 | * COMMENT A sequence of ASCII characters
89 | * within "(" and ")".
90 | * EOF End of header
91 | * RFC822 or
140 | * MIME
141 | * @param skipComments If true, comments are skipped and
142 | * not returned as tokens
143 | */
144 | public HeaderTokenizer(String header, String delimiters,
145 | boolean skipComments) {
146 | string = (header == null) ? "" : header; // paranoia ?!
147 | this.skipComments = skipComments;
148 | this.delimiters = delimiters;
149 | currentPos = nextPos = peekPos = 0;
150 | maxPos = string.length();
151 | }
152 |
153 | /**
154 | * Constructor. Comments are ignored and not returned as tokens
155 | *
156 | * @param header The header that is tokenized
157 | * @param delimiters The delimiters to be used
158 | */
159 | public HeaderTokenizer(String header, String delimiters) {
160 | this(header, delimiters, true);
161 | }
162 |
163 | /**
164 | * Constructor. The RFC822 defined delimiters - RFC822 - are
165 | * used to delimit ATOMS. Also comments are skipped and not
166 | * returned as tokens
167 | *
168 | * @param header the header string
169 | */
170 | public HeaderTokenizer(String header) {
171 | this(header, RFC822);
172 | }
173 |
174 | /**
175 | * Parses the next token from this String. next() is
232 | * called.
A note on RFC822 and MIME headerssetHeader, addHeader, and
44 | * addHeaderLine methods are responsible for enforcing
45 | * the MIME requirements for the specified headers. In addition, these
46 | * header fields must be folded (wrapped) before being sent if they
47 | * exceed the line length limitation for the transport (1000 bytes for
48 | * SMTP). Received headers may have been folded. The application is
49 | * responsible for folding and unfolding headers as appropriate. mail.mime.ignorewhitespacelines, which if set to true
53 | * will cause a line containing only whitespace to be considered
54 | * a blank line terminating the header.
55 | *
56 | * @see org.simplejavamail.jakarta.mail.internet.MimeUtility
57 | * @author John Mani
58 | * @author Bill Shannon
59 | */
60 |
61 | public class InternetHeaders {
62 | private static final boolean ignoreWhitespaceLines =
63 | PropUtil.getBooleanSystemProperty("mail.mime.ignorewhitespacelines",
64 | false);
65 |
66 | /**
67 | * An individual internet header. This class is only used by
68 | * subclasses of InternetHeaders. Received and
272 | * Return-Path headers). If no existing header
273 | * or placeholder for the header is found, new headers are
274 | * added after the special placeholder with the name ":".
275 | *
276 | * @since JavaMail 1.4
277 | */
278 | protected Listnull
456 | * if no headers with the specified name exist.
457 | *
458 | * @param name header name
459 | * @return array of header values, or null if none
460 | */
461 | public String[] getHeader(String name) {
462 | Iteratornull, only the first header is
484 | * returned. Returns null
485 | * if no headers with the specified name exist.
486 | *
487 | * @param name header name
488 | * @param delimiter delimiter
489 | * @return the value fields for all headers with
490 | * this name, or null if none
491 | */
492 | public String getHeader(String name, String delimiter) {
493 | String s[] = getHeader(name);
494 |
495 | if (s == null)
496 | return null;
497 |
498 | if ((s.length == 1) || delimiter == null)
499 | return s[0];
500 |
501 | StringBuilder r = new StringBuilder(s[0]);
502 | for (int i = 1; i < s.length; i++) {
503 | r.append(delimiter);
504 | r.append(s[i]);
505 | }
506 | return r.toString();
507 | }
508 |
509 | /**
510 | * Change the first header line that matches name
511 | * to have value, adding a new header if no existing header
512 | * matches. Remove all matching headers but the first. Received headers should be
552 | * inserted in reverse order (newest before oldest), and that they
553 | * should appear at the beginning of the headers, preceeded only by
554 | * a possible Return-Path header.