/* ----------------------------------------------------------------------------- 
 * handlers.c
 *
 *     Functions for registering SWIG handler functions.   Also includes
 *     default handlers for various error conditions.
 * 
 * Author(s) : David Beazley (beazley@cs.uchicago.edu)
 *             Mike Sliczniak (mzsliczn@midway.uchicago.edu)
 *
 * Copyright (C) 1999-2000.  The University of Chicago
 * See the file LICENSE for information on usage and redistribution.	
 * ----------------------------------------------------------------------------- */

static char cvsroot[] = "$Header: /home/pastacvs/cvs-rep/vermicelli/tot/src/SWILL-0.1/Source/SWILL/handlers.c,v 1.1 2005/01/27 08:46:25 dillema Exp $";

#include "swillint.h"
#include <stdarg.h>

static Hash *Handlers = 0;

/* -----------------------------------------------------------------------------
 * int swill_handle()
 *
 * Register a handler function with the server
 * 
 *      servname   =  Document name used by the server (i.e., "foo.html")
 *      handler    =  Handler function
 *      clientdata =  Data passed to the handler function
 *
 * Note: MIME type is guessed from the servname suffix.
 *
 * The servname may include options before the actual name.  For example:
 * "stdout:foo.html" indicates that output is going to use standard output
 * ----------------------------------------------------------------------------- */

int
swill_handle(const char *servname, SwillHandler handler, void *clientdata) {
  Hash  *handobj;
  const char  *actname;
  char  opt[512] = { 0 };

  if (!Handlers) {
    Handlers = NewHash();
  }
  /* Check for options */
  actname = strchr(servname,':');
  if (actname) {
    strncat(opt,servname,actname - servname);
    actname++;
  } else {
    actname = servname;
  }
  handobj = NewHash();
  if (*actname == '/') actname++;
  Setattr(handobj,"servname",actname);
  Setattr(handobj,"handler",NewVoid((void*)handler,0));
  Setattr(handobj,"clientdata",NewVoid(clientdata,0));
  Setattr(handobj,"mimetype", swill_guess_mimetype(servname));
  
  if (strcmp(opt,"stdout") == 0) {
    SetInt(handobj,"stdout",1);
  }
  Setattr(Handlers,actname,handobj);
  return 0;
}

/* -----------------------------------------------------------------------------
 * swill_file()
 *
 * Serve a registered filename
 * ----------------------------------------------------------------------------- */

int 
swill_file(const char *url, const char *path)
{
  Hash *handobj;
  if (!Handlers) {
    Handlers = NewHash();
  }
  handobj = NewHash();
  Setattr(handobj,"servname",url);
  if (path) {
    Setattr(handobj,"filename",path);
  } else {
    Setattr(handobj,"filename",url);
  }
  Setattr(handobj,"mimetype",swill_guess_mimetype(url));
  Setattr(Handlers,url,handobj);
  return 0;
}

/* -----------------------------------------------------------------------------
 * swill_remove()
 * 
 * Remove a handler
 * ----------------------------------------------------------------------------- */

void 
swill_remove(const char *name) {
  if (!Handlers) return;
  Delattr(Handlers,name);
}

/* -----------------------------------------------------------------------------
 * swill_handler_reset()
 * 
 * Reset all of the handlers
 * ----------------------------------------------------------------------------- */

void
swill_handler_reset(void) {
  Delete(Handlers);
  Handlers = 0;
}

/* -----------------------------------------------------------------------------
 * swill_handler_lookup()
 *
 * Look up a handler given a URI
 * ----------------------------------------------------------------------------- */

Hash *
swill_handler_lookup(const String *uri) {
  if (!Handlers) return 0;
  return Getattr(Handlers,uri);
}

/* -----------------------------------------------------------------------------
 * SwillFileNotFound()
 *
 * Report a file not found error to the client.
 * ----------------------------------------------------------------------------- */

static char *error404msg = "\n\
<html><head><title>File not found</title></head>\n\
<body bgcolor=\"#ffffff\">\n\
<h1>File not found</h1>\n\
Document '%s' not registered with the server.\n\
Click <a href=\"/info\">here</a> for a list of available documents.\n\n\
</body></html>\n";

int 
SwillFileNotFound(DOH *out, void *clientdata) {
  swill_setresponse("404 File not found");
  swill_setheader("Content-Type","text/html");
  Printf(out,error404msg,swill_getvar("__uri__"));
  return 0;
}

