/**********
 * Copyright (c) 2003-2004 Greg Parker.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **********/

#include "includes.h"
#include "formutils.h"
#include "data/connectionlist.h"
#include "data/prefs.h"
#include "rsrc/rsrc.h"
#include "ssh/ssh.h"
#include "forms/CollapseUtils.h"

#include "passwordform.h"


static Boolean RetrieveUsernameAndPassword(void) FORMS_SEGMENT;
static void ForgetPassword(void) FORMS_SEGMENT;
static void SetPasswordEcho(Boolean echo) FORMS_SEGMENT;
static Boolean LoadPasswordForm(void) FORMS_SEGMENT;

extern struct ssh_session_t *ss;


static Boolean RetrieveUsernameAndPassword(void)
{
    FieldPtr usernameFld = PrvGetObjectByID(PasswordFormUsernameFieldID);
    FieldPtr passwordFld = PrvGetObjectByID(PasswordFormPasswordFieldID);
    MemHandle usernameH;
    MemHandle passwordH;
    char *username;
    char *password;

    FldReleaseFocus(usernameFld);
    FldCompactText(usernameFld);
    usernameH = FldGetTextHandle(usernameFld);
    FldSetTextHandle(usernameFld, NULL);

    FldReleaseFocus(passwordFld);
    FldCompactText(passwordFld);
    passwordH = FldGetTextHandle(passwordFld);
    FldSetTextHandle(passwordFld, NULL);

    if (usernameH) {
        username = MemHandleLock(usernameH);
    } else {
        username = "";
    }

    if (passwordH) {
        password = MemHandleLock(passwordH);
    } else {
        password = "";
    }

    ssh_use_password(ss, username, password);

    if (usernameH) {
        MemHandleUnlock(usernameH);
        MemHandleFree(usernameH);
    }

    if (passwordH) {
        MemSet(password, MemHandleSize(passwordH), 0);
        MemHandleUnlock(passwordH);
        MemHandleFree(passwordH);
    }

    return true;
}


static void ForgetPassword(void)
{
    FieldPtr passwordFld = PrvGetObjectByID(PasswordFormPasswordFieldID);
    MemHandle passwordH;

    FldReleaseFocus(passwordFld);
    FldCompactText(passwordFld);
    passwordH = FldGetTextHandle(passwordFld);
    FldSetTextHandle(passwordFld, NULL);

    if (passwordH) {
        MemSet(MemHandleLock(passwordH), MemHandleSize(passwordH), 0);
        MemHandleUnlock(passwordH);
        MemHandleFree(passwordH);
    }
}


static void SetPasswordEcho(Boolean echo)
{
    PrvSetControlValue(PasswordFormEchoCheckboxID, echo);
    FldSetFont(PrvGetObjectByID(PasswordFormPasswordFieldID), 
               echo ? stdFont : (FontID)PasswordFontID);
}


static Boolean LoadPasswordForm(void)
{
    MemHandle recordH;
    Boolean ok = true;
    char *hostname;
    char *username;
    char *portname;

    recordH=ConnectionListReadSelectedRecord(&hostname, &portname, &username);
    if (!recordH) return false;

    if (ok) ok = PrvSetFieldToValueByID(PasswordFormHostFieldID, hostname);
    if (ok) ok = PrvSetFieldToValueByID(PasswordFormUsernameFieldID, username);

    if (ok) {
        if (StrLen(username) == 0) {
            // missing username - set caret to username
            PrvSetFocusByID(PasswordFormUsernameFieldID);
        } else {
            // username ok - set caret to password
            PrvSetFocusByID(PasswordFormPasswordFieldID);
        }
    }

    if (ok) SetPasswordEcho(PrefsGetInt(prefEchoPassword, 0));

    MemHandleUnlock(recordH);

    return ok;
}


static void DoOK(void) 
{
    // send username and password to connection
    if (RetrieveUsernameAndPassword()) {
        // return to terminal form
        FrmReturnToForm(0);
    } else {
        // password extraction failed
        // close connection and return to terminal form
        ssh_close(ss);
        FrmReturnToForm(0);
    }
}


Boolean PasswordFormHandleEvent(EventPtr e)
{
    FormPtr frmP = FrmGetActiveForm();

    switch (e->eType) {
    case frmOpenEvent:
        CollapseSetState(frmP, collapseStateUser);
        if (!LoadPasswordForm()) {
            // load failed - go back to terminal form
            FrmReturnToForm(0);
        } else {
            FrmDrawForm(frmP);
        }
        return true;
        
    case keyDownEvent:
        if (!EvtKeydownIsVirtual(e)) {
            unsigned char c = e->data.keyDown.chr;
            if (c == '\n'  ||  c == '\r') {
                // enter in username - switch to password
                // enter in password - OK button
                // enter in neither - OK button
                UInt16 focusID;
                UInt16 focusIndex = FrmGetFocus(FrmGetActiveForm());
                if (focusIndex == noFocus) {
                    DoOK();
                    return true;
                } 
                focusID = FrmGetObjectId(FrmGetActiveForm(), focusIndex);
                if (focusID == PasswordFormUsernameFieldID) {
                    PrvSetFocusByID(PasswordFormPasswordFieldID);
                    PrvFieldSelectAll(PasswordFormPasswordFieldID);
                    return true;
                } else if (focusID == PasswordFormPasswordFieldID) {
                    DoOK();
                    return true;
                }
            }
        }
        return false;

    case ctlSelectEvent:
        switch (e->data.ctlSelect.controlID) {
        case PasswordFormOKButtonID:
            DoOK();
            return true;

        case PasswordFormCancelButtonID:
            // close connection, return to terminal form
            ssh_close(ss);
            FrmReturnToForm(0);
            return true;

        case PasswordFormEchoCheckboxID:
            // change password field echoing
            PrefsPutInt(prefEchoPassword, e->data.ctlSelect.on);
            SetPasswordEcho(e->data.ctlSelect.on);
            return true;

        default:
            return false;
        }

    case frmCloseEvent:
        // fixme this doesn't get called with FrmReturnToForm()
        // clear entered password, if any
        ForgetPassword();
        return false;

    default:
        return false;
    }
}

