1 
2 /*
3    TetriNET Server for Linux                                     V1.13.XX
4 *************************************************************************
5  What is TetriNET?
6    TetriNET is an addictive 6 player tetris game. Would someone please
7    fill this question in with something more interesting ;)
8 
9 
10  What does this program do?
11    I created this program originally because I wanted to run a TetriNET
12    server off my gateway machine, which ran RedHat Linux, and masqueraded
13    packets between my internal network and the Internet. And thats where
14    my total interest lies. If a new TetriNET comes out, I _may_ try to
15    update the linux server.
16    What this program does is set up a TetriNET server that ordinary
17    TetriNET clients can connect to. It attempts to fix some of the
18    "glaring" holes in the TetriNET protocol that I discovered, and which
19    I'm sure some people use as cheats, but I now see why it is nearly
20    impossible to fix ;), without a modification to the client.
21    I've kept the server as close to the same as the original TetriNET
22    server, but I've added some extras that I've often wanted, such as
23    the "/kick" and "/ban" keywords.
24    Please note, this server in no way encompasses the whole game. The clients
25    are the ones that do most of the work, with the server just passing suitable
26    packets between each client, and of course adding some of it's own.
27 
28  Acknowledgements
29    Naturally I acknowledge the author of the brilliant game TetriNET,
30    St0rmcat. Let me just say that trying to find your homepage was definately
31    an experience (one of the three most hardest things on the internet)... and
32    so was reading it ;) I guess it must be interesting to be defining a "protocol"
33 
34    I also acknowledge the author(s) of the "EggDrop" irc program, (see net.h).
35    The reason is that I borrowed some of their code (really, with minor
36    modifications, net.c is completely theirs). I didn't feel like recreating
37    the wheel, and I'd previously gone through that program line by line
38    anyway, and thought it to be one of the most brilliantly neatly written
39    programs I've seen yet.
40 
41    Thanks to BlueCoder (see crack.h). His goals follow the same lines as mine,
42    and thus was a good source of information. Good luck on your program man,
43    and keep in touch with any of your additions to the protocol  ;)
44 
45    Thanks to those who quite unknowingly tested the Server when it went on live
46    trial, on the 14/9/98 and 15/9/98. I just wish I could remember your nicks ;)
47    One person I DO remember ;), is ^k1mc1^, good fun to play against, and has
48    an excellent team name :)
49 
50   Who Am I
51     My name is Brendan Grieve, and I tend to program now and then on something
52     that interests me. I don't program for a living, but rather live for my
53     programming, if you get my meaning. Most of my code is generally open, since
54     if even one person learns something from it, GREAT. The best way to learn is
55     to look at other code, and to modify it even, to add something in.
56     Also, of course, any bugs can be traced right to the exact line, and patched
57     easily ;)
58 
59     email: brg@cheerful.com
60 
61   What can I do with your Source Code?
62     Learn from it if you want. Use it. If you want to improve it, go ahead, and
63     if you think your changes will be of use to others, then please do
64     email me the changes, and I'll add them to the main distribution.
65     Essentially all code, apart from bits (mentiotioned in their respective
66     header files), are completely public domain.
67 
68     What I want at the moment is for this code to be portable to other
69     unices than just Linux. And for that, naturally I need someone who
70     has other types of unixes to try compile the program.
71 
72     I now have a WISHLIST text file with all the excellent suggestions
73     sent in by various people. They all might one day be added, and if
74     you think of a good way, go right ahead ;), and if it's good, I'll add
75     it to the main distribution.
76 
77 
78 */
79 
80 
81 
82 
83 
84 /*undef TETDEBUG*/		/* Every time I find I need a printf, I'll encase it as a debug */
85 
86 #include "config.h"			/* Generally about the only file */
87                                         /* that the user can safely change */
88 #include <signal.h>
89 #include <unistd.h>
90 #include "main.h"
91 #include "net.h"
92 #include "utils.h"
93 #include "crack.h"
94 #include "game.h"
95 
96 #include "utils.c"
97 #include "net.c"
98 #include "crack.c"
99 #include "game.c"
100 
101 
102 /* remnet (channel, n) - Removes n from the channel list */
remnet(struct channel_t * chan,struct net_t * n)103 void remnet(struct channel_t *chan, struct net_t *n)
104   {
105     struct net_t *nsock,*osock;
106 
107     nsock=chan->net;
108     osock=NULL;
109     while( (nsock!=NULL) && (nsock!= n))
110       {
111         osock=nsock;
112         nsock=nsock->next;
113       }
114     if (nsock!=NULL)
115       {
116         if (osock==NULL)
117           chan->net=nsock->next;
118         else
119           osock->next=nsock->next;
120         nsock->channel=NULL;
121       }
122   }
123 
124 /* addnet (channel, n) - Adds n to the channel list */
addnet(struct channel_t * chan,struct net_t * n)125 void addnet(struct channel_t *chan, struct net_t *n)
126   {
127     n->next=chan->net;
128     chan->net=n;
129     n->channel=chan;
130   }
131 
132 /* writepid() - Writes the current pid to game.pidfile */
writepid(void)133 void writepid(void)
134   {
135     FILE *file_out;
136 
137     file_out = fopen(game.pidfile,"w");
138     if (file_out == NULL)
139       {
140         lvprintf(0,"ERROR: Could not write to PID file %s\n", game.pidfile);
141       }
142     else
143       {
144         fprintf(file_out,"%d", getpid());
145         fclose(file_out);
146         lvprintf(9,"Wrote PID to file %s\n", game.pidfile);
147       }
148   }
149 
150 /* delpid() - Delete the pid file */
delpid(void)151 void delpid(void)
152   {
153     remove(game.pidfile);
154     lvprintf(9,"Removed PID file %s\n", game.pidfile);
155   }
156 
157 /* int numallplayers(chan) - Returns ANY player that is connected in a channel */
numallplayers(struct channel_t * chan)158 int numallplayers(struct channel_t *chan)
159   {
160     int count;
161     struct net_t *n;
162 
163     count=0;
164     n=chan->net;
165     while (n!=NULL)
166       {
167         count++;
168         n=n->next;
169       }
170     return(count);
171   }
172 /* int numplayers(chan)  - Returns number of CONNECTED Players in a channel */
numplayers(struct channel_t * chan)173 int numplayers(struct channel_t *chan)
174   {
175     int count;
176     struct net_t *n;
177 
178     count=0;
179     n=chan->net;
180     while (n!=NULL)
181       {
182         if( ((n->type==NET_CONNECTED) || (n->type==NET_WAITINGFORTEAM))) count++;
183         n=n->next;
184       }
185     return(count);
186   }
187 
188 /* int numchannels() - Returns number of channels  */
numchannels(void)189 int numchannels(void)
190   {
191     int count;
192     struct channel_t *chan;
193 
194     chan=chanlist;
195     count=0;
196     while (chan!= NULL)
197       {
198         count++;
199         chan=chan->next;
200       }
201     return(count);
202 
203   }
204 
205 
206 
207 /* is_banned( net ) - Returns 1 if the IP of the player is banned */
is_banned(struct net_t * n)208 char is_banned(struct net_t *n)
209   { /* I should use regex, but I've not used it before, and it was late. Easier to write a quick one of my own */
210     FILE *file_in;
211     char n1[4], n2[4], n3[4], n4[4];
212     char ip1[4], ip2[4], ip3[4], ip4[4];
213     int i; int found;
214 
215     file_in = fopen(FILE_BAN,"r");
216     if (file_in == NULL)
217       return(0);
218 
219     sprintf(n1,"%lu", (unsigned long)(n->addr&0xff000000)/(unsigned long)0x1000000);
220     sprintf(n2,"%lu", (unsigned long)(n->addr&0x00ff0000)/(unsigned long)0x10000);
221     sprintf(n3,"%lu", (unsigned long)(n->addr&0x0000ff00)/(unsigned long)0x100);
222     sprintf(n4,"%lu", (unsigned long)n->addr&0x000000ff);
223 
224     found = 0;
225     while (!found && !feof(file_in))
226       {
227         /* Read in line by line, and match regular expressions with the IP of sock_index */
228         i = fscanf(file_in," %4[0-9*] . %4[0-9*] . %4[0-9*] . %4[0-9*] \n", ip1, ip2, ip3, ip4);
229         if (i == 4)
230           {
231             if (     ((!strcmp(n1,ip1)) || (!strcmp(ip1,"*")))
232                   && ((!strcmp(n2,ip2)) || (!strcmp(ip2,"*")))
233                   && ((!strcmp(n3,ip3)) || (!strcmp(ip3,"*")))
234                   && ((!strcmp(n4,ip4)) || (!strcmp(ip4,"*")))
235                )
236               {/* Matches! */
237                 found=1;
238               }
239           }
240       }
241     fclose(file_in);
242     return(found);
243   }
244 
245 /* is_op( net ) - Returns 1 if this player is the lowest gameslot, thus the chanop */
is_op(struct net_t * n)246 char is_op(struct net_t *n)
247   {
248     int found;
249     struct net_t *nt;
250     found = 0;
251 
252     nt=n->channel->net;
253     while( nt!=NULL)
254       {
255         if ( ( (nt->type == NET_CONNECTED) || (nt->type == NET_WAITINGFORTEAM) ) && (nt->gameslot < n->gameslot))
256           found = 1;
257         nt=nt->next;
258       }
259     return(!found);
260   }
261 
262 /* passed_level(net, level required to pass) - Returns 1 if the player's security */
263 /*            level is equal to or higher than the level required to pass */
264 /*            Passing is_op gives player a security level of at least 2*/
passed_level(struct net_t * n,int passlevel)265 char passed_level(struct net_t *n, int passlevel)
266   {
267     int currlevel;
268 
269     currlevel=LEVEL_NORMAL; /* Normal Player */
270 
271     if (is_op(n)) currlevel=LEVEL_OP;  /* Op by position */
272 
273     /* Player might already have a higher level... say they did a /op */
274     if (n->securitylevel > currlevel)
275       currlevel=n->securitylevel;
276 
277     return( currlevel >= passlevel);
278   }
279 
280 /* kick(net from, player to be kicked) - Disconnects player, and informs all others that they were kicked */
kick(struct net_t * n_from,int kick_gameslot)281 void kick(struct net_t *n_from, int kick_gameslot)
282   {
283     struct net_t *n;
284     struct net_t *n_to;
285 
286     n=n_from->channel->net;
287     n_to=NULL;
288     while (n!=NULL)
289       {
290         if ( (n->gameslot == kick_gameslot) && ((n->type == NET_CONNECTED) || (n->type == NET_WAITINGFORTEAM)))
291           n_to = n;
292         n=n->next;
293       }
294     if ((n_to!=NULL) && (kick_gameslot>=1) && (kick_gameslot<=6))
295       {
296         lvprintf(4,"#%s-%s: Kicked %s from server\n",n_from->channel->name,n_from->nick,n_to->nick);
297         n=n_from->channel->net;
298         while (n!=NULL)
299           {
300             if ( ((n->type == NET_CONNECTED) || (n->type == NET_WAITINGFORTEAM)))
301               {
302                 tprintf(n->sock,"kick %d\xff", kick_gameslot);
303               }
304             n=n->next;
305           }
306         killsock(n_to->sock); lostnet(n_to);
307       }
308   }
309 
310 /* tet_checkversion( client version ) - Returns 0 if the server supports this */
311 /*   client version. At the moment, ONLY support 1.13 client*/
tet_checkversion(char * buf)312 int tet_checkversion(char *buf)
313   { /* Returns -1 if versioncheck fails */
314     if (!strcmp(TETVERSION,buf))
315       return(0);
316     else
317       return(-1);
318   }
319 
320 /* lvprintf( priority, same as printf ) - Logs to the log IF priority is smaller */
321 /*                                        or equal to game.verbose */
lvprintf(int priority,char * format,...)322 void lvprintf(int priority, char *format, ...)
323 { /* No bounds checking. Be very careful what you log */
324   if (priority <= game.verbose) {
325     va_list va; static char SBUF2[768];
326     va_start(va, format);
327     vsnprintf(SBUF2, sizeof(SBUF2),format,va);
328     lprintf(SBUF2);
329     va_end(va);
330   }
331 }
332 
333 /* lprintf( same as printf ) - Logs to the log. */
lprintf(char * format,...)334 void lprintf(char *format, ...)
335 { /* No bounds checking. Be very careful what you log */
336   va_list va; static char SBUF2[768];
337   FILE *file_out;
338   char *mytime;
339   char *P;
340   time_t cur_time;
341   va_start(va, format);
342   vsnprintf(SBUF2, sizeof(SBUF2),format,va);
343 
344   file_out = fopen(FILE_LOG,"a");
345   if (file_out != NULL)
346     {
347       cur_time = time(NULL);
348       mytime=ctime(&cur_time);
349       P=mytime;
350       P+=4;
351       mytime[strlen(mytime)-6]=0;
352       fprintf(file_out,"%s %s", P, SBUF2);
353       fclose(file_out);
354     }
355   va_end(va);
356 }
357 
358 /* Open a Listening Socket on the TetriNET port */
init_telnet_port()359 void init_telnet_port()
360 {
361   int i,j;
362   struct net_t *n;
363 
364   /* find old entry if it exists */
365   n=gnet;
366   while ( (n!=NULL) && (n->type!=NET_TELNET))
367     n=n->next;
368 
369   if (n==NULL) {
370     /* no existing entry */
371     n=gnet;
372     gnet=malloc(sizeof(struct net_t));
373     gnet->next=n;
374     n=gnet;
375     n->addr=getmyip();
376     n->type=NET_TELNET;
377     strcpy(n->nick,"(telnet)");
378     getmyhostname(n->host);
379   }
380   else {
381     /* already an entry */
382     killsock(n->sock);
383   }
384   j=TELNET_PORT;
385   i=open_listen_socket(&j,game.bindip);
386 
387   if (i>=0) {
388     n->port=j;
389     n->sock=i;
390 
391     lvprintf(3,"Listening at telnet port %d, on socket %d, bound to %s\n", j,i,game.bindip);
392     return;
393   }
394   printf("Couldn't find telnet port %d. (TetriNET already running?)\n",j);
395   lvprintf(0,"Couldn't find telnet port %d.\n", j);
396   exit(1);
397 }
398 
399 /* Open a Listening Socket on the TetriNET query port */
init_query_port()400 void init_query_port()
401 {
402   int i,j;
403   struct net_t *n;
404 
405   /* find old entry if it exists */
406   n=gnet;
407   while ( (n!=NULL) && (n->type!=NET_QUERY))
408     n=n->next;
409 
410   if (n==NULL) {
411     /* no existing entry */
412     n=gnet;
413     gnet=malloc(sizeof(struct net_t));
414     gnet->next=n;
415     n=gnet;
416     n->addr=getmyip();
417     n->type=NET_QUERY;
418     strcpy(n->nick,"(telnet)");
419     getmyhostname(n->host);
420   }
421   else {
422     /* already an entry */
423     killsock(n->sock);
424   }
425   j=QUERY_PORT;
426   i=open_listen_socket(&j,game.bindip);
427 
428   if (i>=0) {
429     n->port=j;
430     n->sock=i;
431 
432     lvprintf(3,"Listening at query port %d, on socket %d, bound to %s\n", j,i,game.bindip);
433     return;
434   }
435   printf("Couldn't find telnet port %d. (TetriNET already running?)\n",j);
436   lvprintf(0,"Couldn't find telnet port %d.\n", j);
437   exit(1);
438 }
439 
440 
441 
442 
443 /* Main loop calls here when activity found on a net socket */
net_activity(int z,char * buf,int len)444 void net_activity(int z, char *buf, int len)
445   {
446     struct net_t *n;
447     struct channel_t *chan;
448 
449     chan=chanlist;
450     n=NULL;
451     while ( (chan!=NULL) && (n==NULL) )
452       {
453         n=chan->net;
454         while( (n!=NULL) && (n->sock!=z) )
455           n=n->next;
456         chan=chan->next;
457       }
458 
459     if (n==NULL)
460       { /* Try global list */
461         n=gnet;
462         while( (n!=NULL) && (n->sock!=z) )
463           n=n->next;
464       }
465 
466 
467     if (n==NULL) return;
468 
469     /* Reset timeout on socket */
470     if (n->status == STAT_PLAYING)
471       n->timeout = game.timeout_ingame;
472     else
473       n->timeout = game.timeout_outgame;
474 
475     switch (n->type)
476       {
477         case NET_TELNET: 		/* Recieved connection */
478           {
479             net_telnet(n,buf);
480             break;
481           }
482         case NET_QUERY:			/* Recieved connection */
483           {
484             net_query(n,buf);
485             break;
486           }
487         case NET_TELNET_INIT:		/* Received clients init sequence */
488           {
489             net_telnet_init(n,buf);
490             break;
491           }
492         case NET_QUERY_INIT:		/* Received clients init sequence */
493           {
494             net_query_init(n,buf);
495             break;
496           }
497         case NET_WAITINGFORTEAM:	/* Waiting for inital team */
498           {
499             net_waitingforteam(n,buf);
500             break;
501           }
502         case NET_CONNECTED:		/* Recieved command from client */
503           {
504             net_connected(n,buf);
505             break;
506           }
507         default:
508           {
509             lvprintf(0,"Internal Error - Untrapped Network activity. (BIG ERROR)\n");
510           }
511       }
512   }
513 
514 /* String length (minus colours) */
strclen(char * S)515 int strclen(char *S)
516   {
517     int i;int count;
518     if (S==NULL)
519       return 0;
520 
521     i=0;count=0;
522     while(S[i]!=0)
523       {
524         if(              (S[i] != BOLD)
525                       && (S[i] != CYAN)
526                       && (S[i] != BLACK)
527                       && (S[i] != BLUE)
528                       && (S[i] != DARKGRAY)
529                       && (S[i] != MAGENTA)
530                       && (S[i] != GREEN)
531                       && (S[i] != NEON)
532                       && (S[i] != SILVER)
533                       && (S[i] != BROWN)
534                       && (S[i] != NAVY)
535                       && (S[i] != VIOLET)
536                       && (S[i] != RED)
537                       && (S[i] != ITALIC)
538                       && (S[i] != TEAL)
539                       && (S[i] != WHITE)
540                       && (S[i] != YELLOW)
541                       && (S[i] != UNDERLINE) )
542                 count++;
543         i++;
544       }
545     return(i);
546   }
547 
548 /* Connected, recieving commands */
net_connected(struct net_t * n,char * buf)549 void net_connected(struct net_t *n, char *buf)
550   {
551     char COMMAND[101]; char PARAM[601]; char MSG[601];
552     char STRG[513], STRG2[513];
553     int num; int num1; int num2; int num3; int num4; int s; int i,j,k,l,x,y;
554     int nn1,nn2,nn3,nn4,nn5,nn6,nn7,nn8,nn9;
555     int valid_param;
556     char *P=NULL;
557     struct channel_t *chan,*ochan,*c,*oc;
558     struct net_t *nsock=NULL;
559     struct net_t *ns1,*ns2;
560 
561     COMMAND[0]=0;PARAM[0]=0;MSG[0]=0;
562     /* Ensure command is proper before passing it to other players */
563     sscanf(buf, "%100s %600[^\n\r]", COMMAND, PARAM);
564     valid_param = 0; /* 0 = invalid    */
565                      /* 1 = valid      */
566                      /* 2 = valid command, but failed some test */
567 
568 
569     /* Party Line Message - pline <playernumber> <message> */
570     if ( !strcasecmp(COMMAND, "pline") )
571       {
572         valid_param=2;
573         s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
574         if ( (s >= 2) && (num==n->gameslot))
575           {
576             if (MSG[0]=='/')
577               {
578                 valid_param=1;
579                 /* First parse to see if it's a server command */
580                 if ( !strncasecmp(MSG, "/kick", 5) && (game.command_kick > 0))
581                   {
582                     valid_param=2;
583                     if ( passed_level(n,game.command_kick) )
584                       {
585                         P=MSG+6;
586                         while( (((*P)-'0') >= 1) && (((*P)-'0') <= 6) )
587                           {
588 
589                             kick(n, (*P)-'0');
590                             P++;
591                           }
592                       }
593                     else
594                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
595 
596                   }
597 
598                 /* Set channel settings */
599                 if ( !strncasecmp(MSG, "/set", 4) && (game.command_set>0))
600                   {
601                     valid_param=2;
602                     if (passed_level(n,game.command_set)
603                       || ((passed_level(n,LEVEL_AUTHOP)||(passed_level(n,LEVEL_OP)&&!n->channel->persistant))
604                            && (game.command_set==4)
605                          )
606                        )
607                       {
608                         PARAM[0]=0;
609                         STRG2[0]=0;
610                         STRG[0]=0;
611                         sscanf(MSG,"%s %s %1024[^\n]", STRG2,STRG,PARAM);
612 
613 
614                         if ( !strcasecmp(STRG,"BLOCK") )
615                           {
616                             k=0;
617                             k=sscanf(PARAM,"%d %d %d %d %d %d %d",&nn1,&nn2,&nn3,&nn4,&nn5,&nn6,&nn7);
618                             if (k==7)
619                               {
620                                 if ((abs(nn1)+abs(nn2)+abs(nn3)+abs(nn4)+abs(nn5)+abs(nn6)+abs(nn7)) == 100)
621                                   {
622                                     n->channel->block_leftl=abs(nn1);
623                                     n->channel->block_leftz=abs(nn2);
624                                     n->channel->block_square=abs(nn3);
625                                     n->channel->block_rightl=abs(nn4);
626                                     n->channel->block_rightz=abs(nn5);
627                                     n->channel->block_halfcross=abs(nn6);
628                                     n->channel->block_line=abs(nn7);
629                                     tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
630                                   }
631                                 else
632                                   {
633                                     tprintf(n->sock,"pline 0 %cAll Parameters must add up to 100%%\xff",NAVY);
634                                   }
635                               }
636                             else if (strlen(PARAM)==0)
637                               {
638                                 tprintf(n->sock,"pline 0 %cBLOCK\xff",RED);
639                                 tprintf(n->sock,"pline 0 %cSet the percentage occurance of blocks in a game\xff",NAVY);
640                                 tprintf(n->sock,"pline 0 %cll\t%cPercent Left L shaped block\xff", BLUE,NAVY);
641                                 tprintf(n->sock,"pline 0 %clz\t%cPercent Left Z shaped block\xff", BLUE,NAVY);
642                                 tprintf(n->sock,"pline 0 %csq\t%cPercent Square shaped block\xff", BLUE,NAVY);
643                                 tprintf(n->sock,"pline 0 %crl\t%cPercent Right L shaped block\xff", BLUE,NAVY);
644                                 tprintf(n->sock,"pline 0 %crz\t%cPercent Right Z shaped block\xff", BLUE,NAVY);
645                                 tprintf(n->sock,"pline 0 %chc\t%cPercent HalfCross shaped block\xff", BLUE,NAVY);
646                                 tprintf(n->sock,"pline 0 %cln\t%cPercent Line shaped block\xff",BLUE,NAVY);
647                                 tprintf(n->sock,"pline 0 %cAll percentages add up to a total of 100%%\xff",NAVY);
648                                 tprintf(n->sock,"pline 0 %cIE: %c/set %cBLOCK %c14 14 15 14 14 14 15\xff",NAVY,BLUE,RED,BLUE);
649                                 tprintf(n->sock,"pline 0 Current Setting: %d %d %d %d %d %d %d\xff",
650                                                   n->channel->block_leftl,
651                                                   n->channel->block_leftz,
652                                                   n->channel->block_square,
653                                                   n->channel->block_rightl,
654                                                   n->channel->block_rightz,
655                                                   n->channel->block_halfcross,
656                                                   n->channel->block_line);
657                               }
658                             else
659                               tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cBLOCK\xff",NAVY,BLUE,RED);
660                           }
661                         else if ( !strcasecmp(STRG,"SPECIAL") )
662                           {
663                             k=0;
664                             k=sscanf(PARAM,"%d %d %d %d %d %d %d %d %d",&nn1,&nn2,&nn3,&nn4,&nn5,&nn6,&nn7,&nn8,&nn9);
665                             if (k==9)
666                               {
667                                 if (   ((abs(nn1)+abs(nn2)+abs(nn3)+abs(nn4)+abs(nn5)+abs(nn6)+abs(nn7)+abs(nn8)+abs(nn9)) == 100)
668                                    )
669                                   {
670                                     n->channel->special_addline=abs(nn1);
671                                     n->channel->special_clearline=abs(nn2);
672                                     n->channel->special_nukefield=abs(nn3);
673                                     n->channel->special_randomclear=abs(nn4);
674                                     n->channel->special_switchfield=abs(nn5);
675                                     n->channel->special_clearspecial=abs(nn6);
676                                     n->channel->special_gravity=abs(nn7);
677                                     n->channel->special_quakefield=abs(nn8);
678                                     n->channel->special_blockbomb=abs(nn9);
679                                     tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
680                                   }
681                                 else
682                                   tprintf(n->sock,"pline 0 %cAll Parameters must add up to 100%%\xff",NAVY);
683                               }
684                             else if (strlen(PARAM)==0)
685                               {
686                                 tprintf(n->sock,"pline 0 %cSPECIAL\xff",RED);
687                                 tprintf(n->sock,"pline 0 %cSet the percentage occurance of special blocks in a game\xff",NAVY);
688                                 tprintf(n->sock,"pline 0 %cA\t%cPercent ADDLINE block\xff",BLUE,NAVY);
689                                 tprintf(n->sock,"pline 0 %cC\t%cPercent CLEARLINE block\xff",BLUE,NAVY);
690                                 tprintf(n->sock,"pline 0 %cN\t%cPercent NUKEFIELD block\xff",BLUE,NAVY);
691                                 tprintf(n->sock,"pline 0 %cR\t%cPercent RANDOMCLEAR block\xff",BLUE,NAVY);
692                                 tprintf(n->sock,"pline 0 %cS\t%cPercent SWITCHFIELD block\xff",BLUE,NAVY);
693                                 tprintf(n->sock,"pline 0 %cB\t%cPercent CLEARSPECIAL block\xff",BLUE,NAVY);
694                                 tprintf(n->sock,"pline 0 %cG\t%cPercent GRAVITY block\xff",BLUE,NAVY);
695                                 tprintf(n->sock,"pline 0 %cQ\t%cPercent QUAKEFIELD block\xff",BLUE,NAVY);
696                                 tprintf(n->sock,"pline 0 %cO\t%cPercent BLOCKBOMB block\xff",BLUE,NAVY);
697                                 tprintf(n->sock,"pline 0 %cAll percentages add up to a total of 100%%\xff",NAVY);
698                                 tprintf(n->sock,"pline 0 %cIE: %c/set %cSPECIAL %c32 18 1 11 3 14 1 6 14\xff",NAVY,BLUE,RED,BLUE);
699                                 tprintf(n->sock,"pline 0 Current Setting: %d %d %d %d %d %d %d %d %d\xff",
700                                               n->channel->special_addline,
701                                               n->channel->special_clearline,
702                                               n->channel->special_nukefield,
703                                               n->channel->special_randomclear,
704                                               n->channel->special_switchfield,
705                                               n->channel->special_clearspecial,
706                                               n->channel->special_gravity,
707                                               n->channel->special_quakefield,
708                                               n->channel->special_blockbomb);
709                               }
710                             else
711                               tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cSPECIAL\xff",NAVY,BLUE,RED);
712                           }
713                         else if ( !strcasecmp(STRG,"SUDDENDEATH") )
714                           {
715                             k=0;
716                             k=sscanf(PARAM,"%d %d %d",&nn1,&nn2,&nn3);
717                             if (k==3)
718                               {
719                                 if ( (nn1 >= 0) && (nn2 >= 0) && (nn3 > 0) )
720                                   {
721                                     n->channel->sd_timeout=nn1;
722                                     n->channel->sd_lines_per_add=nn2;
723                                     n->channel->sd_secs_between_lines=nn3;
724                                     tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
725                                   }
726                                 else
727                                   tprintf(n->sock,"pline 0 %cInvalid Parameters\xff",NAVY);
728                               }
729                             else if (strlen(PARAM)==0)
730                               {
731                                 tprintf(n->sock,"pline 0 %cSUDDENDEATH\xff",RED);
732                                 tprintf(n->sock,"pline 0 %cSet the configuration for SUDDENDEATH mode\xff",NAVY);
733                                 tprintf(n->sock,"pline 0 %cto\t%cNumber of Seconds till SuddenDeath Mode\xff",BLUE,NAVY);
734                                 tprintf(n->sock,"pline 0 %cla\t%cNumber of Lines to add each time\xff",BLUE,NAVY);
735                                 tprintf(n->sock,"pline 0 %csl\t%cNumber of Seconds between each add line\xff",BLUE,NAVY);
736                                 tprintf(n->sock,"pline 0 %cIE: %c/set %cSUDDENDEATH %c180 1 30\xff",NAVY,BLUE,RED,BLUE);
737                                 tprintf(n->sock,"pline 0 Current Setting: %d %d %d\xff",
738                                         n->channel->sd_timeout,
739                                         n->channel->sd_lines_per_add,
740                                         n->channel->sd_secs_between_lines);
741                               }
742                             else
743                               tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cSUDDENDEATH\xff",NAVY,BLUE,RED);
744                           }
745                         else if ( !strcasecmp(STRG,"SUDDENDEATHMSG") )
746                           {
747                             k=0;
748                             k=sscanf(PARAM,"%512[^\n]",STRG2);
749                             if (k==1)
750                               {
751                                 strncpy(n->channel->sd_message,STRG2,SDMSGLEN);n->channel->sd_message[SDMSGLEN-1]=0;
752                                 tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
753                               }
754                             else if (strlen(PARAM)==0)
755                               {
756                                 tprintf(n->sock,"pline 0 %cSUDDENDEATHMSG\xff",RED);
757                                 tprintf(n->sock,"pline 0 %cSet the Message sent to players when SuddenDeath mode arrives\xff",NAVY);
758                                 tprintf(n->sock,"pline 0 %cmsg\t%cMessage to send to players\xff",BLUE,NAVY);
759                                 tprintf(n->sock,"pline 0 %cIE: %c/set %cSUDDENDEATHMSG %cTime's up! It's SUDDEN DEATH MODE!\xff",NAVY,BLUE,RED,BLUE);
760                                 tprintf(n->sock,"pline 0 Current Setting: %s\xff",n->channel->sd_message);
761                               }
762                             else
763                               tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cSUDDENDEATHMSG\xff",NAVY,BLUE,RED);
764                           }
765                         else if ( !strcasecmp(STRG,"RULES") )
766                           {
767                             k=0;
768                             k=sscanf(PARAM,"%d %d %d %d %d %d %d %d",&nn1,&nn2,&nn3,&nn4,&nn5,&nn6,&nn7,&nn8);
769                             if (k==8)
770                               {
771                                 if ( (nn1>=0)&&(nn1<100)&&(nn2>0)&&(nn3>0)&&(nn4>0)&&(nn5>=0)&&(nn6>0)&&(nn6<=18)&&(nn7>=0)&&(nn7<=1)&&(nn8>=0)&&(nn8<=1))
772                                   {
773                                     n->channel->starting_level=nn1;
774                                     n->channel->lines_per_level=nn2;
775                                     n->channel->level_increase=nn3;
776                                     n->channel->lines_per_special=nn4;
777                                     n->channel->special_added=nn5;
778                                     n->channel->special_capacity=nn6;
779                                     n->channel->classic_rules=nn7;
780                                     n->channel->average_levels=nn8;
781                                     tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
782                                   }
783                                 else
784                                   tprintf(n->sock,"pline 0 %cInvalid parameters\xff",NAVY);
785                               }
786                             else if (strlen(PARAM)==0)
787                               {
788                                 tprintf(n->sock,"pline 0 %cRULES\xff",RED);
789                                 tprintf(n->sock,"pline 0 %cSet the Channel Rules in the game\xff",NAVY);
790                                 tprintf(n->sock,"pline 0 %csl\t%cStarting Level of all players\xff",BLUE,NAVY);
791                                 tprintf(n->sock,"pline 0 %cll\t%cLines per level\xff",BLUE,NAVY);
792                                 tprintf(n->sock,"pline 0 %cli\t%cAmount level increases each time\xff",BLUE,NAVY);
793                                 tprintf(n->sock,"pline 0 %cls\t%cLines per special\xff",BLUE,NAVY);
794                                 tprintf(n->sock,"pline 0 %csa\t%cNumber of specials added each time\xff",BLUE,NAVY);
795                                 tprintf(n->sock,"pline 0 %csc\t%cSpecial Capacity of players\xff",BLUE,NAVY);
796                                 tprintf(n->sock,"pline 0 %ccr\t%cPlay with classic rules?\xff",BLUE,NAVY);
797                                 tprintf(n->sock,"pline 0 %cal\t%cAverage all players levels?\xff",BLUE,NAVY);
798                                 tprintf(n->sock,"pline 0 %cIE: %c/set %cRULES %c1 2 1 1 1 18 1 1\xff",NAVY,BLUE,RED,BLUE);
799                                 tprintf(n->sock,"pline 0 Current Setting: %d %d %d %d %d %d %d %d\xff",
800                                       n->channel->starting_level,
801                                       n->channel->lines_per_level,
802                                       n->channel->level_increase,
803                                       n->channel->lines_per_special,
804                                       n->channel->special_added,
805                                       n->channel->special_capacity,
806                                       n->channel->classic_rules,
807                                       n->channel->average_levels);
808                               }
809                             else
810                               tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cRULES\xff",NAVY,BLUE,RED);
811                           }
812                         else if ( !strcasecmp(STRG,"MISC") )
813                           {
814                             k=0;
815                             k=sscanf(PARAM,"%d %d %d",&nn1,&nn2,&nn3);
816                             if (k==3)
817                               {
818                                 if ( (nn1>=0)&&(nn1<=1)&&(nn2>=0)&&(nn2<=1)&&(nn3>=0)&&(nn3<=1))
819                                   {
820                                     n->channel->stripcolour=nn1;
821                                     n->channel->serverannounce=nn2;
822                                     n->channel->pingintercept=nn3;
823                                     tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
824                                   }
825                                 else
826                                   tprintf(n->sock,"pline 0 %cInvalid parameters\xff",NAVY);
827                               }
828                             else if (strlen(PARAM)==0)
829                               {
830                                 tprintf(n->sock,"pline 0 %cMISC\xff",RED);
831                                 tprintf(n->sock,"pline 0 %cSet Misc options\xff",NAVY);
832                                 tprintf(n->sock,"pline 0 %csc\t%cStrip Colour from GameMessages?\xff",BLUE,NAVY);
833                                 tprintf(n->sock,"pline 0 %csa\t%cServer Announces winner?\xff",BLUE,NAVY);
834                                 tprintf(n->sock,"pline 0 %cpi\t%cIntercept \"t\" in a Gamemessage as PING?\xff",BLUE,NAVY);
835                                 tprintf(n->sock,"pline 0 %cIE: %c/set %cMISC %c 1 1 1\xff",NAVY,BLUE,RED,BLUE);
836                                 tprintf(n->sock,"pline 0 Current Setting: %d %d %d\xff",
837                                    n->channel->stripcolour,
838                                    n->channel->serverannounce,
839                                    n->channel->pingintercept);
840                               }
841                             else
842                               tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cMISC\xff",NAVY,BLUE,RED);
843                           }
844                         else
845                           {
846                             tprintf(n->sock,"pline 0 %cSET %ccommands - Set channel attributes\xff",TEAL, NAVY);
847                             tprintf(n->sock,"pline 0 %cCommands are of the general form: %c/set %c<command>%c[%cvalue [..value]%c]\xff",NAVY,BLUE,RED,BLACK,BLUE,BLACK);
848                             tprintf(n->sock,"pline 0 %cWhen given without a value, the current value is returned.\xff",NAVY);
849                             tprintf(n->sock,"pline 0 %c/set %cBLOCK %cll lz sq rl rz hc ln   %cSet Block Configuration\xff", BLUE,RED,BLUE,NAVY);
850                             tprintf(n->sock,"pline 0 %c/set %cSPECIAL %cA C N R S B G Q O   %cSet Special Configuration\xff",BLUE,RED,BLUE,NAVY);
851                             tprintf(n->sock,"pline 0 %c/set %cSUDDENDEATH %cto la sl   %cSet SuddenDeath Configuration\xff",BLUE,RED,BLUE,NAVY);
852                             tprintf(n->sock,"pline 0 %c/set %cSUDDENDEATHMSG %cmsg   %cSet SuddenDeath Message\xff",BLUE,RED,BLUE,NAVY);
853                             tprintf(n->sock,"pline 0 %c/set %cRULES %csl ll li ls sa sc cr al   %cSet Rules Configuration\xff",BLUE,RED,BLUE,NAVY);
854                             tprintf(n->sock,"pline 0 %c/set %cMISC %csc sa pi   %cSet Misc Configuration\xff",BLUE,RED,BLUE,NAVY);
855                             /*tprintf(n->sock,"pline 0 %c/set %cCONFIG %cconfignum   %cSet ALL config options in one shot\xff",BLUE,RED,BLUE,NAVY);*/
856                             tprintf(n->sock,"pline 0 %cType %c/set %ccommandname %cto find out what the parameters mean.\xff",NAVY,BLUE,RED,NAVY);
857                           }
858                       }
859                     else
860                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
861                   }
862 
863                 /* Set channel topic */
864                 if ( !strncasecmp(MSG, "/topic", 6) && (game.command_topic>0))
865                   {
866                     valid_param=2;
867                     if ( passed_level(n,game.command_topic) )
868                       {
869                         P=MSG+7;
870                         if (strlen(MSG)>=7)
871                           {
872                             strncpy(n->channel->description, P, DESCRIPTIONLEN-1); n->channel->description[DESCRIPTIONLEN-1]=0;
873                             lvprintf(4,"#%s-%s changed channel topic to %s\n",n->channel->name,n->nick,n->channel->description);
874                             nsock=n->channel->net;
875                             while (nsock!=NULL)
876                               {
877                                 if ((nsock->type==NET_CONNECTED))
878                                   {
879                                     tprintf(nsock->sock,"pline 0 %c%s%c%c changes the channel topic to %s\xff", GREEN,n->nick,BLACK,GREEN,n->channel->description);
880                                   }
881                                 nsock=nsock->next;
882                               }
883                           }
884                       }
885                     else
886                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
887                   }
888 
889                 /* Who is online */
890                 if ( !strncasecmp(MSG, "/who", 4) && (game.command_who>0))
891                   {
892                     valid_param=2;
893                     if ( passed_level(n,game.command_who) )
894                       {
895                         if (passed_level(n,LEVEL_AUTHOP))
896                           tprintf(n->sock,"pline 0 %cNickname\tTeam            \tChannel\tIP\xff", NAVY);
897                         else
898                           tprintf(n->sock,"pline 0 %cNickname\tTeam            \tChannel\xff", NAVY);
899                         l=1;
900                         chan=chanlist;
901                         while(chan!=NULL)
902                           {
903                             nsock=chan->net;
904                             while (nsock!=NULL)
905                               {
906                                 if (nsock->type==NET_CONNECTED)
907                                   {
908                                     STRG[0]=0;
909                                     STRG2[0]=0;
910                                     strcpy(STRG,nsock->nick);
911                                     j=strclen(STRG);
912                                     k=strlen(STRG);
913                                     while(j<15)
914                                       {
915                                         STRG[k]=' ';
916                                         k++;
917                                         j++;
918                                       }
919                                     STRG[k]=0;
920 
921                                     strcpy(STRG2,nsock->team);
922                                     j=strclen(STRG2);
923                                     k=strlen(STRG2);
924                                     while(j<17)
925                                       {
926                                         STRG2[k]=' ';
927                                         k++;
928                                         j++;
929                                       }
930                                     STRG2[k]=0;
931 
932                                     if (nsock==n)
933                                       j=RED;
934                                     else
935                                       j=DARKGRAY;
936 
937                                     if (passed_level(n,LEVEL_AUTHOP))
938                                       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);
939                                     else
940                                       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);
941                                     l++;
942                                   }
943                                 nsock=nsock->next;
944                               }
945                             chan=chan->next;
946                           }
947                       }
948                     else
949                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
950                   }
951 
952                 /* Set channel priority */
953                 if ( !strncasecmp(MSG, "/priority", 9) && (game.command_priority>0))
954                   {
955                     valid_param=2;
956                     if ( passed_level(n,game.command_priority) )
957                       {
958                         P=MSG+10;
959                         if ( (atoi(P) >= 0) && (atoi(P) < 100) )
960                           {
961                             n->channel->priority=atoi(P);
962                             lvprintf(4,"#%s-%s changed channel priority to %d\n",n->channel->name,n->nick,n->channel->priority);
963                             nsock=n->channel->net;
964                             while (nsock!=NULL)
965                               {
966                                 if ((nsock->type==NET_CONNECTED) )
967                                   {
968                                     tprintf(nsock->sock,"pline 0 %c%s%c%c changes the channel priority to %d\xff", GREEN,n->nick,BLACK,GREEN,n->channel->priority);
969                                   }
970                                 nsock=nsock->next;
971                               }
972                           }
973                         else
974                           {
975                             tprintf(n->sock,"pline 0 %cChannel priority should lie in the range of 0 to 99. 0 prevents people from automatically joining.\xff",NAVY);
976                           }
977                       }
978                     else
979                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
980                   }
981 
982                 /* List Channels */
983                 if ( !strncasecmp(MSG, "/list", 5) && (game.command_list>0))
984                   {
985                     valid_param=2;
986                     if ( passed_level(n,game.command_list) )
987                       {
988                         if (chanlist != NULL)
989                           {
990                             tprintf(n->sock,"pline 0 %cTetriNET Channel Lister - (Type %c/join %c#channelname%c)\xff",NAVY,RED,BLUE,NAVY);
991                             chan=chanlist;
992                             i=1;
993                             while (chan != NULL)
994                               {
995                                 if (n->channel==chan)
996                                   j=RED;
997                                 else
998                                   j=BLUE;
999 
1000                                 if (chan->status==STATE_INGAME)
1001                                   {
1002                                     sprintf(STRG,"%c{INGAME}%c", DARKGRAY,NAVY);
1003                                   }
1004                                 else
1005                                   {
1006                                     sprintf(STRG,"                ");
1007                                   }
1008                                 if (numplayers(chan) >= chan->maxplayers)
1009                                   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);
1010                                 else
1011                                   {
1012                                     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);
1013                                   }
1014                                 i++;
1015                                 chan=chan->next;
1016                               }
1017                           }
1018                       }
1019                     else
1020                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1021                   }
1022 
1023                 /* Join Channel */
1024                 if ( !strncasecmp(MSG, "/j", 2) && (game.command_join>0))
1025                   {
1026                     valid_param=2;
1027                     if ( passed_level(n,game.command_join) || (game.command_join==4))
1028                       {
1029                         if ( !strncasecmp(MSG,"/join", 5) )
1030                           P=MSG+6;
1031                         else
1032                           P=MSG+3;
1033                         STRG[0]=0;
1034                         k = sscanf(P,"%512s", STRG);
1035                         if ((k != 0) )
1036                           {
1037                             /* First, is it a #channel or channel number? */
1038                             j=atoi(STRG);
1039                             chan=NULL;
1040                             ochan=NULL;
1041                             if (j>0)
1042                               { /* Position */
1043                                 chan=chanlist;
1044                                 j--;
1045                                 while( (j>0) && (chan!=NULL) )
1046                                   {
1047                                     chan=chan->next;
1048                                     j--;
1049                                   }
1050                               }
1051                             else if (STRG[0]=='#')
1052                               { /* Name */
1053                                 sscanf(P,"#%512s", STRG);
1054 
1055                                 chan = chanlist;
1056                                 while ( (chan != NULL) && (strcasecmp(STRG,chan->name)) )
1057                                   chan=chan->next;
1058                                 j=0;
1059                               }
1060                             else
1061                               {
1062                                 j=-1;
1063                                 tprintf(n->sock,"pline 0 %cFormat: %c/join %c<#channel|channel number>\xff", NAVY,RED,BLUE);
1064                               }
1065                             ochan=n->channel;
1066                             if ( (chan!=NULL) && (numplayers(chan)>=chan->maxplayers))
1067                               { /* A Full channel */
1068                                 tprintf(n->sock,"pline 0 %cThat channel is %cFULL%c!\xff", NAVY, RED,BLACK);
1069                               }
1070                             else if ( (chan==NULL) && (j>=0) && (numchannels() >= game.maxchannels))
1071                               { /* Too many channels */
1072                                 tprintf(n->sock,"pline 0 %cCannot create any more channels!\xff",RED);
1073                               }
1074                             else if ( (chan==NULL) && (j>=0) && (game.command_join==4) && (n->securitylevel!=LEVEL_AUTHOP))
1075                               { /* Can't create a NEW channel */
1076                                 tprintf(n->sock,"pline 0 %cCannot create new channel\xff",RED);
1077                               }
1078                             else if (j>=0)
1079                               {
1080                                 if (chan == NULL)
1081                                   { /* New channel */
1082                                     chan=chanlist;
1083                                     while ((chan!= NULL) && (chan->next!=NULL)) chan=chan->next;
1084 
1085                                     if (chan==NULL)
1086                                       {
1087                                         chanlist=malloc(sizeof(struct channel_t));
1088                                         chan=chanlist;
1089                                       }
1090                                     else
1091                                       {
1092                                         chan->next=malloc(sizeof(struct channel_t));
1093                                         chan=chan->next;
1094                                       }
1095 
1096                                     chan->next=NULL;
1097                                     chan->net=NULL;
1098                                     strncpy(chan->name, STRG, CHANLEN-1); chan->name[CHANLEN-1]=0;
1099                                     chan->maxplayers=DEFAULTMAXPLAYERS;
1100                                     chan->status=STATE_ONLINE;
1101                                     chan->description[0]=0;
1102                                     chan->priority=DEFAULTPRIORITY;
1103                                     chan->sd_mode=SD_NONE;
1104                                     chan->persistant=0;
1105 
1106                                     /* Copy default settings */
1107                                     chan->starting_level=game.starting_level;
1108                                     chan->lines_per_level=game.lines_per_level;
1109                                     chan->level_increase=game.level_increase;
1110                                     chan->lines_per_special=game.lines_per_special;
1111                                     chan->special_added=game.special_added;
1112                                     chan->special_capacity=game.special_capacity;
1113                                     chan->classic_rules=game.classic_rules;
1114                                     chan->average_levels=game.average_levels;
1115                                     chan->sd_timeout=game.sd_timeout;
1116                                     chan->sd_lines_per_add=game.sd_lines_per_add;
1117                                     chan->sd_secs_between_lines=game.sd_secs_between_lines;
1118                                     strcpy(chan->sd_message,game.sd_message);
1119                                     chan->block_leftl=game.block_leftl;
1120                                     chan->block_leftz=game.block_leftz;
1121                                     chan->block_square=game.block_square;
1122                                     chan->block_rightl=game.block_rightl;
1123                                     chan->block_rightz=game.block_rightz;
1124                                     chan->block_halfcross=game.block_halfcross;
1125                                     chan->block_line=game.block_line;
1126                                     chan->special_addline=game.special_addline;
1127                                     chan->special_clearline=game.special_clearline;
1128                                     chan->special_nukefield=game.special_nukefield;
1129                                     chan->special_randomclear=game.special_randomclear;
1130                                     chan->special_switchfield=game.special_switchfield;
1131                                     chan->special_clearspecial=game.special_clearspecial;
1132                                     chan->special_gravity=game.special_gravity;
1133                                     chan->special_quakefield=game.special_quakefield;
1134                                     chan->special_blockbomb=game.special_blockbomb;
1135                                     chan->stripcolour=game.stripcolour;
1136                                     chan->serverannounce=game.serverannounce;
1137                                     chan->pingintercept=game.pingintercept;
1138 
1139                                     /* Remove ourselves from old channel list */
1140                                     n->channel=chan;
1141 
1142                                     lvprintf(4,"#%s-%s created new channel\n", n->channel->name,n->nick);
1143                                     tprintf(n->sock,"pline 0 %cCreated new Channel - %c#%s%c\xff", GREEN, BLUE, chan->name, BLACK);
1144                                   }
1145 
1146                                 else
1147                                   { /* An already existing channel */
1148                                     n->channel = chan;
1149                                     lvprintf(4,"#%s-%s joined channel\n", n->channel->name,n->nick);
1150 
1151                                     tprintf(n->sock,"pline 0 %cJoined existing Channel - %c#%s%c\xff", GREEN, BLUE, chan->name, BLACK);
1152                                   }
1153                                 remnet(ochan,n);
1154                                 addnet(chan,n);
1155 
1156                                 /* Send to old channel, this player join message */
1157                                 nsock=ochan->net;
1158                                 while (nsock!=NULL)
1159                                   {
1160                                     if ( (nsock->type==NET_CONNECTED) )
1161                                       {
1162                                         /* Tell them we've joined this channel */
1163                                         tprintf(nsock->sock,"pline 0 %c%s%c %chas joined channel #%s\xff", DARKGRAY,n->nick,BLACK,DARKGRAY,n->channel->name);
1164                                       }
1165                                     nsock=nsock->next;
1166                                   }
1167 
1168                                 if ((ochan->status == STATE_INGAME) || (ochan->status ==STATE_PAUSED))
1169                                   {
1170                                     n->status = STAT_NOTPLAYING;
1171                                     tprintf(n->sock,"endgame\xff");
1172                                   }
1173 
1174                                 /* Cleartheir Field */
1175                                 for(y=0;y<FIELD_MAXY;y++)
1176                                   for(x=0;x<FIELD_MAXX;x++)
1177                                     n->field[x][y]=0; /* Nothing */
1178 
1179                                 /* Work out gameslot */
1180                                 num1=n->gameslot;
1181                                 num2=0; num3=1;
1182                                 while ( (num2 < n->channel->maxplayers) && (num3) )
1183                                   {
1184                                     num2++;
1185                                     num3=0;
1186                                     nsock=n->channel->net;
1187                                     while (nsock!=NULL)
1188                                       {
1189                                         if( (nsock!=n) && ( (nsock->type==NET_CONNECTED) || (nsock->type==NET_WAITINGFORTEAM) )&&(nsock->gameslot==num2) ) num3=1;
1190                                         nsock=nsock->next;
1191                                       }
1192                                   }
1193                                 if (num3==1)
1194                                   {
1195                                     lvprintf(0,"#%s-%s Ran out of places in channel (FATAL)\n",n->channel->name,n->nick);
1196                                     killsock(n->sock);lostnet(n);
1197                                     return;
1198                                   }
1199 
1200                                 /* Clear our spot */
1201                                 tprintf(n->sock,"playerleave %d\xff",n->gameslot);
1202                                 n->gameslot=num2;
1203 
1204                                 /* Now, send playerleft to all on old channel AND to player */
1205                                 num3=0;
1206                                 num4=0;
1207                                 STRG2[0]=0;
1208                                 nsock=ochan->net;
1209                                 while (nsock!=NULL)
1210                                   {
1211                                     if ( (nsock!=n) && (nsock->type == NET_CONNECTED))
1212                                       {
1213                                         tprintf(nsock->sock,"playerleave %d\xff", num1);
1214                                         tprintf(n->sock,"playerleave %d\xff", nsock->gameslot);
1215                                         if (strcasecmp(STRG2,nsock->team))
1216                                           {/* Different team, so add player */
1217                                             num3++;
1218                                             if (nsock->status==STAT_PLAYING) num4++;
1219                                             strcpy(STRG2,nsock->team);
1220                                           }
1221                                         else if (STRG2[0]==0)
1222                                           {
1223                                             num3++;
1224                                             if (nsock->status==STAT_PLAYING) num4++;
1225                                           }
1226                                       }
1227                                     nsock=nsock->next;
1228                                   }
1229 
1230                                 /* Now send to new channel, this player joined, AND to player */
1231                                 nsock=n->channel->net;
1232                                 while (nsock!=NULL)
1233                                   {
1234                                     if ( (nsock!=n) && (nsock->type==NET_CONNECTED))
1235                                       {
1236                                         /* Send each other player and their team anme */
1237                                         tprintf(n->sock, "playerjoin %d %s\xffteam %d %s\xff",nsock->gameslot, nsock->nick, nsock->gameslot, nsock->team);
1238                                         /* Send to the other player, this player and their team */
1239                                         tprintf(nsock->sock, "playerjoin %d %s\xffteam %d %s\xff", n->gameslot, n->nick, n->gameslot, n->team);
1240                                         /* Tell them we've joined this channel */
1241                                         tprintf(nsock->sock,"pline 0 %c%s%c %chas joined channel #%s\xff", GREEN,n->nick,BLACK,GREEN,n->channel->name);
1242                                       }
1243                                     nsock=nsock->next;
1244                                   }
1245 
1246                                 /* Set our playernumber */
1247                                 tprintf(n->sock, "playernum %d\xff",n->gameslot);
1248 
1249                                 /* If game is in progress, send all other players fields */
1250                                 if( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) )
1251                                   {
1252                                     nsock=n->channel->net;
1253                                     while (nsock!=NULL)
1254                                       {
1255                                         if( (nsock->type==NET_CONNECTED) &&(nsock!=n))
1256                                           {
1257                                             /* Each player who has lost, send player_lost */
1258                                             if (nsock->status != STAT_PLAYING)
1259                                               {
1260                                                 tprintf(n->sock,"playerlost %d\xff", nsock->gameslot);
1261                                               }
1262                                             sendfield(n, nsock); /* Send to player, this players field */
1263                                           }
1264                                         nsock=nsock->next;
1265                                       }
1266                                   }
1267 
1268                                 /* If we are ingame, then tell this person that we are! */
1269                                 if ( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) )
1270                                   tprintf(n->sock,"ingame\xff");
1271 
1272                                 /* If we are currently paused, kindly let them know that fact to */
1273                                 if ( n->channel->status == STATE_PAUSED )
1274                                   tprintf(n->sock,"pause 1\xff");
1275 
1276                                 /* If 1 or less players/teams now are playing, AND the player that quit WAS playing, STOPIT */
1277                                 if ( (num4 <= 1) && (ochan->status == STATE_INGAME) && (n->status == STAT_PLAYING) )
1278                                   {
1279                                     nsock=ochan->net;
1280                                     while (nsock!=NULL)
1281                                       {
1282                                         if ( (nsock=n) && (nsock->type == NET_CONNECTED))
1283                                           {
1284                                             tprintf(nsock->sock,"endgame\xff");
1285                                             nsock->status=STAT_NOTPLAYING;
1286                                             nsock->timeout=game.timeout_outgame;
1287                                           }
1288                                         nsock=nsock->next;
1289                                       }
1290                                     ochan->status = STATE_ONLINE;
1291                                   }
1292 
1293                                 /* If no players, then we delete the channel IF it's not persistant*/
1294                                 if ( (numallplayers(ochan) == 0) && (ochan!=n->channel) && (!ochan->persistant) )
1295                                   {
1296                                     c=chanlist;
1297                                     oc=NULL;
1298                                     while ( (c != ochan) && (c != NULL) )
1299                                       {
1300                                         oc=c;
1301                                         c=c->next;
1302                                       }
1303                                     if (c != NULL)
1304                                       {
1305                                         if (oc != NULL)
1306                                           oc->next=c->next;
1307                                         else
1308                                           chanlist=c->next;
1309                                         free(c);
1310                                       }
1311                                   }
1312 
1313                                 n->timeout=game.timeout_outgame;
1314                                 if (n->channel->status == STATE_ONLINE)
1315                                   {
1316                                     n->status=STAT_NOTPLAYING;
1317                                   }
1318                                 else
1319                                   {
1320                                     n->status=STAT_LOST;
1321                                   }
1322                               }
1323                           }
1324                       }
1325                     else
1326                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1327                   }
1328 
1329                 /* Clear Winlist - Suggestion by n|ck */
1330                 if ( !strncasecmp(MSG, "/clear", 6) && (game.command_clear>0))
1331                   {
1332                     valid_param=2;
1333                     if ( passed_level(n,game.command_clear) )
1334                       {
1335                         lvprintf(4,"#%s-%s cleared the winlist\n",n->channel->name,n->nick);
1336                         init_winlist();
1337                         writewinlist();
1338                         sendwinlist(n->channel,NULL);
1339                       }
1340                     else
1341                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1342                   }
1343 
1344                 /* Persistant Channel */
1345                 if ( !strncasecmp(MSG, "/persistant", 11) && (game.command_persistant>0))
1346                   {
1347                     valid_param=2;
1348                     if ( passed_level(n,game.command_persistant) )
1349                       {
1350                         P=MSG+12;
1351                         if (*P=='0')
1352                           {
1353                             n->channel->persistant=0;
1354                             tprintf(n->sock,"pline 0 %cChannel will be deleted when last player leaves\xff",NAVY);
1355                           }
1356                         else
1357                           {
1358                             n->channel->persistant=1;
1359                             tprintf(n->sock,"pline 0 %cChannel is now persistant, and will not be deleted\xff",NAVY);
1360                           }
1361                       }
1362                     else
1363                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1364                   }
1365 
1366                 /* Save Config */
1367                 if ( !strncasecmp(MSG, "/save", 5) && (game.command_save>0))
1368                   {
1369                     valid_param=2;
1370                     if ( passed_level(n,game.command_save) )
1371                       {
1372                         gamewrite();
1373                         tprintf(n->sock,"pline 0 %cGame configuration and Persistant Channel info saved\xff",NAVY);
1374                       }
1375                     else
1376                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1377                   }
1378 
1379                 /* Reset/Load Config */
1380                 if ( !strncasecmp(MSG, "/reset", 6) && (game.command_reset>0))
1381                   {
1382                     valid_param=2;
1383                     if ( passed_level(n,game.command_reset) )
1384                       {
1385                         gameread();
1386                         tprintf(n->sock,"pline 0 %cGame configuration and Persistant Channel info loaded\xff",NAVY);
1387                       }
1388                     else
1389                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1390                   }
1391 
1392                 /* Private msg to a person - Suggestion by crazor */
1393                 if ( !strncasecmp(MSG, "/msg", 4) && (game.command_msg>0))
1394                   {
1395                     valid_param=2;
1396                     if ( passed_level(n,game.command_msg) )
1397                       {
1398                         P=MSG+5;
1399                         sscanf(P,"%512s %512[^\n\r ]", STRG, STRG2);
1400 
1401                         P=STRG;
1402                         while( (((*P)-'0') >= 1) && (((*P)-'0') <= 6) )
1403                           {
1404                             j=(*P)-'0';
1405                             nsock=n->channel->net;
1406                             while (nsock!=NULL)
1407                               {
1408                                 if ( (nsock->type == NET_CONNECTED) && (nsock->gameslot == j))
1409                                   {
1410                                     lvprintf(5,"#%s-(%s to %s): %s\n", n->channel->name,n->nick,nsock->nick,STRG2);
1411                                     tprintf(nsock->sock,"pline %d %c(msg)%c %s\xff", n->gameslot, NAVY, BLACK, STRG2);
1412                                   }
1413                                 nsock=nsock->next;
1414                               }
1415                             P++;
1416                           }
1417                       }
1418                     else
1419                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1420                   }
1421 
1422                 /* Move a player to another gamespot */
1423                 if ( !strncasecmp(MSG, "/move", 5) && (game.command_move>0))
1424                   {
1425                     valid_param=2;
1426                     if ( passed_level(n,game.command_move) && (n->channel->status == STATE_ONLINE) )
1427                       {
1428                         P=MSG+6;
1429                         k=0;l=0;
1430                         sscanf(P," %d %d", &k, &l);
1431 
1432                         if ( (k>0) && (k<=6) && (l>0) && (l<=6) && (k!=l) )
1433                           {
1434                             /* Ok, this is NOT supposed to work, but it does ;) */
1435 
1436                             /* Give player l, player k's number */
1437                             /* Give player k, player l's number */
1438                             /* Send to all others, as if they've rejoined */
1439 
1440                             /* Find sock_index... for k */
1441                             ns1=n->channel->net;
1442                             while ( (ns1!=NULL) && !( ((ns1->type == NET_CONNECTED) && (ns1->gameslot==k) )))
1443                               ns1=ns1->next;
1444 
1445                             ns2=n->channel->net;
1446                             while( (ns2!=NULL) && !((ns2->type == NET_CONNECTED) && (ns2->gameslot==l) ))
1447                               ns2=ns2->next;
1448 
1449                             if ( (ns1!=NULL) )
1450                               {
1451                                 tprintf(ns1->sock,"playernum %d\xff", l);
1452                                 ns1->gameslot = l;
1453 
1454                                 if (ns2!=NULL)
1455                                   { /* This player existed... */
1456                                     lvprintf(4,"#%s-%s swaps player %s(%d) with %s(%d)\n", n->channel->name,n->nick,ns1->nick,k,ns2->nick,l);
1457                                     tprintf(ns2->sock,"playernum %d\xff", k);
1458                                     ns2->gameslot=k;
1459                                     tprintf(ns1->sock,"playerjoin %d %s\xff", ns2->gameslot, ns2->nick);
1460                                     tprintf(ns2->sock,"playerjoin %d %s\xff", ns1->gameslot, ns1->nick);
1461                                   }
1462                                 else
1463                                   {
1464                                     lvprintf(4,"#%s-%s moves player %s(%d) to %s(%d)\n", n->channel->name,n->nick,ns1->nick,k,ns1->nick,l);
1465                                     tprintf(ns1->sock,"playerleave %d\xff", k);
1466                                   }
1467 
1468                                 /* Now tell everyone else */
1469                                 nsock=n->channel->net;
1470                                 while (nsock!=NULL)
1471                                   {
1472                                     if ( (nsock->type == NET_CONNECTED) && (nsock!=ns1) && (nsock!=ns2) )
1473                                       {
1474                                         tprintf(nsock->sock,"playerjoin %d %s\xff", ns1->gameslot, ns1->nick);
1475                                         if (ns2!=NULL)
1476                                           { /* Player existed */
1477                                             tprintf(nsock->sock,"playerjoin %d %s\xff", ns2->gameslot,ns2->nick);
1478                                           }
1479                                         else
1480                                           {
1481                                             tprintf(nsock->sock,"playerleave %d\xff", k);
1482                                           }
1483                                       }
1484                                     nsock=nsock->next;
1485                                   }
1486                               }
1487                           }
1488                         else
1489                           tprintf(n->sock,"pline 0 %c/move %c<playernumber> <newplayernumber>\xff", RED, BLUE);
1490 
1491                       }
1492                     else
1493                       {
1494                         if (n->channel->status != STATE_ONLINE)
1495                           tprintf(n->sock,"pline 0 %cCommand unavailable while a game is in progress. Stop it first.\xff",RED);
1496                         else
1497                           tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1498                       }
1499                   }
1500 
1501 
1502                 /* Take "ops" - Suggestion by (jawfx@hotmail.com 21/9/98) */
1503                 if ( !strncasecmp(MSG, "/op", 3) && (game.command_op>0))
1504                   {
1505                     valid_param=2;
1506                     P=MSG+4;
1507                     if (securityread() < 0)
1508                       securitywrite();
1509 
1510                     if ( (strlen(security.op_password) > 0) && !strcmp(P, security.op_password) )
1511                       { /* Passed, this player is OP */
1512                         n->securitylevel =LEVEL_AUTHOP;
1513                         tprintf(n->sock,"pline 0 %cYour security level is now: %cAUTHENTICATED OP\xff", GREEN, RED);
1514                         lvprintf(4,"#%s-%s authenticated successfully for op status\n", n->channel->name,n->nick);
1515                       }
1516                     else
1517                       {
1518                         tprintf(n->sock,"pline 0 Invalid Password! (Attempt logged)\xff");
1519                         lvprintf(1,"#%s-%s Failed attempt to gain OP status\n",  n->channel->name, n->nick);
1520                       }
1521                   }
1522 
1523                 /* Winlist. Display the top X people - Suggestion by crazor */
1524                 if ( !strncasecmp(MSG, "/winlist", 8) && (game.command_winlist>0) )
1525                   {
1526                     valid_param=2;
1527                     if (passed_level(n,game.command_winlist))
1528                       {
1529                         P=MSG+9;
1530                         if (strlen(MSG) == 8)
1531                           j=10;
1532                         else
1533                           j=atoi(P);
1534                         if ( (j >= 1) && (j <= MAXWINLIST) )
1535                           {
1536                             i=0;
1537                             tprintf(n->sock,"pline 0 %cTop %d Winlist\xff", BLUE, j);
1538                             while ( (i < j) && (winlist[i].inuse) )
1539                               {
1540                                 if (winlist[i].status == 't')
1541                                   {
1542                                     if (!strcmp(n->team, winlist[i].name))
1543                                       k = RED;
1544                                     else
1545                                       k = BLACK;
1546                                     tprintf(n->sock,"pline 0 %c%d. %4d - Team %s\xff", k, i+1, winlist[i].score, winlist[i].name);
1547                                   }
1548                                 else
1549                                   {
1550                                     if (!strcmp(n->nick, winlist[i].name))
1551                                       k = RED;
1552                                     else
1553                                       k = BLACK;
1554                                     tprintf(n->sock,"pline 0 %c%d. %4d - Player %s\xff", k, i+1, winlist[i].score, winlist[i].name);
1555                                   }
1556                                 i++;
1557                               }
1558                           }
1559                       }
1560                     else
1561                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1562                   }
1563 
1564                 if ( !strncasecmp(MSG, "/help", 5) && (game.command_help>0) )
1565                   {
1566                     valid_param=2;
1567                     if (passed_level(n,game.command_help))
1568                       {
1569                         tprintf(n->sock,"pline 0 V%s.%s - Built in server commands %c(*) %crequires 'op', %c(!) %crequires '/op'\xff", TETVERSION, SERVERBUILD, TEAL, BLACK, RED, BLACK);
1570                         if (game.command_clear>0)
1571                           {
1572                             STRG[0]=0;
1573                             switch(game.command_clear)
1574                               {
1575                                 case 2: /* Requires OP */
1576                                   {
1577                                     sprintf(STRG,"%c(*)", TEAL);
1578                                     break;
1579                                   }
1580                                 case 3: /* Requires /OP */
1581                                   {
1582                                     sprintf(STRG,"%c(!)", RED);
1583                                     break;
1584                                   }
1585                               }
1586                             tprintf(n->sock,"pline 0   %c/clear\xff", RED);
1587                             tprintf(n->sock,"pline 0       %-4s %cClears the winlist\xff", STRG, BLACK);
1588                           }
1589                         if (game.command_join)
1590                           {
1591                             STRG[0]=0;
1592                             switch(game.command_join)
1593                               {
1594                                 case 2: /* Requires OP */
1595                                   {
1596                                     sprintf(STRG,"%c(*)", TEAL);
1597                                     break;
1598                                   }
1599                                 case 3: /* Requires /OP */
1600                                   {
1601                                     sprintf(STRG,"%c(!)", RED);
1602                                     break;
1603                                   }
1604                               }
1605                             tprintf(n->sock,"pline 0   %c/join %c<#channel|channel number>\xff", RED, BLUE);
1606                             tprintf(n->sock,"pline 0       %-4s %cJoins or creates a virtual tetrinet channel\xff", STRG, BLACK);
1607                           }
1608                         if (game.command_kick)
1609                           {
1610                             STRG[0]=0;
1611                             switch(game.command_kick)
1612                               {
1613                                 case 2: /* Requires OP */
1614                                   {
1615                                     sprintf(STRG,"%c(*)", TEAL);
1616                                     break;
1617                                   }
1618                                 case 3: /* Requires /OP */
1619                                   {
1620                                     sprintf(STRG,"%c(!)", RED);
1621                                     break;
1622                                   }
1623                               }
1624                             tprintf(n->sock,"pline 0   %c/kick %c<playernumber(s)>\xff", RED, BLUE);
1625                             tprintf(n->sock,"pline 0       %-4s %cKicks player(s) from the server\xff", STRG, BLACK);
1626                           }
1627                         if (game.command_list)
1628                           {
1629                             STRG[0]=0;
1630                             switch(game.command_list)
1631                               {
1632                                 case 2: /* Requires OP */
1633                                   {
1634                                     sprintf(STRG,"%c(*)", TEAL);
1635                                     break;
1636                                   }
1637                                 case 3: /* Requires /OP */
1638                                   {
1639                                     sprintf(STRG,"%c(!)", RED);
1640                                     break;
1641                                   }
1642                               }
1643                             tprintf(n->sock,"pline 0   %c/list\xff", RED);
1644                             tprintf(n->sock,"pline 0       %-4s %cLists available virtual TetriNET channels\xff", STRG, BLACK);
1645                           }
1646                         tprintf(n->sock,"pline 0   %c/me %c<action>\xff", RED, BLUE);
1647                         tprintf(n->sock,"pline 0            Performs an action\xff");
1648                         if (game.command_move)
1649                           {
1650                             STRG[0]=0;
1651                             switch(game.command_move)
1652                               {
1653                                 case 2: /* Requires OP */
1654                                   {
1655                                     sprintf(STRG,"%c(*)", TEAL);
1656                                     break;
1657                                   }
1658                                 case 3: /* Requires /OP */
1659                                   {
1660                                     sprintf(STRG,"%c(!)", RED);
1661                                     break;
1662                                   }
1663                               }
1664                             tprintf(n->sock,"pline 0   %c/move %c<playernumber> <new playernumber>\xff", RED, BLUE);
1665                             tprintf(n->sock,"pline 0       %-4s %cMoves a player to a new playernumber\xff", STRG,BLACK);
1666                           }
1667 
1668                         if (game.command_msg)
1669                           {
1670                             STRG[0]=0;
1671                             switch(game.command_msg)
1672                               {
1673                                 case 2: /* Requires OP */
1674                                   {
1675                                     sprintf(STRG,"%c(*)", TEAL);
1676                                     break;
1677                                   }
1678                                 case 3: /* Requires /OP */
1679                                   {
1680                                     sprintf(STRG,"%c(!)", RED);
1681                                     break;
1682                                   }
1683                               }
1684                             tprintf(n->sock,"pline 0   %c/msg %c<playernumber(s)> <msg>\xff", RED, BLUE);
1685                             tprintf(n->sock,"pline 0       %-4s %cPrivately messages player(s)\xff", STRG,BLACK);
1686                           }
1687                         if (game.command_op)
1688                           {
1689                             tprintf(n->sock,"pline 0   %c/op %c<op_password>\xff", RED, BLUE);
1690                             tprintf(n->sock,"pline 0            Gain AUTHENTICATED OP status\xff");
1691                           }
1692                         if (game.command_persistant)
1693                           {
1694                             STRG[0]=0;
1695                             switch(game.command_persistant)
1696                               {
1697                                 case 2: /* Requires OP */
1698                                   {
1699                                     sprintf(STRG,"%c(*)", TEAL);
1700                                     break;
1701                                   }
1702                                 case 3: /* Requires /OP */
1703                                   {
1704                                     sprintf(STRG,"%c(!)", RED);
1705                                     break;
1706                                   }
1707                               }
1708                             tprintf(n->sock,"pline 0   %c/persistant %c<0/1>\xff", RED, BLUE);
1709                             tprintf(n->sock,"pline 0       %-4s %cPersistant channels are not deleted when the last person leaves\xff", STRG, BLACK);
1710                           }
1711                         if (game.command_priority)
1712                           {
1713                             STRG[0]=0;
1714                             switch(game.command_priority)
1715                               {
1716                                 case 2: /* Requires OP */
1717                                   {
1718                                     sprintf(STRG,"%c(*)", TEAL);
1719                                     break;
1720                                   }
1721                                 case 3: /* Requires /OP */
1722                                   {
1723                                     sprintf(STRG,"%c(!)", RED);
1724                                     break;
1725                                   }
1726                               }
1727                             tprintf(n->sock,"pline 0   %c/priority %c<channel priority(1-99)>\xff", RED, BLUE);
1728                             tprintf(n->sock,"pline 0       %-4s %cNew players join the highest priority channel\xff", STRG, BLACK);
1729                           }
1730                         if (game.command_reset)
1731                           {
1732                             STRG[0]=0;
1733                             switch(game.command_reset)
1734                               {
1735                                 case 2: /* Requires OP */
1736                                   {
1737                                     sprintf(STRG,"%c(*)", TEAL);
1738                                     break;
1739                                   }
1740                                 case 3: /* Requires /OP */
1741                                   {
1742                                     sprintf(STRG,"%c(!)", RED);
1743                                     break;
1744                                   }
1745                               }
1746                             tprintf(n->sock,"pline 0   %c/reset\xff", RED);
1747                             tprintf(n->sock,"pline 0       %-4s %cReload saved game configuration AND persistant channel config\xff", STRG, BLACK);
1748                           }
1749                         if (game.command_save)
1750                           {
1751                             STRG[0]=0;
1752                             switch(game.command_save)
1753                               {
1754                                 case 2: /* Requires OP */
1755                                   {
1756                                     sprintf(STRG,"%c(*)", TEAL);
1757                                     break;
1758                                   }
1759                                 case 3: /* Requires /OP */
1760                                   {
1761                                     sprintf(STRG,"%c(!)", RED);
1762                                     break;
1763                                   }
1764                               }
1765                             tprintf(n->sock,"pline 0   %c/save\xff", RED);
1766                             tprintf(n->sock,"pline 0       %-4s %cAll game configuration AND persistant channel info is saved\xff", STRG, BLACK);
1767                           }
1768                         if (game.command_set)
1769                           {
1770                             STRG[0]=0;
1771                             switch(game.command_set)
1772                               {
1773                                 case 2: /* Requires OP */
1774                                   {
1775                                     sprintf(STRG,"%c(*)", TEAL);
1776                                     break;
1777                                   }
1778                                 case 3: /* Requires /OP */
1779                                   {
1780                                     sprintf(STRG,"%c(!)", RED);
1781                                     break;
1782                                   }
1783                               }
1784                             tprintf(n->sock,"pline 0   %c/set\xff", RED);
1785                             tprintf(n->sock,"pline 0       %-4s %cSet Channel Config. Type %c/set %cHELP\xff", STRG, BLACK,BLUE,RED);
1786                           }
1787                         if (game.command_topic)
1788                           {
1789                             STRG[0]=0;
1790                             switch(game.command_topic)
1791                               {
1792                                 case 2: /* Requires OP */
1793                                   {
1794                                     sprintf(STRG,"%c(*)", TEAL);
1795                                     break;
1796                                   }
1797                                 case 3: /* Requires /OP */
1798                                   {
1799                                     sprintf(STRG,"%c(!)", RED);
1800                                     break;
1801                                   }
1802                               }
1803                             tprintf(n->sock,"pline 0   %c/topic %c<channel topic>\xff", RED, BLUE);
1804                             tprintf(n->sock,"pline 0       %-4s %cChanges the topic of the virtual TetriNET channel\xff", STRG, BLACK);
1805                           }
1806                         if (game.command_who)
1807                           {
1808                             STRG[0]=0;
1809                             switch(game.command_who)
1810                               {
1811                                 case 2: /* Requires OP */
1812                                   {
1813                                     sprintf(STRG,"%c(*)", TEAL);
1814                                     break;
1815                                   }
1816                                 case 3: /* Requires /OP */
1817                                   {
1818                                     sprintf(STRG,"%c(!)", RED);
1819                                     break;
1820                                   }
1821                               }
1822                             tprintf(n->sock,"pline 0   %c/who\xff", RED);
1823                             tprintf(n->sock,"pline 0       %-4s %cLists all logged in players, and what channel they're on\xff", STRG, BLACK);
1824                           }
1825 
1826                         if (game.command_winlist)
1827                           {
1828                             STRG[0]=0;
1829                             switch(game.command_winlist)
1830                               {
1831                                 case 2: /* Requires OP */
1832                                   {
1833                                     sprintf(STRG,"%c(*)", TEAL);
1834                                     break;
1835                                   }
1836                                 case 3: /* Requires /OP */
1837                                   {
1838                                     sprintf(STRG,"%c(!)", RED);
1839                                     break;
1840                                   }
1841                               }
1842                             tprintf(n->sock,"pline 0   %c/winlist %c[n]\xff", RED, BLUE);
1843                             tprintf(n->sock,"pline 0       %-4s %cDisplays the top n players\xff",STRG,BLACK);
1844                           }
1845                       }
1846                     else
1847                       tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1848                   }
1849                 if (valid_param==1)
1850                   {
1851                     tprintf(n->sock,"pline 0 %cInvalid /COMMAND!\xff",RED);
1852                   }
1853               }
1854             else
1855               {
1856                 lvprintf(5,"#%s-%s: %s\n", n->channel->name,n->nick,MSG);
1857                 nsock=n->channel->net;
1858                 while (nsock!=NULL)
1859                   {
1860                     if ( (nsock!=n) && (nsock->type == NET_CONNECTED) )
1861                       {  /* Write line, after first resetting it to black (incase colour still exists from nick) */
1862                         tprintf(nsock->sock,"pline %d %c%s\xff", n->gameslot, BLACK, MSG);
1863                       }
1864                     nsock=nsock->next;
1865                   }
1866               }
1867             valid_param=1;
1868           }
1869       }
1870 
1871     /* Party Line Act - plineact <playernumber> <message> */
1872     if ( !strcasecmp(COMMAND, "plineact") )
1873       {
1874         valid_param=2;
1875         s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
1876         if ( (s >= 2) && (num==n->gameslot))
1877           {
1878             valid_param=1;
1879             lvprintf(5,"#%s-%s acts: %s\n",n->channel->name,n->nick,MSG);
1880             nsock=n->channel->net;
1881             while (nsock!=NULL)
1882               {
1883                 if ( (nsock!=n) && (nsock->type == NET_CONNECTED))
1884                   {  /* Write out action, after first resetting colors */
1885                     tprintf(nsock->sock,"plineact %d %s\xff", n->gameslot, MSG);
1886                   }
1887                 nsock=nsock->next;
1888               }
1889           }
1890       }
1891 
1892 
1893     /* Change Team - team <playernumber> <teamname> */
1894     if ( !strcasecmp(COMMAND, "team") )
1895       {
1896         valid_param=2;
1897         s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
1898         if ( (s >= 1) && (num==n->gameslot) && (n->status == STAT_NOTPLAYING))
1899           {
1900             valid_param=1;
1901             strncpy(n->team, MSG, TEAMLEN); n->team[TEAMLEN]=0;
1902             lvprintf(5,"#%s-%s changes team to %s\n",n->channel->name,n->nick,n->team);
1903             nsock=n->channel->net;
1904             while (nsock!=NULL)
1905               {
1906                 if ( (n!=nsock) && (nsock->type == NET_CONNECTED) )
1907                   tprintf(nsock->sock,"team %d %s\xff", n->gameslot, MSG);
1908                 nsock=nsock->next;
1909               }
1910           }
1911       }
1912 
1913     /* Pause Game - pause <0|1> <playernumber> */
1914     if ( !strcasecmp(COMMAND, "pause") )
1915       {
1916         valid_param=2;
1917         s = sscanf(PARAM, "%d %d", &num, &num2);
1918         if ( (s >= 2) && is_op(n) && (n->channel->status == STATE_INGAME) && (num2==n->gameslot) && ( (num==0)||(num==1)) )
1919           {
1920             if (num==1)
1921               lvprintf(4,"#%s-%s pauses game\n",n->channel->name,n->nick);
1922             else
1923               lvprintf(5,"#%2-%s unpauses game\n",n->channel->name,n->nick);
1924 
1925 
1926             valid_param=1;
1927             nsock=n->channel->net;
1928             while(nsock!=NULL)
1929               {
1930                 if ( (nsock->type == NET_CONNECTED) && (nsock->channel==n->channel))
1931                   tprintf(nsock->sock,"pause %d\xff", num);
1932                 nsock=nsock->next;
1933               }
1934             if (num==0)
1935               n->channel->status=STATE_PAUSED;
1936             else
1937               n->channel->status=STATE_INGAME;
1938           }
1939       }
1940 
1941     /* Game message - gmsg <message> */
1942     if ( !strcasecmp(COMMAND, "gmsg") )
1943       {
1944         valid_param=1;
1945         /* If it's just "t", then reply PONG to player only*/
1946         sprintf(MSG,"<%s> t", n->nick);
1947         if ( !strcasecmp(MSG, PARAM) && n->channel->pingintercept)
1948           {
1949             tprintf(n->sock,"gmsg * PONG\xff");
1950           }
1951         else
1952           {
1953             /* FIRST, get the NICK, and strip out color codes. Else it looks horrible */
1954             sprintf(MSG,"<%s>", n->nick);
1955             j=0;
1956             if ( PARAM[0] == '<' )
1957               { /* Yep, its a message. So save nick stripped of colour codes in MSG */
1958                 j=strlen(MSG);
1959                 MSG[0]=0;
1960                 P=MSG;
1961                 for(i=0;i<j;i++)
1962                   {
1963                     if ( n->channel->stripcolour
1964                       && (PARAM[i] != BOLD)
1965                       && (PARAM[i] != CYAN)
1966                       && (PARAM[i] != BLACK)
1967                       && (PARAM[i] != BLUE)
1968                       && (PARAM[i] != DARKGRAY)
1969                       && (PARAM[i] != MAGENTA)
1970                       && (PARAM[i] != GREEN)
1971                       && (PARAM[i] != NEON)
1972                       && (PARAM[i] != SILVER)
1973                       && (PARAM[i] != BROWN)
1974                       && (PARAM[i] != NAVY)
1975                       && (PARAM[i] != VIOLET)
1976                       && (PARAM[i] != RED)
1977                       && (PARAM[i] != ITALIC)
1978                       && (PARAM[i] != TEAL)
1979                       && (PARAM[i] != WHITE)
1980                       && (PARAM[i] != YELLOW)
1981                       && (PARAM[i] != UNDERLINE) )
1982                       {
1983                         *P = PARAM[i];
1984                         P++;
1985                       }
1986                   }
1987                 *P='\0';
1988                 P=PARAM+j+1;
1989                 j=1;
1990               }
1991             lvprintf(5,"#%s-%s: %s\n", n->channel->name,n->nick,PARAM);
1992             nsock=n->channel->net;
1993             while (nsock!=NULL)
1994               {
1995                 if ( (nsock->type == NET_CONNECTED) )
1996                   {
1997                     if (j)
1998                       tprintf(nsock->sock,"gmsg %s %s\xff", MSG, P);
1999                     else
2000                       tprintf(nsock->sock,"gmsg %s\xff", PARAM);
2001                   }
2002                 nsock=nsock->next;
2003               }
2004           }
2005       }
2006 
2007     /* Player Lost - playerlost <playernumber> */
2008     if ( !strcasecmp(COMMAND, "playerlost") )
2009       {
2010         valid_param=2;
2011         s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
2012         if ( (s >= 1) && ( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) ) && (num==n->gameslot) )
2013           {
2014             valid_param=1;
2015             /* Now, is this player actually playing? If not, we just ignore them */
2016             if (n->status == STAT_PLAYING)
2017               {
2018                 /* Set player to be "Lost" */
2019                 n->status = STAT_LOST;
2020                 n->timeout = game.timeout_outgame;
2021                 lvprintf(6,"#%s-%s lost\n",n->channel->name,n->nick);
2022 
2023                 num2=0;    /* Assume no-one left playing */
2024                 num3=0;	/* Player who is still in */
2025                 MSG[0]=0;  /* Store playing team name here */
2026                 /* Check if game is finished, and tell each person this player has lost */
2027                 nsock=n->channel->net;
2028                 ns1=NULL;
2029                 while (nsock!=NULL)
2030                   {
2031                     if ( (nsock!=n) && (nsock->type == NET_CONNECTED) && (nsock->status == STAT_PLAYING))
2032                       {
2033                         tprintf(nsock->sock,"playerlost %d\xff",num);
2034                         if (strcasecmp(MSG,nsock->team))
2035                           { /* Different team, so add player */
2036                             num2++;
2037                             ns1=nsock;
2038                             strcpy(MSG,nsock->team);
2039                           }
2040                         else if (MSG[0]==0)
2041                           {
2042                             num2++;
2043                             ns1=nsock;
2044                           }
2045                       }
2046                     nsock=nsock->next;
2047                   }
2048                 if ( (num2 <= 1) && (ns1!=NULL) )
2049                   { /* 1 or less different teams playing. Stop the game, and take score */
2050                     if (ns1->type == NET_CONNECTED)
2051                       {
2052                         if (strlen(ns1->team) > 0)
2053                           { /* Team won, so add score to team */
2054                             updatewinlist(ns1->team,'t',3);
2055                           }
2056                         else
2057                           { /* Player won, so add score to player name */
2058                             updatewinlist(ns1->nick,'p',3);
2059                           }
2060                       }
2061                     n->channel->status=STATE_ONLINE;
2062                     nsock=n->channel->net;
2063                     while (nsock!=NULL)
2064                       {
2065                         if ( (nsock->type == NET_CONNECTED))
2066                           {
2067                             tprintf(nsock->sock,"endgame\xff");
2068                             tprintf(nsock->sock,"playerwon %d\xff", ns1->gameslot);
2069                             nsock->status=STAT_NOTPLAYING;
2070                             nsock->timeout=game.timeout_outgame;
2071                             /* Send every playing field */
2072 
2073                             ns2=n->channel->net;
2074                             while (ns2!=NULL)
2075                               {
2076                                 if ( (ns2!=nsock) && (ns2->type == NET_CONNECTED))
2077                                   sendfield(nsock,ns2);
2078                                 ns2=ns2->next;
2079                               }
2080 
2081                             /*!!! ADD-IN: Server anounces winner */
2082                             if ( (ns1->type == NET_CONNECTED) && n->channel->serverannounce)
2083                               {
2084                                 if ( strlen(ns1->team) > 0)
2085                                   { /* a team won */
2086                                     tprintf(nsock->sock,"pline 0 ---- Team %s%c WON ----\xff", ns1->team, BLACK);
2087                                   }
2088                                 else
2089                                   { /* a player won */
2090                                     tprintf(nsock->sock,"pline 0 ---- Player %s%c WON ----\xff", ns1->nick, BLACK);
2091                                   }
2092                               }
2093                           }
2094                         nsock=nsock->next;
2095                       }
2096                     writewinlist();
2097                     sendwinlist(n->channel,NULL);	/* Send to all */
2098 
2099                   }
2100 
2101               }
2102 
2103           }
2104       }
2105 
2106     /* Field Update - f <field codes> */
2107     if ( !strcasecmp(COMMAND, "f") )
2108       {
2109         valid_param=2;
2110         s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
2111         if ( (s >= 1) && (num==n->gameslot))
2112           {
2113             valid_param=1;
2114             /* First, transmit these changes as is to all other players */
2115             nsock=n->channel->net;
2116             while (nsock!=NULL)
2117               {
2118                 if ( (nsock!=n) && (nsock->type == NET_CONNECTED))
2119                   tprintf(nsock->sock,"f %d %s\xff", n->gameslot, MSG);
2120                 nsock=nsock->next;
2121               }
2122 
2123             /* Now parse it ourselves, and update our internal knowledge of players field */
2124             parsefield(n, MSG);
2125           }
2126       }
2127 
2128     /* Level - lvl <playernumber> <current level> */
2129     if ( !strcasecmp(COMMAND, "lvl") )
2130       {
2131         valid_param=2;
2132         s = sscanf(PARAM, "%d %d", &num, &num2);
2133         if ( (n->channel->status==STATE_INGAME) && (num==n->gameslot) && (n->status == STAT_PLAYING) )
2134           {
2135             valid_param=1;
2136             nsock=n->channel->net;
2137             while (nsock!=NULL)
2138               {
2139                 if ( (nsock->type == NET_CONNECTED))
2140                   tprintf(nsock->sock,"lvl %d %d\xff", n->gameslot,num2);
2141                 nsock=nsock->next;
2142               }
2143           }
2144       }
2145 
2146     /* Special Block Use - sb <to use on,0=all> <special block> <playernum> */
2147     if ( !strcasecmp(COMMAND, "sb") )
2148       {
2149         valid_param=2;
2150         s = sscanf(PARAM, "%d %s %d", &num, MSG, &num2);
2151         if ( (s >= 3) && (n->channel->status == STATE_INGAME) && (num2==n->gameslot) && (n->status == STAT_PLAYING))
2152           {
2153             valid_param=1;
2154             nsock=n->channel->net;
2155             while (nsock!=NULL)
2156               {
2157                 if ( (nsock!=n) && (nsock->type == NET_CONNECTED) )
2158                   {
2159                     tprintf(nsock->sock,"sb %d %s %d\xff", num, MSG, n->gameslot);
2160                   }
2161                 nsock=nsock->next;
2162               }
2163           }
2164       }
2165 
2166     /* Start/Stop Game - startgame <0/1, 0=stopgame> <playernumber> */
2167     if ( !strcasecmp(COMMAND, "startgame") )
2168       {
2169         valid_param=2;
2170         s = sscanf(PARAM, "%d %d %600[^\n\r]", &num, &num2, MSG);
2171         if ( (s >= 2) && is_op(n) && ( ((num==1) && (n->channel->status == STATE_ONLINE)) || ((num==0) && (n->channel->status == STATE_INGAME)) ) && (num2==n->gameslot) && ( (num == 1) || (num == 0)) )
2172           {
2173             valid_param=1;
2174             if (num==1)
2175               {
2176                 n->channel->status = STATE_INGAME;
2177                 lvprintf(4,"#%s-%s started the game\n", n->channel->name,n->nick);
2178               }
2179             else
2180               {
2181                 n->channel->status = STATE_ONLINE;
2182                 lvprintf(4,"#%s-%s stopped the game\n", n->channel->name,n->nick);
2183                 n->channel->sd_mode=SD_NONE;
2184               }
2185 
2186             /* Read in Game config and winlist, in case they were changed */
2187 /*            gameread();*/
2188             readwinlist();
2189 
2190             /* Set the SuddenDeath timeout, if any */
2191             if (n->channel->sd_timeout>0)
2192               {
2193                 n->channel->sd_mode=SD_INIT;
2194                 n->channel->sd_timeleft=n->channel->sd_timeout;
2195               }
2196             nsock=n->channel->net;
2197             while (nsock!=NULL)
2198               {/* Send to every player the game parameters */
2199                 if ( (nsock->type == NET_CONNECTED))
2200                   {
2201                     if (num == 1) /* Start game */
2202                       {
2203 
2204                         tprintf(nsock->sock,"newgame 0 ");
2205                         tprintf(nsock->sock,"%d %d %d %d %d %d ",
2206                                   n->channel->starting_level, n->channel->lines_per_level,
2207                                   n->channel->level_increase, n->channel->lines_per_special,
2208                                   n->channel->special_added, n->channel->special_capacity);
2209                         for(j=0;j<n->channel->block_leftl;j++) tprintf(nsock->sock,"3");
2210                         for(j=0;j<n->channel->block_leftz;j++) tprintf(nsock->sock,"5");
2211                         for(j=0;j<n->channel->block_square;j++)tprintf(nsock->sock,"2");
2212                         for(j=0;j<n->channel->block_rightl;j++)tprintf(nsock->sock,"4");
2213                         for(j=0;j<n->channel->block_rightz;j++)tprintf(nsock->sock,"6");
2214                         for(j=0;j<n->channel->block_halfcross;j++) tprintf(nsock->sock,"7");
2215                         for(j=0;j<n->channel->block_line;j++)  tprintf(nsock->sock,"1");
2216                         tprintf(nsock->sock," ");
2217                         for(j=0;j<n->channel->special_addline;j++) tprintf(nsock->sock,"1");
2218                         for(j=0;j<n->channel->special_clearline;j++) tprintf(nsock->sock,"2");
2219                         for(j=0;j<n->channel->special_nukefield;j++) tprintf(nsock->sock,"3");
2220                         for(j=0;j<n->channel->special_randomclear;j++) tprintf(nsock->sock,"4");
2221                         for(j=0;j<n->channel->special_switchfield;j++) tprintf(nsock->sock,"5");
2222                         for(j=0;j<n->channel->special_clearspecial;j++) tprintf(nsock->sock,"6");
2223                         for(j=0;j<n->channel->special_gravity;j++) tprintf(nsock->sock,"7");
2224                         for(j=0;j<n->channel->special_quakefield;j++) tprintf(nsock->sock,"8");
2225                         for(j=0;j<n->channel->special_blockbomb;j++) tprintf(nsock->sock,"9");
2226                         tprintf(nsock->sock," %d %d\xff", n->channel->average_levels, n->channel->classic_rules);
2227 
2228                         /* And set them to be playing */
2229                         nsock->status = STAT_PLAYING;
2230 
2231                         /* Give them new timeouts */
2232                         nsock->timeout = game.timeout_ingame;
2233 
2234                         /* BLANK *ALL* the fields and send them to each player */
2235                         /* Clear their Field */
2236                         for(y=0;y<FIELD_MAXY;y++)
2237                           for(x=0;x<FIELD_MAXX;x++)
2238                             nsock->field[x][y]=0; /* Nothing */
2239 
2240                         /* Send to every other player */
2241                         ns1=n->channel->net;
2242                         while (ns1!=NULL)
2243                           {
2244                             if ( (ns1!=nsock) && (ns1->type==NET_CONNECTED) )
2245                               {
2246                                 sendfield(ns1,nsock);
2247                               }
2248                             ns1=ns1->next;
2249                           }
2250                       }
2251                     else  /* End Game */
2252                       {
2253                         tprintf(nsock->sock,"endgame\xff");
2254                         /* And set them to not be playing */
2255                         nsock->status = STAT_NOTPLAYING;
2256                         nsock->timeout = game.timeout_outgame;
2257                       }
2258                   }
2259                 nsock=nsock->next;
2260               }
2261           }
2262       }
2263 
2264 
2265 
2266     /* Log invalid params */
2267     if (valid_param==0)
2268       lvprintf(1,"#%s-%s - Invalid Command - %s\n", n->channel->name,n->nick, buf);
2269   }
2270 
2271 /* The player has sent their inital team name, well they should have anyway */
net_waitingforteam(struct net_t * n,char * buf)2272 void net_waitingforteam(struct net_t *n, char *buf)
2273   {
2274     FILE *file_in;
2275     char strg[1024];
2276     char *P;
2277     struct net_t *nsock;
2278 
2279     sprintf(strg,"team %d ",n->gameslot);
2280     if (strncmp(buf,strg,strlen(strg)))
2281       { /* Incorrect, Kill this player, they never existed ;) */
2282         lvprintf(1,"Incorrect TEAM statement - %s!\n",buf);
2283         killsock(n->sock); lostnet(n);
2284         return;
2285       }
2286 
2287     P=buf+strlen(strg);
2288     n->type=NET_CONNECTED;
2289     n->status=STAT_NOTPLAYING;
2290     strncpy(n->team, P, TEAMLEN); n->team[TEAMLEN]='\0';
2291 
2292     nsock=n->channel->net;
2293     while (nsock!=NULL)
2294       {
2295         if ( (nsock != n) && (nsock->type==NET_CONNECTED))
2296           {
2297             /* Send each other player and their team to this player */
2298             tprintf(n->sock, "playerjoin %d %s\xffteam %d %s\xff", nsock->gameslot, nsock->nick, nsock->gameslot, nsock->team);
2299 
2300             /* Send to the other player, this player and their team */
2301             tprintf(nsock->sock, "playerjoin %d %s\xffteam %d %s\xff", n->gameslot, n->nick, n->gameslot, n->team);
2302           }
2303         nsock=nsock->next;
2304       }
2305 
2306     /* Now for the game.motd if it exists. */
2307     file_in = fopen(FILE_MOTD,"r");
2308     if (file_in != NULL)
2309       {/* Exists, so send it to the player */
2310         while (!feof(file_in))
2311           {
2312             fscanf(file_in,"%1023[^\n]\n", strg);
2313             tprintf(n->sock,"pline 0 %s\xff", strg);
2314           }
2315         fclose(file_in);
2316       }
2317 
2318     /* If game is in progress, send all other players fields */
2319     /* Tell each other player that we are lost... no really :P */
2320     if( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) )
2321       {
2322         nsock=n->channel->net;
2323         while (nsock!=NULL)
2324           {
2325             if( (nsock->type==NET_CONNECTED) &&(nsock!=n) )
2326               {
2327                 /* Each player who has lost, send player_lost */
2328                 if (nsock->status != STAT_PLAYING)
2329                   {
2330                     tprintf(n->sock,"playerlost %d\xff", nsock->gameslot);
2331                   }
2332                 sendfield(n, nsock); /* Send to player, this players field */
2333 
2334                 /* And tell this player that the newjoined player has lost */
2335                 tprintf(nsock->sock,"playerlost %d\xff", n->gameslot);
2336               }
2337             nsock=nsock->next;
2338           }
2339       }
2340 
2341     /* If we are ingame, then tell this person that we are! */
2342     if ( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) )
2343       tprintf(n->sock,"ingame\xff");
2344 
2345     /* If we are currently paused, kindly let them know that fact to */
2346     if ( n->channel->status == STATE_PAUSED )
2347       tprintf(n->sock,"pause 1\xff");
2348 
2349     /* And tell them their channel */
2350     tprintf(n->sock,"pline 0 %c%s%c %chas joined channel #%s\xff", GREEN,n->nick,BLACK,GREEN,n->channel->name);
2351 
2352     lvprintf(2,"#%s-%s New connection\n", n->channel->name,n->nick);
2353   }
2354 
2355 /* Recieving Query commands */
net_query_init(struct net_t * n,char * buf)2356 void net_query_init(struct net_t *n, char *buf)
2357   {
2358     killsock(n->sock);lostnet(n);
2359     return;
2360   }
2361 
2362 /* The person has sent their init string */
net_telnet_init(struct net_t * n,char * buf)2363 void net_telnet_init(struct net_t *n, char *buf)
2364   {
2365     int gameslot,found,i;
2366     int tet_err;
2367     char *dec;
2368     struct channel_t *chan;
2369     struct net_t *nsock;
2370 
2371     /* Work out game slot */
2372     gameslot=0; found=1;
2373     while ( (gameslot < n->channel->maxplayers) && (found) )
2374       {
2375         gameslot++;
2376         found=0;
2377         nsock=n->channel->net;
2378         while (nsock!=NULL)
2379           {
2380             if( ( (nsock->type==NET_CONNECTED) || (nsock->type==NET_WAITINGFORTEAM) )&&(nsock->gameslot==gameslot) ) found=1;
2381             nsock=nsock->next;
2382           }
2383       }
2384 
2385     if (found)
2386       { /* No free Gameslots, so tell that the server is full!! */
2387         tprintf(n->sock,"noconnecting Server is Full!\xff");
2388         lvprintf(9,"%s: Disconnected because of FULL server.\n",n->host);
2389         killsock(n->sock); lostnet(n); return;
2390       }
2391 
2392     /* Set Game Socket */
2393     n->gameslot = gameslot;
2394 
2395     lvprintf(10,"INIT: %s\n", buf);
2396 
2397     /* If init string is in fact "playerquery", return number of logged in players, and kill them */
2398     if (!strcasecmp(buf, "playerquery"))
2399       {
2400         lvprintf(9,"%s: Playerquery request\n",n->host);
2401         tprintf(n->sock, "Number of players logged in: %d\n", numplayers(n->channel));
2402         return;
2403       }
2404 
2405     /* Version - Return Full version of server */
2406     if (!strcasecmp(buf, "version"))
2407       {
2408         lvprintf(9,"%s: Version request\n",n->host);
2409         tprintf(n->sock,"%s.%s\n+OK\n", TETVERSION, SERVERBUILD);
2410         return;
2411       }
2412 
2413     /* ListChan - List of all channels */
2414     if (!strcasecmp(buf, "listchan"))
2415       {
2416         lvprintf(9,"%s: ListChan request\n",n->host);
2417         chan=chanlist;
2418         while(chan!=NULL)
2419           {
2420             tprintf(n->sock,"\"%s\" \"%s\" %d %d %d %d\n",chan->name, chan->description, numplayers(chan), chan->maxplayers, chan->priority, chan->status);
2421             chan=chan->next;
2422           }
2423         tprintf(n->sock,"+OK\n");
2424         return;
2425       }
2426 
2427     /* Listuser - List of all users */
2428     if (!strcasecmp(buf,"listuser"))
2429       {
2430         lvprintf(9,"%s: ListUser request\n",n->host);
2431         chan=chanlist;
2432         while (chan!=NULL)
2433           {
2434             nsock=chan->net;
2435             while (nsock!=NULL)
2436               {
2437                 if(nsock->type==NET_CONNECTED)
2438                   {
2439                     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);
2440                   }
2441                 nsock=nsock->next;
2442               }
2443             chan=chan->next;
2444           }
2445         tprintf(n->sock,"+OK\n");
2446         return;
2447       }
2448 
2449     /* Winlist - Returns Winlist */
2450     if (!strcasecmp(buf,"getwinlist"))
2451       {
2452         lprintf("%s: GetWinlist request\n",n->host);
2453         for(i=0;i<MAXWINLIST;i++)
2454           {
2455             if(winlist[i].inuse)
2456               {
2457                 tprintf(n->sock,"\"%s\" %c %lu\n", winlist[i].name,winlist[i].status,winlist[i].score);
2458               }
2459           }
2460         tprintf(n->sock,"+OK\n");
2461         return;
2462       }
2463 
2464     if (strlen(buf) < 7)
2465       {/* Invalid... quit */
2466         lvprintf(9,"%s: Disconnected due to invalid command (This can be normal)\n",n->host);
2467         killsock(n->sock);lostnet(n);
2468         return;
2469 
2470       }
2471 
2472 
2473 
2474     tet_err = tet_decrypt(buf);
2475     if (tet_err != 0)
2476       { /* Error */
2477         lvprintf(9,"%s: Disconnected due to failed decryption: %s\n",n->host,buf);
2478         killsock(n->sock); lostnet(n);
2479         return;
2480       }
2481 
2482     dec = tet_dec2str(buf);
2483 
2484     lvprintf(10,"DECR: %s\n", dec);
2485 
2486     /* OK, so dec should now hold "tetrisstart <nickname> <version number> */
2487     i = sscanf(dec,"tetrisstart %30[^\x20] %10s", n->nick, n->version);
2488 
2489 
2490     if (i < 2)
2491       {/* To few conversions - Player dies*/
2492         lvprintf(9,"%s: Disconnected due to invalid tetrisstart: %s\n",n->host,dec);
2493         killsock(n->sock); lostnet(n);
2494       }
2495 
2496     /* Ensure a valid nickname */
2497     if (!strcasecmp(n->nick,"server"))
2498       {
2499         lvprintf(9,"%s Disconnected due to invalid nickname: %s\n",n->host,n->nick);
2500         tprintf(n->sock, "noconnecting Nickname %s not allowed!\xff", n->nick);
2501         killsock(n->sock); lostnet(n);
2502       }
2503 
2504     /* Ensure that Version is OK */
2505     if (tet_checkversion(n->version) == -1)
2506       {
2507         tprintf(n->sock, "noconnecting TetriNET version (%s) does not match Server's (%s)!\xff", n->version, TETVERSION);
2508         lvprintf(9,"%s: Client version (%s) not allowed!\n", n->nick, n->version);
2509         killsock(n->sock); lostnet(n);
2510         return;
2511       }
2512 
2513     /* Ensure that no-one else has this nick */
2514     found=0;
2515     chan=chanlist;
2516     while( (chan!=NULL) && !found)
2517       {
2518         nsock=chan->net;
2519         while ((nsock!=NULL) && !found)
2520           {
2521             if( ((nsock->type==NET_CONNECTED) || (nsock->type==NET_WAITINGFORTEAM) )&&(nsock!=n)&&(!strcasecmp(nsock->nick, n->nick)) ) found=1;
2522             nsock=nsock->next;
2523           }
2524         chan=chan->next;
2525       }
2526     if (found)
2527       {
2528         tprintf(n->sock, "noconnecting Nickname already exists on server!\xff");
2529         lvprintf(9,"%s: Disconnected since nickname already exists on server: %s\n",n->host,n->nick);
2530         killsock(n->sock); lostnet(n);
2531         return;
2532       }
2533 
2534     n->team[0] = 0; /* Clear Team */
2535 
2536     /* Now waiting for team */
2537     n->type = NET_WAITINGFORTEAM;
2538 
2539     /* Send Winlist to this new arrival */
2540     sendwinlist(n->channel,n);
2541 
2542     /* Send them their player number */
2543     tprintf(n->sock, "playernum %d\xff",gameslot);
2544 
2545 
2546   }
2547 
2548 /* Someone has just connected. So lets answer them */
net_telnet(struct net_t * n,char * buf)2549 void net_telnet(struct net_t *n, char *buf)
2550   {
2551     unsigned long ip; int k,l; char s[121]; char strg[121];
2552     char n1[4], n2[4], n3[4], n4[4];
2553     struct channel_t *chan, *ochan;
2554     struct net_t *net;
2555     int x,y;
2556 
2557 
2558     net=malloc(sizeof(struct net_t));
2559     net->next=NULL;
2560 
2561     net->sock=answer(n->sock,s,&ip,0);
2562 
2563     while ((net->sock==(-1)) && (errno==EAGAIN))
2564       net->sock=answer(n->sock,s,&ip,0);
2565     /* Find a channel */
2566     chan = chanlist;
2567     ochan = NULL;
2568     while ( chan != NULL )
2569       {
2570         if ( ((ochan == NULL) || (chan->priority > ochan->priority)) && (numplayers(chan) < chan->maxplayers) && (chan->priority!=0))
2571           ochan=chan; /* Found a likely channel */
2572         chan=chan->next;
2573       }
2574 
2575 
2576     /* Save the port stuff */
2577     net->addr=ip;
2578     net->port=n->port;
2579     net->timeout=game.timeout_outgame;
2580     net->securitylevel=LEVEL_NORMAL;
2581     net->status=STAT_NOTPLAYING;
2582     sprintf(net->host,"%s", s);
2583     if (strlen(s) == 0)
2584       { /* No resolved host... copy IP */
2585         sprintf(n1,"%lu", (unsigned long)(n->addr&0xff000000)/(unsigned long)0x1000000);
2586         sprintf(n2,"%lu", (unsigned long)(n->addr&0x00ff0000)/(unsigned long)0x10000);
2587         sprintf(n3,"%lu", (unsigned long)(n->addr&0x0000ff00)/(unsigned long)0x100);
2588         sprintf(n4,"%lu", (unsigned long)n->addr&0x000000ff);
2589         sprintf(net->host,"%s.%s.%s.%s",n1,n2,n3,n4);
2590       }
2591 
2592 
2593 
2594     if(net->sock <0)
2595       {
2596         lvprintf(4,"Failed TELNET incoming connection from %s", s);
2597         killsock(net->sock);
2598         free(net);
2599         return;
2600       }
2601 
2602     /* Is this person banned? */
2603     if (is_banned(net))
2604       {
2605         tprintf(net->sock,"noconnecting You are banned from server!\xff");
2606         killsock(net->sock);
2607         free(net);
2608         return;
2609       }
2610 
2611     if (ochan == NULL)
2612       { /* No channels found, so create a new one :P */
2613         if (numchannels() < game.maxchannels)
2614           {
2615             chan=chanlist;
2616             while ( (chan!=NULL) && (chan->next!=NULL) ) chan=chan->next;
2617 
2618 
2619             if (chan==NULL)
2620               {
2621                 chanlist = malloc(sizeof(struct channel_t));
2622                 chan=chanlist;
2623               }
2624             else
2625               {
2626                 chan->next = malloc(sizeof(struct channel_t));
2627                 chan=chan->next;
2628               }
2629 
2630             chan->next=NULL;
2631             chan->net=NULL;
2632 
2633 
2634 
2635             chan->maxplayers=DEFAULTMAXPLAYERS;
2636             chan->status=STATE_ONLINE;
2637             chan->description[0]=0;
2638             chan->priority=DEFAULTPRIORITY;
2639             chan->sd_mode=SD_NONE;
2640             chan->persistant=0;
2641 
2642             /* Copy default settings */
2643             chan->starting_level=game.starting_level;
2644             chan->lines_per_level=game.lines_per_level;
2645             chan->level_increase=game.level_increase;
2646             chan->lines_per_special=game.lines_per_special;
2647             chan->special_added=game.special_added;
2648             chan->special_capacity=game.special_capacity;
2649             chan->classic_rules=game.classic_rules;
2650             chan->average_levels=game.average_levels;
2651             chan->sd_timeout=game.sd_timeout;
2652             chan->sd_lines_per_add=game.sd_lines_per_add;
2653             chan->sd_secs_between_lines=game.sd_secs_between_lines;
2654             strcpy(chan->sd_message,game.sd_message);
2655             chan->block_leftl=game.block_leftl;
2656             chan->block_leftz=game.block_leftz;
2657             chan->block_square=game.block_square;
2658             chan->block_rightl=game.block_rightl;
2659             chan->block_rightz=game.block_rightz;
2660             chan->block_halfcross=game.block_halfcross;
2661             chan->block_line=game.block_line;
2662             chan->special_addline=game.special_addline;
2663             chan->special_clearline=game.special_clearline;
2664             chan->special_nukefield=game.special_nukefield;
2665             chan->special_randomclear=game.special_randomclear;
2666             chan->special_switchfield=game.special_switchfield;
2667             chan->special_clearspecial=game.special_clearspecial;
2668             chan->special_gravity=game.special_gravity;
2669             chan->special_quakefield=game.special_quakefield;
2670             chan->special_blockbomb=game.special_blockbomb;
2671             chan->stripcolour=game.stripcolour;
2672             chan->serverannounce=game.serverannounce;
2673             chan->pingintercept=game.pingintercept;
2674 
2675 
2676             k=0;l=1;
2677             while (l)
2678               {
2679                 k++;
2680                 ochan=chanlist;
2681                 if (k==1)
2682                   {
2683                     sprintf(strg,"%s", DEFAULTCHANNEL);
2684                     strncpy(chan->name,strg,CHANLEN-1); chan->name[CHANLEN-1]=0;
2685                   }
2686                 else
2687                   {
2688                     sprintf(strg,"%s%d", DEFAULTCHANNEL,k);
2689                     strncpy(chan->name,strg,CHANLEN-1); chan->name[CHANLEN-1]=0;
2690                   }
2691                 l=0;
2692                 while( (ochan != NULL) && (!l) )
2693                   {
2694                     if ( (!strcasecmp(chan->name,ochan->name)) && (chan!=ochan))
2695                       l=1;
2696                     else
2697                       ochan=ochan->next;
2698                   }
2699               }
2700 
2701           }
2702         else
2703           {
2704             lvprintf(4,"Server FULL - Denying\n");
2705             tprintf(net->sock,"noconnecting Server is Full!\xff");
2706             killsock(net->sock);
2707             free(net);
2708             return;
2709           }
2710       }
2711     else
2712       {
2713         chan=ochan; /* Found a channel */
2714       }
2715     net->channel = chan;
2716     addnet(chan,net);
2717 
2718     net->type=NET_TELNET_INIT;
2719     strcpy(net->nick,"???");
2720 
2721     /* Clear their Field */
2722     for(y=0;y<FIELD_MAXY;y++)
2723       for(x=0;x<FIELD_MAXX;x++)
2724         net->field[x][y]=0; /* Nothing */
2725 
2726     lvprintf(9,"Incoming Telnet connection: %s\n", net->host);
2727     /* Now we wait for the client init string */
2728   }
2729 
2730 
2731 
2732 /* Someone has just connected. So lets answer them */
net_query(struct net_t * n,char * buf)2733 void net_query(struct net_t *n, char *buf)
2734   {
2735   }
2736 
lostnet(struct net_t * n)2737 void lostnet(struct net_t *n)
2738   {
2739     int found,playing;
2740     char MSG[TEAMLEN+4];
2741     struct net_t *nsock;
2742 
2743     struct channel_t *chan,*ochan;
2744 
2745     /* Log the lost connection */
2746     if (n->type == NET_CONNECTED)
2747       {
2748 
2749         lvprintf(4,"#%s-%s Lost telnet connection from %s\n", n->channel->name, n->nick, n->host);
2750       }
2751     /* Inform all other active players this one has left iff this one was connected "properly"! */
2752     if ( n->type == NET_CONNECTED )
2753       {
2754         playing=0;
2755         found=0;/* Number of different teams/players playing */
2756         MSG[0]=0; /* Store playing team name here */
2757         nsock=n->channel->net;
2758         while (nsock!=NULL)
2759           {
2760             if ( (nsock!=n) && (nsock->type == NET_CONNECTED) )
2761               { /* Different player, connected, in same channel */
2762                 tprintf(nsock->sock,"playerleave %d\xff", n->gameslot);
2763 
2764                 if (strcasecmp(MSG,nsock->team))
2765                   {/* Different team, so add player */
2766                     found++;
2767                     if (nsock->status == STAT_PLAYING) playing++;
2768                     strcpy(MSG,nsock->team);
2769                   }
2770                 else if (MSG[0]==0)
2771                   {
2772                     found++;
2773                     if (nsock->status == STAT_PLAYING) playing++;
2774                   }
2775               }
2776             nsock=nsock->next;
2777           }
2778 
2779         /* If 1 or less players/teams now are playing, AND the player that quit WAS playing, STOPIT */
2780         if ( (playing <= 1) && (n->channel->status == STATE_INGAME) && (n->status == STAT_PLAYING) )
2781           {
2782             nsock=n->channel->net;
2783             while (nsock!=NULL)
2784               {
2785                 if ( (nsock!=n) && (nsock->type == NET_CONNECTED))
2786                   {
2787                     tprintf(nsock->sock,"endgame\xff");
2788                     nsock->status=STAT_NOTPLAYING;
2789                     nsock->timeout=game.timeout_outgame;
2790                   }
2791                 nsock=nsock->next;
2792               }
2793             n->channel->status = STATE_ONLINE;
2794           }
2795       }
2796 
2797     /* If we're the only numplayers players, then we delete the channel */
2798     if ( (numallplayers(n->channel)==1) && (!n->channel->persistant) )
2799       {
2800         chan=chanlist;
2801         ochan=NULL;
2802         while ( (chan != n->channel) && (chan != NULL) )
2803           {
2804             ochan=chan;
2805             chan=chan->next;
2806           }
2807         if (chan != NULL)
2808           {
2809             if (ochan != NULL)
2810               ochan->next=chan->next;
2811             else
2812               chanlist=chan->next;
2813             free(chan);
2814           }
2815       }
2816     else
2817       remnet(n->channel,n);
2818 
2819     free(n);
2820   }
2821 
net_eof(int z)2822 void net_eof(int z)
2823   {
2824     struct channel_t *chan;
2825     struct net_t *nsock;
2826 
2827     nsock=NULL;
2828     chan=chanlist;
2829     while ( (chan!=NULL) && (nsock==NULL))
2830       {
2831         nsock=chan->net;
2832         while ((nsock!=NULL) && (nsock->sock!=z))
2833           {
2834             nsock=nsock->next;
2835           }
2836         chan=chan->next;
2837       }
2838     if (nsock==NULL)
2839       {
2840         lvprintf(3,"Socket(%d): EOF on unknown socket\n",z);
2841         close(z); killsock(z);
2842         return;
2843       }
2844 
2845 
2846     killsock(z); lostnet(nsock);
2847   }
2848 
got_term(int z)2849 void got_term(int z)
2850   {
2851     struct net_t *nsock;
2852     struct channel_t *chan;
2853 
2854     lvprintf(1,"Got TERM Signal - Quitting\n");
2855     /* Kill all our socks */
2856     nsock=NULL;
2857     chan=chanlist;
2858     while (chan!=NULL)
2859       {
2860         nsock=chan->net;
2861         while (nsock!=NULL)
2862           {
2863             if (nsock->type != NET_FREE)
2864               {
2865                 killsock(nsock->sock);
2866                 lostnet(nsock);
2867               }
2868             nsock=nsock->next;
2869           }
2870         chan=chan->next;
2871       }
2872 
2873     /* Write winlist etc... */
2874     writewinlist();
2875 
2876     /* Remove PID */
2877     delpid();
2878 
2879     /* Done */
2880     exit(0);
2881   }
2882 
init_main(void)2883 void init_main(void)
2884   {
2885     struct sigaction sv;
2886 
2887     lvprintf(0,"\nTetriNET for Linux V%s.%s\n---------------------------------\n", TETVERSION, SERVERBUILD);
2888 
2889 
2890     gnet=NULL;
2891     chanlist=NULL;
2892 
2893     /* set up error traps: We DON'T want Broken pipes!!! In fact, what the hell ARE broken pipes anyway. */
2894     sv.sa_handler=SIG_IGN; sigaction(SIGPIPE,&sv,NULL);
2895 
2896     /* We want to shut down cleanly */
2897     sv.sa_handler=got_term; sigaction(SIGTERM,&sv,NULL);
2898 
2899 
2900 
2901   }
2902 
check_timeouts(void)2903 void check_timeouts(void)
2904   {
2905     struct net_t *n;
2906     struct channel_t *chan;
2907     int found,i;
2908 
2909 
2910     found=0;
2911     chan=chanlist;
2912     while ( (chan!=NULL) )
2913       {
2914         n=chan->net;
2915         while ( (n!=NULL) && !found)
2916           {
2917             if (n->timeout > 0) n->timeout--;
2918             if (!n->timeout)
2919               { /* Timeout has occurred */
2920 
2921                 switch (n->type)
2922                   {
2923                     case NET_TELNET_INIT:
2924                     case NET_WAITINGFORTEAM:
2925                     case NET_CONNECTED:
2926                     case NET_QUERY_INIT:
2927                       {
2928                         lvprintf(4,"#%s-%s: Timed out!\n", n->channel->name,n->nick);
2929                         tprintf(n->sock,"pline 0 %cYou have timed out! Disconnecting!\xff",RED);
2930                         killsock(n->sock);
2931                         lostnet(n);
2932                         found=1;
2933                         break;
2934                       }
2935                   }
2936               }
2937             if (!found) n=n->next;
2938           }
2939         if (!found)
2940           chan=chan->next;
2941         else
2942           {
2943             chan=chanlist;
2944             found=0;
2945           }
2946       }
2947 
2948     /* Sudden Death Timeouts */
2949     chan=chanlist;
2950     while (chan!=NULL)
2951       {
2952         if ( (chan->status==STATE_INGAME) && (chan->sd_mode!=SD_NONE) )
2953           {
2954             chan->sd_timeleft--;
2955             if(chan->sd_timeleft <=0)
2956               {/* Timeout */
2957                 n=chan->net;
2958                 while(n!=NULL)
2959                   {
2960                     if ((n->type==NET_CONNECTED) )
2961                       {
2962                         if (chan->sd_mode==SD_INIT)
2963                           {
2964                             tprintf(n->sock,"gmsg %s\xff",n->channel->sd_message);
2965                           }
2966                         else
2967                           {
2968                             for(i=0;i<n->channel->sd_lines_per_add;i++)
2969                               tprintf(n->sock,"sb 0 a 0\xff");
2970                           }
2971                       }
2972                     n=n->next;
2973                   }
2974                 chan->sd_timeleft=chan->sd_secs_between_lines;
2975                 chan->sd_mode=SD_WAIT;
2976               }
2977           }
2978         chan=chan->next;
2979       }
2980   }
2981 
2982 
2983 
main(int argc,char * argv[])2984 int main(int argc, char *argv[])
2985   {
2986     int xx;
2987     char buf[1050];
2988     int buf_len;
2989     int forknum;
2990     long int timeticks, otimeticks;
2991 
2992 
2993     /* Initialise */
2994     init_main();
2995     init_game();
2996     init_net();
2997     init_telnet_port();
2998     /*init_query_port();*/
2999     init_winlist();
3000     init_security();
3001     readwinlist();
3002 
3003     if (securityread() < 0)
3004       securitywrite();
3005 
3006     /* Now fork out, and start a new process group */
3007     /* Fork. If we are the parent, quit, if child, continue */
3008     if ((forknum=fork()) == -1)
3009       {
3010         printf("Error: Unable to fork new process\n");
3011         exit(5);
3012       }
3013     if (forknum > 0)
3014       {
3015         exit(0);
3016       }
3017     setsid();
3018 
3019     /* Close all stdio */
3020     close(0);
3021     close(1);
3022     close(2);
3023 
3024     /* Write out PID */
3025     writepid();
3026 
3027     /* Reset time */
3028     timeticks = time(NULL);
3029     otimeticks = timeticks;
3030 
3031     while (1)
3032       {
3033 
3034         timeticks=time(NULL);
3035         if ((timeticks-otimeticks) > CYCLE)
3036           { /* Check timeouts */
3037             check_timeouts();
3038           }
3039 
3040         /* flush sockets */
3041         dequeue_sockets();
3042 
3043         /* Read data from a currently waiting socket */
3044         xx=sockgets(buf, &buf_len);
3045         if (xx>=0)  /* Non-error */
3046           {
3047             net_activity(xx, buf, buf_len);
3048           }
3049         else if (xx==-1)        /* EOF from someone */
3050           {
3051             lvprintf(9,"Close Socket\n");
3052             net_eof(buf_len);	/* Close this socket */
3053           }
3054         else if (xx==-2)	/* Select() error */
3055           {
3056             lvprintf(4,"Select error - Whatever the hell that is supposed to be..\n");
3057           }
3058 
3059 
3060       }
3061   }
3062