// PasswordEditorFrame.java
// $Id: PasswordEditorFrame.java,v 1.5 1998/03/18 10:05:19 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.jigsaw.resources;

import org.w3c.tools.resources.*;
import org.w3c.www.http.HTTP;
import org.w3c.jigsaw.http.*;
import org.w3c.jigsaw.frames.*;
import org.w3c.jigsaw.auth.*;
import org.w3c.jigsaw.html.*;
import org.w3c.jigsaw.forms.*;

public class PasswordEditorFrame extends PostableFrame {

  /**
   * Attribute index - The name of the realm to edit.
   */
  protected static int ATTR_REALM = -1;

  static {
    Class     c = null;
    Attribute a = null;

    try {
      c = Class.forName("org.w3c.jigsaw.resources.PasswordEditorFrame");
    } catch (Exception ex) {
      ex.printStackTrace();
      System.exit(1);
    }
    // Register the name of the realm to edit
    a = new StringAttribute("realm"
			    , null
			    , Attribute.EDITABLE);
    ATTR_REALM = AttributeRegistry.registerAttribute(c, a);
  }

  /**
   * The loaded realm, when loaded.
   */
  ResourceReference rr_realm = null;

  /**
   * Get the name of the realm to edit.
   * @return The name of the realm to edit, as a String.
   */

  public String getRealm() {
    return getString(ATTR_REALM, null);
  }

  protected synchronized boolean changePassword(String username,
						String oldpassword,
						String newpassword) 
  {
    // Get a handle on the authentication realm:
    if ( rr_realm == null ) {
      // Load the realm from the auth realm catalog:
      RealmsCatalog c = ((httpd)getServer()).getRealmsCatalog();
      String        r = getRealm();
      if ( r == null ) {
	getServer().errlog(this, "attribute realm no initialized.");
	return false;
      }
      // Really, load the store now:
      
      rr_realm = c.loadRealm(r);
    }
    // If we did get the realm:
    if ( rr_realm != null ) {
      try {
	AuthRealm realm = (AuthRealm) rr_realm.lock();
	// Get the user:
	ResourceReference rr_user = realm.loadUser(username);
	if (rr_user == null)
	  return false;
	try {
	  AuthUser user = (AuthUser)rr_user.lock();
	  // Check the old password first:
	  String passwd = user.getPassword();
	  if ((passwd == null) || ! passwd.equals(oldpassword))
	    return false;
	  // Set the new password:
	  user.setPassword(newpassword);
	  return true;
	} catch (InvalidResourceException ex) {
	  return false;
	} finally {
	  rr_user.unlock();
	}
      } catch (InvalidResourceException ex) {
	return false;
      } finally {
	rr_realm.unlock();
      }
    }
    return false;
  }

  protected HtmlGenerator generateForm(String msg) {
    // Create the HTML and set title:
    HtmlGenerator g = new HtmlGenerator("Password editor for "+getRealm());
    // Add style link
    addStyleSheet(g);
    g.append("<h1>Password editor for "
	     , getRealm()
	     , "</h1>");
    // If some message is available, dump it:
    if ( msg != null ) 
      g.append("<hr>", msg, "</hr>");
    // And then display the form:
    g.append("<form method=\"POST\" action=\"",
	     getURLPath(),
	     "\">");
    g.append("<table width=\"100%\">");
    g.append("<tr><th align=right>username");
    g.append("<th align=left><input type=\"text\" name=\"username\">");
    g.append("<tr><th align=right>old password");
    g.append("<th align=left><input type=\"password\" name=\"opasswd\">");
    g.append("<tr><th align=right>new password");
    g.append("<th align=left><input type=\"password\" name=\"npasswd\">");
    g.append("<tr><th align=right>confirm");
    g.append("<th align=left><input type=\"password\" name=\"cpasswd\">");
    g.append("</table>");
    g.append("<input type=\"submit\" value=\"Change\">");
    g.append("</form>");
    return g;
  }

  protected final HtmlGenerator generateForm() {
    return generateForm(null);
  }

  /**
   * Handle a get request on the password editor.
   * Dump a form suitable for editing a user entry.
   * @param request The request to handle.
   * @return An HTTP Reply instance.
   */

  public Reply get(Request request) 
    throws ProtocolException, NotAProtocolException
  {
    Reply reply = createDefaultReply(request, HTTP.OK);
    reply.setStream(generateForm());
    return reply;
  }

  /**
   * Handle a post request.
   * Do change the password, when possible.
   * @param request The request to handle.
   * @param data The form decoded data.
   * @return An HTTP Reply instance.
   */

  public Reply handle(Request request, URLDecoder data) 
    throws ProtocolException 
  {
    String username = data.getValue("username");
    String opasswd  = data.getValue("opasswd");
    String npasswd  = data.getValue("npasswd");
    String cpasswd  = data.getValue("cpasswd");
    HtmlGenerator g = null;
    if ((username == null)
	|| (opasswd == null)
	|| (npasswd == null)
	|| (cpasswd == null)) {
      // Check that all values are available:
      if (username == null)
	g = generateForm("Fill in <em>all</em> the fields.");
      else
	g = generateForm("Hey, "+username+", could you feel in "
			 + "<em>all</em> the fields please.");
    } else 	if ( ! npasswd.equals(cpasswd) ) {
      // Check that new and confirmed password are the same:
      g = generateForm("New and confirmed password don't "
		       + " match, try again "
		       + ((username == null) ? "." : (username+".")));
    } else if ( changePassword(username, opasswd, npasswd) ) {
      // Run the change:
      g = new HtmlGenerator("Password now changed.");
      // Add style link
      addStyleSheet(g);
      g.append("<h1>Your password has been changed</h1>");
      g.append("<p>Operation succeeded, have fun !");
    } else {
      // Changing the password failed, don't provide explanations:
      g = new HtmlGenerator("Password change failed");
      // Add style link
      addStyleSheet(g);
      g.append("<h1>Changing the password failed</h1>");
      g.append("You were not allowed to change the password for user \""
	       , username
	       , "\".");
    }
    // We always succeed, that's cool:
    Reply reply = createDefaultReply(request, HTTP.OK);
    reply.setStream(g);
    return reply;
  }

}
