--- /dev/null
+<% @header [("title", ["Mailing list creation requests"])];
+
+val admin = Group.inGroupName "lists";
+
+if $"req" <> "" then
+ val dom = $"req";
+ if Util.validEmail dom then
+ val id = MailingList.add (Init.getUserId(), dom, $"msg");
+ if not (MailingList.notifyNew id) then
+ %><h3><b>Error sending e-mail notification</b></h3><%
+ end
+ %><h3><b>Request added</b></h3><%
+ else
+ %><h3><b>Invalid list e-mail address</b></h3><%
+ end
+
+elseif $"cmd" = "open" then
+ %><h3><b>Open requests</b></h3>
+ <a href="list?cmd=list">List all requests</a><%
+
+ foreach (name, req) in MailingList.listOpen () do %>
+<br><hr><br>
+<table>
+<tr> <td align="right"><b>By</b>:</td> <td><a href="user?id=<% #usr req %>"><% name %></a></td> </tr>
+<tr> <td align="right"><b>Time</b>:</td> <td><% #stamp req %></td> </tr>
+<tr> <td align="right"><b>List name</b>:</td> <td><% #data req %></td> </tr>
+<tr> <td align="right" valign="top"><b>Reason</b>:</td> <td colspan="2"><% Web.html (#msg req) %></td> </tr>
+</table>
+
+<% if admin then %>
+ <br>
+ <a href="list?mod=<% #id req %>">[Modify]</a>
+ <a href="list?del=<% #id req %>">[Delete]</a><br>
+ To set up, run: <tt>newlist <% #data req %> <% name %>@hcoop.net <% Util.randomPassword () %></tt>
+<% end %>
+
+<% end
+
+elseif $"cmd" = "list" then
+ %><h3><b>All requests</b></h3><%
+
+ foreach (name, req) in MailingList.list () do %>
+<br><hr><br>
+<table>
+<tr> <td align="right"><b>By</b>:</td> <td colspan="2"><a href="user?id=<% #usr req %>"><% name %></a></td> </tr>
+<tr> <td align="right"><b>Time</b>:</td> <td colspan="2"><% #stamp req %></td> </tr>
+<tr> <td align="right"><b>List name</b>:</td> <td><% #data req %></td> </tr>
+<tr> <td align="right" valign="top"><b>Reason</b>:</td> <td colspan="2"><% Web.html (#msg req) %></td> </tr>
+</table>
+
+<% if admin then %>
+ <br>
+ <a href="list?mod=<% #id req %>">[Modify]</a>
+ <a href="list?del=<% #id req %>">[Delete]</a>
+<% end %>
+
+<% end
+
+elseif $"mod" <> "" then
+ Group.requireGroupName "lists";
+ val id = Web.stoi ($"mod");
+ val req = MailingList.lookup id;
+ val user = Init.lookupUser (#usr req) %>
+<h3><b>Handle request</b></h3>
+
+<form action="list">
+<input type="hidden" name="save" value="<% id %>">
+<table>
+<tr> <td align="right"><b>Requestor</b>:</td> <td><a href="user?id=<% #usr req %>"><% #name user %></a></td> </tr>
+<tr> <td align="right"><b>Time</b>:</td> <td><% #stamp req %></td> </tr>
+<tr> <td align="right"><b>Status</b>:</td> <td><select name="status">
+ <option value="0"<% if #status req = MailingList.NEW then %> selected<% end %>>New</option>
+ <option value="1"<% if #status req = MailingList.INSTALLED then %> selected<% end %>>Installed</option>
+ <option value="2"<% if #status req = MailingList.REJECTED then %> selected<% end %>>Rejected</option>
+</select></td> </tr>
+<tr> <td align="right"><b>List name</b>:</td> <td><input name="dom" value="<% #data req %>"></td> </tr>
+<tr> <td align="right" valign="top"><b>Message</b>:</td> <td><textarea name="msg" rows="10" cols="80" wrap="soft"><% Web.html (#msg req) %></textarea></td> </tr>
+<tr> <td><input type="submit" value="Save"></td> </tr>
+</table>
+</form>
+
+<% elseif $"save" <> "" then
+ Group.requireGroupName "lists";
+ val id = Web.stoi ($"save");
+ val req = MailingList.lookup id;
+ val oldStatus = #status req;
+ val newStatus = MailingList.statusFromInt (Web.stoi ($"status"));
+ MailingList.modify {req with data = $"dom", msg = $"msg", status = newStatus};
+ if oldStatus <> newStatus then
+ if not (MailingList.notifyMod (oldStatus, newStatus, Init.getUserName(), id)) then
+ %><h3><b>Error sending e-mail notification</b></h3><%
+ end
+ end
+ %><h3><b>Request modified</b></h3>
+ Back to: <a href="list?cmd=open">open requests</a>, <a href="list?cmd=list">all requests</a>
+
+<% elseif $"del" <> "" then
+ Group.requireGroupName "lists";
+ val id = Web.stoi ($"del");
+ val req = MailingList.lookup id;
+ val user = Init.lookupUser (#usr req)
+ %><h3><b>Are you sure you want to delete request by <% #name user %> for <tt><% #data req %></tt>?</b></h3>
+ <a href="list?del2=<% id %>">Yes, I'm sure!</a>
+
+<% elseif $"del2" <> "" then
+ Group.requireGroupName "lists";
+ val id = Web.stoi ($"del2");
+ MailingList.delete id
+ %><h3><b>Request deleted</b><h3>
+ Back to: <a href="list?cmd=open">open requests</a>, <a href="list?cmd=list">all requests</a>
+
+<% else %>
+
+<h3><b>Request new mailing list</b></h3>
+
+Enter here the e-mail address you would like for your list. Please keep in mind that the part of your list address before the "@" must be unique across all mailing lists we run. We may reject applications with overly general names here, especially names of current users or UNIX usernames that are likely to be chosen by future members. The "Reason" field is optional.
+
+<form action="list">
+<table>
+<tr> <td align="right" valign="top"><b>List name</b>:</td> <td><input name="req"></td> </tr>
+<tr> <td align="right" valign="top"><b>Reason</b>:</td> <td><textarea name="msg" rows="5" cols="80" wrap="soft"></textarea></td> </tr>
+<tr> <td><input type="submit" value="Request"></td> </tr>
+</table>
+</form>
+
+<% end %>
+
+<% @footer[] %>
\ No newline at end of file
fun validDomain s =
size s > 0 andalso size s < 100 andalso List.all validHost (String.fields (fn ch => ch = #".") s)
+fun validUser s =
+ size s > 0 andalso size s < 50 andalso List.all
+ (fn ch => isIdent ch orelse ch = #"." orelse ch = #"_" orelse ch = #"-" orelse ch = #"+")
+ (String.explode s)
+
+fun validEmailUser s =
+ size s > 0 andalso size s < 50 andalso List.all
+ (fn ch => Char.isAlphaNum ch orelse ch = #"." orelse ch = #"_" orelse ch = #"-" orelse ch = #"+")
+ (String.explode s)
+
+fun validEmail s =
+ (case String.fields (fn ch => ch = #"@") s of
+ [user, host] => validEmailUser user andalso validDomain host
+ | _ => false)
+
fun whoisUrl dom = String.concat ["http://reports.internic.net/cgi/whois?whois_nic=", dom, "&type=domain"]
+val rnd = ref (Random.rand (0, 0))
+
+fun init () = rnd := Random.rand (SysWord.toInt (Posix.Process.pidToWord (Posix.ProcEnv.getpid ())),
+ SysWord.toInt (Posix.Process.pidToWord (Posix.ProcEnv.getpid ())))
+
+fun randomPassword () = Int.toString (Int.abs (Random.randInt (!rnd)))
+
end
\ No newline at end of file