/* *** DaleMUD comm.c main communication routines. Based on DIKU and *** SillyMUD. */ #include <errno.h> #include <stdio.h> #include <ctype.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> #include <netdb.h> #include <string.h> #include <sys/time.h> #include <fcntl.h> #include <signal.h> #include <sys/resource.h> #include "protos.h" void str2ansi(char *p2, char *p1, int start, int stop); char *ParseAnsiColors(int UsingAnsi, char *txt); int construct_prompt(char *buf, struct char_data *ch); void identd_test(struct sockaddr_in in_addr) ; #define MAX_CONNECTS 256 /* max number of descriptors (connections) */ /* THIS IS SYSTEM DEPENDANT, use 64 is not sure! */ #define DFLT_PORT 4000 /* default port */ #define MAX_NAME_LENGTH 15 #define MAX_HOSTNAME 256 #define OPT_USEC 250000 /* time delay corresponding to 4 passes/sec */ #define STATE(d) ((d)->connected) int mud_port; extern int errno; /* extern struct char_data *character_list; */ #if HASH extern struct hash_header room_db; /* In db.c */ #else extern struct room_data *room_db; /* In db.c */ #endif /* extern int top_of_world; In db.c */ struct descriptor_data *descriptor_list, *next_to_process; struct txt_block *bufpool = 0; /* pool of large output buffers */ int buf_largecount; /* # of large buffers which exist */ int buf_overflows; /* # of overflows of output */ int buf_switches; /* # of switches from small to large buf */ /* int slow_nameserver = FALSE; */ int lawful = 0; /* work like the game regulator */ int slow_death = 0; /* Shut her down, Martha, she's sucking mud */ int mudshutdown = 0; /* clean shutdown */ int reboot = 0; /* reboot the game after a shutdown */ int no_specials = 0; /* Suppress ass. of special routines */ long Uptime; /* time that the game has been up */ long SystemFlags; long TempDis=0; int pulse; #if SITELOCK char hostlist[MAX_BAN_HOSTS][30]; /* list of sites to ban */ int numberhosts; #endif int maxdesc, avail_descs; int tics = 0; /* for extern checkpointing */ #define O_LOG_NAME "output.log" #define O_MAX_LINES 30000 static FILE *debugf=NULL; void writetofile(char *msg) { static long lines=0; char *b[5]; int i,j; if(!debugf) { if(!(debugf=fopen(O_LOG_NAME,"wr"))) { perror(O_LOG_NAME); exit(1); } setvbuf(debugf,NULL,_IOFBF,16386); } if(lines>O_MAX_LINES) { rewind(debugf); for(i=0;i<5;i++) { b[i]=(char *)malloc(MAX_STRING_LENGTH); if(fgets(b[i], MAX_STRING_LENGTH, debugf)==NULL) break; } fclose(debugf); if(!(debugf=fopen(O_LOG_NAME,"wr"))) { perror(O_LOG_NAME); exit(1); } setvbuf(debugf,NULL,_IOFBF,16386); for(j=0;j<i;j++) { fputs(b[j],debugf); if (b[j]) free(b[j]); } lines=0; } fprintf(debugf,"%s", msg); lines++; } void testlog(char *msg) { char buf[MAX_STRING_LENGTH*2]; sprintf(buf,"->%s\n", msg); writetofile(buf); return; } void check_affected(char *msg,char *msg2) { struct affected_type *hjp, *old_af; struct char_data *c; char buf[5000], *p; int i,j; if(msg) sprintf(buf,"%s : ", msg); else sprintf(buf,"check_affected: "); writetofile(buf); p=strdup("a simple test in check_affected blank text meaning\ nothing to anyone intelligent anyways.... go get'em!\ Okay.... lets see if we can wack an link list somewhere"); for(c=character_list;c;c=c->next) if(c && c->affected) for(hjp=c->affected;hjp;old_af = hjp, hjp=hjp->next) if(hjp->type > MAX_EXIST_SPELL || hjp->type < 0) { sprintf(buf,"bogus hjp->type for (%s).\r\n", GET_NAME(c)); writetofile(buf); sprintf(buf,"string in old_af: %s\r\n", old_af); writetofile(buf); sprintf(buf,"string in cur_af: %s\r\n", hjp); writetofile(buf); fflush(debugf); abort(); } writetofile("ok\n"); free(p); return; } /* ********************************************************************* * main game loop and related stuff * ********************************************************************* */ int __main () { return(1); } /* jdb code - added to try to handle all the different ways the connections can die, and try to keep these 'invalid' sockets from getting to select */ int close_socket_fd( int desc) { struct descriptor_data *d; /* extern struct descriptor_data *descriptor_list; */ #if LOG_DEBUG slog("begin close_socket_fd"); #endif for (d = descriptor_list;d;d=d->next) { if (d->descriptor == desc) { close_socket(d); } } #if LOG_DEBUG slog("end close_socket_fd"); #endif } int main (int argc, char **argv) { int pos=1; char buf[512], *dir; extern int WizLock; #ifdef SITELOCK int a; #endif #if defined(sun) || defined(NETBSD) struct rlimit rl; int res; #endif #ifdef MALLOC_DEBUG malloc_debug(1); /* some systems might not have this lib */ #endif mud_port = DFLT_PORT; dir = DFLT_DIR; SystemFlags =0; #if LOG_ALL SET_BIT(SystemFlags,SYS_LOGALL); #endif #if defined(sun) || defined(NETBSD) /* ** this block sets the max # of connections. */ #if defined(sun) res = getrlimit(RLIMIT_NOFILE, &rl); rl.rlim_cur = MAX_CONNECTS; res = setrlimit(RLIMIT_NOFILE, &rl); #endif #if defined(NETBSD) res = getrlimit(RLIMIT_OFILE, &rl); rl.rlim_cur = MAX_CONNECTS; res = setrlimit(RLIMIT_OFILE, &rl); #endif #endif #if DEBUG /* never seen this function, must be something john was working on, disabled */ /* msw */ /* malloc_debug(0); */ #endif while ((pos < argc) && (*(argv[pos]) == '-')) { switch (*(argv[pos] + 1)) { case 'l': lawful = 1; log_string("Lawful mode selected."); break; case 'd': if (*(argv[pos] + 2)) dir = argv[pos] + 2; else if (++pos < argc) dir = argv[pos]; else { log_string("Directory arg expected after option -d."); assert(0); } break; case 's': no_specials = 1; log_string("Suppressing assignment of special routines."); break; case 'A': SET_BIT(SystemFlags,SYS_NOANSI); log_string("Disabling ALL color"); break; case 'N': SET_BIT(SystemFlags,SYS_SKIPDNS); log_string("Disabling DNS"); break; case 'R': SET_BIT(SystemFlags,SYS_REQAPPROVE); log_string("Newbie authorizes enabled"); break; case 'L': SET_BIT(SystemFlags,SYS_LOGALL); log_string("Logging all users"); break; default: sprintf(buf, "Unknown option -% in argument string.", *(argv[pos] + 1)); log_string(buf); break; } pos++; } if (pos < argc) if (!isdigit(*argv[pos])) { fprintf(stderr, "Usage: %s [-l] [-s] [-d pathname] [ port # ]\n", argv[0]); assert(0); } else if ((mud_port = atoi(argv[pos])) <= 1024) { printf("Illegal port #\n"); assert(0); } Uptime = time(0); sprintf(buf, "Running game on port %d.", mud_port); log_string(buf); if (chdir(dir) < 0) { perror("chdir"); assert(0); } sprintf(buf, "Using %s as data directory.", dir); log_string(buf); srandom(time(0)); WizLock = FALSE; #if SITELOCK log_string("Blanking denied hosts."); for(a = 0 ; a<= MAX_BAN_HOSTS ; a++) strcpy(hostlist[a]," \0\0\0\0"); numberhosts = 0; #if LOCKGROVE log_string("Locking out Host: oak.grove.iup.edu."); strcpy(hostlist[0],"oak.grove.iup.edu"); numberhosts = 1; log_string("Locking out Host: everest.rutgers.edu."); strcpy(hostlist[1],"everest.rutgers.edu"); numberhosts = 2; #endif /* LOCKGROVE */ #if PERSONAL_PERM_LOCKOUTS numberhosts +=0; #endif #endif /* close stdin */ close(0); run_the_game(mud_port); return(0); } #define PROFILE(x) /* Init sockets, run game, and cleanup sockets */ int run_the_game(int port) { int s; PROFILE(extern etext();) void signal_setup(void); int load(void); PROFILE(monstartup((int) 2, etext);) descriptor_list = NULL; log_string("Signal trapping."); signal_setup(); log_string("Opening mother connection."); s = init_socket(port); #ifdef USE_LAWFUL if (lawful && load() >= 6) { log_string("System load too high at startup."); coma(1); } #endif boot_db(); log_string("Entering game loop."); game_loop(s); close_sockets(s); PROFILE(monitor(0);) if (reboot) { log_string("Rebooting."); assert(52); /* what's so great about HHGTTG, anyhow? */ } log_string("Normal termination of game."); } /* Accept new connects, relay commands, and call 'heartbeat-functs' */ int game_loop(int s) { fd_set input_set, output_set, exc_set; #if 0 fd_set tin, tout, tex; fd_set mtin, mtout, mtex; #endif static int cap; struct timeval last_time, now, timespent, timeout, null_time; static struct timeval opt_time; char comm[MAX_INPUT_LENGTH]; char promptbuf[180]; struct descriptor_data *point, *next_point; int mask; struct room_data *rm; /* extern struct descriptor_data *descriptor_list; */ extern int pulse; extern int maxdesc; extern struct time_info_data time_info; /* In db.c */ null_time.tv_sec = 0; null_time.tv_usec = 0; opt_time.tv_usec = OPT_USEC; /* Init time values */ opt_time.tv_sec = 0; #ifdef NETBSD gettimeofday(&last_time, NULL); #else gettimeofday(&last_time, (struct timeval *) 0); #endif maxdesc = s; /* !! Change if more needed !! */ avail_descs = getdtablesize() -2; /* never used, pointless? */ // mask = sigmask(SIGUSR1) | sigmask(SIGUSR2) | sigmask(SIGINT) | // sigmask(SIGPIPE) | sigmask(SIGALRM) | sigmask(SIGTERM) | // sigmask(SIGURG) | sigmask(SIGXCPU) | sigmask(SIGHUP); /* Main loop */ while (!mudshutdown) { /* Check what's happening out there */ FD_ZERO(&input_set); FD_ZERO(&output_set); FD_ZERO(&exc_set); FD_SET(s, &input_set); #if TITAN maxdesc = 0; if (cap < 20) cap = 20; for (point = descriptor_list; point; point = point->next) { if (point->descriptor <= cap && point->descriptor >= cap-20) { FD_SET(point->descriptor, &input_set); FD_SET(point->descriptor, &exc_set); FD_SET(point->descriptor, &output_set); } if (maxdesc < point->descriptor) maxdesc = point->descriptor; } if (cap > maxdesc) cap = 0; else cap += 20; #else dimd_loop(); for (point = descriptor_list; point; point = point->next) { FD_SET(point->descriptor, &input_set); FD_SET(point->descriptor, &exc_set); FD_SET(point->descriptor, &output_set); if (maxdesc < point->descriptor) maxdesc = point->descriptor; } #endif /* check out the time */ #ifdef NETBSD gettimeofday(&now, NULL); #else gettimeofday(&now, (struct timeval *) 0); #endif timespent = timediff(&now, &last_time); timeout = timediff(&opt_time, ×pent); last_time.tv_sec = now.tv_sec + timeout.tv_sec; last_time.tv_usec = now.tv_usec + timeout.tv_usec; if (last_time.tv_usec >= 1000000) { last_time.tv_usec -= 1000000; last_time.tv_sec++; } // sigsetmask(mask); if (select(maxdesc + 1, &input_set, &output_set, &exc_set, &null_time) < 0) { perror("Select poll"); /* one of the descriptors is broken... */ for (point = descriptor_list; point; point = next_point) { next_point = point->next; write_to_descriptor(point->descriptor, "\n\r"); } } if (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &timeout) < 0) { perror("Select sleep"); /*assert(0);*/ } // sigsetmask(0); /* Respond to whatever might be happening */ /* New connection? */ if (FD_ISSET(s, &input_set)) if (new_descriptor(s) < 0) { perror("New connection"); } /* kick out the freaky folks */ for (point = descriptor_list; point; point = next_point) { next_point = point->next; if (FD_ISSET(point->descriptor, &exc_set)) { FD_CLR(point->descriptor, &input_set); FD_CLR(point->descriptor, &output_set); close_socket(point); } } for (point = descriptor_list; point; point = next_point) { next_point = point->next; if (FD_ISSET(point->descriptor, &input_set)) if (process_input(point) < 0) { close_socket(point); } } /* process_commands; */ for (point = descriptor_list; point; point = next_to_process){ next_to_process = point->next; if ((--(point->wait) <= 0) && get_from_q(&point->input, comm)) { if (point->character && point->connected == CON_PLYNG && point->character->specials.was_in_room != NOWHERE) { point->character->specials.was_in_room = NOWHERE; act("$n has returned.", TRUE, point->character, 0, 0, TO_ROOM); } point->wait = 1; if (point->character) { point->character->specials.timer = 0; } point->prompt_mode = 1; if (point->str) string_add(point, comm); else if (!point->connected) { if (point->showstr_point) { show_string(point, comm); } else { check_affected("Before command issued",""); command_interpreter ( point->character, comm); check_affected("After command issued",""); } } else if(point->connected == CON_EDITING) RoomEdit(point->character,comm); else if(point->connected == CON_OBJ_EDITING) ObjEdit(point->character,comm); else if(point->connected == CON_MOB_EDITING) MobEdit(point->character,comm); else nanny(point, comm); } } /* either they are out of the game */ /* or they want a prompt. */ memory_check("end for 4, begin for 5"); for (point = descriptor_list; point; point = next_point) { next_point = point->next; #ifndef BLOCK_WRITE if (FD_ISSET(point->descriptor, &output_set) && point->output.head) #else if (FD_ISSET(point->descriptor, &output_set) && *(point->output)) #endif if (process_output(point) < 0) close_socket(point); else point->prompt_mode = 1; } /* give the people some prompts */ memory_check("end 5, begin 6"); for (point = descriptor_list; point; point = point->next) if (point->prompt_mode) { if (point->str) write_to_descriptor(point->descriptor, "-> "); else if (!point->connected) if (point->showstr_point) write_to_descriptor(point->descriptor, "[Return to continue/Q to quit]"); else { if(point->character->term == VT100) { struct char_data *ch; int update = 0; ch = point->character; if(GET_MOVE(ch) != ch->last.move) { SET_BIT(update, INFO_MOVE); ch->last.move = GET_MOVE(ch); } if(GET_MAX_MOVE(ch) != ch->last.mmove) { SET_BIT(update, INFO_MOVE); ch->last.mmove = GET_MAX_MOVE(ch); } if(GET_HIT(ch) != ch->last.hit) { SET_BIT(update, INFO_HP); ch->last.hit = GET_HIT(ch); } if(GET_MAX_HIT(ch) != ch->last.mhit) { SET_BIT(update, INFO_HP); ch->last.mhit = GET_MAX_HIT(ch); } if(GET_MANA(ch) != ch->last.mana) { SET_BIT(update, INFO_MANA); ch->last.mana = GET_MANA(ch); } if(GET_MAX_MANA(ch) != ch->last.mmana) { SET_BIT(update, INFO_MANA); ch->last.mmana = GET_MAX_MANA(ch); } if(GET_GOLD(ch) != ch->last.gold) { SET_BIT(update, INFO_GOLD); ch->last.gold = GET_GOLD(ch); } if(GET_EXP(ch) != ch->last.exp) { SET_BIT(update, INFO_EXP); ch->last.exp = GET_EXP(ch); } if(update) UpdateScreen(ch, update); sprintf(promptbuf,"> "); } else { construct_prompt(promptbuf,point->character); } write_to_descriptor(point->descriptor,ParseAnsiColors( \ IS_SET(point->character->player.user_flags,USE_ANSI), \ promptbuf)); } point->prompt_mode = 0; } /* handle heartbeat stuff */ /* Note: pulse now changes every 1/4 sec */ pulse++; if (!(pulse % PULSE_ZONE)) { dlog("Before zone update pulse"); memory_check("BEfore Zone update"); zone_update(); if (lawful) gr(s); } if (!(pulse % PULSE_RIVER)) { dlog("Before river pulse "); memory_check("Before riverpulse"); RiverPulseStuff(pulse); } if (!(pulse % PULSE_TELEPORT)) { dlog("Before Teleport pulse"); memory_check("Tele pulse"); TeleportPulseStuff(pulse); } if (!(pulse % PULSE_VIOLENCE)) { dlog("Before violence pulse..."); memory_check("Pulse violence"); check_mobile_activity(pulse); perform_violence( pulse ); } if (!(pulse % (SECS_PER_MUD_HOUR*4))){ dlog("Before hourly tick pulse"); memory_check(" before pulse weather"); weather_and_time(1); affect_update(pulse); /* things have been sped up by combining */ if ( time_info.hours == 1 ) update_time(); } memory_check("loop end"); if (pulse >= 2400) { pulse = 0; if (lawful) night_watchman(); check_reboot(); } tics++; /* tics since last checkpoint signal */ } } /* ****************************************************************** * general utility stuff (for local use) * ****************************************************************** */ int get_from_q(struct txt_q *queue, char *dest) { struct txt_block *tmp; /* Q empty? */ if (!queue->head) return(0); if (!dest) { log_sev("Sending message to null destination.", 5); return(0); } tmp = queue->head; if (dest && queue->head->text) strcpy(dest, queue->head->text); queue->head = queue->head->next; if (tmp->text) free(tmp->text); if (tmp) free(tmp); return(1); } #ifndef BLOCK_WRITE void write_to_q(char *txt, struct txt_q *queue) { struct txt_block *new; char tbuf[256]; int strl; if (!queue) { log_string("Output message to non-existant queue"); return; } CREATE(new, struct txt_block, 1); strl = strlen(txt); if (strl < 0 || strl > 35000) { log_string("strlen returned bogus length in write_to_q, string was: "); for(strl=0;strl<120;strl++) tbuf[strl]=txt[strl]; tbuf[strl]=0; log_string(strl); if (new) free(new); return; } #if 0 /* Changed for test 2-21 added back to test... */ memory_check("Before CREATE write_to_q",txt); CREATE(new->text, char, strl+1); memory_check("After CREATE write_to_q",txt); strcpy(new->text, txt); memory_check("After strcpy write_to_q",txt); #else if (!(new->text = strdup(txt))){ log_string("strdup returned null"); assert(0); } #endif new->next = NULL; /* Q empty? */ if (!queue->head) { queue->head = queue->tail = new; } else { queue->tail->next = new; queue->tail = new; } } #else void write_to_q(char *txt, struct txt_q *queue) { struct txt_block *new; char tbuf[256]; int strl; if (!queue) { log_string("Output message to non-existant queue"); return; } /*testlog(txt);*/ CREATE(new, struct txt_block, 1); strl = strlen(txt); if (strl < 0 || strl > 45000) { log_string("strlen returned bogus length in write_to_q, string was:"); for(strl=0;strl<120;strl++) tbuf[strl]=txt[strl]; tbuf[strl]=0; log_string(strl); if (new) free(new); return; } new->text = strdup(txt); new->next = NULL; /* Q empty? */ if (!queue->head) { queue->head = queue->tail = new; } else { queue->tail->next = new; queue->tail = new; } } #endif #if BLOCK_WRITE void write_to_output(char *txt, struct descriptor_data *t) { int size; size = strlen(txt); /* if we're in the overflow state already, ignore this */ if (t->bufptr < 0) { log_string("over flow stat in write_to_output, comm.c"); assert(0); return; } /* if we have enough space, just write to buffer and that's it! */ if (t->bufspace >= size) { strcpy(t->output+t->bufptr, txt); t->bufspace -= size; t->bufptr += size; } else { /* otherwise, try to switch to a large buffer */ if (t->large_outbuf || ((size + strlen(t->output)) > LARGE_BUFSIZE)) { /* we're already using large buffer, or even the large buffer in't big enough -- switch to overflow state */ t->bufptr = -1; buf_overflows++; return; } buf_switches++; /* if the pool has a buffer in it, grab it */ if (bufpool) { t->large_outbuf = bufpool; bufpool = bufpool->next; } else { /* else create one */ CREATE(t->large_outbuf, struct txt_block, 1); CREATE(t->large_outbuf->text, char, LARGE_BUFSIZE); buf_largecount++; } strcpy(t->large_outbuf->text, t->output); t->output = t->large_outbuf->text; strcat(t->output, txt); t->bufspace = LARGE_BUFSIZE-1 - strlen(t->output); t->bufptr = strlen(t->output); } } #else /* we use write_to_q instead of write_to_output */ #endif struct timeval timediff(struct timeval *a, struct timeval *b) { struct timeval rslt, tmp; tmp = *a; if ((rslt.tv_usec = tmp.tv_usec - b->tv_usec) < 0) { rslt.tv_usec += 1000000; --(tmp.tv_sec); } if ((rslt.tv_sec = tmp.tv_sec - b->tv_sec) < 0) { rslt.tv_usec = 0; rslt.tv_sec =0; } return(rslt); } #ifndef BLOCK_WRITE /* Empty the queues before closing connection */ void flush_queues(struct descriptor_data *d) { char dummy[MAX_STRING_LENGTH]; while (get_from_q(&d->output, dummy)); while (get_from_q(&d->input, dummy)); } #else void flush_queues(struct descriptor_data *d) { char buf2[MAX_STRING_LENGTH]; if (d->large_outbuf) { d->large_outbuf->next = bufpool; bufpool = d->large_outbuf; } while (get_from_q(&d->input, buf2)) ; } #endif /* ****************************************************************** * socket handling * ****************************************************************** */ #if 0 /* trying merc code out */ int init_socket(int port) { int s; char *opt; char hostname[MAX_HOSTNAME+1]; struct sockaddr_in sa; struct hostent *hp; struct linger ld; bzero(&sa, sizeof(struct sockaddr_in)); gethostname(hostname, MAX_HOSTNAME); hp = gethostbyname(hostname); if (hp == NULL) { perror("gethostbyname"); assert(0); } sa.sin_family = hp->h_addrtype; sa.sin_port = htons(port); s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { perror("Init-socket"); assert(0); } if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof (opt)) < 0) { perror ("setsockopt REUSEADDR"); exit (1); } ld.l_onoff = 1; ld.l_linger = 100; if (setsockopt(s, SOL_SOCKET, SO_LINGER, &ld, sizeof(ld)) < 0) { perror("setsockopt LINGER"); assert(0); } #ifdef NETBSD if ( bind( s, (struct sockaddr *) &sa, sizeof(sa) ) < 0 ) #else if (bind(s, &sa, sizeof(sa), 0) < 0) #endif { perror("bind"); exit(0); } listen(s, 5); return(s); } #else int init_socket( int port ) { static struct sockaddr_in sa_zero; struct sockaddr_in sa; int x = 1; int fd; if ( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) { perror( "Init_socket: socket" ); exit( 1 ); } if ( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (char *) &x, sizeof(x) ) < 0 ) { perror( "Init_socket: SO_REUSEADDR" ); close( fd ); exit( 1 ); } sa = sa_zero; sa.sin_family = AF_INET; sa.sin_port = htons( port ); if ( bind( fd, (struct sockaddr *) &sa, sizeof(sa) ) < 0 ) { perror( "Init_socket: bind" ); close( fd ); exit( 1 ); } if ( listen( fd, 3 ) < 0 ) { perror( "Init_socket: listen" ); close( fd ); exit( 1 ); } return fd; } #endif int new_connection(int s) { struct sockaddr_in isa; #ifdef sun struct sockaddr peer; #endif int i; int t; char buf[100]; i = sizeof(isa); #if 0 getsockname(s, &isa, &i); #endif if ((t = accept(s, (struct sockaddr *)&isa, &i)) < 0){ perror("Accept"); return(-1); } nonblock(t); #ifdef sun i = sizeof(peer); if (!getpeername(t, &peer, &i)) { *(peer.sa_data + 49) = '\0'; sprintf(buf, "New connection from addr %s.", peer.sa_data); log_string(buf); } #endif return(t); } int new_descriptor(int s) { int desc,size,i; struct descriptor_data *newd; struct hostent *from; struct sockaddr_in sock; char buf[200],buf2[200]; extern char login[]; if ((desc = new_connection(s)) < 0) return (-1); if ((desc + 1) >= MAX_CONNECTS) { struct descriptor_data *d; sprintf(buf,"Sorry.. The game is full. (max players %d) Try again later.\n\r",desc); write_to_descriptor(desc,buf); close(desc); for (d = descriptor_list; d; d = d->next) { if (!d->character) close_socket(d); } return(0); } else if (desc > maxdesc) maxdesc = desc; CREATE(newd, struct descriptor_data, 1); #if 0 /* older code replaced */ *newd->host = '\0'; /* find info */ size = sizeof(sock); if (getpeername(desc, (struct sockaddr *) &sock, &size) < 0) { perror("getpeername"); *newd->host = '\0'; } if(*newd->host == '\0') { #ifndef sun if ((long) strncpy(newd->host, inet_ntoa(sock.sin_addr), 49) > 0) { *(newd->host + 49) = '\0'; sprintf(buf, "New connection from addr %s: %d: %d", newd->host, desc, maxdesc); log_sev(buf,3); } #else strcpy(newd->host, (char *)inet_ntoa(&sock.sin_addr)); #endif } /* end old code */ #endif /*newer code */ /* find info */ size = sizeof(sock); if (getpeername(desc, (struct sockaddr *) & sock, &size) < 0) { perror("getpeername"); *newd->host = '\0'; } else if (IS_SET(SystemFlags,SYS_SKIPDNS) || !(from = gethostbyaddr((char *)&sock.sin_addr, sizeof(sock.sin_addr), AF_INET))) { if (!IS_SET(SystemFlags,SYS_SKIPDNS)) perror("gethostbyaddr"); i = sock.sin_addr.s_addr; sprintf(newd->host, "%d.%d.%d.%d", (i & 0xFF000000) >> 24, (i & 0x00FF0000) >> 16, (i & 0x0000FF00) >> 8, (i & 0x000000FF)); } else { strncpy(newd->host, from->h_name, 49); *(newd->host + 49) = '\0'; } #if 0 if (isbanned(newd->host) == BAN_ALL) { close(desc); sprintf(buf2, "Connection attempt denied from [%s]", newd->host); log_string(buf2); if (newd) free(newd); return(0); } #endif sprintf(buf2, "New connection from addr %s: %d: %d", newd->host, desc, maxdesc); log_string(buf2); #if 0 identd_test(sock); /* test stuff */ #endif /* end newer code */ /* init desc data */ newd->descriptor = desc; newd->connected = CON_NME; newd->wait = 1; newd->prompt_mode = 0; *newd->buf = '\0'; newd->str = 0; newd->showstr_head = 0; newd->showstr_point = 0; *newd->last_input= '\0'; #ifndef BLOCK_WRITE newd->output.head = NULL; #else newd->output=newd->small_outbuf; *(newd->output)='\0'; newd->bufspace=SMALL_BUFSIZE-1; newd->large_outbuf=NULL; #endif newd->input.head = NULL; newd->next = descriptor_list; newd->character = 0; newd->original = 0; newd->snoop.snooping = 0; newd->snoop.snoop_by = 0; /* prepend to list */ descriptor_list = newd; SEND_TO_Q(login, newd); SEND_TO_Q("What is thy name? ", newd); return(0); } #ifndef BLOCK_WRITE int process_output(struct descriptor_data *t) { char i[MAX_STRING_LENGTH + MAX_STRING_LENGTH]; if (!t->prompt_mode && !t->connected) if (write_to_descriptor(t->descriptor, "\n\r") < 0) return(-1); /* Cycle thru output queue */ while (get_from_q(&t->output, i)) { if ((t->snoop.snoop_by) && (t->snoop.snoop_by->desc)) { SEND_TO_Q("% ",t->snoop.snoop_by->desc); SEND_TO_Q(i,t->snoop.snoop_by->desc); } if (write_to_descriptor(t->descriptor, i)) return(-1); } if (!t->connected && !(t->character && !IS_NPC(t->character) && IS_SET(t->character->specials.act, PLR_COMPACT))) if (write_to_descriptor(t->descriptor, "\n\r") < 0) return(-1); return(1); } #else /* SEARCH HERE */ int process_output(struct descriptor_data *t) { static char i[LARGE_BUFSIZE + 20]; struct descriptor_data *point, *next_point; /* start writing at the 2nd space so we can prepend "% " for snoop */ if (!t->prompt_mode && !t->connected) { strcpy(i+2, "\n\r"); strcat(i+2, t->output); } else strcpy(i+2, t->output); if (t->bufptr < 0) { log_string("***** OVER FLOW **** in process_output, comm.c"); strcat(i+2, "**OVERFLOW**"); } if (!t->connected && !(t->character && !IS_NPC(t->character) && IS_SET(t->character->specials.act, PLR_COMPACT))) strcat(i+2, "\n\r"); if (write_to_descriptor(t->descriptor, i+2) < 0) return -1; if (t->snoop.snoop_by) { i[0] = '%'; i[1] = ' '; SEND_TO_Q(i, t->snoop.snoop_by->desc); } /* if we were using a large buffer, put the large buffer on the buffer pool and switch back to the small one */ if (t->large_outbuf) { t->large_outbuf->next = bufpool; bufpool = t->large_outbuf; t->large_outbuf = NULL; t->output = t->small_outbuf; } /* reset total bufspace back to that of a small buffer */ t->bufspace = SMALL_BUFSIZE-1; t->bufptr = 0; *(t->output) = '\0'; return(1); } #endif #if 1 /* reset to use this code, lets see if it helps */ int write_to_descriptor(int desc, char *txt) { int sofar, thisround, total; total = strlen(txt); sofar = 0; do { thisround = write(desc, txt + sofar, total - sofar); if (thisround < 0) { if (errno == EWOULDBLOCK) break; perror("Write to socket"); /* lets see if this stops it from crashing close_socket_fd(desc); arioch */ return(-1); } sofar += thisround; } while (sofar < total); return(0); } #else /* merc code */ #define UMIN(a, b) ((a) < (b) ? (a) : (b)) int write_to_descriptor( int desc, char *txt) { int iStart; int nWrite; int nBlock, length; char buf[256]; length = strlen(txt); for ( iStart = 0; iStart < length; iStart += nWrite ) { nBlock = UMIN( length - iStart, 4096 ); if ( ( nWrite = write( desc, txt + iStart, nBlock ) ) < 0 ) { if (errno == EWOULDBLOCK) break; sprintf(buf,"<#=%d> had a error (%d) in write to descriptor (Broken Pipe?)", desc, errno); log_string(buf); perror( "Write_to_descriptor" ); /* close_socket_fd(desc); */ return(-1); } } return(0); } #endif /* SEARCH HERE */ #ifndef BLOCK_WRITE /* base silly process_input */ int process_input(struct descriptor_data *t) { int sofar, thisround, begin, squelch, i, k, flag; char tmp[MAX_INPUT_LENGTH+2], buffer[MAX_INPUT_LENGTH + 60]; sofar = 0; flag = 0; begin = strlen(t->buf); /* Read in some stuff */ do { if ((thisround = read(t->descriptor, t->buf + begin + sofar, (8*MAX_INPUT_LENGTH) - (begin + sofar) - 1)) > 0) { #if 0 MAX_STRING_LENGTH - (begin + sofar) - 1)) > 0) { #endif sofar += thisround; } else { if (thisround < 0) { if (errno != EWOULDBLOCK) { perror("Read1 - ERROR"); return(-1); } else { break; } } else { log_string("EOF encountered on socket read."); return(-1); } } } while (!ISNEWL(*(t->buf + begin + sofar - 1))); *(t->buf + begin + sofar) = 0; /* if no newline is contained in input, return without proc'ing */ for (i = begin; !ISNEWL(*(t->buf + i)); i++) if (!*(t->buf + i)) return(0); /* input contains 1 or more newlines; process the stuff */ for (i = 0, k = 0; *(t->buf + i);) { if (!ISNEWL(*(t->buf + i)) && !(flag=(k>=(MAX_INPUT_LENGTH - 2)))) if (*(t->buf + i) == '\b') { /* backspace */ if (k) { /* more than one char ? */ if (*(tmp + --k) == '$') k--; i++; } else { i++; /* no or just one char.. Skip backsp */ } } else { if (isascii(*(t->buf + i)) && isprint(*(t->buf + i))) { /* trans char, double for '$' (printf) */ if ((*(tmp + k) = *(t->buf + i)) == '$') *(tmp + ++k) = '$'; k++; i++; } else { i++; } } else { *(tmp + k) = 0; if(*tmp == '!') strcpy(tmp,t->last_input); else strcpy(t->last_input,tmp); write_to_q(tmp, &t->input); if ((t->snoop.snoop_by) && (t->snoop.snoop_by->desc)){ write_to_q("% ",&t->snoop.snoop_by->desc->output); write_to_q(tmp,&t->snoop.snoop_by->desc->output); write_to_q("\n\r",&t->snoop.snoop_by->desc->output); } if (flag) { sprintf(buffer, "Line too long. Truncated to:\n\r%s\n\r", tmp); if (write_to_descriptor(t->descriptor, buffer) < 0) return(-1); /* skip the rest of the line */ for (; !ISNEWL(*(t->buf + i)); i++); } /* find end of entry */ for (; ISNEWL(*(t->buf + i)); i++); /* squelch the entry from the buffer */ for (squelch = 0;; squelch++) if ((*(t->buf + squelch) = *(t->buf + i + squelch)) == '\0') break; k = 0; i = 0; } } return(1); } #else int process_input(struct descriptor_data *t) { int sofar, thisround, begin, squelch, i, k, flag; char tmp[MAX_INPUT_LENGTH+2], buffer[MAX_INPUT_LENGTH + 60]; sofar = 0; flag = 0; begin = strlen(t->buf); /* Read in some stuff */ do { if ((thisround = read(t->descriptor, t->buf + begin + sofar, (8*MAX_INPUT_LENGTH) - (begin + sofar) - 1)) > 0) { sofar += thisround; } else { if (thisround < 0) { if (errno != EWOULDBLOCK) { perror("Read1 - ERROR"); return(-1); } else { break; } } else { log_string("EOF encountered on socket read."); return(-1); } } } while (!ISNEWL(*(t->buf + begin + sofar - 1))); *(t->buf + begin + sofar) = 0; /* if no newline is contained in input, return without proc'ing */ for (i = begin; !ISNEWL(*(t->buf + i)); i++) if (!*(t->buf + i)) return(0); /* input contains 1 or more newlines; process the stuff */ for (i = 0, k = 0; *(t->buf + i);) { if (!ISNEWL(*(t->buf + i)) && !(flag=(k>=(MAX_INPUT_LENGTH - 2)))) if (*(t->buf + i) == '\b') { /* backspace */ if (k) { /* more than one char ? */ if (*(tmp + --k) == '$') k--; i++; } else { i++; /* no or just one char.. Skip backsp */ } } else { if (isascii(*(t->buf + i)) && isprint(*(t->buf + i))) { /* trans char, double for '$' (printf) */ if ((*(tmp + k) = *(t->buf + i)) == '$') *(tmp + ++k) = '$'; k++; i++; } else { i++; } } else { *(tmp + k) = 0; if(*tmp == '!') strcpy(tmp,t->last_input); else strcpy(t->last_input,tmp); write_to_q(tmp, &t->input); if ((t->snoop.snoop_by) && (t->snoop.snoop_by->desc)){ SEND_TO_Q("% ",t->snoop.snoop_by->desc); SEND_TO_Q(tmp,t->snoop.snoop_by->desc); SEND_TO_Q("\n\r",t->snoop.snoop_by->desc); } if (flag) { sprintf(buffer, "Line too long. Truncated to:\n\r%s\n\r", tmp); if (write_to_descriptor(t->descriptor, buffer) < 0) return(-1); /* skip the rest of the line */ for (; !ISNEWL(*(t->buf + i)); i++); } /* find end of entry */ for (; ISNEWL(*(t->buf + i)); i++); /* squelch the entry from the buffer */ for (squelch = 0;; squelch++) if ((*(t->buf + squelch) = *(t->buf + i + squelch)) == '\0') break; k = 0; i = 0; } } return(1); } #endif void close_sockets(int s) { log_string("Closing all sockets."); while (descriptor_list) close_socket(descriptor_list); close(s); } void close_socket(struct descriptor_data *d) { char buf[MAX_STRING_LENGTH]; struct txt_block *txt, *txt2; if (!d) { log_string("!d in close_socket"); return; } #if LOG_DEBUG slog("begin close_socket"); #endif close(d->descriptor); flush_queues(d); if (d->descriptor == maxdesc) --maxdesc; /* Forget snooping */ if (d->snoop.snooping) d->snoop.snooping->desc->snoop.snoop_by = 0; if (d->snoop.snoop_by) { send_to_char("Your victim is no longer among us.\n\r",d->snoop.snoop_by); d->snoop.snoop_by->desc->snoop.snooping = 0; } if (d->character) if (d->connected == CON_PLYNG) { do_save(d->character, "", 0); act("$n has lost $s touch with reality.", TRUE, d->character, 0, 0, TO_ROOM); sprintf(buf, "Closing link to: %s.", GET_NAME(d->character)); log_string(buf); if (IS_NPC(d->character)) { /* poly, or switched god */ if (d->character->desc) d->character->orig = d->character->desc->original; } d->character->desc = 0; /* d->character->invis_level = LOW_IMMORTAL; msw 8/9/94 */ if (!IS_AFFECTED(d->character, AFF_CHARM)) { if (d->character->master) { stop_follower(d->character); } } } else { if (GET_NAME(d->character)) { sprintf(buf, "Losing player: %s.", GET_NAME(d->character)); log_string(buf); } free_char(d->character); } else log_string("Losing descriptor without char."); if (next_to_process == d) /* to avoid crashing the process loop */ next_to_process = next_to_process->next; if (d == descriptor_list) /* this is the head of the list */ descriptor_list = descriptor_list->next; else /* This is somewhere inside the list */ { struct descriptor_data *tmp; /* Locate the previous element */ for (tmp = descriptor_list; tmp && tmp->next != d;tmp = tmp->next); if (tmp != NULL) tmp->next = d->next; else { log_string(" ERROR< ERROR< ERROR< ERROR< corrupted list..."); /* not sure where this gets fried, but it keeps poping up now and */ /* then, let me know if you figure it out. msw */ /* DENIS see if you can figure this out */ /* I know that when a new user cuts link in the login process the first */ /* time it will get here, how to stop it I do not know */ } /* end bug */ }/* end inside the list */ if (d->showstr_head) /* this piece of code causes core dumps on */ free(d->showstr_head); /* ardent titans */ if (d) free(d); #if LOG_DEBUG slog("end close_socket"); #endif } void nonblock(int s) { if (fcntl(s, F_SETFL, FNDELAY) == -1) { perror("Noblock"); assert(0); } } #define COMA_SIGN \ "\n\r\ DikuMUD is currently inactive due to excessive load on the host machine.\n\r\ Please try again later.\n\r\n\ \n\r\ Sadly,\n\r\ \n\r\ the DikuMUD system operators\n\r\n\r" /* sleep while the load is too high */ void coma(int s) { #ifdef USE_LAWFUL fd_set input_set; static struct timeval timeout = { 60, 0 }; int conn; int workhours(void); int load(void); log_string("Entering comatose state."); // sigsetmask(sigmask(SIGUSR1) | sigmask(SIGUSR2) | sigmask(SIGINT) | // sigmask(SIGPIPE) | sigmask(SIGALRM) | sigmask(SIGTERM) | // sigmask(SIGURG) | sigmask(SIGXCPU) | sigmask(SIGHUP)); while (descriptor_list) close_socket(descriptor_list); FD_ZERO(&input_set); do { FD_SET(s, &input_set); if (select(64, &input_set, 0, 0, &timeout) < 0){ perror("coma select"); assert(0); } if (FD_ISSET(s, &input_set)) { if (load() < 6){ log_string("Leaving coma with visitor."); // sigsetmask(0); return; } if ((conn = new_connection(s)) >= 0) { write_to_descriptor(conn, COMA_SIGN); sleep(2); close(conn); } } tics = 1; if (workhours()) { log_string("Working hours collision during coma. Exit."); assert(0); } } while (load() >= 6); log_string("Leaving coma."); // sigsetmask(0); #endif } /* **************************************************************** * Public routines for system-to-player-communication * **************************************************************** */ char *ParseAnsiColors(int UsingAnsi, char *txt) { static char buf[MAX_STRING_LENGTH] = ""; char tmp[MAX_INPUT_LENGTH]; register int i,l,f=0; buf[0]=0; for(i=0,l=0;*txt;) { if(*txt=='$' && (toupper(*(txt+1)) == 'C' || (*(txt+1)=='$' && toupper(*(txt+2)) == 'C'))) { if(*(txt+1)=='$') txt+=3; else txt+=2; str2ansi(tmp,txt,0,3); /* if using ANSI */ if (UsingAnsi) strcat(buf,ansi_parse(tmp)); else /* if not using ANSI */ strcat(buf,""); txt+=4; l=strlen(buf); f++; } else { buf[l++]=*txt++; } buf[l]=0; } if(f && UsingAnsi) strcat(buf,ansi_parse("0007")); return buf; } void send_to_char(char *messg, struct char_data *ch) { if (ch) if (ch->desc && messg) SEND_TO_Q( ParseAnsiColors(IS_SET(ch->player.user_flags, USE_ANSI),messg), ch->desc); } void save_all() { struct descriptor_data *i; for (i = descriptor_list; i; i = i->next) if (i->character) save_char(i->character,AUTO_RENT); } void send_to_all(char *messg) { struct descriptor_data *i; if (messg) for (i = descriptor_list; i; i = i->next) if (!i->connected) /* SEND_TO_Q(messg, &i->output); */ SEND_TO_Q( ParseAnsiColors(IS_SET(i->character->player.user_flags, USE_ANSI),messg), i); } void send_to_outdoor(char *messg) { struct descriptor_data *i; if (messg) for (i = descriptor_list; i; i = i->next) if (!i->connected) if (OUTSIDE(i->character)) /* SEND_TO_Q(messg, &i->output); */ SEND_TO_Q( ParseAnsiColors(IS_SET(i->character->player.user_flags, USE_ANSI),messg), i); } void send_to_desert(char *messg) { struct descriptor_data *i; struct room_data *rp; extern struct zone_data *zone_table; if (messg) { for (i = descriptor_list; i; i = i->next) { if (!i->connected) { if (OUTSIDE(i->character)) { if ((rp = real_roomp(i->character->in_room))!=NULL) { if (IS_SET(zone_table[rp->zone].reset_mode, ZONE_DESERT) || rp->sector_type == SECT_DESERT) { /* SEND_TO_Q(messg, &i->output); */ SEND_TO_Q( ParseAnsiColors(IS_SET(i->character->player.user_flags, USE_ANSI),messg), i); } } } } } } } void send_to_out_other(char *messg) { struct descriptor_data *i; struct room_data *rp; extern struct zone_data *zone_table; if (messg) { for (i = descriptor_list; i; i = i->next) { if (!i->connected) { if (OUTSIDE(i->character)) { if ((rp = real_roomp(i->character->in_room))!=NULL) { if (!IS_SET(zone_table[rp->zone].reset_mode, ZONE_DESERT) && !IS_SET(zone_table[rp->zone].reset_mode, ZONE_ARCTIC) && rp->sector_type != SECT_DESERT) { /* SEND_TO_Q(messg, &i->output); */ SEND_TO_Q( ParseAnsiColors(IS_SET(i->character->player.user_flags, USE_ANSI),messg), i); } } } } } } } void send_to_arctic(char *messg) { struct descriptor_data *i; struct room_data *rp; extern struct zone_data *zone_table; if (messg) { for (i = descriptor_list; i; i = i->next) { if (!i->connected) { if (OUTSIDE(i->character)) { if ((rp = real_roomp(i->character->in_room))!=NULL) { if (IS_SET(zone_table[rp->zone].reset_mode, ZONE_ARCTIC)) { /* SEND_TO_Q(messg, &i->output); */ SEND_TO_Q( ParseAnsiColors(IS_SET(i->character->player.user_flags, USE_ANSI),messg), i); } } } } } } } void send_to_except(char *messg, struct char_data *ch) { struct descriptor_data *i; if (messg) for (i = descriptor_list; i; i = i->next) if (ch->desc != i && !i->connected) /* SEND_TO_Q(messg, &i->output); */ SEND_TO_Q( ParseAnsiColors(IS_SET(i->character->player.user_flags, USE_ANSI),messg), i); } void send_to_zone(char *messg, struct char_data *ch) { struct descriptor_data *i; if (messg) for (i = descriptor_list; i; i = i->next) if (ch->desc != i && !i->connected) if (real_roomp(i->character->in_room)->zone == real_roomp(ch->in_room)->zone) /* SEND_TO_Q(messg, &i->output); */ SEND_TO_Q( ParseAnsiColors(IS_SET(i->character->player.user_flags, USE_ANSI),messg), i); } void send_to_room(char *messg, int room) { struct char_data *i; if (messg) for (i = real_roomp(room)->people; i; i = i->next_in_room) if (i->desc) /* SEND_TO_Q(messg, &i->desc->output);*/ SEND_TO_Q( ParseAnsiColors(IS_SET(i->player.user_flags, USE_ANSI),messg), i->desc); } void send_to_room_except(char *messg, int room, struct char_data *ch) { struct char_data *i; if (messg) for (i = real_roomp(room)->people; i; i = i->next_in_room) if (i != ch && i->desc) /* SEND_TO_Q(messg, &i->desc->output); */ SEND_TO_Q( ParseAnsiColors(IS_SET(i->player.user_flags, USE_ANSI),messg), i->desc); } void send_to_room_except_two (char *messg, int room, struct char_data *ch1, struct char_data *ch2) { struct char_data *i; if (messg) for (i = real_roomp(room)->people; i; i = i->next_in_room) if (i != ch1 && i != ch2 && i->desc) /* SEND_TO_Q(messg, &i->desc->output); */ SEND_TO_Q( ParseAnsiColors(IS_SET(i->player.user_flags, USE_ANSI),messg), i->desc); } void str2ansi(char *p2, char *p1, int start, int stop) { int i,j; if((start > stop) || (start < 0)) p2[0] = '\0'; /* null terminate string */ else { if (start == stop) /* will copy only 1 char at pos=start */ { p2[0] = p1[start]; p2[1] = '\0'; } else { j = 0; /* start or (start-1) depends on start index */ /* if starting index for arrays is 0 then use start */ /* if starting index for arrays is 1 then use start-1 */ for (i=start;i<=stop;i++) p2[j++] = p1[i]; p2[j] = '\0'; /* null terminate the string */ } } if (strlen(p2)+1 > 5) log_string("DOH!"); /* remove this after test period */ } /* higher-level communication */ /* ACT */ void act(char *str, int hide_invisible, struct char_data *ch, struct obj_data *obj, void *vict_obj, int type) { register char *strp, *point, *i; int KLUDGE = FALSE; struct char_data *to; char buf[MAX_STRING_LENGTH], tmp[MAX_INPUT_LENGTH]; extern int WizLock; if (!str) return; if (!*str) return; if (ch->in_room <= -1) return; /* can't do it. in room -1 */ /*testlog(str);*/ if (type == TO_VICT) to = (struct char_data *) vict_obj; else if (type == TO_CHAR) to = ch; else to = real_roomp(ch->in_room)->people; for (; to; to = to->next_in_room) { if (to->desc && ((to != ch) || (type == TO_CHAR)) && (CAN_SEE(to, ch) || !hide_invisible) && AWAKE(to) && !((type == TO_NOTVICT) && (to==(struct char_data *) vict_obj))){ for (strp = str, point = buf;;) if (*strp == '$') { switch (*(++strp)) { #if 1 /* parse ansi colors here $CMBFG, where M is modier, B is back ground color and FG is fore $C0001 would be normal, black back, red fore. $C1411 would be bold, blue back, light yellow fore */ act_switch_c: case 'C': case 'c': if (IS_SET(to->player.user_flags, USE_ANSI)) { KLUDGE=TRUE; str2ansi(tmp,strp,1,4); i = ansi_parse(tmp); } else i = ""; ++strp;++strp;++strp;++strp; /* delete nums */ break; #endif case 'n': i = PERS(ch, to); break; case 'N': i = PERS((struct char_data *) vict_obj, to); break; case 'm': i = HMHR(ch); break; case 'M': i = HMHR((struct char_data *) vict_obj); break; case 's': i = HSHR(ch); break; case 'S': i = HSHR((struct char_data *) vict_obj); break; case 'e': i = HSSH(ch); break; case 'E': i = HSSH((struct char_data *) vict_obj); break; case 'o': i = OBJN(obj, to); break; case 'O': i = OBJN((struct obj_data *) vict_obj, to); break; case 'p': i = OBJS(obj, to); break; case 'P': i = OBJS((struct obj_data *) vict_obj, to); break; case 'a': i = SANA(obj); break; case 'A': i = SANA((struct obj_data *) vict_obj); break; case 'T': i = (char *) vict_obj; break; case 'F': i = fname((char *) vict_obj); break; case '$': if(*strp=='$' && toupper(*(strp+1))=='C' && isdigit(*(strp+2)) && isdigit(*(strp+3)) ) { strp++; goto act_switch_c; } i = "$"; break; default: log_string("Illegal $-code to act():"); log_string(str); break; } while (*point = *(i++)) ++point; ++strp; } else if (!(*(point++) = *(strp++))) break; *(--point) = '\n'; *(++point) = '\r'; *(++point) = '\0'; SEND_TO_Q(CAP(buf), to->desc); /* kludge to turn the color back grey, try to move to prompt */ if (KLUDGE && IS_SET(to->player.user_flags,USE_ANSI)) SEND_TO_Q(ansi_parse("0007"),to->desc); } if ((type == TO_VICT) || (type == TO_CHAR)) { return; } } } int raw_force_all( char *to_force) { struct descriptor_data *i; char buf[400]; for (i = descriptor_list; i; i = i->next) if (!i->connected) { sprintf(buf, "The game has forced you to '%s'.\n\r", to_force); send_to_char(buf, i->character); command_interpreter(i->character, to_force); } } int _affected_by_s(struct char_data *ch, int skill) { struct affected_type *hjp; int fs=0,fa=0; switch(skill) { case SPELL_FIRESHIELD: if(IS_AFFECTED(ch,AFF_FIRESHIELD)) fa=1; break; case SPELL_SANCTUARY: if(IS_AFFECTED(ch,AFF_SANCTUARY)) fa=1; break; case SPELL_INVISIBLE: if(IS_AFFECTED(ch,AFF_INVISIBLE)) fa=1; break; case SPELL_TRUE_SIGHT: if(IS_AFFECTED(ch,AFF_TRUE_SIGHT)) fa=1; break; case SPELL_PROT_ENERGY_DRAIN: if(IS_SET(ch->immune,IMM_DRAIN) || IS_SET(ch->M_immune,IMM_DRAIN)) fa=1; break; } if(ch->affected) for (hjp = ch->affected; hjp; hjp = hjp->next) if ( hjp->type == skill ) fs = (hjp->duration + 1); /* in case it's 0 */ if(!fa && !fs) return -1; else if( fa && !fs) return 999; else return fs-1; } int construct_prompt(char *outbuf, struct char_data *ch) { struct room_data *rm; extern const struct title_type titles[MAX_CLASS][ABS_MAX_LVL]; char tbuf[255],*pr_scan,*mask; long l,exp,texp; int i,s_flag=0; *outbuf=0; if(ch->specials.prompt==NULL) { /* use default prompts */ if(IS_IMMORTAL(ch)) mask="Shadowdale: (type help prompt) H:%h R:%R i%iI+> "; else mask="Shadowdale: (type help prompt) H:%h M:%m V:%v> "; } else { mask=ch->specials.prompt; } for(pr_scan = mask; *pr_scan; pr_scan++) { if(*pr_scan == '%') { if(*(++pr_scan)=='%') { tbuf[0]='%'; tbuf[1]=0; } else { switch(*pr_scan) { /* stats for character */ case 'H': sprintf(tbuf,"%d",GET_MAX_HIT(ch)); break; case 'h': sprintf(tbuf,"%d",GET_HIT(ch)); break; case 'M': sprintf(tbuf,"%d",GET_MAX_MANA(ch)); break; case 'm': sprintf(tbuf,"%d",GET_MANA(ch)); break; case 'V': sprintf(tbuf,"%d",GET_MAX_MOVE(ch)); break; case 'v': sprintf(tbuf,"%d",GET_MOVE(ch)); break; case 'G': sprintf(tbuf,"%ld",GET_BANK(ch)); break; case 'g': sprintf(tbuf,"%ld",GET_GOLD(ch)); break; case 'X': /* xp stuff */ sprintf(tbuf,"%ld",GET_EXP(ch)); break; case 'x': /* xp left to level (any level, btw..) */ for(l=1,i=0,exp=999999999;i<PSI_LEVEL_IND;i++,l<<=1) { if(HasClass(ch,l)) { texp=(titles[i][GET_LEVEL(ch,i)+1].exp)-GET_EXP(ch); if(texp<exp) exp=texp; } } sprintf(tbuf,"%ld",exp); break; case 'C': /* mob condition */ #if 1 /* we get float errors here! msw */ if(ch->specials.fighting) { if (GET_MAX_HIT(ch->specials.fighting)==0) strcpy(tbuf,"unknown"); else { i=(100*GET_HIT(ch->specials.fighting))/ \ GET_MAX_HIT(ch->specials.fighting); if(i>=100)strcpy(tbuf,"excellent"); else if(i>=90) strcpy(tbuf,"few scratches"); else if(i>=75) strcpy(tbuf,"small wounds"); else if(i>=50) strcpy(tbuf,"wounded"); else if(i>=30) strcpy(tbuf,"big nasty"); else if(i>=15) strcpy(tbuf,"badly wounded"); else if(i>=0) strcpy(tbuf,"awful"); else strcpy(tbuf,"bleeding"); } } else { strcpy(tbuf,"*"); } #endif break; case 'c': /* tank condition */ #if 0 if(ch->specials.fighting && ch->specials.fighting->specials.fighting) { if (GET_MAX_HIT(ch->specials.fighting->specials.fighting)==0) strcpy(tbuf,"Unknown"); else { i=(100*GET_HIT(ch->specials.fighting->specials.fighting))/ \ GET_MAX_HIT(ch->specials.fighting->specials.fighting); if(i>=100)strcpy(tbuf,"excellent"); else if(i>=90) strcpy(tbuf,"few scratches"); else if(i>=75) strcpy(tbuf,"small wounds"); else if(i>=50) strcpy(tbuf,"wounded"); else if(i>=30) strcpy(tbuf,"big nasty"); else if(i>=15) strcpy(tbuf,"badly wounded"); else if(i>=0) strcpy(tbuf,"awful"); else strcpy(tbuf,"bleeding"); } } else { strcpy(tbuf,"*"); } #endif break; case 's': s_flag = 1; case 'S': /* affected spells */ *tbuf=0; if((i=_affected_by_s(ch,SPELL_FIRESHIELD))!=-1) strcat(tbuf,(i>1)?"F":"f"); else if(s_flag) strcat(tbuf,"-"); if((i=_affected_by_s(ch,SPELL_SANCTUARY))!=-1) strcat(tbuf,(i>1)?"S":"s"); else if(s_flag) strcat(tbuf,"-"); if((i=_affected_by_s(ch,SPELL_INVISIBLE))!=-1) strcat(tbuf,(i>1)?"I":"i"); else if(s_flag) strcat(tbuf,"-"); if((i=_affected_by_s(ch,SPELL_TRUE_SIGHT))!=-1) strcat(tbuf,(i>1)?"T":"t"); else if(s_flag) strcat(tbuf,"-"); if((i=_affected_by_s(ch,SPELL_PROT_ENERGY_DRAIN))!=-1) strcat(tbuf,(i>1)?"D":"d"); else if(s_flag) strcat(tbuf,"-"); if((i=_affected_by_s(ch,SPELL_ANTI_MAGIC_SHELL))!=-1) strcat(tbuf,(i>1)?"A":"a"); else if(s_flag) strcat(tbuf,"-"); break; case 'T': /* did't implemented.. yet */ break; case 'R': /* room number for immortals */ if(IS_IMMORTAL(ch)) { rm = real_roomp(ch->in_room); if (!rm) { char_to_room(ch, 0); rm = real_roomp(ch->in_room); } sprintf(tbuf,"%ld",rm->number); } else { *tbuf=0; } break; case 'i': /* immortal stuff going */ pr_scan++; if(!IS_IMMORTAL(ch)) { *tbuf=0; break; } switch(*pr_scan) { case 'I': /* invisible status */ sprintf(tbuf,"%d",ch->invis_level); break; case 'S': /* stealth mode */ strcpy(tbuf,IS_SET(ch->specials.act, PLR_STEALTH)?"On":"Off"); break; case 'N': /* snoop name */ if(ch->desc->snoop.snooping) strcpy(tbuf,ch->desc->snoop.snooping->player.name); else *tbuf=0; break; default: /* sprintf(tbuf,"Invalid Immmortal Prompt code '%c'",*pr_scan); log_string(tbuf); */ *tbuf=0; break; } break; default: /* sprintf(tbuf,"Invalid Prompt code '%c'",*pr_scan); log_string(tbuf); */ *tbuf=0; break; } } } else { /* end of if ch=='%' */ tbuf[0]=*pr_scan; tbuf[1]=0; } strcat(outbuf,tbuf); } } void UpdateScreen(struct char_data *ch, int update) { char buf[255]; int size; size = ch->size; if (size<=0) return; if(IS_SET(update, INFO_MANA)) { sprintf(buf, VT_CURSAVE); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURSPOS, size - 2, 7); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, " "); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURSPOS, size - 2, 7); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, "%d(%d)", GET_MANA(ch), GET_MAX_MANA(ch)); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURREST); write_to_descriptor(ch->desc->descriptor, buf); } if(IS_SET(update, INFO_MOVE)) { sprintf(buf, VT_CURSAVE); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURSPOS, size - 3, 58); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, " "); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURSPOS, size - 3, 58); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, "%d(%d)", GET_MOVE(ch), GET_MAX_MOVE(ch)); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURREST); write_to_descriptor(ch->desc->descriptor, buf); } if(IS_SET(update, INFO_HP)) { sprintf(buf, VT_CURSAVE); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURSPOS, size - 3, 13); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, " "); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURSPOS, size - 3, 13); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, "%d(%d)", GET_HIT(ch), GET_MAX_HIT(ch)); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURREST); write_to_descriptor(ch->desc->descriptor, buf); } if(IS_SET(update, INFO_GOLD)) { sprintf(buf, VT_CURSAVE); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURSPOS, size - 2, 47); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, " "); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURSPOS, size - 2, 47); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, "%d", GET_GOLD(ch)); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURREST); write_to_descriptor(ch->desc->descriptor, buf); } if(IS_SET(update, INFO_EXP)) { sprintf(buf, VT_CURSAVE); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURSPOS, size - 1, 20); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, " "); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURSPOS, size - 1, 20); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, "%d", GET_EXP(ch)); write_to_descriptor(ch->desc->descriptor, buf); sprintf(buf, VT_CURREST); write_to_descriptor(ch->desc->descriptor, buf); } } void InitScreen(struct char_data *ch) { char buf[255]; int size; size = ch->size; sprintf(buf, VT_HOMECLR); send_to_char(buf, ch); sprintf(buf, VT_MARGSET, 0, size - 5); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, size - 4, 1); send_to_char(buf, ch); sprintf(buf, "-===========================================================================-"); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, size - 3, 1); send_to_char(buf, ch); sprintf(buf, "Hit Points: "); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, size - 3, 40); send_to_char(buf, ch); sprintf(buf, "Movement Points: "); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, size - 2, 1); send_to_char(buf, ch); sprintf(buf, "Mana: "); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, size - 2, 40); send_to_char(buf, ch); sprintf(buf, "Gold: "); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, size - 1, 1); send_to_char(buf, ch); sprintf(buf, "Experience Points: "); send_to_char(buf, ch); ch->last.mana = GET_MANA(ch); ch->last.mmana = GET_MAX_MANA(ch); ch->last.hit = GET_HIT(ch); ch->last.mhit = GET_MAX_HIT(ch); ch->last.move = GET_MOVE(ch); ch->last.mmove = GET_MAX_MOVE(ch); ch->last.exp = GET_EXP(ch); ch->last.gold = GET_GOLD(ch); /* Update all of the info parts */ sprintf(buf, VT_CURSPOS, size - 3, 13); send_to_char(buf, ch); sprintf(buf, "%d(%d)", GET_HIT(ch), GET_MAX_HIT(ch)); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, size - 3, 58); send_to_char(buf, ch); sprintf(buf, "%d(%d)", GET_MOVE(ch), GET_MAX_MOVE(ch)); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, size - 2, 7); send_to_char(buf, ch); sprintf(buf, "%d(%d)", GET_MANA(ch), GET_MAX_MANA(ch)); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, size - 2, 47); send_to_char(buf, ch); sprintf(buf, "%d", GET_GOLD(ch)); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, size - 1, 20); send_to_char(buf, ch); sprintf(buf, "%d", GET_EXP(ch)); send_to_char(buf, ch); sprintf(buf, VT_CURSPOS, 0, 0); send_to_char(buf, ch); } void identd_test(struct sockaddr_in in_addr) { struct sockaddr_in addr; int fd, addrlen, lport, fport; FILE *fp_in, *fp_out; char buf[8192], reply_type[81], opsys[81], ident[1024]; int i; if( (fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("identd socket"); return; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = in_addr.sin_addr.s_addr; addr.sin_port = htons(113); addrlen = sizeof(addr); if (connect(fd, (struct sockaddr *)&addr, addrlen) == -1) { sprintf(buf,"identd server not responding, errno: %d\n", errno); log_string(buf); return; } addrlen = sizeof(addr); if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) == -1) perror("getsockname"); fp_in = fdopen(fd, "r"); fp_out = fdopen(fd, "w"); if (!fp_in || !fp_out) perror("fdopen"); fprintf(fp_out, "%d , %d\n", ntohs(in_addr.sin_port), mud_port); fflush(fp_out); if(fgets(buf, sizeof(buf)-1, fp_in) == NULL) perror("fgets"); shutdown(fd, 1); i = sscanf(buf, "%d , %d : %[^ \t\n\r:] : %[^\t\n\r:] : %[^\n\r]", &lport, &fport, reply_type, opsys, ident); if(i < 3) { fprintf(stderr, "fscanf: too few arguments (%d)\n", i); return; } if(strcmp(reply_type, "ERROR") == 0) { sprintf(buf, "Ident error: error code: %s\n", opsys); log_string(buf); } else if(strcmp(reply_type, "USERID") != 0) { sprintf(buf, "Ident error: illegal reply type: %s\n", reply_type); log_string(buf); } else { sprintf(buf, "ident data -- system:%s user:%s\n", opsys, ident); log_string(buf); } fclose(fp_out); fclose(fp_in); return; }