#pragma ident "$Header: /san01/cvs/ashpool/csrc/modtcl/src/Attic/cmds.c,v 1.5 2004/04/21 21:47:06 aleigh Exp $"

/*
 * Copyright (c) 1994, 2002 Alex Leigh, All Rights Reserved
 * 
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright
 * notice above does not evidence any actual or intended publication of such
 * source code.
 * 
 * Disclosure, copying, distribution, or transmission of this code without
 * express permission is prohibited.
 */

#include <continuity.h>
#include "db.h"
#include "modtcl.h"

struct tclSfn_vector {
    void (*tclFbind_dyn_command) (char *name, Tcl_CmdProc * proc);
};
typedef struct tclSfn_vector tclTfn_vector;

static tclTcmd tclGcmds[] = {
    {"ta_log", tclFta_log, NULL},
    {"ta_write", tclFta_write, NULL},
    {"ta_startresponse", tclFta_startresponse, NULL},
    {"ta_setstatus", tclFta_setstatus, NULL},
    {"ta_http_var_get", tclFta_http_vars_get, NULL},
    {"ta_http_res_get", tclFta_http_res_get, NULL},
    {"ta_http_req_get", tclFta_http_req_get, NULL},
    {"ta_http_query_get", tclFhttp_query_get, NULL},
    {"ta_http_var_set", tclFta_http_var_set, NULL},
    {"ta_http_res_set", tclFta_http_res_set, NULL},
    {"ta_http_req_set", tclFta_http_req_set, NULL},
    {"ta_http_query_value", tclFhttp_query_value, NULL},
    {"ta_pwd", tclFta_pwd, NULL},
    {"ta_list_get", tclFlist_get, NULL},
    {"ta_http_query_parse", tclFhttp_query_parse, NULL},
    {"ta_db_open", tclFdb_open, NULL},
    {"ta_db_select", tclFdb_select, NULL},
    {"ta_db_getrow", tclFdb_getrow, NULL},
    {"ta_db_close", tclFdb_close, NULL},
    {"ta_jpg_getsize", tclFjpg_getsize, NULL},
    {"ta_urldecode", tclFurl_decode, NULL},
    {"ta_urlencode", tclFurl_encode, NULL},
    {"tav_set", tclFtav_set, NULL},
    {"tav_get", tclFtav_get, NULL},
    {"tav_exists", tclFtav_exists, NULL},
    {NULL, NULL, NULL}
};

static tclTcmd *tclGdyn_cmds = NULL;
static int tclGdyn_count = 0;
/* TLS classes: */
static int tclGtls_db;          /* Database Connections */

static hshTvoid_list *tclGtav_hash;
static pthread_rwlock_t tclLtav_hash;

void tclFbind_dyn_command(char *name, Tcl_CmdProc * proc)
{
    char *n;

    assert(name != NULL);
    assert(proc != NULL);

    logFmsg(3,
            "Bind external TCL command. cmd: %s addr: 0x%x",
            name, proc);

    if (tclGdyn_cmds == 0) {
        tclGdyn_cmds = malloc(sizeof(tclTcmd) * 2);
        tclGdyn_cmds->name = NULL;
        tclGdyn_count = 1;
    } else {
        tclGdyn_count++;
        tclGdyn_cmds =
            realloc(tclGdyn_cmds, sizeof(tclTcmd) * (tclGdyn_count + 1));
    }

    n = malloc(strlen(name) + 1);
    strcpy(n, name);

    tclGdyn_cmds[tclGdyn_count - 1].name = n;
    tclGdyn_cmds[tclGdyn_count - 1].proc = proc;
    tclGdyn_cmds[tclGdyn_count].name = NULL;

    return;
}

/*
 * Setup various locals in this file. this is called from the
 * initialization function in modtcl.c
 */
void tclFcmd_init(void)
{
    tclGtls_db = tlsFregister((void *(*)(void *)) dbFclose);
    tclGtav_hash = hshFvoid_init((void (*)(void *)) lstFset_free);
    pthread_rwlock_init(&tclLtav_hash, NULL);
}

void tclFsetup_cmds(Tcl_Interp * interp)
{
    tclFcmds_register(interp, tclGcmds);
    tclFcmds_register(interp, tclGdyn_cmds);
}

