/****************************************************************************\
 .--------------------------------------------------------------------------.
 |               glorglox version 1.23 * advanced image mapper              |
 | Written by Tom Rathborne <tomr@uunet.ca> / based on mapper 1.2 from NCSA |
 +--------------------------------------------------------------------------+
 | Please see http://www.uunet.ca/~tomr/glorglox/ for help on installation. |
 +--------------------------------------------------------------------------+
 |       Portions developed at the National Centre for Supercomputing       |
 |      Applications at the University of Illinois at Urbana-Champaign.     |
 +--------------------------------------------------------------------------+
 |  GIF support: gd 1.2 by Thomas Boutell  http://siva.cshl.org/gd/gd.html  |
 +--------------------------------------------------------------------------+
 | All derivative works must include this gaudy ASCII header to note that   |
 | they are based on glorglox 1.23 by Tom Rathborne <tomr@uunet.ca>.        |
 :==========================================================================:
 | YY.MM.DD * Ver. * HISTORY                                                |
 | 95.01.05 - 0.23 - Started work. It works. (A pleasant surprise.)         |
 | 95.01.19 - 0.42 - Expanded error messages. Enhanced various strings.     |
 | 95.01.10 - 0.69 - Possible Client/Server errors distinguished.           |
 | 95.02.22 - 0.96 - Traded in HSI Raw format for GIF format using gd 1.1.1 |
 | 95.03.15 - 1.00 - Added "NOWHERE" url                                    |
 | 95.04.05 - 1.05 - Fixed strcat() seg fault errors inherited from NCSA    |
 | 95.05.04 - 1.23 - Fixed point-outside-of-picture error                   |
 `--------------------------------------------------------------------------'
\****************************************************************************/

#include <stdio.h>
#include <string.h>
#include "gd.h"
#ifndef pyr
#include <stdlib.h>
#else
#include <ctype.h>
#endif
#include <sys/stat.h>

#include "gconfig.h"

#define VER_STRING "glorglox version 1.23"

#define MAXCOLOR 256
#define MAXLINE 1024
#define X 0
#define Y 1

int             isname(char);
int             getline(char *s, int n, FILE * fp);
char           *safestrcat(char *s1, char *s2);

int
main(int argc, char **argv)
{
	char            input[MAXLINE], picname[MAXLINE], conf[MAXLINE],
	                dest[MAXLINE], header[8], *mapname;
	int             testpoint[2], palsize, testcolor, i, j, k, done = 0,
	                picsize[2];
	FILE           *fp, *picfp;
	char           *t;

	gdImagePtr      picture;

	if (argc != 2)
		clienterr("The wrong number of arguments was passed to <b>glorglox</b>. Your client probably doesn't support ISMAP.");
	mapname = getenv("PATH_INFO");

	if ((!mapname) || (!mapname[0]))
		servererr("No map name was given. This may be a result of server misconfiguration. Please read the <A HREF=\"http://www.uunet.ca/~tomr/glorglox\">instructions</A>.<P>");

	mapname++;
	if (!(t = strchr(argv[1], ',')))
		clienterr("The X and Y coordinates should be separated by commas. No comma was found in the query string. Your client <em>obviously</em> doesn't support image mapping properly.");
	*t++ = '\0';
	testpoint[X] = (double) atoi(argv[1]);
	testpoint[Y] = (double) atoi(t);

	/*
	 * if the mapname contains a '/', it represents a unix path - we get
	 * the translated path, and skip reading the configuration file.
	 */
	if (strchr(mapname, '/')) {
		strcpy(conf, getenv("PATH_TRANSLATED"));
		goto openconf;
	}
	if ((fp = fopen(CONFIG_FILE, "r")) == NULL)
		servererr(safestrcat("Someone probably messed up over here. Couldn't open configuration file: ", CONFIG_FILE));

	while (!(getline(input, MAXLINE, fp))) {
		char            confname[MAXLINE];

		if ((input[0] == '#') || (!input[0]))
			continue;
		for (i = 0; isname(input[i]) && (input[i] != ':'); i++)
			confname[i] = input[i];
		confname[i] = '\0';
		if (!strcmp(confname, mapname))
			goto found;
	}
	/*
	 * if mapname was not found in the configuration file, it still might
	 * represent a file in the server root directory - we get the
	 * translated path, and check to see if a file of that name exists,
	 * jumping to the opening of the map file if it does.
	 */
	if (feof(fp)) {
		struct stat     sbuf;

		strcpy(conf, getenv("PATH_TRANSLATED"));
		if (!stat(conf, &sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG))
			goto openconf;
		else
			servererr("Map not found in configuration file.");
	}
found:
	fclose(fp);
	while (isspace(input[i]) || input[i] == ':')
		++i;

	for (j = 0; input[i] && isname(input[i]); ++i, ++j)
		conf[j] = input[i];
	conf[j] = '\0';

openconf:
	if (!(fp = fopen(conf, "r")))
		servererr(safestrcat("Couldn't open configuration file: ", conf));

	/* first line of config file is path to auxiliary picture */
	getline(picname, MAXLINE, fp);

	if (!(picfp = fopen(picname, "r")))
		servererr(safestrcat("Couldn't open picture file: ", picname));

	picture = gdImageCreateFromGif(picfp);
	fclose(picfp);

	/* Find size of picture */

	if ((testpoint[X] > gdImageSX(picture)) || (testpoint[Y] > gdImageSY(picture)) || (testpoint[X] < 0) || testpoint[Y] < 0)
		servererr(safestrcat("Point outside of picture: ", picname));

	testcolor = gdImageGetPixel(picture, testpoint[X], testpoint[Y]);

	gdImageDestroy(picture);

	/* figure out what URL corresponds to this pixel value */
	while (!(getline(input, MAXLINE, fp) || done)) {
		char            color[8];
		char            url[MAXLINE];

		if ((input[0] == '#') || (!input[0]))
			continue;

		color[0] = '\0';
		url[0] = '\0';

		for (i = 0; isname(input[i]) && (input[i]); i++)
			color[i] = input[i];
		color[i] = '\0';

		while (isspace(input[i]))
			++i;

		for (j = 0; input[i] && isname(input[i]); ++i, ++j)
			url[j] = input[i];
		url[j] = '\0';

		if (!strcmp(color, "default")) {
			strcpy(dest, url);
			continue;
		}
		if (atoi(color) == testcolor) {
			strcpy(dest, url);
			done = 1;
		}
	}
	fclose(fp);

	if (dest[0])
		sendmesg(dest);
	servererr("No default URL specified.");
}

