/*
* Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The
* University of Hong Kong (HKU). All Rights Reserved.
*
* This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1]
*
* [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
package hk.hku.cecid.edi.as2.pkg;
import hk.hku.cecid.piazza.commons.security.SMimeMessage;
import hk.hku.cecid.piazza.commons.util.StringUtilities;
import java.util.Enumeration;
import javax.mail.MessagingException;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
/**
* DispositionNotification represents an AS2 disposition notification.
*
* @author Hugo Y. K. Lam
*
*/
public class DispositionNotification {
public static final String REPORTING_UA = "Reporting-UA";
public static final String ORIG_RECIPIENT = "Original-Recipient";
public static final String FINAL_RECIPIENT = "Final-Recipient";
public static final String ORIG_MESSAGE_ID = "Original-Message-ID";
public static final String DISPOSITION = "Disposition";
public static final String RECEIVED_CONTENT_MIC = "Received-Content-MIC";
private static final String DISCLAIMER = "This is not a guarantee that the message has been completely processed or understood by the receiving translator";
private static final String CONTENT_SUBTYPE = "report; report-type=disposition-notification";
private MimeMultipart multiPart;
private MimeBodyPart textPart;
private MimeBodyPart reportPart;
private InternetHeaders reportValues;
public DispositionNotification() throws AS2MessageException {
multiPart = new MimeMultipart();
textPart = new MimeBodyPart();
reportPart = new MimeBodyPart();
reportValues = new InternetHeaders();
try {
multiPart.setSubType(CONTENT_SUBTYPE);
multiPart.addBodyPart(textPart);
multiPart.addBodyPart(reportPart);
}
catch (MessagingException e) {
throw new AS2MessageException("Unable to construct a new disposition notification", e);
}
}
DispositionNotification(AS2Message as2Message) throws AS2MessageException {
this();
try {
SMimeMessage smime = new SMimeMessage(as2Message.getBodyPart());
if (smime.isSigned()) {
smime = smime.unsign();
}
MimeMultipart multiPartContent;
if (smime.getBodyPart().getContent() instanceof MimeMultipart) {
multiPartContent = (MimeMultipart)smime.getBodyPart().getContent();
}
else {
throw new AS2MessageException("Invalid message content: "
+ smime.getBodyPart().getContentType());
}
if (multiPartContent.getContentType().toLowerCase().startsWith(
AS2Header.CONTENT_TYPE_MULTIPART_REPORT.toLowerCase())) {
parseMDN(multiPartContent);
}
else {
throw new AS2MessageException("Invalid content type: "
+ multiPartContent.getContentType());
}
}
catch (Exception e) {
throw new AS2MessageException("Unable to parse the AS2 MDN", e);
}
}
private void parseMDN(MimeMultipart report) throws AS2MessageException {
try {
int reportCount = report.getCount();
for (int i = 0; i < reportCount; i++) {
MimeBodyPart reportsPart = (MimeBodyPart) report.getBodyPart(i);
if (reportsPart.isMimeType("text/plain")) {
setText(reportsPart.getContent().toString());
}
else if (reportsPart.isMimeType(AS2Header.CONTENT_TYPE_MESSAGE_DISPOSITION_NOTIFICATION)) {
InternetHeaders rptValues = new InternetHeaders(reportsPart
.getInputStream());
setReportValue(REPORTING_UA, rptValues.getHeader(
REPORTING_UA, ", "));
setOriginalMessageID(rptValues.getHeader(
ORIG_RECIPIENT, ", "));
setReportValue(FINAL_RECIPIENT, rptValues.getHeader(
FINAL_RECIPIENT, ", "));
setReportValue(ORIG_MESSAGE_ID, rptValues.getHeader(
ORIG_MESSAGE_ID, ", "));
setReportValue(DISPOSITION, rptValues.getHeader(
DISPOSITION, ", "));
setReportValue(RECEIVED_CONTENT_MIC, rptValues
.getHeader(RECEIVED_CONTENT_MIC, ", "));
}
}
}
catch (Exception e) {
throw new AS2MessageException("Error in parsing MDN", e);
}
}
public boolean matchOriginalContentMIC(String originalMIC) {
String receivedMIC = getReceivedContentMIC();
if (originalMIC == null) {
if (receivedMIC == null) {
return true;
}
else {
return false;
}
}
else {
if (receivedMIC==null) {
return false;
}
else {
try {
originalMIC = StringUtilities.tokenize(originalMIC, ", ")[0];
receivedMIC = StringUtilities.tokenize(receivedMIC, ", ")[0];
if (originalMIC.equals(receivedMIC)) {
return true;
}
else {
return false;
}
}
catch (Exception e) {
return false;
}
}
}
}
public String getOriginalMessageID() {
return StringUtilities.trim(getReportValue(ORIG_MESSAGE_ID), "<", ">");
}
public void setOriginalMessageID(String messageID) {
setReportValue(ORIG_MESSAGE_ID, StringUtilities.wraps(messageID, "<", ">"));
}
public String getReceivedContentMIC() {
return getReportValue(RECEIVED_CONTENT_MIC);
}
public void setReceivedContentMIC(String mic) {
setReportValue(RECEIVED_CONTENT_MIC, mic);
}
public void setReceivedContentMIC(String mic, String alg) {
setReceivedContentMIC(mic + ", " + alg);
}
public Disposition getDisposition() throws AS2MessageException {
return new Disposition(getReportValue(DISPOSITION));
}
public void setDisposition(Disposition disposition) throws AS2MessageException {
setReportValue(DISPOSITION, disposition);
}
public void setText(String text) throws AS2MessageException {
try {
String encodeText = MimeUtility.encodeText(text + "\r\n", "us-ascii",
"7bit");
textPart.setContent(encodeText, "text/plain");
textPart.setHeader("Content-Type", "text/plain; charset=us-ascii");
textPart.setHeader("Content-Transfer-Encoding", "7bit");
}
catch (Exception e) {
throw new AS2MessageException("Unable to set text to MDN", e);
}
}
public String getText() throws AS2MessageException {
try {
return textPart.getContent().toString();
}
catch (Exception e) {
throw new AS2MessageException("Unable to get text from MDN", e);
}
}
public void setReportValue(String key, Object value) {
if (key != null && value != null) {
reportValues.setHeader(key, value.toString());
}
}
public String getReportValue(String key) {
if (key == null) {
return null;
}
else {
return reportValues.getHeader(key, ", ");
}
}
private void saveReportValues() throws AS2MessageException {
try {
Enumeration reportEn = reportValues.getAllHeaderLines();
StringBuffer reportData = new StringBuffer();
while (reportEn.hasMoreElements()) {
reportData.append((String) reportEn.nextElement()).append("\r\n");
}
reportData.append("\r\n");
String reportText = MimeUtility.encodeText(reportData.toString(),
"us-ascii", "7bit");
reportPart.setContent(reportText,
AS2Header.CONTENT_TYPE_MESSAGE_DISPOSITION_NOTIFICATION);
reportPart.setHeader("Content-Type",
AS2Header.CONTENT_TYPE_MESSAGE_DISPOSITION_NOTIFICATION);
reportPart.setHeader("Content-Transfer-Encoding", "7bit");
}
catch (Exception e) {
throw new AS2MessageException("Error in saving report values", e);
}
}
public MimeBodyPart getBodyPart() throws AS2MessageException {
try {
saveReportValues();
MimeBodyPart bodyPart = new MimeBodyPart();
bodyPart.setContent(multiPart);
boolean isContentTypeFolded = new Boolean(System.getProperty("mail.mime.foldtext","true")).booleanValue();
bodyPart.setHeader("Content-Type", isContentTypeFolded? multiPart.getContentType():multiPart.getContentType().replaceAll("\\s"," "));
return bodyPart;
}
catch (Exception e) {
throw new AS2MessageException("Unable to construct the body part", e);
}
}
public void replyTo(AS2Message message, String reportingUA) throws AS2MessageException {
setText(DISCLAIMER);
setReportValue(REPORTING_UA, reportingUA);
setReportValue(ORIG_RECIPIENT, "rfc822; \"" + message.getFromPartyID() + "\"");
setReportValue(FINAL_RECIPIENT, "rfc822; \"" + message.getFromPartyID() + "\"");
setOriginalMessageID(message.getMessageID());
setDisposition(new Disposition());
}
}