/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/
/* * 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 * Rewrite/reorganization. New handling of default, base and relative URLs. * New Configuration directives: * ImapMenu {none, formatted, semiformatted, unformatted} * ImapDefault {error, nocontent, referer, menu, URL} * ImapBase {map, referer, URL} * Support for creating non-graphical menu added. (backwards compatible): * Old: directive URL [x,y ...] * New: directive URL "Menu text" [x,y ...] * or: directive URL x,y ... "Menu text" * Map format and menu concept courtesy Joshua Bell, jsbell@acs.ucalgary.ca. * * Mark Cox, mark@ukweb.com, Allow relative URLs even when no base specified
*/
staticconst command_rec imap_cmds[] =
{
AP_INIT_TAKE1("ImapMenu", ap_set_string_slot,
(void *)APR_OFFSETOF(imap_conf_rec, imap_menu), OR_INDEXES, "the type of menu generated: none, formatted, semiformatted, " "unformatted"),
AP_INIT_TAKE1("ImapDefault", ap_set_string_slot,
(void *)APR_OFFSETOF(imap_conf_rec, imap_default), OR_INDEXES, "the action taken if no match: error, nocontent, referer, " "menu, URL"),
AP_INIT_TAKE1("ImapBase", ap_set_string_slot,
(void *)APR_OFFSETOF(imap_conf_rec, imap_base), OR_INDEXES, "the base for all URL's: map, referer, URL (or start of)"),
{NULL}
};
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 */
}
staticdouble get_x_coord(constchar *args)
{ char *endptr; /* we want it non-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 && !apr_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 */
}
staticdouble get_y_coord(constchar *args)
{ char *endptr; /* we want it non-null */ constchar *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 = ap_strchr_c(args, ','); /* the comma */
if (start_of_y) {
start_of_y++; /* start looking at the character after
the comma */
while (*start_of_y && !apr_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 */
}
/* See if string has a "quoted part", and if so set *quoted_part to * the first character of the quoted part, then hammer a \0 onto the * trailing quote, and set *string to point at the first character * past the second quote. * * Otherwise set *quoted_part to NULL, and leave *string alone.
*/ staticvoid read_quoted(char **string, char **quoted_part)
{ char *strp = *string;
/* assume there's no quoted part */
*quoted_part = NULL;
while (apr_isspace(*strp)) {
strp++; /* go along string until non-whitespace */
}
if (*strp == '"') { /* if that character is a double quote */
strp++; /* step over it */
*quoted_part = strp; /* note where the quoted part begins */
while (*strp && *strp != '"') {
++strp; /* skip the quoted portion */
}
*strp = '\0'; /* end the string with a NUL */
strp++; /* step over the last double quote */
*string = strp;
}
}
/* * returns the mapped URL or NULL.
*/ staticconstchar *imap_url(request_rec *r, constchar *base, constchar *value)
{ /* translates a value into a URL. */
apr_size_t slen, clen; char *string_pos = NULL; constchar *string_pos_const = NULL; char *directory = NULL; constchar *referer = NULL; char *my_base;
if (!strcasecmp(value, "nocontent") || !strcasecmp(value, "error")) { return apr_pstrdup(r->pool, value); /* these are handled elsewhere,
so just copy them */
}
if (!strcasecmp(value, "referer")) {
referer = apr_table_get(r->headers_in, "Referer"); if (referer && *referer) { return referer;
} else { /* XXX: This used to do *value = '\0'; ... which is totally bogus * because it hammers the passed in value, which can be a string * constant, or part of a config, or whatever. Total garbage. * This works around that without changing the rest of this * code much
*/
value = ""; /* if 'referer' but no referring page,
null the value */
}
}
string_pos_const = value; while (apr_isalpha(*string_pos_const)) {
string_pos_const++; /* go along the URL from the map
until a non-letter */
} if (*string_pos_const == ':') { /* if letters and then a colon (like http:) */ /* it's an absolute URL, so use it! */ return apr_pstrdup(r->pool, value);
}
if (!base || !*base) { if (value && *value) { return apr_pstrdup(r->pool, value); /* no base: use what is given */
} /* no base, no value: pick a simple default */ return ap_construct_url(r->pool, "/", r);
}
/* must be a relative URL to be combined with base */ if (ap_strchr_c(base, '/') == NULL && (!strncmp(value, "../", 3)
|| !strcmp(value, ".."))) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00677) "invalid base directive in map file: %s", r->uri); return NULL;
}
my_base = apr_pstrdup(r->pool, base);
string_pos = my_base; while (*string_pos) { 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 (value[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';
} /* but if the map url is relative, leave the
slash on the base (if there is one) */ break;
}
string_pos++; /* until we get to the end of my_base without
finding a slash by itself */
}
while (!strncmp(value, "../", 3) || !strcmp(value, "..")) {
if (directory && (slen = strlen(directory))) {
/* 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 */
value += 2; /* jump over the '..' that we found in the
value */
} elseif (directory) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00678) "invalid directory name in map file: %s", r->uri); return NULL;
}
if (!strncmp(value, "/../", 4) || !strcmp(value, "/..")) {
value++; /* step over the '/' if there are more '..' to do. This way, we leave the starting '/' on value after the last '..', but get
rid of it otherwise */
}
} /* by this point, value does not start
with '..' */
staticint imap_reply(request_rec *r, constchar *redirect)
{ if (!strcasecmp(redirect, "error")) { /* they actually requested an error! */ return HTTP_INTERNAL_SERVER_ERROR;
} if (!strcasecmp(redirect, "nocontent")) { /* tell the client to keep the page it has */ return HTTP_NO_CONTENT;
} if (redirect && *redirect) { /* must be a URL, so redirect to it */
apr_table_setn(r->headers_out, "Location", redirect); return HTTP_MOVED_TEMPORARILY;
} return HTTP_INTERNAL_SERVER_ERROR;
}
status = ap_pcfg_openfile(&imap, r->pool, r->filename);
if (status != APR_SUCCESS) { return HTTP_NOT_FOUND;
}
base = imap_url(r, NULL, imap_base); /* set base according
to default */ if (!base) { return HTTP_INTERNAL_SERVER_ERROR;
}
mapdflt = imap_url(r, NULL, imap_default); /* and default to
global default */ if (!mapdflt) { return HTTP_INTERNAL_SERVER_ERROR;
}
if ((testpoint[X] == -1 || testpoint[Y] == -1) ||
(testpoint[X] == 0 && testpoint[Y] == 0)) { /* if either is -1 or if both are zero (new Lynx) */ /* we don't have valid coordinates */
testpoint[X] = -1;
testpoint[Y] = -1; if (strncasecmp(imap_menu, "none", 2)) {
showmenu = 1; /* show the menu _unless_ ImapMenu is
'none' or 'no' */
}
}
if (showmenu) { /* send start of imagemap menu if
we're going to */
menu_header(r, imap_menu);
}
while (!ap_cfg_getline(input, sizeof(input), imap)) { if (!input[0]) { if (showmenu) {
menu_blank(r, imap_menu);
} continue;
}
if (input[0] == '#') { if (showmenu) {
menu_comment(r, imap_menu, input + 1);
} continue;
} /* blank lines and comments are ignored
if we aren't printing a menu */
/* find the first two space delimited fields, recall that * ap_cfg_getline has removed leading/trailing whitespace. * * note that we're tokenizing as we go... if we were to use the * ap_getword() class of functions we would end up allocating extra * memory for every line of the map file
*/
string_pos = input; if (!*string_pos) { /* need at least two fields */ goto need_2_fields;
}
directive = string_pos; while (*string_pos && !apr_isspace(*string_pos)) { /* past directive */
++string_pos;
} if (!*string_pos) { /* need at least two fields */ goto need_2_fields;
}
*string_pos++ = '\0';
if (!*string_pos) { /* need at least two fields */ goto need_2_fields;
} while (apr_isspace(*string_pos)) { /* past whitespace */
++string_pos;
}
value = string_pos; while (*string_pos && !apr_isspace(*string_pos)) { /* past value */
++string_pos;
} if (apr_isspace(*string_pos)) {
*string_pos++ = '\0';
} else { /* end of input, don't advance past it */
*string_pos = '\0';
}
if (!strncasecmp(directive, "base", 4)) { /* base, base_uri */
base = imap_url(r, NULL, value); if (!base) { goto menu_bail;
} continue; /* base is never printed to a menu */
}
read_quoted(&string_pos, &href_text);
if (!strcasecmp(directive, "default")) { /* default */
mapdflt = imap_url(r, NULL, value); if (!mapdflt) { goto menu_bail;
} if (showmenu) { /* print the default if there's a menu */
redirect = imap_url(r, base, mapdflt); if (!redirect) { goto menu_bail;
}
menu_default(r, imap_menu, redirect,
href_text ? href_text : mapdflt);
} continue;
}
vertex = 0; while (vertex < MAXVERTS &&
sscanf(string_pos, "%lf%*[, ]%lf",
&pointarray[vertex][X], &pointarray[vertex][Y]) == 2) { /* Now skip what we just read... we can't use ANSIism %n */ while (apr_isspace(*string_pos)) { /* past whitespace */
string_pos++;
} while (apr_isdigit(*string_pos)) { /* and the 1st number */
string_pos++;
}
string_pos++; /* skip the ',' */ while (apr_isspace(*string_pos)) { /* past any more whitespace */
string_pos++;
} while (apr_isdigit(*string_pos)) { /* 2nd number */
string_pos++;
}
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 (showmenu) { if (!href_text) {
read_quoted(&string_pos, &href_text); /* href text could
be here instead */
}
redirect = imap_url(r, base, value); if (!redirect) { goto menu_bail;
}
menu_directive(r, imap_menu, redirect,
href_text ? href_text : value); continue;
} /* note that we don't make it past here if we are making a menu */
if (testpoint[X] == -1 || pointarray[0][X] == -1) { continue; /* don't try the following tests if testpoints are invalid, or if there are no
coordinates */
}
if (!strcasecmp(directive, "point")) { /* point */
if (is_closer(testpoint, pointarray, &closest_yet)) {
closest = apr_pstrdup(r->pool, value);
}
continue;
} /* move on to next line whether it's
closest or not */
} /* nothing matched, so we get another line! */
ap_cfg_closefile(imap); /* we are done with the map file; close it */
if (showmenu) {
menu_footer(r); /* finish the menu and we are done */ return OK;
}
if (closest) { /* if a 'point' directive has been seen */
redirect = imap_url(r, base, closest); if (!redirect) { return HTTP_INTERNAL_SERVER_ERROR;
} return (imap_reply(r, redirect));
}
if (mapdflt) { /* a default should be defined, even if
only 'nocontent' */
redirect = imap_url(r, base, mapdflt); if (!redirect) { return HTTP_INTERNAL_SERVER_ERROR;
} return (imap_reply(r, redirect));
}
return HTTP_INTERNAL_SERVER_ERROR; /* If we make it this far,
we failed. They lose! */
need_2_fields:
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00679) "map file %s, line %d syntax error: requires at " "least two fields", r->uri, imap->line_number); /* fall through */
menu_bail:
ap_cfg_closefile(imap); if (showmenu) { /* There's not much else we can do ... we've already sent the headers * to the client.
*/
ap_rputs("\n\n[an internal server error occured]\n", r);
menu_footer(r); return OK;
} return HTTP_INTERNAL_SERVER_ERROR;
}
staticint imap_handler(request_rec *r)
{ /* Optimization: skip the allocation of large local variables on the * stack (in imap_handler_internal()) on requests that aren't using * imagemaps
*/ if (r->method_number != M_GET || (strcmp(r->handler,IMAP_MAGIC_TYPE)
&& strcmp(r->handler, "imap-file"))) { return DECLINED;
} else { return imap_handler_internal(r);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.