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