/* --------------------------------------------------------------------------
 *
 * License
 *
 * The contents of this file are subject to the Jabber Open Source License
 * Version 1.0 (the "License").  You may not copy or use this file, in either
 * source code or executable form, except in compliance with the License.  You
 * may obtain a copy of the License at http://www.jabber.com/license/ or at
 * http://www.opensource.org/.  
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Copyrights
 * 
 * Portions created by or assigned to Jabber.com, Inc. are 
 * Copyright (c) 1999-2000 Jabber.com, Inc.  All Rights Reserved.  Contact
 * information for Jabber.com, Inc. is available at http://www.jabber.com/.
 *
 * Portions Copyright (c) 1998-1999 Jeremie Miller.
 * 
 * Acknowledgements
 * 
 * Special thanks to the Jabber Open Source Contributors for their
 * suggestions and support of Jabber.
 * 
 * --------------------------------------------------------------------------*/

#include "jud.h"
#include <sys/utsname.h>

/* $Id: jud.c,v 1.5 2001/05/03 19:47:41 qmacro Exp $ */

void jud_browse_walk(xht h, const char *key, void *val, void *arg)
{
    xmlnode user = (xmlnode)val;
    xmlnode u, x = (xmlnode)arg;

    if(xmlnode_get_tag(user, "remove") != NULL) return;

    u = xmlnode_insert_tag(x, "user");
    xmlnode_put_attrib(u, "jid", xmlnode_get_attrib(user, "jid"));
    xmlnode_put_attrib(u, "name", xmlnode_get_data(xmlnode_get_tag(user, "name")));
}

void jud_preload(ji j)
{
    xmlnode cx, x = xdb_get(j->xc, j->id, "jabber:jud:users");
    j->users = xhash_new(1999);

    for(x = xmlnode_get_firstchild(x); x != NULL; x = xmlnode_get_nextsibling(x))
    {
        if(xmlnode_get_attrib(x,"jid") == NULL)
            continue;

        cx = xmlnode_dup(x);
        xhash_put(j->users,xmlnode_get_attrib(cx,"jid"),(void*)cx);
    }

    xmlnode_free(x);
}

