/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "MPL"); you may not use this file
 * except in compliance with the MPL. You may obtain a copy of
 * the MPL at http://www.mozilla.org/MPL/
 *
 * Software distributed under the MPL is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the MPL for the specific language governing
 * rights and limitations under the MPL.
 *
 * The Original Code is protoZilla.
 *
 * The Initial Developer of the Original Code is Ramalingam Saravanan.
 * Portions created by Ramalingam Saravanan <svn@xmlterm.org> are
 * Copyright (C) 2000 Ramalingam Saravanan. All Rights Reserved.
 *
 * Contributor(s):
 * Patrick Brunschwig <patrick@mozilla-enigmail.org>
 *
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License (the "GPL"), in which case
 * the provisions of the GPL are applicable instead of
 * those above. If you wish to allow use of your version of this
 * file only under the terms of the GPL and not to allow
 * others to use your version of this file under the MPL, indicate
 * your decision by deleting the provisions above and replace them
 * with the notice and other provisions required by the GPL.
 * If you do not delete the provisions above, a recipient
 * may use your version of this file under either the MPL or the
 * GPL.
 */

#include "nsISupports.idl"
#include "nsIPipe.idl"
#include "nsIFile.idl"
#include "nsIRequest.idl"
#include "nsIPipeListener.idl"

interface nsIRequest;
interface nsIFile;
interface nsIInputStream;
interface nsIOutputStream;
interface nsIStreamListener;
interface nsIPipeTransportHeaders;
interface nsIPipeTransportListener;

%{C++

#include "IPCProcess.h"

#define NS_PIPETRANSPORT_CLASSNAME "Pipe Transport"
#define NS_PIPETRANSPORT_CONTRACTID "@mozilla.org/process/pipe-transport;1"

#define NS_PIPETRANSPORT_CID                     \
{ /* 8431e101-7ab1-11d4-8f02-006008948af5 */     \
   0x8431e101, 0x7ab1, 0x11d4,                   \
{0x8f, 0x02, 0x00, 0x60, 0x08, 0x94, 0x8a, 0xf5} }

%}

/**
 * The nsIPipeTransport interface executes a file in a new process and
 * communicates with the process using pipes.
 *
 * OWNERSHIP AND THREADING MODEL for nsPipeTransport:
 *
 * nsPipeTransport can be created in any thread with an event queue.
 *
 * nsPipeTransport lives only in the thread that it was created in.
 *
 * nsPipeTransport creates a helper thread object, nsStdoutPoller and retains
 * an owning reference to it. nsStdoutPoller also holds a strong reference
 * to a proxy interface (nsIPipeTransportListener) implemented by
 * nsPipeTransport, which is released when the polling thread terminates.
 *
 * The polling thread terminates when it is "interrupted" by nsPipeTransport or
 * when EOF/error is encountered in reading data from the process STDOUT.
 *
 * The "terminate" method should *always* be called to release the process
 * resources when done.
 *
 * For asynchronous reading, when nsStdoutPoller terminates of its own accord,
 * any stream listener is informed by invoking OnStopRequest.
 * Usually this listener will be the same as the owner of nsPipeTransport.
 * (If the owner initiates the request shutdown by first calling "cancel",
 *  then the OnStopRequest method is *not* invoked, because it is assumed
 *  that the listener/owner is already aware of the shutdown.)
 *
 */
[scriptable, uuid(8431e100-7ab1-11d4-8f02-006008948af5)]
interface nsIPipeTransport : nsIRequest
{
    /**
     * Old, oboslete version of init, kept for compatibility reasons
     * For parameters please refer to init above and open
     */
    void init(in nsIFile executable,
              [array, size_is(argCount)] in string args,
              in unsigned long argCount,
              [array, size_is(envCount)] in string env,
              in unsigned long envCount,
              in unsigned long timeoutMS,
              in string killString,
              in boolean noProxy,
              in boolean mergeStderr,
              in nsIPipeListener console);

