/*
 * @(#)NNTP.java
 *
 * 
 */

import java.io.*; 
import java.util.*; 
import java.util.Calendar;
import java.util.Locale;
import java.util.Properties;

import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessageRemovedException;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import javax.servlet.*;
import javax.servlet.http.*;

/**
 * The simplest possible servlet.
 *
 * @author James Duncan Davidson
 */

public class NNTP extends HttpServlet {
	 
	public static String c_dir = "/tmp/";
	public static String a_sep = System.getProperty("file.separator");
	public static String a_line = System.getProperty("line.separator");
	private String c_host = "";
	private String c_username = "";
	private String c_password = "";
	private String c_newsgroup = "";
	private Session session = null;
	private Store store = null;
	private Folder folder = null;
	private Folder folders[] = null;
	private Folder defaut_folders[] = null;
	private Message message[] = null;
	private int c_port = 1119;
	private char c_separator = '.';
	private boolean c_debug = false;
	private String c_charset = "utf-8"; // wes
	private String c_organization = null;
	private int c_timeout = 0;
	 

	public NNTP()
	{
	}

	/**
	 * Constructeur simple! (119 NNTP) 
	 *
	 * @param _dir	    	Dossier des fichiers en attachement
	 * @param _host 	    	Nom du serveur NNTP
	 * @param _username       Nom de l'utilisateur
	 * @param _password       Mot de passe du compte
	 */
	public NNTP(String _host, String _username, String _password)
	{
		this(_host, _username, _password, 119);
	}

	/**
	 * Constructeur complet!
	 *
	 * @param _dir	    	Dossier des fichiers en attachement
	 * @param _host 	    	Nom du serveur nntp
	 * @param _username           Nom de l'utilisateur
	 * @param _password           Mot de passe du compte
	 */
	public NNTP(String _host, String _username, String _password, int _port)
	{
		this.c_host = _host;
		this.c_username = _username;
		this.c_password = _password;
		this.c_port = _port;
		if (!c_dir.endsWith(a_sep)) c_dir += a_sep;
	}

	/**
	 *
	 * @return Properties
	 * @throws MessagingException MessagingException Si une erreur survient.
	 */
	private Properties getSessionProperties() throws MessagingException
	{
		// Get system properties
		Properties props = System.getProperties();
		//props.put("mail.nntp.host", "host");
		//props.put("mail.nntp.port", "port");
		//props.put("mail.nntp.user", "nntp");
		props.put("mail.nntp.connectiontimeout", ""+c_timeout);
		props.put("mail.nntp.timeout", ""+c_timeout);
		return props;
	}

	/**
	 *
	 * @param  String 	newsgroup
	 * @throws MessagingException MessagingException Si une erreur survient.
	 */
	public Message[] getNNTPMessage(String newsgroup) throws NoSuchProviderException, MessagingException
	{
		return getNNTPMessage(newsgroup, false);
	}

	/**
	 *
	 * @param  String 	newsgroup
	 * @param  boolean  	mode debug true ou false
	 * @throws MessagingException MessagingException Si une erreur survient.
	 */
	public Message[] getNNTPMessage(String newsgroup, boolean sDebug) throws NoSuchProviderException, MessagingException
	{
		// check newsgroup
		if (newsgroup == null) throw new MessagingException("Newsgroup is null!");
		
		// Get properties
		Properties props = getSessionProperties();
		
		// Get session
		session = Session.getDefaultInstance(props, null);
		
		// option debug
		session.setDebug(sDebug);
		
		// Get the store
		store = session.getStore("nntp");
		
		// connection!
		store.connect(c_host, c_username, c_password);
		
		if (store.isConnected())
		{
			Folder defaultFolder = store.getDefaultFolder();
			if (defaultFolder == null) throw new MessagingException("Can't find defaut FOLDER !!!");
		
			this.c_separator = defaultFolder.getSeparator();
			
			folder = store.getFolder(newsgroup);
			
			// check pour newsgroup="%"!
			if (folder.exists())
			{
				defaultFolder = store.getDefaultFolder();
				if (defaultFolder == null) throw new MessagingException("Can't find defaut FOLDER !!!");
				
				// en lecture seulement
				folder.open(Folder.READ_ONLY);
			
				if (folder.isOpen())
				{
					message = folder.getMessages();
				}
			}
		}
		// retourne un Array Message tout en gardant la session ouverte...
		return message;
	}

	private Folder[] getNNTPRoot() throws NoSuchProviderException, MessagingException
	{
		return getNNTPRoot(false);
	}
	
