tetrinetx-1.13.16+qirc-1.40c/0040700000076700007670000000000007512457012014777 5ustar drslumdrslumtetrinetx-1.13.16+qirc-1.40c/bin/0040700000076700007670000000000007512457157015561 5ustar drslumdrslumtetrinetx-1.13.16+qirc-1.40c/bin/game.secure0100600000076700007670000000137406766335054017707 0ustar drslumdrslum# TetriNET (linux) Security configuration file # This file contains security configuration for TetriNET, and by default will # be created with all values commented out. # Each configuration value consists of a TAG name, followed by an equal sign # and a value. IE: # op_password=mypass # Any text after a # is ignored, and can be used as comments. # op_password [] - Typing /op will give player op status op_password=pass4word # query_password [] - For query irc client query_password=pass4word # spec_password [] - Use this as team name for gameplay watch spec_password=pass4word # spec_op_password [] - Use this as team name for gameplay watch with extended capability (unused in this release) spec_op_password=pass4word # End of File tetrinetx-1.13.16+qirc-1.40c/bin/game.motd0100600000076700007670000000012706661755543017362 0ustar drslumdrslum- *************** Message of the day **************** - Welcome :) - *** End of motd tetrinetx-1.13.16+qirc-1.40c/bin/game.conf0100600000076700007670000000766506764730056017356 0ustar drslumdrslum# TetriNET (linux) Game configuration file # This file contains configuration for TetriNET, and will be autocreated # with default values if it does not exist. # Each configuration value consists of a TAG name, followed by an equal sign # and a value. IE: # starting_level=1 # Any text after a # is ignored, and can be used as comments. # pidfile [game.pid] - Where should the Process ID be written pidfile=game.pid # bindip [0.0.0.0] - What IP should server be bound to (0.0.0.0 means all) bindip=0.0.0.0 # maxchannels [1] - How many channels should be available on server maxchannels=8 # timeout_ingame [60] - How many seconds of no activity during a game before timeout occurs timeout_ingame=60 # timeout_outgame [1000] - How many seconds of no activity out of game before timeout occurs timeout_outgame=1000 # verbose [4] - How verbose the logs should be. 0=critical, 10=noisy verbose=4 ######## DEFAULT SETTINGS ################ # Settings under here will be used by default in # any new channels created. # serverannounce [1] - Server Announces winners? serverannounce=1 # pingintercept [1] - Intercept pings in game messages? pingintercept=1 # stripcolour [1] - Strip colour from game messages? stripcolour=1 # game_type [normal, nick_only] game_type=normal # winlist_file [1 or 2 or 3] winlist_file=1 # starting_level [1] - What level each player starts at starting_level=1 # lines_per_level [2] - How many lines to make before player level increases lines_per_level=2 # level_increase [1] - Number of levels to increase each time level_increase=1 # lines_per_special [1] - Lines to make to get a special block lines_per_special=1 # special_added [1] - Number of special blocks added each time special_added=1 # special_capacity [18] - Capacity of Special block inventory special_capacity=18 # classic_rules [1] - Play by classic rules? classic_rules=1 # average_levels [1] - Average together all player's game level? average_levels=1 # sd_timeout [0] - Sudden death timeout. After this many secs, server will add lines. 0=disable sd_timeout=0 # sd_lines_per_add [1] - Number of lines server adds each time sd_lines_per_add=1 # sd_secs_between_lines [30] - Number of secs to wait between adding each line sd_secs_between_lines=30 #sd_message [Time's up! It's SUDDEN DEATH MODE!] - Message to display when suddendeath triggers sd_message=Time's up! It's SUDDEN DEATH MODE! # command_xxxxx rules. These set permissions to /commands in the partline # For all, the following apply: # 0 = Disable command for anyone # 1 = Enable anyone to use command # 2 = Enable command only for people who are chanop or better # 3 = Enable command ONLY for authenticated ops (/op) # Special Case: # join 4 = Can join other channels. Can't create new channel (unless authop) # set 4 = Chanop can only modify settings of NON-preset channels (unless authop) # command_help=1 command_kick=2 command_msg=1 command_op=1 command_list=1 command_join=1 command_who=1 command_topic=2 command_priority=2 command_move=2 command_winlist=1 command_set=4 command_persistant=3 command_save=3 command_reset=3 # BLOCK OCCURANCY [Percentage value 0-100]. Must add up to 100 block_leftl=14 block_leftz=14 block_square=15 block_rightl=14 block_rightz=14 block_halfcross=14 block_line=15 # SPECIAL BLOCK OCCURANCY [Percentage value 0-100]. Must add up to 100 special_addline=32 special_clearline=18 special_nukefield=1 special_randomclear=11 special_switchfield=3 special_clearspecial=14 special_gravity=1 special_quakefield=6 special_blockbomb=14 ################ CUSTOM CHANNELS ########### # Below exists (if any) definitions of preset non-removable # channels. They exist in the following form: # [CHANNELNAME] # Note NO # in front of name. # maxplayers=6 # Number of players allowed in (6max) # topic=My Topic # The channel Topic # priority=50 # Priority of channel # block_halfcross=12 #etc... any of the default options here # # End of File tetrinetx-1.13.16+qirc-1.40c/bin/game.allow.example0100600000076700007670000000041006764320327021152 0ustar drslumdrslum# Password must be at least 4 characters. # game.ban is global ban and has highest priority # game.allow has lower priority than game.ban # game.ban.compromise will ban people if they fail in game.allow nickname1 password1 nickname2 password2 nickname3 password3 tetrinetx-1.13.16+qirc-1.40c/bin/game.ban.compromise.example0100600000076700007670000000004707270536732022760 0ustar drslumdrslum#Same format as game.ban *.ipt.aol.com tetrinetx-1.13.16+qirc-1.40c/bin/game.ban.example0100600000076700007670000000104707270540063020575 0ustar drslumdrslum# Wildcards *,? can be put anywhere as needed # Ban entry must consist of 4 or more characters # TO MAKE THE UPDATE TAKE EFFECT YOU MUST USE QIRC feature and # type /quote readaccesslist in your IRC session # All lines beginning with "#" are treated as a comment #Cheating from host 1cust007.tnt2.billgates.da.uu.net *.tnt*.billgates.da.uu.net #Flooding from 192.168.33.200. Ban all C class IP block #Date: 08/28/1999 192.168.33.* #Ban all hostname contain the word foobar *foobar* #Ban IP block from 192.168.10.0 to 192.168.19.255 192.168.1?.* tetrinetx-1.13.16+qirc-1.40c/bin/game.pmotd0100600000076700007670000000026407022147643017530 0ustar drslumdrslum- ------------------------------------------------ - Welcome to Playback service! for gtetrinet/tspec - /help for command help - ------------------------------------------------ tetrinetx-1.13.16+qirc-1.40c/src/0040700000076700007670000000000007512457115015572 5ustar drslumdrslumtetrinetx-1.13.16+qirc-1.40c/src/net.c0100600000076700007670000003621307271162601016523 0ustar drslumdrslum/* net.c - Updated : Completely dynamic allocation now (Brendan Grieve) */ /* i read somewhere that memcpy() is broken on some machines */ /* it's easy to replace, so i'm not gonna take any chances, because it's */ /* pretty important that it work correctly here */ void my_memcpy(dest,src,len) char *dest,*src; int len; { while (len--) *dest++=*src++; } /* bzero() is bsd-only, so here's one for non-bsd systems */ void my_bzero(dest,len) char *dest; int len; { while (len--) *dest++=0; } /* initialize the socklist */ void init_net() { socklist=NULL; } int expmem_net() { int tot=0; struct sock_list *slist; slist=socklist; while(slist!=NULL) { if (!(slist->flags & SOCK_UNUSED)) { if (slist->inbuf != NULL) tot+=strlen(slist->inbuf)+1; if (slist->outbuf != NULL) tot+=strlen(slist->outbuf)+1; } slist=slist->next; } return tot; } /* puts full hostname in s */ void getmyhostname(s) char *s; { struct hostent *hp; char *p; p=getenv("HOSTNAME"); if (p!=NULL) { strncpy(s,p, UHOSTLEN); s[UHOSTLEN] = 0; if (strchr(s,'.')!=NULL) return; } gethostname(s,80); if (strchr(s,'.')!=NULL) return; hp=gethostbyname(s); if (hp==NULL) fatal("Hostname self-lookup failed.",0); strncpy(s,hp->h_name, UHOSTLEN); s[UHOSTLEN] = 0; if (strchr(s,'.')!=NULL) return; if (hp->h_aliases[0] == NULL) fatal("Can't determine your hostname!",0); strncpy(s,hp->h_aliases[0], UHOSTLEN); s[UHOSTLEN] = 0; if (strchr(s,'.')==NULL) fatal("Can't determine your hostname!",0); } /* get my ip number */ IP getmyip() { struct hostent *hp; char s[121]; IP ip; struct in_addr *in; gethostname(s,120); hp=gethostbyname(s); if (hp==NULL) fatal("Hostname self-lookup failed.",0); in=(struct in_addr *)(hp->h_addr_list[0]); ip=(IP)(in->s_addr); return ip; } void neterror(s) char *s; { switch(errno) { case EADDRINUSE: strcpy(s,"Address already in use"); break; case EADDRNOTAVAIL: strcpy(s,"Address invalid on remote machine"); break; case EAFNOSUPPORT: strcpy(s,"Address family not supported"); break; case EALREADY: strcpy(s,"Socket already in use"); break; case EBADF: strcpy(s,"Socket descriptor is bad"); break; case ECONNREFUSED: strcpy(s,"Connection refused"); break; case EFAULT: strcpy(s,"Namespace segment violation"); break; case EINPROGRESS: strcpy(s,"Operation in progress"); break; case EINTR: strcpy(s,"Timeout"); break; case EINVAL: strcpy(s,"Invalid namespace"); break; case EISCONN: strcpy(s,"Socket already connected"); break; case ENETUNREACH: strcpy(s,"Network unreachable"); break; case ENOTSOCK: strcpy(s,"File descriptor, not a socket"); break; case ETIMEDOUT: strcpy(s,"Connection timed out"); break; case ENOTCONN: strcpy(s,"Socket is not connected"); break; case EHOSTUNREACH: strcpy(s,"Host is unreachable"); break; case EPIPE: strcpy(s,"Broken pipe"); break; #ifdef ECONNRESET case ECONNRESET: strcpy(s,"Connection reset by peer"); break; #endif #ifdef EACCES case EACCES: strcpy(s,"Permission denied"); break; #endif case 0: strcpy(s,"Error 0"); break; default: sprintf(s,"Unforseen error %d",errno); break; } } /* request a normal socket for i/o */ void setsock(sock,options) int sock,options; { int parm; struct sock_list *slist; slist= malloc(sizeof(struct sock_list)); slist->next=socklist; socklist=slist; socklist->inbuf=socklist->outbuf=NULL; socklist->flags=options; socklist->sock=sock; if ( !(socklist->flags &SOCK_NONSOCK)) { parm=1; setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(void *)&parm,sizeof(int)); parm=0; setsockopt(sock,SOL_SOCKET,SO_LINGER,(void *)&parm,sizeof(int)); } if (options & SOCK_LISTEN) { /* Tris says this lets us grab the same port again next time */ parm=1; setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void *)&parm, sizeof(int)); } /* yay async i/o ! */ fcntl(sock,F_SETFL,O_NONBLOCK); return; } void setopt (int sock, int options) { int parm, x; parm=1; x = setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(void *)&parm,sizeof(int)); parm=0; x = setsockopt(sock,SOL_SOCKET,SO_LINGER,(void *)&parm,sizeof(int)); x = fcntl(sock,F_SETFL,O_NONBLOCK); } int getsock(options) int options; { int sock=socket(AF_INET,SOCK_STREAM,0); if (sock<0) fatal("Can't open a socket at all!",0); setsock(sock,options); return sock; } /* done with a socket */ void killsock(sock) int sock; { struct sock_list *slist,*oslist; dequeue_sockets(); oslist=NULL; slist=socklist; while (slist!=NULL) { if (slist->sock==sock) { close(slist->sock); if (slist->inbuf != NULL) nfree(slist->inbuf); if (slist->outbuf != NULL) nfree(slist->outbuf); slist->flags=SOCK_UNUSED; if (oslist == NULL) { socklist=slist->next; free(slist); } else { oslist->next=slist->next; free(slist); } return; } oslist=slist; slist=slist->next; } } /* Connects and binds to a specific port+address */ /* Returns -1 if fail, or port # is return in port, and returns socket number */ int open_listen_socket(port,bindip) int *port; char *bindip; { int sock,addrlen; struct sockaddr_in name; sock=getsock(SOCK_LISTEN); my_bzero((char *)&name,sizeof(struct sockaddr_in)); name.sin_family=AF_INET; name.sin_port=htons(*port); /* 0 = just assign us a port */ name.sin_addr.s_addr=getip(bindip); if (bind(sock,(struct sockaddr *)&name,sizeof(name))<0) { printf("ERROR\n"); killsock(sock); return -1; } /* what port are we on? */ addrlen=sizeof(name); if (getsockname(sock,(struct sockaddr *)&name,&addrlen)<0) { printf("ERROR\n"); killsock(sock); return -1; } *port=ntohs(name.sin_port); if (listen(sock,5)<0) { printf("Erk\n"); killsock(sock); return -1; } return sock; } /* returns a socket number for a listening socket that will accept any */ /* connection -- port # is returned in port */ int open_listen(port) int *port; { return(open_listen_socket(port,"0.0.0.0")); } /* given network-style IP address, return hostname */ /* hostname will be "##.##.##.##" format if there was an error */ char *hostnamefromip(ip) unsigned long ip; { struct hostent *hp; unsigned long addr=ip; unsigned char *p; static char s[UHOSTLEN+1]; /* alarm(10);*/ hp=gethostbyaddr((char *)&addr,sizeof(addr),AF_INET); /*alarm(0);*/ if (hp==NULL) { p=(unsigned char *)&addr; sprintf(s,"%u.%u.%u.%u",p[0],p[1],p[2],p[3]); return s; } strncpy(s,hp->h_name,UHOSTLEN); s[UHOSTLEN] = 0; return s; } /* short routine to answer a connect received on a socket made previously */ int answer(sock,ip,binary) int sock; unsigned long *ip; int binary; { int new_sock,addrlen; struct sockaddr_in from; addrlen=sizeof(struct sockaddr); new_sock=accept(sock,(struct sockaddr *)&from,&addrlen); if (new_sock<0) return -1; *ip=from.sin_addr.s_addr; *ip=ntohl(*ip); /* set up all the normal socket crap */ // setsock(new_sock,(binary ? SOCK_BINARY : 0)); return new_sock; } /* attempts to read from all the sockets in socklist */ /* fills s with up to 1023 bytes if available, and returns 0 */ /* on EOF, returns -1, with socket in len */ /* on socket error, returns -2 */ /* if nothing is ready, returns -3 */ int sockread(s,len,socket_list) char *s; int *len;struct sock_list **socket_list; { fd_set fd; int fds,x; struct timeval t; int grab=1023; struct sock_list *slist; *socket_list=NULL; fds=getdtablesize(); #ifdef FD_SETSIZE if (fds>FD_SETSIZE) fds=FD_SETSIZE; /* fixes YET ANOTHER freebsd bug!!! */ #endif /* timeout: 1 sec */ t.tv_sec=1; t.tv_usec=0; FD_ZERO(&fd); slist=socklist; while(slist!=NULL) { if (!(slist->flags & SOCK_UNUSED)) { FD_SET(slist->sock,&fd); slist=slist->next; } } #ifdef HPUX x=select(fds,(int *)&fd,(int *)NULL,(int *)NULL,&t); #else x=select(fds,&fd,NULL,NULL,&t); #endif if (x>0) { /* something happened */ slist=socklist; while(slist!=NULL) { if ((!(slist->flags & SOCK_UNUSED)) && ((FD_ISSET(slist->sock,&fd)) )) { if (slist->flags & (SOCK_LISTEN|SOCK_CONNECT)) { /* listening socket -- don't read, just return activity */ /* same for connection attempt */ if (!(slist->flags & SOCK_STRONGCONN)) { s[0]=0; *len=0; *socket_list=slist; return 0; } /* (for strong connections, require a read to succeed first) */ } x=read(slist->sock,s,grab); if (x<=0) { /* eof */ *len=slist->sock; slist->flags &= ~SOCK_CONNECT; return -1; } s[x]=0; *len=x; *socket_list=slist; return 0; } slist=slist->next; } } else if (x==-1) return -2; /* socket error */ else { s[0]=0; *len = 0; } return -3; } /* sockgets: buffer and read from sockets attempts to read from all registered sockets for up to one second. if after one second, no complete data has been received from any of the sockets, 's' will be empty, 'len' will be 0, and sockgets will return -3. if there is returnable data received from a socket, the data will be in 's' (null-terminated if non-binary), the length will be returned in len, and the socket number will be returned. normal sockets have their input buffered, and each call to sockgets will return one line terminated with a '\n'. binary sockets are not buffered and return whatever coems in as soon as it arrives. listening sockets will return an empty string when a connection comes in. connecting sockets will return an empty string on a successful connect, or EOF on a failed connect. if an EOF is detected from any of the sockets, that socket number will be put in len, and -1 will be returned. * the maximum length of the string returned is 1024 (including null) */ int sockgets(s,len) char *s; int *len; { char xx[1026],*p,*px; int ret; struct sock_list *slist; /* check for stored-up data waiting to be processed */ slist=socklist; while(slist!=NULL) { if (!(slist->flags & SOCK_UNUSED) && (slist->inbuf != NULL)) { /* look for \r too cos windows can't follow RFCs */ p=strchr(slist->inbuf,'\xff'); if (p==NULL) p=strchr(slist->inbuf,'\n'); if (p!=NULL) { *p=0; if (strlen(slist->inbuf) > 1022) slist->inbuf[1022]=0; strcpy(s,slist->inbuf); px=(char *)nmalloc(strlen(p+1)+1); strcpy(px,p+1); nfree(slist->inbuf); if (px[0]) slist->inbuf=px; else { nfree(px); slist->inbuf=NULL; } /* strip CR if this was CR/LF combo */ /* strip FF */ if (s[strlen(s)]=='\xff') s[strlen(s)]=0; if (s[strlen(s)]=='\n') s[strlen(s)]=0; *len = strlen(s); /* <-- oh that looks so cute robey! :) */ return slist->sock; } } slist=slist->next; } /* no pent-up data of any worth -- down to business */ *len=0; slist=NULL; ret=sockread(xx,len,&slist); if (ret<0) { s[0]=0; return ret; } /* binary and listening sockets don't get buffered */ if (slist->flags & SOCK_CONNECT) { if (slist->flags & SOCK_STRONGCONN) { slist->flags &= ~SOCK_STRONGCONN; /* buffer any data that came in, for future read */ /* slist->inbuf=(char *)nmalloc(strlen(xx)+1); strcpy(slist->inbuf,xx);*/ } slist->flags &= ~SOCK_CONNECT; s[0]=0; return slist->sock; } if (slist->flags & SOCK_BINARY) { my_memcpy(s,xx,*len); return slist->sock; } if (slist->flags & SOCK_LISTEN) return slist->sock; /* might be necessary to prepend stored-up data! */ if (slist->inbuf != NULL) { p=slist->inbuf; slist->inbuf=(char *)nmalloc(strlen(p)+strlen(xx)+1); strcpy(slist->inbuf,p); strcat(slist->inbuf,xx); nfree(p); if (strlen(slist->inbuf) < 1024) { strcpy(xx,slist->inbuf); nfree(slist->inbuf); slist->inbuf=NULL; } else { p=slist->inbuf; slist->inbuf=(char *)nmalloc(strlen(p)-1021); strcpy(slist->inbuf,p+1022); *(p+1022)=0; strcpy(xx,p); nfree(p); /* (leave the rest to be post-pended later) */ } } /* look for EOL marker; if it's there, i have something to show */ p=strchr(xx,'\xff'); /* if (p==NULL) p=strchr(xx,'\r');*/ if (p==NULL) p=strchr(xx,'\n'); if (p!=NULL) { *p=0; strcpy(s,xx); strcpy(xx,p+1); /* if (s[strlen(s)-1]=='\r') s[strlen(s)-1]=0;*/ if (s[strlen(s)]=='\xff') s[strlen(s)]=0; if (s[strlen(s)]=='\n') s[strlen(s)]=0; } else { s[0]=0; if (strlen(xx)>=1022) { /* string is too long, so just insert fake \n */ strcpy(s,xx); xx[0]=0; } } *len = strlen(s); /* anything left that needs to be saved? */ if (!xx[0]) { if (s[0]) return slist->sock; else return -3; } /* prepend old data back */ if (slist->inbuf != NULL) { p=slist->inbuf; slist->inbuf=(char *)nmalloc(strlen(p)+strlen(xx)+1); strcpy(slist->inbuf,xx); strcat(slist->inbuf,p); nfree(p); } else { slist->inbuf=(char *)nmalloc(strlen(xx)+1); strcpy(slist->inbuf,xx); } if (s[0]) return slist->sock; else return -3; } /* dump something to a socket */ void tputs(z,s) int z; char *s; { int x; char *p; struct sock_list *slist; if (z<0) return; /* um... HELLO?! sanity check please! */ slist=socklist; while(slist!=NULL) { if (!(slist->flags & SOCK_UNUSED) && (slist->sock==z)) { if (slist->outbuf != NULL) { /* already queueing: just add it */ p=(char *)nmalloc(strlen(slist->outbuf)+strlen(s)+1); strcpy(p,slist->outbuf); strcat(p,s); nfree(slist->outbuf); slist->outbuf=p; return; } x=write(z,s,strlen(s)); if (x==(-1)) x=0; if (x < strlen(s)) { /* socket is full, queue it */ slist->outbuf=(char *)nmalloc(strlen(s)-x+1); strcpy(slist->outbuf,&s[x]); } return; } slist=slist->next; } } /* tputs might queue data for sockets, let's dump as much of it as */ /* possible */ void dequeue_sockets() { char *p; struct sock_list *slist; slist=socklist; while(slist!=NULL) { if (!(slist->flags & SOCK_UNUSED) && (slist->outbuf != NULL)) { /* trick tputs into doing the work */ p=slist->outbuf; slist->outbuf=NULL; tputs(slist->sock,p); nfree(p); } slist=slist->next; } } /* like fprintf, but instead of preceding the format string with a FILE pointer, precede with a socket number */ /* please stop using this one except for server output. dcc output should now use dprintf(idx,"format",[params]); */ void tprintf(int sock, char *format, ...) { static char TBUF[1024]; if (format) { va_list args; va_start (args, format); vsnprintf(TBUF, 1023, format, args); va_end(args); tputs(sock,TBUF); if (strlen(TBUF) > 3) lvprintf(10,"Tprintf(%d): %s\n", sock, TBUF); } } IP getip(char *s) { struct hostent *hp; IP ip; struct in_addr *in; hp=gethostbyname(s); if (hp==NULL) ip=0; else { in=(struct in_addr *)(hp->h_addr_list[0]); ip=(IP)(in->s_addr); } return ip; } tetrinetx-1.13.16+qirc-1.40c/src/config.h0100600000076700007670000000156507271162601017211 0ustar drslumdrslum/* config.h Definitions in here are pretty safe to modify. Generally user defined stuff anyway ;) */ /* Location of the various external files */ #define FILE_MOTD "game.motd" /* Message of the Day File */ #define FILE_PMOTD "game.pmotd" /* Playback motd */ #define FILE_CONF "game.conf" /* Game configuration File */ #define FILE_WINLIST "game.winlist" /* Winlist storage file */ #define FILE_WINLIST2 "game.winlist2" /* Winlist storage file */ #define FILE_WINLIST3 "game.winlist3" /* Winlist storage file */ #define FILE_BAN "game.ban" /* List of Banned IP's */ #define FILE_BAN_COMPROMISE "game.ban.compromise" /* List of Banned IP's */ #define FILE_ALLOW "game.allow" /* List of allow IP's */ #define FILE_LOG "game.log" /* Logfile */ #define FILE_PID "game.pid" /* Default PID */ #define FILE_SECURE "game.secure" /* Security file */ tetrinetx-1.13.16+qirc-1.40c/src/main.c0100600000076700007670000054207707512457115016700 0ustar drslumdrslum /* TetriNET Server for Linux V1.13.XX ************************************************************************* */ /* This source code is with qirc-1.40 addons+patch qirc-1.40 date: Apr 23 2001 Any questions maybe directed to drslum@tetrinet.org or brg@cheerful.com Do not complain about how brutal this coding is. :) */ /*undef TETDEBUG*/ /* Every time I find I need a printf, I'll encase it as a debug */ #include "config.h" /* Generally about the only file */ /* that the user can safely change */ #include #include #include #include "main.h" #include "dns.h" #include "net.h" #include "utils.h" #include "crack.h" #include "game.h" #include "dns.c" #include "utils.c" #include "net.c" #include "crack.c" #include "game.c" /* remnet (channel, n) - Removes n from the channel list */ void remnet(struct channel_t *chan, struct net_t *n) { struct net_t *nsock,*osock; nsock=chan->net; osock=NULL; while( (nsock!=NULL) && (nsock!= n)) { osock=nsock; nsock=nsock->next; } if (nsock!=NULL) { if (osock==NULL) chan->net=nsock->next; else osock->next=nsock->next; nsock->channel=NULL; } } /* addnet (channel, n) - Adds n to the channel list */ void addnet(struct channel_t *chan, struct net_t *n) { n->next=chan->net; chan->net=n; n->channel=chan; } void add_rnet(struct net_t *n, int id) { struct res_t *r; r = malloc(sizeof(struct res_t)); r->net = n; r->res_id = id; r->next = NULL; if (rnet == NULL) rnet = r; else { r->next = rnet; rnet = r; } } void rem_rnet(struct net_t *n) { struct res_t *r, *prev_r; prev_r = rnet; for (r = rnet; r; r = r->next) { if (r->net == n) { if (r == rnet) { rnet = r->next; free(r); return; } else { prev_r->next = r->next; free(r); return; } } prev_r = r; } lvprintf(0, "Fatal error: net not found on resolver list\n"); } struct net_t *find_rnet(int id) { struct res_t *r; for (r = rnet; r; r = r->next) { if (r->res_id == id) return(r->net); } return NULL; } /* writepid() - Writes the current pid to game.pidfile */ void writepid(void) { FILE *file_out; file_out = fopen(game.pidfile,"w"); if (file_out == NULL) { // lvprintf(0,"ERROR: Could not write to PID file %s\n", game.pidfile); } else { fprintf(file_out,"%d", (int)getpid()); fclose(file_out); } } /* delpid() - Delete the pid file */ void delpid(void) { remove(game.pidfile); } /* int numallplayers(chan) - Returns ANY player that is connected in a channel */ int numallplayers(struct channel_t *chan) { int count; struct net_t *n; count=0; n=chan->net; while (n!=NULL) { count++; n=n->next; } return(count); } /* int numplayers(chan) - Returns number of CONNECTED Players in a channel */ int numplayers(struct channel_t *chan) { int count; struct net_t *n; count=0; n=chan->net; while (n!=NULL) { if( ((n->type==NET_CONNECTED) || (n->type==NET_WAITINGFORTEAM))) count++; n=n->next; } return(count); } /* int numchannels() - Returns number of channels */ int numchannels(void) { int count; struct channel_t *chan; chan=chanlist; count=0; while (chan!= NULL) { count++; chan=chan->next; } return(count); } int is_valid_channelname(char *p) { char *r; int valid=1; if (!p) return 0; for (r = p; *r; r++) { if ( (*r >= '0' && *r <= '9') || (*r >= 'A' && *r <= 'Z') || (*r >= 'a' && *r <= 'z') || (*r == '_' || *r == '-') || (*r == '[' || *r ==']') ) continue; valid = 0; break; } return(valid); } char is_explicit_banned(struct net_t *n) { /* I should use regex, but I've not used it before, and it was late. Easier to write a quick one of my own */ char ip_str[UHOSTLEN+1], host[UHOSTLEN+1]; char n1[4], n2[4], n3[4], n4[4]; int i, j; int found; sprintf(n1,"%lu", (unsigned long)(n->addr&0xff000000)/(unsigned long)0x1000000); sprintf(n2,"%lu", (unsigned long)(n->addr&0x00ff0000)/(unsigned long)0x10000); sprintf(n3,"%lu", (unsigned long)(n->addr&0x0000ff00)/(unsigned long)0x100); sprintf(n4,"%lu", (unsigned long)n->addr&0x000000ff); sprintf(ip_str, "%s.%s.%s.%s", n1, n2, n3, n4); found = 0; i = 0; for (j=0; n->host[j] != '\0'; j++) host[j] = tolower(n->host[j]); host[j] = '\0'; while (i < MAXBAN && !found && banlist[i].addr[0] != 0) { if (!fnmatch(banlist[i].addr, host, 0) || !fnmatch(banlist[i].addr, ip_str, 0)) { found = 1; break; } i++; } return(found); } int is_banned(struct net_t *n) { /* I should use regex, but I've not used it before, and it was late. Easier to write a quick one of my own */ char ip_str[UHOSTLEN+1], host[UHOSTLEN+1]; char n1[4], n2[4], n3[4], n4[4]; int i, j; int found, allow; allow = 0; i = 0; while (i < MAXALLOW && allowlist[i].nick[0] != 0) { if (!strcasecmp(n->nick, allowlist[i].nick) && !strcmp(n->team, allowlist[i].pass)) { allow =1; n->team[0] = '\0'; break; } i++; } if (allow) return(0); sprintf(n1,"%lu", (unsigned long)(n->addr&0xff000000)/(unsigned long)0x1000000); sprintf(n2,"%lu", (unsigned long)(n->addr&0x00ff0000)/(unsigned long)0x10000); sprintf(n3,"%lu", (unsigned long)(n->addr&0x0000ff00)/(unsigned long)0x100); sprintf(n4,"%lu", (unsigned long)n->addr&0x000000ff); sprintf(ip_str, "%s.%s.%s.%s", n1, n2, n3, n4); found = 0; i = 0; for (j=0; n->host[j] != '\0'; j++) host[j] = tolower(n->host[j]); host[j] = '\0'; while (!found && i < MAXBAN && combanlist[i].addr[0] != 0) { if (!fnmatch(combanlist[i].addr, ip_str, 0) || !fnmatch(combanlist[i].addr, host, 0)) { found = 1; break; } i++; } return(found); } /* is_op( net ) - Returns 1 if this player is the lowest gameslot, thus the chanop */ char is_op(struct net_t *n) { int found; struct net_t *nt; found = 0; nt=n->channel->net; while( nt!=NULL) { if ( ( (nt->type == NET_CONNECTED) || (nt->type == NET_WAITINGFORTEAM) ) && (nt->gameslot < n->gameslot)) found = 1; nt=nt->next; } return(!found); } /* passed_level(net, level required to pass) - Returns 1 if the player's security */ /* level is equal to or higher than the level required to pass */ /* Passing is_op gives player a security level of at least 2*/ char passed_level(struct net_t *n, int passlevel) { int currlevel; currlevel=LEVEL_NORMAL; /* Normal Player */ if (is_op(n)) currlevel=LEVEL_OP; /* Op by position */ /* Player might already have a higher level... say they did a /op */ if (n->securitylevel > currlevel) currlevel=n->securitylevel; return( currlevel >= passlevel); } /* kick(net from, player to be kicked) - Disconnects player, and informs all others that they were kicked */ void kick(struct net_t *n_from, int kick_gameslot) { struct net_t *n; struct net_t *n_to; n=n_from->channel->net; n_to=NULL; while (n!=NULL) { if ( (n->gameslot == kick_gameslot) && ((n->type == NET_CONNECTED) || (n->type == NET_WAITINGFORTEAM))) n_to = n; n=n->next; } if ((n_to!=NULL) && (kick_gameslot>=1) && (kick_gameslot<=6)) { net_query_parser("kick %s %d %s #%s", n_to->nick, n_to->gameslot, n_to->host, n_to->channel->name); n=n_from->channel->net; net_playback_send(n_to->channel->name, "kick %d\xff", kick_gameslot); while (n!=NULL) { if ( ((n->type == NET_CONNECTED) || (n->type == NET_WAITINGFORTEAM))) { tprintf(n->sock,"kick %d\xff", kick_gameslot); } n=n->next; } killsock(n_to->sock); lostnet(n_to); } } /* tet_checkversion( client version ) - Returns 0 if the server supports this */ /* client version. At the moment, ONLY support 1.13 client*/ int tet_checkversion(char *buf) { /* Returns -1 if versioncheck fails */ if (!strcmp(TETVERSION,buf)) return(0); else return(-1); } /* lvprintf( priority, same as printf ) - Logs to the log IF priority is smaller */ /* or equal to game.verbose */ void lvprintf(int level, char *format, ...) { static char LBUF[1024]; if (format) { va_list args; va_start (args, format); vsnprintf(LBUF, 1023, format, args); va_end(args); if (level <= game.verbose) lprintf("%s", LBUF); } } /* lprintf( same as printf ) - Logs to the log. */ void lprintf(char *format, ...) { static char LBUF[1024]; FILE *file_out; char *mytime; char *P; time_t cur_time; if (format) { va_list args; va_start (args, format); vsnprintf(LBUF, 1023, format, args); va_end(args); file_out = fopen(FILE_LOG,"a"); if (file_out != NULL) { cur_time = time(NULL); mytime=ctime(&cur_time); P=mytime; P+=4; mytime[strlen(mytime)-6]=0; fprintf(file_out,"%s %s", P, LBUF); fclose(file_out); } } } /* Open a Listening Socket on the TetriNET port */ void init_telnet_port() { int i,j; struct net_t *n; /* find old entry if it exists */ n=gnet; while ( (n!=NULL) && (n->type!=NET_TELNET)) n=n->next; if (n==NULL) { /* no existing entry */ n=gnet; gnet=malloc(sizeof(struct net_t)); gnet->next=NULL; n=gnet; n->addr=getmyip(); n->type=NET_TELNET; n->channel = malloc(sizeof(struct channel_t)); n->channel->name[0] = '\0'; strcpy(n->nick,"(telnet)"); getmyhostname(n->host); } else { /* already an entry */ killsock(n->sock); } j=TELNET_PORT; i=open_listen_socket(&j,game.bindip); if (i>=0) { n->port=j; n->sock=i; lvprintf(3,"Listening at telnet port %d, on socket %d, bound to %s\n", j,i,game.bindip); return; } printf("Couldn't find telnet port %d. (TetriNET already running?)\n",j); lvprintf(0,"Couldn't find telnet port %d.\n", j); exit(1); } /* Open a Listening Socket on the TetriNET query port */ void init_query_port() { int i,j; struct net_t *n; /* find old entry if it exists */ n = gnet; if (!n) { lvprintf(0, "Fatal error: gnet not found!! \n"); exit(0); } while (n->next && (n->type!=NET_QUERY)) n=n->next; if (n->next) killsock(n->sock); /* no existing entry */ n->next = malloc(sizeof(struct net_t)); n = n->next; n->addr=getmyip(); n->type=NET_QUERY; n->next=NULL; n->channel = malloc(sizeof(struct channel_t)); n->channel->name[0] = '\0'; strcpy(n->nick,"(telnet)"); getmyhostname(n->host); j=QUERY_PORT; i=open_listen_socket(&j,game.bindip); if (i>=0) { n->port=j; n->sock=i; lvprintf(3,"Listening at query port %d, on socket %d, bound to %s\n", j,i,game.bindip); return; } printf("Couldn't find telnet port %d. (TetriNET already running?)\n",j); lvprintf(0,"Couldn't find telnet port %d.\n", j); exit(1); } /* Open a Listening Socket on the TetriNET query port */ void init_playback_port() { int i,j; struct net_t *n; /* find old entry if it exists */ n = gnet; if (!n) { lvprintf(0, "Fatal error: gnet not found!! \n"); exit(0); } while (n->next && (n->type!=NET_PLAYBACK)) n=n->next; if (n->next) killsock(n->sock); /* no existing entry */ n->next = malloc(sizeof(struct net_t)); n = n->next; n->addr=getmyip(); n->type=NET_PLAYBACK; n->next=NULL; n->channel = malloc(sizeof(struct channel_t)); n->channel->name[0] = '\0'; strcpy(n->nick,"(telnet)"); getmyhostname(n->host); j=PLAYBACK_PORT; i=open_listen_socket(&j,game.bindip); if (i>=0) { n->port=j; n->sock=i; lvprintf(3,"Listening at playback port %d, on socket %d, bound to %s\n", j,i,game.bindip); return; } printf("Couldn't find telnet port %d. (TetriNET already running?)\n",j); lvprintf(0,"Couldn't find telnet port %d.\n", j); exit(1); } /* Main loop calls here when activity found on a net socket */ void net_activity(int z, char *buf, int len) { struct net_t *n; struct channel_t *chan; chan=chanlist; n = NULL; while ( (chan!=NULL) && (n==NULL) ) { n=chan->net; while( (n!=NULL) && (n->sock!=z) ) n=n->next; chan=chan->next; } if (n==NULL) { /* Try global list */ n=gnet; while( (n!=NULL) && (n->sock!=z) ) n=n->next; } if (n==NULL) return; /* Reset timeout on socket */ if (n->status == STAT_PLAYING) n->timeout_ingame = game.timeout_ingame; else n->timeout_outgame = game.timeout_outgame; switch (n->type) { case NET_TELNET: /* Recieved connection */ { net_telnet(n,buf); break; } case NET_QUERY: /* Recieved connection */ { net_query(n,buf); break; } case NET_PLAYBACK: /* Received playback connection */ { net_playback(n,buf); break; } case NET_TELNET_INIT: /* Received clients init sequence */ { net_telnet_init(n,buf); break; } case NET_QUERY_INIT: /* Received clients init sequence */ { net_query_init(n,buf); break; } case NET_PLAYBACK_INIT: { net_playback_init(n,buf); break; } case NET_WAITINGFORTEAM: /* Waiting for inital team */ { net_waitingforteam(n,buf); break; } case NET_CONNECTED: /* Recieved command from client */ { net_connected(n,buf); break; } case NET_QUERY_CONNECTED: { net_query_connected(n,buf); break; } case NET_PLAYBACK_CONNECTED: { net_playback_connected(n,buf); break; } case NET_WAITINGFORDNS: { lvprintf(0, "Internal Error - Untrapped DNS event.\n"); break; } default: { /* lvprintf(0,"Internal Error - Untrapped Network activity.\n"); */ } } } /* String length (minus colours) */ int strclen(char *S) { int i;int count; if (S==NULL) return 0; i=0;count=0; while(S[i]!=0) { if( (S[i] != BOLD) && (S[i] != CYAN) && (S[i] != BLACK) && (S[i] != BLUE) && (S[i] != DARKGRAY) && (S[i] != MAGENTA) && (S[i] != GREEN) && (S[i] != NEON) && (S[i] != SILVER) && (S[i] != BROWN) && (S[i] != NAVY) && (S[i] != VIOLET) && (S[i] != RED) && (S[i] != ITALIC) && (S[i] != TEAL) && (S[i] != WHITE) && (S[i] != YELLOW) && (S[i] != UNDERLINE) && (S[i] != 11) ) count++; i++; } return(i); } /* Connected, recieving commands */ void net_connected(struct net_t *n, char *buf) { char COMMAND[101]; char PARAM[601]; char MSG[601]; char STRG[513], STRG2[513]; int num; int num1; int num2; int num3; int num4; int s; int i,j,k,l,x,y; int valid_param; int byt; char *P=NULL; struct channel_t *chan,*ochan,*c,*oc; struct net_t *nsock=NULL; struct net_t *ns1,*ns2; if (!buf) return; /* sometimes this is really happen!!! zero length buf!!! */ byt = strlen(buf); if (byt <= 2 || byt > 512) return; COMMAND[0]=0;PARAM[0]=0;MSG[0]=0; /* Ensure command is proper before passing it to other players */ sscanf(buf, "%100s %600[^\n\r]", COMMAND, PARAM); valid_param = 0; /* 0 = invalid */ /* 1 = valid */ /* 2 = valid command, but failed some test */ /* Party Line Message - pline */ if ( !strcasecmp(COMMAND, "pline") ) { valid_param=2; s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG); n->timeout_outgame = game.timeout_outgame; if ( ((s >= 2) && (num==n->gameslot)) || (n->type == NET_PLAYBACK_CONNECTED)) { if (MSG[0]=='/') { valid_param=1; /* First parse to see if it's a server command */ if ( !strncasecmp(MSG, "/kick", 5) && (game.command_kick > 0)) { int self_kick = 0; valid_param=2; if ( passed_level(n,game.command_kick) ) { if (strlen(MSG) < 7) { tprintf(n->sock,"pline 0 %cFormat: %c/kick %c\xff", NAVY,RED,BLUE); return; } P=MSG+6; while( (((*P)-'0') >= 1) && (((*P)-'0') <= 6) ) { if (((*P)-'0') == n->gameslot) self_kick = 1; else kick(n, (*P)-'0'); P++; } if (self_kick) kick(n, n->gameslot); } else tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED); } /* Who is online */ if ( !strncasecmp(MSG, "/who", 4) && (game.command_who>0)) { valid_param=2; if ( n->type == NET_PLAYBACK_CONNECTED || passed_level(n,game.command_who) ) { if (n->securitylevel == LEVEL_AUTHOP) tprintf(n->sock,"pline 0 %cNickname\tTeam \tChannel\tIP\xff", NAVY); else tprintf(n->sock,"pline 0 %cNickname\tTeam \tChannel\xff", NAVY); l=1; chan=chanlist; while(chan!=NULL) { nsock=chan->net; while (nsock!=NULL) { if (nsock->type==NET_CONNECTED) { STRG[0]=0; STRG2[0]=0; strcpy(STRG,nsock->nick); j=strclen(STRG); k=strlen(STRG); while(j<15) { STRG[k]=' '; k++; j++; } STRG[k]=0; strcpy(STRG2,nsock->team); j=strclen(STRG2); k=strlen(STRG2); while(j<17) { STRG2[k]=' '; k++; j++; } STRG2[k]=0; if (nsock==n) j=RED; else j=DARKGRAY; if (n->securitylevel == LEVEL_AUTHOP) tprintf(n->sock,"pline 0 %c(%c%d%c) %c%s\t%c%s\t%c#%s\t%s\xff", NAVY,j,l,NAVY, j, STRG,TEAL,STRG2,BLUE,nsock->channel->name,nsock->host); else tprintf(n->sock,"pline 0 %c(%c%d%c) %c%s\t%c%s\t%c#%s\xff", NAVY,j,l,NAVY, j, STRG,TEAL,STRG2,BLUE,nsock->channel->name); l++; } nsock=nsock->next; } chan=chan->next; } } else tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED); } /* List Channels */ if ( !strncasecmp(MSG, "/list", 5) && (game.command_list>0)) { valid_param=2; if ( n->type == NET_PLAYBACK_CONNECTED || passed_level(n,game.command_list) ) { if (chanlist != NULL) { tprintf(n->sock,"pline 0 %cTetriNET Channel Lister - (Type %c/join %c#channelname%c)\xff",NAVY,RED,BLUE,NAVY); chan=chanlist; i=1; while (chan != NULL) { if ((!strcasecmp(n->channel->name, chan->name))) j=RED; else j=BLUE; if (chan->status==STATE_INGAME) { sprintf(STRG,"%c{INGAME}%c", DARKGRAY,NAVY); } else { sprintf(STRG," "); } if (numplayers(chan) >= chan->maxplayers) tprintf(n->sock,"pline 0 %c(%c%d%c) %c#%-6s\t%c[%cFULL%c] %s (%d) %c%s\xff", NAVY, j, i, NAVY, BLUE, chan->name, NAVY,RED,NAVY,STRG, chan->priority,BLACK,chan->description); else { tprintf(n->sock,"pline 0 %c(%c%d%c) %c#%-6s\t%c[%cOPEN%c-%d/%d%c] %s (%d) %c%s\xff", NAVY, j, i, NAVY, BLUE, chan->name, NAVY,TEAL,BLUE,numplayers(chan),chan->maxplayers,NAVY,STRG, chan->priority,BLACK,chan->description); } i++; chan=chan->next; } } } else tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED); } /* Join Channel */ if ( !strncasecmp(MSG, "/j", 2) && (game.command_join>0)) { valid_param=2; if ( passed_level(n,game.command_join) || (game.command_join==4)) { if ( !strncasecmp(MSG,"/join ", 6) ) P=MSG+6; else if ( !strncasecmp(MSG,"/j ", 3) ) P=MSG+3; else { tprintf(n->sock,"pline 0 %cFormat: %c/join %c<#channel|channel number>\xff", NAVY,RED,BLUE); return; } STRG[0]=0; k = sscanf(P,"%512s", STRG); if ((k != 0) ) { /* First, is it a #channel or channel number? */ j=atoi(STRG); chan=NULL; ochan=NULL; if (j>0) { /* Position */ chan=chanlist; j--; while( (j>0) && (chan!=NULL) ) { chan=chan->next; j--; } } else if (STRG[0]=='#') { /* Name */ net_query_TrimStr(STRG); net_query_StripCtrlStr(STRG); sscanf(P,"#%512s", STRG); if (!is_valid_channelname(STRG)) { tprintf(n->sock, "pline 0 %cInvalid channel name!\xff", RED); return; } if (!strcasecmp(STRG, DEFAULTSPECCHANNEL)) { tprintf(n->sock, "pline 0 %cThe channel you request is restricted!\xff", RED); return; } chan = chanlist; while ( (chan != NULL) && (strcasecmp(STRG,chan->name)) ) chan=chan->next; j=0; } else { j=-1; tprintf(n->sock,"pline 0 %cFormat: %c/join %c<#channel|channel number>\xff", NAVY,RED,BLUE); } ochan=n->channel; if ( (chan!=NULL) && (numplayers(chan)>=chan->maxplayers)) { /* A Full channel */ tprintf(n->sock,"pline 0 %cThat channel is %cFULL%c!\xff", NAVY, RED,BLACK); } else if ( (chan==NULL) && (j>=0) && (numchannels() >= game.maxchannels)) { /* Too many channels */ tprintf(n->sock,"pline 0 %cCannot create any more channels!\xff",RED); } else if ( (chan==NULL) && (j>=0) && (game.command_join==4) && (n->securitylevel!=LEVEL_AUTHOP)) { /* Can't create a NEW channel */ tprintf(n->sock,"pline 0 %cCannot create new channel\xff",RED); } else if (j>=0) { if (chan == NULL) { /* New channel */ chan=chanlist; while ((chan!= NULL) && (chan->next!=NULL)) chan=chan->next; if (chan==NULL) { chanlist=malloc(sizeof(struct channel_t)); chan=chanlist; } else { chan->next=malloc(sizeof(struct channel_t)); chan=chan->next; } chan->next=NULL; chan->net=NULL; strncpy(chan->name, STRG, CHANLEN-1); chan->name[CHANLEN-1]=0; chan->maxplayers=DEFAULTMAXPLAYERS; chan->status=STATE_ONLINE; chan->description[0]=0; chan->priority=DEFAULTPRIORITY; chan->sd_mode=SD_NONE; chan->persistant=0; /* Copy default settings */ chan->starting_level=game.starting_level; chan->lines_per_level=game.lines_per_level; chan->level_increase=game.level_increase; chan->lines_per_special=game.lines_per_special; chan->special_added=game.special_added; chan->special_capacity=game.special_capacity; chan->classic_rules=game.classic_rules; chan->average_levels=game.average_levels; chan->sd_timeout=game.sd_timeout; chan->sd_lines_per_add=game.sd_lines_per_add; chan->sd_secs_between_lines=game.sd_secs_between_lines; strcpy(chan->sd_message,game.sd_message); chan->block_leftl=game.block_leftl; chan->block_leftz=game.block_leftz; chan->block_square=game.block_square; chan->block_rightl=game.block_rightl; chan->block_rightz=game.block_rightz; chan->block_halfcross=game.block_halfcross; chan->block_line=game.block_line; chan->special_addline=game.special_addline; chan->special_clearline=game.special_clearline; chan->special_nukefield=game.special_nukefield; chan->special_randomclear=game.special_randomclear; chan->special_switchfield=game.special_switchfield; chan->special_clearspecial=game.special_clearspecial; chan->special_gravity=game.special_gravity; chan->special_quakefield=game.special_quakefield; chan->special_blockbomb=game.special_blockbomb; chan->stripcolour=game.stripcolour; chan->serverannounce=game.serverannounce; chan->pingintercept=game.pingintercept; chan->winlist_file=game.winlist_file; strncpy(chan->game_type, game.game_type, GAMETYPELEN-1); chan->game_type[GAMETYPELEN-1] = 0; /* Remove ourselves from old channel list */ n->channel=chan; net_query_parser("newchan %s %d %s #%s", n->nick, n->gameslot, n->host, n->channel->name); tprintf(n->sock,"pline 0 %cCreated new Channel - %c#%s%c\xff", GREEN, BLUE, chan->name, BLACK); } else { /* An already existing channel */ n->channel = chan; /* net_query_parser("playerjoin %s %d %s #%s", n->nick, n->gameslot, n->host, chan->name); */ tprintf(n->sock,"pline 0 %cJoined existing Channel - %c#%s%c\xff", GREEN, BLUE, chan->name, BLACK); } remnet(ochan,n); addnet(chan,n); /* Send to old channel, this player join message */ nsock=ochan->net; net_playback_send(ochan->name, "pline 0 %c%s%c %chas joined channel #%s\xff", DARKGRAY,n->nick,BLACK,DARKGRAY,n->channel->name); while (nsock!=NULL) { if ( (nsock->type==NET_CONNECTED) ) { /* Tell them we've joined this channel */ tprintf(nsock->sock,"pline 0 %c%s%c %chas joined channel #%s\xff", DARKGRAY,n->nick,BLACK,DARKGRAY,n->channel->name); } nsock=nsock->next; } if ((ochan->status == STATE_INGAME) || (ochan->status ==STATE_PAUSED)) { n->status = STAT_NOTPLAYING; tprintf(n->sock,"endgame\xff"); } /* Cleartheir Field */ for(y=0;yfield[x][y]=0; /* Nothing */ /* Work out gameslot */ num1=n->gameslot; num2=0; num3=1; while ( (num2 < n->channel->maxplayers) && (num3) ) { num2++; num3=0; nsock=n->channel->net; while (nsock!=NULL) { if( (nsock!=n) && ( (nsock->type==NET_CONNECTED) || (nsock->type==NET_WAITINGFORTEAM) )&&(nsock->gameslot==num2) ) num3=1; nsock=nsock->next; } } if (num3==1) { // lvprintf(0,"#%s-%s Ran out of places in channel (FATAL)\n",n->channel->name,n->nick); killsock(n->sock);lostnet(n); return; } /* Clear our spot */ tprintf(n->sock,"playerleave %d\xff",n->gameslot); net_playback_send(ochan->name, "playerleave %d\xff", n->gameslot); n->gameslot=num2; /* Now, send playerleft to all on old channel AND to player */ num3=0; num4=0; STRG2[0]=0; nsock=ochan->net; net_query_parser("playerleave %s %d %s #%s", n->nick, n->gameslot, n->host, ochan->name); while (nsock!=NULL) { if ( (nsock!=n) && (nsock->type == NET_CONNECTED)) { tprintf(nsock->sock,"playerleave %d\xff", num1); tprintf(n->sock,"playerleave %d\xff", nsock->gameslot); if (strcasecmp(STRG2,nsock->team)) {/* Different team, so add player */ num3++; if (nsock->status==STAT_PLAYING) num4++; strcpy(STRG2,nsock->team); } else if (STRG2[0]==0) { num3++; if (nsock->status==STAT_PLAYING) num4++; } } nsock=nsock->next; } /* Now send to new channel, this player joined, AND to player also reset playerstatus */ n->status = STAT_NOTPLAYING; sendwinlist(n); net_playback_send(n->channel->name, "playerjoin %d %s\xffteam %d %s\xff", n->gameslot, n->nick, n->gameslot, n->team); net_query_parser("playerjoin %s %d %s #%s", n->nick, n->gameslot, n->host, n->channel->name); nsock=n->channel->net; while (nsock!=NULL) { if ( (nsock!=n) && (nsock->type==NET_CONNECTED)) { /* Send each other player and their team anme */ tprintf(n->sock, "playerjoin %d %s\xffteam %d %s\xff",nsock->gameslot, nsock->nick, nsock->gameslot, nsock->team); /* Send to the other player, this player and their team */ tprintf(nsock->sock, "playerjoin %d %s\xffteam %d %s\xff", n->gameslot, n->nick, n->gameslot, n->team); /* Tell them we've joined this channel */ tprintf(nsock->sock,"pline 0 %c%s%c %chas joined channel #%s\xff", GREEN,n->nick,BLACK,GREEN,n->channel->name); } nsock=nsock->next; } /* Set our playernumber */ tprintf(n->sock, "playernum %d\xff",n->gameslot); /* If game is in progress, send all other players fields */ if( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) ) { nsock=n->channel->net; while (nsock!=NULL) { if( (nsock->type==NET_CONNECTED) &&(nsock!=n)) { /* Tell this player that the newjoined player has lost */ tprintf(nsock->sock,"playerlost %d\xff", n->gameslot); /* Each player who has lost, send player_lost */ if (nsock->status != STAT_PLAYING) { tprintf(n->sock,"playerlost %d\xff", nsock->gameslot); } sendfield(n, nsock); /* Send to player, this players field */ } nsock=nsock->next; } } /* If we are ingame, then tell this person that we are! */ if ( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) ) tprintf(n->sock,"ingame\xff"); /* If we are currently paused, kindly let them know that fact to */ if ( n->channel->status == STATE_PAUSED ) tprintf(n->sock,"pause 1\xff"); /* If 1 or less players/teams now are playing, AND the player that quit WAS playing, STOPIT */ if ( (num4 <= 1) && (ochan->status == STATE_INGAME) && (n->status == STAT_PLAYING) ) { nsock=ochan->net; while (nsock!=NULL) { if ( (nsock!=n) && (nsock->type == NET_CONNECTED)) { tprintf(nsock->sock,"endgame\xff"); nsock->status=STAT_NOTPLAYING; } nsock=nsock->next; } net_playback_send(ochan->name, "endgame\xff"); ochan->status = STATE_ONLINE; } /* If no players, then we delete the channel IF it's not persistant*/ if ( (numallplayers(ochan) == 0) && (ochan!=n->channel) && (!ochan->persistant) ) { c=chanlist; oc=NULL; while ( (c != ochan) && (c != NULL) ) { oc=c; c=c->next; } if (c != NULL) { if (oc != NULL) oc->next=c->next; else chanlist=c->next; free(c); } } if (n->channel->status == STATE_ONLINE) { n->status=STAT_NOTPLAYING; } else { n->status=STAT_LOST; } } } } else tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED); } /* Save Config */ if ( !strncasecmp(MSG, "/save", 5) && (game.command_save>0)) { valid_param=2; if ( passed_level(n,game.command_save) ) { gamewrite(); tprintf(n->sock,"pline 0 %cGame configuration and Persistant Channel info saved\xff",NAVY); } else tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED); } /* Private msg to a person - Suggestion by crazor */ if ( !strncasecmp(MSG, "/msg", 4) && (game.command_msg>0)) { valid_param=2; if ( passed_level(n,game.command_msg) ) { if (strlen(MSG) < 8) { tprintf(n->sock, "pline 0 %c/msg %c \xff", RED, BLUE); return; } P=MSG+5; i = sscanf(P,"%512s %512[^\n\r]", STRG, STRG2); j = strlen (STRG); if (i != 2 || j > 6) { tprintf(n->sock, "pline 0 %c/msg %c \xff", RED, BLUE); return; } for (i = 0; i < j; i++) { if (STRG[i] < '0' || STRG[i] > '6') break; for (k = i+1; k < j; k++) if (STRG[i] == STRG[k]) break; if (k != j) break; } if (i != j) { tprintf(n->sock, "pline 0 %cInvalid playernumber %c(%s)\xff", RED, BLUE, STRG); return; } P=STRG; while( *P ) { j=(*P)-'0'; nsock=n->channel->net; while (nsock!=NULL) { if ( (nsock->type == NET_CONNECTED) && (nsock->gameslot == j)) { tprintf(nsock->sock,"pline %d %c(msg)%c %s\xff", n->gameslot, NAVY, BLACK, STRG2); } nsock=nsock->next; } P++; } } else tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED); } /* Move a player to another gamespot */ if ( !strncasecmp(MSG, "/move", 5) && (game.command_move>0)) { valid_param=2; if ( passed_level(n,game.command_move) && (n->channel->status == STATE_ONLINE) ) { if (strlen(MSG) < 9) { tprintf(n->sock,"pline 0 %c/move %c \xff", RED, BLUE); return; } P=MSG+6; k=0;l=0; sscanf(P," %d %d", &k, &l); if ( (k>0) && (k<=6) && (l>0) && (l<=6) && (k!=l) ) { /* Ok, this is NOT supposed to work, but it does ;) */ /* Give player l, player k's number */ /* Give player k, player l's number */ /* Send to all others, as if they've rejoined */ /* Find sock_index... for k */ ns1=n->channel->net; while ( (ns1!=NULL) && !( ((ns1->type == NET_CONNECTED) && (ns1->gameslot==k) ))) ns1=ns1->next; ns2=n->channel->net; while( (ns2!=NULL) && !((ns2->type == NET_CONNECTED) && (ns2->gameslot==l) )) ns2=ns2->next; if ( (ns1!=NULL) ) { tprintf(ns1->sock,"playernum %d\xff", l); ns1->gameslot = l; if (ns2!=NULL) { /* This player existed... */ tprintf(ns2->sock,"playernum %d\xff", k); ns2->gameslot=k; tprintf(ns1->sock,"playerjoin %d %s\xff", ns2->gameslot, ns2->nick); tprintf(ns1->sock,"team %d %s\xff", ns2->gameslot, ns2->team); tprintf(ns2->sock,"playerjoin %d %s\xff", ns1->gameslot, ns1->nick); tprintf(ns2->sock,"team %d %s\xff", ns1->gameslot, ns1->team); net_query_parser("move %s(%d) %s(%d) #%s", ns1->nick, k, ns2->nick, l, n->channel->name); } else { tprintf(ns1->sock,"playerleave %d\xff", k); } net_playback_send(n->channel->name, "playerjoin %d %s\xff", ns1->gameslot, ns1->nick); net_playback_send(n->channel->name, "team %d %s\xff", ns1->gameslot, ns1->team); if (ns2 != NULL) { net_playback_send(n->channel->name, "playerjoin %d %s\xff", ns2->gameslot, ns2->nick); net_playback_send(n->channel->name, "team %d %s\xff", ns2->gameslot, ns2->team); } else net_playback_send(n->channel->name, "playerleave %d \xff", k); /* Now tell everyone else */ nsock=n->channel->net; while (nsock!=NULL) { if ( (nsock->type == NET_CONNECTED) && (nsock!=ns1) && (nsock!=ns2) ) { tprintf(nsock->sock,"playerjoin %d %s\xff", ns1->gameslot, ns1->nick); tprintf(nsock->sock,"team %d %s\xff", ns1->gameslot, ns1->team); if (ns2!=NULL) { /* Player existed */ tprintf(nsock->sock,"playerjoin %d %s\xff", ns2->gameslot,ns2->nick); tprintf(nsock->sock,"team %d %s\xff", ns2->gameslot, ns2->team); } else { tprintf(nsock->sock,"playerleave %d\xff", k); } } nsock=nsock->next; } } } else if (n->type != NET_QUERY_CONNECTED && n->type != NET_PLAYBACK_CONNECTED) tprintf(n->sock,"pline 0 %c/move %c \xff", RED, BLUE); } else { if (n->channel->status != STATE_ONLINE) tprintf(n->sock,"pline 0 %cCommand unavailable while a game is in progress. Stop it first.\xff",RED); else tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED); } } /* Take "ops" - Suggestion by (jawfx@hotmail.com 21/9/98) */ if ( !strncasecmp(MSG, "/op", 3) && (game.command_op>0)) { valid_param=2; if (strlen(MSG) < 5) { return; } P=MSG+4; if (securityread() < 0) securitywrite(); if ( (strlen(security.op_password) > 0) && !strcmp(P, security.op_password) ) { /* Passed, this player is OP */ n->securitylevel =LEVEL_AUTHOP; tprintf(n->sock,"pline 0 %cYour security level is now: %cAUTHENTICATED OP\xff", GREEN, RED); net_query_parser("op %s %d %s #%s %s", n->nick, n->gameslot, n->host, n->channel->name, n->nick); } else { tprintf(n->sock,"pline 0 Invalid Password! (Attempt logged)\xff"); lvprintf(1,"#%s-%s Failed attempt to gain OP status\n", n->channel->name, n->nick); } } /* Winlist. Display the top X people - Suggestion by crazor */ if ( !strncasecmp(MSG, "/winlist", 8) && (game.command_winlist>0) ) { struct winlist_t *w; valid_param=2; if (passed_level(n,game.command_winlist)) { w = find_winlist(n); P=MSG+9; if (strlen(MSG) == 8) j=10; else { if (*P == '#') { w = find_winlist_from_chan(P); j = 10; } else j=atoi(P); } if (j > 40) j = 40; if (!w) { tprintf(n->sock, "pline 0 This channel is set to no scoring\xff"); return; } if ( (j >= 1) && (j <= MAXWINLIST) ) { i=0; tprintf(n->sock,"pline 0 %cTop %d Winlist\xff", BLUE, j); while ( (i < j) && (w[i].inuse) ) { if (w[i].status == 't') { if (!strcmp(n->team, w[i].name)) k = RED; else k = BLACK; tprintf(n->sock,"pline 0 %c%d. %4d - Team %s\xff", k, i+1, w[i].score, w[i].name); } else { if (!strcmp(n->nick, w[i].name)) k = RED; else k = BLACK; tprintf(n->sock,"pline 0 %c%d. %4d - Player %s\xff", k, i+1, w[i].score, w[i].name); } i++; } } } else tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED); } if ( !strncasecmp(MSG, "/--version", 9)) { valid_param = 2; tprintf(n->sock,"pline 0 %c%s.%s\xff", WHITE, TETVERSION, SERVERBUILD); } if ( !strncasecmp(MSG, "/help", 5) && (game.command_help>0) ) { valid_param=2; if (passed_level(n,game.command_help)) { tprintf(n->sock,"pline 0 - Built in server commands %c(*) %crequires 'op', %c(!) %crequires '/op'\xff", TEAL, BLACK, RED, BLACK); if (game.command_join) { STRG[0]=0; switch(game.command_join) { case 2: /* Requires OP */ { sprintf(STRG,"%c(*)", TEAL); break; } case 3: /* Requires /OP */ { sprintf(STRG,"%c(!)", RED); break; } } tprintf(n->sock,"pline 0 %c/join %c<#channel|channel number>\xff", RED, BLUE); tprintf(n->sock,"pline 0 %-4s %cJoins or creates a virtual tetrinet channel\xff", STRG, BLACK); } if (game.command_kick) { STRG[0]=0; switch(game.command_kick) { case 2: /* Requires OP */ { sprintf(STRG,"%c(*)", TEAL); break; } case 3: /* Requires /OP */ { sprintf(STRG,"%c(!)", RED); break; } } tprintf(n->sock,"pline 0 %c/kick %c\xff", RED, BLUE); tprintf(n->sock,"pline 0 %-4s %cKicks player(s) from the server\xff", STRG, BLACK); } if (game.command_list) { STRG[0]=0; switch(game.command_list) { case 2: /* Requires OP */ { sprintf(STRG,"%c(*)", TEAL); break; } case 3: /* Requires /OP */ { sprintf(STRG,"%c(!)", RED); break; } } tprintf(n->sock,"pline 0 %c/list\xff", RED); tprintf(n->sock,"pline 0 %-4s %cLists available virtual TetriNET channels\xff", STRG, BLACK); } tprintf(n->sock,"pline 0 %c/me %c\xff", RED, BLUE); tprintf(n->sock,"pline 0 Performs an action\xff"); if (game.command_move) { STRG[0]=0; switch(game.command_move) { case 2: /* Requires OP */ { sprintf(STRG,"%c(*)", TEAL); break; } case 3: /* Requires /OP */ { sprintf(STRG,"%c(!)", RED); break; } } tprintf(n->sock,"pline 0 %c/move %c \xff", RED, BLUE); tprintf(n->sock,"pline 0 %-4s %cMoves a player to a new playernumber\xff", STRG,BLACK); } if (game.command_msg) { STRG[0]=0; switch(game.command_msg) { case 2: /* Requires OP */ { sprintf(STRG,"%c(*)", TEAL); break; } case 3: /* Requires /OP */ { sprintf(STRG,"%c(!)", RED); break; } } tprintf(n->sock,"pline 0 %c/msg %c \xff", RED, BLUE); tprintf(n->sock,"pline 0 %-4s %cPrivately messages player(s)\xff", STRG,BLACK); } if (game.command_op) { tprintf(n->sock,"pline 0 %c/op %c\xff", RED, BLUE); tprintf(n->sock,"pline 0 Gain AUTHENTICATED OP status\xff"); } if (game.command_who) { STRG[0]=0; switch(game.command_who) { case 2: /* Requires OP */ { sprintf(STRG,"%c(*)", TEAL); break; } case 3: /* Requires /OP */ { sprintf(STRG,"%c(!)", RED); break; } } tprintf(n->sock,"pline 0 %c/who\xff", RED); tprintf(n->sock,"pline 0 %-4s %cLists all logged in players, and what channel they're on\xff", STRG, BLACK); } if (game.command_winlist) { STRG[0]=0; switch(game.command_winlist) { case 2: /* Requires OP */ { sprintf(STRG,"%c(*)", TEAL); break; } case 3: /* Requires /OP */ { sprintf(STRG,"%c(!)", RED); break; } } tprintf(n->sock,"pline 0 %c/winlist %c[n]\xff", RED, BLUE); tprintf(n->sock,"pline 0 %-4s %cDisplays the top n players\xff",STRG,BLACK); } } else tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED); } if (valid_param==1) { tprintf(n->sock,"pline 0 %cInvalid /COMMAND!\xff",RED); } } else { net_query_parser("msg %s %d %s #%s %s", n->nick, n->gameslot, n->host, n->channel->name, MSG); net_playback_send(n->channel->name, "pline %d %c%s\xff", n->gameslot, BLACK, MSG); nsock=n->channel->net; while (nsock!=NULL) { if ( (nsock!=n) && (nsock->type == NET_CONNECTED) ) { /* Write line, after first resetting it to black (incase colour still exists from nick) */ tprintf(nsock->sock,"pline %d %c%s\xff", n->gameslot, BLACK, MSG); } nsock=nsock->next; } } valid_param=1; } } /* Party Line Act - plineact */ if ( !strcasecmp(COMMAND, "plineact") ) { valid_param=2; s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG); if ( (s >= 2) && (num==n->gameslot)) { valid_param=1; net_query_parser("plineact %s %d %s #%s %s", n->nick, n->gameslot, n->host, n->channel->name, MSG); net_playback_send(n->channel->name, "plineact %d %s\xff", n->gameslot, MSG); nsock=n->channel->net; while (nsock!=NULL) { if ( (nsock!=n) && (nsock->type == NET_CONNECTED)) { /* Write out action, after first resetting colors */ tprintf(nsock->sock,"plineact %d %s\xff", n->gameslot, MSG); } nsock=nsock->next; } } } /* Change Team - team */ if ( !strcasecmp(COMMAND, "team") ) { valid_param=2; s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG); if ( (s >= 1) && (num==n->gameslot) && (n->status == STAT_NOTPLAYING)) { valid_param=1; /* If it is the same ignore this message */ if (!strncmp(n->team, MSG, TEAMLEN)) return; strncpy(n->team, MSG, TEAMLEN); n->team[TEAMLEN]=0; net_query_parser("team %s %d %s #%s %s", n->nick, n->gameslot, n->host, n->channel->name, n->team); net_playback_send(n->channel->name, "team %d %s\xff", n->gameslot, n->team); nsock=n->channel->net; while (nsock!=NULL) { if ( (n!=nsock) && (nsock->type == NET_CONNECTED) ) tprintf(nsock->sock,"team %d %s\xff", n->gameslot, MSG); nsock=nsock->next; } } } /* Pause Game - pause <0|1> */ if ( !strcasecmp(COMMAND, "pause") ) { valid_param=2; s = sscanf(PARAM, "%d %d", &num, &num2); if ( (s >= 2) && is_op(n) && (num2==n->gameslot) && (n->channel->status == STATE_PAUSED || n->channel->status == STATE_INGAME) && ( (num==0)||(num==1)) ) { if (num==1) { net_query_parser("pause %s %d %s #%s", n->nick, n->gameslot, n->host, n->channel->name); } else { net_query_parser("unpause %s %d %s #%s", n->nick, n->gameslot, n->host, n->channel->name); } net_playback_send(n->channel->name, "pause %d\xff", num); valid_param=1; nsock=n->channel->net; while(nsock!=NULL) { if (nsock->type == NET_CONNECTED) tprintf(nsock->sock,"pause %d\xff", num); nsock=nsock->next; } if (num==1) n->channel->status=STATE_PAUSED; else n->channel->status=STATE_INGAME; } } /* Game message - gmsg */ if ( !strcasecmp(COMMAND, "gmsg") ) { valid_param=1; n->timeout_outgame = game.timeout_outgame; /* If it's just "t", then reply PONG to player only*/ sprintf(MSG,"<%s> t", n->nick); if ( !strcmp(MSG, PARAM) && n->channel->pingintercept) { tprintf(n->sock,"gmsg * PONG\xff"); } else { /* FIRST, get the NICK, and strip out color codes. Else it looks horrible */ if (strlen(PARAM) < 5) return; if (PARAM[0] == '*') { P = strchr(PARAM + 2, ' '); sprintf(MSG, "* %s", n->nick); } else { P = strchr(PARAM, ' '); sprintf(MSG, "<%s>", n->nick); } if (!P) return; sprintf(STRG, "%s%s", MSG, P); strcpy(PARAM, STRG); j = strlen(PARAM); MSG[0]=0; P=MSG; for(i=0;ichannel->stripcolour && (PARAM[i] != BOLD) && (PARAM[i] != CYAN) && (PARAM[i] != BLACK) && (PARAM[i] != BLUE) && (PARAM[i] != DARKGRAY) && (PARAM[i] != MAGENTA) && (PARAM[i] != GREEN) && (PARAM[i] != NEON) && (PARAM[i] != SILVER) && (PARAM[i] != BROWN) && (PARAM[i] != NAVY) && (PARAM[i] != VIOLET) && (PARAM[i] != RED) && (PARAM[i] != ITALIC) && (PARAM[i] != TEAL) && (PARAM[i] != WHITE) && (PARAM[i] != YELLOW) && (PARAM[i] != UNDERLINE) && (PARAM[i] != 11) && (PARAM[i] != 127) ) { *P = PARAM[i]; P++; } } *P='\0'; net_query_parser("gmsg %s %d %s #%s %s", n->nick, n->gameslot, n->host, n->channel->name, MSG); net_playback_send(n->channel->name, "gmsg %s\xff", PARAM); nsock=n->channel->net; while (nsock!=NULL) { if ( (nsock->type == NET_CONNECTED) ) { tprintf(nsock->sock,"gmsg %s\xff", MSG); } nsock=nsock->next; } } } /* Player Lost - playerlost */ if ( !strcasecmp(COMMAND, "playerlost") ) { valid_param=2; s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG); if ( (s >= 1) && ( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) ) && (num==n->gameslot) ) { valid_param=1; /* Now, is this player actually playing? If not, we just ignore them */ if (n->status == STAT_PLAYING) { /* Set player to be "Lost" */ n->status = STAT_LOST; num2=0; /* Assume no-one left playing */ num3=0; /* Player who is still in */ MSG[0]=0; /* Store playing team name here */ /* Check if game is finished, and tell each person this player has lost */ net_playback_send(n->channel->name, "playerlost %d\xff", num); nsock=n->channel->net; ns1=NULL; while (nsock!=NULL) { if ( (nsock!=n) && (nsock->type == NET_CONNECTED) && (nsock->status == STAT_PLAYING)) { tprintf(nsock->sock,"playerlost %d\xff",num); if (strcasecmp(MSG,nsock->team)) { /* Different team, so add player */ num2++; ns1=nsock; strcpy(MSG,nsock->team); } else if (MSG[0]==0) { num2++; ns1=nsock; } num3++; } nsock=nsock->next; } if (ns1 == NULL) { /* This happens when we play alone */ n->channel->status=STATE_ONLINE; tprintf(n->sock, "endgame\xff"); net_playback_send(n->channel->name, "endgame\xff"); n->status=STAT_NOTPLAYING; return; } if ( (num2 <= 1) && (ns1!=NULL) ) { /* 1 or less different teams playing. Stop the game, and take score */ n->channel->status=STATE_ONLINE; nsock=n->channel->net; while (nsock!=NULL) { if ( (nsock->type == NET_CONNECTED)) { tprintf(nsock->sock,"endgame\xff"); tprintf(nsock->sock,"playerwon %d\xff", ns1->gameslot); nsock->status=STAT_NOTPLAYING; /* Send every playing field */ ns2=n->channel->net; while (ns2!=NULL) { if ( (ns2!=nsock) && (ns2->type == NET_CONNECTED)) sendfield(nsock,ns2); ns2=ns2->next; } } nsock=nsock->next; } net_playback_send(n->channel->name, "endgame\xff"); net_playback_send(n->channel->name, "playerwon %d\xff", ns1->gameslot); if (ns1->type == NET_CONNECTED) { char wteam[TEAMLEN+1], w2team[TEAMLEN+1]; char *p; strncpy(wteam, ns1->team, TEAMLEN); wteam[TEAMLEN] = '\0'; strncpy(w2team, n->team, TEAMLEN); w2team[TEAMLEN] = '\0'; p = strstr(wteam, "::"); if (p) *p = '\0'; p = strstr(w2team, "::"); if (p) *p = '\0'; if (!strcasecmp(n->channel->game_type , "nickonly")) { wteam[0] = '\0'; w2team[0] = '\0'; } if (strlen(wteam) > 0) { /* Team won, so add score to team */ if (n->channel->serverannounce) for(nsock=n->channel->net; nsock; nsock=nsock->next) if (nsock->type == NET_CONNECTED) tprintf(nsock->sock,"pline 0 ---- Team %s%c WON ----\xff", ns1->team, BLACK); net_playback_send(n->channel->name, "pline 0 ---- Team %s%c WON ----\xff", ns1->team, BLACK); if (n->channel->winlist_file != -1 ) { if (n->flood_players > 2) updatewinlist(wteam,'t',3,ns1); else updatewinlist(wteam,'t',2,ns1); net_query_parser("teamwon %s #%s", wteam, n->channel->name); } } else { /* Player won, so add score to player name */ if (n->channel->serverannounce && !ns1->teamup) for(nsock=n->channel->net; nsock; nsock=nsock->next) if (nsock->type == NET_CONNECTED) tprintf(nsock->sock,"pline 0 ---- Player %s%c WON ----\xff", ns1->nick, BLACK); net_playback_send(n->channel->name, "pline 0 ---- Player %s%c WON ----\xff", ns1->nick, BLACK); if (n->channel->winlist_file != -1 && !ns1->teamup) { if (ns1->flood_players > 2) updatewinlist(ns1->nick,'p',3,ns1); else updatewinlist(ns1->nick,'p',2,ns1); net_query_parser("playerwon %s #%s", ns1->nick, n->channel->name); } } if (n->flood_players > 4 && n->channel->winlist_file != -1) { if (strlen(w2team) > 0) updatewinlist(w2team, 't', 1, n); else if (!n->teamup) updatewinlist(n->nick, 'p', 1, n); } } writewinlist(n); sendwinlist_to_all(n); /* Send to all */ } } } } /* Field Update - f */ if ( !strcasecmp(COMMAND, "f") ) { valid_param=2; s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG); if ( (s >= 1) && (num==n->gameslot)) { net_playback_send(n->channel->name, "f %d %s\xff", n->gameslot, MSG); valid_param=1; /* First, transmit these changes as is to all other players */ nsock=n->channel->net; n->field_changes++; n->max_pieces_left++; /* Now parse it ourselves, and update our internal knowledge of players field */ if (parsefield(n, MSG) == -1) { tprintf(n->sock, "pline 0 %cBroken client detected. Attempt logged...\xff", RED); lvprintf(4, "Broken client from %s (%s)\n", n->nick, n->host); killsock(n->sock); lostnet(n); return; } while (nsock!=NULL) { if ( (nsock!=n) && (nsock->type == NET_CONNECTED)) tprintf(nsock->sock,"f %d %s\xff", n->gameslot, MSG); nsock=nsock->next; } } } /* Level - lvl */ if ( !strcasecmp(COMMAND, "lvl") ) { int mt; if (16 % n->channel->lines_per_level) mt = 16 / n->channel->lines_per_level + 1; else mt = 16 / n->channel->lines_per_level; valid_param=2; s = sscanf(PARAM, "%d %d", &num, &num2); if (num2 < 0 || (num2 - n->level < 0) || num2 > n->channel->starting_level + 150 || (num2 - n->level > mt * n->channel->level_increase)) { lvprintf(3, "(Possible Cheating) Impossible level update from %s (%s) | req msg: lvl %s | Channel: %s\n", n->nick, n->host, PARAM, n->channel->name); killsock(n->sock); lostnet(n); return; } if ( (n->channel->status==STATE_INGAME) && (num==n->gameslot) && (n->status == STAT_PLAYING) ) { valid_param=1; n->level = num2; net_playback_send(n->channel->name, "lvl %d %d\xff", n->gameslot, num2); nsock=n->channel->net; while (nsock!=NULL) { if ( (nsock->type == NET_CONNECTED)) tprintf(nsock->sock,"lvl %d %d\xff", n->gameslot,num2); nsock=nsock->next; } } } /* Special Block Use - sb */ if ( !strcasecmp(COMMAND, "sb") ) { int k = 0, l = 0; valid_param=2; s = sscanf(PARAM, "%d %s %d", &num, MSG, &num2); if (MSG[0] == 'c' && MSG[1] == 's') { l = atoi(&MSG[2]); n->lines_add_to_all += l; if (l == 1) k = 1; else if (l == 2) k = 2; else if (l == 4) k = 3; else if (n->channel->special_added == 0) { lvprintf(3, "(Probable Cheating) Impossible add_line_to_all from %s (%s) | req msg: %s | Channel: %s | Pieces: %d\n", n->nick, n->host, PARAM, n->channel->name, n->field_changes); killsock(n->sock); lostnet(n); return; } else return; n->max_pieces_left -= ((k+1) * 3); if (l == 4) n->tetris_made++; } else { /* someone is doing special on PURE */ if (n->channel->special_added == 0) { lvprintf(3, "(Obvious Cheating) Special block used on PURE from %s (%s) | req msg: %s | channel: %s\n", n->nick, n->host, PARAM, n->channel->name); killsock(n->sock); lostnet(n); return; } } if ( (s >= 3) && (n->channel->status == STATE_INGAME) && (n->status == STAT_PLAYING)) { valid_param=1; if (num2 != n->gameslot) { lvprintf(3, "(Obvious Cheating) Spoof special block message from %s (%s) | Slot: %d | req msg: %s | Channel: %s\n", n->nick, n->host, n->gameslot, PARAM, n->channel->name); killsock(n->sock); lostnet(n); return; } net_playback_send(n->channel->name, "sb %d %s %d\xff", num, MSG, n->gameslot); nsock=n->channel->net; while (nsock!=NULL) { if ( (nsock!=n) && (nsock->type == NET_CONNECTED) ) { tprintf(nsock->sock,"sb %d %s %d\xff", num, MSG, n->gameslot); } nsock=nsock->next; } } } /* Start/Stop Game - startgame <0/1, 0=stopgame> */ if (!strcasecmp(COMMAND, "startgame")) { int flood_players = 0; int flood_channels = 0; int top_players = 0; struct net_t *nsock2; char newgamestr[2048]; int newgameprinted = 0; valid_param=2; s = sscanf(PARAM, "%d %d %600[^\n\r]", &num, &num2, MSG); if ( (s >= 2) && is_op(n) && ( ((num==1) && (n->channel->status == STATE_ONLINE)) || ((num==0) && (n->channel->status == STATE_INGAME)) ||((num==0) && (n->channel->status == STATE_PAUSED))) && (num2==n->gameslot) && ( (num == 1) || (num == 0)) ) { valid_param=1; if (num==1) { n->channel->status = STATE_INGAME; net_query_parser("gamestart %s %d %s #%s", n->nick, n->gameslot, n->host, n->channel->name); } else { n->channel->status = STATE_ONLINE; n->channel->sd_mode=SD_NONE; net_query_parser("gamestop %s %d %s #%s", n->nick, n->gameslot, n->host, n->channel->name); net_playback_send(n->channel->name, "endgame\xff"); } /* Read in Game config and winlist, in case they were changed */ /* gameread();*/ /* readwinlist(); */ /* Set the SuddenDeath timeout, if any */ if (n->channel->sd_timeout>0) { n->channel->sd_mode=SD_INIT; n->channel->sd_timeleft=n->channel->sd_timeout; } nsock=n->channel->net; flood_players = numplayers(nsock->channel); for (chan = chanlist; chan; chan = chan->next) if (chan->status == STATE_INGAME || chan->status == STATE_PAUSED) flood_channels++; for (nsock = n->channel->net; nsock; nsock=nsock->next) nsock->teamup = 0; for (nsock = n->channel->net; nsock; nsock=nsock->next) { if (nsock->top_player == 1) top_players++; if (strlen(nsock->team) != 0) for (nsock2 = nsock->next; nsock2; nsock2=nsock2->next) { if (nsock!=nsock2 && !strcasecmp(nsock->team, nsock2->team)) { nsock->teamup = 1; nsock2->teamup = 1; } } } nsock=n->channel->net; while (nsock!=NULL) {/* Send to every player the game parameters */ if ( (nsock->type == NET_CONNECTED)) { if (num == 1) /* Start game */ { sprintf(newgamestr,"newgame 0 %d %d %d %d %d %d ", n->channel->starting_level, n->channel->lines_per_level, n->channel->level_increase, n->channel->lines_per_special, n->channel->special_added, n->channel->special_capacity); for(j=0;jchannel->block_leftl;j++) strcat(newgamestr,"3"); for(j=0;jchannel->block_leftz;j++) strcat(newgamestr,"5"); for(j=0;jchannel->block_square;j++) strcat(newgamestr, "2"); for(j=0;jchannel->block_rightl;j++) strcat(newgamestr, "4"); for(j=0;jchannel->block_rightz;j++) strcat(newgamestr, "6"); for(j=0;jchannel->block_halfcross;j++) strcat(newgamestr, "7"); for(j=0;jchannel->block_line;j++) strcat(newgamestr, "1"); strcat(newgamestr, " "); for(j=0;jchannel->special_addline;j++) strcat(newgamestr, "1"); for(j=0;jchannel->special_clearline;j++) strcat(newgamestr, "2"); for(j=0;jchannel->special_nukefield;j++) strcat(newgamestr, "3"); for(j=0;jchannel->special_randomclear;j++) strcat(newgamestr, "4"); for(j=0;jchannel->special_switchfield;j++) strcat(newgamestr,"5"); for(j=0;jchannel->special_clearspecial;j++) strcat(newgamestr,"6"); for(j=0;jchannel->special_gravity;j++) strcat(newgamestr, "7"); for(j=0;jchannel->special_quakefield;j++) strcat(newgamestr,"8"); for(j=0;jchannel->special_blockbomb;j++) strcat(newgamestr,"9"); sprintf(newgamestr ,"%s %d %d\xff", newgamestr, n->channel->average_levels, n->channel->classic_rules); tprintf(nsock->sock, "%s", newgamestr); if (!newgameprinted) { newgameprinted = 1; net_playback_send(n->channel->name,"%s", newgamestr); } /* And set them to be playing */ nsock->status = STAT_PLAYING; /* Update flood parameters */ nsock->flood_players = flood_players; nsock->flood_channels = flood_channels; nsock->lines_add_to_all = 0; nsock->tetris_made = 0; nsock->field_changes = 0; nsock->max_pieces_left = 0; nsock->level = nsock->channel->starting_level; /* BLANK *ALL* the fields and send them to each player */ /* Clear their Field */ for(y=0;yfield[x][y]=0; /* Nothing */ /* Send to every other player */ /* ns1=n->channel->net; while (ns1!=NULL) { if ( (ns1!=nsock) && (ns1->type==NET_CONNECTED) ) { sendfield(ns1,nsock); } ns1=ns1->next; } */ } else /* End Game */ { tprintf(nsock->sock,"endgame\xff"); /* And set them to not be playing */ nsock->status = STAT_NOTPLAYING; } } nsock=nsock->next; } } } /* Log invalid params */ if (valid_param==0) lvprintf(1,"#%s-%s - Invalid Command - %s\n", n->channel->name,n->nick, buf); } /* The player has sent their inital team name, well they should have anyway */ void net_waitingforteam(struct net_t *n, char *buf) { FILE *file_in; char strg[1024]; char *P; struct net_t *nsock; sprintf(strg,"team %d ",n->gameslot); if (strncmp(buf,strg,strlen(strg))) { /* Incorrect, Kill this player, they never existed ;) */ lvprintf(1,"Incorrect TEAM statement - %s!\n",buf); killsock(n->sock); lostnet(n); return; } P=buf+strlen(strg); n->status=STAT_NOTPLAYING; n->flood_players=0; n->flood_channels=0; n->wlist_cache = -1; n->authenticate = 0; n->field_changes = 0; n->max_pieces_left = 0; n->timeout_outgame = game.timeout_outgame; n->timeout_ingame = game.timeout_ingame; strncpy(n->team, P, TEAMLEN); n->team[TEAMLEN]='\0'; if (n->team[0] != 0 && !net_query_isvalidnick(n->team)) { lvprintf(4,"Invalid team name %s-%s\n",n->team,n->host); killsock(n->sock); lostnet(n); return; } if (is_banned(n)) { tprintf(n->sock,"noconnecting Your host is banned from this server.\xff"); killsock(n->sock); lostnet(n); return; } n->type=NET_CONNECTED; nsock=n->channel->net; net_query_parser("playerjoin %s %d %s #%s", n->nick, n->gameslot, n->host, n->channel->name); net_playback_send(n->channel->name, "playerjoin %d %s\xffteam %d %s\xff", n->gameslot, n->nick, n->gameslot, n->team); while (nsock!=NULL) { /* if ( (nsock != n) && (nsock->type==NET_CONNECTED)) */ if ((nsock->type==NET_CONNECTED)) { /* Send each other player and their team to this player */ if (n != nsock) tprintf(n->sock, "playerjoin %d %s\xffteam %d %s\xff", nsock->gameslot, nsock->nick, nsock->gameslot, nsock->team); /* Send to the other player, this player and their team */ tprintf(nsock->sock, "playerjoin %d %s\xffteam %d %s\xff", n->gameslot, n->nick, n->gameslot, n->team); } nsock=nsock->next; } tprintf(n->sock, "pline 0 %c%c%c%c%c%c%c%c\xff", BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK); /* Now for the game.motd if it exists. */ file_in = fopen(FILE_MOTD,"r"); if (file_in != NULL) {/* Exists, so send it to the player */ while (fgets(strg, 256, file_in) != NULL) { net_query_TrimStr(strg); tprintf(n->sock,"pline 0 %s\xff", strg); } fclose(file_in); } /* If game is in progress, send all other players fields */ /* Tell each other player that we are lost... no really :P */ if( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) ) { nsock=n->channel->net; while (nsock!=NULL) { if( (nsock->type==NET_CONNECTED) &&(nsock!=n) ) { /* Each player who has lost, send player_lost */ if (nsock->status != STAT_PLAYING) { tprintf(n->sock,"playerlost %d\xff", nsock->gameslot); } sendfield(n, nsock); /* Send to player, this players field */ /* And tell this player that the newjoined player has lost */ tprintf(nsock->sock,"playerlost %d\xff", n->gameslot); } nsock=nsock->next; } } /* If we are ingame, then tell this person that we are! */ if ( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) ) tprintf(n->sock,"ingame\xff"); /* If we are currently paused, kindly let them know that fact to */ if ( n->channel->status == STATE_PAUSED ) tprintf(n->sock,"pause 1\xff"); /* And tell them their channel */ tprintf(n->sock,"pline 0 %c%s%c %chas joined channel #%s\xff", GREEN,n->nick,BLACK,GREEN,n->channel->name); lvprintf(3,"%s(%s)(%s)\n", n->nick,n->ip,n->host); } /*------------------------- query section ------------------------------ */ int net_query_lostnet(struct net_t *n) { struct net_t *nn; if (n->type == NET_PLAYBACK_CONNECTED) { /* Playback */ nn = gnet; for (nn = gnet; nn; nn = nn->next) { if (nn->type == NET_PLAYBACK_CONNECTED && !strcasecmp(n->channel->name, nn->channel->name) && nn != n) { tprintf(nn->sock, "specleave %s\xff", n->nick); } } /* Query clients */ if (n->type == NET_PLAYBACK_CONNECTED) net_query_parser("specleave %s %d %s #%s", n->nick, 0, n->host, n->channel->name); } else if (n->type == NET_QUERY_CONNECTED) { nn = gnet; for (nn = gnet; nn; nn = nn->next) { if (nn->type == NET_QUERY_CONNECTED && nn != n) { tprintf(nn->sock, ":%s NOTICE %s :*** Signoff: %s (query@%s)\n", myhostname, nn->nick, n->nick, n->host); } } } nn = gnet; while (nn && nn->next != n) nn = nn->next; if (nn && (nn->next == n)) nn->next = n->next; free(n); return 1; } int net_query_playerquery(struct net_t *n, char *buf) { struct channel_t *chan; struct net_t *nsock; int total_user; lvprintf(9,"%s: Playerquery request\n",n->host); total_user = 0; chan = chanlist; while (chan) { nsock = chan->net; while (nsock) { if (nsock->gameslot >= 1 && nsock->gameslot <= 6) total_user++; nsock = nsock->next; } chan = chan->next; } tprintf(n->sock, "[Server_id: %d-%d] [Max_channels: %d] [Total_users: %d] [Curchan_users: %d]\n", getpid(), getppid(), game.maxchannels, total_user, numplayers(n->channel)); killsock(n->sock); net_query_lostnet(n); return 1; } int net_query_IPconvert(struct net_t *n, char *host) { unsigned char x1, x2, x3, x4; IP ip; ip = n->addr; x1 = (ip >> 24); x2 = (ip >> 16) & 0xff; x3 = (ip >> 8) & 0xff; x4 = (ip) & 0xff; if (n->host[0] == 0 || strlen(n->host) >= UHOSTLEN) sprintf(host, "%d.%d.%d.%d",x1,x2,x3,x4); else strcpy(host, n->host); return 1; } /* Trim weird useless chars at the end */ int net_query_TrimStr(char *p) { int len; if (!p) return 0; /* P is NULL */ if (p[0] == '\0') return 1; for (len = strlen(p)-1; len >= 0; len--) { if (p[len] == '\n' || p[len] == 13 || p[len] == ' ') p[len] = '\0'; else break; } return 1; } /* Strip Control characters (warning: direct change to orig str) */ int net_query_StripCtrlStr2(char *p) { char *q, *r; if (!p) return 0; r = p; for (q = r; *r != '\0'; r++) if (*r >= 32) *(q++) = *r; *q = '\0'; if (p[0] == '\0') strcpy(p, "unknown"); return 1; } int net_query_StripCtrlStr(char *p) { char *q, *r; if (!p) return 0; r = p; for (q = r; *r != '\0'; r++) if ((*r >= 'A' && *r <= '}') || (*r == '_') || (*r == '-') || (*r == '~') || (*r >= '0' && *r <= '9')) *(q++) = *r; *q = '\0'; if (p[0] == '\0') strcpy(p, "unknown"); return 1; } int net_query_isvalidnick(char *p) { char *r; int valid=0; if (!p) return 1; if (*p == '\0') return 0; for (r = p; *r != '\0'; r++) { if (*r == ' ' || *r == '\xff' || *r == 10 || *r == 13) { valid = 0; break; } if (*r > 32 || *r < 0) valid = 1; } return(valid); } int net_query_ChanStatStr(int status, char *statstr) { if (status == STATE_OFFLINE) strcpy(statstr, "Offline"); else if (status == STATE_ONLINE) strcpy(statstr, "Not in game"); else if (status == STATE_INGAME) strcpy(statstr, "In game"); else if (status == STATE_PAUSED) strcpy(statstr, "Paused"); else strcpy(statstr, "N/A"); return 1; } /* USER COMMAND */ int net_query_user(struct net_t *n, char *buf) { tprintf(n->sock, "NOTICE AUTH :To Log in, type \"/QUOTE pass server_password\"\n"); return 1; } int net_query_nickfound(char *nick, struct net_t *n) { struct net_t *nn; struct channel_t *chan; if (!nick) return 0; for (chan = chanlist; chan; chan = chan->next) for (nn = chan->net; nn; nn = nn->next) if (nn != n && (nn->type == NET_CONNECTED || nn->type == NET_WAITINGFORTEAM) && !strcasecmp(nick, nn->nick)) return 1; for (nn = gnet; nn; nn = nn->next) if (nn != n && (nn->type == NET_QUERY_CONNECTED || nn->type == NET_PLAYBACK_CONNECTED || nn->type == NET_PLAYBACK_INIT || nn->type == NET_QUERY_INIT) && !strcasecmp(nick, nn->nick)) return 1; return 0; } /* NICK COMMAND */ int net_query_nick(struct net_t *n, char *buf) { char *p; p = strtok(buf, " "); p = strtok(NULL, " "); net_query_TrimStr(p); if (p && (p[0] != '\0')) { if (p[0] == ':') p++; if (!net_query_nickfound(p, n)) { strncpy(n->nick, p, NICKLEN); n->nick[NICKLEN] = 0; } else tprintf(n->sock, ":%s 433 * %s :Nickname is already in use.\n", myhostname, p); } else n->nick[0] = '\0'; return 1; } /* This looks scary mmm */ /* MOTD */ int net_query_cmotd(struct net_t *n, char *buf) { FILE *file_in; char strg[1024]; file_in = fopen(FILE_MOTD,"r"); if (file_in != NULL) { while (fgets(strg, 512, file_in) != NULL) { net_query_TrimStr(strg); tprintf(n->sock,":%s 372 %s :%s\n", myhostname, n->nick, strg); } tprintf(n->sock,":%s 376 %s :End of /MOTD command\n", myhostname, n->nick); fclose(file_in); } return 1; } /* STATS w(winlist) p(operlist) k(banlist) */ int net_query_cstats(struct net_t *n, char *buf) { /* int i; */ char *p; struct net_t *nn; p = strtok (buf, " "); p = strtok (NULL, " "); if (p) { if (p[0] == 'w' || p[0] == 'W') { /* Winlist - Returns Winlist */ /* tprintf(n->sock,"NOTICE AUTH :Nickname Type Score\n"); for(i=0;isock,"NOTICE AUTH :%-17s %c %lu\n", winlist[i].name,winlist[i].status,winlist[i].score); } tprintf(n->sock,"NOTICE AUTH :End of WinList.\n"); */ } else if (p[0] == 'o' || p[0] == 'O' || p[0] == 'p') { /* Oper list */ tprintf(n->sock, "NOTICE AUTH :Current server operators: "); for (nn = gnet; nn; nn = nn->next) if (nn->type == NET_QUERY_CONNECTED) tprintf(n->sock, "%s ", nn->nick); tprintf(n->sock, "\n"); } else if (p[0] == 'k' || p[0] == 'K' || p[0] == 'b') { /* Ban list */ FILE *file_in; char cbuf[256]; file_in = fopen(FILE_BAN,"r"); if (file_in) { while (fgets(cbuf, sizeof(cbuf)-1, file_in) != NULL) tprintf(n->sock, "NOTICE AUTH :%s", cbuf); fclose(file_in); } tprintf(n->sock, "NOTICE AUTH :End of ban list\n"); } else tprintf(n->sock, "NOTICE AUTH :Invalid Stats request\n"); } return 1; } /* Check /quote pass password print welcome messages */ int net_query_authenticate(struct net_t *n, char *buf) { char *p; char strg[10]; time_t tm; struct net_t *nn; p = strtok(buf, " "); p = strtok(NULL, " "); if (!net_query_TrimStr(p)) { killsock(n->sock); net_query_lostnet(n); return 1; } if (n->nick[0] == '\0') strcpy(n->nick, "unknown"); if (securityread() < 0) securitywrite(); if ((strlen(security.query_password) <= 0) || strcmp(p, security.query_password)) { tprintf(n->sock, "NOTICE AUTH :authentication failed... disconnecting\n", myhostname, n->nick); tprintf(n->sock, "NOTICE AUTH :Type \"/server serverhost %d\" to reconnect\n", QUERY_PORT); killsock(n->sock); net_query_lostnet(n); return 1; } n->type = NET_QUERY_CONNECTED; n->securitylevel = LEVEL_AUTHOP; time(&tm); tprintf(n->sock, ":%s 001 %s :Welcome to Tetrinet Relay Network %s\n", myhostname, n->nick, n->nick); tprintf(n->sock, ":%s 002 %s :Your host is %s, running version 2.8\n", myhostname, n->nick, myhostname); tprintf(n->sock, ":%s 003 %s :Server time is %s\n", myhostname, n->nick, ctime(&tm)); tprintf(n->sock, ":%s 004 %s %s bundaberg tetrinet server w/ slummy irc connection\n", myhostname, n->nick, myhostname); /* Now for the game.motd if it exists. */ strcpy(strg, "motd"); net_query_cmotd(n, strg); tprintf(n->sock,"NOTICE AUTH :For HELP type \"/QUOTE help\"\n"); for (nn = gnet; nn; nn = nn->next) if (nn->type == NET_QUERY_CONNECTED) tprintf(nn->sock, ":%s NOTICE %s :*** Notice -- %s (query@%s) is now a server operator(O)\n", myhostname, nn->nick, n->nick, n->host); tprintf(n->sock, ":%s MODE %s :+owszyd\n", n->nick, n->nick); tprintf(n->sock, ":%s 381 %s :You have entered... the Twilight Zone!.\n", myhostname, n->nick); strcpy(strg, "stats p"); net_query_cstats(n, strg); return 1; } /* PONG */ int net_query_cping(struct net_t *n, char *buf) { /* char *p; p = strtok(buf, " "); p = strtok(NULL , ""); if (p) tprintf(n->sock, ":%s PONG %s %s\n", myhostname, n->host, p); */ return 1; } /* LIST */ int net_query_clist(struct net_t *n, char *buf) { struct channel_t *chan; char chan_status[40]; int nusers, nchans; nusers = 0; nchans = 0; tprintf(n->sock, "NOTICE AUTH :#Channel Users Pri Status Topic\n"); for (chan = chanlist; chan; chan = chan->next) { net_query_ChanStatStr(chan->status, chan_status); tprintf(n->sock, "NOTICE AUTH :#%-15s %-2d %-3d %-12s %s\n", chan->name, numplayers(chan), chan->priority, chan_status, chan->description); nusers += numplayers(chan); nchans ++; } tprintf(n->sock, "NOTICE AUTH :Total: %d users in %d channels\n", nusers, nchans); tprintf(n->sock,":%s 323 %s :End of /LIST\n", myhostname, n->nick); return 1; } int net_query_cslist(struct net_t *n, char *buf) { struct net_t *nn; int i; tprintf(n->sock, "NOTICE AUTH :Spectator List\n"); i = 0; for (nn=gnet; nn; nn = nn->next) if (nn->type == NET_PLAYBACK_CONNECTED) tprintf(n->sock, "NOTICE AUTH :#%d: #%-20s %s\n", ++i, nn->channel->name, nn->nick); tprintf(n->sock,":%s 323 %s :End of /SLIST\n", myhostname, n->nick); return 1; } /* WHOIS */ int net_query_cwhois(struct net_t *n, char *buf) { struct channel_t *chan; struct net_t *nsock; int idle, argc, found; char nick[NICKLEN+1], host[UHOSTLEN+1], team[TEAMLEN+1]; char *p; argc = 0; found = 0; p = strtok(buf, " "); p = strtok(NULL, " "); net_query_TrimStr(p); if (!p || (p && p[0] =='\0')) { tprintf(n->sock, ":%s 431 %s :No nickname given\n", myhostname, n->nick); return -1; } /* strcpy(nick, p); */ chan = chanlist; for (chan = chanlist; chan; chan = chan->next) { for (nsock = chan->net; nsock; nsock = nsock->next) { strcpy(nick, nsock->nick); net_query_StripCtrlStr(nick); if (nsock->type == NET_CONNECTED || nsock->type == NET_WAITINGFORTEAM) { if (nsock->gameslot < 1 || nsock->gameslot > 6 || strcasecmp(nick, p)) continue; else { net_query_IPconvert(nsock, host); if (nsock->status == STAT_PLAYING) idle = game.timeout_ingame - nsock->timeout_ingame; else idle = game.timeout_outgame - nsock->timeout_outgame; if (strlen (nsock->team) == 0) strcpy(team, "No team"); else strcpy(team, nsock->team); tprintf(n->sock, ":%s 311 %s %s slot%d %s * :%s\n", myhostname, n->nick, nick, nsock->gameslot , host, team); if (nsock->securitylevel == LEVEL_AUTHOP) tprintf(n->sock, ":%s 319 %s %s :@#%s\n", myhostname, n->nick, nick, nsock->channel->name); else tprintf(n->sock, ":%s 319 %s %s :#%s\n", myhostname, n->nick, nick, nsock->channel->name); tprintf(n->sock, ":%s 312 %s %s %s :Tetrinet Server\n", myhostname, n->nick, nick, myhostname); tprintf(n->sock, ":%s 317 %s %s %d :seconds idle\n", myhostname, n->nick, nick, idle); tprintf(n->sock, ":%s 318 %s %s :End of /WHOIS list.\n", myhostname, n->nick, nick); found = 1; break; } } } } /* Check for query clients */ for (nsock = gnet; nsock; nsock = nsock->next) { if ((nsock->type == NET_QUERY_CONNECTED || nsock->type == NET_PLAYBACK_CONNECTED) && !strcasecmp(nsock->nick, p)) { net_query_IPconvert(nsock, host); if (nsock->type == NET_QUERY_CONNECTED) tprintf(n->sock, ":%s 311 %s %s query %s * :query client\n", myhostname, n->nick, nsock->nick, host); else tprintf(n->sock, ":%s 311 %s %s spectator %s * :spectator client\n", myhostname, n->nick, nsock->nick, host); if (strlen(nsock->channel->name)) tprintf(n->sock, ":%s 319 %s %s :@#%s\n", myhostname, n->nick, nsock->nick, nsock->channel->name); tprintf(n->sock, ":%s 312 %s %s %s :Tetrinet Server\n", myhostname, n->nick, nsock->nick, myhostname); if (nsock->type == NET_QUERY_CONNECTED) tprintf(n->sock, ":%s 313 %s %s :is an IRC Janitor (IRC Operator)\n", myhostname, n->nick, nsock->nick); tprintf(n->sock, ":%s 318 %s %s :End of /WHOIS list.\n", myhostname, n->nick, nsock->nick); found = 1; break; } } if (!found) { tprintf(n->sock, ":%s 401 %s %s :No such nick/channel\n", myhostname, n->nick, p); tprintf(n->sock, ":%s 318 %s %s :End of /WHOIS list.\n", myhostname, n->nick, p); } return 1; } /* WHO and NAMES */ /* still looks ugly... need surgery */ int net_query_cwho(struct net_t *n, char *buf) { char *pstats[7], chan_status[40]; char *p; struct channel_t *chan; struct net_t *nsock; int argc, plen, i, cmdnum, found, nusers, nchans, done; char nick[NICKLEN+1], host[UHOSTLEN+1], team[TEAMLEN+1]; cmdnum = 315; argc = 0; found = 0; nusers = 0; nchans = 0; done = 0; p = strtok(buf, " "); if (!strncasecmp(p, "names", 5)) cmdnum = 366; argc++; p = strtok(NULL, " "); net_query_TrimStr(p); if (p && p[0] != 0) argc++; if (argc == 2 && p[0] == '#') p++; net_query_TrimStr(p); for (chan = chanlist; chan; chan = chan->next, nchans++) { net_query_ChanStatStr(chan->status, chan_status); nsock = chan->net; if (argc==2 && !strcasecmp(p, chan->name) && cmdnum == 315) { tprintf(n->sock, "NOTICE AUTH :#%s Users: %-2d Priority: %-2d State: %s\n", chan->name, numplayers(chan), chan->priority, chan_status); for (i = 1; i <= 6; i++) { plen = NICKLEN + TEAMLEN + 512; pstats[i] = (char *)malloc(plen); sprintf(pstats[i], "empty"); } while (nsock) { strcpy(nick, nsock->nick); net_query_StripCtrlStr(nick); if (nsock->type == NET_CONNECTED) { if (nsock->gameslot < 1 || nsock->gameslot > 6) { killsock(n->sock); net_query_lostnet(n); return -1; } net_query_IPconvert(nsock, host); if (strlen (nsock->team) == 0) strcpy(team, "No team"); else strcpy(team, nsock->team); if (nsock->securitylevel != LEVEL_AUTHOP) sprintf(pstats[nsock->gameslot], ":%s 352 %s #%s slot%d %s %s %s H * :%s\n", myhostname, n->nick, nsock->channel->name, nsock->gameslot, host, myhostname, nick, team); else sprintf(pstats[nsock->gameslot], ":%s 352 %s #%s slot%d %s %s %s H@ * :%s\n", myhostname, n->nick, nsock->channel->name, nsock->gameslot, host, myhostname, nick, team); found = 1; } nsock = nsock->next; } for (i = 1; i <= 6; i++) { if (strcmp(pstats[i], "empty")) tprintf(n->sock, "%s\n", pstats[i]); free(pstats[i]); } } else if (argc == 1 || cmdnum == 366) { /* NAMES */ if (argc == 2 && strcasecmp(chan->name,p)) continue; tprintf(n->sock, ":%s 353 %s = #%s :", myhostname, n->nick, chan->name); done = 1; while (nsock) { strcpy(nick, nsock->nick); net_query_StripCtrlStr(nick); if (nsock->type == NET_CONNECTED || nsock->type == NET_WAITINGFORTEAM ) { if (nsock->securitylevel == LEVEL_AUTHOP) tprintf(n->sock, "@%s ", nick); else tprintf(n->sock, "%s ", nick); nusers++; } nsock = nsock->next; } if (argc == 1) tprintf(n->sock, "\n"); } } if (argc == 2 && cmdnum == 315) { /* check for query operator */ for (nsock = gnet; nsock; nsock = nsock->next) { if (nsock->channel->name[0] == '\0') continue; if (nsock->type == NET_QUERY_CONNECTED && !strcasecmp(nsock->channel->name, p)) { net_query_IPconvert(nsock, host); strcpy(nick, nsock->nick); net_query_StripCtrlStr(nick); tprintf(n->sock, ":%s 352 %s #%s query %s %s %s H*@ * :query client\n", myhostname, n->nick, nsock->channel->name, host, myhostname, nick); } } } if (argc == 2 && cmdnum == 366) { if (!done) tprintf(n->sock, ":%s 353 %s = #%s :", myhostname, n->nick, p); for (nsock = gnet; nsock; nsock = nsock->next) { strcpy(nick, nsock->nick); net_query_StripCtrlStr(nick); if (strlen(nsock->channel->name) == 0) continue; if (nsock->type == NET_QUERY_CONNECTED && !strcasecmp(nsock->channel->name, p)) { tprintf(n->sock, "@%s ", nick); } } tprintf(n->sock, "\n"); } if (argc == 1 && cmdnum != 315) tprintf(n->sock, "NOTICE AUTH :Total: %d users in %d channels\n", nusers, nchans); if (argc != 1 && cmdnum == 315) { if (p) tprintf(n->sock,":%s 315 %s #%s :End of /WHO list.\n", myhostname, n->nick, p); else tprintf(n->sock,":%s 315 %s * :End of /WHO list.\n", myhostname, n->nick); } else tprintf(n->sock,":%s 366 %s * :End of /NAMES list.\n", myhostname, n->nick); return 1; } /* 2nd time and after NICK */ int net_query_cnick(struct net_t *n, char *buf) { char *p; p = strtok(buf, " "); p = strtok(NULL, " "); net_query_TrimStr(p); if (p && (p[0] != '\0')) { if (p[0] == ':') p++; if (!net_query_nickfound(p, n)) { tprintf(n->sock, ":%s!query@%s NICK :%s\n", n->nick, n->host, p); strncpy(n->nick, p, NICKLEN); n->nick[NICKLEN] = 0; } else tprintf(n->sock, ":%s 433 * %s :Nickname is already in use.\n", myhostname, p); } else tprintf(n->sock, ":%s 431 %s :No nickname given\n", myhostname, n->nick); return 1; } /* TOPIC */ int net_query_ctopic(struct net_t *n, char *buf) { char *p; struct channel_t *chan; p = strtok(buf, " "); p = strtok(NULL, " "); if (p) { if (p[0] == '#') p++; else return -1; net_query_TrimStr(p); for (chan = chanlist; chan; chan = chan->next) if (!strcasecmp(chan->name, p)) break; if (!chan) { tprintf(n->sock, ":%s 442 %s #%s :Not a gameplay channel\n", myhostname, n->nick, p); return -1; } p = strtok(NULL, ""); net_query_TrimStr(p); if (!p || (p && p[0] == '\0')) { if (chan->description[0] != '\0') { tprintf(n->sock, ":%s 332 %s #%s :%s\n", myhostname, n->nick, chan->name, chan->description); tprintf(n->sock, ":%s 333 %s #%s server 0\n", myhostname, n->nick, chan->name); } else tprintf(n->sock, ":%s 331 %s #%s :No topic is set\n", myhostname, n->nick, chan->name, chan->description); return 1; } if (p[0] == ':') p++; strncpy(chan->description, p, DESCRIPTIONLEN); chan->description[DESCRIPTIONLEN] = 0; net_query_parser("topic %s 0 %s #%s %s", n->nick, n->host, chan->name, p); } else tprintf(n->sock, ":%s 461 %s TOPIC :Not enough parameters", myhostname, n->nick); return 1; } /* JOIN */ int net_query_cjoin(struct net_t *n, char *buf) { char *p; char whocmd[128]; struct channel_t *chan; p = strtok(buf, " "); p = strtok(NULL, " "); net_query_TrimStr(p); if (!p) return -1; if (p[0] == '#') p++; if (p[0] == '\0') return -1; if (!is_valid_channelname(p)) { tprintf(n->sock, "NOTICE AUTH :Invalid channel name!\n"); return -1; } chan = chanlist; while ((chan != NULL) && (strcasecmp(chan->name, p))) chan=chan->next; if (chan == NULL) { tprintf(n->sock, "NOTICE AUTH :The channel you request does not exist\n"); return -1; } if (n->channel->name[0] == '\0' || strcasecmp(n->channel->name, p)) { if (n->channel->name[0] != 0) tprintf(n->sock, ":%s!query@%s PART :#%s\n", n->nick, n->host, n->channel->name); tprintf(n->sock, ":%s!query@%s JOIN :#%s\n", n->nick, n->host, p); strncpy(n->channel->name, p, CHANLEN-1); sprintf(whocmd, "names #%s\n", n->channel->name); net_query_cwho(n, whocmd); } return 1; } /* PART */ int net_query_cpart(struct net_t *n, char *buf) { char *p; p = strtok(buf, " "); p = strtok(NULL, " "); net_query_TrimStr(p); if (!p) return -1; if (p[0] == '#') p++; if (p[0] == '\0') return -1; if (!strcasecmp(n->channel->name, p)) { tprintf(n->sock, ":%s!query@%s PART :#%s\n", n->nick, n->host, p); n->channel->name[0] = '\0'; } return 1; } /* KILL */ int net_query_ckill(struct net_t *n, char *buf) { char *p; char nick[NICKLEN + 1]; struct channel_t *chan; struct net_t *nn, *nnn; p = strtok(buf, " "); p = strtok(NULL, " "); net_query_TrimStr(p); if (!p || (p && p[0] == '\0')) { tprintf(n->sock, ":%s 461 %s KILL :Not enough parameters\n", myhostname, n->nick); return -1; } for (chan = chanlist; chan; chan = chan->next) { nn = chan->net; for (nn = chan->net; nn; nn = nn->next) { strcpy(nick, nn->nick); net_query_StripCtrlStr(nick); if (!strcasecmp(nick, p)) { for (nnn = gnet; nnn; nnn = nnn->next) if (nnn->type == NET_QUERY_CONNECTED) tprintf(nnn->sock, "NOTICE AUTH :*** Notice -- killed %s (requested by %s)\n", nn->nick, n->nick); killsock(nn->sock); lostnet(nn); return 1; } } } for (nn = gnet; nn; nn = nn->next) { if (!strcasecmp(nn->nick, p) && nn->type == NET_PLAYBACK_CONNECTED) { for (nnn = gnet; nnn; nnn = nnn->next) if (nnn->type == NET_QUERY_CONNECTED) tprintf(nnn->sock, "NOTICE AUTH :*** Notice -- killed %s (requested by %s)\n", nn->nick, n->nick); if (!strcasecmp(nn->nick, p)) { killsock(nn->sock); net_query_lostnet(nn); return 1; } } } tprintf(n->sock, ":%s 401 %s %s :No such nick\n", myhostname, n->nick, p); return 1; } int net_query_ckick(struct net_t *n, char *buf) { char *p; struct channel_t *chan; char chan_name[80]; struct net_t *nn, *nnn; int slot; p = strtok(buf, " "); p = strtok(NULL, " "); if (p) { if (p[0] == '#') p++; if(p[0] != '\0') strncpy(chan_name, p, CHANLEN-1); } p = strtok(NULL, " "); net_query_TrimStr(p); if (!p || (p && p[0] == '\0')) { tprintf(n->sock, ":%s 461 %s KICK :Not enough parameters\n", myhostname, n->nick); return -1; } if (strlen(p) > 4) p+=4; /* strip the text "slot" if any */ slot = atoi(p); if (slot >= 1 && slot <= 6) { for (chan = chanlist; chan; chan = chan->next) { if (!strcasecmp(chan->name, chan_name)) { for (nn = chan->net; nn; nn = nn->next) { if (nn->gameslot == slot && (nn->type == NET_CONNECTED || nn->type == NET_WAITINGFORTEAM)) { if (strlen(n->host) == 0) strcpy(n->host, "unknown"); /* tprintf(n->sock, ":%s!query@%s KICK #%s slot%d :...\n",n->nick, n->host, chan_name, slot, slot); */ for (nnn = gnet; nnn; nnn = nnn->next) if (nnn->type == NET_QUERY_CONNECTED) tprintf(nnn->sock, "NOTICE AUTH :*** Notice -- killed %s (requested by %s)\n", nn->nick, n->nick); killsock(nn->sock); lostnet(nn); return 1; } } } } if (!chan) tprintf(n->sock, ":%s 403 %s #%s :No such channel\n", myhostname, n->nick, chan_name); } else { tprintf(n->sock, "NOTICE AUTH :Invalid slot number.\n"); tprintf(n->sock, "NOTICE AUTH :Usage: kick #channel slot\n"); } return 1; } int net_query_cprivmsg(struct net_t *n, char *buf) { struct channel_t *chan; struct net_t *nn; char *p; p = strtok(buf, " "); p = strtok(NULL, " "); if (p) { if (p[0] != '#') { /* privmsg to a nick */ /* Check for query clients */ for (nn = gnet; nn; nn = nn->next) { if ((!strcasecmp(nn->nick, p) && (nn->type == NET_QUERY_CONNECTED || nn->type == NET_PLAYBACK_CONNECTED)) || nn->type == NET_CONNECTED) { p = strtok (NULL, ""); if (!p) return -1; if (p[0] == ':') p++; net_query_TrimStr(p); if (nn->type == NET_QUERY_CONNECTED) tprintf(nn->sock, ":%s!query@%s PRIVMSG %s :%s\n", n->nick, n->host, nn->nick, p); else if (nn->type == NET_PLAYBACK_CONNECTED) tprintf(nn->sock, "pline 0 <*%s*> %s\xff", n->nick, p); else tprintf(nn->sock, "pline 0 <*%s*> %s\xff", n->nick, p); break; } } if (!nn) tprintf(n->sock, "NOTICE AUTH :Only private message to query/spectator/tetrinet clients is implemented.\n"); return -1; } /* else if it's channel name #channel */ p++; if (p[0] == '\0') return -1; /* can this happen? */ for (chan = chanlist; chan; chan = chan->next) if (!strcasecmp(chan->name, p)) break; if (chan) { p = strtok (NULL, ""); if (!p) return -1; if (p[0] == ':') p++; net_query_TrimStr(p); for (nn = chan->net; nn; nn = nn->next) if (nn->type == NET_CONNECTED) tprintf(nn->sock, "pline 0 %c%c{ %c%s%c } %c%s\xff", DARKGRAY, BOLD, UNDERLINE, n->nick, UNDERLINE, BOLD, p); for (nn = gnet; nn; nn = nn->next) if (nn != n && nn->type == NET_QUERY_CONNECTED) tprintf(nn->sock, ":%s!query@%s PRIVMSG #%s :%s\n", n->nick, n->host, chan->name, p); else if (nn != n && nn->type == NET_PLAYBACK_CONNECTED && !strcasecmp(n->channel->name, nn->channel->name)) tprintf(nn->sock, "pline 0 %c%c{ %c%s%c } %c%s\xff", DARKGRAY, BOLD, UNDERLINE, n->nick, UNDERLINE, BOLD, p); } else tprintf(n->sock, ":%s 401 %s %s :No such gameplay channel\n", myhostname, n->nick, p); } return 1; } int net_query_cwall(struct net_t *n, char *buf) { struct net_t *nn; struct channel_t *chan; char *p; p = strtok(buf, " "); p = strtok(NULL, ""); if (!p) return -1; net_query_TrimStr(p); for (chan = chanlist; chan; chan = chan->next) for (nn = chan->net; nn; nn = nn->next) if (nn->type == NET_CONNECTED) { tprintf(nn->sock, "pline 0 %c\xff", RED); tprintf(nn->sock, "pline 0 %c%c ***** SERVER BROADCAST MESSAGE FROM: %c%s\xff", RED, BOLD, BLUE, n->nick); tprintf(nn->sock, "pline 0 %c%c ***** %s\xff" , RED, BOLD, p); tprintf(nn->sock, "pline 0 %c\xff", RED); } for (nn = gnet; nn; nn = nn->next) if (nn->type == NET_QUERY_CONNECTED) tprintf(nn->sock, "NOTICE AUTH: Broadcast message from %c: %s\n", RED, n->nick, p); return 1; } /* /quote OP or DEOP */ int net_query_copdeop(struct net_t *n, char *buf) { struct net_t *nn; struct channel_t *chan; int op; char *p; op = 0; p = strtok (buf, " "); if (!strcasecmp(buf, "op")) op = 1; p = strtok (NULL, " "); if (p) { if (p[0] != '#') { tprintf(n->sock, "NOTICE AUTH :First parameter must be a gameplay channel\n"); return -1; } p++; for (chan = chanlist; chan; chan = chan->next) if (!strcasecmp(chan->name, p)) break; if (!chan) { tprintf(n->sock, "NOTICE AUTH :Invalid (gameplay) channel #%s\n",p); return -1; } p = strtok (NULL, " "); if (!p) { tprintf(n->sock, "NOTICE AUTH :Usage: /quote op|deop #channel slot\n"); return -1; } for (nn = chan->net; nn; nn = nn->next) if (nn->gameslot == atoi(p)) break; if (nn) { if (op) { nn->securitylevel = LEVEL_AUTHOP; net_query_parser ("op %s %d %s #%s %s", nn->nick, nn->gameslot, nn->host, nn->channel->name, n->nick); tprintf(nn->sock, "pline 0 %cYou are now a server operator (requested by %s)\xff", BLACK, n->nick); } else if (nn->securitylevel == LEVEL_AUTHOP) { nn->securitylevel = LEVEL_NORMAL; net_query_parser ("deop %s %d %s #%s %s", nn->nick, nn->gameslot, nn->host, nn->channel->name, n->nick); tprintf(nn->sock, "pline 0 %cYou are now a normal user (requested by %s)\xff", BLACK, n->nick); } } else { tprintf(n->sock, "NOTICE AUTH :Invalid slot number %s\n", p); tprintf(n->sock, "NOTICE AUTH :Usage: /quote op|deop #channel slot\n"); return -1; } } return 1; } int net_query_cmove(struct net_t *n, char *buf) { char pbuf[1280]; struct channel_t *chan; if (strlen(buf) > 12) buf[12] = '\0'; sprintf(pbuf, "pline 0 /%s", buf); if (strlen(n->channel->name) == 0) return -1; for (chan = chanlist; chan; chan = chan->next) if (!strcasecmp(chan->name, n->channel->name)) break; if (chan) /* This is scary *sigh* :P I will not do it anymore */ if (chan->net) { if (chan->status != STATE_ONLINE) { tprintf(n->sock, "NOTICE AUTH :You cannot move when game is in play\n"); return -1; } n->gameslot = 0; n->channel->status = STATE_ONLINE; strcpy(n->channel->name, chan->name); n->channel->net = chan->net; /* this is so lame :P */ net_connected (n, pbuf); } return 1; } /* /quote SET */ int net_query_cset(struct net_t *n, char *buf) { char *p, *q; struct channel_t *chan; p = strtok(buf, " "); if (n->channel->name[0] == '\0') { tprintf(n->sock, "NOTICE AUTH :You must be in a gameplay channel to use this command\n"); return -1; } for (chan = chanlist; chan; chan=chan->next) if (!strcasecmp(chan->name, n->channel->name)) break; if (!chan) { tprintf(n->sock, "NOTICE AUTH :You must be in a gameplay channel to use this command\n"); return -1; } p = strtok(NULL, " "); if (!p || p[0] < 48) { tprintf(n->sock, "NOTICE AUTH :Current basic setting for #%s\n", n->channel->name); tprintf(n->sock, "NOTICE AUTH :starting_level [%2d]\n", chan->starting_level); tprintf(n->sock, "NOTICE AUTH :lines_per_special [%2d]\n", chan->lines_per_special); tprintf(n->sock, "NOTICE AUTH :special_added [%2d]\n", chan->special_added); tprintf(n->sock, "NOTICE AUTH :classic_rules [%2d]\n", chan->classic_rules); tprintf(n->sock, "NOTICE AUTH :sd_timeout [%2d]\n", chan->sd_timeout); tprintf(n->sock, "NOTICE AUTH :sd_lines_per_add [%2d]\n", chan->sd_lines_per_add); tprintf(n->sock, "NOTICE AUTH :sd_secs_between_lines [%2d]\n", chan->sd_secs_between_lines); tprintf(n->sock, "NOTICE AUTH :priority [%2d]\n", chan->priority); tprintf(n->sock, "NOTICE AUTH :maxplayers [%2d]\n", chan->maxplayers); tprintf(n->sock, "NOTICE AUTH :End of basic settings, type /quote set varname value to set new value\n"); } else { q = strtok(NULL, " "); net_query_TrimStr(q); if (!q || (q && q[0] == '\0')) return -1; if (!strcasecmp(p, "starting_level")) chan->starting_level = atoi(q); else if (!strcasecmp(p, "lines_per_special")) { if (atoi(q) <= 0) { tprintf(n->sock, "NOTICE AUTH :Must be positive integer\n"); return -1; } else chan->lines_per_special = atoi(q); } else if (!strcasecmp(p, "special_added")) chan->special_added = atoi(q); else if (!strcasecmp(p, "classic_rules")) chan->classic_rules = atoi(q); else if (!strcasecmp(p, "sd_timeout")) chan->sd_timeout = atoi(q); else if (!strcasecmp(p, "sd_lines_per_add")) chan->sd_lines_per_add = atoi(q); else if (!strcasecmp(p, "sd_secs_between_lines")) chan->sd_secs_between_lines = atoi(q); else if (!strcasecmp(p, "priority")) chan->priority = atoi(q); else if (!strcasecmp(p, "maxplayers")) { if (atoi(q) <= 0 || atoi(q) > 6) { tprintf(n->sock, "NOTICE AUTH :Must be integer (1,2,3..6)\n"); return -1; } else chan->maxplayers = atoi(q); } else { tprintf(n->sock , "NOTICE AUTH :Invalid varname %s\n", p); return -1; } tprintf(n->sock , "NOTICE AUTH :%s is now %d\n", p, atoi(q)); } return 1; } /* REHASH */ int net_query_crehash(struct net_t *n, char *buf) { struct net_t *nn; gameread(); for (nn = gnet; nn; nn = nn->next) { if (nn->type == NET_QUERY_CONNECTED) tprintf(nn->sock, ":%s NOTICE %s :*** Notice -- %s is rehashing Server config file while whistling innocently\n", myhostname, nn->nick, n->nick); } return 1; } /* READWINLIST */ int net_query_creadwinlist(struct net_t *n, char *buf) { readwinlist(FILE_WINLIST, winlist, MAXWINLIST); readwinlist(FILE_WINLIST2, winlist2, MAXWINLIST); return 1; } int net_query_creadaccesslist(struct net_t *n, char *buf) { struct net_t *nn; init_banlist(banlist, MAXBAN); init_banlist(combanlist, MAXBAN); init_allowlist(allowlist, MAXALLOW); read_banlist(FILE_BAN, banlist, MAXBAN); read_banlist(FILE_BAN_COMPROMISE, combanlist, MAXBAN); read_allowlist(); for (nn = gnet; nn; nn = nn->next) { if (nn->type == NET_QUERY_CONNECTED) tprintf(nn->sock, ":%s NOTICE %s :*** Notice -- %s is rehashing server access list while whistling innocently\n", myhostname, nn->nick, n->nick); } return 1; } /* /quote HELP */ int net_query_chelp(struct net_t *n, char *buf) { tprintf(n->sock, "NOTICE AUTH :Basic commands\n"); tprintf(n->sock, "NOTICE AUTH :-------------------------------------------------------\n"); tprintf(n->sock, "NOTICE AUTH :/list or /quote list\n"); tprintf(n->sock, "NOTICE AUTH :/who #channel\n"); tprintf(n->sock, "NOTICE AUTH :/whois nickname\n"); tprintf(n->sock, "NOTICE AUTH :/names or /quote names\n"); tprintf(n->sock, "NOTICE AUTH :/kill nickname\n"); tprintf(n->sock, "NOTICE AUTH :/kick #channel slotnumber\n"); tprintf(n->sock, "NOTICE AUTH :/join #channel /part #channel\n"); tprintf(n->sock, "NOTICE AUTH :/quote move slot1 slot2\n"); tprintf(n->sock, "NOTICE AUTH :/quote op #channel slotnumber\n"); tprintf(n->sock, "NOTICE AUTH :/quote deop #channel slotnumber\n"); tprintf(n->sock, "NOTICE AUTH :/quote wall or /quote broadcast\n"); tprintf(n->sock, "NOTICE AUTH :/quote set or /quote set varname value\n"); tprintf(n->sock, "NOTICE AUTH :/stats w for winlist\n"); tprintf(n->sock, "NOTICE AUTH :/stats p for server operator\n"); tprintf(n->sock, "NOTICE AUTH :/stats k for kline/ban list\n"); tprintf(n->sock, "NOTICE AUTH :/rehash or /quote reset\n"); tprintf(n->sock, "NOTICE AUTH :This is not a real irc server. Weirdness is expected!\n"); tprintf(n->sock, "NOTICE AUTH :Report bug to drslum@tetrinet.org\n"); return 1; } /* MODE (not completed) just to keep client alive */ int net_query_cmode(struct net_t *n, char *buf) { char *p, *q, *r; p = strtok(buf, " "); p = strtok(NULL, ""); if (!p) return -1; net_query_TrimStr(p); if (p[0] != '#') tprintf(n->sock, ":%s MODE %s\n", n->nick, p); else { q = strtok(p, " "); r = strtok(NULL, ""); if (!r) { tprintf(n->sock, ":%s 324 %s %s +\n", myhostname, n->nick, q); tprintf(n->sock, ":%s 329 %s %s 0\n", myhostname, n->nick, q); } else if (r[0] == 'b') tprintf(n->sock, ":%s 368 %s %s :End of Channel Ban List\n", myhostname, n->nick, q); } return 1; } /* USERHOST (bitchx, mirc)*/ int net_query_cuserhost(struct net_t *n, char *buf) { char *p; p = strtok(buf, " "); p = strtok(NULL, " "); net_query_TrimStr(p); if (!p || p[0] == '\0') return -1; tprintf(n->sock, ":%s 302 %s :%s=+query@%s\n", myhostname, n->nick, p, myhostname); return 1; } /* QUIT */ int net_query_cquit(struct net_t *n, char *buf) { close(n->sock); killsock(n->sock); net_query_lostnet(n); return 1; } /* ISON (dummy) */ int net_query_cison(struct net_t *n, char *buf) { tprintf(n->sock, ":%s 303 %s :%s\n", myhostname, n->nick, n->nick); return 1; } int net_query_cunsupported(struct net_t *n, char *buf) { char *p; p = strtok(buf, " "); if (!p) return -1; if (p[0] == '\0') return 1; /* tprintf(n->sock,":%s 421 %s %s :Unsupported Command\n", myhostname, n->nick, p); */ return 1; } void net_query_connected(struct net_t *n, char *buf) { if (!buf) return; if (strlen(buf) <= 2) return; if (!strncasecmp(buf, "list", 4)) net_query_clist(n, buf); if (!strncasecmp(buf, "slist", 5)) net_query_cslist(n, buf); else if (!strncasecmp(buf, "whowas", 6)) net_query_cunsupported(n, buf); else if (!strncasecmp(buf, "whois", 5)) net_query_cwhois(n, buf); else if (!strncasecmp(buf, "who", 3)) net_query_cwho(n, buf); else if (!strncasecmp(buf, "nick", 4)) net_query_cnick(n, buf); else if (!strncasecmp(buf, "join", 4)) net_query_cjoin(n, buf); else if (!strncasecmp(buf, "part", 4)) net_query_cpart(n, buf); else if (!strncasecmp(buf, "kick", 4)) net_query_ckick(n, buf); else if (!strncasecmp(buf, "kill", 4)) net_query_ckill(n, buf); else if (!strncasecmp(buf, "names", 5)) net_query_cwho(n, buf); else if (!strncasecmp(buf, "privmsg", 7)) net_query_cprivmsg(n,buf); else if (!strncasecmp(buf, "wall", 4)) net_query_cwall(n,buf); else if (!strncasecmp(buf, "broadcast", 9)) net_query_cwall(n,buf); else if (!strncasecmp(buf, "userhost", 8)) net_query_cuserhost(n,buf); else if (!strncasecmp(buf, "ison", 4)) net_query_cison(n,buf); else if (!strncasecmp(buf, "motd", 4)) net_query_cmotd(n,buf); else if (!strncasecmp(buf, "ping", 4)) net_query_cping(n,buf); else if (!strncasecmp(buf, "mode", 4)) net_query_cmode(n,buf); else if (!strncasecmp(buf, "help", 4)) net_query_chelp(n,buf); else if (!strncasecmp(buf, "stats", 5)) net_query_cstats(n,buf); else if (!strncasecmp(buf, "move", 4)) net_query_cmove(n,buf); else if (!strncasecmp(buf, "set", 3) || !strncasecmp(buf, "tset", 4)) net_query_cset(n,buf); else if (!strncasecmp(buf, "topic", 5)) net_query_ctopic(n,buf); else if (!strncasecmp(buf, "op", 2)) net_query_copdeop(n,buf); else if (!strncasecmp(buf, "deop", 4)) net_query_copdeop(n,buf); else if (!strncasecmp(buf, "rehash", 6)) net_query_crehash(n,buf); else if (!strncasecmp(buf, "reset", 5)) net_query_crehash(n,buf); else if (!strncasecmp(buf, "readwinlist", 11)) net_query_creadwinlist(n,buf); else if (!strncasecmp(buf, "readaccesslist", 14)) net_query_creadaccesslist(n,buf); else if (!strncasecmp(buf, "away", 4)) {} else if (!strncasecmp(buf, "quit", 4)) net_query_cquit(n,buf); else net_query_cunsupported(n, buf); } /* Recieving Query commands */ void net_query_init(struct net_t *n, char *buf) { if (!strncasecmp(buf, "pass", 4)) net_query_authenticate(n, buf); else if (!strncasecmp(buf, "nick", 4)) { net_query_nick(n, buf); } else if (!strncasecmp(buf, "user", 4)) net_query_user(n, buf); else { killsock(n->sock); net_query_lostnet(n); } } /* Someone has just connected. So lets answer them */ void net_query(struct net_t *n, char *buf) { IP ip; /* unsigned char x1, x2, x3, x4; */ struct net_t *net; net=malloc(sizeof(struct net_t)); net->next=NULL; net->sock=answer(n->sock,&ip,0); while ((net->sock==(-1)) && (errno==EAGAIN)) net->sock=answer(n->sock,&ip,0); setopt(net->sock, 0); net->addr=ip; net->port=n->port; net->securitylevel=LEVEL_NORMAL; net->status=STAT_NOTPLAYING; net->channel = malloc(sizeof(struct channel_t)); net->channel->name[0] = '\0'; strcpy(net->nick, "(telnet)"); do_async_dns(net); net->type = NET_WAITINGFORDNS; } void net_query_donedns (struct net_t *net) { struct net_t *nn; if(net->sock <0) { killsock(net->sock); free(net); return; } setsock(net->sock, 0); net->type=NET_QUERY_INIT; /* add to gnet ;) */ nn=gnet; while(nn->next) nn=nn->next; if (nn) nn->next = net; } void net_query_parser(char *format, ...) { char *token[60]; /* max 60 words */ int i, j; static char BUF[1024], M[2048]; char nick[NICKLEN+1], msg[1024]; struct net_t *nn; if (format) { va_list args; va_start (args, format); vsnprintf(BUF, 1023, format, args); va_end(args); } else return; i = 0; token[0]=strtok(BUF," "); while(i < 59 && (token[++i]=strtok(NULL, " "))); token[i]=NULL; if(token[0]) { /* token[1] should be nickname */ if (token[1]) { strncpy(nick, token[1], NICKLEN); nick[NICKLEN] = 0; net_query_StripCtrlStr(nick); } if (!strcasecmp(token[0], "msg")) { msg[0] = '\0'; for (j = 5; j < i; j++) { strcat(msg, token[j]); strcat(msg, " "); } net_query_StripCtrlStr2(msg); net_query_TrimStr(msg); sprintf(M, ":%s!slot%s@%s PRIVMSG %s :%s\n", nick, token[2], token[3], token[4], msg); } else if (!strcasecmp(token[0], "gmsg")) { msg[0] = '\0'; for (j = 5; j < i; j++) { strcat (msg, token[j]); strcat(msg, " "); } net_query_StripCtrlStr2(msg); net_query_TrimStr(msg); sprintf(M, "NOTICE AUTH :(%s:gameplay) <%s> %s\n", token[4], nick, msg); } else if (!strcasecmp(token[0], "topic")) { msg[0] = '\0'; for (j = 5; j < i; j++) { strcat (msg, token[j]); strcat(msg, " "); } net_query_StripCtrlStr2(msg); net_query_TrimStr(msg); sprintf(M, ":%s!slot%s@%s TOPIC %s :%s\n", nick, token[2], token[3], token[4], msg); } else if (!strcasecmp(token[0], "plineact")) { msg[0] = '\0'; for (j = 5; j < i; j++) { strcat (msg, token[j]); strcat(msg, " "); } net_query_StripCtrlStr2(msg); net_query_TrimStr(msg); sprintf(M, ":%s!slot%s@%s PRIVMSG %s :\001ACTION %s\001\n", nick, token[2], token[3], token[4], token[5]); } else if (!strcasecmp(token[0], "playerleave")) sprintf(M, ":%s!slot%s@%s PART :%s\n", nick, token[2], token[3], token[4]); else if (!strcasecmp(token[0], "specleave")) sprintf(M, ":%s!spectator@%s PART :%s\n", nick, token[3], token[4]); else if (!strcasecmp(token[0], "playerjoin")) sprintf(M, ":%s!slot%s@%s JOIN :%s\n", nick, token[2], token[3], token[4]); else if (!strcasecmp(token[0], "specjoin")) sprintf(M, ":%s!spectator@%s JOIN :%s\n", nick, token[3], token[4]); else if (!strcasecmp(token[0], "timeout")) sprintf(M, "NOTICE AUTH :%s Idle time limit exceed for %s.\n", token[4], nick); else if (!strcasecmp(token[0], "team") && token[5]) sprintf(M, "NOTICE AUTH :*** %s %s changes team name to %s\n", token[4], nick, token[5]); else if (!strcasecmp(token[0], "pause") || !strcasecmp(token[0], "unpause")) sprintf(M, "NOTICE AUTH :%s %s %ss the game.\n", token[4], nick, token[0]); else if (!strcasecmp(token[0], "newchan")) sprintf(M, "NOTICE AUTH :New channel %s created by %s\n", token[4], nick); else if (!strcasecmp(token[0], "op")) sprintf(M, "NOTICE AUTH :%s %s is now a channel operator (requested by %s)\n", token[4], nick, token[5]); else if (!strcasecmp(token[0], "deop")) sprintf(M, "NOTICE AUTH :%s %s is now a normal user (requested by %s)\n", token[4], nick, token[5]); else if (!strcasecmp(token[0], "kick")) sprintf(M, "NOTICE AUTH :%s %s has been kicked.\n", token[4], nick); else if (!strcasecmp(token[0], "move")) sprintf(M, "NOTICE AUTH :%s %s swapped with %s.\n", token[3], nick, token[2]); else if (!strcasecmp(token[0], "gamestart")) sprintf(M, "NOTICE AUTH :%s %s started the game.\n", token[4], nick); else if (!strcasecmp(token[0], "gamestop")) sprintf(M, "NOTICE AUTH :%s %s stopped the game.\n", token[4], nick); else if (!strcasecmp(token[0], "teamwon")) sprintf(M, "NOTICE AUTH :%s Game ended. Team %s won.\n", token[2], nick); else if (!strcasecmp(token[0], "playerwon")) sprintf(M, "NOTICE AUTH :%s Game ended. Player %s won.\n", token[2], nick); else return; } for (nn = gnet; nn; nn = nn->next) if (nn->type == NET_QUERY_CONNECTED) tputs(nn->sock, M); } /*------------------------ End of query section -------------------------- */ int net_playback_isvalidnick(char *p) { char *r; int valid=1; if (!p) return 1; if (isdigit(*p)) return 0; if (!strcasecmp(p, "server")) return 0; for (r = p; *r; r++) { if ( (*r >= '0' && *r <= '9') || (*r >= 'A' && *r <= 'Z') || (*r >= 'a' && *r <= 'z') || (*r == '_' || *r == '-') || (*r == '[' || *r ==']') ) continue; valid = 0; break; } return(valid); } /* Someone has just connected. So lets answer them */ void net_playback(struct net_t *n, char *buf) { IP ip; /* unsigned char x1, x2, x3, x4; */ struct net_t *net; net=malloc(sizeof(struct net_t)); net->next=NULL; net->sock=answer(n->sock,&ip,0); while ((net->sock==(-1)) && (errno==EAGAIN)) net->sock=answer(n->sock,&ip,0); setopt(net->sock, 0); net->addr=ip; net->port=n->port; net->securitylevel=LEVEL_NORMAL; net->status=STAT_NOTPLAYING; net->channel = malloc(sizeof(struct channel_t)); net->channel->name[0] = '\0'; net->gameslot = 1; strcpy(net->nick, "(telnet)"); do_async_dns(net); net->type = NET_WAITINGFORDNS; } void net_playback_donedns(struct net_t *net) { struct net_t *nn; if(net->sock <0) { killsock(net->sock); free(net); return; } setsock(net->sock, 0); net->type=NET_PLAYBACK_INIT; /* add to gnet ;) */ nn=gnet; while(nn->next) nn=nn->next; if (nn) nn->next = net; /* Is this person banned? */ if (is_explicit_banned(net)) { tprintf(net->sock,"noconnecting Your host is banned from this server.\xff"); killsock(net->sock); free(net); return; } } /* The person has sent their init string */ void net_playback_init(struct net_t *n, char *buf) { int i; int tet_err; char *dec, *p; char strg[1024]; char *P; FILE *file_in; struct net_t *nn; sprintf(strg,"team 1 "); if (!strncmp(buf,strg,strlen(strg))) { if (!n->authenticate) return; P=buf+strlen(strg); net_query_TrimStr(P); strncpy(n->team, P, TEAMLEN); n->team[TEAMLEN]='\0'; if (securityread() < 0) securitywrite(); if ((strlen(security.spec_password) <= 0) || strcmp(n->team, security.spec_password)) { tprintf(n->sock, "noconnecting Unauthorized access! Attempt logged.\xff"); killsock(n->sock); net_query_lostnet(n); return; } n->type = NET_PLAYBACK_CONNECTED; tprintf(n->sock, "pline 0 %c%c%c%c%c%c%c%c\xff", BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK); file_in = fopen(FILE_PMOTD,"r"); if (file_in != NULL) { while (fgets(strg, 512, file_in) != NULL) { net_query_TrimStr(strg); tprintf(n->sock,"pline 0 %s\xff", strg); } fclose(file_in); } strcpy(n->channel->name, DEFAULTSPECCHANNEL); sendwinlist(n); /* Send spectator list */ tprintf(n->sock, "speclist #%s", n->channel->name); for (nn = gnet; nn; nn = nn->next) if (nn->type == NET_PLAYBACK_CONNECTED && !strcasecmp(nn->channel->name, n->channel->name)) { tprintf(n->sock, " "); tprintf(n->sock, "%s", nn->nick); if (nn != n) tprintf(nn->sock, "specjoin %s\xff", n->nick); } tprintf(n->sock, "\xff"); /* Notify query clients */ net_query_parser("specjoin %s %d %s #%s", n->nick, 0, n->host, n->channel->name); lvprintf(3, "Incoming spectator connection: %s(%s)(%s)\n", n->nick, n->ip, n->host); return; } if (strlen(buf) < 7) {/* Invalid... quit */ killsock(n->sock); net_query_lostnet(n); return; } tet_err = tet_decrypt(buf); if (tet_err != 0) { /* Error */ killsock(n->sock); net_query_lostnet(n); return; } dec = tet_dec2str(buf); /* This is used instead of sscanf to get more control tetrisstart message with the bound check according to NICKLEN and VERLEN. */ i = 0; if ((p = strtok(dec, " "))) { i++; if (strcmp(p, "tetrisstart")) { killsock(n->sock); net_query_lostnet(n); return; } if ((p = strtok(NULL, " "))) { i++; if (strlen(p) > NICKLEN) { tprintf(n->sock, "noconnecting Invalid Sign-on (nickname too long)\xff"); killsock(n->sock); net_query_lostnet(n); return; } strncpy(n->nick, p, NICKLEN); n->nick[NICKLEN] = 0; if ((p = strtok(NULL, " "))) { strncpy(n->version, p, VERLEN); n->version[VERLEN] = 0; i++; } } } if (i != 3) { killsock(n->sock); net_query_lostnet(n); return; } // /* OK, so dec should now hold "tetrisstart */ // i = sscanf(dec,"tetrisstart %30[^\x20] %10s", n->nick, n->version); // if (i < 2) // {/* To few conversions - Player dies*/ // killsock(n->sock); net_query_lostnet(n); // return; // } n->team[0] = 0; /* Clear Team */ if (!net_playback_isvalidnick(n->nick)) { tprintf(n->sock, "noconnecting Nickname not allowed!\xff"); killsock(n->sock); net_query_lostnet(n); return; } if (net_query_nickfound(n->nick, n)) { tprintf(n->sock, "noconnecting Nickname already exists on server!\xff"); killsock(n->sock); net_query_lostnet(n); return; } // sendwinlist(n); /* Send them their player number */ tprintf(n->sock, "playernum 1\xff"); n->authenticate = 1; } /* Experimental */ void net_playback_connected(struct net_t *n, char *buf) { struct net_t *nsock, *nn, *nnn; struct channel_t *ochan, *chan; int i, s, num; char COMMAND[101], PARAM[601], MSG[601]; char tmpbuf[1024], *p; COMMAND[0]=0;PARAM[0]=0;MSG[0]=0; if (!buf) return; if (strlen(buf) <= 2) return; /* Ensure command is proper before passing it to other players */ sscanf(buf, "%100s %600[^\n\r]", COMMAND, PARAM); /* Party Line Message - pline */ if ( !strcasecmp(COMMAND, "pline") ) { s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG); if (s < 2) return; if (MSG[0]=='/') { if ( !strcasecmp(MSG, "/join") || !strcasecmp(MSG, "/j") || !strcasecmp(MSG, "/ip") || !strcasecmp(MSG, "/m") || !strcasecmp(MSG, "/msg") || !strcasecmp(MSG, "/move") || !strcasecmp(MSG, "/kick") || !strcasecmp(MSG, "//") || !strcasecmp(MSG, "/view") || !strcasecmp(MSG, "/p")) { strcat(MSG, " "); } if (!strncasecmp (MSG, "/join ", 6) || !strncasecmp (MSG, "/j ", 3)) { int off; if ( !strncasecmp(MSG,"/join ", 6) ) off = 0; else off = -3; /* Check syntax first */ if (buf[14+off] != '#') { tprintf(n->sock, "pline 0 %cUsage: /join #channel\xff", RED); return; } if (!strcasecmp(n->channel->name, &buf[15+off])) { tprintf(n->sock, "pline 0 %cYou are already in that channel!\xff", RED); return; } chan = chanlist; while ((chan != NULL) && (strcasecmp(chan->name, &buf[15+off]))) chan=chan->next; if (!chan && strcasecmp(DEFAULTSPECCHANNEL, &buf[15+off])) { if (strlen(buf) > 15+off) tprintf(n->sock, "pline 0 %cInvalid channel: #%s\xff", RED, &buf[15+off]); return; } /* send playerleave (old chan) */ ochan = chanlist; while ( (ochan != NULL) && (strcasecmp(ochan->name, n->channel->name) )) ochan=ochan->next; if (ochan) { for (nsock = ochan->net; nsock; nsock = nsock->next) if (nsock->type == NET_CONNECTED && nsock->gameslot >= 1 && nsock->gameslot <= 6) tprintf(n->sock, "playerleave %d\xff", nsock->gameslot); } /* send playerjoin (new chan) */ if (strcasecmp(DEFAULTSPECCHANNEL, &buf[15+off])) { if (chan->status == STATE_INGAME) tprintf(n->sock, "ingame\xff"); nsock = chan->net; for (nsock = chan->net; nsock; nsock = nsock->next) { if (nsock->type == NET_CONNECTED && nsock->gameslot >= 1 && nsock->gameslot <= 6) { tprintf(n->sock, "playerjoin %d %s\xffteam %d %s\xff", nsock->gameslot, nsock->nick, nsock->gameslot, nsock->team); sendfield(n, nsock); } } } /* send specleave (old chan) */ nn = gnet; for (nn = gnet; nn; nn = nn->next) { if (nn->type == NET_PLAYBACK_CONNECTED && !strcasecmp(n->channel->name,nn->channel->name) && nn != n) { tprintf(nn->sock, "specleave %s\xff", n->nick); tprintf(nn->sock, "pline 0 %cSpectator %s joined #%s\xff", BLUE, n->nick, &buf[15]); } } /* Query clients */ net_query_parser("specleave %s %d %s #%s", n->nick, 0, n->host, n->channel->name); strcpy(n->channel->name, &buf[15+off]); sendwinlist(n); /* Send spectator list */ tprintf(n->sock, "speclist #%s", n->channel->name); for (nn = gnet; nn; nn = nn->next) if (nn->type == NET_PLAYBACK_CONNECTED && !strcasecmp(nn->channel->name, n->channel->name)) { tprintf(n->sock, " "); tprintf(n->sock, "%s", nn->nick); if (nn != n) tprintf(nn->sock, "specjoin %s\xff", n->nick); } tprintf(n->sock, "\xff"); /* Notify query clients */ net_query_parser("specjoin %s %d %s #%s", n->nick, 0, n->host, n->channel->name); } else if (!strncasecmp (MSG, "/slist", 6) || !strncasecmp (MSG, "/specwho", 8)) { i = 0; tprintf(n->sock,"pline 0 %cSpectator List\xff",NAVY); for (nn = gnet; nn; nn = nn->next) if (nn->type == NET_PLAYBACK_CONNECTED) tprintf(n->sock, "pline 0 %c%d: #%-20s %s\xff", BLUE, ++i, nn->channel->name, nn->nick); } else if (!strncasecmp (MSG, "/qlist", 6)) { if (n->securitylevel != LEVEL_AUTHOP) { tprintf(n->sock, "pline 0 %cYou don't have enough access\xff", RED); return; } i = 0; tprintf(n->sock, "pline 0 %cGlobal Operators: %c", BLUE, DARKGRAY); for (nn = gnet; nn; nn = nn->next) if (nn->type == NET_QUERY_CONNECTED) tprintf(n->sock, "%s ", nn->nick); tprintf(n->sock, "\xff"); } /* Time limit so... */ else if (!strncasecmp (MSG, "/list", 5)) { net_connected (n, "pline 0 /list\xff"); } else if (!strncasecmp (MSG, "/who", 4)) { net_connected (n, "pline 0 /who\xff"); } else if (!strncasecmp (MSG, "/view ", 6)) { i = atoi(&MSG[6]); if (i >= 1 && i <= 6) tprintf(n->sock, "playernum %d\xff", i); } else if (!strncasecmp (MSG, "/op ", 4)) { sprintf(tmpbuf, "pline 0 %s", MSG); net_connected (n, tmpbuf); } else if (!strncasecmp (MSG, "/kick ", 6)) { if (n->securitylevel != LEVEL_AUTHOP) { tprintf(n->sock, "pline 0 %cYou don't have enough access\xff", RED); return; } i = atoi(&MSG[6]); if (i < 1 || i > 6) return; for (chan = chanlist; chan; chan = chan->next) if (!strcasecmp(chan->name, n->channel->name)) break; nnn = NULL; if (chan) { for (nn = chan->net; nn; nn = nn->next) { if (nn->type == NET_CONNECTED) { tprintf(nn->sock, "kick %d\xff", i); if (nn->gameslot == i) nnn = nn; } } } else { tprintf(n->sock, "pline 0 %cInvalid gameplay channel: #%s\xff", RED, n->channel->name); return; } if (!nnn) { tprintf(n->sock, "pline 0 %cgameslot %d does not exist in #%s!\xff", RED, i, n->channel->name); return; } for (nn = gnet; nn; nn = nn->next) if (nn->type == NET_QUERY_CONNECTED) tprintf(nn->sock, "NOTICE AUTH :*** Notice -- %s kicked (requested by %s)\n", nnn->nick, n->nick); else if (nn->type == NET_PLAYBACK_CONNECTED && !strcasecmp(nn->channel->name, n->channel->name)) tprintf(nn->sock, "kick %d\xff", nnn->gameslot); killsock(nnn->sock); lostnet(nnn); } else if (!strncasecmp (MSG, "/move ", 6)) { if (n->securitylevel != LEVEL_AUTHOP) { tprintf(n->sock, "pline 0 %cYou don't have enough access\xff", RED); return; } for (chan = chanlist; chan; chan = chan->next) if (!strcasecmp(chan->name, n->channel->name)) break; if (chan) if (chan->net) { if (chan->status != STATE_ONLINE) { tprintf(n->sock, "pline 0 %cYou cannot move when game is in play\xff", RED); return; } n->gameslot = 0; n->channel->status = STATE_ONLINE; strcpy(n->channel->name, chan->name); n->channel->net = chan->net; sprintf(tmpbuf, "pline 0 %s", MSG); net_connected (n, tmpbuf); } } else if (!strncasecmp (MSG, "/p ", 3) || !strncasecmp (MSG, "// ", 3)) { if (n->securitylevel != LEVEL_AUTHOP) { tprintf(n->sock, "pline 0 %cYou don't have enough access\xff", RED); return; } for (chan = chanlist; chan; chan = chan->next) if (!strcasecmp(chan->name, n->channel->name)) break; /* no comment */ if (chan) { tprintf(n->sock, "pline 0 %c%c<%s> %s\xff", BOLD, BLACK, n->nick, &MSG[3]); sprintf(tmpbuf, "PRIVMSG #%s :%s", chan->name, &MSG[3]); net_query_cprivmsg(n, tmpbuf); } } else if (!strncasecmp (MSG, "/m ", 3) || !strncasecmp (MSG, "/msg ", 5)) { char nick[NICKLEN+1]; p = strtok(MSG, " "); p = strtok(NULL, " "); if (p && p[0] != 0) { strncpy(nick, p, NICKLEN); nick[NICKLEN] = '\0'; p = strtok(NULL, ""); if (!p) { tprintf(n->sock, "pline 0 %cUsage: /m nick message\xff", RED); return; } sprintf(tmpbuf, "PRIVMSG %s :%s", nick, p); net_query_cprivmsg(n, tmpbuf); } else tprintf(n->sock, "pline 0 %cUsage: /m nick message\xff", RED); } else if (!strncasecmp (MSG, "/ip ", 4)) { if (n->securitylevel != LEVEL_AUTHOP) { tprintf(n->sock, "pline 0 %cYou do not have enough access\xff", RED); return; } for (chan = chanlist; chan; chan = chan->next) if (!strcasecmp(chan->name, n->channel->name)) break; /* no comment */ if (chan) { for (i = 4; MSG[i] != 0; i++) { for (nn = chan->net; nn; nn = nn->next) if (nn->type == NET_CONNECTED && MSG[i] == nn->gameslot + '0') { tprintf(n->sock, "pline 0 %c%d: %-20s [%s]\xff", RED, nn->gameslot, nn->nick, nn->host); break; } } } else tprintf(n->sock, "pline 0 %cInvalid channel / slotnumbers\xff", RED); } else if ( !strncasecmp(MSG, "/--version", 9)) { tprintf(n->sock,"pline 0 %c%s.%s\xff", WHITE, TETVERSION, SERVERBUILD); } else if ( !strncasecmp(MSG, "/help", 5)) { tprintf(n->sock,"pline 0 %cBuilt in spectator commands\xff", NAVY); tprintf(n->sock,"pline 0 %c[1] %c/join %c[#channel]\xff", BROWN, RED, BLUE); tprintf(n->sock,"pline 0 %c Join a game play channel\xff", GREEN); tprintf(n->sock,"pline 0 %c[2] %c/list\xff", BROWN, RED, BROWN); tprintf(n->sock,"pline 0 %c List available gameplay channels\xff", GREEN); tprintf(n->sock,"pline 0 %c[3] %c/slist or /specwho\xff", BROWN, RED); tprintf(n->sock,"pline 0 %c List spectators\xff", GREEN); tprintf(n->sock,"pline 0 %c[4] %c/qlist\xff", BROWN, RED); tprintf(n->sock,"pline 0 %c List irc clients\xff", GREEN); tprintf(n->sock,"pline 0 %c[5] %c/who\xff", BROWN, RED); tprintf(n->sock,"pline 0 %c List all playernick / channel\xff", GREEN); tprintf(n->sock,"pline 0 %c[6] %c/op %c[op_password]\xff", BROWN, RED, BLUE); tprintf(n->sock,"pline 0 %c Gain operator priviledge\xff", GREEN); tprintf(n->sock,"pline 0 %c[7] %c/ip %c[slot(s)]\xff", BROWN, RED, BLUE); tprintf(n->sock,"pline 0 %c An oper command to list player IPs\xff", GREEN); tprintf(n->sock,"pline 0 %c[8] %c/kick %c[slot]\xff", BROWN, RED, BLUE); tprintf(n->sock,"pline 0 %c An oper command to kick a player\xff", GREEN); tprintf(n->sock,"pline 0 %c[9] %c/move %c[slot1] [slot2]\xff", BROWN, RED, BLUE); tprintf(n->sock,"pline 0 %c An oper command to move players\xff", GREEN); tprintf(n->sock,"pline 0 %c[10] %c/p or // %c[message]\xff", BROWN, RED, BLUE); tprintf(n->sock,"pline 0 %c An oper command to talk in partyline\xff", GREEN); tprintf(n->sock,"pline 0 %c[11] %c/msg or /m %c[nick] [message]\xff", BROWN, RED, BLUE); tprintf(n->sock,"pline 0 %c Message to irc clients\xff", GREEN); } else tprintf(n->sock,"pline 0 %cInvalid /COMMAND!\xff",RED); } /* End command begin with a "/" */ /* smsg for default pline */ else { for (nn = gnet; nn; nn = nn->next) if (nn!=n && nn->type == NET_PLAYBACK_CONNECTED && !strcasecmp(nn->channel->name, n->channel->name)) tprintf(nn->sock, "smsg %s %s\xff", n->nick, &buf[8]); net_query_parser("msg %s %d %s #%s %s", n->nick, 0, n->host, n->channel->name, &buf[8]); } } /* End pline */ else if ( !strcasecmp(COMMAND, "gmsg") ) { if (n->securitylevel != LEVEL_AUTHOP) { tprintf(n->sock, "gmsg %cYou do not have enough access\xff", RED); return; } for (chan = chanlist; chan; chan = chan->next) if (!strcasecmp(chan->name, n->channel->name)) break; if (chan) for (nn = chan->net; nn; nn = nn->next) if (nn->type == NET_CONNECTED) tprintf(nn->sock, "gmsg %s\xff", PARAM); for (nn = gnet; nn; nn = nn->next) { if (nn->type == NET_PLAYBACK_CONNECTED && !strcasecmp(n->channel->name,nn->channel->name)) tprintf(nn->sock, "gmsg %s\xff", PARAM); else if (nn->type == NET_QUERY_CONNECTED) net_query_parser("gmsg %s %d %s #%s %s (spec msg)", n->nick, 0, n->host, n->channel->name, PARAM); } } lvprintf (10, "playback_conn end\n"); } void net_playback_send(char *channame, char *format, ...) { static char PBUF[1024]; struct net_t *nn; va_list args; if (!channame || !format) return; va_start (args, format); vsnprintf(PBUF, 1023, format, args); va_end(args); for (nn = gnet; nn; nn = nn->next) { if (nn->type == NET_PLAYBACK_CONNECTED && !strcasecmp(channame, nn->channel->name)) tprintf(nn->sock, "%s", PBUF); } } /* The person has sent their init string */ void net_telnet_init(struct net_t *n, char *buf) { int gameslot,found, i; int tet_err; char *dec, *p; struct channel_t *chan; struct net_t *nsock; /* If init string is in fact "playerquery", return number of logged in players, and kill them */ if (!strcasecmp(buf, "playerquery")) { tprintf(n->sock, "Number of players logged in: %d\n", numplayers(n->channel)); return; } /* Version - Return Full version of server */ if (!strcasecmp(buf, "version")) { tprintf(n->sock,"%s.%s\n+OK\n", TETVERSION, SERVERBUILD); return; } /* ListChan - List of all channels */ if (!strcasecmp(buf, "listchan")) { chan=chanlist; while(chan!=NULL) { tprintf(n->sock,"\"%s\" \"%s\" %d %d %d %d\n",chan->name, chan->description, numplayers(chan), chan->maxplayers, chan->priority, chan->status); chan=chan->next; } tprintf(n->sock,"+OK\n"); return; } /* Listuser - List of all users */ if (!strcasecmp(buf,"listuser")) { chan=chanlist; while (chan!=NULL) { nsock=chan->net; while (nsock!=NULL) { if(nsock->type==NET_CONNECTED) { tprintf(n->sock,"\"%s\" \"%s\" \"%s\" %d %d %d \"%s\"\n",nsock->nick, nsock->team, nsock->version,nsock->gameslot,nsock->status,nsock->securitylevel,nsock->channel->name); } nsock=nsock->next; } chan=chan->next; } tprintf(n->sock,"+OK\n"); return; } if (strlen(buf) < 7) {/* Invalid... quit */ killsock(n->sock);lostnet(n); return; } /* Work out game slot */ gameslot=0; found=1; while ( (gameslot < n->channel->maxplayers) && (found) ) { gameslot++; found=0; nsock=n->channel->net; while (nsock!=NULL) { if( ( (nsock->type==NET_CONNECTED) || (nsock->type==NET_WAITINGFORTEAM) )&&(nsock->gameslot==gameslot) ) found=1; nsock=nsock->next; } } if (found) { /* No free Gameslots, so tell that the server is full!! */ tprintf(n->sock,"noconnecting Server is Full!\xff"); killsock(n->sock); lostnet(n); return; } /* Set Game Socket */ n->gameslot = gameslot; tet_err = tet_decrypt(buf); if (tet_err != 0) { /* Error */ killsock(n->sock); lostnet(n); return; } dec = tet_dec2str(buf); /* This is used instead of sscanf to get more control tetrisstart message with the bound check according to NICKLEN and VERLEN. */ i = 0; if ((p = strtok(dec, " "))) { i++; if (strcmp(p, "tetrisstart")) { killsock(n->sock); lostnet(n); return; } if ((p = strtok(NULL, " "))) { i++; if (strlen(p) > NICKLEN) { tprintf(n->sock, "noconnecting Invalid Sign-on (nickname too long)\xff"); killsock(n->sock); lostnet(n); return; } strncpy(n->nick, p, NICKLEN); n->nick[NICKLEN] = 0; if ((p = strtok(NULL, " "))) { strncpy(n->version, p, VERLEN); n->version[VERLEN] = 0; i++; } } } if (i != 3) { killsock(n->sock); lostnet(n); return; } /* OK, so dec should now hold "tetrisstart */ // i = sscanf(dec,"tetrisstart %30[^\x20] %10s", n->nick, n->version); // if (i < 2) // {/* To few conversions - Player dies*/ // killsock(n->sock); lostnet(n); // return; // } /* Ensure a valid nickname */ if (!strcasecmp(n->nick,"server") || !net_query_isvalidnick(n->nick)) { lvprintf(4,"%s Disconnected due to invalid nickname: %s\n",n->host,n->nick); tprintf(n->sock, "noconnecting Nickname not allowed!\xff"); killsock(n->sock); lostnet(n); return; } /* Ensure that Version is OK */ if (tet_checkversion(n->version) == -1) { tprintf(n->sock, "noconnecting TetriNET version (%s) does not match Server's (%s)!\xff", n->version, TETVERSION); killsock(n->sock); lostnet(n); return; } /* Ensure that no-one else has this nick */ found=0; chan=chanlist; if (net_query_nickfound(n->nick, n)) { tprintf(n->sock, "noconnecting Nickname already exists on server!\xff"); killsock(n->sock); lostnet(n); return; } n->team[0] = 0; /* Clear Team */ /* Now waiting for team */ n->type = NET_WAITINGFORTEAM; /* Send Winlist to this new arrival */ sendwinlist(n); /* Send them their player number */ tprintf(n->sock, "playernum %d\xff",gameslot); } /* Someone has just connected. So lets answer them */ void net_telnet(struct net_t *n, char *buf) { unsigned long ip; struct net_t *net; net=malloc(sizeof(struct net_t)); net->next=NULL; net->sock=answer(n->sock,&ip,0); while ((net->sock==(-1)) && (errno==EAGAIN)) net->sock=answer(n->sock,&ip,0); setopt(net->sock, 0); /* Save the port stuff */ net->addr=ip; net->port=n->port; net->securitylevel=LEVEL_NORMAL; net->status=STAT_NOTPLAYING; /* net->timeout_outgame = game.timeout_outgame; net->timeout_ingame = game.timeout_ingame; */ net->timeout_outgame = 30; net->timeout_ingame = 30; do_async_dns(net); net->type = NET_WAITINGFORDNS; /* net has not been added to socket list */ /* EOF on this will be EOF on unknown socket */ } void do_async_dns (struct net_t *n) { char n1[4], n2[4], n3[4], n4[4]; char buf[1024]; int res_id; sprintf(n1,"%lu", (unsigned long)(n->addr&0xff000000)/(unsigned long)0x1000000); sprintf(n2,"%lu", (unsigned long)(n->addr&0x00ff0000)/(unsigned long)0x10000); sprintf(n3,"%lu", (unsigned long)(n->addr&0x0000ff00)/(unsigned long)0x100); sprintf(n4,"%lu", (unsigned long)n->addr&0x000000ff); sprintf(buf, "%s.%s.%s.%s.in-addr.arpa.", n4, n3, n2, n1); sprintf(n->host, "%s.%s.%s.%s", n1, n2, n3, n4); sprintf(n->ip, "%s.%s.%s.%s", n1, n2, n3, n4); res_id = query_do(buf); add_rnet(n, res_id); } void net_donedns(struct net_t *net) { if (net->type != NET_WAITINGFORDNS) return; rem_rnet(net); switch(net->port) { case TELNET_PORT: { net_telnet_donedns (net); break; } case QUERY_PORT: { net_query_donedns (net); break; } case PLAYBACK_PORT: { net_playback_donedns (net); break; } default: { break; } } } void net_telnet_donedns( struct net_t *net) { int k, l, x, y; char strg[121]; struct channel_t *chan, *ochan; if(net->sock <0) { lvprintf(4,"Failed TELNET incoming connection from %s", net->host); killsock(net->sock); free(net); return; } setsock(net->sock, 0); /* Is this person banned? */ if (is_explicit_banned(net)) { /* tprintf(net->sock,"noconnecting You are banned. Server is closed for testing. Please try again next day!!!\xff"); */ tprintf(net->sock,"noconnecting Your host is banned from this server.\xff"); killsock(net->sock); free(net); return; } /* Find a channel */ chan = chanlist; ochan = NULL; while ( chan != NULL ) { if ( ((ochan == NULL) || (chan->priority > ochan->priority)) && (numplayers(chan) < chan->maxplayers) && (chan->priority!=0)) ochan=chan; /* Found a likely channel */ chan=chan->next; } /* Save the port stuff */ if (ochan == NULL) { /* No channels found, so create a new one :P */ if (numchannels() < game.maxchannels) { chan=chanlist; while ( (chan!=NULL) && (chan->next!=NULL) ) chan=chan->next; if (chan==NULL) { chanlist = malloc(sizeof(struct channel_t)); chan=chanlist; } else { chan->next = malloc(sizeof(struct channel_t)); chan=chan->next; } chan->next=NULL; chan->net=NULL; chan->maxplayers=DEFAULTMAXPLAYERS; chan->status=STATE_ONLINE; chan->description[0]=0; chan->priority=DEFAULTPRIORITY; chan->sd_mode=SD_NONE; chan->persistant=0; /* Copy default settings */ chan->starting_level=game.starting_level; chan->lines_per_level=game.lines_per_level; chan->level_increase=game.level_increase; chan->lines_per_special=game.lines_per_special; chan->special_added=game.special_added; chan->special_capacity=game.special_capacity; chan->classic_rules=game.classic_rules; chan->average_levels=game.average_levels; chan->sd_timeout=game.sd_timeout; chan->sd_lines_per_add=game.sd_lines_per_add; chan->sd_secs_between_lines=game.sd_secs_between_lines; strcpy(chan->sd_message,game.sd_message); chan->block_leftl=game.block_leftl; chan->block_leftz=game.block_leftz; chan->block_square=game.block_square; chan->block_rightl=game.block_rightl; chan->block_rightz=game.block_rightz; chan->block_halfcross=game.block_halfcross; chan->block_line=game.block_line; chan->special_addline=game.special_addline; chan->special_clearline=game.special_clearline; chan->special_nukefield=game.special_nukefield; chan->special_randomclear=game.special_randomclear; chan->special_switchfield=game.special_switchfield; chan->special_clearspecial=game.special_clearspecial; chan->special_gravity=game.special_gravity; chan->special_quakefield=game.special_quakefield; chan->special_blockbomb=game.special_blockbomb; chan->stripcolour=game.stripcolour; chan->serverannounce=game.serverannounce; chan->pingintercept=game.pingintercept; chan->winlist_file=game.winlist_file; strncpy(chan->game_type, game.game_type, GAMETYPELEN-1); chan->game_type[GAMETYPELEN-1] = 0; k=0;l=1; while (l) { k++; ochan=chanlist; if (k==1) { sprintf(strg,"%s", DEFAULTCHANNEL); strncpy(chan->name,strg,CHANLEN-1); chan->name[CHANLEN-1]=0; } else { sprintf(strg,"%s%d", DEFAULTCHANNEL,k); strncpy(chan->name,strg,CHANLEN-1); chan->name[CHANLEN-1]=0; } l=0; while( (ochan != NULL) && (!l) ) { if ( (!strcasecmp(chan->name,ochan->name)) && (chan!=ochan)) l=1; else ochan=ochan->next; } } } else { tprintf(net->sock,"noconnecting Server is Full!\xff"); killsock(net->sock); free(net); return; } } else { chan=ochan; /* Found a channel */ } net->channel = chan; addnet(chan,net); net->type=NET_TELNET_INIT; strcpy(net->nick,"???"); /* Clear their Field */ for(y=0;yfield[x][y]=0; /* Nothing */ /* Now we wait for the client init string */ } void lostnet(struct net_t *n) { int found,playing; char MSG[TEAMLEN+4]; struct net_t *nsock; struct channel_t *chan,*ochan; /* Inform all other active players this one has left iff this one was connected "properly"! */ if ( n->type == NET_CONNECTED ) { playing=0; found=0;/* Number of different teams/players playing */ MSG[0]=0; /* Store playing team name here */ nsock=n->channel->net; net_query_parser("playerleave %s %d %s #%s", n->nick, n->gameslot, n->host, n->channel->name); net_playback_send(n->channel->name, "playerleave %d\xff", n->gameslot); while (nsock!=NULL) { if ( (nsock!=n) && (nsock->type == NET_CONNECTED) ) { /* Different player, connected, in same channel */ tprintf(nsock->sock,"playerleave %d\xff", n->gameslot); if (strcasecmp(MSG,nsock->team)) {/* Different team, so add player */ found++; if (nsock->status == STAT_PLAYING) playing++; strcpy(MSG,nsock->team); } else if (MSG[0]==0) { found++; if (nsock->status == STAT_PLAYING) playing++; } } nsock=nsock->next; } /* If 1 or less players/teams now are playing, AND the player that quit WAS playing, STOPIT */ if ( (playing <= 1) && (n->channel->status == STATE_INGAME) && (n->status == STAT_PLAYING) ) { nsock=n->channel->net; while (nsock!=NULL) { if ( (nsock!=n) && (nsock->type == NET_CONNECTED)) { tprintf(nsock->sock,"endgame\xff"); nsock->status=STAT_NOTPLAYING; } nsock=nsock->next; } net_playback_send(n->channel->name, "endgame\xff"); n->channel->status = STATE_ONLINE; } } /* If we're the only numplayers players, then we delete the channel */ if ( (numallplayers(n->channel)==1) && (!n->channel->persistant) ) { chan=chanlist; ochan=NULL; while ( (chan != n->channel) && (chan != NULL) ) { ochan=chan; chan=chan->next; } if (chan != NULL) { if (ochan != NULL) ochan->next=chan->next; else chanlist=chan->next; free(chan); } } else remnet(n->channel,n); free(n); } void net_eof(int z) { struct channel_t *chan; struct net_t *nsock, *nn; nsock=NULL; chan=chanlist; while ( (chan!=NULL) && (nsock==NULL)) { nsock=chan->net; while ((nsock!=NULL) && (nsock->sock!=z)) { nsock=nsock->next; } chan=chan->next; } if (nsock==NULL) /* retry for non channel related */ { for(nn = gnet; nn; nn = nn->next) { if (nn->sock == z) { if (nn->type == NET_QUERY_CONNECTED || nn->type == NET_QUERY_INIT || nn->type == NET_PLAYBACK_INIT || nn->type == NET_PLAYBACK_CONNECTED) { close(z); killsock(z); net_query_lostnet(nn); return; } } } lvprintf(3,"Socket(%d): EOF on unknown socket\n",z); close(z); killsock(z); return; } killsock(z); lostnet(nsock); } void got_term(int z) { lvprintf(1,"Got TERM Signal - Quitting\n"); /* Remove PID */ delpid(); /* Done */ exit(0); } void init_main(void) { struct sigaction sv; lvprintf(0,"\nTetriNET for Linux V%s.%s\n---------------------------------\n", TETVERSION, SERVERBUILD); gnet=NULL; chanlist=NULL; getmyhostname(myhostname); eff_gamecount = 0; visit = 0; /* set up error traps: We DON'T want Broken pipes!!! In fact, what the hell ARE broken pipes anyway. */ sv.sa_handler=SIG_IGN; sigaction(SIGPIPE,&sv,NULL); /* We want to shut down cleanly */ sv.sa_handler=got_term; sigaction(SIGTERM,&sv,NULL); } void init_resolver(void) { rnet = NULL; ov_asynch = 1; ov_type = adns_r_ptr; ov_pipe = 0; ensure_adns_init(); } int probe_async_dns(void) { adns_query q; adns_answer *answer; void *qun_v; int maxresfd; fd_set res_rfds, res_wrfds, res_expfds; struct timeval *tv, tvbuf; struct timeval tv2; int r, ret; char result[256]; struct net_t *nn; int found; maxresfd = 0; FD_ZERO(&res_rfds); FD_ZERO(&res_wrfds); FD_ZERO(&res_expfds); tv2.tv_sec = 0; tv2.tv_usec = 0; tv = &tv2; found = 0; adns_beforeselect(ads, &maxresfd, &res_rfds, &res_wrfds, &res_expfds, &tv, &tvbuf, 0); r = select(maxresfd, &res_rfds, &res_wrfds, &res_expfds, tv); if ( r == -1 ) { if (errno == EINTR) return 0; lvprintf(1, "Failed res select: %d\n", errno); return 0; } adns_afterselect(ads, maxresfd, &res_rfds, &res_wrfds, &res_expfds, 0); for (;;) { q = 0; result[0] = 0; r = adns_check(ads, &q, &answer, &qun_v); if (r == EAGAIN) break; if (r == ESRCH) return 0; ret = query_done(qun_v, answer, result); nn = find_rnet(ret); if (nn == NULL) return 0; if (result[0] != 0) strcpy(nn->host, result); net_donedns(nn); found = 1; } return found; } void check_timeouts(void) { struct net_t *n, *nextn; struct channel_t *chan, *nextchan; int found,i; found=0; visit++; if ((visit % CYCLE2) == 0) { chan=chanlist; while ( (chan!=NULL) ) { n=chan->net; nextchan = chan->next; while ( (n!=NULL) ) { nextn = n->next; if (n->type == NET_QUERY_INIT || n->type == NET_PLAYBACK_CONNECTED || n->type == NET_PLAYBACK_INIT) break; if (n->status == STAT_PLAYING) n->timeout_ingame-=CYCLE2; else n->timeout_outgame-=CYCLE2; if (n->timeout_outgame == (120/CYCLE2)*CYCLE2 + (game.timeout_outgame%CYCLE2)) { tprintf(n->sock,"pline 0 %cYou are about to get disconnected in %d-%d seconds.\xff",RED, 120-CYCLE2, 120+CYCLE2); tprintf(n->sock,"pline 0 %cTo avoid disconnection. Please say something in partyline.\xff",RED); } if (n->timeout_ingame <= 0 || n->timeout_outgame == 0) { /* Timeout has occurred */ switch (n->type) { case NET_TELNET_INIT: case NET_WAITINGFORTEAM: case NET_CONNECTED: { net_query_parser("timeout %s %d %s #%s", n->nick, n->gameslot, n->host, n->channel->name); if (n->type != NET_TELNET_INIT) tprintf(n->sock,"pline 0 %cYou have timed out! Disconnecting!\xff",RED); else tprintf(n->sock,"noconnecting You have timed out!\xff"); killsock(n->sock); lostnet(n); break; } } } n = nextn; } chan = nextchan; } } /* End visit */ /* Sudden Death Timeouts */ chan=chanlist; while (chan!=NULL) { if (numplayers(chan) < 1) { chan = chan->next; continue; } if ( (chan->status==STATE_INGAME) && (chan->sd_mode!=SD_NONE) ) { chan->sd_timeleft-=CYCLE; if(chan->sd_timeleft <=0) {/* Timeout */ n=chan->net; if (chan->sd_mode == SD_INIT) net_playback_send(n->channel->name, "gmsg %s\xff", n->channel->sd_message); while(n!=NULL) { if ((n->type==NET_CONNECTED) ) { if (chan->sd_mode==SD_INIT) { tprintf(n->sock,"gmsg %s\xff",n->channel->sd_message); } else { net_playback_send(n->channel->name, "sb 0 a 0\xff"); for(i=0;ichannel->sd_lines_per_add;i++) { n->field_changes--; n->max_pieces_left += 3; tprintf(n->sock,"sb 0 a 0\xff"); net_playback_send(n->channel->name, "sb 0 a 0\xff"); } } } n=n->next; } chan->sd_timeleft=chan->sd_secs_between_lines; chan->sd_mode=SD_WAIT; } } chan=chan->next; } } int main(int argc, char *argv[]) { int xx; char buf[1050]; int buf_len; int forknum; long int timeticks, otimeticks; /* Initialise */ printf("Loading Tetrix. Please wait...\n"); init_main(); init_resolver(); init_game(); printf("Initializing security/ban list...\n"); init_security(); init_banlist(banlist, MAXBAN); read_banlist(FILE_BAN, banlist, MAXBAN); init_banlist(combanlist, MAXBAN); read_banlist(FILE_BAN_COMPROMISE, combanlist, MAXBAN); init_allowlist(); read_allowlist(); printf("Initializing winlist...\n"); init_winlist(winlist, MAXWINLIST); init_winlist(winlist2, MAXWINLIST); init_winlist(winlist3, MAXWINLIST); readwinlist(FILE_WINLIST, winlist, MAXWINLIST); readwinlist(FILE_WINLIST2, winlist2, MAXWINLIST); readwinlist(FILE_WINLIST3, winlist3, MAXWINLIST); sleep(1); printf("Initialize network connection...\n"); init_net(); printf("Gameplay ... "); usleep(300000); init_telnet_port(); printf("Spectator ... "); usleep(300000); init_playback_port(); printf("Ircadm ... \n"); init_query_port(); printf("Completed!!!\n"); if (securityread() < 0) securitywrite(); /* Now fork out, and start a new process group */ /* Fork. If we are the parent, quit, if child, continue */ if ((forknum=fork()) == -1) { printf("Error: Unable to fork new process\n"); exit(5); } if (forknum > 0) { exit(0); } setsid(); /* Close all stdio */ close(0); close(1); close(2); /* Write out PID */ writepid(); /* Reset time */ timeticks = time(NULL); otimeticks = timeticks; while (1) { timeticks=time(NULL); if ((timeticks-otimeticks) >= CYCLE) { /* Check timeouts */ check_timeouts(); otimeticks = timeticks; } /* flush sockets */ dequeue_sockets(); /* check DNS sockets */ while(probe_async_dns() == 1); /* Read data from a currently waiting socket */ xx=sockgets(buf, &buf_len); if (xx>=0) /* Non-error */ { net_activity(xx, buf, buf_len); } else if (xx==-1) /* EOF from someone */ { lvprintf(4,"Close Socket\n"); net_eof(buf_len); /* Close this socket */ } else if (xx==-2) /* Select() error */ { lvprintf(4,"Select error - Whatever the hell that is supposed to be..\n"); } } } tetrinetx-1.13.16+qirc-1.40c/src/main.h0100600000076700007670000003016207273062314016665 0ustar drslumdrslum/* main.h */ #define TIME_WITH_SYS_TIME 1 #include #include #include #include #include #include #include #include #if HAVE_SYS_SELECT_H #include #endif #include #ifndef LINUX /* linux gets wacko if you include both */ #ifndef __CYGWIN32__ /* Cygnus Win32 isn't all that happy with it either */ #include #endif #endif /* but virtually every other OS NEEDS both */ #include /* is this really necessary? */ #include #include #if HAVE_UNISTD_H #include #endif #include /* almost every module needs some sort of time thingy, so... */ #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #include /* Defines */ #define TETVERSION "1.13" /* What Tetrinet version we are for */ #define SERVERBUILD "16+qirc-1.40b" /* What build we are at */ #define NICKLEN 30 /* Maximum length of Nickname */ #define VERLEN 10 /* Maximum length of Tetrinet version */ #define UHOSTLEN 121 /* Maximum length of Hostname */ #define TEAMLEN NICKLEN /* Maximum length of teamname */ #define GAMETYPELEN 64 /* Maximum length of gametype */ /*#define MAXNET 80*/ /* Maximum network sockets */ #define MAXWINLIST 5120 /* Maximum entries on Winlist */ #define MAXTWINLIST 200 /* Maximum entries for spec winlist */ #define MAXPW 2048 /* Maximum entries in password file */ #define MAXBAN 240 /* Maximum entries in game.ban */ #define MAXALLOW 200 /* Maximum entries in game.allow */ #define TELNET_PORT 31457 /* Telnet port to listen on */ #define QUERY_PORT 31456 /* Query port to listen on */ #define PLAYBACK_PORT 31458 /* For external audience */ #define FIELD_MAXX 12 /* Maximum horizontal size of playing field */ #define FIELD_MAXY 22 /* Maximum vertical size of playing field */ #define PIDFILELEN 80 /* Length of name of PID file */ #define SDMSGLEN 80 /* Length of Sudden Death Message */ #define PASSLEN 20 /* Length of Password */ #define MAXPLAYERS 6 /* Maximum number of players allowed */ #define CHANLEN 16 /* Length of channel names */ #define IPLEN 16 /* Size of IP */ #define DEFAULTCHANNEL "tetrinet" /* Default channel name */ #define DEFAULTSPECCHANNEL "spectators" /* Default channel name */ #define DEFAULTMAXPLAYERS 6 /* Default max players in channel */ #define DEFAULTPRIORITY 50 /* Default priority */ #define DESCRIPTIONLEN 80 /* Description */ #define GAME_NTIMELIMIT 800 /* Time limit for normal games */ #define GAME_TTIMELIMIT 180 /* Time limit for others games */ #define MAXFILENAMELEN 128 /* Max File name length */ #define STATE_OFFLINE 0 /* Offline */ #define STATE_ONLINE 1 /* Not in game */ #define STATE_INGAME 2 /* In game */ #define STATE_PAUSED 3 /* In game but paused */ #define NET_FREE 0 /* Unused at the momen */ #define NET_TELNET 1 /* Person has just connected */ #define NET_TELNET_INIT 2 /* Person is sending init sequence */ #define NET_WAITINGFORTEAM 3 /* Waiting for initial team */ #define NET_CONNECTED 4 /* Everything works out, they're connected */ #define NET_QUERY 5 /* Person has connected to Query Port */ #define NET_QUERY_INIT 6 /* Person is sending query request */ #define NET_QUERY_CONNECTED 7 /* Person is already authenticated. */ #define NET_LOST 9 /* Lost connection */ #define NET_WAITINGFORDNS 10 /* Waiting for resolver */ #define NET_PLAYBACK 20 /* Person has connected to Playback Port */ #define NET_PLAYBACK_INIT 21 /* Person sends playback request */ #define NET_PLAYBACK_CONNECTED 22 /* Playback authenticated */ #define STAT_NOTPLAYING 0 /* Not playing */ #define STAT_PLAYING 1 /* Currently playing */ #define STAT_LOST 2 /* Playing, but lost */ #define SD_NONE 0 /* No mode. Ignore timeout */ #define SD_INIT 1 /* Wait for timeout, it's first suddendeath */ #define SD_WAIT 2 /* Waiting between lines */ #define LEVEL_UNUSED 0 /* Unused level */ #define LEVEL_NORMAL 1 /* Unauthenticated Person */ #define LEVEL_OP 2 /* Op by position player */ #define LEVEL_AUTHOP 3 /* OP'ed person (/op) */ #define CYCLE 1 /* How many (s) is 1 cycle */ #define CYCLE2 10 /* How many (s) is 1 cycle */ typedef unsigned long IP; /* public structure of all the net connections */ struct channel_t { char name[CHANLEN+1]; /* Name of the channel */ int priority; /* Priority of channel */ int maxplayers; /* Maximum players allowed */ unsigned char status; /* STATE_XXXXXX */ struct channel_t *next; /* Next in the queue */ char description[DESCRIPTIONLEN+1]; /* Description */ char persistant; /* 1=can't delete */ struct net_t *net; /* Net structure */ int sd_timeleft; /* Sudden Death Timeout */ int sd_mode; /* What SD mode we're in - SD_XXXX */ int intensity_level; /* high intense mode */ /* Channel Settings */ int starting_level; int lines_per_level; int level_increase; int lines_per_special; int special_added; int special_capacity; int classic_rules; int average_levels; int sd_timeout; int sd_lines_per_add; int sd_secs_between_lines; char sd_message[SDMSGLEN+1]; int block_leftl; int block_leftz; int block_square; int block_rightl; int block_rightz; int block_halfcross; int block_line; int special_addline; int special_clearline; int special_nukefield; int special_randomclear; int special_switchfield; int special_clearspecial; int special_gravity; int special_quakefield; int special_blockbomb; int stripcolour; /* Strip colour from gmsg's */ int serverannounce; /* Server announces winner */ int pingintercept; /* Intercept ping's */ int winlist_file; /* 1 = FILE_WINLIST, 2 = FILE_WINLIST2 */ char game_type[GAMETYPELEN+1];/* normal, onetetris, timelimit */ struct timeval game_timestart; struct timeval game_timestop; int game_tmerr; int game_timeleft; }; /* Server Config */ struct game_t { char bindip[IPLEN+1]; int maxchannels; int starting_level; int lines_per_level; int level_increase; int lines_per_special; int special_added; int special_capacity; int classic_rules; int average_levels; int sd_timeout; int sd_lines_per_add; int sd_secs_between_lines; char sd_message[SDMSGLEN+1]; int timeout_ingame; int timeout_outgame; int block_leftl; int block_leftz; int block_square; int block_rightl; int block_rightz; int block_halfcross; int block_line; int special_addline; int special_clearline; int special_nukefield; int special_randomclear; int special_switchfield; int special_clearspecial; int special_gravity; int special_quakefield; int special_blockbomb; int stripcolour; /* Strip colour from gmsg's */ int serverannounce; /* Server announces winner */ int pingintercept; /* Intercept ping's */ char game_type[GAMETYPELEN+1];/* Game type (normal, onetetris, timelimit) */ int winlist_file; /* Winlist file 1 or 2 or 3*/ int command_clear; /* Allow clearing of winlist? */ int command_kick; /* Allow Kicks? */ int command_msg; /* Allow msg's? */ int command_op; /* Allow command OP */ int command_winlist; /* Allow winlist */ int command_help; /* Allow help */ int command_list; /* Allow list */ int command_join; /* Allow join */ int command_who; /* Allow who */ int command_topic; /* Allow topic */ int command_priority; /* Allow priority */ int command_move; /* Allow move */ int command_set; /* Allow set */ int command_persistant; int command_save; int command_reset; int verbose; /* Verbosity */ char pidfile[PIDFILELEN+1]; }; struct net_t { int sock; /* Socket this player is on */ IP addr; /* IP address of player */ unsigned int port; /* Port number they connected to */ char nick[NICKLEN+1]; /* Nickname of player */ char team[TEAMLEN+1]; /* Teamname of player */ char host[UHOSTLEN+1]; /* Resolved host */ char ip[IPLEN+1]; /* IP address */ char version[VERLEN+1]; /* TetriNET version */ int gameslot; /* What slot (1-6) they occupy */ int level; /* What playing level they've reached */ unsigned char field[FIELD_MAXX][FIELD_MAXY]; /* Playing Field of player */ unsigned char status; /* Current Status - STAT_XXXXX */ int timeout_ingame; /* Timeout on socket */ int timeout_outgame; /* Timeout on socket */ int securitylevel; /* What security LEVEL - LEVEL_XXX */ struct channel_t *channel; /* What channel we're on */ unsigned char type; /* What this record type is - NET_XXXXXX */ int flood_players; /* Total players after game start */ int flood_channels; /* Total channels with > 4 players */ int wlist_cache; /* Last winlist index */ int top_player; /* Is the player in Top 20 */ int lines_add_to_all; /* How many lines add to all he make */ int tetris_made; /* How many tetris he makes */ int field_changes; /* How many time his field is changed */ int max_pieces_left; /* How many pieces you have (maxbound)*/ int authenticate; /* Is the person authenticated */ int teamup; /* Teamup at game start */ struct net_t *next; /* Next in list */ }; struct res_t { struct net_t *net; int res_id; struct res_t *next; }; /* Winlist Structure */ struct winlist_t { char status; /* Type. p=player, t=team */ char name[NICKLEN+1]; /* Name of player/team */ unsigned long int score; /* What they scored */ char inuse; /* 1=inuse 0=available */ }; struct pwddb_t { char name[NICKLEN+1]; char password[PASSLEN+1]; int inuse; }; /* Security structure */ struct security_t { char op_password[PASSLEN+1]; /* Password to take ops */ char query_password[PASSLEN+1]; /* Password for query clients */ char spec_password[PASSLEN+1]; /* Password for spectators */ char spec_op_password[PASSLEN+1]; /* Password for advanced spectators */ }; struct ban_t { char addr[UHOSTLEN+1]; }; struct allow_t { char nick[NICKLEN+1]; char pass[PASSLEN+1]; }; /* Colours defined here */ /* I found these defined in "TetriNET Color Addon for mIRC" by TNL */ #define BOLD 2 #define ITALIC 22 #define UNDERLINE 31 #define BLACK 4 #define DARKGRAY 6 #define SILVER 15 #define NAVY 17 #define BLUE 5 #define CYAN 3 #define GREEN 12 #define NEON 14 #define TEAL 23 #define BROWN 16 #define RED 20 #define MAGENTA 8 #define VIOLET 19 #define YELLOW 25 #define WHITE 24 /* net list */ struct net_t *gnet; /* Start of global "socket" information */ struct res_t *rnet; /* active DNS list */ /* authenticated query connection list */ char myhostname[UHOSTLEN+1]; unsigned long eff_gamecount; int visit; struct game_t game; /* Game Configuration */ struct winlist_t winlist[MAXWINLIST]; /* Winlist */ struct winlist_t winlist2[MAXWINLIST]; /* 2nd Winlist */ struct winlist_t winlist3[MAXWINLIST]; /* 3rd Winlist */ struct security_t security; /* Security structure */ struct ban_t banlist[MAXBAN]; /* Ban structure */ struct ban_t combanlist[MAXBAN]; /* Compromise ban structure */ struct allow_t allowlist[MAXALLOW]; /* game.allow structure */ struct channel_t *chanlist; /* Channel structure */ /* And the proto types */ void do_async_dns(struct net_t *n); void net_donedns(struct net_t *n); void net_telnet_init(struct net_t *n, char *buf); void net_telnet(struct net_t *n, char *buf); void net_telnet_donedns(struct net_t *n); void net_query_init(struct net_t *n, char *buf); void net_query_parser(char *, ...); void net_query_connected(struct net_t *n, char *buf); void net_query(struct net_t *n, char *buf); void net_query_donedns(struct net_t *n); int net_query_isvalidnick(char *p); int net_query_TrimStr(char *p); int net_query_StripCtrlStr(char *p); void net_playback_init(struct net_t *n, char *buf); void net_playback(struct net_t *n, char *buf); void net_playback_donedns(struct net_t *n); void net_playback_connected (struct net_t *n, char *buf); void net_playback_send(char *, char *, ...); void lostnet(struct net_t *n); void net_connected(struct net_t *n, char *buf); void net_waitingforteam(struct net_t *n, char *buf); void init_main(void); void lprintf(char *, ...); void lvprintf(int, char *, ...); tetrinetx-1.13.16+qirc-1.40c/src/c0100700000076700007670000000044007303411103015716 0ustar drslumdrslum#!/bin/sh # # Determines by uname what compile.XXXXXX to run. OSTYPE=`uname | awk '{ printf "%s", $1 }'` echo "Detected Unix Type: $OSTYPE" case $OSTYPE in Linux) exec ./compile.linux $* ;; SunOS) exec ./compile.solaris $* ;; FreeBSD) exec ./compile.freebsd $* ;; esac tetrinetx-1.13.16+qirc-1.40c/src/utils.c0100600000076700007670000000131307512452302017064 0ustar drslumdrslum/* utils.c */ void fatal(char *s, int recoverable) { struct net_t *nsock; struct channel_t *chan; printf("%s\n", s); nsock=NULL; chan=chanlist; while (chan!=NULL) { nsock=chan->net; while (nsock!=NULL) { killsock(nsock->sock); nsock=nsock->next; } chan=chan->next; } exit(1); } void nfree(void *ptr) { int i=0; if (ptr==NULL) { lvprintf(4,"Trying to free NULL pointer\n"); i=i; return; } free(ptr); } void *nmalloc(int size) { void *x; int i=0; x=(void *)malloc(size); if (x==NULL) { i=i; lvprintf(4,"*** FAILED MALLOC"); return NULL; } return x; } tetrinetx-1.13.16+qirc-1.40c/src/COMPILE0100600000076700007670000000165607512456641016617 0ustar drslumdrslumCompile Notes ------------- This documents serves two purposes. It lists all the unixes this program has successfully been compiled on. It also documents how to compile it :) Worked ------ * Redhat Linux * Slackware Linux * Solaris 2.6 * OSF1 (What is this?? OpenBSD?) Compile notes ------------- Easiest way to compile the server is to try run the "c" shell script. This shell script does a quick check as to what type of unix system you are running, and runs a "compile.xxxxx" script based on what it determins you are running. If your system is not known to the "c" script, then you may want to try run each of the "compile.xxxx" scripts till it works. Please email me in this situation the output gotten from "uname -a" and if you got it working, what compile options. Note: libadns is a pre-requisite. You may need to edit the include and lib directory. The default is /usr/local/include and /usr/local/lib for libadns. tetrinetx-1.13.16+qirc-1.40c/src/net.h0100600000076700007670000001135707271162601016532 0ustar drslumdrslum/* net.h Just about all low level network functions. NOTE: Apart from some changes, most of net.c and net.h is from the excellent eggdrop program "eggdrop". I found that what was in net.c absolutely perfectly matched what I needed, and the way it went by doing that unique :) Beautifully written. Author is Robey Pointer, robey@netcom.com. Eggdrop can be most likely found at http://www.valuserve.com/~robey/eggdrop/ NOTE: I feel a little bit better. I found this in the README file ;), and thus the same applies into here then: The files "match.c", "net.c", and "blowfish.c" are exempt from the above restrictions. "match.c" is original code by Chris Fuller (email: crf@cfox.bchs.uh.edu) and has been placed by him into the public domain. "net.c" is by me and I also choose to place it in the public domain. "blowfish.c" is by various sources and is in the public domain. All 3 files contain useful functions that could easily be ported to other applications -- the other parts of the bot generally don't. NOTE: net.c has been heavily modified by me to provide more dynamic allocation of sockets, instead of static. Should save memory, and allow greater than expected number of sockets to be allocated. */ #include /* socket flags: */ #define SOCK_UNUSED 0x01 /* empty socket */ #define SOCK_BINARY 0x02 /* do not buffer input */ #define SOCK_LISTEN 0x04 /* listening port */ #define SOCK_CONNECT 0x08 /* connection attempt */ #define SOCK_NONSOCK 0x10 /* used for file i/o on debug */ #define SOCK_STRONGCONN 0x20 /* don't report success until sure */ /* this is used by the net module to keep track of sockets and what's queued on them */ struct sock_list { int sock; char flags; char *inbuf; char *outbuf; struct sock_list *next; }; /*#define MAXSOCKS MAXNET*2*/ struct sock_list *socklist; /* enough to be safe */ /* i read somewhere that memcpy() is broken on some machines */ /* it's easy to replace, so i'm not gonna take any chances, because it's */ /* pretty important that it work correctly here */ void my_memcpy(char *dest,char *src,int len); /* bzero() is bsd-only, so here's one for non-bsd systems */ void my_bzero(char *dest,int len); /* initialize the socklist */ void init_net(void); int expmem_net(void); /* puts full hostname in s */ void getmyhostname(char *s); /* get my ip number */ IP getmyip(void); void neterror(char *s); /* request a normal socket for i/o */ void setsock(int sock,int options); int getsock(int options); /* done with a socket */ void killsock(int sock); /* returns a socket number for a listening socket that will accept any */ /* connection -- port # is returned in port */ int open_listen(int *port); /* given network-style IP address, return hostname */ /* hostname will be "##.##.##.##" format if there was an error */ char *hostnamefromip(unsigned long ip); /* short routine to answer a connect received on a socket made previously */ /* by open_listen ... returns hostname of the caller & the new socket */ /* does NOT dispose of old "public" socket! */ int answer(int sock,unsigned long *ip,int binary); /* attempts to read from all the sockets in socklist */ /* fills s with up to 511 bytes if available, and returns the array index */ /* on EOF, returns -1, with socket in len */ /* on socket error, returns -2 */ /* if nothing is ready, returns -3 */ int sockread(char *s,int *len,struct sock_list **socket_list); /* sockgets: buffer and read from sockets attempts to read from all registered sockets for up to one second. if after one second, no complete data has been received from any of the sockets, 's' will be empty, 'len' will be 0, and sockgets will return -3. if there is returnable data received from a socket, the data will be in 's' (null-terminated if non-binary), the length will be returned in len, and the socket number will be returned. normal sockets have their input buffered, and each call to sockgets will return one line terminated with a '\n'. binary sockets are not buffered and return whatever coems in as soon as it arrives. listening sockets will return an empty string when a connection comes in. connecting sockets will return an empty string on a successful connect, or EOF on a failed connect. if an EOF is detected from any of the sockets, that socket number will be put in len, and -1 will be returned. * the maximum length of the string returned is 512 (including null) */ int sockgets(char *s,int *len); /* dump something to a socket */ void tputs(int z,char *s); /* tputs might queue data for sockets, let's dump as much of it as */ /* possible */ void dequeue_sockets(void); IP getip(char *s); tetrinetx-1.13.16+qirc-1.40c/src/utils.h0100600000076700007670000000062507271162601017100 0ustar drslumdrslum/* utils.h Generic addons that didn't really fit anywhere. Currently, I think whats mostly in this file were additional functions from eggdrop (see net.h), to get net.c to work (with less modification) ;). */ /* Writes S to stdout, and quits */ void fatal(char *s, int recoverable); /* More controlled free() */ void nfree(void *ptr); /* More controlled malloc() */ void *nmalloc(int size); tetrinetx-1.13.16+qirc-1.40c/src/compile.solaris0100700000076700007670000000031707512452226020617 0ustar drslumdrslum#!/bin/ksh echo [Solaris] Compiling TetriNET Server [../bin/tetrix.solaris] set -x gcc -O2 -Wall -I/usr/local/include main.c -o ../bin/tetrix.solaris $1 $2 $3 -lnsl -lsocket -lresolv -L/usr/local/lib -ladns tetrinetx-1.13.16+qirc-1.40c/src/compile.osf10100700000076700007670000000041507512452173020013 0ustar drslumdrslum#!/bin/sh # uname shows OSF1... What unix is this??? {Checked by Wasptor} echo [OSF1] Compiling TetriNET Server [../bin/tetrix.osf1] set -x gcc -O2 -fno-strength-reduce -Wall -I/usr/local/include main.c -o ../bin/tetrix.osf1 $1 $2 $3 -L/usr/local/include/lib -ladns tetrinetx-1.13.16+qirc-1.40c/src/compile.linux0100700000076700007670000000030507512452137020300 0ustar drslumdrslum#!/bin/sh echo [Linux] Compiling TetriNET Server [../bin/tetrix.linux] set -x gcc -O2 -fno-strength-reduce -Wall -I/usr/local/include main.c -o ../bin/tetrix.linux $1 $2 $3 -L/usr/local/lib -ladns tetrinetx-1.13.16+qirc-1.40c/src/game.c0100600000076700007670000014411307271162601016645 0ustar drslumdrslum/* game.c */ /* securitywrite() */ /* Writes out the security structure into a text format game.secure file */ int securitywrite() { FILE *file_out; file_out = fopen(FILE_SECURE, "w"); if (file_out == NULL) return(-1); fprintf(file_out,"# TetriNET (linux) Security configuration file\n"); fprintf(file_out,"\n"); fprintf(file_out,"# This file contains security configuration for TetriNET, and by default will\n"); fprintf(file_out,"# be created with all values commented out. \n"); fprintf(file_out,"# Each configuration value consists of a TAG name, followed by an equal sign\n"); fprintf(file_out,"# and a value. IE:\n"); fprintf(file_out,"# op_password=mypass\n"); fprintf(file_out,"# Any text after a # is ignored, and can be used as comments.\n"); fprintf(file_out,"\n"); fprintf(file_out,"# op_password [] - Typing /op will give player op status\n"); fprintf(file_out,"#op_password=pass4word\n"); fprintf(file_out,"\n"); fprintf(file_out,"# query_password [] - For query irc client\n"); fprintf(file_out,"#query_password=pass4word\n"); fprintf(file_out,"# spec_password [] - Use this as team name for gameplay watch\n"); fprintf(file_out,"#spec_password=pass4word\n"); fprintf(file_out,"\n"); fprintf(file_out,"# spec_op_password [] - Use this as team name for gameplay watch with extended capability\n"); fprintf(file_out,"#spec_op_password=pass4word\n"); fprintf(file_out,"\n\n"); fprintf(file_out,"# End of File\n"); fclose(file_out); lvprintf(3,"Wrote new security configuration to %s\n", FILE_SECURE); return(0); } /* securityread() */ /* Reads from a text format game.secure file, data into the security structure */ int securityread(void) { FILE *file_in; char buf[513]; char id_tag[81]; char id_value[81]; int i,j,error; security.op_password[0]=0; security.query_password[0]=0; file_in = fopen(FILE_SECURE, "r"); if (file_in == NULL) return(-1); while (fgets(buf, 512, file_in) != NULL) { net_query_TrimStr(buf); i=0; j=strlen(buf); while( (ipersistant) {/* Found one. Write it */ fprintf(file_out,"[%s]\n",chan->name); fprintf(file_out,"maxplayers=%d\n",chan->maxplayers); fprintf(file_out,"topic=%s\n",chan->description); fprintf(file_out,"priority=%d\n",chan->priority); if (chan->starting_level!=game.starting_level) fprintf(file_out,"starting_level=%d\n",chan->starting_level); if (chan->lines_per_level!=game.lines_per_level) fprintf(file_out,"lines_per_level=%d\n",chan->lines_per_level); if (chan->level_increase!=game.level_increase) fprintf(file_out,"level_increase=%d\n",chan->level_increase); if (chan->lines_per_special!=game.lines_per_special) fprintf(file_out,"lines_per_special=%d\n",chan->lines_per_special); if (chan->special_added!=game.special_added) fprintf(file_out,"special_added=%d\n",chan->special_added); if (chan->special_capacity!=game.special_capacity) fprintf(file_out,"special_capacity=%d\n",chan->special_capacity); if (chan->classic_rules!=game.classic_rules) fprintf(file_out,"classic_rules=%d\n",chan->classic_rules); if (chan->average_levels!=game.average_levels) fprintf(file_out,"average_levels=%d\n",chan->average_levels); if (chan->sd_timeout!=game.sd_timeout) fprintf(file_out,"sd_timeout=%d\n",chan->sd_timeout); if (chan->sd_lines_per_add!=game.sd_lines_per_add) fprintf(file_out,"sd_lines_per_add=%d\n",chan->sd_lines_per_add); if (chan->sd_secs_between_lines!=game.sd_secs_between_lines) fprintf(file_out,"sd_secs_between_lines=%d\n",chan->sd_secs_between_lines); if (strcasecmp(chan->sd_message,game.sd_message)) fprintf(file_out,"sd_message=%s\n",chan->sd_message); fprintf(file_out,"block_leftl=%d\n",chan->block_leftl); fprintf(file_out,"block_leftz=%d\n",chan->block_leftz); fprintf(file_out,"block_square=%d\n",chan->block_square); fprintf(file_out,"block_rightl=%d\n",chan->block_rightl); fprintf(file_out,"block_rightz=%d\n",chan->block_rightz); fprintf(file_out,"block_halfcross=%d\n",chan->block_halfcross); fprintf(file_out,"block_line=%d\n",chan->block_line); fprintf(file_out,"special_addline=%d\n",chan->special_addline); fprintf(file_out,"special_clearline=%d\n",chan->special_clearline); fprintf(file_out,"special_nukefield=%d\n",chan->special_nukefield); fprintf(file_out,"special_randomclear=%d\n",chan->special_randomclear); fprintf(file_out,"special_switchfield=%d\n",chan->special_switchfield); fprintf(file_out,"special_clearspecial=%d\n",chan->special_clearspecial); fprintf(file_out,"special_gravity=%d\n",chan->special_gravity); fprintf(file_out,"special_quakefield=%d\n",chan->special_quakefield); fprintf(file_out,"special_blockbomb=%d\n",chan->special_blockbomb); if (chan->stripcolour!=game.stripcolour) fprintf(file_out,"stripcolour=%d\n",chan->stripcolour); if (chan->serverannounce!=game.serverannounce) fprintf(file_out,"serverannounce=%d\n",chan->serverannounce); if (chan->pingintercept!=game.pingintercept) fprintf(file_out,"pingintercept=%d\n",chan->pingintercept); if (strcasecmp(chan->game_type,game.game_type)) fprintf(file_out,"game.game_type=%s\n",chan->game_type); if (chan->winlist_file!=game.winlist_file) fprintf(file_out,"winlist_file=%d\n",chan->winlist_file); fprintf(file_out,"\n"); } chan=chan->next; } fprintf(file_out,"# End of File\n"); fclose(file_out); lvprintf(3,"Wrote new game configuration to %s\n", FILE_CONF); return(0); } /* gameread() */ /* Reads from a text format game.conf file, data into the game structure */ int gameread(void) { /* Read data from game.conf into structure game */ FILE *file_in; char buf[513]; char id_tag[81]; char id_value[81]; int i,j,error; struct channel_t *chan; chan=NULL; file_in = fopen(FILE_CONF, "r"); if (file_in == NULL) return(-1); while (fgets(buf, 512, file_in) != NULL) { net_query_TrimStr(buf); i=0; j=strlen(buf); while( (iname,id_tag)) ) chan=chan->next; if (chan==NULL) { /* New channel */ chan=chanlist; chanlist=malloc(sizeof(struct channel_t)); chanlist->next=chan; chan=chanlist; chan->maxplayers=DEFAULTMAXPLAYERS; chan->status=STATE_ONLINE; chan->description[0]=0; chan->priority=DEFAULTPRIORITY; chan->sd_mode=SD_NONE; chan->persistant=1; strcpy(chan->name,id_tag); /* Copy default settings */ chan->starting_level=game.starting_level; chan->lines_per_level=game.lines_per_level; chan->level_increase=game.level_increase; chan->lines_per_special=game.lines_per_special; chan->special_added=game.special_added; chan->special_capacity=game.special_capacity; chan->classic_rules=game.classic_rules; chan->average_levels=game.average_levels; chan->sd_timeout=game.sd_timeout; chan->sd_lines_per_add=game.sd_lines_per_add; chan->sd_secs_between_lines=game.sd_secs_between_lines; strcpy(chan->sd_message,game.sd_message); chan->block_leftl=game.block_leftl; chan->block_leftz=game.block_leftz; chan->block_square=game.block_square; chan->block_rightl=game.block_rightl; chan->block_rightz=game.block_rightz; chan->block_halfcross=game.block_halfcross; chan->block_line=game.block_line; chan->special_addline=game.special_addline; chan->special_clearline=game.special_clearline; chan->special_nukefield=game.special_nukefield; chan->special_randomclear=game.special_randomclear; chan->special_switchfield=game.special_switchfield; chan->special_clearspecial=game.special_clearspecial; chan->special_gravity=game.special_gravity; chan->special_quakefield=game.special_quakefield; chan->special_blockbomb=game.special_blockbomb; chan->stripcolour=game.stripcolour; chan->serverannounce=game.serverannounce; chan->pingintercept=game.pingintercept; chan->winlist_file=game.winlist_file; strncpy(chan->game_type, game.game_type, GAMETYPELEN-1); chan->game_type[GAMETYPELEN-1] = 0; } } else { id_tag[0]=0; id_value[0]=0; sscanf(buf,"%80[^= ] = %80[^\n]", id_tag, id_value); /* Yuk bit */ if (!strcasecmp(id_tag,"maxplayers")) { if (chan!=NULL) chan->maxplayers=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"priority")) { if (chan!=NULL) chan->priority=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"topic")) { if (chan!=NULL) { strncpy(chan->description, id_value, DESCRIPTIONLEN-1); chan->description[DESCRIPTIONLEN-1]=0; } error=0; } if (!strcasecmp(id_tag,"pidfile")) { strncpy(game.pidfile, id_value, PIDFILELEN-1); game.pidfile[PIDFILELEN-1]=0; error=0; } if (!strcasecmp(id_tag,"bindip")) { strncpy(game.bindip, id_value, IPLEN-1); game.bindip[IPLEN-1]=0; error=0; } if (!strcasecmp(id_tag,"maxchannels")) { game.maxchannels=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"starting_level")) { if (chan==NULL) game.starting_level=atoi(id_value); else chan->starting_level=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"lines_per_level")) { if (chan==NULL) game.lines_per_level=atoi(id_value); else chan->lines_per_level=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"level_increase")) { if (chan==NULL) game.level_increase=atoi(id_value); else chan->level_increase=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"lines_per_special")) { if (chan==NULL) game.lines_per_special=atoi(id_value); else chan->lines_per_special=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_added")) { if (chan==NULL) game.special_added=atoi(id_value); else chan->special_added=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_capacity")) { if (chan==NULL) game.special_capacity=atoi(id_value); else chan->special_capacity=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"classic_rules")) { if (chan==NULL) game.classic_rules=atoi(id_value); else chan->classic_rules=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"average_levels")) { if (chan==NULL) game.average_levels=atoi(id_value); else chan->average_levels=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"sd_timeout")) { if (chan==NULL) game.sd_timeout=atoi(id_value); else chan->sd_timeout=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"sd_lines_per_add")) { if (chan==NULL) game.sd_lines_per_add=atoi(id_value); else chan->sd_lines_per_add=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"sd_secs_between_lines")) { if (chan==NULL) game.sd_secs_between_lines=atoi(id_value); else chan->sd_secs_between_lines=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"sd_message")) { if (chan==NULL) { strncpy(game.sd_message, id_value, SDMSGLEN-1); game.sd_message[SDMSGLEN-1]=0; } else { strncpy(chan->sd_message, id_value, SDMSGLEN-1); chan->sd_message[SDMSGLEN-1]=0; } error=0; } if (!strcasecmp(id_tag,"command_kick")) { game.command_kick=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_msg")) { game.command_msg=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_op")) { game.command_op=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_list")) { game.command_list=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_join")) { game.command_join=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_persistant")) { game.command_persistant=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_save")) { game.command_save=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_reset")) { game.command_reset=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_who")) { game.command_who=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_topic")) { game.command_topic=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_priority")) { game.command_priority=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_move")) { game.command_move=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_winlist")) { game.command_winlist=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_set")) { game.command_set=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"command_help")) { game.command_help=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"serverannounce")) { if (chan==NULL) game.serverannounce=atoi(id_value); else chan->serverannounce=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"pingintercept")) { if (chan==NULL) game.pingintercept=atoi(id_value); else chan->pingintercept=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"stripcolour")) { if (chan==NULL) game.stripcolour=atoi(id_value); else chan->stripcolour=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"game_type")) { if (strcasecmp(id_value, "normal") && strcasecmp(id_value, "nickonly")) { strcpy(id_value, "normal"); } if (chan==NULL) { strncpy(game.game_type, id_value, GAMETYPELEN-1); game.game_type[GAMETYPELEN-1] = 0; } else { strncpy(chan->game_type, id_value, GAMETYPELEN-1); chan->game_type[GAMETYPELEN-1] = 0; } error = 0; } if (!strcasecmp(id_tag,"winlist_file")) { if (chan==NULL) game.winlist_file=atoi(id_value); else chan->winlist_file=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"timeout_ingame")) { game.timeout_ingame=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"timeout_outgame")) { game.timeout_outgame=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"verbose")) { game.verbose=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"block_leftl")) { if (chan==NULL) game.block_leftl=atoi(id_value); else chan->block_leftl=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"block_leftz")) { if (chan==NULL) game.block_leftz=atoi(id_value); else chan->block_leftz=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"block_square")) { if (chan==NULL) game.block_square=atoi(id_value); else chan->block_square=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"block_rightl")) { if (chan==NULL) game.block_rightl=atoi(id_value); else chan->block_rightl=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"block_rightz")) { if (chan==NULL) game.block_rightz=atoi(id_value); else chan->block_rightz=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"block_halfcross")) { if (chan==NULL) game.block_halfcross=atoi(id_value); else chan->block_halfcross=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"block_line")) { if (chan==NULL) game.block_line=atoi(id_value); else chan->block_line=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_addline")) { if (chan==NULL) game.special_addline=atoi(id_value); else chan->special_addline=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_clearline")) { if (chan==NULL) game.special_clearline=atoi(id_value); else chan->special_clearline=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_nukefield")) { if (chan==NULL) game.special_nukefield=atoi(id_value); else chan->special_nukefield=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_switchfield")) { if (chan==NULL) game.special_switchfield=atoi(id_value); else chan->special_switchfield=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_clearspecial")) { if (chan==NULL) game.special_clearspecial=atoi(id_value); else chan->special_clearspecial=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_randomclear")) { if (chan==NULL) game.special_randomclear=atoi(id_value); else chan->special_randomclear=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_gravity")) { if (chan==NULL) game.special_gravity=atoi(id_value); else chan->special_gravity=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_quakefield")) { if (chan==NULL) game.special_quakefield=atoi(id_value); else chan->special_quakefield=atoi(id_value); error=0; } if (!strcasecmp(id_tag,"special_blockbomb")) { if (chan==NULL) game.special_blockbomb=atoi(id_value); else chan->special_blockbomb=atoi(id_value); error=0; } if (error==1) { lvprintf(2,"%s: Unknown Identifier: %s\n", FILE_CONF, buf); } } } } fclose(file_in); lvprintf(3,"Read game configuration from %s\n", FILE_CONF); return(0); } /* init_game() */ /* Reset the game structure to default values, then try read the game data */ /* If game.conf does not exist, create new with defaults, otherwise do some */ /* sanity checks on the read in data */ void init_game(void) { /* Initialise game parameters */ strncpy(game.pidfile, FILE_PID, PIDFILELEN-1); game.pidfile[PIDFILELEN-1]=0; strncpy(game.bindip, "0.0.0.0", IPLEN-1); game.bindip[IPLEN-1]=0; game.maxchannels=1; game.starting_level = 1; game.lines_per_level = 2; game.level_increase = 1; game.lines_per_special =1; game.special_added=1; game.special_capacity=18; game.classic_rules=1; game.average_levels=1; game.sd_timeout=0; game.sd_lines_per_add=1; game.sd_secs_between_lines=30; strncpy(game.sd_message,"Time's up! It's SUDDEN DEATH MODE!", SDMSGLEN-1);game.sd_message[SDMSGLEN-1]=0; game.command_clear=3; game.command_kick=2; game.command_msg=1; game.command_op=1; game.command_list=1; game.command_join=1; game.command_who=1; game.command_topic=2; game.command_priority=2; game.command_move=2; game.command_winlist=1; game.command_help=1; game.command_set=4; game.command_persistant=3; game.command_save=3; game.command_reset=3; game.serverannounce=1; game.pingintercept=1; game.stripcolour=1; strcpy(game.game_type, "normal"); game.winlist_file=1; game.timeout_ingame=60; game.timeout_outgame=1000; game.verbose=4; game.block_leftl=14; game.block_leftz=14; game.block_square=15; game.block_rightl=14; game.block_rightz=14; game.block_halfcross=14; game.block_line=15; game.special_addline=32; game.special_clearline=18; game.special_nukefield=1; game.special_randomclear=11; game.special_switchfield=3; game.special_clearspecial=14; game.special_gravity=1; game.special_quakefield=6; game.special_blockbomb=14; /* First, see if game.conf exists */ if (gameread() == -1) { /* File does not exist, so lets create it */ lvprintf(4,"No game definitions found. Creating game.conf file with defaults.\n"); if (gamewrite() == -1) fatal("Can't write game.conf. Check permissions!",0); } if ((game.block_leftl+game.block_leftz+game.block_square+game.block_rightl +game.block_rightz+game.block_halfcross+game.block_line) != 100) { fatal("Block percentages MUST add up to 100%", 0); } if ((game.special_addline+game.special_clearline +game.special_nukefield+game.special_randomclear +game.special_switchfield+game.special_clearspecial +game.special_gravity+game.special_quakefield+game.special_blockbomb) != 100) { fatal("Special percentages MUST add up to 100%", 0); } if ( (game.starting_level < 1) || (game.starting_level > 100) ) fatal("Starting level must be in the range 1 to 100",0); if ( (game.lines_per_level < 1) || (game.lines_per_level > 100) ) fatal("Lines per level must be in the range 1 to 100",0); if ( (game.level_increase < 0) || (game.level_increase > 50) ) fatal("Level increase must be in the range 0 to 50", 0); if ( (game.lines_per_special < 1) || (game.lines_per_special > 50) ) fatal("Lines per special must be in the range 1 to 50", 0); if ( (game.special_added < 0) || (game.special_added > 50) ) fatal("Specials added must be in the range 0 to 50", 0); if ( (game.special_capacity < 0) || (game.special_capacity > 18) ) fatal("Special capacity must be in the range 0 to 18", 0); if ( (game.classic_rules < 0) || (game.classic_rules > 1) ) fatal("Classic rules must be either 0 or 1",0); if ( (game.average_levels < 0) || (game.average_levels > 1) ) fatal("Average player levels must be either 0 or 1", 0); /* if (gamewrite() == -1) fatal("Can't write game.conf. Check permissions!",0);*/ } struct winlist_t *find_winlist(struct net_t *n) { if (!n) return ((struct winlist_t *)NULL); if (n->channel->winlist_file == -1) return ((struct winlist_t *)NULL); if (n->channel->winlist_file == 2) return (winlist2); if (n->channel->winlist_file == 3) return (winlist3); return (winlist); } struct winlist_t *find_winlist_from_chan(char *chan_name) { char *p; struct channel_t *chan; p = chan_name; if (!p) return(winlist); if (*p == '#') p++; for (chan = chanlist; chan; chan=chan->next) if (!strcasecmp(p, chan->name)) break; if (!chan) return(winlist); if (chan->winlist_file == -1) return ((struct winlist_t *)NULL); if (chan->winlist_file == 2) return (winlist2); if (chan->winlist_file == 3) return (winlist3); return (winlist); } void find_winlist_file(struct net_t *n, char *fn) { if (n->channel->winlist_file == -1) fn[0] = '\0'; else if (n->channel->winlist_file == 2) strncpy(fn, FILE_WINLIST2, MAXFILENAMELEN-1); else if (n->channel->winlist_file == 3) strncpy(fn, FILE_WINLIST3, MAXFILENAMELEN-1); else strncpy(fn, FILE_WINLIST, MAXFILENAMELEN-1); fn[MAXFILENAMELEN-1] = 0; } int find_winlist_size(struct net_t *n) { return(MAXWINLIST); } /* Initialise Winlist structure, to all empty */ void init_winlist(struct winlist_t *w, int max_entries) { int i; for(i=0;i= 0); valid = valid && ( (w[i].status=='p') || (w[i].status=='t') ); valid = valid && (strlen(w[i].name) <= NICKLEN); i++; } if (!valid) { /* Screwed up winlist */ lvprintf(3,"Invalid Winlist - Resetting to 0!\n"); init_winlist(w, max_entries); } } void read_banlist(char *fname, struct ban_t *b, int max_entries) { int i, len; FILE *file_in; char ban_str[UHOSTLEN+1]; file_in = fopen(fname,"r"); if (file_in == NULL) return; ban_str[0] = 0; i = 0; while (i < max_entries && fgets(ban_str, UHOSTLEN-1, file_in)) { if (ban_str == NULL) break; len = strlen(ban_str); if (ban_str[len - 1] == '\n') ban_str[len-1] = '\0'; if (ban_str[0] == '#' || strlen(ban_str) < 4) { continue; } strncpy(b[i].addr, ban_str, UHOSTLEN); b[i].addr[UHOSTLEN] = 0; ban_str[0] = 0; i++; } fclose(file_in); } void read_allowlist() { int i, allow; FILE *file_in; char astr[128], anick[NICKLEN+1], apass[PASSLEN+1]; char *p; file_in = fopen(FILE_ALLOW,"r"); if (file_in == NULL) return; allow = 0; i = 0; while (i < MAXALLOW && fgets(astr, 128, file_in)) { if (astr[strlen(astr) - 1] == '\n') { astr[strlen(astr) - 1] = '\0'; } anick[0] = 0; apass[0] = 0; p = strtok(astr, " "); if (p) { strncpy(anick, p, NICKLEN); anick[NICKLEN] = 0; p = strtok(NULL, " "); if (p) { strncpy(apass, p, PASSLEN); apass[PASSLEN] = 0; } } if (strlen(apass) < 4 || anick[0] == '#') {continue; } strcpy(allowlist[i].nick, anick); strcpy(allowlist[i].pass, apass); i++; } fclose(file_in); } /* Write the winlist out to game.winlist*/ void writewinlist(struct net_t *n) { int i, max_entries; FILE *file_out; struct winlist_t *w; char fname[MAXFILENAMELEN+1]; w = find_winlist(n); if (!w) return; find_winlist_file(n, fname); max_entries = find_winlist_size(n); file_out = fopen(fname, "w"); if (file_out == NULL) return; for(i=0;iwlist_cache >= 0 && n->wlist_cache < max_entries) if (!strcasecmp(w[n->wlist_cache].name, name) && w[n->wlist_cache].status == status) { found=1; i = n->wlist_cache; } while ( (i0) && ( (!w[j-1].inuse) || (w[j-1].score < w[i].score) )) { /* Yep, it's higher than its parent so swap em */ j--; rec_winlist = w[j]; w[j]=w[i]; w[i]=rec_winlist; i=j; } n->wlist_cache = i; } /* Send winlist top10 to playernum (-1 = all) */ void sendwinlist(struct net_t *n) { int j,k; char name[NICKLEN+1]; unsigned char *P; struct net_t *nsock; struct winlist_t *w; if (!n) return; if (n->type != NET_PLAYBACK_CONNECTED) w = find_winlist(n); else w = find_winlist_from_chan (n->channel->name); if (!w) return; nsock=n; if ( ( (nsock->type == NET_CONNECTED)|| (nsock->type == NET_WAITINGFORTEAM) || (nsock->type == NET_PLAYBACK_CONNECTED)) ) { tprintf(nsock->sock,"winlist"); for(j=0;j<10;j++) { if (w[j].inuse) { /* TetriNET client does NOT like colour in the beginning of the name */ P=w[j].name; k=0; name[0]=0; while( *P != 0) { if( (*P != BOLD) && (*P != ITALIC) && (*P != UNDERLINE) && (*P != BLACK) && (*P != DARKGRAY) && (*P != SILVER) && (*P != NAVY) && (*P != BLUE) && (*P != CYAN) && (*P != GREEN) && (*P != NEON) && (*P != TEAL) && (*P != BROWN) && (*P != RED) && (*P != MAGENTA) && (*P != VIOLET) && (*P != YELLOW) && (*P != WHITE) && (*P != 11) && (*P != 32) ) { name[k]=*P; k++; } P++; } name[k]=0; tprintf(nsock->sock, " %c%s;%lu", w[j].status, name, w[j].score); } } tprintf(nsock->sock,"\xff"); } } void sendwinlist_to_all(struct net_t *n) { struct net_t *nsock; for (nsock = n->channel->net; nsock; nsock = nsock->next) sendwinlist(nsock); } /* Parse a field string, and update our internal knowledge of that player's field */ int parsefield(struct net_t *n, char *buf) { char *P; int blocktype,x,y; int bailout; /* First, check size of buf. If its FIELD_MAXX*FIELD_MAXY length, exactly, AND */ /* its first char is not a block type, then it's a field dump! */ bailout = 0; if (strlen(buf)==(FIELD_MAXX*FIELD_MAXY)) { if ( (buf[0] > '/') || (buf[0] < '!') ) { P=buf; for(y=0;yfield[x][y]=blocktype-'0'; } } else bailout=1; } else { P=buf; while ( !bailout && (*P != '\xff') && (*P != '\0') ) { /* Read in type of block char */ blocktype = *P; /* Sanity checking */ if ( (blocktype > '/') || (blocktype < '!') ) bailout=1; else { P++; blocktype-='!'; while ( !bailout && (*P != '\xff') && (*P != '\0') && (*P >= '3') && (*P <= '>') ) { x=*P; P++; y=*P; P++; /* Sanity checking again */ if ( (x >= '3') && (x <= '>') && (y >= '3') && (y <= 'H') ) { /* We have a co-ordinate. We have a block type. Set it! */ x-='3'; y-='3'; n->field[x][y] = blocktype; } else bailout=1; } } } } if (bailout) { /* This should not happen!!! */ lvprintf(2,"Slot(%s): Bailout error on field update!!", n->nick); return -1; } return 1; } /* Send to sock_index_to, the field of sock_index_from */ void sendfield(struct net_t *ns_to, struct net_t *ns_from) { int x,y; char block; const char special[9] = {'a','c','n','r','s','b','g','q','o'}; tprintf(ns_to->sock,"f %d ", ns_from->gameslot); for(y=0;yfield[x][y]+'0'); if ( (block >= '6') && (block <= '>') ) { /* Special block, so break rules and put the letter instead */ block = special[block-'0'-6]; } tprintf(ns_to->sock,"%c", block); } tprintf(ns_to->sock,"\xff"); } tetrinetx-1.13.16+qirc-1.40c/src/game.h0100600000076700007670000000265607271162601016657 0ustar drslumdrslum/* game.h Contains any configuration type external file functions. This includes all functions to read and write the game configuration files, and of course the winlist functions. */ /* Write, in plain english, with comments, a game.conf file from current settings */ int gamewrite(void); /* Read, from a text game.conf file, game settings */ int gameread(void); /* Initialise game settings to default values */ void init_game(void); /* Updates a current entry, or creates a new entry with score */ void updatewinlist(char *name, char status, int score, struct net_t *n); /* For special game types onetetris and timelimit */ void update_ntetris_winlist(struct net_t *n); void update_timelimit_winlist(struct net_t *n); void update_survival_winlist(struct net_t *n); void update_pwdlist(); struct winlist_t *find_winlist(struct net_t *n); struct winlist_t *find_winlist_from_chan(char *chan_name); void find_winlist_file(struct net_t *n, char *fn); int find_winlist_size(struct net_t *n); /* Initialise Winlist structure */ void init_winlist(struct winlist_t *w, int max_entries); void init_pwdlist(); /* Read Winlist, from winlist file */ void readwinlist(char *fname, struct winlist_t *w, int max_entries); void read_pwdlist(); /* Write Winlist to winlist file*/ void writewinlist(struct net_t *n); void write_pwdlist(); /* Send Winlist to players */ void sendwinlist(struct net_t *n); void sendwinlist_to_all(struct net_t *n); tetrinetx-1.13.16+qirc-1.40c/src/crack.c0100600000076700007670000002704107512452310017014 0ustar drslumdrslum/* crack.c This is the initial encryption-decryption module */ /* tet_dec2str(decrypted hex init string) */ /* Converts each hex value from the decrypted hex init string into */ /* corrosponding characters. */ char *tet_dec2str(char *buf) { /* Takes a decrypted string, and returns a string from the hex values */ char *strg; char *P, *Q; unsigned int curr; strg = malloc((strlen(buf)/2)+4); P=buf; Q=strg; P+=2; /* Skip the salt */ while( *P != '\0' ) { sscanf(P,"%2X", &curr); *Q=curr; P+=2; Q++; } *Q=0; return(strg); } /* tet_decrypt(encrypted init string) */ /* Scans string, tries to learn the encryption type and key from the */ /* first couple of values, then uses this on the rest. Overwrites */ /* encrypted string with decrypted hex string */ /* This was done because it means the encryption is IP independent!!!! */ int tet_decrypt(char *buf) { /* Decrypts an entire string. Overwrites encrypted string */ /* Returns 0 on success. -1 if failed */ char done; char *P; char back[3]; int j,k=0; unsigned int prev; unsigned int curr; unsigned char curr_dec; unsigned int enctype[10]; /* The order of the decrypt sequences */ const unsigned int decrypt_data[10] = /* tetrisstart */ /* {0xB4, 0xA5, 0xB4, 0xB2, 0xA9, 0xB3, 0xB3, 0xB4, 0xA1, 0xB2};*/ {0x74, 0x65, 0x74, 0x72, 0x69, 0x73, 0x73, 0x74, 0x61, 0x72}; int enctype_index, enctype_tot; enctype_index = 0; /* First, we teach ourself how to decrypt this beast */ P = buf; sscanf(P,"%2X", &curr); /* First hex pair is the salt */ P+=2; lvprintf(10,"LEARN\n"); enctype_index = 0; while(enctype_index < 10) { /* Learn from first 10 numbers */ done=0; j=1; prev=curr; sscanf(P,"%2X", &curr); while ( (!done) && (j<20) ) { curr_dec = tet_decryptchar(j,prev,curr); k=j; switch (j) { case 1: {j=2;break;} case 2: {j=3;break;} case 3: {j=4;break;} case 4: {j=5;break;} case 5: {j=6;break;} case 6: {j=7;break;} case 7: {j=8;break;} case 8: {j=9;break;} case 9: {j=10;break;} case 10: {j=99;break;} } done=( curr_dec==decrypt_data[enctype_index]); } if (!done) { lvprintf(4,"Unknown encryption type at pos %d.\n", enctype_index); return(-1); } lvprintf(10,"%d\n",k); enctype[enctype_index] = k; enctype_index++; P+=2; } /* Now see if we have a pattern in our 10 checks, and if so, reduce enctype_tot to that pattern */ j=0; done=0; enctype_tot=10; while(!done && (j < 5)) { j++; done=1; for (enctype_index=0; enctype_index < (10-j); enctype_index++) { done = done && (enctype[enctype_index] == enctype[enctype_index+j]); } } if (done) { /* done - Means we found a pattern ever j times */ enctype_tot = j; } lvprintf(10,"total=%d\n",enctype_tot); /* And volia, an IP independent encryption pattern :) I still don't know why it works ;)*/ /* Survived to here, so we should have the decryption sequence */ P = buf; /* Reset */ enctype_index=0; sscanf(P,"%2X", &curr); /* First hex pair is the salt */ P+=2; done = (*P == '\0'); while (!done) { prev=curr; sscanf(P,"%2X", &curr); curr_dec = tet_decryptchar(enctype[enctype_index],prev,curr); enctype_index++; if (enctype_index >= enctype_tot) enctype_index-=(enctype_tot); sprintf(back,"%02X",curr_dec); *P = back[0]; *(P+1)= back[1]; P+=2; done = (*P == '\0'); } return(0); } /* tet_decryptchar(Type of encryption, previous encrypted hexpair, current encrypted hex pair) */ /* Uses my standard decryption sequence on the encrypted hex pair, normalises it */ /* and subtracts from it the last encrypted pair. */ /* NOTE: These are the 10 "normalised" encryption techniques from an XOR */ unsigned char tet_decryptchar(int enctype, unsigned char prev, unsigned char cur) { long int curr; curr = cur; switch (enctype) { /* prev: Pp. cur: Cc */ case 1: /* Type #1 */ { /* - If <0,1,8,9> + Inc 6 else <2,3,A,B> + Inc 2 else <4,5,C,D> + Dec 2 else <6,7,E,F> + Dec 6 - F-c - FF-Cc */ if ( (((0xf&curr)) == 0) || (((0xf&curr)) == 1) || (((0xf&curr)) == 8) || (((0xf&curr)) == 9) ) curr+=6; else if ( (((0xf&curr)) == 2) || (((0xf&curr)) == 3) || (((0xf&curr)) == 0xA) || (((0xf&curr)) == 0xB) ) curr+=2; else if ( (((0xf&curr)) == 4) || (((0xf&curr)) == 5) || (((0xf&curr)) == 0xC) || (((0xf&curr)) == 0xD) ) curr-=2; else curr-=6; curr = (unsigned char)(0xf0&curr)+(0xf-(0xf&curr)); curr = (unsigned char)(0xff-curr); break; } case 4: /* Type #4 */ { /* - If mod 4 == 0 + Inc 3 else mod 4 == 1 + Inc 1 else mod 4 == 2 + Dec 1 else mod 4 == 3 + Dec 3 - F-c - FF-Cc */ if ( (curr % 4) == 0 ) curr+=3; else if ( (curr % 4) == 1 ) curr+=1; else if ( (curr % 4) == 2 ) curr-=1; else if ( (curr % 4) == 3 ) curr-=3; curr = (unsigned char)(0xf0&curr)+(0xf-(0xf&curr)); curr = (unsigned char)(0xff-curr); break; } case 2: /* Type #2 */ { /* - If + Inc 1 else + Dec 1 - F-c - FF-Cc */ if ( (curr % 2) == 0 ) /* If Even */ curr++; else /* If Odd */ curr--; curr = (unsigned char)(0xf0&curr)+(0xf-(0xf&curr)); curr = (unsigned char)(0xff-curr); break; } case 7: /* Type #7 */ { /* - If + inc 2 else + dec 2 - F-c - FF-Cc */ if ( (curr % 4) <= 1 ) /* 0 or 1 */ curr+=2; else /* 2 or 3 */ curr-=2; curr = (unsigned char)(0xf0&curr)+(0xf-(0xf&curr)); curr = (unsigned char)(0xff-curr); break; } case 5: /* Type #5 */ { /* - If <0-7> + inc 8 else <8-F> + dec 8 - If + dec 1 else + inc 1 - F-c - FF-Cc */ if ( ((unsigned char)(0xf&curr) <= 7) ) curr+=8; else curr-=8; if ( (curr % 2) == 0 ) /* If Even */ curr++; else /* If Odd */ curr--; curr = (unsigned char)(0xf0&curr)+(0xf-(0xf&curr)); curr = (unsigned char)(0xff-curr); break; } case 6: /* Type #6 */ { /* - If <0,1,2,3,8,9,A,B> + inc 4 else <4,5,6,7,C,D,E,F> + dec 4 - If + dec 1 else + inc 1 - F-c - FF-Cc */ if ( ( ( ((0xf&curr)) >=0x0 ) && ( ((0xf&curr)) <= 0x3 ) ) || ( ( ((0xf&curr)) >=0x8 ) && ( ((0xf&curr)) <= 0xB ) ) ) curr+=4; else curr-=4; if ( (curr % 2) == 0 ) /* If Even */ curr++; else /* If Odd */ curr--; curr = (unsigned char)(0xf0&curr)+(0xf-(0xf&curr)); curr = (unsigned char)(0xff-curr); break; } case 10: /* Type #10 */ { /* - If <0,1,2,3,8,9,A,B> + inc 4 else <4,5,6,7,C,D,E,F> + dec 4 - F-c - FF-Cc */ if ( ( ( ((0xf&curr)) >=0x0 ) && ( ((0xf&curr)) <= 0x3 ) ) || ( ( ((0xf&curr)) >=0x8 ) && ( ((0xf&curr)) <= 0xB ) ) ) curr+=4; else curr-=4; curr = (unsigned char)(0xf0&curr)+(0xf-(0xf&curr)); curr = (unsigned char)(0xff-curr); break; } case 8: /* Type #8 */ { /* - If <0-7> + Inc 8 else <8-F> + Dec 8 - FF-Cc */ if ( ((unsigned char)(0xf&curr) <= 7) ) curr+=8; else curr-=8; curr = (unsigned char)(0xff-curr); break; } case 9: /* Type #9 */ { /* - F-c - FF-Cc */ curr = (unsigned char)(0xf0&curr)+(0xf-(0xf&curr)); curr = (unsigned char)(0xff-curr); break; } case 3: /* Type #3 */ { /* - If <0-7> + Inc 8 else <8-F> + Dec 8 - F-c - FF-Cc */ if ( ((unsigned char)(0xf&curr) <= 7) ) curr+=8; else curr-=8; curr = (unsigned char)(0xf0&curr)+(0xf-(0xf&curr)); curr = (unsigned char)(0xff-curr); break; } default: { lvprintf(2,"Internal Error - Unknown encryption type #%d\n", enctype); exit(1); break; } } /* If curr is in the range: (re-normalisation) - 00-3F: inc 80+80 - 40-7F: inc 80 - 80-BF: nothing - C0-FF: inc 7F */ if ( (curr >= 0x0) && (curr <= 0x3F) ) curr+=(0x80+0x80); else if ( (curr >= 0x40) && (curr <= 0x7F) ) curr+=(0x80); else if ( (curr >= 0xC0) && (curr <= 0xFF) ) curr+=(0x7F); /* Now subtract from curr, the previous value */ curr -= prev; /* And subtract 0x40, though I have no idea why */ curr -= 0x40; /* Now get it into a reasonable value */ while (curr > 0xFF) curr -= 0xff; while (curr < 0x0) curr += 0xff; return(curr); } tetrinetx-1.13.16+qirc-1.40c/src/crack.h0100600000076700007670000000244007271162601017020 0ustar drslumdrslum/* crack.h This contains my IP independent algorithm to decrypt the initial encrypted initstring sent by the client to the server. 3 days work ;) Addedum (15/9/98): The actual encryption algorithm has now been kindly provided by BlueCoder, found in #tetrinet on EFNET, who is making his own TetriNET clone which is compatible with TetriNET. If I do include it, it will be found very likely in crack.c, with the name blu_decrypt, blu_encrypt. As I'm not creating a client, I don't need to use the exact algorithm, and so my own techniques are used here. */ /* Takes a decrypted string in hex pairs, removes salt, and converts it to ascii */ char *tet_dec2str(char *buf); /* Takes an encrypted string, and overwrites it with the decrypted string */ /* This function "learns" how to decrypt the encryption on the fly, to allow */ /* IP independent decryption (Lets say that that was a side effect ;) */ int tet_decrypt(char *buf); /* Takes an encrypted hex pair, and decryptes it to a decrypted hex pair, based */ /* on one of 10 "normalised" encryption techniques */ unsigned char tet_decryptchar(int enctype, unsigned char prev, unsigned char cur); tetrinetx-1.13.16+qirc-1.40c/src/dns.c0100600000076700007670000001060007512453600016511 0ustar drslumdrslum/* dns.c This source code use libadns code by Ian Jackson and Tony Finch Homepage: http://www.chiark.greenend.org.uk/~ian/adns */ int rcode; const char *config_text; static char *buf; int ov_env=1, ov_pipe=0, ov_asynch=0; int ov_verbose= 0; adns_rrtype ov_type= adns_r_none; int ov_search=0, ov_qc_query=0, ov_qc_anshost=0, ov_qc_cname=1; int ov_tcp=0, ov_cname=0, ov_format=fmt_default; char *ov_id= 0; struct perqueryflags_remember ov_pqfr = { 1,1,1, tm_none }; adns_state ads; struct outstanding_list outstanding; static unsigned long idcounter; void quitnow(int rc) { if (ads) adns_finish(ads); free(buf); free(ov_id); exit(rc); } void sysfail(const char *what, int errnoval) { fprintf(stderr,"adnshost failed: %s: %s\n",what,strerror(errnoval)); quitnow(10); } void outerr(void) { sysfail("write to stdout",errno); } void *xmalloc(size_t sz) { void *p; p= malloc(sz); if (!p) sysfail("malloc",sz); return p; } char *xstrsave(const char *str) { char *p; p= xmalloc(strlen(str)+1); strcpy(p,str); return p; } void ensure_adns_init(void) { adns_initflags initflags; int r; if (ads) return; if (signal(SIGPIPE,SIG_IGN) == SIG_ERR) sysfail("ignore SIGPIPE",errno); initflags= adns_if_noautosys|adns_if_nosigpipe|ov_verbose; if (!ov_env) initflags |= adns_if_noenv; if (config_text) { r= adns_init_strcfg(&ads, initflags, stderr, config_text); } else { r= adns_init(&ads, initflags, 0); } if (r) sysfail("adns_init",r); if (ov_format == fmt_default) ov_format= ov_asynch ? fmt_asynch : fmt_simple; } static void prep_query(struct query_node **qun_r, int *quflags_r) { struct query_node *qun; char idbuf[20]; ensure_adns_init(); qun= malloc(sizeof(*qun)); qun->pqfr= ov_pqfr; if (ov_id) { qun->id= xstrsave(ov_id); } else { sprintf(idbuf,"%lu",idcounter++); idcounter &= 0x0fffffffflu; qun->id= xstrsave(idbuf); } *quflags_r= (ov_search ? adns_qf_search : 0) | (ov_tcp ? adns_qf_usevc : 0) | ((ov_pqfr.show_owner || ov_format == fmt_simple) ? adns_qf_owner : 0) | (ov_qc_query ? adns_qf_quoteok_query : 0) | (ov_qc_anshost ? adns_qf_quoteok_anshost : 0) | (ov_qc_cname ? 0 : adns_qf_quoteok_cname) | ov_cname, *qun_r= qun; } int query_do(const char *domain) { struct query_node *qun; int quflags, r; prep_query(&qun,&quflags); qun->owner= xstrsave(domain); r= adns_submit(ads, domain, ov_type == adns_r_none ? adns_r_addr : ov_type, quflags, qun, &qun->qu); if (r) sysfail("adns_submit",r); LIST_LINK_TAIL(outstanding,qun); return(atoi(qun->id)); } static void dequeue_query(struct query_node *qun) { LIST_UNLINK(outstanding,qun); free(qun->id); free(qun->owner); free(qun); } int get_dns_status(adns_status st, struct query_node *qun, adns_answer *answer) { const char *statusstring; statusstring= adns_strerror(st); if (!strncasecmp(statusstring, "OK", 2)) return 0; return -1; } static const char *owner_show(struct query_node *qun, adns_answer *answer) { return answer->owner ? answer->owner : qun->owner; } static void check_status(adns_status st) { static const adns_status statuspoints[]= { adns_s_ok, adns_s_max_localfail, adns_s_max_remotefail, adns_s_max_tempfail, adns_s_max_misconfig, adns_s_max_misquery }; const adns_status *spp; int minrcode; for (minrcode=0, spp=statuspoints; spp < statuspoints + (sizeof(statuspoints)/sizeof(statuspoints[0])); spp++) if (st > *spp) minrcode++; if (rcode < minrcode) rcode= minrcode; } int query_done(struct query_node *qun, adns_answer *answer, char *result) { adns_status st, ist; int rrn, nrrs; const char *rrp, *realowner, *typename; char *datastr; int ret; st= answer->status; nrrs= answer->nrrs; ret = atoi(qun->id); check_status(st); if (get_dns_status(st, qun, answer) < 0) { result[0] = 0; } if (qun->pqfr.show_owner) { realowner= answer->cname ? answer->cname : owner_show(qun,answer); } else { realowner= 0; } if (nrrs) { for (rrn=0, rrp = answer->rrs.untyped; rrn < nrrs; rrn++, rrp += answer->rrsz) { ist= adns_rr_info(answer->type, &typename, 0, 0, rrp, &datastr); if (ist == adns_s_nomemory) sysfail("adns_rr_info failed",ENOMEM); assert(!ist); strncpy(result, datastr, 120); result[120] = 0; free(datastr); } } free(answer); dequeue_query(qun); return ret; } tetrinetx-1.13.16+qirc-1.40c/src/dns.h0100600000076700007670000000562307512453650016534 0ustar drslumdrslum#include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "adns.h" /* declarations related to option processing */ enum ttlmode { tm_none, tm_rel, tm_abs }; enum outputformat { fmt_default, fmt_simple, fmt_inline, fmt_asynch }; struct perqueryflags_remember { int show_owner, show_type, show_cname; int ttl; }; extern int ov_env, ov_pipe, ov_asynch; extern int ov_verbose; extern adns_rrtype ov_type; extern int ov_search, ov_qc_query, ov_qc_anshost, ov_qc_cname; extern int ov_tcp, ov_cname, ov_format; extern char *ov_id; extern struct perqueryflags_remember ov_pqfr; /* declarations related to query processing */ struct query_node { struct query_node *next, *back; struct perqueryflags_remember pqfr; char *id, *owner; adns_query qu; }; extern adns_state ads; extern struct outstanding_list { struct query_node *head, *tail; } outstanding; void ensure_adns_init(void); int query_do(const char *domain); int query_done(struct query_node *qun, adns_answer *answer, char *result); /* declarations related to main program and useful utility functions */ void sysfail(const char *what, int errnoval); void outerr(void); void *xmalloc(size_t sz); char *xstrsave(const char *str); extern int rcode; extern const char *config_text; /* 0 => use defaults */ #define ADNS_VERSION_STRING "1.0" #define VERSION_MESSAGE(program) \ program " (GNU adns) " ADNS_VERSION_STRING "\n\n" COPYRIGHT_MESSAGE #define VERSION_PRINT_QUIT(program) \ if (fputs(VERSION_MESSAGE(program),stdout) == EOF || \ fclose(stdout)) { \ perror(program ": write version message"); \ quitnow(-1); \ } \ quitnow(0); void quitnow(int rc); #define LIST_INIT(list) ((list).head= (list).tail= 0) #define LINK_INIT(link) ((link).next= (link).back= 0) #define LIST_UNLINK_PART(list,node,part) \ do { \ if ((node)->part back) (node)->part back->part next= (node)->part next; \ else (list).head= (node)->part next; \ if ((node)->part next) (node)->part next->part back= (node)->part back; \ else (list).tail= (node)->part back; \ } while(0) #define LIST_LINK_TAIL_PART(list,node,part) \ do { \ (node)->part next= 0; \ (node)->part back= (list).tail; \ if ((list).tail) (list).tail->part next= (node); else (list).head= (node); \ (list).tail= (node); \ } while(0) #define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,) #define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,) tetrinetx-1.13.16+qirc-1.40c/src/compile.freebsd0100700000076700007670000000032207512452055020551 0ustar drslumdrslum#!/bin/sh echo [Linux] Compiling TetriNET Server [../bin/tetrix.linux] set -x gcc -O2 -I/usr/local/include -fno-strength-reduce -Wall -Iadns/src main.c -o ../bin/tetrix.freebsd $1 $2 $3 -L/usr/local/lib -ladns tetrinetx-1.13.16+qirc-1.40c/README0100600000076700007670000000060607512456525015670 0ustar drslumdrslumTetrinet-x is the implementation of tetrinet 1.13 server. This program is distributed under GNU Public License. For more information. Visit: http://tetrinet.org. Note: This source package requires libadns to be installed. You can get libadns from: http://www.chiark.greenend.org.uk/~ian/adns/ Tetrinet-x is distributed under GNU Public License. See the file COPYING for more detail. tetrinetx-1.13.16+qirc-1.40c/COPYING0100600000076700007670000004310507512453010016026 0ustar drslumdrslum GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. tetrinetx-1.13.16+qirc-1.40c/ChangeLog0100600000076700007670000005546007512454663016573 0ustar drslumdrslumVersion 1.13.16 (Build 16) with qirc patch ------------------------------------------ 04/23/01 qirc-1.40 - Asynchronus reverse DNS resolving support by utilizing GNU adns library 04/22/01 qirc-1.26 - Ban format changed to free-form wildcard(*,?) format See: game.ban.example 04/16/00 qirc-1.24 - Fix check_timeout bug which can cause avalanche disconnection - Separate timeout cycle time for gameplay and suddendeath/custom This is in turn reduce CPU usage significantly - Fix bug which allows a player to perform a switch with dead players - Remove fscanf routine in numerous places and replace with new code to avoid infinite loop bug for notepad-based server runner - Ignore csx where x is not 1,2 or 4 in the game with special blocks. Adjust level update detection parameters for cheat/lag - Make the program display something when the server start :) to avoid newbie confusion of seeing nothing - Fix buffer overflow bug in sendwinlist 03/18/00 qirc-1.23 - Fix buffer overflow in lvprintf() which happens to all version of tetrix! - Fix /who in qirc support - Put the support for /quote set in qirc for basic channel settings 02/06/00 qirc-1.22 - Fix bug in level_increase setting reported by gimp/ekn - Fix motd bug reported by gimp 01/03/00 qirc-1.21-final 12/05/99 qirc-1.20 - Spectator support for gtetrinet and tspec is now ready - Major code clean up. Create net_playback_send() - Rewrite arg part of lvprintf lprintf tprintf net_query_parser() to use a portable vsnprintf. varargs.h style is obsoleted. Also fix the buffer overflow potential due to "vsprintf". - Fix various part in spectator support - Fix a various minor bugs in irc support - Block invalid/corrupt field send by clients - This version will obsolete the qirc-0.5x development. qirc-0.5x will no longer be maintained 11/07/99 qirc-1.08d *beta release* - Fix nick/team name check to better detect invalid nick/team name - Fix spectator support for /move, invalid / command, add /help - Fix qirc to be more rfc1459 compliant 10/16/99 qirc-1.06m *experimental* - Game play watch (spectators) / playback support for gtetrinet and Tspec. (README.qirc.spectators) - New ban format: See examples in ./bin directory. This makes it possible to handle both hostname and IP. - New ban scheme and files: game.(ban, compromise, allow) Server first checks game.ban (hard banlist) and ban that person immediately. After a player has logged on (server received team name), server checks game.ban.compromise and game.allow the players will be banned if they are in compromise file but not in game.allow file. Allow file contains nickname/password which will be allowed as privilledge access. (password = teamname) i.e You can allow just your close AOL friends to play but not other AOL users. - To make new ban/allow list take effect you need to go to an irc session and type /quote readaccesslist !!!! (This is to reduce server resource consumption. We don't want to read banfile on each player join). Restart the server would also do it. - Add game type "nickonly". Server ignores teamnames when updating winlist. Players who teamup will not get any points. - Fix server did not aware of a color in nickname (report by dynweb) - More aggressive cheat detector especially for PURE! Server counts no. of pieces drops and analyze it. i.e. you cannot drop only 3 pieces in total and add 1 line to all. This in turn prevents the lag effect from previous game (have you seen someone playing previous game while you are playing current game?). Server detects a bogus message pattern. And detect invalid lvl update which could cause immediate level increase for all players. To look for a cheater do "cat game.log |grep Cheating" - Add broadcast message command "/quote wall" to qirc - Server now informs qirc clients when a qirc client exits. - Optimize server CPU usage in many places. Also remove most lvprintf line (Only important events are logged). - Fix qirc not to allow same nicknames (irc/player/spectators) - Fix a minor tetrix typo which made the channel STATE INGAME even noone is on the channel. - Change scoring. Winner get 2or3 points runner-up get 0or1 point - Fix unsafe pline command parsing code in original Tetrix. - Fix win report on non-playing sockets. - Add a small code to make it possible for a client to know that this server is a unix server. 03/10/99 qirc-1.05a - Patch against attack using EOL in nick or teamname - Block cheater who uses special in PURE channel - Support 2 winlists which can be set using winlist_file (1, 2 or -1) where -1 = no score recorded. - /winlist #channelname - Fix /msg bug suggested by ekn 02/15/99 qirc-1.04 - Implement flood control at game start to prevent people get flooded off - Implement new timeout control scheme. Timeout is now reset at net_activity, net_telnet and pline. Each net_t has 2 timeout variables to handle each case. - Add wlist_cache variable to net_t to possibly reduce the winlist update time. Also remove readwinlist() at game start and increase MAXWINLIST to 800. Add net_query_creadwinlist - Minor change to net_query_cuserhost and cmode - Bound check strcpy() in various places 02/01/99 qirc-1.03 - Fixed the mysterious access violation bugs =) 01/30/99 qirc-1.02 - Fix pause thingy. - Bound check /topic (net_query_ctopic) - Change startgame 0 so that game can be stopped when paused. - Change MAXWINLIST to 200. suggested by ekn. 01/28/99 qirc-1.01 - add nickname to server chat message :) suggested by ekn 01/26/99 qirc-1.0 - First public release with qirc patch Version 1.13.16 (Build 16) -------------------------- Comments: Treat this as just a version of bug fixes :) Changes: * Added better logging More logging added, and it's easier to understand. * Eradicated coredump on timeout * Changed /Priority Now if you give a channel a priority of 0, no-one will autojoin it. * Fixed bug, when play * Fixed SuddenDeath Addlines Ok, my addlines didn't look proffesional :). Now it just adds lines to you, and doesn't say ANYTHING in the information window. Yep, iAM informed me that TetriNET for Win95 already had the feature, so I didn't need to recreate it, thank heavens, since having a line added to you from looks pretty suspicious. * FIXED a bug that used up file handles game.motd was being opened and never closed. Eventually the server is killed due to lack of filehandles, or is hard to log into. Damn this was a bastard to find :P. * IP column to /who (Suggestion by Hinder - 1/1/1999) If you are an authenticated OP, and type /who, there is an additional column, IP, which shows each players IP. This is added in, with a /ban keyword in mind for a future version (hopefully the next). Version 1.13.15 (Build 15) -------------------------- Comments: Found a few small bugs in Build 14, so I fixed them, plus I've decided to be daring and remove as many of the large loops in the server as I can, since it's chewing CPU time. So now people are grouped by channels instead of in one huge big list, which really makes much more sense. Changes: * Fixed wierd bug Commented out about 30 lines of code. What THE HELL was that doing there :). Should clear a few bugs. * Group Network sockets by Channels Eradicate long loops and program overhead * Fixed preset channels A small bug in Build 14 made preset channels disapear. FIXED! Version 1.13.14 (Build 14) -------------------------- Comments: I have discovered something. I program as a kind of stress relief. During my most happiest days in my life, the last 3 months :), I've programmed just about zilch. Now that I'm getting extemely worried about things, IE, very worried for my beautiful girlfriend, who has certainly changed my life, I program, and boy do I. Many MANY changes in this version. Ok, probably not very interesting information to you, but if a physcologist happens to read this, who knows :P Changes: * MORE bug fixes. Oh hell, someone kill me. * SUDDENDEATH mode (So many people requested this) After a set number of seconds, the game can go into suddendeath, where lines start being added to everyones screen. * Persistant channels (Requested by so many people) You can now create preset channels in game.conf, AND you can even on the tetrinet game, make certain channels persistant. Added the following commands: - /persistant <0/1> Make a channel persistant - /save SAVE persistant channels and info to game.conf. Reasonably intelligent. - /reset LOAD all configuration from game.conf * Updated logging New game.conf tag: verbose. Setting a value to this from 0-10, sets how verbose the log is. A good setting is 4. An extremely noisy setting is 10. * /SET command Added a new TetriNET command. /Set. Type /set help to find out what options there are. /Set allows you to set the type of configuration, like percentage of block types on a per channel basis. If you get a channel just the way you want, AND you own the server, AND you want to keep that channel for future use. Just go /persistant to make it persistant, and then /save to save it :). Saves having to try create the info manually in game.conf. Version 1.13.13 (Build 13) -------------------------- Comments: My last version was to put it plainly and very very nicely, horribly horribly buggy. I'm hoping I've managed to quash every one of those extemely annoying and frustrating bugs. Introducing channels caused a LOT of problems. However, things should be ok now. Changes: * Bug files galore (Too many to list) * Update network engine I found the eggdrop code I originally used a little bit limiting. So I've heavily modified it to provide full dynamic allocation of resources. This should save a stack of memory. Next version, I'll erradicate the many many loops. Version 1.13.12 (Build 12) -------------------------- Comments: Quite a radical change in this one. Introduction of an IRC type channel structure, to allow really powerful servers to run multiple "virtual" tetrinet servers on the same port :) and IP. Changes: * Fixed up uninitilisation bugs WOW, going through my code, I found so many places where I simply did not initialize important variable because I'd added them at a later date, and forgot to add that in. How the previous versions worked, escapes me ;) * Channel structure (Combined discussion anut, rainbrot, me) Redesign the server to allow channels or "virtual" servers. Essentially, when the server is configured to allow more than just one channel, players may "/join" other channels, and play on them, just as if they were seperate servers. Also, When one channel fulls up, new players overflow to new channels... * Binding to IP's (Suggestion by [Op] - 2/11/98) Before, the server listened to ALL IP's on the system. If you want to run a seperate server on seperate IP's, then you can now bind the server to specific IP's. Edit game.conf and modify "bindip", and change it from 0.0.0.0 (All IP's), to that specific IP. Then you can run multiple instances of the tetrinet server, if and only if they bind to different IP's (and thus have different game.conf files). * Added built-in commands: - /join <#channelname|number> Join or create a new virtual channel. - /list List all virtual channels on the server. - /priority Change channel priority. When a new player connects to the server, they join the lowest priority channel that is not full. - /topic Change topic of channel, showed in /list - /who Show ALL logged in players, and what channel they are in. * Added game.conf entries: - bindip [0.0.0.0] What IP to bind server to, or ALL (0.0.0.0) - maxchannels [1] How many virtual channels the server will allow. The default 1, means no other channels are available. You probably want to change this. - command_join - command_list - command_priority - command_topic - commant_who Permissions to use these commands. Version 1.13.11 (Build 11) -------------------------- Comments: Geez, I seem to be making new builds daily :) I had to rush this one out, because of one incredibly serious flaw in Build 10 that I introduced by mistake. It didn't have a limit on the number of players allowed to connect, and as soon as 7 players connect, havoc reigns. Fixed phew. Changes: * Fixed max number of players * Supports AdvancedQuery standard (Added by dds - 13/10/98) Port 31456 allows the following advanced queries to be sent to it: - securequery server_password Gives back of each logged in player. - killplayer server_password gameslot Kicks the player occupying gameslot off server. All the query code was sent in by dds. * Fixed "playerquery" to count people waiting for teams as well Whoops, forgot them, not that it would affect many servers. * Introduced timeout variables in game.conf Two new tags in game.conf introduced: - timeout_ingame [60] - timeout_outgame [1200] They are the number of seconds of no activity before a player is considered timed out, and dropped, when a person is playing a game and when they are not. Note that during a game, because the fields should update at most intervals of 30seconds, the timeout for that should be much less, then for when no game is player, when people do just tend to sit there quietly (but not surely for 1200 seconds:) Version 1.13.10 (Build 10) -------------------------- Changes: * Introduced timeouts (Suggestion by crazor - 17/9/98) If no activity from a player, they are eventually disconnected from the game. * Updated playerquery (Suggestion by dds - 12/9/98) Now returns a more accurate figure for number of logged in players, since it now ONLY counts players that are properly logged in, NOT ghost connections. * Updated /msg /kick etc (Suggestion by iAM - 8/10/98) Now, /msg etc... take for the playernumber argument multiple playernumbers... IE: To msg players 2,3,5, you'd write "/msg 235 My message". To kick players 1 and 6, you'd write "/kick 16 My message" * Fixed Winlist under TetriNET I noticed that when someone has colour in their nicks, and they get onto the winlist, then if the server sends their nick _in colour_ to TetriNET client winlist, the next time that person starts TetriNET client, it crashes. Colour is now stripped out of the data sent to TetriNET client winlist now. * Added security levels (Suggestion by dds - 11/10/98) dds suggested that I introduce a way to prevent /kicks or /clears from being done by any player who just happens to get op. So I've introduced security levels. The game.conf options "command_=number", has now been modified so that you can have number to be one of the following: 0: disabled (IE:command_kick=0) 1: anyone can use (IE:command_winlist=1) 2: OP by position can use (IE:command_kick=2) 3: OP by "/op" can use (IE:command_clear=3) This is so you can configure your server so that some rogue person who happens to get position #1 can't say /clear your winlist on a ladder server :P Version 1.13.09 (Build 09) -------------------------- Changes: * Added tags to game.conf to allow more customization stripcolour (Strip colour in gmsg's) serverannounce (Server announces winner?) pingintercept (Intercept Pings?) command_kick (Allow /kick?) command_msg (Allow /msg?) command_op (Allow /op?) command_winlist (Allow /winlist?) command_help (Allow /help?) command_clear (Allow /clear?) * Patched /op command Doesn't allow /op command while game is going :). Version 1.13.08 (Build 08) -------------------------- Comments: Been about 2 or 3 weeks since I've worked on this, and for the simple reason that I've completely head over heels fallen in love :-). But I'm back onto it. Thanks for all those really nice emails that came in. Changes: * Check for invalid winlist files. If a winlist file is in the wrong format (Say from a previous version) it is reset. Is there much need for backwards compatibility here? * Updated security I knew I'd find some. Buffer overruns. Fixed. * Updated /help Now includes help on the new /msg, /winlist. Also looks prettier ;) * Added /op keyword (Suggestion by (jawfx@hotmail.com 21/9/98)) I've added some security functions as well, by popular request. In game.secure, if you uncomment the "op_password" tag and put a password there, then if a player types "/op ", where is what is given in the game.secure file, then that player will swap places with the OP player. Yes, it works :) If you don't have a game.secure file, then run the server and it will automatically create one for you. Default's to no password, which disables this feature. * Made the colour stripping in gmsg less strict Now only strips exact colour codes, not characters below ascii 32 * Added /clear keyword (Suggestion by n|ck 6/10/98) When the OP types /clear, the server will clear it's internal winlist, and update all the clients. Version 1.13.07 (Build 07) -------------------------- Comments: Oh geez, what a list of bugs ;). I've still not fixed some, but as soon as I trace what they are, we'll see what can be done. Please NOTE: This version uses a different format WINLIST file, and has an extra option in the game.conf file. You will definately have to delete "game.winlist", and you may want to delete "game.conf" file. Yeah, I should have a mechanism that detects corrupt winlist files... I will next version ;), otherwise TetriNET client literally shits itself when funny winlist values come through. Don't blame it either. Changes: * Fixed Winlist score. (dds reported it 18/9/98) Fixed a silly error where I used signed numbers for the winlist score, and thus -1 became some ridiculously large number. * Fixed TET_DEBUG entries in code * Added "/winlist xx" to partyline (crazor 17/9/98) If a person type "/winlist xx", where xx is the number of winlist entries they want to display, then a rank of the top xx entries are displayed, with the players own team and player name highlighted in red. * Added "/msg " (crazor 17/9/98) Added a rather crude way to privately message someone else in the party line. Crude in that the client does not handle it too well, but hey, it works :) * Added Hotswap of game.conf and game.winlist (crazor 17/9/98) Before every game, the game config and winlist are re-read so that if they are modified, the server does NOT have to restart. * Fixed Field Updating incorrectly on-join (iAM 17/9/98) What a stupid error to make. Took me ages to trace it down. * Added PID file (jawfx@hotmail.com - Ken Iverson 21/9/98) Added open "pidfile" to game.conf. The server now writes its PID to this file. Version 1.13.06 (Build #6) -------------------------- Changes: * Better handling of what to do when a player quits. In previous versions, when a currently playing player leaves, my server didn't do a good enough job of checking to see if only 1 team or 1 player was left playing. Now it should stop the game and add score to the winners properly. * Modified "playerquery\xff" to "playerquery\n" I thought that if you sent "playerquery\xff" to a real TetriNET server it would be treated as junk and ignored. However, it is interpreted and crashes it, so I've changed it to "playerquery\n", where \n is newline, which works as it should. What a mistaka to maka. * Removed all snprintf and vsnprintf (drslum - 17/9/98) For security reasons, I usually use bounds checking functions. drslum has notified me that snprintf does not exist under SUN systems. I now use other methods AND at the same time fixed some small potential buffer over-run problems. I would still not recommend the server be run as root. * Removed Colour VIOLET from being forced before every action. This is due to the fact that TetriNET client actually uses colours like toggles. If the action was already VIOLET, that is, the player had no colour codes in their nick, then it became black. I'll fix this by scanning the nick for colour codes in my next build ;) Version 1.13.01-1.13.05 (Build #1, #2, #3, #4, #5) -------------------------------------------------- Consider these version as the "undistributed" versions. They were my private major changes to the TetriNET server, each time I wanted to add something in. At this stage, the server behaves and looks from the client exactly like a TetriNET Server behaves, with some small exceptions, listed in the "Features" section. Features: * /kick The "op" of the server can now kick players using this keyword in the partyline. Normally, unless YOU are the server, TetriNET won't allow you to kick a player. * PING-PONG in GameMessage I got sick of people filling the game message with "t", to test the speed of the Server. While a completely valid thing to do, sometimes it scrolled important messages away. Now, if a player in a game sends "t" to the game message, the server will reply to them, and only to them "PONG", and not forward the "t" to the other players. * Colour Nicks in Game Message People with color nicks were just about unrecognizable in game messages, because colour is not parsed there by the client. Now if a player has colour codes in their nick, and they send a game message, that message has the colour codes stripped out of the nick portion. * Colour Nicks in Party Line Before every message, a "BLACK" colour code is placed, so that the colour from the nick doesn't reach the line. Before every action, a "VIOLET" colour code is placed, so that the colour from the nick doesn't affect the action. * game.motd When a player connects to the server, if there is a game.motd file, it is sent to them as from "". * End of game, annouce winner Ever wonder who won? At the end of a game, the "" will announce the player or team that won. * /help partyline keyword If someone types "/help" in the party line, they get a list of commands that are available, like "/me" and "/kick". * playerquery If a client connects to the Server, and instead of sending their INIT string, sends "playerquery\n", \n is newline "Number of players logged in: n" Where n is the number of players logged in. This is fully compatible with real TetriNET servers, since they will just disconnect you, whereas mine returns the number of players before disconnecting you. * 100 item winlist Yep, for those incredibly long ladder games, I've extended the winlist to store the top 100 teams/players. Of course only the top 10 are shown in the TetriNET winlist, but now you know you can work you way up :) tetrinetx-1.13.16+qirc-1.40c/AUTHORS0100644000076700007670000000012207512456153016056 0ustar drslumdrslumBrendan Grieve Roongroj Phoophuangpairoj tetrinetx-1.13.16+qirc-1.40c/README.qirc.spectators0100600000076700007670000000577107512455277021026 0ustar drslumdrslum!! This is still in an experimental stage !! Please use it at your own risk !! If you have suggestions, please email drslum@tetrinet.org IRC FEATURE ----------- To use this query feature Simple use an ircII client to connect to port 31456 Example: irc drslum tetrinet.org:31456 !!!! This works best on _standard_ ircII clients (i.e. 2.8.2) It is not tested on BitchX or mIRC yet. If you want to change the port, edit the src/main.h file!! Command list (some clients may need to type /quote in front of commands) /list or /quote list /who #channel /whois nickname /names or /quote names /kill nickname /kick #channel slotnumber /join #channel /part #channel /topic #channel [message] /quote slist *Spectator view* /quote move slot1 slot2 *experimental* /quote op #channel slotnumber /quote deop #channel slotnumber /quote wall or /quote broadcast /quote set [varname value] /stats p for server operator list /rehash or /quote reset /motd This is not a real irc server. Weirdness is expected! Read :) qirc.changes for what's new Report bug to drslum@tetrinet.org SPECTATOR FEATURE ----------------- - To use gameplay watch feature (First time user) Look into game.secure file to set spectator and spectator_op password For this release spectator_op_password is not used. Only spec_password and op_password are used - Client programs Gtetrinet(linux) spectator support is completed. Tspec (windows) was proved to work with this release. You can download either of the client at http://tetrinet.org - Log on procedure To Log on, use spectator capatible clients and enter spec_password as team name to log on. Nickname must be alphabetic! or "-_[]". After Logged on, you can now view the game play by /join a channel by default spectator will be in #spectators or as defined in DEFAULTSPECCHANNEL variable in src/main.h. /list, /who -- same as standard tetrix /slist or /specwho -- view spectators in the channel /op -- obtain oper status /view -- big view changer (undetermined) To perform semi high-level function, you need to do /op as you do in normal gameplay. The commands that are available for op are Anything that normal spectator can do, and /kick, /move -- same as standard tetrix /qlist -- view global irc session operators // text or /p text -- chat with players (partyline) /m nick text -- chat with irc session /ip slotnumber(s) -- view players IPs gmsg access -- chat with players (playfield msg) To perform ultimate maintenance, I suggest that you use irc sessions! IRC sessions can do /kill and /whois spectator_nick and /quote slist to list all spectator. IRC session can also chat with a spectator using /msg. Please use only standard irc client 2.8.2. Once again, this is still in experimental stage. Use it with caution. *** Spec PEOPLE drslum -- qirc+spectator addons author zillidot -- gtetrinet author (I use his proggy everyday.) ekn -- tspec author / major tester bundaberg -- standard tetrix 1.13.16 author (Big guy! :))