/* * Playground+ - socket.c * The socket handling code - keep away! * --------------------------------------------------------------------------- */ #include <stdlib.h> #include <stdio.h> #include <assert.h> #include <string.h> #include <unistd.h> #include <ctype.h> #include <errno.h> #include <netdb.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/socket.h> #ifdef LINUX #include "include/un.h" #else #include <sys/un.h> #endif #include <sys/time.h> #include <sys/ioctl.h> #if !defined(linux) #include <sys/filio.h> #endif #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/telnet.h> #define IPROTO 0 #include "include/config.h" #include "include/player.h" #include "include/fix.h" #include "include/proto.h" #include "include/output.h" #ifdef IDENT #include "include/ident.h" extern void send_ident_request(player * p, struct sockaddr_in *sockadd); extern int ident_toclient_fds[2]; extern void read_ident_reply(void); #endif /* externs */ #ifdef SOLARIS extern int close(int); extern int socket(int, int, int); #if !defined(linux) extern int getsockopt(int, int, int, char *, int *); extern int setsockopt(int, int, int, char *, int); extern void perror(char *); extern void bzero(char *, int); extern int select(int, fd_set *, fd_set *, fd_set *, struct timval *); #endif /* Used to be after the #endif */ #ifdef NEED_BIND_DECL extern int bind(int, struct sockaddr *, int); #endif /* NEED_BIND_DECL */ #ifdef NEED_LISTEN_DECL extern int listen(int, int); #endif /* NEED_LISTEN_DECL */ extern int write(int, char *, int); extern int read(int, char *, int); extern char *sprintf(char *, char *,...); #endif /* SOLARIS */ /* interns */ int main_descriptor, alive_descriptor, oi_test; file banish_file, banish_msg, full_msg, splat_msg, under18_msg; /* terminal defintitions NOTE: The incorrect vt100 and ansi definitions have been corrected here - cheers blimey! */ struct terminal terms[] = { {"xterm", "\033[1m", "\033[m", "\033[H\033[2J"}, {"vt220", "\033[1m", "\033[m", "\033[H\033[J"}, {"vt100", "\033[1m", "\033[m", "\033[;H\033[2J"}, {"vt102", "\033[1m", "\033[m", "50\033["}, {"ansi", "\033[1m", "\033[0m", "\033[;H\033[2J"}, {"wyse-30", "\033G4", "\033G0", ""}, {"tvi912", "\033l", "\033m", "\032"}, {"sun", "\033[1m", "\033[m", "\014"}, {"adm", "\033)", "\033(", "1\032"}, {"hp2392", "\033&dB", "\033&d@", "\033H\033J"}, {"", "", "", ""} }; void lscripto(char *filename, char *string, int len) { int fd; char path[160]; char *oldstack = stack, *ptr; memset(path, 0, 160); sprintf(path, "logs/%s", filename); #ifdef BSDISH fd = open(path, (O_WRONLY | O_CREAT | O_APPEND), (S_IRUSR | S_IWUSR)); #else fd = open(path, (O_WRONLY | O_CREAT | O_APPEND | O_SYNC), (S_IRUSR | S_IWUSR)) ; #endif strcpy(stack, string); stack = end_string(stack); for (ptr = oldstack; *ptr; ptr++) switch (*ptr) { case (char) IAC: *ptr = '#'; break; case (char) GA: case (char) EOR: *ptr = '\n'; break; } write(fd, oldstack, len); close(fd); stack = oldstack; } int valid_char_col(char ctest) { ctest = tolower(ctest); if (ctest == 'a' || ctest == 'b' || ctest == 'c' || ctest == 'g' || ctest == 'h' || ctest == 'i' || ctest == 'k' || ctest == 'p' || ctest == 'r' || ctest == 's' || ctest == 'u' || ctest == 'y' || ctest == 'x') return 1; return 0; } char *getcolor(player * p, char col) { static char ret[16]; int rnd; if (p->misc_flags & NOCOLOR && !(p->misc_flags & SYSTEM_COLOR)) return 0; switch (col) { case 'X': rnd = (rand() % 7) + 1; sprintf(ret, "\033[1;3%dm", rnd); return ret; case 'x': rnd = (rand() % 7) + 1; sprintf(ret, "\033[0;3%dm", rnd); return ret; case 'S': case 's': return "\033[3m"; break; case 'K': case 'k': if (p->misc_flags & STOP_BAD_COLORS) return ""; else return "\033[5m"; break; case 'U': case 'u': return "\033[4m"; break; case 'I': case 'i': if (p->misc_flags & STOP_BAD_COLORS) return ""; else return "\033[7m"; break; case 'H': case 'h': return "\033[0;1m"; break; case 'r': return "\033[0;31m"; break; case 'R': return "\033[1;31m"; break; case 'y': return "\033[0;33m"; break; case 'Y': return "\033[1;33m"; break; case 'g': return "\033[0;32m"; break; case 'G': return "\033[1;32m"; break; case 'p': return "\033[0;35m"; break; case 'P': return "\033[1;35m"; break; case 'c': return "\033[0;36m"; break; case 'C': return "\033[1;36m"; break; case 'B': return "\033[1;34m"; break; case 'b': return "\033[0;34m"; break; case 'a': return "\033[1;30m"; break; case 'A': return "\033[0;37m"; break; case 'N': case 'n': if (p->misc_flags & SYSTEM_COLOR && valid_char_col(p->colorset[sys_color_atm])) return getcolor(p, p->colorset[sys_color_atm]); else if (command_type & HIGHLIGHT && p->term) return terms[(p->term) - 1].bold; else if (p->term) return terms[(p->term) - 1].off; else return 0; break; case '^': /* unusable by the silly ressies ;-) */ if (valid_char_col(p->colorset[SYSsc])) return getcolor(p, p->colorset[SYSsc]); else if (p->term) return terms[(p->term) - 1].off; else return 0; break; default: if (p->misc_flags & SYSTEM_COLOR) { if (valid_char_col(col)) return getcolor(p, p->colorset[sys_color_atm]); else if (command_type & HIGHLIGHT && p->term) return terms[(p->term) - 1].bold; else if (p->term) return terms[(p->term) - 1].off; else return 0; } else if (command_type & HIGHLIGHT && p->term) return terms[(p->term) - 1].bold; else if (p->term) return terms[(p->term) - 1].off; else return 0; break; } return 0; } void clear_screen(player * p, char *str) { if (p->term) { if (!write_socket(&p->fd, terms[(p->term) - 1].cls,strlen(terms[(p->term) - 1].cls))) quit(p, 0); } else tell_player(p, " You have to have a termtype set for this command to" " work. Use the command: hitells <termtype>\n"); } /* the hitells command */ void hitells(player * p, char *str) { char *oldstack; int i; oldstack = stack; if (!*str && !(p->term)) { tell_player(p, " Format: Hitells <termtype/?/off>\n"); return; } if (!*str) { sprintf(stack, " Hitells is on, with terminal set to %s.\n", terms[(p->term) - 1].name); stack = end_string(stack); tell_player(p, oldstack); stack = oldstack; return; } if (*str == '?') { strcpy(stack, " Current terminal types available : "); stack = strchr(stack, 0); for (i = 0; terms[i].name[0] != '\0'; i++) { sprintf(stack, "%s, ", terms[i].name); stack = strchr(stack, 0);; } stack -= 2; *stack++ = '.'; *stack++ = '\n'; *stack++ = 0; tell_player(p, oldstack); stack = oldstack; return; } if (!strcasecmp("off", str)) { /* p->term = 0; */ tell_player(p, " Hitells turned off.\n"); if (!(p->misc_flags & NOCOLOR)) { tell_player(p, " Standard color mode disabled due to lack of hitells.\n"); p->misc_flags |= NOCOLOR; } if (p->misc_flags & SYSTEM_COLOR) { tell_player(p, " System colors have been disabled because hitells are off.\n"); p->misc_flags &= ~SYSTEM_COLOR; } p->term = 0; return; } for (i = 0; terms[i].name[0] != '\0'; i++) if (!strcasecmp(str, terms[i].name)) { p->term = i + 1; sprintf(stack, " Hitells turned on, with terminal set to %s.\n", terms[i].name); stack = end_string(stack); tell_player(p, oldstack); stack = oldstack; return; } sprintf(stack, " Terminal type '%s' not supported.\n" " Do hitells '?' to list currently supported terminals.\n", str); stack = end_string(stack); tell_player(p, oldstack); stack = oldstack; return; } /* close down sockets after use */ void close_down_socket() { shutdown(main_descriptor, 2); close(main_descriptor); } #ifdef INTERCOM void close_only_main_fd(void) { close(main_descriptor); return; } #endif /* grab the main socket */ void init_socket(int port) { struct sockaddr_in main_socket; int dummy = 1; char *oldstack; char *hostname; struct hostent *hp; oldstack = stack; /* banish_file = load_file("files/banish"); banish_msg = load_file("files/banish.msg"); full_msg = load_file("files/full.msg"); */ /* grab the main socket */ hostname = (char *) MALLOC(101); bzero((char *) &main_socket, sizeof(struct sockaddr_in)); gethostname(hostname, 100); hp = gethostbyname(hostname); if (hp == NULL) { handle_error("Error: Host machine does not exist!\n"); } main_socket.sin_family = hp->h_addrtype; main_socket.sin_port = htons(port); main_descriptor = socket(AF_INET, SOCK_STREAM, IPROTO); if (main_descriptor < 0) { log("boot", "Couldn't grab the socket!!!"); exit(-1); } if (setsockopt(main_descriptor, SOL_SOCKET, SO_REUSEADDR, (char *) &dummy, sizeof(dummy)) < 0) handle_error("Couldn't setsockopt()"); if (ioctl(main_descriptor, FIONBIO, &dummy) < 0) handle_error("Can't set non-blocking"); if (bind(main_descriptor, (struct sockaddr *) &main_socket, sizeof(main_socket)) < 0) { log("boot", "Couldn't bind socket - something is on that port number!"); exit(-2); } if (listen(main_descriptor, 5) < 0) handle_error("Listen refused"); sprintf(oldstack, "Main socket bound and listening on port %d", port); stack = end_string(oldstack); log("boot", oldstack); stack = oldstack; } /* tell the angel the server is alive */ void do_alive_ping() { static int count = 5; count--; if (!count && alive_descriptor > 0) { count = 5; if (write(alive_descriptor, "SpAng!", 6) < 0) { if (errno != EPIPE) return; log("sigpipe", "Angel pipe closed"); close(alive_descriptor); /* try to clean up */ alive_descriptor = -1; } } } /* connect to the alive socket */ void alive_connect() { struct sockaddr_un sa; alive_descriptor = socket(PF_UNIX, SOCK_STREAM, 0); if (alive_descriptor < 0) handle_error("failed to make socket"); sa.sun_family = AF_UNIX; strcpy(sa.sun_path, SOCKET_PATH); if (connect(alive_descriptor, (struct sockaddr *) &sa, sizeof(sa)) < 0) { close(alive_descriptor); alive_descriptor = -1; log("boot", "Failed to connect to angel, we are on our own from here."); return; } do_alive_ping(); log("boot", "Alive and kicking"); } /* work out whether a player is site banished or not */ int match_banish(player * p, char *line) { char *addr; for (addr = p->num_addr; *addr; addr++, line++) if (*line == '*') { while (isdigit(*addr)) addr++; line++; } else if (*addr != *line) return 0; return 1; } int do_banish(player * p) { char *scan; int i; scan = banish_file.where; for (i = banish_file.length; i;) { if (*scan != '#' && match_banish(p, scan)) { while (*scan != 'L' && *scan != 'C' && *scan != 'N' && *scan != '\n') scan++; switch (*scan) { case 'C': return 1; case 'N': p->flags |= CLOSED_TO_NEWBIES; break; case 'L': p->flags |= SITE_LOG; break; } return 0; } while (i && *scan != '\n') { scan++; i--; } if (i) { scan++; i--; } } return 0; } /* Newbie spam patch by Phypor */ int no_more_newbies(player * p) { int i = 0; player *scan; for (scan = flatlist_start; scan; scan = scan->flat_next) if (!strcmp(p->num_addr, scan->num_addr) && !(scan->residency & BASE)) i++; return (i > atoi(get_config_msg("site_newbies"))) ? 1 : 0; } /* accept new connection on the main socket */ void accept_new_connection(void) { struct sockaddr_in incoming; struct hostent *hp; #ifdef HAVE_SOCKLEN_T socklen_t length; #else int length; #endif /* HAVE_SOCKLEN_T */ int new_socket; player *p; int dummy = 1, no1, no2, no3, no4; #ifdef LOLIGO char *numerical_address; #endif /* LOLIGO */ length = sizeof(incoming); new_socket = accept(main_descriptor, (struct sockaddr *) &incoming, &length); if ((new_socket < 0) && errno == EINTR) { log("error", "EINTR accept trap"); return; } if (new_socket < 0) { log("error", "Error accepting new connection."); return; } if (ioctl(new_socket, FIONBIO, &dummy) < 0) handle_error("Can't set non-blocking"); if (current_players >= max_players) { write(new_socket, full_msg.where, full_msg.length); out_current += full_msg.length; out_pack_current++; return; } p = create_player(); current_player = p; p->fd = new_socket; strncpy(p->num_addr, inet_ntoa(incoming.sin_addr), MAX_INET_ADDR - 2); #ifdef LOLIGO numerical_address = p->num_addr; #else hp = gethostbyaddr((char *) &(incoming.sin_addr.s_addr), sizeof(incoming.sin_addr.s_addr), AF_INET); if (hp) strncpy(p->inet_addr, hp->h_name, MAX_INET_ADDR - 2); else strncpy(p->inet_addr, p->num_addr, MAX_INET_ADDR - 2); #endif sscanf(p->num_addr, "%d.%d.%d.%d", &no1, &no2, &no3, &no4); /* This is to stop a well known individual spamming talkers with newbies (code by Phypor) */ if (no_more_newbies(p)) { tell_player(p, "\n\n" LINE "Sorry but there are too many newbies on at the moment. Please wait a couple\n" "of minutes and try again ...\n\n" LINE "\n\n\n"); destroy_player(p); return; } if (do_banish(p)) { write(new_socket, banish_msg.where, banish_msg.length); out_current += banish_msg.length; out_pack_current++; destroy_player(p); return; } if (time(0) < splat_timeout && no1 == splat1 && no2 == splat2) { write(new_socket, splat_msg.where, splat_msg.length); out_current += banish_msg.length; out_pack_current++; destroy_player(p); return; } else { #ifdef IDENT send_ident_request(p, &incoming); #endif connect_to_prog(p); } current_player = 0; } /* turn on and off echo for passwords */ void password_mode_on(player * p) { p->flags |= PASSWORD_MODE; p->mode |= PASSWORD; if (!(p->flags & DO_LOCAL_ECHO)) tell_player(p, "\377\373\001"); } void password_mode_off(player * p) { p->flags &= ~PASSWORD_MODE; p->mode &= ~PASSWORD; if (!(p->flags & DO_LOCAL_ECHO)) tell_player(p, "\377\374\001"); } /* do a backspace */ void backspace(player * p) { p->ibuffer[p->ibuff_pointer] = 0; if (p->ibuff_pointer > 0) p->ibuff_pointer--; } /* handle telnet control codes */ void telnet_options(player * p) { unsigned char c; if (read(p->fd, &c, 1) != 1) return; switch (c) { case WONT: if (read(p->fd, &c, 1) != 1) return; switch (c) { case TELOPT_STATUS: ping_respond(p); break; } break; case EC: backspace(p); break; case EL: p->ibuff_pointer = 0; break; case IP: quit(p, 0); break; case DO: if (read(p->fd, &c, 1) != 1) return; switch (c) { case TELOPT_ECHO: if (!(p->flags & PASSWORD_MODE)) p->flags |= DO_LOCAL_ECHO; /* start local echo */ break; case TELOPT_SGA: break; case TELOPT_EOR: p->flags |= EOR_ON; p->flags &= ~IAC_GA_DO; tell_player(p, (char [4]) {IAC, WILL, TELOPT_EOR, '\0'}); break; } break; case DONT: if (read(p->fd, &c, 1) != 1) return; switch (c) { case TELOPT_ECHO: p->flags &= ~DO_LOCAL_ECHO; /* stop local echo */ break; case TELOPT_SGA: break; case TELOPT_EOR: p->flags &= ~EOR_ON; if (p->system_flags & IAC_GA_ON) p->flags |= IAC_GA_DO; break; } break; } } /* gets any input from one player */ void get_player_input(player * p) { int chars_ready = 0; char *oldstack, c; oldstack = stack; if (ioctl(p->fd, FIONREAD, &chars_ready) == -1) { quit(p, 0); log("error", "PANIC on FIONREAD ioctl"); perror("SpoooN (socket.c)"); return; } if (!chars_ready) { if (sys_flags & VERBOSE) { if (p->lower_name[0]) { sprintf(oldstack, "%s went netdead.", p->name); stack = end_string(oldstack); log("connection", oldstack); } else log("connection", "Connection went netdead on login."); } quit(p, 0); stack = oldstack; return; } in_current += chars_ready; in_pack_current++; stack = oldstack; for (; !(p->flags & PANIC) && chars_ready; chars_ready--) if (read(p->fd, &c, 1) != 1) { log("connection", "Caught read error on socket."); return; } else switch (c) { case -1: p->flags &= ~(LAST_CHAR_WAS_R | LAST_CHAR_WAS_N); telnet_options(p); return; break; case '\n': if (!(p->flags & LAST_CHAR_WAS_R)) { p->flags |= LAST_CHAR_WAS_N; p->flags |= INPUT_READY; p->ibuffer[p->ibuff_pointer] = 0; p->ibuff_pointer = 0; p->column = 0; return; } break; case '\r': if (!(p->flags & LAST_CHAR_WAS_N)) { p->flags |= LAST_CHAR_WAS_R; p->flags |= INPUT_READY; p->ibuffer[p->ibuff_pointer] = 0; p->ibuff_pointer = 0; p->column = 0; return; } break; default: p->flags &= ~(LAST_CHAR_WAS_R | LAST_CHAR_WAS_N); if (c == 8 || c == 127 || c == -9) { backspace(p); break; } if ((c > 31) && (p->ibuff_pointer < (IBUFFER_LENGTH - 3))) { p->ibuffer[p->ibuff_pointer] = c; p->ibuff_pointer++; if ((!(p->flags & PASSWORD_MODE)) && (p->flags & DO_LOCAL_ECHO)) { if (write(p->fd, &c, 1) < 0 && errno != EINTR) { log("error", "Echoing back to player."); quit(p, 0); return; } out_current++; out_pack_current++; } } else if (!(p->ibuff_pointer < (IBUFFER_LENGTH - 3))) { spam_warning(p); return; } break; } } /* this routine is called when idle */ void scan_sockets() { fd_set fset; player *scan; struct timeval tv; FD_ZERO(&fset); FD_SET(main_descriptor, &fset); for (scan = flatlist_start; scan; scan = scan->flat_next) { if (!((scan->fd < 0) || (scan->flags & PANIC))) FD_SET(scan->fd, &fset); } #ifdef IDENT if (IDENT_CLIENT_READ != -1) FD_SET(IDENT_CLIENT_READ, &fset); #endif #ifdef INTERCOM if (intercom_fd > -1) { if (intercom_last < time(NULL)) kill_intercom(); else FD_SET(intercom_fd, &fset); } else intercom_fd = establish_intercom_server(); #endif tv.tv_sec = 0; tv.tv_usec = 0; if (select(FD_SETSIZE, &fset, 0, 0, &tv) == -1) return; if (FD_ISSET(main_descriptor, &fset)) accept_new_connection(); #ifdef IDENT if (IDENT_CLIENT_READ != -1) if (FD_ISSET(IDENT_CLIENT_READ, &fset)) read_ident_reply(); #endif for (scan = flatlist_start; scan; scan = scan->flat_next) if (!(scan->fd <= 0 || scan->flags & (PANIC | INPUT_READY)) && FD_ISSET(scan->fd, &fset)) get_player_input(scan); #ifdef INTERCOM if (intercom_fd > -1 && FD_ISSET(intercom_fd, &fset)) parse_incoming_intercom(); #endif } /* generic routine to write to one player */ void tell_player(player * p, char *str) { file output; char *oldstack, *script; oldstack = stack; if (((p->fd) < 0) || (p->flags & PANIC) || (!(p->location) && current_player != p)) { return; } if (!(sys_flags & PANIC)) { if (!test_receive(p)) return; } str = masks_process(p, str); output = process_output(p, str); if (p->script) { script = stack; sprintf(stack, "emergency/%s.emergency", p->lower_name); stack = end_string(stack); lscripto(script, output.where, output.length); stack = script; } if (current_player != p && (command_type & PERSONAL || p->flags & TAGGED) && !(command_type & NO_HISTORY) && !((sys_flags & EVERYONE_TAG) || (sys_flags & ROOM_TAG))) process_review(p, output.where, output.length); if (p->flags & SCRIPTING) { script = stack; sprintf(stack, "scripts/%s", p->script_file); stack = end_string(stack); lscripto(script, output.where, output.length); script = script; } if (!write_socket(&p->fd, output.where, output.length)) quit(p, 0); out_current += output.length; out_pack_current++; stack = oldstack; } /* small derivative of tell player to save typing */ void tell_current(char *str) { if (!current_player) return; tell_player(current_player, str); } /* non blockable raw tell */ void non_block_tell(player * p, char *str) { file output; char *script, *oldstack; oldstack = stack; if (((p->fd) < 0) || (p->flags & PANIC)) return; str = masks_process(p, str); output = process_output(p, str); if (p->script) { script = stack; sprintf(stack, "emergency/%s.emergency", p->lower_name); stack = end_string(stack); lscripto(script, output.where, output.length); stack = script; } if (!write_socket(&p->fd, output.where, output.length)) quit(p, 0); out_current += output.length; out_pack_current++; stack = oldstack; } /* general routine to send a prompt */ /* modified so prompt is exactly what its supposed to be --Silver */ void do_prompt(player * p, char *str) { char *oldstack = stack; sprintf(stack, "^N%s", str); stack = strchr(stack, 0);; if (p->flags & IAC_GA_DO) { *stack++ = (char) IAC; *stack++ = (char) GA; } if (p->flags & EOR_ON) { *stack++ = (char) IAC; *stack++ = (char) EOR; } *stack++ = 0; tell_player(p, oldstack); stack = oldstack; } void set_talker_addy(void) { char buf[160], *ptr; struct hostent *he; gethostname(buf, 159); he = gethostbyname(buf); if (!he) { /* shit ass ouch! */ LOGF("error", "gethostbyname fails, errno %d, %s\n", errno, strerror(errno)); strncpy(talker_alpha, "Host Name Error", 159); strncpy(talker_ip, "Host Name Error", 39); return; } if ((ptr = get_config_msg("site_alias")) && *ptr) strncpy(talker_alpha, ptr, 159); else strncpy(talker_alpha, he->h_name, 159); sprintf(talker_ip, "%d.%d.%d.%d", (unsigned char) he->h_addr_list[0][0], (unsigned char) he->h_addr_list[0][1], (unsigned char) he->h_addr_list[0][2], (unsigned char) he->h_addr_list[0][3]); } /* work out whether a player is site banished or not */ int is_site_banned(player * p, char *line, char *check) { char *addr; for (addr = check; *addr; addr++, line++) if (*line == '*') { while (isdigit(*addr)) addr++; line++; } else if (*addr != *line) return 0; return 1; } void check_banish_status(player * p, char *str) { char *scan; int i; char Comments[300] = "", AdminBanning[30] = ""; int Com = 0, AB = 0; int status = -1; if (!*str || !isdigit(*str)) { tell_player(p, " Format: ckban <IP address>\n"); return; } scan = banish_file.where; for (i = banish_file.length; i;) { if (*scan != '#' && is_site_banned(p, scan, str)) { while (*scan != 'L' && *scan != 'C' && *scan != 'N' && *scan != '\n') scan++; switch (*scan) { case 'C': status = 0; break; case 'N': status = 1; break; case 'L': status = 2; break; } } if (status >= 0) { scan++; i--; while (i && isspace(*(scan))) { i--; scan++; } while (i && *scan != '(' && Com < 298) { Comments[Com++] = *scan++; i--; } Comments[Com++] = 0; if (i) scan++; while (i && *scan != ')' && AB < 28) { AdminBanning[AB++] = *scan++; i--; } AdminBanning[AB++] = 0; while (i && *scan != '\n') { scan++; i--; } if (i) { scan++; i--; } switch (status) { case 0: TELLPLAYER(p, "Site is totally banned\nBanned by: %s\nReason: %s\n", AdminBanning, Comments); return; case 1: TELLPLAYER(p, "Site is newbie banned\nBanned by: %s\nReason: %s\n", AdminBanning, Comments); return; case 2: TELLPLAYER(p, "Site is logged, but not banned\nSited by: %s\nReason: %s\n", AdminBanning, Comments); return; } } else { while (i && *scan != '\n') { scan++; i--; } if (i) { scan++; i--; } } } tell_player(p, " That site appears to not be banned...\n"); return; } void ping(player * p, char *str) { char *oldstack = stack; memset(stack, 0, 10); *stack++ = (char) IAC; *stack++ = (char) DO; *stack++ = (char) TELOPT_STATUS; *stack++ = (char) NULL; write(p->fd, oldstack, strlen(oldstack)); stack = oldstack; gettimeofday(&(p->ping_timer), (struct timezone *) NULL); } void ping_timed(player * p) { p->last_ping = -1; /* set the last ping to be pending */ ping(p, ""); } void ping_respond(player * p) { struct timeval endtv; long pt; memset(&endtv, 0, sizeof(struct timeval)); gettimeofday(&endtv, (struct timezone *) NULL); pt = ((endtv.tv_sec - p->ping_timer.tv_sec) * 1000000) + ((endtv.tv_usec - p->ping_timer.tv_usec)); p->last_ping = pt; p->next_ping = PING_INTERVAL; } /* A better (imho) ping command than phypors -- Silver */ /* Note: This is a better command frontend not ping code!! */ void do_ping(player * p, char *str) { char *oldstack, middle[80]; player *scan; int page, pages, count; oldstack = stack; page = atoi(str); if (page <= 0) page = 1; page--; pages = (current_players - 1) / (TERM_LINES - 2); if (page > pages) page = pages; pstack_mid("Connection Speeds"); count = page * (TERM_LINES - 2); for (scan = flatlist_start; count; scan = scan->flat_next) if (!scan) { tell_player(p, " Bad do_ping listing, abort.\n"); log("error", "Bad do_ping list (socket.c)"); stack = oldstack; return; } else if (scan->name[0]) count--; for (count = 0; (count < (TERM_LINES - 1) && scan); scan = scan->flat_next) if (scan->name[0] && scan->location && !(scan->residency & ROBOT_PRIV)) { sprintf(stack, "%-19s - %s (%ld.%02ld secs lag)", scan->name, ping_string(scan), scan->last_ping / 1000000, (scan->last_ping / 10000) % 1000000); stack = strchr(stack, 0); *stack++ = '\n'; count++; } sprintf(middle, "Page %d of %d", page + 1, pages + 1); pstack_mid(middle); *stack++ = 0; tell_player(p, oldstack); stack = oldstack; } /* a new write_socket function to sort out nasty sigpipes (thanks to jamesa for this) */ ssize_t write_socket(int *fd, const void *where, size_t length) { ssize_t output_length = 0; assert(length); if (!length) return (1); if (*fd != -1) { if ((output_length = write(*fd, where, length)) == -1) switch (errno) { case EINTR: /* interupt occured */ case EAGAIN: /* too much data */ case ENOSPC: /* too much data */ return (output_length); case EPIPE: /* sigpipe */ default: close(*fd); *fd = -1; return (0); } else return (output_length); } return (0); }