/* -----------------------------------------------------------------------------
 * SwillAuthenticate()
 *
 * Ask the user to authenticate themselves with a username and password.
 * ----------------------------------------------------------------------------- */

static char *error401msg = "\n\
<html><head><title>Unauthorized</title></head>\n\
<body bgcolor=\"#ffffff\">\n\
<h1>Unauthorized</h1>\n\
You don't have access to this document. Sorry.\n\
</body></html>\n";

int 
SwillAuthenticate(DOH *out, void *clientdata) {
  swill_setresponse("401 Unauthorized");
  swill_setheader("Content-Type","text/html");
  Printf(out,error401msg);
  return 0;
}

/* -----------------------------------------------------------------------------
 * SwillUnsupported()
 *
 * Unsupported HTTP method
 * ----------------------------------------------------------------------------- */

static char *error501msg = "\n\
<html><head><title>Not implemented</title></head>\n\
<body bgcolor=\"#ffffff\">\n\
<h1>Not implemented</h1>\n\
The server does not support '%s' requests.\n\
</body></html>\n";

int 
SwillUnsupported(DOH *out, void *clientdata) {
  swill_setresponse("501 Not Implemented");
  swill_setheader("Content-Type","text/html");
  Printf(out,error501msg,swill_getvar("__method__"));
  return 0;
}

/* -----------------------------------------------------------------------------
 * SwillInternalError()
 *
 * Internal server error.
 * ----------------------------------------------------------------------------- */

static char *error500msg = "\n\
<html><head><title>Internal Error</title></head>\n\
<body bgcolor=\"#ffffff\">\n\
<h1>Internal Error</h1>\n\
</plaintext>\n";

int 
SwillInternalError(DOH *out, void *clientdata) {
  swill_setresponse("500 Internal Error");
  swill_setheader("Content-Type","text/html");
  Printf(out,error500msg);
  return 0;
}

/* -----------------------------------------------------------------------------
 * SwillListHandlers()
 *
 * Print a list of all available handlers.
 * ----------------------------------------------------------------------------- */

int 
SwillListHandlers(DOH *out, void *clientdata) {
  DOH *namelist, *key, *item;
  int i;

  swill_setheader("Content-Type","text/html");
  Printf(out,"<html><head><title>%s</title></head>\n", swill_title(0));
  Printf(out,"<body bgcolor=\"#ffffff\">\n");
  Printf(out,"<h1>%s</h1>\n", swill_title(0));
  Printf(out,"<b>Registered Handlers</b>\n");
  Printf(out,"<ul>\n");
  namelist = NewList();
  for (key = Firstkey(Handlers); key; key = Nextkey(Handlers)) {
    Append(namelist,key);
  }
  /*  List_sort(namelist); */
  for (i = 0; i < Len(namelist); i++ ) {
    item = Getattr(Handlers,Getitem(namelist,i));
    Printf(out,"<li> <a href=\"%s\">%s</a>\n", Getattr(item,"servname"),Getattr(item,"servname"));
  }
  if (Len(namelist) == 0) {
    Printf(out,"<li> None\n");
  }
  Printf(out,"</ul>\n");

  /*
  if (swill_->docroot) {
    Printf(out,"<p><b>Document Root</b>\n");
    Printf(out,"<ul>\n");
    Printf(out,"<li><a href=\"/\">%s</a>\n", swill_w->docroot);
    Printf(out,"</ul>\n");
  }
  */

  Printf(out,"<hr>\n");
  Printf(out,"<em>SWILL %d.%d</em>\n", SWILL_MAJOR_VERSION, SWILL_MINOR_VERSION);
  Delete(namelist);
  return 0;
}

/* -----------------------------------------------------------------------------
 * swill_getvars()
 *
 * A high level function for grabbing form variables.   The user supplies a 
 * format string that specifies names and conversions.  For example:
 *
 *    swill_getvars("s(name)s(email)d(number)", &name, &email, &number)
 *
 * Returns 0 on failure.  1 on success.  
 * ----------------------------------------------------------------------------- */

static const char *isolate_name(const char *c, char *t) {
  int copy = 0;
  while (*c) {
    if (*c == '(') {
      copy = 1;
      c++;
      continue;
    }
    if (*c == ')') {
      *t = 0;
      return c;
    }
    if (copy) {
      *(t++) = *c;
    }
    c++;
  }
  *t = 0;
  return c - 1;
}

