mirror of
https://github.com/moparisthebest/davmail
synced 2025-01-05 18:58:02 -05:00
Fix nullpointer when HTML body is empty
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@40 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
163e611bd1
commit
6a79873d29
@ -17,6 +17,7 @@ import org.w3c.tidy.Tidy;
|
|||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.NamedNodeMap;
|
import org.w3c.dom.NamedNodeMap;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
import javax.mail.internet.MimeUtility;
|
import javax.mail.internet.MimeUtility;
|
||||||
@ -809,7 +810,7 @@ public class ExchangeSession {
|
|||||||
writeBody(os, partHeader);
|
writeBody(os, partHeader);
|
||||||
} else {
|
} else {
|
||||||
Attachment attachment = attachmentsMap.get(partHeader.name);
|
Attachment attachment = attachmentsMap.get(partHeader.name);
|
||||||
|
|
||||||
// TODO : test if .eml extension could be stripped from attachment name directly
|
// TODO : test if .eml extension could be stripped from attachment name directly
|
||||||
// try to get email attachment with .eml extension
|
// try to get email attachment with .eml extension
|
||||||
if (attachment == null && partHeader.name != null) {
|
if (attachment == null && partHeader.name != null) {
|
||||||
@ -1058,15 +1059,19 @@ public class ExchangeSession {
|
|||||||
XmlDocument xmlDocument = new XmlDocument();
|
XmlDocument xmlDocument = new XmlDocument();
|
||||||
try {
|
try {
|
||||||
Document w3cDocument = tidy.parseDOM(inputStream, null);
|
Document w3cDocument = tidy.parseDOM(inputStream, null);
|
||||||
// Fix broken Office xml document with empty namespace
|
Element documentElement = w3cDocument.getDocumentElement();
|
||||||
NamedNodeMap namedNodeMap = w3cDocument.getDocumentElement().getAttributes();
|
|
||||||
for (int i = 0; i < namedNodeMap.getLength(); i++) {
|
if (documentElement != null) {
|
||||||
Node node = namedNodeMap.item(i);
|
// Fix broken Office xml document with empty namespace
|
||||||
String nodeName = node.getNodeName();
|
NamedNodeMap namedNodeMap = w3cDocument.getDocumentElement().getAttributes();
|
||||||
String nodeValue = node.getNodeValue();
|
for (int i = 0; i < namedNodeMap.getLength(); i++) {
|
||||||
if (nodeName != null && nodeName.startsWith("xmlns")
|
Node node = namedNodeMap.item(i);
|
||||||
&& (nodeValue == null || nodeValue.length() == 0)) {
|
String nodeName = node.getNodeName();
|
||||||
w3cDocument.getDocumentElement().removeAttribute(nodeName);
|
String nodeValue = node.getNodeValue();
|
||||||
|
if (nodeName != null && nodeName.startsWith("xmlns")
|
||||||
|
&& (nodeValue == null || nodeValue.length() == 0)) {
|
||||||
|
w3cDocument.getDocumentElement().removeAttribute(nodeName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xmlDocument.load(builder.build(w3cDocument));
|
xmlDocument.load(builder.build(w3cDocument));
|
||||||
@ -1149,77 +1154,80 @@ public class ExchangeSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get inline images from htmlBody (without OWA transformation)
|
// HTML body may be empty
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(htmlBody
|
if (htmlBody != null && htmlBody.length() > 0) {
|
||||||
// quick fix remove default office namespace
|
// get inline images from htmlBody (without OWA transformation)
|
||||||
.replaceFirst("xmlns=\".*\"", "")
|
ByteArrayInputStream bais = new ByteArrayInputStream(htmlBody
|
||||||
// quick fix remove inline processing instructions
|
// quick fix remove default office namespace
|
||||||
.replaceAll("<\\?xml:namespace", "")
|
.replaceFirst("xmlns=\".*\"", "")
|
||||||
.getBytes("UTF-8"));
|
// quick fix remove inline processing instructions
|
||||||
XmlDocument xmlBody = tidyDocument(bais);
|
.replaceAll("<\\?xml:namespace", "")
|
||||||
List<Attribute> htmlBodyAllImgList = xmlBody.getNodes("//img/@src");
|
.getBytes("UTF-8"));
|
||||||
// remove absolute images from body img list
|
XmlDocument xmlBody = tidyDocument(bais);
|
||||||
List<String> htmlBodyImgList = new ArrayList<String>();
|
List<Attribute> htmlBodyAllImgList = xmlBody.getNodes("//img/@src");
|
||||||
for (Attribute imgAttribute : htmlBodyAllImgList) {
|
// remove absolute images from body img list
|
||||||
String value = imgAttribute.getValue();
|
List<String> htmlBodyImgList = new ArrayList<String>();
|
||||||
if (!value.startsWith("http://") && !value.startsWith("https://")) {
|
for (Attribute imgAttribute : htmlBodyAllImgList) {
|
||||||
htmlBodyImgList.add(value);
|
String value = imgAttribute.getValue();
|
||||||
|
if (!value.startsWith("http://") && !value.startsWith("https://")) {
|
||||||
|
htmlBodyImgList.add(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// set inline attachments flag
|
// set inline attachments flag
|
||||||
hasInlineAttachment = (htmlBodyImgList.size() > 0);
|
hasInlineAttachment = (htmlBodyImgList.size() > 0);
|
||||||
|
|
||||||
// use owa generated body to look for inline images
|
// use owa generated body to look for inline images
|
||||||
List<Attribute> imgList = xmlDocument.getNodes("//img/@src");
|
List<Attribute> imgList = xmlDocument.getNodes("//img/@src");
|
||||||
|
|
||||||
// TODO : add body background, does not work in thunderbird
|
// TODO : add body background, does not work in thunderbird
|
||||||
// htmlBodyImgList.addAll(xmlBody.getNodes("//body/@background"));
|
// htmlBodyImgList.addAll(xmlBody.getNodes("//body/@background"));
|
||||||
// imgList.addAll(xmlDocument.getNodes("//td/@background"));
|
// imgList.addAll(xmlDocument.getNodes("//td/@background"));
|
||||||
|
|
||||||
int inlineImageCount = 0;
|
int inlineImageCount = 0;
|
||||||
for (Attribute element : imgList) {
|
for (Attribute element : imgList) {
|
||||||
String attachmentHref = element.getValue();
|
String attachmentHref = element.getValue();
|
||||||
// filter external images
|
// filter external images
|
||||||
if (attachmentHref.startsWith("1_multipart")) {
|
if (attachmentHref.startsWith("1_multipart")) {
|
||||||
attachmentHref = URIUtil.decode(attachmentHref);
|
attachmentHref = URIUtil.decode(attachmentHref);
|
||||||
if (attachmentHref.endsWith("?Security=3")) {
|
if (attachmentHref.endsWith("?Security=3")) {
|
||||||
attachmentHref = attachmentHref.substring(0, attachmentHref.indexOf('?'));
|
attachmentHref = attachmentHref.substring(0, attachmentHref.indexOf('?'));
|
||||||
}
|
}
|
||||||
String attachmentName = attachmentHref.substring(attachmentHref.lastIndexOf('/') + 1);
|
String attachmentName = attachmentHref.substring(attachmentHref.lastIndexOf('/') + 1);
|
||||||
// handle strange cases
|
// handle strange cases
|
||||||
if (attachmentName.charAt(1) == '_') {
|
if (attachmentName.charAt(1) == '_') {
|
||||||
attachmentName = attachmentName.substring(2);
|
attachmentName = attachmentName.substring(2);
|
||||||
}
|
}
|
||||||
if (attachmentName.startsWith("%31_multipart%3F2_")) {
|
if (attachmentName.startsWith("%31_multipart%3F2_")) {
|
||||||
attachmentName = attachmentName.substring(18);
|
attachmentName = attachmentName.substring(18);
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode slashes
|
// decode slashes
|
||||||
attachmentName = attachmentName.replaceAll("_xF8FF_", "/");
|
attachmentName = attachmentName.replaceAll("_xF8FF_", "/");
|
||||||
// exclude inline external images
|
// exclude inline external images
|
||||||
if (!attachmentName.startsWith("http://") && !attachmentName.startsWith("https://")) {
|
if (!attachmentName.startsWith("http://") && !attachmentName.startsWith("https://")) {
|
||||||
Attachment attachment = new Attachment();
|
Attachment attachment = new Attachment();
|
||||||
attachment.name = attachmentName;
|
attachment.name = attachmentName;
|
||||||
attachment.href = messageUrl + "/" + attachmentHref;
|
attachment.href = messageUrl + "/" + attachmentHref;
|
||||||
if (htmlBodyImgList.size() > inlineImageCount) {
|
if (htmlBodyImgList.size() > inlineImageCount) {
|
||||||
String contentid = htmlBodyImgList.get(inlineImageCount++);
|
String contentid = htmlBodyImgList.get(inlineImageCount++);
|
||||||
if (contentid.startsWith("cid:")) {
|
if (contentid.startsWith("cid:")) {
|
||||||
attachment.contentid = contentid.substring("cid:".length());
|
attachment.contentid = contentid.substring("cid:".length());
|
||||||
|
} else {
|
||||||
|
attachment.contentid = contentid;
|
||||||
|
// must patch htmlBody for inline image without cid
|
||||||
|
htmlBody = htmlBody.replaceFirst(attachment.contentid, "cid:" + attachment.contentid);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
attachment.contentid = contentid;
|
logger.warn("More images in OWA body !");
|
||||||
// must patch htmlBody for inline image without cid
|
|
||||||
htmlBody = htmlBody.replaceFirst(attachment.contentid, "cid:" + attachment.contentid);
|
|
||||||
}
|
}
|
||||||
} else {
|
// add only inline images
|
||||||
logger.warn("More images in OWA body !");
|
if (attachment.contentid != null) {
|
||||||
|
attachmentsMap.put(attachmentName, attachment);
|
||||||
|
}
|
||||||
|
logger.debug("Inline image attachment ID:" + attachment.contentid
|
||||||
|
+ " name: " + attachment.name + " href: " + attachment.href);
|
||||||
}
|
}
|
||||||
// add only inline images
|
|
||||||
if (attachment.contentid != null) {
|
|
||||||
attachmentsMap.put(attachmentName, attachment);
|
|
||||||
}
|
|
||||||
logger.debug("Inline image attachment ID:" + attachment.contentid
|
|
||||||
+ " name: " + attachment.name + " href: " + attachment.href);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1314,19 +1322,19 @@ public class ExchangeSession {
|
|||||||
int equalsIndex = token.indexOf('=');
|
int equalsIndex = token.indexOf('=');
|
||||||
if (equalsIndex > 0) {
|
if (equalsIndex > 0) {
|
||||||
String tokenName = token.substring(0, equalsIndex);
|
String tokenName = token.substring(0, equalsIndex);
|
||||||
if ("charset".equals(tokenName)) {
|
if ("charset".equalsIgnoreCase(tokenName)) {
|
||||||
charset = token.substring(equalsIndex + 1);
|
charset = token.substring(equalsIndex + 1);
|
||||||
if (charset.startsWith("\"")) {
|
if (charset.startsWith("\"")) {
|
||||||
charset = charset.substring(1, charset.lastIndexOf("\""));
|
charset = charset.substring(1, charset.lastIndexOf("\""));
|
||||||
}
|
}
|
||||||
} else if ("name".equals(tokenName.toLowerCase())) {
|
} else if ("name".equalsIgnoreCase(tokenName.toLowerCase())) {
|
||||||
name = token.substring(equalsIndex + 1);
|
name = token.substring(equalsIndex + 1);
|
||||||
if (name.startsWith("\"")) {
|
if (name.startsWith("\"")) {
|
||||||
name = name.substring(1, name.lastIndexOf("\""));
|
name = name.substring(1, name.lastIndexOf("\""));
|
||||||
}
|
}
|
||||||
// name can be mime encoded
|
// name can be mime encoded
|
||||||
name = MimeUtility.decodeText(name);
|
name = MimeUtility.decodeText(name);
|
||||||
} else if ("boundary".equals(tokenName)) {
|
} else if ("boundary".equalsIgnoreCase(tokenName)) {
|
||||||
boundary = token.substring(equalsIndex + 1);
|
boundary = token.substring(equalsIndex + 1);
|
||||||
if (boundary.startsWith("\"")) {
|
if (boundary.startsWith("\"")) {
|
||||||
boundary = boundary.substring(1, boundary.lastIndexOf("\""));
|
boundary = boundary.substring(1, boundary.lastIndexOf("\""));
|
||||||
|
Loading…
Reference in New Issue
Block a user