winsmaug1.5/
winsmaug1.5/boards/
winsmaug1.5/building/
winsmaug1.5/councils/
winsmaug1.5/deity/
winsmaug1.5/doc/mudprogs/
winsmaug1.5/gods/
winsmaug1.5/i3/
winsmaug1.5/imc/
winsmaug1.5/notes/
winsmaug1.5/player/a/
winsmaug1.5/web/
winsmaug1.5/web/archives/
winsmaug1.5/web/images/
winsmaug1.5/web/public_html/
winsmaug1.5/web/staff_html/
/* ROM 2.4 Integrated Web Server - Version 1.0
 *
 * This is my first major snippet... Please be kind. ;-)
 * Copyright 1998 -- Defiant -- Rob Siemborski -- mud@towers.crusoe.net
 *
 * Many thanks to Russ and the rest of the developers of ROM for creating
 * such an excellent codebase to program on.
 *
 * If you use this code on your mud, I simply ask that you place my name
 * someplace in the credits.  You can put it where you feel it is
 * appropriate.
 *
 * I offer no guarantee that this will work on any mud except my own, and
 * if you can't get it to work, please don't bother me.  I wrote and tested
 * this only on a Linux 2.0.30 system.  Comments about bugs, are, however,
 * appreciated.
 *
 * Now... On to the installation!
 */

/*
 * Insanity v0.9a pre-release Modifications
 * By Chris Fewtrell (Trax) <C.J.Fewtrell@bcs.org.uk>
 *
 * - Added functionailiy for Secure Web server pages, using standard HTTP
 *   Basic authentication, comparing with pass list generated with command
 *   from within the MUD itself. 
 * - Started work on web interface to help files, allowing them to be browsed
 *   from a web browser rather than being in MUD to read them.
 * - Seperated out the HTTP codes and content type to seperate functions
 *   (intending to allow more than HTML to be served via this)
 * - Adjusted the descriptor handling to prevent anyone from prematurely
 *   stopping a transfer causing a fd exception and the system to exit()
 * - Created a sorta "virtual" web directory for the webserver files to be
 *   actually served. This contains the usual images dir if any images are
 *   needed to be served from a central repository rather than generated.
 *   Be warned though! It WON'T follow any symlinks, I'll add that later
 *   with the stat function.. (maybe :) 
 *
 * Future Possbile additions:
 * - Access to general boards though web interface, prolly prevent posting but
 *   being able to browse and read notes to 'all' would be allowed
 */

/*	Smaug 1.4 addition by Christopher Aaron Haslage (Yakkov) 9/9/99
 *
 *	This is my first code release, I am happy...  Okay, here is the skinny:
 *	Everything has been simplified, the HTML is external, so your webpage
 *	builders can build the webpages themselves.  The directory is /web
 *	
 *	You can also edit web.h for file names and such as well.
 *	
 *	Everything was set at default when entered, change the pages to suit.
 *
 *	Any questions, feel free to e-mail kilokahn@terrabox.com
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <ctype.h>
#include <fcntl.h>

#include "mud.h"
#include "web.h"

#define SECURE_WEB      "../web/staff_html"
#define SECURE_URL	"/staffarea"	        	/* The secure URL. http://mud.is.here:5502SECURE_URL */
#define WEB_IMAGES	"../web/images" 		/* for http://mud.is.here:port/images/blah.stuff */
#define AUTH_DOMAIN	"Telnet Interface Staff Area" 	/* Secure Area Description (tell me where this is used) */
#define MAXDATA 1024
#define WEB_PASS_FILE	SYSTEM_DIR "webpass.dat" 	/* Web Password Storage */

/*
 *	Added a few extra items to make it easier to customize and save time
 *	when making the HTML for the certain areas. -- Chris Haslage - 5/99
 */

#define WEBAUTHOR	"<link rev=\"made\" href=\"mailto:kilokahn@eriecoast.com\">\n"
#define WEBBODY		"<body bgcolor=\"#000000\" text=\"#ffffff\">\n"
void Base64Decode       args((char *bufcoded,unsigned char *bufplain,int outbufsize));

typedef struct web_descriptor WEB_DESCRIPTOR;

