diff options
Diffstat (limited to 'FICS/comproc.old.c')
-rw-r--r-- | FICS/comproc.old.c | 3394 |
1 files changed, 3394 insertions, 0 deletions
diff --git a/FICS/comproc.old.c b/FICS/comproc.old.c new file mode 100644 index 0000000..92386ed --- /dev/null +++ b/FICS/comproc.old.c @@ -0,0 +1,3394 @@ +/* comproc.c + * + */ + +/* + fics - An internet chess server. + Copyright (C) 1993 Richard V. Nash + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +/* Revision history: + name email yy/mm/dd Change + Richard Nash 93/10/22 Created + foxbat 95/03/11 added filters in cmatch. +*/ + +#include "stdinclude.h" + +#include "common.h" +#include "comproc.h" +#include "command.h" +#include "utils.h" +#include "ficsmain.h" +#include "config.h" +#include "playerdb.h" +#include "network.h" +#include "rmalloc.h" +#include "channel.h" +#include "variable.h" +#include "gamedb.h" +#include "gameproc.h" +#include "board.h" +/* #include "hostinfo.h" */ +#include "multicol.h" +#include "ratings.h" +#include "formula.h" +#include "lists.h" +#include "eco.h" +#include <string.h> + +#include <sys/resource.h> + +/* grimm */ +#if defined(SGI) +#else +/* int system(char *arg); */ +#endif + +const none = 0; +const blitz_rat = 1; +const std_rat = 2; +const wild_rat = 3; + +int quota_time; + +PUBLIC int com_rating_recalc(int p, param_list param) +{ + ASSERT(parray[p].adminLevel >= ADMIN_ADMIN); + rating_recalc(); + return COM_OK; +} + +PUBLIC int com_more(int p, param_list param) +{ +/* in_push(IN_HELP); */ + pmore_file(p); + return COM_OK; +} + +PUBLIC int com_news(int p, param_list param) +{ + FILE *fp; + char filename[MAX_FILENAME_SIZE]; + char junk[MAX_LINE_SIZE]; + char *junkp; + int crtime; + char count[10]; + int flag, len; + + if (((param[0].type == 0) || (!strcmp(param[0].val.word, "all")))) { + +/* no params - then just display index over news */ + + pprintf(p, "\n **** BULLETIN BOARD ****\n\n"); + sprintf(filename, "%s/news.index", news_dir); + fp = fopen(filename, "r"); + if (!fp) { + fprintf(stderr, "Can't find news index.\n"); + return COM_OK; + } + flag = 0; + while (!feof(fp)) { + junkp = junk; + fgets(junk, MAX_LINE_SIZE, fp); + if (feof(fp)) + break; + if ((len = strlen(junk)) > 1) { + junk[len - 1] = '\0'; + sscanf(junkp, "%d %s", &crtime, count); + junkp = nextword(junkp); + junkp = nextword(junkp); + if (((param[0].type == TYPE_WORD) && (!strcmp(param[0].val.word, "all")))) { + pprintf(p, "%3s (%s) %s\n", count, strltime(&crtime), junkp); + flag = 1; + } else { + if ((crtime - player_lastconnect(p)) > 0) { + pprintf(p, "%3s (%s) %s\n", count, strltime(&crtime), junkp); + flag = 1; + } + } + } + } + fclose(fp); + crtime = player_lastconnect(p); + if (!flag) { + pprintf(p, "There are no news since your last login (%s).\n", strltime(&crtime)); + } else { + pprintf(p, "\n"); + } + } else { + +/* check if the specific news file exist in index */ + + sprintf(filename, "%s/news.index", news_dir); + fp = fopen(filename, "r"); + if (!fp) { + fprintf(stderr, "Can't find news index.\n"); + return COM_OK; + } + flag = 0; + while ((!feof(fp)) && (!flag)) { + junkp = junk; + fgets(junk, MAX_LINE_SIZE, fp); + if (feof(fp)) + break; + if ((len = strlen(junk)) > 1) { + junk[len - 1] = '\0'; + sscanf(junkp, "%d %s", &crtime, count); + if (!strcmp(count, param[0].val.word)) { + flag = 1; + junkp = nextword(junkp); + junkp = nextword(junkp); + pprintf(p, "\nNEWS %3s (%s)\n\n %s\n\n", count, strltime(&crtime), junkp); + } + } + } + fclose(fp); + if (!flag) { + pprintf(p, "Bad index number!\n"); + return COM_OK; + } +/* file exists - show it */ + + sprintf(filename, "%s/news.%s", news_dir, param[0].val.word); + fp = fopen(filename, "r"); + if (!fp) { + pprintf(p, "No more info.\n"); + return COM_OK; + } + fclose(fp); + sprintf(filename, "news.%s", param[0].val.word); + if (psend_file(p, news_dir, filename) < 0) { + pprintf(p, "Internal error - couldn't send news file!\n"); + } + } + return COM_OK; +} + +PUBLIC int com_quit(int p, param_list param) +{ + if ((parray[p].game >= 0) && (garray[parray[p].game].status == GAME_EXAMINE)) { + pcommand(p, "unexamine"); + } + + if (parray[p].game >= 0) { + 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"); + return COM_OK; + } + psend_file(p, mess_dir, MESS_LOGOUT); + return COM_LOGOUT; +} + +/* + +PUBLIC int com_query(int p, param_list param) +{ + int p1; + int count = 0; + + if (!parray[p].registered) { + pprintf(p, "Only registered players can use the query command.\n"); + return COM_OK; + } + if (parray[p].muzzled) { + pprintf(p, "You are muzzled.\n"); + return COM_OK; + } + if (!printablestring(param[0].val.string)) { + pprintf(p, "Your message contains some unprintable character(s).\n"); + return COM_OK; + } + if (!parray[p].query_log) { + parray[p].query_log = tl_new(5); + } else { + if (tl_numinlast(parray[p].query_log, 60 * 60) >= 2) { + pprintf(p, "Your can only query twice per hour.\n"); + return COM_OK; + } + } + in_push(IN_SHOUT); + for (p1 = 0; p1 < p_num; p1++) { + if (p1 == p) + continue; + if (parray[p1].status != PLAYER_PROMPT) + continue; + if (player_censored(p1, p)) + continue; + count++; + if (parray[p1].highlight) { + pprintf_prompt(p1, "\n\033[7m%s queries:\033[0m %s\n", parray[p].name, + param[0].val.string); + } else { + pprintf_prompt(p1, "\n%s queries: %s\n", parray[p].name, + param[0].val.string); + } + } + pprintf(p, "Query heard by %d player(s).\n", count); + tl_logevent(parray[p].query_log, 1); + in_pop(); + return COM_OK; +} + +*/ + +int CheckShoutQuota(int p) +{ + int timenow = time(0); + int timeleft = 0; + if (in_list("quota", parray[p].name)) { + if ((timeleft = timenow - parray[p].lastshout_a) < quota_time) { + return (quota_time - timeleft); + } else { + return 0; + } + } else { + return 0; + } +} + +PUBLIC int com_shout(int p, param_list param) +{ + int p1; + int count = 0; + int timeleft; /* time left for quota if applicable */ + + if (!parray[p].registered) { + pprintf(p, "Only registered players can use the shout command.\n"); + return COM_OK; + } + if (parray[p].muzzled) { + pprintf(p, "You are muzzled.\n"); + return COM_OK; + } + if (param[0].type == TYPE_NULL) { + if (in_list("quota", parray[p].name)) { + pprintf(p, "[You are on the quota list.]\n"); + if ((timeleft = CheckShoutQuota(p))) { + pprintf(p, "Next shout available in %d seconds.\n", timeleft); + } else { + pprintf(p, "Your next shout is ready for use.\n"); + } + } else { + pprintf(p, "[You are not on the quota list.]\n"); + pprintf(p, "Please specify what it is you want to shout.\n"); + } + return COM_OK; + } + if ((timeleft = CheckShoutQuota(p))) { + pprintf(p, "[You are on the quota list.]\n"); + pprintf(p, "Shout not sent. Next shout in %d seconds.\n", timeleft); + return COM_OK; + } + parray[p].lastshout_a = parray[p].lastshout_b; + parray[p].lastshout_b = time(0); + if (!printablestring(param[0].val.string)) { + pprintf(p, "Your message contains some unprintable character(s).\n"); + return COM_OK; + } +/* in_push(IN_SHOUT); */ + for (p1 = 0; p1 < p_num; p1++) { + if (p1 == p) + continue; + if (parray[p1].status != PLAYER_PROMPT) + continue; + if (!parray[p1].i_shout) + continue; + if (player_censored(p1, p)) + continue; + count++; + pprintf_prompt(p1, "\n%s shouts: %s\n", parray[p].name, + param[0].val.string); + } + pprintf(p, "(%d) %s shouts: %s\n", count, parray[p].name, + param[0].val.string); +/* in_pop(); */ + if ((in_list("quota", parray[p].name)) && (timeleft = CheckShoutQuota(p))) { + pprintf(p, "[You are on the quota list.]\n"); + pprintf(p, "Next shout in %d seconds.\n", timeleft); + return COM_OK; + } + return COM_OK; +} + +PUBLIC int com_cshout(int p, param_list param) +{ + int p1; + int count = 0; + + if (!parray[p].registered) { + pprintf(p, "Only registered players can use the cshout command.\n"); + return COM_OK; + } + if (parray[p].cmuzzled) { + pprintf(p, "You are c-muzzled.\n"); + return COM_OK; + } + if (!printablestring(param[0].val.string)) { + pprintf(p, "Your message contains some unprintable character(s).\n"); + return COM_OK; + } +/* in_push(IN_SHOUT); */ + for (p1 = 0; p1 < p_num; p1++) { + if (p1 == p) + continue; + if (parray[p1].status != PLAYER_PROMPT) + continue; + if (!parray[p1].i_cshout) + continue; + if (player_censored(p1, p)) + continue; + count++; + pprintf_prompt(p1, "\n%s c-shouts: %s\n", parray[p].name, + param[0].val.string); + } + pprintf(p, "(%d) %s c-shouts: %s\n", count, parray[p].name, + param[0].val.string); +/* in_pop(); */ + return COM_OK; +} + +PUBLIC int com_it(int p, param_list param) +{ + int p1; + int count = 0; + int timeleft; + + if (!parray[p].registered) { + pprintf(p, "Only registered players can use the it command.\n"); + return COM_OK; + } + if (parray[p].muzzled) { + pprintf(p, "You are muzzled.\n"); + return COM_OK; + } + if (param[0].type == TYPE_NULL) { + if (in_list("quota", parray[p].name)) { + pprintf(p, "[You are on the quota list.]\n"); + if ((timeleft = CheckShoutQuota(p))) { + pprintf(p, "Next shout available in %d seconds.\n", timeleft); + } else { + pprintf(p, "Your next shout is ready for use.\n"); + } + } else { + pprintf(p, "[You are not on the quota list.]\n"); + pprintf(p, "Please specify what it is you want to shout.\n"); + } + return COM_OK; + } + if ((timeleft = CheckShoutQuota(p))) { + pprintf(p, "[You are on the quota list.]\n"); + pprintf(p, "Shout not sent. Next shout in %d seconds.\n", timeleft); + return COM_OK; + } + parray[p].lastshout_a = parray[p].lastshout_b; + parray[p].lastshout_b = time(0); + + if (!printablestring(param[0].val.string)) { + pprintf(p, "Your message contains some unprintable character(s).\n"); + return COM_OK; + } +/* in_push(IN_SHOUT); */ + for (p1 = 0; p1 < p_num; p1++) { + if (p1 == p) + continue; + if (parray[p1].status != PLAYER_PROMPT) + continue; + if (!parray[p1].i_shout) + continue; + if (player_censored(p1, p)) + continue; + count++; + if ((!strncmp(param[0].val.string, "\'", 1)) || + (!strncmp(param[0].val.string, ",", 1)) || + (!strncmp(param[0].val.string, ".", 1))) { + pprintf_prompt(p1, "\n--> %s%s\n", parray[p].name, + param[0].val.string); + } else { + pprintf_prompt(p1, "\n--> %s %s\n", parray[p].name, + param[0].val.string); + } + } + if ((!strncmp(param[0].val.string, "\'", 1)) || + (!strncmp(param[0].val.string, ",", 1)) || + (!strncmp(param[0].val.string, ".", 1))) { + pprintf(p, "(%d) --> %s%s\n", count, parray[p].name, param[0].val.string); + } else { + pprintf(p, "(%d) --> %s %s\n", count, parray[p].name, param[0].val.string); + } +/* in_pop(); */ + if ((in_list("quota", parray[p].name)) && (timeleft = CheckShoutQuota(p))) { + pprintf(p, "[You are on the quota list.]\n"); + pprintf(p, "Next shout in %d seconds.\n", timeleft); + return COM_OK; + } + return COM_OK; +} + +#define TELL_TELL 0 +#define TELL_SAY 1 +#define TELL_WHISPER 2 +#define TELL_KIBITZ 3 +#define TELL_CHANNEL 4 +PRIVATE int tell(int p, int p1, char *msg, int why, int ch) +{ + char tmp[MAX_LINE_SIZE]; + + if (!printablestring(msg)) { + pprintf(p, "Your message contains some unprintable character(s).\n"); + return COM_OK; + } +/* if (p1 == p) { + * pprintf(p, "Quit talking to yourself! It's embarrassing.\n"); + * return COM_OK; + * } + */ + if ((!parray[p1].i_tell) && (!parray[p].registered)) { + pprintf(p, "Player \"%s\" isn't listening to unregistered tells.\n", + parray[p1].name); + return COM_OK; + } + if ((player_censored(p1, p)) && (parray[p].adminLevel == 0)) { + pprintf(p, "Player \"%s\" is censoring you.\n", parray[p1].name); + return COM_OK; + } +/* in_push(IN_TELL); */ + switch (why) { + case TELL_SAY: + pprintf_highlight(p1, "\n%s", parray[p].name); + pprintf_prompt(p1, " says: %s\n", msg); + break; + case TELL_WHISPER: + pprintf(p1, "\n%s", parray[p].name); + pprintf_prompt(p1, " whispers: %s\n", msg); + break; + case TELL_KIBITZ: + pprintf(p1, "\n%s", parray[p].name); + pprintf_prompt(p1, " kibitzes: %s\n", msg); + break; + case TELL_CHANNEL: + pprintf(p1, "\n%s", parray[p].name); + pprintf_prompt(p1, "(%d): %s\n", ch, msg); + break; + case TELL_TELL: + default: + if (parray[p1].highlight) { + pprintf_highlight(p1, "\n%s", parray[p].name); + } else { + pprintf(p1, "\n%s", parray[p].name); + } + pprintf_prompt(p1, " tells you: %s\n", msg); + break; + } + tmp[0] = '\0'; + if (!(parray[p1].busy[0] == '\0')) { + sprintf(tmp, ", who %s (idle: %d minutes)", parray[p1].busy, + ((player_idle(p1) % 3600) / 60)); + } else { + if (((player_idle(p1) % 3600) / 60) > 2) { + sprintf(tmp, ", who has been idle %d minutes", ((player_idle(p1) % 3600) / 60)); + } + /* else sprintf(tmp," "); */ + } + if ((why == TELL_SAY) || (why == TELL_TELL)) { + pprintf(p, "(told %s%s)\n", parray[p1].name, + (((parray[p1].game>=0) && (garray[parray[p1].game].status == GAME_EXAMINE)) + ? ", who is examining a game" : + (parray[p1].game >= 0 && (parray[p1].game != parray[p].game)) + ? ", who is playing" : tmp)); + parray[p].last_tell = p1; + } +/* in_pop(); */ + return COM_OK; +} + +PRIVATE int chtell(int p, int ch, char *msg) +{ + int p1; + int i, count = 0, listening = 0; + + if ((ch == 0) && (parray[p].adminLevel == 0)) { + pprintf(p, "Only admins may send tells to channel 0.\n"); + return COM_OK; + } + if (ch < 0) { + pprintf(p, "The lowest channel number is 0.\n"); + return COM_OK; + } + if (ch >= MAX_CHANNELS) { + pprintf(p, "The maximum channel number is %d.\n", MAX_CHANNELS - 1); + return COM_OK; + } +/* in_push(IN_TELL); */ + for (i = 0; i < numOn[ch]; i++) { + p1 = channels[ch][i]; + if (p1 == p) { + listening = 1; + continue; + } + if (player_censored(p1, p)) + continue; + if ((parray[p1].status == PLAYER_PASSWORD) + || (parray[p1].status == PLAYER_LOGIN)) + continue; + tell(p, p1, msg, TELL_CHANNEL, ch); + count++; + } + if (count) { + /* parray[p].last_tell = -1; */ + parray[p].last_channel = ch; + } + pprintf(p, "(%d->(%d))", ch, count); + if (!listening) + pprintf(p, " (You're not listening to channel %d.)", ch); + pprintf(p, "\n"); +/* in_pop(); */ + return COM_OK; +} + +PUBLIC int com_whisper(int p, param_list param) +{ + int g; + int p1; + int count = 0; + + if (!parray[p].num_observe && parray[p].game < 0) { + pprintf(p, "You are not playing or observing a game.\n"); + return COM_OK; + } + if (!parray[p].registered && (parray[p].game == -1)) { + pprintf(p, "You must be registered to whisper other people's games.\n"); + return COM_OK; + } + if (parray[p].game >= 0) + g = parray[p].game; + else + g = parray[p].observe_list[0]; + for (p1 = 0; p1 < p_num; p1++) { + if (p1 == p) + continue; + if (parray[p1].status != PLAYER_PROMPT) + continue; + if (player_is_observe(p1, g)) { + tell(p, p1, param[0].val.string, TELL_WHISPER, 0); + if ((parray[p].adminLevel >= ADMIN_ADMIN) || !garray[g].private) + count++; + } + } + pprintf(p, "whispered to %d.\n", count); + return COM_OK; +} + +PUBLIC int com_kibitz(int p, param_list param) +{ + int g; + int p1; + int count = 0; + + if (!parray[p].num_observe && parray[p].game < 0) { + pprintf(p, "You are not playing or observing a game.\n"); + return COM_OK; + } + if (!parray[p].registered && (parray[p].game == -1)) { + pprintf(p, "You must be registered to kibitz other people's games.\n"); + return COM_OK; + } + if (parray[p].game >= 0) + g = parray[p].game; + else + g = parray[p].observe_list[0]; + for (p1 = 0; p1 < p_num; p1++) { + if (p1 == p) + continue; + if (parray[p1].status != PLAYER_PROMPT) + continue; + if (player_is_observe(p1, g) || parray[p1].game == g) { + tell(p, p1, param[0].val.string, TELL_KIBITZ, 0); + if ((parray[p].adminLevel >= ADMIN_ADMIN) || !garray[g].private || (parray[p1].game == g)) + count++; + } + } + pprintf(p, "kibitzed to %d.\n", count); + return COM_OK; +} + +PUBLIC int com_tell(int p, param_list param) +{ + int p1; + + if (param[0].type == TYPE_NULL) + return COM_BADPARAMETERS; + if (param[0].type == TYPE_WORD) { + stolower(param[0].val.word); + if (!strcmp(param[0].val.word, ".")) { + if (parray[p].last_tell < 0) { + pprintf(p, "No one to tell anything to.\n"); + return COM_OK; + } else { + return tell(p, parray[p].last_tell, param[1].val.string, TELL_TELL, 0); + } + } + if (!strcmp(param[0].val.word, ",")) { + if (parray[p].last_channel < 0) { + pprintf(p, "No previous channel.\n"); + return COM_OK; + } else { + return chtell(p, parray[p].last_channel, param[1].val.string); + } + } + p1 = player_find_part_login(param[0].val.word); + if ((p1 < 0) || (parray[p1].status == PLAYER_PASSWORD) + || (parray[p1].status == PLAYER_LOGIN)) { + pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word); + return COM_OK; + } + return tell(p, p1, param[1].val.string, TELL_TELL, 0); + } else { /* Channel */ + return chtell(p, param[0].val.integer, param[1].val.string); + } +} + +PUBLIC int com_xtell(int p, param_list param) +{ + int p1; + char *msg; + char tmp[2048]; + + msg = param[1].val.string; + p1 = player_find_part_login(param[0].val.word); + if ((p1 < 0) || (parray[p1].status == PLAYER_PASSWORD) + || (parray[p1].status == PLAYER_LOGIN)) { + pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word); + return COM_OK; + } + if (!printablestring(msg)) { + pprintf(p, "Your message contains some unprintable character(s).\n"); + return COM_OK; + } + if ((!parray[p1].i_tell) && (!parray[p].registered)) { + pprintf(p, "Player \"%s\" isn't listening to unregistered tells.\n", + parray[p1].name); + return COM_OK; + } + if ((player_censored(p1, p)) && (parray[p].adminLevel == 0)) { + pprintf(p, "Player \"%s\" is censoring you.\n", parray[p1].name); + return COM_OK; + } + if (parray[p1].highlight) { + pprintf_highlight(p1, "\n%s", parray[p].name); + } else { + pprintf(p1, "\n%s", parray[p].name); + } + pprintf_prompt(p1, " tells you: %s\n", msg); + + tmp[0] = '\0'; + if (!(parray[p1].busy[0] == '\0')) { + sprintf(tmp, ", who %s (idle: %d minutes)", parray[p1].busy, + ((player_idle(p1) % 3600) / 60)); + } else { + if (((player_idle(p1) % 3600) / 60) > 2) { + sprintf(tmp, ", who has been idle %d minutes", ((player_idle(p1) % 3600) / 60)); + } + } + pprintf(p, "(told %s%s)\n", parray[p1].name, + (((parray[p1].game>=0) && (garray[parray[p1].game].status == GAME_EXAMINE)) + ? ", who is examining a game" : + (parray[p1].game >= 0 && (parray[p1].game != parray[p].game)) + ? ", who is playing" : tmp)); + return COM_OK; +} + +PUBLIC int com_say(int p, param_list param) +{ + if (parray[p].opponent < 0) { + if (parray[p].last_opponent < 0) { + pprintf(p, "No one to say anything to, try tell.\n"); + return COM_OK; + } else { + return tell(p, parray[p].last_opponent, param[0].val.string, TELL_SAY, 0); + } + } + return tell(p, parray[p].opponent, param[0].val.string, TELL_SAY, 0); +} + +PUBLIC int com_set(int p, param_list param) +{ + int result; + int which; + char *val; + + if (param[1].type == TYPE_NULL) + val = NULL; + else + val = param[1].val.string; + result = var_set(p, param[0].val.word, val, &which); + switch (result) { + case VAR_OK: + break; + case VAR_BADVAL: + pprintf(p, "Bad value given for variable %s.\n", param[0].val.word); + break; + case VAR_NOSUCH: + pprintf(p, "No such variable name %s.\n", param[0].val.word); + break; + case VAR_AMBIGUOUS: + pprintf(p, "Ambiguous variable name %s.\n", param[0].val.word); + break; + } + player_save(p); + return COM_OK; +} + +PUBLIC int FindPlayer(int p, parameter * param, int *p1, int *connected) +{ + if (param->type == TYPE_WORD) { + *p1 = player_search(p, param->val.word); + if (*p1 == 0) + return 0; + if (*p1 < 0) { /* player had to be connected and will be + removed later */ + *connected = 0; + *p1 = (-*p1) - 1; + } else { + *connected = 1; + *p1 = *p1 - 1; + } + } else { + *p1 = p; + *connected = 1; + } + return 1; +} + +PRIVATE void com_stats_andify(int *numbers, int howmany, char *dest) +{ + char tmp[10]; + + *dest = '\0'; + while (howmany--) { + sprintf(tmp, "%d", numbers[howmany]); + strcat(dest, tmp); + if (howmany > 1) + sprintf(tmp, ", "); + else if (howmany == 1) + sprintf(tmp, " and "); + else + sprintf(tmp, ".\n"); + strcat(dest, tmp); + } + return; +} + +PRIVATE void com_stats_rating(char *hdr, statistics * stats, char *dest) +{ + char tmp[100]; + + sprintf(dest, "%-10s%4s %5.1f %4d %4d %4d %4d", + hdr, ratstr(stats->rating), stats->sterr, stats->win, stats->los, stats->dra, stats->num); + if (stats->whenbest) { + sprintf(tmp, " %d", stats->best); + strcat(dest, tmp); + strftime(tmp, sizeof(tmp), " (%d-%b-%y)", localtime((time_t *) & stats->whenbest)); + strcat(dest, tmp); + } + strcat(dest, "\n"); + return; +} + +PUBLIC int com_stats(int p, param_list param) +{ + int g, i, t; + int p1, connected; + char line[255], tmp[255]; + int numbers[MAX_OBSERVE > MAX_SIMUL ? MAX_OBSERVE : MAX_SIMUL]; + + if (!FindPlayer(p, ¶m[0], &p1, &connected)) + return COM_OK; + + sprintf(line, "\nStatistics for %-11s ", parray[p1].name); + if ((connected) && (parray[p1].status == PLAYER_PROMPT)) { + sprintf(tmp, "On for: %s", hms(player_ontime(p1), 0, 0, 0)); + strcat(line, tmp); + sprintf(tmp, " Idle: %s\n", hms(player_idle(p1), 0, 0, 0)); + } else { + if ((t = player_lastdisconnect(p1))) + sprintf(tmp, "(Last disconnected %s):\n", strltime(&t)); + else + sprintf(tmp, "(Never connected.)\n"); + } + strcat(line, tmp); + pprintf(p, "%s", line); + if (parray[p1].simul_info.numBoards) { + for (i = 0, t = 0; i < parray[p1].simul_info.numBoards; i++) { + if ((numbers[t] = parray[p1].simul_info.boards[i] + 1) != 0) + t++; + } + pprintf(p, "%s is giving a simul: game%s ", parray[p1].name, ((t > 1) ? "s" : "")); + com_stats_andify(numbers, t, tmp); + pprintf(p, tmp); + } else if (parray[p1].game >= 0) { + g = parray[p1].game; + if (garray[g].status == GAME_EXAMINE) { + pprintf(p, "(Examining game %d: %s vs. %s)\n", g + 1, + parray[garray[g].white].name, parray[garray[g].black].name); + } else { + pprintf(p, "(playing game %d: %s vs. %s)\n", g + 1, + parray[garray[g].white].name, parray[garray[g].black].name); + } + } + if (parray[p1].num_observe) { + for (i = 0, t = 0; i < parray[p1].num_observe; i++) { + g = parray[p1].observe_list[i]; + if ((g != -1) && ((parray[p].adminLevel >= ADMIN_ADMIN) || (garray[g].private == 0))) + numbers[t++] = g + 1; + } + if (t) { + pprintf(p, "%s is observing game%s ", parray[p1].name, ((t > 1) ? "s" : "")); + com_stats_andify(numbers, t, tmp); + pprintf(p, tmp); + } + } + if (parray[p1].busy[0]) { + pprintf(p, "(%s %s)\n", parray[p1].name, parray[p1].busy); + } + if (!parray[p1].registered) { + pprintf(p, "%s is NOT a registered player.\n\n", parray[p1].name); + } else { + pprintf(p, "\n rating RD win loss draw total best\n"); + com_stats_rating("Blitz", &parray[p1].b_stats, tmp); + pprintf(p, tmp); + com_stats_rating("Standard", &parray[p1].s_stats, tmp); + pprintf(p, tmp); + com_stats_rating("Wild", &parray[p1].w_stats, tmp); + pprintf(p, tmp); + } + pprintf(p, "\n"); + if (parray[p1].adminLevel > 0) { + pprintf(p, "Admin Level: "); + switch (parray[p1].adminLevel) { +/* + case 0: + pprintf(p, "Normal User\n"); + break; + case 5: + pprintf(p, "Extra Cool User\n"); vek wants to be 5 + break; + + Forget it - you can do some admin stuff if your level is > than 0 - DAV + +*/ + case 5: + pprintf(p, "Authorized Helper Person\n"); + break; + case 10: + pprintf(p, "Administrator\n"); + break; + case 15: + pprintf(p, "Help File Librarian/Administrator\n"); + break; + case 20: + pprintf(p, "Master Administrator\n"); + break; + case 50: + pprintf(p, "Master Help File Librarian/Administrator\n"); + break; + case 60: + pprintf(p, "Assistant Super User\n"); + break; + case 100: + pprintf(p, "Super User\n"); + break; + default: + pprintf(p, "%d\n", parray[p1].adminLevel); + break; + } + } + if (parray[p].adminLevel > 0) + pprintf(p, "Full Name : %s\n", (parray[p1].fullName ? parray[p1].fullName : "(none)")); + if (((p1 == p) && (parray[p1].registered)) || (parray[p].adminLevel > 0)) + pprintf(p, "Address : %s\n", (parray[p1].emailAddress ? parray[p1].emailAddress : "(none)")); + if (parray[p].adminLevel > 0) { + pprintf(p, "Host : %s\n", +/* + ((hp = gethostbyaddr((const char*) (connected ? &parray[p1].thisHost : &parray[p1].lastHost), sizeof(parray[p1].thisHost), AF_INET)) == 0) ? "" : hp->h_name, +*/ + dotQuad(connected ? parray[p1].thisHost : parray[p1].lastHost)); + } + if ((parray[p].adminLevel > 0) && (parray[p1].registered)) + if (parray[p1].num_comments) + pprintf(p, "Comments : %d\n", parray[p1].num_comments); + + if (parray[p1].num_plan) { + pprintf(p, "\n"); + for (i = 0; i < parray[p1].num_plan; i++) + pprintf(p, "%2d: %s\n", i + 1, (parray[p1].planLines[i] != NULL) ? parray[p1].planLines[i] : ""); + } + if (!connected) + player_remove(p1); + return COM_OK; +} + + + +PUBLIC int com_variables(int p, param_list param) +{ + int p1, connected; + int i; + + if (!FindPlayer(p, ¶m[0], &p1, &connected)) + return COM_OK; + + pprintf(p, "Variable settings of %s:\n", parray[p1].name); +/* if (parray[p1].fullName) + pprintf(p, " Realname: %s\n", parray[p1].fullName); +*/ + if (parray[p1].uscfRating) + pprintf(p, " USCF: %d\n", parray[p1].uscfRating); + pprintf(p, " time=%-3d inc=%-3d private=%d\n", + parray[p1].d_time, parray[p1].d_inc, parray[p1].private); + pprintf(p, " rated=%d ropen=%d open=%d simopen=%d\n", + parray[p1].rated, parray[p1].ropen, parray[p1].open, parray[p1].sopen); + pprintf(p, " shout=%d cshout=%d kib=%d tell=%d notifiedby=%d\n", + parray[p1].i_shout, parray[p1].i_cshout, parray[p1].i_kibitz, parray[p1].i_tell, parray[p1].notifiedby); + pprintf(p, " pin=%d gin=%d style=%-3d flip=%d\n", + parray[p1].i_login, parray[p1].i_game, parray[p1].style + 1, parray[p1].flip); + pprintf(p, " highlight=%d bell=%d auto=%d mailmess=%d pgn=%d\n", + parray[p1].highlight, parray[p1].bell, parray[p1].automail, parray[p1].i_mailmess, parray[p1].pgn); + pprintf(p, " width=%-3d height=%-3d\n", + parray[p1].d_width, parray[p1].d_height); + if (parray[p1].prompt && parray[p1].prompt != def_prompt) + pprintf(p, " Prompt: %s\n", parray[p1].prompt); + + { /* added code to print channels */ + int count = 0; + for (i = 0; i < MAX_CHANNELS; i++) { + if (on_channel(i, p1)) { + if (!count) + pprintf(p, "\n Channels:"); + pprintf(p, " %d", i); + count++; + } + } + if (count) + pprintf(p, "\n"); + } +/* if (parray[p1].numAlias && (p == p1)) { + pprintf(p, "\n Aliases:\n"); + for (i = 0; i < parray[p1].numAlias; i++) { + pprintf(p, " %s %s\n", parray[p1].alias_list[i].comm_name, + parray[p1].alias_list[i].alias); + } + } +*/ + if (parray[p1].num_formula) { + pprintf(p, "\n"); + for (i = 0; i < parray[p1].num_formula; i++) { + if (parray[p1].formulaLines[i] != NULL) + pprintf(p, " f%d: %s\n", i + 1, parray[p1].formulaLines[i]); + else + pprintf(p, " f%d:\n", i + 1); + } + } + if (parray[p1].formula != NULL) + pprintf(p, "\nFormula: %s\n", parray[p1].formula); + + if (!connected) + player_remove(p1); + return COM_OK; +} + + + +PUBLIC int com_password(int p, param_list param) +{ + char *oldpassword = param[0].val.word; + char *newpassword = param[1].val.word; + char salt[3]; + + if (!parray[p].registered) { + pprintf(p, "Setting a password is only for registered players.\n"); + return COM_OK; + } + if (parray[p].passwd) { + salt[0] = parray[p].passwd[0]; + salt[1] = parray[p].passwd[1]; + salt[2] = '\0'; + if (strcmp(crypt(oldpassword, salt), parray[p].passwd)) { + pprintf(p, "Incorrect password, password not changed!\n"); + return COM_OK; + } + rfree(parray[p].passwd); + parray[p].passwd = NULL; + } + salt[0] = 'a' + rand() % 26; + salt[1] = 'a' + rand() % 26; + salt[2] = '\0'; + parray[p].passwd = strdup(crypt(newpassword, salt)); + pprintf(p, "Password changed to \"%s\".\n", newpassword); + return COM_OK; +} + +PUBLIC int com_uptime(int p, param_list param) +{ + unsigned long uptime = time(0) - startuptime; + struct rusage ru; + int days = (uptime / (60*60*24)); + int hours = ((uptime % (60*60*24)) / (60*60)); + int mins = (((uptime % (60*60*24)) % (60*60)) / 60); + int secs = (((uptime % (60*60*24)) % (60*60)) % 60); + + pprintf(p, "Server location: %s Server version : %s\n", fics_hostname,VERS_NUM); + pprintf(p, "The server has been up since %s.\n", strltime(&startuptime)); + if ((days==0) && (hours==0) && (mins==0)) { + pprintf(p, "(Up for %d second%s)\n", + secs, (secs==1) ? "" : "s"); + } else if ((days==0) && (hours==0)) { + pprintf(p, "(Up for %d minute%s and %d second%s)\n", + mins, (mins==1) ? "" : "s", + secs, (secs==1) ? "" : "s"); + } else if (days==0) { + pprintf(p, "(Up for %d hour%s, %d minute%s and %d second%s)\n", + hours, (hours==1) ? "" : "s", + mins, (mins==1) ? "" : "s", + secs, (secs==1) ? "" : "s"); + } else { + pprintf(p, "(Up for %d day%s, %d hour%s, %d minute%s and %d second%s)\n", + days, (days==1) ? "" : "s", + hours, (hours==1) ? "" : "s", + mins, (mins==1) ? "" : "s", + secs, (secs==1) ? "" : "s"); + } + pprintf(p, "\nAllocs: %u Frees: %u Allocs In Use: %u\n", + malloc_count, free_count, malloc_count - free_count); + if (parray[p].adminLevel >= ADMIN_ADMIN) { + pprintf(p, "\nplayer size:%d, game size:%d, con size:%d, g_num:%d\n", + sizeof(player), sizeof(game), net_consize(), g_num); + getrusage(RUSAGE_SELF, &ru); + pprintf(p, "pagesize = %d, maxrss = %d, total = %d\n", getpagesize(), ru.ru_maxrss, getpagesize() * ru.ru_maxrss); + } + pprintf(p, "\nPlayer limit: %d\n", max_connections); + pprintf(p, "\nThere are currently %d players, with a high of %d since last restart.\n", player_count(), player_high); + pprintf(p, "There are currently %d games, with a high of %d since last restart.\n", game_count(), game_high); + pprintf(p, "\nCompiled on %s\n", COMP_DATE); + return COM_OK; +} + +PUBLIC int com_date(int p, param_list param) +{ + int t = time(0); + pprintf(p, "Local time - %s\n", strltime(&t)); + pprintf(p, "Greenwich time - %s\n", strgtime(&t)); + return COM_OK; +} + +char *inout_string[] = { + "login", "logout" +}; + +PRIVATE int plogins(p, fname) +int p; +char *fname; +{ + FILE *fp; + int inout, thetime, registered; + char loginName[MAX_LOGIN_NAME + 1]; + char ipstr[20]; + + fp = fopen(fname, "r"); + if (!fp) { + pprintf(p, "Sorry, no login information available.\n"); + return COM_OK; + } + while (!feof(fp)) { + if (fscanf(fp, "%d %s %d %d %s\n", &inout, loginName, &thetime, + ®istered, ipstr) != 5) { + fprintf(stderr, "FICS: Error in login info format. %s\n", fname); + fclose(fp); + return COM_OK; + } + pprintf(p, "%s: %-17s %-6s", strltime(&thetime), loginName, + inout_string[inout]); + if (parray[p].adminLevel > 0) { + pprintf(p, " from %s\n", ipstr); + } else + pprintf(p, "\n"); + } + fclose(fp); + return COM_OK; +} + +PUBLIC int com_llogons(int p, param_list param) +{ + char fname[MAX_FILENAME_SIZE]; + + sprintf(fname, "%s/%s", stats_dir, STATS_LOGONS); + return plogins(p, fname); +} + +PUBLIC int com_logons(int p, param_list param) +{ + char fname[MAX_FILENAME_SIZE]; + + if (param[0].type == TYPE_WORD) { + sprintf(fname, "%s/player_data/%c/%s.%s", stats_dir, param[0].val.word[0], param[0].val.word, STATS_LOGONS); + } else { + sprintf(fname, "%s/player_data/%c/%s.%s", stats_dir, parray[p].login[0], parray[p].login, STATS_LOGONS); + } + return plogins(p, fname); +} + +#define WHO_OPEN 0x01 +#define WHO_CLOSED 0x02 +#define WHO_RATED 0x04 +#define WHO_UNRATED 0x08 +#define WHO_FREE 0x10 +#define WHO_PLAYING 0x20 +#define WHO_REGISTERED 0x40 +#define WHO_UNREGISTERED 0x80 + +PRIVATE void who_terse(int p, int num, int *plist, int type) +{ + char ptmp[80 + 20]; /* for highlight */ + multicol *m = multicol_start(PARRAY_SIZE); + int i; + int p1; + int rat; + + /* altered DAV 3/15/95 */ + + for (i = 0; i < num; i++) { + p1 = plist[i]; + if (type == blitz_rat) + rat = parray[p1].b_stats.rating; + if (type == wild_rat) + rat = parray[p1].w_stats.rating; + if (type == std_rat) + rat = parray[p1].s_stats.rating; + + if (type == none) { + sprintf(ptmp, " "); + } else { + sprintf(ptmp, "%-4s", ratstrii(rat, parray[p1].registered)); + if (parray[p1].simul_info.numBoards) { + strcat(ptmp, "~"); + } else if ((parray[p1].game >= 0) && (garray[parray[p1].game].status == GAME_EXAMINE)) { + strcat(ptmp, "#"); + } else if (parray[p1].game >= 0) { + strcat(ptmp, "^"); + } else if (!parray[p1].open) { + strcat(ptmp, ":"); + } else if (player_idle(p1) > 300) { + strcat(ptmp, "."); + } else { + strcat(ptmp, " "); + } + } + if (p == p1) { + psprintf_highlight(p, ptmp + strlen(ptmp), "%s", parray[p1].name); + } else { + strcat(ptmp, parray[p1].name); + } + if ((parray[p1].adminLevel >= 10) && (parray[p1].i_admin)) + strcat(ptmp, "(*)"); + if (in_list("computer", parray[p1].name)) + strcat(ptmp, "(C)"); +/* grimm's fishlist + if (in_list("fish", parray[p1].name)) strcat(ptmp, "(Fish)"); +*/ + if (in_list("fm", parray[p1].name)) + strcat(ptmp, "(FM)"); + if (in_list("im", parray[p1].name)) + strcat(ptmp, "(IM)"); + if (in_list("gm", parray[p1].name)) + strcat(ptmp, "(GM)"); + if (in_list("td", parray[p1].name)) + strcat(ptmp, "(TD)"); + multicol_store(m, ptmp); + } + multicol_pprint(m, p, 80, 2); + multicol_end(m); + pprintf(p, "\n %d Players displayed (of %d). (*) indicates system administrator.\n", num, player_count()); +} + +PRIVATE void who_verbose(p, num, plist) +int p; +int num; +int plist[]; +{ + int i, p1; + char playerLine[255], tmp[255]; /* +8 for highlight */ + + pprintf(p, + " +---------------------------------------------------------------+\n" + ); + pprintf(p, + " | User Standard Blitz On for Idle |\n" + ); + pprintf(p, + " +---------------------------------------------------------------+\n" + ); + + for (i = 0; i < num; i++) { + p1 = plist[i]; + + strcpy(playerLine, " |"); + + if (parray[p1].game >= 0) + sprintf(tmp, "%3d", parray[p1].game + 1); + else + sprintf(tmp, " "); + strcat(playerLine, tmp); + + if (!parray[p1].open) + sprintf(tmp, "X"); + else + sprintf(tmp, " "); + strcat(playerLine, tmp); + + if (parray[p1].registered) + if (parray[p1].rated) { + sprintf(tmp, " "); + } else { + sprintf(tmp, "u"); + } + else + sprintf(tmp, "U"); + strcat(playerLine, tmp); + + /* Modified by DAV 3/15/95 */ + if (p == p1) { + strcpy(tmp, " "); + psprintf_highlight(p, tmp + strlen(tmp), "%-17s", parray[p1].name); + } else { + sprintf(tmp, " %-17s", parray[p1].name); + } + strcat(playerLine, tmp); + + sprintf(tmp, " %4s %-4s %5s ", + ratstrii(parray[p1].s_stats.rating, parray[p1].registered), + ratstrii(parray[p1].b_stats.rating, parray[p1].registered), + hms(player_ontime(p1), 0, 0, 0)); + strcat(playerLine, tmp); + + if (player_idle(p1) >= 60) { + sprintf(tmp, "%5s |\n", hms(player_idle(p1), 0, 0, 0)); + } else { + sprintf(tmp, " |\n"); + } + strcat(playerLine, tmp); + pprintf(p, "%s", playerLine); + } + + pprintf(p, + " | |\n" + ); + pprintf(p, + " | %3d Players Displayed |\n", + num + ); + pprintf(p, + " +---------------------------------------------------------------+\n" + ); +} + +PRIVATE void who_winloss(p, num, plist) +int p; +int num; +int plist[]; +{ + int i, p1; + char playerLine[255], tmp[255]; /* for highlight */ + + pprintf(p, + "Name Stand win loss draw Blitz win loss draw idle\n" + ); + pprintf(p, + "---------------- ----- ------------- ----- ------------- ----\n" + ); + + for (i = 0; i < num; i++) { + p1 = plist[i]; + if (p1 == p) { + psprintf_highlight(p, playerLine, "%-17s", parray[p1].name); + } else { + sprintf(playerLine, "%-17s", parray[p1].name); + } + sprintf(tmp, " %4s %4d %4d %4d ", + ratstrii(parray[p1].s_stats.rating, parray[p1].registered), + (int) parray[p1].s_stats.win, + (int) parray[p1].s_stats.los, + (int) parray[p1].s_stats.dra); + strcat(playerLine, tmp); + + sprintf(tmp, "%4s %4d %4d %4d ", + ratstrii(parray[p1].b_stats.rating, parray[p1].registered), + (int) parray[p1].b_stats.win, + (int) parray[p1].b_stats.los, + (int) parray[p1].b_stats.dra); + strcat(playerLine, tmp); + + if (player_idle(p1) >= 60) { + sprintf(tmp, "%5s\n", hms(player_idle(p1), 0, 0, 0)); + } else { + sprintf(tmp, " \n"); + } + strcat(playerLine, tmp); + + pprintf(p, "%s", playerLine); + } + pprintf(p, " %3d Players Displayed.\n", num); +} + +PRIVATE int who_ok(p, sel_bits) +int p; +unsigned int sel_bits; +{ + if (parray[p].status != PLAYER_PROMPT) + return 0; + if (sel_bits == 0xff) + return 1; + if (sel_bits & WHO_OPEN) + if (!parray[p].open) + return 0; + if (sel_bits & WHO_CLOSED) + if (parray[p].open) + return 0; + if (sel_bits & WHO_RATED) + if (!parray[p].rated) + return 0; + if (sel_bits & WHO_UNRATED) + if (parray[p].rated) + return 0; + if (sel_bits & WHO_FREE) + if (parray[p].game >= 0) + return 0; + if (sel_bits & WHO_PLAYING) + if (parray[p].game < 0) + return 0; + if (sel_bits & WHO_REGISTERED) + if (!parray[p].registered) + return 0; + if (sel_bits & WHO_UNREGISTERED) + if (parray[p].registered) + return 0; + return 1; +} + + +PRIVATE int blitz_cmp(const void *pp1, const void *pp2) +{ + register int p1 = *(int *) pp1; + register int p2 = *(int *) pp2; + if (parray[p1].status != PLAYER_PROMPT) { + if (parray[p2].status != PLAYER_PROMPT) + return 0; + else + return -1; + } + if (parray[p2].status != PLAYER_PROMPT) + return 1; + if (parray[p1].b_stats.rating > parray[p2].b_stats.rating) + return -1; + if (parray[p1].b_stats.rating < parray[p2].b_stats.rating) + return 1; + if (parray[p1].registered > parray[p2].registered) + return -1; + if (parray[p1].registered < parray[p2].registered) + return 1; + return strcmp(parray[p1].login, parray[p2].login); +} + +PRIVATE int stand_cmp(const void *pp1, const void *pp2) +{ + register int p1 = *(int *) pp1; + register int p2 = *(int *) pp2; + if (parray[p1].status != PLAYER_PROMPT) { + if (parray[p2].status != PLAYER_PROMPT) + return 0; + else + return -1; + } + if (parray[p2].status != PLAYER_PROMPT) + return 1; + if (parray[p1].s_stats.rating > parray[p2].s_stats.rating) + return -1; + if (parray[p1].s_stats.rating < parray[p2].s_stats.rating) + return 1; + if (parray[p1].registered > parray[p2].registered) + return -1; + if (parray[p1].registered < parray[p2].registered) + return 1; + return strcmp(parray[p1].login, parray[p2].login); +} + +PRIVATE int wild_cmp(const void *pp1, const void *pp2) +{ + register int p1 = *(int *) pp1; + register int p2 = *(int *) pp2; + if (parray[p1].status != PLAYER_PROMPT) { + if (parray[p2].status != PLAYER_PROMPT) + return 0; + else + return -1; + } + if (parray[p2].status != PLAYER_PROMPT) + return 1; + if (parray[p1].w_stats.rating > parray[p2].w_stats.rating) + return -1; + if (parray[p1].w_stats.rating < parray[p2].w_stats.rating) + return 1; + if (parray[p1].registered > parray[p2].registered) + return -1; + if (parray[p1].registered < parray[p2].registered) + return 1; + return strcmp(parray[p1].login, parray[p2].login); +} + +PRIVATE int alpha_cmp(const void *pp1, const void *pp2) +{ + register int p1 = *(int *) pp1; + register int p2 = *(int *) pp2; + if (parray[p1].status != PLAYER_PROMPT) { + if (parray[p2].status != PLAYER_PROMPT) + return 0; + else + return -1; + } + if (parray[p2].status != PLAYER_PROMPT) + return 1; + return strcmp(parray[p1].login, parray[p2].login); +} + +PUBLIC void sort_players(int players[PARRAY_SIZE], + int ((*cmp_func) (const void *, const void *))) +{ + int i; + + for (i = 0; i < p_num; i++) { + players[i] = i; + } + qsort(players, p_num, sizeof(int), cmp_func); +} + +/* This is the of the most compliclicated commands in terms of parameters */ +PUBLIC int com_who(int p, param_list param) +{ + int style = 0; + float stop_perc = 1.0; + float start_perc = 0; + unsigned int sel_bits = 0xff; + int sortlist[PARRAY_SIZE], plist[PARRAY_SIZE]; + int ((*cmp_func) (const void *, const void *)) = blitz_cmp; + int startpoint; + int stoppoint; + int i, len; + int tmpI, tmpJ; + char c; + int p1, count, num_who; + int sort_type = blitz_rat; + + if (param[0].type == TYPE_WORD) { + len = strlen(param[0].val.word); + for (i = 0; i < len; i++) { + c = param[0].val.word[i]; + if (isdigit(c)) { + if (i == 0 || !isdigit(param[0].val.word[i - 1])) { + tmpI = c - '0'; + if (tmpI == 1) { + start_perc = 0.0; + stop_perc = 0.333333; + } else if (tmpI == 2) { + start_perc = 0.333333; + stop_perc = 0.6666667; + } else if (tmpI == 3) { + start_perc = 0.6666667; + stop_perc = 1.0; + } else if ((i == len - 1) || (!isdigit(param[0].val.word[i + 1]))) + return COM_BADPARAMETERS; + } else { + tmpI = c - '0'; + tmpJ = param[0].val.word[i - 1] - '0'; + if (tmpI == 0) + return COM_BADPARAMETERS; + if (tmpJ > tmpI) + return COM_BADPARAMETERS; + start_perc = ((float) tmpJ - 1.0) / (float) tmpI; + stop_perc = ((float) tmpJ) / (float) tmpI; + } + } else { + switch (c) { + case 'o': + if (sel_bits == 0xff) + sel_bits = WHO_OPEN; + else + sel_bits |= WHO_OPEN; + break; + case 'r': + if (sel_bits == 0xff) + sel_bits = WHO_RATED; + else + sel_bits |= WHO_RATED; + break; + case 'f': + if (sel_bits == 0xff) + sel_bits = WHO_FREE; + else + sel_bits |= WHO_FREE; + break; + case 'a': + if (sel_bits == 0xff) + sel_bits = WHO_FREE | WHO_OPEN; + else + sel_bits |= (WHO_FREE | WHO_OPEN); + break; + case 'R': + if (sel_bits == 0xff) + sel_bits = WHO_REGISTERED; + else + sel_bits |= WHO_REGISTERED; + break; + case 'l': /* Sort order */ + cmp_func = alpha_cmp; + sort_type = none; + break; + case 'A': /* Sort order */ + cmp_func = alpha_cmp; + break; + case 'w': /* Sort order */ + cmp_func = wild_cmp; + sort_type = wild_rat; + break; + case 's': /* Sort order */ + cmp_func = stand_cmp; + sort_type = std_rat; + break; + case 'b': /* Sort order */ + cmp_func = blitz_cmp; + sort_type = blitz_rat; + break; + case 't': /* format */ + style = 0; + break; + case 'v': /* format */ + style = 1; + break; + case 'n': /* format */ + style = 2; + break; + case 'U': + if (sel_bits == 0xff) + sel_bits = WHO_UNREGISTERED; + else + sel_bits |= WHO_UNREGISTERED; + break; + default: + return COM_BADPARAMETERS; + break; + } + } + } + } + sort_players(sortlist, cmp_func); + count = 0; + for (p1 = 0; p1 < p_num; p1++) { + if (!who_ok(sortlist[p1], sel_bits)) + continue; + count++; + } + startpoint = floor((float) count * start_perc); + stoppoint = ceil((float) count * stop_perc) - 1; + num_who = 0; + count = 0; + for (p1 = 0; p1 < p_num; p1++) { + if (!who_ok(sortlist[p1], sel_bits)) + continue; + if ((count >= startpoint) && (count <= stoppoint)) { + plist[num_who++] = sortlist[p1]; + } + count++; + } + if (num_who == 0) { + pprintf(p, "No logged in players match the flags in your who request.\n"); + return COM_OK; + } + switch (style) { + case 0: /* terse */ + who_terse(p, num_who, plist, sort_type); + break; + case 1: /* verbose */ + who_verbose(p, num_who, plist); + break; + case 2: /* win-loss */ + who_winloss(p, num_who, plist); + break; + default: + return COM_BADPARAMETERS; + break; + } + return COM_OK; +} + + + + +PRIVATE int notorcen(int p, param_list param, int *num, int max, + char **list, char *listname) +{ + int i, p1, connected; + + if (param[0].type != TYPE_WORD) { + if (!*num) { + pprintf(p, "Your %s list is empty.\n", listname); + return COM_OK; + } else + pprintf(p, "-- Your %s list contains %d names: --", listname, *num); + /* New code to print names in columns */ + { + multicol *m = multicol_start(MAX_NOTIFY + 1); + for (i = 0; i < *num; i++) + multicol_store_sorted(m, list[i]); + multicol_pprint(m, p, 78, 2); + multicol_end(m); + } + return COM_OK; + } + if (*num >= max) { + pprintf(p, "Sorry, your %s list is already full.\n", listname); + return COM_OK; + } + if (!FindPlayer(p, ¶m[0], &p1, &connected)) + return COM_OK; + + for (i = 0; i < *num; i++) { + if (!strcasecmp(list[i], param[0].val.word)) { + pprintf(p, "Your %s list already includes %s.\n", + listname, parray[p1].name); + if (!connected) + player_remove(p1); + return COM_OK; + } + } + if (p1 == p) { + pprintf(p, "You can't %s yourself.\n", listname); + return COM_OK; + } + list[*num] = strdup(parray[p1].name); + ++(*num); + pprintf(p, "%s is now on your %s list.\n", parray[p1].name, listname); + if (!connected) + player_remove(p1); + return COM_OK; +} + + +PRIVATE int unnotorcen(int p, param_list param, int *num, int max, + char **list, char *listname) +{ + char *pname = NULL; + int i, j; + int unc = 0; + + if (param[0].type == TYPE_WORD) { + pname = param[0].val.word; + } + for (i = 0; i < *num; i++) { + if (!pname || !strcasecmp(pname, list[i])) { + pprintf(p, "%s is removed from your %s list.\n", + list[i], listname); + rfree(list[i]); + list[i] = NULL; + unc++; + } + } + if (unc) { + i = 0; + j = 0; + while (j < *num) { + if (list[j] != NULL) { + list[i++] = list[j]; + } + j++; + } + while (i < j) { + list[i++] = NULL; + } + (*num) -= unc; + } else { + pprintf(p, "No one was removed from your %s list.\n", listname); + } + return COM_OK; +} + + +PUBLIC int com_notify(int p, param_list param) +{ + return notorcen(p, param, &parray[p].num_notify, MAX_NOTIFY, + parray[p].notifyList, "notify"); +} + +PUBLIC int com_censor(int p, param_list param) +{ + return notorcen(p, param, &parray[p].num_censor, MAX_CENSOR, + parray[p].censorList, "censor"); +} + +PUBLIC int com_unnotify(int p, param_list param) +{ + return unnotorcen(p, param, &parray[p].num_notify, MAX_NOTIFY, + parray[p].notifyList, "notify"); +} + +PUBLIC int com_uncensor(int p, param_list param) +{ + return unnotorcen(p, param, &parray[p].num_censor, MAX_CENSOR, + parray[p].censorList, "censor"); +} + + +PUBLIC int com_channel(int p, param_list param) +{ + int i, err; + + if (param[0].type == TYPE_NULL) { /* Turn off all channels */ + for (i = 0; i < MAX_CHANNELS; i++) { + if (!channel_remove(i, p)) + pprintf(p, "Channel %d turned off.\n", i); + } + } else { + i = param[0].val.integer; + if ((i == 0) && (parray[p].adminLevel == 0)) { + pprintf(p, "Only admins may join channel 0.\n"); + return COM_OK; + } + if (i < 0) { + pprintf(p, "The lowest channel number is 0.\n"); + return COM_OK; + } + if (i >= MAX_CHANNELS) { + pprintf(p, "The maximum channel number is %d.\n", MAX_CHANNELS - 1); + return COM_OK; + } + if (on_channel(i, p)) { + if (!channel_remove(i, p)) + pprintf(p, "Channel %d turned off.\n", i); + } else { + if (!(err = channel_add(i, p))) + pprintf(p, "Channel %d turned on.\n", i); + else { + if (err == 1) + pprintf(p, "Channel %d is already full.\n", i); + if (err == 2) + pprintf(p, "Maximum channel number exceeded.\n"); + } + } + } + return COM_OK; +} + +PUBLIC int com_inchannel(int p, param_list param) +{ + int c1, c2; + int i, j, count = 0; + + if (param[0].type == TYPE_NULL) { /* List everyone on every channel */ + c1 = -1; + c2 = -1; + } else if (param[1].type == TYPE_NULL) { /* One parameter */ + c1 = param[0].val.integer; + if (c1 < 0) { + pprintf(p, "The lowest channel number is 0.\n"); + return COM_OK; + } + c2 = -1; + } else { /* Two parameters */ + c1 = param[0].val.integer; + c2 = param[2].val.integer; + if ((c1 < 0) || (c2 < 0)) { + pprintf(p, "The lowest channel number is 0.\n"); + return COM_OK; + } + pprintf(p, "Two parameter inchannel is not implemented.\n"); + return COM_OK; + } + if ((c1 >= MAX_CHANNELS) || (c2 >= MAX_CHANNELS)) { + pprintf(p, "The maximum channel number is %d.\n", MAX_CHANNELS - 1); + return COM_OK; + } + for (i = 0; i < MAX_CHANNELS; i++) { + if (numOn[i] && ((c1 < 0) || (i == c1))) { + pprintf(p, "Channel %d:", i); + for (j = 0; j < numOn[i]; j++) { + pprintf(p, " %s", parray[channels[i][j]].name); + } + count++; + pprintf(p, "\n"); + } + } + if (!count) { + if (c1 < 0) + pprintf(p, "No channels in use.\n"); + else + pprintf(p, "Channel not in use.\n"); + } + return COM_OK; +} + + +PUBLIC int create_new_match(int white_player, int black_player, + int wt, int winc, int bt, int binc, + int rated, char *category, char *board, + int white) +{ + int g = game_new(), p; + char outStr[1024]; + int reverse = 0; + + if (g < 0) + return COM_FAILED; + if (white == 0) { + reverse = 1; + } else if (white == -1) { + if (!bt) { + if (parray[white_player].lastColor == parray[black_player].lastColor) { + if ((parray[white_player].num_white - parray[white_player].num_black) > + (parray[black_player].num_white - parray[black_player].num_black)) + reverse = 1; + } else if (parray[white_player].lastColor == WHITE) + reverse = 1; + } else + reverse = 1; /* Challenger is always white in unbalanced + match */ + } + if (reverse) { + int tmp = white_player; + white_player = black_player; + black_player = tmp; + } + player_remove_request(white_player, black_player, PEND_MATCH); + player_remove_request(black_player, white_player, PEND_MATCH); + player_remove_request(white_player, black_player, PEND_SIMUL); + player_remove_request(black_player, white_player, PEND_SIMUL); + player_decline_offers(white_player, -1, PEND_MATCH); + player_withdraw_offers(white_player, -1, PEND_MATCH); + player_decline_offers(black_player, -1, PEND_MATCH); + player_withdraw_offers(black_player, -1, PEND_MATCH); + player_withdraw_offers(white_player, -1, PEND_SIMUL); + player_withdraw_offers(black_player, -1, PEND_SIMUL); + + wt = wt * 60; /* To Seconds */ + bt = bt * 60; + garray[g].white = white_player; + garray[g].black = black_player; + strcpy(garray[g].white_name, parray[white_player].name); + strcpy(garray[g].black_name, parray[black_player].name); + garray[g].status = GAME_ACTIVE; + garray[g].type = game_isblitz(wt / 60, winc, bt / 60, binc, category, board); + if ((garray[g].type == TYPE_UNTIMED) || (garray[g].type == TYPE_NONSTANDARD)) + garray[g].rated = 0; + else + garray[g].rated = rated; + garray[g].private = parray[white_player].private || + parray[black_player].private; + garray[g].white = white_player; + if (garray[g].type == TYPE_BLITZ) { + garray[g].white_rating = parray[white_player].b_stats.rating; + garray[g].black_rating = parray[black_player].b_stats.rating; + } else if (garray[g].type == TYPE_WILD) { + garray[g].white_rating = parray[white_player].w_stats.rating; + garray[g].black_rating = parray[black_player].w_stats.rating; + } else { + garray[g].white_rating = parray[white_player].s_stats.rating; + garray[g].black_rating = parray[black_player].s_stats.rating; + } + if (board_init(&garray[g].game_state, category, board)) { + pprintf(white_player, "PROBLEM LOADING BOARD. Game Aborted.\n"); + pprintf(black_player, "PROBLEM LOADING BOARD. Game Aborted.\n"); + fprintf(stderr, "FICS: PROBLEM LOADING BOARD %s %s. Game Aborted.\n", + category, board); + } + garray[g].game_state.gameNum = g; + garray[g].wTime = wt * 10; + garray[g].wInitTime = wt * 10; + garray[g].wIncrement = winc * 10; + if (bt == 0) { + garray[g].bTime = wt * 10; + } else { + garray[g].bTime = bt * 10; + } + garray[g].bInitTime = bt * 10; + garray[g].bIncrement = binc * 10; + if (garray[g].game_state.onMove == BLACK) { /* Start with black */ + garray[g].numHalfMoves = 1; + garray[g].moveListSize = 1; + garray[g].moveList = (move_t *) rmalloc(sizeof(move_t)); + garray[g].moveList[0].fromFile = -1; + garray[g].moveList[0].fromRank = -1; + garray[g].moveList[0].toFile = -1; + garray[g].moveList[0].toRank = -1; + garray[g].moveList[0].color = WHITE; + strcpy(garray[g].moveList[0].moveString, "NONE"); + strcpy(garray[g].moveList[0].algString, "NONE"); + } else { + garray[g].numHalfMoves = 0; + garray[g].moveListSize = 0; + garray[g].moveList = NULL; + } + garray[g].timeOfStart = tenth_secs(); + garray[g].startTime = tenth_secs(); + garray[g].lastMoveTime = garray[g].startTime; + garray[g].lastDecTime = garray[g].startTime; + garray[g].clockStopped = 0; + sprintf(outStr, "\n{Game %d (%s vs. %s) Creating %s %s match.}\n", + g + 1, parray[white_player].name, + parray[black_player].name, + rstr[garray[g].rated], + bstr[garray[g].type]); + pprintf(white_player, "%s", outStr); + pprintf(black_player, "%s", outStr); + + for (p = 0; p < p_num; p++) { + if ((p == white_player) || (p == black_player)) + continue; + if (parray[p].status != PLAYER_PROMPT) + continue; + if (!parray[p].i_game) + continue; + pprintf_prompt(p, "%s", outStr); + } + parray[white_player].game = g; + parray[white_player].opponent = black_player; + parray[white_player].side = WHITE; + parray[white_player].promote = QUEEN; + parray[black_player].game = g; + parray[black_player].opponent = white_player; + parray[black_player].side = BLACK; + parray[black_player].promote = QUEEN; + send_boards(g); + + strcpy(garray[g].boardList[garray[g].numHalfMoves], boardToFEN(g)); + + return COM_OK; +} + +PRIVATE int accept_match(int p, int p1) +{ + int g, adjourned, foo; + int wt, winc, bt, binc, rated, white; + char *category, *board; + pending *pend; + char tmp[100]; + + unobserveAll(p); /* stop observing when match starts */ + unobserveAll(p1); + + pend = &parray[p].p_from_list[player_find_pendfrom(p, p1, PEND_MATCH)]; + wt = pend->param1; + winc = pend->param2; + bt = pend->param3; + binc = pend->param4; + rated = pend->param5; + category = pend->char1; + board = pend->char2; + white = (pend->param6 == -1) ? -1 : 1 - pend->param6; + + pprintf(p, "You accept the challenge of %s.\n", parray[p1].name); + pprintf(p1, "\n%s accepts your challenge.\n", parray[p].name); + player_remove_request(p, p1, -1); + player_remove_request(p1, p, -1); + + while ((foo = player_find_pendto(p, -1, -1)) != -1) { + foo = parray[p].p_to_list[foo].whoto; + pprintf_prompt(foo, "\n%s, who was challenging you, has joined a match with %s.\n", parray[p].name, parray[p1].name); + pprintf(p, "Challenge to %s withdrawn.\n", parray[foo].name); + player_remove_request(p, foo, -1); + } + + while ((foo = player_find_pendto(p1, -1, -1)) != -1) { + foo = parray[p1].p_to_list[foo].whoto; + pprintf_prompt(foo, "\n%s, who was challenging you, has joined a match with %s.\n", parray[p1].name, parray[p].name); + pprintf(p1, "Challenge to %s withdrawn.\n", parray[foo].name); + player_remove_request(p1, foo, -1); + } + + while ((foo = player_find_pendfrom(p, -1, -1)) != -1) { + foo = parray[p].p_from_list[foo].whofrom; + pprintf_prompt(foo, "\n%s, whom you were challenging, has joined a match with %s.\n", parray[p].name, parray[p1].name); + pprintf(p, "Challenge from %s removed.\n", parray[foo].name); + player_remove_request(foo, p, -1); + } + + while ((foo = player_find_pendfrom(p1, -1, -1)) != -1) { + foo = parray[p1].p_from_list[foo].whofrom; + pprintf_prompt(foo, "\n%s, whom you were challenging, has joined a match with %s.\n", parray[p1].name, parray[p].name); + pprintf(p1, "Challenge from %s removed.\n", parray[foo].name); + player_remove_request(foo, p1, -1); + } + + g = game_new(); + adjourned = 0; + if (game_read(g, p, p1) >= 0) + adjourned = 1; + else if (game_read(g, p1, p) >= 0) { + int swap; + adjourned = 1; + swap = p; + p = p1; + p1 = swap; + } + if (!adjourned) { /* no adjourned game, so begin a new game */ + game_remove(g); + + if (create_new_match(p, p1, wt, winc, bt, binc, rated, category, board, white) != COM_OK) { + sprintf(tmp, "There was a problem creating the new match.\n"); + pprintf(p, tmp); + pprintf_prompt(p1, tmp); + } + } else { /* resume adjourned game */ + game_delete(p, p1); + + sprintf(tmp, "{Game %d (%s vs. %s) Continuing %s %s match.}\n", g + 1, parray[p].name, parray[p1].name, rstr[garray[g].rated], bstr[garray[g].type]); + pprintf(p, tmp); + pprintf(p1, tmp); + + garray[g].white = p; + garray[g].black = p1; + garray[g].status = GAME_ACTIVE; + garray[g].startTime = tenth_secs(); + garray[g].lastMoveTime = garray[g].startTime; + garray[g].lastDecTime = garray[g].startTime; + parray[p].game = g; + parray[p].opponent = p1; + parray[p].side = WHITE; + parray[p1].game = g; + parray[p1].opponent = p; + parray[p1].side = BLACK; + send_boards(g); + } + return COM_OK; +} + +PUBLIC int com_match(int p, param_list param) +{ + int adjourned; /* adjourned game? */ + int g; /* more adjourned game junk */ + int p1; + int pendfrom, pendto; + int ppend, p1pend; + int wt = -1; /* white start time */ + int winc = -1; /* white increment */ + int bt = -1; /* black start time */ + int binc = -1; /* black increment */ + int rated = -1; /* 1 = rated, 0 = unrated */ + int white = -1; /* 1 = want white, 0 = want black */ + char category[100], board[100], parsebuf[100]; + char strFormula[MAX_STRING_LENGTH]; + char *val; + int type; + int confused = 0; + char *colorstr[] = {"", "[black] ", "[white] "}; + char *adjustr[] = {"", " (adjourned)"}; + + if ((parray[p].game >= 0) && (garray[parray[p].game].status == GAME_EXAMINE)) { + pprintf(p, "You can't challenge while you are examining a game.\n"); + return COM_OK; + } + if (parray[p].game >= 0) { + pprintf(p, "You can't challenge while you are playing a game.\n"); + return COM_OK; + } + stolower(param[0].val.word); + p1 = player_find_part_login(param[0].val.word); + if (p1 < 0) { + pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word); + return COM_OK; + } + + if (p1 == p) { /* Allowing to match yourself to enter analysis mode */ + pprintf(p, "Starting a game in examine mode.\n"); + { + int g = game_new(); + + unobserveAll(p); + + player_decline_offers(p, -1, PEND_MATCH); + player_withdraw_offers(p, -1, PEND_MATCH); + player_withdraw_offers(p, -1, PEND_SIMUL); + + garray[g].wInitTime = garray[g].wIncrement = 0; + garray[g].bInitTime = garray[g].bIncrement = 0; + garray[g].timeOfStart = tenth_secs(); + garray[g].wTime = garray[g].bTime = 0; + garray[g].rated = 0; + garray[g].clockStopped = 0; + garray[g].type = TYPE_UNTIMED; + garray[g].white = garray[g].black = p; + garray[g].status = GAME_EXAMINE; + garray[g].startTime = tenth_secs(); + garray[g].lastMoveTime = garray[g].startTime; + garray[g].lastDecTime = garray[g].startTime; + + parray[p].side = WHITE; /* oh well... */ + parray[p].game = g; + + category[0]='\0'; board[0]='\0'; + if (board_init(&garray[g].game_state, category, board)) { + pprintf(p, "PROBLEM LOADING BOARD. Game Aborted.\n"); + fprintf(stderr, "FICS: PROBLEM LOADING BOARD %s %s. Game Aborted.\n", + category, board); + } + garray[g].game_state.gameNum = g; + strcpy(garray[g].white_name, parray[p].name); + strcpy(garray[g].black_name, parray[p].name); + garray[g].white_rating = garray[g].black_rating = parray[p].s_stats.rating; + + send_boards(g); + + strcpy(garray[g].boardList[garray[g].numHalfMoves], boardToFEN(g)); + + } + return COM_OK; + } + + if (parray[p].open == 0) { + parray[p].open = 1; + pprintf(p, "Setting you open for matches.\n"); + } + if (player_censored(p1, p)) { + pprintf(p, "Player \"%s\" is censoring you.\n", parray[p1].name); + return COM_OK; + } + if (player_censored(p, p1)) { + pprintf(p, "You are censoring \"%s\".\n", parray[p1].name); + return COM_OK; + } + if (!parray[p1].open) { + pprintf(p, "Player \"%s\" is not open to match requests.\n", parray[p1].name); + return COM_OK; + } + if (parray[p1].game >= 0) { + pprintf(p, "Player \"%s\" is involved in another game.\n", parray[p1].name); + return COM_OK; + } +/* look for an adjourned game between p and p1 */ + g = game_new(); + adjourned = ((game_read(g, p, p1) < 0) && (game_read(g, p1, p) < 0)) ? 0 : 1; + if (adjourned) { + type = garray[g].type; + wt = garray[g].wInitTime / 600; + bt = garray[g].bInitTime / 600; + winc = garray[g].wIncrement / 10; + binc = garray[g].bIncrement / 10; + rated = garray[g].rated; + } + game_remove(g); + + pendto = player_find_pendto(p, p1, PEND_MATCH); + pendfrom = player_find_pendfrom(p, p1, PEND_MATCH); + category[0] = '\0'; + board[0] = '\0'; + + if (!adjourned) { + if (param[1].type != TYPE_NULL) { + int numba; /* temp for atoi() */ + + val = param[1].val.string; + while (!confused && (sscanf(val, " %99s", parsebuf) == 1)) { + val = eatword(eatwhite(val)); + if ((category[0] != '\0') && (board[0] == '\0')) + strcpy(board, parsebuf); + else if (isdigit(*parsebuf)) { + if ((numba = atoi(parsebuf)) < 0) { + pprintf(p, "You can't specify negative time controls.\n"); + return COM_OK; + } else if (wt == -1) { + wt = numba; + } else if (winc == -1) { + winc = numba; + } else if (bt == -1) { + bt = numba; + } else if (binc == -1) { + binc = numba; + } else { + confused = 1; + } + } else if (strstr("rated", parsebuf) != NULL) { + if (rated == -1) + rated = 1; + else + confused = 1; + } else if (strstr("unrated", parsebuf) != NULL) { + if (rated == -1) + rated = 0; + else + confused = 1; + } else if (strstr("white", parsebuf) != NULL) { + if (white == -1) + white = 1; + else + confused = 1; + } else if (strstr("black", parsebuf) != NULL) { + if (white == -1) + white = 0; + else + confused = 1; + } else if (category[0] == '\0') + strcpy(category, parsebuf); + else + confused = 1; + } + if (confused) { + pprintf(p, "Can't interpret %s in match command.\n", parsebuf); + return COM_OK; + } + } + rated = ((rated == -1) ? parray[p].rated : rated) && parray[p1].registered && parray[p].registered; + if (winc == -1) + winc = (wt == -1) ? parray[p].d_inc : 0; /* match 5 == match 5 0 */ + if (wt == -1) + wt = parray[p].d_time; + if (bt == -1) + bt = 0; + if (binc == -1) + binc = winc; + + if (category[0] && !board[0]) { + pprintf(p, "You must specify a board and a category.\n"); + return COM_OK; + } + if (category[0]) { + char fname[MAX_FILENAME_SIZE]; + + sprintf(fname, "%s/%s/%s", board_dir, category, board); + if (!file_exists(fname)) { + pprintf(p, "No such category/board: %s/%s\n", category, board); + return COM_OK; + } + } + if ((pendfrom < 0) && (parray[p1].ropen == 0) && (rated != parray[p1].rated)) { + pprintf(p, "%s only wants to play %s games.\n", parray[p1].name, + rstr[parray[p1].rated]); + pprintf(p1, "Ignoring %srated match request from %s.\n", + (parray[p1].rated ? "un" : ""), parray[p].name); + return COM_OK; + } + type = game_isblitz(wt, winc, bt, binc, category, board); + if (rated && (type == TYPE_STAND || type == TYPE_BLITZ || type == TYPE_WILD)) { + if (parray[p].network_player == parray[p1].network_player) { + rated = 1; + } else { + pprintf(p, "Network vs. local player forced to not rated\n"); + rated = 0; + } + } + if (rated && (type == TYPE_NONSTANDARD)) { + pprintf(p, "Game is non-standard - reverting to unrated\n"); + rated = 0; + } + if (rated && (type == TYPE_UNTIMED)) { + pprintf(p, "Game is untimed - reverting to unrated\n"); + rated = 0; + } + /* Now check formula. */ + if ((pendfrom < 0 || param[1].type != TYPE_NULL) && + !GameMatchesFormula(p, p1, wt, winc, bt, binc, rated, type, strFormula)) { + pprintf(p, "Match request does not fit formula for %s:\n", + parray[p1].name); + pprintf(p, "%s's formula: %s\n", parray[p1].name, parray[p1].formula); + pprintf(p, "Evaluated: %s\n", strFormula); + pprintf_prompt(p1, "Ignoring (formula): %s (%d) %s (%d) %s.\n", + parray[p].name, + GetRating(&parray[p], type), + parray[p1].name, + GetRating(&parray[p1], type), + game_str(rated, wt * 60, winc, bt * 60, binc, category, board)); + return COM_OK; + } + /* Ok match offer will be made */ + + } /* adjourned games shouldn't have to worry + about that junk? */ + if (pendto >= 0) { + pprintf(p, "Updating offer already made to \"%s\".\n", parray[p1].name); + } + if (pendfrom >= 0) { + if (pendto >= 0) { + pprintf(p, "Internal error\n"); + fprintf(stderr, "FICS: This shouldn't happen. You can't have a match pending from and to the same person.\n"); + return COM_OK; + } + if (adjourned || ((wt == parray[p].p_from_list[pendfrom].param1) && + (winc == parray[p].p_from_list[pendfrom].param2) && + (bt == parray[p].p_from_list[pendfrom].param3) && + (binc == parray[p].p_from_list[pendfrom].param4) && + (rated == parray[p].p_from_list[pendfrom].param5) && + ((white == -1) || (white + parray[p].p_from_list[pendfrom].param6 == 1)) && + (!strcmp(category, parray[p].p_from_list[pendfrom].char1)) && + (!strcmp(board, parray[p].p_from_list[pendfrom].char2)))) { + /* Identical match, should accept! */ + accept_match(p, p1); + return COM_OK; + } else { + player_remove_pendfrom(p, p1, PEND_MATCH); + player_remove_pendto(p1, p, PEND_MATCH); + } + } + if (pendto < 0) { + ppend = player_new_pendto(p); + if (ppend < 0) { + pprintf(p, "Sorry you can't have any more pending matches.\n"); + return COM_OK; + } + p1pend = player_new_pendfrom(p1); + if (p1pend < 0) { + pprintf(p, "Sorry %s can't have any more pending matches.\n", parray[p1].name); + parray[p].num_to = parray[p].num_to - 1; + return COM_OK; + } + } else { + ppend = pendto; + p1pend = player_find_pendfrom(p1, p, PEND_MATCH); + } + parray[p].p_to_list[ppend].param1 = wt; + parray[p].p_to_list[ppend].param2 = winc; + parray[p].p_to_list[ppend].param3 = bt; + parray[p].p_to_list[ppend].param4 = binc; + parray[p].p_to_list[ppend].param5 = rated; + parray[p].p_to_list[ppend].param6 = white; + strcpy(parray[p].p_to_list[ppend].char1, category); + strcpy(parray[p].p_to_list[ppend].char2, board); + parray[p].p_to_list[ppend].type = PEND_MATCH; + parray[p].p_to_list[ppend].whoto = p1; + parray[p].p_to_list[ppend].whofrom = p; + + parray[p1].p_from_list[p1pend].param1 = wt; + parray[p1].p_from_list[p1pend].param2 = winc; + parray[p1].p_from_list[p1pend].param3 = bt; + parray[p1].p_from_list[p1pend].param4 = binc; + parray[p1].p_from_list[p1pend].param5 = rated; + parray[p1].p_from_list[p1pend].param6 = white; + strcpy(parray[p1].p_from_list[p1pend].char1, category); + strcpy(parray[p1].p_from_list[p1pend].char2, board); + parray[p1].p_from_list[p1pend].type = PEND_MATCH; + parray[p1].p_from_list[p1pend].whoto = p1; + parray[p1].p_from_list[p1pend].whofrom = p; + + if (pendfrom >= 0) { + pprintf(p, "Declining offer from %s and offering new match parameters.\n", parray[p1].name); + pprintf(p1, "\n%s declines your match offer a match with these parameters:", parray[p].name); + } + if (pendto >= 0) { + pprintf(p, "Updating match request to: "); + pprintf(p1, "\n%s updates the match request.\n", parray[p].name); + } else { + pprintf(p, "Issuing: "); + pprintf(p1, "\n", parray[p].name); + } + + pprintf(p, "%s (%s) %s", parray[p].name, + ratstrii(GetRating(&parray[p], type), parray[p].registered), + colorstr[white + 1]); + pprintf_highlight(p, "%s", parray[p1].name); + pprintf(p, " (%s) %s%s.\n", + ratstrii(GetRating(&parray[p1], type), parray[p1].registered), + game_str(rated, wt * 60, winc, bt * 60, binc, category, board), + adjustr[adjourned]); + pprintf(p1, "Challenge: "); + pprintf_highlight(p1, "%s", parray[p].name); + pprintf(p1, " (%s) %s", ratstrii(GetRating(&parray[p], type), parray[p].registered), colorstr[white + 1]); + pprintf(p1, "%s (%s) %s%s.\n", parray[p1].name, + ratstrii(GetRating(&parray[p1], type), parray[p1].registered), + game_str(rated, wt * 60, winc, bt * 60, binc, category, board), + adjustr[adjourned]); + if (parray[p1].bell == 1) + pprintf_noformat(p1, "\007"); + if (in_list("computer", parray[p].name)) { + pprintf(p1, "--** %s is a ", parray[p].name); + pprintf_highlight(p1, "computer"); + pprintf(p1, " **--\n"); + } + if (in_list("computer", parray[p1].name)) { + pprintf(p, "--** %s is a ", parray[p1].name); + pprintf_highlight(p, "computer"); + pprintf(p, " **--\n"); + } + if (in_list("abuser", parray[p].name)) { + pprintf(p1, "--** %s is in the ", parray[p].name); + pprintf_highlight(p1, "abuser"); + pprintf(p1, " list **--\n"); + } + if (in_list("abuser", parray[p1].name)) { + pprintf(p, "--** %s is in the ", parray[p1].name); + pprintf_highlight(p, "abuser"); + pprintf(p, " list **--\n"); + } + if (rated) { + int win, draw, loss; + double newsterr; + + rating_sterr_delta(p1, p, type, time(0), RESULT_WIN, &win, &newsterr); + rating_sterr_delta(p1, p, type, time(0), RESULT_DRAW, &draw, &newsterr); + rating_sterr_delta(p1, p, type, time(0), RESULT_LOSS, &loss, &newsterr); + pprintf(p1, "Your %s rating will change: Win: %s%d, Draw: %s%d, Loss: %s%d\n", + bstr[type], + (win >= 0) ? "+" : "", win, + (draw >= 0) ? "+" : "", draw, + (loss >= 0) ? "+" : "", loss); + pprintf(p1, "Your new RD will be %5.1f\n", newsterr); + + rating_sterr_delta(p, p1, type, time(0), RESULT_WIN, &win, &newsterr); + rating_sterr_delta(p, p1, type, time(0), RESULT_DRAW, &draw, &newsterr); + rating_sterr_delta(p, p1, type, time(0), RESULT_LOSS, &loss, &newsterr); + pprintf(p, "Your %s rating will change: Win: %s%d, Draw: %s%d, Loss: %s%d\n", + bstr[type], + (win >= 0) ? "+" : "", win, + (draw >= 0) ? "+" : "", draw, + (loss >= 0) ? "+" : "", loss); + pprintf(p, "Your new RD will be %5.1f\n", newsterr); + } + pprintf_prompt(p1, "You can \"accept\" or \"decline\", or propose different parameters.\n"); + return COM_OK; +} + +PUBLIC int com_accept(int p, param_list param) +{ + int acceptNum = -1; + int type = -1; + int p1; + + if (parray[p].num_from == 0) { + pprintf(p, "You have no offers to accept.\n"); + return COM_OK; + } + if (param[0].type == TYPE_NULL) { + if (parray[p].num_from != 1) { + pprintf(p, "You have more than one offer to accept.\nUse \"pending\" to see them and \"accept n\" to choose which one.\n"); + return COM_OK; + } + acceptNum = 0; + } else if (param[0].type == TYPE_INT) { + if ((param[0].val.integer < 1) || (param[0].val.integer > parray[p].num_from)) { + pprintf(p, "Out of range. Use \"pending\" to see the list of offers.\n"); + return COM_OK; + } + acceptNum = param[0].val.integer - 1; + } else if (param[0].type == TYPE_WORD) { + if (!strcmp(param[0].val.word, "draw")) { + type = PEND_DRAW; + } else if (!strcmp(param[0].val.word, "pause")) { + type = PEND_PAUSE; + } else if (!strcmp(param[0].val.word, "adjourn")) { + type = PEND_ADJOURN; + } else if (!strcmp(param[0].val.word, "abort")) { + type = PEND_ABORT; + } else if (!strcmp(param[0].val.word, "takeback")) { + type = PEND_TAKEBACK; + } + if (!strcmp(param[0].val.word, "simmatch")) { + type = PEND_SIMUL; + } + if (!strcmp(param[0].val.word, "switch")) { + type = PEND_SWITCH; + } + if (!strcmp(param[0].val.word, "all")) { + while (parray[p].num_from != 0) { + pcommand(p, "accept 1"); + } + return COM_OK; + } + if (type > 0) { + if ((acceptNum = player_find_pendfrom(p, -1, type)) < 0) { + pprintf(p, "There are no pending %s offers.\n", param[0].val.word); + return COM_OK; + } + } else { /* Word must be a name */ + p1 = player_find_part_login(param[0].val.word); + if (p1 < 0) { + pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word); + return COM_OK; + } + if ((acceptNum = player_find_pendfrom(p, p1, -1)) < 0) { + pprintf(p, "There are no pending offers from %s.\n", parray[p1].name); + return COM_OK; + } + } + } + switch (parray[p].p_from_list[acceptNum].type) { + case PEND_MATCH: + accept_match(p, parray[p].p_from_list[acceptNum].whofrom); + return (COM_OK); + break; + case PEND_DRAW: + pcommand(p, "draw"); + break; + case PEND_PAUSE: + pcommand(p, "pause"); + break; + case PEND_ABORT: + pcommand(p, "abort"); + break; + case PEND_TAKEBACK: + pcommand(p, "takeback %d", parray[p].p_from_list[acceptNum].param1); + break; + case PEND_SIMUL: + pcommand(p, "simmatch %s", + parray[parray[p].p_from_list[acceptNum].whofrom].name); + break; + case PEND_SWITCH: + pcommand(p, "switch"); + break; + case PEND_ADJOURN: + pcommand(p, "adjourn"); + break; + } + return COM_OK_NOPROMPT; +} + + + +PUBLIC int com_decline(int p, param_list param) +{ + int declineNum; + int p1 = -1, type = -1; + int count; + + if (parray[p].num_from == 0) { + pprintf(p, "You have no pending offers from other players.\n"); + return COM_OK; + } + if (param[0].type == TYPE_NULL) { + if (parray[p].num_from == 1) { + p1 = parray[p].p_from_list[0].whofrom; + type = parray[p].p_from_list[0].type; + } else { + pprintf(p, "You have more than one pending offer. Please specify which one\nyou wish to decline.\n'Pending' will give you the list.\n"); + return COM_OK; + } + } else { + if (param[0].type == TYPE_WORD) { + /* Draw adjourn match takeback abort or <name> */ + if (!strcmp(param[0].val.word, "match")) { + type = PEND_MATCH; + } else if (!strcmp(param[0].val.word, "draw")) { + type = PEND_DRAW; + } else if (!strcmp(param[0].val.word, "pause")) { + type = PEND_PAUSE; + } else if (!strcmp(param[0].val.word, "abort")) { + type = PEND_ABORT; + } else if (!strcmp(param[0].val.word, "takeback")) { + type = PEND_TAKEBACK; + } else if (!strcmp(param[0].val.word, "adjourn")) { + type = PEND_ADJOURN; + } else if (!strcmp(param[0].val.word, "switch")) { + type = PEND_SWITCH; + } else if (!strcmp(param[0].val.word, "simul")) { + type = PEND_SIMUL; + } else if (!strcmp(param[0].val.word, "all")) { + } else { + p1 = player_find_part_login(param[0].val.word); + if (p1 < 0) { + pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word); + return COM_OK; + } + } + } else { /* Must be an integer */ + declineNum = param[0].val.integer - 1; + if (declineNum >= parray[p].num_from || declineNum < 0) { + pprintf(p, "Invalid offer number. Must be between 1 and %d.\n", parray[p].num_from); + return COM_OK; + } + p1 = parray[p].p_from_list[declineNum].whofrom; + type = parray[p].p_from_list[declineNum].type; + } + } + count = player_decline_offers(p, p1, type); + if (count != 1) + pprintf(p, "%d offers declined\n", count); + return COM_OK; +} + +PUBLIC int com_withdraw(int p, param_list param) +{ + int withdrawNum; + int p1 = -1, type = -1; + int count; + + if (parray[p].num_to == 0) { + pprintf(p, "You have no pending offers to other players.\n"); + return COM_OK; + } + if (param[0].type == TYPE_NULL) { + if (parray[p].num_to == 1) { + p1 = parray[p].p_to_list[0].whoto; + type = parray[p].p_to_list[0].type; + } else { + pprintf(p, "You have more than one pending offer. Please specify which one\nyou wish to withdraw.\n'Pending' will give you the list.\n"); + return COM_OK; + } + } else { + if (param[0].type == TYPE_WORD) { + /* Draw adjourn match takeback abort or <name> */ + if (!strcmp(param[0].val.word, "match")) { + type = PEND_MATCH; + } else if (!strcmp(param[0].val.word, "draw")) { + type = PEND_DRAW; + } else if (!strcmp(param[0].val.word, "pause")) { + type = PEND_PAUSE; + } else if (!strcmp(param[0].val.word, "abort")) { + type = PEND_ABORT; + } else if (!strcmp(param[0].val.word, "takeback")) { + type = PEND_TAKEBACK; + } else if (!strcmp(param[0].val.word, "adjourn")) { + type = PEND_ADJOURN; + } else if (!strcmp(param[0].val.word, "switch")) { + type = PEND_SWITCH; + } else if (!strcmp(param[0].val.word, "simul")) { + type = PEND_SIMUL; + } else if (!strcmp(param[0].val.word, "all")) { + } else { + p1 = player_find_part_login(param[0].val.word); + if (p1 < 0) { + pprintf(p, "No user named \"%s\" is logged in.\n", param[0].val.word); + return COM_OK; + } + } + } else { /* Must be an integer */ + withdrawNum = param[0].val.integer - 1; + if (withdrawNum >= parray[p].num_to || withdrawNum < 0) { + pprintf(p, "Invalid offer number. Must be between 1 and %d.\n", parray[p].num_to); + return COM_OK; + } + p1 = parray[p].p_to_list[withdrawNum].whoto; + type = parray[p].p_to_list[withdrawNum].type; + } + } + count = player_withdraw_offers(p, p1, type); + if (count != 1) + pprintf(p, "%d offers withdrawn\n", count); + return COM_OK; +} + +PUBLIC int com_pending(int p, param_list param) +{ + int i; + + if (!parray[p].num_to) { + pprintf(p, "There are no offers pending TO other players.\n"); + } else { + pprintf(p, "Offers TO other players:\n"); + for (i = 0; i < parray[p].num_to; i++) { + pprintf(p, " "); + player_pend_print(p, &parray[p].p_to_list[i]); + } + } + if (!parray[p].num_from) { + pprintf(p, "\nThere are no offers pending FROM other players.\n"); + } else { + pprintf(p, "\nOffers FROM other players:\n"); + for (i = 0; i < parray[p].num_from; i++) { + pprintf(p, " %d: ", i + 1); + player_pend_print(p, &parray[p].p_from_list[i]); + } + pprintf(p, "\nIf you wish to accept any of these offers type 'accept n'\nor just 'accept' if there is only one offer.\n"); + } + return COM_OK; +} + +PUBLIC int com_refresh(int p, param_list param) +{ + int g, p1; + + if (param[0].type == TYPE_NULL) { + if (parray[p].game >= 0) { + send_board_to(parray[p].game, p); + } else { /* Do observing in here */ + if (parray[p].num_observe) { + for (g = 0; g < parray[p].num_observe; g++) { + send_board_to(parray[p].observe_list[g], p); + } + } else { + pprintf(p, "You are neither playing nor observing a game.\n"); + return COM_OK; + } + } + } else { + g = GameNumFromParam (p, &p1, ¶m[0]); + if (g < 0) + return COM_OK; + if ((g >= g_num) || ((garray[g].status != GAME_ACTIVE) + && (garray[g].status != GAME_EXAMINE))) { + pprintf(p, "No such game.\n"); + } else if (garray[g].private && parray[p].adminLevel==ADMIN_USER) { + pprintf (p, "Sorry, game %d is a private game.\n", g+1); + } else { + if (garray[g].private) + pprintf(p, "Refreshing PRIVATE game %d\n", g+1); + send_board_to(g, p); + } + } + return COM_OK; +} + +PUBLIC int com_open(int p, param_list param) +{ + int retval; + ASSERT(param[0].type == TYPE_NULL); + if ((retval = pcommand(p, "set open")) != COM_OK) + return retval; + else + return COM_OK_NOPROMPT; +} + +PUBLIC int com_simopen(int p, param_list param) +{ + int retval; + ASSERT(param[0].type == TYPE_NULL); + if ((retval = pcommand(p, "set simopen")) != COM_OK) + return retval; + else + return COM_OK_NOPROMPT; +} + +PUBLIC int com_bell(int p, param_list param) +{ + int retval; + ASSERT(param[0].type == TYPE_NULL); + if ((retval = pcommand(p, "set bell")) != COM_OK) + return retval; + else + return COM_OK_NOPROMPT; +} + +PUBLIC int com_flip(int p, param_list param) +{ + int retval; + ASSERT(param[0].type == TYPE_NULL); + if ((retval = pcommand(p, "set flip")) != COM_OK) + return retval; + else + return COM_OK_NOPROMPT; +} + +PUBLIC int com_highlight(int p, param_list param) +{ + pprintf(p, "Obsolete command. Please do set highlight <0-15>.\n"); + return COM_OK; +} + +PUBLIC int com_style(int p, param_list param) +{ + int retval; + ASSERT(param[0].type == TYPE_INT); + if ((retval = pcommand(p, "set style %d", param[0].val.integer)) != COM_OK) + return retval; + else + return COM_OK_NOPROMPT; +} + +PUBLIC int com_promote(int p, param_list param) +{ + int retval; + ASSERT(param[0].type == TYPE_WORD); + if ((retval = pcommand(p, "set promote %s", param[0].val.word)) != COM_OK) + return retval; + else + return COM_OK_NOPROMPT; +} + +PUBLIC int com_alias(int p, param_list param) +{ + int al; + + if (param[0].type == TYPE_NULL) { + for (al = 0; al < parray[p].numAlias; al++) { + pprintf(p, "%s -> %s\n", parray[p].alias_list[al].comm_name, + parray[p].alias_list[al].alias); + } + return COM_OK; + } + al = alias_lookup(param[0].val.word, parray[p].alias_list, parray[p].numAlias); + if (param[1].type == TYPE_NULL) { + if (al < 0) { + pprintf(p, "You have no alias named '%s'.\n", param[0].val.word); + } else { + pprintf(p, "%s -> %s\n", parray[p].alias_list[al].comm_name, + parray[p].alias_list[al].alias); + } + } else { + if (al < 0) { + if (parray[p].numAlias >= MAX_ALIASES - 1) { + pprintf(p, "You have your maximum of %d aliases.\n", MAX_ALIASES - 1); + } else { + + if (!strcmp(param[0].val.string, "quit")) { /* making sure they + can't alias quit */ + pprintf(p, "You can't alias this command.\n"); + } else if (!strcmp(param[0].val.string, "unalias")) { /* making sure they + can't alias unalias + :) */ + pprintf(p, "You can't alias this command.\n"); + } else { + parray[p].alias_list[parray[p].numAlias].comm_name = + strdup(param[0].val.word); + parray[p].alias_list[parray[p].numAlias].alias = + strdup(param[1].val.string); + parray[p].numAlias++; + pprintf(p, "Alias set.\n"); + + } + } + } else { + rfree(parray[p].alias_list[al].alias); + parray[p].alias_list[al].alias = strdup(param[1].val.string); + pprintf(p, "Alias replaced.\n"); + } + parray[p].alias_list[parray[p].numAlias].comm_name = NULL; + } + return COM_OK; +} + +PUBLIC int com_unalias(int p, param_list param) +{ + int al; + int i; + + ASSERT(param[0].type == TYPE_WORD); + al = alias_lookup(param[0].val.word, parray[p].alias_list, parray[p].numAlias); + if (al < 0) { + pprintf(p, "You have no alias named '%s'.\n", param[0].val.word); + } else { + rfree(parray[p].alias_list[al].comm_name); + rfree(parray[p].alias_list[al].alias); + for (i = al; i < parray[p].numAlias; i++) { + parray[p].alias_list[i].comm_name = parray[p].alias_list[i + 1].comm_name; + parray[p].alias_list[i].alias = parray[p].alias_list[i + 1].alias; + } + parray[p].numAlias--; + parray[p].alias_list[parray[p].numAlias].comm_name = NULL; + pprintf(p, "Alias removed.\n"); + } + return COM_OK; +} + +PUBLIC int com_servers(int p, param_list param) +{ +/* + int i; + + ASSERT(param[0].type == TYPE_NULL); + if (numServers == 0) { + */ pprintf(p, "There are no other servers known to this server.\n"); + return COM_OK; +} + /* pprintf(p, "There are %d known servers.\n", numServers); pprintf(p, "(Not + all of these may be active)\n"); pprintf(p, "%-30s%-7s\n", "HOST", + "PORT"); for (i = 0; i < numServers; i++) pprintf(p, "%-30s%-7d\n", + serverNames[i], serverPorts[i]); return COM_OK; } */ +PUBLIC int com_sendmessage(int p, param_list param) +{ + int p1, connected = 1; + + if (!parray[p].registered) { + pprintf(p, "You are not registered and cannot send messages.\n"); + return COM_OK; + } + if ((param[0].type == TYPE_NULL) || (param[1].type == TYPE_NULL)) { + pprintf(p, "No message sent.\n"); + return COM_OK; + } + if (!FindPlayer(p, ¶m[0], &p1, &connected)) + return COM_OK; + + if ((player_censored(p1, p)) && (parray[p].adminLevel == 0)) { + pprintf(p, "Player \"%s\" is censoring you.\n", parray[p1].name); + return COM_OK; + } + if (player_add_message(p1, p, param[1].val.string)) { + pprintf(p, "Couldn't send message to %s. Message buffer full.\n", + parray[p1].name); + } else { + if (connected) + pprintf_prompt(p1, "\n%s just sent you a message.\n", parray[p].name); + } + if (!connected) + player_remove(p1); + return COM_OK; +} + + +PUBLIC int com_messages(int p, param_list param) +{ + if (param[0].type != TYPE_NULL) { + if (param[1].type != TYPE_NULL) + return com_sendmessage(p, param); + else { + ShowMsgsBySender(p, param); + return COM_OK; + } + } + if (player_num_messages(p) <= 0) { + pprintf(p, "You have no messages.\n"); + return COM_OK; + } + pprintf(p, "Messages:\n"); + player_show_messages(p); + return COM_OK; +} + +PUBLIC int com_clearmessages(int p, param_list param) +{ + if (player_num_messages(p) <= 0) { + pprintf(p, "You have no messages.\n"); + return COM_OK; + } + if (param[0].type == TYPE_NULL) { + pprintf(p, "Messages cleared.\n"); + player_clear_messages(p); + return COM_OK; + } + ClearMsgsBySender(p, param); + return COM_OK; +} + +PUBLIC int com_help(int p, param_list param) +{ + int i; + static char nullify = '\0'; + char *iwant, *filenames[1000]; /* enough for all helpfile names */ + + if (param[0].type == TYPE_NULL) { + iwant = &nullify; + } else { + iwant = param[0].val.word; + if (!safestring(iwant)) { + pprintf(p, "Illegal character in command %s.\n", iwant); + return COM_OK; +#if 0 + } else { + char sublist[][8] = {"talk", "play", ""}; + + for (i=0; (sublist[i][0] != '\0') && strcmp(iwant, sublist[i]); i++); + if (sublist[i][0] != '\0') { + char searchdir[MAX_FILENAME_SIZE]; + pprintf(p, "The following \"%s\" commands are available.\n\n", + sublist[i]); + sprintf(searchdir, "%s/../%s_help", comhelp_dir, sublist[i]); + i = search_directory(searchdir, NULL, filenames, 1000); + display_directory(p, filenames, i); + pprintf(p, "\nType \"help [command]\" for more specific help.\n"); + return COM_OK; + } +#endif + } + } + + i = search_directory((*iwant) ? help_dir : comhelp_dir, iwant, filenames, 1000); + if (i == 0) { + pprintf(p, "No help available on \"%s\".\n", iwant); + } else if ((i == 1) || !strcmp(*filenames, iwant)) { + if (psend_file(p, help_dir, *filenames)) { + /* we should never reach this unless the file was just deleted */ + pprintf(p, "Helpfile %s could not be found! ", *filenames); + pprintf(p, "Please inform an admin of this. Thank you.\n"); + } + } else { + if (*iwant) + pprintf(p, "Matches:"); + display_directory(p, filenames, i); + pprintf(p, "[Type \"info\" for a list of FICS general information files.]\n"); + } + return COM_OK; +} + +PUBLIC int com_info(int p, param_list param) +{ + int n; + char *filenames[1000]; + + if ((n = search_directory(info_dir, NULL, filenames, 1000)) > 0) + display_directory(p, filenames, n); + return COM_OK; +} + +PUBLIC int com_adhelp(int p, param_list param) +{ + int i; + static char nullify = '\0'; + char *iwant, *filenames[1000]; /* enough for all helpfile names */ + + if (param[0].type == TYPE_NULL) { + iwant = &nullify; + } else { + iwant = param[0].val.word; + if (!safestring(iwant)) { + pprintf(p, "Illegal character in command %s.\n", iwant); + return COM_OK; + } + } + + i = search_directory(adhelp_dir, iwant, filenames, 1000); + if (i == 0) { + pprintf(p, "No help available on \"%s\".\n", iwant); + } else if ((i == 1) || !strcmp(*filenames, iwant)) { + if (psend_file(p, adhelp_dir, *filenames)) { + /* we should never reach this unless the file was just deleted */ + pprintf(p, "Helpfile %s could not be found! ", *filenames); + pprintf(p, "Please inform an admin of this. Thank you.\n"); + } + } else { + if (*iwant) + pprintf(p, "Matches:\n"); + display_directory(p, filenames, i); + } + return COM_OK; +} + +PUBLIC int com_mailsource(int p, param_list param) +{ + static char nullify = '\0'; + char *iwant, *buffer[1000]; +/* char command[MAX_FILENAME_SIZE]; */ + char subj[81], fname[MAX_FILENAME_SIZE]; + int count; + + if (!parray[p].registered) { + pprintf(p, "Only registered people can use the mailsource command.\n"); + return COM_OK; + } + + if (param[0].type == TYPE_NULL) { + iwant = &nullify; + } else { + iwant = param[0].val.word; + } + + count = search_directory(source_dir, iwant, buffer, 1000); + if (count == 0) { + pprintf(p, "Found no source file matching \"%s\".\n", iwant); + } else if ((count == 1) || !strcmp(iwant, *buffer)) { + /* sprintf(command, "%s -s\"FICS sourcefile: %s\" %s < %s/%s&", MAILPROGRAM, + *buffer, parray[p].emailAddress, source_dir, *buffer); + system(command); */ + + sprintf(subj, "FICS source file from server %s: %s", fics_hostname, *buffer); + sprintf(fname, "%s/%s",source_dir, *buffer); + mail_file_to_user (p, subj, fname); + pprintf(p, "Source file %s sent to %s\n", *buffer, parray[p].emailAddress); + } else { + pprintf(p, "Found %d source files matching that:\n", count); + if (*iwant) + display_directory(p, buffer, count); + else { /* this junk is to get *.c *.h */ + multicol *m = multicol_start(count); + char *s; + int i; + for (i=0; i < count; i++) { + if (((s = buffer[i] + strlen(buffer[i]) - 2) >= buffer[i]) && (!strcmp(s, ".c") || !strcmp(s, ".h"))) + multicol_store(m, buffer[i]); + } + multicol_pprint(m, p, 78, 1); + multicol_end(m); + } + } + return COM_OK; +} + +PUBLIC int com_mailhelp(int p, param_list param) +{ /* Sparky */ + /* FILE *fp; char tmp[MAX_LINE_SIZE]; char fname[MAX_FILENAME_SIZE]; */ + char command[MAX_FILENAME_SIZE]; + char subj[81], fname[MAX_FILENAME_SIZE]; + char *iwant, *buffer[1000]; + + int count; + static char nullify = '\0'; + + if (!parray[p].registered) { + pprintf(p, "Only registered people can use the mailhelp command.\n"); + return COM_OK; + } + if (param[0].type == TYPE_NULL) + iwant = &nullify; + else + iwant = param[0].val.word; + + count = search_directory(help_dir, iwant, buffer, 1000); + if (count == 0) { + pprintf(p, "Found no help file matching \"%s\".\n", iwant); + } else if (count == 1) { + /* sprintf(command, "%s -s \"FICS helpfile: %s\" %s < %s/%s&", MAILPROGRAM, + *buffer, parray[p].emailAddress, help_dir, *buffer); + system(command);a */ + + + sprintf(subj, "FICS help file from server %s: %s", fics_hostname, *buffer); + sprintf(fname, "%s/%s",help_dir, *buffer); + mail_file_to_user (p, subj, fname); + + pprintf(p, "Help file %s sent to %s\n", *buffer, parray[p].emailAddress); + } else { + pprintf(p, "Found %d helpfiles matching that:\n", count); + display_directory(p, buffer, count); + } + + return COM_OK; +} + +PUBLIC int com_mailmess(int p, param_list param) +{ + char command[MAX_FILENAME_SIZE]; + char *buffer[1000]; + char mdir[MAX_FILENAME_SIZE]; + char filename[MAX_FILENAME_SIZE]; + char subj[81], fname[MAX_FILENAME_SIZE]; + + + if (!parray[p].registered) { + pprintf(p, "Only registered people can use the mailmess command.\n"); + return COM_OK; + } + sprintf(filename, "%s.messages", parray[p].login); + sprintf(mdir, "%s/player_data/%c/", stats_dir, parray[p].login[0]); + + if (search_directory(mdir, filename, buffer, 1000)) { +/* Sprintf(command, "%s -s \"Your FICS messages\" %s < %s%s&", MAILPROGRAM, + parray[p].emailAddress, mdir, filename); + system(command); */ + + sprintf(subj, "Your FICS messages from server %s", fics_hostname); + sprintf(fname, "%s/%s", mdir, filename); + mail_file_to_user (p, subj, fname); + + + + pprintf(p, "Messages sent to %s\n", parray[p].emailAddress); + } else { + pprintf(p, "You have no messages.\n"); + } + return COM_OK; + +} + +PUBLIC int com_handles(int p, param_list param) +{ + char *buffer[1000]; + char pdir[MAX_FILENAME_SIZE]; + int count; + + sprintf(pdir, "%s/%c", player_dir, param[0].val.word[0]); + count = search_directory(pdir, param[0].val.word, buffer, 1000); + pprintf(p, "Found %d names.\n", count); + if (count > 0) + display_directory(p, buffer, count); + return COM_OK; +} + +PUBLIC int com_znotify(int p, param_list param) +{ + int p1, count = 0; + + for (p1 = 0; p1 < p_num; p1++) { + if (player_notified(p, p1)) { + if (!count) + pprintf(p, "Present company on your notify list:\n "); + pprintf(p, " %s", parray[p1].name); + count++; + } + } + if (count) + pprintf(p, ".\n"); + else + pprintf(p, "No one from your notify list is logged on.\n"); + + count = 0; + for (p1 = 0; p1 < p_num; p1++) { + if (player_notified(p1, p)) { + if (!count) + pprintf(p, + "The following players have you on their notify list:\n "); + pprintf(p, " %s", parray[p1].name); + count++; + } + } + if (count) + pprintf(p, ".\n"); + else + pprintf(p, "No one logged in has you on their notify list.\n"); + return COM_OK; +} + +PUBLIC int com_qtell(int p, param_list param) +{ + int p1; + char tmp[MAX_STRING_LENGTH]; + char dummy[2]; + char buffer1[MAX_STRING_LENGTH]; /* no highlight and no bell */ + char buffer2[MAX_STRING_LENGTH]; /* no highlight and bell */ + char buffer3[MAX_STRING_LENGTH]; /* highlight and no bell */ + char buffer4[MAX_STRING_LENGTH]; /* highlight and and bell */ + int i, count; +/* FILE *fp; */ + + if (!in_list("td", parray[p].name)) { + pprintf(p, "Only TD programs are allowed to use this command.\n"); + return COM_OK; + } + strcpy(buffer1, ":\0"); + strcpy(buffer2, ":\0"); + strcpy(buffer3, ":\0"); + strcpy(buffer4, ":\0"); + + sprintf(tmp, "%s", param[1].val.string); + for (i = 0, count = 0; ((tmp[i] != '\0') && (count < 1029));) { + if ((tmp[i] == '\\') && (tmp[i + 1] == 'n')) { + strcat(buffer1, "\n:"); + strcat(buffer2, "\n:"); + strcat(buffer3, "\n:"); + strcat(buffer4, "\n:"); + count += 2; + i += 2; + } else if ((tmp[i] == '\\') && (tmp[i + 1] == 'b')) { + strcat(buffer2, "\007"); + strcat(buffer4, "\007"); + count++; + i += 2; + } else if ((tmp[i] == '\\') && (tmp[i + 1] == 'H')) { + strcat(buffer3, "\033[7m"); + strcat(buffer4, "\033[7m"); + count += 4; + i += 2; + } else if ((tmp[i] == '\\') && (tmp[i + 1] == 'h')) { + strcat(buffer3, "\033[0m"); + strcat(buffer4, "\033[0m"); + count += 4; + i += 2; + } else { + dummy[0] = tmp[i]; + dummy[1] = '\0'; + strcat(buffer1, dummy); + strcat(buffer2, dummy); + strcat(buffer3, dummy); + strcat(buffer4, dummy); + count++; + i++; + } + } + + if (param[0].type == TYPE_WORD) { +/* + fp = fopen("/tmp/fics-log", "a"); + fprintf(fp, "PLAYER \"%s\" - MESSAGE \"%s\"\n", param[0].val.word, param[1].val.string); + fclose(fp); +*/ + if ((p1 = player_find_bylogin(param[0].val.word)) < 0) { + pprintf(p, "*qtell %s 1*\n", param[0].val.word); + return COM_OK; + } + pprintf_prompt(p1, "\n%s\n", (parray[p1].highlight && parray[p1].bell) ? buffer4 : + (parray[p1].highlight && !parray[p1].bell) ? buffer3 : + (!parray[p1].highlight && parray[p1].bell) ? buffer2 : + buffer1); + pprintf(p, "*qtell %s 0*\n", parray[p1].name); + + } else { + int p1; + int i; + int ch = param[0].val.integer; + +/* + fp = fopen("/tmp/fics-log", "a"); + fprintf(fp, "CHANNEL \"%d\" - MESSAGE \"%s\"\n", param[0].val.integer, param[1].val.string); + fclose(fp); +*/ + + if (ch == 0) { + pprintf(p, "*qtell %d 1*\n", param[0].val.integer); + return COM_OK; + } + if (ch < 0) { + pprintf(p, "*qtell %d 1*\n", param[0].val.integer); + return COM_OK; + } + if (ch >= MAX_CHANNELS) { + pprintf(p, "*qtell %d 1*\n", param[0].val.integer); + return COM_OK; + } + for (i = 0; i < numOn[ch]; i++) { + p1 = channels[ch][i]; + if (p1 == p) + continue; + if (player_censored(p1, p)) + continue; + if ((parray[p1].status == PLAYER_PASSWORD) + || (parray[p1].status == PLAYER_LOGIN)) + continue; + pprintf_prompt(p1, "\n%s\n", (parray[p1].highlight && parray[p1].bell) ? buffer4 : + (parray[p1].highlight && !parray[p1].bell) ? buffer3 : + (!parray[p1].highlight && parray[p1].bell) ? buffer2 : + buffer1); + } + pprintf(p, "*qtell %d 0*\n", param[0].val.integer); + } + return COM_OK; +} + +PUBLIC int com_getpi(int p, param_list param) +{ + int p1; + + if (!in_list("td", parray[p].name)) { + pprintf(p, "Only TD programs are allowed to use this command.\n"); + return COM_OK; + } + if (((p1 = player_find_bylogin(param[0].val.word)) < 0) || (parray[p1].registered == 0)) { + /* Darkside suggested not to return anything */ + return COM_OK; + } + if (!parray[p1].registered) { + pprintf(p, "*getpi %s -1 -1 -1*\n", parray[p1].name); + } else { + pprintf(p, "*getpi %s %d %d %d*\n", parray[p1].name, + parray[p1].w_stats.rating, + parray[p1].b_stats.rating, + parray[p1].s_stats.rating); + } + return COM_OK; +} + +PUBLIC int com_getps(int p, param_list param) +{ + int p1; + + if ((((p1 = player_find_bylogin(param[0].val.word)) < 0) || (parray[p1].registered == 0)) || (parray[p1].game < 0)) { + pprintf(p, "*status %s 1*\n", param[0].val.word); + return COM_OK; + } + pprintf(p, "*status %s 0 %s*\n", parray[p1].name, parray[(parray[p1].opponent)].name); + return COM_OK; +} +PUBLIC int com_limits(int p, param_list param) +{ + pprintf(p, "\nCurrent hardcoded limits:\n"); + pprintf(p, " Max number of players: %d\n", MAX_PLAYER); + pprintf(p, " Max number of channels and max capacity: %d\n", MAX_CHANNELS); + pprintf(p, " Max number of channels one can be in: %d\n", MAX_INCHANNELS); + pprintf(p, " Max number of people on the notify list: %d\n", MAX_NOTIFY); + pprintf(p, " Max number of aliases: %d\n", MAX_ALIASES); + pprintf(p, " Max number of games you can observe at a time: %d\n", MAX_OBSERVE); + pprintf(p, " Max number of requests pending: %d\n", MAX_PENDING); + pprintf(p, " Max number of people on the censor list: %d\n", MAX_CENSOR); + pprintf(p, " Max number of people in a simul game: %d\n", MAX_SIMUL); + pprintf(p, " Max number of messages one can receive: %d\n", MAX_MESSAGES); + pprintf(p, " Min number of games to be active: %d\n", PROVISIONAL); + pprintf(p, "\nAdmin settable limits:\n"); + pprintf(p, " Quota list gives two shouts per %d seconds.\n", quota_time); + return COM_OK; +} |