/*
 * @(#)GSSException.java	1.7 01/12/03
 *
 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package org.ietf.jgss;

/**
 * This exception is thrown whenever a GSS-API error occurs, including
 * any mechanism specific error.  It may contain both the major and the
 * minor GSS-API status codes.  Major error codes are those defined at the
 * GSS-API level in this class. Minor error codes are mechanism specific
 * error codes that can provide additional information. The underlying
 * mechanism implementation is responsible for setting appropriate minor
 * status codes when throwing this exception.  Aside from delivering the
 * numeric error codes to the caller, this class performs the mapping from
 * their numeric values to textual representations. <p>
 *
 * @author Mayank Upadhyay
 * @version 1.7, 12/03/01
 * @since 1.4
 */
public class GSSException extends Exception {

    /** 
     * Channel bindings mismatch.
     */
    public static final int BAD_BINDINGS = 1; //start with 1

    /** 
     * Unsupported mechanism requested.
     */
    public static final int BAD_MECH = 2;

    /** 
     * Invalid name provided.
     */
    public static final int BAD_NAME = 3;

    /** 
     * Name of unsupported type provided.
     */
    public static final int BAD_NAMETYPE = 4;

    /** 
     * Invalid status code.
     */
    /*
     * This is meant to be thrown by display_status which displays
     * major/minor status when an incorrect status type is passed in to it!
     */
    public static final int BAD_STATUS = 5;

    /** 
     * Token had invalid integrity check.
     */
    public static final int BAD_MIC = 6;

    /** 
     * Security context expired.
     */
    public static final int CONTEXT_EXPIRED = 7;

    /** 
     * Expired credentials.
     */
    public static final int CREDENTIALS_EXPIRED  = 8;

    /** 
     * Defective credentials.
     * 
     */
    public static final int DEFECTIVE_CREDENTIAL = 9;

    /** 
     * Defective token.
     * 
     */
    public static final int DEFECTIVE_TOKEN = 10;

    /** 
     * General failure, unspecified at GSS-API level.
     */
    public static final int FAILURE = 11;

    /** 
     * Invalid security context.
     */
    public static final int NO_CONTEXT = 12;

    /** 
     * Invalid credentials.
     */
    public static final int NO_CRED = 13;
        
    /** 
     * Unsupported QOP value.
     */
    public static final int BAD_QOP = 14;

    /** 
     * Operation unauthorized.
     */
    public static final int UNAUTHORIZED = 15;
    
    /** 
     * Operation unavailable.
     */
    public static final int UNAVAILABLE = 16;

    /** 
     * Duplicate credential element requested.
     */
    public static final int DUPLICATE_ELEMENT = 17;

    /** 
     * Name contains multi-mechanism elements.
     */
    public static final int NAME_NOT_MN = 18;

    /** 
     * The token was a duplicate of an earlier token.
     * This is a fatal error code that may occur during
     * context establishment.  It is not used to indicate
     * supplementary status values. The MessageProp object is
     * used for that purpose.
     */
    public static final int DUPLICATE_TOKEN = 19;

    /** 
     * The token's validity period has expired.  This is a
     * fatal error code that may occur during context establishment.
     * It is not used to indicate supplementary status values.
     * The MessageProp object is used for that purpose.
     */
    public static final int OLD_TOKEN = 20;


    /** 
     * A later token has already been processed.  This is a
     * fatal error code that may occur during context establishment.
     * It is not used to indicate supplementary status values.
     * The MessageProp object is used for that purpose.
     */
    public static final int UNSEQ_TOKEN = 21;

    
    /** 
     * An expected per-message token was not received.  This is a
     * fatal error code that may occur during context establishment.
     * It is not used to indicate supplementary status values.
     * The MessageProp object is used for that purpose.
     */
    public static final int GAP_TOKEN = 22;


    private static String[] messages = {
        "Channel binding mismatch", // BAD_BINDINGS
        "Unsupported mechanism requested", // BAD_MECH
        "Invalid name provided", // BAD_NAME
        "Name of unsupported type provided", //BAD_NAMETYPE
        "Invalid input status selector", // BAD_STATUS
        "Token had invalid integrity check", // BAD_SIG
        "Specified security context expired", // CONTEXT_EXPIRED
        "Expired credentials detected", // CREDENTIALS_EXPIRED
        "Defective credential detected", // DEFECTIVE_CREDENTIAL
        "Defective token detected", // DEFECTIVE_TOKEN
        "Failure unspecified at GSS-API level", // FAILURE
        "Security context init/accept not yet called or context deleted",
						// NO_CONTEXT  
        "No valid credentials provided", // NO_CRED
        "Unsupported QOP value", // BAD_QOP
        "Operation unauthorized", // UNAUTHORIZED
        "Operation unavailable", // UNAVAILABLE
        "Duplicate credential element requested", //DUPLICATE_ELEMENT
        "Name contains multi-mechanism elements", // NAME_NOT_MN
        "The token was a duplicate of an earlier token", //DUPLICATE_TOKEN
        "The token's validity period has expired", //OLD_TOKEN
        "A later token has already been processed", //UNSEQ_TOKEN
        "An expected per-message token was not received", //GAP_TOKEN
    };