	/**
	 *
	 * @param  String 	newsgroup
	 * @param  boolean  	mode debug true ou false
	 * @throws MessagingException MessagingException Si une erreur survient.
	 */
	private Folder[] getNNTPRoot(boolean sDebug) throws NoSuchProviderException, MessagingException
	{
		// Get properties
		Properties props = getSessionProperties();
		
		props.put("mail.nntp.listall", "true");
		
		// Get session
		session = Session.getDefaultInstance(props, null);
		
		// option debug
		session.setDebug(sDebug);
		
		// Get the store
		store = session.getStore("nntp");
		
		// connection!
		store.connect(c_host, c_username, c_password);
		
		Folder defaultFolder = null;
		
		if (store.isConnected())
		{
			defaultFolder = store.getDefaultFolder();
			if (defaultFolder == null) throw new MessagingException("Can't find defaut FOLDER !!!");
		
			defaut_folders = defaultFolder.list();
		}	
		
		return defaut_folders;
	}
	
	/**
	 *
	 */
	public void setDebug(boolean _debug)
	{
		c_debug = _debug;
	}

	/**
	 * Indique le timeout sur la socket.
	 * @param timeout Timeout en milliseconds.
	 */
	public void setSocketTimeout(int timeout)
	{
		this.c_timeout = timeout;
	}

	/**
	 * Indique le timeout sur la socket.
	 * 
	 * @return Timeout
	 */
	public int getSocketTimeout()
	{
		return c_timeout;
	}
	
	/**
	 *
	 * @param _del                  On efface les messages ?
	 * @throws MessagingException MessagingException Si une erreur survient.
	 */
	public void close(boolean _del) throws MessagingException
	{
		if (folder != null && folder.isOpen()) folder.close(_del); // on efface les messages ou pas!
		if (store != null) store.close();
	}

	/**
	 * Retourne l'objet Folder[] courant
	 * 
	 * @return char  separateur de dossier
	 */
	public char getSep()
	{
		return this.c_separator;
	}

	/**
	 * Retourne l'objet Folder courant
	 * 
	 * @return Folder
	 */
	public Folder getFolder()
	{
		return this.folder;
	}

	/**
	 * Retourne l'objet Folder[] courant
	 * 
	 * @return Folder[]
	 */
	public Folder[] getFolders()
	{
		return this.folders;
	}

	/**
	 * Retourne l'objet Folder[] dossier racine 
	 * 
	 * @return Folder[]
	 */
	public Folder[] getRootFolders()
	{
		return this.defaut_folders;
	}

	public void setCharset(String _charset)
	{
		c_charset = _charset;
	}

	/**
	 *
	 * @param _charset   String du charset
	 */
	public void setOrganization(String _organization)
	{
		c_organization = _organization;
	}
	
	/**
	 * 
	 * @param _msg   UNKNOWN si exception
	 * @return String
	 * @exception MessagingException 	Si une erreur survient sur msg.getFrom()[0]!
	 */  
	public static String getFrom(Message _msg) throws MessagingException
	{
		// catch email qui pue... ha usenet!
		String from = ""; 
		try {  from = ""+_msg.getFrom()[0]; }
		catch(AddressException ae)
		{
			try  // truc
			{ 
				String tfrom = ""+ae;
				System.err.println("WARNING : "+tfrom);
				from = tfrom.substring(tfrom.indexOf("`") + 2, tfrom.indexOf("'"));	
			}
			catch (StringIndexOutOfBoundsException e) 
			{  
				from = "UNKNOWN";
			}
		}
		catch(MessageRemovedException ae)
		{
			from = "REMOVED";
		}
		return from;
	}

	
	public static final String replace(String _str, String _what, String _by)
	{
		if (_str==null || _str.equalsIgnoreCase("")) return "";
		if (_what==null || _what.equalsIgnoreCase("")) return _str;
		String a_by = (_by==null)? "" : _by;
		StringBuffer r_str = new StringBuffer();
		int a_begin = 0;
		int a_selBegin = 0;
		while ((a_selBegin=_str.indexOf(_what,a_begin))!=-1)
		{
			r_str.append(_str.substring(a_begin,a_selBegin)+a_by);
			a_begin = a_selBegin+_what.length();
		}
		r_str.append(_str.substring(a_begin));
		return r_str.toString();
	}
	
	/**
	 */
	private final class MyMimeMessage extends MimeMessage
	{
		protected Session session;
		
		private int id = 0;
		
		/**
		 * Constructeur!
		 * 
		 * @param _session	javax.mail.Session
		 */
		protected MyMimeMessage(Session _session)
		{
			super(_session);
			this.session = _session;
		}
	
	/**
	 */
	protected void updateMessageID() throws MessagingException 
        {
        	// Message-ID
        	setHeader("Message-ID", "<"+getMyMessageID(session)+">");
        
        	// Organization
		if (c_organization != null) setHeader("Organization", c_organization);
        
		// User-Agent
        	setHeader("User-Agent", "NNTP_1.0"); // User-Agent...
	}
        
