Add 2-sec delay before issuing rmatch
[capablanca.git] / lasker-2.2.3 / bots / mamer / Mamer.cc
1 //--------------------------------------------------------------------------
2 // Mamer.cc - Source file for the Mamer class
3 //
4 // Matthew E. Moses & Michael A. Long
5 //
6 // $Revision: 1.17 $
7 // $Date: 1998/09/10 19:57:17 $
8 //
9 // $Author: mlong $
10 // $Locker:  $
11 //
12 //--------------------------------------------------------------------------
13
14 // static char RCSid[] = "$Id: Mamer.cc,v 1.17 1998/09/10 19:57:17 mlong Exp $";
15
16 #include "Mamer.hh"
17
18 extern void HandleSignals(int);
19
20 //- Constructor ------------------------------------------------------------
21 Mamer::Mamer() {
22     time_t theTime;
23     struct tm *timeStruct;
24
25     theTime = time((time_t *)NULL);
26     timeStruct = localtime(&theTime);
27
28     loggedInFlag = FALSE;
29
30     memset(configFilename, '\0', MAXPATHLEN);
31     strncpy(configFilename, CONFIG_FILENAME, MIN(strlen(CONFIG_FILENAME), MAXPATHLEN));
32
33     channelNumber = DEFAULT_CHANNEL;
34     memset(hostname, '\0', 256);
35     strncpy(hostname, DEFAULT_HOSTNAME, MIN(strlen(DEFAULT_HOSTNAME), 256));
36     portNumber = DEFAULT_PORT;
37     
38     debugLevel = 0;
39
40     memset(username, '\0', 80);
41     memset(password, '\0', 80);
42     strncpy(username, DEFAULT_USERNAME, MIN(strlen(DEFAULT_USERNAME), 80));
43     strncpy(password, DEFAULT_PASSWORD, MIN(strlen(DEFAULT_PASSWORD), 80));
44
45     sprintf(logFilename, "%s/%s.%04d%02d%02d", 
46             DEFAULT_PATH, DEFAULT_LOG_FILE,
47             1900 + timeStruct->tm_year, timeStruct->tm_mon + 1, 
48             timeStruct->tm_mday);
49
50     sprintf(userFilePath, "%s/%s", DEFAULT_PATH, DEFAULT_USER_PATH);
51     sprintf(dataFilePath, "%s/%s", DEFAULT_PATH, DEFAULT_DATA_PATH);
52     sprintf(homeFilePath, "%s", DEFAULT_PATH);
53
54     tourneyParams.time = DEFAULT_TIME;
55     tourneyParams.inc = DEFAULT_INCREMENT;
56     tourneyParams.mode = 'r';
57     tourneyParams.style = 's';
58     tourneyParams.variant = 'r';
59     tourneyParams.rounds = DEFAULT_ROUNDS;
60     tourneyParams.ratingHigh = 9999;
61     tourneyParams.ratingLow = 0;
62     tourneyParams.maxPlayers = DEFAULT_MAX_PLAYERS;
63
64 } //- End of Mamer
65
66 //- Deconstructor ----------------------------------------------------------
67 Mamer::~Mamer() {
68     User *u = NULL;
69     Tourney *t = NULL;
70     Command *c = NULL;
71
72     while(0 != (u = userList.Head()))
73         userList.Delete();
74
75     while(0 != (t = tourneyList.Head()))
76         tourneyList.Delete();
77
78     while(0 != (c = commandList.Head()))
79         commandList.Delete();
80
81 } //- End of ~Mamer
82
83 //- Initialize -------------------------------------------------------------
84 int Mamer::Initialize(int argc, char **argv) {
85     struct stat statBuffer;
86     char c;
87
88     LoadConfigurationFile();
89
90     while(EOF != (c = getopt(argc, argv, 
91                              "d:D:c:C:s:S:p:P:u:U:l:L:hHa:A:n:N:"))) {
92         switch(c) {
93          case 'd':
94          case 'D':
95             debugLevel = atoi(optarg);
96             break;
97          case 'c':
98          case 'C':
99             channelNumber = atoi(optarg);
100             break;
101          case 's':
102          case 'S':
103            memset(hostname, '\0', 256);
104            strncpy(hostname, optarg, MIN(strlen(optarg), 256));
105            break;
106          case 'n':
107          case 'N':
108             portNumber = atoi(optarg);
109             break;
110          case 'u':
111          case 'U':
112            memset(userFilePath, '\0', MAXPATHLEN);
113             strncpy(userFilePath, optarg, MIN(strlen(optarg), MAXPATHLEN));
114             break;
115          case 'l':
116          case 'L':
117            memset(userFilePath, '\0', MAXPATHLEN);
118             strncpy(logFilename, optarg, MIN(strlen(optarg), MAXPATHLEN));
119             break;
120          case 'a':
121          case 'A':
122            memset(username, '\0', 80);
123             strncpy(username, optarg, MIN(strlen(optarg), 80));
124             break;
125          case 'p':
126          case 'P':
127            memset(password, '\0', 80);
128             strncpy(password, optarg, MIN(strlen(optarg), 80));
129             break;
130          case 'h':
131          case 'H':
132          default:
133             Usage();
134             exit(0);
135         }
136     }
137
138     if(-1 == stat(userFilePath, &statBuffer)) {
139         switch(errno) {
140          case ENOENT:
141             if(-1 == mkdir(userFilePath, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
142                 printf("name = '%s'\n", userFilePath);
143                 perror("create user file path");
144                 return(0);
145             }
146         }
147     }
148
149     if(10 <= debugLevel)
150         DumpConfiguration();
151
152     signal(SIGPIPE, SIG_IGN);
153     signal(SIGTERM, HandleSignals);
154     signal(SIGKILL, HandleSignals);
155     signal(SIGUSR1, HandleSignals);
156     signal(SIGUSR2, HandleSignals);
157
158     BuildCommandList();
159
160     return(1);
161 } //- End of Initialize
162
163 //- s_and_r - Search and Replace a string within a string ------------
164 char *Mamer::s_and_r(char *s, char *tofind, char *toreplace) {
165   char    *toReturn = NULL;
166   int     currSize = 0;
167   char    *return_offset;
168   char    *replace_offset;
169   int     find_len;
170   int     toreplace_len;
171   register int    x;
172   
173   /* if nothing to look at, and nothing to replace.... return nothing */
174   if ( s == NULL || tofind == NULL)
175     return NULL;
176   
177   find_len = strlen(tofind);
178   if ( toreplace != NULL )
179     toreplace_len = strlen(toreplace);
180   else
181     toreplace_len = 0;      /* allow us to have nothing to replace... acts the same a delstring */
182   
183   currSize = (strlen(s) * 2) + 100;       /* add the 100 in case s is small */
184   toReturn = (char*)malloc(currSize);
185   return_offset = toReturn;
186   while ( *s != '\0' ) {
187     if ( *s == *tofind && strncmp(s, tofind, MIN(find_len, (int)strlen(s))) == 0 ) {
188       /* if the first letter matches, and so does the rest.. */
189       /* copy in the replace string */
190       replace_offset = toreplace;
191       for ( x = 0; x < toreplace_len; x++ ) {
192         *return_offset = *replace_offset;
193         return_offset++;
194         replace_offset++;
195       }
196       /* and move up the current position in s to just past the find string */
197       s += find_len;
198     } else { /* it doesn't match.... just copy to the return and continue */
199       *return_offset = *s;
200       return_offset++;
201       s++;
202     }
203   }
204   *return_offset = '\0';
205
206   return toReturn;
207 }
208
209 //- OpenServerConnection ---------------------------------------------------
210 int Mamer::OpenServerConnection(void) {
211     struct sockaddr_in socketAddr;
212     struct hostent     *hostEntry = NULL;
213 //    char               mesg[MAXPATHLEN] = {'\0'};
214     unsigned long      inAddr;
215
216     //- Check is we have a decimal notation host address
217     socketAddr.sin_family = AF_INET;
218     if((unsigned long)INADDR_NONE != (inAddr = inet_addr(hostname)))
219         socketAddr.sin_addr.s_addr = inAddr;
220     else { //- Try to query a namserver to get an address
221         if(NULL == (hostEntry = gethostbyname(hostname))) {
222             cerr << "ERROR: can't resolve hostname '" << hostname
223                 << "'." << endl;
224             cerr << endl;
225             return(0);
226         }
227
228         bcopy(hostEntry->h_addr, (char *)&socketAddr.sin_addr, 
229               hostEntry->h_length);
230     }
231
232     serverSocket = socket(AF_INET, SOCK_STREAM, 0);
233     if(0 > serverSocket) {
234         cerr << "ERROR: can't create TCP socket." << endl;
235         cerr << endl;
236         return(0);
237     }
238
239     socketAddr.sin_port = htons(portNumber);
240     if(0 > connect(serverSocket, (struct sockaddr *)&socketAddr, 
241                    sizeof(struct sockaddr_in))) {
242         cerr << "ERROR: can't create connection to server '"
243              << hostname << "' on port " << portNumber << "." << endl;
244         cerr << "     " << strerror(errno) << endl;
245         cerr << endl;
246         return(0);
247     }
248
249     return(1);
250 } //- End of OpenServerConnection
251
252 //- ListenLoop -------------------------------------------------------------
253 void Mamer::ListenLoop(void) {
254     struct timeval timeout;
255     char           readBuffer[4096], writeBuffer[4096], commandBuffer[4096], channelCmpStr[16];
256     char           *p = NULL, *buffer = NULL, *tmpBuffer = NULL;
257     fd_set         fdMask;
258     long           size = 0;
259     int            i = 0, j = 0;
260
261     sprintf(channelCmpStr, "(%d): ", channelNumber);
262     buffer = new char[4096];
263     if(NULL == buffer) {
264         cerr << "ERROR: problems allocating memory" << endl;
265         cerr << endl;
266         return;
267     }
268
269     tmpBuffer = new char[4096];
270     if(NULL == tmpBuffer) {
271         cerr << "ERROR: problems allocating memory" << endl;
272         cerr << endl;
273         return;
274     }
275
276     timeout.tv_sec = timeout.tv_usec = 0;
277
278     while(1) {
279         FD_ZERO(&fdMask);
280         FD_SET(serverSocket, &fdMask);
281
282 #ifdef HPUX
283         select(serverSocket + 3, (int *)&fdMask, (int *)0, (int *)0, &timeout);
284 #else
285         select(serverSocket + 3, &fdMask, (fd_set *)0, (fd_set *)0, &timeout);
286 #endif
287
288         if(FD_ISSET(serverSocket, &fdMask)) {
289             size = 0;
290             memset(readBuffer, '\0', 4096);
291             memset(writeBuffer, '\0', 4096);
292             size = read(serverSocket, readBuffer, (sizeof(readBuffer) - 1));
293
294             if(size > 0) {
295                 //- fix newlines/linefeeds
296                 memset(buffer, '\0', 4096);
297                 strncpy(buffer, readBuffer, size);
298                 buffer[size] = '\0';
299
300                 if(NULL != (strstr(buffer, "\n\r\\   "))) {
301                   strcpy(tmpBuffer, s_and_r(buffer, "\n\r\\   ", ""));
302                   memset(buffer, '\0', 4096);
303                   strcpy(buffer, tmpBuffer);
304                   size = strlen(buffer);
305                 }
306                 
307                 if(NULL != (strstr(buffer, "\r\n\\   "))) {
308                   strcpy(tmpBuffer, s_and_r(buffer, "\r\n\\   ", ""));
309                   memset(buffer, '\0', 4096);
310                   strcpy(buffer, tmpBuffer);
311                   size = strlen(buffer);
312                 }
313                 
314                 if(NULL != (strstr(buffer, "\n\r "))) {
315                   strcpy(tmpBuffer, s_and_r(buffer, "\n\r   ", ""));
316                   memset(buffer, '\0', 4096);
317                   strcpy(buffer, tmpBuffer);
318                   size = strlen(buffer);
319                 }
320                     
321                 if((FALSE == loggedInFlag) && 
322                    (NULL != strstr(buffer, "login:"))) {
323                     sprintf(writeBuffer, "%s\n", username);
324                     write(serverSocket, writeBuffer, strlen(writeBuffer));
325                 } else if((FALSE == loggedInFlag) &&
326                           (NULL != strstr(buffer, "password:"))) {
327                   sprintf(writeBuffer,
328                           "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s %d\n",
329                           password, 
330                           "set prompt %",
331                           "set pinform 1",
332                           "set ginform 1",
333                           "set mamer 1",
334                           "set shout 0",
335                           "set cshout 0",
336                           "set seek 0",
337                           "set open 0",
338                           "admin",
339                           "set tell 0",
340                           "+ channel ",
341                           channelNumber
342                           );
343                   write(serverSocket, writeBuffer, strlen(writeBuffer));
344                   FILE *theFile;
345                   char manager[NAMELEN], filename[128];
346                   sprintf(filename, "%s/managers", dataFilePath);
347                   if((theFile = fopen(filename, "r"))) {
348                     while(fscanf(theFile, "%s", manager) > 0) {
349                       XServerCom("qtell %s %s %s %s", 
350                                  manager, "Howdy, ", username, " is here!\n");
351                     }
352                   }
353                   fclose(theFile);
354                   
355                   loggedInFlag = TRUE;
356                 }
357                 else if(TRUE == loggedInFlag) {
358                   i = 0;
359                   while(i < size) {
360                     while(('\r' == buffer[i]) ||
361                           ('\n' == buffer[i]) ||
362                           ('%' == buffer[i]) ||
363                           (' ' == buffer[i]))
364                       i++;                  
365                     j = 0;
366                     while(('\r' != buffer[i]) &&
367                           ('\n' != buffer[i]) &&
368                           (i < size))
369                       commandBuffer[j++] = buffer[i++];
370                     commandBuffer[j] = '\0';
371                     
372                     if(NULL != (p = strstr(commandBuffer, channelCmpStr)))
373                       HandleChannel(commandBuffer);
374                     else if(NULL != (p = strstr(commandBuffer, "tells you:")))
375                       HandleTell(commandBuffer);
376                     else if(NULL != (p = strstr(commandBuffer, "has connected")))
377                       HandleConnect(commandBuffer);
378                     else if(NULL != (p = strstr(commandBuffer, "has disconnected")))
379                       HandleDisconnect(commandBuffer);
380                     else if(0 == strncmp(commandBuffer, "{Game ", 6))
381                       HandleGame(commandBuffer);
382                     else if(0 == strncmp(commandBuffer, "*qtell ", 7))
383                       HandleQtell(commandBuffer);
384                     else if(0 == strncmp(commandBuffer, "*getgi ", 7))
385                       HandleGameInfo(commandBuffer);
386                     else if(0 == strncmp(commandBuffer, "*getpi ", 7))
387                       HandlePlayerInfo(commandBuffer);
388                     else {
389                       /*
390                       cout << "Unsupported: " << commandBuffer << endl;
391                       cout << endl;
392                       */
393                     }
394                     
395                     while(('\r' == buffer[i]) ||
396                           ('\n' == buffer[i]) ||
397                           ('%' == buffer[i]) ||
398                           (' ' == buffer[i]))
399                       i++;
400                   }
401                 }
402             } else {
403               if((errno == EINTR) || (errno == EAGAIN) || (errno == EIO) ||
404                  (errno == EBADF) || (errno == EINVAL) || (errno == EFAULT)) {
405                 switch (errno) {
406                 case EINTR:
407                   printf("Error = %s\n", "EINTR");
408                   break;
409                 case EAGAIN:
410                   printf("Error = %s\n", "EAGAIN");
411                   break;
412                 case EIO:
413                   printf("Error = %s\n", "EIO");
414                   break;
415                 case EBADF:
416                   printf("Error = %s\n", "EBADF");
417                   break;
418                 case EINVAL:
419                   printf("Error = %s\n", "EINVAL");
420                   break;
421                 case EFAULT:
422                   printf("Error = %s\n", "EFAULT");
423                   break;
424                 default:
425                   break;
426                 }
427               }
428               break;
429             }
430         }
431         sleep(1);
432     } //- end while(1)
433     
434     if(NULL != buffer)
435       delete [] buffer;
436     
437     if(NULL != tmpBuffer)
438       delete [] tmpBuffer;
439     
440 } //- End of ListenLoop
441
442 //- Start of GivePlace ----------------------------
443 int Mamer::GivePlace(int i, Tourney *t) {
444   TourneyPlayers *tp = NULL, *place = NULL;
445   User *u = NULL;
446   Player *opp = NULL;
447   LinkListIter<TourneyPlayers> playerIter(t->playerList);
448   float score=0.0;
449   int counter=0;
450   char placeName[7];
451
452   memset(placeName, '\0', 7);
453   switch(i) {
454   case 1:
455     strcpy(placeName, "First");
456     break;
457   case 2:
458     strcpy(placeName, "Second");
459     break;
460   case 3:
461     strcpy(placeName, "Third");
462     break;
463   default:
464     break;
465   }
466
467   XServerCom("%s %i %s %s %s%i %s ", "tell", channelNumber, "Tourney Results:", placeName, 
468              "place in tourney #", t->number, "goes to: ");
469
470   opp = t->GetSortPlayer(i);
471   place = t->GetPlayer(opp->name);
472   score = place->score;
473
474   while((tp = playerIter.Next())) {
475     if(tp->score == score) {
476       XServerCom("%s ", tp->name);
477       counter++;
478       u = FindUser(tp->name);
479       if(u == NULL) {
480         CheckUser(tp->name);
481         u = FindUser(tp->name);
482       }
483       //      if(NULL != u) 
484       u->AddStat(i);  // Adds a first/second/third place finish to everyone with the same score as the 1st
485     }
486   }
487   XServerCom("\n");
488
489   return counter;
490 }
491
492 //- Start of AnnounceTourneyEnd
493 void Mamer::AnnounceTourneyEnd(Tourney *t) {
494   TourneyPlayers *tp = NULL;
495   int first=0, second=0, third=0;
496   int numberOfPlayers = 0;
497
498   t->EndTourney();
499   t->SortPlayers();
500   t->SetEndDate();
501   
502   LinkListIter<TourneyPlayers> playerIter(t->playerList);
503
504   while((tp = playerIter.Next())) { 
505     if((tp->activeFlag) && (strcasecmp(tp->name, "_BYE_") != 0))
506       numberOfPlayers++;
507   }
508
509   first = GivePlace(1, t);  //first = number of people tied for first
510
511   if(numberOfPlayers >= 5) {
512     if(first == 1)  { second = GivePlace(2, t); }
513     if(first == 2)  { third = GivePlace(3, t);  }
514     if(numberOfPlayers >= 7) {
515       if(second == 1) { third = GivePlace(3, t);  }
516     }
517   }
518 }
519
520 //- savePlayerData --------------------------------------------------------------
521 void Mamer::savePlayerData(Tourney *t) {
522   LinkListIter<TourneyPlayers> playerIter(t->playerList);
523   TourneyPlayers *tp = NULL, *tmpOpp = NULL;
524   User *u = NULL, *manager=NULL;
525   Player *opp;
526   int w, d, l;
527   float r, tourn_expect=0.0, pre_expect=0.0, delta = 0.0;
528
529   manager = FindUser(t->manager);  // save the manager info
530   if(manager == NULL) {
531     manager = new User(userFilePath, t->manager);  // manager isn't online
532     manager->SetLast(time(0));               // so we have to load him/her
533     manager->AddManagedTourney();
534     manager->SavePlayer(userFilePath);
535     delete(manager);
536   } else {  // manager is online
537     manager->SetLast(time(0));
538     manager->AddManagedTourney();
539     manager->SavePlayer(userFilePath);
540   }
541
542   while((tp = playerIter.Next())) {
543     tourn_expect = 0.0;
544     u = FindUser(tp->name);
545     if(u == NULL) {
546       User *newUser = NULL;
547       newUser = new User(userFilePath, tp->name);
548       u = newUser;
549     }
550     if(debugLevel >= 5)
551       cout << "savePlayerData::" << tp->name << " " << u->name << endl;
552     r = u->GetRating();
553     w = u->GetWins();
554     l = u->GetLosses();
555     d = u->GetDraws();
556     pre_expect = ((float)w + (0.5 * (float)d)) / r;
557     
558     LinkListIter<Player> opponentIter(tp->opponentList);  // List of opponents this player has had
559     while((opp = opponentIter.Next())) { 
560       tmpOpp = t->GetPlayer(opp->name);   // need the player's information to do tourn_expect
561       delta = (float)(((tp->rating != 0) ? tp->rating : 1600) - 
562                       ((tmpOpp->rating != 0) ? tmpOpp->rating : 1600));  // difference in rating
563       tourn_expect = tourn_expect + (1 / (1+pow(10,(delta/400.0))));
564       u->AddStat(opp->floatValue); 
565     }
566     u->AddPlayedTourney();
567     if(tp->activeFlag) {   // If I didn't withdraw or get forfeited reduce my abuse points
568       u->AddAbuse(-1 * t->GetRound());  // This will be the # of rounds played because the tourney is DONE
569       XServerCom("%s %s %d%s", "tournset", tp->name, 0, "\n");
570     }
571     u->CalculateRating(tourn_expect, pre_expect);
572     u->SavePlayer(userFilePath);    
573   }
574 } //- End of savePlayerData ------------------------------------------
575
576 //- Shutdown --------------------------------------------------------------
577 void Mamer::Shutdown(void) {
578   LinkListIter<User> userIter(userList);
579   User *u = NULL;
580   
581   while((u = userIter.Next())) {
582     //    u->SavePlayer(userFilePath);
583     userList.Delete(u); 
584   }
585   
586   write(serverSocket, "exit\n", 5);
587   close(serverSocket);
588   exit(0);
589 } //- End of Shutdown
590
591 //- Usage -----------------------------------------------------------------
592 void Mamer::Usage(void) {
593     cerr << "Usage: mamer [-c channel] [-s server] [-n port number] " << endl;
594     cerr << "             [-d debug level] [-u users database filename] " 
595          << endl;
596     cerr << "             [-l log filename] [-a mamer account name] " << endl;
597     cerr << "             [-p mamer password] [-h help] " << endl;
598     cerr << endl;
599     cerr << "\t-h show usage information." << endl;
600     cerr << "\t-c sets which channel mamer should work on.\n\t   (default = "
601          << channelNumber << ")" << endl;
602     cerr << "\t-s sets the server hostname that mamer connects to.\n\t"
603          << "   (default = " << hostname << ")" << endl;
604     cerr << "\t-n sets the port number on the server to connect to.\n\t"
605          << "   (default = " << portNumber << ")" << endl;
606     cerr << "\t-a sets the username for the account to mamer logs in as.\n\t"
607          << "   (default = " << username << ")" << endl;
608     cerr << "\t-p sets the password for the mamer account.\n\t"
609          << "   (default = " << password << ")" << endl;
610     cerr << "\t-d sets the debugging level.  This determines how much of "
611          << "the\n\t   activity of mamer is written to the logs." << endl;
612     cerr << "\t-u set the location of the users database file.\n\t"
613          << "   (default = " << userFilePath << ")" << endl;
614     cerr << "\t-l sets the location of the log file.\n\t   (default = "
615          << logFilename << ")" << endl;
616     cerr << endl;
617 } //- End of Usage
618
619 //- LoadConfigurationFile -------------------------------------------------
620 void Mamer::LoadConfigurationFile(void) {
621     struct stat statBuffer;
622     int length=0;
623
624     if(-1 != stat(configFilename, &statBuffer)) {
625         char    *buffer = NULL;
626         fstream theFile(configFilename, ios::in);
627         
628         buffer = new char[MAXPATHLEN + 80];
629         if(NULL == buffer)
630             return;
631
632         memset(buffer, '\0', MAXPATHLEN + 80);
633         
634         while(theFile.good()) {
635           theFile.getline(buffer, MAXPATHLEN + 80 - 1, '\n');
636           
637           if(buffer[0] == '#') continue;
638           length = strlen(buffer);
639           
640           if(length >= 4) {
641             if(0 == strncasecmp(buffer, "HOST", 4)) {
642               buffer += 4;
643               while(isspace(buffer[0])) buffer++;
644               
645               memset(hostname, '\0', MAXPATHLEN);
646               strncpy(hostname, buffer, MIN(length, MAXPATHLEN));
647             } else if(0 == strncasecmp(buffer, "DATA", 4)) {
648               buffer += 4;
649               while(isspace(buffer[0])) buffer++;
650               
651               memset(dataFilePath, '\0', MAXPATHLEN);
652               strncpy(dataFilePath, buffer, MIN(length, MAXPATHLEN));
653             } else if(0 == strncasecmp(buffer, "HOME", 4)) {
654               buffer += 4;
655               while(isspace(buffer[0])) buffer++;
656               
657               memset(homeFilePath, '\0', MAXPATHLEN);
658               strncpy(homeFilePath, buffer, MIN(length, MAXPATHLEN));
659             } else if(0 == strncasecmp(buffer, "HELP", 4)) {
660               buffer += 4;
661               while(isspace(buffer[0])) buffer++;
662               
663               memset(helpFilePath, '\0', MAXPATHLEN);
664               strncpy(helpFilePath, buffer, MIN(length, MAXPATHLEN));
665             } else if(0 == strncasecmp(buffer, "USER", 4)) {
666               buffer += 4;
667               while(isspace(buffer[0])) buffer++;
668               
669               memset(username, '\0', 80);
670               strncpy(username, buffer, MIN(length, 80));
671             } else if(0 == strncasecmp(buffer, "PASS", 4)) {
672               buffer += 4;
673               while(isspace(buffer[0])) buffer++;
674               
675               memset(password, '\0', 80);
676               strncpy(password, buffer, MIN(length, 80));
677             } else if(0 == strncasecmp(buffer, "PORT", 4)) {
678               buffer += 4;
679               while(isspace(buffer[0])) buffer++;
680               
681               portNumber = atoi(buffer);
682             } else if(0 == strncasecmp(buffer, "CHAN", 4)) {
683               buffer += 4;
684               while(isspace(buffer[0])) buffer++;
685               
686               channelNumber = atoi(buffer);
687             } else if(0 == strncasecmp(buffer, "DBUG", 4)) {
688               buffer += 4;
689               while(isspace(buffer[0])) buffer++;
690               
691               debugLevel = atoi(buffer);
692             }
693           }
694           if(length >= 3) {
695             if(0 == strncasecmp(buffer, "LOG", 3)) {
696               buffer += 3;
697               while(isspace(buffer[0])) buffer++;
698               
699               memset(logFilename, '\0', MAXPATHLEN);
700               strncpy(logFilename, buffer, MIN(length, MAXPATHLEN));
701             } else if((strlen(buffer) > 3) && (0 == strncasecmp(buffer, "UDB", 3))) {
702               buffer += 3;
703               while(isspace(buffer[0])) buffer++;
704               
705               memset(userFilePath, '\0', MAXPATHLEN);
706               strncpy(userFilePath, buffer, MIN(length, MAXPATHLEN));
707             }
708           }
709         } //- theFile.good()
710     }
711     else {
712         switch(errno) {
713          case EACCES:
714             cerr << "ERROR: permission denied for configuration file '" 
715                  << configFilename << "' using compiled defaults." << endl;
716             cerr << endl;
717             break;
718          case ENOENT:
719             cerr << "WARNING: configuration file '" << configFilename
720                  << "' doesn't exist, using " << endl;
721             cerr << "         compiled defaults." << endl;
722             cerr << endl;
723             break;
724         }
725     }
726
727 } //- End of LoadConfigurationFile
728
729 //- DumpConfiguration -----------------------------------------------------
730 void Mamer::DumpConfiguration(void) {
731     cout << "Mamer Configuration" << endl;
732     cout << "-------------------" << endl;
733     cout << "Hostname : " << hostname << endl;
734     cout << "Port     : " << portNumber << endl;
735     cout << "Channel  : " << channelNumber << endl;
736     cout << endl;
737     cout << "Username : " << username << endl;
738     cout << "Password : " << password << endl;
739     cout << endl;
740     cout << "Home Path: " << homeFilePath << endl;
741     cout << "Data Path: " << dataFilePath << endl;
742     cout << "Help Path: " << helpFilePath << endl;
743     cout << "User File: " << userFilePath << endl;
744     cout << "Log File : " << logFilename << endl;
745     cout << endl;
746     cout << "Debug Lvl: " << debugLevel << endl;
747     cout << endl;
748
749 } //- End of DumpConfiguration
750
751 //- HandleQtell ------------------------------------------------------------
752 int Mamer::HandleQtell(char *message) {
753   char name[NAMELEN];
754   int isOnline;  // Opposite of what is returned in qtell report
755   
756   sscanf(message, "*qtell %s %d*", name, &isOnline); 
757   isOnline = !isOnline;
758
759   User *u = NULL;
760   u = FindUser(name);
761
762   if(isOnline) {
763     if(NULL == u) {
764       CheckUser(name);
765     }
766   }
767     
768   return 1;
769 }
770
771 //- HandleTell ------------------------------------------------------------
772 int Mamer::HandleTell(char *message) {
773     char *p = NULL, *q = NULL, *command = NULL, *tmpCom=NULL;
774     char user[32] = {'\0'};
775     int  i=0, pos = 0, tmp=0, len = 0, ret = 0, tellSize=12;  /* size of " tells you:" */
776
777     //- Parse apart tell message
778     //- <user> tells you: <mesg>
779     //- <user>(*) tells you: <mesg>
780     //- <user>(TM)(GM)(*)..... tells you: <mesg>
781     if((p = strstr(message, "(")) && (q = strstr(message, " tells you:")) && (strlen(p) > strlen(q))) {      
782       tmp = strlen(p) - strlen(q);       /* get the diff to add back in later */
783       pos = strlen(message) - strlen(p);
784       memset(user, '\0', 32);
785       strncpy(user, message, MIN(pos, 31));
786       pos += (tellSize + tmp);
787     } else {
788       p = strstr(message, " tells you:");
789       pos = strlen(message) - strlen(p);
790       memset(user, '\0', 32);
791       strncpy(user, message, MIN(pos, 31));
792       pos += tellSize;
793     }
794
795     CheckUser(user);
796
797     len = strlen(&(message[pos]));
798     command = new char[len + 1]; memset(command, '\0', (len + 1));
799     tmpCom = new char[len + 1];  memset(tmpCom, '\0', (len + 1));
800     if(NULL == command) {
801         cerr << "ERROR: problems allocating memory" << endl;
802         cerr << endl;
803         return(ret);
804     }
805     strncpy(command, &(message[pos]), len);
806     command[len] = '\0';
807     while((command[i] != '\0') && (command[i] != ' ')) tmpCom[i] = command[i++];
808     tmpCom[i] = '\0';
809
810     Command *comm = NULL;
811     comm = FindCommand(tmpCom, user);
812     if(comm == NULL) {
813       if(NULL != command)
814         delete [] command;
815       if(NULL != tmpCom)
816         delete [] tmpCom;
817       return 0;
818     }
819
820     if(10 <= debugLevel) {
821       cout << "Tell Msg: " << message << endl;
822       cout << "User is: " << user << " Command is: " << command<< "\n" << endl;
823     }
824     
825     if(ParseParams(comm, command) == COM_BADPARAMETERS) {
826       TellUser(comm, user);
827       if(NULL != command)
828         delete [] command;
829       if(NULL != tmpCom)
830         delete [] tmpCom;
831       return 0;
832     }
833
834     if(NULL != comm) {
835         User *u = NULL;
836         u = FindUser(user);
837         if(NULL == u) {
838           CheckUser(user);  // This should never happen because we did it above.
839           u = FindUser(user);
840           if(NULL == u)
841             abort();
842         }
843         if((u->GetManagerLevel()) >= (comm->GetManagerLevel())) {
844           ret = (this->*(comm->userFunction))(u, comm->params);
845           if(debugLevel >= 5)
846             cout << comm->GetCommandName() << " return value " << ret << endl;
847           if(((ret == 2) && (!(strcasecmp(comm->GetCommandName(), "setres")))) ||
848              ((ret == 1) && (!(strcasecmp(comm->GetCommandName(), "withdraw")))) ||
849              ((ret == 1) && (!(strcasecmp(comm->GetCommandName(), "forfeit"))))) {
850             NextRound();
851           } else if ((ret != 0) && (!(strcasecmp(comm->GetCommandName(), "setmanagerlevel")))) {
852             AdjustManagerList(ret, comm->params[0].val.word);
853           }
854         } else {
855           TellUser(NoPermissions, user);
856         }
857     }
858
859     if(NULL != command)
860         delete [] command;
861     if(NULL != tmpCom)
862         delete [] tmpCom;
863
864     return(ret);
865 } //- End of HandleTell
866
867 //- HandleChannel ------------------------------------------------------------
868 int Mamer::HandleChannel(char *message) {
869     char *q, *p = NULL, channel[8], mess[1024];
870     char user[NAMELEN] = {'\0'};
871     int  pos = 0, index=0;
872     char *hilist[] = {"hi ", "hello ", "howdy ", "aloha ", "hola ", "bonjour ", "tag ", NULL };
873     char *thanklist[] = {"thanks ", "thank you ", "thanx ", "gracias ", NULL };
874     char *byelist[] = {"bye ", "later ", "caio ", "adios ", "hasta la vista ", NULL };
875     char *swearlist[] = {"fuck", "shit", "god damn", "asshole", "cunt", "cock", "bullshit", "nigger", "asswipe", NULL };
876
877     //- Parse apart channel message
878     //- <user>(1): <mesg>
879     //- <user>(*)(24): <mesg>
880     //- <user>(TM)(49): <mesg>
881     if((p = strchr(message, '('))) {
882       pos = strlen(message) - strlen(p);
883       memset(user, '\0', NAMELEN);
884       strncpy(user, message, MIN(pos, NAMELEN-1));
885     } else
886       return 0;
887
888     if(0 == strcasecmp(user, username)) return 1;
889     CheckUser(user);
890     p = strchr(message, ':');
891     while(*p != '(') p--;
892     q = channel; p++;
893     while(*p != ')') { *q++ = *p++; }
894     *q = '\0';
895
896     p = strchr(message, ':'); p++;
897     q = mess;
898     while(*p != '\0') { *q++ = *p++; }
899     *q = '\0';
900
901     if(debugLevel >= 5)
902       printf("%s %s %s\n", user, channel, mess);
903   
904     mess[strlen(mess)] = '\0';
905     stolower(mess);
906
907     pos = 0;
908     index=0;
909     while (swearlist[index] != NULL) {
910       if (strstr(mess, swearlist[index])) {
911         printf("ABUSE - %s %s\n", user, mess);
912         XServerCom("%s %s\n", "+ c49muzzle", user);
913         pos = 1;
914       }
915       index++;
916     }
917     if ((strstr(mess, username)) && (pos == 0)) {
918       pos = 0;
919       index = 0;
920       while (hilist[index] != NULL) {
921         if (strstr(mess, hilist[index])) {
922           XServerCom("%s %s Hi %s :-)\n", "tell", channel, user);
923           pos = 1;
924         }
925         index++;
926       }
927       index = 0;
928       if(pos == 0)
929         while (thanklist[index] != NULL) {
930           if (strstr(mess, thanklist[index])) {
931             XServerCom("%s %s You're welcome %s!\n", "tell", channel, user);
932             pos = 1;
933           }
934           index++;
935         }
936       index = 0;
937       if(pos == 0) 
938         while (byelist[index] != NULL) {
939           if (strstr(mess, byelist[index])) {
940             XServerCom("%s %s Sad to see you going, %s :(\n", "tell", channel, user);
941             pos = 1;
942           }
943           index++;
944         }
945     }
946     if (strstr(mess, "tourn"))
947       XServerCom("%s %s %s %s %s\n", 
948                  "tell", channel, "To see a list of tourneys type: tell", username, "lt");
949
950     return(1);
951 } //- End of HandleChannel
952
953 //- HandleConnect ------------------------------------------------------------
954 int Mamer::HandleConnect(char *message) {
955     char *p = NULL, *reg = NULL, user[80] = {'\0'}, output[256] = {'\0'}, tmp[32] = {'\0'};
956     Tourney *t = NULL;
957     TourneyPlayers *tp = NULL;
958     LinkListIter<Tourney> tourneyIter(tourneyList);
959     int announceConnect = 0;
960
961     //- Parse apart connect message
962     //- [<user> (R: 123.123.123.123) has connected.]
963     if(5 <= debugLevel)
964       cout << "\nConnect Msg: " << message << endl;
965
966     if((p = strstr(message, " (U:"))) { return(1); }
967     if(!(p = strstr(message, " (R: "))) { return(1); }
968     strncpy(user, &(message[1]), MIN(strlen(message) - strlen(p) - 1, 79));
969     reg = strstr(message, " (R: ");
970     if(reg) {  //If this is a registered user
971       CheckUser(user);
972       while((t = tourneyIter.Next())) {
973         if((tp = t->GetPlayer(user))) {
974           tp->location = ONLINE;
975           announceConnect = 1;
976         }
977       }
978       if(announceConnect) {  // If the player arriving is in a tourney tell us he is arriving.
979         announceConnect = 0;
980         sprintf(output, "%s %d %s %s", "tell", channelNumber, user, "has connected.  Entered in tourney(s):");
981         tourneyIter.Reset();
982         while((t = tourneyIter.Next())) {
983           if(t->GetStatus() != DONE) {
984             if((tp = t->GetPlayer(user))) {
985               sprintf(tmp, " %d", t->number);
986               strcat(output, tmp);
987               announceConnect = 1;
988             }
989           }
990         }
991         if(announceConnect) {
992           XServerCom("%s %s %d%s", "tournset", user, 1, "\n");
993           XServerCom("%s%s", output, "\n");
994         }
995       }
996     } else {
997       if(15 <= debugLevel) {
998         cout << "\nConnect Msg: " << message << endl;
999         cout << "Ignoring User: " << user << endl;
1000       }
1001     }
1002     return(1);
1003 } //- End of HandleConnect
1004
1005 //- HandleDisconnect --------------------------------------------------------
1006 int Mamer::HandleDisconnect(char *message) {
1007   char *p = NULL, user[80] = {'\0'}, output[256] = {'\0'}, tmp[32] = {'\0'};
1008   Tourney *t = NULL;
1009   TourneyPlayers *tp = NULL;
1010   LinkListIter<Tourney> tourneyIter(tourneyList);
1011   int announceDisconnect = 0;
1012   
1013   //- Parse apart disconnect message
1014   //- [<user> has disconnected.]
1015   p = strstr(message, " has disconnected.");
1016   strncpy(user, &(message[1]), MIN(strlen(message) - strlen(p) - 1, 79));
1017   
1018   if(10 <= debugLevel) {
1019     cout << "Disconnect Msg: " << message << endl;
1020     cout << "User is: " << user << "\n" << endl;
1021   }
1022   
1023   LinkListIter<User> userIter(userList);
1024   User *u = NULL;  
1025   while((u = userIter.Next()))
1026     if(1 == u->IsUser(user))
1027       break;
1028
1029   if(NULL != u) {
1030     tourneyIter.Reset();
1031     while((t = tourneyIter.Next())) {
1032       if((tp = t->GetPlayer(user))) {
1033         tp->location = GONE;
1034         announceDisconnect = 1;
1035       }
1036     }
1037     if(announceDisconnect) {  // If the player arriving is in a tourney tell us he is arriving.
1038       announceDisconnect = 0;
1039       sprintf(output, "%s %d %s %s", "tell", channelNumber, user, "has disconnected.  Entered in tourney(s):");
1040       tourneyIter.Reset();
1041       while((t = tourneyIter.Next())) {
1042         if(t->GetStatus() != DONE) {
1043           if((tp = t->GetPlayer(user))) {
1044             sprintf(tmp, " %d", t->number);
1045             strcat(output, tmp);
1046             announceDisconnect = 1;
1047           }
1048         }
1049       }
1050       if(announceDisconnect) {
1051         XServerCom("%s %s %d%s", "tournset", user, 1, "\n");
1052         XServerCom("%s%s", output, "\n");
1053       }
1054     }
1055     u->SavePlayer(userFilePath);
1056     userList.Delete(u);
1057   }
1058   
1059   return(1);
1060 } //- End of HandleDisconnect
1061
1062 //- AdjustManagerList ----------------------
1063 void Mamer::AdjustManagerList(int value, char *name) {
1064   Storage *tmp=NULL, *newName=NULL;
1065   LinkListIter<Storage> managerIter(storageList);
1066   FILE *theFile=NULL;
1067   char filename[128], manager[NAMELEN];
1068   int added=0, needToAdd=1;
1069
1070   memset(filename, '\0', 128);
1071   sprintf(filename, "%s/managers", dataFilePath);
1072   theFile = fopen(filename, "r");
1073   if(theFile == NULL) return;
1074
1075   memset(manager, '\0', NAMELEN);
1076   while(fscanf(theFile, "%s", manager) > 0) {  // build the temporary list
1077     tmp = new Storage(manager, 0);
1078     storageList.Append(tmp);
1079     tmp = NULL;
1080     memset(manager, '\0', NAMELEN);
1081   }
1082   fclose(theFile);
1083
1084   switch(value) {
1085   case -1:
1086     managerIter.Reset();  // remove a manager from the list that is printed later
1087     while((tmp = managerIter.Next()))
1088       if(strlen(tmp->name) == strlen(name)) 
1089         if(0 == (strcasecmp(tmp->name, name)))
1090           storageList.Delete(tmp);
1091     XServerCom("%s %s\n", "- mamermgr", name);
1092     break;
1093   case 1:
1094     newName = new Storage(name, 0);
1095     added = 0;   // Add a user to the manager list that is later printed
1096     needToAdd = 1;
1097     managerIter.Reset();  // Got through the list see if the name is there
1098     while((tmp = managerIter.Next()))
1099       if(strlen(tmp->name) == strlen(newName->name))
1100         if(0 == strcasecmp(tmp->name, newName->name)) { 
1101           needToAdd = 0; 
1102           break; 
1103         }
1104     if(needToAdd) {        // If its not there we have to add it
1105       managerIter.Reset();
1106       while((tmp = managerIter.Next()))        // if the name in the list is > new name
1107         if((strncasecmp(tmp->name, newName->name, MIN(strlen(tmp->name), strlen(newName->name)))) > 0) { 
1108           added = 1;
1109           storageList.Insert(tmp, newName);         // insert the new name before the list name
1110           break;
1111         }
1112       if(!added) storageList.Append(newName);
1113       XServerCom("%s %s\n", "+ mamermgr", name);
1114     }
1115     break;
1116   default:
1117     break;
1118   }
1119   theFile = fopen(filename, "w");
1120   if(!theFile) return;
1121   managerIter.Reset();    // Lets write the new manager file
1122   while((tmp = managerIter.Next())) {
1123     fprintf(theFile, "%s\n", tmp->name);
1124     storageList.Delete(tmp);
1125   }
1126   fclose(theFile);
1127   //  if(newName != NULL) delete(newName);
1128 }
1129
1130 //- UserIsLoaded --------------------------
1131 int Mamer::UserIsLoaded(char *uname) {
1132   User *u = NULL;
1133   LinkListIter<User> userIter(userList);
1134   
1135   while((u = userIter.Next())) {
1136     if(0 == strcasecmp(u->name, uname))
1137       return 1;
1138   }
1139   
1140   return 0;
1141 }//- end UserIsLoaded ------------------------------------------------------
1142
1143 /* this function checks if the user is loaded and if not loads the user */
1144 //- CheckUser ---------------------------------------------------------------
1145 void Mamer::CheckUser(char *user) {
1146   if(!UserIsLoaded(user)) {
1147     if(debugLevel >= 5) 
1148       cout << "CheckUser - Adding User:" << user << ":" << endl;
1149
1150     User *newUser = NULL;
1151     newUser = new User(userFilePath, user);
1152     if(NULL != newUser)
1153       userList.Append(newUser);
1154   }
1155 }//- end of CheckUser -----------------------------------------------------
1156
1157 //- HandleGame ------------------------------------------------------------
1158 int Mamer::HandleGame(char *message) {
1159   char *p, *q, user1[NAMELEN], user2[NAMELEN], action[256], result[8], tmp[256];
1160   int gameNumber, clocktime, inc, rated, isPrivate, result_code, moreGames=1, moreRounds=1, madeMoreGames=0, gameType=-2;
1161   Tourney *t = NULL;
1162   Game *g = NULL;
1163   TourneyPlayers *tp = NULL;
1164
1165   printf("MESSAGE: %s\n", message);
1166
1167   // {Game 8 (Blammor vs. Havard) Blammor resigns} 0-1
1168
1169   sscanf(message, "{Game %d (%s vs. %s", &gameNumber, user1, user2);
1170   user2[strlen(user2)-1] = '\0';
1171
1172   if((p = strchr(message, ')'))) {
1173     q = action; p++; p++;
1174     while((*p != '\0') && (*p != '}')) { *q++ = *p++; }
1175     *q = '\0';
1176   } else { return 0; }
1177
1178   memset(result, '\0', 8);
1179   if((p = strchr(message, '}')) && 
1180      ((strstr(message, ") Creating ") == NULL) && (strstr(message, ") Continuing ") == NULL))) {
1181     //    sscanf(p, "} %s [%d %d %d %d", result, &clocktime, &inc, &rated, &isPrivate);
1182     sscanf(p, "} %s [%d %d %d %d %d", result, &clocktime, &inc, &rated, &isPrivate, &gameType);
1183     
1184     if(!strcmp(result, "1-0")) { result_code = 1;
1185     } else if(!strcmp(result, "0-1")) { result_code = 0;
1186     } else if(!strcmp(result, "1/2-1/2")) { result_code = 2;
1187     } else { result_code = -1; }
1188     
1189     if(debugLevel >= 5)
1190       //      printf("\nGame #%d %s vs. %s  action=%s  result=%s time=%d inc=%d rated=%d private=%d\n", 
1191       //             gameNumber, user1, user2, action, result, clocktime, inc, rated, isPrivate);
1192       printf("\nGame #%d %s vs. %s  action=%s  result=%s time=%d inc=%d rated=%d private=%d gameType=%d\n", 
1193              gameNumber, user1, user2, action, result, clocktime, inc, rated, isPrivate, gameType);
1194     
1195     LinkListIter<Tourney> tourneyIter(tourneyList);
1196     tourneyIter.Reset();
1197     while((t = tourneyIter.Next())) {
1198       if(t->GetStatus() != CLOSED) continue;
1199       LinkListIter<Game> gameIter(t->gameList);
1200       gameIter.Reset();
1201       while((g = gameIter.Next())) {
1202         if(g->IsGame(user1, user2, clocktime, inc, rated, 'r')) { //- There is room to add isPrivate later
1203           XServerCom("%s %i %s %s %s %s%i %s %s %s\n", "tell", channelNumber, g->whiteName, "vs.", g->blackName,
1204                      "a game in tourney #", t->number, "just ended. ", action, result);
1205           if(strcmp(result, "*") == 0) {
1206             g->gameNumber = -1;
1207             continue;
1208           }
1209           moreGames = t->SetGameResult(user1, user2, result_code);  //- SetGameResult deletes the game for us
1210           if(moreGames == 2) {
1211             moreRounds = (t->GetRoundsRemaining());
1212             LinkListIter<TourneyPlayers> playerIter(t->playerList);
1213             playerIter.Reset();
1214             if(moreRounds) {
1215               madeMoreGames = t->MakeAssignments();
1216               while((tp = playerIter.Next())) {
1217                 sprintf(tmp, "%s tells you: listplayers %d\n", tp->name, t->number);
1218                 HandleTell(tmp);
1219               }
1220               if(madeMoreGames) {
1221                 t->TellThemWhoTheyPlay();
1222               } else {          // tourney over!
1223                 AnnounceTourneyEnd(t);
1224                 savePlayerData(t);
1225               }
1226             } else {          // tourney over!
1227               /*
1228               while((tp = playerIter.Next())) {
1229                 sprintf(tmp, "%s tells you: listplayers %d\n", tp->name, t->number);
1230                 HandleTell(tmp);
1231               }
1232               */
1233               AnnounceTourneyEnd(t);
1234               savePlayerData(t);
1235             }
1236           }
1237           break;
1238         }
1239       }
1240     }
1241   } else { 
1242     XServerCom("%s %s %s", "getgi", user1, "\n"); 
1243   }
1244   return(1);
1245 } //- End of HandleGame
1246
1247 //- HandleGameInfo ----------------------------------------------------------
1248 int Mamer::HandleGameInfo(char *message) {
1249   char white[NAMELEN], black[NAMELEN], player[NAMELEN];
1250   int gameNumber, gameTime, inc, rated, isPrivate;
1251   Tourney *t=NULL;
1252   Game *g=NULL;
1253   
1254   sscanf(message, "*getgi %s %s %s %d %d %d %d %d*", player, white, black,
1255          &gameNumber, &gameTime, &inc, &rated, &isPrivate);
1256
1257   gameTime = gameTime / 600;  // Values for getgi are in micro and nano seconds
1258   inc = inc / 10;
1259
1260   LinkListIter<Tourney> tourneyIter(tourneyList);
1261   tourneyIter.Reset();
1262   while((t = tourneyIter.Next())) {
1263     if(t->GetStatus() != CLOSED) continue;
1264     LinkListIter<Game> gameIter(t->gameList);
1265     gameIter.Reset();
1266     while((g = gameIter.Next())) {
1267       if(g->IsGame(white, black, gameTime, inc, rated, 'r')) { //- There is room to add isPrivate later
1268         if(g->gameNumber < 0){
1269           XServerCom("%s %i %s %s %s %s%i %s\n", "tell", channelNumber, white, "vs.", black, 
1270                      "a game in tourney #", t->number, "just started.");
1271         } else {
1272           XServerCom("%s %i %s %s %s %s%i %s\n", "tell", channelNumber, white, "vs.", black, 
1273                      "a game in tourney #", t->number, "just Restarted.");
1274         }
1275         g->gameNumber = gameNumber;
1276       }
1277     }
1278   }
1279   return(1);
1280 } //- End of HandleGameInfo
1281
1282 //- HandlePlayerInfo --------------------------------------------------------
1283 int Mamer::HandlePlayerInfo(char *message) {
1284   char player[NAMELEN];
1285   int ratings[6], return_from_AddPlayer, tourneyNumber;
1286   Tourney *t = NULL;
1287   Player *p = NULL;
1288
1289   sscanf(message, "*getpi %s %d %d %d %d %d %d*",    // Scan in the info
1290          player, &ratings[0], &ratings[2], &ratings[3], &ratings[1], &ratings[4], &ratings[5]);
1291   
1292   if(debugLevel >=15)
1293     printf("Get Player Info: %s blitz=%d stand=%d light=%d wild=%d bug=%d suicide=%d\n",
1294            player, ratings[2], ratings[3], ratings[1], ratings[0], ratings[4], ratings[5]);
1295
1296   p = FindPending(player);
1297 printf("player p=%d\n", p);
1298   if(p != NULL) {
1299     tourneyNumber = p->value;       // find out which tourney we want
1300     t = FindTourney(tourneyNumber); // Get the tourney.  If its in the list it should be valid
1301   } else {
1302     return 0;
1303   } //Check for valid tourney is done in CommandEntry::JoinTourney
1304
1305   return_from_AddPlayer = t->AddPlayer(player, ratings[t->GetVariant()], 0.0);
1306 printf("ret = %d\n", return_from_AddPlayer);
1307   TellUser(JoinedTourney, player, return_from_AddPlayer);
1308   if(return_from_AddPlayer == 1)
1309     XServerCom("%s %s %d%s", "tournset", player, 1, "\n");
1310   pendingList.Delete(p);   //This is safe cause to get here we had to find a Player p
1311
1312   return 1;
1313 } //- End of HandlePlayerInfo
1314
1315 //- FindPending ---------------------------------------------------------------
1316 Player *Mamer::FindPending(char *user) {
1317     Player *p = NULL;
1318     LinkListIter<Player> pendingIter(pendingList);
1319
1320     while((p = pendingIter.Next()))
1321         if(1 == p->IsPlayer(user))
1322             break;
1323
1324     return(p);
1325 } //- End of FindPending
1326
1327 //- FindUser ---------------------------------------------------------------
1328 User *Mamer::FindUser(char *user) {
1329     User *u = NULL;
1330     LinkListIter<User> userIter(userList);
1331
1332     //    printf("FindUser: %18s\n", user);
1333
1334     while((u = userIter.Next()))
1335         if(1 == u->IsUser(user))
1336             break;
1337
1338     return(u);
1339 } //- End of FindUser
1340
1341 //- FindTourney ------------------------------------------------------------
1342 Tourney *Mamer::FindTourney(int tourn) {
1343     Tourney *t = NULL;
1344     LinkListIter<Tourney> tourneyIter(tourneyList);
1345
1346     while((t = tourneyIter.Next())) {
1347         if(1 == t->IsTourney(tourn))
1348             break;
1349     }
1350     return(t);
1351 } //- End of FindUser
1352
1353 //- FindCommand ---------------------------------------------------------------
1354 Command *Mamer::FindCommand(char *comm, char *user) {
1355     Command *c = NULL, *cnull=NULL;
1356     LinkListIter<Command> commIter(commandList);
1357     int commandsFound=0;
1358     char* output = NULL;
1359
1360     output = new char[MAX_LINE_SIZE];
1361     memset(output, '\0', MAX_LINE_SIZE);
1362     commIter.Reset();
1363     while((c = commIter.Next())) {
1364       if(c->IsCommand(comm)) {
1365         commandsFound++;
1366         if((int)(strlen(output) + strlen(c->GetCommandName())) < (MAX_LINE_SIZE - 1))
1367           sprintf(output, "%s %s", output, c->GetCommandName());
1368       }
1369     }
1370     output[strlen(output)] = '\0';
1371
1372     commIter.Reset();
1373     while((c = commIter.Next())) 
1374       if(1 == c->IsCommand(comm))
1375         break;
1376
1377     switch (commandsFound) {
1378     case 0:
1379       TellUser(BadCommand, user);
1380       return(cnull);
1381     case 1:
1382       return(c);
1383     default:
1384       TellUser(MultiCommand, user, output);
1385       return(cnull);
1386     }
1387 } //- End of FindUser
1388
1389 /*
1390   Parameter string format
1391   w - a word 
1392   o - an optional word 
1393   d - integer
1394   p - optional integer
1395   i - word or integer
1396   n - optional word or integer
1397   s - string to end
1398   t - optional string to end
1399
1400   If the parameter option is given in lower case then the parameter is 
1401   converted to lower case before being passsed to the function. If it is
1402   in upper case, then the parameter is passed as typed.
1403
1404   Calling these Appends adds commands to the link list.  They are called with:
1405    1)   the text command Mamer should look for
1406    2)  an alias or substitute for that text
1407    3)  the manager level one needs to be to execute this command
1408    4)  a BRIEF description of the command's function
1409    5)  the parameter types for each parameter (see comments above)
1410    6)  what code to use when telling the user they did something wrong (see TellUser)
1411    7)  and the function pointer to the CommandEntry.cc code that is this command */
1412
1413 //- BuildCommandList ---------------------------------------------------------
1414 void Mamer::BuildCommandList(void) {
1415     commandList.Append(new Command("addchaos", "ac", MANAGER, "Adds (or subs) chaos points.",
1416                                    "wp", (USERFP)&Mamer::AddAbuse));
1417
1418     commandList.Append(new Command("announce", "ann", DIRECTOR, "Announce the tournament to the working channel.",
1419                                    "d", (USERFP)&Mamer::AnnounceTourney));
1420
1421     commandList.Append(new Command("addtotourney", "att", VICE, "Add a user to a tourney.", 
1422                                    "Wd", (USERFP)&Mamer::AddToTourney));
1423
1424     commandList.Append(new Command("create", "cr", DIRECTOR, "Creates a new tournament.",
1425                                    "", (USERFP)&Mamer::CreateTourney));
1426
1427     commandList.Append(new Command("close", "cl", DIRECTOR, "Closes and starts a tournament.",
1428                                    "d", (USERFP)&Mamer::CloseTourney));
1429
1430     commandList.Append(new Command("delete", "del", DIRECTOR, "Deletes a tournament.",
1431                                    "d", (USERFP)&Mamer::DeleteTourney));
1432
1433     commandList.Append(new Command("finger", "fi", USER, "Displays the stats for a user.",
1434                                    "O", (USERFP)&Mamer::FingerUser));
1435
1436     commandList.Append(new Command("forfeit", "fo", DIRECTOR, "Remove a user from a tourney.", 
1437                                    "wd", (USERFP)&Mamer::RemoveFromTourney));
1438
1439     commandList.Append(new Command("join", "j", USER, "Request to enter a tourney.", 
1440                                    "d", (USERFP)&Mamer::JoinTourney));
1441
1442     commandList.Append(new Command("keep", "k", MANAGER, "Keep a tourney in memory.", 
1443                                    "di", (USERFP)&Mamer::KeepTourney));
1444
1445     commandList.Append(new Command("listmanagers", "lm", USER, "Displays the Managers list.",
1446                                    "", (USERFP)&Mamer::ListManagers));
1447
1448     commandList.Append(new Command("listtourneys", "lt", USER, "Displays the tournament list.",
1449                                    "", (USERFP)&Mamer::ListTourneys));
1450
1451     commandList.Append(new Command("listtourneyvars", "vars", USER, "Displays the tournament variables.",
1452                                    "d", (USERFP)&Mamer::ListTourneyVars));
1453
1454     commandList.Append(new Command("listtourneygames", "games", USER, "Displays the tournament games.",
1455                                    "d", (USERFP)&Mamer::ListTourneyGames));
1456
1457     commandList.Append(new Command("listplayers", "lp", USER, "Displays the players in the tourney.",
1458                                    "d", (USERFP)&Mamer::ListTourneyPlayers));
1459
1460     commandList.Append(new Command("listrank", "rank", USER, "Displays player rank.",
1461                                    "n", (USERFP)&Mamer::ListRank));
1462
1463     commandList.Append(new Command("loadedusers", "lu", MANAGER, "Displays the loaded users.",
1464                                    "", (USERFP)&Mamer::LoadedUsers));
1465
1466     commandList.Append(new Command("messman", "mm", VICE, "Message all of the Managers.",
1467                                    "s", (USERFP)&Mamer::MessageManagers));
1468
1469     commandList.Append(new Command("open", "ot", DIRECTOR, "Opens the tournament to players.",
1470                                    "d", (USERFP)&Mamer::OpenTourney));
1471
1472     commandList.Append(new Command("setcommandlevel", "setcl", VICE, "Set the level required to execute a command.",
1473                                    "wd", (USERFP)&Mamer::SetCommandLevel));
1474
1475     commandList.Append(new Command("setinfo", "si", VICE, "Set a user's finger info.",
1476                                    "Wddddddd", (USERFP)&Mamer::SetInfo));
1477
1478     commandList.Append(new Command("setmanagerlevel", "sml", VICE, "Sets manager's level.",
1479                                    "Wd", (USERFP)&Mamer::SetManagerLevel));
1480
1481     commandList.Append(new Command("setres", "sr", DIRECTOR, "Sets the result of a game.",
1482                                    "dWWi", (USERFP)&Mamer::SetResult));
1483
1484     commandList.Append(new Command("setstat", "ss", VICE, "Sets a specific finger stat.",
1485                                    "Wwd", (USERFP)&Mamer::SetStat));
1486
1487     commandList.Append(new Command("settourneyvar", "stv", DIRECTOR, "Sets a Tourney's Variables.",
1488                                    "dwi", (USERFP)&Mamer::SetTourneyVariable));
1489
1490     commandList.Append(new Command("showcommands", "sc", USER, "List commands and descripts.",
1491                                    "o", (USERFP)&Mamer::ShowCommands));
1492
1493     commandList.Append(new Command("showhelpfile", "shf", USER, "Shows a help file.",
1494                                    "o", (USERFP)&Mamer::ShowHelp));
1495
1496     commandList.Append(new Command("help", "help", USER, "Shows a help file.",
1497                                    "o", (USERFP)&Mamer::ShowHelp));
1498
1499     commandList.Append(new Command("shutdown", "sd", VICE, "Shuts down Mamer.",
1500                                    "", (USERFP)&Mamer::Shutdown));
1501
1502     commandList.Append(new Command("who", "who", USER, "Displays the tournament games.",
1503                                    "d", (USERFP)&Mamer::ListTourneyPlayers));
1504
1505     commandList.Append(new Command("withdraw", "with", USER, "Remove yourself from a tourney.", 
1506                                    "d", (USERFP)&Mamer::RemoveFromTourney));
1507
1508 } //- End of BuildCommandList
1509
1510 //- NextRound -------------------------
1511 void Mamer::NextRound() {
1512   int moreGames=0, moreRounds=1, madeMoreGames=0;
1513   Tourney *t = NULL;
1514   Game *g = NULL;
1515   
1516   LinkListIter<Tourney> tourneyIter(tourneyList);
1517   tourneyIter.Reset();
1518   while((t = tourneyIter.Next())) {
1519     if(t->GetStatus() != CLOSED) continue;
1520     moreRounds = (t->GetRoundsRemaining());
1521     moreGames = 0;
1522     LinkListIter<Game> gameIter(t->gameList);
1523     gameIter.Reset();
1524     while((g = gameIter.Next())) moreGames++;
1525
1526     if(moreGames == 0) {
1527       if(debugLevel >= 10)
1528         cout << "No more games!  Next Round Please!  From Next Round" << endl;
1529       cerr << "No more games!  Next Round Please!  From Next Round" << endl;
1530       if(moreRounds) {
1531         madeMoreGames = t->MakeAssignments();
1532         if(madeMoreGames) 
1533           t->TellThemWhoTheyPlay();
1534         else {    // tourney over!
1535           cerr << "Coulnd't make any more games.  End of Tourney.  From Next Round" << endl;
1536           AnnounceTourneyEnd(t);
1537           savePlayerData(t);
1538         }
1539       } else {                  // tourney over!
1540         cerr << "No more rounds.  End of Tourney.  From Next Round" << endl;
1541         AnnounceTourneyEnd(t);
1542         savePlayerData(t);
1543       }
1544     }
1545   }
1546 } //- End of NextRound
1547
1548 //- XServerCom ---------------------------------------------
1549 int Mamer::XServerCom(char *fmt, ...)
1550 {
1551   va_list argptr;
1552   char buffer[1024];
1553   int count;
1554
1555   va_start(argptr, fmt);
1556   count = vsprintf(buffer, fmt, argptr);
1557   write(serverSocket, buffer, strlen(buffer));
1558   va_end(argptr);
1559
1560   /* returns number of elements written */
1561   return (count);
1562 }
1563 //- End of XServerCom
1564
1565 //- TellUser ------------------------------------------------
1566 void Mamer::TellUser(reasons reason, char *name) {
1567   switch (reason) {
1568   case NoPermissions:
1569     XServerCom("qtell %s %s notes: Sorry you do not have permission to do that.\n", name, username);
1570     break;
1571   case BadCommand:
1572     XServerCom("qtell %s %s notes: Command not found.\n", name, username);
1573     break;
1574   default:
1575     break;
1576   }
1577 }//- End of TellUser
1578
1579 //- TellUser ------------------------------------------------
1580 void Mamer::TellUser(reasons reason, char *name, int number) {
1581   switch (reason) {
1582   case JoinedTourney:
1583     switch (number) {
1584     case 0:
1585       XServerCom("qtell %s %s notes: %s\n", name, username, 
1586                  "Can not join\\nYour rating does not fit into current limits. <check tourney vars>");  
1587       break;
1588     case 1:
1589       XServerCom("qtell %s %s notes: %s\n", name, username, "You joined the tournament.");  
1590       break;
1591     case 2:
1592       XServerCom("qtell %s %s notes: %s\n", name, username, "You are already in this tourney.");
1593       break;
1594     case 3:
1595       XServerCom("qtell %s %s notes: %s\n", name, username, "You can not join.  Tourney is not open.");  
1596       break;
1597     default:
1598       break;
1599     }
1600     break;
1601   case NotEnoughPlayers:
1602     XServerCom("qtell %s %s notes: Tourney#%d %s\n", name, username, number, "does not have enough players.");
1603     break;
1604   case NoPlayers:
1605     XServerCom("qtell %s %s notes: Tourney#%d %s\n", name, username, number, "has no players.");
1606     break;
1607   case WillKeepTourney:
1608     XServerCom("qtell %s %s notes: Tourney#%d %s\n", name, username, number, "will be kept.");
1609     break;
1610   case NotKeepTourney:
1611     XServerCom("qtell %s %s notes: Tourney#%d %s\n", name, username, number, "will not be kept.");
1612     break;
1613   case TourneyNotFound:
1614     XServerCom("qtell %s %s notes: %s%d %s\n", name, username, "Tourney #", number, "not found.");
1615     break;
1616   case NotFound:
1617     XServerCom("qtell %s %s notes: %s%d\n", name, username, "Player not found in tourney #", number);
1618     break;
1619   case GameResultNotFound:
1620     XServerCom("qtell %s %s notes: %s%d\n", name, username, "Can not set result to ", number);
1621     break;
1622   case NoPermissions:
1623     XServerCom("qtell %s %s notes: You don't have change permissions for tourney #%d.\n", name, username, number);
1624     break;
1625   case TourneyNotNew:
1626     XServerCom("qtell %s %s notes: %s  %s%d %s\n", name, username, "Can not do that right now.", 
1627                "Tourney #", number, "is not new.");
1628     break;
1629   case TourneyNotOpen:
1630     XServerCom("qtell %s %s notes: %s  %s%d %s\n", name, username, "Can not do that right now.", 
1631                "Tourney #", number, "is not open.");
1632     break;
1633   case TourneyNotClosed:
1634     XServerCom("qtell %s %s notes: %s  %s%d %s\n", name, username, "Can not do that right now.", 
1635                "Tourney #", number, "is not closed.");
1636     break;
1637   case TourneyDone:
1638     XServerCom("qtell %s %s notes: %s  %s%d %s\n", name, username, "Can not do that anymore.", 
1639                "Tourney #", number, "is done.");
1640     break;
1641   case TourneyClosed:
1642     XServerCom("qtell %s %s notes: %s  %s%d %s\n", name, username, "Can not do that anymore.", 
1643                "Tourney #", number, "is closed.");
1644     break;
1645   case TourneyDeleted:
1646     XServerCom("qtell %s %s Notes: %s %s%d %s\n", name, username, "\\n", "Tourney #",
1647                number, " has been deleted.");
1648     break;    
1649   default:
1650     break;
1651   }
1652 }//- End of TellUser
1653
1654 //- TellUser ------------------------------------------------
1655 void Mamer::TellUser(Command *comm, char *name) {
1656   char line[512];
1657   int i, length=strlen(comm->parameterList);
1658
1659   sprintf(line, "qtell %s %s notes: Usage: %s ", name, username, comm->GetCommandName());
1660
1661   for(i=0; i<length; i++) {
1662     switch (comm->parameterList[i]) {
1663     case 'w':
1664       strcat(line, "<word> ");
1665       break;
1666     case 'o':
1667       strcat(line, "<optional word> ");
1668       break;
1669     case 'd':
1670       strcat(line, "<integer> ");
1671       break;
1672     case 'p':
1673       strcat(line, "<optional int> ");
1674       break;
1675     case 'i':
1676       strcat(line, "<word or int> ");
1677       break;
1678     case 'n':
1679       strcat(line, "<optional word or int> ");
1680       break;
1681     case 's':
1682       strcat(line, "<string> ");
1683       break;
1684     case 't':
1685       strcat(line, "<optional string> ");
1686       break;
1687     default:
1688       break;
1689     }
1690   }
1691   strcat(line, "\n");
1692   write(serverSocket, line, strlen(line));
1693 }//- End of TellUser
1694
1695 //- TellUser ------------------------------------------------
1696 void Mamer::TellUser(reasons reason, char *name, char *request) {
1697   switch (reason) {
1698   case NotFound:
1699     XServerCom("qtell %s %s notes: Sorry %s is not found.\n", name, username, request);
1700     break;
1701   case GenericTell:
1702     XServerCom("qtell %s %s notes: %s\n", name, username, request);
1703     break;
1704   case ChangedInfo:
1705     XServerCom("qtell %s %s notes: Changed the info for %s.\n", name, username, request);
1706     break;
1707   case GameResultNotFound:
1708     XServerCom("qtell %s %s notes: %s %s\n", name, username, "Can not set result to", request);
1709     break;
1710   case MultiCommand:
1711     XServerCom("qtell %s %s notes: Ambiguous Command Matches:\\n %s\n", name, username, request);
1712     break;
1713   default:
1714     break;
1715   }
1716 }//- End of TellUser
1717
1718 //- TellUser ------------------------------------------------
1719 void Mamer::TellUser(reasons reason, char *name, char *who, char *which, int new_value) {
1720   switch (reason) {
1721   case ChangedInfo:
1722     XServerCom("qtell %s %s notes: Changed the %s stat for %s to %d.\n", name, username, which, who, new_value);
1723     break;  
1724   case GameResultSet:
1725     switch (new_value) {
1726     case 1:
1727       XServerCom("qtell %s %s notes: The game %s(w) vs. %s(b) has been set to 1-0\n", name, username, who, which);
1728       break;
1729     case 0:
1730       XServerCom("qtell %s %s notes: The game %s(w) vs. %s(b) has been set to 0-1\n", name, username, who, which);
1731       break;
1732     default:
1733       XServerCom("qtell %s %s notes: The game %s(w) vs. %s(b) has been set to 1/2-1/2\n", name, username, who, which);
1734       break;
1735     }
1736     break;
1737   default:
1738     break;
1739   }
1740 }//- End of TellUser
1741
1742 //- TellUser ------------------------------------------------
1743 void Mamer::TellUser(reasons reason, char *name, char *which, char *new_value) {
1744   switch (reason) {
1745   case CanNotChange:
1746     XServerCom("qtell %s %s notes: Can not change the %s var to %s.\n", name, username, which, new_value);
1747     break;
1748   case ChangedInfo:
1749    XServerCom("qtell %s %s notes: Changed %s to %s.\n", name, username, which, new_value);
1750     break;  
1751   default:
1752     break;
1753   }
1754 }//- End of TellUser
1755
1756
1757 //- TellUser ------------------------------------------------
1758 void Mamer::TellUser(reasons reason, char *name, char *uname, int new_value) {
1759   switch (reason) {
1760   case ChangedManagerLevel:
1761     XServerCom("qtell %s %s notes: %s's Manager Level has been changed to %d\n", name, username, uname,new_value);
1762     break;
1763   case ChangedCommandLevel:
1764     XServerCom("qtell %s %s notes: The %s command's manager Level has been changed to %d\n",name,username,uname, new_value);
1765     break;
1766   case PlayerRemoved:
1767     XServerCom("qtell %s %s notes: %s Has been removed from tourney #%i\n", name, username, uname, new_value);
1768     break;
1769   case NotFound:
1770     XServerCom("qtell %s %s notes: %s Is not found in tourney #%i\n", name, username, uname, new_value);
1771     break;
1772   case ChangedAbuse:
1773     XServerCom("qtell %s %s notes: %s's Chaos Points have been changed to %d\n",name, username, uname, new_value);
1774     break;
1775   case CanNotChange:
1776     XServerCom("qtell %s %s notes: Can Not Change the %s stat to %d.\n", name, username, uname, new_value);
1777     break;
1778   case ChangedInfo:
1779     XServerCom("qtell %s %s notes: Changed %s to %d.\n", name, username, uname, new_value);
1780     break;  
1781   default:
1782     break;
1783   }
1784 }//- End of TellUser
1785
1786 //- ParseParams ----------------------------------------------
1787 int Mamer::ParseParams(Command *comm, char *parameters) {
1788   int i, parlen;
1789   int paramLower;
1790   char c;
1791
1792   for (i = 0; i < MAXNUMPARAMS; i++)
1793     comm->params[i].type = TYPE_NULL;       /* Set all parameters to NULL */
1794   parlen = strlen(comm->parameterList);
1795   parameters = eatWhite(parameters);      /* remove and spaces before the command */
1796   parameters = eatWord(parameters);       /* remove the command itself */
1797   for (i = 0; i < parlen; i++) {
1798     c = comm->parameterList[i];
1799     if (isupper(c)) {
1800       paramLower = 0;
1801       c = tolower(c);
1802     } else {
1803       paramLower = 1;
1804     }
1805     switch (c) {
1806     case 'w':
1807     case 'o':                   /* word or optional word */
1808       parameters = eatWhite(parameters);
1809       if (!*parameters)
1810         return (c == 'o' ? COM_OK : COM_BADPARAMETERS);
1811       comm->params[i].val.word = parameters;
1812       comm->params[i].type = TYPE_WORD;
1813       parameters = eatWord(parameters);
1814       if (*parameters != '\0') {
1815         *parameters = '\0';
1816         parameters++;
1817       }
1818       if (paramLower)
1819         stolower(comm->params[i].val.word);
1820       break;
1821
1822     case 'd':
1823     case 'p':                   /* optional or required integer */
1824       parameters = eatWhite(parameters);
1825       if (!*parameters)
1826         return (c == 'p' ? COM_OK : COM_BADPARAMETERS);
1827       if (sscanf(parameters, "%d", &comm->params[i].val.integer) != 1)
1828         return COM_BADPARAMETERS;
1829       comm->params[i].type = TYPE_INT;
1830       parameters = eatWord(parameters);
1831       if (*parameters != '\0') {
1832         *parameters = '\0';
1833         parameters++;
1834       }
1835       break;
1836
1837     case 'i':
1838     case 'n':                   /* optional or required word or integer */
1839       parameters = eatWhite(parameters);
1840       if (!*parameters)
1841         return (c == 'n' ? COM_OK : COM_BADPARAMETERS);
1842       if (sscanf(parameters, "%d", &comm->params[i].val.integer) != 1) {
1843         comm->params[i].val.word = parameters;
1844         comm->params[i].type = TYPE_WORD;
1845       } else {
1846         comm->params[i].type = TYPE_INT;
1847       }
1848       parameters = eatWord(parameters);
1849       if (*parameters != '\0') {
1850         *parameters = '\0';
1851         parameters++;
1852       }
1853       if (comm->params[i].type == TYPE_WORD)
1854         if (paramLower)
1855           stolower(comm->params[i].val.word);
1856       break;
1857
1858     case 's':
1859     case 't':                   /* optional or required string to end */
1860       if (!*parameters)
1861         return (c == 't' ? COM_OK : COM_BADPARAMETERS);
1862       comm->params[i].val.string = parameters;
1863       comm->params[i].type = TYPE_STRING;
1864       while (*parameters)
1865         parameters = nextWord(parameters);
1866       if (paramLower)
1867         stolower(comm->params[i].val.string);
1868       break;
1869     }
1870   }
1871   if (*parameters)
1872     return COM_BADPARAMETERS;
1873   else
1874     return COM_OK;
1875 } //- End ParseParams ------------------
1876
1877 //- isWhiteSpace -------------------------------------------
1878 int Mamer::isWhiteSpace (int c) {
1879   if ((c < ' ') || (c == '\b') || (c == '\n') ||
1880       (c == '\t') || (c == ' ')) {      /* white */
1881     return 1;
1882   } else {
1883     return 0;
1884   }
1885 } //- End isWhiteSpace -------
1886
1887 //- getWord ------------------------------------------------
1888 char *Mamer::getWord (char *str) {
1889   int i;
1890   static char word[MAX_WORD_SIZE];
1891
1892   i = 0;
1893   while (*str && !isWhiteSpace(*str)) {
1894     word[i] = *str;
1895     str++;
1896     i++;
1897     if (i == MAX_WORD_SIZE) {
1898       i = i - 1;
1899       break;
1900     }
1901   }
1902   word[i] = '\0';
1903   return word;
1904 } //- End getWord -------------
1905
1906 //- eatWord -------------------------------------------
1907 char *Mamer::eatWord (char *str) {
1908   while (*str && !isWhiteSpace(*str))
1909     str++;
1910   return str;
1911 } //- eatWord ----
1912
1913 //- eatWhite ------------------------------------------
1914 char *Mamer::eatWhite (char *str) {
1915   while (*str && isWhiteSpace(*str))
1916     str++;
1917   return str;
1918 } //- eatWhite --------
1919
1920 //- eatTailWhite -------------------------------------------
1921 char *Mamer::eatTailWhite (char *str) {
1922   int len;
1923   if (str == NULL)
1924     return NULL;
1925
1926   len = strlen(str);
1927   while (len > 0 && isWhiteSpace(str[len - 1]))
1928     len--;
1929   str[len] = '\0';
1930   return (str);
1931 } //- End of eatTailWhite -----------
1932
1933 //- nextWord -----------------------------------------------
1934 char *Mamer::nextWord(char *str) {
1935   return eatWhite(eatWord(str));
1936 } //- End of nextWord
1937
1938 char *Mamer::stolower(char *str) {
1939   int i;
1940
1941   if (!str)
1942     return NULL;
1943   for (i = 0; str[i]; i++) {
1944     if (isupper(str[i])) {
1945       str[i] = tolower(str[i]);
1946     }
1947   }
1948   return str;
1949 }
1950
1951 //- GenerateTourneyNumber ----------------------------------------------
1952 int Mamer::GenerateTourneyNumber(void) {
1953   Tourney *t = NULL;
1954   int maxT = 0, used=0, i, count=0;
1955   LinkListIter<Tourney> tourneyIter(tourneyList);
1956   
1957   if(NULL != tourneyList.Head()) {    
1958     while((t = tourneyIter.Next()))
1959       count++;
1960     
1961     for(i=1; i<=count; i++) {
1962       used = 0;
1963       tourneyIter.Reset();
1964       while((t = tourneyIter.Next())) {
1965         if(i == t->number)
1966           used = 1;
1967         if(t->number > maxT)
1968           maxT = t->number;     
1969       }
1970       if(!used) 
1971         return i;
1972     }
1973     return(maxT + 1);
1974   }
1975   
1976   return(1);
1977 }
1978
1979
1980 // $Log: Mamer.cc,v $
1981 // Revision 1.17  1998/09/10 19:57:17  mlong
1982 // lots of little bug fixes and a few new features
1983 //
1984 // Revision 1.16  1998/08/04 21:02:13  mlong
1985 // changes to correct a few bugs including the this->* change that
1986 // correctly uses the function pointers now
1987 //
1988 // Revision 1.15  1998/06/18 18:41:30  mlong
1989 // prepairing for yet another move.
1990 //
1991 // Revision 1.14  1998/06/04 19:55:00  mlong
1992 // quick change to the load config file stuff to
1993 // allow for a commented out line
1994 //
1995 // Revision 1.13  1998/04/29 15:23:19  mlong
1996 // prepairing for the move to daimi
1997 // new sorting routine.
1998 //
1999 // Revision 1.12  1998/04/18 18:46:04  mlong
2000 // fixed delete bug &
2001 // added delete tourney function
2002 //
2003 // Revision 1.11  1998/04/17 00:14:37  mlong
2004 // fixes to the setres working with the Link delete method
2005 //
2006 // Revision 1.7  1997/10/22 19:47:38  mlong
2007 // fixed bug for parsing tells into user and command.
2008 //
2009 // Revision 1.6  1997/10/08 21:03:35  chess
2010 // preparing for move to oracle machine at eworks.
2011 //
2012 // Revision 1.5  1997/05/15 18:27:53  chess
2013 // added Player and TourneyPlayers support
2014 // added HandleGetPlayerInfo & HandleetGameInfo
2015 //
2016 // Revision 1.4  1997/04/13 03:14:35  chess
2017 // commands to do user stats manipulation added
2018 // also TellUser function added to make for easier reporting and bug checking
2019 // also added ParseParams that takes the commands parameter list definition
2020 // and parses out the input from the user to determine if the paramters
2021 // supplied are correct.  If so it then sends those params to the
2022 // command.
2023 //
2024 // Revision 1.3  1997/03/21 15:31:04  moses
2025 // added the cleanup of commands
2026 // added the cleanup of tourneys
2027 // added the mamer shutdown command
2028 //
2029 // Revision 1.2  1996/10/01  20:14:43  moses
2030 // Changes to incorparte the new usage of the command list
2031 //
2032 // Revision 1.1  1996/09/30  20:52:48  moses
2033 // Initial revision
2034 //