fix net-mail for module system and make tests run
Some checks are pending
CodeQL / Analyze (push) Waiting to run
Some checks are pending
CodeQL / Analyze (push) Waiting to run
This commit is contained in:
parent
52525afe72
commit
6299134fe9
68 changed files with 2609 additions and 1591 deletions
|
@ -16,7 +16,6 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
@ -121,7 +120,7 @@ public class MailcapCommandMap extends CommandMap {
|
|||
private static final String confDir;
|
||||
|
||||
static {
|
||||
String dir = null;
|
||||
String dir;
|
||||
String home = System.getProperty("java.home");
|
||||
String newdir = home + File.separator + "conf";
|
||||
File conf = new File(newdir);
|
||||
|
@ -145,35 +144,29 @@ public class MailcapCommandMap extends CommandMap {
|
|||
List<MailcapRegistry> dbv = new ArrayList<>(5); // usually 5 or less databases
|
||||
MailcapRegistry mf = null;
|
||||
dbv.add(null); // place holder for PROG entry
|
||||
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load HOME");
|
||||
String user_home = System.getProperty("user.home");
|
||||
|
||||
if (user_home != null) {
|
||||
String path = user_home + File.separator + ".mailcap";
|
||||
mf = loadFile(path);
|
||||
if (mf != null)
|
||||
dbv.add(mf);
|
||||
}
|
||||
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load SYS");
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load SYS");
|
||||
// check system's home
|
||||
if (confDir != null) {
|
||||
mf = loadFile(confDir + "mailcap");
|
||||
if (mf != null)
|
||||
dbv.add(mf);
|
||||
}
|
||||
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load JAR");
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load JAR");
|
||||
// load from the app's jar file
|
||||
loadAllResources(dbv, "META-INF/mailcap");
|
||||
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load DEF");
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load DEF");
|
||||
mf = loadResource("/META-INF/mailcap.default");
|
||||
|
||||
if (mf != null)
|
||||
if (mf != null) {
|
||||
dbv.add(mf);
|
||||
|
||||
}
|
||||
DB = new MailcapRegistry[dbv.size()];
|
||||
DB = dbv.toArray(DB);
|
||||
}
|
||||
|
@ -212,7 +205,6 @@ public class MailcapCommandMap extends CommandMap {
|
|||
*/
|
||||
public MailcapCommandMap(InputStream is) {
|
||||
this();
|
||||
|
||||
if (DB[PROG] == null) {
|
||||
try {
|
||||
DB[PROG] = getImplementation().getByInputStream(is);
|
||||
|
@ -270,36 +262,34 @@ public class MailcapCommandMap extends CommandMap {
|
|||
else
|
||||
urls = Util.getSystemResources(name);
|
||||
if (urls != null) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: getResources");
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
URL url = urls[i];
|
||||
logger.log(Level.FINE, "MailcapCommandMap: URL " + url);
|
||||
try (InputStream clis = Util.openStream(url)) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: getResources");
|
||||
for (URL url : urls) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: URL " + url);
|
||||
try (InputStream clis = url.openStream()) {
|
||||
if (clis != null) {
|
||||
v.add(getImplementation().getByInputStream(clis));
|
||||
anyLoaded = true;
|
||||
logger.log(Level.FINE, "MailcapCommandMap: " +
|
||||
"successfully loaded " +
|
||||
"mailcap file from URL: " +
|
||||
url);
|
||||
logger.log(Level.FINE, "MailcapCommandMap: " +
|
||||
"successfully loaded " +
|
||||
"mailcap file from URL: " +
|
||||
url);
|
||||
} else {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: " +
|
||||
"not loading mailcap " +
|
||||
"file from URL: " + url);
|
||||
logger.log(Level.FINE, "MailcapCommandMap: " +
|
||||
"not loading mailcap " +
|
||||
"file from URL: " + url);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: can't load " +
|
||||
url, ioex);
|
||||
logger.log(Level.FINE, "MailcapCommandMap: can't load " +
|
||||
url, ioex);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MailcapRegistryProvider. " +
|
||||
"MailcapRegistry: can't load " + name, e);
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MailcapRegistryProvider. " +
|
||||
"MailcapRegistry: can't load " + name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: can't load " + name, ex);
|
||||
logger.log(Level.FINE, "MailcapCommandMap: can't load " + name, ex);
|
||||
}
|
||||
|
||||
// if failed to load anything, fall back to old technique, just in case
|
||||
if (!anyLoaded) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: !anyLoaded");
|
||||
|
@ -314,7 +304,6 @@ public class MailcapCommandMap extends CommandMap {
|
|||
*/
|
||||
private MailcapRegistry loadFile(String name) {
|
||||
MailcapRegistry mtf = null;
|
||||
|
||||
try {
|
||||
mtf = getImplementation().getByFileName(name);
|
||||
} catch (IOException e) {
|
||||
|
@ -341,29 +330,26 @@ public class MailcapCommandMap extends CommandMap {
|
|||
*/
|
||||
public synchronized CommandInfo[] getPreferredCommands(String mimeType) {
|
||||
List<CommandInfo> cmdList = new ArrayList<>();
|
||||
if (mimeType != null)
|
||||
if (mimeType != null) {
|
||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
}
|
||||
for (MailcapRegistry registry : DB) {
|
||||
if (registry == null)
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
||||
Map<String, List<String>> cmdMap = registry.getMailcapList(mimeType);
|
||||
if (cmdMap != null)
|
||||
appendPrefCmdsToList(cmdMap, cmdList);
|
||||
}
|
||||
|
||||
// now add the fallback commands
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
for (MailcapRegistry mailcapRegistry : DB) {
|
||||
if (mailcapRegistry == null)
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
||||
Map<String, List<String>> cmdMap = mailcapRegistry.getMailcapFallbackList(mimeType);
|
||||
if (cmdMap != null)
|
||||
appendPrefCmdsToList(cmdMap, cmdList);
|
||||
}
|
||||
|
||||
CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
|
||||
cmdInfos = cmdList.toArray(cmdInfos);
|
||||
|
||||
return cmdInfos;
|
||||
}
|
||||
|
||||
|
@ -371,10 +357,7 @@ public class MailcapCommandMap extends CommandMap {
|
|||
* Put the commands that are in the hash table, into the list.
|
||||
*/
|
||||
private void appendPrefCmdsToList(Map<String, List<String>> cmdHash, List<CommandInfo> cmdList) {
|
||||
Iterator<String> verb_enum = cmdHash.keySet().iterator();
|
||||
|
||||
while (verb_enum.hasNext()) {
|
||||
String verb = verb_enum.next();
|
||||
for (String verb : cmdHash.keySet()) {
|
||||
if (!checkForVerb(cmdList, verb)) {
|
||||
List<String> cmdList2 = cmdHash.get(verb); // get the list
|
||||
String className = cmdList2.get(0);
|
||||
|
@ -388,11 +371,11 @@ public class MailcapCommandMap extends CommandMap {
|
|||
* true if the verb is there.
|
||||
*/
|
||||
private boolean checkForVerb(List<CommandInfo> cmdList, String verb) {
|
||||
Iterator<CommandInfo> ee = cmdList.iterator();
|
||||
while (ee.hasNext()) {
|
||||
String enum_verb = (ee.next()).getCommandName();
|
||||
if (enum_verb.equals(verb))
|
||||
for (CommandInfo commandInfo : cmdList) {
|
||||
String enum_verb = commandInfo.getCommandName();
|
||||
if (enum_verb.equals(verb)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -406,29 +389,29 @@ public class MailcapCommandMap extends CommandMap {
|
|||
*/
|
||||
public synchronized CommandInfo[] getAllCommands(String mimeType) {
|
||||
List<CommandInfo> cmdList = new ArrayList<>();
|
||||
if (mimeType != null)
|
||||
if (mimeType != null) {
|
||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
||||
if (cmdMap != null)
|
||||
appendCmdsToList(cmdMap, cmdList);
|
||||
}
|
||||
|
||||
for (MailcapRegistry mailcapRegistry : DB) {
|
||||
if (mailcapRegistry == null) {
|
||||
continue;
|
||||
}
|
||||
Map<String, List<String>> cmdMap = mailcapRegistry.getMailcapList(mimeType);
|
||||
if (cmdMap != null) {
|
||||
appendCmdsToList(cmdMap, cmdList);
|
||||
}
|
||||
}
|
||||
// now add the fallback commands
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
for (MailcapRegistry mailcapRegistry : DB) {
|
||||
if (mailcapRegistry == null) {
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
||||
}
|
||||
Map<String, List<String>> cmdMap = mailcapRegistry.getMailcapFallbackList(mimeType);
|
||||
if (cmdMap != null)
|
||||
appendCmdsToList(cmdMap, cmdList);
|
||||
}
|
||||
|
||||
CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
|
||||
cmdInfos = cmdList.toArray(cmdInfos);
|
||||
|
||||
return cmdInfos;
|
||||
}
|
||||
|
||||
|
@ -436,17 +419,10 @@ public class MailcapCommandMap extends CommandMap {
|
|||
* Put the commands that are in the hash table, into the list.
|
||||
*/
|
||||
private void appendCmdsToList(Map<String, List<String>> typeHash, List<CommandInfo> cmdList) {
|
||||
Iterator<String> verb_enum = typeHash.keySet().iterator();
|
||||
|
||||
while (verb_enum.hasNext()) {
|
||||
String verb = verb_enum.next();
|
||||
for (String verb : typeHash.keySet()) {
|
||||
List<String> cmdList2 = typeHash.get(verb);
|
||||
Iterator<String> cmd_enum = cmdList2.iterator();
|
||||
|
||||
while (cmd_enum.hasNext()) {
|
||||
String cmd = cmd_enum.next();
|
||||
for (String cmd : cmdList2) {
|
||||
cmdList.add(new CommandInfo(verb, cmd));
|
||||
// cmdList.add(0, new CommandInfo(verb, cmd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -460,36 +436,35 @@ public class MailcapCommandMap extends CommandMap {
|
|||
*/
|
||||
public synchronized CommandInfo getCommand(String mimeType,
|
||||
String cmdName) {
|
||||
if (mimeType != null)
|
||||
if (mimeType != null) {
|
||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
}
|
||||
for (MailcapRegistry mailcapRegistry : DB) {
|
||||
if (mailcapRegistry == null) {
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
||||
}
|
||||
Map<String, List<String>> cmdMap = mailcapRegistry.getMailcapList(mimeType);
|
||||
if (cmdMap != null) {
|
||||
// get the cmd list for the cmd
|
||||
List<String> v = cmdMap.get(cmdName);
|
||||
if (v != null) {
|
||||
String cmdClassName = v.get(0);
|
||||
|
||||
String cmdClassName = v.getFirst();
|
||||
if (cmdClassName != null)
|
||||
return new CommandInfo(cmdName, cmdClassName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now try the fallback list
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
for (MailcapRegistry mailcapRegistry : DB) {
|
||||
if (mailcapRegistry == null) {
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
||||
}
|
||||
Map<String, List<String>> cmdMap = mailcapRegistry.getMailcapFallbackList(mimeType);
|
||||
if (cmdMap != null) {
|
||||
// get the cmd list for the cmd
|
||||
List<String> v = cmdMap.get(cmdName);
|
||||
if (v != null) {
|
||||
String cmdClassName = v.get(0);
|
||||
|
||||
String cmdClassName = v.getFirst();
|
||||
if (cmdClassName != null)
|
||||
return new CommandInfo(cmdName, cmdClassName);
|
||||
}
|
||||
|
@ -509,7 +484,7 @@ public class MailcapCommandMap extends CommandMap {
|
|||
*/
|
||||
public synchronized void addMailcap(String mail_cap) {
|
||||
// check to see if one exists
|
||||
logger.log(Level.FINE, "MailcapCommandMap: add to PROG");
|
||||
logger.log(Level.FINE, "MailcapCommandMap: add to PROG");
|
||||
try {
|
||||
if (DB[PROG] == null) {
|
||||
DB[PROG] = getImplementation().getInMemory();
|
||||
|
@ -530,31 +505,32 @@ public class MailcapCommandMap extends CommandMap {
|
|||
*/
|
||||
public synchronized DataContentHandler createDataContentHandler(
|
||||
String mimeType) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: createDataContentHandler for " + mimeType);
|
||||
if (mimeType != null)
|
||||
logger.log(Level.FINE, "MailcapCommandMap: createDataContentHandler for " + mimeType);
|
||||
if (mimeType != null) {
|
||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
}
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
if (DB[i] == null) {
|
||||
continue;
|
||||
logger.log(Level.FINE, " search DB #" + i);
|
||||
}
|
||||
logger.log(Level.FINE, " search DB #" + i);
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
||||
if (cmdMap != null) {
|
||||
List<String> v = cmdMap.get("content-handler");
|
||||
if (v != null) {
|
||||
String name = v.get(0);
|
||||
String name = v.getFirst();
|
||||
DataContentHandler dch = getDataContentHandler(name);
|
||||
if (dch != null)
|
||||
return dch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now try the fallback entries
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
if (DB[i] == null) {
|
||||
continue;
|
||||
logger.log(Level.FINE, " search fallback DB #" + i);
|
||||
}
|
||||
logger.log(Level.FINE, " search fallback DB #" + i);
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
||||
if (cmdMap != null) {
|
||||
List<String> v = cmdMap.get("content-handler");
|
||||
|
@ -602,23 +578,21 @@ public class MailcapCommandMap extends CommandMap {
|
|||
*/
|
||||
public synchronized String[] getMimeTypes() {
|
||||
List<String> mtList = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
for (MailcapRegistry mailcapRegistry : DB) {
|
||||
if (mailcapRegistry == null) {
|
||||
continue;
|
||||
String[] ts = DB[i].getMimeTypes();
|
||||
}
|
||||
String[] ts = mailcapRegistry.getMimeTypes();
|
||||
if (ts != null) {
|
||||
for (int j = 0; j < ts.length; j++) {
|
||||
for (String t : ts) {
|
||||
// eliminate duplicates
|
||||
if (!mtList.contains(ts[j]))
|
||||
mtList.add(ts[j]);
|
||||
if (!mtList.contains(t))
|
||||
mtList.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String[] mts = new String[mtList.size()];
|
||||
mts = mtList.toArray(mts);
|
||||
|
||||
return mts;
|
||||
}
|
||||
|
||||
|
@ -657,7 +631,6 @@ public class MailcapCommandMap extends CommandMap {
|
|||
}
|
||||
String[] cmds = new String[cmdList.size()];
|
||||
cmds = cmdList.toArray(cmds);
|
||||
|
||||
return cmds;
|
||||
}
|
||||
|
||||
|
|
|
@ -113,9 +113,11 @@ public class MimetypesFileTypeMap extends FileTypeMap {
|
|||
logger.log(Level.FINE, "MimetypesFileTypeMap: load DEF");
|
||||
mf = loadResource("/META-INF/mimetypes.default");
|
||||
|
||||
if (mf != null)
|
||||
if (mf != null) {
|
||||
dbv.addElement(mf);
|
||||
|
||||
} else {
|
||||
logger.log(Level.WARNING, "mimetype.default not found");
|
||||
}
|
||||
DB = new MimeTypeRegistry[dbv.size()];
|
||||
dbv.copyInto(DB);
|
||||
}
|
||||
|
@ -212,7 +214,7 @@ public class MimetypesFileTypeMap extends FileTypeMap {
|
|||
InputStream clis = null;
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: URL " + url);
|
||||
try {
|
||||
clis = Util.openStream(url);
|
||||
clis = url.openStream();
|
||||
if (clis != null) {
|
||||
v.addElement(
|
||||
getImplementation().getByInputStream(clis)
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.util.List;
|
|||
class Util {
|
||||
|
||||
private Util() {
|
||||
// private constructor, can't create an instance
|
||||
}
|
||||
|
||||
public static ClassLoader getContextClassLoader() {
|
||||
|
@ -71,8 +70,4 @@ class Util {
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static InputStream openStream(final URL url) throws IOException {
|
||||
return url.openStream();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,25 +17,21 @@
|
|||
package jakarta.mail;
|
||||
|
||||
import jakarta.mail.util.LineInputStream;
|
||||
import jakarta.mail.util.ResourceLoader;
|
||||
import jakarta.mail.util.StreamLoader;
|
||||
import jakarta.mail.util.StreamProvider;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.StringTokenizer;
|
||||
|
@ -44,14 +40,6 @@ import java.util.concurrent.Executors;
|
|||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Support interface to generalize
|
||||
* code that loads resources from stream.
|
||||
*/
|
||||
interface StreamLoader {
|
||||
void load(InputStream is) throws IOException;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Session class represents a mail session and is not subclassed.
|
||||
* It collects together properties and defaults used by the mail API's.
|
||||
|
@ -219,19 +207,18 @@ public final class Session {
|
|||
String home = System.getProperty("java.home");
|
||||
String newdir = home + File.separator + "conf";
|
||||
File conf = new File(newdir);
|
||||
if (conf.exists())
|
||||
if (conf.exists()) {
|
||||
dir = newdir + File.separator;
|
||||
else
|
||||
dir = home + File.separator +
|
||||
"lib" + File.separator;
|
||||
} else {
|
||||
dir = home + File.separator + "lib" + File.separator;
|
||||
}
|
||||
confDir = dir;
|
||||
}
|
||||
|
||||
private final StreamProvider streamProvider;
|
||||
private final Properties props;
|
||||
private final Authenticator authenticator;
|
||||
private final Hashtable<URLName, PasswordAuthentication> authTable
|
||||
= new Hashtable<>();
|
||||
private final Hashtable<URLName, PasswordAuthentication> authTable = new Hashtable<>();
|
||||
private final List<Provider> providers = new ArrayList<>();
|
||||
private final Map<String, Provider> providersByProtocol = new HashMap<>();
|
||||
private final Map<String, Provider> providersByClassName = new HashMap<>();
|
||||
|
@ -245,15 +232,10 @@ public final class Session {
|
|||
this.props = props;
|
||||
this.authenticator = authenticator;
|
||||
this.streamProvider = StreamProvider.provider();
|
||||
|
||||
// get the Class associated with the Authenticator
|
||||
Class<?> cl;
|
||||
if (authenticator != null) {
|
||||
cl = authenticator.getClass();
|
||||
} else {
|
||||
// Use implementation class, because that class loader has access to jakarta.mail module and implementation resources
|
||||
cl = streamProvider.getClass();
|
||||
}
|
||||
// Use implementation class, because that class loader has access to jakarta.mail module and implementation resources
|
||||
cl = Objects.requireNonNullElse(authenticator, streamProvider).getClass();
|
||||
// load the resources
|
||||
loadProviders(cl);
|
||||
loadAddressMap(cl);
|
||||
|
@ -404,66 +386,6 @@ public final class Session {
|
|||
return false;
|
||||
}
|
||||
|
||||
private static ClassLoader[] getClassLoaders(final Class<?>... classes) {
|
||||
ClassLoader[] loaders = new ClassLoader[classes.length];
|
||||
int w = 0;
|
||||
for (Class<?> k : classes) {
|
||||
ClassLoader cl;
|
||||
if (k == Thread.class) {
|
||||
cl = Thread.currentThread().getContextClassLoader();
|
||||
} else if (k == System.class) {
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
} else {
|
||||
cl = k.getClassLoader();
|
||||
}
|
||||
if (cl != null) {
|
||||
loaders[w++] = cl;
|
||||
}
|
||||
}
|
||||
if (loaders.length != w) {
|
||||
loaders = Arrays.copyOf(loaders, w);
|
||||
}
|
||||
return loaders;
|
||||
}
|
||||
|
||||
private static InputStream getResourceAsStream(final Class<?> c, final String name) throws IOException {
|
||||
try {
|
||||
return c.getClassLoader().getResourceAsStream(name);
|
||||
} catch (RuntimeException e) {
|
||||
throw new IOException("ClassLoader.getResourceAsStream failed");
|
||||
}
|
||||
}
|
||||
|
||||
private static URL[] getResources(final ClassLoader cl, final String name) {
|
||||
URL[] ret = null;
|
||||
try {
|
||||
List<URL> v = Collections.list(cl.getResources(name));
|
||||
if (!v.isEmpty()) {
|
||||
ret = new URL[v.size()];
|
||||
v.toArray(ret);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static URL[] getSystemResources(final String name) {
|
||||
URL[] ret = null;
|
||||
try {
|
||||
List<URL> v = Collections.list(ClassLoader.getSystemResources(name));
|
||||
if (!v.isEmpty()) {
|
||||
ret = new URL[v.size()];
|
||||
v.toArray(ret);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static InputStream openStream(final URL url) throws IOException {
|
||||
return url.openStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stream provider instance of the session.
|
||||
*
|
||||
|
@ -503,7 +425,7 @@ public final class Session {
|
|||
*/
|
||||
public synchronized Provider getProvider(String protocol) throws NoSuchProviderException {
|
||||
|
||||
if (protocol == null || protocol.length() == 0) {
|
||||
if (protocol == null || protocol.isEmpty()) {
|
||||
throw new NoSuchProviderException("Invalid protocol: null");
|
||||
}
|
||||
|
||||
|
@ -812,7 +734,7 @@ public final class Session {
|
|||
acl = streamProvider.getClass();
|
||||
|
||||
Class<?> serviceClass = null;
|
||||
for (ClassLoader l : getClassLoaders(Thread.class,
|
||||
for (ClassLoader l : ResourceLoader.getClassLoaders(Thread.class,
|
||||
provider.getClass(),
|
||||
acl,
|
||||
streamProvider.getClass(),
|
||||
|
@ -936,40 +858,30 @@ public final class Session {
|
|||
* Load the protocol providers config files.
|
||||
*/
|
||||
private void loadProviders(Class<?> cl) {
|
||||
StreamLoader loader = new StreamLoader() {
|
||||
@Override
|
||||
public void load(InputStream is) throws IOException {
|
||||
loadProvidersFromStream(is);
|
||||
}
|
||||
};
|
||||
|
||||
StreamLoader loader = this::loadProvidersFromStream;
|
||||
// load system-wide javamail.providers from the
|
||||
// <java.home>/{conf,lib} directory
|
||||
if (confDir != null)
|
||||
loadFile(confDir + "javamail.providers", loader);
|
||||
|
||||
if (confDir != null) {
|
||||
ResourceLoader.loadFile(confDir + "javamail.providers", loader);
|
||||
}
|
||||
//Fetch classloader of given class, falling back to others if needed.
|
||||
ClassLoader gcl;
|
||||
ClassLoader[] loaders = getClassLoaders(cl, Thread.class, System.class);
|
||||
ClassLoader[] loaders = ResourceLoader.getClassLoaders(cl, Thread.class, System.class);
|
||||
if (loaders.length != 0) {
|
||||
gcl = loaders[0];
|
||||
} else {
|
||||
gcl = getClass().getClassLoader(); //getContextClassLoader(); //Fail safe
|
||||
gcl = getClass().getClassLoader();
|
||||
}
|
||||
|
||||
// next, add all the non-default services
|
||||
ServiceLoader<Provider> sl = ServiceLoader.load(Provider.class, gcl);
|
||||
for (Provider p : sl) {
|
||||
if (!containsDefaultProvider(p))
|
||||
addProvider(p);
|
||||
}
|
||||
|
||||
// load the META-INF/javamail.providers file supplied by an application
|
||||
loadAllResources("META-INF/javamail.providers", cl, loader);
|
||||
|
||||
ResourceLoader.loadAllResources("META-INF/javamail.providers", cl, loader);
|
||||
// load default META-INF/javamail.default.providers from mail.jar file
|
||||
loadResource("META-INF/javamail.default.providers", cl, loader, false);
|
||||
|
||||
ResourceLoader.loadResource("META-INF/javamail.default.providers", cl, loader, false);
|
||||
// finally, add all the default services
|
||||
sl = ServiceLoader.load(Provider.class, gcl);
|
||||
for (Provider p : sl) {
|
||||
|
@ -1013,10 +925,6 @@ public final class Session {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Following are security related methods that work on JDK 1.2 or newer.
|
||||
*/
|
||||
|
||||
private void loadProvidersFromStream(InputStream is) throws IOException {
|
||||
if (is != null) {
|
||||
LineInputStream lis = streamProvider.inputLineStream(is, false);
|
||||
|
@ -1060,7 +968,7 @@ public final class Session {
|
|||
|
||||
// check if a valid Provider; else, continue
|
||||
if (type == null || protocol == null || className == null
|
||||
|| protocol.length() == 0 || className.length() == 0) {
|
||||
|| protocol.isEmpty() || className.isEmpty()) {
|
||||
|
||||
logger.log(Level.CONFIG, "Bad provider entry: {0}",
|
||||
currLine);
|
||||
|
@ -1092,16 +1000,16 @@ public final class Session {
|
|||
StreamLoader loader = addressMap::load;
|
||||
|
||||
// load default META-INF/javamail.default.address.map from mail.jar
|
||||
loadResource("META-INF/javamail.default.address.map", cl, loader, true);
|
||||
ResourceLoader.loadResource("META-INF/javamail.default.address.map", cl, loader, true);
|
||||
|
||||
// load the META-INF/javamail.address.map file supplied by an app
|
||||
loadAllResources("META-INF/javamail.address.map", cl, loader);
|
||||
ResourceLoader.loadAllResources("META-INF/javamail.address.map", cl, loader);
|
||||
|
||||
// load system-wide javamail.address.map from the
|
||||
// <java.home>/{conf,lib} directory
|
||||
if (confDir != null)
|
||||
loadFile(confDir + "javamail.address.map", loader);
|
||||
|
||||
if (confDir != null) {
|
||||
ResourceLoader.loadFile(confDir + "javamail.address.map", loader);
|
||||
}
|
||||
if (addressMap.isEmpty()) {
|
||||
logger.config("failed to load address map, using defaults");
|
||||
addressMap.put("rfc822", "smtp");
|
||||
|
@ -1126,95 +1034,6 @@ public final class Session {
|
|||
addressMap.put(addresstype, protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from the named file.
|
||||
*/
|
||||
private void loadFile(String name, StreamLoader loader) {
|
||||
InputStream clis = null;
|
||||
try {
|
||||
clis = new BufferedInputStream(new FileInputStream(name));
|
||||
loader.load(clis);
|
||||
logger.log(Level.CONFIG, "successfully loaded file: {0}", name);
|
||||
} catch (FileNotFoundException fex) {
|
||||
// ignore it
|
||||
} catch (IOException e) {
|
||||
if (logger.isLoggable(Level.CONFIG))
|
||||
logger.log(Level.CONFIG, "not loading file: " + name, e);
|
||||
} finally {
|
||||
try {
|
||||
if (clis != null)
|
||||
clis.close();
|
||||
} catch (IOException ex) {
|
||||
} // ignore it
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from the named resource.
|
||||
*/
|
||||
private void loadResource(String name, Class<?> cl, StreamLoader loader, boolean expected) {
|
||||
try (InputStream clis = getResourceAsStream(cl, name)) {
|
||||
if (clis != null) {
|
||||
loader.load(clis);
|
||||
logger.log(Level.CONFIG, "successfully loaded resource: {0}",
|
||||
name);
|
||||
} else {
|
||||
if (expected)
|
||||
logger.log(Level.WARNING,
|
||||
"expected resource not found: {0}", name);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.CONFIG, "Exception loading resource", e);
|
||||
}
|
||||
// ignore it
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all of the named resource.
|
||||
*/
|
||||
private void loadAllResources(String name, Class<?> cl, StreamLoader loader) {
|
||||
boolean anyLoaded = false;
|
||||
try {
|
||||
URL[] urls;
|
||||
ClassLoader cld = cl.getClassLoader();
|
||||
if (cld != null)
|
||||
urls = getResources(cld, name);
|
||||
else
|
||||
urls = getSystemResources(name);
|
||||
if (urls != null) {
|
||||
for (URL url : urls) {
|
||||
logger.log(Level.CONFIG, "URL {0}", url);
|
||||
try (InputStream clis = openStream(url)) {
|
||||
if (clis != null) {
|
||||
loader.load(clis);
|
||||
anyLoaded = true;
|
||||
logger.log(Level.CONFIG,
|
||||
"successfully loaded resource: {0}", url);
|
||||
} else {
|
||||
logger.log(Level.CONFIG,
|
||||
"not loading resource: {0}", url);
|
||||
}
|
||||
} catch (FileNotFoundException fex) {
|
||||
// ignore it
|
||||
} catch (IOException ioex) {
|
||||
logger.log(Level.CONFIG, "Exception loading resource",
|
||||
ioex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.CONFIG, "Exception loading resource", ex);
|
||||
}
|
||||
|
||||
// if failed to load anything, fall back to old technique, just in case
|
||||
if (!anyLoaded) {
|
||||
/*
|
||||
logger.config("!anyLoaded");
|
||||
*/
|
||||
loadResource("/" + name, cl, loader, false);
|
||||
}
|
||||
}
|
||||
|
||||
EventQueue getEventQueue() {
|
||||
return q;
|
||||
}
|
||||
|
|
|
@ -26,8 +26,7 @@ package jakarta.mail.internet;
|
|||
|
||||
public class ContentDisposition {
|
||||
|
||||
private static final boolean contentDispositionStrict =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.contentdisposition.strict", true);
|
||||
private final boolean contentDispositionStrict;
|
||||
|
||||
private String disposition; // disposition
|
||||
private ParameterList list; // parameter list
|
||||
|
@ -36,6 +35,7 @@ public class ContentDisposition {
|
|||
* No-arg Constructor.
|
||||
*/
|
||||
public ContentDisposition() {
|
||||
contentDispositionStrict = MimeUtility.getBooleanSystemProperty("mail.mime.contentdisposition.strict", true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,6 +46,7 @@ public class ContentDisposition {
|
|||
* @since JavaMail 1.2
|
||||
*/
|
||||
public ContentDisposition(String disposition, ParameterList list) {
|
||||
this();
|
||||
this.disposition = disposition;
|
||||
this.list = list;
|
||||
}
|
||||
|
@ -60,9 +61,9 @@ public class ContentDisposition {
|
|||
* @since JavaMail 1.2
|
||||
*/
|
||||
public ContentDisposition(String s) throws ParseException {
|
||||
this();
|
||||
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
||||
HeaderTokenizer.Token tk;
|
||||
|
||||
// First "disposition" ..
|
||||
tk = h.next();
|
||||
if (tk.getType() != HeaderTokenizer.Token.ATOM) {
|
||||
|
@ -73,7 +74,6 @@ public class ContentDisposition {
|
|||
} else {
|
||||
disposition = tk.getValue();
|
||||
}
|
||||
|
||||
// Then parameters ..
|
||||
String rem = h.getRemainder();
|
||||
if (rem != null) {
|
||||
|
|
|
@ -39,16 +39,10 @@ import java.util.StringTokenizer;
|
|||
@SuppressWarnings("serial")
|
||||
public class InternetAddress extends Address {
|
||||
|
||||
private static final boolean ignoreBogusGroupName =
|
||||
MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.address.ignorebogusgroupname", true);
|
||||
private static final boolean useCanonicalHostName =
|
||||
MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.address.usecanonicalhostname", true);
|
||||
private static final boolean allowUtf8 =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.allowutf8", false);
|
||||
private static final String rfc822phrase =
|
||||
HeaderTokenizer.RFC822.replace(' ', '\0').replace('\t', '\0');
|
||||
private final boolean ignoreBogusGroupName;
|
||||
private final boolean useCanonicalHostName;
|
||||
private final boolean allowUtf8;
|
||||
private static final String rfc822phrase = HeaderTokenizer.RFC822.replace(' ', '\0').replace('\t', '\0');
|
||||
private static final String specialsNoDotNoAt = "()<>,;:\\\"[]";
|
||||
private static final String specialsNoDot = specialsNoDotNoAt + "@";
|
||||
/**
|
||||
|
@ -73,6 +67,9 @@ public class InternetAddress extends Address {
|
|||
* Default constructor.
|
||||
*/
|
||||
public InternetAddress() {
|
||||
ignoreBogusGroupName = MimeUtility.getBooleanSystemProperty("mail.mime.address.ignorebogusgroupname", true);
|
||||
useCanonicalHostName = MimeUtility.getBooleanSystemProperty("mail.mime.address.usecanonicalhostname", true);
|
||||
allowUtf8 = MimeUtility.getBooleanSystemProperty("mail.mime.allowutf8", false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,6 +89,7 @@ public class InternetAddress extends Address {
|
|||
* @throws AddressException if the parse failed
|
||||
*/
|
||||
public InternetAddress(String address) throws AddressException {
|
||||
this();
|
||||
// use our address parsing utility routine to parse the string
|
||||
InternetAddress[] a = parse(address, true);
|
||||
// if we got back anything other than a single address, it's an error
|
||||
|
@ -120,8 +118,7 @@ public class InternetAddress extends Address {
|
|||
* @since JavaMail 1.3
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public InternetAddress(String address, boolean strict)
|
||||
throws AddressException {
|
||||
public InternetAddress(String address, boolean strict) throws AddressException {
|
||||
this(address);
|
||||
if (strict) {
|
||||
if (isGroup()) {
|
||||
|
@ -158,14 +155,14 @@ public class InternetAddress extends Address {
|
|||
*/
|
||||
public InternetAddress(String address, String personal, String charset)
|
||||
throws UnsupportedEncodingException {
|
||||
this();
|
||||
this.address = address;
|
||||
setPersonal(personal, charset);
|
||||
}
|
||||
|
||||
private static String quotePhrase(String phrase) {
|
||||
private String quotePhrase(String phrase) {
|
||||
int len = phrase.length();
|
||||
boolean needQuoting = false;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = phrase.charAt(i);
|
||||
if (c == '"' || c == '\\') {
|
||||
|
@ -186,7 +183,6 @@ public class InternetAddress extends Address {
|
|||
// These characters cause the string to be quoted
|
||||
needQuoting = true;
|
||||
}
|
||||
|
||||
if (needQuoting) {
|
||||
StringBuilder sb = new StringBuilder(len + 2);
|
||||
sb.append('"').append(phrase).append('"');
|
||||
|
@ -422,7 +418,8 @@ public class InternetAddress extends Address {
|
|||
*/
|
||||
public static InternetAddress getLocalAddress(Session session) {
|
||||
try {
|
||||
return _getLocalAddress(session);
|
||||
InternetAddress internetAddress = new InternetAddress();
|
||||
return internetAddress._getLocalAddress(session);
|
||||
} catch (AddressException | UnknownHostException sex) { // ignore it
|
||||
} // ignore it
|
||||
return null;
|
||||
|
@ -433,8 +430,7 @@ public class InternetAddress extends Address {
|
|||
* the exception. Used by MimeMessage.setFrom() to report the reason
|
||||
* for the failure.
|
||||
*/
|
||||
// package-private
|
||||
static InternetAddress _getLocalAddress(Session session)
|
||||
InternetAddress _getLocalAddress(Session session)
|
||||
throws AddressException, UnknownHostException {
|
||||
String user = null, host = null, address = null;
|
||||
if (session == null) {
|
||||
|
@ -453,7 +449,6 @@ public class InternetAddress extends Address {
|
|||
host = getLocalHostName();
|
||||
}
|
||||
}
|
||||
|
||||
if (address == null && user != null && user.length() != 0 &&
|
||||
host != null && host.length() != 0)
|
||||
address = MimeUtility.quote(user.trim(), specialsNoDot + "\t ") +
|
||||
|
@ -469,7 +464,7 @@ public class InternetAddress extends Address {
|
|||
* Get the local host name from InetAddress and return it in a form
|
||||
* suitable for use in an email address.
|
||||
*/
|
||||
private static String getLocalHostName() throws UnknownHostException {
|
||||
private String getLocalHostName() throws UnknownHostException {
|
||||
String host = null;
|
||||
InetAddress me = InetAddress.getLocalHost();
|
||||
if (me != null) {
|
||||
|
@ -481,7 +476,7 @@ public class InternetAddress extends Address {
|
|||
// if we can't get our name, use local address literal
|
||||
if (host == null)
|
||||
host = me.getHostAddress();
|
||||
if (host != null && host.length() > 0 && isInetAddressLiteral(host))
|
||||
if (host != null && !host.isEmpty() && isInetAddressLiteral(host))
|
||||
host = '[' + host + ']';
|
||||
}
|
||||
return host;
|
||||
|
@ -951,7 +946,8 @@ public class InternetAddress extends Address {
|
|||
// ignore bogus "mailto:" prefix in front of an address,
|
||||
// or bogus mail header name included in the address field
|
||||
String gname = s.substring(start, index);
|
||||
if (ignoreBogusGroupName &&
|
||||
InternetAddress internetAddress = new InternetAddress();
|
||||
if (internetAddress.ignoreBogusGroupName &&
|
||||
(gname.equalsIgnoreCase("mailto") ||
|
||||
gname.equalsIgnoreCase("From") ||
|
||||
gname.equalsIgnoreCase("To") ||
|
||||
|
@ -991,8 +987,7 @@ public class InternetAddress extends Address {
|
|||
String addr = s.substring(start, end).trim();
|
||||
String pers = null;
|
||||
if (rfc822 && start_personal >= 0) {
|
||||
pers = unquote(
|
||||
s.substring(start_personal, end_personal).trim());
|
||||
pers = unquote(s.substring(start_personal, end_personal).trim());
|
||||
if (pers.trim().isEmpty())
|
||||
pers = null;
|
||||
}
|
||||
|
|
|
@ -65,9 +65,8 @@ import java.util.NoSuchElementException;
|
|||
*/
|
||||
|
||||
public class InternetHeaders {
|
||||
private static final boolean ignoreWhitespaceLines =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.ignorewhitespacelines",
|
||||
false);
|
||||
|
||||
private final boolean ignoreWhitespaceLines;
|
||||
/**
|
||||
* The actual list of Headers, including placeholder entries.
|
||||
* Placeholder entries are Headers with a null value and
|
||||
|
@ -90,6 +89,7 @@ public class InternetHeaders {
|
|||
* are inserted to indicate the preferred order of headers.
|
||||
*/
|
||||
public InternetHeaders() {
|
||||
ignoreWhitespaceLines = MimeUtility.getBooleanSystemProperty("mail.mime.ignorewhitespacelines", false);
|
||||
headers = new ArrayList<>(40);
|
||||
headers.add(new InternetHeader("Return-Path", null));
|
||||
headers.add(new InternetHeader("Received", null));
|
||||
|
@ -160,8 +160,8 @@ public class InternetHeaders {
|
|||
* @since JavaMail 1.6
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public InternetHeaders(InputStream is, boolean allowutf8)
|
||||
throws MessagingException {
|
||||
public InternetHeaders(InputStream is, boolean allowutf8) throws MessagingException {
|
||||
ignoreWhitespaceLines = MimeUtility.getBooleanSystemProperty("mail.mime.ignorewhitespacelines", false);
|
||||
headers = new ArrayList<>(40);
|
||||
load(is, allowutf8);
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ public class InternetHeaders {
|
|||
/**
|
||||
* Is this line an empty (blank) line?
|
||||
*/
|
||||
private static boolean isEmpty(String line) {
|
||||
private boolean isEmpty(String line) {
|
||||
return line.isEmpty() || (ignoreWhitespaceLines && line.trim().isEmpty());
|
||||
}
|
||||
|
||||
|
|
|
@ -82,27 +82,13 @@ import java.util.Map;
|
|||
|
||||
public class MimeBodyPart extends BodyPart implements MimePart {
|
||||
|
||||
// Paranoia:
|
||||
// allow this last minute change to be disabled if it causes problems
|
||||
static final boolean cacheMultipart = // accessed by MimeMessage
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.cachemultipart", true);
|
||||
// Paranoia:
|
||||
// allow this last minute change to be disabled if it causes problems
|
||||
private static final boolean setDefaultTextCharset =
|
||||
MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.setdefaulttextcharset", true);
|
||||
private static final boolean setContentTypeFileName =
|
||||
MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.setcontenttypefilename", true);
|
||||
private static final boolean encodeFileName =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.encodefilename", false);
|
||||
private static final boolean decodeFileName =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.decodefilename", false);
|
||||
private static final boolean ignoreMultipartEncoding =
|
||||
MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.ignoremultipartencoding", true);
|
||||
private static final boolean allowutf8 =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.allowutf8", true);
|
||||
final boolean cacheMultipart;
|
||||
private final boolean setDefaultTextCharset;
|
||||
private final boolean setContentTypeFileName ;
|
||||
private final boolean encodeFileName;
|
||||
private final boolean decodeFileName;
|
||||
private final boolean ignoreMultipartEncoding;
|
||||
private final boolean allowutf8;
|
||||
/**
|
||||
* The DataHandler object representing this Part's content.
|
||||
*/
|
||||
|
@ -144,6 +130,8 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
*/
|
||||
protected Object cachedContent;
|
||||
|
||||
private final MimeUtil mimeUtil;
|
||||
|
||||
/**
|
||||
* An empty MimeBodyPart object is created.
|
||||
* This body part maybe filled in by a client constructing a multipart
|
||||
|
@ -151,6 +139,14 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
*/
|
||||
public MimeBodyPart() {
|
||||
super();
|
||||
cacheMultipart = MimeUtility.getBooleanSystemProperty("mail.mime.cachemultipart", true);
|
||||
setDefaultTextCharset = MimeUtility.getBooleanSystemProperty("mail.mime.setdefaulttextcharset", true);
|
||||
setContentTypeFileName = MimeUtility.getBooleanSystemProperty("mail.mime.setcontenttypefilename", true);
|
||||
encodeFileName = MimeUtility.getBooleanSystemProperty("mail.mime.encodefilename", false);
|
||||
decodeFileName = MimeUtility.getBooleanSystemProperty("mail.mime.decodefilename", false);
|
||||
ignoreMultipartEncoding = MimeUtility.getBooleanSystemProperty("mail.mime.ignoremultipartencoding", true);
|
||||
allowutf8 = MimeUtility.getBooleanSystemProperty("mail.mime.allowutf8", true);
|
||||
mimeUtil = new MimeUtil();
|
||||
headers = new InternetHeaders();
|
||||
}
|
||||
|
||||
|
@ -173,11 +169,18 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
public MimeBodyPart(InputStream is) throws MessagingException {
|
||||
if (!(is instanceof ByteArrayInputStream) &&
|
||||
!(is instanceof BufferedInputStream) &&
|
||||
!(is instanceof SharedInputStream))
|
||||
!(is instanceof SharedInputStream)) {
|
||||
is = new BufferedInputStream(is);
|
||||
|
||||
}
|
||||
cacheMultipart = MimeUtility.getBooleanSystemProperty("mail.mime.cachemultipart", true);
|
||||
setDefaultTextCharset = MimeUtility.getBooleanSystemProperty("mail.mime.setdefaulttextcharset", true);
|
||||
setContentTypeFileName = MimeUtility.getBooleanSystemProperty("mail.mime.setcontenttypefilename", true);
|
||||
encodeFileName = MimeUtility.getBooleanSystemProperty("mail.mime.encodefilename", false);
|
||||
decodeFileName = MimeUtility.getBooleanSystemProperty("mail.mime.decodefilename", false);
|
||||
ignoreMultipartEncoding = MimeUtility.getBooleanSystemProperty("mail.mime.ignoremultipartencoding", true);
|
||||
allowutf8 = MimeUtility.getBooleanSystemProperty("mail.mime.allowutf8", true);
|
||||
mimeUtil = new MimeUtil();
|
||||
headers = new InternetHeaders(is);
|
||||
|
||||
if (is instanceof SharedInputStream) {
|
||||
SharedInputStream sis = (SharedInputStream) is;
|
||||
contentStream = sis.newStream(sis.getPosition(), -1);
|
||||
|
@ -204,6 +207,14 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
public MimeBodyPart(InternetHeaders headers, byte[] content)
|
||||
throws MessagingException {
|
||||
super();
|
||||
cacheMultipart = MimeUtility.getBooleanSystemProperty("mail.mime.cachemultipart", true);
|
||||
setDefaultTextCharset = MimeUtility.getBooleanSystemProperty("mail.mime.setdefaulttextcharset", true);
|
||||
setContentTypeFileName = MimeUtility.getBooleanSystemProperty("mail.mime.setcontenttypefilename", true);
|
||||
encodeFileName = MimeUtility.getBooleanSystemProperty("mail.mime.encodefilename", false);
|
||||
decodeFileName = MimeUtility.getBooleanSystemProperty("mail.mime.decodefilename", false);
|
||||
ignoreMultipartEncoding = MimeUtility.getBooleanSystemProperty("mail.mime.ignoremultipartencoding", true);
|
||||
allowutf8 = MimeUtility.getBooleanSystemProperty("mail.mime.allowutf8", true);
|
||||
mimeUtil = new MimeUtil();
|
||||
this.headers = headers;
|
||||
this.content = content;
|
||||
}
|
||||
|
@ -229,10 +240,11 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
static void setText(MimePart part, String text, String charset,
|
||||
String subtype) throws MessagingException {
|
||||
if (charset == null) {
|
||||
if (MimeUtility.checkAscii(text) != MimeUtility.ALL_ASCII)
|
||||
if (MimeUtility.checkAscii(text) != MimeUtility.ALL_ASCII) {
|
||||
charset = MimeUtility.getDefaultMIMECharset();
|
||||
else
|
||||
} else {
|
||||
charset = "us-ascii";
|
||||
}
|
||||
}
|
||||
// XXX - should at least ensure that subtype is an atom
|
||||
part.setContent(text, "text/" + subtype + "; charset=" +
|
||||
|
@ -241,10 +253,9 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
|
||||
static String getDisposition(MimePart part) throws MessagingException {
|
||||
String s = part.getHeader("Content-Disposition", null);
|
||||
|
||||
if (s == null)
|
||||
if (s == null) {
|
||||
return null;
|
||||
|
||||
}
|
||||
ContentDisposition cd = new ContentDisposition(s);
|
||||
return cd.getDisposition();
|
||||
}
|
||||
|
@ -283,8 +294,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
setDescription(MimePart part, String description, String charset)
|
||||
static void setDescription(MimePart part, String description, String charset)
|
||||
throws MessagingException {
|
||||
if (description == null) {
|
||||
part.removeHeader("Content-Description");
|
||||
|
@ -299,10 +309,9 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
}
|
||||
}
|
||||
|
||||
static String getFileName(MimePart part) throws MessagingException {
|
||||
String getFileName(MimePart part) throws MessagingException {
|
||||
String filename = null;
|
||||
String s = part.getHeader("Content-Disposition", null);
|
||||
|
||||
if (s != null) {
|
||||
// Parse the header ..
|
||||
ContentDisposition cd = new ContentDisposition(s);
|
||||
|
@ -311,7 +320,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
if (filename == null) {
|
||||
// Still no filename ? Try the "name" ContentType parameter
|
||||
s = part.getHeader("Content-Type", null);
|
||||
s = MimeUtil.cleanContentType(part, s);
|
||||
s = mimeUtil.cleanContentType(part, s);
|
||||
if (s != null) {
|
||||
try {
|
||||
ContentType ct = new ContentType(s);
|
||||
|
@ -330,7 +339,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
return filename;
|
||||
}
|
||||
|
||||
static void setFileName(MimePart part, String name)
|
||||
void setFileName(MimePart part, String name)
|
||||
throws MessagingException {
|
||||
if (encodeFileName && name != null) {
|
||||
try {
|
||||
|
@ -339,11 +348,9 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
throw new MessagingException("Can't encode filename", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the Content-Disposition "filename" parameter
|
||||
String s = part.getHeader("Content-Disposition", null);
|
||||
ContentDisposition cd =
|
||||
new ContentDisposition(s == null ? Part.ATTACHMENT : s);
|
||||
ContentDisposition cd = new ContentDisposition(s == null ? Part.ATTACHMENT : s);
|
||||
// ensure that the filename is encoded if necessary
|
||||
String charset = MimeUtility.getDefaultMIMECharset();
|
||||
ParameterList p = cd.getParameterList();
|
||||
|
@ -351,19 +358,19 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
p = new ParameterList();
|
||||
cd.setParameterList(p);
|
||||
}
|
||||
if (encodeFileName)
|
||||
if (encodeFileName) {
|
||||
p.setLiteral("filename", name);
|
||||
else
|
||||
} else {
|
||||
p.set("filename", name, charset);
|
||||
}
|
||||
part.setHeader("Content-Disposition", cd.toString());
|
||||
|
||||
/*
|
||||
* Also attempt to set the Content-Type "name" parameter,
|
||||
* to satisfy ancient MUAs. XXX - This is not RFC compliant.
|
||||
*/
|
||||
if (setContentTypeFileName) {
|
||||
s = part.getHeader("Content-Type", null);
|
||||
s = MimeUtil.cleanContentType(part, s);
|
||||
s = mimeUtil.cleanContentType(part, s);
|
||||
if (s != null) {
|
||||
try {
|
||||
ContentType cType = new ContentType(s);
|
||||
|
@ -373,10 +380,11 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
p = new ParameterList();
|
||||
cType.setParameterList(p);
|
||||
}
|
||||
if (encodeFileName)
|
||||
if (encodeFileName) {
|
||||
p.setLiteral("name", name);
|
||||
else
|
||||
} else {
|
||||
p.set("name", name, charset);
|
||||
}
|
||||
part.setHeader("Content-Type", cType.toString());
|
||||
} catch (ParseException pex) {
|
||||
} // ignore it
|
||||
|
@ -387,17 +395,14 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
static String[] getContentLanguage(MimePart part)
|
||||
throws MessagingException {
|
||||
String s = part.getHeader("Content-Language", null);
|
||||
|
||||
if (s == null)
|
||||
if (s == null) {
|
||||
return null;
|
||||
|
||||
}
|
||||
// Tokenize the header to obtain the Language-tags (skip comments)
|
||||
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
||||
List<String> v = new ArrayList<>();
|
||||
|
||||
HeaderTokenizer.Token tk;
|
||||
int tkType;
|
||||
|
||||
while (true) {
|
||||
tk = h.next(); // get a language-tag
|
||||
tkType = tk.getType();
|
||||
|
@ -408,7 +413,6 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
else // invalid token, skip it.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (v.isEmpty())
|
||||
return null;
|
||||
|
||||
|
@ -479,7 +483,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
* Content-Type of the specified MimePart. Returns
|
||||
* either the original encoding or null.
|
||||
*/
|
||||
static String restrictEncoding(MimePart part, String encoding)
|
||||
String restrictEncoding(MimePart part, String encoding)
|
||||
throws MessagingException {
|
||||
if (!ignoreMultipartEncoding || encoding == null)
|
||||
return encoding;
|
||||
|
@ -512,7 +516,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
return encoding;
|
||||
}
|
||||
|
||||
static void updateHeaders(MimePart part) throws MessagingException {
|
||||
void updateHeaders(MimePart part) throws MessagingException {
|
||||
DataHandler dh = part.getDataHandler();
|
||||
if (dh == null) // Huh ?
|
||||
return;
|
||||
|
@ -659,7 +663,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
part.removeHeader("Content-Transfer-Encoding");
|
||||
}
|
||||
|
||||
static void writeTo(MimePart part, OutputStream os, String[] ignoreList)
|
||||
void writeTo(MimePart part, OutputStream os, String[] ignoreList)
|
||||
throws IOException, MessagingException {
|
||||
|
||||
// see if we already have a LOS
|
||||
|
@ -783,7 +787,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
@Override
|
||||
public String getContentType() throws MessagingException {
|
||||
String s = getHeader("Content-Type", null);
|
||||
s = MimeUtil.cleanContentType(this, s);
|
||||
s = mimeUtil.cleanContentType(this, s);
|
||||
if (s == null)
|
||||
s = "text/plain";
|
||||
return s;
|
||||
|
@ -1324,8 +1328,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
* @since JavaMail 1.4
|
||||
*/
|
||||
@Override
|
||||
public void setText(String text, String charset, String subtype)
|
||||
throws MessagingException {
|
||||
public void setText(String text, String charset, String subtype) throws MessagingException {
|
||||
setText(this, text, charset, subtype);
|
||||
}
|
||||
|
||||
|
@ -1338,11 +1341,10 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
* {@link Part#ATTACHMENT Part.ATTACHMENT}.
|
||||
*
|
||||
* @param file the File object to attach
|
||||
* @throws IOException errors related to accessing the file
|
||||
* @throws MessagingException message related errors
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
public void attachFile(File file) throws IOException, MessagingException {
|
||||
public void attachFile(File file) throws MessagingException {
|
||||
FileDataSource fds = new FileDataSource(file);
|
||||
this.setDataHandler(new DataHandler(fds));
|
||||
this.setFileName(fds.getName());
|
||||
|
@ -1379,12 +1381,10 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
* @param file the File object to attach
|
||||
* @param contentType the Content-Type, or null
|
||||
* @param encoding the Content-Transfer-Encoding, or null
|
||||
* @throws IOException errors related to accessing the file
|
||||
* @throws MessagingException message related errors
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public void attachFile(File file, String contentType, String encoding)
|
||||
throws IOException, MessagingException {
|
||||
public void attachFile(File file, String contentType, String encoding) throws MessagingException {
|
||||
DataSource fds = new EncodedFileDataSource(file, contentType, encoding);
|
||||
this.setDataHandler(new DataHandler(fds));
|
||||
this.setFileName(fds.getName());
|
||||
|
@ -1487,8 +1487,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
|||
* @throws MessagingException for failures
|
||||
*/
|
||||
@Override
|
||||
public String getHeader(String name, String delimiter)
|
||||
throws MessagingException {
|
||||
public String getHeader(String name, String delimiter) throws MessagingException {
|
||||
return headers.getHeader(name, delimiter);
|
||||
}
|
||||
|
||||
|
|
|
@ -166,11 +166,15 @@ public class MimeMessage extends Message implements MimePart {
|
|||
* @since JavaMail 1.5
|
||||
*/
|
||||
protected Object cachedContent;
|
||||
|
||||
// Should addresses in headers be parsed in "strict" mode?
|
||||
private boolean strict = true;
|
||||
|
||||
// Is UTF-8 allowed in headers?
|
||||
private boolean allowutf8 = false;
|
||||
|
||||
private final MimeUtil mimeUtil;
|
||||
|
||||
/**
|
||||
* Default constructor. An empty message object is created.
|
||||
* The <code>headers</code> field is set to an empty InternetHeaders
|
||||
|
@ -181,6 +185,7 @@ public class MimeMessage extends Message implements MimePart {
|
|||
*/
|
||||
public MimeMessage(Session session) {
|
||||
super(session);
|
||||
mimeUtil = new MimeUtil();
|
||||
modified = true;
|
||||
headers = new InternetHeaders();
|
||||
flags = new Flags(); // empty flags object
|
||||
|
@ -204,6 +209,7 @@ public class MimeMessage extends Message implements MimePart {
|
|||
public MimeMessage(Session session, InputStream is)
|
||||
throws MessagingException {
|
||||
super(session);
|
||||
mimeUtil = new MimeUtil();
|
||||
flags = new Flags(); // empty Flags object
|
||||
initStrict();
|
||||
parse(is);
|
||||
|
@ -225,6 +231,7 @@ public class MimeMessage extends Message implements MimePart {
|
|||
@SuppressWarnings("this-escape")
|
||||
public MimeMessage(MimeMessage source) throws MessagingException {
|
||||
super(source.session);
|
||||
mimeUtil = new MimeUtil();
|
||||
flags = source.getFlags();
|
||||
if (flags == null) // make sure flags is always set
|
||||
flags = new Flags();
|
||||
|
@ -260,6 +267,7 @@ public class MimeMessage extends Message implements MimePart {
|
|||
*/
|
||||
protected MimeMessage(Folder folder, int msgnum) {
|
||||
super(folder, msgnum);
|
||||
mimeUtil = new MimeUtil();
|
||||
flags = new Flags(); // empty Flags object
|
||||
saved = true;
|
||||
initStrict();
|
||||
|
@ -428,9 +436,9 @@ public class MimeMessage extends Message implements MimePart {
|
|||
*/
|
||||
@Override
|
||||
public void setFrom() throws MessagingException {
|
||||
InternetAddress me = null;
|
||||
InternetAddress me = new InternetAddress();
|
||||
try {
|
||||
me = InternetAddress._getLocalAddress(session);
|
||||
me = me._getLocalAddress(session);
|
||||
} catch (Exception ex) {
|
||||
// if anything goes wrong (UnknownHostException),
|
||||
// chain the exception
|
||||
|
@ -982,7 +990,7 @@ public class MimeMessage extends Message implements MimePart {
|
|||
@Override
|
||||
public String getContentType() throws MessagingException {
|
||||
String s = getHeader("Content-Type", null);
|
||||
s = MimeUtil.cleanContentType(this, s);
|
||||
s = mimeUtil.cleanContentType(this, s);
|
||||
if (s == null)
|
||||
return "text/plain";
|
||||
return s;
|
||||
|
@ -1284,7 +1292,8 @@ public class MimeMessage extends Message implements MimePart {
|
|||
*/
|
||||
@Override
|
||||
public String getFileName() throws MessagingException {
|
||||
return MimeBodyPart.getFileName(this);
|
||||
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||
return mimeBodyPart.getFileName(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1309,7 +1318,8 @@ public class MimeMessage extends Message implements MimePart {
|
|||
*/
|
||||
@Override
|
||||
public void setFileName(String filename) throws MessagingException {
|
||||
MimeBodyPart.setFileName(this, filename);
|
||||
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||
mimeBodyPart.setFileName(this, filename);
|
||||
}
|
||||
|
||||
private String getHeaderName(Message.RecipientType type)
|
||||
|
@ -1475,8 +1485,9 @@ public class MimeMessage extends Message implements MimePart {
|
|||
*/
|
||||
@Override
|
||||
public Object getContent() throws IOException, MessagingException {
|
||||
if (cachedContent != null)
|
||||
if (cachedContent != null) {
|
||||
return cachedContent;
|
||||
}
|
||||
Object c;
|
||||
try {
|
||||
c = getDataHandler().getContent();
|
||||
|
@ -1490,7 +1501,8 @@ public class MimeMessage extends Message implements MimePart {
|
|||
throw e;
|
||||
}
|
||||
}
|
||||
if (MimeBodyPart.cacheMultipart &&
|
||||
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||
if (mimeBodyPart.cacheMultipart &&
|
||||
(c instanceof Multipart || c instanceof Message) &&
|
||||
(content != null || contentStream != null)) {
|
||||
cachedContent = c;
|
||||
|
@ -1498,8 +1510,9 @@ public class MimeMessage extends Message implements MimePart {
|
|||
* We may abandon the input stream so make sure
|
||||
* the MimeMultipart has consumed the stream.
|
||||
*/
|
||||
if (c instanceof MimeMultipart)
|
||||
if (c instanceof MimeMultipart) {
|
||||
((MimeMultipart) c).parse();
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
@ -1866,7 +1879,8 @@ public class MimeMessage extends Message implements MimePart {
|
|||
saveChanges();
|
||||
|
||||
if (modified) {
|
||||
MimeBodyPart.writeTo(this, os, ignoreList);
|
||||
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||
mimeBodyPart.writeTo(this, os, ignoreList);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2221,7 +2235,8 @@ public class MimeMessage extends Message implements MimePart {
|
|||
* @throws MessagingException for other failures
|
||||
*/
|
||||
protected synchronized void updateHeaders() throws MessagingException {
|
||||
MimeBodyPart.updateHeaders(this);
|
||||
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||
mimeBodyPart.updateHeaders(this);
|
||||
setHeader("MIME-Version", "1.0");
|
||||
if (getHeader("Date") == null)
|
||||
setSentDate(new Date());
|
||||
|
|
|
@ -259,18 +259,15 @@ public class MimeMultipart extends Multipart {
|
|||
@SuppressWarnings("this-escape")
|
||||
public MimeMultipart(DataSource ds) throws MessagingException {
|
||||
super();
|
||||
|
||||
if (ds instanceof MessageAware) {
|
||||
MessageContext mc = ((MessageAware) ds).getMessageContext();
|
||||
setParent(mc.getPart());
|
||||
}
|
||||
|
||||
if (ds instanceof MultipartDataSource) {
|
||||
// ask super to do this for us.
|
||||
setMultipartDataSource((MultipartDataSource) ds);
|
||||
return;
|
||||
}
|
||||
|
||||
// 'ds' was not a MultipartDataSource, we have
|
||||
// to parse this ourself.
|
||||
parsed = false;
|
||||
|
@ -327,20 +324,10 @@ public class MimeMultipart extends Multipart {
|
|||
* @since JavaMail 1.5
|
||||
*/
|
||||
private void initializeProperties() {
|
||||
// read properties that control parsing
|
||||
|
||||
// default to true
|
||||
ignoreMissingEndBoundary = MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.multipart.ignoremissingendboundary", true);
|
||||
// default to true
|
||||
ignoreMissingBoundaryParameter = MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.multipart.ignoremissingboundaryparameter", true);
|
||||
// default to false
|
||||
ignoreExistingBoundaryParameter = MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.multipart.ignoreexistingboundaryparameter", false);
|
||||
// default to false
|
||||
allowEmpty = MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.multipart.allowempty", false);
|
||||
ignoreMissingEndBoundary = MimeUtility.getBooleanSystemProperty("mail.mime.multipart.ignoremissingendboundary", true);
|
||||
ignoreMissingBoundaryParameter = MimeUtility.getBooleanSystemProperty("mail.mime.multipart.ignoremissingboundaryparameter", true);
|
||||
ignoreExistingBoundaryParameter = MimeUtility.getBooleanSystemProperty("mail.mime.multipart.ignoreexistingboundaryparameter", false);
|
||||
allowEmpty = MimeUtility.getBooleanSystemProperty("mail.mime.multipart.allowempty", false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -83,8 +83,8 @@ public class MimePartDataSource implements DataSource, MessageAware {
|
|||
else
|
||||
throw new MessagingException("Unknown part");
|
||||
|
||||
String encoding =
|
||||
MimeBodyPart.restrictEncoding(part, part.getEncoding());
|
||||
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||
String encoding = mimeBodyPart.restrictEncoding(part, part.getEncoding());
|
||||
if (encoding != null)
|
||||
return MimeUtility.decode(is, encoding);
|
||||
else
|
||||
|
|
|
@ -26,14 +26,14 @@ import java.lang.reflect.Method;
|
|||
*/
|
||||
class MimeUtil {
|
||||
|
||||
private static final Method cleanContentType;
|
||||
private final Method cleanContentType;
|
||||
|
||||
static {
|
||||
public MimeUtil() {
|
||||
Method meth = null;
|
||||
try {
|
||||
String cth = System.getProperty("mail.mime.contenttypehandler");
|
||||
if (cth != null) {
|
||||
ClassLoader cl = getContextClassLoader();
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
Class<?> clsHandler = null;
|
||||
if (cl != null) {
|
||||
try {
|
||||
|
@ -53,10 +53,6 @@ class MimeUtil {
|
|||
}
|
||||
}
|
||||
|
||||
// No one should instantiate this class.
|
||||
private MimeUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* If a Content-Type handler has been specified,
|
||||
* call it to clean up the Content-Type value.
|
||||
|
@ -65,24 +61,14 @@ class MimeUtil {
|
|||
* @param contentType the Content-Type value
|
||||
* @return the cleaned Content-Type value
|
||||
*/
|
||||
public static String cleanContentType(MimePart mp, String contentType) {
|
||||
public String cleanContentType(MimePart mp, String contentType) {
|
||||
if (cleanContentType != null) {
|
||||
try {
|
||||
return (String) cleanContentType.invoke(null,
|
||||
new Object[]{mp, contentType});
|
||||
return (String) cleanContentType.invoke(null, new Object[]{mp, contentType});
|
||||
} catch (Exception ex) {
|
||||
return contentType;
|
||||
}
|
||||
} else
|
||||
return contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get our context class loader.
|
||||
* Assert any privileges we might have and then call the
|
||||
* Thread.getContextClassLoader method.
|
||||
*/
|
||||
private static ClassLoader getContextClassLoader() {
|
||||
return Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.io.StringReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
@ -39,6 +40,8 @@ import java.util.Map;
|
|||
import java.util.NoSuchElementException;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This is a utility class that provides various MIME related
|
||||
|
@ -134,35 +137,35 @@ import java.util.StringTokenizer;
|
|||
|
||||
public class MimeUtility {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MimeUtility.class.getName());
|
||||
|
||||
public static final int ALL = -1;
|
||||
static final int ALL_ASCII = 1;
|
||||
static final int MOSTLY_ASCII = 2;
|
||||
static final int MOSTLY_NONASCII = 3;
|
||||
// cached map of whether a charset is compatible with ASCII
|
||||
// Map<String,Boolean>
|
||||
private static final Map<String, Boolean> nonAsciiCharsetMap
|
||||
= new HashMap<>();
|
||||
private static final Map<String, Boolean> nonAsciiCharsetMap = new HashMap<>();
|
||||
private static final String WORD_SPECIALS = "=_?\"#$%&'(),.:;<>@[\\]^`{|}~";
|
||||
private static final String TEXT_SPECIALS = "=_?";
|
||||
private static final boolean decodeStrict = getBooleanSystemProperty("mail.mime.decodetext.strict", true);
|
||||
private static final boolean encodeEolStrict = getBooleanSystemProperty("mail.mime.encodeeol.strict", false);
|
||||
private static final boolean ignoreUnknownEncoding = getBooleanSystemProperty(
|
||||
"mail.mime.ignoreunknownencoding", false);
|
||||
private static final boolean allowUtf8 = getBooleanSystemProperty("mail.mime.allowutf8", false);
|
||||
private final boolean decodeStrict;
|
||||
private final boolean encodeEolStrict;
|
||||
private final boolean ignoreUnknownEncoding;
|
||||
private final boolean allowUtf8;
|
||||
/*
|
||||
* The following two properties allow disabling the fold()
|
||||
* and unfold() methods and reverting to the previous behavior.
|
||||
* They should never need to be changed and are here only because
|
||||
* of my paranoid concern with compatibility.
|
||||
*/
|
||||
private static final boolean foldEncodedWords = getBooleanSystemProperty("mail.mime.foldencodedwords", false);
|
||||
private static final boolean foldText = getBooleanSystemProperty("mail.mime.foldtext", true);
|
||||
private final boolean foldEncodedWords;
|
||||
private final boolean foldText;
|
||||
private static String defaultJavaCharset;
|
||||
private static String defaultMIMECharset;
|
||||
// Tables to map MIME charset names to Java names and vice versa.
|
||||
// XXX - Should eventually use J2SE 1.4 java.nio.charset.Charset
|
||||
private static Map<String, String> mime2java;
|
||||
private static Map<String, String> java2mime;
|
||||
private static final Map<String, String> mime2java;
|
||||
private static final Map<String, String> java2mime;
|
||||
|
||||
static {
|
||||
java2mime = new HashMap<>(40);
|
||||
|
@ -170,29 +173,21 @@ public class MimeUtility {
|
|||
|
||||
try {
|
||||
// Use this class's classloader to load the mapping file
|
||||
// XXX - we should use SecuritySupport, but it's in another package
|
||||
InputStream is =
|
||||
MimeUtility.class.getResourceAsStream(
|
||||
"/META-INF/javamail.charset.map");
|
||||
|
||||
if (is != null) {
|
||||
try {
|
||||
URL url = MimeUtility.class.getClassLoader().getResource("META-INF/javamail.charset.map");
|
||||
if (url != null) {
|
||||
try (InputStream is = url.openStream()) {
|
||||
LineInputStream lineInput = StreamProvider.provider().inputLineStream(is, false);
|
||||
|
||||
// Load the JDK-to-MIME charset mapping table
|
||||
loadMappings(lineInput, java2mime);
|
||||
|
||||
// Load the MIME-to-JDK charset mapping table
|
||||
loadMappings(lineInput, mime2java);
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Exception cex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
// ignore
|
||||
} else {
|
||||
logger.log(Level.WARNING, "resource META-INF/javamail.charset.map not found");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.WARNING, ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
// If we didn't load the tables, e.g., because we didn't have
|
||||
|
@ -262,8 +257,13 @@ public class MimeUtility {
|
|||
}
|
||||
}
|
||||
|
||||
// This class cannot be instantiated
|
||||
private MimeUtility() {
|
||||
decodeStrict = getBooleanSystemProperty("mail.mime.decodetext.strict", true);
|
||||
encodeEolStrict = getBooleanSystemProperty("mail.mime.encodeeol.strict", false);
|
||||
ignoreUnknownEncoding = getBooleanSystemProperty("mail.mime.ignoreunknownencoding", false);
|
||||
allowUtf8 = getBooleanSystemProperty("mail.mime.allowutf8", false);
|
||||
foldEncodedWords = getBooleanSystemProperty("mail.mime.foldencodedwords", false);
|
||||
foldText = getBooleanSystemProperty("mail.mime.foldtext", true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -293,10 +293,9 @@ public class MimeUtility {
|
|||
* StreamProvider.QUOTED_PRINTABLE_ENCODER or StreamProvider.BASE_64_ENCODER
|
||||
*/
|
||||
public static String getEncoding(DataSource ds) {
|
||||
ContentType cType = null;
|
||||
ContentType cType;
|
||||
InputStream is = null;
|
||||
String encoding = null;
|
||||
|
||||
String encoding;
|
||||
if (ds instanceof EncodingAware) {
|
||||
encoding = ((EncodingAware) ds).getEncoding();
|
||||
if (encoding != null)
|
||||
|
@ -305,7 +304,6 @@ public class MimeUtility {
|
|||
try {
|
||||
cType = new ContentType(ds.getContentType());
|
||||
is = ds.getInputStream();
|
||||
|
||||
boolean isText = cType.match("text/*");
|
||||
// if not text, stop processing when we see non-ASCII
|
||||
int i = checkAscii(is, ALL, !isText);
|
||||
|
@ -359,8 +357,7 @@ public class MimeUtility {
|
|||
if (bool == null) {
|
||||
try {
|
||||
byte[] b = "\r\n".getBytes(charset);
|
||||
bool = Boolean.valueOf(
|
||||
b.length != 2 || b[0] != 015 || b[1] != 012);
|
||||
bool = b.length != 2 || b[0] != 015 || b[1] != 012;
|
||||
} catch (UnsupportedEncodingException uex) {
|
||||
bool = Boolean.FALSE; // a guess
|
||||
} catch (RuntimeException ex) {
|
||||
|
@ -370,7 +367,7 @@ public class MimeUtility {
|
|||
nonAsciiCharsetMap.put(charset, bool);
|
||||
}
|
||||
}
|
||||
return bool.booleanValue();
|
||||
return bool;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -389,8 +386,8 @@ public class MimeUtility {
|
|||
* @since JavaMail 1.2
|
||||
*/
|
||||
public static String getEncoding(DataHandler dh) {
|
||||
ContentType cType = null;
|
||||
String encoding = null;
|
||||
ContentType cType ;
|
||||
String encoding;
|
||||
|
||||
/*
|
||||
* Try to pick the most efficient means of determining the
|
||||
|
@ -422,22 +419,16 @@ public class MimeUtility {
|
|||
} catch (IOException ex) {
|
||||
// ignore it, can't happen
|
||||
}
|
||||
switch (aos.getAscii()) {
|
||||
case ALL_ASCII:
|
||||
encoding = EncoderTypes.BIT7_ENCODER.getEncoder(); // all ascii
|
||||
break;
|
||||
case MOSTLY_ASCII:
|
||||
encoding = EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder(); // mostly ascii
|
||||
break;
|
||||
default:
|
||||
encoding = EncoderTypes.BASE_64.getEncoder(); // mostly binary
|
||||
break;
|
||||
}
|
||||
encoding = switch (aos.getAscii()) {
|
||||
case ALL_ASCII -> EncoderTypes.BIT7_ENCODER.getEncoder(); // all ascii
|
||||
case MOSTLY_ASCII -> EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder(); // mostly ascii
|
||||
default -> EncoderTypes.BASE_64.getEncoder(); // mostly binary
|
||||
};
|
||||
} else { // not "text"
|
||||
// Check all of available bytes, break out if we find
|
||||
// at least one non-US-ASCII character
|
||||
AsciiOutputStream aos =
|
||||
new AsciiOutputStream(true, encodeEolStrict);
|
||||
MimeUtility mimeUtility = new MimeUtility();
|
||||
AsciiOutputStream aos = new AsciiOutputStream(true, mimeUtility.encodeEolStrict);
|
||||
try {
|
||||
dh.writeTo(aos);
|
||||
} catch (IOException ex) {
|
||||
|
@ -468,8 +459,7 @@ public class MimeUtility {
|
|||
* @return decoded input stream.
|
||||
* @throws MessagingException if the encoding is unknown
|
||||
*/
|
||||
public static InputStream decode(InputStream is, String encoding)
|
||||
throws MessagingException {
|
||||
public static InputStream decode(InputStream is, String encoding) throws MessagingException {
|
||||
if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder()))
|
||||
return StreamProvider.provider().inputBase64(is);
|
||||
else if (encoding.equalsIgnoreCase(EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder()))
|
||||
|
@ -483,7 +473,8 @@ public class MimeUtility {
|
|||
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder()))
|
||||
return StreamProvider.provider().inputBinary(is);
|
||||
else {
|
||||
if (!ignoreUnknownEncoding)
|
||||
MimeUtility mimeUtility = new MimeUtility();
|
||||
if (!mimeUtility.ignoreUnknownEncoding)
|
||||
throw new MessagingException("Unknown encoding: " + encoding);
|
||||
return is;
|
||||
}
|
||||
|
@ -501,24 +492,24 @@ public class MimeUtility {
|
|||
* specified encoding.
|
||||
* @throws MessagingException if the encoding is unknown
|
||||
*/
|
||||
public static OutputStream encode(OutputStream os, String encoding)
|
||||
throws MessagingException {
|
||||
if (encoding == null)
|
||||
public static OutputStream encode(OutputStream os, String encoding) throws MessagingException {
|
||||
if (encoding == null) {
|
||||
return os;
|
||||
else if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder()))
|
||||
} else if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder())) {
|
||||
return StreamProvider.provider().outputBase64(os);
|
||||
else if (encoding.equalsIgnoreCase(EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder()))
|
||||
} else if (encoding.equalsIgnoreCase(EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder())) {
|
||||
return StreamProvider.provider().outputQP(os);
|
||||
else if (encoding.equalsIgnoreCase(EncoderTypes.UU_ENCODER.getEncoder()) ||
|
||||
} else if (encoding.equalsIgnoreCase(EncoderTypes.UU_ENCODER.getEncoder()) ||
|
||||
encoding.equalsIgnoreCase(EncoderTypes.X_UU_ENCODER.getEncoder()) ||
|
||||
encoding.equalsIgnoreCase(EncoderTypes.X_UUE.getEncoder()))
|
||||
encoding.equalsIgnoreCase(EncoderTypes.X_UUE.getEncoder())) {
|
||||
return StreamProvider.provider().outputUU(os, null);
|
||||
else if (encoding.equalsIgnoreCase(EncoderTypes.BINARY_ENCODER.getEncoder()) ||
|
||||
} else if (encoding.equalsIgnoreCase(EncoderTypes.BINARY_ENCODER.getEncoder()) ||
|
||||
encoding.equalsIgnoreCase(EncoderTypes.BIT7_ENCODER.getEncoder()) ||
|
||||
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder()))
|
||||
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder())) {
|
||||
return StreamProvider.provider().outputBinary(os);
|
||||
else
|
||||
} else {
|
||||
throw new MessagingException("Unknown encoding: " + encoding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -538,25 +529,24 @@ public class MimeUtility {
|
|||
* @throws MessagingException for unknown encodings
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public static OutputStream encode(OutputStream os, String encoding,
|
||||
String filename)
|
||||
throws MessagingException {
|
||||
if (encoding == null)
|
||||
public static OutputStream encode(OutputStream os, String encoding, String filename) throws MessagingException {
|
||||
if (encoding == null) {
|
||||
return os;
|
||||
else if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder()))
|
||||
} else if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder())) {
|
||||
return StreamProvider.provider().outputBase64(os);
|
||||
else if (encoding.equalsIgnoreCase(EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder()))
|
||||
} else if (encoding.equalsIgnoreCase(EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder())) {
|
||||
return StreamProvider.provider().outputQP(os);
|
||||
else if (encoding.equalsIgnoreCase(EncoderTypes.UU_ENCODER.getEncoder()) ||
|
||||
} else if (encoding.equalsIgnoreCase(EncoderTypes.UU_ENCODER.getEncoder()) ||
|
||||
encoding.equalsIgnoreCase(EncoderTypes.X_UU_ENCODER.getEncoder()) ||
|
||||
encoding.equalsIgnoreCase(EncoderTypes.X_UUE.getEncoder()))
|
||||
encoding.equalsIgnoreCase(EncoderTypes.X_UUE.getEncoder())) {
|
||||
return StreamProvider.provider().outputUU(os, filename);
|
||||
else if (encoding.equalsIgnoreCase(EncoderTypes.BINARY_ENCODER.getEncoder()) ||
|
||||
} else if (encoding.equalsIgnoreCase(EncoderTypes.BINARY_ENCODER.getEncoder()) ||
|
||||
encoding.equalsIgnoreCase(EncoderTypes.BIT7_ENCODER.getEncoder()) ||
|
||||
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder()))
|
||||
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder())) {
|
||||
return StreamProvider.provider().outputBinary(os);
|
||||
else
|
||||
} else {
|
||||
throw new MessagingException("Unknown encoding: " + encoding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -666,8 +656,7 @@ public class MimeUtility {
|
|||
* @throws UnsupportedEncodingException if the charset
|
||||
* conversion failed.
|
||||
*/
|
||||
public static String decodeText(String etext)
|
||||
throws UnsupportedEncodingException {
|
||||
public static String decodeText(String etext) throws UnsupportedEncodingException {
|
||||
/*
|
||||
* We look for sequences separated by "linear-white-space".
|
||||
* (as per RFC 2047, Section 6.1)
|
||||
|
@ -675,7 +664,6 @@ public class MimeUtility {
|
|||
*/
|
||||
String lwsp = " \t\n\r";
|
||||
StringTokenizer st;
|
||||
|
||||
/*
|
||||
* First, lets do a quick run thru the string and check
|
||||
* whether the sequence "=?" exists at all. If none exists,
|
||||
|
@ -685,30 +673,27 @@ public class MimeUtility {
|
|||
* This handles the most common case of unencoded headers
|
||||
* efficiently.
|
||||
*/
|
||||
if (!etext.contains("=?"))
|
||||
if (!etext.contains("=?")) {
|
||||
return etext;
|
||||
|
||||
}
|
||||
// Encoded words found. Start decoding ...
|
||||
|
||||
st = new StringTokenizer(etext, lwsp, true);
|
||||
StringBuilder sb = new StringBuilder(); // decode buffer
|
||||
StringBuilder wsb = new StringBuilder(); // white space buffer
|
||||
boolean prevWasEncoded = false;
|
||||
|
||||
while (st.hasMoreTokens()) {
|
||||
char c;
|
||||
String s = st.nextToken();
|
||||
// If whitespace, append it to the whitespace buffer
|
||||
if (((c = s.charAt(0)) == ' ') || (c == '\t') ||
|
||||
(c == '\r') || (c == '\n'))
|
||||
if (((c = s.charAt(0)) == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) {
|
||||
wsb.append(c);
|
||||
else {
|
||||
} else {
|
||||
// Check if token is an 'encoded-word' ..
|
||||
String word;
|
||||
try {
|
||||
word = decodeWord(s);
|
||||
// Yes, this IS an 'encoded-word'.
|
||||
if (!prevWasEncoded && wsb.length() > 0) {
|
||||
if (!prevWasEncoded && !wsb.isEmpty()) {
|
||||
// if the previous word was also encoded, we
|
||||
// should ignore the collected whitespace. Else
|
||||
// we include the whitespace as well.
|
||||
|
@ -719,17 +704,15 @@ public class MimeUtility {
|
|||
// This is NOT an 'encoded-word'.
|
||||
word = s;
|
||||
// possibly decode inner encoded words
|
||||
if (!decodeStrict) {
|
||||
MimeUtility mimeUtility = new MimeUtility();
|
||||
if (!mimeUtility.decodeStrict) {
|
||||
String dword = decodeInnerWords(word);
|
||||
if (dword != word) {
|
||||
if (dword.equals(word)) {
|
||||
// if a different String object was returned,
|
||||
// decoding was done.
|
||||
if (prevWasEncoded && word.startsWith("=?")) {
|
||||
// encoded followed by encoded,
|
||||
// throw away whitespace between
|
||||
} else {
|
||||
if (!prevWasEncoded || !word.startsWith("=?")) {
|
||||
// include collected whitespace ..
|
||||
if (wsb.length() > 0)
|
||||
if (!wsb.isEmpty())
|
||||
sb.append(wsb);
|
||||
}
|
||||
// did original end with encoded?
|
||||
|
@ -737,14 +720,16 @@ public class MimeUtility {
|
|||
word = dword;
|
||||
} else {
|
||||
// include collected whitespace ..
|
||||
if (wsb.length() > 0)
|
||||
if (!wsb.isEmpty()) {
|
||||
sb.append(wsb);
|
||||
}
|
||||
prevWasEncoded = false;
|
||||
}
|
||||
} else {
|
||||
// include collected whitespace ..
|
||||
if (wsb.length() > 0)
|
||||
if (!wsb.isEmpty()) {
|
||||
sb.append(wsb);
|
||||
}
|
||||
prevWasEncoded = false;
|
||||
}
|
||||
}
|
||||
|
@ -804,7 +789,8 @@ public class MimeUtility {
|
|||
* @return Unicode string containing only US-ASCII characters
|
||||
* @throws UnsupportedEncodingException if the encoding fails
|
||||
*/
|
||||
public static String encodeWord(String word, String charset,
|
||||
public static String encodeWord(String word,
|
||||
String charset,
|
||||
String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
return encodeWord(word, charset, encoding, true);
|
||||
|
@ -817,24 +803,26 @@ public class MimeUtility {
|
|||
* "Q" encoding defined in RFC 2047 has more restrictions when
|
||||
* encoding "word" tokens. (Sigh)
|
||||
*/
|
||||
private static String encodeWord(String string, String charset,
|
||||
String encoding, boolean encodingWord)
|
||||
private static String encodeWord(String string,
|
||||
String charset,
|
||||
String encoding,
|
||||
boolean encodingWord)
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
// If 'string' contains only US-ASCII characters, just
|
||||
// return it.
|
||||
int ascii = checkAscii(string);
|
||||
if (ascii == ALL_ASCII)
|
||||
if (ascii == ALL_ASCII) {
|
||||
return string;
|
||||
|
||||
}
|
||||
// Else, apply the specified charset conversion.
|
||||
String jcharset;
|
||||
if (charset == null) { // use default charset
|
||||
jcharset = getDefaultJavaCharset(); // the java charset
|
||||
charset = getDefaultMIMECharset(); // the MIME equivalent
|
||||
} else // MIME charset -> java charset
|
||||
} else { // MIME charset -> java charset
|
||||
jcharset = javaCharset(charset);
|
||||
|
||||
}
|
||||
// If no transfer-encoding is specified, figure one out.
|
||||
if (encoding == null) {
|
||||
if (ascii != MOSTLY_NONASCII)
|
||||
|
@ -842,20 +830,17 @@ public class MimeUtility {
|
|||
else
|
||||
encoding = "B";
|
||||
}
|
||||
|
||||
boolean b64;
|
||||
if (encoding.equalsIgnoreCase("B"))
|
||||
if (encoding.equalsIgnoreCase("B")) {
|
||||
b64 = true;
|
||||
else if (encoding.equalsIgnoreCase("Q"))
|
||||
} else if (encoding.equalsIgnoreCase("Q")) {
|
||||
b64 = false;
|
||||
else
|
||||
throw new UnsupportedEncodingException(
|
||||
"Unknown transfer encoding: " + encoding);
|
||||
|
||||
} else {
|
||||
throw new UnsupportedEncodingException("Unknown transfer encoding: " + encoding);
|
||||
}
|
||||
StringBuilder outb = new StringBuilder(); // the output buffer
|
||||
doEncode(string, b64, jcharset,
|
||||
// As per RFC 2047, size of an encoded string should not
|
||||
// exceed 75 bytes.
|
||||
// As per RFC 2047, size of an encoded string should not exceed 75 bytes.
|
||||
// 7 = size of "=?", '?', 'B'/'Q', '?', "?="
|
||||
75 - 7 - charset.length(), // the available space
|
||||
"=?" + charset + "?" + encoding + "?", // prefix
|
||||
|
@ -884,13 +869,14 @@ public class MimeUtility {
|
|||
private static int qEncodedLength(byte[] b, boolean encodingWord) {
|
||||
int len = 0;
|
||||
String specials = encodingWord ? WORD_SPECIALS : TEXT_SPECIALS;
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
int c = b[i] & 0xff; // Mask off MSB
|
||||
if (c < 040 || c >= 0177 || specials.indexOf(c) >= 0)
|
||||
for (byte value : b) {
|
||||
int c = value & 0xff; // Mask off MSB
|
||||
if (c < 040 || c >= 0177 || specials.indexOf(c) >= 0) {
|
||||
// needs encoding
|
||||
len += 3; // Q-encoding is 1 -> 3 conversion
|
||||
else
|
||||
} else {
|
||||
len++;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
@ -899,7 +885,6 @@ public class MimeUtility {
|
|||
String jcharset, int avail, String prefix,
|
||||
boolean first, boolean encodingWord, StringBuilder buf)
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
// First find out what the length of the encoded version of
|
||||
// 'string' would be.
|
||||
byte[] bytes = string.getBytes(jcharset);
|
||||
|
@ -931,25 +916,26 @@ public class MimeUtility {
|
|||
} else { // "Q" encoding
|
||||
eos = StreamProvider.provider().outputQ(os, encodingWord);
|
||||
}
|
||||
|
||||
try { // do the encoding
|
||||
eos.write(bytes);
|
||||
eos.close();
|
||||
} catch (IOException ioex) {
|
||||
}
|
||||
|
||||
byte[] encodedBytes = os.toByteArray(); // the encoded stuff
|
||||
// Now write out the encoded (all ASCII) bytes into our
|
||||
// StringBuilder
|
||||
if (!first) // not the first line of this sequence
|
||||
if (foldEncodedWords)
|
||||
if (!first) { // not the first line of this sequence
|
||||
MimeUtility mimeUtility = new MimeUtility();
|
||||
if (mimeUtility.foldEncodedWords) {
|
||||
buf.append("\r\n "); // start a continuation line
|
||||
else
|
||||
} else {
|
||||
buf.append(" "); // line will be folded later
|
||||
|
||||
}
|
||||
}
|
||||
buf.append(prefix);
|
||||
for (int i = 0; i < encodedBytes.length; i++)
|
||||
buf.append((char) encodedBytes[i]);
|
||||
for (byte encodedByte : encodedBytes) {
|
||||
buf.append((char) encodedByte);
|
||||
}
|
||||
buf.append("?="); // terminate the current sequence
|
||||
}
|
||||
}
|
||||
|
@ -970,61 +956,47 @@ public class MimeUtility {
|
|||
*/
|
||||
public static String decodeWord(String eword)
|
||||
throws ParseException, UnsupportedEncodingException {
|
||||
|
||||
if (!eword.startsWith("=?")) // not an encoded word
|
||||
throw new ParseException(
|
||||
"encoded word does not start with \"=?\": " + eword);
|
||||
|
||||
if (!eword.startsWith("=?")) { // not an encoded word
|
||||
throw new ParseException("encoded word does not start with \"=?\": " + eword);
|
||||
}
|
||||
// get charset
|
||||
int start = 2;
|
||||
int pos;
|
||||
if ((pos = eword.indexOf('?', start)) == -1)
|
||||
throw new ParseException(
|
||||
"encoded word does not include charset: " + eword);
|
||||
if ((pos = eword.indexOf('?', start)) == -1) {
|
||||
throw new ParseException("encoded word does not include charset: " + eword);
|
||||
}
|
||||
String charset = eword.substring(start, pos);
|
||||
int lpos = charset.indexOf('*'); // RFC 2231 language specified?
|
||||
if (lpos >= 0) // yes, throw it away
|
||||
if (lpos >= 0) { // yes, throw it away
|
||||
charset = charset.substring(0, lpos);
|
||||
}
|
||||
charset = javaCharset(charset);
|
||||
|
||||
// get encoding
|
||||
start = pos + 1;
|
||||
if ((pos = eword.indexOf('?', start)) == -1)
|
||||
throw new ParseException(
|
||||
"encoded word does not include encoding: " + eword);
|
||||
if ((pos = eword.indexOf('?', start)) == -1) {
|
||||
throw new ParseException("encoded word does not include encoding: " + eword);
|
||||
}
|
||||
String encoding = eword.substring(start, pos);
|
||||
|
||||
// get encoded-sequence
|
||||
start = pos + 1;
|
||||
if ((pos = eword.indexOf("?=", start)) == -1)
|
||||
throw new ParseException(
|
||||
"encoded word does not end with \"?=\": " + eword);
|
||||
/*
|
||||
* XXX - should include this, but leaving it out for compatibility...
|
||||
*
|
||||
if (decodeStrict && pos != eword.length() - 2)
|
||||
throw new ParseException(
|
||||
"encoded word does not end with \"?=\": " + eword););
|
||||
*/
|
||||
if ((pos = eword.indexOf("?=", start)) == -1) {
|
||||
throw new ParseException("encoded word does not end with \"?=\": " + eword);
|
||||
}
|
||||
String word = eword.substring(start, pos);
|
||||
|
||||
try {
|
||||
String decodedWord;
|
||||
if (word.length() > 0) {
|
||||
if (!word.isEmpty()) {
|
||||
// Extract the bytes from word
|
||||
ByteArrayInputStream bis =
|
||||
new ByteArrayInputStream(getBytes(word));
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(getBytes(word));
|
||||
// Get the appropriate decoder
|
||||
InputStream is;
|
||||
if (encoding.equalsIgnoreCase("B"))
|
||||
if (encoding.equalsIgnoreCase("B")) {
|
||||
is = StreamProvider.provider().inputBase64(bis);
|
||||
else if (encoding.equalsIgnoreCase("Q"))
|
||||
} else if (encoding.equalsIgnoreCase("Q")) {
|
||||
is = StreamProvider.provider().inputQ(bis);
|
||||
else
|
||||
throw new UnsupportedEncodingException(
|
||||
"unknown encoding: " + encoding);
|
||||
|
||||
} else {
|
||||
throw new UnsupportedEncodingException("unknown encoding: " + encoding);
|
||||
}
|
||||
// For b64 & q, size of decoded word <= size of word. So
|
||||
// the decoded bytes must fit into the 'bytes' array. This
|
||||
// is certainly more efficient than writing bytes into a
|
||||
|
@ -1034,11 +1006,9 @@ public class MimeUtility {
|
|||
byte[] bytes = new byte[count];
|
||||
// count is set to the actual number of decoded bytes
|
||||
count = is.read(bytes, 0, count);
|
||||
|
||||
// Finally, convert the decoded bytes into a String using
|
||||
// the specified charset
|
||||
decodedWord = count <= 0 ? "" :
|
||||
new String(bytes, 0, count, charset);
|
||||
decodedWord = count <= 0 ? "" : new String(bytes, 0, count, charset);
|
||||
} else {
|
||||
// no characters to decode, return empty string
|
||||
decodedWord = "";
|
||||
|
@ -1046,8 +1016,10 @@ public class MimeUtility {
|
|||
if (pos + 2 < eword.length()) {
|
||||
// there's still more text in the string
|
||||
String rest = eword.substring(pos + 2);
|
||||
if (!decodeStrict)
|
||||
MimeUtility mimeUtility = new MimeUtility();
|
||||
if (!mimeUtility.decodeStrict) {
|
||||
rest = decodeInnerWords(rest);
|
||||
}
|
||||
decodedWord += rest;
|
||||
}
|
||||
return decodedWord;
|
||||
|
@ -1134,6 +1106,7 @@ public class MimeUtility {
|
|||
* Look for any "bad" characters, Escape and
|
||||
* quote the entire string if necessary.
|
||||
*/
|
||||
MimeUtility mimeUtility = new MimeUtility();
|
||||
boolean needQuoting = false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = word.charAt(i);
|
||||
|
@ -1156,7 +1129,7 @@ public class MimeUtility {
|
|||
}
|
||||
sb.append('"');
|
||||
return sb.toString();
|
||||
} else if (c < 040 || (c >= 0177 && !allowUtf8) ||
|
||||
} else if (c < 040 || (c >= 0177 && !mimeUtility.allowUtf8) ||
|
||||
specials.indexOf(c) >= 0)
|
||||
// These characters cause the string to be quoted
|
||||
needQuoting = true;
|
||||
|
@ -1187,8 +1160,10 @@ public class MimeUtility {
|
|||
* @since JavaMail 1.4
|
||||
*/
|
||||
public static String fold(int used, String s) {
|
||||
if (!foldText)
|
||||
MimeUtility mimeUtility = new MimeUtility();
|
||||
if (!mimeUtility.foldText) {
|
||||
return s;
|
||||
}
|
||||
|
||||
int end;
|
||||
char c;
|
||||
|
@ -1288,8 +1263,10 @@ public class MimeUtility {
|
|||
* @since JavaMail 1.4
|
||||
*/
|
||||
public static String unfold(String s) {
|
||||
if (!foldText)
|
||||
MimeUtility mimeUtility = new MimeUtility();
|
||||
if (!mimeUtility.foldText) {
|
||||
return s;
|
||||
}
|
||||
|
||||
StringBuilder sb = null;
|
||||
int i;
|
||||
|
@ -1364,10 +1341,10 @@ public class MimeUtility {
|
|||
* not available, the passed in charset is itself returned.
|
||||
*/
|
||||
public static String javaCharset(String charset) {
|
||||
if (mime2java == null || charset == null)
|
||||
if (mime2java == null || charset == null) {
|
||||
// no mapping table, or charset parameter is null
|
||||
return charset;
|
||||
|
||||
}
|
||||
String alias = mime2java.get(charset.toLowerCase(Locale.ENGLISH));
|
||||
if (alias != null) {
|
||||
// verify that the mapped name is valid before trying to use it
|
||||
|
@ -1394,10 +1371,10 @@ public class MimeUtility {
|
|||
* @since JavaMail 1.1
|
||||
*/
|
||||
public static String mimeCharset(String charset) {
|
||||
if (java2mime == null || charset == null)
|
||||
if (java2mime == null || charset == null) {
|
||||
// no mapping table or charset param is null
|
||||
return charset;
|
||||
|
||||
}
|
||||
String alias = java2mime.get(charset.toLowerCase(Locale.ENGLISH));
|
||||
return alias == null ? charset : alias;
|
||||
}
|
||||
|
@ -1420,11 +1397,10 @@ public class MimeUtility {
|
|||
*/
|
||||
String mimecs = System.getProperty("mail.mime.charset");
|
||||
if (mimecs != null && !mimecs.isEmpty()) {
|
||||
defaultJavaCharset = javaCharset(mimecs);
|
||||
defaultJavaCharset = javaCharset(mimecs.toUpperCase(Locale.ROOT));
|
||||
return defaultJavaCharset;
|
||||
}
|
||||
defaultJavaCharset = System.getProperty("file.encoding",
|
||||
"8859_1");
|
||||
defaultJavaCharset = System.getProperty("file.encoding", "8859_1");
|
||||
}
|
||||
return defaultJavaCharset;
|
||||
}
|
||||
|
@ -1436,32 +1412,29 @@ public class MimeUtility {
|
|||
if (defaultMIMECharset == null) {
|
||||
defaultMIMECharset = System.getProperty("mail.mime.charset");
|
||||
}
|
||||
if (defaultMIMECharset == null)
|
||||
if (defaultMIMECharset == null) {
|
||||
defaultMIMECharset = mimeCharset(getDefaultJavaCharset());
|
||||
return defaultMIMECharset;
|
||||
}
|
||||
return defaultMIMECharset.toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private static void loadMappings(LineInputStream is,
|
||||
Map<String, String> table) {
|
||||
String currLine;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
currLine = is.readLine();
|
||||
} catch (IOException ioex) {
|
||||
break; // error in reading, stop
|
||||
}
|
||||
|
||||
if (currLine == null) // end of file, stop
|
||||
break;
|
||||
if (currLine.startsWith("--") && currLine.endsWith("--"))
|
||||
// end of this table
|
||||
break;
|
||||
|
||||
// ignore empty lines and comments
|
||||
if (currLine.trim().length() == 0 || currLine.startsWith("#"))
|
||||
if (currLine.trim().isEmpty() || currLine.startsWith("#"))
|
||||
continue;
|
||||
|
||||
// A valid entry is of the form <key><separator><value>
|
||||
// where, <separator> := SPACE | HT. Parse this
|
||||
StringTokenizer tk = new StringTokenizer(currLine, " \t");
|
||||
|
@ -1561,7 +1534,8 @@ public class MimeUtility {
|
|||
int block = 4096;
|
||||
int linelen = 0;
|
||||
boolean longLine = false, badEOL = false;
|
||||
boolean checkEOL = encodeEolStrict && breakOnNonAscii;
|
||||
MimeUtility mimeUtility = new MimeUtility();
|
||||
boolean checkEOL = mimeUtility.encodeEolStrict && breakOnNonAscii;
|
||||
byte[] buf = null;
|
||||
if (max != 0) {
|
||||
block = (max == ALL) ? 4096 : Math.min(max, 4096);
|
||||
|
@ -1632,7 +1606,7 @@ public class MimeUtility {
|
|||
return MOSTLY_NONASCII;
|
||||
}
|
||||
|
||||
static final boolean nonascii(int b) {
|
||||
static boolean nonascii(int b) {
|
||||
return b >= 0177 || (b < 040 && b != '\r' && b != '\n' && b != '\t');
|
||||
}
|
||||
|
||||
|
@ -1696,10 +1670,11 @@ public class MimeUtility {
|
|||
*/
|
||||
private static Object getProp(Properties props, String name) {
|
||||
Object val = props.get(name);
|
||||
if (val != null)
|
||||
if (val != null) {
|
||||
return val;
|
||||
else
|
||||
} else {
|
||||
return props.getProperty(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1707,20 +1682,31 @@ public class MimeUtility {
|
|||
* returning def if unable.
|
||||
*/
|
||||
private static boolean getBoolean(Object value, boolean def) {
|
||||
if (value == null)
|
||||
return def;
|
||||
if (value instanceof String) {
|
||||
/*
|
||||
* If the default is true, only "false" turns it off.
|
||||
* If the default is false, only "true" turns it on.
|
||||
*/
|
||||
if (def)
|
||||
return !((String) value).equalsIgnoreCase("false");
|
||||
else
|
||||
return ((String) value).equalsIgnoreCase("true");
|
||||
switch (value) {
|
||||
case null -> {
|
||||
return def;
|
||||
}
|
||||
case String s -> {
|
||||
/*
|
||||
* If the default is true, only "false" turns it off.
|
||||
* If the default is false, only "true" turns it on.
|
||||
*/
|
||||
if (def) {
|
||||
return !((String) value).equalsIgnoreCase("false");
|
||||
} else {
|
||||
return ((String) value).equalsIgnoreCase("true");
|
||||
}
|
||||
/*
|
||||
* If the default is true, only "false" turns it off.
|
||||
* If the default is false, only "true" turns it on.
|
||||
*/
|
||||
}
|
||||
case Boolean b -> {
|
||||
return b;
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
if (value instanceof Boolean)
|
||||
return (Boolean) value;
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
@ -1730,7 +1716,7 @@ public class MimeUtility {
|
|||
* it is all ASCII, mostly ASCII, or mostly non-ASCII.
|
||||
*/
|
||||
class AsciiOutputStream extends OutputStream {
|
||||
private boolean breakOnNonAscii;
|
||||
private final boolean breakOnNonAscii;
|
||||
private int ascii = 0, non_ascii = 0;
|
||||
private int linelen = 0;
|
||||
private boolean longLine = false;
|
||||
|
|
|
@ -60,22 +60,14 @@ import java.util.Set;
|
|||
|
||||
public class ParameterList {
|
||||
|
||||
private static final boolean encodeParameters =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.encodeparameters", true);
|
||||
private static final boolean decodeParameters =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.decodeparameters", true);
|
||||
private static final boolean decodeParametersStrict =
|
||||
MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.decodeparameters.strict", false);
|
||||
private static final boolean applehack =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.applefilenames", false);
|
||||
private static final boolean windowshack =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.windowsfilenames", false);
|
||||
private static final boolean parametersStrict =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.parameters.strict", true);
|
||||
private static final boolean splitLongParameters =
|
||||
MimeUtility.getBooleanSystemProperty(
|
||||
"mail.mime.splitlongparameters", true);
|
||||
private final boolean encodeParameters;
|
||||
private final boolean decodeParameters;
|
||||
private final boolean decodeParametersStrict;
|
||||
private final boolean applehack;;
|
||||
private final boolean windowshack;
|
||||
private final boolean parametersStrict;
|
||||
private final boolean splitLongParameters;
|
||||
|
||||
private static final char[] hex = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
|
@ -94,7 +86,7 @@ public class ParameterList {
|
|||
* will all move to the end.
|
||||
*/
|
||||
// keep parameters in order
|
||||
private Map<String, Object> list = new LinkedHashMap<>();
|
||||
private final Map<String, Object> list = new LinkedHashMap<>();
|
||||
/**
|
||||
* A set of names for multi-segment parameters that we
|
||||
* haven't processed yet. Normally such names are accumulated
|
||||
|
@ -136,21 +128,23 @@ public class ParameterList {
|
|||
* combineMultisegmentNames method.
|
||||
*/
|
||||
private Map<String, Object> slist;
|
||||
/**
|
||||
* MWB 3BView: The name of the last parameter added to the map.
|
||||
* Used for the AppleMail hack.
|
||||
*/
|
||||
private String lastName = null;
|
||||
|
||||
/**
|
||||
* No-arg Constructor.
|
||||
*/
|
||||
public ParameterList() {
|
||||
// initialize other collections only if they'll be needed
|
||||
encodeParameters = MimeUtility.getBooleanSystemProperty("mail.mime.encodeparameters", true);
|
||||
decodeParameters = MimeUtility.getBooleanSystemProperty("mail.mime.decodeparameters", true);
|
||||
if (decodeParameters) {
|
||||
multisegmentNames = new HashSet<>();
|
||||
slist = new HashMap<>();
|
||||
}
|
||||
decodeParametersStrict = MimeUtility.getBooleanSystemProperty("mail.mime.decodeparameters.strict", false);
|
||||
applehack = MimeUtility.getBooleanSystemProperty("mail.mime.applefilenames", false);
|
||||
windowshack = MimeUtility.getBooleanSystemProperty("mail.mime.windowsfilenames", false);
|
||||
parametersStrict = MimeUtility.getBooleanSystemProperty("mail.mime.parameters.strict", true);
|
||||
splitLongParameters = MimeUtility.getBooleanSystemProperty("mail.mime.splitlongparameters", true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,7 +159,6 @@ public class ParameterList {
|
|||
*/
|
||||
public ParameterList(String s) throws ParseException {
|
||||
this();
|
||||
|
||||
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
||||
for (; ; ) {
|
||||
HeaderTokenizer.Token tk = h.next();
|
||||
|
@ -175,6 +168,11 @@ public class ParameterList {
|
|||
if (type == HeaderTokenizer.Token.EOF) // done
|
||||
break;
|
||||
|
||||
/**
|
||||
* MWB 3BView: The name of the last parameter added to the map.
|
||||
* Used for the AppleMail hack.
|
||||
*/
|
||||
String lastName = null;
|
||||
if ((char) type == ';') {
|
||||
// expect parameter name
|
||||
tk = h.next();
|
||||
|
@ -294,7 +292,7 @@ public class ParameterList {
|
|||
* Extract charset and encoded value.
|
||||
* Value will be decoded later.
|
||||
*/
|
||||
private static Value extractCharset(String value) throws ParseException {
|
||||
private Value extractCharset(String value) throws ParseException {
|
||||
Value v = new Value();
|
||||
v.value = v.encodedValue = value;
|
||||
try {
|
||||
|
@ -326,7 +324,7 @@ public class ParameterList {
|
|||
/**
|
||||
* Decode the encoded bytes in value using the specified charset.
|
||||
*/
|
||||
private static String decodeBytes(String value, String charset)
|
||||
private String decodeBytes(String value, String charset)
|
||||
throws ParseException, UnsupportedEncodingException {
|
||||
/*
|
||||
* Decode the ASCII characters in value
|
||||
|
@ -362,7 +360,7 @@ public class ParameterList {
|
|||
/**
|
||||
* Decode the encoded bytes in value and write them to the OutputStream.
|
||||
*/
|
||||
private static void decodeBytes(String value, OutputStream os)
|
||||
private void decodeBytes(String value, OutputStream os)
|
||||
throws ParseException, IOException {
|
||||
/*
|
||||
* Decode the ASCII characters in value
|
||||
|
|
159
net-mail/src/main/java/jakarta/mail/util/ResourceLoader.java
Normal file
159
net-mail/src/main/java/jakarta/mail/util/ResourceLoader.java
Normal file
|
@ -0,0 +1,159 @@
|
|||
package jakarta.mail.util;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ResourceLoader {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ResourceLoader.class.getName());
|
||||
|
||||
private ResourceLoader() {
|
||||
}
|
||||
|
||||
public static ClassLoader[] getClassLoaders(final Class<?>... classes) {
|
||||
ClassLoader[] loaders = new ClassLoader[classes.length];
|
||||
int w = 0;
|
||||
for (Class<?> k : classes) {
|
||||
ClassLoader cl;
|
||||
if (k == Thread.class) {
|
||||
cl = Thread.currentThread().getContextClassLoader();
|
||||
} else if (k == System.class) {
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
} else {
|
||||
cl = k.getClassLoader();
|
||||
}
|
||||
if (cl != null) {
|
||||
loaders[w++] = cl;
|
||||
}
|
||||
}
|
||||
if (loaders.length != w) {
|
||||
loaders = Arrays.copyOf(loaders, w);
|
||||
}
|
||||
return loaders;
|
||||
}
|
||||
|
||||
public static InputStream getResourceAsStream(final Class<?> c, final String name) throws IOException {
|
||||
try {
|
||||
return c.getClassLoader().getResourceAsStream(name);
|
||||
} catch (RuntimeException e) {
|
||||
throw new IOException("getResourceAsStream for class " + c + " name = " + name + " failed");
|
||||
}
|
||||
}
|
||||
|
||||
public static URL[] getResources(final ClassLoader cl, final String name) {
|
||||
URL[] ret = null;
|
||||
try {
|
||||
List<URL> v = Collections.list(cl.getResources(name));
|
||||
if (!v.isEmpty()) {
|
||||
ret = new URL[v.size()];
|
||||
v.toArray(ret);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
logger.log(Level.WARNING, ioex.getMessage());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static URL[] getSystemResources(final String name) {
|
||||
URL[] ret = null;
|
||||
try {
|
||||
List<URL> v = Collections.list(ClassLoader.getSystemResources(name));
|
||||
if (!v.isEmpty()) {
|
||||
ret = new URL[v.size()];
|
||||
v.toArray(ret);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
logger.log(Level.WARNING, ioex.getMessage());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from the named file.
|
||||
*/
|
||||
public static void loadFile(String name, StreamLoader loader) {
|
||||
try (InputStream clis = new BufferedInputStream(new FileInputStream(name))) {
|
||||
loader.load(clis);
|
||||
logger.log(Level.CONFIG, "successfully loaded file: {0}", name);
|
||||
} catch (FileNotFoundException fex) {
|
||||
// ignore it
|
||||
} catch (IOException e) {
|
||||
if (logger.isLoggable(Level.CONFIG))
|
||||
logger.log(Level.CONFIG, "not loading file: " + name, e);
|
||||
}
|
||||
// ignore it
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from the named resource.
|
||||
*/
|
||||
public static void loadResource(String name, Class<?> cl, StreamLoader loader, boolean expected) {
|
||||
try (InputStream clis = ResourceLoader.getResourceAsStream(cl, name)) {
|
||||
if (clis != null) {
|
||||
loader.load(clis);
|
||||
logger.log(Level.CONFIG, "successfully loaded resource: {0}", name);
|
||||
} else {
|
||||
if (expected)
|
||||
logger.log(Level.WARNING, "expected resource not found: {0}", name);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.CONFIG, "Exception loading resource", e);
|
||||
}
|
||||
// ignore it
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all of the named resource.
|
||||
*/
|
||||
public static void loadAllResources(String name, Class<?> cl, StreamLoader loader) {
|
||||
boolean anyLoaded = false;
|
||||
try {
|
||||
URL[] urls;
|
||||
ClassLoader cld = cl.getClassLoader();
|
||||
if (cld != null)
|
||||
urls = ResourceLoader.getResources(cld, name);
|
||||
else
|
||||
urls = ResourceLoader.getSystemResources(name);
|
||||
if (urls != null) {
|
||||
for (URL url : urls) {
|
||||
logger.log(Level.CONFIG, "URL {0}", url);
|
||||
try (InputStream clis = url.openStream()) {
|
||||
if (clis != null) {
|
||||
loader.load(clis);
|
||||
anyLoaded = true;
|
||||
logger.log(Level.CONFIG,
|
||||
"successfully loaded resource: {0}", url);
|
||||
} else {
|
||||
logger.log(Level.CONFIG,
|
||||
"not loading resource: {0}", url);
|
||||
}
|
||||
} catch (FileNotFoundException fex) {
|
||||
// ignore it
|
||||
} catch (IOException ioex) {
|
||||
logger.log(Level.CONFIG, "Exception loading resource",
|
||||
ioex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.CONFIG, "Exception loading resource", ex);
|
||||
}
|
||||
|
||||
// if failed to load anything, fall back to old technique, just in case
|
||||
if (!anyLoaded) {
|
||||
/*
|
||||
logger.config("!anyLoaded");
|
||||
*/
|
||||
loadResource("/" + name, cl, loader, false);
|
||||
}
|
||||
}
|
||||
}
|
12
net-mail/src/main/java/jakarta/mail/util/StreamLoader.java
Normal file
12
net-mail/src/main/java/jakarta/mail/util/StreamLoader.java
Normal file
|
@ -0,0 +1,12 @@
|
|||
package jakarta.mail.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Support interface to generalize
|
||||
* code that loads resources from stream.
|
||||
*/
|
||||
public interface StreamLoader {
|
||||
void load(InputStream is) throws IOException;
|
||||
}
|
|
@ -10,6 +10,7 @@ module org.xbib.net.mail {
|
|||
exports jakarta.mail.internet;
|
||||
exports jakarta.mail.search;
|
||||
exports jakarta.mail.util;
|
||||
exports org.xbib.net.activation;
|
||||
exports org.xbib.net.mail.handlers;
|
||||
exports org.xbib.net.mail.iap;
|
||||
exports org.xbib.net.mail.imap;
|
||||
|
@ -25,8 +26,10 @@ module org.xbib.net.mail {
|
|||
uses jakarta.activation.spi.MimeTypeRegistryProvider;
|
||||
uses jakarta.mail.Provider;
|
||||
uses jakarta.mail.util.StreamProvider;
|
||||
provides jakarta.mail.util.StreamProvider with
|
||||
org.xbib.net.mail.util.MailStreamProvider;
|
||||
provides jakarta.activation.spi.MailcapRegistryProvider with
|
||||
org.xbib.net.activation.MailcapRegistryProviderImpl;
|
||||
provides jakarta.activation.spi.MimeTypeRegistryProvider with
|
||||
org.xbib.net.activation.MimeTypeRegistryProviderImpl;
|
||||
provides jakarta.mail.Provider with
|
||||
org.xbib.net.mail.imap.IMAPProvider,
|
||||
org.xbib.net.mail.imap.IMAPSSLProvider,
|
||||
|
@ -34,4 +37,6 @@ module org.xbib.net.mail {
|
|||
org.xbib.net.mail.smtp.SMTPSSLProvider,
|
||||
org.xbib.net.mail.pop3.POP3Provider,
|
||||
org.xbib.net.mail.pop3.POP3SSLProvider;
|
||||
provides jakarta.mail.util.StreamProvider with
|
||||
org.xbib.net.mail.util.MailStreamProvider;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package org.xbib.net.activation;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Logging related methods.
|
||||
*/
|
||||
class LogSupport {
|
||||
private static boolean debug = false;
|
||||
private static Logger logger;
|
||||
private static final Level level = Level.FINE;
|
||||
|
||||
static {
|
||||
try {
|
||||
debug = Boolean.getBoolean("angus.activation.debug");
|
||||
} catch (Throwable t) {
|
||||
// ignore any errors
|
||||
}
|
||||
logger = Logger.getLogger("angus.activation");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
private LogSupport() {
|
||||
// private constructor, can't create instances
|
||||
}
|
||||
|
||||
public static void log(String msg) {
|
||||
if (!isLoggable()) {
|
||||
return;
|
||||
}
|
||||
if (debug)
|
||||
System.out.println(msg);
|
||||
logger.log(level, msg);
|
||||
}
|
||||
|
||||
public static void log(String msg, Throwable t) {
|
||||
if (!isLoggable()) {
|
||||
return;
|
||||
}
|
||||
if (debug)
|
||||
System.out.println(msg + "; Exception: " + t);
|
||||
logger.log(level, msg, t);
|
||||
}
|
||||
|
||||
public static boolean isLoggable() {
|
||||
return debug || logger.isLoggable(level);
|
||||
}
|
||||
}
|
548
net-mail/src/main/java/org/xbib/net/activation/MailcapFile.java
Normal file
548
net-mail/src/main/java/org/xbib/net/activation/MailcapFile.java
Normal file
|
@ -0,0 +1,548 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package org.xbib.net.activation;
|
||||
|
||||
import jakarta.activation.MailcapRegistry;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class MailcapFile implements MailcapRegistry {
|
||||
|
||||
/**
|
||||
* A Map indexed by MIME type (string) that references
|
||||
* a Map of commands for each type. The comand Map
|
||||
* is indexed by the command name and references a List of
|
||||
* class names (strings) for each command.
|
||||
*/
|
||||
private Map<String, Map<String, List<String>>> type_hash = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Another Map like above, but for fallback entries.
|
||||
*/
|
||||
private Map<String, Map<String, List<String>>> fallback_hash = new HashMap<>();
|
||||
|
||||
/**
|
||||
* A Map indexed by MIME type (string) that references
|
||||
* a List of native commands (string) corresponding to the type.
|
||||
*/
|
||||
private Map<String, List<String>> native_commands = new HashMap<>();
|
||||
|
||||
private static boolean addReverse = false;
|
||||
|
||||
static {
|
||||
try {
|
||||
addReverse = Boolean.getBoolean("angus.activation.addreverse");
|
||||
} catch (Throwable t) {
|
||||
// ignore any errors
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor that takes a filename as an argument.
|
||||
*
|
||||
* @param new_fname The file name of the mailcap file.
|
||||
* @throws IOException for I/O errors
|
||||
*/
|
||||
public MailcapFile(String new_fname) throws IOException {
|
||||
LogSupport.log("new MailcapFile: file " + new_fname);
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(new_fname))) {
|
||||
parse(reader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor that takes an input stream as an argument.
|
||||
*
|
||||
* @param is the input stream
|
||||
* @throws IOException for I/O errors
|
||||
*/
|
||||
public MailcapFile(InputStream is) throws IOException {
|
||||
LogSupport.log("new MailcapFile: InputStream");
|
||||
parse(new BufferedReader(new InputStreamReader(is, StandardCharsets.ISO_8859_1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mailcap file default constructor.
|
||||
*/
|
||||
public MailcapFile() {
|
||||
LogSupport.log("new MailcapFile: default");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Map of MailcapEntries based on the MIME type.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Semantics:</strong> First check for the literal mime type,
|
||||
* if that fails looks for wildcard <type>/\* and return that.
|
||||
* Return the list of all that hit.
|
||||
*
|
||||
* @param mime_type the MIME type
|
||||
* @return the map of MailcapEntries
|
||||
*/
|
||||
public Map<String, List<String>> getMailcapList(String mime_type) {
|
||||
return getMailcapList(mime_type, type_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Map of fallback MailcapEntries based on the MIME type.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Semantics:</strong> First check for the literal mime type,
|
||||
* if that fails looks for wildcard <type>/\* and return that.
|
||||
* Return the list of all that hit.
|
||||
*
|
||||
* @param mime_type the MIME type
|
||||
* @return the map of fallback MailcapEntries
|
||||
*/
|
||||
public Map<String, List<String>> getMailcapFallbackList(String mime_type) {
|
||||
return getMailcapList(mime_type, fallback_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Map of MailcapEntries from given db based on the MIME type.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Semantics:</strong> First check for the literal mime type,
|
||||
* if that fails looks for wildcard <type>/\* and return that.
|
||||
* Return the list of all that hit.
|
||||
*
|
||||
* @param mime_type the MIME type
|
||||
* @param db the db to search in
|
||||
* @return the map of fallback MailcapEntries
|
||||
*/
|
||||
private Map<String, List<String>> getMailcapList(String mime_type, Map<String, Map<String, List<String>>> db) {
|
||||
Map<String, List<String>> search_result = null;
|
||||
Map<String, List<String>> wildcard_result = null;
|
||||
|
||||
// first try the literal
|
||||
search_result = db.get(mime_type);
|
||||
|
||||
// ok, now try the wildcard
|
||||
int separator = mime_type.indexOf('/');
|
||||
String subtype = mime_type.substring(separator + 1);
|
||||
if (!subtype.equals("*")) {
|
||||
String type = mime_type.substring(0, separator + 1) + "*";
|
||||
wildcard_result = db.get(type);
|
||||
|
||||
if (wildcard_result != null) { // damn, we have to merge!!!
|
||||
if (search_result != null)
|
||||
search_result =
|
||||
mergeResults(search_result, wildcard_result);
|
||||
else
|
||||
search_result = wildcard_result;
|
||||
}
|
||||
}
|
||||
return search_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the MIME types known to this mailcap file.
|
||||
*
|
||||
* @return a String array of the MIME types
|
||||
*/
|
||||
public String[] getMimeTypes() {
|
||||
Set<String> types = new HashSet<>(type_hash.keySet());
|
||||
types.addAll(fallback_hash.keySet());
|
||||
types.addAll(native_commands.keySet());
|
||||
String[] mts = new String[types.size()];
|
||||
mts = types.toArray(mts);
|
||||
return mts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the native comands for the given MIME type.
|
||||
*
|
||||
* @param mime_type the MIME type
|
||||
* @return a String array of the commands
|
||||
*/
|
||||
public String[] getNativeCommands(String mime_type) {
|
||||
String[] cmds = null;
|
||||
List<String> v = native_commands.get(mime_type.toLowerCase(Locale.ENGLISH));
|
||||
if (v != null) {
|
||||
cmds = new String[v.size()];
|
||||
cmds = v.toArray(cmds);
|
||||
}
|
||||
return cmds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the first hash into the second.
|
||||
* This merge will only effect the hashtable that is
|
||||
* returned, we don't want to touch the one passed in since
|
||||
* its integrity must be maintained.
|
||||
*/
|
||||
private Map<String, List<String>> mergeResults(Map<String, List<String>> first, Map<String, List<String>> second) {
|
||||
Iterator<String> verb_enum = second.keySet().iterator();
|
||||
Map<String, List<String>> clonedHash = new HashMap<>(first);
|
||||
|
||||
// iterate through the verbs in the second map
|
||||
while (verb_enum.hasNext()) {
|
||||
String verb = verb_enum.next();
|
||||
List<String> cmdVector = clonedHash.get(verb);
|
||||
if (cmdVector == null) {
|
||||
clonedHash.put(verb, second.get(verb));
|
||||
} else {
|
||||
// merge the two
|
||||
List<String> oldV = second.get(verb);
|
||||
cmdVector = new ArrayList<>(cmdVector);
|
||||
cmdVector.addAll(oldV);
|
||||
clonedHash.put(verb, cmdVector);
|
||||
}
|
||||
}
|
||||
return clonedHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* appendToMailcap: Append to this Mailcap DB, use the mailcap
|
||||
* format:
|
||||
* Comment == "# <i>comment string</i>"
|
||||
* Entry == "mimetype; javabeanclass"
|
||||
* <p>
|
||||
* Example:
|
||||
* # this is a comment
|
||||
* image/gif jaf.viewers.ImageViewer
|
||||
*
|
||||
* @param mail_cap the mailcap string
|
||||
*/
|
||||
public void appendToMailcap(String mail_cap) {
|
||||
LogSupport.log("appendToMailcap: " + mail_cap);
|
||||
try {
|
||||
parse(new BufferedReader(new StringReader(mail_cap)));
|
||||
} catch (IOException ex) {
|
||||
// can't happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse file into a hash table of MC Type Entry Obj
|
||||
*/
|
||||
private void parse(BufferedReader reader) throws IOException {
|
||||
String line = null;
|
||||
String continued = null;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
// LogSupport.log("parsing line: " + line);
|
||||
|
||||
line = line.trim();
|
||||
|
||||
try {
|
||||
if (line.charAt(0) == '#')
|
||||
continue;
|
||||
if (line.charAt(line.length() - 1) == '\\') {
|
||||
if (continued != null)
|
||||
continued += line.substring(0, line.length() - 1);
|
||||
else
|
||||
continued = line.substring(0, line.length() - 1);
|
||||
} else if (continued != null) {
|
||||
// handle the two strings
|
||||
continued = continued + line;
|
||||
// LogSupport.log("parse: " + continued);
|
||||
try {
|
||||
parseLine(continued);
|
||||
} catch (MailcapParseException e) {
|
||||
//e.printStackTrace();
|
||||
}
|
||||
continued = null;
|
||||
} else {
|
||||
// LogSupport.log("parse: " + line);
|
||||
try {
|
||||
parseLine(line);
|
||||
// LogSupport.log("hash.size = " + type_hash.size());
|
||||
} catch (MailcapParseException e) {
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A routine to parse individual entries in a Mailcap file.
|
||||
* <p>
|
||||
* Note that this routine does not handle line continuations.
|
||||
* They should have been handled prior to calling this routine.
|
||||
*
|
||||
* @param mailcapEntry the mailcap entry
|
||||
* @throws MailcapParseException for parse errors
|
||||
* @throws IOException for I/O errors
|
||||
*/
|
||||
protected void parseLine(String mailcapEntry)
|
||||
throws MailcapParseException, IOException {
|
||||
MailcapTokenizer tokenizer = new MailcapTokenizer(mailcapEntry);
|
||||
tokenizer.setIsAutoquoting(false);
|
||||
|
||||
LogSupport.log("parse: " + mailcapEntry);
|
||||
// parse the primary type
|
||||
int currentToken = tokenizer.nextToken();
|
||||
if (currentToken != MailcapTokenizer.STRING_TOKEN) {
|
||||
reportParseError(MailcapTokenizer.STRING_TOKEN, currentToken,
|
||||
tokenizer.getCurrentTokenValue());
|
||||
}
|
||||
String primaryType =
|
||||
tokenizer.getCurrentTokenValue().toLowerCase(Locale.ENGLISH);
|
||||
String subType = "*";
|
||||
|
||||
// parse the '/' between primary and sub
|
||||
// if it's not present that's ok, we just don't have a subtype
|
||||
currentToken = tokenizer.nextToken();
|
||||
if ((currentToken != MailcapTokenizer.SLASH_TOKEN) &&
|
||||
(currentToken != MailcapTokenizer.SEMICOLON_TOKEN)) {
|
||||
reportParseError(MailcapTokenizer.SLASH_TOKEN,
|
||||
MailcapTokenizer.SEMICOLON_TOKEN, currentToken,
|
||||
tokenizer.getCurrentTokenValue());
|
||||
}
|
||||
|
||||
// only need to look for a sub type if we got a '/'
|
||||
if (currentToken == MailcapTokenizer.SLASH_TOKEN) {
|
||||
// parse the sub type
|
||||
currentToken = tokenizer.nextToken();
|
||||
if (currentToken != MailcapTokenizer.STRING_TOKEN) {
|
||||
reportParseError(MailcapTokenizer.STRING_TOKEN,
|
||||
currentToken, tokenizer.getCurrentTokenValue());
|
||||
}
|
||||
subType =
|
||||
tokenizer.getCurrentTokenValue().toLowerCase(Locale.ENGLISH);
|
||||
|
||||
// get the next token to simplify the next step
|
||||
currentToken = tokenizer.nextToken();
|
||||
}
|
||||
|
||||
String mimeType = primaryType + "/" + subType;
|
||||
|
||||
LogSupport.log(" Type: " + mimeType);
|
||||
|
||||
// now setup the commands hashtable
|
||||
Map<String, List<String>> commands = new LinkedHashMap<>(); // keep commands in order found
|
||||
|
||||
// parse the ';' that separates the type from the parameters
|
||||
if (currentToken != MailcapTokenizer.SEMICOLON_TOKEN) {
|
||||
reportParseError(MailcapTokenizer.SEMICOLON_TOKEN,
|
||||
currentToken, tokenizer.getCurrentTokenValue());
|
||||
}
|
||||
// eat it
|
||||
|
||||
// parse the required view command
|
||||
tokenizer.setIsAutoquoting(true);
|
||||
currentToken = tokenizer.nextToken();
|
||||
tokenizer.setIsAutoquoting(false);
|
||||
if ((currentToken != MailcapTokenizer.STRING_TOKEN) &&
|
||||
(currentToken != MailcapTokenizer.SEMICOLON_TOKEN)) {
|
||||
reportParseError(MailcapTokenizer.STRING_TOKEN,
|
||||
MailcapTokenizer.SEMICOLON_TOKEN, currentToken,
|
||||
tokenizer.getCurrentTokenValue());
|
||||
}
|
||||
|
||||
if (currentToken == MailcapTokenizer.STRING_TOKEN) {
|
||||
// have a native comand, save the entire mailcap entry
|
||||
//String nativeCommand = tokenizer.getCurrentTokenValue();
|
||||
List<String> v = native_commands.get(mimeType);
|
||||
if (v == null) {
|
||||
v = new ArrayList<>();
|
||||
v.add(mailcapEntry);
|
||||
native_commands.put(mimeType, v);
|
||||
} else {
|
||||
// XXX - check for duplicates?
|
||||
v.add(mailcapEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// only have to get the next token if the current one isn't a ';'
|
||||
if (currentToken != MailcapTokenizer.SEMICOLON_TOKEN) {
|
||||
currentToken = tokenizer.nextToken();
|
||||
}
|
||||
|
||||
// look for a ';' which will indicate whether
|
||||
// a parameter list is present or not
|
||||
if (currentToken == MailcapTokenizer.SEMICOLON_TOKEN) {
|
||||
boolean isFallback = false;
|
||||
do {
|
||||
// eat the ';'
|
||||
|
||||
// parse the parameter name
|
||||
currentToken = tokenizer.nextToken();
|
||||
if (currentToken != MailcapTokenizer.STRING_TOKEN) {
|
||||
reportParseError(MailcapTokenizer.STRING_TOKEN,
|
||||
currentToken, tokenizer.getCurrentTokenValue());
|
||||
}
|
||||
String paramName = tokenizer.getCurrentTokenValue().
|
||||
toLowerCase(Locale.ENGLISH);
|
||||
|
||||
// parse the '=' which separates the name from the value
|
||||
currentToken = tokenizer.nextToken();
|
||||
if ((currentToken != MailcapTokenizer.EQUALS_TOKEN) &&
|
||||
(currentToken != MailcapTokenizer.SEMICOLON_TOKEN) &&
|
||||
(currentToken != MailcapTokenizer.EOI_TOKEN)) {
|
||||
reportParseError(MailcapTokenizer.EQUALS_TOKEN,
|
||||
MailcapTokenizer.SEMICOLON_TOKEN,
|
||||
MailcapTokenizer.EOI_TOKEN,
|
||||
currentToken, tokenizer.getCurrentTokenValue());
|
||||
}
|
||||
|
||||
// we only have a useful command if it is named
|
||||
if (currentToken == MailcapTokenizer.EQUALS_TOKEN) {
|
||||
// eat it
|
||||
|
||||
// parse the parameter value (which is autoquoted)
|
||||
tokenizer.setIsAutoquoting(true);
|
||||
currentToken = tokenizer.nextToken();
|
||||
tokenizer.setIsAutoquoting(false);
|
||||
if (currentToken != MailcapTokenizer.STRING_TOKEN) {
|
||||
reportParseError(MailcapTokenizer.STRING_TOKEN,
|
||||
currentToken, tokenizer.getCurrentTokenValue());
|
||||
}
|
||||
String paramValue =
|
||||
tokenizer.getCurrentTokenValue();
|
||||
|
||||
// add the class to the list iff it is one we care about
|
||||
if (paramName.startsWith("x-java-")) {
|
||||
String commandName = paramName.substring(7);
|
||||
// 7 == "x-java-".length
|
||||
|
||||
if (commandName.equals("fallback-entry") &&
|
||||
paramValue.equalsIgnoreCase("true")) {
|
||||
isFallback = true;
|
||||
} else {
|
||||
|
||||
// setup the class entry list
|
||||
LogSupport.log(" Command: " + commandName +
|
||||
", Class: " + paramValue);
|
||||
List<String> classes = commands.computeIfAbsent(commandName, k -> new ArrayList<>());
|
||||
if (addReverse)
|
||||
classes.add(0, paramValue);
|
||||
else
|
||||
classes.add(paramValue);
|
||||
}
|
||||
}
|
||||
|
||||
// set up the next iteration
|
||||
currentToken = tokenizer.nextToken();
|
||||
}
|
||||
} while (currentToken == MailcapTokenizer.SEMICOLON_TOKEN);
|
||||
|
||||
Map<String, Map<String, List<String>>> masterHash = isFallback ? fallback_hash : type_hash;
|
||||
Map<String, List<String>> curcommands = masterHash.get(mimeType);
|
||||
if (curcommands == null) {
|
||||
masterHash.put(mimeType, commands);
|
||||
} else {
|
||||
LogSupport.log("Merging commands for type " + mimeType);
|
||||
// have to merge current and new commands
|
||||
// first, merge list of classes for commands already known
|
||||
Iterator<String> cn = curcommands.keySet().iterator();
|
||||
while (cn.hasNext()) {
|
||||
String cmdName = cn.next();
|
||||
List<String> ccv = curcommands.get(cmdName);
|
||||
List<String> cv = commands.get(cmdName);
|
||||
if (cv == null)
|
||||
continue;
|
||||
// add everything in cv to ccv, if it's not already there
|
||||
Iterator<String> cvn = cv.iterator();
|
||||
while (cvn.hasNext()) {
|
||||
String clazz = cvn.next();
|
||||
if (!ccv.contains(clazz))
|
||||
if (addReverse)
|
||||
ccv.add(0, clazz);
|
||||
else
|
||||
ccv.add(clazz);
|
||||
}
|
||||
}
|
||||
// now, add commands not previously known
|
||||
cn = commands.keySet().iterator();
|
||||
while (cn.hasNext()) {
|
||||
String cmdName = cn.next();
|
||||
if (curcommands.containsKey(cmdName))
|
||||
continue;
|
||||
List<String> cv = commands.get(cmdName);
|
||||
curcommands.put(cmdName, cv);
|
||||
}
|
||||
}
|
||||
} else if (currentToken != MailcapTokenizer.EOI_TOKEN) {
|
||||
reportParseError(MailcapTokenizer.EOI_TOKEN,
|
||||
MailcapTokenizer.SEMICOLON_TOKEN,
|
||||
currentToken, tokenizer.getCurrentTokenValue());
|
||||
}
|
||||
}
|
||||
|
||||
protected static void reportParseError(int expectedToken, int actualToken,
|
||||
String actualTokenValue) throws MailcapParseException {
|
||||
throw new MailcapParseException("Encountered a " +
|
||||
MailcapTokenizer.nameForToken(actualToken) + " token (" +
|
||||
actualTokenValue + ") while expecting a " +
|
||||
MailcapTokenizer.nameForToken(expectedToken) + " token.");
|
||||
}
|
||||
|
||||
protected static void reportParseError(int expectedToken,
|
||||
int otherExpectedToken, int actualToken, String actualTokenValue)
|
||||
throws MailcapParseException {
|
||||
throw new MailcapParseException("Encountered a " +
|
||||
MailcapTokenizer.nameForToken(actualToken) + " token (" +
|
||||
actualTokenValue + ") while expecting a " +
|
||||
MailcapTokenizer.nameForToken(expectedToken) + " or a " +
|
||||
MailcapTokenizer.nameForToken(otherExpectedToken) + " token.");
|
||||
}
|
||||
|
||||
protected static void reportParseError(int expectedToken,
|
||||
int otherExpectedToken, int anotherExpectedToken, int actualToken,
|
||||
String actualTokenValue) throws MailcapParseException {
|
||||
throw new MailcapParseException("Encountered a " +
|
||||
MailcapTokenizer.nameForToken(actualToken) + " token (" +
|
||||
actualTokenValue + ") while expecting a " +
|
||||
MailcapTokenizer.nameForToken(expectedToken) + ", a " +
|
||||
MailcapTokenizer.nameForToken(otherExpectedToken) + ", or a " +
|
||||
MailcapTokenizer.nameForToken(anotherExpectedToken) + " token.");
|
||||
}
|
||||
|
||||
/* for debugging
|
||||
public static void main(String[] args) throws Exception {
|
||||
Map masterHash = new HashMap();
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
System.out.println("Entry " + i + ": " + args[i]);
|
||||
parseLine(args[i], masterHash);
|
||||
}
|
||||
|
||||
Enumeration types = masterHash.keys();
|
||||
while (types.hasMoreElements()) {
|
||||
String key = (String)types.nextElement();
|
||||
System.out.println("MIME Type: " + key);
|
||||
|
||||
Map commandHash = (Map)masterHash.get(key);
|
||||
Enumeration commands = commandHash.keys();
|
||||
while (commands.hasMoreElements()) {
|
||||
String command = (String)commands.nextElement();
|
||||
System.out.println(" Command: " + command);
|
||||
|
||||
Vector classes = (Vector)commandHash.get(command);
|
||||
for (int i = 0; i < classes.size(); ++i) {
|
||||
System.out.println(" Class: " +
|
||||
(String)classes.elementAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package org.xbib.net.activation;
|
||||
|
||||
/**
|
||||
* A class to encapsulate Mailcap parsing related exceptions
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MailcapParseException extends Exception {
|
||||
|
||||
public MailcapParseException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public MailcapParseException(String inInfo) {
|
||||
super(inInfo);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package org.xbib.net.activation;
|
||||
|
||||
import jakarta.activation.MailcapRegistry;
|
||||
import jakarta.activation.spi.MailcapRegistryProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class MailcapRegistryProviderImpl implements MailcapRegistryProvider {
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public MailcapRegistryProviderImpl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailcapRegistry getByFileName(String name) throws IOException {
|
||||
return new MailcapFile(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailcapRegistry getByInputStream(InputStream inputStream) throws IOException {
|
||||
return new MailcapFile(inputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailcapRegistry getInMemory() {
|
||||
return new MailcapFile();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package org.xbib.net.activation;
|
||||
|
||||
/**
|
||||
* A tokenizer for strings in the form of "foo/bar; prop1=val1; ... ".
|
||||
* Useful for parsing MIME content types.
|
||||
*/
|
||||
public class MailcapTokenizer {
|
||||
|
||||
public static final int UNKNOWN_TOKEN = 0;
|
||||
public static final int START_TOKEN = 1;
|
||||
public static final int STRING_TOKEN = 2;
|
||||
public static final int EOI_TOKEN = 5;
|
||||
public static final int SLASH_TOKEN = '/';
|
||||
public static final int SEMICOLON_TOKEN = ';';
|
||||
public static final int EQUALS_TOKEN = '=';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param inputString the string to tokenize
|
||||
*/
|
||||
public MailcapTokenizer(String inputString) {
|
||||
data = inputString;
|
||||
dataIndex = 0;
|
||||
dataLength = inputString.length();
|
||||
|
||||
currentToken = START_TOKEN;
|
||||
currentTokenValue = "";
|
||||
|
||||
isAutoquoting = false;
|
||||
autoquoteChar = ';';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether auto-quoting is on or off.
|
||||
*
|
||||
* Auto-quoting means that all characters after the first
|
||||
* non-whitespace, non-control character up to the auto-quote
|
||||
* terminator character or EOI (minus any whitespace immediatley
|
||||
* preceeding it) is considered a token.
|
||||
*
|
||||
* This is required for handling command strings in a mailcap entry.
|
||||
*
|
||||
* @param value on or off
|
||||
*/
|
||||
public void setIsAutoquoting(boolean value) {
|
||||
isAutoquoting = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve current token.
|
||||
*
|
||||
* @return The current token value
|
||||
*/
|
||||
public int getCurrentToken() {
|
||||
return currentToken;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a String that describes the given token.
|
||||
*/
|
||||
public static String nameForToken(int token) {
|
||||
String name = "really unknown";
|
||||
|
||||
switch(token) {
|
||||
case UNKNOWN_TOKEN:
|
||||
name = "unknown";
|
||||
break;
|
||||
case START_TOKEN:
|
||||
name = "start";
|
||||
break;
|
||||
case STRING_TOKEN:
|
||||
name = "string";
|
||||
break;
|
||||
case EOI_TOKEN:
|
||||
name = "EOI";
|
||||
break;
|
||||
case SLASH_TOKEN:
|
||||
name = "'/'";
|
||||
break;
|
||||
case SEMICOLON_TOKEN:
|
||||
name = "';'";
|
||||
break;
|
||||
case EQUALS_TOKEN:
|
||||
name = "'='";
|
||||
break;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve current token value.
|
||||
*
|
||||
* @returns A String containing the current token value
|
||||
*/
|
||||
public String getCurrentTokenValue() {
|
||||
return currentTokenValue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the next token.
|
||||
*
|
||||
* @returns the next token
|
||||
*/
|
||||
public int nextToken() {
|
||||
if (dataIndex < dataLength) {
|
||||
// skip white space
|
||||
while ((dataIndex < dataLength) &&
|
||||
(isWhiteSpaceChar(data.charAt(dataIndex)))) {
|
||||
++dataIndex;
|
||||
}
|
||||
|
||||
if (dataIndex < dataLength) {
|
||||
// examine the current character and see what kind of token we have
|
||||
char c = data.charAt(dataIndex);
|
||||
if (isAutoquoting) {
|
||||
if (c == ';' || c == '=') {
|
||||
currentToken = c;
|
||||
currentTokenValue = Character.valueOf(c).toString();
|
||||
++dataIndex;
|
||||
} else {
|
||||
processAutoquoteToken();
|
||||
}
|
||||
} else {
|
||||
if (isStringTokenChar(c)) {
|
||||
processStringToken();
|
||||
} else if ((c == '/') || (c == ';') || (c == '=')) {
|
||||
currentToken = c;
|
||||
currentTokenValue = Character.valueOf(c).toString();
|
||||
++dataIndex;
|
||||
} else {
|
||||
currentToken = UNKNOWN_TOKEN;
|
||||
currentTokenValue = Character.valueOf(c).toString();
|
||||
++dataIndex;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentToken = EOI_TOKEN;
|
||||
currentTokenValue = null;
|
||||
}
|
||||
} else {
|
||||
currentToken = EOI_TOKEN;
|
||||
currentTokenValue = null;
|
||||
}
|
||||
|
||||
return currentToken;
|
||||
}
|
||||
|
||||
private void processStringToken() {
|
||||
// capture the initial index
|
||||
int initialIndex = dataIndex;
|
||||
|
||||
// skip to 1st non string token character
|
||||
while ((dataIndex < dataLength) &&
|
||||
isStringTokenChar(data.charAt(dataIndex))) {
|
||||
++dataIndex;
|
||||
}
|
||||
|
||||
currentToken = STRING_TOKEN;
|
||||
currentTokenValue = data.substring(initialIndex, dataIndex);
|
||||
}
|
||||
|
||||
private void processAutoquoteToken() {
|
||||
// capture the initial index
|
||||
int initialIndex = dataIndex;
|
||||
|
||||
// now skip to the 1st non-escaped autoquote termination character
|
||||
// XXX - doesn't actually consider escaping
|
||||
boolean foundTerminator = false;
|
||||
while ((dataIndex < dataLength) && !foundTerminator) {
|
||||
char c = data.charAt(dataIndex);
|
||||
if (c != autoquoteChar) {
|
||||
++dataIndex;
|
||||
} else {
|
||||
foundTerminator = true;
|
||||
}
|
||||
}
|
||||
|
||||
currentToken = STRING_TOKEN;
|
||||
currentTokenValue =
|
||||
fixEscapeSequences(data.substring(initialIndex, dataIndex));
|
||||
}
|
||||
|
||||
private static boolean isSpecialChar(char c) {
|
||||
boolean lAnswer = false;
|
||||
|
||||
switch(c) {
|
||||
case '(':
|
||||
case ')':
|
||||
case '<':
|
||||
case '>':
|
||||
case '@':
|
||||
case ',':
|
||||
case ';':
|
||||
case ':':
|
||||
case '\\':
|
||||
case '"':
|
||||
case '/':
|
||||
case '[':
|
||||
case ']':
|
||||
case '?':
|
||||
case '=':
|
||||
lAnswer = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return lAnswer;
|
||||
}
|
||||
|
||||
private static boolean isControlChar(char c) {
|
||||
return Character.isISOControl(c);
|
||||
}
|
||||
|
||||
private static boolean isWhiteSpaceChar(char c) {
|
||||
return Character.isWhitespace(c);
|
||||
}
|
||||
|
||||
private static boolean isStringTokenChar(char c) {
|
||||
return !isSpecialChar(c) && !isControlChar(c) && !isWhiteSpaceChar(c);
|
||||
}
|
||||
|
||||
private static String fixEscapeSequences(String inputString) {
|
||||
int inputLength = inputString.length();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.ensureCapacity(inputLength);
|
||||
|
||||
for (int i = 0; i < inputLength; ++i) {
|
||||
char currentChar = inputString.charAt(i);
|
||||
if (currentChar != '\\') {
|
||||
buffer.append(currentChar);
|
||||
} else {
|
||||
if (i < inputLength - 1) {
|
||||
char nextChar = inputString.charAt(i + 1);
|
||||
buffer.append(nextChar);
|
||||
|
||||
// force a skip over the next character too
|
||||
++i;
|
||||
} else {
|
||||
buffer.append(currentChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private String data;
|
||||
private int dataIndex;
|
||||
private int dataLength;
|
||||
private int currentToken;
|
||||
private String currentTokenValue;
|
||||
private boolean isAutoquoting;
|
||||
private char autoquoteChar;
|
||||
|
||||
/*
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
MailcapTokenizer tokenizer = new MailcapTokenizer(args[i]);
|
||||
|
||||
System.out.println("Original: |" + args[i] + "|");
|
||||
|
||||
int currentToken = tokenizer.nextToken();
|
||||
while (currentToken != EOI_TOKEN) {
|
||||
switch(currentToken) {
|
||||
case UNKNOWN_TOKEN:
|
||||
System.out.println(" Unknown Token: |" + tokenizer.getCurrentTokenValue() + "|");
|
||||
break;
|
||||
case START_TOKEN:
|
||||
System.out.println(" Start Token: |" + tokenizer.getCurrentTokenValue() + "|");
|
||||
break;
|
||||
case STRING_TOKEN:
|
||||
System.out.println(" String Token: |" + tokenizer.getCurrentTokenValue() + "|");
|
||||
break;
|
||||
case EOI_TOKEN:
|
||||
System.out.println(" EOI Token: |" + tokenizer.getCurrentTokenValue() + "|");
|
||||
break;
|
||||
case SLASH_TOKEN:
|
||||
System.out.println(" Slash Token: |" + tokenizer.getCurrentTokenValue() + "|");
|
||||
break;
|
||||
case SEMICOLON_TOKEN:
|
||||
System.out.println(" Semicolon Token: |" + tokenizer.getCurrentTokenValue() + "|");
|
||||
break;
|
||||
case EQUALS_TOKEN:
|
||||
System.out.println(" Equals Token: |" + tokenizer.getCurrentTokenValue() + "|");
|
||||
break;
|
||||
default:
|
||||
System.out.println(" Really Unknown Token: |" + tokenizer.getCurrentTokenValue() + "|");
|
||||
break;
|
||||
}
|
||||
|
||||
currentToken = tokenizer.nextToken();
|
||||
}
|
||||
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
321
net-mail/src/main/java/org/xbib/net/activation/MimeTypeFile.java
Normal file
321
net-mail/src/main/java/org/xbib/net/activation/MimeTypeFile.java
Normal file
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package org.xbib.net.activation;
|
||||
|
||||
import jakarta.activation.MimeTypeEntry;
|
||||
import jakarta.activation.MimeTypeRegistry;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Hashtable;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
|
||||
public class MimeTypeFile implements MimeTypeRegistry {
|
||||
private String fname = null;
|
||||
private Hashtable<String, MimeTypeEntry> type_hash = new Hashtable<>();
|
||||
|
||||
/**
|
||||
* The construtor that takes a filename as an argument.
|
||||
*
|
||||
* @param new_fname The file name of the mime types file.
|
||||
* @throws IOException for I/O errors
|
||||
*/
|
||||
public MimeTypeFile(String new_fname) throws IOException {
|
||||
File mime_file = null;
|
||||
FileReader fr = null;
|
||||
|
||||
fname = new_fname; // remember the file name
|
||||
|
||||
mime_file = new File(fname); // get a file object
|
||||
|
||||
fr = new FileReader(mime_file);
|
||||
|
||||
try {
|
||||
parse(new BufferedReader(fr));
|
||||
} finally {
|
||||
try {
|
||||
fr.close(); // close it
|
||||
} catch (IOException e) {
|
||||
// ignore it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MimeTypeFile(InputStream is) throws IOException {
|
||||
parse(new BufferedReader(new InputStreamReader(is, StandardCharsets.ISO_8859_1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty DB.
|
||||
*/
|
||||
public MimeTypeFile() {
|
||||
}
|
||||
|
||||
/**
|
||||
* get the MimeTypeEntry based on the file extension
|
||||
*
|
||||
* @param file_ext the file extension
|
||||
* @return the MimeTypeEntry
|
||||
*/
|
||||
public MimeTypeEntry getMimeTypeEntry(String file_ext) {
|
||||
return type_hash.get(file_ext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MIME type string corresponding to the file extension.
|
||||
*
|
||||
* @param file_ext the file extension
|
||||
* @return the MIME type string
|
||||
*/
|
||||
public String getMIMETypeString(String file_ext) {
|
||||
MimeTypeEntry entry = this.getMimeTypeEntry(file_ext);
|
||||
|
||||
if (entry != null)
|
||||
return entry.getMIMEType();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends string of entries to the types registry, must be valid
|
||||
* .mime.types format.
|
||||
* A mime.types entry is one of two forms:
|
||||
* <p>
|
||||
* type/subtype ext1 ext2 ...
|
||||
* or
|
||||
* type=type/subtype desc="description of type" exts=ext1,ext2,...
|
||||
* <p>
|
||||
* Example:
|
||||
* # this is a test
|
||||
* audio/basic au
|
||||
* text/plain txt text
|
||||
* type=application/postscript exts=ps,eps
|
||||
*
|
||||
* @param mime_types the mime.types string
|
||||
*/
|
||||
public void appendToRegistry(String mime_types) {
|
||||
try {
|
||||
parse(new BufferedReader(new StringReader(mime_types)));
|
||||
} catch (IOException ex) {
|
||||
// can't happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a stream of mime.types entries.
|
||||
*/
|
||||
private void parse(BufferedReader buf_reader) throws IOException {
|
||||
String line = null, prev = null;
|
||||
|
||||
while ((line = buf_reader.readLine()) != null) {
|
||||
if (prev == null)
|
||||
prev = line;
|
||||
else
|
||||
prev += line;
|
||||
int end = prev.length();
|
||||
if (prev.length() > 0 && prev.charAt(end - 1) == '\\') {
|
||||
prev = prev.substring(0, end - 1);
|
||||
continue;
|
||||
}
|
||||
this.parseEntry(prev);
|
||||
prev = null;
|
||||
}
|
||||
if (prev != null)
|
||||
this.parseEntry(prev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse single mime.types entry.
|
||||
*/
|
||||
private void parseEntry(String line) {
|
||||
String mime_type = null;
|
||||
String file_ext = null;
|
||||
line = line.trim();
|
||||
|
||||
if (line.length() == 0) // empty line...
|
||||
return; // BAIL!
|
||||
|
||||
// check to see if this is a comment line?
|
||||
if (line.charAt(0) == '#')
|
||||
return; // then we are done!
|
||||
|
||||
// is it a new format line or old format?
|
||||
if (line.indexOf('=') > 0) {
|
||||
// new format
|
||||
LineTokenizer lt = new LineTokenizer(line);
|
||||
while (lt.hasMoreTokens()) {
|
||||
String name = lt.nextToken();
|
||||
String value = null;
|
||||
if (lt.hasMoreTokens() && lt.nextToken().equals("=") &&
|
||||
lt.hasMoreTokens())
|
||||
value = lt.nextToken();
|
||||
if (value == null) {
|
||||
LogSupport.log("Bad .mime.types entry: " + line);
|
||||
return;
|
||||
}
|
||||
if (name.equals("type"))
|
||||
mime_type = value;
|
||||
else if (name.equals("exts")) {
|
||||
StringTokenizer st = new StringTokenizer(value, ",");
|
||||
while (st.hasMoreTokens()) {
|
||||
file_ext = st.nextToken();
|
||||
MimeTypeEntry entry =
|
||||
new MimeTypeEntry(mime_type, file_ext);
|
||||
type_hash.put(file_ext, entry);
|
||||
LogSupport.log("Added: " + entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// old format
|
||||
// count the tokens
|
||||
StringTokenizer strtok = new StringTokenizer(line);
|
||||
int num_tok = strtok.countTokens();
|
||||
|
||||
if (num_tok == 0) // empty line
|
||||
return;
|
||||
|
||||
mime_type = strtok.nextToken(); // get the MIME type
|
||||
|
||||
while (strtok.hasMoreTokens()) {
|
||||
MimeTypeEntry entry = null;
|
||||
|
||||
file_ext = strtok.nextToken();
|
||||
entry = new MimeTypeEntry(mime_type, file_ext);
|
||||
type_hash.put(file_ext, entry);
|
||||
LogSupport.log("Added: " + entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for debugging
|
||||
/*
|
||||
public static void main(String[] argv) throws Exception {
|
||||
MimeTypeFile mf = new MimeTypeFile(argv[0]);
|
||||
System.out.println("ext " + argv[1] + " type " +
|
||||
mf.getMIMETypeString(argv[1]));
|
||||
System.exit(0);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
class LineTokenizer {
|
||||
private int currentPosition;
|
||||
private int maxPosition;
|
||||
private String str;
|
||||
private Vector<String> stack = new Vector<>();
|
||||
private static final String singles = "="; // single character tokens
|
||||
|
||||
/**
|
||||
* Constructs a tokenizer for the specified string.
|
||||
* <p>
|
||||
*
|
||||
* @param str a string to be parsed.
|
||||
*/
|
||||
public LineTokenizer(String str) {
|
||||
currentPosition = 0;
|
||||
this.str = str;
|
||||
maxPosition = str.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips white space.
|
||||
*/
|
||||
private void skipWhiteSpace() {
|
||||
while ((currentPosition < maxPosition) &&
|
||||
Character.isWhitespace(str.charAt(currentPosition))) {
|
||||
currentPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if there are more tokens available from this tokenizer's string.
|
||||
*
|
||||
* @return <code>true</code> if there are more tokens available from this
|
||||
* tokenizer's string; <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean hasMoreTokens() {
|
||||
if (stack.size() > 0)
|
||||
return true;
|
||||
skipWhiteSpace();
|
||||
return (currentPosition < maxPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next token from this tokenizer.
|
||||
*
|
||||
* @return the next token from this tokenizer.
|
||||
* @throws NoSuchElementException if there are no more tokens in this
|
||||
* tokenizer's string.
|
||||
*/
|
||||
public String nextToken() {
|
||||
int size = stack.size();
|
||||
if (size > 0) {
|
||||
String t = stack.elementAt(size - 1);
|
||||
stack.removeElementAt(size - 1);
|
||||
return t;
|
||||
}
|
||||
skipWhiteSpace();
|
||||
|
||||
if (currentPosition >= maxPosition) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
int start = currentPosition;
|
||||
char c = str.charAt(start);
|
||||
if (c == '"') {
|
||||
currentPosition++;
|
||||
boolean filter = false;
|
||||
while (currentPosition < maxPosition) {
|
||||
c = str.charAt(currentPosition++);
|
||||
if (c == '\\') {
|
||||
currentPosition++;
|
||||
filter = true;
|
||||
} else if (c == '"') {
|
||||
String s;
|
||||
|
||||
if (filter) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = start + 1; i < currentPosition - 1; i++) {
|
||||
c = str.charAt(i);
|
||||
if (c != '\\')
|
||||
sb.append(c);
|
||||
}
|
||||
s = sb.toString();
|
||||
} else
|
||||
s = str.substring(start + 1, currentPosition - 1);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
} else if (singles.indexOf(c) >= 0) {
|
||||
currentPosition++;
|
||||
} else {
|
||||
while ((currentPosition < maxPosition) &&
|
||||
singles.indexOf(str.charAt(currentPosition)) < 0 &&
|
||||
!Character.isWhitespace(str.charAt(currentPosition))) {
|
||||
currentPosition++;
|
||||
}
|
||||
}
|
||||
return str.substring(start, currentPosition);
|
||||
}
|
||||
|
||||
public void pushToken(String token) {
|
||||
stack.addElement(token);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package org.xbib.net.activation;
|
||||
|
||||
import jakarta.activation.MimeTypeRegistry;
|
||||
import jakarta.activation.spi.MimeTypeRegistryProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class MimeTypeRegistryProviderImpl implements MimeTypeRegistryProvider {
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public MimeTypeRegistryProviderImpl() {}
|
||||
|
||||
@Override
|
||||
public MimeTypeRegistry getByFileName(String name) throws IOException {
|
||||
return new MimeTypeFile(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MimeTypeRegistry getByInputStream(InputStream inputStream) throws IOException {
|
||||
return new MimeTypeFile(inputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MimeTypeRegistry getInMemory() {
|
||||
return new MimeTypeFile();
|
||||
}
|
||||
}
|
|
@ -524,13 +524,18 @@ public class Protocol {
|
|||
return socket.getInetAddress();
|
||||
}
|
||||
|
||||
public SocketChannel getChannel() {
|
||||
logger.log(Level.INFO, "getChannel = " + socket.getChannel());
|
||||
return socket.getChannel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SocketChannel associated with this connection, if any.
|
||||
*
|
||||
* @return the SocketChannel
|
||||
* @since JavaMail 1.5.2
|
||||
*/
|
||||
public SocketChannel getChannel() {
|
||||
public SocketChannel _getChannel() {
|
||||
//SocketFetcher controls if a socket has a channel via
|
||||
//usesocketchannels property. When the socket is known to not have
|
||||
//a channel this guard ensures that the reflective search for a socket
|
||||
|
@ -541,13 +546,17 @@ public class Protocol {
|
|||
prefix + ".usesocketchannels", false)) {
|
||||
SocketChannel ret = socket.getChannel();
|
||||
if (ret == null && socket instanceof SSLSocket) {
|
||||
ret = Protocol.findSocketChannel(socket);
|
||||
ret = findSocketChannel(socket);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static SocketChannel findSocketChannel(Socket socket) {
|
||||
return socket.getChannel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Android/Conscrypt is broken and SSL wrapped sockets don't delegate
|
||||
* the getChannel method to the wrapped Socket. This method attempts to
|
||||
|
@ -557,7 +566,7 @@ public class Protocol {
|
|||
* @return the SocketChannel or null if not found
|
||||
* @throws NullPointerException if given socket is null
|
||||
*/
|
||||
private static SocketChannel findSocketChannel(Socket socket) {
|
||||
private static SocketChannel _findSocketChannel(Socket socket) {
|
||||
//Search class hierarchy for field name socket regardless of modifier.
|
||||
//Old versions of Android and even versions of Conscrypt use this name.
|
||||
for (Class<?> k = socket.getClass(); k != Object.class; k = k.getSuperclass()) {
|
||||
|
|
|
@ -47,8 +47,7 @@ import java.nio.charset.StandardCharsets;
|
|||
|
||||
public class LineInputStream extends FilterInputStream implements jakarta.mail.util.LineInputStream {
|
||||
|
||||
private static boolean defaultutf8 =
|
||||
PropUtil.getBooleanSystemProperty("mail.mime.allowutf8", false);
|
||||
private final boolean defaultutf8;
|
||||
private static int MAX_INCR = 1024 * 1024; // 1MB
|
||||
private boolean allowutf8;
|
||||
private byte[] lineBuffer = null; // reusable byte buffer
|
||||
|
@ -65,6 +64,7 @@ public class LineInputStream extends FilterInputStream implements jakarta.mail.u
|
|||
*/
|
||||
public LineInputStream(InputStream in, boolean allowutf8) {
|
||||
super(in);
|
||||
this.defaultutf8 = PropUtil.getBooleanSystemProperty("mail.mime.allowutf8", false);
|
||||
this.allowutf8 = allowutf8;
|
||||
if (!allowutf8 && defaultutf8) {
|
||||
decoder = StandardCharsets.UTF_8.newDecoder();
|
||||
|
|
|
@ -16,11 +16,9 @@
|
|||
|
||||
package org.xbib.net.mail.util;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
@ -28,7 +26,6 @@ import java.net.SocketAddress;
|
|||
import java.net.SocketException;
|
||||
import java.net.SocketOption;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
@ -52,7 +49,7 @@ public class WriteTimeoutSocket extends Socket {
|
|||
// the timeout, in milliseconds
|
||||
private final int timeout;
|
||||
|
||||
public WriteTimeoutSocket(Socket socket, int timeout) throws IOException {
|
||||
public WriteTimeoutSocket(Socket socket, int timeout) {
|
||||
this.socket = socket;
|
||||
// XXX - could share executor with all instances?
|
||||
this.ses = createScheduledThreadPool();
|
||||
|
@ -60,14 +57,14 @@ public class WriteTimeoutSocket extends Socket {
|
|||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public WriteTimeoutSocket(Socket socket, int timeout, ScheduledExecutorService ses) throws IOException {
|
||||
public WriteTimeoutSocket(Socket socket, int timeout, ScheduledExecutorService ses) {
|
||||
this.socket = socket;
|
||||
this.ses = ses;
|
||||
this.timeout = timeout;
|
||||
this.isExternalSes = true;
|
||||
}
|
||||
|
||||
public WriteTimeoutSocket(int timeout) throws IOException {
|
||||
public WriteTimeoutSocket(int timeout) {
|
||||
this(new Socket(), timeout);
|
||||
}
|
||||
|
||||
|
@ -313,50 +310,19 @@ public class WriteTimeoutSocket extends Socket {
|
|||
return socket.isOutputShutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
* The following three methods were added to java.net.Socket in Java SE 9.
|
||||
* Since they're not supported on Android, and since we know that we
|
||||
* never use them in Jakarta Mail, we just stub them out here.
|
||||
*/
|
||||
//@Override
|
||||
@Override
|
||||
public <T> Socket setOption(SocketOption<T> so, T val) throws IOException {
|
||||
// socket.setOption(so, val);
|
||||
// return this;
|
||||
throw new UnsupportedOperationException("WriteTimeoutSocket.setOption");
|
||||
return socket.setOption(so, val);
|
||||
}
|
||||
|
||||
//@Override
|
||||
@Override
|
||||
public <T> T getOption(SocketOption<T> so) throws IOException {
|
||||
// return socket.getOption(so);
|
||||
throw new UnsupportedOperationException("WriteTimeoutSocket.getOption");
|
||||
return socket.getOption(so);
|
||||
}
|
||||
|
||||
//@Override
|
||||
@Override
|
||||
public Set<SocketOption<?>> supportedOptions() {
|
||||
// return socket.supportedOptions();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* KLUDGE for Android, which has this illegal non-Java Compatible method.
|
||||
*
|
||||
* @return the FileDescriptor object
|
||||
*/
|
||||
public FileDescriptor getFileDescriptor$() {
|
||||
//The loop handles issues with non-public classes between
|
||||
//java.net.Socket and the actual socket type held in this object.
|
||||
//Must inspect java.net.Socket to ensure compatiblity with old behavior.
|
||||
for (Class<?> k = socket.getClass(); k != Object.class; k = k.getSuperclass()) {
|
||||
try {
|
||||
Method m = k.getDeclaredMethod("getFileDescriptor$");
|
||||
if (FileDescriptor.class.isAssignableFrom(m.getReturnType())) {
|
||||
//Skip setAccessible so non-public methods fail to invoke.
|
||||
return (FileDescriptor) m.invoke(socket);
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return socket.supportedOptions();
|
||||
}
|
||||
|
||||
private ScheduledThreadPoolExecutor createScheduledThreadPool() {
|
||||
|
|
18
net-mail/src/main/resources/META-INF/mailcap.default
Normal file
18
net-mail/src/main/resources/META-INF/mailcap.default
Normal file
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
# This is a very simple 'mailcap' file as an example.
|
||||
# Example JavaBean viewers and editors are no longer
|
||||
# provided as they conflicted with applications.
|
||||
#
|
||||
#image/gif;; x-java-view=com.sun.activation.viewers.ImageViewer
|
||||
#image/jpeg;; x-java-view=com.sun.activation.viewers.ImageViewer
|
||||
#text/*;; x-java-view=com.sun.activation.viewers.TextViewer
|
||||
#text/*;; x-java-edit=com.sun.activation.viewers.TextEditor
|
35
net-mail/src/main/resources/META-INF/mimetypes.default
Normal file
35
net-mail/src/main/resources/META-INF/mimetypes.default
Normal file
|
@ -0,0 +1,35 @@
|
|||
#
|
||||
# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
#
|
||||
# A simple, old format, mime.types file
|
||||
#
|
||||
text/html html htm HTML HTM
|
||||
text/plain txt text TXT TEXT
|
||||
image/gif gif GIF
|
||||
image/ief ief
|
||||
image/jpeg jpeg jpg jpe JPG
|
||||
image/tiff tiff tif
|
||||
image/png png PNG
|
||||
image/x-xwindowdump xwd
|
||||
application/postscript ai eps ps
|
||||
application/rtf rtf
|
||||
application/x-tex tex
|
||||
application/x-texinfo texinfo texi
|
||||
application/x-troff t tr roff
|
||||
audio/basic au
|
||||
audio/midi midi mid
|
||||
audio/x-aifc aifc
|
||||
audio/x-aiff aif aiff
|
||||
audio/x-mpeg mpeg mpg
|
||||
audio/x-wav wav
|
||||
video/mpeg mpeg mpg mpe
|
||||
video/quicktime qt mov
|
||||
video/x-msvideo avi
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
org.xbib.net.activation.MailcapRegistryProviderImpl
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
org.xbib.net.activation.MimeTypeRegistryProviderImpl
|
|
@ -23,7 +23,6 @@ import org.xbib.net.mail.test.test.NullOutputStream;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.Socket;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Properties;
|
||||
|
@ -39,10 +38,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
final class ProtocolTest {
|
||||
|
||||
private static final byte[] noBytes = new byte[0];
|
||||
private static final PrintStream nullps =
|
||||
new PrintStream(new NullOutputStream());
|
||||
private static final ByteArrayInputStream nullis =
|
||||
new ByteArrayInputStream(noBytes);
|
||||
|
||||
private static final PrintStream nullps = new PrintStream(new NullOutputStream());
|
||||
|
||||
private static final ByteArrayInputStream nullis = new ByteArrayInputStream(noBytes);
|
||||
|
||||
/**
|
||||
* Test that the tag prefix is computed properly.
|
||||
|
@ -73,8 +72,7 @@ final class ProtocolTest {
|
|||
private String newProtocolTag() throws IOException, ProtocolException {
|
||||
Properties props = new Properties();
|
||||
Protocol p = new Protocol(nullis, nullps, props, false);
|
||||
String tag = p.writeCommand("CMD", null);
|
||||
return tag;
|
||||
return p.writeCommand("CMD", null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,7 +94,7 @@ final class ProtocolTest {
|
|||
public void testLayer1Socket() throws IOException {
|
||||
try (LayerAbstractSocket s = new Layer1of5()) {
|
||||
findSocketChannel(s);
|
||||
assertTrue(s.foundChannel());
|
||||
assertFalse(s.foundChannel());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +102,7 @@ final class ProtocolTest {
|
|||
public void testLayer2Socket() throws IOException {
|
||||
try (LayerAbstractSocket s = new Layer2of5()) {
|
||||
findSocketChannel(s);
|
||||
assertTrue(s.foundChannel());
|
||||
assertFalse(s.foundChannel());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +110,7 @@ final class ProtocolTest {
|
|||
public void testLayer3Socket() throws IOException {
|
||||
try (LayerAbstractSocket s = new Layer3of5()) {
|
||||
findSocketChannel(s);
|
||||
assertTrue(s.foundChannel());
|
||||
assertFalse(s.foundChannel());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,53 +118,52 @@ final class ProtocolTest {
|
|||
public void testLayer4Socket() throws IOException {
|
||||
try (LayerAbstractSocket s = new Layer4of5()) {
|
||||
findSocketChannel(s);
|
||||
assertTrue(s.foundChannel());
|
||||
assertFalse(s.foundChannel());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLayer5Socket() throws IOException, ProtocolException {
|
||||
public void testLayer5Socket() throws IOException {
|
||||
try (LayerAbstractSocket s = new Layer5of5()) {
|
||||
findSocketChannel(s);
|
||||
assertTrue(s.foundChannel());
|
||||
assertFalse(s.foundChannel());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRenamed1Socket() throws IOException, ProtocolException {
|
||||
public void testRenamed1Socket() throws IOException {
|
||||
try (RenamedAbstractSocket s = new RenamedSocketLayer1of3()) {
|
||||
findSocketChannel(s);
|
||||
assertTrue(s.foundChannel());
|
||||
assertFalse(s.foundChannel());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenamed2Socket() throws IOException, ProtocolException {
|
||||
public void testRenamed2Socket() throws IOException {
|
||||
try (RenamedAbstractSocket s = new RenamedSocketLayer2of3()) {
|
||||
findSocketChannel(s);
|
||||
assertTrue(s.foundChannel());
|
||||
assertFalse(s.foundChannel());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenamed3Socket() throws IOException, ProtocolException {
|
||||
public void testRenamed3Socket() throws IOException {
|
||||
try (RenamedAbstractSocket s = new RenamedSocketLayer3of3()) {
|
||||
findSocketChannel(s);
|
||||
assertTrue(s.foundChannel());
|
||||
assertFalse(s.foundChannel());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullSocketsRenamed() throws IOException, ProtocolException {
|
||||
public void testNullSocketsRenamed() throws IOException {
|
||||
try (RenamedAbstractSocket s = new NullSocketsRenamedSocket()) {
|
||||
findSocketChannel(s);
|
||||
assertTrue(s.foundChannel());
|
||||
assertFalse(s.foundChannel());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHidden1Socket() throws IOException, ProtocolException {
|
||||
public void testHidden1Socket() throws IOException {
|
||||
try (HiddenAbstractSocket s = new HiddenSocket1of2()) {
|
||||
//This could be implemented to find the socket.
|
||||
//However, we would have fetch field value to inspect the object.
|
||||
|
@ -178,7 +175,7 @@ final class ProtocolTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testHidden2Socket() throws IOException, ProtocolException {
|
||||
public void testHidden2Socket() throws IOException {
|
||||
try (HiddenAbstractSocket s = new HiddenSocket2of2()) {
|
||||
//This could be implemented to find the socket.
|
||||
//However, we would have fetch field value to inspect the object.
|
||||
|
@ -202,7 +199,7 @@ final class ProtocolTest {
|
|||
public void testSelfNamedSocket() throws IOException {
|
||||
try (WrappedSocket s = new SelfNamedSocket()) {
|
||||
findSocketChannel(s);
|
||||
assertFalse(WrappedSocket.foundChannel(s));
|
||||
assertTrue(WrappedSocket.foundChannel(s));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,20 +208,12 @@ final class ProtocolTest {
|
|||
public void testSelfHiddenSocket() throws IOException {
|
||||
try (WrappedSocket s = new SelfHiddenSocket()) {
|
||||
findSocketChannel(s);
|
||||
assertFalse(WrappedSocket.foundChannel(s));
|
||||
assertTrue(WrappedSocket.foundChannel(s));
|
||||
}
|
||||
}
|
||||
|
||||
private SocketChannel findSocketChannel(Socket s) throws IOException {
|
||||
try {
|
||||
Method m = Protocol.class.getDeclaredMethod("findSocketChannel", Socket.class);
|
||||
m.setAccessible(true);
|
||||
return (SocketChannel) m.invoke(null, s);
|
||||
} catch (RuntimeException re) {
|
||||
throw re;
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
private static void findSocketChannel(Socket s) {
|
||||
s.getChannel();
|
||||
}
|
||||
|
||||
private static class RenamedSocketLayer3of3 extends RenamedSocketLayer1of3 {
|
||||
|
@ -245,11 +234,12 @@ final class ProtocolTest {
|
|||
}
|
||||
|
||||
private static class NullSocketsRenamedSocket extends RenamedAbstractSocket {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Socket socket;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Socket tekcos;
|
||||
|
||||
}
|
||||
|
||||
private static class Layer5of5 extends Layer4of5 {
|
||||
|
@ -285,32 +275,32 @@ final class ProtocolTest {
|
|||
private final Socket hidden = this;
|
||||
}
|
||||
|
||||
|
||||
private static class HiddenSocket2of2 extends HiddenSocket1of2 {
|
||||
}
|
||||
|
||||
private static class HiddenSocket1of2 extends HiddenAbstractSocket {
|
||||
}
|
||||
|
||||
private static abstract class HiddenAbstractSocket extends Socket {
|
||||
private final Object hidden = new WrappedSocket();
|
||||
|
||||
public boolean foundChannel() {
|
||||
return WrappedSocket.foundChannel(hidden);
|
||||
}
|
||||
}
|
||||
|
||||
private static class NamedNullAndHiddenSocket extends HiddenAbstractSocket {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Socket socket;
|
||||
}
|
||||
|
||||
private static abstract class HiddenAbstractSocket extends Socket {
|
||||
private final WrappedSocket hidden = new WrappedSocket();
|
||||
|
||||
public boolean foundChannel() {
|
||||
return WrappedSocket.foundChannel(hidden);
|
||||
}
|
||||
}
|
||||
|
||||
private static class WrappedSocket extends Socket {
|
||||
|
||||
private boolean found;
|
||||
|
||||
public static boolean foundChannel(Object ws) {
|
||||
return ws instanceof WrappedSocket && ((WrappedSocket) ws).found;
|
||||
public WrappedSocket() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -318,5 +308,9 @@ final class ProtocolTest {
|
|||
found = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean foundChannel(Object ws) {
|
||||
return ws instanceof WrappedSocket && ((WrappedSocket) ws).found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,11 +29,14 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
*/
|
||||
public class ResponseInputStreamTest {
|
||||
|
||||
public ResponseInputStreamTest() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an EOF while reading a literal throws an IOException.
|
||||
*/
|
||||
@Test
|
||||
public void testEofWhileReadingLiteral() throws Exception {
|
||||
public void testEofWhileReadingLiteral() {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(
|
||||
"test{1}\r\n".getBytes(StandardCharsets.ISO_8859_1));
|
||||
ResponseInputStream ris = new ResponseInputStream(bis);
|
||||
|
|
|
@ -18,6 +18,9 @@ package org.xbib.net.mail.test.imap;
|
|||
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Store;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
import org.xbib.net.mail.test.test.TestServer;
|
||||
|
@ -44,6 +47,8 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
@Timeout(20)
|
||||
public final class IMAPAuthDebugTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(IMAPAuthDebugTest.class.getName());
|
||||
|
||||
/**
|
||||
* Test that authentication information isn't included in the debug output.
|
||||
*/
|
||||
|
@ -63,6 +68,7 @@ public final class IMAPAuthDebugTest {
|
|||
/**
|
||||
* Test that authentication information *is* included in the debug output.
|
||||
*/
|
||||
@Disabled("we have no debug output outside of logging")
|
||||
@Test
|
||||
public void testAuth() {
|
||||
final Properties properties = new Properties();
|
||||
|
@ -80,28 +86,19 @@ public final class IMAPAuthDebugTest {
|
|||
final IMAPHandler handler = new IMAPHandler();
|
||||
server = new TestServer(handler);
|
||||
server.start();
|
||||
|
||||
properties.setProperty("mail.imap.host", "localhost");
|
||||
properties.setProperty("mail.imap.port", String.valueOf(server.getPort()));
|
||||
final Session session = Session.getInstance(properties);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
||||
final Store store = session.getStore("imap");
|
||||
try {
|
||||
try (Store store = session.getStore("imap")) {
|
||||
store.connect("test", "test");
|
||||
} catch (Exception ex) {
|
||||
System.out.println(ex);
|
||||
//ex.printStackTrace();
|
||||
logger.log(Level.SEVERE, ex.getMessage(), ex);
|
||||
fail(ex.toString());
|
||||
} finally {
|
||||
store.close();
|
||||
}
|
||||
|
||||
bos.close();
|
||||
ByteArrayInputStream bis =
|
||||
new ByteArrayInputStream(bos.toByteArray());
|
||||
BufferedReader r = new BufferedReader(
|
||||
new InputStreamReader(bis, StandardCharsets.US_ASCII));
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(bis, StandardCharsets.US_ASCII));
|
||||
String line;
|
||||
boolean found = false;
|
||||
while ((line = r.readLine()) != null) {
|
||||
|
|
|
@ -17,15 +17,15 @@
|
|||
package org.xbib.net.mail.test.imap;
|
||||
|
||||
import jakarta.mail.Folder;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Store;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.net.mail.test.test.TestServer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Properties;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.net.mail.test.test.TestServer;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* Test that failures while closing a folder are handled properly.
|
||||
|
@ -34,54 +34,27 @@ public final class IMAPCloseFailureTest {
|
|||
|
||||
private static final String HOST = "localhost";
|
||||
|
||||
static class NoIMAPHandler extends IMAPHandler {
|
||||
static boolean first = true;
|
||||
|
||||
@Override
|
||||
public void examine(OutputStream outputStream, String line) throws IOException {
|
||||
if (first)
|
||||
no(outputStream, "mailbox gone");
|
||||
else
|
||||
super.examine(outputStream, line);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
static class BadIMAPHandler extends IMAPHandler {
|
||||
static boolean first = true;
|
||||
|
||||
@Override
|
||||
public void examine(OutputStream outputStream, String line) throws IOException {
|
||||
if (first)
|
||||
bad(outputStream, "mailbox gone");
|
||||
else
|
||||
super.examine(outputStream, line);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloseNo() {
|
||||
public void testCloseNo() throws Exception {
|
||||
testClose(new NoIMAPHandler());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloseBad() {
|
||||
testClose(new BadIMAPHandler());
|
||||
assertThrows(MessagingException.class, () -> {
|
||||
testClose(new BadIMAPHandler());
|
||||
});
|
||||
}
|
||||
|
||||
public void testClose(IMAPHandler handler) {
|
||||
public void testClose(IMAPHandler handler) throws Exception {
|
||||
TestServer server = null;
|
||||
try {
|
||||
server = new TestServer(handler);
|
||||
server.start();
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("mail.imap.host", HOST);
|
||||
properties.setProperty("mail.imap.port", String.valueOf(server.getPort()));
|
||||
Session session = Session.getInstance(properties);
|
||||
//session.setDebug(true);
|
||||
|
||||
Store store = session.getStore("imap");
|
||||
try {
|
||||
store.connect("test", "test");
|
||||
|
@ -92,22 +65,42 @@ public final class IMAPCloseFailureTest {
|
|||
// with a connection that can't be used to open a folder.
|
||||
f.open(Folder.READ_WRITE);
|
||||
f.close(false);
|
||||
} catch (Exception ex) {
|
||||
System.out.println(ex);
|
||||
//ex.printStackTrace();
|
||||
fail(ex.toString());
|
||||
} finally {
|
||||
if (store.isConnected())
|
||||
store.close();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage());
|
||||
} finally {
|
||||
if (server != null) {
|
||||
server.quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class NoIMAPHandler extends IMAPHandler {
|
||||
static boolean first = true;
|
||||
|
||||
@Override
|
||||
public void examine(OutputStream outputStream, String line) throws IOException {
|
||||
if (first) {
|
||||
no(outputStream, "mailbox gone");
|
||||
} else {
|
||||
super.examine(outputStream, line);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
static class BadIMAPHandler extends IMAPHandler {
|
||||
static boolean first = true;
|
||||
|
||||
@Override
|
||||
public void examine(OutputStream outputStream, String line) throws IOException {
|
||||
if (first) {
|
||||
bad(outputStream, "mailbox gone");
|
||||
} else {
|
||||
super.examine(outputStream, line);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,11 +28,14 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.util.Properties;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/**
|
||||
* Test the IMAPProtocol class.
|
||||
*/
|
||||
public class IMAPProtocolTest {
|
||||
|
||||
public IMAPProtocolTest() {
|
||||
}
|
||||
|
||||
private static final boolean debug = false;
|
||||
private static final String content = "aXQncyBteSB0ZXN0IG1haWwNCg0K\r\n";
|
||||
private static final String response =
|
||||
|
@ -68,16 +71,14 @@ public class IMAPProtocolTest {
|
|||
props,
|
||||
debug);
|
||||
BODY b = p.fetchBody(1, "1.1");
|
||||
assertEquals("section number", "1.1", b.getSection());
|
||||
//System.out.println(b);
|
||||
//System.out.write(b.getByteArray().getNewBytes());
|
||||
assertEquals("1.1", b.getSection());
|
||||
String result = new String(b.getByteArray().getNewBytes(), StandardCharsets.US_ASCII);
|
||||
assertEquals("getByteArray.getNewBytes", content, result);
|
||||
assertEquals(content, result);
|
||||
InputStream is = b.getByteArrayInputStream();
|
||||
byte[] ba = new byte[is.available()];
|
||||
is.read(ba);
|
||||
result = new String(ba, StandardCharsets.US_ASCII);
|
||||
assertEquals("getByteArrayInputStream", content, result);
|
||||
assertEquals(content, result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,15 +94,13 @@ public class IMAPProtocolTest {
|
|||
props,
|
||||
debug);
|
||||
BODY b = p.fetchBody(1, "1.1", 0, content.length(), null);
|
||||
assertEquals("section number", "1.1", b.getSection());
|
||||
//System.out.println(b);
|
||||
//System.out.write(b.getByteArray().getNewBytes());
|
||||
assertEquals("1.1", b.getSection());
|
||||
String result = new String(b.getByteArray().getNewBytes(), StandardCharsets.US_ASCII);
|
||||
assertEquals("getByteArray.getNewBytes", content, result);
|
||||
assertEquals(content, result);
|
||||
InputStream is = b.getByteArrayInputStream();
|
||||
byte[] ba = new byte[is.available()];
|
||||
is.read(ba);
|
||||
result = new String(ba, StandardCharsets.US_ASCII);
|
||||
assertEquals("getByteArrayInputStream", content, result);
|
||||
assertEquals(content, result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.xbib.net.mail.imap.protocol.BASE64MailboxEncoder;
|
|||
import org.xbib.net.mail.imap.protocol.IMAPResponse;
|
||||
import org.xbib.net.mail.imap.protocol.Status;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* Test the Status class.
|
||||
|
@ -75,20 +76,24 @@ public class StatusTest {
|
|||
/**
|
||||
* Test that a bad response throws a ParsingException
|
||||
*/
|
||||
@Test //(expected = ParsingException.class)
|
||||
public void testBadResponseNoAttrList() throws Exception {
|
||||
String mbox = "test";
|
||||
IMAPResponse response = new IMAPResponse("* STATUS test ");
|
||||
Status s = new Status(response);
|
||||
@Test
|
||||
public void testBadResponseNoAttrList() {
|
||||
assertThrows(ParsingException.class, () -> {
|
||||
String mbox = "test";
|
||||
IMAPResponse response = new IMAPResponse("* STATUS test ");
|
||||
Status s = new Status(response);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a bad response throws a ParsingException
|
||||
*/
|
||||
@Test // (expected = ParsingException.class)
|
||||
public void testBadResponseNoAttrs() throws Exception {
|
||||
String mbox = "test";
|
||||
IMAPResponse response = new IMAPResponse("* STATUS test (");
|
||||
Status s = new Status(response);
|
||||
@Test
|
||||
public void testBadResponseNoAttrs() {
|
||||
assertThrows(ParsingException.class, () -> {
|
||||
String mbox = "test";
|
||||
IMAPResponse response = new IMAPResponse("* STATUS test (");
|
||||
Status s = new Status(response);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
package org.xbib.net.mail.test.imap.protocol;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.io.InputStream;
|
||||
import java.util.Objects;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.xbib.net.mail.imap.protocol.UIDSet;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
@ -33,17 +36,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
*
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
|
||||
//@RunWith(Parameterized.class)
|
||||
public class UIDSetTest {
|
||||
private TestData data;
|
||||
|
||||
private static boolean gen_test_input = false; // output good
|
||||
private static int errors = 0; // number of errors detected
|
||||
private static int errors = 0; // number of errors detected
|
||||
|
||||
private static boolean junit;
|
||||
|
||||
static class TestData {
|
||||
public static class TestData {
|
||||
public String name;
|
||||
public String uids;
|
||||
public long max;
|
||||
|
@ -51,25 +50,24 @@ public class UIDSetTest {
|
|||
public long[] expect;
|
||||
}
|
||||
|
||||
public UIDSetTest(TestData t) {
|
||||
data = t;
|
||||
public UIDSetTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testData() {
|
||||
test(data);
|
||||
@ParameterizedTest
|
||||
@MethodSource("data")
|
||||
public void testData(TestData t) {
|
||||
test(t);
|
||||
}
|
||||
|
||||
//@Parameters
|
||||
public static Collection<TestData[]> data() throws Exception {
|
||||
junit = true;
|
||||
// XXX - gratuitous array requirement
|
||||
List<TestData[]> testData = new ArrayList<>();
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(
|
||||
UIDSetTest.class.getResourceAsStream("uiddata")));
|
||||
InputStream inputStream = Objects.requireNonNull(UIDSetTest.class.getResourceAsStream("uiddata"));
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
|
||||
TestData t;
|
||||
while ((t = parse(in)) != null)
|
||||
while ((t = parse(in)) != null) {
|
||||
testData.add(new TestData[]{t});
|
||||
}
|
||||
return testData;
|
||||
}
|
||||
|
||||
|
@ -80,7 +78,7 @@ public class UIDSetTest {
|
|||
if (argv[optind].equals("-")) {
|
||||
// ignore
|
||||
} else if (argv[optind].equals("-g")) {
|
||||
gen_test_input = true;
|
||||
//gen_test_input = true;
|
||||
} else if (argv[optind].equals("--")) {
|
||||
optind++;
|
||||
break;
|
||||
|
@ -92,80 +90,80 @@ public class UIDSetTest {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// read from stdin
|
||||
BufferedReader in =
|
||||
new BufferedReader(new InputStreamReader(System.in));
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||||
TestData t;
|
||||
while ((t = parse(in)) != null)
|
||||
while ((t = parse(in)) != null) {
|
||||
test(t);
|
||||
System.exit(errors);
|
||||
}
|
||||
//System.exit(errors);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the input, returning a test case.
|
||||
*/
|
||||
public static TestData parse(BufferedReader in) throws Exception {
|
||||
|
||||
String line = null;
|
||||
String line;
|
||||
for (; ; ) {
|
||||
line = in.readLine();
|
||||
if (line == null)
|
||||
if (line == null) {
|
||||
return null;
|
||||
if (line.length() == 0 || line.startsWith("#"))
|
||||
}
|
||||
if (line.isEmpty() || line.startsWith("#")) {
|
||||
continue;
|
||||
|
||||
if (!line.startsWith("TEST"))
|
||||
}
|
||||
if (!line.startsWith("TEST")) {
|
||||
throw new Exception("Bad test data format");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
TestData t = new TestData();
|
||||
int i = line.indexOf(' '); // XXX - crude
|
||||
t.name = line.substring(i + 1);
|
||||
|
||||
line = in.readLine();
|
||||
StringTokenizer st = new StringTokenizer(line);
|
||||
String tok = st.nextToken();
|
||||
if (!tok.equals("DATA"))
|
||||
if (!tok.equals("DATA")) {
|
||||
throw new Exception("Bad test data format: " + line);
|
||||
}
|
||||
tok = st.nextToken();
|
||||
if (tok.equals("NULL"))
|
||||
if (tok.equals("NULL")) {
|
||||
t.uids = null;
|
||||
else if (tok.equals("EMPTY"))
|
||||
} else if (tok.equals("EMPTY")) {
|
||||
t.uids = "";
|
||||
else
|
||||
} else {
|
||||
t.uids = tok;
|
||||
|
||||
}
|
||||
line = in.readLine();
|
||||
st = new StringTokenizer(line);
|
||||
tok = st.nextToken();
|
||||
if (tok.equals("MAX")) {
|
||||
tok = st.nextToken();
|
||||
try {
|
||||
t.max = Long.valueOf(tok);
|
||||
t.max = Long.parseLong(tok);
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new Exception("Bad MAX value in line: " + line);
|
||||
}
|
||||
if (st.hasMoreTokens())
|
||||
if (st.hasMoreTokens()) {
|
||||
t.maxuids = st.nextToken();
|
||||
else
|
||||
} else {
|
||||
t.maxuids = t.uids;
|
||||
}
|
||||
line = in.readLine();
|
||||
st = new StringTokenizer(line);
|
||||
tok = st.nextToken();
|
||||
}
|
||||
List<Long> uids = new ArrayList<>();
|
||||
if (!tok.equals("EXPECT"))
|
||||
if (!tok.equals("EXPECT")) {
|
||||
throw new Exception("Bad test data format: " + line);
|
||||
}
|
||||
while (st.hasMoreTokens()) {
|
||||
tok = st.nextToken();
|
||||
if (tok.equals("NULL"))
|
||||
if (tok.equals("NULL")) {
|
||||
t.expect = null;
|
||||
else if (tok.equals("EMPTY"))
|
||||
} else if (tok.equals("EMPTY")) {
|
||||
t.expect = new long[0];
|
||||
else {
|
||||
} else {
|
||||
try {
|
||||
uids.add(Long.valueOf(tok));
|
||||
} catch (NumberFormatException ex) {
|
||||
|
@ -173,13 +171,13 @@ public class UIDSetTest {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (uids.size() > 0) {
|
||||
if (!uids.isEmpty()) {
|
||||
t.expect = new long[uids.size()];
|
||||
i = 0;
|
||||
for (Long l : uids)
|
||||
t.expect[i++] = l.longValue();
|
||||
for (Long l : uids) {
|
||||
t.expect[i++] = l;
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -187,46 +185,47 @@ public class UIDSetTest {
|
|||
* Test the data in the test case.
|
||||
*/
|
||||
public static void test(TestData t) {
|
||||
// XXX - handle nulls
|
||||
|
||||
// first, test string to array
|
||||
UIDSet[] uidset = UIDSet.parseUIDSets(t.uids);
|
||||
long[] uids;
|
||||
if (t.max > 0)
|
||||
if (t.max > 0) {
|
||||
uids = UIDSet.toArray(uidset, t.max);
|
||||
else
|
||||
} else {
|
||||
uids = UIDSet.toArray(uidset);
|
||||
if (junit)
|
||||
}
|
||||
if (junit) {
|
||||
assertArrayEquals(t.expect, uids);
|
||||
else if (!arrayEquals(t.expect, uids)) {
|
||||
System.out.println("Test: " + t.name);
|
||||
System.out.println("FAIL");
|
||||
} else if (!arrayEquals(t.expect, uids)) {
|
||||
//System.out.println("Test: " + t.name);
|
||||
//System.out.println("FAIL");
|
||||
errors++;
|
||||
}
|
||||
|
||||
// now, test the reverse
|
||||
UIDSet[] uidset2 = UIDSet.createUIDSets(uids);
|
||||
String suid = UIDSet.toString(uidset2);
|
||||
String euid = t.max > 0 ? t.maxuids : t.uids;
|
||||
if (junit)
|
||||
if (junit) {
|
||||
assertEquals(euid, suid);
|
||||
else if (!euid.equals(suid)) {
|
||||
System.out.println("Test: " + t.name);
|
||||
System.out.println("FAIL2");
|
||||
} else if (!euid.equals(suid)) {
|
||||
//System.out.println("Test: " + t.name);
|
||||
//System.out.println("FAIL2");
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean arrayEquals(long[] a, long[] b) {
|
||||
if (a == b)
|
||||
if (a == b) {
|
||||
return true;
|
||||
if (a == null || b == null)
|
||||
}
|
||||
if (a == null || b == null) {
|
||||
return false;
|
||||
if (a.length != b.length)
|
||||
}
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != b[i])
|
||||
}
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (a[i] != b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.xbib.net.mail.test.pop3;
|
|||
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Store;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
import org.xbib.net.mail.test.test.TestServer;
|
||||
|
@ -26,7 +27,6 @@ import java.io.BufferedReader;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
@ -63,6 +63,7 @@ public final class POP3AuthDebugTest {
|
|||
/**
|
||||
* Test that authentication information *is* included in the debug output.
|
||||
*/
|
||||
@Disabled
|
||||
@Test
|
||||
public void testAuth() {
|
||||
final Properties properties = new Properties();
|
||||
|
@ -81,21 +82,15 @@ public final class POP3AuthDebugTest {
|
|||
server = new TestServer(handler);
|
||||
server.start();
|
||||
Thread.sleep(1000);
|
||||
|
||||
properties.setProperty("mail.pop3.host", "localhost");
|
||||
properties.setProperty("mail.pop3.port", String.valueOf(server.getPort()));
|
||||
final Session session = Session.getInstance(properties);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
||||
final Store store = session.getStore("pop3");
|
||||
try {
|
||||
try (Store store = session.getStore("pop3")) {
|
||||
store.connect("test", "test");
|
||||
} catch (Exception ex) {
|
||||
fail(ex.toString());
|
||||
} finally {
|
||||
store.close();
|
||||
}
|
||||
|
||||
bos.close();
|
||||
ByteArrayInputStream bis =
|
||||
new ByteArrayInputStream(bos.toByteArray());
|
||||
|
@ -114,7 +109,6 @@ public final class POP3AuthDebugTest {
|
|||
r.close();
|
||||
return found;
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage());
|
||||
return false; // XXX - doesn't matter
|
||||
} finally {
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.xbib.net.mail.test.smtp;
|
|||
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Transport;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
import org.xbib.net.mail.test.test.TestServer;
|
||||
|
@ -26,7 +27,6 @@ import java.io.BufferedReader;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
@ -63,6 +63,7 @@ public final class SMTPAuthDebugTest {
|
|||
/**
|
||||
* Test that authentication information *is* included in the debug output.
|
||||
*/
|
||||
@Disabled
|
||||
@Test
|
||||
public void testAuth() {
|
||||
final Properties properties = new Properties();
|
||||
|
@ -81,25 +82,18 @@ public final class SMTPAuthDebugTest {
|
|||
server = new TestServer(handler);
|
||||
server.start();
|
||||
Thread.sleep(1000);
|
||||
|
||||
properties.setProperty("mail.smtp.host", "localhost");
|
||||
properties.setProperty("mail.smtp.port", String.valueOf(server.getPort()));
|
||||
final Session session = Session.getInstance(properties);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
||||
final Transport t = session.getTransport("smtp");
|
||||
try {
|
||||
try (Transport t = session.getTransport("smtp")) {
|
||||
t.connect("test", "test");
|
||||
} catch (Exception ex) {
|
||||
fail(ex.toString());
|
||||
} finally {
|
||||
t.close();
|
||||
}
|
||||
bos.close();
|
||||
ByteArrayInputStream bis =
|
||||
new ByteArrayInputStream(bos.toByteArray());
|
||||
BufferedReader r = new BufferedReader(
|
||||
new InputStreamReader(bis, StandardCharsets.US_ASCII));
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(bis, StandardCharsets.US_ASCII));
|
||||
String line;
|
||||
boolean found = false;
|
||||
while ((line = r.readLine()) != null) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.nio.charset.Charset;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
/**
|
||||
* Test handling of line terminators.
|
||||
|
@ -63,40 +64,44 @@ public class LineInputStreamTest {
|
|||
@Test
|
||||
public void testLines() throws IOException {
|
||||
for (String s : lines) {
|
||||
LineInputStream is = createStream(s);
|
||||
assertEquals("line1", is.readLine());
|
||||
assertEquals("line2", is.readLine());
|
||||
assertEquals("line3", is.readLine());
|
||||
assertEquals(null, is.readLine());
|
||||
try (LineInputStream is = createStream(s)) {
|
||||
assertEquals("line1", is.readLine());
|
||||
assertEquals("line2", is.readLine());
|
||||
assertEquals("line3", is.readLine());
|
||||
assertNull(is.readLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() throws IOException {
|
||||
for (String s : empty) {
|
||||
LineInputStream is = createStream(s);
|
||||
assertEquals("", is.readLine());
|
||||
assertEquals("", is.readLine());
|
||||
assertEquals("", is.readLine());
|
||||
assertEquals(null, is.readLine());
|
||||
try (LineInputStream is = createStream(s)) {
|
||||
assertEquals("", is.readLine());
|
||||
assertEquals("", is.readLine());
|
||||
assertEquals("", is.readLine());
|
||||
assertNull(is.readLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMixed() throws IOException {
|
||||
for (String s : mixed) {
|
||||
LineInputStream is = createStream(s);
|
||||
assertEquals("line1", is.readLine());
|
||||
assertEquals("", is.readLine());
|
||||
assertEquals("line3", is.readLine());
|
||||
assertEquals(null, is.readLine());
|
||||
try (LineInputStream is = createStream(s)) {
|
||||
assertEquals("line1", is.readLine());
|
||||
assertEquals("", is.readLine());
|
||||
assertEquals("line3", is.readLine());
|
||||
assertNull(is.readLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUtf8Fail() throws IOException {
|
||||
LineInputStream is = createStream("a\u00A9b\n", StandardCharsets.UTF_8);
|
||||
assertNotEquals("a\u00A9b", is.readLine());
|
||||
try (LineInputStream is = createStream("a\u00A9b\n", StandardCharsets.UTF_8)) {
|
||||
assertNotEquals("a\u00A9b", is.readLine());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -108,9 +113,9 @@ public class LineInputStreamTest {
|
|||
|
||||
@Test
|
||||
public void testIso() throws IOException {
|
||||
LineInputStream is =
|
||||
createStream("a\251b\n", StandardCharsets.ISO_8859_1);
|
||||
assertEquals("a\251b", is.readLine());
|
||||
try (LineInputStream is = createStream("a\251b\n", StandardCharsets.ISO_8859_1)) {
|
||||
assertEquals("a\251b", is.readLine());
|
||||
}
|
||||
}
|
||||
|
||||
private LineInputStream createStream(String s) {
|
||||
|
@ -118,7 +123,6 @@ public class LineInputStreamTest {
|
|||
}
|
||||
|
||||
private LineInputStream createStream(String s, Charset cs) {
|
||||
return new LineInputStream(
|
||||
new ByteArrayInputStream(s.getBytes(cs)));
|
||||
return new LineInputStream(new ByteArrayInputStream(s.getBytes(cs)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.xbib.net.mail.test.stream;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.net.mail.util.LineInputStream;
|
||||
|
||||
|
@ -31,14 +30,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
*/
|
||||
public class LineInputStreamUtf8FailTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.out.println("LineInputStreamUtf8Fail");
|
||||
System.clearProperty("mail.mime.allowutf8");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUtf8() throws Exception {
|
||||
System.clearProperty("mail.mime.allowutf8");
|
||||
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
||||
"a\u00A9b\n".getBytes(StandardCharsets.UTF_8)), false);
|
||||
assertEquals("a\302\251b", is.readLine());
|
||||
|
@ -46,6 +40,7 @@ public class LineInputStreamUtf8FailTest {
|
|||
|
||||
@Test
|
||||
public void testIso() throws IOException {
|
||||
System.clearProperty("mail.mime.allowutf8");
|
||||
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
||||
"a\251b\n".getBytes(StandardCharsets.ISO_8859_1)), false);
|
||||
assertEquals("a\251b", is.readLine());
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.xbib.net.mail.test.stream;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.net.mail.util.LineInputStream;
|
||||
|
||||
|
@ -32,28 +30,22 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
*/
|
||||
public class LineInputStreamUtf8Test {
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.out.println("LineInputStreamUtf8");
|
||||
System.setProperty("mail.mime.allowutf8", "true");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUtf8() throws Exception {
|
||||
System.setProperty("mail.mime.allowutf8", "true");
|
||||
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
||||
"a\u00A9b\n".getBytes(StandardCharsets.UTF_8)), false);
|
||||
assertEquals("a\u00A9b", is.readLine());
|
||||
System.clearProperty("mail.mime.allowutf8");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIso() throws IOException {
|
||||
System.setProperty("mail.mime.allowutf8", "true");
|
||||
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
||||
"a\251b\n".getBytes(StandardCharsets.ISO_8859_1)), false);
|
||||
assertEquals("a\251b", is.readLine());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
System.clearProperty("mail.mime.allowutf8");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ import java.util.logging.Logger;
|
|||
* Inspired by, and derived from, POP3Server by sbo.
|
||||
*
|
||||
* For SSL/TLS support, depends on a keystore with a single X509 certificate in
|
||||
* mail/src/test/resources/com/sun/mail/test/keystore.jks.
|
||||
* keystore.jks.
|
||||
*
|
||||
* @author sbo
|
||||
* @author Bill Shannon
|
||||
|
@ -121,23 +121,19 @@ public final class TestServer {
|
|||
private static SSLContext createSSLContext()
|
||||
throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
|
||||
KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||
keyStore.load(TestServer.class.getResourceAsStream("keystore.jks"),
|
||||
"changeit".toCharArray());
|
||||
|
||||
keyStore.load(TestServer.class.getResourceAsStream("keystore.jks"), "changeit".toCharArray());
|
||||
// Create key manager
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
kmf.init(keyStore, "changeit".toCharArray());
|
||||
KeyManager[] km = kmf.getKeyManagers();
|
||||
|
||||
// Create trust manager
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
||||
tmf.init(keyStore);
|
||||
TrustManager[] tm = tmf.getTrustManagers();
|
||||
|
||||
// Initialize SSLContext
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(km, tm, null);
|
||||
|
||||
logger.log(Level.INFO, "SSL context = " + sslContext);
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
|
@ -152,21 +148,6 @@ public final class TestServer {
|
|||
executorService.execute(this::run);
|
||||
}
|
||||
|
||||
/*public void start() {
|
||||
// don't return until server is really listening
|
||||
// XXX - this might not be necessary
|
||||
for (int tries = 0; tries < 10; tries++) {
|
||||
if (isListening(getPort())) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Server isn't listening");
|
||||
}*/
|
||||
|
||||
private void run() {
|
||||
try {
|
||||
keepOn = true;
|
||||
|
@ -210,49 +191,9 @@ public final class TestServer {
|
|||
} else {
|
||||
logger.log(Level.INFO, "server socket already closed");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
} catch (InterruptedException e) {
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/*public int clientCount() {
|
||||
synchronized (clients) {
|
||||
// isListening creates a client that we don't count
|
||||
return clients.size() - 1;
|
||||
}
|
||||
}*/
|
||||
|
||||
/*public void waitForClients(int n) {
|
||||
if (n > clientCount())
|
||||
throw new RuntimeException("not that many clients");
|
||||
for (; ; ) {
|
||||
int num = -1; // ignore isListening client
|
||||
synchronized (clients) {
|
||||
for (Thread t : clients) {
|
||||
if (!t.isAlive()) {
|
||||
if (++num >= n)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/*private boolean isListening(int port) {
|
||||
try {
|
||||
Socket s = new Socket();
|
||||
s.connect(new InetSocketAddress("localhost", port), 100);
|
||||
// it's listening!
|
||||
s.close();
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
//System.out.println(ex);
|
||||
}
|
||||
return false;
|
||||
}*/
|
||||
|
||||
}
|
||||
|
|
|
@ -61,7 +61,6 @@ public class AddFromTest {
|
|||
m.setFrom(iaddr);
|
||||
m.addFrom(addresses);
|
||||
assertEquals(1, m.getHeader("From").length);
|
||||
assertEquals("From header", ADDR + ", " + ADDR,
|
||||
m.getHeader("From", ","));
|
||||
assertEquals(ADDR + ", " + ADDR, m.getHeader("From", ","));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ import jakarta.mail.MessagingException;
|
|||
import jakarta.mail.Session;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.mail.internet.MimeMultipart;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.net.mail.test.test.AsciiStringInputStream;
|
||||
|
||||
|
@ -34,29 +32,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
*/
|
||||
public class AllowEncodedMessagesTest {
|
||||
|
||||
private static Session s = Session.getInstance(new Properties());
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.out.println("AllowEncodedMessages");
|
||||
System.setProperty("mail.mime.allowencodedmessages", "true");
|
||||
}
|
||||
private static final Session s = Session.getInstance(new Properties());
|
||||
|
||||
@Test
|
||||
public void testEncodedMessages() throws Exception {
|
||||
System.setProperty("mail.mime.allowencodedmessages", "true");
|
||||
MimeMessage m = createMessage();
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
BodyPart bp = mp.getBodyPart(0);
|
||||
assertEquals("message/rfc822", bp.getContentType());
|
||||
|
||||
MimeMessage m2 = (MimeMessage) bp.getContent();
|
||||
assertEquals("text/plain", m2.getContentType());
|
||||
assertEquals("test message\r\n", m2.getContent());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
// should be unnecessary
|
||||
System.clearProperty("mail.mime.allowencodedmessages");
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.Base64;
|
|||
import java.util.Random;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test base64 encoding/decoding.
|
||||
|
@ -43,27 +42,16 @@ public class BASE64Test {
|
|||
|
||||
@Test
|
||||
public void test() throws IOException {
|
||||
// test a range of buffer sizes
|
||||
for (int bufsize = 1; bufsize < 100; bufsize++) {
|
||||
//System.out.println("Buffer size: " + bufsize);
|
||||
byte[] buf = new byte[bufsize];
|
||||
|
||||
// test a set of patterns
|
||||
|
||||
// first, all zeroes
|
||||
Arrays.fill(buf, (byte) 0);
|
||||
test("Zeroes", buf);
|
||||
|
||||
// now, all ones
|
||||
Arrays.fill(buf, (byte) 0xff);
|
||||
test("Ones", buf);
|
||||
|
||||
// now, small integers
|
||||
for (int i = 0; i < bufsize; i++)
|
||||
for (int i = 0; i < bufsize; i++) {
|
||||
buf[i] = (byte) i;
|
||||
}
|
||||
test("Ints", buf);
|
||||
|
||||
// finally, random numbers
|
||||
Random rnd = new Random();
|
||||
rnd.nextBytes(buf);
|
||||
test("Random", buf);
|
||||
|
@ -78,57 +66,41 @@ public class BASE64Test {
|
|||
* decoding stream. Check all combinations.
|
||||
*/
|
||||
private static void test(String name, byte[] buf) throws IOException {
|
||||
// first encode and decode with method
|
||||
byte[] encoded = Base64.getEncoder().encode(buf);
|
||||
byte[] nbuf = Base64.getDecoder().decode(encoded);
|
||||
compare(name, "method", buf, nbuf);
|
||||
|
||||
// encode with stream, compare with method encoded version
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
BASE64EncoderStream os =
|
||||
new BASE64EncoderStream(bos, Integer.MAX_VALUE);
|
||||
BASE64EncoderStream os = new BASE64EncoderStream(bos, Integer.MAX_VALUE);
|
||||
os.write(buf);
|
||||
os.flush();
|
||||
os.close();
|
||||
byte[] sbuf = bos.toByteArray();
|
||||
compare(name, "encoded", encoded, sbuf);
|
||||
|
||||
// encode with stream, decode with method
|
||||
nbuf = Base64.getDecoder().decode(sbuf);
|
||||
compare(name, "stream->method", buf, nbuf);
|
||||
|
||||
// encode with stream, decode with stream
|
||||
ByteArrayInputStream bin = new ByteArrayInputStream(sbuf);
|
||||
BASE64DecoderStream in = new BASE64DecoderStream(bin);
|
||||
readAll(in, nbuf, nbuf.length);
|
||||
compare(name, "stream", buf, nbuf);
|
||||
|
||||
// encode with method, decode with stream
|
||||
for (int i = 1; i <= nbuf.length; i++) {
|
||||
bin = new ByteArrayInputStream(encoded);
|
||||
in = new BASE64DecoderStream(bin);
|
||||
readAll(in, nbuf, i);
|
||||
compare(name, "method->stream " + i, buf, nbuf);
|
||||
}
|
||||
|
||||
// encode with stream, decode with stream, many buffers
|
||||
|
||||
// first, fill the output with multiple buffers, up to the limit
|
||||
int limit = 10000; // more than 8K
|
||||
bos = new ByteArrayOutputStream();
|
||||
os = new BASE64EncoderStream(bos);
|
||||
for (int size = 0, blen = buf.length; size < limit; size += blen) {
|
||||
if (size + blen > limit) {
|
||||
blen = limit - size;
|
||||
// write out partial buffer, starting at non-zero offset
|
||||
os.write(buf, buf.length - blen, blen);
|
||||
} else
|
||||
} else {
|
||||
os.write(buf);
|
||||
}
|
||||
}
|
||||
os.flush();
|
||||
os.close();
|
||||
|
||||
// read the encoded output and check the line length
|
||||
String type = "big stream"; // for error messages below
|
||||
sbuf = bos.toByteArray();
|
||||
bin = new ByteArrayInputStream(sbuf);
|
||||
|
@ -141,24 +113,22 @@ public class BASE64Test {
|
|||
} else {
|
||||
int n = bin.read(inbuf, 0, blen + 2);
|
||||
assertEquals(blen + 2, n);
|
||||
assertTrue(nbuf[blen] == (byte) '\r' && inbuf[blen + 1] == (byte) '\n');
|
||||
assertEquals((byte) '\r', inbuf[blen]);
|
||||
assertEquals((byte) '\n', inbuf[blen + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
// decode the output and check the data
|
||||
bin = new ByteArrayInputStream(sbuf);
|
||||
in = new BASE64DecoderStream(bin);
|
||||
inbuf = new byte[buf.length];
|
||||
for (int size = 0, blen = buf.length; size < limit; size += blen) {
|
||||
if (size + blen > limit)
|
||||
if (size + blen > limit) {
|
||||
blen = limit - size;
|
||||
}
|
||||
int n = in.read(nbuf, 0, blen);
|
||||
assertEquals(blen, n);
|
||||
if (blen != buf.length) {
|
||||
// have to compare with end of original buffer
|
||||
byte[] cbuf = new byte[blen];
|
||||
System.arraycopy(buf, buf.length - blen, cbuf, 0, blen);
|
||||
// need a version of the read buffer that's the right size
|
||||
byte[] cnbuf = new byte[blen];
|
||||
System.arraycopy(nbuf, 0, cnbuf, 0, blen);
|
||||
compare(name, type, cbuf, cnbuf);
|
||||
|
@ -168,8 +138,9 @@ public class BASE64Test {
|
|||
}
|
||||
}
|
||||
|
||||
private static byte[] origLine;
|
||||
private static byte[] encodedLine;
|
||||
private static final byte[] origLine;
|
||||
|
||||
private static final byte[] encodedLine;
|
||||
|
||||
static {
|
||||
origLine =
|
||||
|
@ -190,29 +161,24 @@ public class BASE64Test {
|
|||
public void testLineLength() throws Exception {
|
||||
for (int i = 0; i < origLine.length; i++) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
||||
OutputStream os = new BASE64EncoderStream(bos);
|
||||
os.write(origLine, 0, i);
|
||||
os.write(origLine, i, origLine.length - i);
|
||||
os.write((byte) '0');
|
||||
os.flush();
|
||||
os.close();
|
||||
|
||||
byte[] line = new byte[encodedLine.length];
|
||||
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
||||
assertArrayEquals(encodedLine, line);
|
||||
}
|
||||
|
||||
for (int i = 0; i < origLine.length; i++) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
||||
OutputStream os = new BASE64EncoderStream(bos);
|
||||
os.write(origLine, 0, i);
|
||||
os.write(origLine, i, origLine.length - i);
|
||||
os.write(origLine);
|
||||
os.flush();
|
||||
os.close();
|
||||
|
||||
byte[] line = new byte[encodedLine.length];
|
||||
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
||||
assertArrayEquals(encodedLine, line);
|
||||
|
@ -220,30 +186,28 @@ public class BASE64Test {
|
|||
|
||||
for (int i = 1; i < 5; i++) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
||||
OutputStream os = new BASE64EncoderStream(bos);
|
||||
for (int j = 0; j < i; j++)
|
||||
for (int j = 0; j < i; j++) {
|
||||
os.write((byte) '0');
|
||||
}
|
||||
os.write(origLine, i, origLine.length - i);
|
||||
os.write((byte) '0');
|
||||
os.flush();
|
||||
os.close();
|
||||
|
||||
byte[] line = new byte[encodedLine.length];
|
||||
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
||||
assertArrayEquals(encodedLine, line);
|
||||
}
|
||||
for (int i = origLine.length - 5; i < origLine.length; i++) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
||||
OutputStream os = new BASE64EncoderStream(bos);
|
||||
os.write(origLine, 0, i);
|
||||
for (int j = 0; j < origLine.length - i; j++)
|
||||
for (int j = 0; j < origLine.length - i; j++) {
|
||||
os.write((byte) '0');
|
||||
}
|
||||
os.write((byte) '0');
|
||||
os.flush();
|
||||
os.close();
|
||||
|
||||
byte[] line = new byte[encodedLine.length];
|
||||
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
||||
assertArrayEquals(encodedLine, line);
|
||||
|
@ -256,19 +220,9 @@ public class BASE64Test {
|
|||
for (int i = 0; i < 1000; i++)
|
||||
decoded[i] = (byte) 'A';
|
||||
byte[] encoded = Base64.getEncoder().encode(decoded);
|
||||
// Exceed InputStream.DEFAULT_BUFFER_SIZE
|
||||
assertTrue(decoded.length > 8192);
|
||||
BASE64DecoderStream sut =
|
||||
new BASE64DecoderStream(new ByteArrayInputStream(encoded));
|
||||
// XXX - should test this using something equivalent to JDK 9's
|
||||
// InputStream.readAllBytes, but for now...
|
||||
BASE64DecoderStream sut = new BASE64DecoderStream(new ByteArrayInputStream(encoded));
|
||||
int n = sut.read(decoded, 0, 0);
|
||||
assertEquals(n, 0);
|
||||
|
||||
// Exercise
|
||||
//byte[] result = sut.readAllBytes();
|
||||
// Verify
|
||||
//assertArrayEquals(decoded, result);
|
||||
assertEquals(0, n);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,8 +240,6 @@ public class BASE64Test {
|
|||
off += got;
|
||||
need -= got;
|
||||
}
|
||||
if (need != 0)
|
||||
System.out.println("couldn't read all bytes");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -295,27 +247,9 @@ public class BASE64Test {
|
|||
*/
|
||||
private static void compare(String name, String type,
|
||||
byte[] buf, byte[] nbuf) {
|
||||
/*
|
||||
if (nbuf.length != buf.length) {
|
||||
System.out.println(name + ": " + type +
|
||||
" decoded array size wrong: " +
|
||||
"got " + nbuf.length + ", expected " + buf.length);
|
||||
dump(name + " buf", buf);
|
||||
dump(name + " nbuf", nbuf);
|
||||
}
|
||||
*/
|
||||
assertEquals(buf.length, nbuf.length);
|
||||
for (int i = 0; i < buf.length; i++) {
|
||||
assertEquals(buf[i], nbuf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the contents of the buffer.
|
||||
*/
|
||||
private static void dump(String name, byte[] buf) {
|
||||
System.out.println(name);
|
||||
for (int i = 0; i < buf.length; i++)
|
||||
System.out.println(buf[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import jakarta.mail.Session;
|
|||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.mail.internet.MimeMultipart;
|
||||
import jakarta.mail.internet.MimePart;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.net.mail.test.test.AsciiStringInputStream;
|
||||
|
||||
|
@ -34,17 +33,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
*/
|
||||
public class ContentTypeCleanerTest {
|
||||
|
||||
private static Session s = Session.getInstance(new Properties());
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.out.println("ContentTypeCleaner");
|
||||
System.setProperty("mail.mime.contenttypehandler",
|
||||
ContentTypeCleanerTest.class.getName());
|
||||
}
|
||||
private static final Session s = Session.getInstance(new Properties());
|
||||
|
||||
@Test
|
||||
public void testGarbage() throws Exception {
|
||||
System.setProperty("mail.mime.contenttypehandler", ContentTypeCleanerTest.class.getName());
|
||||
MimeMessage m = createMessage();
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
BodyPart bp = mp.getBodyPart(0);
|
||||
|
@ -54,6 +47,7 @@ public class ContentTypeCleanerTest {
|
|||
|
||||
@Test
|
||||
public void testValid() throws Exception {
|
||||
System.setProperty("mail.mime.contenttypehandler", ContentTypeCleanerTest.class.getName());
|
||||
MimeMessage m = createMessage();
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
BodyPart bp = mp.getBodyPart(1);
|
||||
|
@ -63,6 +57,7 @@ public class ContentTypeCleanerTest {
|
|||
|
||||
@Test
|
||||
public void testEmpty() throws Exception {
|
||||
System.setProperty("mail.mime.contenttypehandler", ContentTypeCleanerTest.class.getName());
|
||||
MimeMessage m = createMessage();
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
BodyPart bp = mp.getBodyPart(2);
|
||||
|
@ -71,10 +66,12 @@ public class ContentTypeCleanerTest {
|
|||
}
|
||||
|
||||
public static String cleanContentType(MimePart mp, String contentType) {
|
||||
if (contentType == null)
|
||||
if (contentType == null) {
|
||||
return null;
|
||||
if (contentType.equals("complete garbage"))
|
||||
}
|
||||
if (contentType.equals("complete garbage")) {
|
||||
return "text/plain";
|
||||
}
|
||||
return contentType;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,29 +16,18 @@
|
|||
|
||||
package org.xbib.net.mail.test.util;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test that the "mail.mime.decodeparameters" System property
|
||||
* causes the parameters to be properly decoded.
|
||||
*/
|
||||
public class DecodeParametersTest extends ParameterListDecode {
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.setProperty("mail.mime.decodeparameters", "true");
|
||||
}
|
||||
public class DecodeParametersTest extends ParameterListDecodeTest {
|
||||
|
||||
@Test
|
||||
public void testDecode() throws Exception {
|
||||
System.setProperty("mail.mime.decodeparameters", "true");
|
||||
testDecode("paramdata");
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
// should be unnecessary
|
||||
System.clearProperty("mail.mime.decodeparameters");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package org.xbib.net.mail.test.util;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
/**
|
||||
* Test "mail.mime.encodefilename" System property set to "true"
|
||||
* and "mail.mime.encodeparameters" set to "false".
|
||||
*/
|
||||
public class EncodeFileNameNoEncodeParametersTest extends EncodeFileNameTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.out.println("EncodeFileNameNoEncodeParameters");
|
||||
System.setProperty("mail.mime.charset", "utf-8");
|
||||
System.setProperty("mail.mime.encodefilename", "true");
|
||||
System.setProperty("mail.mime.encodeparameters", "false");
|
||||
}
|
||||
}
|
|
@ -16,46 +16,46 @@
|
|||
|
||||
package org.xbib.net.mail.test.util;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeBodyPart;
|
||||
import jakarta.mail.internet.MimeUtility;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test "mail.mime.encodefilename" System property set.
|
||||
*/
|
||||
public class EncodeFileNameTest extends NoEncodeFileNameTest {
|
||||
public class EncodeFileNameTest {
|
||||
|
||||
// depends on exactly how MimeUtility.encodeText splits long words
|
||||
private static String expected1 =
|
||||
"=?utf-8?B?w4DDgcOFw4bDgMOBw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw4DDgcOF?=";
|
||||
private static String expected2 =
|
||||
"=?utf-8?B?w4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5XDlsOYw5nDmsObw5w=?=";
|
||||
private static String expected3 =
|
||||
"=?utf-8?B?w53DnsOfw6DDocOiw6PDpMOlw6bDp8Oow6nDqsOrw6zDrcOuw6/DsMOx?=";
|
||||
private static String expected4 =
|
||||
"=?utf-8?B?w7LDs8O0w7XDtsO4w7nDusO7w7zDvcO+w7/DgMOBw4XDhsOHLmRvYw==?=";
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.out.println("EncodeFileName");
|
||||
System.setProperty("mail.mime.charset", "utf-8");
|
||||
System.setProperty("mail.mime.encodefilename", "true");
|
||||
// assume mail.mime.encodeparameters defaults to true
|
||||
System.clearProperty("mail.mime.encodeparameters");
|
||||
}
|
||||
private static final Logger logger = Logger.getLogger(EncodeFileNameTest.class.getName());
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
System.setProperty("mail.mime.charset", "utf-8");
|
||||
System.setProperty("mail.mime.encodefilename", "true");
|
||||
System.clearProperty("mail.mime.encodeparameters");
|
||||
String encodedFileName = "=?utf-8?B?w4DDgcOFw4bDgMOBw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw4DD" +
|
||||
"gcOFw4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5XDlsOYw5nDmsObw5" +
|
||||
"zDncOew5/DoMOhw6LDo8Okw6XDpsOnw6jDqcOqw6vDrMOtw67Dr8Oww7HDssOz" +
|
||||
"w7TDtcO2w7jDucO6w7vDvMO9w77Dv8OAw4HDhcOGw4cuZG9j?=";
|
||||
String fileName = MimeUtility.decodeText(encodedFileName);
|
||||
MimeBodyPartPublicUpdateHeaders mbp = new MimeBodyPartPublicUpdateHeaders();
|
||||
mbp.setText("test");
|
||||
mbp.setFileName(fileName);
|
||||
mbp.updateHeaders();
|
||||
String h = mbp.getHeader("Content-Type", "");
|
||||
logger.log(Level.INFO, "h = " + h);
|
||||
assertTrue(h.contains("name="));
|
||||
// depends on exactly how MimeUtility.encodeText splits long words
|
||||
String expected1 = "=?UTF-8?B?w4DDgcOFw4bDgMOBw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw4DDgcOF?=";
|
||||
assertTrue(h.contains(expected1));
|
||||
String expected2 = "=?UTF-8?B?w4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5XDlsOYw5nDmsObw5w=?=";
|
||||
assertTrue(h.contains(expected2));
|
||||
String expected3 = "=?UTF-8?B?w53DnsOfw6DDocOiw6PDpMOlw6bDp8Oow6nDqsOrw6zDrcOuw6/DsMOx?=";
|
||||
assertTrue(h.contains(expected3));
|
||||
String expected4 = "=?UTF-8?B?w7LDs8O0w7XDtsO4w7nDusO7w7zDvcO+w7/DgMOBw4XDhsOHLmRvYw==?=";
|
||||
assertTrue(h.contains(expected4));
|
||||
h = mbp.getHeader("Content-Disposition", "");
|
||||
assertTrue(h.contains("filename="));
|
||||
|
@ -63,5 +63,15 @@ public class EncodeFileNameTest extends NoEncodeFileNameTest {
|
|||
assertTrue(h.contains(expected2));
|
||||
assertTrue(h.contains(expected3));
|
||||
assertTrue(h.contains(expected4));
|
||||
System.clearProperty("mail.mime.charset");
|
||||
System.clearProperty("mail.mime.encodefilename");
|
||||
System.clearProperty("mail.mime.encodeparameters");
|
||||
}
|
||||
|
||||
private static class MimeBodyPartPublicUpdateHeaders extends MimeBodyPart {
|
||||
@Override
|
||||
public void updateHeaders() throws MessagingException {
|
||||
super.updateHeaders();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.Properties;
|
|||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -41,7 +42,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
*/
|
||||
public class MimeBodyPartTest {
|
||||
|
||||
private static String[] languages = new String[]{
|
||||
private static final String[] languages = new String[]{
|
||||
"language1", "language2", "language3", "language4", "language5",
|
||||
"language6", "language7", "language8", "language9", "language10",
|
||||
"language11", "language12", "language13", "language14", "language15"
|
||||
|
@ -57,7 +58,6 @@ public class MimeBodyPartTest {
|
|||
mbp.setContentLanguage(languages);
|
||||
String header = mbp.getHeader("Content-Language", ",");
|
||||
assertTrue(header.indexOf("\r\n") > 0);
|
||||
|
||||
String[] langs = mbp.getContentLanguage();
|
||||
assertArrayEquals(languages, langs);
|
||||
}
|
||||
|
@ -179,11 +179,10 @@ public class MimeBodyPartTest {
|
|||
"test" +
|
||||
"\n";
|
||||
MimeBodyPart mbp = new MimeBodyPart(new AsciiStringInputStream(part));
|
||||
assertEquals("empty C-T-E value", null, mbp.getEncoding());
|
||||
assertNull(mbp.getEncoding());
|
||||
assertEquals("test\n", mbp.getContent());
|
||||
}
|
||||
|
||||
|
||||
private static MimeMessage createMessage(Session s)
|
||||
throws MessagingException {
|
||||
String content =
|
||||
|
@ -199,7 +198,6 @@ public class MimeBodyPartTest {
|
|||
"test part\n" +
|
||||
"\n" +
|
||||
"-----\n";
|
||||
|
||||
return new MimeMessage(s, new AsciiStringInputStream(content));
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ public class MimeMessageTest {
|
|||
String addr = "joe@example.com";
|
||||
MimeMessage m = new MimeMessage(s);
|
||||
m.setRecipient(TO, new InternetAddress(addr));
|
||||
assertEquals("To: is set", addr, m.getRecipients(TO)[0].toString());
|
||||
assertEquals(addr, m.getRecipients(TO)[0].toString());
|
||||
m.setRecipient(TO, (Address) null);
|
||||
assertArrayEquals(null, m.getRecipients(TO));
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public class MimeMessageTest {
|
|||
String addr = "joe@example.com";
|
||||
MimeMessage m = new MimeMessage(s);
|
||||
m.setFrom(new InternetAddress(addr));
|
||||
assertEquals("From: is set", addr, m.getFrom()[0].toString());
|
||||
assertEquals(addr, m.getFrom()[0].toString());
|
||||
m.setFrom((Address) null);
|
||||
assertArrayEquals(null, m.getFrom());
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ public class MimeMessageTest {
|
|||
String addr = "joe@example.com";
|
||||
MimeMessage m = new MimeMessage(s);
|
||||
m.setSender(new InternetAddress(addr));
|
||||
assertEquals("Sender: is set", addr, m.getSender().toString());
|
||||
assertEquals(addr, m.getSender().toString());
|
||||
m.setSender((Address) null);
|
||||
assertNull(m.getSender());
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import java.io.InputStream;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
|
@ -37,55 +37,47 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
*/
|
||||
public class MimeMultipartBCSIndexTest {
|
||||
|
||||
private String EMLContent = "From: dslztx@gmail.com \n" +
|
||||
"To: dslztx <dslztx@gmail.com>\n" +
|
||||
"Subject: bcs index test \n" +
|
||||
"Date: Sat, 25 Aug 2018 08:35:14 +0800\n" +
|
||||
"Content-Type: multipart/alternative;\n" +
|
||||
"\tboundary=\"----=_000_6675<37><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=----\"\n" +
|
||||
"\n" +
|
||||
"This is a multi-part message in MIME format.\n" +
|
||||
"\n" +
|
||||
"------=_000_6675<37><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=----\n" +
|
||||
"Content-Type: text/plain;\n" +
|
||||
"\tcharset=\"utf-8\"\n" +
|
||||
"Content-Transfer-Encoding: base64\n" +
|
||||
"\n" +
|
||||
"aGVsbG8gd29ybGQ=\n" +
|
||||
"\n" +
|
||||
"------=_000_6675<37><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=----\n" +
|
||||
"Content-Type: text/html;\n" +
|
||||
"\tcharset=\"utf-8\"\n" +
|
||||
"Content-Transfer-Encoding: base64\n" +
|
||||
"\n" +
|
||||
"PGh0bWw+CjxoZWFkZXI+PHRpdGxlPlRoaXMgaXMgdGl0bGU8L3RpdGxlPjwvaGVhZGVyPgo8Ym9\n" +
|
||||
"keT4KSGVsbG8gd29ybGQKPC9ib2R5Pgo8L2h0bWw+\n" +
|
||||
"\n" +
|
||||
"------=_000_6675<37><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=------";
|
||||
|
||||
@Test
|
||||
public void testBCSTableIndexInconsistency() {
|
||||
|
||||
try {
|
||||
String EMLContent = "From: dslztx@gmail.com \n" +
|
||||
"To: dslztx <dslztx@gmail.com>\n" +
|
||||
"Subject: bcs index test \n" +
|
||||
"Date: Sat, 25 Aug 2018 08:35:14 +0800\n" +
|
||||
"Content-Type: multipart/alternative;\n" +
|
||||
"\tboundary=\"----=_000_6675<37><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=----\"\n" +
|
||||
"\n" +
|
||||
"This is a multi-part message in MIME format.\n" +
|
||||
"\n" +
|
||||
"------=_000_6675<37><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=----\n" +
|
||||
"Content-Type: text/plain;\n" +
|
||||
"\tcharset=\"utf-8\"\n" +
|
||||
"Content-Transfer-Encoding: base64\n" +
|
||||
"\n" +
|
||||
"aGVsbG8gd29ybGQ=\n" +
|
||||
"\n" +
|
||||
"------=_000_6675<37><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=----\n" +
|
||||
"Content-Type: text/html;\n" +
|
||||
"\tcharset=\"utf-8\"\n" +
|
||||
"Content-Transfer-Encoding: base64\n" +
|
||||
"\n" +
|
||||
"PGh0bWw+CjxoZWFkZXI+PHRpdGxlPlRoaXMgaXMgdGl0bGU8L3RpdGxlPjwvaGVhZGVyPgo8Ym9\n" +
|
||||
"keT4KSGVsbG8gd29ybGQKPC9ib2R5Pgo8L2h0bWw+\n" +
|
||||
"\n" +
|
||||
"------=_000_6675<37><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=------";
|
||||
InputStream in = new ByteArrayInputStream(EMLContent.getBytes(StandardCharsets.ISO_8859_1));
|
||||
|
||||
Session session = Session.getDefaultInstance(new Properties());
|
||||
|
||||
MimeMessage mimeMessage = new MimeMessage(session,
|
||||
in);
|
||||
|
||||
MimeMessage mimeMessage = new MimeMessage(session, in);
|
||||
MimeMultipart topMultipart = (MimeMultipart) mimeMessage.getContent();
|
||||
|
||||
assertTrue(topMultipart.getCount() == 2);
|
||||
assertTrue(topMultipart.getBodyPart(0).getContent().equals("hello world"));
|
||||
assertTrue(topMultipart.getBodyPart(1).getContent().equals("<html>\n" +
|
||||
assertEquals(2, topMultipart.getCount());
|
||||
assertEquals("hello world", topMultipart.getBodyPart(0).getContent());
|
||||
assertEquals("<html>\n" +
|
||||
"<header><title>This is title</title></header>\n" +
|
||||
"<body>\n" +
|
||||
"Hello world\n" +
|
||||
"</body>\n" +
|
||||
"</html>"));
|
||||
"</html>", topMultipart.getBodyPart(1).getContent());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,12 +40,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
*/
|
||||
|
||||
public class MimeMultipartParseTest {
|
||||
private static final Session session =
|
||||
Session.getInstance(new Properties(), null);
|
||||
|
||||
private static final Session session = Session.getInstance(new Properties(), null);
|
||||
|
||||
private static final int maxsize = 10000;
|
||||
private static final String data =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
private static final String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
@Test
|
||||
public void testParse() throws Exception {
|
||||
|
|
|
@ -37,7 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
*/
|
||||
public class MimeMultipartPreambleTest {
|
||||
@SuppressWarnings({"SingleCharacterStringConcatenation"})
|
||||
private String THREE_PART_MAIL =
|
||||
private final String THREE_PART_MAIL =
|
||||
"From: user1@example.com\n" +
|
||||
"To: user2@example.com\n" +
|
||||
"Subject: Receipts\n" +
|
||||
|
@ -99,20 +99,13 @@ public class MimeMultipartPreambleTest {
|
|||
new ByteArrayInputStream(text.getBytes(StandardCharsets.US_ASCII)));
|
||||
|
||||
MimeMultipart topMultipart = (MimeMultipart) mimeMessage.getContent();
|
||||
assertEquals("This is a multi-part message in MIME format.",
|
||||
topMultipart.getPreamble().trim());
|
||||
assertEquals("This is a multi-part message in MIME format.", topMultipart.getPreamble().trim());
|
||||
assertEquals(3, topMultipart.getCount());
|
||||
|
||||
BodyPart part1 = topMultipart.getBodyPart(0);
|
||||
assertEquals("Wrong content type for part 1",
|
||||
"text/plain;charset=\"us-ascii\"", part1.getContentType());
|
||||
|
||||
assertEquals("text/plain;charset=\"us-ascii\"", part1.getContentType(), "Wrong content type for part 1");
|
||||
BodyPart part2 = topMultipart.getBodyPart(1);
|
||||
assertEquals("Wrong content type for part 2",
|
||||
"application/pdf;name=\"Receipt 1.pdf\"", part2.getContentType());
|
||||
|
||||
assertEquals("application/pdf;name=\"Receipt 1.pdf\"", part2.getContentType(), "Wrong content type for part 2");
|
||||
BodyPart part3 = topMultipart.getBodyPart(2);
|
||||
assertEquals("Wrong content type for part 3",
|
||||
"application/pdf;name=\"Receipt 2.pdf\"", part3.getContentType());
|
||||
assertEquals("application/pdf;name=\"Receipt 2.pdf\"", part3.getContentType(), "Wrong content type for part 3");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ import org.xbib.net.mail.test.test.NullOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* Test the properties that control the MimeMultipart class.
|
||||
|
@ -38,7 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
*/
|
||||
public class MimeMultipartPropertyTest {
|
||||
|
||||
private static Session s = Session.getInstance(new Properties());
|
||||
private static final Session s = Session.getInstance(new Properties());
|
||||
|
||||
/**
|
||||
* Clear all properties before each test.
|
||||
|
@ -52,7 +53,7 @@ public class MimeMultipartPropertyTest {
|
|||
public void testBoundary() throws Exception {
|
||||
MimeMessage m = createMessage("x", "x", true);
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
assertEquals(mp.getCount(), 2);
|
||||
assertEquals(2, mp.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -61,41 +62,43 @@ public class MimeMultipartPropertyTest {
|
|||
"mail.mime.multipart.ignoreexistingboundaryparameter", "true");
|
||||
MimeMessage m = createMessage("x", "-", true);
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
assertEquals(mp.getCount(), 2);
|
||||
assertEquals(2, mp.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoundaryMissing() throws Exception {
|
||||
MimeMessage m = createMessage(null, "x", true);
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
assertEquals(mp.getCount(), 2);
|
||||
assertEquals(2, mp.getCount());
|
||||
}
|
||||
|
||||
@Test // (expected = MessagingException.class)
|
||||
public void testBoundaryMissingEx() throws Exception {
|
||||
System.setProperty(
|
||||
"mail.mime.multipart.ignoremissingboundaryparameter", "false");
|
||||
MimeMessage m = createMessage(null, "x", true);
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
mp.getCount(); // throw exception
|
||||
assertTrue(false); // never get here
|
||||
@Test
|
||||
public void testBoundaryMissingEx() {
|
||||
assertThrows(MessagingException.class, () -> {
|
||||
System.setProperty("mail.mime.multipart.ignoremissingboundaryparameter", "false");
|
||||
MimeMessage m = createMessage(null, "x", true);
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
mp.getCount(); // throw exception
|
||||
fail(); // never get here
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndBoundaryMissing() throws Exception {
|
||||
MimeMessage m = createMessage("x", "x", false);
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
assertEquals(mp.getCount(), 2);
|
||||
assertEquals(2, mp.getCount());
|
||||
}
|
||||
|
||||
@Test // (expected = MessagingException.class)
|
||||
public void testEndBoundaryMissingEx() throws Exception {
|
||||
System.setProperty(
|
||||
"mail.mime.multipart.ignoremissingendboundary", "false");
|
||||
MimeMessage m = createMessage("x", "x", false);
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
mp.getCount(); // throw exception
|
||||
assertTrue(false); // never get here
|
||||
@Test
|
||||
public void testEndBoundaryMissingEx() {
|
||||
assertThrows(MessagingException.class, () -> {
|
||||
System.setProperty("mail.mime.multipart.ignoremissingendboundary", "false");
|
||||
MimeMessage m = createMessage("x", "x", false);
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
mp.getCount(); // throw exception
|
||||
fail(); // never get here
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -103,15 +106,17 @@ public class MimeMultipartPropertyTest {
|
|||
System.setProperty("mail.mime.multipart.allowempty", "true");
|
||||
MimeMessage m = createEmptyMessage();
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
assertEquals(mp.getCount(), 0);
|
||||
assertEquals(0, mp.getCount());
|
||||
}
|
||||
|
||||
@Test //(expected = MessagingException.class)
|
||||
public void testAllowEmptyEx() throws Exception {
|
||||
MimeMessage m = createEmptyMessage();
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
mp.getCount(); // throw exception
|
||||
assertTrue(false); // never get here
|
||||
assertThrows(MessagingException.class, () -> {
|
||||
MimeMessage m = createEmptyMessage();
|
||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
mp.getCount(); // throw exception
|
||||
fail(); // never get here
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -121,16 +126,18 @@ public class MimeMultipartPropertyTest {
|
|||
MimeMultipart mp = new MimeMultipart();
|
||||
m.setContent(mp);
|
||||
m.writeTo(new NullOutputStream());
|
||||
assertEquals(mp.getCount(), 0);
|
||||
assertEquals(0, mp.getCount());
|
||||
}
|
||||
|
||||
@Test //(expected = IOException.class)
|
||||
public void testAllowEmptyOutputEx() throws Exception {
|
||||
MimeMessage m = new MimeMessage(s);
|
||||
MimeMultipart mp = new MimeMultipart();
|
||||
m.setContent(mp);
|
||||
m.writeTo(new NullOutputStream()); // throw exception
|
||||
assertTrue(false); // never get here
|
||||
assertThrows(IOException.class, () -> {
|
||||
MimeMessage m = new MimeMessage(s);
|
||||
MimeMultipart mp = new MimeMultipart();
|
||||
m.setContent(mp);
|
||||
m.writeTo(new NullOutputStream()); // throw exception
|
||||
fail(); // never get here
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -65,7 +65,7 @@ public class MimeUtilityTest {
|
|||
* Test that utf-16be data is encoded with base64 and not quoted-printable.
|
||||
*/
|
||||
@Test
|
||||
public void testNonAsciiEncoding() throws Exception {
|
||||
public void testNonAsciiEncoding() {
|
||||
DataSource ds = new ByteArrayDataSource(utf16beBytes,
|
||||
"text/plain; charset=utf-16be");
|
||||
String en = MimeUtility.getEncoding(ds);
|
||||
|
@ -79,7 +79,7 @@ public class MimeUtilityTest {
|
|||
* throw NullPointerException.
|
||||
*/
|
||||
@Test
|
||||
public void getEncodingMissingFile() throws Exception {
|
||||
public void getEncodingMissingFile() {
|
||||
File missing = new File(getClass().getName());
|
||||
assertFalse(missing.exists());
|
||||
FileDataSource fds = new FileDataSource(missing);
|
||||
|
@ -106,22 +106,16 @@ public class MimeUtilityTest {
|
|||
throw expect;
|
||||
}
|
||||
}
|
||||
|
||||
ByteArrayDataSource bads = new ByteArrayDataSource("", content);
|
||||
bads.setName(null);
|
||||
assertTrue(encodings.contains(MimeUtility.getEncoding(bads)));
|
||||
assertTrue(encodings.contains(
|
||||
MimeUtility.getEncoding(new DataHandler(bads))));
|
||||
|
||||
assertTrue(encodings.contains(MimeUtility.getEncoding(new DataHandler(bads))));
|
||||
bads.setName("");
|
||||
assertTrue(encodings.contains(MimeUtility.getEncoding(bads)));
|
||||
assertTrue(encodings.contains(
|
||||
MimeUtility.getEncoding(new DataHandler(bads))));
|
||||
|
||||
assertTrue(encodings.contains(MimeUtility.getEncoding(new DataHandler(bads))));
|
||||
bads.setName(getClass().getName());
|
||||
assertTrue(encodings.contains(MimeUtility.getEncoding(bads)));
|
||||
assertTrue(encodings.contains(
|
||||
MimeUtility.getEncoding(new DataHandler(bads))));
|
||||
assertTrue(encodings.contains(MimeUtility.getEncoding(new DataHandler(bads))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,14 +133,14 @@ public class MimeUtilityTest {
|
|||
String en = MimeUtility.encodeText(sp, "utf-8", "B");
|
||||
String dt = MimeUtility.decodeText(en);
|
||||
// encoding it and decoding it shouldn't change it
|
||||
assertEquals(dt, sp);
|
||||
assertEquals(sp, dt);
|
||||
String[] w = en.split(" ");
|
||||
// the first word should end with the second half of a pair
|
||||
String dw = MimeUtility.decodeWord(w[0]);
|
||||
assertTrue(dw.charAt(dw.length() - 1) == '\udc00');
|
||||
assertEquals('\udc00', dw.charAt(dw.length() - 1));
|
||||
// and the second word should start with the first half of a pair
|
||||
dw = MimeUtility.decodeWord(w[1]);
|
||||
assertTrue(dw.charAt(0) == '\ud801');
|
||||
assertEquals('\ud801', dw.charAt(0));
|
||||
|
||||
// test various string lengths
|
||||
int ch = 0xFE000;
|
||||
|
@ -171,15 +165,14 @@ public class MimeUtilityTest {
|
|||
String badcp936 = "=?cp936?B?xbfUqqLjIChFVVIpttK7u4EwhDYgKENOWSk=?=";
|
||||
String good = "=?gb18030?B?xbfUqqLjIChFVVIpttK7u4EwhDYgKENOWSk=?=";
|
||||
String goodDecoded = MimeUtility.decodeWord(good);
|
||||
|
||||
assertEquals("gb2312", goodDecoded, MimeUtility.decodeWord(badgb2312));
|
||||
assertEquals("gbk", goodDecoded, MimeUtility.decodeWord(badgbk));
|
||||
assertEquals("ms936", goodDecoded, MimeUtility.decodeWord(badms936));
|
||||
assertEquals("cp936", goodDecoded, MimeUtility.decodeWord(badcp936));
|
||||
assertEquals(goodDecoded, MimeUtility.decodeWord(badgb2312));
|
||||
assertEquals(goodDecoded, MimeUtility.decodeWord(badgbk));
|
||||
assertEquals(goodDecoded, MimeUtility.decodeWord(badms936));
|
||||
assertEquals(goodDecoded, MimeUtility.decodeWord(badcp936));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocaleISO885915() throws Exception {
|
||||
public void testLocaleISO885915() {
|
||||
assertEquals("ISO-8859-15", MimeUtility.javaCharset("en_US.iso885915"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ public class ModifyMessageTest {
|
|||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
m.setHeader("a", "b");
|
||||
m.saveChanges();
|
||||
|
||||
MimeMessage m2 = new MimeMessage(m);
|
||||
assertEquals("b", m2.getHeader("a", null));
|
||||
}
|
||||
|
@ -54,7 +53,6 @@ public class ModifyMessageTest {
|
|||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||
m.setHeader("Subject", "test");
|
||||
m.saveChanges();
|
||||
|
||||
MimeMessage m2 = new MimeMessage(m);
|
||||
assertEquals("test", m2.getHeader("Subject", null));
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package org.xbib.net.mail.test.util;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeBodyPart;
|
||||
import jakarta.mail.internet.MimeUtility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
@ -24,19 +26,18 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
* Test "mail.mime.encodefilename" System property not set and
|
||||
* "mail.mime.encodeparameters" set to "false".
|
||||
*/
|
||||
public class NoEncodeFileNameNoEncodeParametersTest extends NoEncodeFileNameTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.out.println("NoEncodeFileNameNoEncodeParameters");
|
||||
System.setProperty("mail.mime.charset", "utf-8");
|
||||
System.setProperty("mail.mime.encodeparameters", "false");
|
||||
// assume mail.mime.encodefilename defaults to false
|
||||
System.clearProperty("mail.mime.encodefilename");
|
||||
}
|
||||
public class NoEncodeFileNameNoEncodeParametersTest {
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
System.setProperty("mail.mime.charset", "utf-8");
|
||||
System.setProperty("mail.mime.encodeparameters", "false");
|
||||
System.clearProperty("mail.mime.encodefilename");
|
||||
String encodedFileName = "=?utf-8?B?w4DDgcOFw4bDgMOBw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw4DD" +
|
||||
"gcOFw4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5XDlsOYw5nDmsObw5" +
|
||||
"zDncOew5/DoMOhw6LDo8Okw6XDpsOnw6jDqcOqw6vDrMOtw67Dr8Oww7HDssOz" +
|
||||
"w7TDtcO2w7jDucO6w7vDvMO9w77Dv8OAw4HDhcOGw4cuZG9j?=";
|
||||
String fileName = MimeUtility.decodeText(encodedFileName);
|
||||
MimeBodyPartPublicUpdateHeaders mbp = new MimeBodyPartPublicUpdateHeaders();
|
||||
mbp.setText("test");
|
||||
mbp.setFileName(fileName);
|
||||
|
@ -47,5 +48,16 @@ public class NoEncodeFileNameNoEncodeParametersTest extends NoEncodeFileNameTest
|
|||
h = mbp.getHeader("Content-Disposition", "");
|
||||
assertTrue(h.contains("filename="));
|
||||
assertTrue(h.contains(fileName));
|
||||
System.clearProperty("mail.mime.charset");
|
||||
System.clearProperty("mail.mime.encodeparameters");
|
||||
System.clearProperty("mail.mime.encodefilename");
|
||||
}
|
||||
|
||||
private static class MimeBodyPartPublicUpdateHeaders extends MimeBodyPart {
|
||||
@Override
|
||||
public void updateHeaders() throws MessagingException {
|
||||
super.updateHeaders();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,9 +20,6 @@ import jakarta.mail.MessagingException;
|
|||
import jakarta.mail.internet.MimeBodyPart;
|
||||
import jakarta.mail.internet.MimeUtility;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
@ -31,65 +28,40 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
*/
|
||||
public class NoEncodeFileNameTest {
|
||||
|
||||
protected static String fileName;
|
||||
|
||||
// a bunch of non-ASCII characters
|
||||
private static String encodedFileName =
|
||||
"=?utf-8?B?w4DDgcOFw4bDgMOBw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw4DD" +
|
||||
"gcOFw4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5XDlsOYw5nDmsObw5" +
|
||||
"zDncOew5/DoMOhw6LDo8Okw6XDpsOnw6jDqcOqw6vDrMOtw67Dr8Oww7HDssOz" +
|
||||
"w7TDtcO2w7jDucO6w7vDvMO9w77Dv8OAw4HDhcOGw4cuZG9j?=";
|
||||
|
||||
static {
|
||||
try {
|
||||
fileName = MimeUtility.decodeText(encodedFileName);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
// should never happen
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// RFC 2231 encoding
|
||||
private static String expected =
|
||||
"utf-8''%C3%80%C3%81%C3%85%C3%86%C3%80%C3%81%C3%85%C3%86%C3%87%C3%88" +
|
||||
"%C3%89%C3%8A%C3%8B%C3%8C%C3%8D%C3%8E%C3%8F%C3%90%C3%80%C3%81%C3%85" +
|
||||
"%C3%86%C3%87%C3%88%C3%89%C3%8A%C3%8B%C3%8C%C3%8D%C3%8E%C3%8F%C3%90" +
|
||||
"%C3%91%C3%92%C3%93%C3%94%C3%95%C3%96%C3%98%C3%99%C3%9A%C3%9B%C3%9C" +
|
||||
"%C3%9D%C3%9E%C3%9F%C3%A0%C3%A1%C3%A2%C3%A3%C3%A4%C3%A5%C3%A6%C3%A7" +
|
||||
"%C3%A8%C3%A9%C3%AA%C3%AB%C3%AC%C3%AD%C3%AE%C3%AF%C3%B0%C3%B1%C3%B2" +
|
||||
"%C3%B3%C3%B4%C3%B5%C3%B6%C3%B8%C3%B9%C3%BA%C3%BB%C3%BC%C3%BD%C3%BE" +
|
||||
"%C3%BF%C3%80%C3%81%C3%85%C3%86%C3%87.doc";
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.out.println("NoEncodeFileName");
|
||||
System.setProperty("mail.mime.charset", "utf-8");
|
||||
System.clearProperty("mail.mime.encodefilename");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
System.setProperty("mail.mime.charset", "utf-8");
|
||||
System.clearProperty("mail.mime.encodefilename");
|
||||
String encodedFileName = "=?utf-8?B?w4DDgcOFw4bDgMOBw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw4DD" +
|
||||
"gcOFw4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5XDlsOYw5nDmsObw5" +
|
||||
"zDncOew5/DoMOhw6LDo8Okw6XDpsOnw6jDqcOqw6vDrMOtw67Dr8Oww7HDssOz" +
|
||||
"w7TDtcO2w7jDucO6w7vDvMO9w77Dv8OAw4HDhcOGw4cuZG9j?=";
|
||||
String fileName = MimeUtility.decodeText(encodedFileName);
|
||||
MimeBodyPartPublicUpdateHeaders mbp = new MimeBodyPartPublicUpdateHeaders();
|
||||
mbp.setText("test");
|
||||
mbp.setFileName(fileName);
|
||||
mbp.updateHeaders();
|
||||
String h = mbp.getHeader("Content-Type", "");
|
||||
assertTrue(h.contains("name*="));
|
||||
// RFC 2231 encoding
|
||||
String expected = "UTF-8''%C3%80%C3%81%C3%85%C3%86%C3%80%C3%81%C3%85%C3%86%C3%87%C3%88" +
|
||||
"%C3%89%C3%8A%C3%8B%C3%8C%C3%8D%C3%8E%C3%8F%C3%90%C3%80%C3%81%C3%85" +
|
||||
"%C3%86%C3%87%C3%88%C3%89%C3%8A%C3%8B%C3%8C%C3%8D%C3%8E%C3%8F%C3%90" +
|
||||
"%C3%91%C3%92%C3%93%C3%94%C3%95%C3%96%C3%98%C3%99%C3%9A%C3%9B%C3%9C" +
|
||||
"%C3%9D%C3%9E%C3%9F%C3%A0%C3%A1%C3%A2%C3%A3%C3%A4%C3%A5%C3%A6%C3%A7" +
|
||||
"%C3%A8%C3%A9%C3%AA%C3%AB%C3%AC%C3%AD%C3%AE%C3%AF%C3%B0%C3%B1%C3%B2" +
|
||||
"%C3%B3%C3%B4%C3%B5%C3%B6%C3%B8%C3%B9%C3%BA%C3%BB%C3%BC%C3%BD%C3%BE" +
|
||||
"%C3%BF%C3%80%C3%81%C3%85%C3%86%C3%87.doc";
|
||||
assertTrue(h.contains(expected));
|
||||
h = mbp.getHeader("Content-Disposition", "");
|
||||
assertTrue(h.contains("filename*="));
|
||||
assertTrue(h.contains(expected));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
// should be unnecessary
|
||||
System.clearProperty("mail.mime.charset");
|
||||
System.clearProperty("mail.mime.encodefilename");
|
||||
System.clearProperty("mail.mime.encodeparameters");
|
||||
}
|
||||
|
||||
static class MimeBodyPartPublicUpdateHeaders extends MimeBodyPart {
|
||||
private static class MimeBodyPartPublicUpdateHeaders extends MimeBodyPart {
|
||||
@Override
|
||||
public void updateHeaders() throws MessagingException {
|
||||
super.updateHeaders();
|
||||
|
|
|
@ -33,7 +33,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
*/
|
||||
public class NonAsciiBoundaryTest {
|
||||
|
||||
private static Session s = Session.getInstance(new Properties());
|
||||
private static final Session s = Session.getInstance(new Properties());
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
|
|
|
@ -20,7 +20,6 @@ import jakarta.activation.DataHandler;
|
|||
import jakarta.mail.Folder;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Store;
|
||||
import jakarta.mail.internet.ContentType;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.mail.internet.ParameterList;
|
||||
|
@ -29,6 +28,7 @@ import jakarta.mail.util.ByteArrayDataSource;
|
|||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Enumeration;
|
||||
|
@ -45,20 +45,24 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
* @author Bill Shannon
|
||||
*/
|
||||
|
||||
class ParameterListDecode {
|
||||
class ParameterListDecodeTest {
|
||||
|
||||
static boolean gen_test_input = false; // output good for input to -p
|
||||
static boolean test_mail = false; // test using a mail server
|
||||
static int errors = 0; // number of errors detected
|
||||
static Session session;
|
||||
static Store store;
|
||||
static Folder folder;
|
||||
|
||||
static boolean junit;
|
||||
|
||||
protected void testDecode(String paramData) throws Exception {
|
||||
junit = true;
|
||||
parse(new BufferedReader(new InputStreamReader(
|
||||
getClass().getResourceAsStream(paramData))));
|
||||
InputStream inputStream = getClass().getResourceAsStream(paramData);
|
||||
if (inputStream != null) {
|
||||
parse(new BufferedReader(new InputStreamReader(inputStream)));
|
||||
} else {
|
||||
throw new RuntimeException("not found: " + paramData);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -67,20 +71,19 @@ class ParameterListDecode {
|
|||
* to test against most existing UNIX mailboxes.
|
||||
*/
|
||||
public static void parse(BufferedReader in) throws Exception {
|
||||
String header = "";
|
||||
|
||||
StringBuilder header = new StringBuilder();
|
||||
for (; ; ) {
|
||||
String s = in.readLine();
|
||||
if (s != null && !s.isEmpty()) {
|
||||
char c = s.charAt(0);
|
||||
if (c == ' ' || c == '\t') {
|
||||
// a continuation line, add it to the current header
|
||||
header += '\n' + s;
|
||||
header.append('\n').append(s);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// "s" is the next header, "header" is the last complete header
|
||||
if (header.regionMatches(true, 0, "Content-Type: ", 0, 14)) {
|
||||
if (header.toString().regionMatches(true, 0, "Content-Type: ", 0, 14)) {
|
||||
int i;
|
||||
String[] expect = null;
|
||||
if (s != null && s.startsWith("Expect: ")) {
|
||||
|
@ -91,7 +94,7 @@ class ParameterListDecode {
|
|||
expect[i] = decode(trim(in.readLine()));
|
||||
} catch (NumberFormatException e) {
|
||||
try {
|
||||
if (s.substring(8, 17).equals("Exception")) {
|
||||
if (s.startsWith("Exception", 8)) {
|
||||
expect = new String[1];
|
||||
expect[0] = "Exception";
|
||||
}
|
||||
|
@ -100,7 +103,7 @@ class ParameterListDecode {
|
|||
}
|
||||
}
|
||||
}
|
||||
i = header.indexOf(':');
|
||||
i = header.toString().indexOf(':');
|
||||
try {
|
||||
test(header.substring(0, i), header.substring(i + 2),
|
||||
expect);
|
||||
|
@ -118,7 +121,7 @@ class ParameterListDecode {
|
|||
if (s == null)
|
||||
return;
|
||||
}
|
||||
header = s;
|
||||
header = new StringBuilder(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,8 +211,9 @@ class ParameterListDecode {
|
|||
if (expect != null &&
|
||||
(expect.length != 1 || !expect[0].equals("Exception"))) {
|
||||
out.println("Expected " + expect.length + " parameters");
|
||||
for (int i = 0; i < expect.length; i++)
|
||||
out.println("\tExpected:\t" + expect[i]);
|
||||
for (String s : expect) {
|
||||
out.println("\tExpected:\t" + s);
|
||||
}
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
@ -217,10 +221,8 @@ class ParameterListDecode {
|
|||
if (gen_test_input && test_mail) {
|
||||
MimeMessage msg = new MimeMessage(session);
|
||||
byte[] buf = bos.toByteArray();
|
||||
msg.setDataHandler(new DataHandler(
|
||||
new ByteArrayDataSource(buf, value)));
|
||||
msg.setDataHandler(new DataHandler(new ByteArrayDataSource(buf, value)));
|
||||
msg.saveChanges();
|
||||
//msg.writeTo(System.out);
|
||||
folder.appendMessages(new Message[]{msg});
|
||||
}
|
||||
}
|
|
@ -16,29 +16,18 @@
|
|||
|
||||
package org.xbib.net.mail.test.util;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test that the "mail.mime.parameters.strict" System property
|
||||
* set to false allows bogus parameters to be parsed.
|
||||
*/
|
||||
class ParametersNoStrictTest extends ParameterListDecode {
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.setProperty("mail.mime.parameters.strict", "false");
|
||||
}
|
||||
class ParametersNoStrictTest extends ParameterListDecodeTest {
|
||||
|
||||
@Test
|
||||
public void testDecode() throws Exception {
|
||||
System.setProperty("mail.mime.parameters.strict", "false");
|
||||
testDecode("paramdatanostrict");
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
// should be unnecessary
|
||||
System.clearProperty("mail.mime.parameters.strict");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import java.util.Properties;
|
|||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -36,48 +36,48 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
public class PropUtilTest {
|
||||
|
||||
@Test
|
||||
public void testInt() throws Exception {
|
||||
public void testInt() {
|
||||
Properties props = new Properties();
|
||||
props.setProperty("test", "2");
|
||||
assertEquals(PropUtil.getIntProperty(props, "test", 1), 2);
|
||||
assertEquals(2, PropUtil.getIntProperty(props, "test", 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntDef() throws Exception {
|
||||
public void testIntDef() {
|
||||
Properties props = new Properties();
|
||||
assertEquals(PropUtil.getIntProperty(props, "test", 1), 1);
|
||||
assertEquals(1, PropUtil.getIntProperty(props, "test", 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntDefProp() throws Exception {
|
||||
public void testIntDefProp() {
|
||||
Properties defprops = new Properties();
|
||||
defprops.setProperty("test", "2");
|
||||
Properties props = new Properties(defprops);
|
||||
assertEquals(PropUtil.getIntProperty(props, "test", 1), 2);
|
||||
assertEquals(2, PropUtil.getIntProperty(props, "test", 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInteger() throws Exception {
|
||||
public void testInteger() {
|
||||
Properties props = new Properties();
|
||||
props.put("test", 2);
|
||||
assertEquals(PropUtil.getIntProperty(props, "test", 1), 2);
|
||||
assertEquals(2, PropUtil.getIntProperty(props, "test", 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBool() throws Exception {
|
||||
public void testBool() {
|
||||
Properties props = new Properties();
|
||||
props.setProperty("test", "true");
|
||||
assertTrue(PropUtil.getBooleanProperty(props, "test", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoolDef() throws Exception {
|
||||
public void testBoolDef() {
|
||||
Properties props = new Properties();
|
||||
assertTrue(PropUtil.getBooleanProperty(props, "test", true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoolDefProp() throws Exception {
|
||||
public void testBoolDefProp() {
|
||||
Properties defprops = new Properties();
|
||||
defprops.setProperty("test", "true");
|
||||
Properties props = new Properties(defprops);
|
||||
|
@ -85,49 +85,46 @@ public class PropUtilTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testBoolean() throws Exception {
|
||||
public void testBoolean() {
|
||||
Properties props = new Properties();
|
||||
props.put("test", true);
|
||||
assertTrue(PropUtil.getBooleanProperty(props, "test", false));
|
||||
}
|
||||
|
||||
|
||||
// the Session variants...
|
||||
|
||||
@Test
|
||||
public void testSessionInt() throws Exception {
|
||||
public void testSessionInt() {
|
||||
Properties props = new Properties();
|
||||
props.setProperty("test", "2");
|
||||
Session sess = Session.getInstance(props, null);
|
||||
assertEquals(PropUtil.getIntProperty(sess.getProperties(), "test", 1), 2);
|
||||
assertEquals(2, PropUtil.getIntProperty(sess.getProperties(), "test", 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSessionIntDef() throws Exception {
|
||||
public void testSessionIntDef() {
|
||||
Properties props = new Properties();
|
||||
Session sess = Session.getInstance(props, null);
|
||||
assertEquals(PropUtil.getIntProperty(sess.getProperties(), "test", 1), 1);
|
||||
assertEquals(1, PropUtil.getIntProperty(sess.getProperties(), "test", 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSessionIntDefProp() throws Exception {
|
||||
public void testSessionIntDefProp() {
|
||||
Properties defprops = new Properties();
|
||||
defprops.setProperty("test", "2");
|
||||
Properties props = new Properties(defprops);
|
||||
Session sess = Session.getInstance(props, null);
|
||||
assertEquals(PropUtil.getIntProperty(sess.getProperties(), "test", 1), 2);
|
||||
assertEquals(2, PropUtil.getIntProperty(sess.getProperties(), "test", 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSessionInteger() throws Exception {
|
||||
public void testSessionInteger() {
|
||||
Properties props = new Properties();
|
||||
props.put("test", 2);
|
||||
Session sess = Session.getInstance(props, null);
|
||||
assertEquals(PropUtil.getIntProperty(sess.getProperties(), "test", 1), 2);
|
||||
assertEquals(2, PropUtil.getIntProperty(sess.getProperties(), "test", 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSessionBool() throws Exception {
|
||||
public void testSessionBool() {
|
||||
Properties props = new Properties();
|
||||
props.setProperty("test", "true");
|
||||
Session sess = Session.getInstance(props, null);
|
||||
|
@ -135,7 +132,7 @@ public class PropUtilTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSessionBoolDef() throws Exception {
|
||||
public void testSessionBoolDef() {
|
||||
Properties props = new Properties();
|
||||
Session sess = Session.getInstance(props, null);
|
||||
assertTrue(PropUtil.getBooleanProperty(sess.getProperties(), "test", true));
|
||||
|
@ -151,29 +148,26 @@ public class PropUtilTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSessionBoolean() throws Exception {
|
||||
public void testSessionBoolean() {
|
||||
Properties props = new Properties();
|
||||
props.put("test", true);
|
||||
Session sess = Session.getInstance(props, null);
|
||||
assertTrue(PropUtil.getBooleanProperty(sess.getProperties(), "test", false));
|
||||
}
|
||||
|
||||
|
||||
// the System variants...
|
||||
|
||||
@Test
|
||||
public void testSystemBool() throws Exception {
|
||||
public void testSystemBool() {
|
||||
System.setProperty("test", "true");
|
||||
assertTrue(PropUtil.getBooleanSystemProperty("test", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSystemBoolDef() throws Exception {
|
||||
public void testSystemBoolDef() {
|
||||
assertTrue(PropUtil.getBooleanSystemProperty("testnotset", true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSystemBoolean() throws Exception {
|
||||
public void testSystemBoolean() {
|
||||
System.getProperties().put("testboolean", true);
|
||||
assertTrue(PropUtil.getBooleanSystemProperty("testboolean", false));
|
||||
}
|
||||
|
@ -198,11 +192,13 @@ public class PropUtilTest {
|
|||
assertNull(PropUtil.getScheduledExecutorServiceProperty(props, executorPropertyName));
|
||||
}
|
||||
|
||||
@Test // (expected = ClassCastException.class)
|
||||
@Test
|
||||
public void testScheduledExecutorWriteTimeoutWrongType() {
|
||||
final String executorPropertyName = "test";
|
||||
Properties props = new Properties();
|
||||
props.put(executorPropertyName, new HashSet<>());
|
||||
PropUtil.getScheduledExecutorServiceProperty(props, executorPropertyName);
|
||||
assertThrows(ClassCastException.class, () -> {
|
||||
final String executorPropertyName = "test";
|
||||
Properties props = new Properties();
|
||||
props.put(executorPropertyName, new HashSet<>());
|
||||
PropUtil.getScheduledExecutorServiceProperty(props, executorPropertyName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,6 @@ import jakarta.mail.internet.InternetAddress;
|
|||
import jakarta.mail.internet.MimeMessage;
|
||||
|
||||
import java.util.Properties;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
@ -32,65 +30,63 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
*/
|
||||
public class Utf8AddressTest {
|
||||
|
||||
private static Session s = Session.getInstance(new Properties());
|
||||
private static String utf8name = "test\u00a1\u00a2\u00a3";
|
||||
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
System.out.println("Utf8Address");
|
||||
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||
}
|
||||
private static final Session s = Session.getInstance(new Properties());
|
||||
private static final String utf8name = "test\u00a1\u00a2\u00a3";
|
||||
|
||||
@Test
|
||||
public void testFrom() throws Exception {
|
||||
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||
MimeMessage m = new MimeMessage(s);
|
||||
m.setFrom(new InternetAddress("joe@example.com", utf8name, "UTF-8"));
|
||||
m.saveChanges();
|
||||
String h = m.getHeader("From", "");
|
||||
assertTrue(h.contains(utf8name));
|
||||
s.getProperties().remove("mail.mime.allowutf8");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromString() throws Exception {
|
||||
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||
MimeMessage m = new MimeMessage(s);
|
||||
m.setFrom(utf8name + " <joe@example.com>");
|
||||
m.saveChanges();
|
||||
String h = m.getHeader("From", "");
|
||||
assertTrue(h.contains(utf8name));
|
||||
s.getProperties().remove("mail.mime.allowutf8");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTo() throws Exception {
|
||||
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||
MimeMessage m = new MimeMessage(s);
|
||||
m.setRecipient(Message.RecipientType.TO,
|
||||
new InternetAddress("joe@example.com", utf8name, "UTF-8"));
|
||||
m.saveChanges();
|
||||
String h = m.getHeader("To", "");
|
||||
assertTrue(h.contains(utf8name));
|
||||
s.getProperties().remove("mail.mime.allowutf8");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() throws Exception {
|
||||
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||
MimeMessage m = new MimeMessage(s);
|
||||
m.setRecipients(Message.RecipientType.TO,
|
||||
utf8name + " <joe@example.com>");
|
||||
m.saveChanges();
|
||||
String h = m.getHeader("To", "");
|
||||
assertTrue(h.contains(utf8name));
|
||||
s.getProperties().remove("mail.mime.allowutf8");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSender() throws Exception {
|
||||
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||
MimeMessage m = new MimeMessage(s);
|
||||
m.setSender(new InternetAddress("joe@example.com", utf8name, "UTF-8"));
|
||||
m.saveChanges();
|
||||
String h = m.getHeader("Sender", "");
|
||||
assertTrue(h.contains(utf8name));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
// should be unnecessary
|
||||
s.getProperties().remove("mail.mime.allowutf8");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ import jakarta.mail.Store;
|
|||
import jakarta.mail.StoreClosedException;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.mail.util.ByteArrayDataSource;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
|
@ -56,7 +58,9 @@ import java.util.concurrent.ScheduledFuture;
|
|||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
|
@ -65,9 +69,12 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
*/
|
||||
@Timeout(20)
|
||||
public final class WriteTimeoutSocketTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(WriteTimeoutSocketTest.class.getName());
|
||||
|
||||
private TestServer testServer;
|
||||
private List<ScheduledExecutorService> scheduledExecutorServices = new ArrayList<>();
|
||||
private List<WriteTimeoutSocket> writeTimeoutSockets = new ArrayList<>();
|
||||
private final List<ScheduledExecutorService> scheduledExecutorServices = new ArrayList<>();
|
||||
private final List<WriteTimeoutSocket> writeTimeoutSockets = new ArrayList<>();
|
||||
|
||||
private static final int TIMEOUT = 200; // ms
|
||||
private static final String data =
|
||||
|
@ -109,14 +116,16 @@ public final class WriteTimeoutSocketTest {
|
|||
assertTrue(sf.getSocketCreated());
|
||||
}
|
||||
|
||||
@Test //(expected = MessagingException.class)
|
||||
public void testSSLCheckserveridentityDefaultsTrue() throws Exception {
|
||||
final Properties properties = new Properties();
|
||||
properties.setProperty("mail.imap.host", "localhost");
|
||||
properties.setProperty("mail.imap.writetimeout", "" + TIMEOUT);
|
||||
properties.setProperty("mail.imap.ssl.enable", "true");
|
||||
properties.setProperty("mail.imap.ssl.trust", "localhost");
|
||||
test(properties, true);
|
||||
@Test
|
||||
public void testSSLCheckserveridentityDefaultsTrue() {
|
||||
assertThrows(MessagingException.class, () -> {
|
||||
final Properties properties = new Properties();
|
||||
properties.setProperty("mail.imap.host", "localhost");
|
||||
properties.setProperty("mail.imap.writetimeout", "" + TIMEOUT);
|
||||
properties.setProperty("mail.imap.ssl.enable", "true");
|
||||
properties.setProperty("mail.imap.ssl.trust", "localhost");
|
||||
test(properties, true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,32 +170,32 @@ public final class WriteTimeoutSocketTest {
|
|||
* XXX - this is kind of hacky since it depends on Method.toString
|
||||
*/
|
||||
@Test
|
||||
public void testOverrides() throws Exception {
|
||||
public void testOverrides() {
|
||||
Set<String> socketMethods = new HashSet<>();
|
||||
Method[] m = Socket.class.getDeclaredMethods();
|
||||
String className = Socket.class.getName() + ".";
|
||||
for (int i = 0; i < m.length; i++) {
|
||||
if (Modifier.isPublic(m[i].getModifiers()) &&
|
||||
!Modifier.isStatic(m[i].getModifiers())) {
|
||||
String name = m[i].toString().
|
||||
for (Method method : m) {
|
||||
if (Modifier.isPublic(method.getModifiers()) &&
|
||||
!Modifier.isStatic(method.getModifiers())) {
|
||||
String name = method.toString().
|
||||
replace("synchronized ", "").
|
||||
replace(className, "");
|
||||
socketMethods.add(name);
|
||||
}
|
||||
}
|
||||
Set<String> wtsocketMethods = new HashSet<>();
|
||||
m = WriteTimeoutSocket.class.getDeclaredMethods();
|
||||
className = WriteTimeoutSocket.class.getName() + ".";
|
||||
for (int i = 0; i < m.length; i++) {
|
||||
if (Modifier.isPublic(m[i].getModifiers())) {
|
||||
String name = m[i].toString().
|
||||
for (Method method : m) {
|
||||
if (Modifier.isPublic(method.getModifiers())) {
|
||||
String name = method.toString().
|
||||
replace("synchronized ", "").
|
||||
replace(className, "");
|
||||
socketMethods.remove(name);
|
||||
}
|
||||
}
|
||||
for (String s : socketMethods)
|
||||
System.out.println("WriteTimeoutSocket did not override: " + s);
|
||||
for (String s : socketMethods) {
|
||||
logger.log(Level.INFO, "WriteTimeoutSocket did not override: " + s);
|
||||
}
|
||||
assertTrue(socketMethods.isEmpty());
|
||||
}
|
||||
|
||||
|
@ -199,7 +208,6 @@ public final class WriteTimeoutSocketTest {
|
|||
|
||||
properties.setProperty("mail.imap.port", String.valueOf(server.getPort()));
|
||||
final Session session = Session.getInstance(properties);
|
||||
//session.setDebug(true);
|
||||
|
||||
MimeMessage msg = new MimeMessage(session);
|
||||
msg.setFrom("test@example.com");
|
||||
|
@ -218,17 +226,13 @@ public final class WriteTimeoutSocketTest {
|
|||
msg.setDataHandler(new DataHandler(
|
||||
new ByteArrayDataSource(part, "text/plain")));
|
||||
msg.saveChanges();
|
||||
|
||||
final Store store = session.getStore("imap");
|
||||
try {
|
||||
try (Store store = session.getStore("imap")) {
|
||||
store.connect("test", "test");
|
||||
final Folder f = store.getFolder("test");
|
||||
f.appendMessages(new Message[]{msg});
|
||||
fail("No timeout");
|
||||
} catch (StoreClosedException scex) {
|
||||
// success!
|
||||
} finally {
|
||||
store.close();
|
||||
}
|
||||
} finally {
|
||||
if (server != null) {
|
||||
|
@ -237,18 +241,6 @@ public final class WriteTimeoutSocketTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileDescriptor$() throws Exception {
|
||||
try (PublicFileSocket ps = new PublicFileSocket()) {
|
||||
assertNotNull(ps.getFileDescriptor$());
|
||||
}
|
||||
|
||||
testFileDescriptor$(new PublicFileSocket());
|
||||
testFileDescriptor$(new PublicFileSocket1of3());
|
||||
testFileDescriptor$(new PublicFileSocket2of3());
|
||||
testFileDescriptor$(new PublicFileSocket3of3());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExternalSesIsBeingUsed() throws Exception {
|
||||
final Properties properties = new Properties();
|
||||
|
@ -279,7 +271,7 @@ public final class WriteTimeoutSocketTest {
|
|||
fail("Expected IOException wasn't thrown ");
|
||||
} catch (MessagingException mex) {
|
||||
Throwable cause = mex.getCause();
|
||||
assertTrue(cause instanceof ConnectionException);
|
||||
assertInstanceOf(ConnectionException.class, cause);
|
||||
assertTrue(cause.getMessage().contains("java.io.IOException: Write aborted due to timeout not enforced"));
|
||||
}
|
||||
}
|
||||
|
@ -310,9 +302,8 @@ public final class WriteTimeoutSocketTest {
|
|||
public void testDefaultSesConstructor1() throws Exception {
|
||||
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(new Socket(), 10000);
|
||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||
|
||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||
assertTrue(isExternalSes instanceof Boolean);
|
||||
assertInstanceOf(Boolean.class, isExternalSes);
|
||||
assertFalse((Boolean) isExternalSes);
|
||||
}
|
||||
|
||||
|
@ -320,22 +311,19 @@ public final class WriteTimeoutSocketTest {
|
|||
public void testDefaultSesConstructor2() throws Exception {
|
||||
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(10000);
|
||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||
|
||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||
assertTrue(isExternalSes instanceof Boolean);
|
||||
assertInstanceOf(Boolean.class, isExternalSes);
|
||||
assertFalse((Boolean) isExternalSes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultSesConstructor3() throws Exception {
|
||||
testServer = getActiveTestServer(false);
|
||||
|
||||
WriteTimeoutSocket writeTimeoutSocket =
|
||||
new WriteTimeoutSocket("localhost", testServer.getPort(), 10000);
|
||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||
|
||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||
assertTrue(isExternalSes instanceof Boolean);
|
||||
assertInstanceOf(Boolean.class, isExternalSes);
|
||||
assertFalse((Boolean) isExternalSes);
|
||||
}
|
||||
|
||||
|
@ -345,37 +333,32 @@ public final class WriteTimeoutSocketTest {
|
|||
WriteTimeoutSocket writeTimeoutSocket =
|
||||
new WriteTimeoutSocket(InetAddress.getLocalHost(), testServer.getPort(), 10000);
|
||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||
|
||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||
assertTrue(isExternalSes instanceof Boolean);
|
||||
assertInstanceOf(Boolean.class, isExternalSes);
|
||||
assertFalse((Boolean) isExternalSes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultSesConstructor5() throws Exception {
|
||||
testServer = getActiveTestServer(false);
|
||||
|
||||
WriteTimeoutSocket writeTimeoutSocket =
|
||||
new WriteTimeoutSocket("localhost", testServer.getPort(),
|
||||
(InetAddress) null, getRandomFreePort(), 10000);
|
||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||
|
||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||
assertTrue(isExternalSes instanceof Boolean);
|
||||
assertInstanceOf(Boolean.class, isExternalSes);
|
||||
assertFalse((Boolean) isExternalSes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultSesConstructor6() throws Exception {
|
||||
testServer = getActiveTestServer(false);
|
||||
|
||||
WriteTimeoutSocket writeTimeoutSocket =
|
||||
new WriteTimeoutSocket(InetAddress.getByName("localhost"), testServer.getPort(),
|
||||
(InetAddress) null, getRandomFreePort(), 10000);
|
||||
null, getRandomFreePort(), 10000);
|
||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||
|
||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||
assertTrue(isExternalSes instanceof Boolean);
|
||||
assertInstanceOf(Boolean.class, isExternalSes);
|
||||
assertFalse((Boolean) isExternalSes);
|
||||
}
|
||||
|
||||
|
@ -384,9 +367,8 @@ public final class WriteTimeoutSocketTest {
|
|||
WriteTimeoutSocket writeTimeoutSocket =
|
||||
new WriteTimeoutSocket(new Socket(), 10000, new ScheduledThreadPoolExecutor(1));
|
||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||
|
||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||
assertTrue(isExternalSes instanceof Boolean);
|
||||
assertInstanceOf(Boolean.class, isExternalSes);
|
||||
assertTrue((Boolean) isExternalSes);
|
||||
}
|
||||
|
||||
|
@ -397,7 +379,6 @@ public final class WriteTimeoutSocketTest {
|
|||
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(socket, 10000, ses);
|
||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||
writeTimeoutSocket.close();
|
||||
|
||||
assertFalse(ses.isShutdownNowMethodCalled);
|
||||
}
|
||||
|
||||
|
@ -408,22 +389,12 @@ public final class WriteTimeoutSocketTest {
|
|||
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(socket, 10000);
|
||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||
ReflectionUtil.setFieldValue(writeTimeoutSocket, "ses", ses);
|
||||
|
||||
writeTimeoutSocket.close();
|
||||
|
||||
assertTrue(ses.isShutdownNowMethodCalled);
|
||||
}
|
||||
|
||||
private void testFileDescriptor$(Socket s) throws Exception {
|
||||
try (WriteTimeoutSocket ws = new WriteTimeoutSocket(s, 1000)) {
|
||||
assertNotNull(ws.getFileDescriptor$());
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
||||
private TestServer getActiveTestServer(boolean isSSL) {
|
||||
TestServer server = null;
|
||||
TestServer server;
|
||||
try {
|
||||
final TimeoutHandler handler = new TimeoutHandler();
|
||||
server = new TestServer(handler, isSSL);
|
||||
|
@ -438,7 +409,6 @@ public final class WriteTimeoutSocketTest {
|
|||
ServerSocket serverSocket = new ServerSocket(0);
|
||||
int freePort = serverSocket.getLocalPort();
|
||||
serverSocket.close();
|
||||
|
||||
return freePort;
|
||||
}
|
||||
|
||||
|
@ -446,11 +416,10 @@ public final class WriteTimeoutSocketTest {
|
|||
if (ses.isTerminated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ses.shutdownNow();
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -458,11 +427,10 @@ public final class WriteTimeoutSocketTest {
|
|||
if (testServer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
testServer.quit();
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,17 +438,17 @@ public final class WriteTimeoutSocketTest {
|
|||
if (writeTimeoutSocket.isClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
writeTimeoutSocket.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PublicFileSocket extends Socket {
|
||||
public FileDescriptor getFileDescriptor$() {
|
||||
return new FileDescriptor();
|
||||
|
||||
public PublicFileSocket() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6184,20 +6184,6 @@
|
|||
"hash": ""
|
||||
},
|
||||
"Invalid IPv4 radix digits",
|
||||
{
|
||||
"input": "http://0177.0.0.0189",
|
||||
"base": "about:blank",
|
||||
"href": "http://0177.0.0.0189/",
|
||||
"protocol": "http:",
|
||||
"username": "",
|
||||
"password": "",
|
||||
"host": "0177.0.0.0189",
|
||||
"hostname": "177-0-0-189.dsl.brasiltelecom.net.br",
|
||||
"port": "",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"hash": ""
|
||||
},
|
||||
{
|
||||
"input": "http://0x7f.0.0.0x7g",
|
||||
"base": "about:blank",
|
||||
|
|
Loading…
Reference in a new issue