        /**
         * Retourne un unique Message-ID.
         */
        private String getMyMessageID(Session _session)
        {
          InternetAddress localAddress = InternetAddress.getLocalAddress(_session);
          String address = (localAddress != null) ? localAddress.getAddress() : "nntpuser@localhost";
          
          //Unique string is ...JavaNNTP.
          StringBuffer buffer = new StringBuffer();
          buffer.append(buffer.hashCode());
          buffer.append(".");
          buffer.append(id++);
          buffer.append(System.currentTimeMillis());
          buffer.append(".");
          buffer.append("JavaNNTP.");
          buffer.append(address); 
          System.err.println(buffer.toString());
          return buffer.toString();
        }
    } // fin de classe
	

    /**
     * Main 
     */
        public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
        throws IOException, ServletException
    {
	System.out.println("NNTP Servlet wird initialisiert");
	
	response.setContentType("text/html");
  	PrintWriter out = response.getWriter();

	String s = null;
	String host = request.getParameter("host");
	String username = request.getParameter("username");
	String password = request.getParameter("password");
//	int port = request.getParameter(port);
	String newsgroup = request.getParameter("newsgroup");

	// out.println("mail ist : " + recipient);

         NNTP nntp = new NNTP(host, username, password);

        nntp.setDebug(false);
        nntp.setSocketTimeout(50000);
        try
        {
            /*
            // WARNING : There are >45,000 newsgroups on !
            Folder[] root = nntp.getNNTPRoot(true);
            String home = System.getProperty("user.home");

            File a_F = new File(home, "newsng.txt");
            if (a_F.exists() && !a_F.delete()) throw new Exception("Can't overwrite '"+a_F.getName()+"'");

            RandomAccessFile f_In = null;
            f_In = new RandomAccessFile(a_F,"rw");

            if (root !=null)
            {
                System.err.println("Root Folder : " + root.length);
                for (int i=0, n=root.length; iDen Output finden Sie in einiger Zeit hier");

            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, "8859_1"));
            Message[] message = nntp.getNNTPMessage(newsgroup, true); 

            System.err.println("Newsgroup  : " + nntp.getFolder());
            System.err.println("Separator  : " + nntp.getFolder().getSeparator());
            System.err.println("Message length : " + message.length);

      // Ausgabestrom in Datei erzeugen 
      // 
      // Eine lokale Ausgabedatei in eine Instanz in File kapseln. 
      File ausgabeDatei = new File("/tmp/0001"); 
      // FileWriter erzeugen. 
      FileWriter fw = new FileWriter(ausgabeDatei); 
      // Den FileWriter in einem BufferedWriter verpacken. 
      BufferedWriter bw = new BufferedWriter(fw); 

            // inverse...
            for (int i = message.length-1, n = 0; n < i; i--)
            {
                // warning From... we are in world of usenet!
		// Hier schreibe ich alle Artikelheader ins Log
                // System.err.println(i + " from : " + NNTP.getFrom(message[i]) + "\tsubject : " + message[i].getSubject());

                    // write output message
		      Object content = message[i].getContent();
		      if (content instanceof String) {
	                  String body = (String) content;
	                  bw.write(body);
 			}
            }
	     bw.flush();
	     bw.close();
        }
	 catch ( IOException i ) {
	  i.printStackTrace();
	}
        catch (Exception e)
        {
            System.out.println(e);
            System.out.println("Pile : ");
            e.printStackTrace();
        }
        finally
        {
           try { nntp.close(true); } catch (MessagingException me)    {}
	// schmeiss das hadoop an
	 Process r = Runtime.getRuntime().exec("/bin/rm -rf /tmp/output");
	 Process p = Runtime.getRuntime().exec("/usr/local/cloudcomputing/hadoop/bin/hadoop jar /usr/local/cloudcomputing/hadoop/wordcount.jar org.myorg.WordCount /tmp/0001 /tmp/output");
            
            BufferedReader stdInput = new BufferedReader(new 
                 InputStreamReader(p.getInputStream()));

            BufferedReader stdError = new BufferedReader(new 
                 InputStreamReader(p.getErrorStream()));

            // read the output from the command
            System.out.println("Here is the standard output of the command:\n");
            while ((s = stdInput.readLine()) != null) {
                out.println(s);
            }
	 // read any errors from the attempted command
            System.out.println("Here is the standard error of the command (if any):\n");
            while ((s = stdError.readLine()) != null) {
                System.out.println(s);
            }
            
          //  System.exit(0);

	//
        }
    }

} // fin de classe