]> matita.cs.unibo.it Git - helm.git/commitdiff
* first version of the profile manager committed
authorLuca Padovani <luca.padovani@unito.it>
Tue, 21 Oct 2003 08:28:42 +0000 (08:28 +0000)
committerLuca Padovani <luca.padovani@unito.it>
Tue, 21 Oct 2003 08:28:42 +0000 (08:28 +0000)
helm/DEVEL/profile-manager/Makefile [new file with mode: 0644]
helm/DEVEL/profile-manager/control.html [new file with mode: 0644]
helm/DEVEL/profile-manager/index.html [new file with mode: 0644]
helm/DEVEL/profile-manager/profile-manager.xsl [new file with mode: 0644]
helm/DEVEL/profile-manager/profile.ml [new file with mode: 0644]
helm/DEVEL/profile-manager/profile_manager.ml [new file with mode: 0644]
helm/DEVEL/profile-manager/profile_manager_env.ml [new file with mode: 0644]
helm/DEVEL/profile-manager/response.ml [new file with mode: 0644]
helm/DEVEL/profile-manager/welcome.html [new file with mode: 0644]

diff --git a/helm/DEVEL/profile-manager/Makefile b/helm/DEVEL/profile-manager/Makefile
new file mode 100644 (file)
index 0000000..5566443
--- /dev/null
@@ -0,0 +1,36 @@
+BIN_DIR = /usr/local/bin
+REQUIRES = http
+PREDICATES = 
+OCAMLOPTIONS = -package "$(REQUIRES)" -predicates "$(PREDICATES)" -pp camlp4o
+OCAMLFIND = ocamlfind
+OCAMLC = $(OCAMLFIND) ocamlc -thread $(OCAMLOPTIONS)
+OCAMLOPT = $(OCAMLFIND) ocamlopt -thread $(OCAMLOPTIONS)
+OCAMLDEP = ocamldep -pp camlp4o
+
+LIBRARIES = $(shell $(OCAMLFIND) query -recursive -predicates "byte $(PREDICATES)" -format "%d/%a" $(REQUIRES))
+LIBRARIES_OPT = $(shell $(OCAMLFIND) query -recursive -predicates "native $(PREDICATES)" -format "%d/%a" $(REQUIRES))
+
+OBJS = response.cmo profile.cmo profile_manager_env.cmo profile_manager.cmo
+
+profile-manager: $(OBJS) $(LIBRARIES)
+       $(OCAMLC) -linkpkg -o $@ $(OBJS)
+
+profile-manager.opt: $(OBJS:.cmo=.cmx) $(LIBRARIES_OPT)
+       $(OCAMLOPT) -linkpkg -o $@ $(OBJS:.cmo=.cmx)
+
+.SUFFIXES: .ml .mli .cmo .cmi .cmx
+.ml.cmo:
+       $(OCAMLC) -c $<
+.mli.cmi:
+       $(OCAMLC) -c $<
+.ml.cmx:
+       $(OCAMLOPT) -c $<
+
+$(OBJS): $(LIBRARIES)
+$(OBJS:.cmo=.cmx)): $(LIBRARIES_OPT)
+
+clean:
+       rm -f *.cm[iox] *.o rdfly rdfly.opt
+
+.PHONY: install uninstall clean
+
diff --git a/helm/DEVEL/profile-manager/control.html b/helm/DEVEL/profile-manager/control.html
new file mode 100644 (file)
index 0000000..2feb02f
--- /dev/null
@@ -0,0 +1,240 @@
+<html>
+
+<head>
+<title>Profile Manager Control Panel</title>
+
+<style type="text/css">
+#normal { background-color: white; font-family: sans-serif }
+td.head { font-weight: bold; background-color: #e6e6fa; color: brown }
+td.back { background-color: #e6e6fa; color: brown }
+#indent { margin-left: 1cm; margin-right: 1cm }
+</style>
+
+<script language="JavaScript">
+<!--
+function getParam(name, def)
+{
+  var search = top.location.search;
+  search = search.slice(1);
+  var args = search.split("&");
+  var value = "-1";
+  for (var i = 0 ; i < args.length ; i++) {
+    var couple = args[i].split("=");
+    if (couple[0] == name) value = couple[1];
+  }
+  if (value == "-1") value = def;
+  return value;
+}
+
+function getInitialURL()
+{
+  return getParam("pmURL", "http://mowgli.cs.unibo.it:58099/");
+}
+
+function getURL()
+{
+  return document.pmURL.elements[0].value;
+}
+
+function setURL(ss)
+{
+  if (ss.selectedIndex == 0) {
+    document.pmURL.elements[0].value = "";
+  } else {
+    document.pmURL.elements[0].value = "http://" + ss.options[ss.selectedIndex].value;
+  }
+}
+
+function escapePassword(pwd)
+{
+  if (ss == "") {
+    return "";
+  } else {
+    return ("&password=" + escape(pwd));
+  }
+}
+
+function getAccess(ss)
+{
+  return (ss.options[ss.selectedIndex].value);
+}
+-->
+</script>
+
+</head>
+
+<body>
+<a name="top"/>
+<table border="0" width="100%" cellpadding="4">
+<tr><td class="head" align="center"><big><big>Profile Manager Control Panel</big></big></td></tr>
+</table>
+
+<br />
+
+<div>
+This is a control panel for the profile manager. You can control a
+local or remote profile manager by filling the appropriate field below
+and sending the desired commands. Any command issued to the profile
+manager results into an XML response.  Note that in order to use this
+page <i>you must have JavaScript enabled</i>.  If you have troubles,
+please send an email to the author: lpadovan at cs dot unibo dot it.
+</div>
+
+<p>
+<div style="color: red">
+<b>WARNING</b>: the information stored in a profile,
+including the password, IS NOT encrypted in the profile nor while it
+is travelling from your computer to the profile manager.  DO NOT USE
+THE PROFILE MANAGER FOR STORING SENSIBLE INFORMATION LIKE PASSWORDS
+FOR SECURE ACCOUNTS OR ANY OTHER PERSONAL DATA.  </div>
+</p>
+
+<div>
+<br />
+
+<table border="1">
+   <tr> <td>
+     <form name="pmURL">
+       Profile Manager <b>URL</b>
+       <input type="text" value="http://localhost:58099/" size="50"/>
+       <select onChange="setURL(this)">
+         <option value="">---</option>
+        <option value="localhost:58099/">localhost</option>
+        <option value="mowgli.cs.unibo.it:58099/">mowgli</option>
+       </select>
+     </form>
+   </td> </tr>
+   <tr> <td>
+     <form>
+        <b>List</b> the profiles currently stored in the Profile Manager<br />
+        <input type="button" value="List"
+        onClick="top.result.location.replace(getURL() + 'list')"/>
+      </form>
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <form name="newProfile">
+        <b>Create</b> a new profile<br />
+       <table>
+         <tr><td>Profile ID:</td><td> <input type="text" name="id" value="" /> (leave blank if you want an ID to be assigned automatically)</td></tr>
+         <tr><td>Password:</td><td><input type="text" name="password" value="" /> (optional)</td></tr>
+       </table>
+       <input type="button" value="Create"
+        onClick="top.result.location.replace(getURL() +
+         'new?id=' + escape(document.newProfile.elements[0].value))"/>
+      </form>
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <form name="delProfile">
+        <b>Delete</b> an existing profile<br />
+       <table>
+         <tr><td>Profile ID:</td><td> <input type="text" name="id" value="" /></td></tr>
+         <tr><td>Password:</td><td><input type="text" name="password" value="" /> (optional)</td></tr>
+       </table>
+       <input type="button" value="Delete"
+        onClick="top.result.location.replace(getURL() +
+         'del?id=' + escape(document.delProfile.elements[0].value) +
+         '&password=' + escape(document.delProfile.elements[1].value))"/>
+      </form>
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <form name="getProfile">
+        <b>Retrieve</b> an existing profile<br />
+       <table>
+         <tr><td>Profile ID:</td><td> <input type="text" name="id" value="" /></td></tr>
+         <tr><td>Password:</td><td><input type="text" name="password" value="" /> (optional)</td></tr>
+       </table>
+       <input type="button" value="Get"
+        onClick="top.result.location.replace(getURL() +
+         'get?id=' + escape(document.getProfile.elements[0].value) +
+         '&password=' + escape(document.getProfile.elements[1].value))"/>
+      </form>
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <form name="setProfile">
+        <b>Set</b> the value for a field in an existing profile<br />
+       <table>
+         <tr><td>Profile ID:</td><td> <input type="text" name="id" value="" /></td></tr>
+         <tr><td>Password:</td><td><input type="text" name="password" value="" /> (optional)</td></tr>
+         <tr><td>Field:</td><td><input type="text" name="field" value="" /></td></tr>
+         <tr><td>Value:</td><td><input type="text" name="value" value="" /> (optional, if blank will remove the field from the profile)</td></tr>
+       </table>
+       <input type="button" value="Set"
+        onClick="top.result.location.replace(getURL() +
+         'set?id=' + escape(document.setProfile.elements[0].value) +
+         '&password=' + escape(document.setProfile.elements[1].value) +
+         '&field=' + escape(document.setProfile.elements[2].value) +
+         '&value=' + escape(document.setProfile.elements[3].value))"/>
+      </form>
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <form name="setPassword">
+        <b>Set/Change</b> the password for a profile<br />
+       <table>
+         <tr><td>Profile ID:</td><td> <input type="text" name="id" value="" /></td></tr>
+         <tr><td>Old password:</td><td><input type="text" name="old_password" value="" /> (optional)</td></tr>
+         <tr><td>New password:</td><td><input type="text" name="new_password" value="" /> (optional)</td></tr>
+       </table>
+       <input type="button" value="Set/Change"
+        onClick="top.result.location.replace(getURL() +
+         'password?id=' + escape(document.setPassword.elements[0].value) +
+         '&old_password=' + escape(document.setPassword.elements[1].value) +
+         '&new_password=' + escape(document.setPassword.elements[2].value))"/>
+      </form>
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <form name="setAccess">
+        <b>Set</b> the access capabilities for a profile<br />
+       <table>
+         <tr><td>Profile ID:</td><td> <input type="text" name="id" value="" /></td></tr>
+         <tr><td>Password:</td><td><input type="text" name="password" value="" /> (optional)</td></tr>
+         <tr><td>Read access:</td><td>
+         <select>
+           <option value="allowed">allowed</option>
+           <option value="denied">denied</option>
+           <option value="password">allowed with password</option>
+         </select>
+         </td></tr>
+         <tr><td>Write access:</td><td>
+         <select>
+           <option value="allowed">allowed</option>
+           <option value="denied">denied</option>
+           <option value="password">allowed with password</option>
+         </select>
+         </td></tr>
+         <tr><td>Profile access:</td><td>
+         <select>
+           <option value="allowed">allowed</option>
+           <option value="denied">denied</option>
+           <option value="password">allowed with password</option>
+         </select>
+         </td></tr>
+       </table>
+       <input type="button" value="Set"
+        onClick="top.result.location.replace(getURL() +
+         'access?id=' + escape(document.setAccess.elements[0].value) +
+         '&password=' + escape(document.setAccess.elements[1].value) +
+         '&read=' + getAccess(document.setAccess.elements[2]) +
+         '&write=' + getAccess(document.setAccess.elements[3]) +
+         '&profile=' + getAccess(document.setAccess.elements[4]))"/>
+      </form>
+    </td>
+  </tr>
+</table>
+</div>
+
+</body>
+
+</html>
+
diff --git a/helm/DEVEL/profile-manager/index.html b/helm/DEVEL/profile-manager/index.html
new file mode 100644 (file)
index 0000000..caeebcf
--- /dev/null
@@ -0,0 +1,8 @@
+<html>
+
+<frameset rows="75%,*">
+  <frame src="control.html" name="control"/>
+  <frame src="welcome.html" name="result"/>
+</frameset>
+
+</html>
diff --git a/helm/DEVEL/profile-manager/profile-manager.xsl b/helm/DEVEL/profile-manager/profile-manager.xsl
new file mode 100644 (file)
index 0000000..e32d587
--- /dev/null
@@ -0,0 +1,55 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:template name="profile_manager_list">
+    <xsl:param name="managerURL" select="''"/>
+    <xsl:copy-of select="document(string-concat($managerURL, 'list'))"/>
+  </xsl:template>
+
+  <xsl:template name="profile_manager_new">
+    <xsl:param name="managerURL" select="''"/>
+    <xsl:param name="id" select="''"/> <!-- optional -->
+    <xsl:param name="password" select="''"/> <!-- optional -->
+    <xsl:copy-of select="document(concat($managerURL, 'new?id=', $id, '&amp;password=', $password))"/>
+  </xsl:template>
+  
+  <xsl:template name="profile_manager_delete">
+    <xsl:param name="managerURL" select="''"/>
+    <xsl:param name="id" select="''"/>
+    <xsl:param name="password" select="''"/> <!-- optional -->
+    <xsl:copy-of select="document(concat($managerURL, 'del?id=', $id, '&amp;password=', $password))"/>  
+  </xsl:template>
+  
+  <xsl:template name="profile_manager_get">
+    <xsl:param name="managerURL" select="''"/>
+    <xsl:param name="id" select="''"/>
+    <xsl:param name="password" select="''"/> <!-- optional -->
+    <xsl:copy-of select="document(concat($managerURL, 'get?id=', $id, '&amp;password=', $password))"/>  
+  </xsl:template>
+  
+  <xsl:template name="profile_manager_set">
+    <xsl:param name="managerURL" select="''"/>
+    <xsl:param name="id" select="''"/>
+    <xsl:param name="field" select="''"/>
+    <xsl:param name="value" select="''"/> <!-- optional -->
+    <xsl:param name="password" select="''"/> <!-- optional -->
+    <xsl:copy-of select="document(concat($managerURL, 'set?id=', $id, '&amp;field=', $field, '&amp;value=', $value, '&amp;password=', $password))"/>  
+  </xsl:template>
+  
+  <xsl:template name="profile_manager_set_password">
+    <xsl:param name="managerURL" select="''"/>
+    <xsl:param name="id" select="''"/>
+    <xsl:param name="old_password" select="''"/> <!-- optional -->
+    <xsl:param name="new_password" select="''"/> <!-- optional -->
+    <xsl:copy-of select="document(concat($managerURL, 'get?id=', $id, '&amp;old_password=', $old_password, '&amp;new_password=', $new_password))"/>  
+  </xsl:template>
+  
+  <xsl:template name="profile_manager_set_access">
+    <xsl:param name="managerURL" select="''"/>
+    <xsl:param name="id" select="''"/>
+    <xsl:param name="read" select="''"/> <!-- optional -->
+    <xsl:param name="write" select="''"/> <!-- optional -->
+    <xsl:param name="profile" select="''"/> <!-- optional -->
+    <xsl:copy-of select="document(concat($managerURL, 'get?id=', $id, '&amp;read=', $read, '&amp;write=', $write, '&amp;profile=', $profile))"/>  
+  </xsl:template>
+  
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/helm/DEVEL/profile-manager/profile.ml b/helm/DEVEL/profile-manager/profile.ml
new file mode 100644 (file)
index 0000000..9c19b3c
--- /dev/null
@@ -0,0 +1,119 @@
+
+exception Permission_denied
+exception Invalid_access of string
+
+type access_t =
+    Allowed
+  | Denied
+  | Password
+
+let access_of_string old =
+  function
+      None -> old
+    | Some "allowed" -> Allowed
+    | Some "denied" -> Denied
+    | Some "password" -> Password
+    | Some s -> raise (Invalid_access s)
+
+let string_of_access =
+  function
+      Allowed -> "allowed"
+    | Denied -> "denied"
+    | Password -> "password"
+
+type t =
+    { id : string;
+      mutable password : string;
+      mutable read_access : access_t;
+      mutable write_access : access_t;
+      mutable profile_access : access_t;
+      data : (string, string) Hashtbl.t;
+    }
+
+let serialize profile with_data =
+  let serialize_data data =
+    let sl = ref [] in
+    Hashtbl.iter
+      (fun field value ->
+       sl := ("  <field id=\"" ^ (Response.quote_attribute field) ^ "\">" ^ (Response.quote value) ^ "</field>\n")::!sl)
+      data ;
+    List.fold_left (^) "" !sl
+  in
+  "<profile id=\"" ^ profile.id ^
+  "\" read=\"" ^ (string_of_access profile.read_access) ^
+  "\" write=\"" ^ (string_of_access profile.write_access) ^
+  "\" profile=\"" ^ (string_of_access profile.profile_access) ^
+  "\">\n" ^ (if with_data then serialize_data profile.data else "") ^ "</profile>"
+
+let create key pwd =
+  let access, pwd' =
+    match pwd with
+      Some s -> Password, s
+    | None -> Allowed, ""
+  in
+  let profile =
+    { id = key;
+      password = pwd';
+      read_access = access;
+      write_access = access;
+      profile_access = access;
+      data = Hashtbl.create 11
+    }
+  in
+  profile
+
+let test_read_access profile pwd =
+  match pwd, profile.read_access with
+    Some s, Password when s = profile.password -> ()
+  | None, Password when profile.password = "" -> ()
+  | _, Allowed -> ()
+  | _ -> raise Permission_denied
+
+let test_write_access profile pwd =
+  match pwd, profile.write_access with
+    Some s, Password when s = profile.password -> ()
+  | None, Password when profile.password = "" -> ()
+  | _, Allowed -> ()
+  | _ -> raise Permission_denied
+
+let test_profile_access profile pwd =
+  match pwd, profile.profile_access with
+    Some s, Password when s = profile.password -> ()
+  | None, Password when profile.password = "" -> ()
+  | _, Allowed -> ()
+  | _ -> raise Permission_denied
+
+let get profile pwd =
+  test_read_access profile pwd ;
+  serialize profile true
+
+let set profile field value pwd =
+  test_write_access profile pwd ;
+  begin
+    match value with
+      Some value' -> Hashtbl.replace profile.data field value'
+    | None -> Hashtbl.remove profile.data field
+  end ;
+  Response.ok ()
+
+let del profile pwd =
+  test_profile_access profile pwd ;
+  Response.ok ()
+
+let set_password profile new_pwd pwd =
+  test_profile_access profile pwd ;
+  let new_pwd' =
+    match new_pwd with
+      Some s -> s
+    | None -> ""
+  in
+  prerr_endline ("old " ^ profile.password ^ " new " ^ new_pwd') ;
+  profile.password <- new_pwd' ;
+  Response.ok ()
+
+let set_access profile read_access write_access profile_access pwd =
+  test_profile_access profile pwd ;
+  profile.read_access <- access_of_string profile.read_access read_access ;
+  profile.write_access <- access_of_string profile.write_access write_access ;
+  profile.profile_access <- access_of_string profile.profile_access profile_access ;
+  Response.ok ()
diff --git a/helm/DEVEL/profile-manager/profile_manager.ml b/helm/DEVEL/profile-manager/profile_manager.ml
new file mode 100644 (file)
index 0000000..1c61e6a
--- /dev/null
@@ -0,0 +1,177 @@
+(*
+ * Copyright (C) 2003:
+ *    Stefano Zacchiroli <zack@cs.unibo.it>
+ *    for the HELM Team http://helm.cs.unibo.it/
+ *
+ *  This file is part of HELM, an Hypertextual, Electronic
+ *  Library of Mathematics, developed at the Computer Science
+ *  Department, University of Bologna, Italy.
+ *
+ *  HELM 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.
+ *
+ *  HELM 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 HELM; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ *  MA  02111-1307, USA.
+ *
+ *  For details, see the HELM World-Wide-Web page,
+ *  http://helm.cs.unibo.it/
+ *)
+
+exception Impossible
+
+let (profile_db : (string, Profile.t) Hashtbl.t) =
+  try
+    let ch = open_in Profile_manager_env.profile_db_path in
+    input_value ch
+  with
+    _ -> Hashtbl.create 211
+
+let get_param_opt (req : Http_types.request) p =
+  try
+    match req#param p with
+      "" -> None
+    | s -> Some s
+  with
+    Http_types.Param_not_found _ -> None
+
+let new_key () =
+  let hex_of_nibble n =
+    if n >= 0 && n < 10 then
+      string_of_int n
+    else if n >= 10 && n < 16 then
+      String.make 1 (Char.chr (n - 10 + (Char.code 'A')))
+    else
+      raise Impossible
+  in
+  let rec aux s =
+    function
+       0 -> s
+      | n -> aux ((hex_of_nibble (Random.int 16)) ^ s) (n - 1)
+  in
+  aux "" 4
+
+let new_unique_key =
+  let rec aux () =
+    let key = new_key () in
+    if Hashtbl.mem profile_db key then
+      aux ()
+    else
+      key
+  in
+  aux
+
+let list_profiles () =
+  let pl = ref [] in
+  Hashtbl.iter
+    (fun _ profile -> pl := (Profile.serialize profile false) :: !pl)
+    profile_db ;
+  "<profiles>" ^ (List.fold_left (^) "" !pl) ^ "</profiles>"
+
+let get_profile id pwd =
+  let profile = Hashtbl.find profile_db id in
+  Profile.get profile pwd
+
+let new_profile id pwd =
+  match id with
+    Some id' when Hashtbl.mem profile_db id' -> get_profile id' pwd
+  | Some id' -> 
+      let profile = Profile.create id' pwd in
+      Hashtbl.add profile_db profile.Profile.id profile ;
+      Profile.serialize profile true
+  | None ->
+      let profile = Profile.create (new_unique_key ()) None in
+      Hashtbl.add profile_db profile.Profile.id profile ;
+      Profile.serialize profile true
+
+let set_profile id field value pwd =
+  let profile = Hashtbl.find profile_db id in
+  Profile.set profile field value pwd
+
+let del_profile id pwd =
+  let profile = Hashtbl.find profile_db id in
+  let res = Profile.del profile pwd in
+  Hashtbl.remove profile_db id ;
+  res
+
+let set_password id new_pwd pwd =
+  let profile = Hashtbl.find profile_db id in
+  Profile.set_password profile new_pwd pwd
+
+let set_access id read_access write_access profile_access pwd =
+  let profile = Hashtbl.find profile_db id in
+  Profile.set_access profile read_access write_access profile_access pwd
+
+let callback (req : Http_types.request) outchan =
+  let res = 
+    try
+      prerr_endline ("Connection from " ^ req#clientAddr) ;
+      prerr_endline ("Received request: " ^ req#path) ;
+      begin
+       match req#path with
+         "/list" -> list_profiles ()
+       | "/get" ->
+           let id = req#param "id"
+           and pwd = get_param_opt req "password" in
+           get_profile id pwd
+       | "/set" ->
+           let id = req#param "id"
+           and field = req#param "field"
+           and value = get_param_opt req "value"
+           and pwd = get_param_opt req "password" in
+           set_profile id field value pwd
+       | "/del" ->
+           let id = req#param "id"
+           and pwd = get_param_opt req "password" in
+           del_profile id pwd
+       | "/new" ->
+           let id = get_param_opt req "id"
+           and pwd = get_param_opt req "password" in
+           new_profile id pwd
+       | "/password" ->
+           let id = req#param "id"
+           and old_pwd = get_param_opt req "old_password"
+           and new_pwd = get_param_opt req "new_password" in
+           set_password id new_pwd old_pwd
+       | "/access" ->
+           let id = req#param "id"
+           and pwd = get_param_opt req "password"
+           and read_access = get_param_opt req "read"
+           and write_access = get_param_opt req "write"
+           and profile_access = get_param_opt req "profile" in
+           set_access id read_access write_access profile_access pwd
+       | s -> Response.error ("unrecognized command: " ^ s)
+      end
+    with
+      Not_found -> Response.error "unknown profile"
+    | Profile.Permission_denied -> Response.error "permission denied"
+    | e -> Response.error ("uncaught exception: " ^ (Printexc.to_string e))
+  in
+  Http_daemon.respond
+    ~body:res ~headers:["Content-Type", "text/xml"] outchan
+
+    (* daemon initialization *)
+
+let save_db () =
+  let ch = open_out Profile_manager_env.profile_db_path in
+  output_value ch profile_db ;
+  close_out ch
+
+let main () =
+  at_exit save_db ;
+  Sys.catch_break true ;
+  try
+    Http_daemon.start' ~timeout:(Some 600) ~port:58099 ~mode:`Thread callback
+  with
+    Sys.Break -> ()
+in
+main ()
+
diff --git a/helm/DEVEL/profile-manager/profile_manager_env.ml b/helm/DEVEL/profile-manager/profile_manager_env.ml
new file mode 100644 (file)
index 0000000..cac43bd
--- /dev/null
@@ -0,0 +1,6 @@
+
+let profile_db_path =
+  try
+    Sys.getenv "PROFILE_MANAGER_DB_PATH"
+  with
+    Not_found -> "/tmp/profile.db"
diff --git a/helm/DEVEL/profile-manager/response.ml b/helm/DEVEL/profile-manager/response.ml
new file mode 100644 (file)
index 0000000..e47a666
--- /dev/null
@@ -0,0 +1,8 @@
+
+let quote_attribute s = s
+
+let quote s = s
+
+let error s = "<error>" ^ (quote s) ^ "</error>"
+
+let ok () = "<ok/>"
diff --git a/helm/DEVEL/profile-manager/welcome.html b/helm/DEVEL/profile-manager/welcome.html
new file mode 100644 (file)
index 0000000..f6fbed4
--- /dev/null
@@ -0,0 +1,6 @@
+<html>
+
+<body bgcolor="white">
+</body>
+
+</html>