Plasma GitLab Archive
Projects Blog Knowledge

(*
 * <COPYRIGHT>
 * Copyright 2003 Gerd Stolpmann
 *
 * <GPL>
 * This file is part of WTimer.
 *
 * WTimer 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.
 *
 * WTimer 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: init.ml,v 1.5 2003/03/23 11:59:14 gerd Exp $
 * ----------------------------------------------------------------------
 *
 *)

open Wd_dialog
open Wd_types
open Db_types.Types
open Db_types
open Db.Types

(**********************************************************************)
(* Definition of additional output encodings                          *)
(**********************************************************************)

(* These functions map strings to strings in order to beautify the
 * displayed text. They can be called from UI language by the
 * <ui:encode> element.
 *)

(* (1) Mappings from dates to strings: Input is an ISO date in the
 * format YYYY-MM-DD, e.g. 2002-08-31
 *)

let enc_year date_str = 
  (* for <ui:encode enc="year">: outputs the year only *)
  let date = Date.from_string date_str in
  let year = (Date.access date).year in
  string_of_int year
;;

let enc_mday date_str =
  (* for <ui:encode enc="mday">: output is the day number *)
  let date = Date.from_string date_str in
  let mday = (Date.access date).mday in
  string_of_int mday
;;

let enc_mday_en date_str =
  (* for <ui:encode enc="mday-en">: output is the ordinal day number *)
  let s = enc_mday date_str in
  match s.[ String.length s - 1] with
      '1' -> if s="11" then s ^ "th" else s ^ "st"
    | '2' -> if s="12" then s ^ "th" else s ^ "nd" 
    | '3' -> if s="13" then s ^ "th" else s ^ "rd"
    | _   -> s ^ "th"
;;

let tm_of_date date =
  (* convert Db.Types.date to Unix.tm *)
  let _, udate = Unix.mktime 
		   { Unix.tm_sec = 0;
		     Unix.tm_min = 0;
		     Unix.tm_hour = 0;
		     Unix.tm_mday = (Date.access date).mday;
		     Unix.tm_mon = (Date.access date).month - 1;
		     Unix.tm_year = (Date.access date).year - 1900;
		     Unix.tm_wday = 0;
		     Unix.tm_yday = 0;
		     Unix.tm_isdst = false;
		   } in
  udate
;;

let enc_weekday_en date_str =
  (* for <ui:encode enc="weekday-en">: output is the weekday name *)
  let date = Date.from_string date_str in
  let weekday = (tm_of_date date).Unix.tm_wday in
  [| "Sunday";
     "Monday";
     "Tuesday";
     "Wednesday";
     "Thursday";
     "Friday";
     "Saturday";
  |].(weekday);
;;


let enc_month date_str =
  (* for <ui:encode enc="month-en">: output is the month number (1-12) *)
  let date = Date.from_string date_str in
  string_of_int ((Date.access date).month)
;;


let enc_month_en date_str =
  (* for <ui:encode enc="month-en">: output is the month name *)
  let date = Date.from_string date_str in
  let month = (Date.access date).month - 1 in
  [| "January"; "February"; "March"; "April"; "May"; "June";
     "July"; "August"; "September"; "October"; "November"; "December"
  |].(month);
;;


(* Now follows a more complicated function that performs some date
 * computation. Input is the start date, usually the first day of a
 * month, and an integer from 0 to 36, the position. Imagine you
 * have a calendar sheet for a month, e.g.
 * 
 *     October 2002
 * Su Mo Tu We Th Fr Sa
 *        1  2  3  4  5
 *  6  7  8  9 10 11 12
 * 13 14 15 16 17 18 19
 * 20 21 22 23 24 25 26
 * 27 28 29 30 31
 *
 * The position counts the day positions of the sheet. The sunday in the
 * first row is position 0, the monday in the sixth row is position 36.
 * The result of the function is either "", meaning that the position
 * is empty, or a number > 0 denoting the day to display.
 *
 * The input string contains the date and the position, separated by
 * a single space. The output string is the decimal representation of
 * the day, or "".
 *)

let enc_cal_day date_pos_str =
  try
    let k = String.index date_pos_str ' ' in
    let date = Date.from_string (String.sub date_pos_str 0 k) in
    let pos = int_of_string 
		(String.sub 
		   date_pos_str (k+1) (String.length date_pos_str - k - 1)) in
    let weekday = (tm_of_date date).Unix.tm_wday in (* 0 to 6 *)
    let days = Date.days_of_month date in
    let first_pos = weekday in                     (* first filled position *)
    let last_pos = first_pos + days - 1 in         (* last filled position *)
    if pos >= first_pos && pos <= last_pos then
      string_of_int (pos - first_pos + 1)
    else
      ""
  with
      Not_found -> "??"
;;
 
(**********************************************************************)
(* Database                                                           *)
(**********************************************************************)

(* [db] is an unbound database handle. Later it will be bound to a certain
 * database, but the connection will remain closed until the first real
 * db access happens, i.e. the connection is established lazily. The 
 * advantage of this approach that it is compatible with the JSERV 
 * mode where new processes are started, and it must be ensured that the
 * database connection is opened for each process individually.
 *)