int 
swill_getargs(const char *fmt, ...) {
  const char *c;
  char name[256];
  va_list ap;
  int opt = 0;
  int code = 0;
  char *value = 0;
  void *ptr = 0;

  va_start(ap,fmt);
  c = fmt;

  /* Walk the fmt string and get arguments */
  while (*c) {
    if (*c == '|') {
      opt = 1;
      c++;
      continue;
    }
    code = *c;
    ptr = va_arg(ap, void *);
    c = isolate_name(c,name);
    value = swill_getvar(name);
    if (!value) {
      if (!opt) {   /* Not optional.  Error */
	va_end(ap);
	return 0;
      }
      c++;
      continue;
    }
    switch(code) {
    case 's':         /* String */
      *((char **) ptr) = value;
      break;
      
    case 'i':         /* Integer */
      *((int *) ptr) = (int) strtol(value,NULL,0);
      break;
      
    case 'l':         /* Long */
      *((long *) ptr) = atol(value);
      break;

    case 'h':         /* Short */
      *((short *) ptr) = (short) strtol(value,NULL,0);
      break;

    case 'b':         /* Byte */
      *((char *) ptr) = (char) strtol(value,NULL,0);
      break;

    case 'I':         /* unsigned integer */
      *((unsigned int *) ptr) = (unsigned int) strtoul(value, NULL, 0);
      break;
      
    case 'L':         /* unsigned long */
      *((unsigned long *) ptr) = (unsigned long) strtoul(value, NULL, 0);
      break;

    case 'H':         /* unsigned short */
      *((unsigned short *) ptr) = (unsigned short) strtoul(value,NULL,0);
      break;

    case 'B':         /* unsigned byte */
      *((unsigned char *) ptr) = (unsigned char) strtoul(value,NULL,0);
      break;

    case 'f':         /* Float */
      *((float *) ptr) = (float) atof(value);
      break;

    case 'd':         /* Double */
      *((double *) ptr) = atof(value);
      break;

    case 'p':
      *((void **) ptr) = (void *) strtoul(value, NULL, 0);
      break;

    default:
      break;
    }
    c++;
  }
  va_end(ap);
  return 1;
}

void
swill_printurl(FILE *f, const char *url, const char *fmt, ...) {
  const char *c;
  char name[256];
  va_list ap;
  int code = 0;
  char   *svalue;
  int     ivalue;
  unsigned int uivalue;
  long    lvalue;
  unsigned long ulvalue;
  double  dvalue;
  void *ptr = 0;
  int     first = 1;

  va_start(ap,fmt);
  
  fprintf(f,"%s",url);

  c = fmt;
  if (*c) {
    fprintf(f,"?");
  }
  /* Walk the fmt string and get arguments */
  while (*c) {
    code = *c;
    c = isolate_name(c,name);
    if (!first) {
      swill_fprintf(f,"&");
    }
    first = 0;
    switch(code) {
    case 's':         /* String */
      svalue = va_arg(ap, char *);
      swill_fprintf(f,"%s=%(url)s", name, svalue);
      break;
      
    case 'i':         /* Integer */
    case 'h':
    case 'b':
      ivalue = va_arg(ap, int);
      swill_fprintf(f,"%s=%(url)d", name, ivalue);
      break;
      
    case 'l':         /* Long */
      lvalue = va_arg(ap, long);
      swill_fprintf(f,"%s=%(url)ld", name, lvalue);
      break;

    case 'I':         /* unsigned integer */
    case 'H':
    case 'B':
      uivalue = va_arg(ap, unsigned);
      swill_fprintf(f,"%s=%(url)u", name, uivalue);
      break;
      
    case 'L':         /* unsigned long */
      ulvalue = va_arg(ap, unsigned long);
      swill_fprintf(f,"%s=%(url)ul", name, ulvalue);
      break;

    case 'f':         /* Float */
    case 'd':
      dvalue = va_arg(ap, double);
      swill_fprintf(f,"%s=%(url)0.17f", name, dvalue);
      break;

    case 'p':
      ptr = va_arg(ap, void *);
      swill_fprintf(f,"%s=%(url)p", name, ptr);
      break;

    default:
      break;
    }
    c++;
  }
  va_end(ap);
  return;
}






syntax highlighted by Code2HTML, v. 0.9.1