   /**
    * The major code for this exception
    *
    * @serial
    */
    private int major;

   /**
    * The minor code for this exception
    *
    * @serial
    */
    private int minor = 0; 

   /**
    * The text string for minor code
    *
    * @serial
    */
    private String minorMessage = null;

   /**
    * Alternate text string for major code
    *
    * @serial
    */

    private String majorString = null; 

    /** 
     *  Creates a GSSException object with a specified major code.
     * 
     * @param majorCode the The GSS error code for the problem causing this
     * exception to be thrown.
     */
    public GSSException (int majorCode) {
        
        if (validateMajor(majorCode))
            major = majorCode;
        else
            major = FAILURE;
    }

    /** 
     * Construct a GSSException object with a specified major code and a
     * specific major string for it.
     * 
     * @param majorCode the fatal error code causing this exception.
     * @param majorString an expicit message to be included in this exception
     */
    GSSException (int majorCode, String majorString) {
        
        if (validateMajor(majorCode))
            major = majorCode;
        else
            major = FAILURE;
	this.majorString = majorString;
    }


    /** 
     * Creates a GSSException object with the specified major code, minor
     * code, and minor code textual explanation.  This constructor is to be
     * used when the exception is originating from the underlying mechanism
     * level. It allows the setting of both the GSS code and the mechanism
     * code.
     * 
     * @param majorCode the GSS error code for the problem causing this
     * exception to be thrown. 
     * @param minorCode the mechanism level error code for the problem
     * causing this exception to be thrown.
     * @param minorString the textual explanation of the mechanism error
     * code.
     */
    public GSSException (int majorCode, int minorCode, String minorString) {
        
        if (validateMajor(majorCode))
            major = majorCode;
        else
            major = FAILURE;

        minor = minorCode;
        minorMessage = minorString;
    }

    /** 
     * Returns the GSS-API level major error code for the problem causing
     * this exception to be thrown. Major error codes are
     * defined at the mechanism independent GSS-API level in this
     * class. Mechanism specific error codes that might provide more
     * information aer set as the minor error code.
     * 
     * @return int the GSS-API level major error code causing this exception
     * @see #getMajorString
     * @see #getMinor
     * @see #getMinorString
     */
    public int getMajor() {
        return major;
    }

    /** 
     * Returns the mechanism level error code for the problem causing this
     * exception to be thrown. The minor code is set by the underlying
     * mechanism.
     *
     * @return int the mechanism error code; 0 indicates that it has not
     * been set.
     * @see #getMinorString
     * @see #setMinor
     */
    public int  getMinor(){
        return minor;
    }

    /** 
     * Returns a string explaining the GSS-API level major error code in
     * this exception.
     * 
     * @return String explanation string for the major error code
     * @see #getMajor
     * @see #toString
     */
    public String getMajorString() {
    
	if (majorString != null)
	    return majorString;
	else
	    return messages[major - 1];
    }


    /** 
     * Returns a string explaining the mechanism specific error code.
     * If the minor status code is 0, then no mechanism level error details
     * will be available.
     * 
     * @return String a textual explanation of mechanism error code
     * @see #getMinor
     * @see #getMajorString
     * @see #toString
     */
    public String getMinorString() {
            
        return minorMessage;
    }


    /** 
     * Used by the exception thrower to set the mechanism
     * level minor error code and its string explanation.  This is used by
     * mechanism providers to indicate error details.
     * 
     * @param minorCode the mechanism specific error code
     * @param message textual explanation of the mechanism error code
     * @see #getMinor
     */
    public void setMinor(int minorCode, String message) {
    
        minor = minorCode;
        minorMessage = message;
    }
    

    /** 
     * Returns a textual representation of both the major and the minor
     * status codes.
     * 
     * @return a String with the error descriptions
     */
    public String toString() {
        return ("GSSException: " + getMessage());
    }

    /** 
     * Returns a textual representation of both the major and the minor
     * status codes.
     * 
     * @overrides Throwable#geMessage
     * @return a String with the error descriptions
     */
    public String getMessage() {
        if (minor == 0)
            return (getMajorString());
        
        return (getMajorString() 
		+ " (Mechanism level: " + getMinorString() + ")");
    }


    /*
     * Validates the major code in the proper range.
     */
    private boolean validateMajor(int major) {
    
        if (major > 0 && major <= messages.length)
            return (true);
            
        return (false);
    }
}
