<?PHP

#
#   FILE:  SPT--SPTUser.php
#
#   METHODS PROVIDED:
#       SPTUser()
#           - constructor
#       SomeMethod($SomeParameter, $AnotherParameter)
#           - short description of method
#
#   AUTHOR:
#
#   Part of the Scout Portal Toolkit
#   Copyright 2004 Internet Scout Project
#   http://scout.wisc.edu
#

class SPTUser extends User {
    # ---- PUBLIC INTERFACE --------------------------------------------------
    # ---- user interface preference mnemonics
    # color avoidance flags
    const UIPREF_AVOID_RED =           1;
    const UIPREF_AVOID_REDGREEN =      2;
    const UIPREF_AVOID_BLUEYELLOW =    4;
    const UIPREF_AVOID_GREENYELLOW =   8;
    const UIPREF_AVOID_ORANGE =        16;
    const UIPREF_AVOID_REDBLACK =      32;
    const UIPREF_AVOID_PURPLEGREY =    64;
    const UIPREF_AVOID_USEMAXMONOCHR = 128;

    # content display options
    const UIPREF_CONTENTDENSITY_NOPREFERENCE =  0;
    const UIPREF_CONTENTDENSITY_DETAILED =  1;
    const UIPREF_CONTENTDENSITY_OVERVIEW =  2;

    # content view options
    const UIPREF_CONTENTVIEW_NOPREFERENCE =  0;
    const UIPREF_CONTENTVIEW_TEXTINTENSIVE =  1;
    const UIPREF_CONTENTVIEW_IMAGEINTENSIVE =  2;

    # audio description options
    const UIPREF_AUDIODESCRIPTION_NONE =  0;
    const UIPREF_AUDIODESCRIPTION_STANDARD =  1;
    const UIPREF_AUDIODESCRIPTION_EXPANDED =  2;

    # caption type options
    const UIPREF_CAPTIONTYPE_NONE =  0;
    const UIPREF_CAPTIONTYPE_VERBATIM =  1;
    const UIPREF_CAPTIONTYPE_REDUCEDREADINGLEVEL =  2;

    # object constructor
    function SPTUser($UserInfo = NULL)
    {
        global $Session;

        # create database handle for parent and local use
        $DB = new SPTDatabase();
        $this->DB = $DB;

        # if no user info supplied
        if ($UserInfo == NULL)
        {
            # if session is available in global context
            if (isset($Session))
            {
                # call parent constructor with global session
                $this->User($Session);
            }
            else
            {
                # call parent constructor with our own session
                $OurSession = new Session($this->DB);
                $this->User($OurSession);
            }
        }
        else
        {
            # call parent constructor with our DB handle
            $this->User($this->DB, $UserInfo);
        }

        # if user is logged in
        if ($this->IsLoggedIn())
        {
            # if user already has a UI preferences record in DB
            $DB->Query("SELECT * FROM UserUIPreferences WHERE UserId = '".$this->Id()."'");
            if ($DB->NumRowsSelected())
            {
                # load in UI preferences
                $this->UserUIPreferencesCache = $DB->FetchRow();
            }
            else
            {
                # add UI preferences record to DB for user
                $DB->Query("INSERT INTO UserUIPreferences (UserId) VALUES (".$this->Id().")");
            }
        }
    }

    # user interface / accessibility preferences
    function PrefFontSize($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("FontSize", $NewValue);  }
    function PrefFontTypeFace($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("FontTypeFace", $NewValue);  }
    function PrefFontColor($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("FontColor", $NewValue);  }
    function PrefBackgroundColor($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("BackgroundColor", $NewValue);  }
    function PrefColorAvoidanceFlags($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("ColorAvoidanceFlags", $NewValue);  }
    function PrefContentDensity($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("ContentDensity", $NewValue);  }
    function PrefContentView($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("ContentView", $NewValue);  }
    function PrefAudioDescriptionLevel($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("AudioDescriptionLevel", $NewValue);  }
    function PrefAudioDescriptionLanguage($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("AudioDescriptionLanguage", $NewValue);  }
    function PrefVisualDescriptionLanguage($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("VisualDescriptionLanguage", $NewValue);  }
    function PrefImageDescriptionLanguage($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("ImageDescriptionLanguage", $NewValue);  }
    function PrefUseGraphicAlternatives($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("UseGraphicAlternatives", $NewValue);  }
    function PrefSignLanguage($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("SignLanguage", $NewValue);  }
    function PrefCaptionType($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("CaptionType", $NewValue);  }
    function PrefCaptionRate($NewValue = DB_NOVALUE)
            {  return $this->UUPUpdateValue("CaptionRate", $NewValue);  }