struct web_descriptor {
    int fd;
    char request[MAXDATA*2];
    struct sockaddr_in their_addr;
    int sin_size;
    WEB_DESCRIPTOR *next;	
    bool valid;
    bool keepalive;
};


typedef struct web_password WEB_PASS;

struct web_password
{
    WEB_PASS *next;
    char *username;
    char *password;
};


WEB_PASS *web_passwords;
WEB_DESCRIPTOR *web_desc_free;

void web_colourconv( char *buffer, const char *txt);


/*
 * Content type stuff
 * This should let us use multiple filetypes
 * behind the server (graphics, html, text etc..)
 * all based on suffix matching
 */

#define CONTENT_HTML	1
#define CONTENT_TEXT	2
#define CONTENT_GIF	3
#define CONTENT_JPEG	4
#define CONTENT_GZIP	5
#define CONTENT_WAV	6
#define CONTENT_VRML	7
#define CONTENT_CLASS   8

struct type_data
{
    char *suffix;
    int type;
};

struct type_data content_types [] =
{
    { ".html",	CONTENT_HTML 	},
    { ".htm",	CONTENT_HTML	},
    { ".gif",	CONTENT_GIF 	},
    { ".txt",	CONTENT_TEXT	},
    { ".text",	CONTENT_TEXT	},
    { ".jpg",	CONTENT_JPEG	},
    { ".jpeg",	CONTENT_JPEG	},
    { ".gz",	CONTENT_GZIP	},
    { ".gzip",	CONTENT_GZIP	},
    { ".wav",	CONTENT_WAV	},
    { ".wrl",	CONTENT_VRML	},
    { ".class",	CONTENT_CLASS   },

    { "",	CONTENT_TEXT	}
};



/* FUNCTION DEFS */
int 	send_buf		(int fd, const char* buf);
void	handle_web_request	(WEB_DESCRIPTOR *wdesc);
void 	handle_web_who_request	(WEB_DESCRIPTOR *wdesc);
void 	handle_web_main		(WEB_DESCRIPTOR *wdesc);
void 	handle_web_unfound	(WEB_DESCRIPTOR *wdesc);
void 	handle_web_wizlist	(WEB_DESCRIPTOR *wdesc);
void 	handle_images		(WEB_DESCRIPTOR *wdesc, char *path);
void	handle_web_about		(WEB_DESCRIPTOR *wdesc);
void	handle_who_routine	(WEB_DESCRIPTOR *wdesc);
void	show_web_file		(char *filename, WEB_DESCRIPTOR *wdesc);

bool    check_web_pass          (char *username, char *password);
void    handle_secure_web       (WEB_DESCRIPTOR *wdesc, char *username, char *password, char *path);
void    save_webpass            ( void );

WEB_DESCRIPTOR *	new_web_desc	(void);
void 			free_web_desc	(WEB_DESCRIPTOR *desc);

/* The mark of the end of a HTTP/1.x request */
const char ENDREQUEST[5] = { 13, 10, 13, 10, 0 }; /* (CRLFCRLF) */

/* Externs */
int top_web_desc;

/* Locals */
WEB_DESCRIPTOR *web_descs;
int sockfd;

bool init_web(int port) 
{
    struct sockaddr_in my_addr;
    char buf[1024];

    web_descs = NULL;
    web_desc_free = NULL;

    sprintf(buf, "Attaching Internal Web Server to Port %d", port);
    log_string(buf);

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    {
	log_string("----> Web Server: Error getting socket");
	perror("web-socket");
	sprintf(buf, "Web server (%d) : Failed initialization - Error getting socket", port);
//	wiznet(buf, NULL, NULL, WIZ_WEB, 0, 0);
	return FALSE;
    }

    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(port);
    my_addr.sin_addr.s_addr = htons(INADDR_ANY);
    bzero(&(my_addr.sin_zero),8);

    if((bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr))) == -1)
    {
	log_string("----> Web Server: Error binding socket");
	perror("web-bind");
	sprintf(buf, "Web server (%d) : Failed initialization - Error binding socket", port);
//	wiznet(buf, NULL, NULL, WIZ_WEB, 0, 0);
	return FALSE;
    }

    /* Only listen for 5 connects at once, do we really need more? */
    listen(sockfd, 5);

    sprintf(buf, "Web server: Initalization complete. Servering on port %d.", port);
