(*
 * <COPYRIGHT>
 * Copyright 2002 Joachim Schrod Network and Publication Consultance GmbH, Gerd Stolpmann
 *
 * <GPL>
 * This file is part of WDialog.
 *
 * WDialog is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * WDialog is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with WDialog; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * </>
 *)

(* $Id: wd_dialog.mli,v 3.7 2004/12/12 17:57:32 stolpmann Exp $
 * ----------------------------------------------------------------------
 *
 *)


(** This module defines the base class [dialog] from which all dialog
  * classes should inherit
  *)

open Wd_types
open Wd_template

val dump_interactors : Format.formatter -> interactors -> unit
  (** Prints a readable description of the contents of the [interactors]
   * argument to the passed [formatter]. This function is a valid printer
   * for the toplevel and the debugger.
   *)


(** The class [dialog] is the implementation of {!Wd_types.dialog_type} that
  * should be used as base definition for all dialog objects. This class 
  * defines all methods but [handle] and [prepare_page] - these must be 
  * defined in the subclasses provided by the application programmer. 
  * Furthermore, there are some extensions to {!Wd_types.dialog_type}
  * realized as private methods to simplify access to templates.
  * These additional methods begin with [t_], but are otherwise named
  * like the corresponding function in the module {!Wd_template}.
  *
  * The class takes three anonymous parameters:
  *
  * - The universe for which the dialog is defined
  * - The name of the dialog in the UI definition
  * - The environment of the current CGI activation
  *)
