Fix printing of date with rating
[capablanca.git] / lasker-2.2.3 / src / comproc.c
1 /*
2    Copyright (c) 1993 Richard V. Nash.
3    Copyright (c) 2000 Dan Papasian
4    Copyright (C) Andrew Tridgell 2002
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22 #include "includes.h"
23
24 const int none = 0;
25 const int blitz_rat = 1;
26 const int std_rat = 2;
27 const int wild_rat = 3;
28 const int light_rat = 4;
29 const int bug_rat = 5;
30
31 int com_more(int p, param_list param)
32 {
33         pmore_text(p);
34         return COM_OK;
35 }
36
37 int com_quit(int p, param_list param)
38 {
39         struct player *pp = &player_globals.parray[p];
40
41         /* Examined games are killed on logout */
42         if ((pp->game >= 0) && 
43             ((game_globals.garray[pp->game].status != GAME_EXAMINE) && 
44              (game_globals.garray[pp->game].status != GAME_SETUP))) {
45                 pprintf(p, "You can't quit while you are playing a game.\nType 'resign' to resign the game, or you can request an abort with 'abort'.\n");
46                 return COM_OK;
47         }
48
49         psend_logoutfile(p, MESS_DIR, MESS_LOGOUT);
50         return COM_LOGOUT;
51 }
52
53 int com_set(int p, param_list param)
54 {
55   int result;
56   int which;
57   char *val;
58
59   if (param[1].type == TYPE_NULL)
60     val = NULL;
61   else
62     val = param[1].val.string;
63   result = var_set(p, param[0].val.word, val, &which);
64   switch (result) {
65   case VAR_OK:
66     break;
67   case VAR_BADVAL:
68     pprintf(p, "Bad value given for variable %s.\n", param[0].val.word);
69     break;
70   case VAR_NOSUCH:
71     pprintf(p, "No such variable name %s.\n", param[0].val.word);
72     break;
73   case VAR_AMBIGUOUS:
74     pprintf(p, "Ambiguous variable name %s.\n", param[0].val.word);
75     break;
76   }
77   /* player_save(p); */
78   return COM_OK;
79 }
80
81 int FindPlayer(int p, char* name, int *p1, int *connected)
82 {
83   *p1 = player_search(p, name);
84   if (*p1 == 0)
85     return 0;
86   if (*p1 < 0) {                /* player had to be connected and will be
87                            removed later */
88     *connected = 0;
89     *p1 = (-*p1) - 1;
90   } else {
91     *connected = 1;
92     *p1 = *p1 - 1;
93   }
94   return 1;
95 }
96
97 static void com_stats_andify(int *numbers, int howmany, char *dest)
98 {
99   char tmp[10];
100
101   *dest = '\0';
102   while (howmany--) {
103     sprintf(tmp, "%d", numbers[howmany]);
104     strcat(dest, tmp);
105     if (howmany > 1)
106       sprintf(tmp, ", ");
107     else if (howmany == 1)
108       sprintf(tmp, " and ");
109     else
110       sprintf(tmp, ".\n");
111     strcat(dest, tmp);
112   }
113   return;
114 }
115
116 static void com_stats_rating(char *hdr, struct statistics * stats, char *dest, long now)
117 {
118   char tmp[100];
119
120   *dest = 0;
121
122   if (stats->num == 0) return;
123
124   sprintf(dest, "%-10s%4s    %5.1f   %4d   %4d   %4d   %4d", hdr,
125           ratstr(stats->rating), current_sterr(stats->sterr, now-stats->ltime),
126           stats->win, stats->los, stats->dra, stats->num);
127   if (stats->whenbest) {
128     time_t besttime = stats->whenbest; // [HGM] time_t could have larger size than int, so don't pass localtime a pointer to it
129     sprintf(tmp, "   %d", stats->best);
130     strcat(dest, tmp);
131     strftime(tmp, sizeof(tmp), " (%d-%b-%Y)", localtime(&besttime));
132     strcat(dest, tmp);
133   }
134   strcat(dest, "\n");
135   return;
136 }
137
138 int com_stats(int p, param_list param)
139 {
140   int g, i;
141   time_t t;
142   int p1, connected;
143   char line[255], tmp[255], tmp2[255];
144   int numbers[MAX_OBSERVE > MAX_SIMUL ? MAX_OBSERVE : MAX_SIMUL];
145   int onTime;
146   int showRatingsFlag, showNotesFlag;
147   int showCommentsFlag = 0;
148   long now;
149
150   showRatingsFlag = showNotesFlag = 1; /* everything on by default */
151
152   if (param[0].type == TYPE_WORD) {
153     if (!FindPlayer(p, param[0].val.word, &p1, &connected))
154       return COM_OK;
155     if (param[1].type == TYPE_WORD) { /* optional second parameter */
156       char *c = param[1].val.word;
157        showRatingsFlag = showNotesFlag = 0;
158       while (*c != '\0') {
159         if (*c == 'r') { showRatingsFlag = 1; c++; }
160         else if (*c == 'n') { showNotesFlag = 1; c++; }
161         else if ((*c == 'c') && check_admin(p, ADMIN_ADMIN)) {
162           showCommentsFlag = 1; c++; }
163         else {
164           if (!connected)
165             player_remove(p1);
166           return COM_BADPARAMETERS;
167         }
168       }
169     }
170   } else {
171       p1 = p;
172       connected = 1;
173   }
174
175   strcpy(tmp2, player_globals.parray[p1].name);
176   AddPlayerLists(p1, tmp2);
177   tmp2[17] = '\0';
178   sprintf(line, "\nStatistics for %-17s", tmp2);
179   if ((connected) && (player_globals.parray[p1].status == PLAYER_PROMPT)) {
180     sprintf(tmp, "On for: %s", hms_desc(player_ontime(p1)));
181     strcat(line, tmp);
182     sprintf(tmp, "   Idle: %s\n", hms_desc(player_idle(p1)));
183   } else {
184     if ((t = player_lastdisconnect(p1)))
185       sprintf(tmp, "(Last disconnected %s):\n", strltime(&t));
186     else
187       sprintf(tmp, "(Never connected.)\n");
188   }
189   strcat(line, tmp);
190   pprintf(p, "%s", line);
191   if (((player_globals.parray[p1].simul_info) != NULL) && (player_globals.parray[p1].simul_info->numBoards)) {
192     for (i = 0, t = 0; i < player_globals.parray[p1].simul_info->numBoards; i++) {
193       if ((numbers[t] = player_globals.parray[p1].simul_info->boards[i] + 1) != 0)
194         t++;
195     }
196     pprintf(p, "%s is giving a simul: game%s ", player_globals.parray[p1].name, ((t > 1) ? "s" : ""));
197     com_stats_andify(numbers, t, tmp);
198     pprintf(p, tmp);
199   } else if (player_globals.parray[p1].game >= 0) {
200     g = player_globals.parray[p1].game;
201     if (game_globals.garray[g].status == GAME_EXAMINE) {
202       pprintf(p, "(Examining game %d: %s vs. %s)\n", g + 1, 
203             game_globals.garray[g].white_name, game_globals.garray[g].black_name);
204     } else if (game_globals.garray[g].status == GAME_SETUP) {
205       pprintf(p, "(Setting up game %d: %s vs. %s)\n", g + 1,
206             game_globals.garray[g].white_name, game_globals.garray[g].black_name);
207     } else {
208       pprintf(p, "(playing game %d: %s vs. %s)\n", g + 1,
209             player_globals.parray[game_globals.garray[g].white].name, player_globals.parray[game_globals.garray[g].black].name);
210       if (game_globals.garray[g].link >= 0) {
211         pprintf(p, "(partner is playing game %d: %s vs. %s)\n", game_globals.garray[g].link + 1,
212             player_globals.parray[game_globals.garray[game_globals.garray[g].link].white].name,
213             player_globals.parray[game_globals.garray[game_globals.garray[g].link].black].name);
214       }
215     }
216   }
217   if (player_globals.parray[p1].num_observe) {
218     for (i = 0, t = 0; i < player_globals.parray[p1].num_observe; i++) {
219       g = player_globals.parray[p1].observe_list[i];
220       if ((g != -1) && (check_admin(p, ADMIN_ADMIN) || (game_globals.garray[g].private == 0)))
221         numbers[t++] = g + 1;
222     }
223     if (t) {
224       pprintf(p, "%s is observing game%s ", player_globals.parray[p1].name, ((t > 1) ? "s" : ""));
225       com_stats_andify(numbers, t, tmp);
226       pprintf(p, tmp);
227     }
228   }
229   if (player_globals.parray[p1].busy != NULL) {
230     pprintf(p, "(%s %s)\n", player_globals.parray[p1].name, player_globals.parray[p1].busy);
231   }
232   if (!CheckPFlag(p1, PFLAG_REG)) {
233     pprintf(p, "%s is NOT a registered player.\n\n", player_globals.parray[p1].name);
234   } else {
235     if (showRatingsFlag > 0) {
236       now = time(NULL);
237       pprintf(p, "\n         rating     RD     win   loss   draw  total   best\n");
238       com_stats_rating("Blitz", &player_globals.parray[p1].b_stats, tmp, now);
239       if (*tmp) pprintf(p, tmp);
240       com_stats_rating("Standard", &player_globals.parray[p1].s_stats, tmp, now);
241       if (*tmp) pprintf(p, tmp);
242       com_stats_rating("Lightning", &player_globals.parray[p1].l_stats, tmp, now);
243       if (*tmp) pprintf(p, tmp);
244       com_stats_rating("Wild", &player_globals.parray[p1].w_stats, tmp, now);
245       if (*tmp) pprintf(p, tmp);
246       com_stats_rating("Bughouse", &player_globals.parray[p1].bug_stats, tmp, now);
247       if (*tmp) pprintf(p, tmp);
248     }
249   }
250   pprintf(p, "\n");
251   if (player_globals.parray[p1].adminLevel > 0) {
252     pprintf(p, "Admin Level: ");
253     switch (5*(player_globals.parray[p1].adminLevel/5)) {
254     case 5:
255       pprintf(p, "Authorized Helper Person\n");
256       break;
257     case 10:
258       pprintf(p, "Administrator\n");
259       break;
260     case 15:
261       pprintf(p, "Help File Librarian/Administrator\n");
262       break;
263     case 20:
264       pprintf(p, "Master Administrator\n");
265       break;
266     case 50:
267       pprintf(p, "Master Help File Librarian/Administrator\n");
268       break;
269     case 60:
270       pprintf(p, "Assistant Super User\n");
271       break;
272     case 100:
273       pprintf(p, "Super User\n");
274       break;
275     default:
276       pprintf(p, "%d\n", player_globals.parray[p1].adminLevel);
277       break;
278     }
279   }
280
281   if (check_admin(p, 1) && !CheckPFlag(p, PFLAG_HIDEINFO)) {
282     pprintf(p, "Full Name  : %s\n", (player_globals.parray[p1].fullName ? player_globals.parray[p1].fullName : "(none)"));
283     pprintf(p, "Address    : %s\n", (player_globals.parray[p1].emailAddress ? player_globals.parray[p1].emailAddress : "(none)"));
284     pprintf(p, "Host       : %s\n",
285             dotQuad(connected ? player_globals.parray[p1].thisHost : player_globals.parray[p1].lastHost));
286     if (CheckPFlag(p1, PFLAG_REG))
287       if (player_globals.parray[p1].num_comments)
288         pprintf(p, "Comments   : %d\n", player_globals.parray[p1].num_comments);
289   } else if ((p1 == p) && CheckPFlag(p1, PFLAG_REG))
290     pprintf(p, "Address    : %s\n", (player_globals.parray[p1].emailAddress ? player_globals.parray[p1].emailAddress : "(none)"));
291
292   if (player_globals.parray[p1].socket != -1) {
293     pprintf(p, "\nTimeseal: %s\n", net_globals.con[player_globals.parray[p1].socket]->timeseal ? "yes" : "no");
294   }
295   
296   if (connected && CheckPFlag(p1, PFLAG_REG)
297       && (p==p1 || (check_admin(p, 1) && !CheckPFlag(p, PFLAG_HIDEINFO)))) {
298     char *timeToStr = ctime((time_t *) &player_globals.parray[p1].timeOfReg);
299
300     timeToStr[strlen(timeToStr)-1]='\0';
301     pprintf(p, "\n");
302     onTime = (time(0) - player_globals.parray[p1].logon_time) + player_globals.parray[p1].totalTime;
303
304     pprintf(p, "Total time on-line: %s\n", hms_desc(onTime) );
305     pprintf(p, "%% of life on-line:  %3.1f  (since %s)\n", 
306            (double)((onTime*100)/(double)(time(0)-player_globals.parray[p1].timeOfReg)),
307            timeToStr);
308   }
309
310   if (player_globals.parray[p1].num_plan && (showNotesFlag > 0)) {
311     pprintf(p, "\n");
312     for (i = 0; i < player_globals.parray[p1].num_plan; i++)
313       pprintf(p, "%2d: %s\n", i + 1, (player_globals.parray[p1].planLines[i] != NULL) ? player_globals.parray[p1].planLines[i] : "");
314   }
315   if (showCommentsFlag) {
316     pprintf(p, "\n");
317     pprintf(p, "Comments for %s:\n",player_globals.parray[p1].name);
318     player_show_comments(p, p1); 
319   }
320   if (!connected)
321     player_remove(p1);
322   return COM_OK;
323 }
324
325 int com_password(int p, param_list param)
326 {
327         struct player *pp = &player_globals.parray[p];
328         char *oldpassword = param[0].val.word;
329         char *newpassword = param[1].val.word;
330         char salt[3];
331
332         if (!CheckPFlag(p, PFLAG_REG)) {
333                 pprintf(p, "Setting a password is only for registered players.\n");
334                 return COM_OK;
335         }
336         if (pp->passwd) {
337                 salt[0] = pp->passwd[3];
338                 salt[1] = pp->passwd[4];
339                 salt[2] = '\0';
340                 if (strcmp(chessd_crypt(oldpassword,salt), pp->passwd)) {
341                         pprintf(p, "Incorrect password, password not changed!\n");
342                         return COM_OK;
343                 }
344                 free(pp->passwd);
345                 pp->passwd = NULL;
346         }
347         salt[0] = 'a' + random() % 26;
348         salt[1] = 'a' + random() % 26;
349         salt[2] = '\0';
350         pp->passwd = strdup(chessd_crypt(newpassword,salt));
351         pprintf(p, "Password changed to \"%s\".\n", newpassword);
352         return COM_OK;
353 }
354
355 int com_uptime(int p, param_list param)
356 {
357   time_t uptime = time(0) - command_globals.startuptime;
358   int days  = (uptime / (60*60*24));
359   int hours = ((uptime % (60*60*24)) / (60*60));
360   int mins  = (((uptime % (60*60*24)) % (60*60)) / 60); 
361   int secs  = (((uptime % (60*60*24)) % (60*60)) % 60);
362
363   pprintf(p, "Server location: %s   Server version : %s\n", 
364           config_get_tmp("SERVER_HOSTNAME"), VERS_NUM);
365   pprintf(p, "The server has been up since %s.\n", strltime(&command_globals.startuptime));
366
367   pprintf(p,"Up for");
368
369   if(days)
370     pprintf(p," %d day%s", days, (days == 1) ? "" : "s");
371
372   if(hours)
373     pprintf(p," %d hour%s", hours, (hours == 1) ? "" : "s");
374
375   if(mins)
376     pprintf(p," %d minute%s", mins, (mins == 1) ? "" : "s");
377
378   if(secs)
379     pprintf(p," %d second%s", secs, (secs == 1) ? "" : "s");
380
381   pprintf(p,".\n");
382
383   pprintf(p, "\nPlayer limit: %d\n", config_get_int("MAX_PLAYER", DEFAULT_MAX_PLAYER));
384   pprintf(p, "\nThere are currently %d players, with a high of %d since last restart.\n", player_count(1), command_globals.player_high);
385   pprintf(p, "There are currently %d games, with a high of %d since last restart.\n", game_count(), command_globals.game_high);
386   pprintf(p, "\nCompiled on %s\n", COMP_DATE);
387   return COM_OK;
388 }
389
390 int com_date(int p, param_list param)
391 {
392         time_t t = time(0);
393         pprintf(p, "Local time     - %s\n", strltime(&t));
394         pprintf(p, "Greenwich time - %s\n", strgtime(&t));
395         return COM_OK;
396 }
397
398 static const char *inout_string[] = {
399   "login", "logout"
400 };
401
402 static int plogins(int p, char *fname)
403 {
404         FILE *fp;
405         int inout, registered;
406         time_t thetime;
407         char loginName[MAX_LOGIN_NAME + 1];
408         char ipstr[20];
409         
410         fp = fopen_p("%s", "r", fname);
411         if (!fp) {
412                 pprintf(p, "Sorry, no login information available.\n");
413                 return COM_OK;
414         }
415         while (!feof(fp)) {
416                 unsigned t;
417                 if (fscanf(fp, "%d %s %u %d %s\n", &inout, loginName, &t,
418                            &registered, ipstr) != 5) {
419                         d_printf( "CHESSD: Error in login info format. %s\n", 
420                                 fname);
421                         fclose(fp);
422                         return COM_OK;
423                 }
424                 thetime = (time_t)t;
425                 pprintf(p, "%s: %-17s %-6s", strltime(&thetime), loginName,
426                         inout_string[inout]);
427                 if (check_admin(p, 1) && !CheckPFlag(p, PFLAG_HIDEINFO)) {
428                         pprintf(p, " from %s\n", ipstr);
429                 } else
430                         pprintf(p, "\n");
431         }
432         fclose(fp);
433         return COM_OK;
434 }
435
436 int com_llogons(int p, param_list param)
437 {
438         int result;
439         if (!CheckPFlag(p, PFLAG_REG)) {
440                 pprintf(p,"Sorry, guest users may not use this command\n");
441                 return COM_OK;
442         }
443         result = plogins(p, STATS_DIR "/" STATS_LOGONS);
444         return result;
445 }
446
447 int com_logons(int p, param_list param)
448 {
449         struct player *pp = &player_globals.parray[p];
450         char fname[MAX_FILENAME_SIZE];
451
452         if (param[0].type == TYPE_WORD) {
453                 int p1, connected;
454                 if (!FindPlayer(p, param[0].val.word, &p1, &connected))
455                         return COM_OK;
456                 sprintf(fname, "%s/player_data/%c/%s.%s", 
457                         STATS_DIR, 
458                         player_globals.parray[p1].login[0], 
459                         player_globals.parray[p1].login, STATS_LOGONS);
460                 if (!connected)
461                         player_remove(p1);
462         } else {
463                 sprintf(fname, "%s/player_data/%c/%s.%s", 
464                         STATS_DIR, 
465                         pp->login[0], 
466                         pp->login, 
467                         STATS_LOGONS);
468         }
469         return plogins(p, fname);
470 }
471
472 #define WHO_OPEN 0x01
473 #define WHO_CLOSED 0x02
474 #define WHO_RATED 0x04
475 #define WHO_UNRATED 0x08
476 #define WHO_FREE 0x10
477 #define WHO_PLAYING 0x20
478 #define WHO_REGISTERED 0x40
479 #define WHO_UNREGISTERED 0x80
480 #define WHO_BUGTEAM 0x100
481
482 #define WHO_ALL 0xff
483
484 void AddPlayerLists (int p1, char *ptmp)
485 {
486         if (check_admin(p1, ADMIN_ADMIN) && CheckPFlag(p1, PFLAG_ADMINLIGHT))
487                 strcat(ptmp, "(*)");
488         if (in_list(p1, L_COMPUTER, player_globals.parray[p1].name))
489                 strcat(ptmp, "(C)");
490         if (in_list(p1, L_FM, player_globals.parray[p1].name))
491                 strcat(ptmp, "(FM)");
492         if (in_list(p1, L_IM, player_globals.parray[p1].name))
493                 strcat(ptmp, "(IM)");
494         if (in_list(p1, L_GM, player_globals.parray[p1].name))
495                 strcat(ptmp, "(GM)");
496         if (in_list(p1, L_WGM, player_globals.parray[p1].name))
497                 strcat(ptmp, "(WGM)");
498         if (in_list(p1, L_TD, player_globals.parray[p1].name))
499                 strcat(ptmp, "(TD)");
500         if (in_list(p1, L_TEAMS, player_globals.parray[p1].name))
501                 strcat(ptmp, "(T)");
502         if (in_list(p1, L_BLIND, player_globals.parray[p1].name))
503                 strcat(ptmp, "(B)");
504 }
505
506 static void who_terse(int p, int num, int *plist, int type)
507 {
508   struct player *pp = &player_globals.parray[p];
509   char ptmp[80 + 20];           /* for highlight */
510   multicol *m = multicol_start(player_globals.parray_size);
511   int i;
512   int p1;
513   int rat = 0;
514
515   /* altered DAV 3/15/95 */
516
517   for (i = 0; i < num; i++) {
518     p1 = plist[i];
519
520     if (type == blitz_rat)
521       rat = player_globals.parray[p1].b_stats.rating;
522     else if (type == wild_rat)
523       rat = player_globals.parray[p1].w_stats.rating;
524     else if (type == std_rat)
525       rat = player_globals.parray[p1].s_stats.rating;
526     else if (type == light_rat)
527       rat = player_globals.parray[p1].l_stats.rating;
528     else if (type == bug_rat)
529       rat = player_globals.parray[p1].bug_stats.rating;
530
531     if (type == none) {
532       sprintf(ptmp, "     ");
533     } else {
534       sprintf(ptmp, "%-4s", ratstrii(rat, p1));
535       if ((player_globals.parray[p1].simul_info != NULL) && (player_globals.parray[p1].simul_info->numBoards))
536           strcat(ptmp, "~");
537       else if ((player_globals.parray[p1].game >= 0) && ((game_globals.garray[player_globals.parray[p1].game].status == GAME_EXAMINE) || (game_globals.garray[player_globals.parray[p1].game].status == GAME_SETUP)))
538         strcat(ptmp, "#");
539       else if (player_globals.parray[p1].game >= 0)
540         strcat(ptmp, "^");
541       else if (!CheckPFlag(p1, PFLAG_OPEN))
542         strcat(ptmp, ":");
543       else if (player_idle(p1) > 300)
544         strcat(ptmp, ".");
545       else
546         strcat(ptmp, " ");
547     }
548
549     if (p == p1) {
550       psprintf_highlight(p, ptmp + strlen(ptmp), "%s", player_globals.parray[p1].name);
551     } else {
552       strcat(ptmp, player_globals.parray[p1].name);
553     }
554
555     AddPlayerLists(p1, ptmp);
556     multicol_store(m, ptmp);
557   }
558   multicol_pprint(m, p, pp->d_width, 2);
559   multicol_end(m);
560   pprintf(p, "\n %d players displayed (of %d). (*) indicates system administrator.\n", num, player_count(1));
561 }
562
563 static void who_verbose(p, num, plist)
564 int p;
565 int num;
566 int plist[];
567 {
568   int i, p1;
569   char playerLine[255], tmp[255];       /* +8 for highlight */
570   char p1WithAttrs[255];
571
572   pprintf(p,
573       " +---------------------------------------------------------------+\n"
574     );
575   pprintf(p,
576       " |      User              Standard    Blitz        On for   Idle |\n"
577     );
578   pprintf(p,
579       " +---------------------------------------------------------------+\n"
580     );
581
582   for (i = 0; i < num; i++) {
583     p1 = plist[i];
584
585     strcpy(playerLine, " |");
586
587     if (player_globals.parray[p1].game >= 0)
588       sprintf(tmp, "%3d", player_globals.parray[p1].game + 1);
589     else
590       sprintf(tmp, "   ");
591     strcat(playerLine, tmp);
592
593     if (!CheckPFlag(p1, PFLAG_OPEN))
594       sprintf(tmp, "X");
595     else
596       sprintf(tmp, " ");
597     strcat(playerLine, tmp);
598
599     if (CheckPFlag(p1, PFLAG_REG))
600       if (CheckPFlag(p1, PFLAG_RATED)) {
601         sprintf(tmp, " ");
602       } else {
603         sprintf(tmp, "u");
604       }
605     else
606       sprintf(tmp, "U");
607     strcat(playerLine, tmp);
608
609     /* Modified by hersco to include lists in 'who v.' */
610     strcpy (p1WithAttrs, player_globals.parray[p1].name);
611     AddPlayerLists(p1, p1WithAttrs);
612     p1WithAttrs[17] = '\0';
613
614     /* Modified by DAV 3/15/95 */
615     if (p == p1) {
616       strcpy(tmp, " ");
617       psprintf_highlight(p, tmp + strlen(tmp), "%-17s", p1WithAttrs);
618     } else {
619       sprintf(tmp, " %-17s", p1WithAttrs);
620     }
621     strcat(playerLine, tmp);
622
623     sprintf(tmp, " %4s        %-4s        %5s  ",
624             ratstrii(player_globals.parray[p1].s_stats.rating, p1),
625             ratstrii(player_globals.parray[p1].b_stats.rating, p1),
626             hms(player_ontime(p1), 0, 0, 0));
627     strcat(playerLine, tmp);
628
629     if (player_idle(p1) >= 60) {
630       sprintf(tmp, "%5s   |\n", hms(player_idle(p1), 0, 0, 0));
631     } else {
632       sprintf(tmp, "        |\n");
633     }
634     strcat(playerLine, tmp);
635     pprintf(p, "%s", playerLine);
636   }
637
638   pprintf(p,
639       " |                                                               |\n"
640     );
641   pprintf(p,
642      " |    %3d Players Displayed                                      |\n",
643           num
644     );
645   pprintf(p,
646       " +---------------------------------------------------------------+\n"
647     );
648 }
649
650 static void who_winloss(p, num, plist)
651 int p;
652 int num;
653 int plist[];
654 {
655   int i, p1;
656   char playerLine[255], tmp[255];       /* for highlight */
657   char p1WithAttrs[255];
658
659   pprintf(p,
660           "Name               Stand     win loss draw   Blitz    win loss draw    idle\n"
661     );
662   pprintf(p,
663           "----------------   -----     -------------   -----    -------------    ----\n"
664     );
665
666   for (i = 0; i < num; i++) {
667     playerLine[0] = '\0';
668     p1 = plist[i];
669
670     /* Modified by hersco to include lists in 'who n.' */
671     strcpy (p1WithAttrs, player_globals.parray[p1].name);
672     AddPlayerLists(p1, p1WithAttrs);
673     p1WithAttrs[17] = '\0';
674
675     if (p1 == p) {
676       psprintf_highlight(p, playerLine, "%-17s", p1WithAttrs);
677     } else {
678       sprintf(playerLine, "%-17s", p1WithAttrs);
679     }
680     sprintf(tmp, "  %4s     %4d %4d %4d   ",
681             ratstrii(player_globals.parray[p1].s_stats.rating, p1),
682             (int) player_globals.parray[p1].s_stats.win,
683             (int) player_globals.parray[p1].s_stats.los,
684             (int) player_globals.parray[p1].s_stats.dra);
685     strcat(playerLine, tmp);
686
687     sprintf(tmp, "%4s    %4d %4d %4d   ",
688             ratstrii(player_globals.parray[p1].b_stats.rating, p1),
689             (int) player_globals.parray[p1].b_stats.win,
690             (int) player_globals.parray[p1].b_stats.los,
691             (int) player_globals.parray[p1].b_stats.dra);
692     strcat(playerLine, tmp);
693
694     if (player_idle(p1) >= 60) {
695       sprintf(tmp, "%5s\n", hms(player_idle(p1), 0, 0, 0));
696     } else {
697       sprintf(tmp, "     \n");
698     }
699     strcat(playerLine, tmp);
700
701     pprintf(p, "%s", playerLine);
702   }
703   pprintf(p, "    %3d Players Displayed.\n", num);
704 }
705
706 static int who_ok(int p, unsigned int sel_bits)
707 {
708   struct player *pp = &player_globals.parray[p];
709   int p2;
710   if (pp->status != PLAYER_PROMPT)
711     return 0;
712   if (sel_bits == WHO_ALL)
713     return 1;
714   if (sel_bits & WHO_OPEN)
715     if (!CheckPFlag(p, PFLAG_OPEN) || CheckPFlag(p, PFLAG_TOURNEY))
716       return 0;
717   if (sel_bits & WHO_CLOSED)
718     if (CheckPFlag(p, PFLAG_OPEN))
719       return 0;
720   if (sel_bits & WHO_RATED)
721     if (!CheckPFlag(p, PFLAG_RATED))
722       return 0;
723   if (sel_bits & WHO_UNRATED)
724     if (CheckPFlag(p, PFLAG_RATED))
725       return 0;
726   if (sel_bits & WHO_FREE)
727     if (pp->game >= 0)
728       return 0;
729   if (sel_bits & WHO_PLAYING)
730     if (pp->game < 0)
731       return 0;
732   if (sel_bits & WHO_REGISTERED)
733     if (!CheckPFlag(p, PFLAG_REG))
734       return 0;
735   if (sel_bits & WHO_UNREGISTERED)
736     if (CheckPFlag(p, PFLAG_REG))
737       return 0;
738   if (sel_bits & WHO_BUGTEAM) {
739     p2 = pp->partner;
740     if (p2 < 0 || player_globals.parray[p2].partner != p)
741       return 0;
742     }  
743   return 1;
744 }
745
746
747 static int blitz_cmp(const void *pp1, const void *pp2)
748 {
749   register int p1 = *(int *) pp1;
750   register int p2 = *(int *) pp2;
751   if (player_globals.parray[p1].status != PLAYER_PROMPT) {
752     if (player_globals.parray[p2].status != PLAYER_PROMPT)
753       return 0;
754     else
755       return -1;
756   }
757   if (player_globals.parray[p2].status != PLAYER_PROMPT)
758     return 1;
759   if (player_globals.parray[p1].b_stats.rating > player_globals.parray[p2].b_stats.rating)
760     return -1;
761   if (player_globals.parray[p1].b_stats.rating < player_globals.parray[p2].b_stats.rating)
762     return 1;
763   if (CheckPFlag(p1, PFLAG_REG) && !CheckPFlag(p2, PFLAG_REG))
764     return -1;
765   if (!CheckPFlag(p1, PFLAG_REG) && CheckPFlag(p2, PFLAG_REG))
766     return 1;
767   return strcmp(player_globals.parray[p1].login, player_globals.parray[p2].login);
768 }
769
770 static int light_cmp(const void *pp1, const void *pp2)
771 {         
772   register int p1 = *(int *) pp1;
773   register int p2 = *(int *) pp2;
774   if (player_globals.parray[p1].status != PLAYER_PROMPT) {
775     if (player_globals.parray[p2].status != PLAYER_PROMPT)
776       return 0; 
777     else
778       return -1;
779   }       
780   if (player_globals.parray[p2].status != PLAYER_PROMPT)
781     return 1;
782   if (player_globals.parray[p1].l_stats.rating > player_globals.parray[p2].l_stats.rating)
783     return -1;
784   if (player_globals.parray[p1].l_stats.rating < player_globals.parray[p2].l_stats.rating)
785     return 1;
786   if (CheckPFlag(p1, PFLAG_REG) && !CheckPFlag(p2, PFLAG_REG))
787     return -1;
788   if (!CheckPFlag(p1, PFLAG_REG) && CheckPFlag(p2, PFLAG_REG))
789     return 1;
790   return strcmp(player_globals.parray[p1].login, player_globals.parray[p2].login);
791 }
792
793 static int bug_cmp(const void *pp1, const void *pp2)
794 {  
795   register int p1 = *(int *) pp1;
796   register int p2 = *(int *) pp2;
797   if (player_globals.parray[p1].status != PLAYER_PROMPT) {
798     if (player_globals.parray[p2].status != PLAYER_PROMPT)
799       return 0;
800     else
801       return -1;
802   }
803   if (player_globals.parray[p2].status != PLAYER_PROMPT)
804     return 1;
805   if (player_globals.parray[p1].bug_stats.rating > player_globals.parray[p2].bug_stats.rating)
806     return -1;
807   if (player_globals.parray[p1].bug_stats.rating < player_globals.parray[p2].bug_stats.rating)
808     return 1;
809   if (CheckPFlag(p1, PFLAG_REG) && !CheckPFlag(p2, PFLAG_REG))
810     return -1;
811   if (!CheckPFlag(p1, PFLAG_REG) && CheckPFlag(p2, PFLAG_REG))
812     return 1;
813   return strcmp(player_globals.parray[p1].login, player_globals.parray[p2].login);
814 }
815
816 static int stand_cmp(const void *pp1, const void *pp2)
817 {
818   register int p1 = *(int *) pp1;
819   register int p2 = *(int *) pp2;
820   if (player_globals.parray[p1].status != PLAYER_PROMPT) {
821     if (player_globals.parray[p2].status != PLAYER_PROMPT)
822       return 0;
823     else
824       return -1;
825   }
826   if (player_globals.parray[p2].status != PLAYER_PROMPT)
827     return 1;
828   if (player_globals.parray[p1].s_stats.rating > player_globals.parray[p2].s_stats.rating)
829     return -1;
830   if (player_globals.parray[p1].s_stats.rating < player_globals.parray[p2].s_stats.rating)
831     return 1;
832   if (CheckPFlag(p1, PFLAG_REG) && !CheckPFlag(p2, PFLAG_REG))
833     return -1;
834   if (!CheckPFlag(p1, PFLAG_REG) && CheckPFlag(p2, PFLAG_REG))
835     return 1;
836   return strcmp(player_globals.parray[p1].login, player_globals.parray[p2].login);
837 }
838
839 static int wild_cmp(const void *pp1, const void *pp2)
840 {
841   register int p1 = *(int *) pp1;
842   register int p2 = *(int *) pp2;
843   if (player_globals.parray[p1].status != PLAYER_PROMPT) {
844     if (player_globals.parray[p2].status != PLAYER_PROMPT)
845       return 0;
846     else
847       return -1;
848   }
849   if (player_globals.parray[p2].status != PLAYER_PROMPT)
850     return 1;
851   if (player_globals.parray[p1].w_stats.rating > player_globals.parray[p2].w_stats.rating)
852     return -1;
853   if (player_globals.parray[p1].w_stats.rating < player_globals.parray[p2].w_stats.rating)
854     return 1;
855   if (CheckPFlag(p1, PFLAG_REG) && !CheckPFlag(p2, PFLAG_REG))
856     return -1;
857   if (!CheckPFlag(p1, PFLAG_REG) && CheckPFlag(p2, PFLAG_REG))
858     return 1;
859   return strcmp(player_globals.parray[p1].login, player_globals.parray[p2].login);
860 }
861
862 static int alpha_cmp(const void *pp1, const void *pp2)
863 {
864   register int p1 = *(int *) pp1;
865   register int p2 = *(int *) pp2;
866   if (player_globals.parray[p1].status != PLAYER_PROMPT) {
867     if (player_globals.parray[p2].status != PLAYER_PROMPT)
868       return 0;
869     else
870       return -1;
871   }
872   if (player_globals.parray[p2].status != PLAYER_PROMPT)
873     return 1;
874   return strcmp(player_globals.parray[p1].login, player_globals.parray[p2].login);
875 }
876
877 static void sort_players(int *players,
878                          int ((*cmp_func) (const void *, const void *)))
879 {
880         int i;
881
882         for (i = 0; i < player_globals.p_num; i++) {
883                 players[i] = i;
884         }
885         qsort(players, player_globals.p_num, sizeof(int), cmp_func);
886 }
887
888 /* This is the of the most compliclicated commands in terms of parameters */
889 int com_who(int p, param_list param)
890 {
891         struct player *pp = &player_globals.parray[p];
892         int style = 0;
893         float stop_perc = 1.0;
894         float start_perc = 0;
895         unsigned int sel_bits = WHO_ALL;
896         int *sortlist, *plist;
897         int ((*cmp_func) (const void *, const void *));
898         int startpoint;
899         int stoppoint;
900         int i, len;
901         int tmpI, tmpJ;
902         char c;
903         int p1, count, num_who;
904         int sort_type;
905         int total;
906
907         sortlist = malloc(sizeof(int) * player_globals.p_num);
908         plist = malloc(sizeof(int) * player_globals.p_num);
909         
910         total = pp->d_time * 60 + pp->d_inc * 40;
911         if (total < 180) {
912                 sort_type = light_rat;
913                 cmp_func = light_cmp;
914         } else if (total >= 900) {
915                 sort_type = std_rat;
916                 cmp_func = stand_cmp;
917         } else {
918                 sort_type = blitz_rat;
919                 cmp_func = blitz_cmp;
920         }
921         
922         if (param[0].type != TYPE_NULL) {
923                 len = strlen(param[0].val.string);
924                 for (i = 0; i < len; i++) {
925                         c = param[0].val.string[i];
926                         if (isdigit(c)) {
927                                 if (i == 0 || !isdigit(param[0].val.string[i - 1])) {
928                                         tmpI = c - '0';
929                                         if (tmpI == 1) {
930                                                 start_perc = 0.0;
931                                                 stop_perc = 0.333333;
932                                         } else if (tmpI == 2) {
933                                                 start_perc = 0.333333;
934                                                 stop_perc = 0.6666667;
935                                         } else if (tmpI == 3) {
936                                                 start_perc = 0.6666667;
937                                                 stop_perc = 1.0;
938                                         } else if ((i == len - 1) || (!isdigit(param[0].val.string[i + 1])))
939                                                 goto bad_parameters;
940                                 } else {
941                                         tmpI = c - '0';
942                                         tmpJ = param[0].val.string[i - 1] - '0';
943                                         if (tmpI == 0)
944                                                 goto bad_parameters;
945                                         if (tmpJ > tmpI)
946                                                 goto bad_parameters;
947                                         start_perc = ((float) tmpJ - 1.0) / (float) tmpI;
948                                         stop_perc = ((float) tmpJ) / (float) tmpI;
949                                 }
950                         } else {
951                                 switch (c) {
952                                 case ' ':
953                                 case '\n':
954                                 case '\t':
955                                         break;
956                                 case 'o':
957                                         if (sel_bits == WHO_ALL)
958                                                 sel_bits = WHO_OPEN;
959                                         else
960                                                 sel_bits |= WHO_OPEN;
961                                         break;
962                                 case 'r':
963                                         if (sel_bits == WHO_ALL)
964                                                 sel_bits = WHO_RATED;
965                                         else
966                                                 sel_bits |= WHO_RATED;
967                                         break;
968                                 case 'f':
969                                         if (sel_bits == WHO_ALL)
970                                                 sel_bits = WHO_FREE;
971                                         else
972                                                 sel_bits |= WHO_FREE;
973                                         break;
974                                 case 'a':
975                                         if (sel_bits == WHO_ALL)
976                                                 sel_bits = WHO_FREE | WHO_OPEN;
977                                         else
978                                                 sel_bits |= (WHO_FREE | WHO_OPEN);
979                                         break;
980                                 case 'R':
981                                         if (sel_bits == WHO_ALL)
982                                                 sel_bits = WHO_REGISTERED;
983                                         else
984                                                 sel_bits |= WHO_REGISTERED;
985                                         break;
986                                 case 'l':               /* Sort order */
987                                         cmp_func = alpha_cmp;
988                                         sort_type = none;
989                                         break;
990                                 case 'A':               /* Sort order */
991                                         cmp_func = alpha_cmp;
992                                         break;
993                                 case 'w':               /* Sort order */
994                                         cmp_func = wild_cmp;
995                                         sort_type = wild_rat;
996                                         break;
997                                 case 's':               /* Sort order */
998                                         cmp_func = stand_cmp;
999                                         sort_type = std_rat;
1000                                         break;
1001                                 case 'b':               /* Sort order */
1002                                         cmp_func = blitz_cmp;
1003                                         sort_type = blitz_rat;
1004                                         break;
1005                                 case 'L':               /* Sort order */
1006                                         cmp_func = light_cmp;
1007                                         sort_type = light_rat;
1008                                         break;
1009                                 case 't':               /* format */
1010                                         style = 0;
1011                                         break;
1012                                 case 'v':               /* format */
1013                                         style = 1;
1014                                         break;
1015                                 case 'n':               /* format */
1016                                         style = 2;
1017                                         break;
1018                                 case 'U':
1019                                         if (sel_bits == WHO_ALL)
1020                                                 sel_bits = WHO_UNREGISTERED;
1021                                         else
1022                                                 sel_bits |= WHO_UNREGISTERED;
1023                                         break;
1024                                 case 'B':
1025                                         if (sel_bits == WHO_ALL)
1026                                                 sel_bits = WHO_BUGTEAM;
1027                                         else
1028                                                 sel_bits |= WHO_BUGTEAM;
1029                                         cmp_func = bug_cmp;
1030                                         sort_type = bug_rat;
1031                                         break;
1032                                 default:
1033                                         goto bad_parameters;
1034                                 }
1035                         }
1036                 }
1037         }
1038         sort_players(sortlist, cmp_func);
1039         count = 0;
1040         for (p1 = 0; p1 < player_globals.p_num; p1++) {
1041                 if (!who_ok(sortlist[p1], sel_bits))
1042                         continue;
1043                 count++;
1044         }
1045         startpoint = floor((float) count * start_perc);
1046         stoppoint = ceil((float) count * stop_perc) - 1;
1047         num_who = 0;
1048         count = 0;
1049         for (p1 = 0; p1 < player_globals.p_num; p1++) {
1050                 if (!who_ok(sortlist[p1], sel_bits))
1051                         continue;
1052                 if ((count >= startpoint) && (count <= stoppoint)) {
1053                         plist[num_who++] = sortlist[p1];
1054                 }
1055                 count++;
1056         }
1057         
1058         if (num_who == 0) {
1059                 pprintf(p, "No logged in players match the flags in your who request.\n");
1060                 return COM_OK;
1061         }
1062         
1063         switch (style) {
1064         case 0:                 /* terse */
1065                 who_terse(p, num_who, plist, sort_type);
1066                 break;
1067         case 1:                 /* verbose */
1068                 who_verbose(p, num_who, plist);
1069                 break;
1070         case 2:                 /* win-loss */
1071                 who_winloss(p, num_who, plist);
1072                 break;
1073         default:
1074                 goto bad_parameters;
1075         }
1076         
1077         return COM_OK;
1078
1079 bad_parameters:
1080         return COM_BADPARAMETERS;
1081 }
1082
1083 int com_open(int p, param_list param)
1084 {
1085   int retval;
1086   if ((retval = pcommand(p, "set open")) != COM_OK)
1087     return retval;
1088   else
1089     return COM_OK_NOPROMPT;
1090 }
1091
1092 int com_simopen(int p, param_list param)
1093 {
1094   int retval;
1095   if ((retval = pcommand(p, "set simopen")) != COM_OK)
1096     return retval;
1097   else
1098     return COM_OK_NOPROMPT;
1099 }
1100
1101 int com_bell(int p, param_list param)
1102 {
1103   int retval;
1104   if ((retval = pcommand(p, "set bell")) != COM_OK)
1105     return retval;
1106   else
1107     return COM_OK_NOPROMPT;
1108 }
1109
1110 int com_flip(int p, param_list param)
1111 {
1112   int retval;
1113   if ((retval = pcommand(p, "set flip")) != COM_OK)
1114     return retval;
1115   else
1116     return COM_OK_NOPROMPT;
1117 }
1118
1119 int com_style(int p, param_list param)
1120 {
1121   int retval;
1122   if ((retval = pcommand(p, "set style %d", param[0].val.integer)) != COM_OK)
1123     return retval;
1124   else
1125     return COM_OK_NOPROMPT;
1126 }
1127
1128 int com_promote(int p, param_list param)
1129 {
1130   int retval;
1131   if ((retval = pcommand(p, "set promote %s", param[0].val.word)) != COM_OK)
1132     return retval;
1133   else
1134     return COM_OK_NOPROMPT;
1135 }
1136
1137 void alias_add(int p, const char *name, const char *value)
1138 {
1139         struct player *pp = &player_globals.parray[p];
1140
1141         pp->alias_list = (struct alias_type *)realloc(pp->alias_list, 
1142                                                       sizeof(struct alias_type) * (pp->numAlias+1));
1143         pp->alias_list[pp->numAlias].comm_name = strdup(name);
1144         pp->alias_list[pp->numAlias].alias = strdup(value);
1145         pp->numAlias++;
1146 }
1147
1148
1149 int com_alias(int p, param_list param)
1150 {
1151         struct player *pp = &player_globals.parray[p];
1152         int al, i;
1153         const char *noalias[] = {"quit", "unalias", NULL};
1154
1155         if (param[0].type == TYPE_NULL) {
1156                 for (al = 0; al < pp->numAlias; al++) {
1157                         pprintf(p, "%s -> %s\n", 
1158                                 pp->alias_list[al].comm_name,
1159                                 pp->alias_list[al].alias);
1160                 }
1161                 return COM_OK;
1162         }
1163
1164         al = alias_lookup(param[0].val.word, pp->alias_list, pp->numAlias);
1165         if (param[1].type == TYPE_NULL) {
1166                 if (al < 0) {
1167                         pprintf(p, "You have no alias named '%s'.\n", param[0].val.word);
1168                 } else {
1169                         pprintf(p, "%s -> %s\n", 
1170                                 pp->alias_list[al].comm_name,
1171                                 pp->alias_list[al].alias);
1172                 }
1173                 return COM_OK;
1174         } 
1175
1176         if (al >= 0) {
1177                 FREE(pp->alias_list[al].alias);
1178                 pp->alias_list[al].alias = strdup(param[1].val.string);
1179                 pprintf(p, "Alias %s replaced.\n", param[0].val.string);
1180                 return COM_OK;
1181         }
1182
1183         if (pp->numAlias >= config_get_int("MAX_ALIASES", DEFAULT_MAX_ALIASES)) {
1184                 pprintf(p, "You have your maximum number of aliases.\n");
1185                 return COM_OK;
1186         } 
1187
1188         for (i=0;noalias[i];i++) {
1189                 if (strcasecmp(param[0].val.string, noalias[i]) == 0) { 
1190                         pprintf(p, "Sorry, you can't alias this command.\n");
1191                         return COM_OK;
1192                 }
1193         }
1194
1195         alias_add(p, param[0].val.word, param[1].val.string);
1196
1197         pprintf(p, "Alias set.\n");
1198
1199         return COM_OK;
1200 }
1201
1202 int com_unalias(int p, param_list param)
1203 {
1204         struct player *pp = &player_globals.parray[p];
1205         int al;
1206         int i;
1207         
1208         al = alias_lookup(param[0].val.word, pp->alias_list, pp->numAlias);
1209         if (al < 0) {
1210                 pprintf(p, "You have no alias named '%s'.\n", param[0].val.word);
1211                 return COM_OK;
1212         } 
1213
1214         FREE(pp->alias_list[al].comm_name);
1215         FREE(pp->alias_list[al].alias);
1216         for (i = al; i < pp->numAlias-1; i++) {
1217                 pp->alias_list[i].comm_name = pp->alias_list[i+1].comm_name;
1218                 pp->alias_list[i].alias = pp->alias_list[i+1].alias;
1219         }
1220         pp->numAlias--;
1221         pp->alias_list = (struct alias_type *)realloc(pp->alias_list, 
1222                                                       sizeof(struct alias_type) * pp->numAlias);
1223         pprintf(p,"Alias removed.\n");
1224
1225         return COM_OK;
1226 }
1227
1228
1229 int com_handles(int p, param_list param)
1230 {
1231         char *buffer[1000];
1232         char pdir[MAX_FILENAME_SIZE];
1233         int count;
1234         
1235         sprintf(pdir, "%s/%c", PLAYER_DIR, param[0].val.word[0]);
1236         count = search_directory(pdir, param[0].val.word, buffer, 1000);
1237         pprintf(p, "Found %d names.\n", count);
1238         if (count > 0)
1239                 display_directory(p, buffer, count);
1240         return COM_OK;
1241 }
1242
1243 int com_getgi(int p, param_list param)
1244 {
1245   int p1, g;
1246   struct player *pp = &player_globals.parray[p];
1247
1248   if (!in_list(p, L_TD, pp->name)) {
1249     pprintf(p, "Only TD programs are allowed to use this command.\n");
1250     return COM_OK;
1251   }
1252   if (((p1 = player_find_bylogin(param[0].val.word)) < 0)
1253       || (!CheckPFlag(p1, PFLAG_REG))) {
1254     /* Darkside suggested not to return anything */
1255     return COM_OK;
1256   }
1257   if (!CheckPFlag(p1, PFLAG_REG)) {
1258     pprintf(p, "*getgi %s none none -1 -1 -1 -1 -1*\n", player_globals.parray[p1].name);
1259   } else if (player_globals.parray[p1].game >= 0) {
1260     g = player_globals.parray[p1].game;
1261     if (game_globals.garray[g].status == GAME_ACTIVE) {
1262       pprintf(p, "*getgi %s %s %s %d %d %d %d %d*\n", 
1263               player_globals.parray[p1].name,
1264               game_globals.garray[g].white_name,
1265               game_globals.garray[g].black_name,
1266               g + 1,
1267               game_globals.garray[g].wInitTime,
1268               game_globals.garray[g].wIncrement,
1269               game_globals.garray[g].rated,
1270               game_globals.garray[g].private);
1271     } else {
1272       pprintf(p, "%s is not playing a game.\n", player_globals.parray[p1].name);
1273     }
1274   } else {
1275     pprintf(p, "%s is not playing a game.\n", player_globals.parray[p1].name);
1276   }
1277   return COM_OK;
1278 }
1279
1280 int com_getpi(int p, param_list param)
1281 {
1282   struct player *pp = &player_globals.parray[p];
1283   int p1;
1284
1285   if (!in_list(p, L_TD, pp->name)) {
1286     pprintf(p, "Only TD programs are allowed to use this command.\n");
1287     return COM_OK;
1288   }
1289   if (((p1 = player_find_bylogin(param[0].val.word)) < 0)
1290       || (!CheckPFlag(p1, PFLAG_REG))) {
1291     /* Darkside suggested not to return anything */
1292     return COM_OK;
1293   }
1294   if (!CheckPFlag(p1, PFLAG_REG)) {
1295     pprintf(p, "*getpi %s -1 -1 -1*\n", player_globals.parray[p1].name);
1296   } else {
1297     pprintf(p, "*getpi %s %d %d %d %d*\n", player_globals.parray[p1].name,
1298             player_globals.parray[p1].w_stats.rating,
1299             player_globals.parray[p1].b_stats.rating,
1300             player_globals.parray[p1].s_stats.rating, 
1301             player_globals.parray[p1].l_stats.rating);    
1302   }
1303   return COM_OK;
1304 }
1305
1306 int com_limits(int p, param_list param)
1307 {
1308         struct player *pp = &player_globals.parray[p];
1309
1310         pprintf(p, "\nCurrent hardcoded limits:\n");
1311         pprintf(p, "  Max number of channels and max capacity: %d\n", MAX_CHANNELS);
1312         pprintf(p, "  Max number of channels one can be in: %d\n", MAX_INCHANNELS);
1313         pprintf(p, "  Max number of people on the notify list: %d\n", MAX_NOTIFY);
1314         pprintf(p, "  Max number of people on the censor list: %d\n", MAX_CENSOR);
1315         pprintf(p, "  Max number of people in a simul game: %d\n", MAX_SIMUL);
1316         pprintf(p, "  Max number of messages one can receive: %d\n", MAX_MESSAGES);
1317         pprintf(p, "  Min number of games to be active: %d\n", PROVISIONAL);
1318         if (!check_admin(p, ADMIN_ADMIN) && 
1319             !titled_player(p,pp->login)) { 
1320                 pprintf(p, "  Size of journal (entries): %d\n", MAX_JOURNAL);
1321         } else {
1322                 pprintf(p, "  Size of journal (entries): 26\n");
1323         }
1324         pprintf(p, "\nAdmin settable limits:\n");
1325         pprintf(p, "  Shout quota gives two shouts per %d seconds.\n", seek_globals.quota_time);
1326         return COM_OK;
1327 }
1328
1329
1330 int com_remote(int p, param_list param)
1331 {
1332         int p1;
1333
1334         if ((p1 = player_find_part_login(param[0].val.word)) < 0) {
1335                 pprintf(p, "%s is not logged in.\n", param[0].val.word);
1336                 return COM_OK;
1337         }
1338         if (!in_list(p1, L_REMOTE, player_globals.parray[p].login)) {
1339                 pprintf(p, "You are not in the remote list for %s\n",
1340                         player_globals.parray[p1].login);
1341                 return COM_OK;
1342         }
1343         pprintf(p, "Command issued as %s\n", player_globals.parray[p1].name);
1344         pprintf(p1, "Remote command [%s] issued by %s\n", 
1345                 param[1].val.string, player_globals.parray[p].name);
1346         pcommand(p1, "%s\n", param[1].val.string);
1347         return COM_OK;
1348 }