//    wiznet(buf, NULL, NULL, WIZ_WEB, 0, 0);

//    sys_data.webup = TRUE;

    return TRUE;
}

struct timeval ZERO_TIME = { 0, 0 };

void handle_web(void) 
{
    int max_fd;
    WEB_DESCRIPTOR *current, *prev=NULL, *next;
    fd_set readfds;

    FD_ZERO(&readfds);
    FD_SET(sockfd, &readfds);

    /* it *will* be atleast sockfd */
    max_fd = sockfd;

    /* add in all the current web descriptors */
    for(current=web_descs; current ; current = current->next) 
    {
	FD_SET(current->fd, &readfds);
	if(max_fd < current->fd)
	    max_fd = current->fd;
    }
	
    /* Wait for ONE descriptor to have activity */
    select(max_fd+1, &readfds, NULL, NULL, &ZERO_TIME);

    if(FD_ISSET(sockfd, &readfds)) 
    {
	/* NEW CONNECTION -- INIT & ADD TO LIST */

	current = new_web_desc();
	current->sin_size  = sizeof(struct sockaddr_in);
	current->request[0] = '\0';

	if((current->fd = accept(sockfd, (struct sockaddr *)&(current->their_addr), &(current->sin_size))) == -1) 
	{
	    log_string("----> Web Server: Error accepting connection");
	    perror("web-accept");
	    free_web_desc(current);
	    FD_CLR(sockfd, &readfds);
	    return;
	}

	current->next = web_descs;
	web_descs = current;

	/* END ADDING NEW DESC */
    }

    /* DATA IN! */
    for(prev = NULL, current=web_descs; current != NULL; current = next) 
    {
	next = current->next;

	if (FD_ISSET(current->fd, &readfds)) /* We Got Data! */
	{
	    char buf[MAXDATA];
	    int numbytes;

	    if((numbytes=read(current->fd,buf,sizeof(buf))) == -1) 
	    {
		perror("web-read");
		if(prev)
		    prev->next = next;
		else
		    web_descs = next;

		free_web_desc(current);
		continue;
	    }

	    buf[numbytes] = '\0';

	    strcat(current->request,buf);
	}

	prev = current;
    } /* DONE WITH DATA IN */

    /* DATA OUT */
    /* Hmm we want to delay this if possible, to prevent it prematurely */
    for(prev= NULL, current=web_descs; current != NULL; current = next )
    {
	next = current->next;

	if(strstr(current->request, "HTTP/1.") /* 1.x request (vernum on FIRST LINE) */
	    && strstr(current->request, ENDREQUEST))
	{
	    handle_web_request(current);
	}
	else if(!strstr(current->request, "HTTP/1.")
		 &&  strchr(current->request, '\n')) /* HTTP/0.9 (no ver number) */
	{
	    handle_web_request(current);		
	}
	else
	{
	    prev = current;
	    continue; /* Don't have full request yet! */
	}

	if(current->keepalive)
	{
	    prev = current;
	    continue;
	}

	close(current->fd);

	if(!prev) 
 	{
	    web_descs = current->next;
	} 
	else 
	{
	    prev->next = current->next;
	}

	free_web_desc(current);
    }   /* END DATA-OUT */
}

/* Generic Utility Function */

int send_buf(int fd, const char* buf) 
{
    return send(fd, buf, strlen(buf), 0);
}

int determine_type(char *path)
{
    int i;

    for(i=0 ; *content_types[i].suffix ; i++)
    {
	if(!str_suffix(content_types[i].suffix, path))
	    return content_types[i].type;
    }

    /* If we dunno, we'll use plain text then */
    return CONTENT_TEXT;
}

void send_200OK(WEB_DESCRIPTOR *wdesc)
{
    send_buf(wdesc->fd,"HTTP/1.1 200 OK\n");
}

void send_404UNFOUND(WEB_DESCRIPTOR *wdesc)
{
    send_buf(wdesc->fd, "HTTP/1.1 404 Not Found\n");
}

