Update of /cvsroot/mrpostman/mrpostman/src/org/mrbook/mrpostman/maildotcom
In directory sc8-pr-cvs1:/tmp/cvs-serv10610/mrpostman/src/org/mrbook/mrpostman/maildotcom
Added Files:
Attachment.java MailMessage.java PatternTest.java
MailDotComMessageParser.java MailDotComMessageParserTest.java
MailIdentifier.java
Log Message:
--- NEW FILE: Attachment.java ---
/*
* -*- mode: java; c-basic-indent: 4; indent-tabs-mode: nil -*-
* :indentSize=4:noTabs=true:tabSize=4:indentOnTab=true:indentOnEnter=true:mode=java:
* ex: set tabstop=4 expandtab:
*
* MrPostman - webmail <-> email gateway
* Copyright (C) 2002-2003 MrPostman Development Group
* Projectpage: http://mrbook.org/mrpostman/
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* In particular, this implies that users are responsible for
* using MrPostman after reading the terms and conditions given
* by their web-mail provider.
*
* You should have received a copy of the GNU General Public License
* Named LICENSE in the base directory of this distribution,
* if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.mrbook.mrpostman.maildotcom;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.ArrayList;
import java.util.Iterator;
/**
* @author chris
* Represents an Attachment in the MailDotComMessageParser
*/
public class Attachment {
private String partId = null;
private String filename = null;
private String url = null;
private LinkedHashMap headerLines = null;
private ArrayList bodyLines;
private String bodyDelimiter = null;
/**
*
*/
public Attachment() {
super();
headerLines = new LinkedHashMap();
bodyLines = new ArrayList();
}
/**
* @return
*/
public String getFilename() {
return filename;
}
/**
* @return
*/
public String getPartId() {
return partId;
}
/**
* @param string
*/
public void setFilename(String string) {
filename = string;
}
/**
* @param string
*/
public void setPartId(String string) {
partId = string;
}
/**
* @return
*/
public String getUrl() {
return url;
}
/**
* @param string
*/
public void setUrl(String string) {
url = string;
}
public void addHeaderLine(String headerKeyStr, String headerValueStr) {
headerLines.put(headerKeyStr, headerValueStr);
}
public void addBodyLine(String line) {
bodyLines.add(line);
}
public String toString() {
StringBuffer buff = new StringBuffer();
if (!isEmbeddedAttachment()) {
buff.append("Attachment URL: ").append(url);
buff.append("\nFilename: ").append(filename);
buff.append("\nPartId: ").append(partId);
buff.append(headerLines.toString()).append("\n");
} else {
buff.append("Inline Attachement\n");
buff.append(headerLines.toString()).append("\n");
for (Iterator it = bodyLines.iterator(); it.hasNext(); ) {
buff.append((String)it.next()).append("\n");
}
}
return buff.toString();
}
/**
* @return
*/
public boolean isEmbeddedAttachment() {
return bodyLines.size() > 0;
}
/**
* @param string
*/
public void setBodyDelimiter(String string) {
bodyDelimiter = string;
}
/**
* @return
*/
public String getBodyDelimiter() {
return bodyDelimiter;
}
public String getHeader(String key) {
return (String)headerLines.get(key);
}
public Collection getBodyLines() {
return bodyLines;
}
public LinkedHashMap getHeaders() {
return headerLines;
}
}
--- NEW FILE: MailMessage.java ---
/*
* -*- mode: java; c-basic-indent: 4; indent-tabs-mode: nil -*-
* :indentSize=4:noTabs=true:tabSize=4:indentOnTab=true:indentOnEnter=true:mode=java:
* ex: set tabstop=4 expandtab:
*
* MrPostman - webmail <-> email gateway
* Copyright (C) 2002-2003 MrPostman Development Group
* Projectpage: http://mrbook.org/mrpostman/
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* In particular, this implies that users are responsible for
* using MrPostman after reading the terms and conditions given
* by their web-mail provider.
*
* You should have received a copy of the GNU General Public License
* Named LICENSE in the base directory of this distribution,
* if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.mrbook.mrpostman.maildotcom;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
/**
* Helper class to represent a Message
* @author chris
*
*/
public class MailMessage {
private LinkedHashMap headerLines = null;
private ArrayList attachments = null;
private ArrayList bodyLines;
private String boundary;
private int attachmentCount;
private LinkedHashMap bodyHeaderLines = null;
/**
* Counter used when generating part numbers when constructing MIME encoded message...
*/
private int tmpPartCount = 0;
public MailMessage() {
headerLines = new LinkedHashMap();
bodyLines = new ArrayList();
bodyHeaderLines = new LinkedHashMap();
attachments = new ArrayList();
attachmentCount = -1;
}
public void addBodyLine(String line) {
bodyLines.add(line);
}
public void addHeaderLine(String key, String value) {
headerLines.put(key, value);
}
public String getHeader(String key) {
return (String)headerLines.get(key);
}
public void addBodyHeaderLine(String key, String value) {
bodyHeaderLines.put(key, value);
}
public String getBodyHeader(String key) {
return (String)bodyHeaderLines.get(key);
}
public void addAttachment(Attachment attachment) {
attachments.add(attachment);
}
public Attachment getCurrentAttachment() {
return (Attachment) attachments.get(attachmentCount);
}
public String toString() {
StringBuffer buff = new StringBuffer();
for(Iterator it = headerLines.keySet().iterator(); it.hasNext();) {
String hdrKey = (String)it.next();
String value = (String)headerLines.get(hdrKey);
buff.append(hdrKey + ": " + value).append("\n");
}
buff.append("\n");
for(Iterator it = bodyHeaderLines.keySet().iterator(); it.hasNext();) {
String hdrKey = (String)it.next();
String value = (String)bodyHeaderLines.get(hdrKey);
buff.append(hdrKey + ": " + value).append("\n");
}
buff.append("\n");
for(Iterator it = bodyLines.iterator(); it.hasNext();) {
buff.append((String)it.next()).append("\n");
}
buff.append(attachments);
return buff.toString();
}
/**
* @return
*/
public int getAttachmentCount() {
return attachmentCount;
}
/**
* @param i
*/
public void setAttachmentCount(int i) {
attachmentCount = i;
}
public void incrementAttachmentCount() {
attachmentCount++;
}
public int getNumberAttachments() {
return attachments.size();
}
public Collection getBodyLines() {
return bodyLines;
}
/**
* Return the Attachment at specified index (starting from 0)
* @throws IndexOutOfBoundsException if invalid index passed
* @param index
* @return
*/
public Attachment getAttachment(int index) throws IndexOutOfBoundsException {
return (Attachment)attachments.get(index);
}
/**
* @return
*/
public String getBoundary() {
return boundary;
}
/**
* @param string
*/
public void setBoundary(String string) {
boundary = string;
}
/**
* @return
*/
public int getTmpPartCount() {
return tmpPartCount;
}
/**
* @param i
*/
public void setTmpPartCount(int i) {
tmpPartCount = i;
}
public LinkedHashMap getBodyHeaders() {
return bodyHeaderLines;
}
public LinkedHashMap getHeaders() {
return headerLines;
}
/**
* Utility method to return a LinkedHasMap (as used in our Header lists) into
* a flat list of encoded header lines i.e. "key: value"
* @return Collection
*/
public static Collection getHeadersAsCollection(LinkedHashMap lhmap) {
ArrayList list = new ArrayList(lhmap.keySet().size());
for(Iterator it = lhmap.keySet().iterator(); it.hasNext();) {
String hdrKey = (String)it.next();
String value = (String)lhmap.get(hdrKey);
list.add(hdrKey + ": " + value);
}
return list;
}
}
--- NEW FILE: PatternTest.java ---
/*
* -*- mode: java; c-basic-indent: 4; indent-tabs-mode: nil -*-
* :indentSize=4:noTabs=true:tabSize=4:indentOnTab=true:indentOnEnter=true:mode=java:
* ex: set tabstop=4 expandtab:
*
* MrPostman - webmail <-> email gateway
* Copyright (C) 2002-2003 MrPostman Development Group
* Projectpage: http://mrbook.org/mrpostman/
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* In particular, this implies that users are responsible for
* using MrPostman after reading the terms and conditions given
* by their web-mail provider.
*
* You should have received a copy of the GNU General Public License
* Named LICENSE in the base directory of this distribution,
* if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.mrbook.mrpostman.maildotcom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author chris
* Simple class to test Patterns during development
*/
public class PatternTest {
/**
*
*/
public PatternTest() {
super();
}
public static void main(String[] args) {
String line = "<A HREF=\"/getattach/attach1.zip?folder=INBOX&msg_uid=1073739904&filename=attach1.zip&partsno=3\" target=\"_blank\"><FONT COLOR=\"BLUE\">attach1.zip</FONT></A></STRONG><BR>";
Pattern attachPattern = Pattern.compile("^.*?<A HREF=\"(/getattach/(.*)\\?folder=INBOX&msg_uid=(.*)&filename=(.*)&partsno=(.*))\".*?>.*$");
Matcher match = attachPattern.matcher(line);
if (match.find()) {
System.out.println(match.group(1));
System.out.println(match.group(2));
System.out.println(match.group(3));
} else {
System.out.println("No match");
}
}
}
--- NEW FILE: MailDotComMessageParser.java ---
/*
* -*- mode: java; c-basic-indent: 4; indent-tabs-mode: nil -*-
* :indentSize=4:noTabs=true:tabSize=4:indentOnTab=true:indentOnEnter=true:mode=java:
* ex: set tabstop=4 expandtab:
*
* MrPostman - webmail <-> email gateway
* Copyright (C) 2002-2003 MrPostman Development Group
* Projectpage: http://mrbook.org/mrpostman/
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* In particular, this implies that users are responsible for
* using MrPostman after reading the terms and conditions given
* by their web-mail provider.
*
* You should have received a copy of the GNU General Public License
* Named LICENSE in the base directory of this distribution,
* if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.mrbook.mrpostman.maildotcom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.logging.Logger;
import java.io.BufferedReader;
import java.io.IOException;
/**
* @author chris
*
* Parse the message data returned from Mail.com into an object representation suitable for encoding into a
* MIME message
*/
public class MailDotComMessageParser {
private static Logger logger =
Logger.getLogger(
"org.mrbook.mrpostman.maildotcom.MailDotComMessageParser");
//State settings
private static final int START = 0;
private static final int PROCESSING_HEADER = 1;
private static final int FINDING_BODY = 2;
private static final int PROCESSING_BODY = 3;
private static final int FINDING_ATTACHMENT = 4;
private static final int PROCESSING_ATTACHMENT = 5;
private static final int PROCESSING_INLINE_ATTACHMENT = 6;
private static final int STOPPED = 9;
private static final int DONE = 10;
/**
* Represents the state of the parser.
*/
private int state = START;
/**
* Represents the delimeter used around the body of the message. Can be either
* TEXT_BODY_DELIM or HTML_BODY_DELIM
*/
private String bodyDelimiter = null;
private MailMessage message = null;
//Message and attachment patterns...
private Pattern bfieldpattern = Pattern.compile("<b>([^:]*):.*</b>");
private Pattern bbfieldpattern = Pattern.compile("<B>([^:]*):.*</B>\\s*(.*)\\s*<BR>");
private Pattern attachPattern =
Pattern.compile("^.*?<A HREF=\"(/getattach/(.*)\\?folder=INBOX&msg_uid=(.*)&filename=(.*)&partsno=(\\d+))\".*?>.*$");
//Pattern.compile("<a target=\"_blank\" href=\"(.*)\">");
private Pattern attachStartPattern =
Pattern.compile("^<HR SIZE=1>$");
private static final String TEXT_BODY_START_DELIM = "<PRE>";
private static final String TEXT_BODY_END_DELIM = "</PRE>";
private static final String HTML_BODY_START_DELIM = "<XHTML>";
private static final String HTML_BODY_END_DELIM = "</XHTML>";
/**
*
*/
public MailDotComMessageParser() {
super();
state = START;
}
/**
* Process the message.
* This method is called for each line in the received message
* Returns the number of body lines processed. This is used to stop parsing if this is just a TOP command
*/
MailMessage processMessage(BufferedReader br, int numLines)
throws IOException {
//The message may be embedded between <PRE> </PRE> tags if sent in Text
//or in <xhtml></xhtml> if sent in HTML
//The same message may contain both if sent in both TEXT and HTM but the others will be as different
//body parts
boolean insidePre = false;
boolean insideXHTML = false;
int lineNo = 0;
logger.finest("*** Starting message processing ***");
//Create our structure to store the parsed message content...
message = new MailMessage();
String line = null;
//We start by finding and processing the header...
state = PROCESSING_HEADER;
while ((line = br.readLine()) != null && state != DONE) {
logger.finest("MailDotComMessageParser html: " + line);
// TODO - I suspect this may happen - but am not sure so if you
// see this in your log let me know! - CH
if (line.indexOf("Your Mail.com session is sponsored by:") > -1) {
logger.warning("*** SPONSOR PAGE ***");
}
//Process the header...
switch (state) {
case PROCESSING_HEADER :
processMessageHeader(br, line);
break;
case FINDING_BODY :
processMessageFindStartOfBody(br, line);
break;
case PROCESSING_BODY :
processMessageBody(br, line);
break;
case FINDING_ATTACHMENT :
findingAttachments(br, line);
break;
case PROCESSING_ATTACHMENT :
processAttachments(br, line);
break;
case PROCESSING_INLINE_ATTACHMENT :
processInlineAttachmentBody(br, line);
break;
}
//A TOP command can stop this processing prematurely...
if (numLines > -1) {
if (lineNo >= numLines) {
state = STOPPED;
break;
}
}
} //end while
logger.finest(message.toString());
logger.finest("*** Finished message processing ***");
return message;
}
/**
* Process the message header.
*
* @param message
* @param br
* @param numLines
* @param line
* @return
* @throws IOException
*/
void processMessageHeader(
BufferedReader br,
String line)
throws IOException {
String headerKeyStr = null;
String headerValueStr = null;
String line2 = null;
boolean processedHeader = false;
//There are two formats for header values, we'll handle them both..
Matcher match = bfieldpattern.matcher(line);
if (match.find()) {
/*
In this case the header key is on one line, the value is on the next. e.g.
<b>To:</b>
MrPostman <mrp...@ma...><br>
*/
headerKeyStr = match.group(1);
line2 = br.readLine();
headerValueStr = unescape(line2.substring(0, line2.length() - 4));
} else {
match = bbfieldpattern.matcher(line);
if (match.find()) {
/* key and header on same line. e.g.
<b>Return-Path:</b> <ch...@so...><br>
*/
headerKeyStr = match.group(1);
headerValueStr = unescape(match.group(2));
}
}
//If we found a header line then process this information here...
if (headerKeyStr != null) {
message.addHeaderLine(headerKeyStr, headerValueStr);
logger.fine(
"Found header: " + headerKeyStr + " : " + headerValueStr);
} else {
//We may have processed all our header fields, we'll know this if they have sent
//a </p> on its own
if (line.equals("</p>")) {
logger.fine("Finished processing header, </p> found.");
state = FINDING_BODY;
}
}
}
/**
* Process the message and wait for start of message body
*
* If we have processed the header, check for body part content-type lines
* and the start of the body data (if present). e.g.
* <b>Content-Type:</b> text/html; charset=us-ascii<br>
* <b>Content-Transfer-Encoding:</b> 7bit<br>
* <br>
* <xhtml>
*
* or
*
* <PRE>hi this is the body text
* </PRE>
*
* @param message
* @param br
* @param line
* @return
* @throws IOException
*/
void processMessageFindStartOfBody(
BufferedReader br,
String line)
throws IOException {
// For messages with a body type other than TEXT additional content-type lines
// will be present...
Matcher match = bbfieldpattern.matcher(line);
if (match.find()) {
/* key and header on same line. e.g.
<b>Content-Type:</b> text/html; charset=us-ascii<br>
*/
String headerKeyStr = match.group(1);
String headerValueStr = unescape(match.group(2));
logger.fine(
"Found body part header: " + headerKeyStr + " : " + headerValueStr);
message.addBodyHeaderLine(headerKeyStr, headerValueStr);
} else if (line.toUpperCase().startsWith(TEXT_BODY_START_DELIM)) {
bodyDelimiter = TEXT_BODY_START_DELIM;
state = PROCESSING_BODY;
logger.fine(
"We have entered body - delimited by " + TEXT_BODY_START_DELIM);
//we'll strip the pre tag
message.addBodyLine(line.substring(TEXT_BODY_START_DELIM.length()));
} else if (line.toUpperCase().startsWith(HTML_BODY_START_DELIM)) {
bodyDelimiter = HTML_BODY_START_DELIM;
state = PROCESSING_BODY;
logger.fine(
"We have entered body - delimited by " + HTML_BODY_START_DELIM);
//we'll leave the xhtml tags complete
message.addBodyLine(line);
}
}
/**
* Process the message body.
*
* @param message
* @param br
* @param line
* @return
* @throws IOException
*/
void processMessageBody(
BufferedReader br,
String line)
throws IOException {
boolean addLineToBody = false;
if (bodyDelimiter.equals(TEXT_BODY_START_DELIM)) {
// check if we have finished the body part...
if (line.toUpperCase().startsWith(TEXT_BODY_END_DELIM)) {
logger.fine(
"We are have left body - delimited by "
+ TEXT_BODY_END_DELIM);
bodyDelimiter = null;
state = FINDING_ATTACHMENT;
} else {
//Add this line to our body content...
addLineToBody = true;
}
} else if (bodyDelimiter.equals(HTML_BODY_START_DELIM)) {
// check if we have finished the body part...
if (line.toUpperCase().startsWith(HTML_BODY_END_DELIM)) {
logger.fine(
"We are have left body - delimited by "
+ HTML_BODY_END_DELIM);
bodyDelimiter = null;
state = FINDING_ATTACHMENT;
// include the </xhtml> end tag in the body content...
addLineToBody = true;
} else {
//Add this line to our body content...
addLineToBody = true;
}
}
if (addLineToBody) {
message.addBodyLine(line);
}
}
/**
* Find any attachments in the message.
* This method is called for each line in the received message after the main body has been processed.
*
* Attachments always start with:
* <hr size="1">
*/
private void findingAttachments(BufferedReader br, String line) {
//Check for attachment start...
Matcher match = attachStartPattern.matcher(line.toUpperCase());
if (match.find()) {
Attachment attachment = new Attachment();
message.incrementAttachmentCount();
message.addAttachment(attachment);
logger.fine("Found attachment start.");
state = PROCESSING_ATTACHMENT;
}
}
/**
* Process any attachments in the message.
* This method is called for each line in the received message after the main body has been processed.
*
* Attachments which are not inline will appear similar to this:
* <hr size="1">
* <b>Content-Type:</b> application/zip; name="attach2.zip"<br>
* <b>Content-Transfer-Encoding:</b> base64<br>
* <b>Content-Disposition:</b> inline; filename="attach2.zip"<br>
* <br>
* <br><strong><a target="_blank" href="http://mail01.mail.com/getattach/attach2.zip?folder=INBOX&msg_uid=1073240058&filename=attach2.zip&partsno=2"><font color="BLUE">attach2.zip</font></a></strong><br>
*
*/
private void processAttachments(BufferedReader br, String line) {
// Attachments will have content type header lines...
Matcher match = bbfieldpattern.matcher(line);
if (match.find()) {
/* key and header on same line. e.g.
<b>Content-Type:</b> text/html; charset=us-ascii<br>
*/
String headerKeyStr = match.group(1);
String headerValueStr = unescape(match.group(2));
logger.fine(
"Found attachment header: " + headerKeyStr + " : " + headerValueStr);
message.getCurrentAttachment().addHeaderLine(headerKeyStr, headerValueStr);
}
//Attachments can be inline for mime types which the browser can display or as links...
//Check for attachment links...
match = attachPattern.matcher(line);
if (match.find()) {
String attachmentUrl = match.group(1);
String filename = match.group(4);
String partno = match.group(5);
message.getCurrentAttachment().setFilename(filename);
message.getCurrentAttachment().setUrl(attachmentUrl);
message.getCurrentAttachment().setPartId(partno);
logger.fine("Found attachment: " + message.getCurrentAttachment().toString());
//finished this attachment...
state = FINDING_ATTACHMENT;
}
//Check for inline attachments...
if (line.toUpperCase().startsWith(TEXT_BODY_START_DELIM)) {
message.getCurrentAttachment().setBodyDelimiter(TEXT_BODY_START_DELIM);
state = PROCESSING_INLINE_ATTACHMENT;
logger.fine("We have entered inline attachment body - delimited by " + TEXT_BODY_START_DELIM);
//we'll strip the pre tag
message.getCurrentAttachment().addBodyLine(line.substring(TEXT_BODY_START_DELIM.length()));
} else if (line.toUpperCase().startsWith(HTML_BODY_START_DELIM)) {
message.getCurrentAttachment().setBodyDelimiter(HTML_BODY_START_DELIM);
state = PROCESSING_INLINE_ATTACHMENT;
logger.fine("We have entered inline attachment body - delimited by " + HTML_BODY_START_DELIM);
//we'll leave the xhtml tags complete
message.getCurrentAttachment().addBodyLine(line);
}
}
/**
* Process the inline attachment body.
*
* @param message
* @param br
* @param line
* @return
* @throws IOException
*/
void processInlineAttachmentBody(
BufferedReader br,
String line)
throws IOException {
boolean addLineToBody = false;
if (message.getCurrentAttachment().getBodyDelimiter().equals(TEXT_BODY_START_DELIM)) {
// check if we have finished the body part...
if (line.toUpperCase().startsWith(TEXT_BODY_END_DELIM)) {
logger.fine(
"We are have left body - delimited by "
+ TEXT_BODY_END_DELIM);
state = FINDING_ATTACHMENT;
} else {
//Add this line to our body content...
addLineToBody = true;
}
} else if (message.getCurrentAttachment().getBodyDelimiter().equals(HTML_BODY_START_DELIM)) {
// check if we have finished the body part...
if (line.toUpperCase().startsWith(HTML_BODY_END_DELIM)) {
logger.fine(
"We are have left body - delimited by "
+ HTML_BODY_END_DELIM);
state = FINDING_ATTACHMENT;
// include the </xhtml> end tag in the body content...
addLineToBody = true;
} else {
//Add this line to our body content...
addLineToBody = true;
}
}
if (addLineToBody) {
message.getCurrentAttachment().addBodyLine(line);
}
}
private String unescape(String mystr) {
String line = mystr.replaceAll("\\&", "\\&");
line = line.replaceAll("\\<", "<");
line = line.replaceAll("\\>", ">");
line = line.replaceAll("\\"", "\"");
line = line.replaceAll("\\"", "\"");
return line;
}
/**
* @return
*/
public MailMessage getMessage() {
return message;
}
}
--- NEW FILE: MailDotComMessageParserTest.java ---
/*
* -*- mode: java; c-basic-indent: 4; indent-tabs-mode: nil -*-
* :indentSize=4:noTabs=true:tabSize=4:indentOnTab=true:indentOnEnter=true:mode=java:
* ex: set tabstop=4 expandtab:
*
* MrPostman - webmail <-> email gateway
* Copyright (C) 2002-2003 MrPostman Development Group
* Projectpage: http://mrbook.org/mrpostman/
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* In particular, this implies that users are responsible for
* using MrPostman after reading the terms and conditions given
* by their web-mail provider.
*
* You should have received a copy of the GNU General Public License
* Named LICENSE in the base directory of this distribution,
* if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.mrbook.mrpostman.maildotcom;
import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import junit.framework.TestCase;
//TODO - Add test case with two embedded attachments
public class MailDotComMessageParserTest extends TestCase {
//FILE1 = HTML with TXT attachment...
public static final String MSG_FILE1 = "test/mesg1.mail.htm";
//FILE2 = HTML with ZIP attachment...
public static final String MSG_FILE2 = "test/mesg2.mail.htm";
//FILE3 = TEXT body...
public static final String MSG_FILE3 = "test/mesg3.mail.htm";
//FILE4 = HTML with HTML attachment...
public static final String MSG_FILE4 = "test/mesg4.mail.htm";
//FILE5 - HTML with image attachment...
public static final String MSG_FILE5 = "test/mesg5.mail.htm";
//FILE6 - HTML with 2 zip attachments...
public static final String MSG_FILE6 = "test/mesg6.mail.htm";
//FILE7 - Multipart/alternative HTML and TEXT
public static final String MSG_FILE7 = "test/mesg7.mail.htm";
public MailDotComMessageParserTest(String name) {
super(name);
}
/**
* This code will verify that the html message body code is working correctly
* This code will also verify that the inline text attachment code is working correctly
* @throws Exception
*/
public void testParserFile1() throws Exception {
try {
MailMessage msg = runParser(MSG_FILE1);
// check headers...
assertEquals(msg.getHeader("From"), "Chris Humphreys <ch...@so...>");
assertEquals(msg.getHeader("To"), "MrPostman <mrp...@ma...>");
assertEquals(msg.getHeader("Subject"), "test html with txt attachment");
assertEquals(msg.getHeader("Date"), "Sat, 10 Jan 2004 13:02:56 +0000");
// check msg body...
assertEquals(msg.getBodyHeader("Content-Type"), "text/html; charset=us-ascii");
assertTrue(comparePartBodies(msg.getBodyLines(), createMsg1Body()));
// check attachment...
assertEquals(1, msg.getNumberAttachments());
assertTrue(msg.getAttachment(0).isEmbeddedAttachment());
assertEquals(msg.getAttachment(0).getHeader("Content-Type"), "text/plain; name=\"attach1.txt\"");
assertEquals((String)msg.getAttachment(0).getBodyLines().iterator().next(), "text of attachment");
//correct!
} catch (Exception e) {
fail("Exception " + e.getMessage());
}
}
/**
* This test will verify that the attachment link code is working correctly
* @throws Exception
*/
public void testParserFile2() throws Exception {
try {
MailMessage msg = runParser(MSG_FILE2);
// check headers...
assertEquals(msg.getHeader("From"), "Chris Humphreys <ch...@so...>");
assertEquals(msg.getHeader("To"), "MrPostman <mrp...@ma...>");
assertEquals(msg.getHeader("Subject"), "test with zip attachment");
assertEquals(msg.getHeader("Date"), "Sun, 04 Jan 2004 18:14:06 +0000");
// we'll assume msg body works ok as it is similar to test1.
// check attachment...
assertEquals(1, msg.getNumberAttachments());
assertFalse(msg.getAttachment(0).isEmbeddedAttachment());
assertEquals(msg.getAttachment(0).getHeader("Content-Type"), "application/zip; name=\"attach2.zip\"");
assertEquals(msg.getAttachment(0).getFilename(), "attach2.zip");
assertEquals(msg.getAttachment(0).getUrl(), "/getattach/attach2.zip?folder=INBOX&msg_uid=1073240058&filename=attach2.zip&partsno=2");
//correct!
} catch (Exception e) {
fail("Exception " + e.getMessage());
}
}
/**
* This test verifies that the Header code and the TEXT body code works correctly.
* @throws Exception
*/
public void testParserFile3() throws Exception {
try {
MailMessage msg = runParser(MSG_FILE3);
// check headers...
assertEquals(msg.getHeader("From"), "Chris Humphreys <ch...@so...>");
assertEquals(msg.getHeader("To"), "MrPostman <mrp...@ma...>");
assertEquals(msg.getHeader("Subject"), "single body text");
assertEquals(msg.getHeader("Date"), "Tue, 06 Jan 2004 21:36:38 +0000");
// check msg body...
assertEquals(msg.getHeader("Content-Type"), "text/plain; charset=us-ascii; format=flowed");
assertEquals(msg.getHeader("Content-Transfer-Encoding"), "7bit");
assertEquals((String)msg.getBodyLines().iterator().next(),"hi this is the body text");
// check attachment...
assertEquals(0, msg.getNumberAttachments());
// correct!
} catch (Exception e) {
fail("Exception " + e.getMessage());
}
}
/**
* This test verifies the inline HTML attachment code works correctly
* @throws Exception
*/
public void testParserFile4() throws Exception {
try {
MailMessage msg = runParser(MSG_FILE4);
//we'll assume headers work correctly...
//we'all assume html body works correctly...
// check attachment...
assertEquals(1, msg.getNumberAttachments());
assertTrue(msg.getAttachment(0).isEmbeddedAttachment());
assertEquals(msg.getAttachment(0).getHeader("Content-Type"), "text/html; name=\"attach3.html\"");
assertTrue(comparePartBodies(msg.getAttachment(0).getBodyLines(), createMsg4AttachmentBody()));
//correct!
} catch (Exception e) {
fail("Exception " + e.getMessage());
}
}
/**
* This test verifies that image attachment code works correctly
* This message has an blank html body and JPG attachment
* @throws Exception
*/
public void testParserFile5() throws Exception {
try {
MailMessage msg = runParser(MSG_FILE5);
// we'll assume headers work correctly...
//we'all assume html body works correctly...
// check attachment...
assertEquals(1, msg.getNumberAttachments());
assertFalse(msg.getAttachment(0).isEmbeddedAttachment());
assertEquals(msg.getAttachment(0).getHeader("Content-Type"), "image/jpeg; name=\"gui-1.jpg\"");
assertEquals(msg.getAttachment(0).getUrl(), "/getattach/gui-1.jpg?folder=INBOX&msg_uid=1073739625&filename=gui-1.jpg&partsno=2");
assertEquals(msg.getAttachment(0).getFilename(), "gui-1.jpg");
//correct!
} catch (Exception e) {
fail("Exception " + e.getMessage());
}
}
/**
* This test verifies that multiple non-embedded attachment code
* works correctly
* @throws Exception
*/
public void testParserFile6() throws Exception {
try {
MailMessage msg = runParser(MSG_FILE6);
//we'll assume headers work correctly...
//we'all assume html body works correctly...
// check attachment...
assertEquals(2, msg.getNumberAttachments());
assertFalse(msg.getAttachment(0).isEmbeddedAttachment());
assertEquals(msg.getAttachment(0).getHeader("Content-Type"), "application/zip; name=\"attach2.zip\"");
assertEquals(msg.getAttachment(0).getUrl(), "/getattach/attach2.zip?folder=INBOX&msg_uid=1073739904&filename=attach2.zip&partsno=2");
assertEquals(msg.getAttachment(0).getFilename(), "attach2.zip");
assertFalse(msg.getAttachment(1).isEmbeddedAttachment());
assertEquals(msg.getAttachment(1).getHeader("Content-Type"), "application/zip; name=\"attach1.zip\"");
assertEquals(msg.getAttachment(1).getUrl(), "/getattach/attach1.zip?folder=INBOX&msg_uid=1073739904&filename=attach1.zip&partsno=3");
assertEquals(msg.getAttachment(1).getFilename(), "attach1.zip");
//correct!
} catch (Exception e) {
fail("Exception " + e.getMessage());
}
}
/**
* This test verifies that the Header code and the TEXT body code works correctly.
* Mail.com will infact just return the HTML version and ignore the TEXT version
* @throws Exception
*/
public void testParserFile7() throws Exception {
try {
MailMessage msg = runParser(MSG_FILE7);
// check headers...
assertEquals(msg.getHeader("From"), "Chris Humphreys <ch...@so...>");
assertEquals(msg.getHeader("To"), "MrPostman <mrp...@ma...>");
assertEquals(msg.getHeader("Subject"), "multipart alternative");
assertEquals(msg.getHeader("Date"), "Sun, 11 Jan 2004 19:19:06 +0000");
// check msg body...
assertEquals(msg.getBodyHeader("Content-Type"), "text/html; charset=us-ascii");
assertEquals(msg.getBodyHeader("Content-Transfer-Encoding"), "7bit");
assertTrue(comparePartBodies(msg.getBodyLines(), createMsg7Body()));
// check attachment...
assertEquals(0, msg.getNumberAttachments());
// correct!
} catch (Exception e) {
fail("Exception " + e.getMessage());
}
}
private MailMessage runParser(String fileName) throws Exception {
BufferedReader br = new BufferedReader( new FileReader(fileName));
MailDotComMessageParser parser = new MailDotComMessageParser();
parser.processMessage(br, -1);
MailMessage message = parser.getMessage();
return message;
}
private Collection createMsg1Body() {
//see message1.eml
//Note: it is given that mail.com will convert the file to xhtml
ArrayList bodyLines = new ArrayList();
bodyLines.add("<xhtml>");
bodyLines.add("<head>");
bodyLines.add(" <xmeta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\">");
bodyLines.add(" <title></title>");
bodyLines.add("</head>");
bodyLines.add("<xbody text=\"#000000\" bgcolor=\"#ffffff\">");
bodyLines.add("hi there html body<br>");
bodyLines.add("</xbody>");
bodyLines.add("</xhtml>");
return bodyLines;
}
private Collection createMsg4AttachmentBody() {
//see message4.eml
//Note: it is given that mail.com will convert the file to xhtml
ArrayList bodyLines = new ArrayList();
bodyLines.add("<xhtml>");
bodyLines.add("<xbody>");
bodyLines.add("attachment");
bodyLines.add("</xbody>");
bodyLines.add("</xhtml>");
return bodyLines;
}
private Collection createMsg7Body() {
//see message7.eml
//Note: it is given that mail.com will convert the file to xhtml
ArrayList bodyLines = new ArrayList();
bodyLines.add("<xhtml>");
bodyLines.add("<head>");
bodyLines.add(" <xmeta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\">");
bodyLines.add(" <title></title>");
bodyLines.add("</head>");
bodyLines.add("<xbody text=\"#000000\" bgcolor=\"#ffffff\">");
bodyLines.add("There are two bodies on this message!<br>");
bodyLines.add("</xbody>");
bodyLines.add("</xhtml>");
return bodyLines;
}
private boolean comparePartBodies(Collection bodyALines, Collection bodyBLines) {
Iterator itB = bodyBLines.iterator();
Iterator itA = bodyALines.iterator();
boolean equal = true;
while (true) {
if (itA.hasNext()) {
if (!itB.hasNext()) {
equal = false;
break;
} else {
//we have two lines, lets compare them...
String lineA = (String)itA.next();
if (!lineA.equals((String)itB.next())) {
equal = false;
break;
}
}
} else {
if (itB.hasNext()) {
equal = false;
break;
} else {
break;
}
}
}
return equal;
}
}
--- NEW FILE: MailIdentifier.java ---
/*
* -*- mode: java; c-basic-indent: 4; indent-tabs-mode: nil -*-
* :indentSize=4:noTabs=true:tabSize=4:indentOnTab=true:indentOnEnter=true:mode=java:
* ex: set tabstop=4 expandtab:
*
* MrPostman - webmail <-> email gateway
* Copyright (C) 2002-2003 MrPostman Development Group
* Projectpage: http://mrbook.org/mrpostman/
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* In particular, this implies that users are responsible for
* using MrPostman after reading the terms and conditions given
* by their web-mail provider.
*
* You should have received a copy of the GNU General Public License
* Named LICENSE in the base directory of this distribution,
* if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.mrbook.mrpostman.maildotcom;
/**
* @author chris
*
* Represents a MailIdentifier
*/
public class MailIdentifier {
String MailID = null;
String author = null;
String date = null;
String subject = null;
boolean unread = false;
boolean flagged = false;
int size;
boolean retrieveSuccess = false;
/**
*
*/
public MailIdentifier() {
super();
}
public String toString() {
return new String(
"MailID="
+ MailID
+ ", unread="
+ unread
+ " flagged="
+ flagged
+ " size="
+ size);
}
}
|