Apache log directory creation
[hcoop/domtool2.git] / src / plugins / apache.sml
index d706de9..13fa497 100644 (file)
@@ -61,29 +61,29 @@ val _ = Env.type_one "location"
 
 val dl = ErrorMsg.dummyLoc
 
-val _ = Main.registerDefault ("WebNodes",
-                             (TList (TBase "node", dl), dl),
-                             (fn () => (EList (map (fn s => (EString s, dl)) Config.Apache.webNodes), dl)))
+val _ = Defaults.registerDefault ("WebNodes",
+                                 (TList (TBase "node", dl), dl),
+                                 (fn () => (EList (map (fn s => (EString s, dl)) Config.Apache.webNodes), dl)))
 
-val _ = Main.registerDefault ("SSL",
-                             (TBase "bool", dl),
-                             (fn () => (EVar "false", dl)))
+val _ = Defaults.registerDefault ("SSL",
+                                 (TBase "bool", dl),
+                                 (fn () => (EVar "false", dl)))
 
-val _ = Main.registerDefault ("User",
-                             (TBase "your_user", dl),
-                             (fn () => (EString (Domain.getUser ()), dl)))
+val _ = Defaults.registerDefault ("User",
+                                 (TBase "your_user", dl),
+                                 (fn () => (EString (Domain.getUser ()), dl)))
 
-val _ = Main.registerDefault ("Group",
-                             (TBase "your_group", dl),
-                             (fn () => (EString (Domain.getUser ()), dl)))
+val _ = Defaults.registerDefault ("Group",
+                                 (TBase "your_group", dl),
+                                 (fn () => (EString (Domain.getUser ()), dl)))
 
-val _ = Main.registerDefault ("DocumentRoot",
-                             (TBase "your_path", dl),
-                             (fn () => (EString ("/home/" ^ Domain.getUser () ^ "/public_html"), dl)))
+val _ = Defaults.registerDefault ("DocumentRoot",
+                                 (TBase "your_path", dl),
+                                 (fn () => (EString (Config.homeBase ^ "/" ^ Domain.getUser () ^ "/public_html"), dl)))
 
-val _ = Main.registerDefault ("ServerAdmin",
-                             (TBase "email", dl),
-                             (fn () => (EString (Domain.getUser () ^ "@" ^ Config.defaultDomain), dl)))
+val _ = Defaults.registerDefault ("ServerAdmin",
+                                 (TBase "email", dl),
+                                 (fn () => (EString (Domain.getUser () ^ "@" ^ Config.defaultDomain), dl)))
 
 
 val redirect_code = fn (EVar "temp", _) => SOME "temp"
@@ -131,37 +131,128 @@ val apache_option = fn (EVar "execCGI", _) => SOME "ExecCGI"
                     | (EVar "indexes", _) => SOME "Indexes"
                     | _ => NONE
 
+val autoindex_width = fn (EVar "autofit", _) => SOME "*"
+                      | (EApp ((EVar "characters", _), n), _) =>
+                        Option.map Int.toString (Env.int n)
+                      | _ => NONE
+
+val autoindex_option = fn (EApp ((EVar "descriptionWidth", _), w), _) =>
+                         Option.map (fn w => ("DescriptionWidth", SOME w))
+                         (autoindex_width w)
+                       | (EVar "fancyIndexing", _) => SOME ("FancyIndexing", NONE)
+                       | (EVar "foldersFirst", _) => SOME ("FoldersFirst", NONE)
+                       | (EVar "htmlTable", _) => SOME ("HTMLTable", NONE)
+                       | (EVar "iconsAreLinks", _) => SOME ("IconsAreLinks", NONE)
+                       | (EApp ((EVar "iconHeight", _), n), _) =>
+                         Option.map (fn w => ("IconHeight", SOME (Int.toString w)))
+                                    (Env.int n)
+                       | (EApp ((EVar "iconWidth", _), n), _) =>
+                         Option.map (fn w => ("IconWidth", SOME (Int.toString w)))
+                                    (Env.int n)
+                       | (EVar "ignoreCase", _) => SOME ("IgnoreCase", NONE)
+                       | (EVar "ignoreClient", _) => SOME ("IgnoreClient", NONE)
+                       | (EApp ((EVar "nameWidth", _), w), _) =>
+                         Option.map (fn w => ("NameWidth", SOME w))
+                                    (autoindex_width w)
+                       | (EVar "scanHtmlTitles", _) => SOME ("ScanHTMLTitles", NONE)
+                       | (EVar "suppressColumnSorting", _) => SOME ("SuppressColumnSorting", NONE)
+                       | (EVar "suppressDescription", _) => SOME ("SuppressDescription", NONE)
+                       | (EVar "suppressHtmlPreamble", _) => SOME ("SuppressHTMLPreamble", NONE)
+                       | (EVar "suppressIcon", _) => SOME ("SuppressIcon", NONE)
+                       | (EVar "suppressLastModified", _) => SOME ("SuppressLastModified", NONE)
+                       | (EVar "suppressRules", _) => SOME ("SuppressRules", NONE)
+                       | (EVar "suppressSize", _) => SOME ("SuppressSize", NONE)
+                       | (EVar "trackModified", _) => SOME ("TrackModified", NONE)
+                       | (EVar "versionSort", _) => SOME ("VersionSort", NONE)
+                       | (EVar "xhtml", _) => SOME ("XHTML", NONE)
+
+                       | _ => NONE
 
 val vhostsChanged = ref false
 
 val () = Slave.registerPreHandler
             (fn () => vhostsChanged := false)
 