void jud_otherstuff(ji j, jpacket jp)
{
    char *str;
    struct utsname un;
    xmlnode x;
    int start;
    time_t t;
    char nstr[10];

    log_debug(ZONE,"server iq packet");

    if(jpacket_subtype(jp) != JPACKET__GET)
    {
        jutil_error(jp->x, TERROR_NOTALLOWED);
        deliver(dpacket_new(jp->x),NULL);
        return;
    }

    if(NSCHECK(jp->iq,NS_TIME))
    {
        jutil_iqresult(jp->x);
        xmlnode_put_attrib(xmlnode_insert_tag(jp->x,"query"),"xmlns",NS_TIME);
        jpacket_reset(jp);
        xmlnode_insert_cdata(xmlnode_insert_tag(jp->iq,"utc"),jutil_timestamp(),-1);
        xmlnode_insert_cdata(xmlnode_insert_tag(jp->iq,"tz"),tzname[0],-1);

        /* create nice display time */
        t = time(NULL);
        str = ctime(&t);
        str[strlen(str) - 1] = '\0'; /* cut off newline */
        xmlnode_insert_cdata(xmlnode_insert_tag(jp->iq,"display"),str,-1);
        deliver(dpacket_new(jp->x),NULL);
        return;
    }

    if(NSCHECK(jp->iq,NS_VERSION))
    {
        jutil_iqresult(jp->x);
        xmlnode_put_attrib(xmlnode_insert_tag(jp->x,"query"),"xmlns",NS_VERSION);
        jpacket_reset(jp);

        xmlnode_insert_cdata(xmlnode_insert_tag(jp->iq,"name"),"jud",-1);
        xmlnode_insert_cdata(xmlnode_insert_tag(jp->iq,"version"),VERSION,-1);

        uname(&un);
        x = xmlnode_insert_tag(jp->iq,"os");
        xmlnode_insert_cdata(x,un.sysname,-1);
        xmlnode_insert_cdata(x," ",1);
        xmlnode_insert_cdata(x,un.release,-1);

        deliver(dpacket_new(jp->x),NULL);
        return;
    }

    if(NSCHECK(jp->iq,NS_BROWSE))
    {
        jutil_iqresult(jp->x);
        x = xmlnode_insert_tag(jp->x,"service");
        xmlnode_put_attrib(x,"type","jud");
        xmlnode_put_attrib(x,"xmlns",NS_BROWSE);
        xmlnode_put_attrib(x,"name",xmlnode_get_tag_data(j->config,"vCard/FN"));

        if(j_strcmp(jp->to->resource,"users") == 0 && xmlnode_get_tag(j->config, "userbrowse") != NULL)
        {
          xhash_walk(j->users,jud_browse_walk,(void*)x);
        }
        else
        {
          xmlnode_insert_cdata(xmlnode_insert_tag(x,"ns"),NS_REGISTER,-1);
          xmlnode_insert_cdata(xmlnode_insert_tag(x,"ns"),NS_SEARCH,-1);
        }
        deliver(dpacket_new(jp->x),NULL);
        return;
    }


    if(NSCHECK(jp->iq,NS_LAST))
    {
        jutil_iqresult(jp->x);
        xmlnode_put_attrib(xmlnode_insert_tag(jp->x,"query"),"xmlns",NS_LAST);
        jpacket_reset(jp);

        start = time(NULL) - j->start;
        sprintf(nstr,"%d",start);
        xmlnode_put_attrib(jp->iq,"seconds",nstr);

        deliver(dpacket_new(jp->x),NULL);
        return;
    }

    if(NSCHECK(jp->iq,NS_VCARD))
    {
        jutil_iqresult(jp->x);
        xmlnode_put_attrib(xmlnode_insert_tag(jp->x,"vCard"),"xmlns",NS_VCARD);
        jpacket_reset(jp);

        xmlnode_insert_node(jp->iq,xmlnode_get_firstchild(xmlnode_get_tag(j->config,"vCard")));

        deliver(dpacket_new(jp->x),NULL);
        return;
    }


    jutil_error(jp->x, TERROR_NOTIMPL);
    deliver(dpacket_new(jp->x),NULL);

}

/* phandler callback */
result jud_packets(instance i, dpacket dp, void *arg)
{
    ji j = (ji)arg;
    jpacket jp;

    /* if the delivery failed */
    if((jp = jpacket_new(dp->x)) == NULL)
    {
        deliver_fail(dp,"Illegal Packet");
        return r_DONE;
    }

    if(j->users == NULL)
        jud_preload(j);

    if(jp->type == JPACKET_IQ)
    {
        if(NSCHECK(jp->iq,NS_REGISTER))
        {
            jud_register(j, jp);
            return r_DONE;
        }
        if(NSCHECK(jp->iq,NS_SEARCH))
        {
            jud_search(j, jp);
            return r_DONE;
        }

        jud_otherstuff(j, jp);
        return r_DONE;
    }

    jutil_error(jp->x, TERROR_BAD);
    deliver(dpacket_new(jp->x),NULL);
    return r_DONE;
}


/*** everything starts here ***/
void jud(instance i, xmlnode x)
{
    ji j;

    log_debug(ZONE,"jud loading");

    j = pmalloco(i->p,sizeof(_ji));
    j->i = i;
    j->xc = xdb_cache(i);
    j->config =  xdb_get(j->xc,jid_new(i->p,"config@-internal"),"jabber:config:jud");
    j->id = jid_new(i->p,i->id);
    j->start = time(NULL);

    register_phandler(i,o_DELIVER,jud_packets,(void*)j);
}
