home *** CD-ROM | disk | FTP | other *** search
-
- /*-
- * Copyright (c) 1995 The Apache Group. All rights reserved.
- *
- *
- * Apache httpd license
- * ====================
- *
- *
- * This is the license for the Apache Server. It covers all the
- * files which come in this distribution, and should never be removed.
- *
- * The "Apache Group" has based this server, called "Apache", on
- * public domain code distributed under the name "NCSA httpd 1.3".
- *
- * NCSA httpd 1.3 was placed in the public domain by the National Center
- * for Supercomputing Applications at the University of Illinois
- * at Urbana-Champaign.
- *
- * As requested by NCSA we acknowledge,
- *
- * "Portions developed at the National Center for Supercomputing
- * Applications at the University of Illinois at Urbana-Champaign."
- *
- * Copyright on the sections of code added by the "Apache Group" belong
- * to the "Apache Group" and/or the original authors. The "Apache Group" and
- * authors hereby grant permission for their code, along with the
- * public domain NCSA code, to be distributed under the "Apache" name.
- *
- * Reuse of "Apache Group" code outside of the Apache distribution should
- * be acknowledged with the following quoted text, to be included with any new
- * work;
- *
- * "Portions developed by the "Apache Group", taken with permission
- * from the Apache Server http://www.apache.org/apache/ "
- *
- *
- * Permission is hereby granted to anyone to redistribute Apache under
- * the "Apache" name. We do not grant permission for the resale of Apache, but
- * we do grant permission for vendors to bundle Apache free with other software,
- * or to charge a reasonable price for redistribution, provided it is made
- * clear that Apache is free. Permission is also granted for vendors to
- * sell support for Apache. We explicitly forbid the redistribution of
- * Apache under any other name.
- *
- * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
- /*
- * This imagemap module started as a port of the original imagemap.c
- * written by Rob McCool (11/13/93 robm@ncsa.uiuc.edu).
- * This version includes the mapping algorithms found in version 1.3
- * of imagemap.c.
- *
- * Contributors to this code include:
- *
- * Kevin Hughes, kevinh@pulua.hcc.hawaii.edu
- *
- * Eric Haines, erich@eye.com
- * "macmartinized" polygon code copyright 1992 by Eric Haines, erich@eye.com
- *
- * Randy Terbush, randy@zyzzyva.com
- * port to Apache module format, "base_uri" and support for relative URLs
- *
- * James H. Cloos, Jr., cloos@jhcloos.com
- * Added point datatype, using code in NCSA's version 1.8 imagemap.c
- * program, as distributed with version 1.4.1 of their server.
- * The point code is originally added by Craig Milo Rogers, Rogers@ISI.Edu
- *
- * Nathan Kurz, nate@tripod.com
- * Partial rewrite/reorginazation to be generally more forgiving.
- * main changes: uses 'default' if no coordinates given (Lynx).
- * ignores bad lines in map file instead of server error.
- * bug in uri_base handling that sometimes caused relative
- * urls in Location fixed; more schemes checked for.
- * 'point' directive mixes better with 'default' directive.
- */
-
- #include "httpd.h"
- #include "http_config.h"
- #include "http_request.h"
- #include "http_core.h"
- #include "http_protocol.h"
- #include "http_main.h"
- #include "http_log.h"
- #include "util_script.h"
-
-
- #define IMAP_MAGIC_TYPE "application/x-httpd-imap"
- #define MAXLINE 500
- #define MAXVERTS 100
- #define X 0
- #define Y 1
-
- char *getline(char *, int, FILE *);
- double strtod(); /* SunOS needed this */
-
- module imap_module;
-
- int pointinrect(double point[2], double coords[MAXVERTS][2])
- {
- return ((point[X] >= coords[0][X] && point[X] <= coords[1][X]) &&
- (point[Y] >= coords[0][Y] && point[Y] <= coords[1][Y]));
- }
-
- int pointincircle(double point[2], double coords[MAXVERTS][2])
- {
- int radius1, radius2;
-
- radius1 = ((coords[0][Y] - coords[1][Y]) * (coords[0][Y] - coords[1][Y]))
- + ((coords[0][X] - coords[1][X]) * (coords[0][X] - coords[1][X]));
-
- radius2 = ((coords[0][Y] - point[Y]) * (coords[0][Y] - point[Y]))
- + ((coords[0][X] - point[X]) * (coords[0][X] - point[X]));
-
- return (radius2 <= radius1);
- }
-
- int pointinpoly(double point[2], double pgon[MAXVERTS][2])
- {
- int i, numverts, inside_flag, xflag0;
- int crossings;
- double *p, *stop;
- double tx, ty, y;
-
- for (i = 0; pgon[i][X] != -1 && i < MAXVERTS; i++);
-
- numverts = i;
- crossings = 0;
-
- tx = point[X];
- ty = point[Y];
- y = pgon[numverts - 1][Y];
-
- p = (double *) pgon + 1;
- if ((y >= ty) != (*p >= ty)) {
-
- if ((xflag0 = (pgon[numverts - 1][X] >= tx)) == (*(double *) pgon >= tx)) {
- if (xflag0)
- crossings++;
- }
- else {
- crossings += (pgon[numverts - 1][X] - (y - ty) *
- (*(double *) pgon - pgon[numverts - 1][X]) /
- (*p - y)) >= tx;
- }
- }
-
- stop = pgon[numverts];
-
- for (y = *p, p += 2; p < stop; y = *p, p += 2) {
-
- if (y >= ty) {
-
- while ((p < stop) && (*p >= ty))
- p += 2;
-
- if (p >= stop)
- break;
- if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) {
-
- if (xflag0)
- crossings++;
- }
- else {
- crossings += (*(p - 3) - (*(p - 2) - ty) *
- (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
- }
- }
- else {
- while ((p < stop) && (*p < ty))
- p += 2;
-
- if (p >= stop)
- break;
-
- if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) {
- if (xflag0)
- crossings++;
- }
- else {
- crossings += (*(p - 3) - (*(p - 2) - ty) *
- (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
- }
- }
- }
-
- inside_flag = crossings & 0x01;
- return (inside_flag);
- }
-
-
- int is_closer(double point[2], double coords[MAXVERTS][2], double *closest)
- {
- double dist_squared =((point[X] - coords[0][X]) * (point[X] - coords[0][X]))
- + ((point[Y] - coords[0][Y]) * (point[Y] - coords[0][Y]));
-
- if (point[X] < 0 || point[Y] < 0 )
- return(0); /* don't mess around with negative coordinates */
-
- if ( *closest < 0 || dist_squared < *closest ) {
- *closest = dist_squared;
- return(1); /* if this is the first point or is the closest yet
- set 'closest' equal to this distance^2 */
- }
-
- return(0); /* if it's not the first or closest */
-
- }
-
- double get_x_coord(char *args)
- {
- char *endptr = NULL;
- double x_coord = -1; /* -1 is returned if no coordinate is given */
-
- if (args == NULL)
- return(-1); /* in case we aren't passed anything */
-
- while( *args && !isdigit(*args) && *args != ',')
- args++; /* jump to the first digit, but not past a comma or end */
-
- x_coord = strtod(args, &endptr);
-
- if (endptr > args) /* if a conversion was made */
- return(x_coord);
-
- return(-1); /* else if no conversion was made, or if no args was given */
- }
-
- double get_y_coord(char *args)
- {
- char *endptr = NULL;
- char *start_of_y = NULL;
- double y_coord = -1; /* -1 is returned on error */
-
- if (args == NULL)
- return(-1); /* in case we aren't passed anything */
-
- start_of_y = strchr(args, ','); /* the comma */
-
- if (start_of_y) {
-
- start_of_y++; /* start looking at the character after the comma */
-
- while( *start_of_y && !isdigit(*start_of_y))
- start_of_y++; /* jump to the first digit, but not past the end */
-
- y_coord = strtod(start_of_y, &endptr);
-
- if (endptr > start_of_y)
- return(y_coord);
- }
-
- return(-1); /* if no conversion was made, or no comma was found in args */
- }
-
-
- void set_redirect(request_rec *r, char *base_uri, char *mapurl)
- {
- char redirect[MAXLINE] = {'\0'};
- char *string_pos = base_uri;
- char *directory = NULL;
-
- if (
- (!strncmp(mapurl, "http:", 5)) ||
- (!strncmp(mapurl, "mailto:", 7)) ||
- (!strncmp(mapurl, "news:", 5)) ||
- (!strncmp(mapurl, "ftp:", 4)) ||
- (!strncmp(mapurl, "gopher:", 7)) ||
- (!strncmp(mapurl, "nntp:", 5)) ) {
-
- table_set(r->headers_out, "Location", mapurl);
- return; /* if they give us an absolute URL, use it! */
- }
-
- while (*string_pos) { /* starts out the same as base_uri */
-
- if (*string_pos == '/' && *(string_pos+1) == '/') {
- string_pos += 2; /* if there are two slashes, jump over them */
- continue;
- }
-
- if (*string_pos == '/') { /* the first single slash */
- if ( mapurl[0] == '/' ) {
- *string_pos = '\0';
- } /* if the URL from the map starts from root, end the
- base URL string at the first single slash */
- else {
- directory = string_pos; /* save the start of the directory portion */
-
- string_pos = strrchr(string_pos, '/'); /* now reuse string_pos */
- string_pos++; /* step over that last slash */
- *string_pos = '\0';
- } /* otherwise make sure we are dealing with a directory
- instead of a file */
- break;
- }
-
- string_pos++; /* until we get to the end of base_uri without finding
- a slash by itself */
- }
- /* by this point, base_uri never ends with a slash.
- it has to come from mapurl if there's to be one. */
-
- while ( ! strncmp(mapurl, "../", 3) || ! strcmp(mapurl, "..") ) {
- /* handle relative mapurl's from the map file */
-
- if ( directory && (string_pos = strrchr(directory, '/')) )
- *string_pos = '\0';
- /* for each '..', knock a directory off the end
- by ending the string right at the last slash.
- But only consider the directory portion: don't eat
- into the server name. And only try if a directory
- portion was found */
-
- mapurl += 2; /* jump over the '..' that we found in the mapurl */
-
- if (! strncmp(mapurl, "/../", 4) || ! strcmp(mapurl, "/..") )
- /* check for both so a file ..foo still works */
-
- mapurl++; /* step over the '/' if there are more '..' to do.
- this way, we leave the starting '/' on mapurl after
- the last '..', but get rid of it otherwise */
-
- } /* by this point, mapurl does not start with '..' */
-
-
- sprintf(redirect, "%s%s", base_uri, mapurl);
-
- table_set(r->headers_out, "Location", redirect);
-
- return;
-
- }
-
-
-
- int imap_handler(request_rec *r)
- {
- char base_uri[MAXLINE] = {'\0'};
- char input[MAXLINE] = {'\0'};
- char maptype[MAXLINE] = {'\0'};
- char mapurl[MAXLINE] = {'\0'};
- char mapdflt[MAXLINE] = {'\0'};
- char mapclosest[MAXLINE] = {'\0'};
- double closest = -1;
-
- double testpoint[2];
- double pointarray[MAXVERTS][2] = { {-1,-1} };
- int vertex = 0;
-
- char *referer = table_get(r->headers_in, "Referer");
-
- char *string_pos = NULL;
- int chars_read = 0;
-
- FILE *imap;
-
- if (! (imap = fopen(r->filename, "r")))
- return SERVER_ERROR;
-
- if (r->server->port == 80 )
- sprintf(base_uri, "http://%s", r->server->server_hostname);
- else
- sprintf(base_uri, "http://%s:%d", r->server->server_hostname,
- r->server->port);
- /* base_uri starts as http://server_hostname,
- can later be changed by lines in map file */
-
- testpoint[X] = get_x_coord(r->args);
- testpoint[Y] = get_y_coord(r->args);
-
- while (getline(input, MAXLINE, imap)) {
-
- if ( input[0] == '#' || ! input[0] )
- continue; /* ignore comments and blank lines */
-
- string_pos = input; /* always start at the beginning of line */
-
- bzero(maptype, MAXLINE);
- bzero(mapurl, MAXLINE); /* clear these just to be safe */
-
- sscanf(input, "%s %s %n", maptype, mapurl, &chars_read);
- string_pos += chars_read;
-
- if ( ! strcmp(maptype, "base_uri") ) { /* base_uri */
-
- if ( ! strcmp(mapurl, "map") )
- strcpy(base_uri, r->uri); /* use the map as the base */
-
- else if ( ! strcmp(mapurl, "referer") )
- if (referer)
- strcpy(base_uri, referer); /* use the refering page as base */
- /* if there is no refering page, the base is left as http://servername */
-
- else
- strcpy(base_uri, mapurl); /* use what we are given as base */
-
- continue;
- }
-
- if ( ! strcmp(maptype, "default") ) { /* default */
-
- strcpy(mapdflt, mapurl); /* use what is given as the default */
-
- continue;
- }
-
- if ( testpoint[X] < 0 || testpoint[Y] < 0 ) { /* no coordinates */
-
- /* if we don't have valid test coordinates,
- don't bother trying any of the tests that
- follow (point, rect, poly, etc) */
- continue;
- }
-
- vertex = 0;
- while ( vertex < MAXVERTS &&
- sscanf(string_pos, "%lf,%lf %n", &pointarray[vertex][X],
- &pointarray[vertex][Y], &chars_read) == 2) {
- string_pos += chars_read;
- vertex++;
- } /* so long as there are more vertices to read, and
- we have room, read them in. We start where we left
- off of the last sscanf, not at the beginning.*/
-
- pointarray[vertex][X] = -1; /* signals the end of vertices */
-
-
- if ( ! strcmp(maptype, "poly") ) { /* poly */
-
- if (pointinpoly (testpoint, pointarray) ) {
- set_redirect(r, base_uri, mapurl);
- fclose(imap);
- return REDIRECT;
-
- }
- }
-
- if ( ! strcmp(maptype, "circle") ) { /* circle */
-
- if (pointincircle (testpoint, pointarray) ) {
- set_redirect(r, base_uri, mapurl);
- fclose(imap);
- return REDIRECT;
-
- }
- }
-
- if ( ! strcmp(maptype, "rect") ) { /* rect */
-
- if (pointinrect (testpoint, pointarray) ) {
- set_redirect(r, base_uri, mapurl);
- fclose(imap);
- return REDIRECT;
-
- }
- }
-
- if ( ! strcmp(maptype, "point") ) { /* point */
-
- if (is_closer(testpoint, pointarray, &closest) )
- strcpy(mapclosest, mapurl); /* if the closest point yet save it */
-
- continue;
- } /* move on to next line whether it's closest or not */
-
- /* nothing matched, so we get another line! */
- } /* (I wonder if that should be logged as an error?) */
-
-
- fclose(imap); /* we won't be needing the map file anymore */
-
- if (*mapclosest) { /* if a 'point' directive has been seen */
- set_redirect(r, base_uri, mapclosest);
- fclose(imap); /* redirect to the closest point found */
- return REDIRECT;
- }
-
- if (*mapdflt) { /* if a default has been assigned */
- set_redirect(r, base_uri, mapdflt);
- fclose(imap); /* redirect to that default */
- return REDIRECT;
- }
-
- return SERVER_ERROR; /* they lose -- but we get here if and only if there
- was no default and nothing matched */
-
- }
-
-
- handler_rec imap_handlers[] = {
- { IMAP_MAGIC_TYPE, imap_handler },
- { NULL }
- };
-
- module imap_module = {
- STANDARD_MODULE_STUFF,
- NULL, /* initializer */
- NULL, /* dir config creater */
- NULL, /* dir merger --- default is to override */
- NULL, /* server config */
- NULL, /* merge server config */
- NULL, /* command table */
- imap_handlers, /* handlers */
- NULL, /* filename translation */
- NULL, /* check_user_id */
- NULL, /* check auth */
- NULL, /* check access */
- NULL, /* type_checker */
- NULL, /* fixups */
- NULL /* logger */
- };
-
-
-
-
-
-
-
-
-
-
-