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.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -121,7 +120,7 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
private static final String confDir;
|
private static final String confDir;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
String dir = null;
|
String dir;
|
||||||
String home = System.getProperty("java.home");
|
String home = System.getProperty("java.home");
|
||||||
String newdir = home + File.separator + "conf";
|
String newdir = home + File.separator + "conf";
|
||||||
File conf = new File(newdir);
|
File conf = new File(newdir);
|
||||||
|
@ -145,17 +144,14 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
List<MailcapRegistry> dbv = new ArrayList<>(5); // usually 5 or less databases
|
List<MailcapRegistry> dbv = new ArrayList<>(5); // usually 5 or less databases
|
||||||
MailcapRegistry mf = null;
|
MailcapRegistry mf = null;
|
||||||
dbv.add(null); // place holder for PROG entry
|
dbv.add(null); // place holder for PROG entry
|
||||||
|
|
||||||
logger.log(Level.FINE, "MailcapCommandMap: load HOME");
|
logger.log(Level.FINE, "MailcapCommandMap: load HOME");
|
||||||
String user_home = System.getProperty("user.home");
|
String user_home = System.getProperty("user.home");
|
||||||
|
|
||||||
if (user_home != null) {
|
if (user_home != null) {
|
||||||
String path = user_home + File.separator + ".mailcap";
|
String path = user_home + File.separator + ".mailcap";
|
||||||
mf = loadFile(path);
|
mf = loadFile(path);
|
||||||
if (mf != null)
|
if (mf != null)
|
||||||
dbv.add(mf);
|
dbv.add(mf);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log(Level.FINE, "MailcapCommandMap: load SYS");
|
logger.log(Level.FINE, "MailcapCommandMap: load SYS");
|
||||||
// check system's home
|
// check system's home
|
||||||
if (confDir != null) {
|
if (confDir != null) {
|
||||||
|
@ -163,17 +159,14 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
if (mf != null)
|
if (mf != null)
|
||||||
dbv.add(mf);
|
dbv.add(mf);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log(Level.FINE, "MailcapCommandMap: load JAR");
|
logger.log(Level.FINE, "MailcapCommandMap: load JAR");
|
||||||
// load from the app's jar file
|
// load from the app's jar file
|
||||||
loadAllResources(dbv, "META-INF/mailcap");
|
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");
|
mf = loadResource("/META-INF/mailcap.default");
|
||||||
|
if (mf != null) {
|
||||||
if (mf != null)
|
|
||||||
dbv.add(mf);
|
dbv.add(mf);
|
||||||
|
}
|
||||||
DB = new MailcapRegistry[dbv.size()];
|
DB = new MailcapRegistry[dbv.size()];
|
||||||
DB = dbv.toArray(DB);
|
DB = dbv.toArray(DB);
|
||||||
}
|
}
|
||||||
|
@ -212,7 +205,6 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
*/
|
*/
|
||||||
public MailcapCommandMap(InputStream is) {
|
public MailcapCommandMap(InputStream is) {
|
||||||
this();
|
this();
|
||||||
|
|
||||||
if (DB[PROG] == null) {
|
if (DB[PROG] == null) {
|
||||||
try {
|
try {
|
||||||
DB[PROG] = getImplementation().getByInputStream(is);
|
DB[PROG] = getImplementation().getByInputStream(is);
|
||||||
|
@ -271,10 +263,9 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
urls = Util.getSystemResources(name);
|
urls = Util.getSystemResources(name);
|
||||||
if (urls != null) {
|
if (urls != null) {
|
||||||
logger.log(Level.FINE, "MailcapCommandMap: getResources");
|
logger.log(Level.FINE, "MailcapCommandMap: getResources");
|
||||||
for (int i = 0; i < urls.length; i++) {
|
for (URL url : urls) {
|
||||||
URL url = urls[i];
|
|
||||||
logger.log(Level.FINE, "MailcapCommandMap: URL " + url);
|
logger.log(Level.FINE, "MailcapCommandMap: URL " + url);
|
||||||
try (InputStream clis = Util.openStream(url)) {
|
try (InputStream clis = url.openStream()) {
|
||||||
if (clis != null) {
|
if (clis != null) {
|
||||||
v.add(getImplementation().getByInputStream(clis));
|
v.add(getImplementation().getByInputStream(clis));
|
||||||
anyLoaded = true;
|
anyLoaded = true;
|
||||||
|
@ -299,7 +290,6 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
} catch (Exception ex) {
|
} 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 failed to load anything, fall back to old technique, just in case
|
||||||
if (!anyLoaded) {
|
if (!anyLoaded) {
|
||||||
logger.log(Level.FINE, "MailcapCommandMap: !anyLoaded");
|
logger.log(Level.FINE, "MailcapCommandMap: !anyLoaded");
|
||||||
|
@ -314,7 +304,6 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
*/
|
*/
|
||||||
private MailcapRegistry loadFile(String name) {
|
private MailcapRegistry loadFile(String name) {
|
||||||
MailcapRegistry mtf = null;
|
MailcapRegistry mtf = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mtf = getImplementation().getByFileName(name);
|
mtf = getImplementation().getByFileName(name);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -341,29 +330,26 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
*/
|
*/
|
||||||
public synchronized CommandInfo[] getPreferredCommands(String mimeType) {
|
public synchronized CommandInfo[] getPreferredCommands(String mimeType) {
|
||||||
List<CommandInfo> cmdList = new ArrayList<>();
|
List<CommandInfo> cmdList = new ArrayList<>();
|
||||||
if (mimeType != null)
|
if (mimeType != null) {
|
||||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||||
|
}
|
||||||
for (int i = 0; i < DB.length; i++) {
|
for (MailcapRegistry registry : DB) {
|
||||||
if (DB[i] == null)
|
if (registry == null)
|
||||||
continue;
|
continue;
|
||||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
Map<String, List<String>> cmdMap = registry.getMailcapList(mimeType);
|
||||||
if (cmdMap != null)
|
if (cmdMap != null)
|
||||||
appendPrefCmdsToList(cmdMap, cmdList);
|
appendPrefCmdsToList(cmdMap, cmdList);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now add the fallback commands
|
// now add the fallback commands
|
||||||
for (int i = 0; i < DB.length; i++) {
|
for (MailcapRegistry mailcapRegistry : DB) {
|
||||||
if (DB[i] == null)
|
if (mailcapRegistry == null)
|
||||||
continue;
|
continue;
|
||||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
Map<String, List<String>> cmdMap = mailcapRegistry.getMailcapFallbackList(mimeType);
|
||||||
if (cmdMap != null)
|
if (cmdMap != null)
|
||||||
appendPrefCmdsToList(cmdMap, cmdList);
|
appendPrefCmdsToList(cmdMap, cmdList);
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
|
CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
|
||||||
cmdInfos = cmdList.toArray(cmdInfos);
|
cmdInfos = cmdList.toArray(cmdInfos);
|
||||||
|
|
||||||
return cmdInfos;
|
return cmdInfos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,10 +357,7 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
* Put the commands that are in the hash table, into the list.
|
* Put the commands that are in the hash table, into the list.
|
||||||
*/
|
*/
|
||||||
private void appendPrefCmdsToList(Map<String, List<String>> cmdHash, List<CommandInfo> cmdList) {
|
private void appendPrefCmdsToList(Map<String, List<String>> cmdHash, List<CommandInfo> cmdList) {
|
||||||
Iterator<String> verb_enum = cmdHash.keySet().iterator();
|
for (String verb : cmdHash.keySet()) {
|
||||||
|
|
||||||
while (verb_enum.hasNext()) {
|
|
||||||
String verb = verb_enum.next();
|
|
||||||
if (!checkForVerb(cmdList, verb)) {
|
if (!checkForVerb(cmdList, verb)) {
|
||||||
List<String> cmdList2 = cmdHash.get(verb); // get the list
|
List<String> cmdList2 = cmdHash.get(verb); // get the list
|
||||||
String className = cmdList2.get(0);
|
String className = cmdList2.get(0);
|
||||||
|
@ -388,12 +371,12 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
* true if the verb is there.
|
* true if the verb is there.
|
||||||
*/
|
*/
|
||||||
private boolean checkForVerb(List<CommandInfo> cmdList, String verb) {
|
private boolean checkForVerb(List<CommandInfo> cmdList, String verb) {
|
||||||
Iterator<CommandInfo> ee = cmdList.iterator();
|
for (CommandInfo commandInfo : cmdList) {
|
||||||
while (ee.hasNext()) {
|
String enum_verb = commandInfo.getCommandName();
|
||||||
String enum_verb = (ee.next()).getCommandName();
|
if (enum_verb.equals(verb)) {
|
||||||
if (enum_verb.equals(verb))
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,29 +389,29 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
*/
|
*/
|
||||||
public synchronized CommandInfo[] getAllCommands(String mimeType) {
|
public synchronized CommandInfo[] getAllCommands(String mimeType) {
|
||||||
List<CommandInfo> cmdList = new ArrayList<>();
|
List<CommandInfo> cmdList = new ArrayList<>();
|
||||||
if (mimeType != null)
|
if (mimeType != null) {
|
||||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||||
|
}
|
||||||
for (int i = 0; i < DB.length; i++) {
|
for (MailcapRegistry mailcapRegistry : DB) {
|
||||||
if (DB[i] == null)
|
if (mailcapRegistry == null) {
|
||||||
continue;
|
continue;
|
||||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
}
|
||||||
if (cmdMap != null)
|
Map<String, List<String>> cmdMap = mailcapRegistry.getMailcapList(mimeType);
|
||||||
|
if (cmdMap != null) {
|
||||||
appendCmdsToList(cmdMap, cmdList);
|
appendCmdsToList(cmdMap, cmdList);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// now add the fallback commands
|
// now add the fallback commands
|
||||||
for (int i = 0; i < DB.length; i++) {
|
for (MailcapRegistry mailcapRegistry : DB) {
|
||||||
if (DB[i] == null)
|
if (mailcapRegistry == null) {
|
||||||
continue;
|
continue;
|
||||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
}
|
||||||
|
Map<String, List<String>> cmdMap = mailcapRegistry.getMailcapFallbackList(mimeType);
|
||||||
if (cmdMap != null)
|
if (cmdMap != null)
|
||||||
appendCmdsToList(cmdMap, cmdList);
|
appendCmdsToList(cmdMap, cmdList);
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
|
CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
|
||||||
cmdInfos = cmdList.toArray(cmdInfos);
|
cmdInfos = cmdList.toArray(cmdInfos);
|
||||||
|
|
||||||
return cmdInfos;
|
return cmdInfos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,17 +419,10 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
* Put the commands that are in the hash table, into the list.
|
* Put the commands that are in the hash table, into the list.
|
||||||
*/
|
*/
|
||||||
private void appendCmdsToList(Map<String, List<String>> typeHash, List<CommandInfo> cmdList) {
|
private void appendCmdsToList(Map<String, List<String>> typeHash, List<CommandInfo> cmdList) {
|
||||||
Iterator<String> verb_enum = typeHash.keySet().iterator();
|
for (String verb : typeHash.keySet()) {
|
||||||
|
|
||||||
while (verb_enum.hasNext()) {
|
|
||||||
String verb = verb_enum.next();
|
|
||||||
List<String> cmdList2 = typeHash.get(verb);
|
List<String> cmdList2 = typeHash.get(verb);
|
||||||
Iterator<String> cmd_enum = cmdList2.iterator();
|
for (String cmd : cmdList2) {
|
||||||
|
|
||||||
while (cmd_enum.hasNext()) {
|
|
||||||
String cmd = cmd_enum.next();
|
|
||||||
cmdList.add(new CommandInfo(verb, cmd));
|
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,
|
public synchronized CommandInfo getCommand(String mimeType,
|
||||||
String cmdName) {
|
String cmdName) {
|
||||||
if (mimeType != null)
|
if (mimeType != null) {
|
||||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||||
|
}
|
||||||
for (int i = 0; i < DB.length; i++) {
|
for (MailcapRegistry mailcapRegistry : DB) {
|
||||||
if (DB[i] == null)
|
if (mailcapRegistry == null) {
|
||||||
continue;
|
continue;
|
||||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
}
|
||||||
|
Map<String, List<String>> cmdMap = mailcapRegistry.getMailcapList(mimeType);
|
||||||
if (cmdMap != null) {
|
if (cmdMap != null) {
|
||||||
// get the cmd list for the cmd
|
// get the cmd list for the cmd
|
||||||
List<String> v = cmdMap.get(cmdName);
|
List<String> v = cmdMap.get(cmdName);
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
String cmdClassName = v.get(0);
|
String cmdClassName = v.getFirst();
|
||||||
|
|
||||||
if (cmdClassName != null)
|
if (cmdClassName != null)
|
||||||
return new CommandInfo(cmdName, cmdClassName);
|
return new CommandInfo(cmdName, cmdClassName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now try the fallback list
|
// now try the fallback list
|
||||||
for (int i = 0; i < DB.length; i++) {
|
for (MailcapRegistry mailcapRegistry : DB) {
|
||||||
if (DB[i] == null)
|
if (mailcapRegistry == null) {
|
||||||
continue;
|
continue;
|
||||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
}
|
||||||
|
Map<String, List<String>> cmdMap = mailcapRegistry.getMailcapFallbackList(mimeType);
|
||||||
if (cmdMap != null) {
|
if (cmdMap != null) {
|
||||||
// get the cmd list for the cmd
|
// get the cmd list for the cmd
|
||||||
List<String> v = cmdMap.get(cmdName);
|
List<String> v = cmdMap.get(cmdName);
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
String cmdClassName = v.get(0);
|
String cmdClassName = v.getFirst();
|
||||||
|
|
||||||
if (cmdClassName != null)
|
if (cmdClassName != null)
|
||||||
return new CommandInfo(cmdName, cmdClassName);
|
return new CommandInfo(cmdName, cmdClassName);
|
||||||
}
|
}
|
||||||
|
@ -531,29 +506,30 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
public synchronized DataContentHandler createDataContentHandler(
|
public synchronized DataContentHandler createDataContentHandler(
|
||||||
String mimeType) {
|
String mimeType) {
|
||||||
logger.log(Level.FINE, "MailcapCommandMap: createDataContentHandler for " + mimeType);
|
logger.log(Level.FINE, "MailcapCommandMap: createDataContentHandler for " + mimeType);
|
||||||
if (mimeType != null)
|
if (mimeType != null) {
|
||||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||||
|
}
|
||||||
for (int i = 0; i < DB.length; i++) {
|
for (int i = 0; i < DB.length; i++) {
|
||||||
if (DB[i] == null)
|
if (DB[i] == null) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
logger.log(Level.FINE, " search DB #" + i);
|
logger.log(Level.FINE, " search DB #" + i);
|
||||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
||||||
if (cmdMap != null) {
|
if (cmdMap != null) {
|
||||||
List<String> v = cmdMap.get("content-handler");
|
List<String> v = cmdMap.get("content-handler");
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
String name = v.get(0);
|
String name = v.getFirst();
|
||||||
DataContentHandler dch = getDataContentHandler(name);
|
DataContentHandler dch = getDataContentHandler(name);
|
||||||
if (dch != null)
|
if (dch != null)
|
||||||
return dch;
|
return dch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now try the fallback entries
|
// now try the fallback entries
|
||||||
for (int i = 0; i < DB.length; i++) {
|
for (int i = 0; i < DB.length; i++) {
|
||||||
if (DB[i] == null)
|
if (DB[i] == null) {
|
||||||
continue;
|
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);
|
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
||||||
if (cmdMap != null) {
|
if (cmdMap != null) {
|
||||||
|
@ -602,23 +578,21 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
*/
|
*/
|
||||||
public synchronized String[] getMimeTypes() {
|
public synchronized String[] getMimeTypes() {
|
||||||
List<String> mtList = new ArrayList<>();
|
List<String> mtList = new ArrayList<>();
|
||||||
|
for (MailcapRegistry mailcapRegistry : DB) {
|
||||||
for (int i = 0; i < DB.length; i++) {
|
if (mailcapRegistry == null) {
|
||||||
if (DB[i] == null)
|
|
||||||
continue;
|
continue;
|
||||||
String[] ts = DB[i].getMimeTypes();
|
}
|
||||||
|
String[] ts = mailcapRegistry.getMimeTypes();
|
||||||
if (ts != null) {
|
if (ts != null) {
|
||||||
for (int j = 0; j < ts.length; j++) {
|
for (String t : ts) {
|
||||||
// eliminate duplicates
|
// eliminate duplicates
|
||||||
if (!mtList.contains(ts[j]))
|
if (!mtList.contains(t))
|
||||||
mtList.add(ts[j]);
|
mtList.add(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] mts = new String[mtList.size()];
|
String[] mts = new String[mtList.size()];
|
||||||
mts = mtList.toArray(mts);
|
mts = mtList.toArray(mts);
|
||||||
|
|
||||||
return mts;
|
return mts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,7 +631,6 @@ public class MailcapCommandMap extends CommandMap {
|
||||||
}
|
}
|
||||||
String[] cmds = new String[cmdList.size()];
|
String[] cmds = new String[cmdList.size()];
|
||||||
cmds = cmdList.toArray(cmds);
|
cmds = cmdList.toArray(cmds);
|
||||||
|
|
||||||
return cmds;
|
return cmds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,9 +113,11 @@ public class MimetypesFileTypeMap extends FileTypeMap {
|
||||||
logger.log(Level.FINE, "MimetypesFileTypeMap: load DEF");
|
logger.log(Level.FINE, "MimetypesFileTypeMap: load DEF");
|
||||||
mf = loadResource("/META-INF/mimetypes.default");
|
mf = loadResource("/META-INF/mimetypes.default");
|
||||||
|
|
||||||
if (mf != null)
|
if (mf != null) {
|
||||||
dbv.addElement(mf);
|
dbv.addElement(mf);
|
||||||
|
} else {
|
||||||
|
logger.log(Level.WARNING, "mimetype.default not found");
|
||||||
|
}
|
||||||
DB = new MimeTypeRegistry[dbv.size()];
|
DB = new MimeTypeRegistry[dbv.size()];
|
||||||
dbv.copyInto(DB);
|
dbv.copyInto(DB);
|
||||||
}
|
}
|
||||||
|
@ -212,7 +214,7 @@ public class MimetypesFileTypeMap extends FileTypeMap {
|
||||||
InputStream clis = null;
|
InputStream clis = null;
|
||||||
logger.log(Level.FINE, "MimetypesFileTypeMap: URL " + url);
|
logger.log(Level.FINE, "MimetypesFileTypeMap: URL " + url);
|
||||||
try {
|
try {
|
||||||
clis = Util.openStream(url);
|
clis = url.openStream();
|
||||||
if (clis != null) {
|
if (clis != null) {
|
||||||
v.addElement(
|
v.addElement(
|
||||||
getImplementation().getByInputStream(clis)
|
getImplementation().getByInputStream(clis)
|
||||||
|
|
|
@ -20,7 +20,6 @@ import java.util.List;
|
||||||
class Util {
|
class Util {
|
||||||
|
|
||||||
private Util() {
|
private Util() {
|
||||||
// private constructor, can't create an instance
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClassLoader getContextClassLoader() {
|
public static ClassLoader getContextClassLoader() {
|
||||||
|
@ -71,8 +70,4 @@ class Util {
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InputStream openStream(final URL url) throws IOException {
|
|
||||||
return url.openStream();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,25 +17,21 @@
|
||||||
package jakarta.mail;
|
package jakarta.mail;
|
||||||
|
|
||||||
import jakarta.mail.util.LineInputStream;
|
import jakarta.mail.util.LineInputStream;
|
||||||
|
import jakarta.mail.util.ResourceLoader;
|
||||||
|
import jakarta.mail.util.StreamLoader;
|
||||||
import jakarta.mail.util.StreamProvider;
|
import jakarta.mail.util.StreamProvider;
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
@ -44,14 +40,6 @@ import java.util.concurrent.Executors;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
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.
|
* The Session class represents a mail session and is not subclassed.
|
||||||
* It collects together properties and defaults used by the mail API's.
|
* 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 home = System.getProperty("java.home");
|
||||||
String newdir = home + File.separator + "conf";
|
String newdir = home + File.separator + "conf";
|
||||||
File conf = new File(newdir);
|
File conf = new File(newdir);
|
||||||
if (conf.exists())
|
if (conf.exists()) {
|
||||||
dir = newdir + File.separator;
|
dir = newdir + File.separator;
|
||||||
else
|
} else {
|
||||||
dir = home + File.separator +
|
dir = home + File.separator + "lib" + File.separator;
|
||||||
"lib" + File.separator;
|
}
|
||||||
confDir = dir;
|
confDir = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final StreamProvider streamProvider;
|
private final StreamProvider streamProvider;
|
||||||
private final Properties props;
|
private final Properties props;
|
||||||
private final Authenticator authenticator;
|
private final Authenticator authenticator;
|
||||||
private final Hashtable<URLName, PasswordAuthentication> authTable
|
private final Hashtable<URLName, PasswordAuthentication> authTable = new Hashtable<>();
|
||||||
= new Hashtable<>();
|
|
||||||
private final List<Provider> providers = new ArrayList<>();
|
private final List<Provider> providers = new ArrayList<>();
|
||||||
private final Map<String, Provider> providersByProtocol = new HashMap<>();
|
private final Map<String, Provider> providersByProtocol = new HashMap<>();
|
||||||
private final Map<String, Provider> providersByClassName = new HashMap<>();
|
private final Map<String, Provider> providersByClassName = new HashMap<>();
|
||||||
|
@ -245,15 +232,10 @@ public final class Session {
|
||||||
this.props = props;
|
this.props = props;
|
||||||
this.authenticator = authenticator;
|
this.authenticator = authenticator;
|
||||||
this.streamProvider = StreamProvider.provider();
|
this.streamProvider = StreamProvider.provider();
|
||||||
|
|
||||||
// get the Class associated with the Authenticator
|
// get the Class associated with the Authenticator
|
||||||
Class<?> cl;
|
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
|
// Use implementation class, because that class loader has access to jakarta.mail module and implementation resources
|
||||||
cl = streamProvider.getClass();
|
cl = Objects.requireNonNullElse(authenticator, streamProvider).getClass();
|
||||||
}
|
|
||||||
// load the resources
|
// load the resources
|
||||||
loadProviders(cl);
|
loadProviders(cl);
|
||||||
loadAddressMap(cl);
|
loadAddressMap(cl);
|
||||||
|
@ -404,66 +386,6 @@ public final class Session {
|
||||||
return false;
|
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.
|
* Get the stream provider instance of the session.
|
||||||
*
|
*
|
||||||
|
@ -503,7 +425,7 @@ public final class Session {
|
||||||
*/
|
*/
|
||||||
public synchronized Provider getProvider(String protocol) throws NoSuchProviderException {
|
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");
|
throw new NoSuchProviderException("Invalid protocol: null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,7 +734,7 @@ public final class Session {
|
||||||
acl = streamProvider.getClass();
|
acl = streamProvider.getClass();
|
||||||
|
|
||||||
Class<?> serviceClass = null;
|
Class<?> serviceClass = null;
|
||||||
for (ClassLoader l : getClassLoaders(Thread.class,
|
for (ClassLoader l : ResourceLoader.getClassLoaders(Thread.class,
|
||||||
provider.getClass(),
|
provider.getClass(),
|
||||||
acl,
|
acl,
|
||||||
streamProvider.getClass(),
|
streamProvider.getClass(),
|
||||||
|
@ -936,40 +858,30 @@ public final class Session {
|
||||||
* Load the protocol providers config files.
|
* Load the protocol providers config files.
|
||||||
*/
|
*/
|
||||||
private void loadProviders(Class<?> cl) {
|
private void loadProviders(Class<?> cl) {
|
||||||
StreamLoader loader = new StreamLoader() {
|
StreamLoader loader = this::loadProvidersFromStream;
|
||||||
@Override
|
|
||||||
public void load(InputStream is) throws IOException {
|
|
||||||
loadProvidersFromStream(is);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// load system-wide javamail.providers from the
|
// load system-wide javamail.providers from the
|
||||||
// <java.home>/{conf,lib} directory
|
// <java.home>/{conf,lib} directory
|
||||||
if (confDir != null)
|
if (confDir != null) {
|
||||||
loadFile(confDir + "javamail.providers", loader);
|
ResourceLoader.loadFile(confDir + "javamail.providers", loader);
|
||||||
|
}
|
||||||
//Fetch classloader of given class, falling back to others if needed.
|
//Fetch classloader of given class, falling back to others if needed.
|
||||||
ClassLoader gcl;
|
ClassLoader gcl;
|
||||||
ClassLoader[] loaders = getClassLoaders(cl, Thread.class, System.class);
|
ClassLoader[] loaders = ResourceLoader.getClassLoaders(cl, Thread.class, System.class);
|
||||||
if (loaders.length != 0) {
|
if (loaders.length != 0) {
|
||||||
gcl = loaders[0];
|
gcl = loaders[0];
|
||||||
} else {
|
} else {
|
||||||
gcl = getClass().getClassLoader(); //getContextClassLoader(); //Fail safe
|
gcl = getClass().getClassLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
// next, add all the non-default services
|
// next, add all the non-default services
|
||||||
ServiceLoader<Provider> sl = ServiceLoader.load(Provider.class, gcl);
|
ServiceLoader<Provider> sl = ServiceLoader.load(Provider.class, gcl);
|
||||||
for (Provider p : sl) {
|
for (Provider p : sl) {
|
||||||
if (!containsDefaultProvider(p))
|
if (!containsDefaultProvider(p))
|
||||||
addProvider(p);
|
addProvider(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the META-INF/javamail.providers file supplied by an application
|
// 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
|
// 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
|
// finally, add all the default services
|
||||||
sl = ServiceLoader.load(Provider.class, gcl);
|
sl = ServiceLoader.load(Provider.class, gcl);
|
||||||
for (Provider p : sl) {
|
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 {
|
private void loadProvidersFromStream(InputStream is) throws IOException {
|
||||||
if (is != null) {
|
if (is != null) {
|
||||||
LineInputStream lis = streamProvider.inputLineStream(is, false);
|
LineInputStream lis = streamProvider.inputLineStream(is, false);
|
||||||
|
@ -1060,7 +968,7 @@ public final class Session {
|
||||||
|
|
||||||
// check if a valid Provider; else, continue
|
// check if a valid Provider; else, continue
|
||||||
if (type == null || protocol == null || className == null
|
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}",
|
logger.log(Level.CONFIG, "Bad provider entry: {0}",
|
||||||
currLine);
|
currLine);
|
||||||
|
@ -1092,16 +1000,16 @@ public final class Session {
|
||||||
StreamLoader loader = addressMap::load;
|
StreamLoader loader = addressMap::load;
|
||||||
|
|
||||||
// load default META-INF/javamail.default.address.map from mail.jar
|
// 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
|
// 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
|
// load system-wide javamail.address.map from the
|
||||||
// <java.home>/{conf,lib} directory
|
// <java.home>/{conf,lib} directory
|
||||||
if (confDir != null)
|
if (confDir != null) {
|
||||||
loadFile(confDir + "javamail.address.map", loader);
|
ResourceLoader.loadFile(confDir + "javamail.address.map", loader);
|
||||||
|
}
|
||||||
if (addressMap.isEmpty()) {
|
if (addressMap.isEmpty()) {
|
||||||
logger.config("failed to load address map, using defaults");
|
logger.config("failed to load address map, using defaults");
|
||||||
addressMap.put("rfc822", "smtp");
|
addressMap.put("rfc822", "smtp");
|
||||||
|
@ -1126,95 +1034,6 @@ public final class Session {
|
||||||
addressMap.put(addresstype, protocol);
|
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() {
|
EventQueue getEventQueue() {
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,7 @@ package jakarta.mail.internet;
|
||||||
|
|
||||||
public class ContentDisposition {
|
public class ContentDisposition {
|
||||||
|
|
||||||
private static final boolean contentDispositionStrict =
|
private final boolean contentDispositionStrict;
|
||||||
MimeUtility.getBooleanSystemProperty("mail.mime.contentdisposition.strict", true);
|
|
||||||
|
|
||||||
private String disposition; // disposition
|
private String disposition; // disposition
|
||||||
private ParameterList list; // parameter list
|
private ParameterList list; // parameter list
|
||||||
|
@ -36,6 +35,7 @@ public class ContentDisposition {
|
||||||
* No-arg Constructor.
|
* No-arg Constructor.
|
||||||
*/
|
*/
|
||||||
public ContentDisposition() {
|
public ContentDisposition() {
|
||||||
|
contentDispositionStrict = MimeUtility.getBooleanSystemProperty("mail.mime.contentdisposition.strict", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,6 +46,7 @@ public class ContentDisposition {
|
||||||
* @since JavaMail 1.2
|
* @since JavaMail 1.2
|
||||||
*/
|
*/
|
||||||
public ContentDisposition(String disposition, ParameterList list) {
|
public ContentDisposition(String disposition, ParameterList list) {
|
||||||
|
this();
|
||||||
this.disposition = disposition;
|
this.disposition = disposition;
|
||||||
this.list = list;
|
this.list = list;
|
||||||
}
|
}
|
||||||
|
@ -60,9 +61,9 @@ public class ContentDisposition {
|
||||||
* @since JavaMail 1.2
|
* @since JavaMail 1.2
|
||||||
*/
|
*/
|
||||||
public ContentDisposition(String s) throws ParseException {
|
public ContentDisposition(String s) throws ParseException {
|
||||||
|
this();
|
||||||
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
||||||
HeaderTokenizer.Token tk;
|
HeaderTokenizer.Token tk;
|
||||||
|
|
||||||
// First "disposition" ..
|
// First "disposition" ..
|
||||||
tk = h.next();
|
tk = h.next();
|
||||||
if (tk.getType() != HeaderTokenizer.Token.ATOM) {
|
if (tk.getType() != HeaderTokenizer.Token.ATOM) {
|
||||||
|
@ -73,7 +74,6 @@ public class ContentDisposition {
|
||||||
} else {
|
} else {
|
||||||
disposition = tk.getValue();
|
disposition = tk.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then parameters ..
|
// Then parameters ..
|
||||||
String rem = h.getRemainder();
|
String rem = h.getRemainder();
|
||||||
if (rem != null) {
|
if (rem != null) {
|
||||||
|
|
|
@ -39,16 +39,10 @@ import java.util.StringTokenizer;
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class InternetAddress extends Address {
|
public class InternetAddress extends Address {
|
||||||
|
|
||||||
private static final boolean ignoreBogusGroupName =
|
private final boolean ignoreBogusGroupName;
|
||||||
MimeUtility.getBooleanSystemProperty(
|
private final boolean useCanonicalHostName;
|
||||||
"mail.mime.address.ignorebogusgroupname", true);
|
private final boolean allowUtf8;
|
||||||
private static final boolean useCanonicalHostName =
|
private static final String rfc822phrase = HeaderTokenizer.RFC822.replace(' ', '\0').replace('\t', '\0');
|
||||||
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 static final String specialsNoDotNoAt = "()<>,;:\\\"[]";
|
private static final String specialsNoDotNoAt = "()<>,;:\\\"[]";
|
||||||
private static final String specialsNoDot = specialsNoDotNoAt + "@";
|
private static final String specialsNoDot = specialsNoDotNoAt + "@";
|
||||||
/**
|
/**
|
||||||
|
@ -73,6 +67,9 @@ public class InternetAddress extends Address {
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
public InternetAddress() {
|
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
|
* @throws AddressException if the parse failed
|
||||||
*/
|
*/
|
||||||
public InternetAddress(String address) throws AddressException {
|
public InternetAddress(String address) throws AddressException {
|
||||||
|
this();
|
||||||
// use our address parsing utility routine to parse the string
|
// use our address parsing utility routine to parse the string
|
||||||
InternetAddress[] a = parse(address, true);
|
InternetAddress[] a = parse(address, true);
|
||||||
// if we got back anything other than a single address, it's an error
|
// 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
|
* @since JavaMail 1.3
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("this-escape")
|
@SuppressWarnings("this-escape")
|
||||||
public InternetAddress(String address, boolean strict)
|
public InternetAddress(String address, boolean strict) throws AddressException {
|
||||||
throws AddressException {
|
|
||||||
this(address);
|
this(address);
|
||||||
if (strict) {
|
if (strict) {
|
||||||
if (isGroup()) {
|
if (isGroup()) {
|
||||||
|
@ -158,14 +155,14 @@ public class InternetAddress extends Address {
|
||||||
*/
|
*/
|
||||||
public InternetAddress(String address, String personal, String charset)
|
public InternetAddress(String address, String personal, String charset)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException {
|
||||||
|
this();
|
||||||
this.address = address;
|
this.address = address;
|
||||||
setPersonal(personal, charset);
|
setPersonal(personal, charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String quotePhrase(String phrase) {
|
private String quotePhrase(String phrase) {
|
||||||
int len = phrase.length();
|
int len = phrase.length();
|
||||||
boolean needQuoting = false;
|
boolean needQuoting = false;
|
||||||
|
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
char c = phrase.charAt(i);
|
char c = phrase.charAt(i);
|
||||||
if (c == '"' || c == '\\') {
|
if (c == '"' || c == '\\') {
|
||||||
|
@ -186,7 +183,6 @@ public class InternetAddress extends Address {
|
||||||
// These characters cause the string to be quoted
|
// These characters cause the string to be quoted
|
||||||
needQuoting = true;
|
needQuoting = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needQuoting) {
|
if (needQuoting) {
|
||||||
StringBuilder sb = new StringBuilder(len + 2);
|
StringBuilder sb = new StringBuilder(len + 2);
|
||||||
sb.append('"').append(phrase).append('"');
|
sb.append('"').append(phrase).append('"');
|
||||||
|
@ -422,7 +418,8 @@ public class InternetAddress extends Address {
|
||||||
*/
|
*/
|
||||||
public static InternetAddress getLocalAddress(Session session) {
|
public static InternetAddress getLocalAddress(Session session) {
|
||||||
try {
|
try {
|
||||||
return _getLocalAddress(session);
|
InternetAddress internetAddress = new InternetAddress();
|
||||||
|
return internetAddress._getLocalAddress(session);
|
||||||
} catch (AddressException | UnknownHostException sex) { // ignore it
|
} catch (AddressException | UnknownHostException sex) { // ignore it
|
||||||
} // ignore it
|
} // ignore it
|
||||||
return null;
|
return null;
|
||||||
|
@ -433,8 +430,7 @@ public class InternetAddress extends Address {
|
||||||
* the exception. Used by MimeMessage.setFrom() to report the reason
|
* the exception. Used by MimeMessage.setFrom() to report the reason
|
||||||
* for the failure.
|
* for the failure.
|
||||||
*/
|
*/
|
||||||
// package-private
|
InternetAddress _getLocalAddress(Session session)
|
||||||
static InternetAddress _getLocalAddress(Session session)
|
|
||||||
throws AddressException, UnknownHostException {
|
throws AddressException, UnknownHostException {
|
||||||
String user = null, host = null, address = null;
|
String user = null, host = null, address = null;
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
|
@ -453,7 +449,6 @@ public class InternetAddress extends Address {
|
||||||
host = getLocalHostName();
|
host = getLocalHostName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address == null && user != null && user.length() != 0 &&
|
if (address == null && user != null && user.length() != 0 &&
|
||||||
host != null && host.length() != 0)
|
host != null && host.length() != 0)
|
||||||
address = MimeUtility.quote(user.trim(), specialsNoDot + "\t ") +
|
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
|
* Get the local host name from InetAddress and return it in a form
|
||||||
* suitable for use in an email address.
|
* suitable for use in an email address.
|
||||||
*/
|
*/
|
||||||
private static String getLocalHostName() throws UnknownHostException {
|
private String getLocalHostName() throws UnknownHostException {
|
||||||
String host = null;
|
String host = null;
|
||||||
InetAddress me = InetAddress.getLocalHost();
|
InetAddress me = InetAddress.getLocalHost();
|
||||||
if (me != null) {
|
if (me != null) {
|
||||||
|
@ -481,7 +476,7 @@ public class InternetAddress extends Address {
|
||||||
// if we can't get our name, use local address literal
|
// if we can't get our name, use local address literal
|
||||||
if (host == null)
|
if (host == null)
|
||||||
host = me.getHostAddress();
|
host = me.getHostAddress();
|
||||||
if (host != null && host.length() > 0 && isInetAddressLiteral(host))
|
if (host != null && !host.isEmpty() && isInetAddressLiteral(host))
|
||||||
host = '[' + host + ']';
|
host = '[' + host + ']';
|
||||||
}
|
}
|
||||||
return host;
|
return host;
|
||||||
|
@ -951,7 +946,8 @@ public class InternetAddress extends Address {
|
||||||
// ignore bogus "mailto:" prefix in front of an address,
|
// ignore bogus "mailto:" prefix in front of an address,
|
||||||
// or bogus mail header name included in the address field
|
// or bogus mail header name included in the address field
|
||||||
String gname = s.substring(start, index);
|
String gname = s.substring(start, index);
|
||||||
if (ignoreBogusGroupName &&
|
InternetAddress internetAddress = new InternetAddress();
|
||||||
|
if (internetAddress.ignoreBogusGroupName &&
|
||||||
(gname.equalsIgnoreCase("mailto") ||
|
(gname.equalsIgnoreCase("mailto") ||
|
||||||
gname.equalsIgnoreCase("From") ||
|
gname.equalsIgnoreCase("From") ||
|
||||||
gname.equalsIgnoreCase("To") ||
|
gname.equalsIgnoreCase("To") ||
|
||||||
|
@ -991,8 +987,7 @@ public class InternetAddress extends Address {
|
||||||
String addr = s.substring(start, end).trim();
|
String addr = s.substring(start, end).trim();
|
||||||
String pers = null;
|
String pers = null;
|
||||||
if (rfc822 && start_personal >= 0) {
|
if (rfc822 && start_personal >= 0) {
|
||||||
pers = unquote(
|
pers = unquote(s.substring(start_personal, end_personal).trim());
|
||||||
s.substring(start_personal, end_personal).trim());
|
|
||||||
if (pers.trim().isEmpty())
|
if (pers.trim().isEmpty())
|
||||||
pers = null;
|
pers = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,9 +65,8 @@ import java.util.NoSuchElementException;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class InternetHeaders {
|
public class InternetHeaders {
|
||||||
private static final boolean ignoreWhitespaceLines =
|
|
||||||
MimeUtility.getBooleanSystemProperty("mail.mime.ignorewhitespacelines",
|
private final boolean ignoreWhitespaceLines;
|
||||||
false);
|
|
||||||
/**
|
/**
|
||||||
* The actual list of Headers, including placeholder entries.
|
* The actual list of Headers, including placeholder entries.
|
||||||
* Placeholder entries are Headers with a null value and
|
* 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.
|
* are inserted to indicate the preferred order of headers.
|
||||||
*/
|
*/
|
||||||
public InternetHeaders() {
|
public InternetHeaders() {
|
||||||
|
ignoreWhitespaceLines = MimeUtility.getBooleanSystemProperty("mail.mime.ignorewhitespacelines", false);
|
||||||
headers = new ArrayList<>(40);
|
headers = new ArrayList<>(40);
|
||||||
headers.add(new InternetHeader("Return-Path", null));
|
headers.add(new InternetHeader("Return-Path", null));
|
||||||
headers.add(new InternetHeader("Received", null));
|
headers.add(new InternetHeader("Received", null));
|
||||||
|
@ -160,8 +160,8 @@ public class InternetHeaders {
|
||||||
* @since JavaMail 1.6
|
* @since JavaMail 1.6
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("this-escape")
|
@SuppressWarnings("this-escape")
|
||||||
public InternetHeaders(InputStream is, boolean allowutf8)
|
public InternetHeaders(InputStream is, boolean allowutf8) throws MessagingException {
|
||||||
throws MessagingException {
|
ignoreWhitespaceLines = MimeUtility.getBooleanSystemProperty("mail.mime.ignorewhitespacelines", false);
|
||||||
headers = new ArrayList<>(40);
|
headers = new ArrayList<>(40);
|
||||||
load(is, allowutf8);
|
load(is, allowutf8);
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ public class InternetHeaders {
|
||||||
/**
|
/**
|
||||||
* Is this line an empty (blank) line?
|
* 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());
|
return line.isEmpty() || (ignoreWhitespaceLines && line.trim().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,27 +82,13 @@ import java.util.Map;
|
||||||
|
|
||||||
public class MimeBodyPart extends BodyPart implements MimePart {
|
public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
|
|
||||||
// Paranoia:
|
final boolean cacheMultipart;
|
||||||
// allow this last minute change to be disabled if it causes problems
|
private final boolean setDefaultTextCharset;
|
||||||
static final boolean cacheMultipart = // accessed by MimeMessage
|
private final boolean setContentTypeFileName ;
|
||||||
MimeUtility.getBooleanSystemProperty("mail.mime.cachemultipart", true);
|
private final boolean encodeFileName;
|
||||||
// Paranoia:
|
private final boolean decodeFileName;
|
||||||
// allow this last minute change to be disabled if it causes problems
|
private final boolean ignoreMultipartEncoding;
|
||||||
private static final boolean setDefaultTextCharset =
|
private final boolean allowutf8;
|
||||||
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);
|
|
||||||
/**
|
/**
|
||||||
* The DataHandler object representing this Part's content.
|
* The DataHandler object representing this Part's content.
|
||||||
*/
|
*/
|
||||||
|
@ -144,6 +130,8 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
*/
|
*/
|
||||||
protected Object cachedContent;
|
protected Object cachedContent;
|
||||||
|
|
||||||
|
private final MimeUtil mimeUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An empty MimeBodyPart object is created.
|
* An empty MimeBodyPart object is created.
|
||||||
* This body part maybe filled in by a client constructing a multipart
|
* 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() {
|
public MimeBodyPart() {
|
||||||
super();
|
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();
|
headers = new InternetHeaders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,11 +169,18 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
public MimeBodyPart(InputStream is) throws MessagingException {
|
public MimeBodyPart(InputStream is) throws MessagingException {
|
||||||
if (!(is instanceof ByteArrayInputStream) &&
|
if (!(is instanceof ByteArrayInputStream) &&
|
||||||
!(is instanceof BufferedInputStream) &&
|
!(is instanceof BufferedInputStream) &&
|
||||||
!(is instanceof SharedInputStream))
|
!(is instanceof SharedInputStream)) {
|
||||||
is = new BufferedInputStream(is);
|
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);
|
headers = new InternetHeaders(is);
|
||||||
|
|
||||||
if (is instanceof SharedInputStream) {
|
if (is instanceof SharedInputStream) {
|
||||||
SharedInputStream sis = (SharedInputStream) is;
|
SharedInputStream sis = (SharedInputStream) is;
|
||||||
contentStream = sis.newStream(sis.getPosition(), -1);
|
contentStream = sis.newStream(sis.getPosition(), -1);
|
||||||
|
@ -204,6 +207,14 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
public MimeBodyPart(InternetHeaders headers, byte[] content)
|
public MimeBodyPart(InternetHeaders headers, byte[] content)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
super();
|
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.headers = headers;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
}
|
}
|
||||||
|
@ -229,11 +240,12 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
static void setText(MimePart part, String text, String charset,
|
static void setText(MimePart part, String text, String charset,
|
||||||
String subtype) throws MessagingException {
|
String subtype) throws MessagingException {
|
||||||
if (charset == null) {
|
if (charset == null) {
|
||||||
if (MimeUtility.checkAscii(text) != MimeUtility.ALL_ASCII)
|
if (MimeUtility.checkAscii(text) != MimeUtility.ALL_ASCII) {
|
||||||
charset = MimeUtility.getDefaultMIMECharset();
|
charset = MimeUtility.getDefaultMIMECharset();
|
||||||
else
|
} else {
|
||||||
charset = "us-ascii";
|
charset = "us-ascii";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// XXX - should at least ensure that subtype is an atom
|
// XXX - should at least ensure that subtype is an atom
|
||||||
part.setContent(text, "text/" + subtype + "; charset=" +
|
part.setContent(text, "text/" + subtype + "; charset=" +
|
||||||
MimeUtility.quote(charset, HeaderTokenizer.MIME));
|
MimeUtility.quote(charset, HeaderTokenizer.MIME));
|
||||||
|
@ -241,10 +253,9 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
|
|
||||||
static String getDisposition(MimePart part) throws MessagingException {
|
static String getDisposition(MimePart part) throws MessagingException {
|
||||||
String s = part.getHeader("Content-Disposition", null);
|
String s = part.getHeader("Content-Disposition", null);
|
||||||
|
if (s == null) {
|
||||||
if (s == null)
|
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
ContentDisposition cd = new ContentDisposition(s);
|
ContentDisposition cd = new ContentDisposition(s);
|
||||||
return cd.getDisposition();
|
return cd.getDisposition();
|
||||||
}
|
}
|
||||||
|
@ -283,8 +294,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void setDescription(MimePart part, String description, String charset)
|
||||||
setDescription(MimePart part, String description, String charset)
|
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
if (description == null) {
|
if (description == null) {
|
||||||
part.removeHeader("Content-Description");
|
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 filename = null;
|
||||||
String s = part.getHeader("Content-Disposition", null);
|
String s = part.getHeader("Content-Disposition", null);
|
||||||
|
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
// Parse the header ..
|
// Parse the header ..
|
||||||
ContentDisposition cd = new ContentDisposition(s);
|
ContentDisposition cd = new ContentDisposition(s);
|
||||||
|
@ -311,7 +320,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
if (filename == null) {
|
if (filename == null) {
|
||||||
// Still no filename ? Try the "name" ContentType parameter
|
// Still no filename ? Try the "name" ContentType parameter
|
||||||
s = part.getHeader("Content-Type", null);
|
s = part.getHeader("Content-Type", null);
|
||||||
s = MimeUtil.cleanContentType(part, s);
|
s = mimeUtil.cleanContentType(part, s);
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
try {
|
try {
|
||||||
ContentType ct = new ContentType(s);
|
ContentType ct = new ContentType(s);
|
||||||
|
@ -330,7 +339,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setFileName(MimePart part, String name)
|
void setFileName(MimePart part, String name)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
if (encodeFileName && name != null) {
|
if (encodeFileName && name != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -339,11 +348,9 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
throw new MessagingException("Can't encode filename", ex);
|
throw new MessagingException("Can't encode filename", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the Content-Disposition "filename" parameter
|
// Set the Content-Disposition "filename" parameter
|
||||||
String s = part.getHeader("Content-Disposition", null);
|
String s = part.getHeader("Content-Disposition", null);
|
||||||
ContentDisposition cd =
|
ContentDisposition cd = new ContentDisposition(s == null ? Part.ATTACHMENT : s);
|
||||||
new ContentDisposition(s == null ? Part.ATTACHMENT : s);
|
|
||||||
// ensure that the filename is encoded if necessary
|
// ensure that the filename is encoded if necessary
|
||||||
String charset = MimeUtility.getDefaultMIMECharset();
|
String charset = MimeUtility.getDefaultMIMECharset();
|
||||||
ParameterList p = cd.getParameterList();
|
ParameterList p = cd.getParameterList();
|
||||||
|
@ -351,19 +358,19 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
p = new ParameterList();
|
p = new ParameterList();
|
||||||
cd.setParameterList(p);
|
cd.setParameterList(p);
|
||||||
}
|
}
|
||||||
if (encodeFileName)
|
if (encodeFileName) {
|
||||||
p.setLiteral("filename", name);
|
p.setLiteral("filename", name);
|
||||||
else
|
} else {
|
||||||
p.set("filename", name, charset);
|
p.set("filename", name, charset);
|
||||||
|
}
|
||||||
part.setHeader("Content-Disposition", cd.toString());
|
part.setHeader("Content-Disposition", cd.toString());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Also attempt to set the Content-Type "name" parameter,
|
* Also attempt to set the Content-Type "name" parameter,
|
||||||
* to satisfy ancient MUAs. XXX - This is not RFC compliant.
|
* to satisfy ancient MUAs. XXX - This is not RFC compliant.
|
||||||
*/
|
*/
|
||||||
if (setContentTypeFileName) {
|
if (setContentTypeFileName) {
|
||||||
s = part.getHeader("Content-Type", null);
|
s = part.getHeader("Content-Type", null);
|
||||||
s = MimeUtil.cleanContentType(part, s);
|
s = mimeUtil.cleanContentType(part, s);
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
try {
|
try {
|
||||||
ContentType cType = new ContentType(s);
|
ContentType cType = new ContentType(s);
|
||||||
|
@ -373,10 +380,11 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
p = new ParameterList();
|
p = new ParameterList();
|
||||||
cType.setParameterList(p);
|
cType.setParameterList(p);
|
||||||
}
|
}
|
||||||
if (encodeFileName)
|
if (encodeFileName) {
|
||||||
p.setLiteral("name", name);
|
p.setLiteral("name", name);
|
||||||
else
|
} else {
|
||||||
p.set("name", name, charset);
|
p.set("name", name, charset);
|
||||||
|
}
|
||||||
part.setHeader("Content-Type", cType.toString());
|
part.setHeader("Content-Type", cType.toString());
|
||||||
} catch (ParseException pex) {
|
} catch (ParseException pex) {
|
||||||
} // ignore it
|
} // ignore it
|
||||||
|
@ -387,17 +395,14 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
static String[] getContentLanguage(MimePart part)
|
static String[] getContentLanguage(MimePart part)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
String s = part.getHeader("Content-Language", null);
|
String s = part.getHeader("Content-Language", null);
|
||||||
|
if (s == null) {
|
||||||
if (s == null)
|
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
// Tokenize the header to obtain the Language-tags (skip comments)
|
// Tokenize the header to obtain the Language-tags (skip comments)
|
||||||
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
||||||
List<String> v = new ArrayList<>();
|
List<String> v = new ArrayList<>();
|
||||||
|
|
||||||
HeaderTokenizer.Token tk;
|
HeaderTokenizer.Token tk;
|
||||||
int tkType;
|
int tkType;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
tk = h.next(); // get a language-tag
|
tk = h.next(); // get a language-tag
|
||||||
tkType = tk.getType();
|
tkType = tk.getType();
|
||||||
|
@ -408,7 +413,6 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
else // invalid token, skip it.
|
else // invalid token, skip it.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v.isEmpty())
|
if (v.isEmpty())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -479,7 +483,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
* Content-Type of the specified MimePart. Returns
|
* Content-Type of the specified MimePart. Returns
|
||||||
* either the original encoding or null.
|
* either the original encoding or null.
|
||||||
*/
|
*/
|
||||||
static String restrictEncoding(MimePart part, String encoding)
|
String restrictEncoding(MimePart part, String encoding)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
if (!ignoreMultipartEncoding || encoding == null)
|
if (!ignoreMultipartEncoding || encoding == null)
|
||||||
return encoding;
|
return encoding;
|
||||||
|
@ -512,7 +516,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
return encoding;
|
return encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updateHeaders(MimePart part) throws MessagingException {
|
void updateHeaders(MimePart part) throws MessagingException {
|
||||||
DataHandler dh = part.getDataHandler();
|
DataHandler dh = part.getDataHandler();
|
||||||
if (dh == null) // Huh ?
|
if (dh == null) // Huh ?
|
||||||
return;
|
return;
|
||||||
|
@ -659,7 +663,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
part.removeHeader("Content-Transfer-Encoding");
|
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 {
|
throws IOException, MessagingException {
|
||||||
|
|
||||||
// see if we already have a LOS
|
// see if we already have a LOS
|
||||||
|
@ -783,7 +787,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
@Override
|
@Override
|
||||||
public String getContentType() throws MessagingException {
|
public String getContentType() throws MessagingException {
|
||||||
String s = getHeader("Content-Type", null);
|
String s = getHeader("Content-Type", null);
|
||||||
s = MimeUtil.cleanContentType(this, s);
|
s = mimeUtil.cleanContentType(this, s);
|
||||||
if (s == null)
|
if (s == null)
|
||||||
s = "text/plain";
|
s = "text/plain";
|
||||||
return s;
|
return s;
|
||||||
|
@ -1324,8 +1328,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
* @since JavaMail 1.4
|
* @since JavaMail 1.4
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setText(String text, String charset, String subtype)
|
public void setText(String text, String charset, String subtype) throws MessagingException {
|
||||||
throws MessagingException {
|
|
||||||
setText(this, text, charset, subtype);
|
setText(this, text, charset, subtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1338,11 +1341,10 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
* {@link Part#ATTACHMENT Part.ATTACHMENT}.
|
* {@link Part#ATTACHMENT Part.ATTACHMENT}.
|
||||||
*
|
*
|
||||||
* @param file the File object to attach
|
* @param file the File object to attach
|
||||||
* @throws IOException errors related to accessing the file
|
|
||||||
* @throws MessagingException message related errors
|
* @throws MessagingException message related errors
|
||||||
* @since JavaMail 1.4
|
* @since JavaMail 1.4
|
||||||
*/
|
*/
|
||||||
public void attachFile(File file) throws IOException, MessagingException {
|
public void attachFile(File file) throws MessagingException {
|
||||||
FileDataSource fds = new FileDataSource(file);
|
FileDataSource fds = new FileDataSource(file);
|
||||||
this.setDataHandler(new DataHandler(fds));
|
this.setDataHandler(new DataHandler(fds));
|
||||||
this.setFileName(fds.getName());
|
this.setFileName(fds.getName());
|
||||||
|
@ -1379,12 +1381,10 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
* @param file the File object to attach
|
* @param file the File object to attach
|
||||||
* @param contentType the Content-Type, or null
|
* @param contentType the Content-Type, or null
|
||||||
* @param encoding the Content-Transfer-Encoding, or null
|
* @param encoding the Content-Transfer-Encoding, or null
|
||||||
* @throws IOException errors related to accessing the file
|
|
||||||
* @throws MessagingException message related errors
|
* @throws MessagingException message related errors
|
||||||
* @since JavaMail 1.5
|
* @since JavaMail 1.5
|
||||||
*/
|
*/
|
||||||
public void attachFile(File file, String contentType, String encoding)
|
public void attachFile(File file, String contentType, String encoding) throws MessagingException {
|
||||||
throws IOException, MessagingException {
|
|
||||||
DataSource fds = new EncodedFileDataSource(file, contentType, encoding);
|
DataSource fds = new EncodedFileDataSource(file, contentType, encoding);
|
||||||
this.setDataHandler(new DataHandler(fds));
|
this.setDataHandler(new DataHandler(fds));
|
||||||
this.setFileName(fds.getName());
|
this.setFileName(fds.getName());
|
||||||
|
@ -1487,8 +1487,7 @@ public class MimeBodyPart extends BodyPart implements MimePart {
|
||||||
* @throws MessagingException for failures
|
* @throws MessagingException for failures
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getHeader(String name, String delimiter)
|
public String getHeader(String name, String delimiter) throws MessagingException {
|
||||||
throws MessagingException {
|
|
||||||
return headers.getHeader(name, delimiter);
|
return headers.getHeader(name, delimiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,11 +166,15 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
* @since JavaMail 1.5
|
* @since JavaMail 1.5
|
||||||
*/
|
*/
|
||||||
protected Object cachedContent;
|
protected Object cachedContent;
|
||||||
|
|
||||||
// Should addresses in headers be parsed in "strict" mode?
|
// Should addresses in headers be parsed in "strict" mode?
|
||||||
private boolean strict = true;
|
private boolean strict = true;
|
||||||
|
|
||||||
// Is UTF-8 allowed in headers?
|
// Is UTF-8 allowed in headers?
|
||||||
private boolean allowutf8 = false;
|
private boolean allowutf8 = false;
|
||||||
|
|
||||||
|
private final MimeUtil mimeUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor. An empty message object is created.
|
* Default constructor. An empty message object is created.
|
||||||
* The <code>headers</code> field is set to an empty InternetHeaders
|
* 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) {
|
public MimeMessage(Session session) {
|
||||||
super(session);
|
super(session);
|
||||||
|
mimeUtil = new MimeUtil();
|
||||||
modified = true;
|
modified = true;
|
||||||
headers = new InternetHeaders();
|
headers = new InternetHeaders();
|
||||||
flags = new Flags(); // empty flags object
|
flags = new Flags(); // empty flags object
|
||||||
|
@ -204,6 +209,7 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
public MimeMessage(Session session, InputStream is)
|
public MimeMessage(Session session, InputStream is)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
super(session);
|
super(session);
|
||||||
|
mimeUtil = new MimeUtil();
|
||||||
flags = new Flags(); // empty Flags object
|
flags = new Flags(); // empty Flags object
|
||||||
initStrict();
|
initStrict();
|
||||||
parse(is);
|
parse(is);
|
||||||
|
@ -225,6 +231,7 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
@SuppressWarnings("this-escape")
|
@SuppressWarnings("this-escape")
|
||||||
public MimeMessage(MimeMessage source) throws MessagingException {
|
public MimeMessage(MimeMessage source) throws MessagingException {
|
||||||
super(source.session);
|
super(source.session);
|
||||||
|
mimeUtil = new MimeUtil();
|
||||||
flags = source.getFlags();
|
flags = source.getFlags();
|
||||||
if (flags == null) // make sure flags is always set
|
if (flags == null) // make sure flags is always set
|
||||||
flags = new Flags();
|
flags = new Flags();
|
||||||
|
@ -260,6 +267,7 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
*/
|
*/
|
||||||
protected MimeMessage(Folder folder, int msgnum) {
|
protected MimeMessage(Folder folder, int msgnum) {
|
||||||
super(folder, msgnum);
|
super(folder, msgnum);
|
||||||
|
mimeUtil = new MimeUtil();
|
||||||
flags = new Flags(); // empty Flags object
|
flags = new Flags(); // empty Flags object
|
||||||
saved = true;
|
saved = true;
|
||||||
initStrict();
|
initStrict();
|
||||||
|
@ -428,9 +436,9 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setFrom() throws MessagingException {
|
public void setFrom() throws MessagingException {
|
||||||
InternetAddress me = null;
|
InternetAddress me = new InternetAddress();
|
||||||
try {
|
try {
|
||||||
me = InternetAddress._getLocalAddress(session);
|
me = me._getLocalAddress(session);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// if anything goes wrong (UnknownHostException),
|
// if anything goes wrong (UnknownHostException),
|
||||||
// chain the exception
|
// chain the exception
|
||||||
|
@ -982,7 +990,7 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
@Override
|
@Override
|
||||||
public String getContentType() throws MessagingException {
|
public String getContentType() throws MessagingException {
|
||||||
String s = getHeader("Content-Type", null);
|
String s = getHeader("Content-Type", null);
|
||||||
s = MimeUtil.cleanContentType(this, s);
|
s = mimeUtil.cleanContentType(this, s);
|
||||||
if (s == null)
|
if (s == null)
|
||||||
return "text/plain";
|
return "text/plain";
|
||||||
return s;
|
return s;
|
||||||
|
@ -1284,7 +1292,8 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getFileName() throws MessagingException {
|
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
|
@Override
|
||||||
public void setFileName(String filename) throws MessagingException {
|
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)
|
private String getHeaderName(Message.RecipientType type)
|
||||||
|
@ -1475,8 +1485,9 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object getContent() throws IOException, MessagingException {
|
public Object getContent() throws IOException, MessagingException {
|
||||||
if (cachedContent != null)
|
if (cachedContent != null) {
|
||||||
return cachedContent;
|
return cachedContent;
|
||||||
|
}
|
||||||
Object c;
|
Object c;
|
||||||
try {
|
try {
|
||||||
c = getDataHandler().getContent();
|
c = getDataHandler().getContent();
|
||||||
|
@ -1490,7 +1501,8 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (MimeBodyPart.cacheMultipart &&
|
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||||
|
if (mimeBodyPart.cacheMultipart &&
|
||||||
(c instanceof Multipart || c instanceof Message) &&
|
(c instanceof Multipart || c instanceof Message) &&
|
||||||
(content != null || contentStream != null)) {
|
(content != null || contentStream != null)) {
|
||||||
cachedContent = c;
|
cachedContent = c;
|
||||||
|
@ -1498,9 +1510,10 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
* We may abandon the input stream so make sure
|
* We may abandon the input stream so make sure
|
||||||
* the MimeMultipart has consumed the stream.
|
* the MimeMultipart has consumed the stream.
|
||||||
*/
|
*/
|
||||||
if (c instanceof MimeMultipart)
|
if (c instanceof MimeMultipart) {
|
||||||
((MimeMultipart) c).parse();
|
((MimeMultipart) c).parse();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1866,7 +1879,8 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
saveChanges();
|
saveChanges();
|
||||||
|
|
||||||
if (modified) {
|
if (modified) {
|
||||||
MimeBodyPart.writeTo(this, os, ignoreList);
|
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||||
|
mimeBodyPart.writeTo(this, os, ignoreList);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2221,7 +2235,8 @@ public class MimeMessage extends Message implements MimePart {
|
||||||
* @throws MessagingException for other failures
|
* @throws MessagingException for other failures
|
||||||
*/
|
*/
|
||||||
protected synchronized void updateHeaders() throws MessagingException {
|
protected synchronized void updateHeaders() throws MessagingException {
|
||||||
MimeBodyPart.updateHeaders(this);
|
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||||
|
mimeBodyPart.updateHeaders(this);
|
||||||
setHeader("MIME-Version", "1.0");
|
setHeader("MIME-Version", "1.0");
|
||||||
if (getHeader("Date") == null)
|
if (getHeader("Date") == null)
|
||||||
setSentDate(new Date());
|
setSentDate(new Date());
|
||||||
|
|
|
@ -259,18 +259,15 @@ public class MimeMultipart extends Multipart {
|
||||||
@SuppressWarnings("this-escape")
|
@SuppressWarnings("this-escape")
|
||||||
public MimeMultipart(DataSource ds) throws MessagingException {
|
public MimeMultipart(DataSource ds) throws MessagingException {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (ds instanceof MessageAware) {
|
if (ds instanceof MessageAware) {
|
||||||
MessageContext mc = ((MessageAware) ds).getMessageContext();
|
MessageContext mc = ((MessageAware) ds).getMessageContext();
|
||||||
setParent(mc.getPart());
|
setParent(mc.getPart());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ds instanceof MultipartDataSource) {
|
if (ds instanceof MultipartDataSource) {
|
||||||
// ask super to do this for us.
|
// ask super to do this for us.
|
||||||
setMultipartDataSource((MultipartDataSource) ds);
|
setMultipartDataSource((MultipartDataSource) ds);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'ds' was not a MultipartDataSource, we have
|
// 'ds' was not a MultipartDataSource, we have
|
||||||
// to parse this ourself.
|
// to parse this ourself.
|
||||||
parsed = false;
|
parsed = false;
|
||||||
|
@ -327,20 +324,10 @@ public class MimeMultipart extends Multipart {
|
||||||
* @since JavaMail 1.5
|
* @since JavaMail 1.5
|
||||||
*/
|
*/
|
||||||
private void initializeProperties() {
|
private void initializeProperties() {
|
||||||
// read properties that control parsing
|
ignoreMissingEndBoundary = MimeUtility.getBooleanSystemProperty("mail.mime.multipart.ignoremissingendboundary", true);
|
||||||
|
ignoreMissingBoundaryParameter = MimeUtility.getBooleanSystemProperty("mail.mime.multipart.ignoremissingboundaryparameter", true);
|
||||||
// default to true
|
ignoreExistingBoundaryParameter = MimeUtility.getBooleanSystemProperty("mail.mime.multipart.ignoreexistingboundaryparameter", false);
|
||||||
ignoreMissingEndBoundary = MimeUtility.getBooleanSystemProperty(
|
allowEmpty = MimeUtility.getBooleanSystemProperty("mail.mime.multipart.allowempty", false);
|
||||||
"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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -83,8 +83,8 @@ public class MimePartDataSource implements DataSource, MessageAware {
|
||||||
else
|
else
|
||||||
throw new MessagingException("Unknown part");
|
throw new MessagingException("Unknown part");
|
||||||
|
|
||||||
String encoding =
|
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||||
MimeBodyPart.restrictEncoding(part, part.getEncoding());
|
String encoding = mimeBodyPart.restrictEncoding(part, part.getEncoding());
|
||||||
if (encoding != null)
|
if (encoding != null)
|
||||||
return MimeUtility.decode(is, encoding);
|
return MimeUtility.decode(is, encoding);
|
||||||
else
|
else
|
||||||
|
|
|
@ -26,14 +26,14 @@ import java.lang.reflect.Method;
|
||||||
*/
|
*/
|
||||||
class MimeUtil {
|
class MimeUtil {
|
||||||
|
|
||||||
private static final Method cleanContentType;
|
private final Method cleanContentType;
|
||||||
|
|
||||||
static {
|
public MimeUtil() {
|
||||||
Method meth = null;
|
Method meth = null;
|
||||||
try {
|
try {
|
||||||
String cth = System.getProperty("mail.mime.contenttypehandler");
|
String cth = System.getProperty("mail.mime.contenttypehandler");
|
||||||
if (cth != null) {
|
if (cth != null) {
|
||||||
ClassLoader cl = getContextClassLoader();
|
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||||
Class<?> clsHandler = null;
|
Class<?> clsHandler = null;
|
||||||
if (cl != null) {
|
if (cl != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -53,10 +53,6 @@ class MimeUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No one should instantiate this class.
|
|
||||||
private MimeUtil() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a Content-Type handler has been specified,
|
* If a Content-Type handler has been specified,
|
||||||
* call it to clean up the Content-Type value.
|
* call it to clean up the Content-Type value.
|
||||||
|
@ -65,24 +61,14 @@ class MimeUtil {
|
||||||
* @param contentType the Content-Type value
|
* @param contentType the Content-Type value
|
||||||
* @return the cleaned 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) {
|
if (cleanContentType != null) {
|
||||||
try {
|
try {
|
||||||
return (String) cleanContentType.invoke(null,
|
return (String) cleanContentType.invoke(null, new Object[]{mp, contentType});
|
||||||
new Object[]{mp, contentType});
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
return contentType;
|
return contentType;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
return contentType;
|
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.OutputStream;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URL;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -39,6 +40,8 @@ import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a utility class that provides various MIME related
|
* This is a utility class that provides various MIME related
|
||||||
|
@ -134,35 +137,35 @@ import java.util.StringTokenizer;
|
||||||
|
|
||||||
public class MimeUtility {
|
public class MimeUtility {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(MimeUtility.class.getName());
|
||||||
|
|
||||||
public static final int ALL = -1;
|
public static final int ALL = -1;
|
||||||
static final int ALL_ASCII = 1;
|
static final int ALL_ASCII = 1;
|
||||||
static final int MOSTLY_ASCII = 2;
|
static final int MOSTLY_ASCII = 2;
|
||||||
static final int MOSTLY_NONASCII = 3;
|
static final int MOSTLY_NONASCII = 3;
|
||||||
// cached map of whether a charset is compatible with ASCII
|
// cached map of whether a charset is compatible with ASCII
|
||||||
// Map<String,Boolean>
|
// Map<String,Boolean>
|
||||||
private static final Map<String, Boolean> nonAsciiCharsetMap
|
private static final Map<String, Boolean> nonAsciiCharsetMap = new HashMap<>();
|
||||||
= new HashMap<>();
|
|
||||||
private static final String WORD_SPECIALS = "=_?\"#$%&'(),.:;<>@[\\]^`{|}~";
|
private static final String WORD_SPECIALS = "=_?\"#$%&'(),.:;<>@[\\]^`{|}~";
|
||||||
private static final String TEXT_SPECIALS = "=_?";
|
private static final String TEXT_SPECIALS = "=_?";
|
||||||
private static final boolean decodeStrict = getBooleanSystemProperty("mail.mime.decodetext.strict", true);
|
private final boolean decodeStrict;
|
||||||
private static final boolean encodeEolStrict = getBooleanSystemProperty("mail.mime.encodeeol.strict", false);
|
private final boolean encodeEolStrict;
|
||||||
private static final boolean ignoreUnknownEncoding = getBooleanSystemProperty(
|
private final boolean ignoreUnknownEncoding;
|
||||||
"mail.mime.ignoreunknownencoding", false);
|
private final boolean allowUtf8;
|
||||||
private static final boolean allowUtf8 = getBooleanSystemProperty("mail.mime.allowutf8", false);
|
|
||||||
/*
|
/*
|
||||||
* The following two properties allow disabling the fold()
|
* The following two properties allow disabling the fold()
|
||||||
* and unfold() methods and reverting to the previous behavior.
|
* and unfold() methods and reverting to the previous behavior.
|
||||||
* They should never need to be changed and are here only because
|
* They should never need to be changed and are here only because
|
||||||
* of my paranoid concern with compatibility.
|
* of my paranoid concern with compatibility.
|
||||||
*/
|
*/
|
||||||
private static final boolean foldEncodedWords = getBooleanSystemProperty("mail.mime.foldencodedwords", false);
|
private final boolean foldEncodedWords;
|
||||||
private static final boolean foldText = getBooleanSystemProperty("mail.mime.foldtext", true);
|
private final boolean foldText;
|
||||||
private static String defaultJavaCharset;
|
private static String defaultJavaCharset;
|
||||||
private static String defaultMIMECharset;
|
private static String defaultMIMECharset;
|
||||||
// Tables to map MIME charset names to Java names and vice versa.
|
// Tables to map MIME charset names to Java names and vice versa.
|
||||||
// XXX - Should eventually use J2SE 1.4 java.nio.charset.Charset
|
// XXX - Should eventually use J2SE 1.4 java.nio.charset.Charset
|
||||||
private static Map<String, String> mime2java;
|
private static final Map<String, String> mime2java;
|
||||||
private static Map<String, String> java2mime;
|
private static final Map<String, String> java2mime;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
java2mime = new HashMap<>(40);
|
java2mime = new HashMap<>(40);
|
||||||
|
@ -170,29 +173,21 @@ public class MimeUtility {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use this class's classloader to load the mapping file
|
// Use this class's classloader to load the mapping file
|
||||||
// XXX - we should use SecuritySupport, but it's in another package
|
URL url = MimeUtility.class.getClassLoader().getResource("META-INF/javamail.charset.map");
|
||||||
InputStream is =
|
if (url != null) {
|
||||||
MimeUtility.class.getResourceAsStream(
|
try (InputStream is = url.openStream()) {
|
||||||
"/META-INF/javamail.charset.map");
|
|
||||||
|
|
||||||
if (is != null) {
|
|
||||||
try {
|
|
||||||
LineInputStream lineInput = StreamProvider.provider().inputLineStream(is, false);
|
LineInputStream lineInput = StreamProvider.provider().inputLineStream(is, false);
|
||||||
|
|
||||||
// Load the JDK-to-MIME charset mapping table
|
// Load the JDK-to-MIME charset mapping table
|
||||||
loadMappings(lineInput, java2mime);
|
loadMappings(lineInput, java2mime);
|
||||||
|
|
||||||
// Load the MIME-to-JDK charset mapping table
|
// Load the MIME-to-JDK charset mapping table
|
||||||
loadMappings(lineInput, mime2java);
|
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) {
|
} catch (Exception ex) {
|
||||||
|
logger.log(Level.WARNING, ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't load the tables, e.g., because we didn't have
|
// 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() {
|
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
|
* StreamProvider.QUOTED_PRINTABLE_ENCODER or StreamProvider.BASE_64_ENCODER
|
||||||
*/
|
*/
|
||||||
public static String getEncoding(DataSource ds) {
|
public static String getEncoding(DataSource ds) {
|
||||||
ContentType cType = null;
|
ContentType cType;
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
String encoding = null;
|
String encoding;
|
||||||
|
|
||||||
if (ds instanceof EncodingAware) {
|
if (ds instanceof EncodingAware) {
|
||||||
encoding = ((EncodingAware) ds).getEncoding();
|
encoding = ((EncodingAware) ds).getEncoding();
|
||||||
if (encoding != null)
|
if (encoding != null)
|
||||||
|
@ -305,7 +304,6 @@ public class MimeUtility {
|
||||||
try {
|
try {
|
||||||
cType = new ContentType(ds.getContentType());
|
cType = new ContentType(ds.getContentType());
|
||||||
is = ds.getInputStream();
|
is = ds.getInputStream();
|
||||||
|
|
||||||
boolean isText = cType.match("text/*");
|
boolean isText = cType.match("text/*");
|
||||||
// if not text, stop processing when we see non-ASCII
|
// if not text, stop processing when we see non-ASCII
|
||||||
int i = checkAscii(is, ALL, !isText);
|
int i = checkAscii(is, ALL, !isText);
|
||||||
|
@ -359,8 +357,7 @@ public class MimeUtility {
|
||||||
if (bool == null) {
|
if (bool == null) {
|
||||||
try {
|
try {
|
||||||
byte[] b = "\r\n".getBytes(charset);
|
byte[] b = "\r\n".getBytes(charset);
|
||||||
bool = Boolean.valueOf(
|
bool = b.length != 2 || b[0] != 015 || b[1] != 012;
|
||||||
b.length != 2 || b[0] != 015 || b[1] != 012);
|
|
||||||
} catch (UnsupportedEncodingException uex) {
|
} catch (UnsupportedEncodingException uex) {
|
||||||
bool = Boolean.FALSE; // a guess
|
bool = Boolean.FALSE; // a guess
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
|
@ -370,7 +367,7 @@ public class MimeUtility {
|
||||||
nonAsciiCharsetMap.put(charset, bool);
|
nonAsciiCharsetMap.put(charset, bool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bool.booleanValue();
|
return bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -389,8 +386,8 @@ public class MimeUtility {
|
||||||
* @since JavaMail 1.2
|
* @since JavaMail 1.2
|
||||||
*/
|
*/
|
||||||
public static String getEncoding(DataHandler dh) {
|
public static String getEncoding(DataHandler dh) {
|
||||||
ContentType cType = null;
|
ContentType cType ;
|
||||||
String encoding = null;
|
String encoding;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to pick the most efficient means of determining the
|
* Try to pick the most efficient means of determining the
|
||||||
|
@ -422,22 +419,16 @@ public class MimeUtility {
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
// ignore it, can't happen
|
// ignore it, can't happen
|
||||||
}
|
}
|
||||||
switch (aos.getAscii()) {
|
encoding = switch (aos.getAscii()) {
|
||||||
case ALL_ASCII:
|
case ALL_ASCII -> EncoderTypes.BIT7_ENCODER.getEncoder(); // all ascii
|
||||||
encoding = EncoderTypes.BIT7_ENCODER.getEncoder(); // all ascii
|
case MOSTLY_ASCII -> EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder(); // mostly ascii
|
||||||
break;
|
default -> EncoderTypes.BASE_64.getEncoder(); // mostly binary
|
||||||
case MOSTLY_ASCII:
|
};
|
||||||
encoding = EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder(); // mostly ascii
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
encoding = EncoderTypes.BASE_64.getEncoder(); // mostly binary
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else { // not "text"
|
} else { // not "text"
|
||||||
// Check all of available bytes, break out if we find
|
// Check all of available bytes, break out if we find
|
||||||
// at least one non-US-ASCII character
|
// at least one non-US-ASCII character
|
||||||
AsciiOutputStream aos =
|
MimeUtility mimeUtility = new MimeUtility();
|
||||||
new AsciiOutputStream(true, encodeEolStrict);
|
AsciiOutputStream aos = new AsciiOutputStream(true, mimeUtility.encodeEolStrict);
|
||||||
try {
|
try {
|
||||||
dh.writeTo(aos);
|
dh.writeTo(aos);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
@ -468,8 +459,7 @@ public class MimeUtility {
|
||||||
* @return decoded input stream.
|
* @return decoded input stream.
|
||||||
* @throws MessagingException if the encoding is unknown
|
* @throws MessagingException if the encoding is unknown
|
||||||
*/
|
*/
|
||||||
public static InputStream decode(InputStream is, String encoding)
|
public static InputStream decode(InputStream is, String encoding) throws MessagingException {
|
||||||
throws MessagingException {
|
|
||||||
if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder()))
|
if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder()))
|
||||||
return StreamProvider.provider().inputBase64(is);
|
return StreamProvider.provider().inputBase64(is);
|
||||||
else if (encoding.equalsIgnoreCase(EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder()))
|
else if (encoding.equalsIgnoreCase(EncoderTypes.QUOTED_PRINTABLE_ENCODER.getEncoder()))
|
||||||
|
@ -483,7 +473,8 @@ public class MimeUtility {
|
||||||
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder()))
|
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder()))
|
||||||
return StreamProvider.provider().inputBinary(is);
|
return StreamProvider.provider().inputBinary(is);
|
||||||
else {
|
else {
|
||||||
if (!ignoreUnknownEncoding)
|
MimeUtility mimeUtility = new MimeUtility();
|
||||||
|
if (!mimeUtility.ignoreUnknownEncoding)
|
||||||
throw new MessagingException("Unknown encoding: " + encoding);
|
throw new MessagingException("Unknown encoding: " + encoding);
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
@ -501,25 +492,25 @@ public class MimeUtility {
|
||||||
* specified encoding.
|
* specified encoding.
|
||||||
* @throws MessagingException if the encoding is unknown
|
* @throws MessagingException if the encoding is unknown
|
||||||
*/
|
*/
|
||||||
public static OutputStream encode(OutputStream os, String encoding)
|
public static OutputStream encode(OutputStream os, String encoding) throws MessagingException {
|
||||||
throws MessagingException {
|
if (encoding == null) {
|
||||||
if (encoding == null)
|
|
||||||
return os;
|
return os;
|
||||||
else if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder()))
|
} else if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder())) {
|
||||||
return StreamProvider.provider().outputBase64(os);
|
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);
|
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_UU_ENCODER.getEncoder()) ||
|
||||||
encoding.equalsIgnoreCase(EncoderTypes.X_UUE.getEncoder()))
|
encoding.equalsIgnoreCase(EncoderTypes.X_UUE.getEncoder())) {
|
||||||
return StreamProvider.provider().outputUU(os, null);
|
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.BIT7_ENCODER.getEncoder()) ||
|
||||||
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder()))
|
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder())) {
|
||||||
return StreamProvider.provider().outputBinary(os);
|
return StreamProvider.provider().outputBinary(os);
|
||||||
else
|
} else {
|
||||||
throw new MessagingException("Unknown encoding: " + encoding);
|
throw new MessagingException("Unknown encoding: " + encoding);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap an encoder around the given output stream.
|
* Wrap an encoder around the given output stream.
|
||||||
|
@ -538,26 +529,25 @@ public class MimeUtility {
|
||||||
* @throws MessagingException for unknown encodings
|
* @throws MessagingException for unknown encodings
|
||||||
* @since JavaMail 1.2
|
* @since JavaMail 1.2
|
||||||
*/
|
*/
|
||||||
public static OutputStream encode(OutputStream os, String encoding,
|
public static OutputStream encode(OutputStream os, String encoding, String filename) throws MessagingException {
|
||||||
String filename)
|
if (encoding == null) {
|
||||||
throws MessagingException {
|
|
||||||
if (encoding == null)
|
|
||||||
return os;
|
return os;
|
||||||
else if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder()))
|
} else if (encoding.equalsIgnoreCase(EncoderTypes.BASE_64.getEncoder())) {
|
||||||
return StreamProvider.provider().outputBase64(os);
|
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);
|
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_UU_ENCODER.getEncoder()) ||
|
||||||
encoding.equalsIgnoreCase(EncoderTypes.X_UUE.getEncoder()))
|
encoding.equalsIgnoreCase(EncoderTypes.X_UUE.getEncoder())) {
|
||||||
return StreamProvider.provider().outputUU(os, filename);
|
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.BIT7_ENCODER.getEncoder()) ||
|
||||||
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder()))
|
encoding.equalsIgnoreCase(EncoderTypes.BIT8_ENCODER.getEncoder())) {
|
||||||
return StreamProvider.provider().outputBinary(os);
|
return StreamProvider.provider().outputBinary(os);
|
||||||
else
|
} else {
|
||||||
throw new MessagingException("Unknown encoding: " + encoding);
|
throw new MessagingException("Unknown encoding: " + encoding);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode a RFC 822 "text" token into mail-safe form as per
|
* Encode a RFC 822 "text" token into mail-safe form as per
|
||||||
|
@ -666,8 +656,7 @@ public class MimeUtility {
|
||||||
* @throws UnsupportedEncodingException if the charset
|
* @throws UnsupportedEncodingException if the charset
|
||||||
* conversion failed.
|
* conversion failed.
|
||||||
*/
|
*/
|
||||||
public static String decodeText(String etext)
|
public static String decodeText(String etext) throws UnsupportedEncodingException {
|
||||||
throws UnsupportedEncodingException {
|
|
||||||
/*
|
/*
|
||||||
* We look for sequences separated by "linear-white-space".
|
* We look for sequences separated by "linear-white-space".
|
||||||
* (as per RFC 2047, Section 6.1)
|
* (as per RFC 2047, Section 6.1)
|
||||||
|
@ -675,7 +664,6 @@ public class MimeUtility {
|
||||||
*/
|
*/
|
||||||
String lwsp = " \t\n\r";
|
String lwsp = " \t\n\r";
|
||||||
StringTokenizer st;
|
StringTokenizer st;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First, lets do a quick run thru the string and check
|
* First, lets do a quick run thru the string and check
|
||||||
* whether the sequence "=?" exists at all. If none exists,
|
* 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
|
* This handles the most common case of unencoded headers
|
||||||
* efficiently.
|
* efficiently.
|
||||||
*/
|
*/
|
||||||
if (!etext.contains("=?"))
|
if (!etext.contains("=?")) {
|
||||||
return etext;
|
return etext;
|
||||||
|
}
|
||||||
// Encoded words found. Start decoding ...
|
// Encoded words found. Start decoding ...
|
||||||
|
|
||||||
st = new StringTokenizer(etext, lwsp, true);
|
st = new StringTokenizer(etext, lwsp, true);
|
||||||
StringBuilder sb = new StringBuilder(); // decode buffer
|
StringBuilder sb = new StringBuilder(); // decode buffer
|
||||||
StringBuilder wsb = new StringBuilder(); // white space buffer
|
StringBuilder wsb = new StringBuilder(); // white space buffer
|
||||||
boolean prevWasEncoded = false;
|
boolean prevWasEncoded = false;
|
||||||
|
|
||||||
while (st.hasMoreTokens()) {
|
while (st.hasMoreTokens()) {
|
||||||
char c;
|
char c;
|
||||||
String s = st.nextToken();
|
String s = st.nextToken();
|
||||||
// If whitespace, append it to the whitespace buffer
|
// If whitespace, append it to the whitespace buffer
|
||||||
if (((c = s.charAt(0)) == ' ') || (c == '\t') ||
|
if (((c = s.charAt(0)) == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) {
|
||||||
(c == '\r') || (c == '\n'))
|
|
||||||
wsb.append(c);
|
wsb.append(c);
|
||||||
else {
|
} else {
|
||||||
// Check if token is an 'encoded-word' ..
|
// Check if token is an 'encoded-word' ..
|
||||||
String word;
|
String word;
|
||||||
try {
|
try {
|
||||||
word = decodeWord(s);
|
word = decodeWord(s);
|
||||||
// Yes, this IS an 'encoded-word'.
|
// Yes, this IS an 'encoded-word'.
|
||||||
if (!prevWasEncoded && wsb.length() > 0) {
|
if (!prevWasEncoded && !wsb.isEmpty()) {
|
||||||
// if the previous word was also encoded, we
|
// if the previous word was also encoded, we
|
||||||
// should ignore the collected whitespace. Else
|
// should ignore the collected whitespace. Else
|
||||||
// we include the whitespace as well.
|
// we include the whitespace as well.
|
||||||
|
@ -719,17 +704,15 @@ public class MimeUtility {
|
||||||
// This is NOT an 'encoded-word'.
|
// This is NOT an 'encoded-word'.
|
||||||
word = s;
|
word = s;
|
||||||
// possibly decode inner encoded words
|
// possibly decode inner encoded words
|
||||||
if (!decodeStrict) {
|
MimeUtility mimeUtility = new MimeUtility();
|
||||||
|
if (!mimeUtility.decodeStrict) {
|
||||||
String dword = decodeInnerWords(word);
|
String dword = decodeInnerWords(word);
|
||||||
if (dword != word) {
|
if (dword.equals(word)) {
|
||||||
// if a different String object was returned,
|
// if a different String object was returned,
|
||||||
// decoding was done.
|
// decoding was done.
|
||||||
if (prevWasEncoded && word.startsWith("=?")) {
|
if (!prevWasEncoded || !word.startsWith("=?")) {
|
||||||
// encoded followed by encoded,
|
|
||||||
// throw away whitespace between
|
|
||||||
} else {
|
|
||||||
// include collected whitespace ..
|
// include collected whitespace ..
|
||||||
if (wsb.length() > 0)
|
if (!wsb.isEmpty())
|
||||||
sb.append(wsb);
|
sb.append(wsb);
|
||||||
}
|
}
|
||||||
// did original end with encoded?
|
// did original end with encoded?
|
||||||
|
@ -737,14 +720,16 @@ public class MimeUtility {
|
||||||
word = dword;
|
word = dword;
|
||||||
} else {
|
} else {
|
||||||
// include collected whitespace ..
|
// include collected whitespace ..
|
||||||
if (wsb.length() > 0)
|
if (!wsb.isEmpty()) {
|
||||||
sb.append(wsb);
|
sb.append(wsb);
|
||||||
|
}
|
||||||
prevWasEncoded = false;
|
prevWasEncoded = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// include collected whitespace ..
|
// include collected whitespace ..
|
||||||
if (wsb.length() > 0)
|
if (!wsb.isEmpty()) {
|
||||||
sb.append(wsb);
|
sb.append(wsb);
|
||||||
|
}
|
||||||
prevWasEncoded = false;
|
prevWasEncoded = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -804,7 +789,8 @@ public class MimeUtility {
|
||||||
* @return Unicode string containing only US-ASCII characters
|
* @return Unicode string containing only US-ASCII characters
|
||||||
* @throws UnsupportedEncodingException if the encoding fails
|
* @throws UnsupportedEncodingException if the encoding fails
|
||||||
*/
|
*/
|
||||||
public static String encodeWord(String word, String charset,
|
public static String encodeWord(String word,
|
||||||
|
String charset,
|
||||||
String encoding)
|
String encoding)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException {
|
||||||
return encodeWord(word, charset, encoding, true);
|
return encodeWord(word, charset, encoding, true);
|
||||||
|
@ -817,24 +803,26 @@ public class MimeUtility {
|
||||||
* "Q" encoding defined in RFC 2047 has more restrictions when
|
* "Q" encoding defined in RFC 2047 has more restrictions when
|
||||||
* encoding "word" tokens. (Sigh)
|
* encoding "word" tokens. (Sigh)
|
||||||
*/
|
*/
|
||||||
private static String encodeWord(String string, String charset,
|
private static String encodeWord(String string,
|
||||||
String encoding, boolean encodingWord)
|
String charset,
|
||||||
|
String encoding,
|
||||||
|
boolean encodingWord)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException {
|
||||||
|
|
||||||
// If 'string' contains only US-ASCII characters, just
|
// If 'string' contains only US-ASCII characters, just
|
||||||
// return it.
|
// return it.
|
||||||
int ascii = checkAscii(string);
|
int ascii = checkAscii(string);
|
||||||
if (ascii == ALL_ASCII)
|
if (ascii == ALL_ASCII) {
|
||||||
return string;
|
return string;
|
||||||
|
}
|
||||||
// Else, apply the specified charset conversion.
|
// Else, apply the specified charset conversion.
|
||||||
String jcharset;
|
String jcharset;
|
||||||
if (charset == null) { // use default charset
|
if (charset == null) { // use default charset
|
||||||
jcharset = getDefaultJavaCharset(); // the java charset
|
jcharset = getDefaultJavaCharset(); // the java charset
|
||||||
charset = getDefaultMIMECharset(); // the MIME equivalent
|
charset = getDefaultMIMECharset(); // the MIME equivalent
|
||||||
} else // MIME charset -> java charset
|
} else { // MIME charset -> java charset
|
||||||
jcharset = javaCharset(charset);
|
jcharset = javaCharset(charset);
|
||||||
|
}
|
||||||
// If no transfer-encoding is specified, figure one out.
|
// If no transfer-encoding is specified, figure one out.
|
||||||
if (encoding == null) {
|
if (encoding == null) {
|
||||||
if (ascii != MOSTLY_NONASCII)
|
if (ascii != MOSTLY_NONASCII)
|
||||||
|
@ -842,20 +830,17 @@ public class MimeUtility {
|
||||||
else
|
else
|
||||||
encoding = "B";
|
encoding = "B";
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean b64;
|
boolean b64;
|
||||||
if (encoding.equalsIgnoreCase("B"))
|
if (encoding.equalsIgnoreCase("B")) {
|
||||||
b64 = true;
|
b64 = true;
|
||||||
else if (encoding.equalsIgnoreCase("Q"))
|
} else if (encoding.equalsIgnoreCase("Q")) {
|
||||||
b64 = false;
|
b64 = false;
|
||||||
else
|
} else {
|
||||||
throw new UnsupportedEncodingException(
|
throw new UnsupportedEncodingException("Unknown transfer encoding: " + encoding);
|
||||||
"Unknown transfer encoding: " + encoding);
|
}
|
||||||
|
|
||||||
StringBuilder outb = new StringBuilder(); // the output buffer
|
StringBuilder outb = new StringBuilder(); // the output buffer
|
||||||
doEncode(string, b64, jcharset,
|
doEncode(string, b64, jcharset,
|
||||||
// As per RFC 2047, size of an encoded string should not
|
// As per RFC 2047, size of an encoded string should not exceed 75 bytes.
|
||||||
// exceed 75 bytes.
|
|
||||||
// 7 = size of "=?", '?', 'B'/'Q', '?', "?="
|
// 7 = size of "=?", '?', 'B'/'Q', '?', "?="
|
||||||
75 - 7 - charset.length(), // the available space
|
75 - 7 - charset.length(), // the available space
|
||||||
"=?" + charset + "?" + encoding + "?", // prefix
|
"=?" + charset + "?" + encoding + "?", // prefix
|
||||||
|
@ -884,14 +869,15 @@ public class MimeUtility {
|
||||||
private static int qEncodedLength(byte[] b, boolean encodingWord) {
|
private static int qEncodedLength(byte[] b, boolean encodingWord) {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
String specials = encodingWord ? WORD_SPECIALS : TEXT_SPECIALS;
|
String specials = encodingWord ? WORD_SPECIALS : TEXT_SPECIALS;
|
||||||
for (int i = 0; i < b.length; i++) {
|
for (byte value : b) {
|
||||||
int c = b[i] & 0xff; // Mask off MSB
|
int c = value & 0xff; // Mask off MSB
|
||||||
if (c < 040 || c >= 0177 || specials.indexOf(c) >= 0)
|
if (c < 040 || c >= 0177 || specials.indexOf(c) >= 0) {
|
||||||
// needs encoding
|
// needs encoding
|
||||||
len += 3; // Q-encoding is 1 -> 3 conversion
|
len += 3; // Q-encoding is 1 -> 3 conversion
|
||||||
else
|
} else {
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,7 +885,6 @@ public class MimeUtility {
|
||||||
String jcharset, int avail, String prefix,
|
String jcharset, int avail, String prefix,
|
||||||
boolean first, boolean encodingWord, StringBuilder buf)
|
boolean first, boolean encodingWord, StringBuilder buf)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException {
|
||||||
|
|
||||||
// First find out what the length of the encoded version of
|
// First find out what the length of the encoded version of
|
||||||
// 'string' would be.
|
// 'string' would be.
|
||||||
byte[] bytes = string.getBytes(jcharset);
|
byte[] bytes = string.getBytes(jcharset);
|
||||||
|
@ -931,25 +916,26 @@ public class MimeUtility {
|
||||||
} else { // "Q" encoding
|
} else { // "Q" encoding
|
||||||
eos = StreamProvider.provider().outputQ(os, encodingWord);
|
eos = StreamProvider.provider().outputQ(os, encodingWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
try { // do the encoding
|
try { // do the encoding
|
||||||
eos.write(bytes);
|
eos.write(bytes);
|
||||||
eos.close();
|
eos.close();
|
||||||
} catch (IOException ioex) {
|
} catch (IOException ioex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] encodedBytes = os.toByteArray(); // the encoded stuff
|
byte[] encodedBytes = os.toByteArray(); // the encoded stuff
|
||||||
// Now write out the encoded (all ASCII) bytes into our
|
// Now write out the encoded (all ASCII) bytes into our
|
||||||
// StringBuilder
|
// StringBuilder
|
||||||
if (!first) // not the first line of this sequence
|
if (!first) { // not the first line of this sequence
|
||||||
if (foldEncodedWords)
|
MimeUtility mimeUtility = new MimeUtility();
|
||||||
|
if (mimeUtility.foldEncodedWords) {
|
||||||
buf.append("\r\n "); // start a continuation line
|
buf.append("\r\n "); // start a continuation line
|
||||||
else
|
} else {
|
||||||
buf.append(" "); // line will be folded later
|
buf.append(" "); // line will be folded later
|
||||||
|
}
|
||||||
|
}
|
||||||
buf.append(prefix);
|
buf.append(prefix);
|
||||||
for (int i = 0; i < encodedBytes.length; i++)
|
for (byte encodedByte : encodedBytes) {
|
||||||
buf.append((char) encodedBytes[i]);
|
buf.append((char) encodedByte);
|
||||||
|
}
|
||||||
buf.append("?="); // terminate the current sequence
|
buf.append("?="); // terminate the current sequence
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -970,61 +956,47 @@ public class MimeUtility {
|
||||||
*/
|
*/
|
||||||
public static String decodeWord(String eword)
|
public static String decodeWord(String eword)
|
||||||
throws ParseException, UnsupportedEncodingException {
|
throws ParseException, UnsupportedEncodingException {
|
||||||
|
if (!eword.startsWith("=?")) { // not an encoded word
|
||||||
if (!eword.startsWith("=?")) // not an encoded word
|
throw new ParseException("encoded word does not start with \"=?\": " + eword);
|
||||||
throw new ParseException(
|
}
|
||||||
"encoded word does not start with \"=?\": " + eword);
|
|
||||||
|
|
||||||
// get charset
|
// get charset
|
||||||
int start = 2;
|
int start = 2;
|
||||||
int pos;
|
int pos;
|
||||||
if ((pos = eword.indexOf('?', start)) == -1)
|
if ((pos = eword.indexOf('?', start)) == -1) {
|
||||||
throw new ParseException(
|
throw new ParseException("encoded word does not include charset: " + eword);
|
||||||
"encoded word does not include charset: " + eword);
|
}
|
||||||
String charset = eword.substring(start, pos);
|
String charset = eword.substring(start, pos);
|
||||||
int lpos = charset.indexOf('*'); // RFC 2231 language specified?
|
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 = charset.substring(0, lpos);
|
||||||
|
}
|
||||||
charset = javaCharset(charset);
|
charset = javaCharset(charset);
|
||||||
|
|
||||||
// get encoding
|
// get encoding
|
||||||
start = pos + 1;
|
start = pos + 1;
|
||||||
if ((pos = eword.indexOf('?', start)) == -1)
|
if ((pos = eword.indexOf('?', start)) == -1) {
|
||||||
throw new ParseException(
|
throw new ParseException("encoded word does not include encoding: " + eword);
|
||||||
"encoded word does not include encoding: " + eword);
|
}
|
||||||
String encoding = eword.substring(start, pos);
|
String encoding = eword.substring(start, pos);
|
||||||
|
|
||||||
// get encoded-sequence
|
// get encoded-sequence
|
||||||
start = pos + 1;
|
start = pos + 1;
|
||||||
if ((pos = eword.indexOf("?=", start)) == -1)
|
if ((pos = eword.indexOf("?=", start)) == -1) {
|
||||||
throw new ParseException(
|
throw new ParseException("encoded word does not end with \"?=\": " + eword);
|
||||||
"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););
|
|
||||||
*/
|
|
||||||
String word = eword.substring(start, pos);
|
String word = eword.substring(start, pos);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String decodedWord;
|
String decodedWord;
|
||||||
if (word.length() > 0) {
|
if (!word.isEmpty()) {
|
||||||
// Extract the bytes from word
|
// Extract the bytes from word
|
||||||
ByteArrayInputStream bis =
|
ByteArrayInputStream bis = new ByteArrayInputStream(getBytes(word));
|
||||||
new ByteArrayInputStream(getBytes(word));
|
|
||||||
|
|
||||||
// Get the appropriate decoder
|
// Get the appropriate decoder
|
||||||
InputStream is;
|
InputStream is;
|
||||||
if (encoding.equalsIgnoreCase("B"))
|
if (encoding.equalsIgnoreCase("B")) {
|
||||||
is = StreamProvider.provider().inputBase64(bis);
|
is = StreamProvider.provider().inputBase64(bis);
|
||||||
else if (encoding.equalsIgnoreCase("Q"))
|
} else if (encoding.equalsIgnoreCase("Q")) {
|
||||||
is = StreamProvider.provider().inputQ(bis);
|
is = StreamProvider.provider().inputQ(bis);
|
||||||
else
|
} else {
|
||||||
throw new UnsupportedEncodingException(
|
throw new UnsupportedEncodingException("unknown encoding: " + encoding);
|
||||||
"unknown encoding: " + encoding);
|
}
|
||||||
|
|
||||||
// For b64 & q, size of decoded word <= size of word. So
|
// For b64 & q, size of decoded word <= size of word. So
|
||||||
// the decoded bytes must fit into the 'bytes' array. This
|
// the decoded bytes must fit into the 'bytes' array. This
|
||||||
// is certainly more efficient than writing bytes into a
|
// is certainly more efficient than writing bytes into a
|
||||||
|
@ -1034,11 +1006,9 @@ public class MimeUtility {
|
||||||
byte[] bytes = new byte[count];
|
byte[] bytes = new byte[count];
|
||||||
// count is set to the actual number of decoded bytes
|
// count is set to the actual number of decoded bytes
|
||||||
count = is.read(bytes, 0, count);
|
count = is.read(bytes, 0, count);
|
||||||
|
|
||||||
// Finally, convert the decoded bytes into a String using
|
// Finally, convert the decoded bytes into a String using
|
||||||
// the specified charset
|
// the specified charset
|
||||||
decodedWord = count <= 0 ? "" :
|
decodedWord = count <= 0 ? "" : new String(bytes, 0, count, charset);
|
||||||
new String(bytes, 0, count, charset);
|
|
||||||
} else {
|
} else {
|
||||||
// no characters to decode, return empty string
|
// no characters to decode, return empty string
|
||||||
decodedWord = "";
|
decodedWord = "";
|
||||||
|
@ -1046,8 +1016,10 @@ public class MimeUtility {
|
||||||
if (pos + 2 < eword.length()) {
|
if (pos + 2 < eword.length()) {
|
||||||
// there's still more text in the string
|
// there's still more text in the string
|
||||||
String rest = eword.substring(pos + 2);
|
String rest = eword.substring(pos + 2);
|
||||||
if (!decodeStrict)
|
MimeUtility mimeUtility = new MimeUtility();
|
||||||
|
if (!mimeUtility.decodeStrict) {
|
||||||
rest = decodeInnerWords(rest);
|
rest = decodeInnerWords(rest);
|
||||||
|
}
|
||||||
decodedWord += rest;
|
decodedWord += rest;
|
||||||
}
|
}
|
||||||
return decodedWord;
|
return decodedWord;
|
||||||
|
@ -1134,6 +1106,7 @@ public class MimeUtility {
|
||||||
* Look for any "bad" characters, Escape and
|
* Look for any "bad" characters, Escape and
|
||||||
* quote the entire string if necessary.
|
* quote the entire string if necessary.
|
||||||
*/
|
*/
|
||||||
|
MimeUtility mimeUtility = new MimeUtility();
|
||||||
boolean needQuoting = false;
|
boolean needQuoting = false;
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
char c = word.charAt(i);
|
char c = word.charAt(i);
|
||||||
|
@ -1156,7 +1129,7 @@ public class MimeUtility {
|
||||||
}
|
}
|
||||||
sb.append('"');
|
sb.append('"');
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
} else if (c < 040 || (c >= 0177 && !allowUtf8) ||
|
} else if (c < 040 || (c >= 0177 && !mimeUtility.allowUtf8) ||
|
||||||
specials.indexOf(c) >= 0)
|
specials.indexOf(c) >= 0)
|
||||||
// These characters cause the string to be quoted
|
// These characters cause the string to be quoted
|
||||||
needQuoting = true;
|
needQuoting = true;
|
||||||
|
@ -1187,8 +1160,10 @@ public class MimeUtility {
|
||||||
* @since JavaMail 1.4
|
* @since JavaMail 1.4
|
||||||
*/
|
*/
|
||||||
public static String fold(int used, String s) {
|
public static String fold(int used, String s) {
|
||||||
if (!foldText)
|
MimeUtility mimeUtility = new MimeUtility();
|
||||||
|
if (!mimeUtility.foldText) {
|
||||||
return s;
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
int end;
|
int end;
|
||||||
char c;
|
char c;
|
||||||
|
@ -1288,8 +1263,10 @@ public class MimeUtility {
|
||||||
* @since JavaMail 1.4
|
* @since JavaMail 1.4
|
||||||
*/
|
*/
|
||||||
public static String unfold(String s) {
|
public static String unfold(String s) {
|
||||||
if (!foldText)
|
MimeUtility mimeUtility = new MimeUtility();
|
||||||
|
if (!mimeUtility.foldText) {
|
||||||
return s;
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder sb = null;
|
StringBuilder sb = null;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1364,10 +1341,10 @@ public class MimeUtility {
|
||||||
* not available, the passed in charset is itself returned.
|
* not available, the passed in charset is itself returned.
|
||||||
*/
|
*/
|
||||||
public static String javaCharset(String charset) {
|
public static String javaCharset(String charset) {
|
||||||
if (mime2java == null || charset == null)
|
if (mime2java == null || charset == null) {
|
||||||
// no mapping table, or charset parameter is null
|
// no mapping table, or charset parameter is null
|
||||||
return charset;
|
return charset;
|
||||||
|
}
|
||||||
String alias = mime2java.get(charset.toLowerCase(Locale.ENGLISH));
|
String alias = mime2java.get(charset.toLowerCase(Locale.ENGLISH));
|
||||||
if (alias != null) {
|
if (alias != null) {
|
||||||
// verify that the mapped name is valid before trying to use it
|
// verify that the mapped name is valid before trying to use it
|
||||||
|
@ -1394,10 +1371,10 @@ public class MimeUtility {
|
||||||
* @since JavaMail 1.1
|
* @since JavaMail 1.1
|
||||||
*/
|
*/
|
||||||
public static String mimeCharset(String charset) {
|
public static String mimeCharset(String charset) {
|
||||||
if (java2mime == null || charset == null)
|
if (java2mime == null || charset == null) {
|
||||||
// no mapping table or charset param is null
|
// no mapping table or charset param is null
|
||||||
return charset;
|
return charset;
|
||||||
|
}
|
||||||
String alias = java2mime.get(charset.toLowerCase(Locale.ENGLISH));
|
String alias = java2mime.get(charset.toLowerCase(Locale.ENGLISH));
|
||||||
return alias == null ? charset : alias;
|
return alias == null ? charset : alias;
|
||||||
}
|
}
|
||||||
|
@ -1420,11 +1397,10 @@ public class MimeUtility {
|
||||||
*/
|
*/
|
||||||
String mimecs = System.getProperty("mail.mime.charset");
|
String mimecs = System.getProperty("mail.mime.charset");
|
||||||
if (mimecs != null && !mimecs.isEmpty()) {
|
if (mimecs != null && !mimecs.isEmpty()) {
|
||||||
defaultJavaCharset = javaCharset(mimecs);
|
defaultJavaCharset = javaCharset(mimecs.toUpperCase(Locale.ROOT));
|
||||||
return defaultJavaCharset;
|
return defaultJavaCharset;
|
||||||
}
|
}
|
||||||
defaultJavaCharset = System.getProperty("file.encoding",
|
defaultJavaCharset = System.getProperty("file.encoding", "8859_1");
|
||||||
"8859_1");
|
|
||||||
}
|
}
|
||||||
return defaultJavaCharset;
|
return defaultJavaCharset;
|
||||||
}
|
}
|
||||||
|
@ -1436,32 +1412,29 @@ public class MimeUtility {
|
||||||
if (defaultMIMECharset == null) {
|
if (defaultMIMECharset == null) {
|
||||||
defaultMIMECharset = System.getProperty("mail.mime.charset");
|
defaultMIMECharset = System.getProperty("mail.mime.charset");
|
||||||
}
|
}
|
||||||
if (defaultMIMECharset == null)
|
if (defaultMIMECharset == null) {
|
||||||
defaultMIMECharset = mimeCharset(getDefaultJavaCharset());
|
defaultMIMECharset = mimeCharset(getDefaultJavaCharset());
|
||||||
return defaultMIMECharset;
|
}
|
||||||
|
return defaultMIMECharset.toUpperCase(Locale.ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadMappings(LineInputStream is,
|
private static void loadMappings(LineInputStream is,
|
||||||
Map<String, String> table) {
|
Map<String, String> table) {
|
||||||
String currLine;
|
String currLine;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
currLine = is.readLine();
|
currLine = is.readLine();
|
||||||
} catch (IOException ioex) {
|
} catch (IOException ioex) {
|
||||||
break; // error in reading, stop
|
break; // error in reading, stop
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currLine == null) // end of file, stop
|
if (currLine == null) // end of file, stop
|
||||||
break;
|
break;
|
||||||
if (currLine.startsWith("--") && currLine.endsWith("--"))
|
if (currLine.startsWith("--") && currLine.endsWith("--"))
|
||||||
// end of this table
|
// end of this table
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// ignore empty lines and comments
|
// ignore empty lines and comments
|
||||||
if (currLine.trim().length() == 0 || currLine.startsWith("#"))
|
if (currLine.trim().isEmpty() || currLine.startsWith("#"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// A valid entry is of the form <key><separator><value>
|
// A valid entry is of the form <key><separator><value>
|
||||||
// where, <separator> := SPACE | HT. Parse this
|
// where, <separator> := SPACE | HT. Parse this
|
||||||
StringTokenizer tk = new StringTokenizer(currLine, " \t");
|
StringTokenizer tk = new StringTokenizer(currLine, " \t");
|
||||||
|
@ -1561,7 +1534,8 @@ public class MimeUtility {
|
||||||
int block = 4096;
|
int block = 4096;
|
||||||
int linelen = 0;
|
int linelen = 0;
|
||||||
boolean longLine = false, badEOL = false;
|
boolean longLine = false, badEOL = false;
|
||||||
boolean checkEOL = encodeEolStrict && breakOnNonAscii;
|
MimeUtility mimeUtility = new MimeUtility();
|
||||||
|
boolean checkEOL = mimeUtility.encodeEolStrict && breakOnNonAscii;
|
||||||
byte[] buf = null;
|
byte[] buf = null;
|
||||||
if (max != 0) {
|
if (max != 0) {
|
||||||
block = (max == ALL) ? 4096 : Math.min(max, 4096);
|
block = (max == ALL) ? 4096 : Math.min(max, 4096);
|
||||||
|
@ -1632,7 +1606,7 @@ public class MimeUtility {
|
||||||
return MOSTLY_NONASCII;
|
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');
|
return b >= 0177 || (b < 040 && b != '\r' && b != '\n' && b != '\t');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1696,31 +1670,43 @@ public class MimeUtility {
|
||||||
*/
|
*/
|
||||||
private static Object getProp(Properties props, String name) {
|
private static Object getProp(Properties props, String name) {
|
||||||
Object val = props.get(name);
|
Object val = props.get(name);
|
||||||
if (val != null)
|
if (val != null) {
|
||||||
return val;
|
return val;
|
||||||
else
|
} else {
|
||||||
return props.getProperty(name);
|
return props.getProperty(name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interpret the value object as a boolean,
|
* Interpret the value object as a boolean,
|
||||||
* returning def if unable.
|
* returning def if unable.
|
||||||
*/
|
*/
|
||||||
private static boolean getBoolean(Object value, boolean def) {
|
private static boolean getBoolean(Object value, boolean def) {
|
||||||
if (value == null)
|
switch (value) {
|
||||||
|
case null -> {
|
||||||
return def;
|
return def;
|
||||||
if (value instanceof String) {
|
}
|
||||||
|
case String s -> {
|
||||||
/*
|
/*
|
||||||
* If the default is true, only "false" turns it off.
|
* If the default is true, only "false" turns it off.
|
||||||
* If the default is false, only "true" turns it on.
|
* If the default is false, only "true" turns it on.
|
||||||
*/
|
*/
|
||||||
if (def)
|
if (def) {
|
||||||
return !((String) value).equalsIgnoreCase("false");
|
return !((String) value).equalsIgnoreCase("false");
|
||||||
else
|
} else {
|
||||||
return ((String) value).equalsIgnoreCase("true");
|
return ((String) value).equalsIgnoreCase("true");
|
||||||
}
|
}
|
||||||
if (value instanceof Boolean)
|
/*
|
||||||
return (Boolean) value;
|
* 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 -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1730,7 +1716,7 @@ public class MimeUtility {
|
||||||
* it is all ASCII, mostly ASCII, or mostly non-ASCII.
|
* it is all ASCII, mostly ASCII, or mostly non-ASCII.
|
||||||
*/
|
*/
|
||||||
class AsciiOutputStream extends OutputStream {
|
class AsciiOutputStream extends OutputStream {
|
||||||
private boolean breakOnNonAscii;
|
private final boolean breakOnNonAscii;
|
||||||
private int ascii = 0, non_ascii = 0;
|
private int ascii = 0, non_ascii = 0;
|
||||||
private int linelen = 0;
|
private int linelen = 0;
|
||||||
private boolean longLine = false;
|
private boolean longLine = false;
|
||||||
|
|
|
@ -60,22 +60,14 @@ import java.util.Set;
|
||||||
|
|
||||||
public class ParameterList {
|
public class ParameterList {
|
||||||
|
|
||||||
private static final boolean encodeParameters =
|
private final boolean encodeParameters;
|
||||||
MimeUtility.getBooleanSystemProperty("mail.mime.encodeparameters", true);
|
private final boolean decodeParameters;
|
||||||
private static final boolean decodeParameters =
|
private final boolean decodeParametersStrict;
|
||||||
MimeUtility.getBooleanSystemProperty("mail.mime.decodeparameters", true);
|
private final boolean applehack;;
|
||||||
private static final boolean decodeParametersStrict =
|
private final boolean windowshack;
|
||||||
MimeUtility.getBooleanSystemProperty(
|
private final boolean parametersStrict;
|
||||||
"mail.mime.decodeparameters.strict", false);
|
private final boolean splitLongParameters;
|
||||||
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 static final char[] hex = {
|
private static final char[] hex = {
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||||
|
@ -94,7 +86,7 @@ public class ParameterList {
|
||||||
* will all move to the end.
|
* will all move to the end.
|
||||||
*/
|
*/
|
||||||
// keep parameters in order
|
// 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
|
* A set of names for multi-segment parameters that we
|
||||||
* haven't processed yet. Normally such names are accumulated
|
* haven't processed yet. Normally such names are accumulated
|
||||||
|
@ -136,21 +128,23 @@ public class ParameterList {
|
||||||
* combineMultisegmentNames method.
|
* combineMultisegmentNames method.
|
||||||
*/
|
*/
|
||||||
private Map<String, Object> slist;
|
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.
|
* No-arg Constructor.
|
||||||
*/
|
*/
|
||||||
public ParameterList() {
|
public ParameterList() {
|
||||||
// initialize other collections only if they'll be needed
|
// 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) {
|
if (decodeParameters) {
|
||||||
multisegmentNames = new HashSet<>();
|
multisegmentNames = new HashSet<>();
|
||||||
slist = new HashMap<>();
|
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 {
|
public ParameterList(String s) throws ParseException {
|
||||||
this();
|
this();
|
||||||
|
|
||||||
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
||||||
for (; ; ) {
|
for (; ; ) {
|
||||||
HeaderTokenizer.Token tk = h.next();
|
HeaderTokenizer.Token tk = h.next();
|
||||||
|
@ -175,6 +168,11 @@ public class ParameterList {
|
||||||
if (type == HeaderTokenizer.Token.EOF) // done
|
if (type == HeaderTokenizer.Token.EOF) // done
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MWB 3BView: The name of the last parameter added to the map.
|
||||||
|
* Used for the AppleMail hack.
|
||||||
|
*/
|
||||||
|
String lastName = null;
|
||||||
if ((char) type == ';') {
|
if ((char) type == ';') {
|
||||||
// expect parameter name
|
// expect parameter name
|
||||||
tk = h.next();
|
tk = h.next();
|
||||||
|
@ -294,7 +292,7 @@ public class ParameterList {
|
||||||
* Extract charset and encoded value.
|
* Extract charset and encoded value.
|
||||||
* Value will be decoded later.
|
* Value will be decoded later.
|
||||||
*/
|
*/
|
||||||
private static Value extractCharset(String value) throws ParseException {
|
private Value extractCharset(String value) throws ParseException {
|
||||||
Value v = new Value();
|
Value v = new Value();
|
||||||
v.value = v.encodedValue = value;
|
v.value = v.encodedValue = value;
|
||||||
try {
|
try {
|
||||||
|
@ -326,7 +324,7 @@ public class ParameterList {
|
||||||
/**
|
/**
|
||||||
* Decode the encoded bytes in value using the specified charset.
|
* 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 {
|
throws ParseException, UnsupportedEncodingException {
|
||||||
/*
|
/*
|
||||||
* Decode the ASCII characters in value
|
* 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.
|
* 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 {
|
throws ParseException, IOException {
|
||||||
/*
|
/*
|
||||||
* Decode the ASCII characters in value
|
* 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.internet;
|
||||||
exports jakarta.mail.search;
|
exports jakarta.mail.search;
|
||||||
exports jakarta.mail.util;
|
exports jakarta.mail.util;
|
||||||
|
exports org.xbib.net.activation;
|
||||||
exports org.xbib.net.mail.handlers;
|
exports org.xbib.net.mail.handlers;
|
||||||
exports org.xbib.net.mail.iap;
|
exports org.xbib.net.mail.iap;
|
||||||
exports org.xbib.net.mail.imap;
|
exports org.xbib.net.mail.imap;
|
||||||
|
@ -25,8 +26,10 @@ module org.xbib.net.mail {
|
||||||
uses jakarta.activation.spi.MimeTypeRegistryProvider;
|
uses jakarta.activation.spi.MimeTypeRegistryProvider;
|
||||||
uses jakarta.mail.Provider;
|
uses jakarta.mail.Provider;
|
||||||
uses jakarta.mail.util.StreamProvider;
|
uses jakarta.mail.util.StreamProvider;
|
||||||
provides jakarta.mail.util.StreamProvider with
|
provides jakarta.activation.spi.MailcapRegistryProvider with
|
||||||
org.xbib.net.mail.util.MailStreamProvider;
|
org.xbib.net.activation.MailcapRegistryProviderImpl;
|
||||||
|
provides jakarta.activation.spi.MimeTypeRegistryProvider with
|
||||||
|
org.xbib.net.activation.MimeTypeRegistryProviderImpl;
|
||||||
provides jakarta.mail.Provider with
|
provides jakarta.mail.Provider with
|
||||||
org.xbib.net.mail.imap.IMAPProvider,
|
org.xbib.net.mail.imap.IMAPProvider,
|
||||||
org.xbib.net.mail.imap.IMAPSSLProvider,
|
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.smtp.SMTPSSLProvider,
|
||||||
org.xbib.net.mail.pop3.POP3Provider,
|
org.xbib.net.mail.pop3.POP3Provider,
|
||||||
org.xbib.net.mail.pop3.POP3SSLProvider;
|
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();
|
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 associated with this connection, if any.
|
||||||
*
|
*
|
||||||
* @return the SocketChannel
|
* @return the SocketChannel
|
||||||
* @since JavaMail 1.5.2
|
* @since JavaMail 1.5.2
|
||||||
*/
|
*/
|
||||||
public SocketChannel getChannel() {
|
public SocketChannel _getChannel() {
|
||||||
//SocketFetcher controls if a socket has a channel via
|
//SocketFetcher controls if a socket has a channel via
|
||||||
//usesocketchannels property. When the socket is known to not have
|
//usesocketchannels property. When the socket is known to not have
|
||||||
//a channel this guard ensures that the reflective search for a socket
|
//a channel this guard ensures that the reflective search for a socket
|
||||||
|
@ -541,13 +546,17 @@ public class Protocol {
|
||||||
prefix + ".usesocketchannels", false)) {
|
prefix + ".usesocketchannels", false)) {
|
||||||
SocketChannel ret = socket.getChannel();
|
SocketChannel ret = socket.getChannel();
|
||||||
if (ret == null && socket instanceof SSLSocket) {
|
if (ret == null && socket instanceof SSLSocket) {
|
||||||
ret = Protocol.findSocketChannel(socket);
|
ret = findSocketChannel(socket);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static SocketChannel findSocketChannel(Socket socket) {
|
||||||
|
return socket.getChannel();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Android/Conscrypt is broken and SSL wrapped sockets don't delegate
|
* Android/Conscrypt is broken and SSL wrapped sockets don't delegate
|
||||||
* the getChannel method to the wrapped Socket. This method attempts to
|
* 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
|
* @return the SocketChannel or null if not found
|
||||||
* @throws NullPointerException if given socket is null
|
* @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.
|
//Search class hierarchy for field name socket regardless of modifier.
|
||||||
//Old versions of Android and even versions of Conscrypt use this name.
|
//Old versions of Android and even versions of Conscrypt use this name.
|
||||||
for (Class<?> k = socket.getClass(); k != Object.class; k = k.getSuperclass()) {
|
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 {
|
public class LineInputStream extends FilterInputStream implements jakarta.mail.util.LineInputStream {
|
||||||
|
|
||||||
private static boolean defaultutf8 =
|
private final boolean defaultutf8;
|
||||||
PropUtil.getBooleanSystemProperty("mail.mime.allowutf8", false);
|
|
||||||
private static int MAX_INCR = 1024 * 1024; // 1MB
|
private static int MAX_INCR = 1024 * 1024; // 1MB
|
||||||
private boolean allowutf8;
|
private boolean allowutf8;
|
||||||
private byte[] lineBuffer = null; // reusable byte buffer
|
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) {
|
public LineInputStream(InputStream in, boolean allowutf8) {
|
||||||
super(in);
|
super(in);
|
||||||
|
this.defaultutf8 = PropUtil.getBooleanSystemProperty("mail.mime.allowutf8", false);
|
||||||
this.allowutf8 = allowutf8;
|
this.allowutf8 = allowutf8;
|
||||||
if (!allowutf8 && defaultutf8) {
|
if (!allowutf8 && defaultutf8) {
|
||||||
decoder = StandardCharsets.UTF_8.newDecoder();
|
decoder = StandardCharsets.UTF_8.newDecoder();
|
||||||
|
|
|
@ -16,11 +16,9 @@
|
||||||
|
|
||||||
package org.xbib.net.mail.util;
|
package org.xbib.net.mail.util;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
@ -28,7 +26,6 @@ import java.net.SocketAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.SocketOption;
|
import java.net.SocketOption;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
@ -52,7 +49,7 @@ public class WriteTimeoutSocket extends Socket {
|
||||||
// the timeout, in milliseconds
|
// the timeout, in milliseconds
|
||||||
private final int timeout;
|
private final int timeout;
|
||||||
|
|
||||||
public WriteTimeoutSocket(Socket socket, int timeout) throws IOException {
|
public WriteTimeoutSocket(Socket socket, int timeout) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
// XXX - could share executor with all instances?
|
// XXX - could share executor with all instances?
|
||||||
this.ses = createScheduledThreadPool();
|
this.ses = createScheduledThreadPool();
|
||||||
|
@ -60,14 +57,14 @@ public class WriteTimeoutSocket extends Socket {
|
||||||
this.timeout = timeout;
|
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.socket = socket;
|
||||||
this.ses = ses;
|
this.ses = ses;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.isExternalSes = true;
|
this.isExternalSes = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WriteTimeoutSocket(int timeout) throws IOException {
|
public WriteTimeoutSocket(int timeout) {
|
||||||
this(new Socket(), timeout);
|
this(new Socket(), timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,50 +310,19 @@ public class WriteTimeoutSocket extends Socket {
|
||||||
return socket.isOutputShutdown();
|
return socket.isOutputShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
@Override
|
||||||
* 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
|
|
||||||
public <T> Socket setOption(SocketOption<T> so, T val) throws IOException {
|
public <T> Socket setOption(SocketOption<T> so, T val) throws IOException {
|
||||||
// socket.setOption(so, val);
|
return socket.setOption(so, val);
|
||||||
// return this;
|
|
||||||
throw new UnsupportedOperationException("WriteTimeoutSocket.setOption");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Override
|
@Override
|
||||||
public <T> T getOption(SocketOption<T> so) throws IOException {
|
public <T> T getOption(SocketOption<T> so) throws IOException {
|
||||||
// return socket.getOption(so);
|
return socket.getOption(so);
|
||||||
throw new UnsupportedOperationException("WriteTimeoutSocket.getOption");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Override
|
@Override
|
||||||
public Set<SocketOption<?>> supportedOptions() {
|
public Set<SocketOption<?>> supportedOptions() {
|
||||||
// return socket.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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScheduledThreadPoolExecutor createScheduledThreadPool() {
|
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.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
@ -39,10 +38,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
final class ProtocolTest {
|
final class ProtocolTest {
|
||||||
|
|
||||||
private static final byte[] noBytes = new byte[0];
|
private static final byte[] noBytes = new byte[0];
|
||||||
private static final PrintStream nullps =
|
|
||||||
new PrintStream(new NullOutputStream());
|
private static final PrintStream nullps = new PrintStream(new NullOutputStream());
|
||||||
private static final ByteArrayInputStream nullis =
|
|
||||||
new ByteArrayInputStream(noBytes);
|
private static final ByteArrayInputStream nullis = new ByteArrayInputStream(noBytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that the tag prefix is computed properly.
|
* Test that the tag prefix is computed properly.
|
||||||
|
@ -73,8 +72,7 @@ final class ProtocolTest {
|
||||||
private String newProtocolTag() throws IOException, ProtocolException {
|
private String newProtocolTag() throws IOException, ProtocolException {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
Protocol p = new Protocol(nullis, nullps, props, false);
|
Protocol p = new Protocol(nullis, nullps, props, false);
|
||||||
String tag = p.writeCommand("CMD", null);
|
return p.writeCommand("CMD", null);
|
||||||
return tag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,7 +94,7 @@ final class ProtocolTest {
|
||||||
public void testLayer1Socket() throws IOException {
|
public void testLayer1Socket() throws IOException {
|
||||||
try (LayerAbstractSocket s = new Layer1of5()) {
|
try (LayerAbstractSocket s = new Layer1of5()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertTrue(s.foundChannel());
|
assertFalse(s.foundChannel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +102,7 @@ final class ProtocolTest {
|
||||||
public void testLayer2Socket() throws IOException {
|
public void testLayer2Socket() throws IOException {
|
||||||
try (LayerAbstractSocket s = new Layer2of5()) {
|
try (LayerAbstractSocket s = new Layer2of5()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertTrue(s.foundChannel());
|
assertFalse(s.foundChannel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +110,7 @@ final class ProtocolTest {
|
||||||
public void testLayer3Socket() throws IOException {
|
public void testLayer3Socket() throws IOException {
|
||||||
try (LayerAbstractSocket s = new Layer3of5()) {
|
try (LayerAbstractSocket s = new Layer3of5()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertTrue(s.foundChannel());
|
assertFalse(s.foundChannel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,53 +118,52 @@ final class ProtocolTest {
|
||||||
public void testLayer4Socket() throws IOException {
|
public void testLayer4Socket() throws IOException {
|
||||||
try (LayerAbstractSocket s = new Layer4of5()) {
|
try (LayerAbstractSocket s = new Layer4of5()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertTrue(s.foundChannel());
|
assertFalse(s.foundChannel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLayer5Socket() throws IOException, ProtocolException {
|
public void testLayer5Socket() throws IOException {
|
||||||
try (LayerAbstractSocket s = new Layer5of5()) {
|
try (LayerAbstractSocket s = new Layer5of5()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertTrue(s.foundChannel());
|
assertFalse(s.foundChannel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRenamed1Socket() throws IOException, ProtocolException {
|
public void testRenamed1Socket() throws IOException {
|
||||||
try (RenamedAbstractSocket s = new RenamedSocketLayer1of3()) {
|
try (RenamedAbstractSocket s = new RenamedSocketLayer1of3()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertTrue(s.foundChannel());
|
assertFalse(s.foundChannel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRenamed2Socket() throws IOException, ProtocolException {
|
public void testRenamed2Socket() throws IOException {
|
||||||
try (RenamedAbstractSocket s = new RenamedSocketLayer2of3()) {
|
try (RenamedAbstractSocket s = new RenamedSocketLayer2of3()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertTrue(s.foundChannel());
|
assertFalse(s.foundChannel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRenamed3Socket() throws IOException, ProtocolException {
|
public void testRenamed3Socket() throws IOException {
|
||||||
try (RenamedAbstractSocket s = new RenamedSocketLayer3of3()) {
|
try (RenamedAbstractSocket s = new RenamedSocketLayer3of3()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertTrue(s.foundChannel());
|
assertFalse(s.foundChannel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNullSocketsRenamed() throws IOException, ProtocolException {
|
public void testNullSocketsRenamed() throws IOException {
|
||||||
try (RenamedAbstractSocket s = new NullSocketsRenamedSocket()) {
|
try (RenamedAbstractSocket s = new NullSocketsRenamedSocket()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertTrue(s.foundChannel());
|
assertFalse(s.foundChannel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHidden1Socket() throws IOException, ProtocolException {
|
public void testHidden1Socket() throws IOException {
|
||||||
try (HiddenAbstractSocket s = new HiddenSocket1of2()) {
|
try (HiddenAbstractSocket s = new HiddenSocket1of2()) {
|
||||||
//This could be implemented to find the socket.
|
//This could be implemented to find the socket.
|
||||||
//However, we would have fetch field value to inspect the object.
|
//However, we would have fetch field value to inspect the object.
|
||||||
|
@ -178,7 +175,7 @@ final class ProtocolTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHidden2Socket() throws IOException, ProtocolException {
|
public void testHidden2Socket() throws IOException {
|
||||||
try (HiddenAbstractSocket s = new HiddenSocket2of2()) {
|
try (HiddenAbstractSocket s = new HiddenSocket2of2()) {
|
||||||
//This could be implemented to find the socket.
|
//This could be implemented to find the socket.
|
||||||
//However, we would have fetch field value to inspect the object.
|
//However, we would have fetch field value to inspect the object.
|
||||||
|
@ -202,7 +199,7 @@ final class ProtocolTest {
|
||||||
public void testSelfNamedSocket() throws IOException {
|
public void testSelfNamedSocket() throws IOException {
|
||||||
try (WrappedSocket s = new SelfNamedSocket()) {
|
try (WrappedSocket s = new SelfNamedSocket()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertFalse(WrappedSocket.foundChannel(s));
|
assertTrue(WrappedSocket.foundChannel(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,20 +208,12 @@ final class ProtocolTest {
|
||||||
public void testSelfHiddenSocket() throws IOException {
|
public void testSelfHiddenSocket() throws IOException {
|
||||||
try (WrappedSocket s = new SelfHiddenSocket()) {
|
try (WrappedSocket s = new SelfHiddenSocket()) {
|
||||||
findSocketChannel(s);
|
findSocketChannel(s);
|
||||||
assertFalse(WrappedSocket.foundChannel(s));
|
assertTrue(WrappedSocket.foundChannel(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SocketChannel findSocketChannel(Socket s) throws IOException {
|
private static void findSocketChannel(Socket s) {
|
||||||
try {
|
s.getChannel();
|
||||||
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 class RenamedSocketLayer3of3 extends RenamedSocketLayer1of3 {
|
private static class RenamedSocketLayer3of3 extends RenamedSocketLayer1of3 {
|
||||||
|
@ -245,11 +234,12 @@ final class ProtocolTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class NullSocketsRenamedSocket extends RenamedAbstractSocket {
|
private static class NullSocketsRenamedSocket extends RenamedAbstractSocket {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private Socket tekcos;
|
private Socket tekcos;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Layer5of5 extends Layer4of5 {
|
private static class Layer5of5 extends Layer4of5 {
|
||||||
|
@ -285,32 +275,32 @@ final class ProtocolTest {
|
||||||
private final Socket hidden = this;
|
private final Socket hidden = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class HiddenSocket2of2 extends HiddenSocket1of2 {
|
private static class HiddenSocket2of2 extends HiddenSocket1of2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class HiddenSocket1of2 extends HiddenAbstractSocket {
|
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 {
|
private static class NamedNullAndHiddenSocket extends HiddenAbstractSocket {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private Socket socket;
|
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 static class WrappedSocket extends Socket {
|
||||||
|
|
||||||
private boolean found;
|
private boolean found;
|
||||||
|
|
||||||
public static boolean foundChannel(Object ws) {
|
public WrappedSocket() {
|
||||||
return ws instanceof WrappedSocket && ((WrappedSocket) ws).found;
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -318,5 +308,9 @@ final class ProtocolTest {
|
||||||
found = true;
|
found = true;
|
||||||
return null;
|
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 class ResponseInputStreamTest {
|
||||||
|
|
||||||
|
public ResponseInputStreamTest() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that an EOF while reading a literal throws an IOException.
|
* Test that an EOF while reading a literal throws an IOException.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testEofWhileReadingLiteral() throws Exception {
|
public void testEofWhileReadingLiteral() {
|
||||||
ByteArrayInputStream bis = new ByteArrayInputStream(
|
ByteArrayInputStream bis = new ByteArrayInputStream(
|
||||||
"test{1}\r\n".getBytes(StandardCharsets.ISO_8859_1));
|
"test{1}\r\n".getBytes(StandardCharsets.ISO_8859_1));
|
||||||
ResponseInputStream ris = new ResponseInputStream(bis);
|
ResponseInputStream ris = new ResponseInputStream(bis);
|
||||||
|
|
|
@ -18,6 +18,9 @@ package org.xbib.net.mail.test.imap;
|
||||||
|
|
||||||
import jakarta.mail.Session;
|
import jakarta.mail.Session;
|
||||||
import jakarta.mail.Store;
|
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.Test;
|
||||||
import org.junit.jupiter.api.Timeout;
|
import org.junit.jupiter.api.Timeout;
|
||||||
import org.xbib.net.mail.test.test.TestServer;
|
import org.xbib.net.mail.test.test.TestServer;
|
||||||
|
@ -44,6 +47,8 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||||
@Timeout(20)
|
@Timeout(20)
|
||||||
public final class IMAPAuthDebugTest {
|
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.
|
* 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.
|
* Test that authentication information *is* included in the debug output.
|
||||||
*/
|
*/
|
||||||
|
@Disabled("we have no debug output outside of logging")
|
||||||
@Test
|
@Test
|
||||||
public void testAuth() {
|
public void testAuth() {
|
||||||
final Properties properties = new Properties();
|
final Properties properties = new Properties();
|
||||||
|
@ -80,28 +86,19 @@ public final class IMAPAuthDebugTest {
|
||||||
final IMAPHandler handler = new IMAPHandler();
|
final IMAPHandler handler = new IMAPHandler();
|
||||||
server = new TestServer(handler);
|
server = new TestServer(handler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
properties.setProperty("mail.imap.host", "localhost");
|
properties.setProperty("mail.imap.host", "localhost");
|
||||||
properties.setProperty("mail.imap.port", String.valueOf(server.getPort()));
|
properties.setProperty("mail.imap.port", String.valueOf(server.getPort()));
|
||||||
final Session session = Session.getInstance(properties);
|
final Session session = Session.getInstance(properties);
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
try (Store store = session.getStore("imap")) {
|
||||||
final Store store = session.getStore("imap");
|
|
||||||
try {
|
|
||||||
store.connect("test", "test");
|
store.connect("test", "test");
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
System.out.println(ex);
|
logger.log(Level.SEVERE, ex.getMessage(), ex);
|
||||||
//ex.printStackTrace();
|
|
||||||
fail(ex.toString());
|
fail(ex.toString());
|
||||||
} finally {
|
|
||||||
store.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bos.close();
|
bos.close();
|
||||||
ByteArrayInputStream bis =
|
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
||||||
new ByteArrayInputStream(bos.toByteArray());
|
BufferedReader r = new BufferedReader(new InputStreamReader(bis, StandardCharsets.US_ASCII));
|
||||||
BufferedReader r = new BufferedReader(
|
|
||||||
new InputStreamReader(bis, StandardCharsets.US_ASCII));
|
|
||||||
String line;
|
String line;
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
while ((line = r.readLine()) != null) {
|
while ((line = r.readLine()) != null) {
|
||||||
|
|
|
@ -17,15 +17,15 @@
|
||||||
package org.xbib.net.mail.test.imap;
|
package org.xbib.net.mail.test.imap;
|
||||||
|
|
||||||
import jakarta.mail.Folder;
|
import jakarta.mail.Folder;
|
||||||
|
import jakarta.mail.MessagingException;
|
||||||
import jakarta.mail.Session;
|
import jakarta.mail.Session;
|
||||||
import jakarta.mail.Store;
|
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.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Properties;
|
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.
|
* Test that failures while closing a folder are handled properly.
|
||||||
|
@ -34,54 +34,27 @@ public final class IMAPCloseFailureTest {
|
||||||
|
|
||||||
private static final String HOST = "localhost";
|
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
|
@Test
|
||||||
public void testCloseNo() {
|
public void testCloseNo() throws Exception {
|
||||||
testClose(new NoIMAPHandler());
|
testClose(new NoIMAPHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCloseBad() {
|
public void testCloseBad() {
|
||||||
|
assertThrows(MessagingException.class, () -> {
|
||||||
testClose(new BadIMAPHandler());
|
testClose(new BadIMAPHandler());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testClose(IMAPHandler handler) {
|
public void testClose(IMAPHandler handler) throws Exception {
|
||||||
TestServer server = null;
|
TestServer server = null;
|
||||||
try {
|
try {
|
||||||
server = new TestServer(handler);
|
server = new TestServer(handler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.setProperty("mail.imap.host", HOST);
|
properties.setProperty("mail.imap.host", HOST);
|
||||||
properties.setProperty("mail.imap.port", String.valueOf(server.getPort()));
|
properties.setProperty("mail.imap.port", String.valueOf(server.getPort()));
|
||||||
Session session = Session.getInstance(properties);
|
Session session = Session.getInstance(properties);
|
||||||
//session.setDebug(true);
|
|
||||||
|
|
||||||
Store store = session.getStore("imap");
|
Store store = session.getStore("imap");
|
||||||
try {
|
try {
|
||||||
store.connect("test", "test");
|
store.connect("test", "test");
|
||||||
|
@ -92,22 +65,42 @@ public final class IMAPCloseFailureTest {
|
||||||
// with a connection that can't be used to open a folder.
|
// with a connection that can't be used to open a folder.
|
||||||
f.open(Folder.READ_WRITE);
|
f.open(Folder.READ_WRITE);
|
||||||
f.close(false);
|
f.close(false);
|
||||||
} catch (Exception ex) {
|
|
||||||
System.out.println(ex);
|
|
||||||
//ex.printStackTrace();
|
|
||||||
fail(ex.toString());
|
|
||||||
} finally {
|
} finally {
|
||||||
if (store.isConnected())
|
if (store.isConnected())
|
||||||
store.close();
|
store.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
fail(e.getMessage());
|
|
||||||
} finally {
|
} finally {
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
server.quit();
|
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 java.util.Properties;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the IMAPProtocol class.
|
* Test the IMAPProtocol class.
|
||||||
*/
|
*/
|
||||||
public class IMAPProtocolTest {
|
public class IMAPProtocolTest {
|
||||||
|
|
||||||
|
public IMAPProtocolTest() {
|
||||||
|
}
|
||||||
|
|
||||||
private static final boolean debug = false;
|
private static final boolean debug = false;
|
||||||
private static final String content = "aXQncyBteSB0ZXN0IG1haWwNCg0K\r\n";
|
private static final String content = "aXQncyBteSB0ZXN0IG1haWwNCg0K\r\n";
|
||||||
private static final String response =
|
private static final String response =
|
||||||
|
@ -68,16 +71,14 @@ public class IMAPProtocolTest {
|
||||||
props,
|
props,
|
||||||
debug);
|
debug);
|
||||||
BODY b = p.fetchBody(1, "1.1");
|
BODY b = p.fetchBody(1, "1.1");
|
||||||
assertEquals("section number", "1.1", b.getSection());
|
assertEquals("1.1", b.getSection());
|
||||||
//System.out.println(b);
|
|
||||||
//System.out.write(b.getByteArray().getNewBytes());
|
|
||||||
String result = new String(b.getByteArray().getNewBytes(), StandardCharsets.US_ASCII);
|
String result = new String(b.getByteArray().getNewBytes(), StandardCharsets.US_ASCII);
|
||||||
assertEquals("getByteArray.getNewBytes", content, result);
|
assertEquals(content, result);
|
||||||
InputStream is = b.getByteArrayInputStream();
|
InputStream is = b.getByteArrayInputStream();
|
||||||
byte[] ba = new byte[is.available()];
|
byte[] ba = new byte[is.available()];
|
||||||
is.read(ba);
|
is.read(ba);
|
||||||
result = new String(ba, StandardCharsets.US_ASCII);
|
result = new String(ba, StandardCharsets.US_ASCII);
|
||||||
assertEquals("getByteArrayInputStream", content, result);
|
assertEquals(content, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,15 +94,13 @@ public class IMAPProtocolTest {
|
||||||
props,
|
props,
|
||||||
debug);
|
debug);
|
||||||
BODY b = p.fetchBody(1, "1.1", 0, content.length(), null);
|
BODY b = p.fetchBody(1, "1.1", 0, content.length(), null);
|
||||||
assertEquals("section number", "1.1", b.getSection());
|
assertEquals("1.1", b.getSection());
|
||||||
//System.out.println(b);
|
|
||||||
//System.out.write(b.getByteArray().getNewBytes());
|
|
||||||
String result = new String(b.getByteArray().getNewBytes(), StandardCharsets.US_ASCII);
|
String result = new String(b.getByteArray().getNewBytes(), StandardCharsets.US_ASCII);
|
||||||
assertEquals("getByteArray.getNewBytes", content, result);
|
assertEquals(content, result);
|
||||||
InputStream is = b.getByteArrayInputStream();
|
InputStream is = b.getByteArrayInputStream();
|
||||||
byte[] ba = new byte[is.available()];
|
byte[] ba = new byte[is.available()];
|
||||||
is.read(ba);
|
is.read(ba);
|
||||||
result = new String(ba, StandardCharsets.US_ASCII);
|
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.IMAPResponse;
|
||||||
import org.xbib.net.mail.imap.protocol.Status;
|
import org.xbib.net.mail.imap.protocol.Status;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the Status class.
|
* Test the Status class.
|
||||||
|
@ -75,20 +76,24 @@ public class StatusTest {
|
||||||
/**
|
/**
|
||||||
* Test that a bad response throws a ParsingException
|
* Test that a bad response throws a ParsingException
|
||||||
*/
|
*/
|
||||||
@Test //(expected = ParsingException.class)
|
@Test
|
||||||
public void testBadResponseNoAttrList() throws Exception {
|
public void testBadResponseNoAttrList() {
|
||||||
|
assertThrows(ParsingException.class, () -> {
|
||||||
String mbox = "test";
|
String mbox = "test";
|
||||||
IMAPResponse response = new IMAPResponse("* STATUS test ");
|
IMAPResponse response = new IMAPResponse("* STATUS test ");
|
||||||
Status s = new Status(response);
|
Status s = new Status(response);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that a bad response throws a ParsingException
|
* Test that a bad response throws a ParsingException
|
||||||
*/
|
*/
|
||||||
@Test // (expected = ParsingException.class)
|
@Test
|
||||||
public void testBadResponseNoAttrs() throws Exception {
|
public void testBadResponseNoAttrs() {
|
||||||
|
assertThrows(ParsingException.class, () -> {
|
||||||
String mbox = "test";
|
String mbox = "test";
|
||||||
IMAPResponse response = new IMAPResponse("* STATUS test (");
|
IMAPResponse response = new IMAPResponse("* STATUS test (");
|
||||||
Status s = new Status(response);
|
Status s = new Status(response);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
|
|
||||||
package org.xbib.net.mail.test.imap.protocol;
|
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 org.xbib.net.mail.imap.protocol.UIDSet;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
@ -33,17 +36,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
*
|
*
|
||||||
* @author Bill Shannon
|
* @author Bill Shannon
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//@RunWith(Parameterized.class)
|
|
||||||
public class UIDSetTest {
|
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;
|
private static boolean junit;
|
||||||
|
|
||||||
static class TestData {
|
public static class TestData {
|
||||||
public String name;
|
public String name;
|
||||||
public String uids;
|
public String uids;
|
||||||
public long max;
|
public long max;
|
||||||
|
@ -51,25 +50,24 @@ public class UIDSetTest {
|
||||||
public long[] expect;
|
public long[] expect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UIDSetTest(TestData t) {
|
public UIDSetTest() {
|
||||||
data = t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest
|
||||||
public void testData() {
|
@MethodSource("data")
|
||||||
test(data);
|
public void testData(TestData t) {
|
||||||
|
test(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Parameters
|
|
||||||
public static Collection<TestData[]> data() throws Exception {
|
public static Collection<TestData[]> data() throws Exception {
|
||||||
junit = true;
|
junit = true;
|
||||||
// XXX - gratuitous array requirement
|
|
||||||
List<TestData[]> testData = new ArrayList<>();
|
List<TestData[]> testData = new ArrayList<>();
|
||||||
BufferedReader in = new BufferedReader(new InputStreamReader(
|
InputStream inputStream = Objects.requireNonNull(UIDSetTest.class.getResourceAsStream("uiddata"));
|
||||||
UIDSetTest.class.getResourceAsStream("uiddata")));
|
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
|
||||||
TestData t;
|
TestData t;
|
||||||
while ((t = parse(in)) != null)
|
while ((t = parse(in)) != null) {
|
||||||
testData.add(new TestData[]{t});
|
testData.add(new TestData[]{t});
|
||||||
|
}
|
||||||
return testData;
|
return testData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +78,7 @@ public class UIDSetTest {
|
||||||
if (argv[optind].equals("-")) {
|
if (argv[optind].equals("-")) {
|
||||||
// ignore
|
// ignore
|
||||||
} else if (argv[optind].equals("-g")) {
|
} else if (argv[optind].equals("-g")) {
|
||||||
gen_test_input = true;
|
//gen_test_input = true;
|
||||||
} else if (argv[optind].equals("--")) {
|
} else if (argv[optind].equals("--")) {
|
||||||
optind++;
|
optind++;
|
||||||
break;
|
break;
|
||||||
|
@ -92,80 +90,80 @@ public class UIDSetTest {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read from stdin
|
// read from stdin
|
||||||
BufferedReader in =
|
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||||||
new BufferedReader(new InputStreamReader(System.in));
|
|
||||||
|
|
||||||
TestData t;
|
TestData t;
|
||||||
while ((t = parse(in)) != null)
|
while ((t = parse(in)) != null) {
|
||||||
test(t);
|
test(t);
|
||||||
System.exit(errors);
|
}
|
||||||
|
//System.exit(errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse the input, returning a test case.
|
* Parse the input, returning a test case.
|
||||||
*/
|
*/
|
||||||
public static TestData parse(BufferedReader in) throws Exception {
|
public static TestData parse(BufferedReader in) throws Exception {
|
||||||
|
String line;
|
||||||
String line = null;
|
|
||||||
for (; ; ) {
|
for (; ; ) {
|
||||||
line = in.readLine();
|
line = in.readLine();
|
||||||
if (line == null)
|
if (line == null) {
|
||||||
return null;
|
return null;
|
||||||
if (line.length() == 0 || line.startsWith("#"))
|
}
|
||||||
|
if (line.isEmpty() || line.startsWith("#")) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (!line.startsWith("TEST"))
|
if (!line.startsWith("TEST")) {
|
||||||
throw new Exception("Bad test data format");
|
throw new Exception("Bad test data format");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestData t = new TestData();
|
TestData t = new TestData();
|
||||||
int i = line.indexOf(' '); // XXX - crude
|
int i = line.indexOf(' '); // XXX - crude
|
||||||
t.name = line.substring(i + 1);
|
t.name = line.substring(i + 1);
|
||||||
|
|
||||||
line = in.readLine();
|
line = in.readLine();
|
||||||
StringTokenizer st = new StringTokenizer(line);
|
StringTokenizer st = new StringTokenizer(line);
|
||||||
String tok = st.nextToken();
|
String tok = st.nextToken();
|
||||||
if (!tok.equals("DATA"))
|
if (!tok.equals("DATA")) {
|
||||||
throw new Exception("Bad test data format: " + line);
|
throw new Exception("Bad test data format: " + line);
|
||||||
|
}
|
||||||
tok = st.nextToken();
|
tok = st.nextToken();
|
||||||
if (tok.equals("NULL"))
|
if (tok.equals("NULL")) {
|
||||||
t.uids = null;
|
t.uids = null;
|
||||||
else if (tok.equals("EMPTY"))
|
} else if (tok.equals("EMPTY")) {
|
||||||
t.uids = "";
|
t.uids = "";
|
||||||
else
|
} else {
|
||||||
t.uids = tok;
|
t.uids = tok;
|
||||||
|
}
|
||||||
line = in.readLine();
|
line = in.readLine();
|
||||||
st = new StringTokenizer(line);
|
st = new StringTokenizer(line);
|
||||||
tok = st.nextToken();
|
tok = st.nextToken();
|
||||||
if (tok.equals("MAX")) {
|
if (tok.equals("MAX")) {
|
||||||
tok = st.nextToken();
|
tok = st.nextToken();
|
||||||
try {
|
try {
|
||||||
t.max = Long.valueOf(tok);
|
t.max = Long.parseLong(tok);
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
throw new Exception("Bad MAX value in line: " + line);
|
throw new Exception("Bad MAX value in line: " + line);
|
||||||
}
|
}
|
||||||
if (st.hasMoreTokens())
|
if (st.hasMoreTokens()) {
|
||||||
t.maxuids = st.nextToken();
|
t.maxuids = st.nextToken();
|
||||||
else
|
} else {
|
||||||
t.maxuids = t.uids;
|
t.maxuids = t.uids;
|
||||||
|
}
|
||||||
line = in.readLine();
|
line = in.readLine();
|
||||||
st = new StringTokenizer(line);
|
st = new StringTokenizer(line);
|
||||||
tok = st.nextToken();
|
tok = st.nextToken();
|
||||||
}
|
}
|
||||||
List<Long> uids = new ArrayList<>();
|
List<Long> uids = new ArrayList<>();
|
||||||
if (!tok.equals("EXPECT"))
|
if (!tok.equals("EXPECT")) {
|
||||||
throw new Exception("Bad test data format: " + line);
|
throw new Exception("Bad test data format: " + line);
|
||||||
|
}
|
||||||
while (st.hasMoreTokens()) {
|
while (st.hasMoreTokens()) {
|
||||||
tok = st.nextToken();
|
tok = st.nextToken();
|
||||||
if (tok.equals("NULL"))
|
if (tok.equals("NULL")) {
|
||||||
t.expect = null;
|
t.expect = null;
|
||||||
else if (tok.equals("EMPTY"))
|
} else if (tok.equals("EMPTY")) {
|
||||||
t.expect = new long[0];
|
t.expect = new long[0];
|
||||||
else {
|
} else {
|
||||||
try {
|
try {
|
||||||
uids.add(Long.valueOf(tok));
|
uids.add(Long.valueOf(tok));
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
|
@ -173,13 +171,13 @@ public class UIDSetTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (uids.size() > 0) {
|
if (!uids.isEmpty()) {
|
||||||
t.expect = new long[uids.size()];
|
t.expect = new long[uids.size()];
|
||||||
i = 0;
|
i = 0;
|
||||||
for (Long l : uids)
|
for (Long l : uids) {
|
||||||
t.expect[i++] = l.longValue();
|
t.expect[i++] = l;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,46 +185,47 @@ public class UIDSetTest {
|
||||||
* Test the data in the test case.
|
* Test the data in the test case.
|
||||||
*/
|
*/
|
||||||
public static void test(TestData t) {
|
public static void test(TestData t) {
|
||||||
// XXX - handle nulls
|
|
||||||
|
|
||||||
// first, test string to array
|
|
||||||
UIDSet[] uidset = UIDSet.parseUIDSets(t.uids);
|
UIDSet[] uidset = UIDSet.parseUIDSets(t.uids);
|
||||||
long[] uids;
|
long[] uids;
|
||||||
if (t.max > 0)
|
if (t.max > 0) {
|
||||||
uids = UIDSet.toArray(uidset, t.max);
|
uids = UIDSet.toArray(uidset, t.max);
|
||||||
else
|
} else {
|
||||||
uids = UIDSet.toArray(uidset);
|
uids = UIDSet.toArray(uidset);
|
||||||
if (junit)
|
}
|
||||||
|
if (junit) {
|
||||||
assertArrayEquals(t.expect, uids);
|
assertArrayEquals(t.expect, uids);
|
||||||
else if (!arrayEquals(t.expect, uids)) {
|
} else if (!arrayEquals(t.expect, uids)) {
|
||||||
System.out.println("Test: " + t.name);
|
//System.out.println("Test: " + t.name);
|
||||||
System.out.println("FAIL");
|
//System.out.println("FAIL");
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now, test the reverse
|
|
||||||
UIDSet[] uidset2 = UIDSet.createUIDSets(uids);
|
UIDSet[] uidset2 = UIDSet.createUIDSets(uids);
|
||||||
String suid = UIDSet.toString(uidset2);
|
String suid = UIDSet.toString(uidset2);
|
||||||
String euid = t.max > 0 ? t.maxuids : t.uids;
|
String euid = t.max > 0 ? t.maxuids : t.uids;
|
||||||
if (junit)
|
if (junit) {
|
||||||
assertEquals(euid, suid);
|
assertEquals(euid, suid);
|
||||||
else if (!euid.equals(suid)) {
|
} else if (!euid.equals(suid)) {
|
||||||
System.out.println("Test: " + t.name);
|
//System.out.println("Test: " + t.name);
|
||||||
System.out.println("FAIL2");
|
//System.out.println("FAIL2");
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean arrayEquals(long[] a, long[] b) {
|
private static boolean arrayEquals(long[] a, long[] b) {
|
||||||
if (a == b)
|
if (a == b) {
|
||||||
return true;
|
return true;
|
||||||
if (a == null || b == null)
|
}
|
||||||
|
if (a == null || b == null) {
|
||||||
return false;
|
return false;
|
||||||
if (a.length != b.length)
|
}
|
||||||
|
if (a.length != b.length) {
|
||||||
return false;
|
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 false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.xbib.net.mail.test.pop3;
|
||||||
|
|
||||||
import jakarta.mail.Session;
|
import jakarta.mail.Session;
|
||||||
import jakarta.mail.Store;
|
import jakarta.mail.Store;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.Timeout;
|
import org.junit.jupiter.api.Timeout;
|
||||||
import org.xbib.net.mail.test.test.TestServer;
|
import org.xbib.net.mail.test.test.TestServer;
|
||||||
|
@ -26,7 +27,6 @@ import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
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.
|
* Test that authentication information *is* included in the debug output.
|
||||||
*/
|
*/
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testAuth() {
|
public void testAuth() {
|
||||||
final Properties properties = new Properties();
|
final Properties properties = new Properties();
|
||||||
|
@ -81,21 +82,15 @@ public final class POP3AuthDebugTest {
|
||||||
server = new TestServer(handler);
|
server = new TestServer(handler);
|
||||||
server.start();
|
server.start();
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
|
|
||||||
properties.setProperty("mail.pop3.host", "localhost");
|
properties.setProperty("mail.pop3.host", "localhost");
|
||||||
properties.setProperty("mail.pop3.port", String.valueOf(server.getPort()));
|
properties.setProperty("mail.pop3.port", String.valueOf(server.getPort()));
|
||||||
final Session session = Session.getInstance(properties);
|
final Session session = Session.getInstance(properties);
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
try (Store store = session.getStore("pop3")) {
|
||||||
final Store store = session.getStore("pop3");
|
|
||||||
try {
|
|
||||||
store.connect("test", "test");
|
store.connect("test", "test");
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
fail(ex.toString());
|
fail(ex.toString());
|
||||||
} finally {
|
|
||||||
store.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bos.close();
|
bos.close();
|
||||||
ByteArrayInputStream bis =
|
ByteArrayInputStream bis =
|
||||||
new ByteArrayInputStream(bos.toByteArray());
|
new ByteArrayInputStream(bos.toByteArray());
|
||||||
|
@ -114,7 +109,6 @@ public final class POP3AuthDebugTest {
|
||||||
r.close();
|
r.close();
|
||||||
return found;
|
return found;
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
e.printStackTrace();
|
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
return false; // XXX - doesn't matter
|
return false; // XXX - doesn't matter
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.xbib.net.mail.test.smtp;
|
||||||
|
|
||||||
import jakarta.mail.Session;
|
import jakarta.mail.Session;
|
||||||
import jakarta.mail.Transport;
|
import jakarta.mail.Transport;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.Timeout;
|
import org.junit.jupiter.api.Timeout;
|
||||||
import org.xbib.net.mail.test.test.TestServer;
|
import org.xbib.net.mail.test.test.TestServer;
|
||||||
|
@ -26,7 +27,6 @@ import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
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.
|
* Test that authentication information *is* included in the debug output.
|
||||||
*/
|
*/
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testAuth() {
|
public void testAuth() {
|
||||||
final Properties properties = new Properties();
|
final Properties properties = new Properties();
|
||||||
|
@ -81,25 +82,18 @@ public final class SMTPAuthDebugTest {
|
||||||
server = new TestServer(handler);
|
server = new TestServer(handler);
|
||||||
server.start();
|
server.start();
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
|
|
||||||
properties.setProperty("mail.smtp.host", "localhost");
|
properties.setProperty("mail.smtp.host", "localhost");
|
||||||
properties.setProperty("mail.smtp.port", String.valueOf(server.getPort()));
|
properties.setProperty("mail.smtp.port", String.valueOf(server.getPort()));
|
||||||
final Session session = Session.getInstance(properties);
|
final Session session = Session.getInstance(properties);
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
try (Transport t = session.getTransport("smtp")) {
|
||||||
final Transport t = session.getTransport("smtp");
|
|
||||||
try {
|
|
||||||
t.connect("test", "test");
|
t.connect("test", "test");
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
fail(ex.toString());
|
fail(ex.toString());
|
||||||
} finally {
|
|
||||||
t.close();
|
|
||||||
}
|
}
|
||||||
bos.close();
|
bos.close();
|
||||||
ByteArrayInputStream bis =
|
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
||||||
new ByteArrayInputStream(bos.toByteArray());
|
BufferedReader r = new BufferedReader(new InputStreamReader(bis, StandardCharsets.US_ASCII));
|
||||||
BufferedReader r = new BufferedReader(
|
|
||||||
new InputStreamReader(bis, StandardCharsets.US_ASCII));
|
|
||||||
String line;
|
String line;
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
while ((line = r.readLine()) != null) {
|
while ((line = r.readLine()) != null) {
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test handling of line terminators.
|
* Test handling of line terminators.
|
||||||
|
@ -63,41 +64,45 @@ public class LineInputStreamTest {
|
||||||
@Test
|
@Test
|
||||||
public void testLines() throws IOException {
|
public void testLines() throws IOException {
|
||||||
for (String s : lines) {
|
for (String s : lines) {
|
||||||
LineInputStream is = createStream(s);
|
try (LineInputStream is = createStream(s)) {
|
||||||
assertEquals("line1", is.readLine());
|
assertEquals("line1", is.readLine());
|
||||||
assertEquals("line2", is.readLine());
|
assertEquals("line2", is.readLine());
|
||||||
assertEquals("line3", is.readLine());
|
assertEquals("line3", is.readLine());
|
||||||
assertEquals(null, is.readLine());
|
assertNull(is.readLine());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEmpty() throws IOException {
|
public void testEmpty() throws IOException {
|
||||||
for (String s : empty) {
|
for (String s : empty) {
|
||||||
LineInputStream is = createStream(s);
|
try (LineInputStream is = createStream(s)) {
|
||||||
assertEquals("", is.readLine());
|
assertEquals("", is.readLine());
|
||||||
assertEquals("", is.readLine());
|
assertEquals("", is.readLine());
|
||||||
assertEquals("", is.readLine());
|
assertEquals("", is.readLine());
|
||||||
assertEquals(null, is.readLine());
|
assertNull(is.readLine());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMixed() throws IOException {
|
public void testMixed() throws IOException {
|
||||||
for (String s : mixed) {
|
for (String s : mixed) {
|
||||||
LineInputStream is = createStream(s);
|
try (LineInputStream is = createStream(s)) {
|
||||||
assertEquals("line1", is.readLine());
|
assertEquals("line1", is.readLine());
|
||||||
assertEquals("", is.readLine());
|
assertEquals("", is.readLine());
|
||||||
assertEquals("line3", is.readLine());
|
assertEquals("line3", is.readLine());
|
||||||
assertEquals(null, is.readLine());
|
assertNull(is.readLine());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUtf8Fail() throws IOException {
|
public void testUtf8Fail() throws IOException {
|
||||||
LineInputStream is = createStream("a\u00A9b\n", StandardCharsets.UTF_8);
|
try (LineInputStream is = createStream("a\u00A9b\n", StandardCharsets.UTF_8)) {
|
||||||
assertNotEquals("a\u00A9b", is.readLine());
|
assertNotEquals("a\u00A9b", is.readLine());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUtf8() throws IOException {
|
public void testUtf8() throws IOException {
|
||||||
|
@ -108,17 +113,16 @@ public class LineInputStreamTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIso() throws IOException {
|
public void testIso() throws IOException {
|
||||||
LineInputStream is =
|
try (LineInputStream is = createStream("a\251b\n", StandardCharsets.ISO_8859_1)) {
|
||||||
createStream("a\251b\n", StandardCharsets.ISO_8859_1);
|
|
||||||
assertEquals("a\251b", is.readLine());
|
assertEquals("a\251b", is.readLine());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private LineInputStream createStream(String s) {
|
private LineInputStream createStream(String s) {
|
||||||
return createStream(s, StandardCharsets.US_ASCII);
|
return createStream(s, StandardCharsets.US_ASCII);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LineInputStream createStream(String s, Charset cs) {
|
private LineInputStream createStream(String s, Charset cs) {
|
||||||
return new LineInputStream(
|
return new LineInputStream(new ByteArrayInputStream(s.getBytes(cs)));
|
||||||
new ByteArrayInputStream(s.getBytes(cs)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.xbib.net.mail.test.stream;
|
package org.xbib.net.mail.test.stream;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.xbib.net.mail.util.LineInputStream;
|
import org.xbib.net.mail.util.LineInputStream;
|
||||||
|
|
||||||
|
@ -31,14 +30,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
*/
|
*/
|
||||||
public class LineInputStreamUtf8FailTest {
|
public class LineInputStreamUtf8FailTest {
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void before() {
|
|
||||||
System.out.println("LineInputStreamUtf8Fail");
|
|
||||||
System.clearProperty("mail.mime.allowutf8");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUtf8() throws Exception {
|
public void testUtf8() throws Exception {
|
||||||
|
System.clearProperty("mail.mime.allowutf8");
|
||||||
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
||||||
"a\u00A9b\n".getBytes(StandardCharsets.UTF_8)), false);
|
"a\u00A9b\n".getBytes(StandardCharsets.UTF_8)), false);
|
||||||
assertEquals("a\302\251b", is.readLine());
|
assertEquals("a\302\251b", is.readLine());
|
||||||
|
@ -46,6 +40,7 @@ public class LineInputStreamUtf8FailTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIso() throws IOException {
|
public void testIso() throws IOException {
|
||||||
|
System.clearProperty("mail.mime.allowutf8");
|
||||||
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
||||||
"a\251b\n".getBytes(StandardCharsets.ISO_8859_1)), false);
|
"a\251b\n".getBytes(StandardCharsets.ISO_8859_1)), false);
|
||||||
assertEquals("a\251b", is.readLine());
|
assertEquals("a\251b", is.readLine());
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.xbib.net.mail.test.stream;
|
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.junit.jupiter.api.Test;
|
||||||
import org.xbib.net.mail.util.LineInputStream;
|
import org.xbib.net.mail.util.LineInputStream;
|
||||||
|
|
||||||
|
@ -32,28 +30,22 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
*/
|
*/
|
||||||
public class LineInputStreamUtf8Test {
|
public class LineInputStreamUtf8Test {
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void before() {
|
|
||||||
System.out.println("LineInputStreamUtf8");
|
|
||||||
System.setProperty("mail.mime.allowutf8", "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUtf8() throws Exception {
|
public void testUtf8() throws Exception {
|
||||||
|
System.setProperty("mail.mime.allowutf8", "true");
|
||||||
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
||||||
"a\u00A9b\n".getBytes(StandardCharsets.UTF_8)), false);
|
"a\u00A9b\n".getBytes(StandardCharsets.UTF_8)), false);
|
||||||
assertEquals("a\u00A9b", is.readLine());
|
assertEquals("a\u00A9b", is.readLine());
|
||||||
|
System.clearProperty("mail.mime.allowutf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIso() throws IOException {
|
public void testIso() throws IOException {
|
||||||
|
System.setProperty("mail.mime.allowutf8", "true");
|
||||||
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
LineInputStream is = new LineInputStream(new ByteArrayInputStream(
|
||||||
"a\251b\n".getBytes(StandardCharsets.ISO_8859_1)), false);
|
"a\251b\n".getBytes(StandardCharsets.ISO_8859_1)), false);
|
||||||
assertEquals("a\251b", is.readLine());
|
assertEquals("a\251b", is.readLine());
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void after() {
|
|
||||||
System.clearProperty("mail.mime.allowutf8");
|
System.clearProperty("mail.mime.allowutf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ import java.util.logging.Logger;
|
||||||
* Inspired by, and derived from, POP3Server by sbo.
|
* Inspired by, and derived from, POP3Server by sbo.
|
||||||
*
|
*
|
||||||
* For SSL/TLS support, depends on a keystore with a single X509 certificate in
|
* 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 sbo
|
||||||
* @author Bill Shannon
|
* @author Bill Shannon
|
||||||
|
@ -121,23 +121,19 @@ public final class TestServer {
|
||||||
private static SSLContext createSSLContext()
|
private static SSLContext createSSLContext()
|
||||||
throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
|
throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
|
||||||
KeyStore keyStore = KeyStore.getInstance("JKS");
|
KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||||
keyStore.load(TestServer.class.getResourceAsStream("keystore.jks"),
|
keyStore.load(TestServer.class.getResourceAsStream("keystore.jks"), "changeit".toCharArray());
|
||||||
"changeit".toCharArray());
|
|
||||||
|
|
||||||
// Create key manager
|
// Create key manager
|
||||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||||
kmf.init(keyStore, "changeit".toCharArray());
|
kmf.init(keyStore, "changeit".toCharArray());
|
||||||
KeyManager[] km = kmf.getKeyManagers();
|
KeyManager[] km = kmf.getKeyManagers();
|
||||||
|
|
||||||
// Create trust manager
|
// Create trust manager
|
||||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
||||||
tmf.init(keyStore);
|
tmf.init(keyStore);
|
||||||
TrustManager[] tm = tmf.getTrustManagers();
|
TrustManager[] tm = tmf.getTrustManagers();
|
||||||
|
|
||||||
// Initialize SSLContext
|
// Initialize SSLContext
|
||||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||||
sslContext.init(km, tm, null);
|
sslContext.init(km, tm, null);
|
||||||
|
logger.log(Level.INFO, "SSL context = " + sslContext);
|
||||||
return sslContext;
|
return sslContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,21 +148,6 @@ public final class TestServer {
|
||||||
executorService.execute(this::run);
|
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() {
|
private void run() {
|
||||||
try {
|
try {
|
||||||
keepOn = true;
|
keepOn = true;
|
||||||
|
@ -210,49 +191,9 @@ public final class TestServer {
|
||||||
} else {
|
} else {
|
||||||
logger.log(Level.INFO, "server socket already closed");
|
logger.log(Level.INFO, "server socket already closed");
|
||||||
}
|
}
|
||||||
} catch (final Exception e) {
|
} catch (InterruptedException e) {
|
||||||
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(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.setFrom(iaddr);
|
||||||
m.addFrom(addresses);
|
m.addFrom(addresses);
|
||||||
assertEquals(1, m.getHeader("From").length);
|
assertEquals(1, m.getHeader("From").length);
|
||||||
assertEquals("From header", ADDR + ", " + ADDR,
|
assertEquals(ADDR + ", " + ADDR, m.getHeader("From", ","));
|
||||||
m.getHeader("From", ","));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,6 @@ import jakarta.mail.MessagingException;
|
||||||
import jakarta.mail.Session;
|
import jakarta.mail.Session;
|
||||||
import jakarta.mail.internet.MimeMessage;
|
import jakarta.mail.internet.MimeMessage;
|
||||||
import jakarta.mail.internet.MimeMultipart;
|
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.junit.jupiter.api.Test;
|
||||||
import org.xbib.net.mail.test.test.AsciiStringInputStream;
|
import org.xbib.net.mail.test.test.AsciiStringInputStream;
|
||||||
|
|
||||||
|
@ -34,29 +32,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
*/
|
*/
|
||||||
public class AllowEncodedMessagesTest {
|
public class AllowEncodedMessagesTest {
|
||||||
|
|
||||||
private static Session s = Session.getInstance(new Properties());
|
private static final Session s = Session.getInstance(new Properties());
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void before() {
|
|
||||||
System.out.println("AllowEncodedMessages");
|
|
||||||
System.setProperty("mail.mime.allowencodedmessages", "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodedMessages() throws Exception {
|
public void testEncodedMessages() throws Exception {
|
||||||
|
System.setProperty("mail.mime.allowencodedmessages", "true");
|
||||||
MimeMessage m = createMessage();
|
MimeMessage m = createMessage();
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
BodyPart bp = mp.getBodyPart(0);
|
BodyPart bp = mp.getBodyPart(0);
|
||||||
assertEquals("message/rfc822", bp.getContentType());
|
assertEquals("message/rfc822", bp.getContentType());
|
||||||
|
|
||||||
MimeMessage m2 = (MimeMessage) bp.getContent();
|
MimeMessage m2 = (MimeMessage) bp.getContent();
|
||||||
assertEquals("text/plain", m2.getContentType());
|
assertEquals("text/plain", m2.getContentType());
|
||||||
assertEquals("test message\r\n", m2.getContent());
|
assertEquals("test message\r\n", m2.getContent());
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void after() {
|
|
||||||
// should be unnecessary
|
|
||||||
System.clearProperty("mail.mime.allowencodedmessages");
|
System.clearProperty("mail.mime.allowencodedmessages");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ import java.util.Base64;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test base64 encoding/decoding.
|
* Test base64 encoding/decoding.
|
||||||
|
@ -43,27 +42,16 @@ public class BASE64Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws IOException {
|
public void test() throws IOException {
|
||||||
// test a range of buffer sizes
|
|
||||||
for (int bufsize = 1; bufsize < 100; bufsize++) {
|
for (int bufsize = 1; bufsize < 100; bufsize++) {
|
||||||
//System.out.println("Buffer size: " + bufsize);
|
|
||||||
byte[] buf = new byte[bufsize];
|
byte[] buf = new byte[bufsize];
|
||||||
|
|
||||||
// test a set of patterns
|
|
||||||
|
|
||||||
// first, all zeroes
|
|
||||||
Arrays.fill(buf, (byte) 0);
|
Arrays.fill(buf, (byte) 0);
|
||||||
test("Zeroes", buf);
|
test("Zeroes", buf);
|
||||||
|
|
||||||
// now, all ones
|
|
||||||
Arrays.fill(buf, (byte) 0xff);
|
Arrays.fill(buf, (byte) 0xff);
|
||||||
test("Ones", buf);
|
test("Ones", buf);
|
||||||
|
for (int i = 0; i < bufsize; i++) {
|
||||||
// now, small integers
|
|
||||||
for (int i = 0; i < bufsize; i++)
|
|
||||||
buf[i] = (byte) i;
|
buf[i] = (byte) i;
|
||||||
|
}
|
||||||
test("Ints", buf);
|
test("Ints", buf);
|
||||||
|
|
||||||
// finally, random numbers
|
|
||||||
Random rnd = new Random();
|
Random rnd = new Random();
|
||||||
rnd.nextBytes(buf);
|
rnd.nextBytes(buf);
|
||||||
test("Random", buf);
|
test("Random", buf);
|
||||||
|
@ -78,57 +66,41 @@ public class BASE64Test {
|
||||||
* decoding stream. Check all combinations.
|
* decoding stream. Check all combinations.
|
||||||
*/
|
*/
|
||||||
private static void test(String name, byte[] buf) throws IOException {
|
private static void test(String name, byte[] buf) throws IOException {
|
||||||
// first encode and decode with method
|
|
||||||
byte[] encoded = Base64.getEncoder().encode(buf);
|
byte[] encoded = Base64.getEncoder().encode(buf);
|
||||||
byte[] nbuf = Base64.getDecoder().decode(encoded);
|
byte[] nbuf = Base64.getDecoder().decode(encoded);
|
||||||
compare(name, "method", buf, nbuf);
|
compare(name, "method", buf, nbuf);
|
||||||
|
|
||||||
// encode with stream, compare with method encoded version
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
BASE64EncoderStream os =
|
BASE64EncoderStream os = new BASE64EncoderStream(bos, Integer.MAX_VALUE);
|
||||||
new BASE64EncoderStream(bos, Integer.MAX_VALUE);
|
|
||||||
os.write(buf);
|
os.write(buf);
|
||||||
os.flush();
|
os.flush();
|
||||||
os.close();
|
os.close();
|
||||||
byte[] sbuf = bos.toByteArray();
|
byte[] sbuf = bos.toByteArray();
|
||||||
compare(name, "encoded", encoded, sbuf);
|
compare(name, "encoded", encoded, sbuf);
|
||||||
|
|
||||||
// encode with stream, decode with method
|
|
||||||
nbuf = Base64.getDecoder().decode(sbuf);
|
nbuf = Base64.getDecoder().decode(sbuf);
|
||||||
compare(name, "stream->method", buf, nbuf);
|
compare(name, "stream->method", buf, nbuf);
|
||||||
|
|
||||||
// encode with stream, decode with stream
|
|
||||||
ByteArrayInputStream bin = new ByteArrayInputStream(sbuf);
|
ByteArrayInputStream bin = new ByteArrayInputStream(sbuf);
|
||||||
BASE64DecoderStream in = new BASE64DecoderStream(bin);
|
BASE64DecoderStream in = new BASE64DecoderStream(bin);
|
||||||
readAll(in, nbuf, nbuf.length);
|
readAll(in, nbuf, nbuf.length);
|
||||||
compare(name, "stream", buf, nbuf);
|
compare(name, "stream", buf, nbuf);
|
||||||
|
|
||||||
// encode with method, decode with stream
|
|
||||||
for (int i = 1; i <= nbuf.length; i++) {
|
for (int i = 1; i <= nbuf.length; i++) {
|
||||||
bin = new ByteArrayInputStream(encoded);
|
bin = new ByteArrayInputStream(encoded);
|
||||||
in = new BASE64DecoderStream(bin);
|
in = new BASE64DecoderStream(bin);
|
||||||
readAll(in, nbuf, i);
|
readAll(in, nbuf, i);
|
||||||
compare(name, "method->stream " + i, buf, nbuf);
|
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
|
int limit = 10000; // more than 8K
|
||||||
bos = new ByteArrayOutputStream();
|
bos = new ByteArrayOutputStream();
|
||||||
os = new BASE64EncoderStream(bos);
|
os = new BASE64EncoderStream(bos);
|
||||||
for (int size = 0, blen = buf.length; size < limit; size += blen) {
|
for (int size = 0, blen = buf.length; size < limit; size += blen) {
|
||||||
if (size + blen > limit) {
|
if (size + blen > limit) {
|
||||||
blen = limit - size;
|
blen = limit - size;
|
||||||
// write out partial buffer, starting at non-zero offset
|
|
||||||
os.write(buf, buf.length - blen, blen);
|
os.write(buf, buf.length - blen, blen);
|
||||||
} else
|
} else {
|
||||||
os.write(buf);
|
os.write(buf);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
os.flush();
|
os.flush();
|
||||||
os.close();
|
os.close();
|
||||||
|
|
||||||
// read the encoded output and check the line length
|
|
||||||
String type = "big stream"; // for error messages below
|
String type = "big stream"; // for error messages below
|
||||||
sbuf = bos.toByteArray();
|
sbuf = bos.toByteArray();
|
||||||
bin = new ByteArrayInputStream(sbuf);
|
bin = new ByteArrayInputStream(sbuf);
|
||||||
|
@ -141,24 +113,22 @@ public class BASE64Test {
|
||||||
} else {
|
} else {
|
||||||
int n = bin.read(inbuf, 0, blen + 2);
|
int n = bin.read(inbuf, 0, blen + 2);
|
||||||
assertEquals(blen + 2, n);
|
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);
|
bin = new ByteArrayInputStream(sbuf);
|
||||||
in = new BASE64DecoderStream(bin);
|
in = new BASE64DecoderStream(bin);
|
||||||
inbuf = new byte[buf.length];
|
inbuf = new byte[buf.length];
|
||||||
for (int size = 0, blen = buf.length; size < limit; size += blen) {
|
for (int size = 0, blen = buf.length; size < limit; size += blen) {
|
||||||
if (size + blen > limit)
|
if (size + blen > limit) {
|
||||||
blen = limit - size;
|
blen = limit - size;
|
||||||
|
}
|
||||||
int n = in.read(nbuf, 0, blen);
|
int n = in.read(nbuf, 0, blen);
|
||||||
assertEquals(blen, n);
|
assertEquals(blen, n);
|
||||||
if (blen != buf.length) {
|
if (blen != buf.length) {
|
||||||
// have to compare with end of original buffer
|
|
||||||
byte[] cbuf = new byte[blen];
|
byte[] cbuf = new byte[blen];
|
||||||
System.arraycopy(buf, buf.length - blen, cbuf, 0, 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];
|
byte[] cnbuf = new byte[blen];
|
||||||
System.arraycopy(nbuf, 0, cnbuf, 0, blen);
|
System.arraycopy(nbuf, 0, cnbuf, 0, blen);
|
||||||
compare(name, type, cbuf, cnbuf);
|
compare(name, type, cbuf, cnbuf);
|
||||||
|
@ -168,8 +138,9 @@ public class BASE64Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] origLine;
|
private static final byte[] origLine;
|
||||||
private static byte[] encodedLine;
|
|
||||||
|
private static final byte[] encodedLine;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
origLine =
|
origLine =
|
||||||
|
@ -190,29 +161,24 @@ public class BASE64Test {
|
||||||
public void testLineLength() throws Exception {
|
public void testLineLength() throws Exception {
|
||||||
for (int i = 0; i < origLine.length; i++) {
|
for (int i = 0; i < origLine.length; i++) {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
OutputStream os = new BASE64EncoderStream(bos);
|
OutputStream os = new BASE64EncoderStream(bos);
|
||||||
os.write(origLine, 0, i);
|
os.write(origLine, 0, i);
|
||||||
os.write(origLine, i, origLine.length - i);
|
os.write(origLine, i, origLine.length - i);
|
||||||
os.write((byte) '0');
|
os.write((byte) '0');
|
||||||
os.flush();
|
os.flush();
|
||||||
os.close();
|
os.close();
|
||||||
|
|
||||||
byte[] line = new byte[encodedLine.length];
|
byte[] line = new byte[encodedLine.length];
|
||||||
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
||||||
assertArrayEquals(encodedLine, line);
|
assertArrayEquals(encodedLine, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < origLine.length; i++) {
|
for (int i = 0; i < origLine.length; i++) {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
OutputStream os = new BASE64EncoderStream(bos);
|
OutputStream os = new BASE64EncoderStream(bos);
|
||||||
os.write(origLine, 0, i);
|
os.write(origLine, 0, i);
|
||||||
os.write(origLine, i, origLine.length - i);
|
os.write(origLine, i, origLine.length - i);
|
||||||
os.write(origLine);
|
os.write(origLine);
|
||||||
os.flush();
|
os.flush();
|
||||||
os.close();
|
os.close();
|
||||||
|
|
||||||
byte[] line = new byte[encodedLine.length];
|
byte[] line = new byte[encodedLine.length];
|
||||||
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
||||||
assertArrayEquals(encodedLine, line);
|
assertArrayEquals(encodedLine, line);
|
||||||
|
@ -220,30 +186,28 @@ public class BASE64Test {
|
||||||
|
|
||||||
for (int i = 1; i < 5; i++) {
|
for (int i = 1; i < 5; i++) {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
OutputStream os = new BASE64EncoderStream(bos);
|
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((byte) '0');
|
||||||
|
}
|
||||||
os.write(origLine, i, origLine.length - i);
|
os.write(origLine, i, origLine.length - i);
|
||||||
os.write((byte) '0');
|
os.write((byte) '0');
|
||||||
os.flush();
|
os.flush();
|
||||||
os.close();
|
os.close();
|
||||||
|
|
||||||
byte[] line = new byte[encodedLine.length];
|
byte[] line = new byte[encodedLine.length];
|
||||||
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
||||||
assertArrayEquals(encodedLine, line);
|
assertArrayEquals(encodedLine, line);
|
||||||
}
|
}
|
||||||
for (int i = origLine.length - 5; i < origLine.length; i++) {
|
for (int i = origLine.length - 5; i < origLine.length; i++) {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
OutputStream os = new BASE64EncoderStream(bos);
|
OutputStream os = new BASE64EncoderStream(bos);
|
||||||
os.write(origLine, 0, i);
|
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.write((byte) '0');
|
os.write((byte) '0');
|
||||||
os.flush();
|
os.flush();
|
||||||
os.close();
|
os.close();
|
||||||
|
|
||||||
byte[] line = new byte[encodedLine.length];
|
byte[] line = new byte[encodedLine.length];
|
||||||
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
System.arraycopy(bos.toByteArray(), 0, line, 0, line.length);
|
||||||
assertArrayEquals(encodedLine, line);
|
assertArrayEquals(encodedLine, line);
|
||||||
|
@ -256,19 +220,9 @@ public class BASE64Test {
|
||||||
for (int i = 0; i < 1000; i++)
|
for (int i = 0; i < 1000; i++)
|
||||||
decoded[i] = (byte) 'A';
|
decoded[i] = (byte) 'A';
|
||||||
byte[] encoded = Base64.getEncoder().encode(decoded);
|
byte[] encoded = Base64.getEncoder().encode(decoded);
|
||||||
// Exceed InputStream.DEFAULT_BUFFER_SIZE
|
BASE64DecoderStream sut = new BASE64DecoderStream(new ByteArrayInputStream(encoded));
|
||||||
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...
|
|
||||||
int n = sut.read(decoded, 0, 0);
|
int n = sut.read(decoded, 0, 0);
|
||||||
assertEquals(n, 0);
|
assertEquals(0, n);
|
||||||
|
|
||||||
// Exercise
|
|
||||||
//byte[] result = sut.readAllBytes();
|
|
||||||
// Verify
|
|
||||||
//assertArrayEquals(decoded, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -286,8 +240,6 @@ public class BASE64Test {
|
||||||
off += got;
|
off += got;
|
||||||
need -= 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,
|
private static void compare(String name, String type,
|
||||||
byte[] buf, byte[] nbuf) {
|
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);
|
assertEquals(buf.length, nbuf.length);
|
||||||
for (int i = 0; i < buf.length; i++) {
|
for (int i = 0; i < buf.length; i++) {
|
||||||
assertEquals(buf[i], nbuf[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.MimeMessage;
|
||||||
import jakarta.mail.internet.MimeMultipart;
|
import jakarta.mail.internet.MimeMultipart;
|
||||||
import jakarta.mail.internet.MimePart;
|
import jakarta.mail.internet.MimePart;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.xbib.net.mail.test.test.AsciiStringInputStream;
|
import org.xbib.net.mail.test.test.AsciiStringInputStream;
|
||||||
|
|
||||||
|
@ -34,17 +33,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
*/
|
*/
|
||||||
public class ContentTypeCleanerTest {
|
public class ContentTypeCleanerTest {
|
||||||
|
|
||||||
private static Session s = Session.getInstance(new Properties());
|
private static final Session s = Session.getInstance(new Properties());
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void before() {
|
|
||||||
System.out.println("ContentTypeCleaner");
|
|
||||||
System.setProperty("mail.mime.contenttypehandler",
|
|
||||||
ContentTypeCleanerTest.class.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGarbage() throws Exception {
|
public void testGarbage() throws Exception {
|
||||||
|
System.setProperty("mail.mime.contenttypehandler", ContentTypeCleanerTest.class.getName());
|
||||||
MimeMessage m = createMessage();
|
MimeMessage m = createMessage();
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
BodyPart bp = mp.getBodyPart(0);
|
BodyPart bp = mp.getBodyPart(0);
|
||||||
|
@ -54,6 +47,7 @@ public class ContentTypeCleanerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValid() throws Exception {
|
public void testValid() throws Exception {
|
||||||
|
System.setProperty("mail.mime.contenttypehandler", ContentTypeCleanerTest.class.getName());
|
||||||
MimeMessage m = createMessage();
|
MimeMessage m = createMessage();
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
BodyPart bp = mp.getBodyPart(1);
|
BodyPart bp = mp.getBodyPart(1);
|
||||||
|
@ -63,6 +57,7 @@ public class ContentTypeCleanerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEmpty() throws Exception {
|
public void testEmpty() throws Exception {
|
||||||
|
System.setProperty("mail.mime.contenttypehandler", ContentTypeCleanerTest.class.getName());
|
||||||
MimeMessage m = createMessage();
|
MimeMessage m = createMessage();
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
BodyPart bp = mp.getBodyPart(2);
|
BodyPart bp = mp.getBodyPart(2);
|
||||||
|
@ -71,10 +66,12 @@ public class ContentTypeCleanerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String cleanContentType(MimePart mp, String contentType) {
|
public static String cleanContentType(MimePart mp, String contentType) {
|
||||||
if (contentType == null)
|
if (contentType == null) {
|
||||||
return null;
|
return null;
|
||||||
if (contentType.equals("complete garbage"))
|
}
|
||||||
|
if (contentType.equals("complete garbage")) {
|
||||||
return "text/plain";
|
return "text/plain";
|
||||||
|
}
|
||||||
return contentType;
|
return contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,29 +16,18 @@
|
||||||
|
|
||||||
package org.xbib.net.mail.test.util;
|
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;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that the "mail.mime.decodeparameters" System property
|
* Test that the "mail.mime.decodeparameters" System property
|
||||||
* causes the parameters to be properly decoded.
|
* causes the parameters to be properly decoded.
|
||||||
*/
|
*/
|
||||||
public class DecodeParametersTest extends ParameterListDecode {
|
public class DecodeParametersTest extends ParameterListDecodeTest {
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void before() {
|
|
||||||
System.setProperty("mail.mime.decodeparameters", "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDecode() throws Exception {
|
public void testDecode() throws Exception {
|
||||||
|
System.setProperty("mail.mime.decodeparameters", "true");
|
||||||
testDecode("paramdata");
|
testDecode("paramdata");
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void after() {
|
|
||||||
// should be unnecessary
|
|
||||||
System.clearProperty("mail.mime.decodeparameters");
|
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;
|
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 org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test "mail.mime.encodefilename" System property set.
|
* 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 final Logger logger = Logger.getLogger(EncodeFileNameTest.class.getName());
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Override
|
|
||||||
public void test() throws Exception {
|
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();
|
MimeBodyPartPublicUpdateHeaders mbp = new MimeBodyPartPublicUpdateHeaders();
|
||||||
mbp.setText("test");
|
mbp.setText("test");
|
||||||
mbp.setFileName(fileName);
|
mbp.setFileName(fileName);
|
||||||
mbp.updateHeaders();
|
mbp.updateHeaders();
|
||||||
String h = mbp.getHeader("Content-Type", "");
|
String h = mbp.getHeader("Content-Type", "");
|
||||||
|
logger.log(Level.INFO, "h = " + h);
|
||||||
assertTrue(h.contains("name="));
|
assertTrue(h.contains("name="));
|
||||||
|
// depends on exactly how MimeUtility.encodeText splits long words
|
||||||
|
String expected1 = "=?UTF-8?B?w4DDgcOFw4bDgMOBw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw4DDgcOF?=";
|
||||||
assertTrue(h.contains(expected1));
|
assertTrue(h.contains(expected1));
|
||||||
|
String expected2 = "=?UTF-8?B?w4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5XDlsOYw5nDmsObw5w=?=";
|
||||||
assertTrue(h.contains(expected2));
|
assertTrue(h.contains(expected2));
|
||||||
|
String expected3 = "=?UTF-8?B?w53DnsOfw6DDocOiw6PDpMOlw6bDp8Oow6nDqsOrw6zDrcOuw6/DsMOx?=";
|
||||||
assertTrue(h.contains(expected3));
|
assertTrue(h.contains(expected3));
|
||||||
|
String expected4 = "=?UTF-8?B?w7LDs8O0w7XDtsO4w7nDusO7w7zDvcO+w7/DgMOBw4XDhsOHLmRvYw==?=";
|
||||||
assertTrue(h.contains(expected4));
|
assertTrue(h.contains(expected4));
|
||||||
h = mbp.getHeader("Content-Disposition", "");
|
h = mbp.getHeader("Content-Disposition", "");
|
||||||
assertTrue(h.contains("filename="));
|
assertTrue(h.contains("filename="));
|
||||||
|
@ -63,5 +63,15 @@ public class EncodeFileNameTest extends NoEncodeFileNameTest {
|
||||||
assertTrue(h.contains(expected2));
|
assertTrue(h.contains(expected2));
|
||||||
assertTrue(h.contains(expected3));
|
assertTrue(h.contains(expected3));
|
||||||
assertTrue(h.contains(expected4));
|
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.assertArrayEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,7 +42,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
*/
|
*/
|
||||||
public class MimeBodyPartTest {
|
public class MimeBodyPartTest {
|
||||||
|
|
||||||
private static String[] languages = new String[]{
|
private static final String[] languages = new String[]{
|
||||||
"language1", "language2", "language3", "language4", "language5",
|
"language1", "language2", "language3", "language4", "language5",
|
||||||
"language6", "language7", "language8", "language9", "language10",
|
"language6", "language7", "language8", "language9", "language10",
|
||||||
"language11", "language12", "language13", "language14", "language15"
|
"language11", "language12", "language13", "language14", "language15"
|
||||||
|
@ -57,7 +58,6 @@ public class MimeBodyPartTest {
|
||||||
mbp.setContentLanguage(languages);
|
mbp.setContentLanguage(languages);
|
||||||
String header = mbp.getHeader("Content-Language", ",");
|
String header = mbp.getHeader("Content-Language", ",");
|
||||||
assertTrue(header.indexOf("\r\n") > 0);
|
assertTrue(header.indexOf("\r\n") > 0);
|
||||||
|
|
||||||
String[] langs = mbp.getContentLanguage();
|
String[] langs = mbp.getContentLanguage();
|
||||||
assertArrayEquals(languages, langs);
|
assertArrayEquals(languages, langs);
|
||||||
}
|
}
|
||||||
|
@ -179,11 +179,10 @@ public class MimeBodyPartTest {
|
||||||
"test" +
|
"test" +
|
||||||
"\n";
|
"\n";
|
||||||
MimeBodyPart mbp = new MimeBodyPart(new AsciiStringInputStream(part));
|
MimeBodyPart mbp = new MimeBodyPart(new AsciiStringInputStream(part));
|
||||||
assertEquals("empty C-T-E value", null, mbp.getEncoding());
|
assertNull(mbp.getEncoding());
|
||||||
assertEquals("test\n", mbp.getContent());
|
assertEquals("test\n", mbp.getContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static MimeMessage createMessage(Session s)
|
private static MimeMessage createMessage(Session s)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
String content =
|
String content =
|
||||||
|
@ -199,7 +198,6 @@ public class MimeBodyPartTest {
|
||||||
"test part\n" +
|
"test part\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"-----\n";
|
"-----\n";
|
||||||
|
|
||||||
return new MimeMessage(s, new AsciiStringInputStream(content));
|
return new MimeMessage(s, new AsciiStringInputStream(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class MimeMessageTest {
|
||||||
String addr = "joe@example.com";
|
String addr = "joe@example.com";
|
||||||
MimeMessage m = new MimeMessage(s);
|
MimeMessage m = new MimeMessage(s);
|
||||||
m.setRecipient(TO, new InternetAddress(addr));
|
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);
|
m.setRecipient(TO, (Address) null);
|
||||||
assertArrayEquals(null, m.getRecipients(TO));
|
assertArrayEquals(null, m.getRecipients(TO));
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ public class MimeMessageTest {
|
||||||
String addr = "joe@example.com";
|
String addr = "joe@example.com";
|
||||||
MimeMessage m = new MimeMessage(s);
|
MimeMessage m = new MimeMessage(s);
|
||||||
m.setFrom(new InternetAddress(addr));
|
m.setFrom(new InternetAddress(addr));
|
||||||
assertEquals("From: is set", addr, m.getFrom()[0].toString());
|
assertEquals(addr, m.getFrom()[0].toString());
|
||||||
m.setFrom((Address) null);
|
m.setFrom((Address) null);
|
||||||
assertArrayEquals(null, m.getFrom());
|
assertArrayEquals(null, m.getFrom());
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ public class MimeMessageTest {
|
||||||
String addr = "joe@example.com";
|
String addr = "joe@example.com";
|
||||||
MimeMessage m = new MimeMessage(s);
|
MimeMessage m = new MimeMessage(s);
|
||||||
m.setSender(new InternetAddress(addr));
|
m.setSender(new InternetAddress(addr));
|
||||||
assertEquals("Sender: is set", addr, m.getSender().toString());
|
assertEquals(addr, m.getSender().toString());
|
||||||
m.setSender((Address) null);
|
m.setSender((Address) null);
|
||||||
assertNull(m.getSender());
|
assertNull(m.getSender());
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import org.junit.jupiter.api.Test;
|
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;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +37,10 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||||
*/
|
*/
|
||||||
public class MimeMultipartBCSIndexTest {
|
public class MimeMultipartBCSIndexTest {
|
||||||
|
|
||||||
private String EMLContent = "From: dslztx@gmail.com \n" +
|
@Test
|
||||||
|
public void testBCSTableIndexInconsistency() {
|
||||||
|
try {
|
||||||
|
String EMLContent = "From: dslztx@gmail.com \n" +
|
||||||
"To: dslztx <dslztx@gmail.com>\n" +
|
"To: dslztx <dslztx@gmail.com>\n" +
|
||||||
"Subject: bcs index test \n" +
|
"Subject: bcs index test \n" +
|
||||||
"Date: Sat, 25 Aug 2018 08:35:14 +0800\n" +
|
"Date: Sat, 25 Aug 2018 08:35:14 +0800\n" +
|
||||||
|
@ -62,30 +65,19 @@ public class MimeMultipartBCSIndexTest {
|
||||||
"keT4KSGVsbG8gd29ybGQKPC9ib2R5Pgo8L2h0bWw+\n" +
|
"keT4KSGVsbG8gd29ybGQKPC9ib2R5Pgo8L2h0bWw+\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"------=_000_6675<37><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=------";
|
"------=_000_6675<37><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=------";
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBCSTableIndexInconsistency() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
InputStream in = new ByteArrayInputStream(EMLContent.getBytes(StandardCharsets.ISO_8859_1));
|
InputStream in = new ByteArrayInputStream(EMLContent.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
|
||||||
Session session = Session.getDefaultInstance(new Properties());
|
Session session = Session.getDefaultInstance(new Properties());
|
||||||
|
MimeMessage mimeMessage = new MimeMessage(session, in);
|
||||||
MimeMessage mimeMessage = new MimeMessage(session,
|
|
||||||
in);
|
|
||||||
|
|
||||||
MimeMultipart topMultipart = (MimeMultipart) mimeMessage.getContent();
|
MimeMultipart topMultipart = (MimeMultipart) mimeMessage.getContent();
|
||||||
|
assertEquals(2, topMultipart.getCount());
|
||||||
assertTrue(topMultipart.getCount() == 2);
|
assertEquals("hello world", topMultipart.getBodyPart(0).getContent());
|
||||||
assertTrue(topMultipart.getBodyPart(0).getContent().equals("hello world"));
|
assertEquals("<html>\n" +
|
||||||
assertTrue(topMultipart.getBodyPart(1).getContent().equals("<html>\n" +
|
|
||||||
"<header><title>This is title</title></header>\n" +
|
"<header><title>This is title</title></header>\n" +
|
||||||
"<body>\n" +
|
"<body>\n" +
|
||||||
"Hello world\n" +
|
"Hello world\n" +
|
||||||
"</body>\n" +
|
"</body>\n" +
|
||||||
"</html>"));
|
"</html>", topMultipart.getBodyPart(1).getContent());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,12 +40,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class MimeMultipartParseTest {
|
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 int maxsize = 10000;
|
||||||
private static final String data =
|
private static final String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParse() throws Exception {
|
public void testParse() throws Exception {
|
||||||
|
|
|
@ -37,7 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
*/
|
*/
|
||||||
public class MimeMultipartPreambleTest {
|
public class MimeMultipartPreambleTest {
|
||||||
@SuppressWarnings({"SingleCharacterStringConcatenation"})
|
@SuppressWarnings({"SingleCharacterStringConcatenation"})
|
||||||
private String THREE_PART_MAIL =
|
private final String THREE_PART_MAIL =
|
||||||
"From: user1@example.com\n" +
|
"From: user1@example.com\n" +
|
||||||
"To: user2@example.com\n" +
|
"To: user2@example.com\n" +
|
||||||
"Subject: Receipts\n" +
|
"Subject: Receipts\n" +
|
||||||
|
@ -99,20 +99,13 @@ public class MimeMultipartPreambleTest {
|
||||||
new ByteArrayInputStream(text.getBytes(StandardCharsets.US_ASCII)));
|
new ByteArrayInputStream(text.getBytes(StandardCharsets.US_ASCII)));
|
||||||
|
|
||||||
MimeMultipart topMultipart = (MimeMultipart) mimeMessage.getContent();
|
MimeMultipart topMultipart = (MimeMultipart) mimeMessage.getContent();
|
||||||
assertEquals("This is a multi-part message in MIME format.",
|
assertEquals("This is a multi-part message in MIME format.", topMultipart.getPreamble().trim());
|
||||||
topMultipart.getPreamble().trim());
|
|
||||||
assertEquals(3, topMultipart.getCount());
|
assertEquals(3, topMultipart.getCount());
|
||||||
|
|
||||||
BodyPart part1 = topMultipart.getBodyPart(0);
|
BodyPart part1 = topMultipart.getBodyPart(0);
|
||||||
assertEquals("Wrong content type for part 1",
|
assertEquals("text/plain;charset=\"us-ascii\"", part1.getContentType(), "Wrong content type for part 1");
|
||||||
"text/plain;charset=\"us-ascii\"", part1.getContentType());
|
|
||||||
|
|
||||||
BodyPart part2 = topMultipart.getBodyPart(1);
|
BodyPart part2 = topMultipart.getBodyPart(1);
|
||||||
assertEquals("Wrong content type for part 2",
|
assertEquals("application/pdf;name=\"Receipt 1.pdf\"", part2.getContentType(), "Wrong content type for part 2");
|
||||||
"application/pdf;name=\"Receipt 1.pdf\"", part2.getContentType());
|
|
||||||
|
|
||||||
BodyPart part3 = topMultipart.getBodyPart(2);
|
BodyPart part3 = topMultipart.getBodyPart(2);
|
||||||
assertEquals("Wrong content type for part 3",
|
assertEquals("application/pdf;name=\"Receipt 2.pdf\"", part3.getContentType(), "Wrong content type for part 3");
|
||||||
"application/pdf;name=\"Receipt 2.pdf\"", part3.getContentType());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,8 @@ import org.xbib.net.mail.test.test.NullOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
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.
|
* Test the properties that control the MimeMultipart class.
|
||||||
|
@ -38,7 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
*/
|
*/
|
||||||
public class MimeMultipartPropertyTest {
|
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.
|
* Clear all properties before each test.
|
||||||
|
@ -52,7 +53,7 @@ public class MimeMultipartPropertyTest {
|
||||||
public void testBoundary() throws Exception {
|
public void testBoundary() throws Exception {
|
||||||
MimeMessage m = createMessage("x", "x", true);
|
MimeMessage m = createMessage("x", "x", true);
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
assertEquals(mp.getCount(), 2);
|
assertEquals(2, mp.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -61,41 +62,43 @@ public class MimeMultipartPropertyTest {
|
||||||
"mail.mime.multipart.ignoreexistingboundaryparameter", "true");
|
"mail.mime.multipart.ignoreexistingboundaryparameter", "true");
|
||||||
MimeMessage m = createMessage("x", "-", true);
|
MimeMessage m = createMessage("x", "-", true);
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
assertEquals(mp.getCount(), 2);
|
assertEquals(2, mp.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBoundaryMissing() throws Exception {
|
public void testBoundaryMissing() throws Exception {
|
||||||
MimeMessage m = createMessage(null, "x", true);
|
MimeMessage m = createMessage(null, "x", true);
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
assertEquals(mp.getCount(), 2);
|
assertEquals(2, mp.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // (expected = MessagingException.class)
|
@Test
|
||||||
public void testBoundaryMissingEx() throws Exception {
|
public void testBoundaryMissingEx() {
|
||||||
System.setProperty(
|
assertThrows(MessagingException.class, () -> {
|
||||||
"mail.mime.multipart.ignoremissingboundaryparameter", "false");
|
System.setProperty("mail.mime.multipart.ignoremissingboundaryparameter", "false");
|
||||||
MimeMessage m = createMessage(null, "x", true);
|
MimeMessage m = createMessage(null, "x", true);
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
mp.getCount(); // throw exception
|
mp.getCount(); // throw exception
|
||||||
assertTrue(false); // never get here
|
fail(); // never get here
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEndBoundaryMissing() throws Exception {
|
public void testEndBoundaryMissing() throws Exception {
|
||||||
MimeMessage m = createMessage("x", "x", false);
|
MimeMessage m = createMessage("x", "x", false);
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
assertEquals(mp.getCount(), 2);
|
assertEquals(2, mp.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // (expected = MessagingException.class)
|
@Test
|
||||||
public void testEndBoundaryMissingEx() throws Exception {
|
public void testEndBoundaryMissingEx() {
|
||||||
System.setProperty(
|
assertThrows(MessagingException.class, () -> {
|
||||||
"mail.mime.multipart.ignoremissingendboundary", "false");
|
System.setProperty("mail.mime.multipart.ignoremissingendboundary", "false");
|
||||||
MimeMessage m = createMessage("x", "x", false);
|
MimeMessage m = createMessage("x", "x", false);
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
mp.getCount(); // throw exception
|
mp.getCount(); // throw exception
|
||||||
assertTrue(false); // never get here
|
fail(); // never get here
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -103,15 +106,17 @@ public class MimeMultipartPropertyTest {
|
||||||
System.setProperty("mail.mime.multipart.allowempty", "true");
|
System.setProperty("mail.mime.multipart.allowempty", "true");
|
||||||
MimeMessage m = createEmptyMessage();
|
MimeMessage m = createEmptyMessage();
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
assertEquals(mp.getCount(), 0);
|
assertEquals(0, mp.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test //(expected = MessagingException.class)
|
@Test //(expected = MessagingException.class)
|
||||||
public void testAllowEmptyEx() throws Exception {
|
public void testAllowEmptyEx() throws Exception {
|
||||||
|
assertThrows(MessagingException.class, () -> {
|
||||||
MimeMessage m = createEmptyMessage();
|
MimeMessage m = createEmptyMessage();
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
mp.getCount(); // throw exception
|
mp.getCount(); // throw exception
|
||||||
assertTrue(false); // never get here
|
fail(); // never get here
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -121,16 +126,18 @@ public class MimeMultipartPropertyTest {
|
||||||
MimeMultipart mp = new MimeMultipart();
|
MimeMultipart mp = new MimeMultipart();
|
||||||
m.setContent(mp);
|
m.setContent(mp);
|
||||||
m.writeTo(new NullOutputStream());
|
m.writeTo(new NullOutputStream());
|
||||||
assertEquals(mp.getCount(), 0);
|
assertEquals(0, mp.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test //(expected = IOException.class)
|
@Test //(expected = IOException.class)
|
||||||
public void testAllowEmptyOutputEx() throws Exception {
|
public void testAllowEmptyOutputEx() throws Exception {
|
||||||
|
assertThrows(IOException.class, () -> {
|
||||||
MimeMessage m = new MimeMessage(s);
|
MimeMessage m = new MimeMessage(s);
|
||||||
MimeMultipart mp = new MimeMultipart();
|
MimeMultipart mp = new MimeMultipart();
|
||||||
m.setContent(mp);
|
m.setContent(mp);
|
||||||
m.writeTo(new NullOutputStream()); // throw exception
|
m.writeTo(new NullOutputStream()); // throw exception
|
||||||
assertTrue(false); // never get here
|
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 that utf-16be data is encoded with base64 and not quoted-printable.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testNonAsciiEncoding() throws Exception {
|
public void testNonAsciiEncoding() {
|
||||||
DataSource ds = new ByteArrayDataSource(utf16beBytes,
|
DataSource ds = new ByteArrayDataSource(utf16beBytes,
|
||||||
"text/plain; charset=utf-16be");
|
"text/plain; charset=utf-16be");
|
||||||
String en = MimeUtility.getEncoding(ds);
|
String en = MimeUtility.getEncoding(ds);
|
||||||
|
@ -79,7 +79,7 @@ public class MimeUtilityTest {
|
||||||
* throw NullPointerException.
|
* throw NullPointerException.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void getEncodingMissingFile() throws Exception {
|
public void getEncodingMissingFile() {
|
||||||
File missing = new File(getClass().getName());
|
File missing = new File(getClass().getName());
|
||||||
assertFalse(missing.exists());
|
assertFalse(missing.exists());
|
||||||
FileDataSource fds = new FileDataSource(missing);
|
FileDataSource fds = new FileDataSource(missing);
|
||||||
|
@ -106,22 +106,16 @@ public class MimeUtilityTest {
|
||||||
throw expect;
|
throw expect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayDataSource bads = new ByteArrayDataSource("", content);
|
ByteArrayDataSource bads = new ByteArrayDataSource("", content);
|
||||||
bads.setName(null);
|
bads.setName(null);
|
||||||
assertTrue(encodings.contains(MimeUtility.getEncoding(bads)));
|
assertTrue(encodings.contains(MimeUtility.getEncoding(bads)));
|
||||||
assertTrue(encodings.contains(
|
assertTrue(encodings.contains(MimeUtility.getEncoding(new DataHandler(bads))));
|
||||||
MimeUtility.getEncoding(new DataHandler(bads))));
|
|
||||||
|
|
||||||
bads.setName("");
|
bads.setName("");
|
||||||
assertTrue(encodings.contains(MimeUtility.getEncoding(bads)));
|
assertTrue(encodings.contains(MimeUtility.getEncoding(bads)));
|
||||||
assertTrue(encodings.contains(
|
assertTrue(encodings.contains(MimeUtility.getEncoding(new DataHandler(bads))));
|
||||||
MimeUtility.getEncoding(new DataHandler(bads))));
|
|
||||||
|
|
||||||
bads.setName(getClass().getName());
|
bads.setName(getClass().getName());
|
||||||
assertTrue(encodings.contains(MimeUtility.getEncoding(bads)));
|
assertTrue(encodings.contains(MimeUtility.getEncoding(bads)));
|
||||||
assertTrue(encodings.contains(
|
assertTrue(encodings.contains(MimeUtility.getEncoding(new DataHandler(bads))));
|
||||||
MimeUtility.getEncoding(new DataHandler(bads))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,14 +133,14 @@ public class MimeUtilityTest {
|
||||||
String en = MimeUtility.encodeText(sp, "utf-8", "B");
|
String en = MimeUtility.encodeText(sp, "utf-8", "B");
|
||||||
String dt = MimeUtility.decodeText(en);
|
String dt = MimeUtility.decodeText(en);
|
||||||
// encoding it and decoding it shouldn't change it
|
// encoding it and decoding it shouldn't change it
|
||||||
assertEquals(dt, sp);
|
assertEquals(sp, dt);
|
||||||
String[] w = en.split(" ");
|
String[] w = en.split(" ");
|
||||||
// the first word should end with the second half of a pair
|
// the first word should end with the second half of a pair
|
||||||
String dw = MimeUtility.decodeWord(w[0]);
|
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
|
// and the second word should start with the first half of a pair
|
||||||
dw = MimeUtility.decodeWord(w[1]);
|
dw = MimeUtility.decodeWord(w[1]);
|
||||||
assertTrue(dw.charAt(0) == '\ud801');
|
assertEquals('\ud801', dw.charAt(0));
|
||||||
|
|
||||||
// test various string lengths
|
// test various string lengths
|
||||||
int ch = 0xFE000;
|
int ch = 0xFE000;
|
||||||
|
@ -171,15 +165,14 @@ public class MimeUtilityTest {
|
||||||
String badcp936 = "=?cp936?B?xbfUqqLjIChFVVIpttK7u4EwhDYgKENOWSk=?=";
|
String badcp936 = "=?cp936?B?xbfUqqLjIChFVVIpttK7u4EwhDYgKENOWSk=?=";
|
||||||
String good = "=?gb18030?B?xbfUqqLjIChFVVIpttK7u4EwhDYgKENOWSk=?=";
|
String good = "=?gb18030?B?xbfUqqLjIChFVVIpttK7u4EwhDYgKENOWSk=?=";
|
||||||
String goodDecoded = MimeUtility.decodeWord(good);
|
String goodDecoded = MimeUtility.decodeWord(good);
|
||||||
|
assertEquals(goodDecoded, MimeUtility.decodeWord(badgb2312));
|
||||||
assertEquals("gb2312", goodDecoded, MimeUtility.decodeWord(badgb2312));
|
assertEquals(goodDecoded, MimeUtility.decodeWord(badgbk));
|
||||||
assertEquals("gbk", goodDecoded, MimeUtility.decodeWord(badgbk));
|
assertEquals(goodDecoded, MimeUtility.decodeWord(badms936));
|
||||||
assertEquals("ms936", goodDecoded, MimeUtility.decodeWord(badms936));
|
assertEquals(goodDecoded, MimeUtility.decodeWord(badcp936));
|
||||||
assertEquals("cp936", goodDecoded, MimeUtility.decodeWord(badcp936));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocaleISO885915() throws Exception {
|
public void testLocaleISO885915() {
|
||||||
assertEquals("ISO-8859-15", MimeUtility.javaCharset("en_US.iso885915"));
|
assertEquals("ISO-8859-15", MimeUtility.javaCharset("en_US.iso885915"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,6 @@ public class ModifyMessageTest {
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
m.setHeader("a", "b");
|
m.setHeader("a", "b");
|
||||||
m.saveChanges();
|
m.saveChanges();
|
||||||
|
|
||||||
MimeMessage m2 = new MimeMessage(m);
|
MimeMessage m2 = new MimeMessage(m);
|
||||||
assertEquals("b", m2.getHeader("a", null));
|
assertEquals("b", m2.getHeader("a", null));
|
||||||
}
|
}
|
||||||
|
@ -54,7 +53,6 @@ public class ModifyMessageTest {
|
||||||
MimeMultipart mp = (MimeMultipart) m.getContent();
|
MimeMultipart mp = (MimeMultipart) m.getContent();
|
||||||
m.setHeader("Subject", "test");
|
m.setHeader("Subject", "test");
|
||||||
m.saveChanges();
|
m.saveChanges();
|
||||||
|
|
||||||
MimeMessage m2 = new MimeMessage(m);
|
MimeMessage m2 = new MimeMessage(m);
|
||||||
assertEquals("test", m2.getHeader("Subject", null));
|
assertEquals("test", m2.getHeader("Subject", null));
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
|
|
||||||
package org.xbib.net.mail.test.util;
|
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 org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
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
|
* Test "mail.mime.encodefilename" System property not set and
|
||||||
* "mail.mime.encodeparameters" set to "false".
|
* "mail.mime.encodeparameters" set to "false".
|
||||||
*/
|
*/
|
||||||
public class NoEncodeFileNameNoEncodeParametersTest extends NoEncodeFileNameTest {
|
public class NoEncodeFileNameNoEncodeParametersTest {
|
||||||
|
|
||||||
@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");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
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();
|
MimeBodyPartPublicUpdateHeaders mbp = new MimeBodyPartPublicUpdateHeaders();
|
||||||
mbp.setText("test");
|
mbp.setText("test");
|
||||||
mbp.setFileName(fileName);
|
mbp.setFileName(fileName);
|
||||||
|
@ -47,5 +48,16 @@ public class NoEncodeFileNameNoEncodeParametersTest extends NoEncodeFileNameTest
|
||||||
h = mbp.getHeader("Content-Disposition", "");
|
h = mbp.getHeader("Content-Disposition", "");
|
||||||
assertTrue(h.contains("filename="));
|
assertTrue(h.contains("filename="));
|
||||||
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.MimeBodyPart;
|
||||||
import jakarta.mail.internet.MimeUtility;
|
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 org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@ -31,27 +28,23 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
*/
|
*/
|
||||||
public class NoEncodeFileNameTest {
|
public class NoEncodeFileNameTest {
|
||||||
|
|
||||||
protected static String fileName;
|
@Test
|
||||||
|
public void test() throws Exception {
|
||||||
// a bunch of non-ASCII characters
|
System.setProperty("mail.mime.charset", "utf-8");
|
||||||
private static String encodedFileName =
|
System.clearProperty("mail.mime.encodefilename");
|
||||||
"=?utf-8?B?w4DDgcOFw4bDgMOBw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw4DD" +
|
String encodedFileName = "=?utf-8?B?w4DDgcOFw4bDgMOBw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw4DD" +
|
||||||
"gcOFw4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5XDlsOYw5nDmsObw5" +
|
"gcOFw4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5XDlsOYw5nDmsObw5" +
|
||||||
"zDncOew5/DoMOhw6LDo8Okw6XDpsOnw6jDqcOqw6vDrMOtw67Dr8Oww7HDssOz" +
|
"zDncOew5/DoMOhw6LDo8Okw6XDpsOnw6jDqcOqw6vDrMOtw67Dr8Oww7HDssOz" +
|
||||||
"w7TDtcO2w7jDucO6w7vDvMO9w77Dv8OAw4HDhcOGw4cuZG9j?=";
|
"w7TDtcO2w7jDucO6w7vDvMO9w77Dv8OAw4HDhcOGw4cuZG9j?=";
|
||||||
|
String fileName = MimeUtility.decodeText(encodedFileName);
|
||||||
static {
|
MimeBodyPartPublicUpdateHeaders mbp = new MimeBodyPartPublicUpdateHeaders();
|
||||||
try {
|
mbp.setText("test");
|
||||||
fileName = MimeUtility.decodeText(encodedFileName);
|
mbp.setFileName(fileName);
|
||||||
} catch (UnsupportedEncodingException ex) {
|
mbp.updateHeaders();
|
||||||
// should never happen
|
String h = mbp.getHeader("Content-Type", "");
|
||||||
}
|
assertTrue(h.contains("name*="));
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 2231 encoding
|
// RFC 2231 encoding
|
||||||
private static String expected =
|
String expected = "UTF-8''%C3%80%C3%81%C3%85%C3%86%C3%80%C3%81%C3%85%C3%86%C3%87%C3%88" +
|
||||||
"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%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%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%91%C3%92%C3%93%C3%94%C3%95%C3%96%C3%98%C3%99%C3%9A%C3%9B%C3%9C" +
|
||||||
|
@ -59,37 +52,16 @@ public class NoEncodeFileNameTest {
|
||||||
"%C3%A8%C3%A9%C3%AA%C3%AB%C3%AC%C3%AD%C3%AE%C3%AF%C3%B0%C3%B1%C3%B2" +
|
"%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%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";
|
"%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 {
|
|
||||||
MimeBodyPartPublicUpdateHeaders mbp = new MimeBodyPartPublicUpdateHeaders();
|
|
||||||
mbp.setText("test");
|
|
||||||
mbp.setFileName(fileName);
|
|
||||||
mbp.updateHeaders();
|
|
||||||
String h = mbp.getHeader("Content-Type", "");
|
|
||||||
assertTrue(h.contains("name*="));
|
|
||||||
assertTrue(h.contains(expected));
|
assertTrue(h.contains(expected));
|
||||||
h = mbp.getHeader("Content-Disposition", "");
|
h = mbp.getHeader("Content-Disposition", "");
|
||||||
assertTrue(h.contains("filename*="));
|
assertTrue(h.contains("filename*="));
|
||||||
assertTrue(h.contains(expected));
|
assertTrue(h.contains(expected));
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void after() {
|
|
||||||
// should be unnecessary
|
|
||||||
System.clearProperty("mail.mime.charset");
|
System.clearProperty("mail.mime.charset");
|
||||||
System.clearProperty("mail.mime.encodefilename");
|
System.clearProperty("mail.mime.encodefilename");
|
||||||
System.clearProperty("mail.mime.encodeparameters");
|
System.clearProperty("mail.mime.encodeparameters");
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MimeBodyPartPublicUpdateHeaders extends MimeBodyPart {
|
private static class MimeBodyPartPublicUpdateHeaders extends MimeBodyPart {
|
||||||
@Override
|
@Override
|
||||||
public void updateHeaders() throws MessagingException {
|
public void updateHeaders() throws MessagingException {
|
||||||
super.updateHeaders();
|
super.updateHeaders();
|
||||||
|
|
|
@ -33,7 +33,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
*/
|
*/
|
||||||
public class NonAsciiBoundaryTest {
|
public class NonAsciiBoundaryTest {
|
||||||
|
|
||||||
private static Session s = Session.getInstance(new Properties());
|
private static final Session s = Session.getInstance(new Properties());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
|
|
|
@ -20,7 +20,6 @@ import jakarta.activation.DataHandler;
|
||||||
import jakarta.mail.Folder;
|
import jakarta.mail.Folder;
|
||||||
import jakarta.mail.Message;
|
import jakarta.mail.Message;
|
||||||
import jakarta.mail.Session;
|
import jakarta.mail.Session;
|
||||||
import jakarta.mail.Store;
|
|
||||||
import jakarta.mail.internet.ContentType;
|
import jakarta.mail.internet.ContentType;
|
||||||
import jakarta.mail.internet.MimeMessage;
|
import jakarta.mail.internet.MimeMessage;
|
||||||
import jakarta.mail.internet.ParameterList;
|
import jakarta.mail.internet.ParameterList;
|
||||||
|
@ -29,6 +28,7 @@ import jakarta.mail.util.ByteArrayDataSource;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
@ -45,20 +45,24 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
* @author Bill Shannon
|
* @author Bill Shannon
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class ParameterListDecode {
|
class ParameterListDecodeTest {
|
||||||
|
|
||||||
static boolean gen_test_input = false; // output good for input to -p
|
static boolean gen_test_input = false; // output good for input to -p
|
||||||
static boolean test_mail = false; // test using a mail server
|
static boolean test_mail = false; // test using a mail server
|
||||||
static int errors = 0; // number of errors detected
|
static int errors = 0; // number of errors detected
|
||||||
static Session session;
|
static Session session;
|
||||||
static Store store;
|
|
||||||
static Folder folder;
|
static Folder folder;
|
||||||
|
|
||||||
static boolean junit;
|
static boolean junit;
|
||||||
|
|
||||||
protected void testDecode(String paramData) throws Exception {
|
protected void testDecode(String paramData) throws Exception {
|
||||||
junit = true;
|
junit = true;
|
||||||
parse(new BufferedReader(new InputStreamReader(
|
InputStream inputStream = getClass().getResourceAsStream(paramData);
|
||||||
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.
|
* to test against most existing UNIX mailboxes.
|
||||||
*/
|
*/
|
||||||
public static void parse(BufferedReader in) throws Exception {
|
public static void parse(BufferedReader in) throws Exception {
|
||||||
String header = "";
|
StringBuilder header = new StringBuilder();
|
||||||
|
|
||||||
for (; ; ) {
|
for (; ; ) {
|
||||||
String s = in.readLine();
|
String s = in.readLine();
|
||||||
if (s != null && !s.isEmpty()) {
|
if (s != null && !s.isEmpty()) {
|
||||||
char c = s.charAt(0);
|
char c = s.charAt(0);
|
||||||
if (c == ' ' || c == '\t') {
|
if (c == ' ' || c == '\t') {
|
||||||
// a continuation line, add it to the current header
|
// a continuation line, add it to the current header
|
||||||
header += '\n' + s;
|
header.append('\n').append(s);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// "s" is the next header, "header" is the last complete header
|
// "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;
|
int i;
|
||||||
String[] expect = null;
|
String[] expect = null;
|
||||||
if (s != null && s.startsWith("Expect: ")) {
|
if (s != null && s.startsWith("Expect: ")) {
|
||||||
|
@ -91,7 +94,7 @@ class ParameterListDecode {
|
||||||
expect[i] = decode(trim(in.readLine()));
|
expect[i] = decode(trim(in.readLine()));
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
try {
|
try {
|
||||||
if (s.substring(8, 17).equals("Exception")) {
|
if (s.startsWith("Exception", 8)) {
|
||||||
expect = new String[1];
|
expect = new String[1];
|
||||||
expect[0] = "Exception";
|
expect[0] = "Exception";
|
||||||
}
|
}
|
||||||
|
@ -100,7 +103,7 @@ class ParameterListDecode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = header.indexOf(':');
|
i = header.toString().indexOf(':');
|
||||||
try {
|
try {
|
||||||
test(header.substring(0, i), header.substring(i + 2),
|
test(header.substring(0, i), header.substring(i + 2),
|
||||||
expect);
|
expect);
|
||||||
|
@ -118,7 +121,7 @@ class ParameterListDecode {
|
||||||
if (s == null)
|
if (s == null)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
header = s;
|
header = new StringBuilder(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,8 +211,9 @@ class ParameterListDecode {
|
||||||
if (expect != null &&
|
if (expect != null &&
|
||||||
(expect.length != 1 || !expect[0].equals("Exception"))) {
|
(expect.length != 1 || !expect[0].equals("Exception"))) {
|
||||||
out.println("Expected " + expect.length + " parameters");
|
out.println("Expected " + expect.length + " parameters");
|
||||||
for (int i = 0; i < expect.length; i++)
|
for (String s : expect) {
|
||||||
out.println("\tExpected:\t" + expect[i]);
|
out.println("\tExpected:\t" + s);
|
||||||
|
}
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,10 +221,8 @@ class ParameterListDecode {
|
||||||
if (gen_test_input && test_mail) {
|
if (gen_test_input && test_mail) {
|
||||||
MimeMessage msg = new MimeMessage(session);
|
MimeMessage msg = new MimeMessage(session);
|
||||||
byte[] buf = bos.toByteArray();
|
byte[] buf = bos.toByteArray();
|
||||||
msg.setDataHandler(new DataHandler(
|
msg.setDataHandler(new DataHandler(new ByteArrayDataSource(buf, value)));
|
||||||
new ByteArrayDataSource(buf, value)));
|
|
||||||
msg.saveChanges();
|
msg.saveChanges();
|
||||||
//msg.writeTo(System.out);
|
|
||||||
folder.appendMessages(new Message[]{msg});
|
folder.appendMessages(new Message[]{msg});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,29 +16,18 @@
|
||||||
|
|
||||||
package org.xbib.net.mail.test.util;
|
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;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that the "mail.mime.parameters.strict" System property
|
* Test that the "mail.mime.parameters.strict" System property
|
||||||
* set to false allows bogus parameters to be parsed.
|
* set to false allows bogus parameters to be parsed.
|
||||||
*/
|
*/
|
||||||
class ParametersNoStrictTest extends ParameterListDecode {
|
class ParametersNoStrictTest extends ParameterListDecodeTest {
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void before() {
|
|
||||||
System.setProperty("mail.mime.parameters.strict", "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDecode() throws Exception {
|
public void testDecode() throws Exception {
|
||||||
|
System.setProperty("mail.mime.parameters.strict", "false");
|
||||||
testDecode("paramdatanostrict");
|
testDecode("paramdatanostrict");
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void after() {
|
|
||||||
// should be unnecessary
|
|
||||||
System.clearProperty("mail.mime.parameters.strict");
|
System.clearProperty("mail.mime.parameters.strict");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ import java.util.Properties;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
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.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,48 +36,48 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
public class PropUtilTest {
|
public class PropUtilTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInt() throws Exception {
|
public void testInt() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty("test", "2");
|
props.setProperty("test", "2");
|
||||||
assertEquals(PropUtil.getIntProperty(props, "test", 1), 2);
|
assertEquals(2, PropUtil.getIntProperty(props, "test", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIntDef() throws Exception {
|
public void testIntDef() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
assertEquals(PropUtil.getIntProperty(props, "test", 1), 1);
|
assertEquals(1, PropUtil.getIntProperty(props, "test", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIntDefProp() throws Exception {
|
public void testIntDefProp() {
|
||||||
Properties defprops = new Properties();
|
Properties defprops = new Properties();
|
||||||
defprops.setProperty("test", "2");
|
defprops.setProperty("test", "2");
|
||||||
Properties props = new Properties(defprops);
|
Properties props = new Properties(defprops);
|
||||||
assertEquals(PropUtil.getIntProperty(props, "test", 1), 2);
|
assertEquals(2, PropUtil.getIntProperty(props, "test", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInteger() throws Exception {
|
public void testInteger() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.put("test", 2);
|
props.put("test", 2);
|
||||||
assertEquals(PropUtil.getIntProperty(props, "test", 1), 2);
|
assertEquals(2, PropUtil.getIntProperty(props, "test", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBool() throws Exception {
|
public void testBool() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty("test", "true");
|
props.setProperty("test", "true");
|
||||||
assertTrue(PropUtil.getBooleanProperty(props, "test", false));
|
assertTrue(PropUtil.getBooleanProperty(props, "test", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBoolDef() throws Exception {
|
public void testBoolDef() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
assertTrue(PropUtil.getBooleanProperty(props, "test", true));
|
assertTrue(PropUtil.getBooleanProperty(props, "test", true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBoolDefProp() throws Exception {
|
public void testBoolDefProp() {
|
||||||
Properties defprops = new Properties();
|
Properties defprops = new Properties();
|
||||||
defprops.setProperty("test", "true");
|
defprops.setProperty("test", "true");
|
||||||
Properties props = new Properties(defprops);
|
Properties props = new Properties(defprops);
|
||||||
|
@ -85,49 +85,46 @@ public class PropUtilTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBoolean() throws Exception {
|
public void testBoolean() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.put("test", true);
|
props.put("test", true);
|
||||||
assertTrue(PropUtil.getBooleanProperty(props, "test", false));
|
assertTrue(PropUtil.getBooleanProperty(props, "test", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// the Session variants...
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSessionInt() throws Exception {
|
public void testSessionInt() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty("test", "2");
|
props.setProperty("test", "2");
|
||||||
Session sess = Session.getInstance(props, null);
|
Session sess = Session.getInstance(props, null);
|
||||||
assertEquals(PropUtil.getIntProperty(sess.getProperties(), "test", 1), 2);
|
assertEquals(2, PropUtil.getIntProperty(sess.getProperties(), "test", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSessionIntDef() throws Exception {
|
public void testSessionIntDef() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
Session sess = Session.getInstance(props, null);
|
Session sess = Session.getInstance(props, null);
|
||||||
assertEquals(PropUtil.getIntProperty(sess.getProperties(), "test", 1), 1);
|
assertEquals(1, PropUtil.getIntProperty(sess.getProperties(), "test", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSessionIntDefProp() throws Exception {
|
public void testSessionIntDefProp() {
|
||||||
Properties defprops = new Properties();
|
Properties defprops = new Properties();
|
||||||
defprops.setProperty("test", "2");
|
defprops.setProperty("test", "2");
|
||||||
Properties props = new Properties(defprops);
|
Properties props = new Properties(defprops);
|
||||||
Session sess = Session.getInstance(props, null);
|
Session sess = Session.getInstance(props, null);
|
||||||
assertEquals(PropUtil.getIntProperty(sess.getProperties(), "test", 1), 2);
|
assertEquals(2, PropUtil.getIntProperty(sess.getProperties(), "test", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSessionInteger() throws Exception {
|
public void testSessionInteger() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.put("test", 2);
|
props.put("test", 2);
|
||||||
Session sess = Session.getInstance(props, null);
|
Session sess = Session.getInstance(props, null);
|
||||||
assertEquals(PropUtil.getIntProperty(sess.getProperties(), "test", 1), 2);
|
assertEquals(2, PropUtil.getIntProperty(sess.getProperties(), "test", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSessionBool() throws Exception {
|
public void testSessionBool() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty("test", "true");
|
props.setProperty("test", "true");
|
||||||
Session sess = Session.getInstance(props, null);
|
Session sess = Session.getInstance(props, null);
|
||||||
|
@ -135,7 +132,7 @@ public class PropUtilTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSessionBoolDef() throws Exception {
|
public void testSessionBoolDef() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
Session sess = Session.getInstance(props, null);
|
Session sess = Session.getInstance(props, null);
|
||||||
assertTrue(PropUtil.getBooleanProperty(sess.getProperties(), "test", true));
|
assertTrue(PropUtil.getBooleanProperty(sess.getProperties(), "test", true));
|
||||||
|
@ -151,29 +148,26 @@ public class PropUtilTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSessionBoolean() throws Exception {
|
public void testSessionBoolean() {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.put("test", true);
|
props.put("test", true);
|
||||||
Session sess = Session.getInstance(props, null);
|
Session sess = Session.getInstance(props, null);
|
||||||
assertTrue(PropUtil.getBooleanProperty(sess.getProperties(), "test", false));
|
assertTrue(PropUtil.getBooleanProperty(sess.getProperties(), "test", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// the System variants...
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSystemBool() throws Exception {
|
public void testSystemBool() {
|
||||||
System.setProperty("test", "true");
|
System.setProperty("test", "true");
|
||||||
assertTrue(PropUtil.getBooleanSystemProperty("test", false));
|
assertTrue(PropUtil.getBooleanSystemProperty("test", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSystemBoolDef() throws Exception {
|
public void testSystemBoolDef() {
|
||||||
assertTrue(PropUtil.getBooleanSystemProperty("testnotset", true));
|
assertTrue(PropUtil.getBooleanSystemProperty("testnotset", true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSystemBoolean() throws Exception {
|
public void testSystemBoolean() {
|
||||||
System.getProperties().put("testboolean", true);
|
System.getProperties().put("testboolean", true);
|
||||||
assertTrue(PropUtil.getBooleanSystemProperty("testboolean", false));
|
assertTrue(PropUtil.getBooleanSystemProperty("testboolean", false));
|
||||||
}
|
}
|
||||||
|
@ -198,11 +192,13 @@ public class PropUtilTest {
|
||||||
assertNull(PropUtil.getScheduledExecutorServiceProperty(props, executorPropertyName));
|
assertNull(PropUtil.getScheduledExecutorServiceProperty(props, executorPropertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // (expected = ClassCastException.class)
|
@Test
|
||||||
public void testScheduledExecutorWriteTimeoutWrongType() {
|
public void testScheduledExecutorWriteTimeoutWrongType() {
|
||||||
|
assertThrows(ClassCastException.class, () -> {
|
||||||
final String executorPropertyName = "test";
|
final String executorPropertyName = "test";
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.put(executorPropertyName, new HashSet<>());
|
props.put(executorPropertyName, new HashSet<>());
|
||||||
PropUtil.getScheduledExecutorServiceProperty(props, executorPropertyName);
|
PropUtil.getScheduledExecutorServiceProperty(props, executorPropertyName);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,6 @@ import jakarta.mail.internet.InternetAddress;
|
||||||
import jakarta.mail.internet.MimeMessage;
|
import jakarta.mail.internet.MimeMessage;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@ -32,65 +30,63 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
*/
|
*/
|
||||||
public class Utf8AddressTest {
|
public class Utf8AddressTest {
|
||||||
|
|
||||||
private static Session s = Session.getInstance(new Properties());
|
private static final Session s = Session.getInstance(new Properties());
|
||||||
private static String utf8name = "test\u00a1\u00a2\u00a3";
|
private static final String utf8name = "test\u00a1\u00a2\u00a3";
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void before() {
|
|
||||||
System.out.println("Utf8Address");
|
|
||||||
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFrom() throws Exception {
|
public void testFrom() throws Exception {
|
||||||
|
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||||
MimeMessage m = new MimeMessage(s);
|
MimeMessage m = new MimeMessage(s);
|
||||||
m.setFrom(new InternetAddress("joe@example.com", utf8name, "UTF-8"));
|
m.setFrom(new InternetAddress("joe@example.com", utf8name, "UTF-8"));
|
||||||
m.saveChanges();
|
m.saveChanges();
|
||||||
String h = m.getHeader("From", "");
|
String h = m.getHeader("From", "");
|
||||||
assertTrue(h.contains(utf8name));
|
assertTrue(h.contains(utf8name));
|
||||||
|
s.getProperties().remove("mail.mime.allowutf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFromString() throws Exception {
|
public void testFromString() throws Exception {
|
||||||
|
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||||
MimeMessage m = new MimeMessage(s);
|
MimeMessage m = new MimeMessage(s);
|
||||||
m.setFrom(utf8name + " <joe@example.com>");
|
m.setFrom(utf8name + " <joe@example.com>");
|
||||||
m.saveChanges();
|
m.saveChanges();
|
||||||
String h = m.getHeader("From", "");
|
String h = m.getHeader("From", "");
|
||||||
assertTrue(h.contains(utf8name));
|
assertTrue(h.contains(utf8name));
|
||||||
|
s.getProperties().remove("mail.mime.allowutf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTo() throws Exception {
|
public void testTo() throws Exception {
|
||||||
|
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||||
MimeMessage m = new MimeMessage(s);
|
MimeMessage m = new MimeMessage(s);
|
||||||
m.setRecipient(Message.RecipientType.TO,
|
m.setRecipient(Message.RecipientType.TO,
|
||||||
new InternetAddress("joe@example.com", utf8name, "UTF-8"));
|
new InternetAddress("joe@example.com", utf8name, "UTF-8"));
|
||||||
m.saveChanges();
|
m.saveChanges();
|
||||||
String h = m.getHeader("To", "");
|
String h = m.getHeader("To", "");
|
||||||
assertTrue(h.contains(utf8name));
|
assertTrue(h.contains(utf8name));
|
||||||
|
s.getProperties().remove("mail.mime.allowutf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testToString() throws Exception {
|
public void testToString() throws Exception {
|
||||||
|
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||||
MimeMessage m = new MimeMessage(s);
|
MimeMessage m = new MimeMessage(s);
|
||||||
m.setRecipients(Message.RecipientType.TO,
|
m.setRecipients(Message.RecipientType.TO,
|
||||||
utf8name + " <joe@example.com>");
|
utf8name + " <joe@example.com>");
|
||||||
m.saveChanges();
|
m.saveChanges();
|
||||||
String h = m.getHeader("To", "");
|
String h = m.getHeader("To", "");
|
||||||
assertTrue(h.contains(utf8name));
|
assertTrue(h.contains(utf8name));
|
||||||
|
s.getProperties().remove("mail.mime.allowutf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSender() throws Exception {
|
public void testSender() throws Exception {
|
||||||
|
s.getProperties().setProperty("mail.mime.allowutf8", "true");
|
||||||
MimeMessage m = new MimeMessage(s);
|
MimeMessage m = new MimeMessage(s);
|
||||||
m.setSender(new InternetAddress("joe@example.com", utf8name, "UTF-8"));
|
m.setSender(new InternetAddress("joe@example.com", utf8name, "UTF-8"));
|
||||||
m.saveChanges();
|
m.saveChanges();
|
||||||
String h = m.getHeader("Sender", "");
|
String h = m.getHeader("Sender", "");
|
||||||
assertTrue(h.contains(utf8name));
|
assertTrue(h.contains(utf8name));
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void after() {
|
|
||||||
// should be unnecessary
|
|
||||||
s.getProperties().remove("mail.mime.allowutf8");
|
s.getProperties().remove("mail.mime.allowutf8");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@ import jakarta.mail.Store;
|
||||||
import jakarta.mail.StoreClosedException;
|
import jakarta.mail.StoreClosedException;
|
||||||
import jakarta.mail.internet.MimeMessage;
|
import jakarta.mail.internet.MimeMessage;
|
||||||
import jakarta.mail.util.ByteArrayDataSource;
|
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.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.Timeout;
|
import org.junit.jupiter.api.Timeout;
|
||||||
|
@ -56,7 +58,9 @@ import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
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.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
@ -65,9 +69,12 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||||
*/
|
*/
|
||||||
@Timeout(20)
|
@Timeout(20)
|
||||||
public final class WriteTimeoutSocketTest {
|
public final class WriteTimeoutSocketTest {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(WriteTimeoutSocketTest.class.getName());
|
||||||
|
|
||||||
private TestServer testServer;
|
private TestServer testServer;
|
||||||
private List<ScheduledExecutorService> scheduledExecutorServices = new ArrayList<>();
|
private final List<ScheduledExecutorService> scheduledExecutorServices = new ArrayList<>();
|
||||||
private List<WriteTimeoutSocket> writeTimeoutSockets = new ArrayList<>();
|
private final List<WriteTimeoutSocket> writeTimeoutSockets = new ArrayList<>();
|
||||||
|
|
||||||
private static final int TIMEOUT = 200; // ms
|
private static final int TIMEOUT = 200; // ms
|
||||||
private static final String data =
|
private static final String data =
|
||||||
|
@ -109,14 +116,16 @@ public final class WriteTimeoutSocketTest {
|
||||||
assertTrue(sf.getSocketCreated());
|
assertTrue(sf.getSocketCreated());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test //(expected = MessagingException.class)
|
@Test
|
||||||
public void testSSLCheckserveridentityDefaultsTrue() throws Exception {
|
public void testSSLCheckserveridentityDefaultsTrue() {
|
||||||
|
assertThrows(MessagingException.class, () -> {
|
||||||
final Properties properties = new Properties();
|
final Properties properties = new Properties();
|
||||||
properties.setProperty("mail.imap.host", "localhost");
|
properties.setProperty("mail.imap.host", "localhost");
|
||||||
properties.setProperty("mail.imap.writetimeout", "" + TIMEOUT);
|
properties.setProperty("mail.imap.writetimeout", "" + TIMEOUT);
|
||||||
properties.setProperty("mail.imap.ssl.enable", "true");
|
properties.setProperty("mail.imap.ssl.enable", "true");
|
||||||
properties.setProperty("mail.imap.ssl.trust", "localhost");
|
properties.setProperty("mail.imap.ssl.trust", "localhost");
|
||||||
test(properties, true);
|
test(properties, true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -161,32 +170,32 @@ public final class WriteTimeoutSocketTest {
|
||||||
* XXX - this is kind of hacky since it depends on Method.toString
|
* XXX - this is kind of hacky since it depends on Method.toString
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testOverrides() throws Exception {
|
public void testOverrides() {
|
||||||
Set<String> socketMethods = new HashSet<>();
|
Set<String> socketMethods = new HashSet<>();
|
||||||
Method[] m = Socket.class.getDeclaredMethods();
|
Method[] m = Socket.class.getDeclaredMethods();
|
||||||
String className = Socket.class.getName() + ".";
|
String className = Socket.class.getName() + ".";
|
||||||
for (int i = 0; i < m.length; i++) {
|
for (Method method : m) {
|
||||||
if (Modifier.isPublic(m[i].getModifiers()) &&
|
if (Modifier.isPublic(method.getModifiers()) &&
|
||||||
!Modifier.isStatic(m[i].getModifiers())) {
|
!Modifier.isStatic(method.getModifiers())) {
|
||||||
String name = m[i].toString().
|
String name = method.toString().
|
||||||
replace("synchronized ", "").
|
replace("synchronized ", "").
|
||||||
replace(className, "");
|
replace(className, "");
|
||||||
socketMethods.add(name);
|
socketMethods.add(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Set<String> wtsocketMethods = new HashSet<>();
|
|
||||||
m = WriteTimeoutSocket.class.getDeclaredMethods();
|
m = WriteTimeoutSocket.class.getDeclaredMethods();
|
||||||
className = WriteTimeoutSocket.class.getName() + ".";
|
className = WriteTimeoutSocket.class.getName() + ".";
|
||||||
for (int i = 0; i < m.length; i++) {
|
for (Method method : m) {
|
||||||
if (Modifier.isPublic(m[i].getModifiers())) {
|
if (Modifier.isPublic(method.getModifiers())) {
|
||||||
String name = m[i].toString().
|
String name = method.toString().
|
||||||
replace("synchronized ", "").
|
replace("synchronized ", "").
|
||||||
replace(className, "");
|
replace(className, "");
|
||||||
socketMethods.remove(name);
|
socketMethods.remove(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (String s : socketMethods)
|
for (String s : socketMethods) {
|
||||||
System.out.println("WriteTimeoutSocket did not override: " + s);
|
logger.log(Level.INFO, "WriteTimeoutSocket did not override: " + s);
|
||||||
|
}
|
||||||
assertTrue(socketMethods.isEmpty());
|
assertTrue(socketMethods.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +208,6 @@ public final class WriteTimeoutSocketTest {
|
||||||
|
|
||||||
properties.setProperty("mail.imap.port", String.valueOf(server.getPort()));
|
properties.setProperty("mail.imap.port", String.valueOf(server.getPort()));
|
||||||
final Session session = Session.getInstance(properties);
|
final Session session = Session.getInstance(properties);
|
||||||
//session.setDebug(true);
|
|
||||||
|
|
||||||
MimeMessage msg = new MimeMessage(session);
|
MimeMessage msg = new MimeMessage(session);
|
||||||
msg.setFrom("test@example.com");
|
msg.setFrom("test@example.com");
|
||||||
|
@ -218,17 +226,13 @@ public final class WriteTimeoutSocketTest {
|
||||||
msg.setDataHandler(new DataHandler(
|
msg.setDataHandler(new DataHandler(
|
||||||
new ByteArrayDataSource(part, "text/plain")));
|
new ByteArrayDataSource(part, "text/plain")));
|
||||||
msg.saveChanges();
|
msg.saveChanges();
|
||||||
|
try (Store store = session.getStore("imap")) {
|
||||||
final Store store = session.getStore("imap");
|
|
||||||
try {
|
|
||||||
store.connect("test", "test");
|
store.connect("test", "test");
|
||||||
final Folder f = store.getFolder("test");
|
final Folder f = store.getFolder("test");
|
||||||
f.appendMessages(new Message[]{msg});
|
f.appendMessages(new Message[]{msg});
|
||||||
fail("No timeout");
|
fail("No timeout");
|
||||||
} catch (StoreClosedException scex) {
|
} catch (StoreClosedException scex) {
|
||||||
// success!
|
// success!
|
||||||
} finally {
|
|
||||||
store.close();
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (server != null) {
|
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
|
@Test
|
||||||
public void testExternalSesIsBeingUsed() throws Exception {
|
public void testExternalSesIsBeingUsed() throws Exception {
|
||||||
final Properties properties = new Properties();
|
final Properties properties = new Properties();
|
||||||
|
@ -279,7 +271,7 @@ public final class WriteTimeoutSocketTest {
|
||||||
fail("Expected IOException wasn't thrown ");
|
fail("Expected IOException wasn't thrown ");
|
||||||
} catch (MessagingException mex) {
|
} catch (MessagingException mex) {
|
||||||
Throwable cause = mex.getCause();
|
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"));
|
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 {
|
public void testDefaultSesConstructor1() throws Exception {
|
||||||
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(new Socket(), 10000);
|
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(new Socket(), 10000);
|
||||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||||
|
|
||||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||||
assertTrue(isExternalSes instanceof Boolean);
|
assertInstanceOf(Boolean.class, isExternalSes);
|
||||||
assertFalse((Boolean) isExternalSes);
|
assertFalse((Boolean) isExternalSes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,22 +311,19 @@ public final class WriteTimeoutSocketTest {
|
||||||
public void testDefaultSesConstructor2() throws Exception {
|
public void testDefaultSesConstructor2() throws Exception {
|
||||||
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(10000);
|
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(10000);
|
||||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||||
|
|
||||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||||
assertTrue(isExternalSes instanceof Boolean);
|
assertInstanceOf(Boolean.class, isExternalSes);
|
||||||
assertFalse((Boolean) isExternalSes);
|
assertFalse((Boolean) isExternalSes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultSesConstructor3() throws Exception {
|
public void testDefaultSesConstructor3() throws Exception {
|
||||||
testServer = getActiveTestServer(false);
|
testServer = getActiveTestServer(false);
|
||||||
|
|
||||||
WriteTimeoutSocket writeTimeoutSocket =
|
WriteTimeoutSocket writeTimeoutSocket =
|
||||||
new WriteTimeoutSocket("localhost", testServer.getPort(), 10000);
|
new WriteTimeoutSocket("localhost", testServer.getPort(), 10000);
|
||||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||||
|
|
||||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||||
assertTrue(isExternalSes instanceof Boolean);
|
assertInstanceOf(Boolean.class, isExternalSes);
|
||||||
assertFalse((Boolean) isExternalSes);
|
assertFalse((Boolean) isExternalSes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,37 +333,32 @@ public final class WriteTimeoutSocketTest {
|
||||||
WriteTimeoutSocket writeTimeoutSocket =
|
WriteTimeoutSocket writeTimeoutSocket =
|
||||||
new WriteTimeoutSocket(InetAddress.getLocalHost(), testServer.getPort(), 10000);
|
new WriteTimeoutSocket(InetAddress.getLocalHost(), testServer.getPort(), 10000);
|
||||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||||
|
|
||||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||||
assertTrue(isExternalSes instanceof Boolean);
|
assertInstanceOf(Boolean.class, isExternalSes);
|
||||||
assertFalse((Boolean) isExternalSes);
|
assertFalse((Boolean) isExternalSes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultSesConstructor5() throws Exception {
|
public void testDefaultSesConstructor5() throws Exception {
|
||||||
testServer = getActiveTestServer(false);
|
testServer = getActiveTestServer(false);
|
||||||
|
|
||||||
WriteTimeoutSocket writeTimeoutSocket =
|
WriteTimeoutSocket writeTimeoutSocket =
|
||||||
new WriteTimeoutSocket("localhost", testServer.getPort(),
|
new WriteTimeoutSocket("localhost", testServer.getPort(),
|
||||||
(InetAddress) null, getRandomFreePort(), 10000);
|
(InetAddress) null, getRandomFreePort(), 10000);
|
||||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||||
|
|
||||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||||
assertTrue(isExternalSes instanceof Boolean);
|
assertInstanceOf(Boolean.class, isExternalSes);
|
||||||
assertFalse((Boolean) isExternalSes);
|
assertFalse((Boolean) isExternalSes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultSesConstructor6() throws Exception {
|
public void testDefaultSesConstructor6() throws Exception {
|
||||||
testServer = getActiveTestServer(false);
|
testServer = getActiveTestServer(false);
|
||||||
|
|
||||||
WriteTimeoutSocket writeTimeoutSocket =
|
WriteTimeoutSocket writeTimeoutSocket =
|
||||||
new WriteTimeoutSocket(InetAddress.getByName("localhost"), testServer.getPort(),
|
new WriteTimeoutSocket(InetAddress.getByName("localhost"), testServer.getPort(),
|
||||||
(InetAddress) null, getRandomFreePort(), 10000);
|
null, getRandomFreePort(), 10000);
|
||||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||||
|
|
||||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||||
assertTrue(isExternalSes instanceof Boolean);
|
assertInstanceOf(Boolean.class, isExternalSes);
|
||||||
assertFalse((Boolean) isExternalSes);
|
assertFalse((Boolean) isExternalSes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,9 +367,8 @@ public final class WriteTimeoutSocketTest {
|
||||||
WriteTimeoutSocket writeTimeoutSocket =
|
WriteTimeoutSocket writeTimeoutSocket =
|
||||||
new WriteTimeoutSocket(new Socket(), 10000, new ScheduledThreadPoolExecutor(1));
|
new WriteTimeoutSocket(new Socket(), 10000, new ScheduledThreadPoolExecutor(1));
|
||||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||||
|
|
||||||
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
Object isExternalSes = ReflectionUtil.getPrivateFieldValue(writeTimeoutSocket, "isExternalSes");
|
||||||
assertTrue(isExternalSes instanceof Boolean);
|
assertInstanceOf(Boolean.class, isExternalSes);
|
||||||
assertTrue((Boolean) isExternalSes);
|
assertTrue((Boolean) isExternalSes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +379,6 @@ public final class WriteTimeoutSocketTest {
|
||||||
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(socket, 10000, ses);
|
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(socket, 10000, ses);
|
||||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||||
writeTimeoutSocket.close();
|
writeTimeoutSocket.close();
|
||||||
|
|
||||||
assertFalse(ses.isShutdownNowMethodCalled);
|
assertFalse(ses.isShutdownNowMethodCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,22 +389,12 @@ public final class WriteTimeoutSocketTest {
|
||||||
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(socket, 10000);
|
WriteTimeoutSocket writeTimeoutSocket = new WriteTimeoutSocket(socket, 10000);
|
||||||
writeTimeoutSockets.add(writeTimeoutSocket);
|
writeTimeoutSockets.add(writeTimeoutSocket);
|
||||||
ReflectionUtil.setFieldValue(writeTimeoutSocket, "ses", ses);
|
ReflectionUtil.setFieldValue(writeTimeoutSocket, "ses", ses);
|
||||||
|
|
||||||
writeTimeoutSocket.close();
|
writeTimeoutSocket.close();
|
||||||
|
|
||||||
assertTrue(ses.isShutdownNowMethodCalled);
|
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) {
|
private TestServer getActiveTestServer(boolean isSSL) {
|
||||||
TestServer server = null;
|
TestServer server;
|
||||||
try {
|
try {
|
||||||
final TimeoutHandler handler = new TimeoutHandler();
|
final TimeoutHandler handler = new TimeoutHandler();
|
||||||
server = new TestServer(handler, isSSL);
|
server = new TestServer(handler, isSSL);
|
||||||
|
@ -438,7 +409,6 @@ public final class WriteTimeoutSocketTest {
|
||||||
ServerSocket serverSocket = new ServerSocket(0);
|
ServerSocket serverSocket = new ServerSocket(0);
|
||||||
int freePort = serverSocket.getLocalPort();
|
int freePort = serverSocket.getLocalPort();
|
||||||
serverSocket.close();
|
serverSocket.close();
|
||||||
|
|
||||||
return freePort;
|
return freePort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,11 +416,10 @@ public final class WriteTimeoutSocketTest {
|
||||||
if (ses.isTerminated()) {
|
if (ses.isTerminated()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ses.shutdownNow();
|
ses.shutdownNow();
|
||||||
} catch (Exception e) {
|
} 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) {
|
if (testServer == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
testServer.quit();
|
testServer.quit();
|
||||||
} catch (Exception e) {
|
} 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()) {
|
if (writeTimeoutSocket.isClosed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
writeTimeoutSocket.close();
|
writeTimeoutSocket.close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println(e.getMessage());
|
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PublicFileSocket extends Socket {
|
private static class PublicFileSocket extends Socket {
|
||||||
public FileDescriptor getFileDescriptor$() {
|
|
||||||
return new FileDescriptor();
|
public PublicFileSocket() {
|
||||||
|
super();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6184,20 +6184,6 @@
|
||||||
"hash": ""
|
"hash": ""
|
||||||
},
|
},
|
||||||
"Invalid IPv4 radix digits",
|
"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",
|
"input": "http://0x7f.0.0.0x7g",
|
||||||
"base": "about:blank",
|
"base": "about:blank",
|
||||||
|
|
Loading…
Reference in a new issue