/*--------------------------------------------------------------------------* * ** WolfPaw 1.0 ** * *--------------------------------------------------------------------------* * WolfPaw 1.0 (c) 1997,1998 by Dale Corse * *--------------------------------------------------------------------------* * The WolfPaw Coding Team is headed by: Greywolf * * With the Assitance from: Callinon, Dhamon, Sentra, Wyverns, Altrag * * Scryn, Thoric, Justice, Tricops and Mask. * *--------------------------------------------------------------------------* * Wolfpaw Integrated Web Server Protocol Module * *--------------------------------------------------------------------------*/ /* Code Based On: * ROM 2.4 Integrated Web Server - Version 1.0 * Copyright 1998 -- Defiant -- Rob Siemborski -- mud@towers.crusoe.net * His Copyright states to please include him in your mud credits. * Modifications from that release Copyright Greywolf (Dale Corse) 1998 * My copyright says: * * [ABSOULUTLY NOTHING!] * * Except this: * * I will awnser questions, and help you fix bugs.. with MY CODE * not you other stuff, and i am not resposible for anything that * happens to you as a result of using this code, not even if it * makes you lose your girlfriend, mets your ice cream, formats * you hard drive, or causes nuclear holocost (sp?). Also, please * dont use this code, and say you did it, cause Defiant, Altrag, and I * did. So doing that would piss us off. * * --GW */ #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 <netinet/in.h> #include <arpa/inet.h> #include "mud.h" /* Moved the Struct to Mud.h */ /* FUNCTION DEFS */ int send_buf(int fd, char* buf, bool filter ); void handle_web_request(WEB_DESCRIPTOR *wdesc); void handle_web_who_request(WEB_DESCRIPTOR *wdesc); void handle_web_wwwwho_request(WEB_DESCRIPTOR *wdesc); void handle_web_wizlist_request(WEB_DESCRIPTOR *wdesc); void handle_web_news_request(WEB_DESCRIPTOR *wdesc); char *color_filter( char *string ); char *text2html(const char *ip); char *parse_quotes( char *arg ); /* The mark of the end of a HTTP/1.x request */ const char ENDREQUEST[5] = { 13, 10, 13, 10, 0 }; /* (CRLFCRLF) */ /* Externs */ extern int top_web_desc; /* Linked List stuff --GW */ extern WEB_DESCRIPTOR *first_webdesc; extern WEB_DESCRIPTOR *last_webdesc; /* Locals */ int sockfd; void init_web(int port) { struct sockaddr_in my_addr; char buf[MSL]; // Disabled - AOTAII has the port now..GW return; sprintf(buf,"Web features starting on port: %d", port); log_string(buf); WEBSERVER_STATUS = TRUE; /* Lets clear these out .. --GW */ first_webdesc = NULL; last_webdesc = NULL; top_web_desc = 0; if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("web-socket"); WEBSERVER_STATUS=FALSE; return; } 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) { perror("web-bind"); log_string("WebServer Disabled."); WEBSERVER_STATUS = FALSE; return; } /* Only listen for 5 connects at once, do we really need more? */ /* Nah .. but thanks for asking! =P *smirk* --GW */ listen(sockfd, 5); } struct timeval ZERO_TIME = { 0, 0 }; void handle_web(void) { int max_fd; WEB_DESCRIPTOR *current, *next; fd_set readfds; if ( WEBSERVER_STATUS == FALSE ) return; FD_ZERO(&readfds); FD_SET(sockfd, &readfds); /* it *will* be atleast sockfd */ max_fd = sockfd; /* add in all the current web descriptors */ /* Linked stuff again --GW */ 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(sockfd, &readfds)) { /* NEW CONNECTION -- INIT & ADD TO LIST */ /* Ok .. so we dont really need those memory functions included in the original release, a function for 1 line of code .. no. --GW */ CREATE( current, WEB_DESCRIPTOR, 1 ); 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) { perror("web-accept"); DISPOSE(current); return; } /* Ugh .. lets just use LINK here .. --GW */ LINK( current, first_webdesc, last_webdesc, next, prev ); /* END ADDING NEW DESC */ } /* DATA IN! */ /* Nother change for Linked List stuff --GW */ 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) { perror("web-read"); return; } buf[numbytes] = '\0'; strcat(current->request,buf); } } /* DONE WITH DATA IN */ /* DATA OUT */ /* Again .... --GW */ 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); /* Again, no function needed! also moved this up to here, were done with it, so nuke away! --GW */ UNLINK(current, first_webdesc,last_webdesc,next,prev); DISPOSE(current); } /* Removed a whack of stuff here, we dont need it. --GW */ } /* END DATA-OUT */ /* Generic Utility Function */ int send_buf(int fd, char* buf, bool filter ) { if ( filter ) { send(fd, "<CODE>", 6, 0); buf = color_filter(buf); buf = text2html(buf); send(fd, "</CODE>", 7, 0); } return send(fd, buf, strlen(buf), 0); } void handle_web_request(WEB_DESCRIPTOR *wdesc) { char buf[MSL]; char *hstbuf; struct sockaddr_in *sock; sock = (struct sockaddr_in *)wdesc->their_addr; buf[0]='\0'; hstbuf=NULL; hstbuf = STRALLOC("UNKNOWN"); //hstbuf = inet_ntoa( sock->sin_addr ); /* 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.0 501 Not Implemented", FALSE); return; } else if(strstr(wdesc->request, "HTTP/1.")) { send_buf(wdesc->fd,"HTTP/1.0 200 OK\n", FALSE); send_buf(wdesc->fd,"Content-type: text/html\n\n",FALSE); } /* Handle the actual request */ if(strstr(wdesc->request, "/wholist")) { log_string("Web Hit: WHOLIST"); handle_web_who_request(wdesc); } else if(strstr(wdesc->request, "/wwwlist")) { sprintf(buf,"Web Hit: WWW-WHOLIST (IP: %s)",hstbuf); log_string(buf); handle_web_who_request(wdesc); } else if(strstr(wdesc->request, "/wizlist")) { sprintf(buf,"Web Hit: WIZ-LIST (IP: %s)",hstbuf); log_string(buf); handle_web_wizlist_request(wdesc); } else if(!str_prefix(wdesc->request, "/skills")) { log_string("Web Hit: Skills Listing"); // handle_skills_request(wdesc); } else if(strstr(wdesc->request, "/news")) { sprintf(buf,"Web Hit: NEWS (IP: %s)",hstbuf); log_string(buf); handle_web_news_request(wdesc); } else { sprintf(buf,"Web Hit: INVALID_URL (IP: %s)",hstbuf); log_string(buf); send_buf(wdesc->fd,"Option not Currently Supported.", FALSE); } } void shutdown_web (void) { WEB_DESCRIPTOR *current,*next; /* Close All Current Connections */ /* lets change this around ... blah blah --GW */ for(current=first_webdesc; current; current = next) { next = current->next; close(current->fd); /* Again, no function needed! --GW */ UNLINK(current, first_webdesc,last_webdesc,next,prev); DISPOSE(current); } /* Stop Listening */ close(sockfd); } void handle_web_who_request(WEB_DESCRIPTOR *wdesc) { FILE *fp; char buf[MAX_STRING_LENGTH]; char *buf2; int c; int num = 0; /* Well .. why have 2 copies of your who? Smaug already supports webwho, however wont give anyone the cgi for it .. so here we go! --GW */ /* Send the Basic Html Config, hard coded background .. sue me. --GW */ send_buf(wdesc->fd,"<HTML><HEAD><TITLE>Age of the Ancients -- Who Listing</TITLE></HEAD>\n\r", FALSE); buf2 = STRALLOC("<BODY BACKGROUND=*http://www.ancients.org/PAoA1.jpg* BGCOLOR=*#000000* TEXT=*#F8FFFA* LINK=*#9E9295* VLINK=*#B5B5B5*><B>Age of the Ancients Who Listing</B><P>\n\r"); buf2 = parse_quotes(buf2); send_buf(wdesc->fd,buf2,FALSE); /* Decided to change this, to handle the Who stuff right here. --GW */ /*not */ /* send_buf(wdesc->fd,"<BR>|}*-=-=-=-=-=-=-=-[ Current Adventurers of the Ancients ]-=-=-=-=-=-=-=-*{|</CENTER><BR><BR>",FALSE); send_buf(wdesc->fd,"<TABLE>",FALSE); for( desc = first_descriptor; desc; desc = next_desc ) { next_desc = desc->next; if ( desc->connected != CON_PLAYING ) continue; ch = desc->character; if ( IS_SET( ch->pcdata->flagstwo, MOREPC_INCOG ) || IS_SET( ch->act, PLR_WIZINVIS ) ) continue; if ( IS_IMMORTAL(ch) ) { switch ( ch->level ) { default: break; *59* case MAX_LEVEL - 0: class = "HYPERION";break; *58* case MAX_LEVEL - 1: class = "COUNCIL";break; *57* case MAX_LEVEL - 2: class = "HEAD GOD";break; *56* case MAX_LEVEL - 3: class = "GOD"; break; *55* case MAX_LEVEL - 4: class = "FATE"; break; *54* case MAX_LEVEL - 5: class = "TITAN"; break; *53* case MAX_LEVEL - 6: class = "LORD"; break; *52* case MAX_LEVEL - 7: class = "WIZARD"; break; *51* case MAX_LEVEL - 8: class = "EMPATH"; break; } } if ( ch->pcdata->clan ) { sprintf(clanbuf,"%s",ch->pcdata->clan->whoname); clan = STRALLOC(clanbuf); fclan = TRUE; } else { clan = STRALLOC( " " ); fclan = FALSE; } send_buf(wdesc->fd,"<TR>",FALSE); if ( fclan ) sprintf(buf,"<TD><FONT FACE=*Ariel,Helvetica*><FONT SIZE=-1>%s</FONT></FONT></TD>", !IS_IMMORTAL(ch) ? color_filter(clan) : class ); else sprintf(buf,"<TD><FONT FACE=*Ariel,Helvetica*><FONT SIZE=-1>%s</FONT></FONT></TD>", !IS_IMMORTAL(ch) ? clan : class ); buf2 = STRALLOC(buf); buf2 = parse_quotes(buf2); send_buf(wdesc->fd,buf2,FALSE); sprintf(titlebuf,"%s",ch->pcdata->title); title = STRALLOC(titlebuf); sprintf(buf,"<TD><FONT FACE=*Ariel,Helvetica*><FONT SIZE=-1>%s</FONT></FONT></TD>",color_filter(title)); buf2 = STRALLOC(buf); buf2 = parse_quotes(buf2); send_buf(wdesc->fd,buf2,FALSE); send_buf(wdesc->fd,"</TR>",FALSE); cnt++; } send_buf(wdesc->fd,"</TABLE>",FALSE); sprintf(buf,"Current Players Online: %d<BR>",cnt); send_buf(wdesc->fd,buf,FALSE); */ do_who(NULL,""); /* * Modified version of Show File, used in here --GW */ 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++] = '\r'; buf[num ] = '\0'; if ( strlen(buf) > 32000 ) { bug("Strlen Greater then 32000: show_file",0); buf[32000] = '\0'; } num = 0; send_buf(wdesc->fd,buf,TRUE); send_buf(wdesc->fd,"<BR>",FALSE); /*Equiv to /n/r --GW */ } new_fclose(fp); } return; } void handle_web_wwwwho_request(WEB_DESCRIPTOR *wdesc) { FILE *fp; char buf[MAX_STRING_LENGTH]; char *buf2; int c; int num = 0; /* Well .. why have 2 copies of your who? Smaug already supports webwho, however wont give anyone the cgi for it .. so here we go! --GW */ send_buf(wdesc->fd,"<HTML><HEAD><TITLE>Age of the Ancients -- WWW-Who Listing</TITLE></HEAD>\n\r", FALSE); buf2 = STRALLOC("<BODY BACKGROUND=*http://www.ancients.org/PAoA1.jpg*BGCOLOR=*#000000* TEXT=*#F8FFFA* LINK=*#9E9295* VLINK=*#B5B5B5*><font face=*Arial*><B>Age of the Ancients WWW-Who Listing</B><P>\n\r"); buf2 = parse_quotes(buf2); send_buf(wdesc->fd,buf2,FALSE); do_who(NULL,"www"); /* * Modified version of Show File, used in here --GW */ if ( (fp = fopen( WEBWHO_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++] = '\r'; buf[num ] = '\0'; if ( strlen(buf) > 32000 ) { bug("Strlen Greater then 32000: show_file",0); buf[32000] = '\0'; } num = 0; buf2 = STRALLOC("<font face=*Arial*>"); buf2 = parse_quotes(buf2); send_buf(wdesc->fd,buf2,FALSE); send_buf(wdesc->fd,buf,TRUE); send_buf(wdesc->fd,"</font>",FALSE); send_buf(wdesc->fd,"<BR>",FALSE); /* Equiv to /n/r --GW */ } new_fclose(fp); } return; } #define WEBNEWS_FILE SYSTEM_DIR "WEBNEWS" void handle_web_news_request(WEB_DESCRIPTOR *wdesc) { FILE *fp; char buf[MAX_STRING_LENGTH]; char *buf2; int c; int num = 0; /* Well .. why have 2 copies of your who? Smaug already supports webwho, however wont give anyone the cgi for it .. so here we go! --GW */ send_buf(wdesc->fd,"<HTML><HEAD><TITLE>Age of the Ancients -- WWW-NEWS Listing</TITLE></HEAD>\n\r", FALSE); buf2 = STRALLOC("<BODY BACKGROUND=*http://www.ancients.org/PAoA1.jpg*BGCOLOR=*#000000* TEXT=*#F8FFFA* LINK=*#9E9295* VLINK=*#B5B5B5*><font face=*Arial*><B>Age of the Ancients WWW-NEWS Listing</B><P>\n\r"); buf2 = parse_quotes(buf2); send_buf(wdesc->fd,buf2,FALSE); /* * Modified version of Show File, used in here --GW */ if ( (fp = fopen( WEBNEWS_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++] = '\r'; buf[num ] = '\0'; if ( strlen(buf) > 32000 ) { bug("Strlen Greater then 32000: show_file",0); buf[32000] = '\0'; } num = 0; buf2 = STRALLOC("<font face=*Arial*>"); buf2 = parse_quotes(buf2); send_buf(wdesc->fd,buf2,FALSE); send_buf(wdesc->fd,buf,TRUE); send_buf(wdesc->fd,"</font>",FALSE); send_buf(wdesc->fd,"<BR>",FALSE); /* Equiv to /n/r --GW */ } new_fclose(fp); } return; } #define WEBWIZLIST_FILE SYSTEM_DIR "WEBWIZLIST" void handle_web_wizlist_request(WEB_DESCRIPTOR *wdesc) { FILE *fp; char buf[MAX_STRING_LENGTH]; char *buf2; int c; int num = 0; /* Well .. why have 2 copies of your who? Smaug already supports webwho, however wont give anyone the cgi for it .. so here we go! --GW */ send_buf(wdesc->fd,"<HTML><HEAD><TITLE>Age of the Ancients -- Wizlist</TITLE></HEAD>\n\r", FALSE); buf2 = STRALLOC("<BODY BACKGROUND=*http://www.ancients.org/PAoA1.jpg* BGCOLOR=*#000000* TEXT=*#F8FFFA* LINK=*#9E9295* VLINK=*#B5B5B5*><font face=*Arial*><B>Age of the Ancients Wizlist</B><P>\n\r"); buf2 = parse_quotes(buf2); send_buf(wdesc->fd,buf2,FALSE); do_who(NULL,""); /* * Modified version of Show File, used in here --GW */ if ( (fp = fopen( WEBWIZLIST_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++] = '\r'; buf[num ] = '\0'; if ( strlen(buf) > 32000 ) { bug("Strlen Greater then 32000: show_file",0); buf[32000] = '\0'; } num = 0; /* Lets Center the Who list --GW */ /* send_buf(wdesc->fd,"<CENTER>",FALSE);*/ send_buf(wdesc->fd,buf,FALSE); send_buf(wdesc->fd,"<BR>",FALSE); /* Equiv to /n/r --GW */ /* send_buf(wdesc->fd,"</CENTER>",FALSE);*/ send_buf(wdesc->fd,"</font>",FALSE); } new_fclose(fp); } return; } /* The Mem functions that did reside here, arnt needed anymore, so ill save the real estate. =P --GW */ /* Rip out the Smaug Color Sequences --GW */ /* Hey -- I didnt sayit was perfect.. a hack at most*/ char *color_filter( char *string ) { int c; char temp[MSL]; char *temp2; temp2 = string; for ( c = 0; temp2[c] != '\0' ; c++ ) { /* First Scan for color .. then others --GW */ if ( temp2[c] == '&' || temp2[c] == '^' ) { temp2[c] = '%'; temp2[c+1] = 's'; sprintf(temp,temp2,""); temp2 = STRALLOC(temp); c = -1; /* found 1 .. start again */ } } return temp2; } /* * 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[] = { { "<", "<" }, { ">", ">" }, { "&", "&" }, { "\"", """ }, { " ", " " }, { 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; }