home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / mod_imap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-07  |  25.0 KB  |  830 lines

  1.  
  2. /* ====================================================================
  3.  * Copyright (c) 1995 The Apache Group.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer. 
  11.  *
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in
  14.  *    the documentation and/or other materials provided with the
  15.  *    distribution.
  16.  *
  17.  * 3. All advertising materials mentioning features or use of this
  18.  *    software must display the following acknowledgment:
  19.  *    "This product includes software developed by the Apache Group
  20.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  21.  *
  22.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  23.  *    endorse or promote products derived from this software without
  24.  *    prior written permission.
  25.  *
  26.  * 5. Redistributions of any form whatsoever must retain the following
  27.  *    acknowledgment:
  28.  *    "This product includes software developed by the Apache Group
  29.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  32.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  34.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  35.  * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  42.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  * ====================================================================
  44.  *
  45.  * This software consists of voluntary contributions made by many
  46.  * individuals on behalf of the Apache Group and was originally based
  47.  * on public domain software written at the National Center for
  48.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  49.  * For more information on the Apache Group and the Apache HTTP server
  50.  * project, please see <http://www.apache.org/>.
  51.  *
  52.  */
  53.  
  54. /*
  55.  * This imagemap module started as a port of the original imagemap.c
  56.  * written by Rob McCool (11/13/93 robm@ncsa.uiuc.edu).
  57.  * This version includes the mapping algorithms found in version 1.3
  58.  * of imagemap.c.
  59.  *
  60.  * Contributors to this code include:
  61.  *
  62.  * Kevin Hughes, kevinh@pulua.hcc.hawaii.edu
  63.  *
  64.  * Eric Haines, erich@eye.com
  65.  * "macmartinized" polygon code copyright 1992 by Eric Haines, erich@eye.com
  66.  *
  67.  * Randy Terbush, randy@zyzzyva.com
  68.  * port to Apache module format, "base_uri" and support for relative URLs
  69.  * 
  70.  * James H. Cloos, Jr., cloos@jhcloos.com
  71.  * Added point datatype, using code in NCSA's version 1.8 imagemap.c
  72.  * program, as distributed with version 1.4.1 of their server.
  73.  * The point code is originally added by Craig Milo Rogers, Rogers@ISI.Edu
  74.  *
  75.  * Nathan Kurz, nate@tripod.com
  76.  * Rewrite/reorganization.  New handling of default, base and relative URLs.  
  77.  * New Configuration directives:
  78.  *    ImapMenu {none, formatted, semiformatted, unformatted}
  79.  *    ImapDefault {error, nocontent, referer, menu, URL}
  80.  *    ImapBase {map, referer, URL}
  81.  * Support for creating non-graphical menu added.  (backwards compatible):
  82.  *    Old:  directive URL [x,y ...]
  83.  *    New:  directive URL "Menu text" [x,y ...]
  84.  *     or:  directive URL x,y ... "Menu text"
  85.  * Map format and menu concept courtesy Joshua Bell, jsbell@acs.ucalgary.ca.
  86.  *
  87.  * Mark Cox, mark@ukweb.com, Allow relative URLs even when no base specified
  88.  */
  89.  
  90. #include "httpd.h"
  91. #include "http_config.h"
  92. #include "http_request.h"
  93. #include "http_core.h"
  94. #include "http_protocol.h"
  95. #include "http_main.h"
  96. #include "http_log.h"
  97. #include "util_script.h"
  98.  
  99. #define IMAP_MAGIC_TYPE "application/x-httpd-imap"
  100. #define LARGEBUF 500
  101. #define SMALLBUF 100
  102. #define MAXVERTS 100
  103. #define X 0
  104. #define Y 1
  105.  
  106. #define IMAP_MENU_DEFAULT "formatted"
  107. #define IMAP_DEFAULT_DEFAULT "nocontent"
  108. #define IMAP_BASE_DEFAULT "map"
  109.  
  110. #ifdef SUNOS4
  111. double strtod();   /* SunOS needed this */
  112. #endif
  113.  
  114. module imap_module;
  115.  
  116. typedef struct { 
  117.   char *imap_menu;
  118.   char *imap_default;
  119.   char *imap_base;
  120. } imap_conf_rec;
  121.  
  122. void *create_imap_dir_config (pool *p, char *dummy) { 
  123.   imap_conf_rec *icr = 
  124.     (imap_conf_rec *)palloc(p, sizeof(imap_conf_rec));
  125.  
  126.   icr->imap_menu = NULL;
  127.   icr->imap_default = NULL;
  128.   icr->imap_base = NULL;
  129.  
  130.   return icr;
  131. }
  132.  
  133. void *merge_imap_dir_configs (pool *p, void *basev, void *addv)
  134. {
  135.   imap_conf_rec *new=(imap_conf_rec *)pcalloc (p, sizeof(imap_conf_rec));
  136.   imap_conf_rec *base = (imap_conf_rec *)basev;
  137.   imap_conf_rec *add = (imap_conf_rec *)addv;
  138.  
  139.   new->imap_menu = add->imap_menu ? add->imap_menu : base->imap_menu;
  140.   new->imap_default=add->imap_default ? add->imap_default : base->imap_default;
  141.   new->imap_base =add-> imap_base ? add->imap_base : base->imap_base;
  142.  
  143.   return new;
  144. }
  145.  
  146.  
  147. command_rec imap_cmds[] = {
  148. { "ImapMenu", set_string_slot, 
  149.     (void*)XtOffsetOf(imap_conf_rec, imap_menu), OR_INDEXES, TAKE1,
  150.     "the type of menu generated: none, formatted, semiformatted, unformatted"},
  151. { "ImapDefault", set_string_slot, 
  152.     (void*)XtOffsetOf(imap_conf_rec, imap_default), OR_INDEXES, TAKE1,
  153.     "the action taken if no match: error, nocontent, referer, menu, URL" },
  154. { "ImapBase", set_string_slot, 
  155.     (void*)XtOffsetOf(imap_conf_rec, imap_base), OR_INDEXES, TAKE1,
  156.     "the base for all URL's: map, referer, URL (or start of)" },
  157. { NULL }
  158. };
  159.  
  160. int pointinrect(double point[2], double coords[MAXVERTS][2])
  161. {
  162.     double max[2], min[2];
  163.     if (coords[0][X] > coords[1][X]) {
  164.         max[0] = coords[0][X];
  165.         min[0] = coords[1][X];
  166.     } else {
  167.         max[0] = coords[1][X];
  168.         min[0] = coords[0][X];
  169.     }
  170.  
  171.     if (coords[0][Y] > coords[1][Y]) {
  172.         max[1] = coords[0][Y];
  173.         min[1] = coords[1][Y];
  174.     } else {
  175.         max[1] = coords[1][Y];
  176.         min[1] = coords[0][Y];
  177.     }
  178.  
  179.     return ((point[X] >= min[0] && point[X] <= max[0]) &&
  180.         (point[Y] >= min[1] && point[Y] <= max[1]));
  181. }
  182.  
  183. int pointincircle(double point[2], double coords[MAXVERTS][2])
  184. {
  185.     int radius1, radius2;
  186.  
  187.     radius1 = ((coords[0][Y] - coords[1][Y]) * (coords[0][Y] - coords[1][Y]))
  188.     + ((coords[0][X] - coords[1][X]) * (coords[0][X] - coords[1][X]));
  189.     
  190.     radius2 = ((coords[0][Y] - point[Y]) * (coords[0][Y] - point[Y]))
  191.     + ((coords[0][X] - point[X]) * (coords[0][X] - point[X]));
  192.  
  193.     return (radius2 <= radius1);
  194. }
  195.  
  196. int pointinpoly(double point[2], double pgon[MAXVERTS][2])
  197. {
  198.     int i, numverts, inside_flag, xflag0;
  199.     int crossings;
  200.     double *p, *stop;
  201.     double tx, ty, y;
  202.  
  203.     for (i = 0; pgon[i][X] != -1 && i < MAXVERTS; i++);
  204.  
  205.     numverts = i;
  206.     crossings = 0;
  207.  
  208.     tx = point[X];
  209.     ty = point[Y];
  210.     y = pgon[numverts - 1][Y];
  211.  
  212.     p = (double *) pgon + 1;
  213.     if ((y >= ty) != (*p >= ty)) {
  214.  
  215.     if ((xflag0 = (pgon[numverts - 1][X] >= tx)) == (*(double *) pgon >= tx)) {
  216.         if (xflag0)
  217.         crossings++;
  218.     }
  219.     else {
  220.         crossings += (pgon[numverts - 1][X] - (y - ty) *
  221.               (*(double *) pgon - pgon[numverts - 1][X]) /
  222.               (*p - y)) >= tx;
  223.     }
  224.     }
  225.  
  226.     stop = pgon[numverts];
  227.  
  228.     for (y = *p, p += 2; p < stop; y = *p, p += 2) {
  229.     
  230.     if (y >= ty) {
  231.         
  232.         while ((p < stop) && (*p >= ty))
  233.         p += 2;
  234.         
  235.         if (p >= stop)
  236.         break;
  237.         if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) {
  238.         
  239.         if (xflag0)
  240.             crossings++;
  241.         }
  242.         else {
  243.         crossings += (*(p - 3) - (*(p - 2) - ty) *
  244.                   (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
  245.         }
  246.     }
  247.     else {
  248.         while ((p < stop) && (*p < ty))
  249.         p += 2;
  250.  
  251.         if (p >= stop)
  252.         break;
  253.  
  254.         if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) {
  255.         if (xflag0)
  256.             crossings++;
  257.         }
  258.         else {
  259.         crossings += (*(p - 3) - (*(p - 2) - ty) *
  260.                   (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
  261.         }
  262.     }
  263.     }
  264.  
  265.     inside_flag = crossings & 0x01;
  266.     return (inside_flag);
  267. }
  268.  
  269.  
  270. int is_closer(double point[2], double coords[MAXVERTS][2], double *closest)
  271. {
  272.   double dist_squared =((point[X] - coords[0][X]) * (point[X] - coords[0][X]))
  273.          + ((point[Y] - coords[0][Y]) * (point[Y] - coords[0][Y]));
  274.  
  275.   if (point[X] < 0 || point[Y] < 0 ) 
  276.     return(0);          /* don't mess around with negative coordinates */
  277.  
  278.   if ( *closest < 0 || dist_squared < *closest ) {
  279.     *closest = dist_squared;
  280.     return(1);         /* if this is the first point or is the closest yet
  281.               set 'closest' equal to this distance^2 */
  282.   }
  283.   
  284.   return(0);           /* if it's not the first or closest */
  285.  
  286. }
  287.  
  288. double get_x_coord(char *args) 
  289. {
  290.   char *endptr;           /* we want it non-null */
  291.   double x_coord = -1;    /* -1 is returned if no coordinate is given */
  292.  
  293.   if (args == NULL)
  294.     return(-1);           /* in case we aren't passed anything */
  295.  
  296.   while( *args && !isdigit(*args) && *args != ',') 
  297.     args++;   /* jump to the first digit, but not past a comma or end */
  298.  
  299.   x_coord = strtod(args, &endptr);
  300.  
  301.   if (endptr > args)   /* if a conversion was made */
  302.     return(x_coord); 
  303.  
  304.   return(-1);  /* else if no conversion was made, or if no args was given */
  305. }
  306.  
  307. double get_y_coord(char *args) 
  308. {
  309.   char *endptr;        /* we want it non-null */
  310.   char *start_of_y = NULL;
  311.   double y_coord = -1;    /* -1 is returned on error */
  312.  
  313.   if (args == NULL)
  314.     return(-1);           /* in case we aren't passed anything */
  315.  
  316.   start_of_y = strchr(args, ',');  /* the comma */
  317.  
  318.   if (start_of_y) {
  319.     
  320.     start_of_y++;    /* start looking at the character after the comma */
  321.  
  322.     while( *start_of_y && !isdigit(*start_of_y))  
  323.       start_of_y++;  /* jump to the first digit, but not past the end */
  324.  
  325.     y_coord = strtod(start_of_y, &endptr);
  326.  
  327.     if (endptr > start_of_y) 
  328.       return(y_coord); 
  329.   }
  330.   
  331.   return(-1);   /* if no conversion was made, or no comma was found in args */
  332. }
  333.   
  334.  
  335. int read_quoted(char *string, char *quoted_part)
  336.   char *starting_pos = string;
  337.   
  338.   while ( isspace(*string) )
  339.     string++;    /* go along string until non-whitespace */
  340.  
  341.   if ( *string == '"' ) { /* if that character is a double quote */
  342.  
  343.     string++;  /* step over it */
  344.  
  345.     while ( *string && *string != '"' ) {
  346.       *quoted_part++ = *string++;  /* copy the quoted portion */
  347.     }
  348.  
  349.     *quoted_part = '\0';  /* end the string with a SNUL */
  350.     
  351.     string++;  /* step over the last double quote */
  352.   }
  353.  
  354.   return(string - starting_pos); /* return the total characters read */
  355. }
  356.  
  357.  
  358. void imap_url(request_rec *r, char *base, char *value, char *url) 
  359. {
  360. /* translates a value into a URL. */
  361.   int slen, clen;
  362.   char *string_pos = NULL;
  363.   char *directory = NULL;
  364.   char *referer = NULL;
  365.   char my_base[SMALLBUF] = {'\0'};
  366.  
  367.   if ( ! strcasecmp(value, "map" ) || ! strcasecmp(value, "menu") ) {
  368.     if (r->server->port == 80 ) { 
  369.       sprintf(url, "http://%s%s", r->server->server_hostname, r->uri);
  370.     }
  371.     else {
  372.       sprintf(url, "http://%s:%d%s", r->server->server_hostname,
  373.           r->server->port, r->uri);      
  374.     }
  375.     return;  
  376.   }
  377.  
  378.   if ( ! strcasecmp(value, "nocontent") || ! strcasecmp(value, "error") ) {
  379.     strcpy(url, value);
  380.     return;    /* these are handled elsewhere, so just copy them */
  381.   }
  382.  
  383.   if ( ! strcasecmp(value, "referer" ) ) {
  384.     referer = table_get(r->headers_in, "Referer");
  385.     if ( referer && *referer ) {
  386.       strcpy(url, referer);
  387.       return;
  388.     }
  389.     else {
  390.       *value = '\0';  /* if 'referer' but no referring page, null the value */
  391.     }                 
  392.   }         
  393.  
  394.   string_pos = value;
  395.   while ( isalpha(*string_pos) )
  396.     string_pos++;    /* go along the URL from the map until a non-letter */
  397.   if ( *string_pos == ':' ) { 
  398.     strcpy(url, value);        /* if letters and then a colon (like http:) */
  399.     return;                    /* it's an absolute URL, so use it! */
  400.   }
  401.  
  402.   if ( ! base || ! *base ) {
  403.     if ( value && *value ) {  
  404.       strcpy(url, value);   /* no base: use what is given */
  405.     }         
  406.     else {                  
  407.       if (r->server->port == 80 ) {  
  408.     sprintf(url, "http://%s/", r->server->server_hostname);
  409.       }            
  410.       if (r->server->port != 80 ) {
  411.     sprintf(url, "http://%s:%d/", r->server->server_hostname, 
  412.         r->server->port);
  413.       }                     /* no base, no value: pick a simple default */
  414.     }
  415.     return;  
  416.   }
  417.  
  418.   strcpy(my_base, base);  /* must be a relative URL to be combined with base */
  419.   string_pos = my_base; 
  420.   while (*string_pos) {  
  421.     if (*string_pos == '/' && *(string_pos+1) == '/') {
  422.       string_pos += 2;  /* if there are two slashes, jump over them */
  423.       continue;
  424.     }
  425.     if (*string_pos == '/') {  /* the first single slash */
  426.     if ( value[0] == '/' ) {
  427.       *string_pos = '\0';  
  428.     }              /* if the URL from the map starts from root, end the
  429.               base URL string at the first single slash */
  430.     else {
  431.       directory = string_pos; /* save the start of the directory portion */
  432.  
  433.       string_pos = strrchr(string_pos, '/');  /* now reuse string_pos */
  434.       string_pos++;  /* step over that last slash */
  435.       *string_pos = '\0';
  436.     }              /* but if the map url is relative, leave the
  437.             slash on the base (if there is one) */
  438.     break;
  439.       }
  440.     string_pos++;   /* until we get to the end of my_base without finding
  441.                a slash by itself */
  442.   }
  443.  
  444.   while ( ! strncmp(value, "../", 3) || ! strcmp(value, "..") ) { 
  445.  
  446.       if (directory && (slen = strlen (directory))) {
  447.  
  448.       /* for each '..',  knock a directory off the end 
  449.          by ending the string right at the last slash.
  450.          But only consider the directory portion: don't eat
  451.          into the server name.  And only try if a directory
  452.          portion was found */    
  453.       
  454.       clen = slen - 1;
  455.     
  456.       while ((slen - clen) == 1) {
  457.     
  458.           if ((string_pos = strrchr(directory, '/')))
  459.           *string_pos = '\0';
  460.           clen = strlen (directory);
  461.           if (clen == 0) break;
  462.       }
  463.  
  464.       value += 2;      /* jump over the '..' that we found in the value */
  465.       }
  466.       
  467.       if (! strncmp(value, "/../", 4) || ! strcmp(value, "/..") )
  468.  
  469.       value++;       /* step over the '/' if there are more '..' to do.
  470.                this way, we leave the starting '/' on value after
  471.                the last '..', but get rid of it otherwise */ 
  472.      
  473.   }                   /* by this point, value does not start with '..' */
  474.  
  475.   if ( value && *value ) {
  476.     sprintf(url, "%s%s", my_base, value);   
  477.   }
  478.   else {
  479.     sprintf(url, "%s", my_base);   
  480.   }
  481.   return;
  482. }
  483.  
  484. int imap_reply(request_rec *r, char *redirect)
  485.   if ( ! strcasecmp(redirect, "error") ) {
  486.     return SERVER_ERROR;  /* they actually requested an error! */
  487.   }
  488.   if ( ! strcasecmp(redirect, "nocontent") ) {
  489.     r->status_line = pstrdup(r->pool, "204 No Content");
  490.     soft_timeout ("send no content", r);
  491.     send_http_header(r);
  492.     return OK;            /* tell the client to keep the page it has */
  493.   }
  494.   if (redirect && *redirect ) { 
  495.     table_set(r->headers_out, "Location", redirect);
  496.     return REDIRECT;      /* must be a URL, so redirect to it */
  497.   }    
  498.   return SERVER_ERROR;
  499. }
  500.  
  501. void menu_header(request_rec *r, char *menu)
  502. {
  503.   if (! strcasecmp(menu, "formatted")) {
  504.     r->content_type = "text/html";
  505.     soft_timeout ("send menu", r);
  506.     send_http_header(r);
  507.     rvputs(r, "<html>\n<head><title>Menu for ", r->uri,
  508.        "</title></head>\n\n<body>\n", NULL);
  509.     rvputs(r, "<h1>Menu for ", r->uri, "</h1>\n<hr>\n\n", NULL);
  510.   } 
  511.   if (! strcasecmp(menu, "semiformatted")) {
  512.     r->content_type = "text/html";
  513.     soft_timeout ("send menu", r);
  514.     send_http_header(r);
  515.     rvputs(r, "<html>\n<head><title>Menu for ", r->uri,
  516.        "</title></head>\n\n<body>\n", NULL);
  517.   } 
  518.   if (! strcasecmp(menu, "unformatted")) {
  519.     r->content_type = "text/html";
  520.     soft_timeout ("send menu", r);
  521.     send_http_header(r);
  522.     rvputs(r, "<html>\n<head><title>Menu for ", r->uri,
  523.        "</title></head>\n\n<body>\n", NULL);
  524.   }
  525.   return;
  526. }
  527.  
  528. void menu_blank(request_rec *r, char *menu)
  529. {
  530.   if (! strcasecmp(menu, "formatted") ) {
  531.     rputs("\n", r);
  532.   }
  533.   if (! strcasecmp(menu, "semiformatted") ) {
  534.     rputs("<br>\n", r);
  535.   }
  536.   if (! strcasecmp(menu, "unformatted") ) {
  537.     rputs("\n", r);  
  538.   }
  539.   return;  
  540. }
  541.  
  542. void menu_comment(request_rec *r, char *menu, char *comment)
  543. {
  544.   if (! strcasecmp(menu, "formatted") ) {
  545.     rputs("\n", r);  /* print just a newline if 'formatted' */
  546.   }
  547.   if (! strcasecmp(menu, "semiformatted") && *comment ) {
  548.     rvputs(r, comment, "\n", NULL);
  549.   }             
  550.   if (! strcasecmp(menu, "unformatted") && *comment ) {
  551.     rvputs(r, comment, "\n", NULL);
  552.   }             
  553.   return;    /* comments are ignored in the 'formatted' form */
  554. }
  555.  
  556. void menu_default(request_rec *r, char *menu, char *href, char *text)
  557. {
  558.   if ( ! strcasecmp(href, "error") || ! strcasecmp(href, "nocontent") ) {
  559.     return;   /* don't print such lines, these aren'te really href's */
  560.   }
  561.   if ( ! strcasecmp(menu, "formatted" ) ) {
  562.     rvputs(r, "<pre>(Default) <a href=\"", href, "\">", text, "</a></pre>\n",
  563.        NULL);
  564.   }
  565.   if ( ! strcasecmp(menu, "semiformatted" ) ) {
  566.     rvputs(r, "<pre>(Default) <a href=\"", href, "\">", text, "</a></pre>\n",
  567.        NULL);
  568.   }
  569.   if ( ! strcasecmp(menu, "unformatted" ) ) {
  570.     rvputs(r, "<a href=\"", href, "\">", text, "</a>", NULL);
  571.   }
  572.   return;
  573. }
  574.  
  575. void menu_directive(request_rec *r, char *menu, char *href, char *text)
  576. {
  577.   if ( ! strcasecmp(href, "error") || ! strcasecmp(href, "nocontent") ) {
  578.     return;   /* don't print such lines, as this isn't really an href */
  579.   }
  580.   if ( ! strcasecmp(menu, "formatted" ) ) {
  581.     rvputs(r, "<pre>          <a href=\"", href, "\">", text, "</a></pre>\n",
  582.        NULL);
  583.   }
  584.   if ( ! strcasecmp(menu, "semiformatted" ) ) {
  585.     rvputs(r, "<pre>          <a href=\"", href, "\">", text, "</a></pre>\n",
  586.        NULL);
  587.   }
  588.   if ( ! strcasecmp(menu, "unformatted" ) ) {
  589.     rvputs(r, "<a href=\"", href, "\">", text, "</a>", NULL);
  590.   }
  591.   return;
  592. }
  593.  
  594. void menu_footer(request_rec *r)
  595. {
  596.   rputs("\n\n</body>\n</html>\n", r);  /* finish the menu */
  597. }
  598.  
  599. int imap_handler(request_rec *r)
  600. {
  601.   char input[LARGEBUF] = {'\0'};
  602.   char href_text[SMALLBUF] = {'\0'};
  603.   char base[SMALLBUF] = {'\0'};
  604.   char redirect[SMALLBUF] = {'\0'};
  605.   char directive[SMALLBUF] = {'\0'};
  606.   char value[SMALLBUF] = {'\0'};
  607.   char mapdflt[SMALLBUF] = {'\0'};
  608.   char closest[SMALLBUF] = {'\0'};
  609.   double closest_yet = -1;
  610.  
  611.   double testpoint[2] = { -1,-1 }; 
  612.   double pointarray[MAXVERTS + 1][2] = { {-1,-1} };
  613.   int vertex = 0;
  614.  
  615.   char *string_pos = NULL;
  616.   int chars_read = 0;
  617.   int showmenu = 0;
  618.  
  619.   imap_conf_rec *icr = get_module_config(r->per_dir_config, &imap_module);
  620.  
  621.   char *imap_menu = icr->imap_menu ? 
  622.     icr->imap_menu : IMAP_MENU_DEFAULT;
  623.   char *imap_default = icr->imap_default ? 
  624.     icr->imap_default : IMAP_DEFAULT_DEFAULT;
  625.   char *imap_base = icr->imap_base ?
  626.     icr->imap_base : IMAP_BASE_DEFAULT;
  627.  
  628.   FILE *imap = pfopen(r->pool, r->filename, "r"); 
  629.  
  630.   if ( ! imap ) 
  631.     return NOT_FOUND;
  632.  
  633.   imap_url(r, NULL, imap_base, base);       /* set base according to default */
  634.   imap_url(r, NULL, imap_default, mapdflt); /* and default to global default */
  635.  
  636.   testpoint[X] = get_x_coord(r->args);
  637.   testpoint[Y] = get_y_coord(r->args);
  638.  
  639.   if ((testpoint[X] == -1 || testpoint[Y] == -1) ||
  640.       (testpoint[X] == 0  && testpoint[Y] == 0) ) {
  641.               /* if either is -1 or if both are zero (new Lynx) */
  642.               /* we don't have valid coordinates */
  643.     testpoint[X] = -1;
  644.     testpoint[Y] = -1;
  645.     if ( strncasecmp(imap_menu, "none", 2) )
  646.       showmenu = 1;    /* show the menu _unless_ ImapMenu is 'none' or 'no' */
  647.   }
  648.  
  649.   if (showmenu) {        /* send start of imagemap menu if we're going to */
  650.     menu_header(r, imap_menu);
  651.   }
  652.  
  653.   while (!cfg_getline(input, LARGEBUF, imap)) {
  654.     string_pos = input;   /* always start at the beginning of line */
  655.  
  656.     directive[0] = '\0';
  657.     value[0] = '\0';  
  658.     href_text[0] = '\0';
  659.     redirect[0] = '\0';
  660.     chars_read = 0; /* clear these before using */
  661.  
  662.     if ( ! input[0] ) {     
  663.       if (showmenu) {
  664.     menu_blank(r, imap_menu);
  665.       }
  666.       continue;                           
  667.     }
  668.  
  669.     if ( input[0] == '#' ) {
  670.       if (showmenu) {
  671.     menu_comment(r, imap_menu, input + 1); 
  672.       }           
  673.       continue;
  674.     } /* blank lines and comments are ignored if we aren't printing a menu */
  675.  
  676.  
  677.     if (sscanf(input, "%s %s", directive, value) != 2) {
  678.       continue;                           /* make sure we read two fields */
  679.     }
  680.     /* Now skip what we just read... we can't use ANSIism %n */
  681.     while (!(isspace(*string_pos)))    /* past directive */
  682.     string_pos++;
  683.     while (isspace(*string_pos))    /* and whitespace */
  684.     string_pos++;
  685.     while (!(isspace(*string_pos)))    /* and value... have to watch it */
  686.     string_pos++;            /* can have punctuation and stuff */
  687.     
  688.     if ( ! strncasecmp(directive, "base", 4 ) ) {       /* base, base_uri */
  689.       imap_url(r, NULL, value, base);
  690.       continue; /* base is never printed to a menu */
  691.     }    
  692.  
  693.     chars_read = read_quoted(string_pos, href_text);
  694.     string_pos += chars_read;      /* read the quoted href text if present */
  695.  
  696.     if ( ! strcasecmp(directive, "default" ) ) {        /* default */
  697.       imap_url(r, NULL, value, mapdflt);
  698.       if (showmenu) {              /* print the default if there's a menu */
  699.     if (! *href_text) {           /* if we didn't find a "href text" */
  700.       strcpy(href_text, mapdflt); /* use the href itself as text */
  701.     }
  702.     imap_url(r, base, mapdflt, redirect); 
  703.     menu_default(r, imap_menu, redirect, href_text);
  704.       }
  705.       continue;
  706.     }
  707.  
  708.     vertex = 0;
  709.     while ( vertex < MAXVERTS &&  
  710.      sscanf(string_pos, "%lf,%lf",
  711.      &pointarray[vertex][X], &pointarray[vertex][Y])   == 2)
  712.     {
  713.     /* Now skip what we just read... we can't use ANSIism %n */
  714.     while(isspace(*string_pos))    /* past whitespace */
  715.         string_pos++;
  716.     while(isdigit(*string_pos))    /* and the 1st number */
  717.         string_pos++;
  718.     string_pos++;            /* skip the ',' */
  719.     while(isdigit(*string_pos))    /* 2nd number */
  720.         string_pos++;
  721.     vertex++;
  722.     }                /* so long as there are more vertices to read, and
  723.             we have room, read them in.  We start where we left
  724.             off of the last sscanf, not at the beginning.*/
  725.                   
  726.     pointarray[vertex][X] = -1;  /* signals the end of vertices */
  727.  
  728.     if (showmenu) {
  729.       read_quoted(string_pos, href_text); /* href text could be here instead */
  730.       if (! *href_text) {           /* if we didn't find a "href text" */
  731.     strcpy(href_text, value);  /* use the href itself in the menu */
  732.       }
  733.       imap_url(r, base, value, redirect); 
  734.       menu_directive(r, imap_menu, redirect, href_text);
  735.       continue;
  736.     }
  737.     /* note that we don't make it past here if we are making a menu */
  738.  
  739.     if (testpoint[X] == -1 || pointarray[0][X] == -1 )
  740.       continue;    /* don't try the following tests if testpoints
  741.             are invalid, or if there are no coordinates */
  742.  
  743.     if ( ! strcasecmp(directive, "poly" ) ) {        /* poly */
  744.  
  745.       if (pointinpoly (testpoint, pointarray) ) {
  746.     pfclose(r->pool, imap); 
  747.     imap_url(r, base, value, redirect);     
  748.     return (imap_reply(r, redirect));
  749.       }
  750.       continue;
  751.     }
  752.  
  753.     if ( ! strcasecmp(directive, "circle" ) ) {        /* circle */
  754.     
  755.       if (pointincircle (testpoint, pointarray) ) {
  756.     pfclose(r->pool, imap); 
  757.     imap_url(r, base, value, redirect);     
  758.     return (imap_reply(r, redirect));
  759.       }
  760.       continue;
  761.     }
  762.     
  763.     if ( ! strcasecmp(directive, "rect" ) ) {        /* rect */
  764.       
  765.       if (pointinrect (testpoint, pointarray) ) {
  766.     pfclose(r->pool, imap); 
  767.     imap_url(r, base, value, redirect);     
  768.     return (imap_reply(r, redirect));
  769.       }
  770.       continue;
  771.     }
  772.     
  773.     if ( ! strcasecmp(directive, "point" ) ) {         /* point */
  774.       
  775.       if (is_closer(testpoint, pointarray, &closest_yet) ) {
  776.     strcpy(closest, value);  /* if the closest point yet save it */
  777.       }
  778.       
  779.       continue;    
  780.     }     /* move on to next line whether it's closest or not */
  781.     
  782.   }       /* nothing matched, so we get another line! */
  783.  
  784.   pfclose(r->pool, imap);   /* we are done with the map file, so close it */
  785.  
  786.   if (showmenu) {
  787.     menu_footer(r);   /* finish the menu and we are done */
  788.     return OK;                
  789.   }
  790.  
  791.   if (*closest) {    /* if a 'point' directive has been seen */
  792.     imap_url(r, base, closest, redirect);     
  793.     return (imap_reply(r, redirect));
  794.   }    
  795.  
  796.   if (*mapdflt ) {   /* a default should be defined, even if only 'nocontent'*/
  797.     imap_url(r, base, mapdflt, redirect);
  798.     return(imap_reply(r, redirect));
  799.   }    
  800.  
  801.   return SERVER_ERROR;   /* If we make it this far, we failed. They lose! */
  802. }
  803.  
  804.  
  805. handler_rec imap_handlers[] = {
  806. { IMAP_MAGIC_TYPE, imap_handler },
  807. { "imap-file", imap_handler },
  808. { NULL }
  809. };
  810.  
  811. module imap_module = {
  812.    STANDARD_MODULE_STUFF,
  813.    NULL,            /* initializer */
  814.    create_imap_dir_config,    /* dir config creater */
  815.    merge_imap_dir_configs,    /* dir merger --- default is to override */
  816.    NULL,            /* server config */
  817.    NULL,            /* merge server config */
  818.    imap_cmds,            /* command table */
  819.    imap_handlers,        /* handlers */
  820.    NULL,            /* filename translation */
  821.    NULL,            /* check_user_id */
  822.    NULL,            /* check auth */
  823.    NULL,            /* check access */
  824.    NULL,            /* type_checker */
  825.    NULL,            /* fixups */
  826.    NULL                /* logger */
  827. };
  828.