    /**
       Get/generate a cryptographic keypair for user login.
       CWIS can use RSA encryption on the password field of login
       forms.  This function gets the most recently generated
       keypair, clearing out keys older than 48 hours, and
       re-generating a new key if the most recent one is older than 24
       hours.
       @return openssl format keypair
     */
    static function GetCryptKey()
    {
        $DB = new Database();

        # Clear all keys more than two days old
        $DB->Query("DELETE FROM LoginKeys WHERE NOW() - CreationTime > 172800");
        $DB->Query("DELETE FROM UsedLoginTokens WHERE NOW()-KeyCTime > 172800");

        # Get the most recently generated key
        $DB->Query("SELECT NOW()-CreationTime as Age,"
                   ."KeyPair FROM LoginKeys "
                   ."ORDER BY Age ASC LIMIT 1");
        $Row = $DB->FetchRow();

        # If there is no key in the database, or the key is too old
        if ( ($Row===FALSE) || ($Row["Age"]>=86400) )
        {
            # Generate a new OpenSSL format keypair
            $KeyPair = openssl_pkey_new(
                array(
                    'private_key_bits' => 512, # Make this a Sysadmin pref later?
                    'private_key_type' => OPENSSL_KEYTYPE_RSA
                    ));

            # Serialize it for storage
            openssl_pkey_export($KeyPair, $KeyPairDBFormat);

            # And stick it into the database
            $DB->Query("INSERT INTO LoginKeys "
                       ."(KeyPair, CreationTime) VALUES ("
                       ."\"".addslashes($KeyPairDBFormat)."\","
                       ."NOW())");
        }
        else
        {
            # If we do have a current key in the database,
            #  Convert it to openssl format for usage
            $KeyPair = openssl_pkey_get_private( $Row["KeyPair"] );
        }

        return $KeyPair;
    }

    /**
       Extract the modulus and exponent of the public key from an
       openssl format keypair to send in login forms.
       @param KeyPair An openssl format keypair as returned by SPTUser::GetCryptKey().
       @return Associative array containing "Modulus" and "Exponent" key parameters
    */
    static function ExtractPubKeyParameters($KeyPair)
    {
        # Export the keypair as an ASCII signing request (which contains the data we want)
        openssl_csr_export(openssl_csr_new(array(), $KeyPair), $Export, false);

        $Modulus  = "";
        $Exponent = "";

        $Patterns = array(
            '/Modulus \([0-9]+ bit\):(.*)Exponent: [0-9]+ \(0x([0-9a-f]+)\)/ms',
            '/Public-Key: \([0-9]+ bit\).*Modulus:(.*)Exponent: [0-9]+ \(0x([0-9a-f]+)\)/ms',
            );

        foreach ($Patterns as $Pattern)
        {
            if (preg_match($Pattern, $Export, $Matches))
            {
                $Modulus = $Matches[1];
                $Exponent = $Matches[2];
                break;
            }
        }

        # Clean newlines and whitespace out of the modulus
        $Modulus = preg_replace("/[^0-9a-f]/","",$Modulus);

        # Return key material
        return array( "Modulus" => $Modulus, "Exponent" => $Exponent );
    }

    # ---- PRIVATE INTERFACE -------------------------------------------------

    var $DB;
    var $UserUIPreferencesCache;

    function UUPUpdateValue($FieldName, $NewValue)
    {
        return $this->DB->UpdateValue("UserUIPreferences", $FieldName,
                $NewValue, "UserId = '".$this->Id()."'",
                $this->UserUIPreferencesCache);
    }
}

?>