void tclFcmds_register(Tcl_Interp * interp, tclTcmd * cmd)
{
    if (cmd == NULL)
        return;

    while (cmd->name != NULL) {
        /*
         * logFmsg(3,"mod/tcl: tclFcmds_register: Binding proc %s to 0x%x",
         * cmd->name, cmd->proc);
         */
        Tcl_CreateCommand(interp, cmd->name, cmd->proc, cmd->clientData,
                          NULL);
        ++cmd;
    }
}

int tclFta_log(ClientData ignored, Tcl_Interp * interp, int argc,
               char **argv)
{
    if (argc != 3) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " loglevel string\"", NULL);
        return TCL_ERROR;
    }
    logFmsg(atoi(argv[1]), "TCL: %s", argv[2]);

    return TCL_OK;
}

int tclFta_write(ClientData ignored, Tcl_Interp * interp, int argc,
                 char **argv)
{
    httpTtrans *t;

    if (argc != 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " string\"", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    assert(t != NULL);

    httpFwrite(t, argv[1], strlen(argv[1]));

    return TCL_OK;
}

int tclFta_startresponse(ClientData ignored, Tcl_Interp * interp, int argc,
                         char **argv)
{
    httpTtrans *t;

    if (argc != 1) {
        Tcl_AppendResult(interp, "wrong # args: No arguments", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    assert(t != NULL);

    httpFstart_response(t);

    return TCL_OK;
}

int tclFta_setstatus(ClientData ignored, Tcl_Interp * interp, int argc,
                     char **argv)
{
    httpTtrans *t;

    if (argc != 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " respcode\"", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    assert(t != NULL);

    httpFset_status(t, atoi(argv[1]), NULL);

    return TCL_OK;
}

int tclFta_http_vars_get(ClientData ignored, Tcl_Interp * interp, int argc,
                         char **argv)
{
    httpTtrans *t;
    char *v;

    if (argc != 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " string\"", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    assert(t != NULL);

    v = lstFset_get(t->vars, argv[1]);

    if (v != NULL) {
        Tcl_SetResult(interp, v, TCL_VOLATILE);
        return TCL_OK;
    }
    Tcl_SetResult(interp, "", TCL_STATIC);
    return TCL_OK;
}


int tclFta_http_req_get(ClientData ignored, Tcl_Interp * interp, int argc,
                        char **argv)
{
    httpTtrans *t;
    char *v;

    if (argc != 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " string\"", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    assert(t != NULL);

    v = lstFset_get(t->req_hdrs, argv[1]);

    if (v != NULL) {
        Tcl_SetResult(interp, v, TCL_VOLATILE);
        return TCL_OK;
    }
    Tcl_SetResult(interp, "", TCL_STATIC);
    return TCL_OK;
}

int tclFhttp_query_get(ClientData ignored, Tcl_Interp * interp, int argc,
                       char **argv)
{
    httpTtrans *t;
    char *v;

    if (argc != 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " string\"", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    assert(t != NULL);

    v = lstFset_get(t->query, argv[1]);

    if (v != NULL) {
        Tcl_SetResult(interp, v, TCL_VOLATILE);
        return TCL_OK;
    }
    Tcl_SetResult(interp, "", TCL_STATIC);
    return TCL_OK;
}


int tclFta_http_res_get(ClientData ignored, Tcl_Interp * interp, int argc,
                        char **argv)
{
    httpTtrans *t;
    char *v;

    if (argc != 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         " string\"", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    assert(t != NULL);

    v = lstFset_get(t->res_hdrs, argv[1]);

    if (v != NULL) {
        Tcl_SetResult(interp, v, TCL_VOLATILE);
        return TCL_OK;
    }
    Tcl_SetResult(interp, "", TCL_STATIC);
    return TCL_OK;
}

int tclFta_pwd(ClientData ignored, Tcl_Interp * interp, int argc,
               char **argv)
{
    httpTtrans *t;
    char *path, *pb, *p;
    int len;

    if (argc != 1) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    assert(t != NULL);

    path = lstFset_get(t->vars, "path");
    if (path == NULL) {
        Tcl_AppendResult(interp, "Could not get path.", NULL);
        return TCL_ERROR;
    }
    len = strlen(path);

    pb = Tcl_Alloc(len + 1);
    strncpy(pb, path, len + 1);

    p = (pb + len);

    while (1) {
        if (*p == '/') {
            *p = '\0';
            Tcl_SetResult(interp, pb, TCL_DYNAMIC);
            return TCL_OK;
            break;
        }
        if (p == pb) {
            Tcl_SetResult(interp, "", TCL_STATIC);
            return TCL_OK;
        }
        p--;
    }
}

int tclFta_http_var_set(ClientData ignored, Tcl_Interp * interp, int argc,
                        char **argv)
{
    httpTtrans *t;

    if (argc != 3) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         "name value", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    if (t == NULL) {
        Tcl_AppendResult(interp, "Could not find transaction.", NULL);
        return TCL_ERROR;
    }
    lstFset_update(t->vars, argv[1], argv[2]);

    return TCL_OK;
}

int tclFta_http_res_set(ClientData ignored, Tcl_Interp * interp, int argc,
                        char **argv)
{
    httpTtrans *t;

    if (argc != 3) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         "name value", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    if (t == NULL) {
        Tcl_AppendResult(interp, "Could not find transaction.", NULL);
        return TCL_ERROR;
    }
    lstFset_update(t->res_hdrs, argv[1], argv[2]);

    return TCL_OK;
}

int tclFta_http_req_set(ClientData ignored, Tcl_Interp * interp, int argc,
                        char **argv)
{
    httpTtrans *t;

    if (argc != 3) {
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                         "name value", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    if (t == NULL) {
        Tcl_AppendResult(interp, "Could not find transaction.", NULL);
        return TCL_ERROR;
    }
    lstFset_update(t->req_hdrs, argv[1], argv[2]);

    return TCL_OK;
}

int tclFurl_decode(ClientData ignored, Tcl_Interp * interp, int argc,
                   char **argv)
{
    dynTstring *dyn;

    if (argc != 2) {
        Tcl_AppendResult(interp, "bad argumentation: should be \"",
                         argv[0], "url\"", NULL);
        return TCL_ERROR;
    }
    dyn = dynFinit();
    utlFurl_decode(dyn, argv[1]);

    Tcl_AppendResult(interp, dynFgetstr(dyn), NULL);
    dynFfree(dyn);
    return TCL_OK;
}

int tclFurl_encode(ClientData ignored, Tcl_Interp * interp, int argc,
                   char **argv)
{
    dynTstring *dyn;

    if (argc != 2) {
        Tcl_AppendResult(interp, "bad argumentation: should be \"",
                         argv[0], "url\"", NULL);
        return TCL_ERROR;
    }
    dyn = dynFinit();
    utlFurl_encode(dyn, argv[1]);

    Tcl_AppendResult(interp, dynFgetstr(dyn), NULL);
    dynFfree(dyn);
    return TCL_OK;
}



int tclFlist_get(ClientData ignored, Tcl_Interp * interp, int argc,
                 char **argv)
{
    lstTset *p;
    char *d;

    if (argc != 3) {
        Tcl_AppendResult(interp, "bad argumentation: should be \"",
                         argv[0], "list name\"", NULL);
        return TCL_ERROR;
    }

    p = tlsFget(argv[1], 0);

    if (p == NULL) {
        Tcl_SetResult(interp, "", TCL_STATIC);
        return TCL_OK;
    }
    d = lstFset_get(p, argv[2]);
    if (d == NULL) {
        Tcl_SetResult(interp, "", TCL_STATIC);
        return TCL_OK;
    }
    Tcl_AppendResult(interp, d, NULL);
    return TCL_OK;
}

int tclFhttp_query_value(ClientData ignored, Tcl_Interp * interp, int argc,
                         char **argv)
{
    httpTtrans *t;
    char *query, *value;
    lstTset *set;

    if (argc != 2) {
        Tcl_AppendResult(interp, "bad argumentation: should be \"",
                         argv[0], "name\"", NULL);
        return TCL_ERROR;
    }

    t = httpFthread_gettrans();
    if (t == NULL) {
        Tcl_AppendResult(interp, "Could not find transaction.", NULL);
        return TCL_ERROR;
    }

    set = httpFget_query (t);
    if (set == NULL) {
        Tcl_SetResult(interp, "", TCL_STATIC);
        return TCL_OK;
    }

    value = lstFset_get(set, argv[1]);
    if (value == NULL) {
        Tcl_SetResult(interp, "", TCL_STATIC);
        return TCL_OK;
    }

    Tcl_AppendResult(interp, value, NULL);

    return TCL_OK;
}


int tclFhttp_query_parse(ClientData ignored, Tcl_Interp * interp, int argc,
                         char **argv)
{
    httpTtrans *t;
    char *tlsid, *query;
    lstTset *set;

    if (argc != 1) {
        Tcl_AppendResult(interp, "bad argumentation: should be \"",
                         argv[0], "\"", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    if (t == NULL) {
        Tcl_AppendResult(interp, "Could not find transaction.", NULL);
        return TCL_ERROR;
    }
    query = lstFset_get(t->vars, "query");
    if (query == NULL) {
        Tcl_SetResult(interp, "", TCL_STATIC);
        return TCL_OK;
    }
    set = qryFlst_parse(query);
    if (set == NULL) {
        Tcl_SetResult(interp, "", TCL_STATIC);
        return TCL_OK;
    }
    tlsid = tlsFadd_makeid(set, 0);
    Tcl_AppendResult(interp, tlsid, NULL);

    return TCL_OK;
}

int tclFdb_close(ClientData ignored, Tcl_Interp * interp, int argc,
                 char **argv)
{
    void *db;

    if (argc != 2) {
        Tcl_AppendResult(interp, "bad argumentation: should be \"",
                         argv[0], " db\"");
        return TCL_ERROR;
    }
    /* Doing this will cause the close if it's a valid handle */
    tlsFdel(argv[1], tclGtls_db);

    return TCL_OK;
}

int tclFdb_open(ClientData ignored, Tcl_Interp * interp, int argc,
                char **argv)
{
    httpTtrans *t;
    void *db;
    char *tlsid, *query;

    assert(interp != NULL);

    if (argc != 4) {
        Tcl_AppendResult(interp, "bad argumentation: should be \"",
                         argv[0], " user password service\"", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    if (t == NULL) {
        Tcl_AppendResult(interp, "Could not find transaction.", NULL);
        return TCL_ERROR;
    }
    db = dbFopen(argv[1], argv[2], argv[3]);
    if (db == NULL) {
        Tcl_AppendResult(interp, "Database open failed.", NULL);
        return TCL_ERROR;
    }
    tlsid = tlsFadd_makeid(db, tclGtls_db);
    Tcl_AppendResult(interp, tlsid, NULL);

    return TCL_OK;
}

int tclFdb_select(ClientData ignored, Tcl_Interp * interp, int argc,
                  char **argv)
{
    httpTtrans *t;
    char *tlsid, *query;
    void *db;
    lstTset *set;

    if (argc != 3) {
        Tcl_AppendResult(interp, "bad argumentation: should be \"",
                         argv[0], " conn sql\"", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    if (t == NULL) {
        Tcl_AppendResult(interp, "Could not find transaction.", NULL);
        return TCL_ERROR;
    }
    db = tlsFget(argv[1], tclGtls_db);
    if (db == NULL) {
        Tcl_AppendResult(interp, "Invalid database handle.", NULL);
        return TCL_ERROR;
    }
    set = dbFselect(db, argv[2]);
    if (set == NULL) {
        Tcl_AppendResult(interp, "dbFselect failed.", NULL);
        return TCL_ERROR;
    }
    tlsid = tlsFadd_makeid(set, 0);
    Tcl_AppendResult(interp, tlsid, NULL);

    return TCL_OK;
}

int tclFdb_getrow(ClientData ignored, Tcl_Interp * interp, int argc,
                  char **argv)
{
    httpTtrans *t;
    int res;
    void *db;
    lstTset *set;

    if (argc != 3) {
        Tcl_AppendResult(interp, "bad argumentation: should be \"",
                         argv[0], " conn resultset\"", NULL);
        return TCL_ERROR;
    }
    t = httpFthread_gettrans();
    if (t == NULL) {
        Tcl_AppendResult(interp, "Could not find transaction.", NULL);
        return TCL_ERROR;
    }
    db = tlsFget(argv[1], tclGtls_db);
    if (db == NULL) {
        Tcl_AppendResult(interp, "Invalid database handle.", NULL);
        return TCL_ERROR;
    }
    set = tlsFget(argv[2], 0);
    if (set == NULL) {
        Tcl_AppendResult(interp, "Invalid resource set handle.", NULL);
        return TCL_ERROR;
    }
    res = dbFgetrow(db, set);

    if (res == -1) {
        Tcl_AppendResult(interp, "dbFgetrow failed.", NULL);
        return TCL_ERROR;
    }
    if (res == 2)
        Tcl_SetResult(interp, "0", TCL_STATIC);
    else
        Tcl_SetResult(interp, "1", TCL_STATIC);

    return TCL_OK;
}

/*
 * Return the height and width of a given jpeg file. This requires mod/image
 * to work. Returns the string "width height" or "" on error.
 */
int tclFjpg_getsize(ClientData ignored, Tcl_Interp * interp, int argc,
                    char **argv)
{
    int h, w;
    char buf[32];

    if (argc != 2) {
        Tcl_AppendResult(interp, "bad argumentation: should be \"",
                         argv[0], " filename\"", NULL);
        return TCL_ERROR;
    }
    if (imgFjpeg_size(argv[1], &w, &h) == -1) {
        Tcl_AppendResult(interp, "Invalid file.", NULL);
        return TCL_ERROR;
    }
    snprintf(buf, 32, "%d %d", w, h);

    Tcl_AppendResult(interp, buf, NULL);

    return TCL_OK;
}

/*
 * tav_set array key value 
 */
int tclFtav_set(ClientData ignored, Tcl_Interp * interp, int argc,
                char **argv)
{
    lstTset *set;

    if (argc != 4) {
        Tcl_AppendResult(interp,
                         "bad argumentation: should be tav_set array key value",
                         NULL);
        return TCL_ERROR;
    }

    pthread_rwlock_wrlock(&tclLtav_hash);

    set = (lstTset *) hshFvoid_find(tclGtav_hash, argv[1]);

    if (set == NULL) {
        set = lstFset_create(argv[1]);
        hshFvoid_add(tclGtav_hash, argv[1], set);
    }

    lstFset_update(set, argv[2], argv[3]);

    pthread_rwlock_unlock(&tclLtav_hash);

    return TCL_OK;
}

/*
 * tav_get array key 
 */
int tclFtav_get(ClientData ignored, Tcl_Interp * interp, int argc,
                char **argv)
{
    lstTset *set;

    if (argc != 3) {
        Tcl_AppendResult(interp,
                         "bad argumentation: should be tav_get array key",
                         NULL);
        return TCL_ERROR;
    }

    pthread_rwlock_wrlock(&tclLtav_hash);

    set = (lstTset *) hshFvoid_find(tclGtav_hash, argv[1]);

    if (set != NULL)
        Tcl_AppendResult(interp, lstFset_get(set, argv[2]), NULL);

    pthread_rwlock_unlock(&tclLtav_hash);

    return TCL_OK;
}

/*
 * tav_exists array key 
 */
int tclFtav_exists(ClientData ignored, Tcl_Interp * interp, int argc,
                   char **argv)
{
    lstTset *set;
    char *value;

    if (argc != 3) {
        Tcl_AppendResult(interp,
                         "bad argumentation: should be tav_exists array key",
                         NULL);
        return TCL_ERROR;
    }

    pthread_rwlock_wrlock(&tclLtav_hash);

    set = (lstTset *) hshFvoid_find(tclGtav_hash, argv[1]);

    if (set != NULL) {
        if (lstFset_get(set, argv[2]) != NULL) {
            Tcl_AppendResult(interp, "1", NULL);
        } else {
            Tcl_AppendResult(interp, "0", NULL);
        }
    } else {
        Tcl_AppendResult(interp, "0", NULL);
    }

    pthread_rwlock_unlock(&tclLtav_hash);

    return TCL_OK;
}
