Logo Search packages:      
Sourcecode: w3cam version File versions  Download package

cgi.c

/*
 * CGI C-library, v1.1.1
 *
 * Copyright (C) '97,'98,'.. Rasca, Berlin
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdlib.h>           /* getenv() */
#include <stdio.h>            /* printf() */
#include <string.h>           /* strcat() */
#include <limits.h>           /* PATH_MAX */
#include <unistd.h>           /* getpid() */
#include <sys/stat.h>   /* stat() */
#include <sys/utsname.h>/* uname() */
#include <time.h>       /* time() */
#include "cgi.h"
#ifdef DEBIAN
#define DEFAULT_CFGFILE "/etc/w3cam.cgi.scf"
#endif

#define MAX_LINE  1024
#define EMPTY           '\0'

static char *cgi_background = NULL;
static char *cgi_foreground = NULL;
static char *cgi_stylesheet = NULL;
static char *cgi_source_url = NULL;
static char *cgi_loggingdir = NULL;
static char *cgi_defaultmta = NULL;
static char *cgi_bottomline = NULL;
static char *cgi_meta_desc = NULL;
static char *cgi_meta_keyw = NULL;
static char **cgi_form = NULL;
static char **cgi_cfg = NULL;
static char *program = NULL;
static const char *prog_wp = NULL;
static int  run_as_nph = 0;
static int  cgi_refresh_time = 0;
static char *cgi_refresh_url = 0;

/* http 1.0 status codes
 */
static http_code http[] =
      { /*
      status code, reason-phrase
            */
      { 100, "Continue" },                                  /* 1.1 */
    { 200, "Ok" },
    { 201, "Created" },
    { 202, "Accepted" },
      { 203, "Non-Authoritative Information"},  /* 1.1 */
    { 204, "No Content" },
      { 205, "Reset Content" },                             /* 1.1 */
    { 301, "Moved Permanently" },
    { 302, "Moved Temporarily" },
    { 304, "Not Modified" },
      { 305, "Use Proxy" },                                 /* 1.1 */
    { 400, "Bad Request" },
    { 401, "Unauthorized" },
    { 403, "Forbidden" },
    { 404, "Not Found" },
      { 410, "Gone" },                                      /* 1.1 */
    { 500, "Internal Server Error" },
    { 501, "Not Implemented" },
    { 502, "Bad Gateway" },
    { 503, "Service Unavailable" },
    { 000, NULL },
    };

/*
 * return RFC 822, 1123 date string
 * next call will override previous value!
 */
char *
cgi_gmt_str (long date)
{
      char *day[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
      char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
      static char str[48];    /* should be enough */
      struct tm *s;

      s = gmtime (&date);
      sprintf (str, "%s, %02d %s %d %02d:%02d:%02d GMT", day[s->tm_wday],
                  s->tm_mday, mon[s->tm_mon], s->tm_year + 1900, s->tm_hour,
                  s->tm_min, s->tm_sec);
      return (str);
}


/*
 * returns the url, where the cgi is included/started
 */
const char *
cgi_url_ref ()
{
      char *url;
      static char urlb[URL_MAX+1];

      url = getenv ("HTTP_REFERER");
      if (!url) {
            /* not CGI conform, but try ..
             */
            url = getenv ("REFERER_URL");
      }
      if (!url) {
            url = getenv ("DOCUMENT_URI");
            if (url) {
                  urlb[0] = '\0';
                  strcat (urlb, "http://");
                  strcat (urlb, cgi_server_name());
                  strcat (urlb, ":");
                  strcat (urlb, getenv("SERVER_PORT"));
                  strcat (urlb, url);
                  url = urlb;
            } else {
                  const char *server;
                  /* may be lynx is starting local CGIs ..? */
                  server = cgi_server_software();
                  if (server && prog_wp) {
                        if (strstr (server, "Lynx")) {
                              if ((strlen (prog_wp) + 8) < URL_MAX) {
                                    sprintf (urlb, "lynxcgi:%s", prog_wp);
                                    url = urlb;
                              }
                        }
                  }
            }
      }
      if (url) {
            if (*url == '\0') {
                  url = NULL;
            }
      }
      return (url);
}


/*
 * returns the name of the server software
 */
const char *
cgi_server_software (void)
{
      return (getenv ("SERVER_SOFTWARE"));
}

/*
 * returns the name of the server
 */
const char *
cgi_server_name (void)
{
      const char *sn;
      struct utsname un;

      sn = getenv ("SERVER_NAME");
      if (!sn) {
            sn = getenv ("HOSTNAME");
            if (!sn) {
                  uname (&un);
                  sn = un.nodename;
            }
      }
      return (sn);
}

/*
 * returns the name of the script
 */
const char *
cgi_script_name (void)
{
      const char *sn = NULL;
      const char *server;
      static char url[URL_MAX+1];

      sn = getenv ("SCRIPT_NAME");
      if (!sn) {
            /* lynx cgi ? */
            server = cgi_server_software();
            if (server && prog_wp) {
                  if (strstr (server, "Lynx")) {
                        if ((strlen (prog_wp) + 8) < URL_MAX) {
                              sprintf (url, "lynxcgi:%s", prog_wp);
                              sn = url;
                        }
                  }
            }
      }
      return (sn);
}

/*
 * returns the name of the browser software
 */
const char *
cgi_client_software (void)
{
      return (getenv ("HTTP_USER_AGENT"));
}

/*
 */
const char *
cgi_remote_host (void)
{
      const char *host;

      host = getenv ("REMOTE_HOST");
      if (!host)
            return ( getenv ("REMOTE_ADDR") );
      return ( host );
}

/*
 * print a http status line
 */
void
cgi_status (int num)
{
      printf ("HTTP/1.0 %d %s\r\n", http[num].num, http[num].str);
}

/*
 * send the content type given in "ct", if "name" is not
 * NULL it is added in the following way, e.g.
 * Content-Type: text/html; name="foo.gif"
 */
void
cgi_content_type (const char *ct, const char *name)
{
      if (run_as_nph) {
            cgi_status (http_ok);
            printf ("Server: %s/libcgi/%s\r\n", program, VER);
            printf ("Date: %s\r\n", cgi_gmt_str (time(NULL)));
      }
      if (name) {
            printf ("Content-Type: %s; name=\"%s\"\r\n\r\n", ct, name);
      } else {
            printf ("Content-Type: %s\r\n\r\n", ct);
      }
}

/*
 */
void
cgi_multipart (const char *boundary)
{
      if (run_as_nph) {
            cgi_status (http_ok);
            printf ("Server: %s/libcgi/%s\r\n", program, VER);
            printf ("Date: %s\r\n", cgi_gmt_str (time(NULL)));
      }
      printf ("Content-Type: multipart/x-mixed-replace;boundary=%s\n", boundary);
      printf ("\n%s\n", boundary);
}

/*
 * send a status line and content type if 'content_t' is not NULL,
 * e.g. cgi_response (http_ok, "text/html");
 */
void
cgi_response (int num, char *content_t)
{
      if (run_as_nph) {
            cgi_status (num);
            printf ("Server: %s/libcgi/%s\r\n", program, VER);
            printf ("Date: %s\r\n", cgi_gmt_str (time(NULL)));
      }
      if (content_t) {
            printf ("Content-Type: %s\r\n", content_t);
      }
      printf ("\r\n");
}

/*
 * return the base url
 */
const char *
cgi_base (void)
{
      static char base[URL_MAX+1];
      const char *url_ref, *p;
      int i, len;

      url_ref = cgi_url_ref();
      if (url_ref) {
            len = strlen (url_ref);
            if (url_ref[len-1] == '/') {
                  strcpy (base, url_ref);
            } else {
                  p = strrchr (url_ref, '/');
                  if (p) {
                        i = 0;
                        while (url_ref < (p+1)) {
                              base[i] = *url_ref;
                              url_ref++;
                              i++;
                        }
                        base[i] = '\0';
                  } else {
                        /* should never be reached ..! */
                        return (NULL);
                  }
            }
            return (base);
      }
      return (NULL);
}

/*
 * redirect to the given url, which could be a relative or an
 * absolute url. note: relative urls could be a problem with
 * some browsers, cause sometimes there is no way to find out
 * the "REFERER"..
 */
void
cgi_redirect (const char *url)
{
      const char *p, *s, *hash;
      char buff[URL_MAX+1];

      if (run_as_nph) {
            cgi_status (http_moved_permanently);
            printf ("Server: %s/libcgi/%s\r\n", program, VER);
            printf ("Date: %s\r\n", cgi_gmt_str (time(NULL)));
      }
      if (strstr (url, "://") > url) {
            /* itīs an absolute URL ..
             */
            printf ("Location: %s\r\n", url);
      } else if (*url == '/') {
            /* relative URL which starts at the root
             */
            if ((s = p = cgi_base ()) != NULL ) {
                  int i;
                  for (i = 0; i < 3; i++) {
                        if (p) {
                              p = strchr (p, '/');
                        }
                        p++;
                  }
                  if (p) {
                        strncpy (buff, s, p-s-1);
                        buff[p-s-1] = '\0'; 
                        printf ("Location: %s%s\r\n", buff, url);
                  } else {
                        printf ("Location: %s\r\n", url);
                  }
            } else {
                  printf ("Location: %s\r\n", url);
            }
      } else if (*url == '#') {
            p = cgi_url_ref();
            if (p) {
                  hash = strrchr (p, '#');
                  if (!hash) {
                        printf ("Location: %s%s\r\n", p, url);
                  } else {
                        /* there is still a name value, we have to remove it ..
                         */
                        strncpy (buff, p, hash-p);
                        buff[hash-p] = '\0';
                        strcat (buff, url);
                        printf ("Location: %s\r\n", buff);
                  }
            } else
                  printf ("Location: %s\r\n", url);
      } else {
            /* some other kind of relative URL..
             */
            p = cgi_base();
            printf ("Location: %s%s\r\n", p ? p:"", url);
      }
      printf ("Content-Type: text/html\r\n\r\n");
}

/*
 * lock a name file
 */
int
cgi_lock (const char *file)
{
      char pfile[PATH_MAX+1];
      char lfile[PATH_MAX+1];
      FILE *pfp;
      int pid, loop;
      struct stat info;

      loop = 5; /* try five times to lock .. */
      pid = getpid();
      strcpy (pfile, file);
      sprintf (pfile+strlen(file), ".%d", pid);
      strcpy (lfile, file);
      strcat (lfile, ".LCK");

      pfp = fopen (pfile, "wb");
      if (!pfp) {
            perror (pfile);
            return (0);
      }
      fwrite (&pid, sizeof (pid), 1, pfp);
      fclose (pfp);
      while ((stat (lfile, &info) == 0) || (link (pfile, lfile) != 0)) {
            sleep (1);
            loop--;
            if (loop < 1) {
                  unlink (pfile);
                  return (0);
            }
      }
      return (1);
}


/*
 * unlock the named file
 */
int
cgi_unlock (const char *file)
{
      char pfile[PATH_MAX+1];
      char lfile[PATH_MAX+1];
      int pid;

      pid = getpid();
      strcpy (pfile, file);
      sprintf (pfile+strlen(file), ".%d", pid);
      strcpy (lfile, file);
      strcat (lfile, ".LCK");
      unlink (pfile);
      unlink (lfile);
      return (1);
}



/*
 */
void
cgi_html_start (const char *title)
{
      printf ("<HTML>\n");
      printf ("<HEAD>\n");
      printf ("\t<TITLE>%s</TITLE>\n", title);
      if (cgi_source_url) {
            printf ("\t<!-- source: %s -->\n", cgi_source_url);
      }
      if (cgi_meta_desc) {
            printf ("\t<META name=\"description\" content=\"%s\">\n",
                        cgi_meta_desc);
      }
      if (cgi_meta_keyw) {
            printf ("\t<META name=\"keywords\" content=\"%s\">\n",
                        cgi_meta_keyw);
      }
      if (cgi_refresh_time > 0) {
            printf ("\t<META http-equiv=refresh content=\"%d; url='",
                        cgi_refresh_time);
            if (cgi_refresh_url)
                  printf ("%s'\">\n", cgi_refresh_url);
            else if (getenv("QUERY_STRING"))
                  printf ("%s?%s'\">\n", cgi_script_name(), getenv("QUERY_STRING"));
            else
                  printf ("%s'\">\n", cgi_script_name());
      }
      if (cgi_stylesheet) {
            printf ("\t<LINK rel=stylesheet href=\"%s\">\n", cgi_stylesheet);
      }
      printf ("</HEAD>\n");
      printf ("<BODY");
      if (cgi_background) {
            if (*cgi_background == '/') {
                  printf (" background=\"%s\"", cgi_background);
            } else {
                  printf (" bgcolor=\"%s\"", cgi_background);
            }
      }
      if (cgi_foreground)
            printf (" text=\"%s\"", cgi_foreground);
      printf (">\n");
}

/*
 */
void
cgi_html_end (const char *s)
{
      if (s) {
            printf ("%s\n", s);
      }
      if (cgi_bottomline) {
            printf ("%s\n", cgi_bottomline);
      }
      printf ("</BODY>\n</HTML>\n");
}


/*
 */
const char *
cgi_sourceURL (void)
{
      return (cgi_source_url);
}

/*
 */
const char *
cgi_logdir (void)
{
      return (cgi_loggingdir);
}

/*
 */
const char *
cgi_defaultMTA (void)
{
      return (cgi_defaultmta);
}

/*
 */
int
cgi_init (const char *pname)
{
#     define CFG_bg     "background"
#     define CFG_fg     "foreground"
#     define CFG_css    "stylesheet"
#     define CFG_src    "source_url"
#     define CFG_log    "loggingdir"
#     define CFG_btl    "bottomline"
#     define CFG_mta    "detaultMTA"
#     define CFG_desc   "meta_desc"
#     define CFG_keyw   "meta_keyw"
      char cfgfile[PATH_MAX+1];
      char buff[MAX_LINE], *p;
      char key[256], value[256];
      FILE *fp;
      int len;
      int cfg_num = 0;

      prog_wp = pname;
      program = strrchr (pname, '/');
      if (program) program++;
      else program = (char *)pname;
      if (strstr (program, "nph-"))
            run_as_nph = 1;
      strcpy (cfgfile, pname);
      strcat (cfgfile, ".scf");
      fp = fopen (cfgfile, "rb");
#ifdef DEBIAN
    if (!fp)
        fp = fopen (DEFAULT_CFGFILE, "rb");
#endif
      if (!fp) {
            return (0);
      }
      while (fgets (buff, MAX_LINE, fp) != NULL) {
            p = buff;
            while (*p && (*p == ' ' || *p == '\t'))
                  p++;
            if (*p == '#')
                  continue;
            *value = EMPTY;
            sscanf (p, " %[^= \t] = %[^\n]", key, value);
            if (*value) {
                  len = strlen (value);
                  if (len > 0) {
                        if (*value == '"') {
                              /* remove quote chars */
                              memmove (value, value+1, len + 1);
                              p = strrchr (value, '"');
                              if (p)
                                    *p = EMPTY;
                        } else {
                              /* use last white char as end point */
                              p = strchr (value, '\t');
                              if (p)
                                    *p = EMPTY;
                              else {
                                    p = strchr (value, ' ');
                                    if (p)
                                          *p = EMPTY;
                              }
                        }
                  }
            } else {
                  continue;
            }
#ifdef DEBUG
            fprintf (stderr, "key=%s, value=%s\n", key, value);
#endif
            len = strlen (key);
            if ((len == strlen (CFG_bg)) && (strcmp (key, CFG_bg) ==0)) {
                  cgi_background = (char *) malloc (strlen (value) +1);
                  strcpy (cgi_background, value);
            } else
            if ((len == strlen (CFG_fg)) && (strcmp (key, CFG_fg) ==0)) {
                  cgi_foreground = (char *) malloc (strlen (value) +1);
                  strcpy (cgi_foreground, value);
            } else
            if ((len == strlen (CFG_css)) && (strcmp (key, CFG_css) ==0)) {
                  cgi_stylesheet = (char *) malloc (strlen (value) +1);
                  strcpy (cgi_stylesheet, value);
            } else
            if ((len == strlen (CFG_src)) && (strcmp (key, CFG_src) ==0)) {
                  cgi_source_url = (char *) malloc (strlen (value) +1);
                  strcpy (cgi_source_url, value);
            } else
            if ((len == strlen (CFG_log)) && (strcmp (key, CFG_log) ==0)) {
                  cgi_loggingdir = (char *) malloc (strlen (value) +1);
                  strcpy (cgi_loggingdir, value);
            } else
            if ((len == strlen (CFG_btl)) && (strcmp (key, CFG_btl) ==0)) {
                  cgi_bottomline = (char *) malloc (strlen (value) +1);
                  strcpy (cgi_bottomline, value);
            } else
            if ((len == strlen (CFG_mta)) && (strcmp (key, CFG_mta) ==0)) {
                  cgi_defaultmta = (char *) malloc (strlen (value) +1);
                  strcpy (cgi_defaultmta, value);
            } else
            if ((len == strlen (CFG_desc)) && (strcmp (key, CFG_desc) ==0)) {
                  cgi_meta_desc = (char *) malloc (strlen (value) +1);
                  strcpy (cgi_meta_desc, value);
            } else
            if ((len == strlen (CFG_keyw)) && (strcmp (key, CFG_keyw) ==0)) {
                  cgi_meta_keyw = (char *) malloc (strlen (value) +1);
                  strcpy (cgi_meta_keyw, value);
            } else {
                  /* private configuration data
                   */
                  cfg_num += 2;
                  if (cfg_num == 2) {     /* first time */
                        cgi_cfg = calloc (3, sizeof(char *));
                  } else {
                        cgi_cfg = realloc (cgi_cfg, (cfg_num+1) * sizeof (char *));
                  }
                  cgi_cfg[cfg_num-2] = strdup (key);
                  cgi_cfg[cfg_num-1] = strdup (value);
                  cgi_cfg[cfg_num] = NULL;
            }
      }
      fclose (fp);
      return (1);
}


/*
 */
int
cgi_content (void)
{
      char *c;
      c = getenv ("CONTENT_TYPE");
      if (c) {
            if (strstr (c, "multipart/form-data"))
                  return (MULTIPART_FORM);
      }
      return (0);
}


/*
 * returns the method: CGI_METHOD_{GET|POST|PUT}
 */
int
cgi_method (void)
{
      const char *method;
      int rc = 0;

      method = getenv ("REQUEST_METHOD");
      if (method) {
            if (strcmp (method, "GET") == 0)
                  rc = CGI_METHOD_GET;
            else if (strcmp (method, "POST") == 0)
                  rc = CGI_METHOD_POST;
            else if (strcmp (method, "PUT") == 0)
                  rc = CGI_METHOD_PUT;
            else if (strcmp (method, "DELETE") == 0)
                  rc = CGI_METHOD_DELETE;
      }
      return (rc);
}

/*
 */
static char *
hex_to_asc (const char *str, int len)
{
      char *p, *s;
      char buff[4];
      int chr;

      if (!str)
            return (NULL);
      s = (char *) malloc (len + 1);
      p = s;
      buff[2] = '\0';
      while (*str && len) {
            if (*str == '%') {
                  strncpy (buff, str+1, 2);
                  sscanf (buff, "%02X", &chr);
                  *p = (unsigned char) chr;
                  str += 3;
                  len -= 3;
            } else {
                  if (*str == '+')
                        *p = ' ';
                  else
                        *p = *str;
                  str++;
                  len--;
            }
            p++;
      }
      *p = '\0';
      return (s);
}


/*
 */
char **
cgi_parse_string (const char *str)
{
      char **kv = NULL;
      const char *p, *end;
      int num = 1, i;
      int len;

      if (!str)
            return (NULL);
      p = str;
      while ((p = strchr (p, '&')) != NULL) {
            num++;
            p++;
      }
      kv = (char **) calloc ((num * 2 +1), sizeof (char **));
      p = str;
      i = 0;
      do {
            len = 0;
            if (*p == '&') {
                  p++;
            }
            end = p;
            while ((*end != '=') && (*end != '\0') && (*end != '&')) {
                  len++;
                  end++;
            }
            kv[i] = hex_to_asc (p, len);
            if (*end == '&') {
                  /* variable has no value .. */
                  p += len;
                  i++;
                  continue;
            }
            p += len+1;
            end = p;
            i++;
            len = 0;
            while ((*end != '&') && (*end != '\0')) {
                  len++;
                  end++;
            }
            kv[i] = hex_to_asc (p, len);
            if (len > 0)
                  p++;
            i++;
      } while ((p = strchr (p, '&')) != NULL);
      return (kv);
}

/*
 * return content length as int
 */
int
cgi_content_length (void)
{
      const char *len_env;
      int len = 0;

      len_env = getenv ("CONTENT_LENGTH");
      if (!len_env)
            return (0);
      sscanf (len_env, " %d ", &len);
      return (len);
}

/*
 * read multipart request
 * still not ready!
 */
mime **
cgi_parse_multipart (void)
{
      mime **mpart = NULL;
      char *boundary;
      char line[MAX_LINE];
      int len, sl, read = 0, max = MAX_LINE;

      boundary = getenv("CONTENT_TYPE");
      boundary = strstr (boundary, "boundary=");
      len = cgi_content_length ();
      if (!boundary || !len)
            return (NULL);

      if (len < MAX_LINE)
            max = len;
      boundary += 9;
      do {
            /* find the start boundary
             */
            fgets (line, max, stdin);
            read += strlen (line);
            if (strstr (line, boundary))
                  break;
      } while (read < len);

      printf ("found\n");
      do {
            fgets (line, max, stdin);
            sl = strlen (line);
            if (sl >= 20) {
                  if (strncasecmp (line, "content-disposition:", 20)) {
                  }
            }
            read += sl;
      } while (read < len);
      return (mpart);
}


/*
 * read stdin and encode query data
 */
char **
cgi_parse_stdin (void)
{
      char **form = NULL;
      char *buff;
      int len;

      len = cgi_content_length();
      if (!len)
            return (NULL);
      buff = (char *) malloc (len+1);
      buff[len] = '\0';
      fread (buff, 1, len, stdin);
      form = cgi_parse_string(buff);
      free (buff);
      return (form);
}

/*
 */
char **
cgi_parse_query (void)
{
      char *qs = getenv ("QUERY_STRING");
      if (!qs)
            return (NULL);
      return (cgi_parse_string (qs));
}

/*
 * parse a formular, not depending on the request method
 * PUT method not done until now
 */
char **
cgi_parse_form (void)
{
      int method;

      /* changes globals! (cgi_form) */
      method = cgi_method();
      if (method == CGI_METHOD_POST) {
            if (cgi_content() == MULTIPART_FORM)
                  cgi_form = (char **) cgi_parse_multipart ();
            else
                  cgi_form = cgi_parse_stdin();
      } else if (method == CGI_METHOD_GET)
            cgi_form = cgi_parse_query();
      else
            cgi_form = NULL;
      return (cgi_form);
}

/*
 * return the corresponding value for a given key
 */
char *
cgi_form_value (const char *key)
{
      char **form;
      if (!key)
            return (NULL);
      if (!cgi_form)
            return (NULL);
      form = cgi_form;
      while (*form) {
            if (strcmp (key, *form) == 0)
                  return (*(form+1));
            form += 2;
      }
      return (NULL);
}

/*
 * return the corresponding value for a given key
 */
char *
cgi_cfg_value (const char *key)
{
      char **cfg;
      if (!key)
            return (NULL);
      if (!cgi_cfg)
            return (NULL);
      cfg = cgi_cfg;
      while (*cfg) {
            if (strcmp (key, *cfg) == 0)
                  return (*(cfg+1));
            cfg += 2;
      }
      return (NULL);
}

/*
 * set refresh time, use 0 to disable
 */
void
cgi_refresh (int t, char *url)
{
      cgi_refresh_time = t;
      cgi_refresh_url = url;
}


Generated by  Doxygen 1.6.0   Back to index