void send_401UNAUTHORISED(WEB_DESCRIPTOR *wdesc, char *realm)
{
     char buf[MAX_INPUT_LENGTH];

     sprintf(buf, "WWW-Authenticate: Basic realm=\"%s\"\n", realm);

     send_buf(wdesc->fd,"HTTP/1.1 401 Unauthorised\n");
     send_buf(wdesc->fd, buf);
}

void send_content(WEB_DESCRIPTOR *wdesc, int type)
{
    switch(type)
    {
	case CONTENT_HTML:
    	    send_buf(wdesc->fd,"Content-type: text/html\n\n");
	    break;
	default:
	case CONTENT_TEXT:
    	    send_buf(wdesc->fd,"Content-type: text/plain\n\n");
	    break;
	case CONTENT_GIF:
    	    send_buf(wdesc->fd,"Content-type: image/gif\n\n");
	    break;	
	case CONTENT_WAV:
    	    send_buf(wdesc->fd,"Content-type: audio/x-wav\n\n");
	    break;
	case CONTENT_GZIP:
    	    send_buf(wdesc->fd,"Content-type: application/x-zip-compressed\n\n");
	    break;
	case CONTENT_VRML:
    	    send_buf(wdesc->fd,"Content-type: x-world/x-vrml\n\n");
	    break;
	case CONTENT_CLASS:
/*    	    send_buf(wdesc->fd,"Content-type: application/octect-stream\n\n"); */
	    send_buf(wdesc->fd,"Content-type: application/octet-stream\n\n");
	    break;
	
    }
}


void handle_web_request(WEB_DESCRIPTOR *wdesc)
{
    char buf[MAX_STRING_LENGTH];
    char path[MAX_STRING_LENGTH];
    char *stuff;
    int addr;

        stuff = one_argument(wdesc->request, path);
	one_argument(stuff, path);

	/* process request */
	/* are we using HTTP/1.x? If so, write out header stuff.. */
	if(!strstr(wdesc->request, "GET"))
	{
		send_buf(wdesc->fd,"HTTP/1.1 501 Not Implemented");
		return;
	} 
	else if(strstr(wdesc->request, "HTTP/1."))
	{
	    /* Check for and handle secure area access */
	    if(!str_prefix(SECURE_URL, path))
	    {
		char *where;
		char encoded[MAX_INPUT_LENGTH];
		char username[MAX_INPUT_LENGTH];
		char *password = "";
	
		username[0]='\0';
		encoded[0]='\0';

		where = strstr(stuff, "Authorization: Basic");

		if(!where)
		    send_401UNAUTHORISED(wdesc, AUTH_DOMAIN);
		else
		{
	
		    where += strlen("Authorization: Basic");

		    where++;
		    for(password = encoded; *where && !isspace(*where);
					where++, password++)
			*password = *where;

		    *password = '\0';

		    Base64Decode(encoded, username, MAX_INPUT_LENGTH);

		    for(password = username; *password && *password != ':';
							password++);

		    if(*password == ':')
		    {
			*password = '\0';
			password++;
		    }
	    	}

		if(!check_web_pass(username, password))
		{
		    handle_secure_web(wdesc, "", "", path+strlen(SECURE_URL));
		    return;
		}
		else
		{
		     handle_secure_web(wdesc, username, password, path+strlen(SECURE_URL));
	 	     return;
		}
	    }
	}

	addr = ntohl( wdesc->their_addr.sin_addr.s_addr );

	sprintf(buf, "Web - Request for %s recived from %d.%d.%d.%d",
			path, ( addr >> 24 ) & 0xFF, ( addr >> 16 ) & 0xFF,
				( addr >>  8 ) & 0xFF, ( addr       ) & 0xFF);
//        wiznet(buf,NULL,NULL,WIZ_WEB,0,0);

	    /* Handle the actual request */
	if(!str_cmp(path, "/wholist") || !str_cmp(path, "/wholist.html"))
	{
	    	handle_web_who_request(wdesc);
			if (sysdata.webcounter==TRUE)
			{
				log_string("Telnet Interface Hit: WHOLIST");
			}
	}
	else if(!str_cmp(path, "/") || !str_cmp(path, "/index.html"))
	{
		handle_web_main(wdesc);
			if (sysdata.webcounter==TRUE)
			{
		                log_string("Telnet Interface Hit: INDEX");
			}
	}
	else if(!str_cmp(path, "/wizlist") || !str_cmp(path, "/wizlist.html"))
	{
	    	handle_web_wizlist(wdesc);
			if (sysdata.webcounter==TRUE)
			{
		                log_string("Telnet Interface Hit: WIZLIST");
			}
	}
	else if(!str_cmp(path, "/about") || !str_cmp(path, "/about.html"))
	{
	    	handle_web_about(wdesc);
			if (sysdata.webcounter==TRUE)
			{
		                log_string("Telnet Interface Hit: ABOUT");
			}
	}
	else if(!str_prefix("/images/", path))
	{
	    handle_images(wdesc, path+strlen("/images"));
	}
	else if(!str_prefix(SECURE_URL, path))
	{
		handle_secure_web(wdesc, "", "", path);
	}
	else 
	    handle_web_unfound(wdesc);
}

void shutdown_web (void) 
{
    WEB_DESCRIPTOR *current,*next;

    /* Close All Current Connections */
    for(current=web_descs; current != NULL; current = next) {
	next = current->next;
	close(current->fd);
	free_web_desc(current);
    }

    /* Stop Listening */
    close(sockfd);

//     sys_data.webup = FALSE;
}

void handle_web_main(WEB_DESCRIPTOR *wdesc)
{
    send_200OK(wdesc);
    send_content(wdesc, CONTENT_HTML);

show_web_file(PUB_INDEX, wdesc);
}

void handle_web_unfound(WEB_DESCRIPTOR *wdesc)
{
    send_404UNFOUND(wdesc);
    send_content(wdesc, CONTENT_HTML);

show_web_file(PUB_ERROR, wdesc);

    return;
}

void handle_web_wizlist(WEB_DESCRIPTOR *wdesc)
{
    char buf[MAX_STRING_LENGTH];
    char colbuf[2*MAX_STRING_LENGTH];
    FILE *fp;
    int num = 0;
    char let;

    send_200OK(wdesc);
    send_content(wdesc, CONTENT_HTML);

show_web_file(PUB_WIZLIST_H, wdesc);

    if ( (fp = fopen( WEBWIZ_FILE, "r" )) != NULL )
    {
        while ( !feof(fp) )
        {
            while ( (let = fgetc(fp)) != EOF
		&& num < (MAX_STRING_LENGTH-2))
	    {
		if(let != '\r')
		    buf[num++] = let;
	    }

        }
        buf[num]='\0';
        fclose(fp);
    }
    else
        sprintf(buf, "Error opening Staff list Data file<br>\n\r");

    web_colourconv(colbuf, buf);

    send_buf(wdesc->fd, colbuf);

show_web_file(PUB_WIZLIST_F, wdesc);
}


/*
 * Many thanks to Altrag who contributed this function! --GW
 */
char *text2html(const char *ip)
{
  static struct
  {
    const char *text;
    const char *html;
    int tlen, hlen;
  } convert_table[] =
  { { "<", "&lt;" }, { ">", "&gt;" }, { "&", "&amp;" }, { "\"", "&quot;" },
    { " ", "&nbsp;" }, { NULL, NULL } };

  static char buf[MAX_STRING_LENGTH*2];/* Safety here .. --GW */
  char *bp = buf;
  int i;

  if (!convert_table[0].tlen)
  {
    for (i = 0; convert_table[i].text; ++i)
    {
      convert_table[i].tlen = strlen(convert_table[i].text);
      convert_table[i].hlen = strlen(convert_table[i].html);
    }
  }
  while (*ip)
  {
    for (i = 0; convert_table[i].text; ++i)
      if (!strncmp(ip, convert_table[i].text, convert_table[i].tlen))
        break;
    if (convert_table[i].text)
    {
      strcpy(bp, convert_table[i].html);
      bp += convert_table[i].hlen;
      ip += convert_table[i].tlen;
    }
    else
      *bp++ = *ip++;
  }
  *bp = '\0';
  return buf;
}

char *parse_quotes(char *arg)
{
int str;

for ( str = 0; arg[str] != '\0'; str++ )
{
if ( arg[str] == '*' )
arg[str] = '"';
}

return arg;
}

void handle_web_who_request(WEB_DESCRIPTOR *wdesc)
{
    send_200OK(wdesc);
    send_content(wdesc, CONTENT_HTML);

show_web_file(PUB_WHOLIST_H, wdesc);

do_who(NULL,"");
handle_who_routine(wdesc);

show_web_file(PUB_WHOLIST_F, wdesc);
}

void handle_web_about(WEB_DESCRIPTOR *wdesc)
{
    send_200OK(wdesc);
    send_content(wdesc, CONTENT_HTML);

show_web_file(PUB_ABOUT, wdesc);
}

WEB_DESCRIPTOR *new_web_desc(void)
{
    WEB_DESCRIPTOR *desc;

    if(web_desc_free == NULL) 
    {
	CREATE(desc, WEB_DESCRIPTOR, 1);
	top_web_desc++;
    } 
    else 
    {
	desc = web_desc_free;
	web_desc_free = web_desc_free->next;
    }

    desc->keepalive = FALSE;
    desc->next = NULL;

    return desc;	
}

void free_web_desc(WEB_DESCRIPTOR *desc)
{
    desc->next = web_desc_free;
    web_desc_free = desc;
}

void handle_images(WEB_DESCRIPTOR *wdesc, char *path)
{
    char buf[MAX_STRING_LENGTH];
    char file[MAX_INPUT_LENGTH];
    int type, fd;
    void *buffer;

    if(!str_cmp(path, "") || !str_cmp(path, "/"))
	sprintf(file, "%s%s", WEB_IMAGES, "/index.html");
    else
        sprintf(file, "%s%s", WEB_IMAGES, path);

    if(file[strlen(file)-2]=='/')
    {
	strcat(file, "index.html");
    }

    /* Work out the filetype so we know what we are doing */
    type = determine_type(file);

    fclose(fpReserve);

    if((fd=open(file, O_RDONLY | O_NONBLOCK )) == -1)
    {
	send_404UNFOUND(wdesc);
	send_content(wdesc, CONTENT_HTML);

sprintf(buf, 
	"<HTML><HEAD>\n" WEBAUTHOR
	"<TITLE>%s Telnet Interface -- URL Not Found</TITLE>\n"
	"</HEAD>\n\r" WEBBODY
	"<center><b><font size=+3>%s Telnet Interface</b></font>\n"
	"<br><b><font size=+3>URL Not Found</b></font>\n"
	"<P>The URL, %s, that you requested could not be found.\n\r"

	"<P><a href=\"./\">Go Back to the %s Telnet Interface</a>\n"
	"</center></body></html>\n",
	sysdata.mud_name, sysdata.mud_name, path, sysdata.mud_name );
	send_buf(wdesc->fd, buf);
    }
    else
    {
	int readlen=0;

	buffer = malloc(1024);
	send_200OK(wdesc);
	send_content(wdesc, type);

	while((readlen = read(fd, buffer, 1024)) > 0)
	    send(wdesc->fd, buffer, readlen, 0);

	close(fd);
	free(buffer);
    }

    fpReserve = fopen(NULL_FILE, "r");

    return;
}

void handle_secure_web(WEB_DESCRIPTOR *wdesc, char *username,
					char *password, char *path)
{
    char file[MAX_INPUT_LENGTH];
    int type, fd;
    void *buffer;

    if(username[0]=='\0' || password[0]=='\0')
    {
	send_401UNAUTHORISED(wdesc, "Telnet Interface Staff Area");
 	return;
    }

	if (sysdata.webcounter==TRUE)
	{
		log_string("Telnet Interface Hit: STAFF AREA");
	}


    if(!str_cmp(path, "") || !str_cmp(path, "/"))
	sprintf(file, "%s%s", SECURE_WEB, "/index.html");
    else
        sprintf(file, "%s%s", SECURE_WEB, path);

    if(file[strlen(file)-2]=='/')
    {
	strcat(file, "index.html");
    }

    /* Work out the filetype so we know what we are doing */
    type = determine_type(file);

    fclose(fpReserve);

    if((fd=open(file, O_RDONLY | O_NONBLOCK )) == -1)
    {
	send_404UNFOUND(wdesc);
	send_content(wdesc, CONTENT_HTML);

	show_web_file(STA_ERROR, wdesc);
    }
    else
    {
	int readlen=0;

	buffer = malloc(1024);
	send_200OK(wdesc);
	send_content(wdesc, type);

	while((readlen = read(fd, buffer, 1024)) > 0)
	    send(wdesc->fd, buffer, readlen, 0);

	close(fd);
	free(buffer);
    }

    fpReserve = fopen(NULL_FILE, "r");

    return;
}

bool check_web_pass(char *username, char *password)
{
    WEB_PASS *current;

    for(current = web_passwords ; current ; current = current->next)
	if(!str_cmp(current->username, username))
	    if(!str_cmp(current->password, crypt(password, "yt")))
		return TRUE;
    
    return FALSE;
}

bool change_web_pass(char *username, char *newpass)
{
    WEB_PASS *current, *new;

    for(current = web_passwords ; current ; current = current->next)
	if(!str_cmp(current->username, username))
	    break;

    if(!current)
    {
	log_string("Creating new webpass entry...");

	CREATE(new, WEB_PASS, 1);
	new->username = str_dup(username);
	new->password = str_dup("");

	new->next = web_passwords;
	web_passwords = new;

    }
    else
	new = current;

    STRFREE(new->password);

    new->password = str_dup(crypt(newpass, "yt"));

    save_webpass();

    return TRUE;
}    	

void do_changewebpass(CHAR_DATA *ch, char *argument)
{
    
    char buf[MAX_INPUT_LENGTH];

    argument = one_argument(argument, buf);

    if(change_web_pass(ch->name, buf))
    {
	send_to_char("Web password set.\n\r", ch);
    }
    else
    {
	send_to_char("There was a problem setting the web password.\n\r", ch);
    }

    return;
}

void save_webpass()
{
    FILE *fpWebPass;
    WEB_PASS *current;

    if( ( fpWebPass = fopen( WEB_PASS_FILE, "w" ) ) )
    {
	log_string("Saving web passes");

        for(current = web_passwords ; current ; current = current->next)
	    fprintf(fpWebPass, "WebPass %s~\n%s~\n", current->username, current->password);
        fprintf(fpWebPass, "$0\n");

	fclose(fpWebPass);
    }

    fpReserve = fopen( NULL_FILE, "r" );
}

void load_webpass()
{
	FILE *fpWebPass;

        fclose(fpReserve);

        if( ( fpWebPass = fopen( WEB_PASS_FILE, "r" ) ) )
	{
	     WEB_PASS *new;
	     char *word;

	     for( word = fread_word(fpWebPass) ; str_cmp(word, "$0") ; )
	     {
	         CREATE(new, WEB_PASS, 1);
		 new->username = fread_string(fpWebPass);
	         new->password = fread_string(fpWebPass);

		 new->next = web_passwords;
		 web_passwords = new;
		 word = fread_word(fpWebPass);

	     }
         
  	    fclose(fpWebPass);

	}

	fpReserve = fopen( NULL_FILE, "r" ); 

}


void release_web_desc(int desc)
{
    WEB_DESCRIPTOR *current;
        
    for(current=web_descs; current ; current = current->next)
    {   
        if(current->fd == desc)
        {
            current->keepalive = FALSE;
            return;
        }
    }   
}       
    
int web_colour( char type, char *string )
{
    char	code[ 50 ];
    char	*p = '\0';

    switch( type )
    {
	default:
//	    sprintf( code, "" );
	    break;
	case 'Y':
	    sprintf( code, "</font><font color=#FFFF00>");
	    break;
	case 'y':
	    sprintf( code, "</font><font color=#FFFF00>");
	    break;
	case 'x':
	    sprintf( code, "</font><font color=#000000>" );
	    break;
	case 'b':
	    sprintf( code, "</font><font color=#00007F>" );
	    break;
	case 'c':
	    sprintf( code, "</font><font color=#007F7F>" );
	    break;
	case 'g':
	    sprintf( code, "</font><font color=#007F00>" );
	    break;
	case 'r':
	    sprintf( code, "</font><font color=#7F0000>" );
	    break;
	case 'w':
	    sprintf( code, "</font><font color=#BFBFBF>" );
	    break;
	case 'B':
	    sprintf( code, "</font><font color=#0000FF>" );
	    break;
	case 'C':
	    sprintf( code, "</font><font color=#00FFFF>" );
	    break;
	case 'G':
	    sprintf( code, "</font><font color=#00FF00>" );
	    break;
	case 'R':
	    sprintf( code, "</font><font color=#FF0000>" );
	    break;
	case 'W':
	    sprintf( code, "</font><font color=#FFFFFF>" );
	    break;
	case 'z':
	    sprintf( code, "</font><font color=#7F7F7F>" );
	    break;
	case 'O':
	    sprintf( code, "</font><font color=#7F7F00>" );
	    break;
	case 'p':
	    sprintf( code, "</font><font color=#7F007F>" );
	    break;
	case 'P':
	    sprintf( code, "</font><font color=#FF00FF>" );
	    break;
	case '/':
	    sprintf( code, "<br>" );
	    break;
	case '{':
	    sprintf( code, "%c", '{' );
	    break;
	case '-':
	    sprintf( code, "%c", '~' );
	    break;
    }

    p = code;
    while( *p != '\0' )
    {
	*string = *p++;
	*++string = '\0';
    }

    return( strlen( code ) );
}


void web_colourconv( char *buffer, const char *txt)
{
    const	char	*point;
		int	skip = 0;

    if( txt )
    {
	    for( point = txt ; *point ; point++ )
	    {
		if( *point == '&' )
		{
		    point++;
		    skip = web_colour( *point, buffer );
		    while( skip-- > 0 )
			++buffer;
		    continue;
		}
		*buffer = *point;
		*++buffer = '\0';
	    }
	    *buffer = '\0';
    }
    return;
}

/*
 *	This was added because of webmasters complaining on how they don't
 *	know how to code.  So web.h was added as well as extra directories
 *	in ../web (public_html and staff_html).     [readme.txt in ../web]
 *
 *	The file:  *.tih means 'Telnet Interface Header' (for beginning
 *	the html files) and *.tif 'Telnet Interface Footer' (for ending
 *	the html files).  The middle is filled in with generated code.
 *	
 *	-- Christopher Aaron Haslage (Yakkov) -- 6/3/99 (No Help Needed)
 */

void show_web_file(char *filename, WEB_DESCRIPTOR *wdesc )
{
    char buf[MAX_STRING_LENGTH];
    FILE *fp;
    int num = 0;
    char let;


    if ( (fp = fopen( filename, "r" )) != NULL )
    {
        while ( !feof(fp) )
        {
            while ( (let = fgetc(fp)) != EOF
		&& num < (MAX_STRING_LENGTH-2))
	    {
		if(let != '\r')
		    buf[num++] = let;
	    }

        }
        buf[num]='\0';
        fclose(fp);
    }
    else

        sprintf(buf, "\n\r<P><font color=red>\n"
		"ERROR: Missing or corrupted file in the Telnet Interface!\n"
		"</font><font color=white><P>\n\r");

    send_buf(wdesc->fd, buf);

}

void handle_who_routine(WEB_DESCRIPTOR *wdesc)
{
    FILE *fp;
    char buf[MAX_STRING_LENGTH], col_buf[MAX_STRING_LENGTH];
    int c;
    int num = 0;

    if ( (fp = fopen( WHO_FILE, "r" )) != NULL )
    {
      while ( !feof(fp) )
      {
        while ((buf[num]=fgetc(fp)) != EOF
        &&      buf[num] != '\n'
        &&      buf[num] != '\r'
        &&      num < (MAX_STRING_LENGTH-2))
          num++;
        c = fgetc(fp);
        if ( (c != '\n' && c != '\r') || c == buf[num] )
          ungetc(c, fp);
        buf[num++] = '\n';
        buf[num  ] = '\0';

        if ( strlen(buf) > 32000 )
        {
         bug("Strlen Greater then 32000: show_file",0);
         buf[32000] = '\0';
        }
        num = 0;
      web_colourconv(col_buf, buf);
      send_buf(wdesc->fd,col_buf);
//      send_buf(wdesc->fd,"<BR>");  
      }
fclose(fp);
  }
return;
}