+fun findVhostUser fname =
+    let
+       val inf = TextIO.openIn fname
+
+       fun loop () =
+           case TextIO.inputLine inf of
+               NONE => NONE
+             | SOME line =>
+               case String.tokens Char.isSpace line of
+                   ["SuexecUserGroup", user, _] => SOME user
+                 | _ => loop ()
+    in
+       loop ()
+       before TextIO.closeIn inf
+    end
+
 val () = Slave.registerFileHandler (fn fs =>
-                                      let
-                                          val spl = OS.Path.splitDirFile (#file fs)
-                                      in
-                                          if String.isSuffix ".vhost" (#file spl)
-                                             orelse String.isSuffix ".vhost_ssl" (#file spl) then
-                                              (vhostsChanged := true;
-                                               case #action fs of
-                                                   Slave.Delete =>
-                                                   ignore (OS.Process.system (Config.rm
-                                                                              ^ " -rf "
-                                                                              ^ Config.Apache.confDir
-                                                                              ^ "/"
-                                                                              ^ #file spl))
-                                                 | _ =>
-                                                   ignore (OS.Process.system (Config.cp
-                                                                              ^ " "
-                                                                              ^ #file fs
-                                                                              ^ " "
-                                                                              ^ Config.Apache.confDir
-                                                                              ^ "/"
-                                                                              ^ #file spl)))
-                                          else
-                                              ()
-                                      end)
+                                      case findVhostUser (#file fs) of
+                                          NONE => print ("Can't find user in " ^ #file fs ^ "!  Taking no action.\n")
+                                        | SOME user =>
+                                          let
+                                              val spl = OS.Path.splitDirFile (#file fs)
+                                          in
+                                              if String.isSuffix ".vhost" (#file spl)
+                                                 orelse String.isSuffix ".vhost_ssl" (#file spl) then
+                                                  (vhostsChanged := true;
+                                                   case #action fs of
+                                                       Slave.Delete =>
+                                                       let
+                                                           val {base, ...} = OS.Path.splitBaseExt (#file spl)
+
+                                                           val logname = OS.Path.joinDirFile
+                                                                             {dir = Config.Apache.logDir,
+                                                                              file = user}
+                                                       in
+                                                           ignore (OS.Process.system (Config.rm
+                                                                                      ^ " -rf "
+                                                                                      ^ Config.Apache.confDir
+                                                                                      ^ "/"
+                                                                                      ^ #file spl));
+                                                           Slave.writeList (logname,
+                                                                            List.filter (fn s => s <> base)
+                                                                                        (Slave.readList logname))
+                                                       end
+                                                       
+                                                     | Slave.Add =>
+                                                       let
+                                                           val _ = 
+                                                               OS.Process.system (Config.cp
+                                                                                  ^ " "
+                                                                                  ^ #file fs
+                                                                                  ^ " "
+                                                                                  ^ Config.Apache.confDir
+                                                                                  ^ "/"
+                                                                                  ^ #file spl)
+
+                                                           val {base, ...} = OS.Path.splitBaseExt (#file spl)
+
+                                                           val logname = OS.Path.joinDirFile
+                                                                             {dir = Config.Apache.logDir,
+                                                                              file = user}
+
+                                                           val outf = TextIO.openAppend logname
+                                                       in
+                                                           TextIO.output (outf, base);
+                                                           TextIO.output1 (outf, #"\n");
+                                                           TextIO.closeOut outf
+                                                       end
+        
+                                                     | _ =>
+                                                       ignore (OS.Process.system (Config.cp
+                                                                                  ^ " "
+                                                                                  ^ #file fs
+                                                                                  ^ " "
+                                                                                  ^ Config.Apache.confDir
+                                                                                  ^ "/"
+                                                                                  ^ #file spl)))
+                                              else
+                                                  ()
+                                          end)
 
 val () = Slave.registerPostHandler
         (fn () =>
@@ -178,6 +269,30 @@ val rewriteEnabled = ref false
 val currentVhost = ref ""
 val currentVhostId = ref ""
 
+val pre = ref (fn _ : {nodes : string list, id : string, hostname : string} => ())
+fun registerPre f =
+    let
+       val old = !pre
+    in
+       pre := (fn x => (old x; f x))
+    end
+
+val post = ref (fn () => ())
+fun registerPost f =
+    let
+       val old = !post
+    in
+       post := (fn () => (old (); f ()))
+    end
+
+val aliaser = ref (fn _ : string => ())
+fun registerAliaser f =
+    let
+       val old = !aliaser
+    in
+       aliaser := (fn x => (old x; f x))
+    end
+
 val () = Env.containerV_one "vhost"
         ("host", Env.string)
         (fn (env, host) =>
@@ -232,9 +347,11 @@ val () = Env.containerV_one "vhost"
                 write Config.Apache.logDir;
                 write "/";
                 write vhostId;
-                write "/access.log combined\n"
+                write "/access.log combined\n";
+                !pre {nodes = nodes, id = vhostId, hostname = fullHost}
             end,
-         fn () => (write "</VirtualHost>\n";
+         fn () => (!post ();
+                   write "</VirtualHost>\n";
                    app TextIO.closeOut (!vhostFiles)))
 
 val () = Env.container_one "location"
@@ -402,7 +519,8 @@ val () = Env.action_one "serverAlias"
         (fn host =>
             (write "\tServerAlias ";
              write host;
-             write "\n"))
+             write "\n";
+             !aliaser host))
 
 val authType = fn (EVar "basic", _) => SOME "basic"
                | (EVar "digest", _) => SOME "digest"
@@ -521,4 +639,64 @@ val () = Env.action_one "authzSvnAccessFile"
                      write path;
                      write "\n"))
 
+val () = Env.action_two "addDescription"
+        ("description", Env.string, "patterns", Env.list Env.string)
+        (fn (desc, pats) =>
+            case pats of
+                [] => ()
+              | _ => (write "\tAddDescription \"";
+                      write (String.toString desc);
+                      write "\"";
+                      app (fn pat => (write " "; write pat)) pats;
+                      write "\n"))
+
+val () = Env.action_one "indexOptions"
+        ("options", Env.list autoindex_option)
+        (fn opts =>
+            case opts of
+                [] => ()
+              | _ => (write "\tIndexOptions";
+                      app (fn (opt, arg) =>
+                              (write " ";
+                               write opt;
+                               Option.app (fn arg =>
+                                              (write "="; write arg)) arg)) opts;
+                      write "\n"))
+
+val () = Env.action_one "set_indexOptions"
+        ("options", Env.list autoindex_option)
+        (fn opts =>
+            case opts of
+                [] => ()
+              | _ => (write "\tIndexOptions";
+                      app (fn (opt, arg) =>
+                              (write " +";
+                               write opt;
+                               Option.app (fn arg =>
+                                              (write "="; write arg)) arg)) opts;
+                      write "\n"))
+
+val () = Env.action_one "unset_indexOptions"
+        ("options", Env.list autoindex_option)
+        (fn opts =>
+            case opts of
+                [] => ()
+              | _ => (write "\tIndexOptions";
+                      app (fn (opt, _) =>
+                              (write " -";
+                               write opt)) opts;
+                      write "\n"))
+
+val () = Env.action_one "headerName"
+        ("name", Env.string)
+        (fn name => (write "\tHeaderName ";
+                     write name;
+                     write "\n"))
+
+val () = Env.action_one "readmeName"
+        ("name", Env.string)
+        (fn name => (write "\tReadmeName ";
+                     write name;
+                     write "\n"))
+
 end