/********************************************************************* v.1.3 ESE.c expandable search engine... allows for dropping in of functions to have any desired pieces of the player or saved_player searched throughout all files. Requirments: ewtoo talker Installing: add this file on to the end of plists.c, the easiest way is cat ESE.cz >> plists.c (make sure both files are in the src/ dir when you do this, and use This Actual File Name instead of ESE.cz) Find all occurances of COMMAND_INIT in this code and remove the line, these are used by Ruby Clist and are retained in the release as an example of entries for clist.h Add an entry to clist.h for the function master_search_command which should be invoked by the command 'search' and should be avaible with the SU priv If you are installing this in a PG+ talker, change the existant commands (in clist.h) for xref, etrace, and itrace to call the function use_search (if thats too complicated, just remove these commands from clist.h all toghter and tell ppl to use 'search') (on the two above, dont forget the command extern in clist.h) Determine which (if any) search functions are incompatible with your code... which happens due to the src where this is installed not having certains player struct members. For instance, if you dont have 'pennies' as part of your players, then richest_search and the entry for it in SearchTypes[] needs to be purged. If you do not have strcasestr() in your src, you must define NEED_STRCASESTR ... Change TELLPLAYER, LOGF, ENDSTACK to your varible argument functions if needed. To 'unbreak' the url search for PG+ 1.x, change the occurances of p->url to p->alt_email Add the help file at the bottom to doc/help Bug Reports: send to phypor@benland.muc.edu Licences: freely distributable and modifiable, as long as credit given in help credits...ex: 'ESE, expandable search engine v1.3 by phypor' or the version output... ex: ' -=*> ESE, expandable search engine v1.3 (by phypor) enabled' Warranty: non, the author is in no way responsible for use, misuse, abuse, or any other actions misactions, reactions of this code, its provided as is. Author: phypor "if it breaks you get to keep both pieces" ~old linux proverb *********************************************************************/ #ifndef LINE #define LINE "---------------------------------------------------------------------------\n" #endif /* !LINE */ #undef NEED_STRCASESTR /* define this if needed */ #ifdef NEED_STRCASESTR extern char *strcasestr ( char *, char * ); #endif /* NEED_STRCASESTR */ typedef char *search_func ( player *, char * ); search_func name_search, xref_search, email_search, site_search, url_search, richest_search, resby_search, staff_stats_search, trouble_search, swarn_search, git_search; struct search_type { char *type; int priv; search_func *search_func; char *desc; } SearchTypes[] = { {"names", SU, name_search, "Search for string in names"}, {"xref", SU, xref_search, "Search for string at beginning of names"}, {"sites", SU, site_search, "Search for string in last site"}, {"emails", ADMIN, email_search, "Search for string in emails"}, {"urls", SU, url_search, "Search for string in urls"}, {"gits", SU, git_search, "Search for string in git message"}, {"swarn", SU, swarn_search, "Search for string in saved warns"}, {"resby", LOWER_ADMIN, resby_search, "Search for players res'd by a certain su"}, {"richest", LOWER_ADMIN, richest_search, "Search for players with excess money"}, {"trouble", SU, trouble_search, "Search for trouble causers"}, {"sstats", LOWER_ADMIN, staff_stats_search, "View staff stats"}, {"", 0, 0, ""} }; typedef struct search_type search_type; void master_search ( player * p, char * str, search_type * st ) { char c, *oldstack = stack, *got, mid[160]; int i, hits = 0, outnow = 0; saved_player *scan, **hash; player dummy; if ((!strcasecmp (st->type, "richest") || !strcasecmp (st->type, "trouble")) && !isdigit(*str)) { tell_player (p, " For this search, you must supply a number\n"); return; } if (*str) sprintf(mid, "Searching %s for '%s'", st->type, str); else sprintf(mid, "Output from %s", st->type); pstack_mid(mid); *stack++ = '\n'; if (!strcasecmp (st->type, "sstats")) stack += sprintf (stack, " resd warn boot rm'd ject main idle\n"); if (!strcasecmp (st->type, "trouble")) stack += sprintf (stack, " warn ject boot idle main idle git ban\n"); for (c = 'a'; (c <= 'z' && !outnow); c++) { hash = saved_hash[((int) (tolower(c)) - (int) 'a')]; for (i = 0; (i < HASH_SIZE && !outnow); i++, hash++) { for (scan = *hash; (scan && !outnow); scan = scan->next) { if (scan->residency == BANISHD || scan->residency & SYSTEM_ROOM) continue; if (hits > 99) { stack += sprintf (stack, "\n --- Too many hits, search terminated ---\n\n"); outnow++; continue; } memset (&dummy, 0, sizeof (player)); strncpy (dummy.lower_name, scan->lower_name, MAX_NAME - 1); dummy.fd = p->fd; if (!load_player (&dummy)) { LOGF ("error", "No player loaded for a saved player ! [%s]", scan->lower_name); TELLPLAYER (p, "No player loaded for a saved player [%s]", scan->lower_name); continue; } if ((got = (st->search_func) (&dummy, str))) { hits++; strcpy(stack, got); stack = strchr(stack, 0); } } } } if (!hits) { stack = oldstack; TELLPLAYER (p, " No matches of '%s' found in %s search.\n", str, st->type); return; } if (oldstack[strlen (oldstack) - 1] != '\n') *stack++ = '\n'; *stack++ = '\n'; if (hits == 1) sprintf(mid, "One %s match found", st->type); else sprintf(mid, "%d %s matches found", hits, st->type); pstack_mid(mid); *stack++ = 0; tell_player (p, oldstack); stack = oldstack; } void show_search_types ( player * p ) { int i; char *oldstack = stack; pstack_mid("Areas you may search"); *stack++ = '\n'; for (i = 0; SearchTypes[i].type[0]; i++) if (!SearchTypes[i].priv || p->residency & SearchTypes[i].priv) stack += sprintf (stack, " %-20s %s\n", SearchTypes[i].type, SearchTypes[i].desc); *stack++ = '\n'; ENDSTACK(LINE); tell_player (p, oldstack); stack = oldstack; } void master_search_command ( player * p, char * str ) { int i; char *query = ""; COMMAND_INIT ("search", master_search_command, SU, 0, 1, 0, SUPERc); if (strcasecmp (str, "sstats") && !(query = strchr(str, ' '))) { tell_player (p, " Format: search \n"); show_search_types (p); return; } if (*query) *query++ = 0; if (strlen (query) > 30) { tell_player (p, " Query too long, truncated\n"); query[30] = 0; } for (i = 0; SearchTypes[i].type[0]; i++) if (!strncasecmp (SearchTypes[i].type, str, strlen (str))) { if (SearchTypes[i].priv && !(p->residency & SearchTypes[i].priv)) continue; master_search (p, query, &SearchTypes[i]); return; } TELLPLAYER (p, "Couldn't find '%s' to search ...\n", str); show_search_types (p); } char *percentile (int top, int bot) { static char ret[8]; float perc; if (!bot || bot < 0) return " ??%"; perc = ((float) top / (float) bot) * 100; if (perc > 100) strcpy(ret, "+100"); else if (perc == 100) strcpy(ret, "100%"); else if (!perc) strcpy(ret, " 0%"); else sprintf(ret, "%3.0f%%", perc); return ret; } char *name_search ( player * p, char * str ) { static char clc[MAX_NAME + 5]; if (!strcasestr(p->lower_name, str)) return (char *) NULL; memset (clc, 0, MAX_NAME + 5); if (p->residency & (CODER | ADMIN | LOWER_ADMIN)) sprintf (clc, "^B%s^N, ", p->lower_name); else if (p->residency & (PSU | SU | ASU | ADC)) sprintf (clc, "^G%s^N, ", p->lower_name); else sprintf (clc, "%s, ", p->lower_name); return clc; } char *xref_search ( player * p, char * str ) { static char clc[MAX_NAME + 5]; if (strncmp (p->lower_name, str, strlen (str))) return (char *) NULL; memset (clc, 0, MAX_NAME + 5); if (p->residency & (CODER | ADMIN | LOWER_ADMIN)) sprintf (clc, "^B%s^N, ", p->lower_name); else if (p->residency & (PSU | SU | ASU | ADC)) sprintf (clc, "^G%s^N, ", p->lower_name); else sprintf (clc, "%s, ", p->lower_name); return clc; } char *email_search ( player * p, char * str ) { static char clc[160]; if (!strcasestr (p->email, str)) return (char *) NULL; memset (clc, 0, 160); if (p->residency & (CODER | ADMIN | LOWER_ADMIN)) sprintf (clc, " ^B%-20s %s^N\n", p->lower_name, p->email); else if (p->residency & (PSU | SU | ASU | ADC)) sprintf (clc, " ^G%-20s %s^N\n", p->lower_name, p->email); else sprintf (clc, " %-20s %s^N\n", p->lower_name, p->email); return clc; } char *site_search ( player * p, char * str ) { static char clc[160]; if (!p->saved || !strcasestr(p->saved->last_host, str)) return (char *) NULL; memset(clc, 0, 160); if (current_player && current_player->residency & (LOWER_ADMIN | ADMIN)) sprintf(clc, " %-20s %s <%s>\n", p->lower_name, p->saved->last_host, p->email); else sprintf(clc, " %-20s %s\n", p->lower_name, p->saved->last_host); return clc; } char *url_search ( player * p, char * str ) { static char clc[160]; if (!strcasestr (p->url, str)) return (char *) NULL; memset (clc, 0, 160); sprintf (clc, " %-20s %s^N\n", p->lower_name, p->url); return clc; } char *richest_search ( player * p, char * str ) { static char clc[160]; if (p->pennies < 10) return (char *) NULL; if (p->pennies < atoi(str)) return (char *) NULL; memset (clc, 0, 160); sprintf (clc, " %-20s %d %s\n", p->lower_name, p->pennies, get_config_msg("cash_name")); return clc; } char *resby_search ( player * p, char * str ) { static char clc[MAX_NAME + 5]; if (!p->ressied_by[0] || !strcasestr (p->ressied_by, str)) return (char *) NULL; memset (clc, 0, MAX_NAME + 5); if (p->residency & (CODER | ADMIN | LOWER_ADMIN)) sprintf (clc, "^B%s^N, ", p->lower_name); else if (p->residency & (PSU | SU | ASU | ADC)) sprintf (clc, "^G%s^N, ", p->lower_name); else sprintf (clc, "%s, ", p->lower_name); return clc; } char *staff_stats_search ( player * p, char * str ) { static char clc[160]; char *ptr; if (!(p->residency & (PSU | ADC))) return (char *) NULL; memset (clc, 0, 160); ptr = clc; ptr += sprintf (ptr, " %-20s %4d %4d %4d %4d %4d %s", p->lower_name, p->num_ressied, p->num_warned, p->num_booted, p->num_rmd, p->num_ejected, percentile(p->time_in_main, p->total_login)); sprintf (ptr, " %s\n", percentile(p->total_idle_time, p->total_login)); return clc; } char *trouble_search ( player * p, char * str ) { static char clc[160]; char *ptr; if ((p->warn_count + p->eject_count + p->idled_out_count + p->booted_count) < atoi (str) && !(p->git_string[0])) return (char *) NULL; memset (clc, 0, 160); ptr = clc; ptr += sprintf (ptr, " %-20s %4d %4d %4d %4d %s", p->lower_name, p->warn_count, p->eject_count, p->booted_count, p->idled_out_count, percentile(p->time_in_main, p->total_login)); sprintf (ptr, " %s %c %c\n", percentile(p->total_idle_time, p->total_login), (p->git_string[0] ? '*' : ' '), (p->residency & BANISHD ? '*' : ' ')); return clc; } char *git_search ( player * p, char * str ) { static char clc[160]; if (!p->git_string[0]) return (char *) NULL; if (!strcasestr (p->git_string, str) && !strcasestr (p->git_by, str)) return (char *) NULL; memset (clc, 0, 160); sprintf (clc, " %-20s (%s) %s^N\n", p->lower_name, p->git_by, p->git_string); return clc; } char *swarn_search ( player * p, char * str ) { static char clc[160]; if (!p->swarn_message[0]) return (char *) NULL; if (!strcasestr (p->swarn_message, str) && !strcasestr (p->swarn_sender, str)) return (char *) NULL; memset (clc, 0, 160); sprintf (clc, " %-20s (%s) %s^N\n", p->lower_name, p->swarn_sender, p->swarn_message); return clc; } void use_search ( player * p, char * str ) { char squeal[160]; COMMAND_INIT("xref", use_search, (PSU|SU), 0, 1, 0, SUPERc); COMMAND_INIT("etrace", use_search, LOWER_ADMIN, 0, 1, 0, ADMINc); COMMAND_INIT("itrace", use_search, SU, 0, 1, 0, SUPERc); COMMAND_INIT("sitetrace", use_search, SU, 0, 1, 0, SUPERc); tell_player (p, " This command has depreciated, use the 'search' command.\n"); if (!*str) return; memset (squeal, 0, 160); if (strlen (str) > 140) /* make sure we cant overwrite the lil buffer */ str[140] = 0; if (!strcasecmp (first_char(p), "xref")) { sprintf (squeal, "xref %s", str); master_search_command(p, squeal); return; } if (!strcasecmp (first_char(p), "etrace")) { sprintf (squeal, "emails %s", str); master_search_command(p, squeal); return; } sprintf (squeal, "sites %s", str); master_search_command(p, squeal); return; } #ifdef NEED_STRCASESTR /* like strstr, but case insenstive */ char *strcasestr(char *haystack, char *needle) { char s[5], *nptr, *hptr; if (!needle || !*needle) return (char *) NULL; memset(s, 0, 5); strncpy(s, needle, 4); lower_case(s); while (*haystack) { if (tolower(*haystack) == s[0]) { if (!s[1]) return haystack; if (*(haystack + 1) && tolower(*(haystack + 1)) == s[1]) { if (!s[2]) return haystack; if (*(haystack + 2) && tolower(*(haystack + 2)) == s[2]) { if (!s[3]) return haystack; if (*(haystack + 3) && tolower(*(haystack + 3)) == s[3]) { hptr = haystack + 4; nptr = needle + 4; for (; *nptr && *hptr; nptr++, hptr++) if (tolower(*nptr) != tolower(*hptr)) break; if (!*nptr) return haystack; } } } } haystack++; } /* strstr returns NULL, not an actual char that is NULL... so we will follow its way */ return (char *) NULL; } #endif /* NEED_STRCASESTR */ /* ------------------- help file ... cut here ---------------- :search SEARCH - search various parts of players in file for various strings Type Action names search for in players' names xref search for at the beginning of players names. sites search for in players last host (note, the last host is saved as alpha if it has it, ip if not... so check both if you are really looking) emails search for in players emails urls search for in players urls gits search for in git strings and in who made the player a git swarn search for in saved warns and in who set the saved warn resby search for (usually the name of a su) in who made players a resident. richest search for all those that have more than of money trouble search for all those that have more than of discipline commands used on them sstats show all staff and stats Note, not all priv levels have access to all types of searches. */