📄 webmailsession.java
字号:
xml_message.setAttribute("attachment","true");
}
if(msgs[i] instanceof MimeMessage) {
int size=((MimeMessage) msgs[i]).getSize();
size/=1024;
xml_message.setAttribute("size",(size>0?size+"":"<1")+" kB");
}
/* Subject */
subject="";
if(msgs[i].getSubject() != null) {
try {
subject=MimeUtility.decodeText(msgs[i].getSubject());
} catch(UnsupportedEncodingException ex) {
parent.getStorage().log(Storage.LOG_WARN,"Unsupported Encoding: "+ex.getMessage());
}
}
if(subject == null || subject.equals("")) {
subject=getStringResource("no subject");
}
/* Set all of what we found into the DOM */
xml_message.setHeader("FROM",from);
try {
// Modified by exce, start.
// hmm, why decode subject twice? Though it doesn't matter..
// Modified by exce, end.
xml_message.setHeader("SUBJECT",MimeUtility.decodeText(subject));
} catch(UnsupportedEncodingException e) {
parent.getStorage().log(Storage.LOG_WARN,
"Unsupported Encoding: "+e.getMessage());
}
xml_message.setHeader("TO",to);
xml_message.setHeader("CC",cc);
xml_message.setHeader("BCC",bcc);
xml_message.setHeader("REPLY-TO",replyto);
/* Date */
Date d=msgs[i].getSentDate();
String ds="";
if(d!=null) {
ds=df.format(d);
}
xml_message.setHeader("DATE",ds);
}
long time_stop=System.currentTimeMillis();
// try {
// XMLCommon.writeXML(model.getRoot(),new FileOutputStream("/tmp/wmdebug"),"");
// } catch(IOException ex) {}
parent.getStorage().log(Storage.LOG_DEBUG,"Construction of message list took "+(time_stop-time_start)+" ms. Time for IMAP transfer was "+(fetch_stop-fetch_start)+" ms.");
folder.close(false);
} catch(NullPointerException e) {
e.printStackTrace();
throw new NoSuchFolderException(folderhash);
} catch(MessagingException ex) {
ex.printStackTrace();
}
}
/**
* This indicates standard getMessage behaviour: Fetch the message from the IMAP server and store it in the
* current UserModel.
* @see getMessage(String,int,int)
*/
public static final int GETMESSAGE_MODE_STANDARD=0;
/**
* Set this mode in getMessage to indicate that the message is requested to generate a reply message and
* should therefore be set as the current "work" message.
* @see getMessage(String,int,int)
*/
public static final int GETMESSAGE_MODE_REPLY=1;
/**
* Set this mode in getMessage to indicate that the message is to be forwarded to someone else and a "work"
* message should be generated.
* @see getMessage(String,int,int)
*/
public static final int GETMESSAGE_MODE_FORWARD=2;
/**
* This is a wrapper to call getMessage with standard mode.
* @see getMessage(String,int,int)
*/
public void getMessage(String folderhash, int msgnum) throws NoSuchFolderException {
getMessage(folderhash,msgnum,GETMESSAGE_MODE_STANDARD);
}
/**
* Fetch a message from a folder.
* Will put the messages parameters in the sessions environment
*
* @param foldername Name of the folder were the message should be fetched from
* @param msgnum Number of the message to fetch
* @param mode there are three different modes: standard, reply and forward. reply and forward will enter the message
* into the current work element of the user and set some additional flags on the message if the user
* has enabled this option.
* @see net.wastl.webmail.server.WebMailSession.GETMESSAGE_MODE_STANDARD
* @see net.wastl.webmail.server.WebMailSession.GETMESSAGE_MODE_REPLY
* @see net.wastl.webmail.server.WebMailSession.GETMESSAGE_MODE_FORWARD
*/
public void getMessage(String folderhash, int msgnum, int mode) throws NoSuchFolderException {
// security reasons:
// attachments=null;
try {
TimeZone tz=TimeZone.getDefault();
DateFormat df=DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.SHORT, user.getPreferredLocale());
df.setTimeZone(tz);
Folder folder=getFolder(folderhash);
Element xml_folder=model.getFolder(folderhash);
if(folder==null) {
throw new NoSuchFolderException("No such folder: "+folderhash);
}
if(folder.isOpen() && folder.getMode()==Folder.READ_WRITE) {
folder.close(false);
folder.open(Folder.READ_ONLY);
} else if(!folder.isOpen()) {
folder.open(Folder.READ_ONLY);
}
MimeMessage m=(MimeMessage)folder.getMessage(msgnum);
String messageid;
try {
StringTokenizer tok=new StringTokenizer(m.getMessageID(),"<>");
messageid=tok.nextToken();
} catch(NullPointerException ex) {
// For mail servers that don't generate a Message-ID (Outlook et al)
messageid=user.getLogin()+"."+msgnum+".jwebmail@"+user.getDomain();
}
Element xml_current=model.setCurrentMessage(messageid);
XMLMessage xml_message=model.getMessage(xml_folder,m.getMessageNumber()+"",
messageid);
/* Check whether we already cached this message (not only headers but complete)*/
boolean cached=xml_message.messageCompletelyCached();
/* If we cached the message, we don't need to fetch it again */
if(!cached) {
//Element xml_header=model.getHeader(xml_message);
try {
String from=MimeUtility.decodeText(Helper.joinAddress(m.getFrom()));
String replyto=MimeUtility.decodeText(Helper.joinAddress(m.getReplyTo()));
String to=MimeUtility.decodeText(Helper.joinAddress(m.getRecipients(Message.RecipientType.TO)));
String cc=MimeUtility.decodeText(Helper.joinAddress(m.getRecipients(Message.RecipientType.CC)));
String bcc=MimeUtility.decodeText(Helper.joinAddress(m.getRecipients(Message.RecipientType.BCC)));
Date date_orig=m.getSentDate();
String date=getStringResource("no date");
if(date_orig!=null) {
date=df.format(date_orig);
}
String subject="";
if(m.getSubject() != null) {
subject=MimeUtility.decodeText(m.getSubject());
}
if(subject == null || subject.equals("")) {
subject=getStringResource("no subject");
}
try {
Flags.Flag[] sf = m.getFlags().getSystemFlags();
for(int j=0;j<sf.length;j++) {
if(sf[j]==Flags.Flag.RECENT) xml_message.setAttribute("recent","true");
if(sf[j]==Flags.Flag.SEEN) xml_message.setAttribute("seen","true");
if(sf[j]==Flags.Flag.DELETED) xml_message.setAttribute("deleted","true");
if(sf[j]==Flags.Flag.ANSWERED) xml_message.setAttribute("answered","true");
if(sf[j]==Flags.Flag.DRAFT) xml_message.setAttribute("draft","true");
if(sf[j]==Flags.Flag.FLAGGED) xml_message.setAttribute("flagged","true");
if(sf[j]==Flags.Flag.USER) xml_message.setAttribute("user","true");
}
} catch(NullPointerException ex) {}
if(m.getContentType().toUpperCase().startsWith("MULTIPART/")) {
xml_message.setAttribute("attachment","true");
}
int size=m.getSize();
size/=1024;
xml_message.setAttribute("size",(size>0?size+"":"<1")+" kB");
/* Set all of what we found into the DOM */
xml_message.setHeader("FROM",from);
xml_message.setHeader("SUBJECT",Fancyfier.apply(subject));
xml_message.setHeader("TO",to);
xml_message.setHeader("CC",cc);
xml_message.setHeader("BCC",bcc);
xml_message.setHeader("REPLY-TO",replyto);
xml_message.setHeader("DATE",date);
/* Decode MIME contents recursively */
xml_message.removeAllParts();
parseMIMEContent(m,xml_message,messageid);
} catch(UnsupportedEncodingException e) {
parent.getStorage().log(Storage.LOG_WARN,"Unsupported Encoding in parseMIMEContent: "+e.getMessage());
System.err.println("Unsupported Encoding in parseMIMEContent: "+e.getMessage());
}
}
/* Set seen flag (Maybe make that threaded to improve performance) */
if(user.wantsSetFlags()) {
if(folder.isOpen() && folder.getMode()==Folder.READ_ONLY) {
folder.close(false);
folder.open(Folder.READ_WRITE);
} else if(!folder.isOpen()) {
folder.open(Folder.READ_WRITE);
}
folder.setFlags(msgnum,msgnum,new Flags(Flags.Flag.SEEN),true);
folder.setFlags(msgnum,msgnum,new Flags(Flags.Flag.RECENT), false);
if((mode & GETMESSAGE_MODE_REPLY) == GETMESSAGE_MODE_REPLY) {
folder.setFlags(msgnum,msgnum,new Flags(Flags.Flag.ANSWERED),true);
}
}
folder.close(false);
/* In this part we determine whether the message was requested so that it may be used for
further editing (replying or forwarding). In this case we set the current "work" message to the
message we just fetched and then modifiy it a little (quote, add a "Re" to the subject, etc). */
XMLMessage work=null;
if((mode & GETMESSAGE_MODE_REPLY) == GETMESSAGE_MODE_REPLY ||
(mode & GETMESSAGE_MODE_FORWARD) == GETMESSAGE_MODE_FORWARD) {
//System.err.println("Setting work message!");
work=model.setWorkMessage(xml_message);
String newmsgid=WebMailServer.generateMessageID(user.getUserName());
if(work != null && (mode & GETMESSAGE_MODE_REPLY) == GETMESSAGE_MODE_REPLY) {
String from=work.getHeader("FROM");
work.setHeader("FROM",user.getEmail());
work.setHeader("TO",from);
work.prepareReply(getStringResource("reply subject prefix"),
getStringResource("reply subject postfix"),
getStringResource("reply message prefix"),
getStringResource("reply message postfix"));
} else if(work != null && (mode & GETMESSAGE_MODE_FORWARD) == GETMESSAGE_MODE_FORWARD) {
String from=work.getHeader("FROM");
work.setHeader("FROM",user.getEmail());
work.setHeader("TO","");
work.setHeader("CC","");
work.prepareForward(getStringResource("forward subject prefix"),
getStringResource("forward subject postfix"),
getStringResource("forward message prefix"),
getStringResource("forward message postfix"));
/* Copy all references to MIME parts to the new message id */
Enumeration attids=getMimeParts(work.getAttribute("msgid"));
while(attids.hasMoreElements()) {
String key=(String)attids.nextElement();
StringTokenizer tok2=new StringTokenizer(key,"/");
tok2.nextToken();
String newkey=tok2.nextToken();
mime_parts_decoded.put(newmsgid+"/"+newkey,mime_parts_decoded.get(key));
}
}
/* Clear the msgnr and msgid fields at last */
work.setAttribute("msgnr","0");
work.setAttribute("msgid",newmsgid);
prepareCompose();
}
} catch(MessagingException ex) {
ex.printStackTrace();
}
}
/**
Use depth-first search to go through MIME-Parts recursively.
@param p Part to begin with
*/
protected void parseMIMEContent(Part p, XMLMessagePart parent_part, String msgid) throws MessagingException {
StringBuffer content=new StringBuffer(1000);
XMLMessagePart xml_part;
try {
if(p.getContentType().toUpperCase().startsWith("TEXT/HTML")) {
/* The part is a text in HTML format. We will try to use "Tidy" to create a well-formated
XHTML DOM from it and then remove JavaScript and other "evil" stuff.
For replying to such a message, it will be useful to just remove all of the tags and display
only the text.
*/
xml_part=parent_part.createPart("html");
/* Here we create a DOM tree. */
Tidy tidy=new Tidy();
tidy.setUpperCaseTags(true);
Document htmldoc=tidy.parseDOM(p.getInputStream(),null);
//XMLCommon.debugXML(htmldoc);
/* Now let's look for all the malicious JavaScript and other <SCRIPT> tags,
URLS containing the "javascript:" and tags containing "onMouseOver" and such
stuff. */
// if(user.getBoolVar("filter javascript")) new JavaScriptCleaner(htmldoc);
new JavaScriptCleaner(htmldoc);
//XMLCommon.debugXML(htmldoc);
/* HTML doesn't allow us to do such fancy stuff like different quote colors,
perhaps this will be implemented in the future */
/* So we just add this HTML document to the message part, which will deal with
removing headers and tags that we don't need */
xml_part.addContent(htmldoc);
} else if(p.getContentType().toUpperCase().startsWith("TEXT") ||
p.getContentType().toUpperCase().startsWith("MESSAGE")) {
/* The part is a standard message part in some incarnation of text (html or plain).
We should decode it and take care of some extra issues like recognize quoted parts,
filter JavaScript parts and replace smileys with smiley-icons if the user has
set wantsFancy() */
xml_part=parent_part.createPart("text");
// TODO:
System.err.println("text hit");
BufferedReader in;
if(p instanceof MimeBodyPart) {
int size=p.getSize();
MimeBodyPart mpb=(MimeBodyPart)p;
InputStream is=mpb.getInputStream();
/* Workaround for Java or Javamail Bug */
is=new BufferedInputStream(is);
ByteStore ba=ByteStore.getBinaryFromIS(is,size);
in=new BufferedReader(new InputStreamReader(new ByteArrayInputStream(ba.getBytes())));
/* End of workaround */
size=is.available();
} else {
in=new BufferedReader(new InputStreamReader(p.getInputStream()));
}
//System.err.println("Content-Type: "+p.getContentType());
String token="";
int quote_level=0, old_quotelevel=0;
boolean javascript_mode=false;
/* Read in the message part line by line */
while((token=in.readLine()) != null) {
/* First decode all language and MIME dependant stuff */
// Default to ISO-8859-1 (Western Latin 1)
String charset="ISO-8859-1";
// Check whether the part contained a charset in the content-type header
StringTokenizer tok2=new StringTokenizer(p.getContentType(),";=");
String blah=tok2.nextToken();
if(tok2.hasMoreTokens()) {
blah=tok2.nextToken().trim();
if(blah.toLowerCase().equals("charset") && tok2.hasMoreTokens()) {
charset=tok2.nextToken().trim();
}
}
try {
token=new String(token.getBytes(),charset);
} catch(UnsupportedEncodingException ex1) {
parent.getStorage().log(Storage.LOG_INFO,"Java Engine does not support charset "+charset+". Trying to convert from MIME ...");
try {
charset=MimeUtility.javaCharset(charset);
token=new String(token.getBytes(),charset);
} catch(UnsupportedEncodingException ex) {
parent.getStorage().log(Storage.LOG_WARN,"Converted charset ("+charset+") does not work. Using default charset (ouput may contain errors)");
token=new String(token.getBytes());
}
}
/* Here we figure out which quote level this line has, simply by counting how many
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -