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

cgi.c

/*
 * 
 * cgi.c -
 * 
 * $Id: cgi.c,v 1.61.4.17 2006/08/16 17:28:32 opengl2772 Exp $
 * 
 * Copyright (C) 1997-1999 Satoru Takabayashi All rights reserved.
 * Copyright (C) 2000-2005 Namazu Project All rights reserved.
 * This is free software with ABSOLUTELY NO WARRANTY.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA
 * 
 * 
 */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
# ifdef _WIN32
# include <io.h>
# endif
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif

#include "namazu.h"
#include "libnamazu.h"
#include "util.h"
#include "usage.h"
#include "message.h"
#include "cgi.h"
#include "output.h"
#include "field.h"
#include "hlist.h"
#include "i18n.h"
#include "idxname.h"
#include "var.h"
#include "util.h"
#include "system.h"

/*
 *
 * Private functions
 *
 */

static int validate_idxname ( const char * idxname );
static void remove_ending_slashes ( char *str );
static struct cgivar * add_cgivar ( struct cgivar *ptr, const char *name, char *value );
static void free_cgi_vars ( struct cgivar *cv );
static char * get_query_string ( void );
static struct cgivar * get_cgi_vars ( const char *qs );
static int process_cgi_vars ( struct cgiarg *ca );
static int apply_cgifunc ( const struct cgivar *cv, struct cgiarg *ca );
static void process_cgi_var_query ( char *value, struct cgiarg *ca );
static void process_cgi_var_subquery ( char *value, struct cgiarg *ca );
static void process_cgi_var_format ( char *value, struct cgiarg *ca );
static void process_cgi_var_sort ( char *value, struct cgiarg *ca );
static void process_cgi_var_max ( char *value, struct cgiarg *ca );
static void process_cgi_var_whence ( char *value, struct cgiarg *ca );
static void process_cgi_var_lang ( char *value, struct cgiarg *ca );
static void process_cgi_var_result ( char *value, struct cgiarg *ca );
static void process_cgi_var_reference ( char *value, struct cgiarg *ca );
static void process_cgi_var_submit ( char *value, struct cgiarg *ca );
static void process_cgi_var_idxname ( char *value, struct cgiarg *ca );

/*
 * Table for cgi vars and corresponding functions. 
 * This table must be under function prototypes.
 */
static struct cgivar_func cgifunctab[] = {
    { "query",     process_cgi_var_query },
    { "key",       process_cgi_var_query },  /* backward comat. */
    { "subquery",  process_cgi_var_subquery },
    { "format",    process_cgi_var_format }, /* backward comat. */
    { "sort",      process_cgi_var_sort },
    { "max",       process_cgi_var_max },
    { "whence",    process_cgi_var_whence },
    { "lang",      process_cgi_var_lang },
    { "result",    process_cgi_var_result },
    { "reference", process_cgi_var_reference },
    { "idxname",   process_cgi_var_idxname },
    { "dbname",    process_cgi_var_idxname },  /* backward comat. */
    { "submit",    process_cgi_var_submit },
    { NULL,        NULL }   /* sentry */
};

/*
 * Validate idxname. (if it contain '/', it's invalid)
 */
static int 
validate_idxname(const char * idxname)
{
    int win32 = 0;
#if  defined(_WIN32) || defined(__EMX__)
    win32 = 1;
#endif

    if (*idxname == '\0' || *idxname == '/' || (win32 && *idxname == '\\')) {
        printf("%s text/html" CRLF CRLF, MSG_MIME_HEADER);
      puts_entitize(idxname);
      printf(" : ");
        printf(_("Invalid idxname."));
        exit(EXIT_FAILURE);
    }
    while (*idxname) {
        if (nmz_strprefixcasecmp("../", idxname) == 0 ||
          strcmp("..", idxname) == 0 ||
            (win32 && nmz_strprefixcasecmp("..\\", idxname) == 0) || 
            (win32 && nmz_strprefixcasecmp("..." , idxname) == 0)) 
        {
          printf("%s text/html" CRLF CRLF, MSG_MIME_HEADER);
          puts_entitize(idxname);
          printf(" : ");
            printf(_("Invalid idxname."));
            exit(EXIT_FAILURE);
        }
      /* Skip until next '/' */
      while (*idxname && *idxname != '/' && !(win32 && *idxname == '\\')) {
          idxname++;
      }
      /* Skip '/' */
      if (*idxname) {
          idxname++;
      }
    }
    return 1;
}

static void 
remove_ending_slashes(char *str)
{
    int win32 = 0;
#if  defined(_WIN32) || defined(__EMX__)
    win32 = 1;
#endif

    str = str + strlen(str) - 1;

    while (*str == '/' || (win32 && *str == '\\')) {
        *str = '\0';
        str--;
    }
}

static struct cgivar *
add_cgivar(struct cgivar *ptr, const char *name, char *value)
{
    struct cgivar *tmp;

    tmp = malloc(sizeof(struct cgivar));
    if (tmp == NULL) {
       printf("add_cgivar_malloc");
       return NULL;
    }
    tmp->name = malloc(strlen(name) + 1);
    if (tmp->name == NULL) {
       printf("add_cgivar_malloc");
         free(tmp);
       return NULL;
    }

    tmp->value = malloc(strlen(value) + 1);
    if (tmp->value == NULL) {
       printf("add_cgivar_malloc");
         free(tmp->name);
         free(tmp);
       return NULL;
    }

    strcpy(tmp->name, name);
    strcpy(tmp->value, value);
    tmp->next = ptr;
    return tmp;
}

static void 
free_cgi_vars(struct cgivar *cv)
{
    if (cv == NULL)
      return;
    free(cv->name);
    free(cv->value);
    free_cgi_vars(cv->next);
    free(cv);
}

static char *
get_query_string(void) 
{
    int contlen;
    char *script_name    = "";
    char *query_string   = "";

    if ((query_string = getenv("QUERY_STRING"))) {
        /* 
       * get QUERY_STRING from environmental variables.
       */
        contlen = strlen(query_string);
        if (contlen > CGI_QUERY_MAX) {
          die("%s", _("Too long QUERY_STRING"));
        }
      script_name = getenv("SCRIPT_NAME");
        if (script_name == NULL) {
            return NULL;
        }
    } else if (!(nmz_strprefixcasecmp(getenv("SERVER_SOFTWARE"), "Microsoft-"))
            || !(nmz_strprefixcasecmp(getenv("SERVER_SOFTWARE"), "AnWeb"))
            || !(nmz_strprefixcasecmp(getenv("SERVER_SOFTWARE"), "iPlanet-"))) {
      query_string = "";
      script_name = getenv("SCRIPT_NAME");
        if (script_name == NULL) {
            return NULL;
        }
    } else {
      /* Must not be reached here. */
      assert(0);
    }
    return query_string;
}

static struct cgivar *
get_cgi_vars(const char *querystring)
{
    struct cgivar *cv = NULL; /* SHOULD BE NULL for sentinel! */

    while (1) {
      int len;
      const char *tmp;
        char *pSemicolon;
      char name[BUFSIZE];
      char value[BUFSIZE];

        name[BUFSIZE - 1] = '\0';

      tmp = strchr(querystring, '=');
      if (tmp == NULL) {
          break;
      }
      len = tmp - querystring;
      if (len >= BUFSIZE) {
          len = BUFSIZE - 1;
          nmz_warn_printf("%s", "truncating a CGI paramater name.\n");
      }
      strncpy(name, querystring, len);
      *(name + len) = '\0';
      querystring += len;

      querystring++;
      tmp = strchr(querystring, '&');
        pSemicolon = strchr(querystring, ';');
        if (tmp == NULL || (pSemicolon && (tmp > pSemicolon))) {
            tmp = pSemicolon;
        }
        if (tmp == NULL) {
          tmp = querystring + strlen(querystring);  /* last point: '\0' */
      }
      len = tmp - querystring;
      if (len >= BUFSIZE) {
          len = BUFSIZE - 1;
          nmz_warn_printf("%s", "truncating a CGI paramater value.\n");
      }
      strncpy(value, querystring, len);
      *(value + len) = '\0';
      nmz_decode_uri(value);
      querystring += len;

      cv = add_cgivar(cv, name, value);

      if (cv == NULL) {
          fprintf(stderr, "an error occurred at add_cgivar.\n");
          exit(EXIT_FAILURE);
      }

      if (*querystring == '\0') {
          break;
      }
      querystring++;
    }
    return cv;
}

static int 
process_cgi_vars(struct cgiarg *ca)
{
    char *qs;
    struct cgivar *cv;

    qs = get_query_string();
    if (qs == NULL) {
      return 1; /* NOT CGI */
    }
    cv = get_cgi_vars(qs);

    for (; cv != NULL; cv = cv->next) {
      if (!apply_cgifunc(cv, ca)) {
          /* Message for httpd's error_log */
          nmz_warn_printf("unknown cgi var: %s=%s\n", cv->name, cv->value);
      }
    }
    free_cgi_vars(cv);
    return 0;
}

static int 
apply_cgifunc(const struct cgivar *cv, struct cgiarg *ca) 
{
    struct cgivar_func *cf = cgifunctab;

    for (; cf->name != NULL; cf++) {
      if (strcmp(cv->name, cf->name) == 0) {
          cf->func(cv->value, ca);
          return 1;  /* applied */
      }
    }
    return 0; /* not applied */
}

static void 
process_cgi_var_query(char *value, struct cgiarg *ca)
{
    if (strlen(value) > QUERY_MAX) {
      die(nmz_strerror(ERR_TOO_LONG_QUERY));
    }
#ifdef MSIE4MACFIX
#define MSIE4MAC "Mozilla/4.0 (compatible; MSIE 4.01; Mac"

    if (nmz_strprefixcasecmp(value, "%1B") == 0) {
      char *agent = getenv("HTTP_USER_AGENT");
      if (agent && nmz_strprefixcasecmp(agent, MSIE4MAC) == 0) {
          nmz_decode_uri(value);
      }
    }
#endif /* MSIE4MACFIX */

    strcpy(ca->query, value);
}

static void 
process_cgi_var_subquery(char *value, struct cgiarg *ca)
{
    if (strlen(value) > QUERY_MAX) {
      die(nmz_strerror(ERR_TOO_LONG_QUERY));
    }
#ifdef MSIE4MACFIX
#define MSIE4MAC "Mozilla/4.0 (compatible; MSIE 4.01; Mac"

    if (nmz_strprefixcasecmp(value, "%1B") == 0) {
      char *agent = getenv("HTTP_USER_AGENT");
      if (agent && nmz_strprefixcasecmp(agent, MSIE4MAC) == 0) {
          nmz_decode_uri(value);
      }
    }
#endif /* MSIE4MACFIX */

    strcpy(ca->subquery, value);
}

/*
 * This function is for backward compatibility with 1.3.0.x
 */
static void 
process_cgi_var_format(char *value, struct cgiarg *ca)
{
    if (strcmp(value, "short") == 0) {
      set_templatesuffix("short");
    } else if (strcmp(value, "long") == 0) {
      set_templatesuffix("normal");
    }
}

static void 
process_cgi_var_sort(char *value, struct cgiarg *ca)
{
    if (nmz_strprefixcasecmp(value, "score") == 0) {
      nmz_set_sortmethod(SORT_BY_SCORE);
      nmz_set_sortorder(DESCENDING);
    } if (nmz_strprefixcasecmp(value, "later") == 0) {  /* backward compat. */
      nmz_set_sortmethod(SORT_BY_DATE);
      nmz_set_sortorder(DESCENDING);
    } if (nmz_strprefixcasecmp(value, "earlier") == 0) { /* backward compat. */
      nmz_set_sortmethod(SORT_BY_DATE);
      nmz_set_sortorder(ASCENDING);
    } else if (nmz_strprefixcasecmp(value, "date:late") == 0) {
      nmz_set_sortmethod(SORT_BY_DATE);
      nmz_set_sortorder(DESCENDING);
    } else if (nmz_strprefixcasecmp(value, "date:early") == 0) {
      nmz_set_sortmethod(SORT_BY_DATE);
      nmz_set_sortorder(ASCENDING);
    } else if (nmz_strprefixcasecmp(value, "field:") == 0) {
      int n;
      char field[BUFSIZE];

      value += strlen("field:");
      n = strspn(value, FIELD_SAFE_CHARS);
      strncpy(field, value, n);
      field[n] = '\0';  /* Hey, don't forget this after strncpy()! */
      nmz_set_sortfield(field);

      value += n;
      nmz_set_sortmethod(SORT_BY_FIELD);
      if (nmz_strprefixcasecmp(value, ":ascending") == 0) {
          nmz_set_sortorder(ASCENDING);
          value += strlen(":ascending");
      } else if (nmz_strprefixcasecmp(value, ":descending") == 0) {
          nmz_set_sortorder(DESCENDING);
          value += strlen(":descending");
      }
    } 
}

static void 
process_cgi_var_max(char *value, struct cgiarg *ca)
{
    int max;

    if (sscanf(value, "%d", &max) != 1) {
        return;
    }

    if (max < 0)
      max = 0;
    if (max > RESULT_MAX)
      max = RESULT_MAX;

    set_maxresult(max);
}

static void 
process_cgi_var_whence(char *value, struct cgiarg *ca)
{
    int whence;

    if (sscanf(value, "%d", &whence) != 1) {
        return;
    }

    if (whence < 0) {
      whence = 0;
    }
    set_listwhence(whence);
}

static void 
process_cgi_var_lang(char *value, struct cgiarg *ca)
{
    nmz_set_lang(value);
}

static void 
process_cgi_var_result(char *value, struct cgiarg *ca)
{
    set_templatesuffix(value);
}

static void 
process_cgi_var_reference(char *value, struct cgiarg *ca)
{
    if (strcmp(value, "off") == 0) {
      set_refprint(0);
    }
    
}

static void 
process_cgi_var_submit(char *value, struct cgiarg *ca)
{
    /* Do nothing; */
}

static void 
process_cgi_var_idxname(char *value, struct cgiarg *ca)
{
    char *pp;

    for (pp = value; *pp ;) {
      char name[BUFSIZE] = "", tmp[BUFSIZE] = "", *x;

      if ((x = (char *)strchr(pp, (int)','))) {
          *x = '\0';
          strncpy(name, pp, BUFSIZE);
          name[BUFSIZE - 1] = '\0';
          pp = x + 1;
      } else {
          strncpy(name, pp, BUFSIZE);
          name[BUFSIZE - 1] = '\0';
          pp += strlen(pp);
      }
      validate_idxname(name);
      remove_ending_slashes(name);

      strncpy(tmp, nmz_get_defaultidx(), BUFSIZE - 1);
      strncat(tmp, "/", BUFSIZE - strlen(tmp) - 1);
      strncat(tmp, name, BUFSIZE - strlen(tmp) - 1);
      tmp[BUFSIZE - 1] = '\0';
      if (nmz_add_index(tmp) != SUCCESS) {
          nmz_warn_printf("invalid idxname: %s", name);
      }
    }
}

/*
 *
 * Public functions
 *
 */

/* initialize CGI mode. actually, to be invoked from commandline
 * with no arguments also trhough this function */
void 
init_cgi(char *query, char *subquery)
{
    struct cgiarg ca;  /* passed for process_cgi_var_*() functions 
               for modifying important variables. */

    ca.query    = query;
    ca.subquery = subquery;

    if (process_cgi_vars(&ca)) {
      show_mini_usage();   /* if it is NOT CGI, show usage and exit */
      exit(EXIT_FAILURE);
    }

    if (nmz_get_idxnum() == 0) {
      /* Use defaultidx for taget. */
      if (nmz_add_index(nmz_get_defaultidx()) != SUCCESS) {
          nmz_warn_printf("invalid idxname: %s", nmz_get_defaultidx());
      }
    } 
}

Generated by  Doxygen 1.6.0   Back to index