let db = Db.Connection.create()
;;

let rollback() =
  if Db.Connection.is_connected db then
    Db.Connection.rollback db
;;


(**********************************************************************)
(* Fatal errors                                                       *)
(**********************************************************************)

(* Note: Don't forget to rollback the DB transaction !!! *)


let log_error_stderr error =
  Printf.eprintf "[%s] [error] [wtimer application] %s\n"
    (Netdate.format "%c" (Netdate.create ~zone:Netdate.localzone (Unix.time())))
    error;
  flush stderr
;;


let log_error_syslog error =
  let _ = 
    Sys.command ("logger -p user.err -t wtimer " ^ 
		 Filename.quote ("[instance " ^ Const.wtimer_dir ^ "] ") ^
		 Filename.quote error) in
  ()
;;


let log_error =
  log_error_syslog   (* or log_error_stderr *)
;;


let simple_error_page (ch : Netchannels.out_obj_channel) error =
  log_error (Printexc.to_string error);
  let out = ch # output_string in
  out "<html><body><h1>Internal Error</h1>\n";
  out "The application wtimer cannot serve your request. The ";
  out "exact reason can be found in the error log. Please inform ";
  out "your administrator about this incidence.\n";
  out "</body></html>\n";
  rollback()
;;


let extended_error_page (universe : universe_type) ch error =
  log_error (Printexc.to_string error);
  (* Instantiate the template "fatal-error" of the startpage manually. *)
  (* Step 1: Create our own faked cgi_activation object *)
  let cgi_env = new Netcgi_env.custom_environment () in
  let dummy = new Netchannels.output_null () in
  cgi_env # set_output_ch dummy;
  cgi_env # set_cgi ~gateway_interface:"FAKE CGI" ~request_method:"GET" ();
  cgi_env # set_input_state `Received_header;
  cgi_env # set_output_state `Start;
  let cgi = 
    new Netcgi.std_activation ~env:(cgi_env :> Netcgi_env.cgi_environment) () in
  (* Step 2: Get the startpage object *)
  let environment = Wd_cycle.make_environment cgi in
  let startpage = universe # create environment "startpage" in
  (* Step 3: Initialize the startpage object *)
  let errid = Definitions.errid_of_error error in
  startpage # set_variable "runtime-error" (String_value errid);
  let session = !Registry.new_session universe environment in
  startpage # set_variable "session" (Dialog_value (Some session));
  (* Step 4: Output the template "fatal-error" *)
  let inst = Wd_template.apply_byname startpage "fatal-error" [] in
  let s = Wd_template.to_string startpage inst in
  ch # output_string s;
  rollback()
;;


(* [print_error] is called to output fatal errors. It is initialized with
 * a very simple definition which is replaced later by a more 
 * sophisticated one.
 *)

let print_error = ref simple_error_page
;;


(**********************************************************************)
(* Register dialogs etc.                                              *)
(**********************************************************************)

let reg config universe =
  (* Get the parameters to connect to the database: *)
  let db_name   = Get_config.option config "database-name" in
  let user_name = Get_config.option config "database-user" in
  let passwd    = Get_config.option config "database-passwd" in
  
  (* Bind to the database: *)
  Db.Connection.bind ~db_name ~user_name ~passwd db;
  
  (* Register output encodings: *)
  universe # application # add_output_encoding "weekday-en" enc_weekday_en;
  universe # application # add_output_encoding "month-en" enc_month_en;
  universe # application # add_output_encoding "month" enc_month;
  universe # application # add_output_encoding "mday-en" enc_mday_en;
  universe # application # add_output_encoding "mday" enc_mday;
  universe # application # add_output_encoding "year" enc_year;
  universe # application # add_output_encoding "cal-day" enc_cal_day;
  
  (* Register dialogs: *)
  universe # register "startpage" (new Startpage.startpage db);
  universe # register "editor" (new Editor.editor db);
  universe # register "timetravel" (new Timetravel.timetravel db);
  universe # register "session" (new Session.session);
  universe # register "selectuser" (new Selectuser.selectuser db);
  universe # register "export" (new Export.export db);
  universe # register "admin" (new Admin.admin db);
  universe # register "admin-password" (new Admin_password.admin_password db);
  universe # register "admin-accounts" 
                                (new Admin_accounts.admin_accounts config db);
  universe # register "admin-access" (new Admin_access.admin_access db);
  
  print_error := (extended_error_page universe)
;;


(* ======================================================================
 * History:
 * 
 * $Log: init.ml,v $
 * Revision 1.5  2003/03/23 11:59:14  gerd
 * 	GPL
 *
 * Revision 1.4  2003/02/03 01:28:59  gerd
 * 	Continued.
 *
 * Revision 1.3  2003/01/28 01:07:00  gerd
 * 	Continued.
 *
 * Revision 1.2  2003/01/27 22:14:39  gerd
 * 	Initial revision.
 *
 * 
 *)

This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml