/* 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 :)
* - Including a MUD-Net web module to add the functionaility of the MUD-Net webserver
* code directly into the mud itself for use here, preventing the need for
* the seperate server and client processes (I know it sorta depends on the
* mud be FE never stays down for long..)
*
* 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
*/
/*
* Additional Modifications based upon with with Insanity Codebase
* By Chris Fewtrell (Trax) <C.J.Fewtrell@bcs.org.uk>
*
* - Web server root directory created, all URLs that use internal code
* generated HTML intercept first, then path is handed off to webroot
* handler allowing a directory tree to be built up there. Should allow
* easier management of the file behind the internal web server.
*/
/* Modded for use on 1stMUD by Markanth 14/05/2003 */
#include "merc.h"
#include "webserver.h"
#include "globals.h"
#include "interp.h"
#include "tables.h"
#include "olc.h"
#include "lookup.h"
#include "recycle.h"
#include "magic.h"
#include "gsn.h"
#include "telnet.h"
#include "tablesave.h"
WPWD_DATA pwd;
const struct savetable_type pwdsavetable[] = {
{"name", FIELD_STRING, (void *) &pwd.name, NULL, NULL},
{"pwd", FIELD_STRING, (void *) &pwd.passw, NULL, NULL},
{NULL, 0, NULL, NULL, NULL}
};
TABLESAVE(rw_webpasswds)
{
rw_list(type, WPWD_FILE, WPWD_DATA, wpwd_first, wpwd_last, next, prev,
new_pwd, "WPWD", pwd, pwdsavetable);
}
void update_webpasses(CHAR_DATA * ch, bool pDelete)
{
WPWD_DATA *c_next;
WPWD_DATA *curr;
if (IS_NPC(ch))
return;
for (curr = wpwd_first; curr != NULL; curr = c_next)
{
c_next = curr->next;
if (!str_cmp(ch->name, curr->name))
{
UNLINK(curr, wpwd_first, wpwd_last, next, prev);
free_pwd(curr);
rw_webpasswds(action_write);
}
}
if (pDelete || IS_NULLSTR(ch->pcdata->webpass))
return;
curr = new_pwd();
replace_string(curr->name, ch->name);
replace_string(curr->passw, ch->pcdata->webpass);
LINK(curr, wpwd_first, wpwd_last, next, prev);
rw_webpasswds(action_write);
return;
}
CH_CMD(do_webpass)
{
char arg1[MIL];
char *pArg;
char *pwdnew;
char *p;
char cEnd;
if (!ch || IS_NPC(ch))
return;
if (!IS_IMMORTAL(ch))
{
chprintln(ch, "This feature is only available to immortals, sorry.");
return;
}
pArg = arg1;
while (isspace(*argument))
argument++;
cEnd = ' ';
if (*argument == '\'' || *argument == '\"')
cEnd = *argument++;
while (*argument != '\0')
{
if (*argument == cEnd)
{
argument++;
break;
}
*pArg++ = *argument++;
}
*pArg = '\0';
if (IS_NULLSTR(arg1))
{
chprintln(ch, "Syntax: webpass <new>.");
return;
}
d_write(ch->desc, echo_off_str, 0);
if (strlen(arg1) < 5)
{
chprintln(ch, "New password must be at least five characters long.");
d_write(ch->desc, echo_on_str, 0);
return;
}
pwdnew = crypt(arg1, ch->name);
for (p = pwdnew; *p != '\0'; p++)
{
if (*p == '~')
{
chprintln(ch, "New password not acceptable, try again.");
d_write(ch->desc, echo_on_str, 0);
return;
}
}
replace_string(ch->pcdata->webpass, pwdnew);
save_char_obj(ch);
update_webpasses(ch, FALSE);
chprintln(ch, "Ok.");
d_write(ch->desc, echo_on_str, 0);
return;
}
bool check_web_pass(const char *username, const char *password)
{
WPWD_DATA *current;
for (current = wpwd_first; current; current = current->next)
if (!str_casecmp(current->name, username))
if (!str_casecmp(current->passw, crypt(password, username)))
return TRUE;
return FALSE;
}
#if !defined(NO_WEB)
/* Thanks to John Ludeman for this code...
* Define translation matrix for Base64 decode.
* it's fast and const should make it shared text page.
*/
const int pr2six[256] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64,
64, 64, 64, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
47, 48, 49, 50, 51,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
/*
* Decode a base64 encoded string
*/
void Base64Decode(char *bufcoded, unsigned char *bufplain, int outbufsize)
{
int nbytesdecoded;
int nprbytes;
char *bufin = bufcoded;
unsigned char *bufout = bufplain;
/* Strip leading whitespace */
while (*bufcoded == ' ' || *bufcoded == '\t')
++bufcoded;
/*
* Figure out how many characters are in the input buffer.
* If this would decode into more bytes than would fit into
* the output buffer, adjust the number of input bytes downwards.
*/
bufin = bufcoded;
while (pr2six[(int) *(bufin++)] <= 63)
;
nprbytes = bufin - bufcoded - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
if (nbytesdecoded > outbufsize)
nprbytes = (outbufsize * 4) / 3;
bufin = bufcoded;
while (nprbytes > 0)
{
*(bufout++) =
(unsigned char) (pr2six[(int) *bufin] << 2 | pr2six[(int) bufin[1]]
>> 4);
*(bufout++) =
(unsigned char) (pr2six[(int) bufin[1]] << 4 |
pr2six[(int) bufin[2]] >> 2);
*(bufout++) =
(unsigned char) (pr2six[(int) bufin[2]] << 6 |
pr2six[(int) bufin[3]]);
bufin += 4;
nprbytes -= 4;
}
if (nprbytes & 03)
{
if (pr2six[(int) bufin[-2]] > 63)
nbytesdecoded -= 2;
else
nbytesdecoded -= 1;
}
bufplain[nbytesdecoded] = '\0';
}
/* The mark of the end of a HTTP/1.x request */
const char ENDREQUEST[5] = { 13, 10, 13, 10, 0 }; /* (CRLFCRLF) */
/* Locals */
WEB_DESCRIPTOR *first_webdesc;
WEB_DESCRIPTOR *last_webdesc;
int web_socket;
bool init_web_server()
{
struct sockaddr_in my_addr;
int x = 1;
first_webdesc = NULL;
last_webdesc = NULL;
logf("Attaching Internal Web Server to Port %d", WEBSERVERPORT);
if ((web_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
log_string("----> Web Server: Error getting socket");
log_error("web-socket");
return FALSE;
}
if (setsockopt(web_socket, SOL_SOCKET, SO_REUSEADDR, (void *) &x, sizeof(x))
< 0)
{
log_error("init_web: SO_REUSEADDR");
close(web_socket);
web_socket = -1;
return FALSE;
}
#if defined(SO_LINGER) && !defined(SYSV)
{
struct linger ld;
ld.l_onoff = 1;
ld.l_linger = 1000;
if (setsockopt
(web_socket, SOL_SOCKET, SO_LINGER, (void *) &ld, sizeof(ld)) < 0)
{
log_error("Init_web: SO_LINGER");
close(web_socket);
web_socket = -1;
return FALSE;
}
}
#endif
memset(&my_addr, '\0', sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(WEBSERVERPORT);
if ((bind(web_socket, (struct sockaddr *) &my_addr, sizeof(my_addr))) == -1)
{
log_string("----> Web Server: Error binding socket");
log_error("web-bind");
close(web_socket);
web_socket = -1;
return FALSE;
}
/* Only listen for 5 connects at once, do we really need more? */
/* We might now since I've attached this to the live web page - Samson */
if (listen(web_socket, 20) < 0)
{
log_error("web-listen");
close(web_socket);
web_socket = -1;
return FALSE;
}
return TRUE;
}
struct timeval ZERO_TIME = { 0, 0 };
void update_web_server(void)
{
int max_fd;
WEB_DESCRIPTOR *current, *next;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(web_socket, &readfds);
/* it *will* be atleast web_socket */
max_fd = web_socket;
/* add in all the current web descriptors */
for (current = first_webdesc; 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(web_socket, &readfds))
{
/* NEW CONNECTION -- INIT & ADD TO LIST */
size_t size;
alloc_mem(current, WEB_DESCRIPTOR, 1);
size = sizeof(struct sockaddr_in);
current->request[0] = '\0';
if ((current->fd =
accept(web_socket, (struct sockaddr *) &(current->their_addr),
(socklen_t *) & (size))) == -1)
{
log_string("----> Web Server: Error accepting connection");
log_error("web-accept");
free_mem(current);
FD_CLR(web_socket, &readfds);
return;
}
LINK(current, first_webdesc, last_webdesc, next, prev);
/* END ADDING NEW DESC */
}
/* DATA IN! */
for (current = first_webdesc; current; current = 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)
{
log_error("web-read");
continue;
}
buf[numbytes] = '\0';
strcat(current->request, buf);
}
} /* DONE WITH DATA IN */
/* DATA OUT */
/* Hmm we want to delay this if possible, to prevent it prematurely */
for (current = first_webdesc; current; 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
{
continue; /* Don't have full request yet! */
}
close(current->fd);
UNLINK(current, first_webdesc, last_webdesc, next, prev);
free_mem(current);
}
/* END DATA-OUT */
}
/* Generic Utility Function */
int send_buf(int fd, const char *fmt, ...)
{
char buf[2 * MSL];
va_list args;
int len;
if (IS_NULLSTR(fmt))
return 0;
va_start(args, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if (len > 0)
return send(fd, buf, strlen(buf), 0);
else
return len;
}
void send_401UNAUTHORISED(WEB_DESCRIPTOR * wdesc, char *realm)
{
send_buf(wdesc->fd, "HTTP/1.1 401 Unauthorised\n");
send_buf(wdesc->fd, "WWW-Authenticate: Basic realm=\"%s\"\n", realm);
}
bool lastcolor = FALSE;
#define SET_WWW_FONT(buf, color) \
do \
{ \
strcpy(buf, "<FONT color=\"" color "\">"); \
lastcolor = TRUE; \
} \
while (0);
int html_colour(char type, char *string)
{
char code[MIL];
char out[MSL];
char *p = '\0';
if (lastcolor == TRUE)
strcpy(out, "</FONT>");
else
out[0] = '\0';
switch (type)
{
case '\0':
break;
case ' ':
strcpy(code, " ");
break;
default:
case 'x':
strncpy(code,
"<script type='text/javascript'>document.writeln('<FONT color=' + document.fgColor + '>');</script>",
MIL);
break;
case 'b':
SET_WWW_FONT(code, "navy");
break;
case 'c':
SET_WWW_FONT(code, "teal");
break;
case 'g':
SET_WWW_FONT(code, "green");
break;
case 'm':
SET_WWW_FONT(code, "purple");
break;
case 'r':
SET_WWW_FONT(code, "maroon");
break;
case 'w':
SET_WWW_FONT(code, "silver");
break;
case 'y':
SET_WWW_FONT(code, "olive");
break;
case 'B':
SET_WWW_FONT(code, "blue");
break;
case 'C':
SET_WWW_FONT(code, "cyan");
break;
case 'G':
SET_WWW_FONT(code, "lime");
break;
case 'M':
SET_WWW_FONT(code, "magenta");
break;
case 'R':
SET_WWW_FONT(code, "red");
break;
case 'W':
SET_WWW_FONT(code, "white");
break;
case 'Y':
SET_WWW_FONT(code, "yellow");
break;
case 'd':
SET_WWW_FONT(code, "black");
break;
case 'D':
SET_WWW_FONT(code, "gray");
break;
case '-':
strcpy(code, "~");
break;
case '`':
switch (number_range(1, 14))
{
case 1:
SET_WWW_FONT(code, "navy");
break;
case 2:
SET_WWW_FONT(code, "teal");
break;
case 3:
SET_WWW_FONT(code, "green");
break;
case 4:
SET_WWW_FONT(code, "purple");
break;
case 5:
SET_WWW_FONT(code, "maroon");
break;
default:
case 6:
SET_WWW_FONT(code, "silver");
break;
case 7:
SET_WWW_FONT(code, "olive");
break;
case 8:
SET_WWW_FONT(code, "blue");
break;
case 9:
SET_WWW_FONT(code, "cyan");
break;
case 10:
SET_WWW_FONT(code, "lime");
break;
case 11:
SET_WWW_FONT(code, "magenta");
break;
case 12:
SET_WWW_FONT(code, "red");
break;
case 13:
SET_WWW_FONT(code, "white");
break;
case 14:
SET_WWW_FONT(code, "yellow");
break;
}
break;
case ANSI_KEY:
strcpy(code, "{");
break;
}
strcat(out, code);
p = out;
while (*p != '\0')
{
*string = *p++;
*++string = '\0';
}
return (strlen(out));
}
const char *ansitohtml(int attr, int fore)
{
bool b = (attr == CL_BRIGHT);
int random_fore(void);
switch (fore)
{
case FG_BLACK:
return b ? "gray" : "black";
case FG_RED:
return b ? "red" : "maroon";
case FG_GREEN:
return b ? "lime" : "green";
case FG_YELLOW:
return b ? "yellow" : "olive";
case FG_BLUE:
return b ? "blue" : "navy";
case FG_MAGENTA:
return b ? "magenta" : "purple";
case FG_CYAN:
return b ? "cyan" : "teal";
case FG_WHITE:
return b ? "white" : "silver";
case FG_RANDOM:
return ansitohtml(attr, random_fore());
case FG_NONE:
default:
return
"<script type='text/javascript'>document.writeln(document.fgColor);</script>";
}
}
int html_custom_colour(int slot, char *string)
{
char code[MIL];
char out[MSL];
char *p = NUL;
if (lastcolor == TRUE)
{
strcpy(out, "</FONT>");
lastcolor = FALSE;
}
else
out[0] = NUL;
sprintf(code, "<FONT color=\"%s\">",
ansitohtml(cslot_table[slot].col_attr, cslot_table[slot].col_fore));
lastcolor = TRUE;
strcat(out, code);
p = out;
while (*p != NUL)
{
*string = *p++;
*++string = NUL;
}
return (strlen(out));
}
void html_colourconv(char *buffer, const char *txt)
{
const char *point;
int skip = 0;
const char *end = "</FONT>";
lastcolor = FALSE;
for (point = txt; *point; point++)
{
if (*point == ANSI_KEY)
{
point++;
if (*point == '\0')
point--;
else
skip = html_colour(*point, buffer);
while (skip-- > 0)
++buffer;
continue;
}
else if (*point == ANSI_CUSTOM)
{
int slot = 0;
point++;
while (*point && *point != ANSI_END)
{
if (isdigit(*point))
slot = (slot * 10) + (*point - '0');
point++;
}
if (slot < 0 || slot >= MAX_CUSTOM_COLOUR)
{
bug("invalid custom color");
}
else
{
skip = html_custom_colour(slot, buffer);
while (skip-- > 0)
++buffer;
}
continue;
}
if (*point == '<')
{
*buffer = '&';
*++buffer = 'l';
*++buffer = 't';
*++buffer = ';';
*++buffer = '\0';
continue;
}
if (*point == '>')
{
*buffer = '&';
*++buffer = 'g';
*++buffer = 't';
*++buffer = ';';
*++buffer = '\0';
continue;
}
if (*point == '"')
{
*buffer = '&';
*++buffer = 'q';
*++buffer = 'u';
*++buffer = 'o';
*++buffer = 't';
*++buffer = ';';
*++buffer = '\0';
continue;
}
if (*point == '&')
{
*buffer = '&';
*++buffer = 'a';
*++buffer = 'm';
*++buffer = 'p';
*++buffer = '\0';
continue;
}
if (*point == '\n')
{
*buffer = '<';
*++buffer = 'b';
*++buffer = 'r';
*++buffer = '>';
*++buffer = '\0';
}
*buffer = *point;
*++buffer = '\0';
}
if (lastcolor == TRUE)
{
for (point = end; *point; point++)
{
*buffer = *point;
*++buffer = '\0';
}
}
*buffer = '\0';
return;
}
const char *HTTP_URL(const char *fmt, ...)
{
static char buf[5][MIL];
char path[MIL];
char *result;
static int i;
path[0] = NUL;
if (!IS_NULLSTR(fmt))
{
va_list args;
va_start(args, fmt);
vsnprintf(path, sizeof(path), fmt, args);
va_end(args);
}
++i;
i %= 5;
result = buf[i];
sprintf(result, DEFAULT_URL "%s", HOSTNAME, WEBSERVERPORT, path);
return result;
}
char *get_next(char *path)
{
static char *buf[5];
static int i;
if (IS_NULLSTR(path))
return path;
++i;
i %= 5;
buf[i] = strchr(path, '/');
if (!IS_NULLSTR(buf[i]))
buf[i]++;
return buf[i];
}
bool get_name_password(WEB_DESCRIPTOR * wdesc, const char *stuff)
{
char *where;
char encoded[MIL];
char username[MIL];
char *password = &str_empty[0];
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, (unsigned char *) username, MIL);
for (password = username; *password && *password != ':'; password++);
{
if (*password == ':')
{
*password = '\0';
password++;
}
}
}
return check_web_pass(username, password);
}
void under_line(char *under_lined, const char *spaced_out)
{
char *point;
strcpy(under_lined, spaced_out);
for (point = under_lined; *point; point++)
{
if (*point == ' ')
{
*point = '_';
}
else
{
*point = LOWER(*point);
}
}
return;
}
int min_class_level(int sn)
{
int min_so_far = MAX_LEVEL;
int iClass;
for (iClass = 0; iClass < maxClass; iClass++)
{
if (skill_table[sn].skill_level[iClass] < min_so_far)
min_so_far = skill_table[sn].skill_level[iClass];
}
return min_so_far;
}
void print_header(WEB_DESCRIPTOR * wdesc, const char *title)
{
int i;
send_buf(wdesc->fd, "<HTML>\n");
send_buf(wdesc->fd, "<HEAD>\n");
send_buf(wdesc->fd, "<TITLE>%s @ %s</TITLE>\n", title, MUD_NAME);
send_buf(wdesc->fd,
"</HEAD><BODY BGCOLOR=BLACK TEXT=WHITE LINK=YELLOW VLINK=RED>\n");
send_buf(wdesc->fd,
"<TABLE CELLSPACING=3 CELLPADDING=3 BORDER=0><TR><TD VALIGN=TOP WIDTH=15%%>\n");
send_buf(wdesc->fd, "<UL>\n");
for (i = 0; request_table[i].req != NULL; i++)
{
if (request_table[i].name == NULL)
continue;
send_buf(wdesc->fd, "<LI><A href=\"%s\">%s</A></LI>\n",
HTTP_URL(request_table[i].req), request_table[i].name);
}
send_buf(wdesc->fd, "</UL>\n");
send_buf(wdesc->fd, "</TD><TD VALIGN=TOP WIDTH=100%%>\n");
send_buf(wdesc->fd, "<H2>%s @ %s</H2>\n", title, MUD_NAME);
}
void print_footer(WEB_DESCRIPTOR * wdesc)
{
send_buf(wdesc->fd, "</TD></TR></TABLE>\n");
send_buf(wdesc->fd, "<BR><ADDRESS>\n");
send_buf(wdesc->fd,
"This page is automatically generated by %s.\n", MUD_NAME);
send_buf(wdesc->fd, "</ADDRESS>\n");
send_buf(wdesc->fd, "</BODY>\n");
send_buf(wdesc->fd, "</HTML>\n");
}
void print_file(WEB_DESCRIPTOR * wdesc, char *filename)
{
READ_DATA *fp;
if ((fp = open_read(filename)) != NULL)
{
send_buf(wdesc->fd, fp->str);
close_read(fp);
}
else
{
logf("Failed to open file %s.", filename);
}
}
char *format_obj_to_html(OBJ_DATA * obj)
{
AFFECT_DATA *paf;
static char output[MSL * 5];
char buf[MSL * 5];
output[0] = '\0';
if (IS_NULLSTR(obj->description))
return output;
if (IS_OBJ_STAT(obj, ITEM_INVIS))
strcat(output, "(Invis) ");
if (IS_OBJ_STAT(obj, ITEM_DARK))
strcat(output, "(Dark) ");
if (IS_OBJ_STAT(obj, ITEM_EVIL))
strcat(output, "(Red Aura) ");
if (IS_OBJ_STAT(obj, ITEM_BLESS))
strcat(output, "(Blue Aura) ");
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
strcat(output, "(Magical) ");
if (IS_OBJ_STAT(obj, ITEM_GLOW))
strcat(output, "(Glowing) ");
if (IS_OBJ_STAT(obj, ITEM_HUM))
strcat(output, "(Humming) ");
if (obj->item_type == ITEM_WEAPON)
{
for (paf = obj->first_affect; paf; paf = paf->next)
{
if (IS_SET(paf->bitvector, WEAPON_FLAMING))
strcat(output, "(Flaming) ");
if (IS_SET(paf->bitvector, WEAPON_FROST))
strcat(output, "(Frost) ");
if (IS_SET(paf->bitvector, WEAPON_VAMPIRIC))
strcat(output, "(Vampiric) ");
if (IS_SET(paf->bitvector, WEAPON_SHOCKING))
strcat(output, "(Shocking) ");
if (IS_SET(paf->bitvector, WEAPON_POISON))
strcat(output, "(Poison) ");
if (IS_SET(paf->bitvector, WEAPON_SHARP))
strcat(output, "(Sharp) ");
if (IS_SET(paf->bitvector, WEAPON_VORPAL))
strcat(output, "(Vorpal) ");
}
}
if (IS_OBJ_STAT(obj, ITEM_AUCTIONED))
strcat(output, "(Auctioned) ");
if (obj->condition <= 9 && obj->condition >= 0)
strcat(output, "(Ruined) ");
else if (obj->condition >= 10 && obj->condition <= 24)
strcat(output, "(Broken) ");
if (obj->description != NULL)
{
char temp[MSL];
html_colourconv(buf, obj->description);
sprintf(temp, "<A href=\"%s\">%s</A><br>",
HTTP_URL("objs/%ld", obj->pIndexData->vnum), buf);
strcat(output, temp);
}
return output;
}
char *show_list_to_html(OBJ_DATA * list)
{
static char output[MSL * 6];
const char **prgpstrShow;
int *prgnShow;
char *pstrShow;
OBJ_DATA *obj;
int nShow;
int iShow;
int count;
char temp[MSL];
bool found;
count = 0;
for (obj = list; obj != NULL; obj = obj->next_content)
count++;
alloc_mem(prgpstrShow, const char *, count);
alloc_mem(prgnShow, int, count);
nShow = 0;
output[0] = '\0';
for (obj = list; obj != NULL; obj = obj->next_content)
{
if (obj->wear_loc == WEAR_NONE)
{
pstrShow = format_obj_to_html(obj);
found = FALSE;
for (iShow = nShow - 1; iShow >= 0; iShow--)
{
if (!str_cmp(prgpstrShow[iShow], pstrShow))
{
prgnShow[iShow]++;
found = TRUE;
break;
}
}
if (!found)
{
prgpstrShow[nShow] = str_dup(pstrShow);
prgnShow[nShow] = 1;
nShow++;
}
}
}
for (iShow = 0; iShow < nShow; iShow++)
{
if (IS_NULLSTR(prgpstrShow[iShow]))
{
free_string(prgpstrShow[iShow]);
continue;
}
if (prgnShow[iShow] != 1)
{
sprintf(temp, "(%2d) ", prgnShow[iShow]);
strcat(output, temp);
}
else
strcat(output, " ");
sprintf(temp, "%s<br>", prgpstrShow[iShow]);
strcat(output, temp);
free_string(prgpstrShow[iShow]);
if (strlen(output) > 5500)
{
strcat(output, " (More stuff not shown)<br>");
break;
}
}
free_mem(prgpstrShow);
free_mem(prgnShow);
return output;
}
char *show_char_to_html_0(CHAR_DATA * victim)
{
static char buf[MSL * 6];
char cbuf[MSL * 6];
char temp[MSL];
buf[0] = '\0';
if (IS_AFFECTED(victim, AFF_INVISIBLE))
strcat(buf, "(Invis) ");
if (victim->invis_level >= LEVEL_IMMORTAL)
strcat(buf, "(Wizi) ");
if (IS_AFFECTED(victim, AFF_HIDE))
strcat(buf, "(Hide) ");
if (IS_AFFECTED(victim, AFF_CHARM))
strcat(buf, "(Charmed) ");
if (IS_AFFECTED(victim, AFF_PASS_DOOR))
strcat(buf, "(Translucent) ");
if (IS_AFFECTED(victim, AFF_FAERIE_FIRE))
strcat(buf, "(Pink Aura) ");
if (IS_EVIL(victim))
strcat(buf, "(Red Aura) ");
if (IS_GOOD(victim))
strcat(buf, "(Golden Aura) ");
if (IS_AFFECTED(victim, AFF_SANCTUARY))
strcat(buf, "(White Aura) ");
if (!IS_NPC(victim) && !victim->desc)
strcat(buf, "(Linkdead) ");
if (!IS_NPC(victim))
{
if (IS_SET(victim->comm, COMM_AFK))
strcat(buf, "*AFK* ");
if (victim->war)
strcat(buf, "(WAR) ");
if (!IS_NPC(victim) && IS_SET(victim->act, PLR_KILLER))
strcat(buf, "(KILLER) ");
if (!IS_NPC(victim) && IS_SET(victim->act, PLR_THIEF))
strcat(buf, "(THIEF) ");
if (IS_SET(victim->comm, COMM_QUIET))
strcat(buf, "[QUIET] ");
if (victim->desc && victim->desc->editor != ED_NONE)
strcat(buf, "[OLC] ");
if (victim->pcdata->in_progress != NULL)
strcat(buf, "[Note] ");
if (IS_QUESTOR(victim))
strcat(buf, "[Q] ");
}
if (victim->level > 0)
{
long vict_condition;
if (victim->max_hit > 0)
vict_condition = victim->hit * 100 / victim->max_hit;
else
vict_condition = -1;
if (vict_condition < 0)
strcat(buf, "(DEAD) ");
else if (vict_condition < 33)
strcat(buf, "(Wounded) ");
}
if (victim->position ==
(IS_NPC(victim) ? victim->start_pos : POS_STANDING)
&& !IS_NULLSTR(victim->long_descr))
{
if (IS_NPC(victim))
{
html_colourconv(cbuf, victim->long_descr);
sprintf(temp, "<A href=\"%s\">%s</A>", HTTP_URL("chars/%ld",
victim->pIndexData->
vnum), cbuf);
strcat(buf, temp);
}
return (buf);
}
if (IS_NPC(victim))
{
html_colourconv(cbuf, victim->short_descr);
sprintf(temp, "<A href=\"%s\">%s</A>", HTTP_URL("chars/%ld",
victim->pIndexData->
vnum), cbuf);
strcat(buf, temp);
}
else
{
strcat(buf, victim->name);
}
switch (victim->position)
{
case POS_DEAD:
strcat(buf, " is DEAD!!");
break;
case POS_MORTAL:
strcat(buf, " is mortally wounded.");
break;
case POS_INCAP:
strcat(buf, " is incapacitated.");
break;
case POS_STUNNED:
strcat(buf, " is lying here stunned.");
break;
case POS_SLEEPING:
if (victim->on != NULL)
{
if (IS_SET(victim->on->value[2], SLEEP_AT))
{
sprintf(temp, " is sleeping at %s.", victim->on->short_descr);
strcat(buf, temp);
}
else if (IS_SET(victim->on->value[2], SLEEP_ON))
{
sprintf(temp, " is sleeping on %s.", victim->on->short_descr);
strcat(buf, temp);
}
else
{
sprintf(temp, " is sleeping in %s.", victim->on->short_descr);
strcat(buf, temp);
}
}
else
strcat(buf, " is sleeping here.");
break;
case POS_RESTING:
if (victim->on != NULL)
{
if (IS_SET(victim->on->value[2], REST_AT))
{
sprintf(temp, " is resting at %s.", victim->on->short_descr);
strcat(buf, temp);
}
else if (IS_SET(victim->on->value[2], REST_ON))
{
sprintf(temp, " is resting on %s.", victim->on->short_descr);
strcat(buf, temp);
}
else
{
sprintf(temp, " is resting in %s.", victim->on->short_descr);
strcat(buf, temp);
}
}
else
strcat(buf, " is resting here.");
break;
case POS_SITTING:
if (victim->on != NULL)
{
if (IS_SET(victim->on->value[2], SIT_AT))
{
sprintf(temp, " is sitting at %s.", victim->on->short_descr);
strcat(buf, temp);
}
else if (IS_SET(victim->on->value[2], SIT_ON))
{
sprintf(temp, " is sitting on %s.", victim->on->short_descr);
strcat(buf, temp);
}
else
{
sprintf(temp, " is sitting in %s.", victim->on->short_descr);
strcat(buf, temp);
}
}
else
strcat(buf, " is sitting here.");
break;
case POS_STANDING:
if (victim->on != NULL)
{
if (IS_SET(victim->on->value[2], STAND_AT))
{
sprintf(temp, " is standing at %s.", victim->on->short_descr);
strcat(buf, temp);
}
else if (IS_SET(victim->on->value[2], STAND_ON))
{
sprintf(temp, " is standing on %s.", victim->on->short_descr);
strcat(buf, temp);
}
else
{
sprintf(temp, " is standing in %s.", victim->on->short_descr);
strcat(buf, temp);
}
}
strcat(buf, " is here.");
break;
case POS_FIGHTING:
strcat(buf, " is here, fighting ");
if (victim->fighting == NULL)
strcat(buf, "thin air??");
else if (victim->in_room == victim->fighting->in_room)
{
strcat(buf,
IS_NPC(victim) ? victim->fighting->short_descr : victim->
fighting->name);
strcat(buf, ".");
}
else
strcat(buf, "someone who left??");
break;
default:
break;
}
return (buf);
}
char *show_char_to_html(CHAR_DATA * list)
{
CHAR_DATA *rch;
static char output[MSL * 10];
output[0] = '\0';
for (rch = list; rch != NULL; rch = rch->next_in_room)
{
if (rch->invis_level >= LEVEL_IMMORTAL)
continue;
strcat(output, show_char_to_html_0(rch));
strcat(output, "<br>");
}
return (output);
}
HANDLE_URL(HandleMemoryRequest)
{
int sn, count_spell = 0, count_skill = 0;
for (sn = 0; sn < maxSkill; sn++)
{
if (skill_table[sn].name == NULL)
break;
if (skill_table[sn].spell_fun != spell_null)
count_spell += 1;
else
count_skill += 1;
}
print_header(wdesc, "Technical Info");
send_buf(wdesc->fd, "<TABLE>\n");
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Affects</TD> <TD>%5d</TD></TR>\n", top_affect);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Areas</TD> <TD>%5d</TD></TR>\n", top_area);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>ExDes</TD> <TD>%5d</TD></TR>\n", top_ed);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Exits</TD> <TD>%5d</TD></TR>\n", top_exit);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Helps</TD> <TD>%5d</TD></TR>\n", top_help);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Socials</TD> <TD>%5d</TD></TR>\n", maxSocial);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Spells</TD> <TD>%5d</TD></TR>\n", count_spell);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Skills</TD> <TD>%5d</TD></TR>\n", count_skill);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd,
"<TD>Mobs</TD> <TD>%5d (%5d in use)</TD></TR>\n",
top_mob_index, mobile_count);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Objs</TD> <TD>%5d</TD></TR>\n", top_obj_index);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Resets</TD> <TD>%5d</TD></TR>\n", top_reset);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Rooms</TD> <TD>%5d</TD></TR>\n", top_room);
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Shops</TD> <TD>%5d</TD></TR>\n", top_shop);
send_buf(wdesc->fd, "</TABLE>\n");
print_footer(wdesc);
return TRUE;
}
HANDLE_URL(HandleRulesRequest)
{
HELP_DATA *pHelp;
print_header(wdesc, "Rules");
send_buf(wdesc->fd, "<PRE>\n");
if ((pHelp = help_lookup("RULES")) != NULL)
{
char buf[MSL * 2];
html_colourconv(buf, pHelp->text);
send_buf(wdesc->fd, buf);
}
else
send_buf(wdesc->fd, "There are no rules!! Anarchy!!\n");
send_buf(wdesc->fd, "</PRE>\n");
print_footer(wdesc);
return TRUE;
}
HANDLE_URL(HandleAreaRequest)
{
AREA_DATA *pArea;
int count = 0;
print_header(wdesc, "Areas");
send_buf(wdesc->fd, "<TABLE>\n");
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd, "<TD>Low/High Level</TD>\n");
send_buf(wdesc->fd, "<TD>Author</TD>\n");
send_buf(wdesc->fd, "<TD>Area Name</TD></TR>\n");
for (pArea = area_first;;)
{
if (pArea == NULL)
break;
if (!IS_SET(pArea->area_flags, AREA_CLOSED | AREA_PLAYER_HOMES))
{
send_buf(wdesc->fd, "<TR>\n");
if (!IS_NULLSTR(pArea->lvl_comment))
send_buf(wdesc->fd, "<TD>%s</TD>\n", pArea->lvl_comment);
else
send_buf(wdesc->fd, "<TD>%03d %03d</TD>\n", pArea->min_level,
pArea->max_level);
send_buf(wdesc->fd, "<TD>%s</TD>\n", pArea->credits);
send_buf(wdesc->fd, "<TD>%s</TD></TR>\n", pArea->name);
count++;
}
pArea = pArea->next;
}
send_buf(wdesc->fd, "</TABLE>\n");
send_buf(wdesc->fd, "<P>Areas Found: %d.</P>\n", count);
print_footer(wdesc);
return TRUE;
}
HANDLE_URL(HandleSpellsRequest)
{
int gn;
int sn, i;
int tn;
RACE_DATA *race;
bool *displayed;
int past_default = TRUE;
char buf[MSL];
char buf2[MSL];
char buf3[MSL];
alloc_mem(displayed, bool, maxSkill);
memset(displayed, FALSE, maxSkill);
print_header(wdesc, "Spells and Skills");
for (gn = 0; gn < maxGroup; gn++)
{
if (group_table[gn].name == NULL)
break;
if (!str_cmp(group_table[gn].name, "rom basics"))
{
send_buf(wdesc->fd, "<H3>Basic Skills</H3>\n");
send_buf(wdesc->fd,
"All players receive the <I>basic</I> skills for their class.<BR>\n");
send_buf(wdesc->fd, "<TABLE><TR>\n");
send_buf(wdesc->fd, "<TD>Basic Group</TD>\n");
send_buf(wdesc->fd, "<TD>Skills Included</TD></TR>\n");
}
if (!str_cmp(group_table[gn].name, "mage default"))
{
past_default = FALSE;
send_buf(wdesc->fd, "</TABLE>\n");
send_buf(wdesc->fd, "<H3>Default Skill/Spell Groups</H3>\n");
send_buf(wdesc->fd,
"Players receive the <I>default</I> skills and spell groups if they bypass customization.<BR>\n");
send_buf(wdesc->fd, "<TABLE><TR>\n");
send_buf(wdesc->fd, "<TD>Default Group</TD>\n");
send_buf(wdesc->fd, "<TD>Skills Included</TD>\n");
send_buf(wdesc->fd, "<TD>Skill/Spell Groups Included</TD></TR>\n");
}
if (!str_cmp(group_table[gn].name, "weaponsmaster"))
{
past_default = TRUE;
send_buf(wdesc->fd, "</TABLE>\n");
send_buf(wdesc->fd, "<H3>Other Skill/Spell Groups</H3>\n");
send_buf(wdesc->fd,
"Players may gain these skills and spells.<BR>\n");
send_buf(wdesc->fd, "<TABLE><TR>\n");
send_buf(wdesc->fd, "<TD>Skill/Spell Group</TD>\n");
send_buf(wdesc->fd, "<TD>Skills/Spells Included</TD></TR>\n");
}
under_line(buf3, group_table[gn].name);
send_buf(wdesc->fd, "<TR><TD><A NAME=\"%s\">%s</A></TD><TD>",
buf3, group_table[gn].name);
buf[0] = '\0';
for (sn = 0; sn < MAX_IN_GROUP; sn++)
{
if (group_table[gn].spells[sn] == NULL)
break;
tn = skill_lookup(group_table[gn].spells[sn]);
if (tn != -1)
{
sprintf(buf2, "%s, ", group_table[gn].spells[sn]);
strcat(buf, buf2);
displayed[tn] = TRUE;
}
}
if (!IS_NULLSTR(buf) && (strlen(buf) > 2))
buf[(strlen(buf) - 2)] = '\0';
else
strcpy(buf, "None");
if (!past_default)
{
send_buf(wdesc->fd, "%s</TD><TD>\n", buf);
buf[0] = '\0';
for (sn = 0; sn < MAX_IN_GROUP; sn++)
{
if (group_table[gn].spells[sn] == NULL)
break;
tn = skill_lookup(group_table[gn].spells[sn]);
if (tn == -1)
{
under_line(buf3, group_table[gn].spells[sn]);
sprintf(buf2, "<A HREF=\"#%s\">%s</A>, ", buf3,
group_table[gn].spells[sn]);
strcat(buf, buf2);
}
else
{
displayed[tn] = TRUE;
}
}
if (!IS_NULLSTR(buf) && (strlen(buf) > 2))
buf[(strlen(buf) - 2)] = '\0';
else
strcpy(buf, "None");
}
send_buf(wdesc->fd, "%s</TD></TR>\n", buf);
}
send_buf(wdesc->fd, "</TABLE>\n");
send_buf(wdesc->fd, "<H3>Other Skills and Spells</H3>\n");
send_buf(wdesc->fd,
"The following skills and spells are available to various mortals.<BR>\n");
send_buf(wdesc->fd, "<TABLE><TR><TD>\n");
buf[0] = '\0';
for (sn = 1; sn < maxSkill; sn++)
{
if (skill_table[sn].name == NULL)
break;
if (!displayed[sn] && (min_class_level(sn) < ANGEL))
{
sprintf(buf2, "%s, ", skill_table[sn].name);
strcat(buf, buf2);
displayed[sn] = TRUE;
}
}
if (!IS_NULLSTR(buf) && (strlen(buf) > 2))
buf[(strlen(buf) - 2)] = '\0';
else
strcpy(buf, "None");
send_buf(wdesc->fd, "%s</TD></TR>\n", buf);
send_buf(wdesc->fd, "</TABLE>\n");
send_buf(wdesc->fd,
"<P>To view skills in class specific tables, visit the <a href=\"%s\">Classes</a> section.</P>\n",
HTTP_URL("class"));
send_buf(wdesc->fd, "<H3><A NAME=\"RaceSkills\">Race Skills</A></H3>\n");
send_buf(wdesc->fd, "The following skills and spells are race specific.\n");
send_buf(wdesc->fd, "<TABLE><TR>\n");
send_buf(wdesc->fd, "<TD>Race</TD>\n");
send_buf(wdesc->fd, "<TD>Skills</TD></TR>\n");
for (race = race_first; race; race = race->next)
{
if (!race->pc_race)
continue;
send_buf(wdesc->fd, "<TR><TD>%s</TD><TD>\n", race->name);
buf[0] = '\0';
for (sn = 1; sn < maxSkill; sn++)
{
if (skill_table[sn].name == NULL)
break;
for (i = 0; i < 5; i++)
{
if (race->skills[i] == NULL)
break;
if (skill_lookup(race->skills[i]) == sn)
{
sprintf(buf2, "%s, ", skill_table[sn].name);
strcat(buf, buf2);
displayed[sn] = TRUE;
}
}
}
if (!IS_NULLSTR(buf) && (strlen(buf) > 2))
buf[(strlen(buf) - 2)] = '\0';
else
strcpy(buf, "None");
send_buf(wdesc->fd, "%s</TD></TR>\n", buf);
}
send_buf(wdesc->fd, "</TABLE>\n");
send_buf(wdesc->fd, "<H3>Immortal Skills and Spells</H3>\n");
send_buf(wdesc->fd,
"The following skills and spells are available to various immortals.\n");
send_buf(wdesc->fd,
"This list includes some spells under development.<BR>\n");
send_buf(wdesc->fd, "<TABLE><TR>\n");
send_buf(wdesc->fd, "<TD>Spells</TD></TR>\n");
send_buf(wdesc->fd, "<TR><TD>\n");
buf[0] = '\0';
for (sn = 1; sn < maxSkill; sn++)
{
if (skill_table[sn].name == NULL)
break;
if (!displayed[sn])
{
sprintf(buf2, "%s, ", skill_table[sn].name);
strcat(buf, buf2);
displayed[sn] = TRUE;
}
}
if (!IS_NULLSTR(buf) && (strlen(buf) > 2))
buf[(strlen(buf) - 2)] = '\0';
else
strcpy(buf, "None");
send_buf(wdesc->fd, "%s</TD></TR>\n", buf);
send_buf(wdesc->fd, "</TABLE>\n");
print_footer(wdesc);
free_mem(displayed);
return TRUE;
}
HANDLE_URL(HandleWhoRequest)
{
CHAR_DATA *wch;
char buf[MSL * 2];
print_header(wdesc, "Players currently");
send_buf(wdesc->fd, "<TABLE><TR>\n");
send_buf(wdesc->fd, "<TD><I>Level</I></TD>\n");
send_buf(wdesc->fd, "<TD><I>Race</I></TD>\n");
send_buf(wdesc->fd, "<TD><I>Class</I></TD>\n");
send_buf(wdesc->fd, "<TD><I>Clan</I></TD>\n");
send_buf(wdesc->fd, "<TD><I>Name<I></TD></TR>\n");
for (wch = player_first; wch != NULL; wch = wch->next_player)
{
if (wch->invis_level >= LEVEL_IMMORTAL
|| wch->incog_level >= LEVEL_IMMORTAL)
continue;
send_buf(wdesc->fd, "<TR>\n");
if (IS_NULLSTR(wch->pcdata->who_descr))
{
send_buf(wdesc->fd, "<TD>%d</TD>\n", wch->level);
send_buf(wdesc->fd,
"<TD><A href=\"%s\">%s</A></TD>\n",
HTTP_URL("races/%s", wch->race->name), wch->race->name);
send_buf(wdesc->fd, "<TD>%s</TD>\n", class_who(wch));
}
else
{
html_colourconv(buf, wch->pcdata->who_descr);
send_buf(wdesc->fd, "<TD COLSPAN=3>%s</TD>\n", buf);
}
if (is_clan(wch))
{
html_colourconv(buf, wch->clan->who_name);
send_buf(wdesc->fd,
"<TD><A href=\"%s\">%s</A></TD>\n",
HTTP_URL("clans/%s", wch->clan->name), buf);
}
else
send_buf(wdesc->fd, "<TD></TD>\n");
send_buf(wdesc->fd, "<TD>");
send_buf(wdesc->fd, wch->name);
html_colourconv(buf, wch->pcdata->title);
send_buf(wdesc->fd, buf);
send_buf(wdesc->fd, "</TD></TR>\n");
}
send_buf(wdesc->fd, "</TABLE><BR>\n");
print_footer(wdesc);
return TRUE;
}
const char *stat_type_name[MAX_GAMESTAT][2] = {
/* Display filename */
{"PLAYER KILLERS", "pkill"},
{"MOB KILLERS", "mkill"},
{"PK DEATHS", "pkdead"},
{"MOB DEATHS", "mdead"}
};
HANDLE_URL(HandleStatsRequest)
{
int pos;
char *buf = get_next(path);
if (IS_NULLSTR(buf))
{
print_header(wdesc, "Stats");
send_buf(wdesc->fd, "<OL>\n");
for (pos = 0; pos < MAX_GAMESTAT; pos++)
{
send_buf(wdesc->fd,
"<li><A HREF=\"%s\">%s</A>\n", HTTP_URL("stats/%s",
stat_type_name[pos]
[1]),
stat_type_name[pos][0]);
}
send_buf(wdesc->fd, "</OL>\n");
print_footer(wdesc);
return TRUE;
}
else
{
for (pos = 0; pos < MAX_GAMESTAT; pos++)
{
if (!str_cmp(stat_type_name[pos][1], buf))
{
PROTOTYPE(int count_statlist, (void));
PROTOTYPE(int compare_stats, (const void *, const void *));
char temp[MSL];
STAT_DATA *curr;
STAT_DATA **top;
int count, loop;
bool found = FALSE;
EXTERN int compare_type;
sprintf(temp, "Ranking of %s", stat_type_name[pos][0]);
print_header(wdesc, temp);
send_buf(wdesc->fd, "<TABLE>\n");
alloc_mem(top, STAT_DATA *, count_statlist());
count = 0;
compare_type = pos;
loop = 0;
pos = 0;
for (curr = stat_first; curr != NULL; curr = curr->next)
{
top[count] = curr;
count++;
found = TRUE;
}
qsort(top, count, sizeof(*top), compare_stats);
send_buf(wdesc->fd,
"<TR><TD><I>Rank</I></TD><TD><I>Name</I></TD><TD><I>Number</I></TD>"
"<TD><I>Rank</I></TD><TD><I>Name</I></TD><TD><I>Number</I></TD></TR>");
for (loop = 0; loop < count; loop++)
{
if (loop >= 50)
break;
sprintf(temp, "%s<TD>%2d)</TD><TD>%-20s</TD><TD>%ld</TD>\n",
pos == 0 ? "<TR>" : "", loop + 1, top[loop]->name,
top[loop]->gamestat[compare_type]);
send_buf(wdesc->fd, temp);
if (++pos % 2 == 0)
{
send_buf(wdesc->fd, "</TR>");
pos = 0;
}
}
if (!found)
send_buf(wdesc->fd,
"<TR><TD COLSPAN=3>No one found yet.</TD></TR>\n");
send_buf(wdesc->fd, "</TABLE>");
send_buf(wdesc->fd,
"<BR><A href=\"%s\">Back to Stats Index</A>\n",
HTTP_URL("stats"));
print_footer(wdesc);
free_mem(top);
return TRUE;
}
}
}
return FALSE;
}
HANDLE_URL(HandleCommandsRequest)
{
CMD_DATA *i;
int pos = 0;
HELP_DATA *pHelp;
int count = 0;
print_header(wdesc, "Commands");
send_buf(wdesc->fd, "<TABLE>\n");
for (i = cmd_first_sorted; i; i = i->next_sort)
{
if (i->level >= LEVEL_IMMORTAL || !i->show)
continue;
count = 0;
for (pHelp = help_first; pHelp; pHelp = pHelp->next)
{
count++;
if (is_name(i->name, pHelp->keyword))
break;
}
if (pHelp)
send_buf(wdesc->fd, "%s<TD><A href=\"%s\">%s</TD>\n",
(pos == 0) ? "<TR>" : "", HTTP_URL("helps/%d", count),
i->name);
else
send_buf(wdesc->fd, "%s<TD>%s</TD>\n", (pos == 0) ? "<TR>" : "",
i->name);
if (++pos % 5 == 0)
{
send_buf(wdesc->fd, "</TR>");
pos = 0;
}
}
send_buf(wdesc->fd, "</TABLE>\n");
print_footer(wdesc);
return TRUE;
}
HANDLE_URL(HandleHelpsRequest)
{
HELP_DATA *pHelp;
char *buf = get_next(path);
int pos = 0;
char temp[MIL];
if (IS_NULLSTR(buf))
{
int count = 0;
print_header(wdesc, "Help Files");
send_buf(wdesc->fd, "<TABLE>\n");
for (pHelp = help_first; pHelp != NULL; pHelp = pHelp->next)
{
count++;
if (pHelp->level <= MAX_MORTAL_LEVEL && pHelp->level >= 0)
{
const char *temp;
char wordkey[MSL];
temp = pHelp->keyword;
while (!IS_NULLSTR(temp))
{
wordkey[0] = '\0';
temp = one_argument(temp, wordkey);
send_buf(wdesc->fd,
"%s<TD><A HREF=\"%s\">%s</A></TD>\n",
(pos == 0) ? "<TR>" : "", HTTP_URL("helps/%d",
count),
wordkey);
if (++pos % 5 == 0)
{
send_buf(wdesc->fd, "</TR>");
pos = 0;
}
}
}
}
send_buf(wdesc->fd, "</TABLE>\n");
print_footer(wdesc);
return TRUE;
}
else
{
pos = 0;
for (pHelp = help_first; pHelp != NULL; pHelp = pHelp->next)
{
pos++;
sprintf(temp, "%d", pos);
if (!str_cmp(buf, temp))
{
char buf2[MSL * 5];
print_header(wdesc, pHelp->keyword);
send_buf(wdesc->fd, "<TABLE>\n");
send_buf(wdesc->fd, "<TR><TD>[%d] %s<TD></TR>\n", pHelp->level,
pHelp->keyword);
html_colourconv(buf2, fix_string(pHelp->text));
send_buf(wdesc->fd, "<TR><TD>%s</TD></TR>\n", buf2);
send_buf(wdesc->fd, "</TABLE>\n");
send_buf(wdesc->fd,
"<BR><A HREF=\"%s\">Back to Help Index</A>\n",
HTTP_URL("helps"));
print_footer(wdesc);
return TRUE;
}
}
}
return FALSE;
}
HANDLE_URL(HandleRaceRequest)
{
RACE_DATA *race;
char *buf = get_next(path);
if (IS_NULLSTR(buf))
{
print_header(wdesc, "Races");
send_buf(wdesc->fd, "<TABLE><TR>\n");
send_buf(wdesc->fd, "<TD><I>Race</I></TD>\n");
send_buf(wdesc->fd,
"<I><TD>Str</TD><TD>Int</TD><TD>Wis</TD><TD>Dex</TD><TD>Con</TD></I>\n");
send_buf(wdesc->fd, "<TD><I>Creation<BR>Points</I></TD></TR>\n");
for (race = race_first; race != NULL; race = race->next)
{
if (!race->pc_race)
continue;
send_buf(wdesc->fd, "<TR>\n");
send_buf(wdesc->fd,
"<TD><A HREF=\"%s"
"\">%s</A></TD>\n<TD>%d</TD>\n<TD>%d</TD>\n<TD>%d</TD>\n"
"<TD>%d</TD>\n<TD>%d</TD><TD ALIGN=\"center\">%d</TD></TR>\n",
HTTP_URL("races/%s",
race->name), race->name,
race->max_stats[STAT_STR],
race->max_stats[STAT_INT],
race->max_stats[STAT_WIS],
race->max_stats[STAT_DEX],
race->max_stats[STAT_CON], race->points);
}
send_buf(wdesc->fd, "</TABLE>\n");
send_buf(wdesc->fd,
"<P>Creation points increase the amount of experience it takes to gain a level. Maximum a stat can go is 30.</P>\n");
send_buf(wdesc->fd,
"<P>To view skills and spells available to each race, visit the <a href=\"%s\">Skill/Spell</A> section.</P>\n",
HTTP_URL("spells#RaceSkills"));
print_footer(wdesc);
return TRUE;
}
else
{
for (race = race_first; race; race = race->next)
{
if (!str_cmp(race->name, buf))
{
HELP_DATA *pHelp;
char buf2[MSL * 2];
print_header(wdesc, race->name);
if ((pHelp = help_lookup(race->name)) != NULL)
{
html_colourconv(buf2, pHelp->text);
send_buf(wdesc->fd, "<P>%s</P><BR>\n", buf2);
}
else
send_buf(wdesc->fd, "<P>No Info Available</P><BR>\n");
print_footer(wdesc);
return TRUE;
}
}
}
return FALSE;
}
HANDLE_URL(HandleClanRequest)
{
CLAN_DATA *clan;
char buf[MSL * 3], i[MSL], j[MSL];
MBR_DATA *pmbr;
print_header(wdesc, "Clans");
send_buf(wdesc->fd, "<TABLE>\n");
send_buf(wdesc->fd,
"<TR><B><I><TD>Name</TD><TD>Leaders</TD></I></B></TR>\n");
for (clan = clan_first; clan; clan = clan->next)
{
html_colourconv(buf, clan->who_name);
i[0] = '\0';
j[0] = '\0';
for (pmbr = mbr_first; pmbr != NULL; pmbr = pmbr->next)
{
if (pmbr->clan != clan || pmbr->rank != (MAX_RANK - 1))
continue;
sprintf(j, " %s,", pmbr->name);
strcat(i, j);
}
if (!IS_NULLSTR(i))
{
i[strlen(i) - 1] = '\0';
send_buf(wdesc->fd, "<TR><TD>%s</TD><TD>%s</TD></TR>\n", buf, i);
}
else
send_buf(wdesc->fd, "<TR><TD>%s</TD><TD>None</TD></TR>\n", buf);
}
send_buf(wdesc->fd, "</TABLE>\n");
print_footer(wdesc);
return TRUE;
}
HANDLE_URL(HandleClassRequest)
{
int i;
char *buf = get_next(path);
if (IS_NULLSTR(buf))
{
print_header(wdesc, "Classes");
send_buf(wdesc->fd, "<TABLE>\n");
for (i = 0; i < maxClass; i++)
{
send_buf(wdesc->fd,
"<TR><TD><A HREF=\"%s\">%s</A>"
"</TD></TR>\n", HTTP_URL("class/%s",
class_table[i].name),
class_table[i].name);
}
send_buf(wdesc->fd, "</TABLE>\n");
print_footer(wdesc);
return TRUE;
}
else
{
for (i = 0; i < maxClass; i++)
{
if (!str_cmp(class_table[i].name, buf))
{
char buf2[MSL * 2], buf3[MSL];
char skill_list[MAX_MORTAL_LEVEL + 1][MSL];
int snc, lev;
HELP_DATA *pHelp;
print_header(wdesc, class_table[i].name);
if ((pHelp = help_lookup(class_table[i].name)) != NULL)
{
html_colourconv(buf2, pHelp->text);
send_buf(wdesc->fd, "<TABLE><TR><TD>%s</TD></TR></TABLE>\n",
buf2);
}
send_buf(wdesc->fd, "<TABLE>\n");
for (lev = 0; lev < MAX_MORTAL_LEVEL + 1; lev++)
skill_list[lev][0] = '\0';
for (snc = 0; snc < maxSkill; snc++)
{
if (skill_table[snc].name == NULL)
break;
if ((lev = skill_table[snc].skill_level[i]) <=
MAX_MORTAL_LEVEL)
{
sprintf(buf3, "%s, ", skill_table[snc].name);
if (IS_NULLSTR(skill_list[lev]))
sprintf(skill_list[lev],
"<TR><TD>Level %d</TD><TD>%s", lev, buf3);
else
strcat(skill_list[lev], buf3);
}
}
for (lev = 0; lev < MAX_MORTAL_LEVEL + 1; lev++)
{
if (skill_list[lev][0] != '\0')
{
if (strlen(skill_list[lev]) > 2)
skill_list[lev][(strlen(skill_list[lev]) - 2)] =
'\0';
send_buf(wdesc->fd, skill_list[lev]);
send_buf(wdesc->fd, "</TD></TR>\n");
}
}
send_buf(wdesc->fd, "</TABLE>\n");
print_footer(wdesc);
return TRUE;
}
}
}
return FALSE;
}
HANDLE_URL(HandleNotesRequest)
{
char *buf = get_next(path);
int pos = 0;
if (IS_NULLSTR(buf))
{
print_header(wdesc, "Notes");
send_buf(wdesc->fd, "<OL>\n");
for (pos = 0; pos < MAX_BOARD - 1; pos++)
{
send_buf(wdesc->fd,
"<li><A HREF=\"%s\">%s</A>\n", HTTP_URL("notes/%s",
boards
[pos].short_name),
boards[pos].short_name);
}
send_buf(wdesc->fd, "</OL>\n");
print_footer(wdesc);
return TRUE;
}
else
{
for (pos = 0; pos < MAX_BOARD - 1; pos++)
{
if (!str_cmp(boards[pos].short_name, buf))
{
BOARD_DATA *board = &boards[pos];
NOTE_DATA *pnote;
char buf2[MSL * 5];
sprintf(buf2, "Notes on %s Board", board->short_name);
print_header(wdesc, buf2);
for (pnote = board->note_first; pnote != NULL;
pnote = pnote->next)
{
if (!is_name("all", pnote->to_list))
continue;
html_colourconv(buf2, pnote->text);
send_buf(wdesc->fd,
"<TABLE><TR><TD><b>%s</b></TD><TD>%s</TD></TR><TR><TD><B>Date</B></TD>\n"
"<TD>%s</TD></TR><TR><TD COLSPAN=2>%s</TD><TR></TABLE><BR>\n",
pnote->sender, pnote->subject, pnote->date, buf2);
}
send_buf(wdesc->fd,
"<BR><A href=\"%s\">Back to Board Index</A>\n",
HTTP_URL("notes"));
print_footer(wdesc);
return TRUE;
}
}
}
return FALSE;
}
HANDLE_URL(HandleObjsRequest)
{
OBJ_INDEX_DATA *pObj;
char *buf = get_next(path);
if (!IS_NULLSTR(buf))
{
if (!is_number(buf))
{
return FALSE;
}
if ((pObj = get_obj_index(atol(buf))) != NULL)
{
char buf2[MSL * 3];
print_header(wdesc, smash_colour(pObj->short_descr));
html_colourconv(buf2, pObj->short_descr);
send_buf(wdesc->fd, "<P>%s<br>", buf2);
html_colourconv(buf2, pObj->description);
send_buf(wdesc->fd, "%s<br>", buf2);
send_buf(wdesc->fd, "Material: %s<br>", pObj->material);
send_buf(wdesc->fd, "Type: %s<br></P>", item_name(pObj->item_type));
print_footer(wdesc);
return TRUE;
}
}
return FALSE;
}
HANDLE_URL(HandleMobsRequest)
{
MOB_INDEX_DATA *pMob;
char *buf = get_next(path);
if (!IS_NULLSTR(buf))
{
if (!is_number(buf))
{
return FALSE;
}
if ((pMob = get_mob_index(atol(buf))) != NULL)
{
char buf2[MSL * 3];
print_header(wdesc, smash_colour(pMob->short_descr));
html_colourconv(buf2, pMob->short_descr);
send_buf(wdesc->fd, "<P>%s<br>", buf2);
html_colourconv(buf2, pMob->description);
send_buf(wdesc->fd, "%s<br>", buf2);
send_buf(wdesc->fd, "Race: %s<br>", pMob->race->name);
send_buf(wdesc->fd, "Sex: %s<br>", sex_table[pMob->sex].name);
send_buf(wdesc->fd, "Alignment: %d<br>", pMob->alignment);
send_buf(wdesc->fd, "</P>");
print_footer(wdesc);
return TRUE;
}
}
return FALSE;
}
HANDLE_URL(HandleRoomsRequest)
{
ROOM_INDEX_DATA *pRoom;
char *buf = get_next(path);
vnum_t vnum;
if (IS_NULLSTR(buf))
{
vnum = ROOM_VNUM_TEMPLE;
}
else
{
if (!is_number(buf))
{
return FALSE;
}
vnum = atol(buf);
}
if ((pRoom = get_room_index(vnum)) != NULL)
{
if (!IS_SET(pRoom->area->area_flags, AREA_CLOSED | AREA_PLAYER_HOMES))
{
EXIT_DATA *pexit;
int door;
char buf2[MSL * 4];
print_header(wdesc, pRoom->name);
send_buf(wdesc->fd, "<TABLE><TR><TD colspan=3>");
html_colourconv(buf2, pRoom->name);
send_buf(wdesc->fd, buf2);
send_buf(wdesc->fd, "</TD><TD colspan=3>%s", pRoom->area->name);
send_buf(wdesc->fd, "</TD></TR><TR><TD colspan=6>");
html_colourconv(buf2, pRoom->description);
send_buf(wdesc->fd, buf2);
send_buf(wdesc->fd, "</TD></TR><TR>");
for (door = 0; door < MAX_DIR; door++)
{
if ((pexit = pRoom->exit[door]) != NULL
&& pexit->u1.to_room != NULL)
{
send_buf(wdesc->fd,
"<TD><A href=\"%s\">%s</A></TD>",
HTTP_URL("rooms/%ld", pexit->u1.to_room->vnum),
dir_name[door]);
}
else
send_buf(wdesc->fd, "<TD></TD>");
}
send_buf(wdesc->fd, "</TR><TR><TD colspan=6>%s</TD>",
show_list_to_html(pRoom->first_content));
send_buf(wdesc->fd, "</TR><TR><TD colspan=6>%s</TD>",
show_char_to_html(pRoom->first_person));
send_buf(wdesc->fd, "</TR></TABLE>");
print_footer(wdesc);
return TRUE;
}
}
return FALSE;
}
HANDLE_URL(HandleSocialsRequest)
{
SOCIAL_DATA *iSocial;
int i = 0;
print_header(wdesc, "Socials");
send_buf(wdesc->fd, "<TABLE><TR>\n");
for (iSocial = social_first; iSocial; iSocial = iSocial->next)
send_buf(wdesc->fd, "%s<TD>%s</TD>\n",
i++ % 5 == 0 ? "</TR><TR>" : "", iSocial->name);
send_buf(wdesc->fd, "%s</TABLE>\n", i % 5 != 0 ? "</TR>" : "");
print_footer(wdesc);
return TRUE;
}
HANDLE_URL(HandleImmRequest)
{
if (get_name_password(wdesc, stuff))
{
char *buf = get_next(path);
if (IS_NULLSTR(buf))
{
print_header(wdesc, "Immortal Info Page");
send_buf(wdesc->fd,
"<hr><P><A href=\"%s\">Skill Debug List</A></P>",
HTTP_URL("staffarea/skdebug"));
send_buf(wdesc->fd,
"<P><A href=\"%s\">Log Files</A></P>",
HTTP_URL("staffarea/log"));
send_buf(wdesc->fd, "<hr>");
print_footer(wdesc);
return TRUE;
}
else
{
if (!str_prefix("skdebug", buf))
{
int i, sn;
print_header(wdesc, "Skill List");
send_buf(wdesc->fd, "<TABLE><TR><TD>Skill Name</TD>\n");
for (i = 0; i < maxClass; i++)
send_buf(wdesc->fd, "<TD>%s</TD>\n", class_table[i].name);
send_buf(wdesc->fd, "</TR>\n");
for (sn = 0; sn < maxSkill; sn++)
{
send_buf(wdesc->fd, "<TR><TD>%s</TD>\n",
skill_table[sn].name);
for (i = 0; i < maxClass; i++)
{
if (skill_table[sn].skill_level[i] >= LEVEL_IMMORTAL)
send_buf(wdesc->fd, "<TD>---</TD>\n");
else
send_buf(wdesc->fd, "<TD>%d</TD>\n",
skill_table[sn].skill_level[i]);
}
send_buf(wdesc->fd, "</TR>\n");
}
send_buf(wdesc->fd, "</TABLE>");
print_footer(wdesc);
return TRUE;
}
else if (!str_prefix("log", buf))
{
char buf2[MSL];
char *check = get_next(buf);
struct dirent **Dir;
int o, i;
if (IS_NULLSTR(check))
{
char buff[MSL];
int count = 0;
print_header(wdesc, "Log Files");
send_buf(wdesc->fd, "<TABLE><TR>\n");
o = scandir(LOG_DIR, &Dir, 0, alphasort);
for (i = 0; i != o; i++)
{
if (!str_suffix(".log", Dir[i]->d_name))
{
strcpy(buff, Dir[i]->d_name);
buff[strlen(buff) - 4] = '\0';
send_buf(wdesc->fd,
"%s<TD><A href=\"%s\">%s</A></TD>\n",
count % 5 == 0 ? "</TR><TR>" : "",
HTTP_URL("staffarea/log/%s", buff),
Dir[i]->d_name);
count++;
}
}
send_buf(wdesc->fd, "%s</TABLE>\n",
count % 5 != 0 ? "</TR>" : "");
print_footer(wdesc);
return TRUE;
}
else
{
o = scandir(LOG_DIR, &Dir, 0, alphasort);
for (i = 0; i != o; i++)
{
if (!str_suffix(".log", Dir[i]->d_name))
{
strcpy(buf2, Dir[i]->d_name);
buf2[strlen(buf2) - 4] = '\0';
if (!str_cmp(buf2, check))
{
print_header(wdesc, buf2);
send_buf(wdesc->fd, "<PRE>\n");
sprintf(buf2, LOG_DIR "%s", Dir[i]->d_name);
print_file(wdesc, buf2);
send_buf(wdesc->fd, "</PRE>\n");
print_footer(wdesc);
return TRUE;
}
}
}
}
return FALSE;
}
}
return FALSE;
}
else
{
print_header(wdesc, "Invalid Username/Password");
send_buf(wdesc->fd,
"<P>Invalid username/password. Each field is Case Sensitive.</P>\n");
print_footer(wdesc);
return TRUE;
}
}
HANDLE_URL(HandleHistoryRequest)
{
int i;
bool found = FALSE;
print_header(wdesc, "Channel History");
send_buf(wdesc->fd, "<PRE>\n");
for (i = (www_index + 1) % 20; i != www_index; i = (i + 1) % 20)
{
if (!IS_NULLSTR(www_history[i]))
{
found = TRUE;
send_buf(wdesc->fd, "%s\n", smash_colour(www_history[i]));
}
}
if (!IS_NULLSTR(www_history[www_index]))
{
send_buf(wdesc->fd, "%s\n", smash_colour(www_history[www_index]));
found = TRUE;
}
if (!found)
send_buf(wdesc->fd, "None.\n");
else
send_buf(wdesc->fd, "\nCurrent time: %s.\n",
str_time(current_time, -1, "%I:%M:%S %p"));
send_buf(wdesc->fd, "</PRE>");
print_footer(wdesc);
return TRUE;
}
HANDLE_URL(HandleIndexRequest)
{
print_header(wdesc, "Welcome");
send_buf(wdesc->fd, "<P>Connect to <A href=\"" TELNET_URL "\">%s</A></P>\n",
HOSTNAME, port, MUD_NAME);
print_footer(wdesc);
return TRUE;
}
HANDLE_URL(HandleUnknownRequest)
{
print_header(wdesc, "Error");
send_buf(wdesc->fd, "<p>Unknown url '%s'.</p>", path);
print_footer(wdesc);
return TRUE;
}
const struct request_type request_table[] = {
{"index", "Home", HandleIndexRequest, FALSE},
{"online", "Online", HandleWhoRequest, FALSE},
{"tech", "Tech", HandleMemoryRequest, FALSE},
{"areas", "Areas", HandleAreaRequest, FALSE},
{"spells", "Spells", HandleSpellsRequest, FALSE},
{"rules", "Rules", HandleRulesRequest, FALSE},
{"socials", "Socials", HandleSocialsRequest, FALSE},
{"helps", "Helps", HandleHelpsRequest, FALSE},
{"notes", "Notes", HandleNotesRequest, FALSE},
{"races", "Races", HandleRaceRequest, FALSE},
{"commands", "Commands", HandleCommandsRequest, FALSE},
{"clans", "Clans", HandleClanRequest, FALSE},
{"class", "Classes", HandleClassRequest, FALSE},
{"history", "History", HandleHistoryRequest, FALSE},
{"stats", "Stats", HandleStatsRequest, FALSE},
{"rooms", "Explore", HandleRoomsRequest, FALSE},
{"objs", NULL, HandleObjsRequest, FALSE},
{"chars", NULL, HandleMobsRequest, FALSE},
{"staffarea", "Imm Only", HandleImmRequest, TRUE},
{NULL, NULL, NULL, 0}
};
void handle_web_request(WEB_DESCRIPTOR * wdesc)
{
char temp[MSL];
const char *stuff;
char *path;
int addr, i;
char web_buf[MSL];
stuff = first_arg(wdesc->request, temp, FALSE);
first_arg(stuff, temp, FALSE);
path = temp;
if (path[0] == '/')
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;
}
addr = ntohl(wdesc->their_addr.sin_addr.s_addr);
strcpy(web_buf, inet_ntoa(wdesc->their_addr.sin_addr));
if (IS_NULLSTR(path))
{
HandleIndexRequest(wdesc, "", "");
return;
}
logf("WebServer: %s requested '%s'.", web_buf, path);
for (i = 0; request_table[i].fun != NULL; i++)
{
if (request_table[i].secure && !strstr(wdesc->request, "HTTP/1."))
break;
if (!str_prefix(request_table[i].req, path))
{
if ((*request_table[i].fun) (wdesc, path, stuff))
{
tail_chain();
return;
}
else
break;
}
}
HandleUnknownRequest(wdesc, path, stuff);
tail_chain();
}
void shutdown_web_server(void)
{
WEB_DESCRIPTOR *current, *next;
/* Stop Listening */
log_string("Closing webserver...");
close(web_socket);
web_socket = -1;
WebUP = FALSE;
/* Close All Current Connections */
for (current = first_webdesc; current; current = next)
{
next = current->next;
close(current->fd);
UNLINK(current, first_webdesc, last_webdesc, next, prev);
free_mem(current);
}
}
#endif