package 
   lml;

 
  import 
   java.io.BufferedOutputStream;
 
  import 
   java.io.File;
 
  import 
   java.io.FileOutputStream;
 
  import 
   java.io.InputStream;

 
  import 
   javax.mail.Message;
 
  import 
   javax.mail.MessagingException;
 
  import 
   javax.mail.Multipart;
 
  import 
   javax.mail.Part;
 
  import 
   javax.mail.internet.MimeUtility;

 
  import 
   org.apache.log4j.Logger;

 
  import 
   common.Constants;

 
  /** */ 
  /**
 * 这是一个解析邮件的工具类,不负责回显工作,与表示层无关<br>
 * 主要的方法是:
 * <ul>
 * <li>判断一个邮件体是否附件</li>
 * <li>判断一封邮件是否含有附件</li>
 * <li>解析邮件的正文</li>
 * </ul>
 * 
 * @author M.Liang Liu
 * @date 2007年5月25日16:08:40
 */ 
  
 
  public 
    
  class 
   LmlMessage  
  ... 
  {

    /** *//**
     * 得到邮件正文内容 邮件的正文可能是多种类型:
     * <ul>
     * <li> text/plain </li>
     * <li> text/html</li>
     * <li> multipart/alternative</li>
     * <li> multipart/related:内有内嵌的文件,噢噢~</li>
     * <li> mutilpart/* </li>
     * <li> message/rfc822 </li>
     * </ul>
     * 
     * @param msg:待解析正文的邮件对象或邮件体(邮件的一部分)对象
     * @author M.Liang Liu
     * @version 1.0
     * @since 1.6
     * @return 根据邮件类型返回不同的邮件正文
     */
    public static String getBody(Part part, String userName) ...{
        Logger logger = Logger.getLogger("LmlMessage.java");
        StringBuffer sb = new StringBuffer();
        sb.append(new String(""));
        try ...{
            logger.debug("The type of the part is:" + part.getContentType());
            /** *//**
             * 纯文本或者html格式的,可以直接解析掉
             */
            if (part.isMimeType("text/plain") || part.isMimeType("text/html")) ...{
                sb.append(part.getContent());
            } else if (part.isMimeType("multipart/*")) ...{
                /** *//**
                 * 可供选择的,一般情况下第一个是plain,第二个是html格式的
                 */
                if (part.isMimeType("multipart/alternative")) ...{
                    Multipart mp = (Multipart) part.getContent();
                    int index = 0;// 兼容不正确的格式,返回第一个部分
                    if (mp.getCount() > 1)
                        index = 1;// 第2个部分为html格式的哦~
                    logger.debug("Now will choose the index(start from 0):"
                            + index);
                    /** *//**
                     * 已经根据情况进行了判断,就算不符合标准格式也不怕了.
                     */
                    Part tmp = mp.getBodyPart(index);
                    sb.append(tmp.getContent());
                } else if (part.isMimeType("multipart/related")) ...{
                    /** *//**
                     * related格式的,那么第一个部分包含了body,里面含有内嵌的内容的链接.
                     */
                    Multipart mp = (Multipart) part.getContent();
                    Part tmp = mp.getBodyPart(0);
                    String body = LmlMessage.getBody(tmp, userName);
                    int count = mp.getCount();
                    /** *//**
                     * 要把那些可能的内嵌对象都先读出来放在服务器上,然后在替换相对地址为绝对地址
                     */
                    for (int k = 1; count > 1 && k < count; k++) ...{
                        Part att = mp.getBodyPart(k);
                        String attname = att.getFileName();
                        attname = MimeUtility.decodeText(attname);
                        try ...{
                            File attFile = new File(
                                    Constants.tomcat_AttHome_Key, userName
                                            .concat(attname));
                            FileOutputStream fileoutput = new FileOutputStream(
                                    attFile);
                            InputStream is = att.getInputStream();
                            BufferedOutputStream outs = new BufferedOutputStream(
                                    fileoutput);
                            byte b[] = new byte[att.getSize()];
                            is.read(b);
                            outs.write(b);
                            outs.close();
                        } catch (Exception e) ...{
                            logger
                                    .error("Error occurred when to get the photos from server");
                        }
                        String Content_ID[] = att.getHeader("Content-ID");
                        if (Content_ID != null && Content_ID.length > 0) ...{
                            String cid_name = Content_ID[0].replaceAll("<", "")
                                    .replaceAll(">", "");
                            body = body.replaceAll("cid:" + cid_name,
                                    Constants.server_attHome_Key.concat("/")
                                            .concat(userName.concat(attname)));
                        }
                    }

                    sb.append(body);
                    return sb.toString();
                } else ...{
                    /** *//**
                     * 其他multipart/*格式的如mixed格式,那么第一个部分包含了body,用递归解析第一个部分就可以了
                     */
                    Multipart mp = (Multipart) part.getContent();
                    Part tmp = mp.getBodyPart(0);
                    return LmlMessage.getBody(tmp, userName);
                }
            } else if (part.isMimeType("message/rfc822")) ...{
                return LmlMessage
                        .getBody((Message) part.getContent(), userName);
            } else ...{
                /** *//**
                 * 否则的话,死马当成活马医,直接解析第一部分,呜呜~
                 */
                Object obj = part.getContent();
                if (obj instanceof String) ...{
                    sb.append(obj);
                } else ...{
                    Multipart mp = (Multipart) obj;
                    Part tmp = mp.getBodyPart(0);
                    return LmlMessage.getBody(tmp, userName);
                }
            }
        } catch (Exception e) ...{
            return "解析正文错误!";
        }
        return sb.toString();
    }

    public static String getBody(Message msg, String userName) ...{
        return LmlMessage.getBody((Part) msg, userName);
    }

    /** *//**
     * 判断一封邮件是否含有附件<br>
     * 首先要满足:msg的mimetype是multipart/*类型的,然后要有某bodyPart的disposition是attachment
     * 
     * @param msg:要判断是否含有附件的邮件
     * @author M.Liang Liu
     * @version 1.0
     * @see public static boolean isAttachment(Part part)
     * @return true:含有附件<br>
     *         false:不含有附件
     */
    public static boolean hasAttachment(Message msg) ...{
        Part part = (Part) msg;
        try ...{
            if (part.isMimeType("multipart/*")) ...{
                Multipart mp = (Multipart) part.getContent();
                int count = mp.getCount();
                for (int i = 0; i < count; i++) ...{
                    Part tmp = mp.getBodyPart(i);
                    if (LmlMessage.isAttachment(tmp))
                        return true;
                }
            }
        } catch (Exception e) ...{
            return false;
        }
        return false;
    }

    /** *//**
     * 判断一个邮件体是否是附件<br>
     * 核心代码主要是解析其头部的disposition,一般设置了是disposition是attachment的才是附件
     * 
     * @author M.Liang Liu
     * @version 1.0
     * @return:如果是附件的话,那么返回true;<br>
     *                           否则/异常false;
     */
    public static boolean isAttachment(Part part) ...{
        try ...{
            String disposition = part.getDisposition();
            if ((disposition != null)
                    && ((disposition.equals(Part.ATTACHMENT)) || (disposition
                            .equals(Part.INLINE))))
                return true;
        } catch (Exception e) ...{
            /** *//**
             * 上面的方法只是适合于附件不是中文,或者中文名较短的情况,<br>
             * 附件中文名过长时就不能用了,因为javamail Api中的part.getDisposition()根本就不能得到正确的数据了<br>
             * 捕获异常后,分别再详细判断处理
             */
            String contentType = "";
            try ...{
                contentType = part.getContentType();
            } catch (MessagingException e1) ...{
                return false;
            }
            if (contentType.startsWith("application/octet-stream"))
                return true;
            return false;
        }
        return false;
    }
}