3 import javax.servlet.*;
4 import javax.servlet.http.*;
7 import java.sql.SQLException;
8 import java.sql.ResultSet;
9 import java.sql.ResultSetMetaData;
10 import java.text.SimpleDateFormat;
11 import java.util.Date;
12 import java.util.ResourceBundle;
14 public class MoiraServlet extends HttpServlet {
15 static final String MOIRA_SERVER = "moira.mit.edu";
16 Kticket kt = new Kticket("jis5", "foobar", "ATHENA.MIT.EDU");
17 boolean ktinit = false;
18 private static final int MAXDISPLAY = 10;
19 Hashtable FileParts = new Hashtable();
20 Hashtable FileTimes = new Hashtable();
21 static final SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
22 static final int KE_RD_AP_BADD = 39525414; // This is a kludge
25 public synchronized void service(HttpServletRequest request, HttpServletResponse response) {
26 System.err.println("MoiraSerlvet: Service");
27 System.err.println("---------------------");
29 if (!ktinit) { // Once only initialization
31 Thread t = new Thread(kt);
37 Hashtable qv = new Hashtable();
41 try { // Get Parameters
42 Enumeration e = request.getParameterNames();
43 while (e.hasMoreElements()) {
44 String pname = (String)e.nextElement();
45 String [] pvaluearray = request.getParameterValues(pname);
47 if (pvaluearray.length > 1) {
48 for (int i = 0; i < pvaluearray.length; i++)
49 pvalue += pvaluearray[i];
50 } else pvalue = pvaluearray[0];
52 System.err.println(pname + " = " + pvalue);
53 qv.put(pname, pvalue);
56 modifier = (String)qv.get("modifier");
57 if (modifier == null) modifier = "";
59 if (modifier.equals("showform")) {
60 do_showform(qv, request, response);
62 } else if (modifier.equals("showurl")) {
63 do_showurl(qv, request, response);
65 } else if (modifier.equals("makesession")) {
66 request.getSession(true);
70 String operation = (String) qv.get("operation");
71 if (operation == null) {
73 DataOutputStream out = new DataOutputStream(response.getOutputStream());
74 response.setContentType("text/html");
75 if (modifier.equals("getfile"))
76 out.writeBytes("You need to select an operation from the list on the left!");
77 else if (modifier.equals("displayonly"))
78 out.writeBytes("error");
79 else if (modifier.equals("getlistname")) {
80 out.writeBytes(do_getlistinput(qv, request, response));
83 } catch (Exception ee) {
88 if (operation.charAt(operation.length()-2) == '\r') // Trim newline stuff
89 operation = operation.substring(0, operation.length() - 2);
90 if (modifier.equals("getlistname")) {
91 msg = do_getlistinput(qv, request, response);
92 if (msg.equals("")) return;
93 } else if (modifier.equals("getfile")) {
94 msg = getfile(operation);
95 } else if (operation.equals("getmembers")) {
96 if (modifier.equals("displayonly")) {
99 msg = do_getmembers(qv, request, response);
100 if (msg.equals("")) return;
101 } else if (operation.equals("addfinal")) {
102 if (modifier.equals("displayonly")) {
103 msg = "added members";
105 msg = do_addfinal(qv, request, response);
106 if (msg.equals("")) return;
107 } else if (operation.equals("editme")) {
108 if (modifier.equals("displayonly")) {
109 msg = "add or remove yourself from a list";
111 msg = do_editme(qv, request, response);
112 if (msg.equals("")) return;
113 } else if (operation.equals("removemembers")) {
114 if (modifier.equals("displayonly")) {
115 msg = "edit/remove members";
117 msg = do_removemembers(qv, request, response);
118 if (msg.equals("")) return;
119 } else if (operation.equals("delmembers")) {
120 if (modifier.equals("displayonly")) {
121 msg = "edit/remove members";
123 msg = do_delmember(qv, request, response);
124 if (msg.equals("")) return;
125 } else if (operation.equals("delconfirm")) {
126 if (modifier.equals("displayonly")) {
127 msg = "member deleted";
129 msg = do_delconfirm(qv, request, response);
130 if (msg.equals("")) return;
131 } else if (operation.equals("addmember")) {
132 if (modifier.equals("displayonly")) {
133 msg = "add member(s)";
135 msg = do_addmember(qv, request, response);
136 if (msg.equals("")) return;
137 } else if (operation.equals("addme")) {
138 if (modifier.equals("displayonly")) {
139 msg = "added to list";
141 msg = do_addremme(qv, request, response, true);
142 } else if (operation.equals("delme")) {
143 if (modifier.equals("displayonly")) {
144 msg = "removed from list";
146 msg = do_addremme(qv, request, response, false);
147 } else if (operation.equals("displaylistinfo")) {
148 if (modifier.equals("displayonly")) {
149 msg = "display list characteristics";
151 msg = do_showlistinfo(qv, request, response);
152 } else if (operation.equals("updatelistinfo")) {
153 if (modifier.equals("displayonly")) {
154 msg = "update list characteristics";
156 msg = do_updatelistinfo(qv, request, response);
157 } else if (operation.equals("updatelistinfoconf")) {
158 if (modifier.equals("displayonly")) {
159 msg = "update list characteristics";
161 msg = do_updatelistinfoconf(qv, request, response);
163 sendError("Unimplemented Operation: " + (String)qv.get("operation"), response, true);
167 } catch (AuthenticationError e) {
168 msg = "<b>" + e.getMessage() + "</b><p>\r\n";
169 } catch (Exception e) {
170 msg += "<h1>Error during Processing</h1>\r\n";
171 msg += "Please try again later</HTML>\r\n";
176 DataOutputStream out = new DataOutputStream(response.getOutputStream());
177 response.setContentType("text/html");
178 if (!MOIRA_SERVER.equals("moira.mit.edu") && modifier.equals(""))
179 out.writeBytes("<font color=red>Moira Server: " + MOIRA_SERVER + "<br></font>\r\n");
182 } catch (Exception e) {
187 void sendError(String message, HttpServletResponse response, boolean showheader) {
190 msg = "<HTML><TITLE>Error</TITLE></HEAD><BODY BGCOLOR=#FFFFFF>\r\n";
191 msg += "<H1>Error</H1>\r\n";
193 msg += "<p></body></html>\r\n";
194 } else msg = "<b>" + message + "</b>";
196 DataOutputStream out = new DataOutputStream(response.getOutputStream());
197 response.setContentType("text/html");
200 } catch (Exception e) {
206 * Authenticate the user.
208 * @param request The HttpServlet request object
209 * @return String value of the Kerberos username who owns this request
210 * @exception AuthenticationError if authentication cannot be performed
212 String do_authentication(HttpServletRequest request) throws AuthenticationError {
214 // Attempt to obtain authenticated username from the session
216 HttpSession session = request.getSession(true);
217 String kname = (String) session.getValue("kname");
218 if (kname != null) return (kname);
220 String client_email = (String)request.getAttribute("org.apache.jserv.SSL_CLIENT_EMAIL");
221 if (client_email == null)
222 throw new AuthenticationError("You must use a Certificate to access this service.");
224 // Need to remove the @MIT.EDU portion
225 int i = client_email.indexOf('@');
227 throw new AuthenticationError("Malformed or non-MIT Certificate, shouldn't happen!");
228 if (!client_email.substring(i+1).equals("MIT.EDU"))
229 throw new AuthenticationError("Certificate Email Address must end in MIT.EDU");
230 kname = client_email.substring(0, i);
231 session.putValue("kname", kname);
235 String do_getmembers(Hashtable qv, HttpServletRequest request, HttpServletResponse response) throws AuthenticationError {
236 String kname = do_authentication(request);
239 String arg = (String) qv.get("list");
240 if (arg == null || arg.equals("")) {
241 msg = "<p>Argument is required</p>";
245 // Obtain the list of members stashed in the session object
246 // If this is the first call to do_getmembers for this list,
247 // we won't have one in which case we will obtain it from Moira
251 Member [] members = null;
252 HttpSession session = request.getSession(true);
253 if (session != null) {
254 list = (String)session.getValue("list");
255 if (list == null) list = "";
256 members = (Member []) session.getValue("members");
258 if (!list.equals(arg)) // Different list from argument, new session
259 members = null; // Force obtaining members from Moira
261 // Determine offset of list to view
263 String tmp = (String)qv.get("offset");
265 offset = Integer.parseInt(tmp);
267 boolean showall = false;
268 if (offset < 0) showall = true;
270 if (members == null) {
275 members = mc.get_members_of_list(arg);
276 mc.done(); // Done will disconnect
279 session.putValue("members", members);
280 session.putValue("list", arg);
281 } catch (MoiraException m) {
284 msg += m.getMessage();
285 msg += "</b></P>\r\n";
287 CharArrayWriter err = new CharArrayWriter();
288 PrintWriter perr = new PrintWriter(err);
289 m.printStackTrace(perr);
291 msg += err.toString();
294 } catch (Exception e) {
298 if (mc != null) mc.done();
302 // Do the actual display of the members
304 return("<b>No members for list " + arg + "</b>");
306 msg = "<table border=0>\r\n";
307 msg += "<tr><td> </td><td><table border=1 cellpadding=2>\r\n";
308 msg += "<tr><td colspan=2><b>Members of list: " + arg + "</b></td></tr>\r\n";
309 int len = offset + MAXDISPLAY;
310 if (len > members.length) len = members.length;
313 len = members.length;
315 for (int i = offset; i < len; i++) {
316 msg += "<tr><td>" + members[i].getMemberType() + "</td>";
317 msg += "<td>" + quote(members[i].getMemberId()) + "</td></tr>\r\n";
319 msg += "</table></td><td> </td></tr><tr>\r\n";
320 if ((offset > 0) && !showall) {
321 msg += "<td width=50><form method=POST action=\"" +
322 response.encodeUrl("showresult.jhtml") + "\">\r\n";
323 msg += "<input type=hidden name=operation value=getmembers>";
324 msg += "<input type=hidden name=offset value=\"" + (offset - MAXDISPLAY) + "\">\r\n";
325 msg += "<input type=hidden name=list value=\"" + arg + "\">";
326 msg += "<input type=submit value=\"Previous\"></form></td>\r\n";
328 msg += "<td width=50> </td>";
329 if (!showall && ((offset > 0) || (members.length > len))) {
330 msg += "<td width=50><form method=POST action=\"" +
331 response.encodeUrl("showresult.jhtml") + "\">\r\n";
332 msg += "<input type=hidden name=operation value=getmembers>";
333 msg += "<input type=hidden name=offset value=\"-1\">";
334 msg += "<input type=hidden name=list value=\"" + arg + "\">";
335 msg += "<input type=submit value=\"Show All\"></form></td>\r\n";
337 msg += "<td width=50> </td>";
338 if (members.length > len && !showall) {
339 msg += "<td width=50><form method=POST action=\"" +
340 response.encodeUrl("showresult.jhtml") + "\">\r\n";
341 msg += "<input type=hidden name=operation value=getmembers>";
342 msg += "<input type=hidden name=offset value=\"" + (offset + MAXDISPLAY) + "\">\r\n";
343 msg += "<input type=hidden name=list value=\"" + arg + "\">";
344 msg += "<input type=submit value=\"Next\"></form></td>\r\n";
346 msg += "<td width=50> </td>";
348 msg += "</table>\r\n";
352 void do_showform(Hashtable qv, HttpServletRequest request, HttpServletResponse response) {
353 String server = request.getServerName();
354 if (server.indexOf(".") == -1)
355 server += ".mit.edu"; // MIT Specific kludge!!! XXX
356 String msg = "<form method=post action=\"" + response.encodeUrl("https://" + server + ":445/moira/showresult.jhtml") + "\">";
358 DataOutputStream out = new DataOutputStream(response.getOutputStream());
359 response.setContentType("text/html");
362 } catch (Exception e) {
363 e.printStackTrace(); // Nothing else I can do here
367 void do_showurl(Hashtable qv, HttpServletRequest request, HttpServletResponse response) {
368 HttpSession session = request.getSession(true); // Sigh, have to create the session here if it doesn't already exist.
369 String msg = "<a href=\"" + response.encodeUrl((String)qv.get("url"))
372 DataOutputStream out = new DataOutputStream(response.getOutputStream());
373 response.setContentType("text/html");
376 } catch (Exception e) {
377 e.printStackTrace(); // Nothing else I can do here
381 String do_getlistinput(Hashtable qv, HttpServletRequest request, HttpServletResponse response) {
382 HttpSession session = request.getSession(false);
384 list = (String) qv.get("list");
385 if ((list == null) && (session != null)) list = (String) session.getValue("list");
386 if (list == null) list = "";
387 return("<input name=list value=\"" + list + "\" length=15 size=12 maxlength=40>\r\n");
390 String do_addmember(Hashtable qv, HttpServletRequest request, HttpServletResponse response) throws AuthenticationError {
392 String list = (String) qv.get("list");
393 if (list == null || list.equals("")) {
394 msg = "<p>Argument is required</p>";
398 String kname = do_authentication(request);
400 HttpSession session = request.getSession(true);
407 li = mc.get_list_info(list);
408 } catch (MoiraException m) {
409 msg += "Error getting list info: " + m.getMessage();
411 CharArrayWriter err = new CharArrayWriter();
412 PrintWriter perr = new PrintWriter(err);
413 m.printStackTrace(perr);
415 msg += err.toString();
419 if (mc != null) mc.done();
422 String list_description = "";
423 if (li != null) list_description = descript(li.description);
425 msg += "<form method=post action=\"" +
426 response.encodeUrl("showresult.jhtml") + "\">\r\n";
427 msg += " <table border=1 cellpadding=2>\r\n <tr> \r\n <td colspan=2> \r\n <p><b>Add member(s) to list " + list + "<br>\r\n</b>Description: " + list_description + "<br>\r\n (you may enter more than one member of the same type by listing \r\n each member on its own line)</p>\r\n </td>\r\n </tr>\r\n <tr> \r\n <td> \r\n <select name=type>\r\n <option value=\"USER\" selected>user</option>\r\n <option value=\"STRING\">string</option>\r\n <option value=\"LIST\">list</option>\r\n </select>\r\n </td>\r\n <td> \r\n <textarea name=\"member\" cols=\"20\" rows=\"4\"></textarea>\r\n </td>\r\n </tr>\r\n </table>\r\n";
428 msg += "<input type=hidden name=list value=\"" + list + "\">\r\n";
429 msg += "<input type=hidden name=operation value=addfinal>\r\n";
430 msg += "<input type=submit name=submit value=\"Add Member(s)\">\r\n";
431 session.putValue("list", list);
432 session.removeValue("members"); // In case we had them from old list
436 String do_editme(Hashtable qv, HttpServletRequest request, HttpServletResponse response) throws AuthenticationError {
438 String arg = (String) qv.get("list");
439 if (arg == null || arg.equals("")) {
440 msg = "<p>Argument is required</p>";
444 String kname = do_authentication(request);
446 HttpSession session = request.getSession(true);
449 boolean found = false;
450 boolean sublists = false;
451 Member [] members = null;
455 members = mc.get_members_of_list(arg);
456 if (members != null) {
457 for (int i = 0; i < members.length; i++) {
458 if (members[i].getMemberId().equals(kname)) {
462 if (members[i].getMemberType().equals("LIST")) {
468 } catch (MoiraException m) {
471 msg += m.getMessage();
472 msg += "</b></P>\r\n";
474 CharArrayWriter err = new CharArrayWriter();
475 PrintWriter perr = new PrintWriter(err);
476 m.printStackTrace(perr);
478 msg += err.toString();
481 } catch (Exception e) {
485 if (mc != null) mc.done();
487 msg = "You are " + (found ? "" : "not ") + "a member of the list <b>" + arg + "</b>.<br>\r\n";
488 if (!found && sublists)
489 msg += "Note: You may be a member of a sublist of <b>" + arg + "</b>. You may wish to check the sublists by using the <b>show list members</b> function.<br>\r\n";
490 msg += "<form method=POST action=\"" + response.encodeUrl("showresult.jhtml") + "\">\r\n";
491 msg += "<input type=hidden name=list value=\"" + arg + "\">\r\n";
493 msg += "<input type=hidden name=operation value=delme>\r\n";
495 msg += "<input type=hidden name=operation value=addme>\r\n";
496 msg += "<input name=submit type=submit value=\"" + (found ? "Remove Me" : "Add Me") + "\">\r\n";
498 if (members != null) {
499 session.putValue("list", arg);
500 session.putValue("members", members);
505 String do_addremme(Hashtable qv, HttpServletRequest request, HttpServletResponse response, boolean add) throws AuthenticationError {
506 HttpSession session = request.getSession(false); // Better be one
507 if (session == null) {
508 return("<p>Could not proceed, has it been 30 minutes since you last interaction. If so, back up and try again.</p>");
511 String kname = do_authentication(request);
514 String listname = (String) session.getValue("list");
515 if (listname == null) {
516 return("<p>Could not find list name (shouldn't happen).</p>");
523 mc.delete_member_from_list(listname, "USER", kname);
525 mc.add_member_to_list(listname, "USER", kname);
526 } catch (MoiraException m) {
527 msg = "<p><b>Unable to " + (add? "add" : "remove") + " you " + (add? "to" : "from") + " the " + listname + " list.<br>\r\n";
528 msg += "The error from Moira was: " + m.getMessage() + "</b></p>";
530 CharArrayWriter err = new CharArrayWriter();
531 PrintWriter perr = new PrintWriter(err);
532 m.printStackTrace(perr);
534 msg += err.toString();
538 if (mc != null) mc.done();
540 if (add) msg = "You have been added to the <b>" + listname + "</b> list.";
541 else msg = "You have been removed from the <b>" + listname + "</b> list.";
545 String do_removemembers(Hashtable qv, HttpServletRequest request, HttpServletResponse response) throws AuthenticationError {
546 Delmember [] del = null;
548 String arg = (String) qv.get("list");
549 if (arg == null || arg.equals("")) {
550 msg = "<p>Argument is required</p>";
554 String kname = do_authentication(request);
556 HttpSession session = request.getSession(true);
562 Member [] members = mc.get_members_of_list(arg);
563 if (members == null) {
564 return("<P><b>No such list or empty list</b></p>.");
566 del = new Delmember[members.length];
567 for (int i = 0; i < members.length; i++) {
568 del[i] = new Delmember(members[i]);
572 session.putValue("list", arg);
573 session.removeValue("members"); // In case left over from previous call
574 session.putValue("delmembers", del);
575 } catch (MoiraException m) {
578 msg += m.getMessage();
579 msg += "</b></P>\r\n";
581 CharArrayWriter err = new CharArrayWriter();
582 PrintWriter perr = new PrintWriter(err);
583 m.printStackTrace(perr);
585 msg += err.toString();
587 } catch (Exception e) {
591 if (mc != null) mc.done();
593 return (do_remdisplay(qv, request, response, del, 0));
596 String do_remdisplay(Hashtable qv, HttpServletRequest request, HttpServletResponse response, Delmember [] del, int offset) {
597 // Offset = -1 means show everybody
598 boolean showall = false;
603 String msg = "<h2>Select Members to Delete</h2>\r\n";
604 if (((offset > 0) || del.length > MAXDISPLAY) && !showall)
605 msg += "<p><font color=red>Note: Selections are remembered when you select the \"Previous\" and \"Next Buttons\".</font></p>\r\n";
606 msg += "<form method=POST action=\"" +
607 response.encodeUrl("showresult.jhtml") + "\">\r\n";
608 msg += "<table border=0><tr><td></td><td>\r\n";
609 msg += "<table border=1 cellpadding=2>\r\n";
611 if (showall) len = del.length;
612 else len = offset + MAXDISPLAY;
613 if (del.length < len)
615 for (int i = offset; i < len; i++) {
616 msg += "<tr><td><input type=checkbox name=selected value=\" " + i + "\"";
617 if (del[i].marked) msg += " checked";
618 msg += "></td><td>" + del[i].member.getMemberType() + "</td>";
619 msg += "<td>" + quote(del[i].member.getMemberId()) + "</td></tr>\r\n";
621 msg += "</table></td>\r\n";
622 msg += "<td><input type=hidden name=operation value=delmembers></td></tr>\r\n";
624 msg += "<td><input type=submit name=dodel value=\"Previous\"></td>";
626 msg += "<td width=50> </td>";
627 if (!showall && (del.length > MAXDISPLAY))
628 msg += "<td><input type=submit name=dodel value=\"Show All\"></td>";
629 else msg += "<td width=50> </td>";
630 if (((offset + MAXDISPLAY) < del.length) && !showall)
631 msg += "<td><input type=submit name=dodel value=\"Next\"></td></tr>\r\n";
632 else msg += "<td width=50> </td></tr>\r\n";
633 msg += "<tr><td></td><td><input type=submit name=dodel value=\"Delete Selected\"></td><td></td></tr></table></form>\r\n";
634 HttpSession session = request.getSession(false);
635 session.putValue("offset", new Integer(offset));
640 String do_delmember(Hashtable qv, HttpServletRequest request, HttpServletResponse response) throws AuthenticationError {
641 String kname = do_authentication(request);
643 HttpSession session = request.getSession(false); // Better be one
644 if (session == null) {
645 return("<p>Could not proceed, has it been 30 minutes since you last interaction. If so, back up and try again.</p>");
648 Delmember [] del = (Delmember []) session.getValue("delmembers");
650 return("<p>Could not proceed, membership list doesn't exist, this should not happen!</p>");
651 Integer OffsetO = (Integer) session.getValue("offset");
652 if (OffsetO == null) { // Hmmm....
653 OffsetO = new Integer(0);
656 int offset = OffsetO.intValue();
658 String dodel = (String)qv.get("dodel"); // This is the submit button
660 return("<p>Could not proceed, submit button incorrect, shouldn't happen.</p>");
662 // Process the selections on this form
664 int last = offset + MAXDISPLAY;
665 if (last > del.length) last = del.length;
666 for (int i = offset; i < last; i++) // Clear marked bits for displayed
667 del[i].marked = false; // entries
669 String selected = (String)qv.get("selected");
670 if (selected == null) selected = ""; // None selected
672 StreamTokenizer tk = new StreamTokenizer(new StringReader(selected));
675 while (tk.nextToken() != StreamTokenizer.TT_EOF) {
676 if (tk.ttype != StreamTokenizer.TT_NUMBER) continue;
677 int v = (int) tk.nval;
678 del[v].marked = true;
680 } catch (IOException e) {
682 return("<p>Exception while processing...</p>");
685 if (dodel.equals("Next"))
686 return(do_remdisplay(qv, request, response, del, offset + MAXDISPLAY));
687 if (dodel.equals("Previous"))
688 return(do_remdisplay(qv, request, response, del, offset - MAXDISPLAY));
689 if (dodel.equals("Show All"))
690 return(do_remdisplay(qv, request, response, del, -1));
691 if (!dodel.equals("Delete Selected"))
692 return("<p>Cannot proceed, bad submit value, should not happen</p>");
693 // At this point we are going to display a list of who will be
694 // deleted and offer a confirmation.
696 String listname = (String) session.getValue("list");
697 if (listname == null) {
698 return("<p>Could not find list name (shouldn't happen).</p>");
701 // Check to see if anyone will be removed
703 boolean havesome = false;
704 for (int i = 0; i < del.length; i++) {
711 return("No members selected to be removed");
713 // Some will be, so throw up confirmation dialog
715 String msg = "<h2>Please Confirm Deletion of:</h2>\r\n";
716 msg += "<table border=1 cellpadding=2>\r\n";
717 for (int i = 0; i < del.length; i++) {
719 msg += "<tr><td>" + del[i].member.getMemberType() + "</td>";
720 msg += "<td>" + quote(del[i].member.getMemberId()) + "</td></tr>\r\n";
723 msg += "</table>\r\n";
724 msg += "<form method=POST action=\"" +
725 response.encodeUrl("showresult.jhtml") + "\">\r\n";
726 msg += "<input type=hidden name=operation value=delconfirm>\r\n";
727 msg += "<input type=submit value=\"Confirm Deletion\">\r\n";
728 msg += "</form>\r\n";
732 String do_delconfirm(Hashtable qv, HttpServletRequest request, HttpServletResponse response) throws AuthenticationError {
734 String kname = do_authentication(request);
738 HttpSession session = request.getSession(false); // Better be one
739 if (session == null) {
740 return("<p>Could not proceed, has it been 30 minutes since you last interaction. If so, back up and try again.</p>");
743 String listname = (String)session.getValue("list");
745 Delmember [] del = (Delmember []) session.getValue("delmembers");
747 return("<p>Cannot proceed, nothing to delete, shouldn't happen!</p>");
749 Vector problems = new Vector();
750 Vector success = new Vector();
756 for (int i = 0; i < del.length; i++) {
759 mc.delete_member_from_list(listname, del[i].member.getMemberType(), del[i].member.getMemberId());
760 success.addElement(del[i].member);
762 } catch (MoiraException m) {
763 problems.addElement("<tr><td>" + quote(del[i].member.getMemberId()) + "</td><td>" + m.getMessage() + "</td></tr>\r\n");
766 } catch (MoiraException m) {
767 msg = "<p><b>" + m.getMessage() + "</b></p>";
769 CharArrayWriter err = new CharArrayWriter();
770 PrintWriter perr = new PrintWriter(err);
771 m.printStackTrace(perr);
773 msg += err.toString();
777 if (mc != null) mc.done();
781 if (success.size() > 0) {
782 msg += "<h2>Deleted the following:</h2>\r\n";
783 msg += "<table border=1 cellpadding=2>\r\n";
784 for (int i = 0; i < success.size(); i++) {
785 msg += "<tr><td>" + quote(((Member)success.elementAt(i)).getMemberId()) + "</td></tr>\r\n";
787 msg += "</table>\r\n";
789 if (problems.size() > 0) {
790 msg += "<p><h2>There were difficulties removing:</h2>\r\n";
791 msg += "<table border=1 cellpadding=2>\r\n";
792 for (int i = 0; i < problems.size(); i++) {
793 msg += (String)problems.elementAt(i);
795 msg += "</table>\r\n";
801 String do_showlistinfo(Hashtable qv, HttpServletRequest request, HttpServletResponse response) throws AuthenticationError {
803 String kname = do_authentication(request);
805 String list = (String)qv.get("list");
807 if (list == null || list.equals("")) {
808 return("Hmmm, no list specified");
811 HttpSession session = request.getSession(true);
819 li = mc.get_list_info(list);
820 } catch (MoiraException m) {
821 msg += "Error getting list info: " + m.getMessage();
823 CharArrayWriter err = new CharArrayWriter();
824 PrintWriter perr = new PrintWriter(err);
825 m.printStackTrace(perr);
827 msg += err.toString();
831 if (mc != null) mc.done();
834 return("Did not find list info.");
836 msg += "<b>List: " + list + "</b><br>\r\n";
837 msg += "Description: " + descript(li.description) + "<br>\r\n";
839 msg += "This list is a mailing list.<br>\r\n";
841 msg += "This list is a Group and its ID number is " + li.gid + ".<br>\r\n";
842 msg += "The Administrator of this list is the " + li.ace_type + ": " + li.ace_name + ".<br>\r\n";
843 msg += "This list is: " + mkflags(li) + ".<br>\r\n";
844 msg += "Last modification by " + li.moduser + " at " + df.format(li.modtime) + " with " + li.modwith + ".<br>\r\n";
848 String do_updatelistinfo(Hashtable qv, HttpServletRequest request, HttpServletResponse response) throws AuthenticationError {
850 String kname = do_authentication(request);
852 String list = (String)qv.get("list");
854 if (list == null || list.equals("")) {
855 return("Hmmm, no list specified");
858 HttpSession session = request.getSession(true);
866 li = mc.get_list_info(list);
867 } catch (MoiraException m) {
868 msg += "Error getting list info: " + m.getMessage();
870 CharArrayWriter err = new CharArrayWriter();
871 PrintWriter perr = new PrintWriter(err);
872 m.printStackTrace(perr);
874 msg += err.toString();
878 if (mc != null) mc.done();
881 return("Did not find list info.");
884 session.putValue("listinfo", li); // Save for the confirmation call
885 session.putValue("list", list); // Save for side bar update
886 session.removeValue("members"); // In case left over...
888 msg += "<form method=POST action=\"" +
889 response.encodeUrl("showresult.jhtml") + "\">\r\n";
890 msg += "<input type=hidden name=operation value=updatelistinfoconf>\r\n";
891 msg += "<b>Update characteristics of list " + list + "</b><p>\r\n";
892 msg += "Is this list a maillist? <input type=radio name=maillist value=1 "
893 + (li.maillist ? "checked" : "") + ">Yes <input type=radio name=maillist value=0 " + (li.maillist ? "" : "checked") + "> No<br>\r\n";
894 // Note: We don't update group information here
896 msg += "Is this list a public list? <input type=radio name=public value=1 "
897 + (li.bpublic ? "checked" : "") + ">Yes <input type=radio name=public value=0 " + (li.bpublic ? "" : "checked") + "> No<br>\r\n";
898 msg += "Is this list a hidden list? <input type=radio name=hidden value=1 "
899 + (li.hidden ? "checked" : "") + ">Yes <input type=radio name=hidden value=0 " + (li.hidden ? "" : "checked") + "> No<p>\r\n";
901 msg += "The Administrator for this list is<br>\r\n";
902 msg += "<select name=ace_type><option value=\"USER\"" +
903 (li.ace_type.equals("USER") ? " selected" : "") + ">user</option>" +
904 "<option value=\"LIST\"" + (li.ace_type.equals("LIST") ? " selected" : "") + ">list</option>" +
905 "<option value=\"KERBEROS\"" + (li.ace_type.equals("KERBEROS") ? " selected" : "") + ">kerberos</option></select>";
906 msg += " <input name=ace_name value=\"" + li.ace_name + "\"><br>\r\n";
907 msg += "Description:<br>\r\n";
908 msg += "<textarea name=description cols=60 rows=3>" + li.description + "</textarea><br>\r\n";
909 msg += "<input type=submit value=\"Make Update\"></form>\r\n";
913 String do_updatelistinfoconf(Hashtable qv, HttpServletRequest request, HttpServletResponse response) throws AuthenticationError {
915 String kname = do_authentication(request);
916 HttpSession session = request.getSession(false); // Better be one
917 if (session == null) {
918 return("<p>Could not proceed, has it been 30 minutes since you last interaction. If so, back up and try again.</p>");
921 ListInfo li = (ListInfo)session.getValue("listinfo");
923 return("<p>Could not proceed, could not find orignial list info, should not happen!</p>");
926 String tmp = (String)qv.get("description");
927 if (tmp != null) li.description = tmp;
928 tmp = (String)qv.get("maillist");
930 if (tmp.equals("1")) li.maillist = true;
931 else li.maillist = false;
933 tmp = (String)qv.get("public");
935 if (tmp.equals("1")) li.bpublic = true;
936 else li.bpublic = false;
938 tmp = (String)qv.get("hidden");
940 if (tmp.equals("1")) li.hidden = true;
941 else li.hidden = false;
943 tmp = (String)qv.get("ace_type");
947 tmp = (String)qv.get("ace_name");
955 mc.update_list_info(li.name, li);
956 } catch (MoiraException e) {
958 if (e.getMessage().startsWith("No such list")) {
959 msg = "<p><b>Error updating " + li.name + ".<br>\r\n";
960 msg += "The list you specified as administrator does not exist.</p>\r\n";
961 } else if(e.getMessage().startsWith("No such user")) {
962 msg = "<p><b>Error updating " + li.name + ".<br>\r\n";
963 msg += "The user you specified as administrator is not known to Moira.</p>\r\n";
965 msg = "<p><b>Error during update of " + li.name + ": " + e.getMessage() + "</b></p>";
967 CharArrayWriter err = new CharArrayWriter();
968 PrintWriter perr = new PrintWriter(err);
969 e.printStackTrace(perr);
971 msg += err.toString();
975 if (mc != null) mc.done();
977 String msg = "<b>Update of " + li.name + " succeeded</b><p>\r\n";
978 qv.put("list", li.name);
979 msg += do_showlistinfo(qv, request, response);
983 String do_addfinal(Hashtable qv, HttpServletRequest request, HttpServletResponse response) throws AuthenticationError {
984 HttpSession session = request.getSession(false); // Better be one
985 if (session == null) {
986 return("<p>Could not proceed, has it been 30 minutes since you last interaction. If so, back up and try again.</p>");
989 String kname = do_authentication(request);
991 String listname = (String) session.getValue("list");
992 if (listname == null) {
993 return("<p>Unable to find list name! (shouldn't happen).</p>");
996 String member = (String)qv.get("member");
997 String type = (String)qv.get("type");
998 if (member == null || type == null || member.equals("")) {
999 return("<p>No names selected to be added!</p>");
1002 StreamTokenizer tk = null;
1003 msg += "<table border=1 cellpadding=2>\r\n";
1004 boolean addheader = false;
1005 Vector warnings = new Vector();
1006 Vector problems = new Vector();
1010 tk = new StreamTokenizer(new StringReader(member));
1013 tk.wordChars('@', '@');
1014 tk.wordChars('0', '9');
1015 tk.wordChars('_', '_');
1016 while (tk.nextToken() != StreamTokenizer.TT_EOF) {
1017 if (tk.ttype != StreamTokenizer.TT_WORD) continue;
1020 // Pre-process user input
1021 String [] user = canonicalize(tk.sval, type);
1023 mc.add_member_to_list(listname, user[1], user[0]);
1025 msg += "<tr><td>Added to list</td></tr>\r\n";
1028 msg += "<tr><td>" + user[1] + "</td><td>" + user[0] + "</td></tr>\r\n";
1029 if (user.length > 2)
1030 warnings.addElement(user[2]);
1031 } catch (MoiraException e) {
1032 String err = "<tr><td>" + tk.sval + "</td><td>" + e.getMessage() + "</td></tr>\r\n";
1033 problems.addElement(err);
1036 if (!addheader) // We didn't seem to be able to add anyone
1037 msg += "<tr><td>No one added!</td></tr>\r\n";
1038 msg += "</table>\r\n";
1041 } catch (MoiraException e) {
1043 msg = "<p><b>Error adding " + tk.sval + ": " + e.getMessage() + "</b></p>";
1045 msg = "<p><b>Error during add: " + e.getMessage() + "</b></p>";
1047 CharArrayWriter err = new CharArrayWriter();
1048 PrintWriter perr = new PrintWriter(err);
1049 e.printStackTrace(perr);
1051 msg += err.toString();
1054 } catch (IOException e) {
1055 e.printStackTrace(); // Shouldn't happen
1057 if (mc != null) mc.done();
1059 if (problems.size() != 0) {
1060 msg += "<p>There were difficulties adding the following users:<br>\r\n";
1061 msg += "<table border=1 cellpadding=2>\r\n";
1062 for (int i = 0; i < problems.size(); i++)
1063 msg += problems.elementAt(i);
1064 msg += "</table>\r\n";
1066 if (warnings.size() != 0) {
1067 msg += "<p>The following warnings were generated:<br>\r\n";
1068 msg += "<table border=1 cellpadding=2>\r\n";
1069 for (int i = 0; i < warnings.size(); i++)
1070 msg += "<tr><td>" + warnings.elementAt(i) + "</td></tr>\r\n";
1071 msg += "</table>\r\n";
1076 String getfile(String operation) {
1077 ResourceBundle bd = null;
1079 bd = ResourceBundle.getBundle("mit.moira.FileParts");
1080 } catch (java.util.MissingResourceException e) {
1081 return("Cannot find FileParts.properties");
1083 if (bd == null) return("Cannot find FileParts.properties!");
1084 String filename = null;
1086 filename = bd.getString(operation);
1087 } catch (java.util.MissingResourceException e) {
1088 return("Cannot find file for operation: " + operation);
1090 if (filename == null) {
1091 return("Cannot find file for operation: " + operation);
1093 File file = new File(filename);
1094 if (!file.isFile()) return("Cannot file file: " + filename);
1095 long filemodtime = file.lastModified();
1096 Long cachemodtime = (Long) FileTimes.get(filename);
1097 if (cachemodtime == null || filemodtime > cachemodtime.longValue()) {
1098 // Need to fetch the file into the cache
1099 byte [] buffer = null;
1101 BufferedInputStream input = new BufferedInputStream(new FileInputStream(filename));
1102 buffer = new byte[input.available()];
1105 } catch (FileNotFoundException f) {
1106 // Should never happen given check above
1107 } catch (IOException e) {
1108 return("IO Error Reading: " + filename);
1110 String data = new String(buffer);
1111 data += "\r\n<!-- FileName: " + filename + "-->\r\n";
1112 FileTimes.put(filename, new Long(filemodtime));
1113 FileParts.put(filename, data);
1116 return ((String)FileParts.get(filename));
1120 String mkflags(ListInfo li) {
1134 retval = "private and " + retval;
1138 retval = "private, " + retval;
1148 retval = "active and " + retval;
1152 retval = "active, " + retval;
1159 * pre-process user input. Mostly this catches cases where the
1160 * incorrect type is used to add someone to a list.
1162 * @param user String or Userid being proposed for an add
1163 * @param type Either LIST,STRING or USER
1164 * @return an array of elements. The first is the user portion followed by the type and an optional warning message.
1167 private String [] canonicalize(String user, String type) throws MoiraException {
1169 String [] retval = null;
1170 if (type.equals("STRING")) {
1171 i = user.indexOf('@');
1173 String host = user.substring(i + 1);
1174 if (host.equalsIgnoreCase("mit.edu")) {
1175 retval = new String[3];
1176 retval[0] = user.substring(0, i);
1178 retval[2] = "Converted " + user + " to userid " + retval[0];
1182 retval = new String[2];
1184 retval[1] = "STRING";
1186 } else { // No @ sign
1187 throw new MoiraException("STRING (mailing list entries) must have an \'@\' in them!");
1189 } else if (type.equals("USER")) {
1190 i = user.indexOf('@');
1192 String host = user.substring(i + 1);
1193 if (host.equalsIgnoreCase("mit.edu")) {
1194 retval = new String[3];
1195 retval[0] = user.substring(0, i);
1197 retval[2] = "Converted " + user + " to userid " + retval[0];
1200 throw new MoiraException("USER types must not have \'@\'s in them!");
1202 retval = new String[2];
1206 } else if (type.equals("LIST")) {
1207 i = user.indexOf('@');
1208 if (i == -1) { // No '@' sign, just process normally
1209 retval = new String[2];
1214 String host = user.substring(i + 1);
1215 if (host.equalsIgnoreCase("mit.edu")) { // trim mit.edu
1216 retval = new String[3];
1217 retval[0] = user.substring(0, i);
1219 retval[2] = "Converted " + user + " to list named " + retval[0];
1222 throw new MoiraException("LIST types may not contain \'@\'s in them!");
1224 } else { // Just pass through everything else for now
1225 retval = new String[2];
1233 * Remove <SCRIPT> tags from input String
1235 * @param input String to check out
1236 * @return String with <SCRIPT> tag removed
1238 private String descript(String input) {
1239 String lc = input.toLowerCase();
1240 int i = lc.indexOf("<scri");
1241 int j = lc.lastIndexOf("</scri");
1242 int len = input.length();
1243 if (i == -1) return (input); // Nothing to do.
1244 else if (j == -1) { // No closing script tag
1245 return (input.substring(0, i));
1247 return (input.substring(0, i) + input.substring(j));
1252 * Shutdown the servlet
1255 public void destroy() {
1262 * Connect to the Moira Server. Special case the error KE_RD_AP_BADD.
1263 * This error occurs if the tickets we have contain the wrong IP address.
1264 * This can happen if we are on a multi-homed system. If this happens,
1265 * get new tickets and try again. If we exceed the loop count, throw
1266 * an exception (sigh).
1268 * @return A Moira Connection Object
1269 * @exception MoiraException on any error
1271 protected Moira connect() throws MoiraException {
1272 Moira retval = null;
1273 boolean error = true;
1276 while (count++ < 10) { // Got to stop at some point!
1277 retval = Moira.getInstance(MOIRA_SERVER);
1282 return (retval); // No exception, return. yeah!
1283 } catch (MoiraException m) {
1284 if ((m.getCode() != KE_RD_AP_BADD) || (count > 8)) {
1285 throw m; // Re-throw if not the error we expect or we are looping
1288 if (retval != null) {
1292 System.err.println("MoiraServlet: Forced Renewal...");
1293 kt.renew(); // Renew tickets
1295 // Fell through, count exceeded
1296 throw new MoiraException("Cannot authenticate successfully to Moira");
1298 if (error && (retval != null)) retval.done();
1302 public static String quote(String value) {
1303 if (value.indexOf('<') == -1 &&
1304 value.indexOf('>') == -1) return (value); // Nothing to quote
1305 StringBuffer buf = new StringBuffer(value.length() + 10);
1306 for (int i = 0; i < value.length(); i++) {
1307 char c = value.charAt(i);
1308 if (c != '<' && c != '>') buf.append(c);
1310 if (c == '<') buf.append("<");
1311 if (c == '>') buf.append(">");
1314 return (new String(buf));
1319 boolean marked = false;
1320 Member member = null;
1322 Delmember(Member m) {