    /**
     * Initializes PipeTransport by executing the specified file using the
     * supplied argument list and environment variables.
     * It is expected that nsIPipeTransport will be embedded in a
     * full-featured channel, which will also act as an async stream
     * observer/listener and forward calls to the actual observer/listener.
     *
     * @param executable   executable file
     * @param cwd          working directory for the excutable
     * @param startupFlags flags defining how the process should be created
     */

    void initialize(in nsIFile executable,
              in nsIFile cwd,
              in unsigned long startupFlags);

    /**
     * Opens a PipeTransport by executing the specified file using the
     * supplied argument list and environment variables.
     * It is expected that nsIPipeTransport will be embedded in a
     * full-featured channel, which will also act as an async stream
     * observer/listener and forward calls to the actual observer/listener.
     *
     * @param args        arguments string array
     *                    (excluding the executable path itself)
     * @param env         environment (variable=value) string array
     * @param timeoutMS   timeout (in milliseconds) after which the process
     *                    at the other end of the pipe can be assumed to be
     *                    dead
     *                    (if == 0, a default value, usually an hour, is used)
     * @param killString  string to be transmitted to process before it is
     *                    killed (specify null string, if none)
     * @param noProxy     do not use proxy for async callback
     *                    (must use join to terminate process, in this case)
     * @param mergeStderr merge STDERR with STDOUT
     * @param console     nsIPipeListener object to capture STDERR
     */
    void open([array, size_is(argCount)] in string args,
              in unsigned long argCount,
              [array, size_is(envCount)] in string env,
              in unsigned long envCount,
              in unsigned long timeoutMS,
              in string killString,
              in boolean noProxy,
              in boolean mergeStderr,
              in nsIPipeListener console);

    /**
     * detach process after start
     */
    const long PROCESS_DETACHED       = 0x01;
    const long INHERIT_PROC_ATTRIBS   = 0x02;

    /**
     * Returns console object used to capture STDERR by default
     */
    readonly attribute nsIPipeListener console;

    /**
     * Returns listener object to feed data to STDIN
     * (call to OnStopRequest closes STDIN)
     */
    readonly attribute nsIStreamListener listener;

    /**
     * Specifies interface to handle MIME headers read from STDOUT
     */
    attribute nsIPipeTransportHeaders headerProcessor;

    /**
     * Controls console logging of STDOUT from process
     */
    attribute boolean loggingEnabled;

    /**
     * Open an input stream on this transport.
     *
     * @param offset - read starting at this offset
     * @param count  - read this many bytes (pass PRUint32(-1) if unlimited)
     * @param flags  - optional transport specific flags
     */
    nsIInputStream openInputStream(in unsigned long offset,
                                   in unsigned long count,
                                   in unsigned long flags);

    /**
     * Open an output stream on this transport.
     *
     * @param offset - write starting at this offset
     * @param count  - write no more than this many bytes (pass PRUint32(-1) if unlimited)
     * @param flags  - optional transport specific flags
     */
    nsIOutputStream openOutputStream(in unsigned long offset,
                                     in unsigned long count,
                                     in unsigned long flags);

    /**
     * Asynchronously read data from the transport.
     *
     * @param listener - notify this listener when data is available
     * @param ctxt     - opaque parameter passed to listener methods
     * @param offset   - read starting at this offset
     * @param count    - read this many bytes (pass PRUint32(-1) if unlimited)
     * @param flags    - optional transport specific flags
     */
    nsIRequest asyncRead(in nsIStreamListener listener,
                         in nsISupports ctxt,
                         in unsigned long offset,
                         in unsigned long count,
                         in unsigned long flags);

    /**
     * Checks if process is still actively piping I/O
     */
    boolean isAttached();

    /**
     * Joins STDOUT handling thread (blocking until STDOUT is closed),
     * (Necessary and only works if noProxy is true)
     * The process still needs to be terminated to free resources.
     */
    void join();

