--- /dev/null
+.cm
+passgen.mlt
--- /dev/null
+all: passgen.mlt
+
+passgen.mlt: /etc/hcoop.header /etc/hcoop.footer passgen.mlt.in
+ hcoop_html "HCoop Passgen" passgen.mlt.in >passgen.mlt
--- /dev/null
+<% PassGen.commit () %>
--- /dev/null
+<% PassGen.begin () %>
--- /dev/null
+signature CONFIG = sig
+ val dbstring : string
+end
--- /dev/null
+structure Config :> CONFIG = struct
+
+val dbstring = "dbname=passgen"
+
+end
--- /dev/null
+<html><head>
+<title>Hcoop Passgen: Exception</title>
+</head><body>
+
+<h1>Exception</h1>
+
+<% switch Web.getExn () of
+ Fail msg => %>
+<b>Fail</b>: <% Web.htmlNl msg %>
+<% | OS.SysErr (name, NONE) => %>
+<b>System error</b>: <% Web.html name %>
+<% | OS.SysErr (name, SOME syserr) => %>
+<b>System error</b>: <% Web.html name %>: <% Web.html (OS.errorName syserr) %>: <% Web.htmlNl (OS.errorMsg syserr) %>
+<% | IO.Io {name, function, ...} => %>
+<b>IO error</b>: <% Web.html name %> for <% Web.html function %><br>
+<% | PassGen.C.Sql msg => %>
+<b>SQL</b>: <% Web.htmlNl msg %>
+<% | Web.Format s => %>
+<b>Format</b>: <% Web.htmlNl s %>
+
+<% | ex => %>
+<b>Unknown exception kind.</b> Backtrace:
+<% foreach s in SMLofNJ.exnHistory ex do %>
+<li> <% Web.html s %></li>
+<% end
+end %>
+
+</body></html>
--- /dev/null
+before before
+after after
+exn exn
+
+out out
+pub /afs/hcoop.net/user/h/hc/hcoop/public_html/cgi-bin
+
+cm /usr/local/share/smlsql/smlsql.cm
+cm /usr/local/share/smlsql/libpq/sources.cm
--- /dev/null
+<% val (id, pass) = PassGen.gen () %>
+
+<table>
+<tr><td align="right"><b>ID:</b></td> <td><% id %></td></tr>
+<tr><td align="right"><b>Password:</b></td> <td><% pass %></td></tr>
+</table>
--- /dev/null
+signature PASSGEN = sig
+ structure C : SQL_CLIENT
+
+ val begin : unit -> unit
+ val commit : unit -> unit
+
+ val gen : unit -> int * string
+end
--- /dev/null
+structure PassGen :> PASSGEN = struct
+
+open Config Sql
+structure C = PgClient
+
+val db = ref (NONE : C.conn option)
+fun getDb () = valOf (!db)
+
+fun begin () =
+ let
+ val c = C.conn dbstring
+ in
+ db := SOME c;
+ ignore (C.dml c "BEGIN")
+ end
+
+fun commit () =
+ let
+ val db = getDb ()
+ in
+ C.dml db "COMMIT";
+ C.close db
+ end
+
+fun gen () =
+ let
+ val db = getDb ()
+
+ val id = case C.oneRow db "SELECT nextval('PassSeq')" of
+ [id] => C.intFromSql id
+ | _ => raise Fail "Bad nextval() return"
+
+ val proc = Unix.execute ("/usr/bin/apg", ["/usr/bin/apg", "-d", "-n", "1"])
+ val inf = Unix.textInstreamOf proc
+
+ val pass = case TextIO.inputLine inf of
+ NONE => raise Fail "No apg output"
+ | SOME line => String.substring (line, 0, size line - 1)
+ in
+ ignore (Unix.reap proc);
+ ignore (C.dml db ($`INSERT INTO Pass (id, pass) VALUES (^(C.intToSql id), ^(C.stringToSql pass))`));
+ (id, pass)
+ end
+
+end
--- /dev/null
+CREATE SEQUENCE PassSeq;
+
+CREATE TABLE Pass(
+ id INTEGER PRIMARY KEY,
+ pass TEXT NOT NULL);