/*
 * $Id: ConsoleCommand.html,v 1.2 2004/09/24 13:07:22 suhrin Exp $
 
 * Copyright (c) 1999-2004 Gnome Ltd. All Rights Reserved.
 
 * This software is the confidential and proprietary information of
 * Gnome Ltd. You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms
 * of the license agreement you entered into with Gnome Ltd.
 */

package SK.gnome.dwarf.mail.sample;

import java.io.*;
import java.util.Collection;
import java.util.Iterator;
import java.security.AccessControlException;

import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;

import SK.gnome.dwarf.auth.AuthId;
import SK.gnome.dwarf.auth.login.BasicCallbackHandler;
import SK.gnome.dwarf.main.Main;
import SK.gnome.dwarf.main.Console;
import SK.gnome.dwarf.mail.MailException;
import SK.gnome.dwarf.mail.mime.MimePart;
import SK.gnome.dwarf.mail.mime.MimeMessageBuilder;
import SK.gnome.dwarf.mail.smtp.Recipient;
import SK.gnome.dwarf.mail.smtp.SMTPParameters;
import SK.gnome.dwarf.mail.smtp.proc.MailAgent;
import SK.gnome.dwarf.mail.smtp.proc.MailAgentMessage;
import SK.gnome.dwarf.mail.smtp.proc.Preprocessing;

/**
 * Provides agent for remote execution of console commands.
 *
 <p>The agent is activated by a message to postmaster's address with subject equal to
 * the <tt>"console command"</tt> string. The message body must consist of two lines with the
 * authentication information (username and password) and one or more lines with the console
 * commands to be executed. The output from executed commands is sent back to the sender
 * address in a new mail message.
 *
 <p>Please note that this agent is only for testing purposes since it may open a security
 * hole, therefore do not use it in a production server!
 */

public class ConsoleCommand extends MailAgent implements Preprocessing
{
  /**
   * Creates a new <tt>ConsoleCommand</tt> agent.
   *
   @param  name  the service name
   */

  public ConsoleCommand(String name)
  super(name);
  }

  protected void preprocess(MailAgentMessage message, Collection recipients)
    throws IOException, MailException
  
    // first of all, mark the passed recipients as finished
    // (if you omit this step, the message will be normally delivered
    // to the given recipients later)

    for (Iterator it = recipients.iterator(); it.hasNext())
    Recipient rcpt = (Recipient)it.next();
      if (!rcpt.isFinished())
        rcpt.finish(Recipient.DELIVERED, "2.1.5""Delivered to mail agent");
    }

    // this output stream will hold responses from the console commands

    ByteArrayOutputStream out = new ByteArrayOutputStream();
    Writer writer = new OutputStreamWriter(out);

    // get the MIME view of the message data

    MimePart part = message.getMimePart();
    InputStream in = null;
    try
    // get the decoded message content as an input stream

      in = part.getDecodedInputStream();
      BufferedReader reader = new BufferedReader(new InputStreamReader(in));

      // get the username from the first line

      String username = reader.readLine();
      if (username == null)
        throw new MailException("No username");

      // get the password from the second line

      String password = reader.readLine();
      if (password == null)
        throw new MailException("No password");

      try
      // authenticate the subject with the given username and password, because
        // the console command must be executed on behalf of a concrete subject

        Subject subject = new Subject();
        Console console = Main.getMainServer().getConsole();
        AuthId authId = console.login(subject, new BasicCallbackHandler(username, password.toCharArray()));

        // take the rest of message lines as console commands and execute them; skip empty lines

        String command;
        while ((command = reader.readLine()) != null)
        command = command.trim();
          if (command.length() 0)
          writer.write("\r\n#command=" + command + "\r\n");
            console.execute(subject, command, writer);
          }
        }

        // logout the subject since we don't need it any more

        console.logout(authId, subject);
      }
      catch (LoginException le)
      String msg = "Failed login [user=" + username + ", cause=\"" + le.getMessage() "\"]";
        log(LOG_INFO, msg);
        writer.write(msg);
      }
      catch (AccessControlException ace)
      log(LOG_ERROR, "Error while user authorization", ace);
        writer.write("Unauthorized access [user=" + username + ", cause=\"" + ace.getMessage() "\"]");
      }
    }
    finally
    try
      in.close();
      }
      catch (Exception e)
      {
      }
    

    // flush out the output stream

    writer.flush();

    // create and send a response message with the output of executed commands as the message body

    MimeMessageBuilder msg = new MimeMessageBuilder();
    String postmaster = ((SMTPParameters)getParameters()).getPostmasterAddress();
    msg.setFrom("Mail Delivery Subsystem <" + postmaster + ">");
    msg.setTo(part.getHeader("From"null));
    msg.setSubject("Output of console command");
    msg.setHeader("In-Reply-To", part.getHeader("Message-Id"null));
    ByteArrayInputStream buf = new ByteArrayInputStream(out.toByteArray());
    msg.setContent(buf, "text/plain""quoted-printable");
    context.sendMessage(msg);
  }    
}