    /**
     * Terminates process, if active.
     */
    void terminate();

    /**
     * Returns exit code of process which has exited;
     *  fails with an exception if process is still attached.
     */
    long exitCode();

    /**
     * Writes string to process STDIN (synchronously)
     * (Note: child process may exit for valid reasons even before
     *  the first call to writeSync, causing an an exception to be
     *  thrown because STDIN has been closed by the child.)
     */
    void writeSync(in string inputData, in unsigned long inputLength);

    /**
     * closes process STDIN (required even if no data is being transmitted)
     */
    void closeStdin();

    /**
     * Writes stream data to process STDIN (asynchronously),
     * and close inputStream and STDIN after writing, if requested
     */
    void writeAsync(in nsIInputStream aFromStream,
                    in unsigned long aCount,
                    in boolean closeAfterWrite);

    /**
     * Transmits command string to process, blocks for output and returns the
     * STDOUT response as a string up to maxChars (=-1 for unlimited) long,
     * delimited by an optional prompt.
     * If prompt begins with newline, that newline character is returned,
     * but the rest of the prompt string is not returned.
     * If clear is true, any prior data in STDOUT is cleared.
     */

    string execPrompt(in string command, in string prompt,
                      in long maxOutputLen, in boolean clearPrev);


    /**
     * Blocks for output and returns the first line from STDOUT
     * as a string, up to maxChars (=-1 for unlimited) long.
     * NOTE: This method is intended for short output; for longer
     * output, reading using a stream is the better method.
     */

    string readLine(in long maxOutputLen);

    attribute unsigned long bufferSegmentSize;
    attribute unsigned long bufferMaxSize;
    attribute unsigned long headersMaxSize;

};


[scriptable, uuid(8431e110-7ab1-11d4-8f02-006008948af5)]
interface nsIPipeTransportHeaders : nsISupports
{
  /**
   * Calls channel to parse MIME headers, returning content length
   * or -1 for unknown content length.
   * If invalid MIME headers or no channel set, returns error.
   */
  long parseMimeHeaders(in string mimeHeaders, in unsigned long count);
};


[scriptable, uuid(8431e120-7ab1-11d4-8f02-006008948af5)]
interface nsIPipeTransportListener : nsIPipeTransportHeaders
{
  /**
   * Starts listener, and invokes OnStartRequest on listener, if any.
   * NOTE: Should not be called if blocked for synchronous read.
   */
  void startRequest();

  /**
   * Stops listener
   */
  void stopRequest(in nsresult status);
};


[noscript, uuid(8431e130-7ab1-11d4-8f02-006008948af5)]
interface nsIPipeTransportPoller : nsISupports
{
  /**
   * Starts polling of STDOUT
   */
  void asyncStart(in nsIOutputStream aOutputStream,
                  in nsIPipeTransportListener aProxyPipeObserver,
                  in boolean joinable,
                  in unsigned long aMimeHeadersMaxSize);

  /**
   * Interrupts polling thread.
   */
  boolean interrupt();

  /**
   * Returns true if polling thread has been interrupted/
   */
  boolean isInterrupted();

  /**
   * Joins polling thread, if joinable (blocking until it terminates)
   */
  void join();

  /**
   * Controls console logging of STDOUT from process
   */
  attribute boolean loggingEnabled;
};


[noscript, uuid(8431e190-7ab1-11d4-8f02-006008948af5)]
interface nsIPipeTransportWriter : nsISupports
{
  /**
   * writes count bytes from input stream to STDIN pipe (asynchronously) and
   * then closes the STDIN pipe
   */
  void writeFromStream(in nsIInputStream aFromStream,
                       in unsigned long aCount,
                       in IPCFileDescStar pipe,
                       in boolean closeAfterWrite);
                       
  /**
   * Joins writer thread, if joinable (blocking until it terminates)
   */
  void join();
};


///////////////////////////////////////////////////////////////////////////////
