Alter Makefile to force 32-bit compile
[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 && !t->IsPaused()) {
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()], p->floatValue); // [HGM] use score to signal att/join
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("pause", "pa", DIRECTOR, "Supresses start of new round.",
1473                                    "d", (USERFP)&Mamer::PauseTourney));
1474
1475     commandList.Append(new Command("resume", "re", DIRECTOR, "Resumes a paused tournament.",
1476                                    "d", (USERFP)&Mamer::ResumeTourney));
1477
1478     commandList.Append(new Command("setcommandlevel", "setcl", VICE, "Set the level required to execute a command.",
1479                                    "wd", (USERFP)&Mamer::SetCommandLevel));
1480
1481     commandList.Append(new Command("setinfo", "si", VICE, "Set a user's finger info.",
1482                                    "Wddddddd", (USERFP)&Mamer::SetInfo));
1483
1484     commandList.Append(new Command("setmanagerlevel", "sml", VICE, "Sets manager's level.",
1485                                    "Wd", (USERFP)&Mamer::SetManagerLevel));
1486
1487     commandList.Append(new Command("setres", "sr", DIRECTOR, "Sets the result of a game.",
1488                                    "dWWi", (USERFP)&Mamer::SetResult));
1489
1490     commandList.Append(new Command("setstat", "ss", VICE, "Sets a specific finger stat.",
1491                                    "Wwd", (USERFP)&Mamer::SetStat));
1492
1493     commandList.Append(new Command("settourneyvar", "stv", DIRECTOR, "Sets a Tourney's Variables.",
1494                                    "dwi", (USERFP)&Mamer::SetTourneyVariable));
1495
1496     commandList.Append(new Command("showcommands", "sc", USER, "List commands and descripts.",
1497                                    "o", (USERFP)&Mamer::ShowCommands));
1498
1499     commandList.Append(new Command("showhelpfile", "shf", USER, "Shows a help file.",
1500                                    "o", (USERFP)&Mamer::ShowHelp));
1501
1502     commandList.Append(new Command("help", "help", USER, "Shows a help file.",
1503                                    "o", (USERFP)&Mamer::ShowHelp));
1504
1505     commandList.Append(new Command("shutdown", "sd", VICE, "Shuts down Mamer.",
1506                                    "", (USERFP)&Mamer::Shutdown));
1507
1508     commandList.Append(new Command("who", "who", USER, "Displays the tournament games.",
1509                                    "d", (USERFP)&Mamer::ListTourneyPlayers));
1510
1511     commandList.Append(new Command("withdraw", "with", USER, "Remove yourself from a tourney.", 
1512                                    "d", (USERFP)&Mamer::RemoveFromTourney));
1513
1514 } //- End of BuildCommandList
1515
1516 //- NextRound -------------------------
1517 void Mamer::NextRound() {
1518   int moreGames=0, moreRounds=1, madeMoreGames=0;
1519   Tourney *t = NULL;
1520   Game *g = NULL;
1521   
1522   LinkListIter<Tourney> tourneyIter(tourneyList);
1523   tourneyIter.Reset();
1524   while((t = tourneyIter.Next())) {
1525     if(t->GetStatus() != CLOSED || t->IsPaused()) continue;
1526     moreRounds = (t->GetRoundsRemaining());
1527     moreGames = 0;
1528     LinkListIter<Game> gameIter(t->gameList);
1529     gameIter.Reset();
1530     while((g = gameIter.Next())) moreGames++;
1531
1532     if(moreGames == 0) {
1533       if(debugLevel >= 10)
1534         cout << "No more games!  Next Round Please!  From Next Round" << endl;
1535       cerr << "No more games!  Next Round Please!  From Next Round" << endl;
1536       if(moreRounds) {
1537         madeMoreGames = t->MakeAssignments();
1538         if(madeMoreGames) 
1539           t->TellThemWhoTheyPlay();
1540         else {    // tourney over!
1541           cerr << "Couldn't make any more games.  End of Tourney.  From Next Round" << endl;
1542           AnnounceTourneyEnd(t);
1543           savePlayerData(t);
1544         }
1545       } else {                  // tourney over!
1546         cerr << "No more rounds.  End of Tourney.  From Next Round" << endl;
1547         AnnounceTourneyEnd(t);
1548         savePlayerData(t);
1549       }
1550     }
1551   }
1552 } //- End of NextRound
1553
1554 //- XServerCom ---------------------------------------------
1555 int Mamer::XServerCom(char *fmt, ...)
1556 {
1557   va_list argptr;
1558   char buffer[1024];
1559   int count;
1560
1561   va_start(argptr, fmt);
1562   count = vsprintf(buffer, fmt, argptr);
1563   write(serverSocket, buffer, strlen(buffer));
1564   va_end(argptr);
1565
1566   /* returns number of elements written */
1567   return (count);
1568 }
1569 //- End of XServerCom
1570
1571 //- TellUser ------------------------------------------------
1572 void Mamer::TellUser(reasons reason, char *name) {
1573   switch (reason) {
1574   case NoPermissions:
1575     XServerCom("qtell %s %s notes: Sorry you do not have permission to do that.\n", name, username);
1576     break;
1577   case BadCommand:
1578     XServerCom("qtell %s %s notes: Command not found.\n", name, username);
1579     break;
1580   default:
1581     break;
1582   }
1583 }//- End of TellUser
1584
1585 //- TellUser ------------------------------------------------
1586 void Mamer::TellUser(reasons reason, char *name, int number) {
1587   switch (reason) {
1588   case JoinedTourney:
1589     switch (number) {
1590     case 0:
1591       XServerCom("qtell %s %s notes: %s\n", name, username, 
1592                  "Can not join\\nYour rating does not fit into current limits. <check tourney vars>");  
1593       break;
1594     case 1:
1595       XServerCom("qtell %s %s notes: %s\n", name, username, "You joined the tournament.");  
1596       break;
1597     case 2:
1598       XServerCom("qtell %s %s notes: %s\n", name, username, "You are already in this tourney.");
1599       break;
1600     case 3:
1601       XServerCom("qtell %s %s notes: %s\n", name, username, "You can not join.  Tourney is not open.");  
1602       break;
1603     default:
1604       break;
1605     }
1606     break;
1607   case NotEnoughPlayers:
1608     XServerCom("qtell %s %s notes: Tourney#%d %s\n", name, username, number, "does not have enough players.");
1609     break;
1610   case NoPlayers:
1611     XServerCom("qtell %s %s notes: Tourney#%d %s\n", name, username, number, "has no players.");
1612     break;
1613   case WillKeepTourney:
1614     XServerCom("qtell %s %s notes: Tourney#%d %s\n", name, username, number, "will be kept.");
1615     break;
1616   case NotKeepTourney:
1617     XServerCom("qtell %s %s notes: Tourney#%d %s\n", name, username, number, "will not be kept.");
1618     break;
1619   case TourneyNotFound:
1620     XServerCom("qtell %s %s notes: %s%d %s\n", name, username, "Tourney #", number, "not found.");
1621     break;
1622   case NotFound:
1623     XServerCom("qtell %s %s notes: %s%d\n", name, username, "Player not found in tourney #", number);
1624     break;
1625   case GameResultNotFound:
1626     XServerCom("qtell %s %s notes: %s%d\n", name, username, "Can not set result to ", number);
1627     break;
1628   case NoPermissions:
1629     XServerCom("qtell %s %s notes: You don't have change permissions for tourney #%d.\n", name, username, number);
1630     break;
1631   case TourneyNotNew:
1632     XServerCom("qtell %s %s notes: %s  %s%d %s\n", name, username, "Can not do that right now.", 
1633                "Tourney #", number, "is not new.");
1634     break;
1635   case TourneyNotOpen:
1636     XServerCom("qtell %s %s notes: %s  %s%d %s\n", name, username, "Can not do that right now.", 
1637                "Tourney #", number, "is not open.");
1638     break;
1639   case TourneyNotClosed:
1640     XServerCom("qtell %s %s notes: %s  %s%d %s\n", name, username, "Can not do that right now.", 
1641                "Tourney #", number, "is not closed.");
1642     break;
1643   case TourneyDone:
1644     XServerCom("qtell %s %s notes: %s  %s%d %s\n", name, username, "Can not do that anymore.", 
1645                "Tourney #", number, "is done.");
1646     break;
1647   case TourneyClosed:
1648     XServerCom("qtell %s %s notes: %s  %s%d %s\n", name, username, "Can not do that anymore.", 
1649                "Tourney #", number, "is closed.");
1650     break;
1651   case TourneyDeleted:
1652     XServerCom("qtell %s %s Notes: %s %s%d %s\n", name, username, "\\n", "Tourney #",
1653                number, " has been deleted.");
1654     break;    
1655   default:
1656     break;
1657   }
1658 }//- End of TellUser
1659
1660 //- TellUser ------------------------------------------------
1661 void Mamer::TellUser(Command *comm, char *name) {
1662   char line[512];
1663   int i, length=strlen(comm->parameterList);
1664
1665   sprintf(line, "qtell %s %s notes: Usage: %s ", name, username, comm->GetCommandName());
1666
1667   for(i=0; i<length; i++) {
1668     switch (comm->parameterList[i]) {
1669     case 'w':
1670       strcat(line, "<word> ");
1671       break;
1672     case 'o':
1673       strcat(line, "<optional word> ");
1674       break;
1675     case 'd':
1676       strcat(line, "<integer> ");
1677       break;
1678     case 'p':
1679       strcat(line, "<optional int> ");
1680       break;
1681     case 'i':
1682       strcat(line, "<word or int> ");
1683       break;
1684     case 'n':
1685       strcat(line, "<optional word or int> ");
1686       break;
1687     case 's':
1688       strcat(line, "<string> ");
1689       break;
1690     case 't':
1691       strcat(line, "<optional string> ");
1692       break;
1693     default:
1694       break;
1695     }
1696   }
1697   strcat(line, "\n");
1698   write(serverSocket, line, strlen(line));
1699 }//- End of TellUser
1700
1701 //- TellUser ------------------------------------------------
1702 void Mamer::TellUser(reasons reason, char *name, char *request) {
1703   switch (reason) {
1704   case NotFound:
1705     XServerCom("qtell %s %s notes: Sorry %s is not found.\n", name, username, request);
1706     break;
1707   case GenericTell:
1708     XServerCom("qtell %s %s notes: %s\n", name, username, request);
1709     break;
1710   case ChangedInfo:
1711     XServerCom("qtell %s %s notes: Changed the info for %s.\n", name, username, request);
1712     break;
1713   case GameResultNotFound:
1714     XServerCom("qtell %s %s notes: %s %s\n", name, username, "Can not set result to", request);
1715     break;
1716   case MultiCommand:
1717     XServerCom("qtell %s %s notes: Ambiguous Command Matches:\\n %s\n", name, username, request);
1718     break;
1719   default:
1720     break;
1721   }
1722 }//- End of TellUser
1723
1724 //- TellUser ------------------------------------------------
1725 void Mamer::TellUser(reasons reason, char *name, char *who, char *which, int new_value) {
1726   switch (reason) {
1727   case ChangedInfo:
1728     XServerCom("qtell %s %s notes: Changed the %s stat for %s to %d.\n", name, username, which, who, new_value);
1729     break;  
1730   case GameResultSet:
1731     switch (new_value) {
1732     case 1:
1733       XServerCom("qtell %s %s notes: The game %s(w) vs. %s(b) has been set to 1-0\n", name, username, who, which);
1734       break;
1735     case 0:
1736       XServerCom("qtell %s %s notes: The game %s(w) vs. %s(b) has been set to 0-1\n", name, username, who, which);
1737       break;
1738     default:
1739       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);
1740       break;
1741     }
1742     break;
1743   default:
1744     break;
1745   }
1746 }//- End of TellUser
1747
1748 //- TellUser ------------------------------------------------
1749 void Mamer::TellUser(reasons reason, char *name, char *which, char *new_value) {
1750   switch (reason) {
1751   case CanNotChange:
1752     XServerCom("qtell %s %s notes: Can not change the %s var to %s.\n", name, username, which, new_value);
1753     break;
1754   case ChangedInfo:
1755    XServerCom("qtell %s %s notes: Changed %s to %s.\n", name, username, which, new_value);
1756     break;  
1757   default:
1758     break;
1759   }
1760 }//- End of TellUser
1761
1762
1763 //- TellUser ------------------------------------------------
1764 void Mamer::TellUser(reasons reason, char *name, char *uname, int new_value) {
1765   switch (reason) {
1766   case ChangedManagerLevel:
1767     XServerCom("qtell %s %s notes: %s's Manager Level has been changed to %d\n", name, username, uname,new_value);
1768     break;
1769   case ChangedCommandLevel:
1770     XServerCom("qtell %s %s notes: The %s command's manager Level has been changed to %d\n",name,username,uname, new_value);
1771     break;
1772   case PlayerRemoved:
1773     XServerCom("qtell %s %s notes: %s Has been removed from tourney #%i\n", name, username, uname, new_value);
1774     break;
1775   case NotFound:
1776     XServerCom("qtell %s %s notes: %s Is not found in tourney #%i\n", name, username, uname, new_value);
1777     break;
1778   case ChangedAbuse:
1779     XServerCom("qtell %s %s notes: %s's Chaos Points have been changed to %d\n",name, username, uname, new_value);
1780     break;
1781   case CanNotChange:
1782     XServerCom("qtell %s %s notes: Can Not Change the %s stat to %d.\n", name, username, uname, new_value);
1783     break;
1784   case ChangedInfo:
1785     XServerCom("qtell %s %s notes: Changed %s to %d.\n", name, username, uname, new_value);
1786     break;  
1787   default:
1788     break;
1789   }
1790 }//- End of TellUser
1791
1792 //- ParseParams ----------------------------------------------
1793 int Mamer::ParseParams(Command *comm, char *parameters) {
1794   int i, parlen;
1795   int paramLower;
1796   char c;
1797
1798   for (i = 0; i < MAXNUMPARAMS; i++)
1799     comm->params[i].type = TYPE_NULL;       /* Set all parameters to NULL */
1800   parlen = strlen(comm->parameterList);
1801   parameters = eatWhite(parameters);      /* remove and spaces before the command */
1802   parameters = eatWord(parameters);       /* remove the command itself */
1803   for (i = 0; i < parlen; i++) {
1804     c = comm->parameterList[i];
1805     if (isupper(c)) {
1806       paramLower = 0;
1807       c = tolower(c);
1808     } else {
1809       paramLower = 1;
1810     }
1811     switch (c) {
1812     case 'w':
1813     case 'o':                   /* word or optional word */
1814       parameters = eatWhite(parameters);
1815       if (!*parameters)
1816         return (c == 'o' ? COM_OK : COM_BADPARAMETERS);
1817       comm->params[i].val.word = parameters;
1818       comm->params[i].type = TYPE_WORD;
1819       parameters = eatWord(parameters);
1820       if (*parameters != '\0') {
1821         *parameters = '\0';
1822         parameters++;
1823       }
1824       if (paramLower)
1825         stolower(comm->params[i].val.word);
1826       break;
1827
1828     case 'd':
1829     case 'p':                   /* optional or required integer */
1830       parameters = eatWhite(parameters);
1831       if (!*parameters)
1832         return (c == 'p' ? COM_OK : COM_BADPARAMETERS);
1833       if (sscanf(parameters, "%d", &comm->params[i].val.integer) != 1)
1834         return COM_BADPARAMETERS;
1835       comm->params[i].type = TYPE_INT;
1836       parameters = eatWord(parameters);
1837       if (*parameters != '\0') {
1838         *parameters = '\0';
1839         parameters++;
1840       }
1841       break;
1842
1843     case 'i':
1844     case 'n':                   /* optional or required word or integer */
1845       parameters = eatWhite(parameters);
1846       if (!*parameters)
1847         return (c == 'n' ? COM_OK : COM_BADPARAMETERS);
1848       if (sscanf(parameters, "%d", &comm->params[i].val.integer) != 1) {
1849         comm->params[i].val.word = parameters;
1850         comm->params[i].type = TYPE_WORD;
1851       } else {
1852         comm->params[i].type = TYPE_INT;
1853       }
1854       parameters = eatWord(parameters);
1855       if (*parameters != '\0') {
1856         *parameters = '\0';
1857         parameters++;
1858       }
1859       if (comm->params[i].type == TYPE_WORD)
1860         if (paramLower)
1861           stolower(comm->params[i].val.word);
1862       break;
1863
1864     case 's':
1865     case 't':                   /* optional or required string to end */
1866       if (!*parameters)
1867         return (c == 't' ? COM_OK : COM_BADPARAMETERS);
1868       comm->params[i].val.string = parameters;
1869       comm->params[i].type = TYPE_STRING;
1870       while (*parameters)
1871         parameters = nextWord(parameters);
1872       if (paramLower)
1873         stolower(comm->params[i].val.string);
1874       break;
1875     }
1876   }
1877   if (*parameters)
1878     return COM_BADPARAMETERS;
1879   else
1880     return COM_OK;
1881 } //- End ParseParams ------------------
1882
1883 //- isWhiteSpace -------------------------------------------
1884 int Mamer::isWhiteSpace (int c) {
1885   if ((c < ' ') || (c == '\b') || (c == '\n') ||
1886       (c == '\t') || (c == ' ')) {      /* white */
1887     return 1;
1888   } else {
1889     return 0;
1890   }
1891 } //- End isWhiteSpace -------
1892
1893 //- getWord ------------------------------------------------
1894 char *Mamer::getWord (char *str) {
1895   int i;
1896   static char word[MAX_WORD_SIZE];
1897
1898   i = 0;
1899   while (*str && !isWhiteSpace(*str)) {
1900     word[i] = *str;
1901     str++;
1902     i++;
1903     if (i == MAX_WORD_SIZE) {
1904       i = i - 1;
1905       break;
1906     }
1907   }
1908   word[i] = '\0';
1909   return word;
1910 } //- End getWord -------------
1911
1912 //- eatWord -------------------------------------------
1913 char *Mamer::eatWord (char *str) {
1914   while (*str && !isWhiteSpace(*str))
1915     str++;
1916   return str;
1917 } //- eatWord ----
1918
1919 //- eatWhite ------------------------------------------
1920 char *Mamer::eatWhite (char *str) {
1921   while (*str && isWhiteSpace(*str))
1922     str++;
1923   return str;
1924 } //- eatWhite --------
1925
1926 //- eatTailWhite -------------------------------------------
1927 char *Mamer::eatTailWhite (char *str) {
1928   int len;
1929   if (str == NULL)
1930     return NULL;
1931
1932   len = strlen(str);
1933   while (len > 0 && isWhiteSpace(str[len - 1]))
1934     len--;
1935   str[len] = '\0';
1936   return (str);
1937 } //- End of eatTailWhite -----------
1938
1939 //- nextWord -----------------------------------------------
1940 char *Mamer::nextWord(char *str) {
1941   return eatWhite(eatWord(str));
1942 } //- End of nextWord
1943
1944 char *Mamer::stolower(char *str) {
1945   int i;
1946
1947   if (!str)
1948     return NULL;
1949   for (i = 0; str[i]; i++) {
1950     if (isupper(str[i])) {
1951       str[i] = tolower(str[i]);
1952     }
1953   }
1954   return str;
1955 }
1956
1957 //- GenerateTourneyNumber ----------------------------------------------
1958 int Mamer::GenerateTourneyNumber(void) {
1959   Tourney *t = NULL;
1960   int maxT = 0, used=0, i, count=0;
1961   LinkListIter<Tourney> tourneyIter(tourneyList);
1962   
1963   if(NULL != tourneyList.Head()) {    
1964     while((t = tourneyIter.Next()))
1965       count++;
1966     
1967     for(i=1; i<=count; i++) {
1968       used = 0;
1969       tourneyIter.Reset();
1970       while((t = tourneyIter.Next())) {
1971         if(i == t->number)
1972           used = 1;
1973         if(t->number > maxT)
1974           maxT = t->number;     
1975       }
1976       if(!used) 
1977         return i;
1978     }
1979     return(maxT + 1);
1980   }
1981   
1982   return(1);
1983 }
1984
1985
1986 // $Log: Mamer.cc,v $
1987 // Revision 1.17  1998/09/10 19:57:17  mlong
1988 // lots of little bug fixes and a few new features
1989 //
1990 // Revision 1.16  1998/08/04 21:02:13  mlong
1991 // changes to correct a few bugs including the this->* change that
1992 // correctly uses the function pointers now
1993 //
1994 // Revision 1.15  1998/06/18 18:41:30  mlong
1995 // prepairing for yet another move.
1996 //
1997 // Revision 1.14  1998/06/04 19:55:00  mlong
1998 // quick change to the load config file stuff to
1999 // allow for a commented out line
2000 //
2001 // Revision 1.13  1998/04/29 15:23:19  mlong
2002 // prepairing for the move to daimi
2003 // new sorting routine.
2004 //
2005 // Revision 1.12  1998/04/18 18:46:04  mlong
2006 // fixed delete bug &
2007 // added delete tourney function
2008 //
2009 // Revision 1.11  1998/04/17 00:14:37  mlong
2010 // fixes to the setres working with the Link delete method
2011 //
2012 // Revision 1.7  1997/10/22 19:47:38  mlong
2013 // fixed bug for parsing tells into user and command.
2014 //
2015 // Revision 1.6  1997/10/08 21:03:35  chess
2016 // preparing for move to oracle machine at eworks.
2017 //
2018 // Revision 1.5  1997/05/15 18:27:53  chess
2019 // added Player and TourneyPlayers support
2020 // added HandleGetPlayerInfo & HandleetGameInfo
2021 //
2022 // Revision 1.4  1997/04/13 03:14:35  chess
2023 // commands to do user stats manipulation added
2024 // also TellUser function added to make for easier reporting and bug checking
2025 // also added ParseParams that takes the commands parameter list definition
2026 // and parses out the input from the user to determine if the paramters
2027 // supplied are correct.  If so it then sends those params to the
2028 // command.
2029 //
2030 // Revision 1.3  1997/03/21 15:31:04  moses
2031 // added the cleanup of commands
2032 // added the cleanup of tourneys
2033 // added the mamer shutdown command
2034 //
2035 // Revision 1.2  1996/10/01  20:14:43  moses
2036 // Changes to incorparte the new usage of the command list
2037 //
2038 // Revision 1.1  1996/09/30  20:52:48  moses
2039 // Initial revision
2040 //