class virtual dialog :
  universe_type ->
  (* name: *) string ->
  environment ->
  object
    inherit Wd_types.dialog_type
      (** This class implements [dialog_type] *)

    (** The following private methods are shortcuts for the {!Wd_template}
     * module. 
     *)

    method private t_get : string -> template
	(** Returns the template *)
    method private t_apply : template -> (string * tree) list -> tree
	(** Applies the template, and passes the parameters to it *)
    method private t_apply_byname : string -> (string * tree) list -> tree
	(** Applies the named template, and passes the parameters to it *)
    method private t_apply_lazily : string -> (string * tree) list -> tree
	(** Constructs the expression that applies the names template on
	 *  demand. 
	 *)
    method private t_concat : tree -> tree list -> tree
	(** Concatenates the [tree list], and put the separator [tree] between
	 *  the parts
	 *)
    method private t_empty : tree
        (** The empty XML tree *)
    method private t_text : string -> tree
	(** The XML tree containing this text *)
    method private t_html : string -> tree
	(** The XML tree containing this HTML material *)
    method private t_to_string : tree -> string
	(** Evaluates the XML tree in the current environment, and returns
	 *  the corresponding output string (HTML code)
	 *)

    method private put_tree : string -> Wd_template.tree -> unit
      (** Sets the [string] variable to the string representation
       * of the [tree]
       *)

  end

    (** {b Construction}
     * [new dialog universe name env]: Makes a new dialog called [name] which
     * is bound to the [universe]
     *
     * Normally, the class [dialog] is not used directly. It is intended
     * to inherit from [dialog], and to define the two methods [prepare_page]
     * and [handle]; these are virtual in the base class:
     *
     * {[class my_dialog universe name env =
     *   object (self)
     *     inherit dialog universe name env
     *   method prepare_page = ...
     *   method handle = ...
     * end]}
     *
     * After defining such a class, you can create a new [my_dialog] by
     * [new my_dialog universe "my_dialog" env].
     * However, it is not recommended to do it this way. The module {!Wd_universe}
     * includes a registry of constructors, and every dialog should put
     * its constructor into it:
     *
     * [universe # register "my_dialog" (new my_dialog)]
     *
     * For example, you can place this statement where you call
     * {!Wd_run_cgi.run}:
     *
     * {[let universe = new Wd_universe.universe in
     * universe # register ...;
     * Wd_run_cgi.run ... ~universe]}
     *
     * After the dialog has been registered, you can create new instances
     * of the dialog by calling [universe#create]:
     *
     * [let dlg = universe # create env "my_dialog"]
     *)


class instant_session_manager : unit -> Wd_types.session_manager_type
  (** The "instant" session manager serializes the state of the dialog,
   * and includes it literally into the HTML form. The serialized string is included
   * in the generated HTML forms, and passed by CGI parameter from one activation
   * to the next activation. The advantages are that you need not to set up any
   * database to store the sessions, and that the session state is included
   * in the history of the browser. The disadvantages are increased network
   * traffic, and missing protection of the session data (the end user can
   * decode the session state), i.e. the class is insecure, and should only
   * be used in trusted environments.
   *)


exception Invalid_session_checksum
  (** Raised when the session checksum as stored in the database is not the
   * same that is transmitted by the browser. This normally means that a
   * historic page was submitted ("Back" button).
   *)

exception Session_not_found
  (** Raises when the current session was not found in the database. *)



class database_session_manager : 
  ?private_key : string ->
  ?enable_checksum : bool ->
  allocate:(unit -> int) ->
  insert:(int -> string -> unit) ->
  update:(int -> string -> string -> string -> unit) ->
  lookup:(int -> string -> (string * string)) ->
  unit ->
    Wd_types.session_manager_type
  (** The database session manager allows it to store the contents of 
   * sessions in databases. The database table should consist of rows
   * with at least the four columns
   *
   * - [id]: The row identifier chosen by the database system. This is
   *   an integer
   * - [skey]: The secure key consists of 32 hex digits, and is another 
   *   identifier for the row that is chosen by WDialog
   * - [value]: The value is a large BASE64-encoded string. The length
   *   depends on the session size
   * - [checksum]: A checksum of [value], again 32 hex digits
   *
   * Note that sessions stored in databases behave differently with
   * respect to the history function of the browser. It is not possible
   * to "go back", or to select historic pages otherwise, and submit
   * them again. This will be detected by the [database_session_manager], 
   * and the exception [Invalid_session_checksum] will be raised. There
   * is currently no way to turn this check off, nor to make the
   * check more fine-grained. (Maybe an implementation with multiple
   * versions of the same session is the way to go, I don't know yet.)
   *
   * The [database_session_manager] does never delete sessions. It is
   * recommended to remove unused sessions after a timeout period.
   *
   * For a transaction-based DBMS, it is sufficient if the [update]
   * function commits the current transaction.
   *
   * @param allocate The function [allocate] must allocate a new [id]
   * and return it.
   *
   * @param insert The function [insert] must insert a new row, containing only
   * the [id] and the passed [skey]; the other two fields can be
   * empty (empty string, or "null").
   *
   * @param update The function [update] takes the [id], the [skey], the [value], and
   * the [checksum] as arguments, and must update the row identified
   * by [id] and [skey]. It is up to the implementation whether the
   * [id] or the [skey] is the preferred lookup key; however it MUST
   * be checked whether the found row has the demanded [skey] for
   * security reasons; if this is not the case, the exception
   * [Session_not_found] must be raised. This exception must be
   * raised, too, if the row cannot be found at all. (If there are
   * several matching rows, this is an implementation error!)
   *
   * @param lookup The function [lookup] gets the [id] and the [skey] as arguments,
   * and must return the corresponding [value] and [checksum] as
   * pair. Again, the exception [Session_not_found] must be raised
   * if the row cannot be found, or the [skey] is wrong.
   *
   * @param private_key The optional argument [private_key] can be used to inject randomness
   * into the algorithm that computes the secure key. This makes the
   * secure key unpredictable for the user, so nobody can "hijack" a
   * session by guessing the secure key.
   *
   * @param enable_checksum If true (the default), the checksum of the
   * web request is compared with the database checksum. This ensures that
   * only responses of the latest dialog state can be processed. By
   * setting this parameter to [false], the checksum is ignored, and the
   * user can also submit historical web forms. In general, this is a bad
   * idea, and you will run into trouble, unless your application is can
   * cope with that.
   *
   *)

(* ======================================================================
 * History:
 *
 * $Log: wd_dialog.mli,v $
 * Revision 3.7  2004/12/12 17:57:32  stolpmann
 * 	Added <q:wd-link> and <q:wd-xlink> to generate links for
 * applications that cannot use Javascript. Limited functionality, however.
 * See stdlib.xml for details.
 *
 * Revision 3.6  2003/03/21 20:57:54  stolpmann
 * 	ocamldoc problems
 *
 * Revision 3.5  2003/03/21 14:23:44  stolpmann
 * 	ocamldoc updated
 *
 * Revision 3.4  2003/03/09 17:08:29  stolpmann
 * 	New class database_session_manager
 *
 * Revision 3.3  2002/02/16 17:29:45  stolpmann
 * 	mostly ocamldoc.
 *
 * Revision 3.2  2002/02/14 16:15:21  stolpmann
 * 	Added copyright notice.
 *
 * Revision 3.1  2002/02/12 20:29:22  stolpmann
 * 	Initial release at sourceforge.
 *
 * Revision 1.10  2002/02/05 18:44:16  gerd
 * 	New: class instant_session_manager
 *
 * Revision 1.9  2002/01/14 15:03:24  gerd
 * 	Major change: Typing has been completely revised, and almost
 * every tiny thing has now a new type. Also renamed a lot.
 *
 * Revision 1.8  2000/12/21 15:00:37  gerd
 * 	Server popups: The generated "open" function has now a second
 * parameter which is passed back to the application. The Popup_request
 * event gets this parameter. The parameter can be used freely by the
 * application.
 *
 * Revision 1.7  2000/12/04 18:27:50  gerd
 * 	Added several type and exception definitions that were
 * previously only accessible in Uiobject_pre.
 *
 * Revision 1.6  2000/12/04 12:00:07  gerd
 * 	Moved dump_interactors from uiobject_pre to this module.
 *
 * Revision 1.5  2000/11/30 18:41:11  gerd
 * 	New interface is_server_popup_request.
 * 	exn_default_context has been removed.
 *
 * Revision 1.4  2000/05/15 11:46:33  gerd
 * 	Necessary changes for uidebugger.
 *
 * Revision 1.3  2000/05/08 15:31:26  gerd
 * 	New methods: exn_object_declaration and exn_default_context.
 *
 * Revision 1.2  2000/04/17 10:10:52  gerd
 * 	New Cgi module.
 * 	File upload strongly improved.
 *
 * Revision 1.1  2000/04/13 17:42:58  gerd
 * 	Initial revision.
 *
 *
 *)