sendmesg(char *url)
{
	if (!strcmp("NOWHERE", url)) {
		if (!strlen(getenv("HTTP_REFERER")))
			printf("content-type: text/html%c%c", 10, 10);
		else
			printf("Location: %s%c%c", getenv("HTTP_REFERER"), 10, 10);

		printf("<HTML>%c<HEAD><TITLE>Go back!</TITLE></HEAD>%c<BODY><H1>Go back!</H1><HR>You clicked on something that goes NOWHERE!<HR></BODY>%c</HTML>", 10, 10, 10);
	} else {
		if (strchr(url, ':'))	/*** It is a full URL ***/
			printf("Location: ");
		else		/*** It is a virtual URL ***/
                        if(atoi(getenv("SERVER_PORT"))!=80) printf("Location: http://%s:%s", getenv("SERVER_NAME"), getenv("SERVER_PORT"));
                        else printf("Location: http://%s", getenv("SERVER_NAME"));


		printf("%s%c%c", url, 10, 10);
		printf("<HTML>%c<HEAD><TITLE>Document Pointer</TITLE></HEAD>%c<BODY><H1>Document Pointer</H1><HR>You need to see <A HREF=\"%s\">this</A>!<HR></BODY>%c</HTML>", 10, 10, url, 10);
	}
	exit(1);
}

servererr(char *msg)
{
	printf("Content-type: text/html%c%c", 10, 10);
	printf("<HTML>%c<HEAD><TITLE>glorglox server Error</TITLE></HEAD>%c<BODY>%c", 10, 10, 10);
	printf("<H1>glorglox server Error</H1><HR>%c", 10);
	printf("<B>The glorglox image map server encountered an error:</B><P>%c", 10);
	printf("%s<HR>%c", msg, 10);
	printf("<B>%s</b><hr>%c", VER_STRING, 10);
	printf("Please contact <I><A HREF=\"mailto:%s\">%s</A></I> with details of what you were doing when the error occurred.%c</BODY>%c</HTML>", ERROR_CONTACT, ERROR_CONTACT, 10, 10);
	exit(-1);
}

clienterr(char *msg)
{
	printf("Content-type: text/html%c%c", 10, 10);
	printf("<HTML>%c<HEAD><TITLE>glorglox client Error</TITLE></HEAD>%c<BODY>%c", 10, 10, 10);
	printf("<H1>glorglox client Error</H1><HR>%c", 10);
	printf("<B>The glorglox image map server encountered an error with information submitted from your client program:</B><P>%c", 10);
	printf("%s<HR>%c", msg, 10);
	printf("<B>%s</b><hr>%c", VER_STRING, 10);
	printf("This may still be a server error. Please contact <I><A HREF=\"mailto:%s\">%s</A></I> if you don't think that it's your fault.%c</BODY>%c</HTML>", ERROR_CONTACT, ERROR_CONTACT, 10, 10);
	exit(-1);
}

int
isname(char c)
{
	return (!isspace(c));
}

int
getline(char *s, int n, FILE * fp)
{
	char           *cp;

	if (fgets(s, n, fp) == NULL)
		return 1;
	if ((cp = strchr(s, '\n')) != NULL)
		*cp = '\0';
	return 0;
}


char           *
safestrcat(char *s1, char *s2)
{
	char           *result;

	result = malloc(strlen(s1) + strlen(s2) + 3);	/* 3 extra bytes never
							 * hurt anyone! */

	strcpy(result, s1);
	strcat(result, s2);

	return (result);
}
