/* 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[] = { { "<", "<" }, { ">", ">" }, { "&", "&" }, { "\"", """ }, { " ", " " }, { 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; }