/* cl_ignore.c Client-side ignore list management Copyright (C) 1996-1997 Id Software, Inc. 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. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include "QF/cbuf.h" #include "QF/cmd.h" #include "QF/dstring.h" #include "QF/info.h" #include "QF/keys.h" #include "QF/llist.h" #include "QF/sys.h" #include "QF/va.h" #include "client.h" #include "cl_chat.h" llist_t *ignore_list, *dead_ignore_list; static void CL_Ignore_Free (void *ele, void *unused) { ignore_t *ig = (ignore_t *) ele; if (ig->lastname) free ((void *)ig->lastname); free (ig); } static qboolean CL_Ignore_Compare (const void *ele, const void *cmp, void *unused) { return *(int *)cmp == ((ignore_t *) ele)->uid; } static qboolean isc_iterator (ignore_t *ig, llist_node_t *node) { if (cl.players[ig->slot].userid != ig->uid) // We got out of sync somehow llist_remove (node); return true; } static void CL_Ignore_Sanity_Check (void) { llist_iterate (ignore_list, LLIST_ICAST (isc_iterator)); } static qboolean live_iterator (ignore_t *ig, llist_node_t *node) { Sys_Printf ("%5i - %s\n", ig->uid, Info_ValueForKey (cl.players[ig->slot].userinfo, "name")); return true; } static qboolean dead_iterator (ignore_t *ig, llist_node_t *node) { Sys_Printf ("%s\n", ig->lastname); return true; } static void CL_Ignore_f (void) { CL_Ignore_Sanity_Check (); if (Cmd_Argc () == 1) { Sys_Printf ( "Users ignored by user id\n" "------------------------\n" ); llist_iterate (ignore_list, LLIST_ICAST (live_iterator)); Sys_Printf ( "\n" "Users ignored by name (not currently connected)\n" "-----------------------------------------------\n" ); llist_iterate (dead_ignore_list, LLIST_ICAST (dead_iterator)); } else if (Cmd_Argc () == 2) { int i, uid = atoi (Cmd_Argv (1)); for (i = 0; i < MAX_CLIENTS; i++) { if (cl.players[i].userid == uid) { ignore_t *new = calloc (1, sizeof (ignore_t)); new->slot = i; new->uid = uid; llist_append (ignore_list, new); Sys_Printf ("User %i (%s) is now ignored.\n", uid, Info_ValueForKey (cl.players[i].userinfo, "name")); return; } } Sys_Printf ("No user %i present on the server.\n", uid); } else Sys_Printf ("Usage: ignore [userid]\n"); } static void CL_Unignore_f (void) { int uid; llist_node_t *node; CL_Ignore_Sanity_Check (); if (Cmd_Argc() != 2) Sys_Printf ("usage: unignore userid\n"); else { uid = atoi (Cmd_Argv (1)); if ((node = llist_findnode (ignore_list, &uid))) { Sys_Printf ("User %i (%s) is no longer ignored.\n", uid, Info_ValueForKey (cl.players[LLIST_DATA (node, ignore_t)->slot].userinfo, "name")); CL_Ignore_Free (llist_remove (node), 0); return; } Sys_Printf ("User %i does not exist or is not presently ignored.\n", uid); } } /* HACK HACK HACK (phrosty) replaced GCC-specific nested functions with this. come back and make this cleaner later. */ static const char *g_cam_str; static dstring_t *g_cam_test; static qboolean g_cam_allowed; static qboolean cam_iterator (ignore_t *ig, llist_node_t *node) { if (cl.players[ig->slot].userid != ig->uid) { // We got out of sync somehow llist_remove (node); return true; } dsprintf (g_cam_test, "%s: ", Info_ValueForKey (cl.players[ig->slot].userinfo, "name")); if (!strncmp (g_cam_test->str, g_cam_str, sizeof (g_cam_test->str))) { return g_cam_allowed = false; } else return true; } qboolean CL_Chat_Allow_Message (const char *str) { g_cam_str = str; g_cam_test = dstring_newstr (); g_cam_allowed = true; llist_iterate (ignore_list, LLIST_ICAST (cam_iterator)); return g_cam_allowed; } void CL_Chat_User_Disconnected (int uid) { ignore_t *ig; CL_Ignore_Sanity_Check (); if ((ig = llist_remove (llist_findnode (ignore_list, &uid)))) { if (ig->lastname) free ((void *)ig->lastname); ig->lastname = strdup (Info_ValueForKey (cl.players[ig->slot].userinfo, "name")); llist_append (dead_ignore_list, ig); Sys_Printf ("Ignored user %i (%s) left the server. Now ignoring by name...\n", ig->uid, ig->lastname); } } static const char *g_ccn_name; static ignore_t *g_ccn_found; static qboolean ccn_iterator (ignore_t *ig, llist_node_t *node) { if (!strcmp (ig->lastname, g_ccn_name)) { g_ccn_found = ig; return false; } else return true; } void CL_Chat_Check_Name (const char *name, int slot) { g_ccn_name = name; g_ccn_found = 0; llist_iterate (dead_ignore_list, LLIST_ICAST (ccn_iterator)); if (g_ccn_found) { g_ccn_found->slot = slot; g_ccn_found->uid = cl.players[slot].userid; llist_append (ignore_list, llist_remove (llist_getnode (dead_ignore_list, g_ccn_found))); Sys_Printf ("User %i (%s) is using an ignored name. Now ignoring by user id...\n", g_ccn_found->uid, g_ccn_found->lastname); } } void CL_Chat_Flush_Ignores (void) { llist_flush (ignore_list); } static void CL_ChatInfo (int val) { if (val < 1 || val > 3) val = 0; if (cls.chat != val) { cls.chat = val; Cbuf_AddText(cl_cbuf, va ("setinfo chat \"%d\"\n", val)); } } static void cl_chat_keydest (keydest_t keydest) { switch (keydest) { case key_game: case key_demo: CL_ChatInfo (0); break; case key_message: CL_ChatInfo (1); break; case key_console: case key_menu: case key_unfocused: case key_last: // should not happen CL_ChatInfo (2); break; } } void CL_Chat_Init (void) { ignore_list = llist_new (CL_Ignore_Free, CL_Ignore_Compare, 0); dead_ignore_list = llist_new (CL_Ignore_Free, CL_Ignore_Compare, 0); Cmd_AddCommand ("ignore", CL_Ignore_f, "Ignores chat and name-change messages from a user."); Cmd_AddCommand ("unignore", CL_Unignore_f, "Removes a previously ignored user from the ignore list."); Key_KeydestCallback (cl_chat_keydest); }