/***************************************************************** * Plugin to collect IDs of players connecting to server. * It will only store IDs if they don't exist on the server * already (However, if the same ID but different NAME, then * ID IS stored. Hence all the players 'fakenicks' will * be stored along with their IDs). * * author: jugger1@blueyonder.co.uk * * Fixed bug in welcome message. Added 'greetings' sound on entry. * Added fix for blank database entries. * (2/10/2003) ver 1.2.1 * * Updated to collect Steam tags. * (30/9/2003) ver 1.2.0 * * Corrected Linux issue with comments done using '//' when compiling. * (9/3/2002) ver 1.1.5 * * Corrected bug when renaming on reaching MAX_NICKS. * Added a 'new line' character to each output to the database, as * it sometimes appended all the names/info of several players * together on a line; rendering the plugin inoperable. * (25/2/2002) ver 1.1.4 * * Added error messaging and WelcomeMsg (0/1) to disable/enable * welcome message when users connect. * (14/2/02) ver 1.1.3 * * After the plugin detects MAX_NICKS names stored, it'll auto * rename the person concerned to the last name used from the * database. (8/2/2002) ver 1.1.2 * * Merged the 2 separate database files in to one: "info_id.ini" * (or "info_ip.ini" for a LAN server) * (7/2/2002) ver 1.1.1 * * Added 'admin_showme' command to allow all names attached to * a ID or IP to be listed (5/2/2002) ver 1.1.0 * * Added server detection so that it'll record IP address if * LAN server detected ('sv_lan 1') (4/2/2002) ver 1.0.1 * ******************************************************************/ #include <core> #include <console> #include <string> #include <admin> #include <adminlib> /***************************************************************** * Maximum number of Names/IDs/IPs in database. To increase this * you'll need to recompile the plugin. It does use memory on the * server, so you might want to experiment with it! * I know how to do this dynamically in C, but not in the Small * language. Any suggestons, * email me please: jugger1@blueyonder.co.uk * * Also, this makes the files size for the plugin in large! * MAX_ENTRIES 4000 makes it above 1 MB *****************************************************************/ /* glodabl variable declarations */ #define MAX_ENTRIES 5000 #define MAX_NICKS 10 /* Maximum nicks to allow in database */ #define DELAY_TIME 10 /* delay for ID to be gained */ #define MAX_INFO_LENGTH 39 /* maximum length (in chars) of ID or IP */ #define MAX_ERRORS 5 /* max errors to be listed by the plugin */ new STRING_VERSION[MAX_DATA_LENGTH] = "1.2.1"; new PLUGIN_NAME[] = "plugin_userinfo"; /* storage for player NAMEs and IDs/IPs in the database */ new DB_NAME[MAX_ENTRIES][MAX_NAME_LENGTH]; new DB_INFO[MAX_ENTRIES][MAX_INFO_LENGTH]; /* storage for player Names and IDs/IPs connected to the server */ new NAME[MAX_PLAYERS][MAX_NAME_LENGTH]; new INFO[MAX_PLAYERS][MAX_INFO_LENGTH]; /* Greeting and timer flags */ new GREETED[MAX_PLAYERS]; new PL_TIMER[MAX_PLAYERS]; /* Database Files */ new FILE[2][] = {"id_info.ini", "ip_info.ini"}; /* others */ new Entries=0, sType; new Separator[] = ","; /* error handling */ new Error; new ErrorMsg[MAX_ERRORS][MAX_TEXT_LENGTH]; /* options */ new WelcomeMsg = 1; /* 0 or 1 - greeting on or off */ /* Functions: Declarations */ forward DatabaseAdd(Index); forward DatabaseCheck(UserIndex, iMatch); forward DatabaseLoad(); forward RecordUser(Timer, WaitCount, RepeatCount, HLUser); forward admin_showme(HLCommand, HLData, HLUserName, UserIndex); /* Functions: Events */ /* called once on server start */ public plugin_init() { /* Checks critical Admin Mod values. This plugin will NOT function without these settings */ new Critical[7][] = { "file_access_write", "1", "file_access_read", "1", "allow_client_exec", "1", ""}; Error = 0; /* error handling */ for (new i=0; strlen(Critical[i]); i+=2 ) { if ( getvar(Critical[i])!=strtonum(Critical[i+1]) ) { snprintf(ErrorMsg[Error++], MAX_TEXT_LENGTH, "%s: %s MUST be set to %s", PLUGIN_NAME, Critical[i], Critical[i+1]); } } if ( !Error ) { plugin_registerinfo("Jugger's ID/IP Collector","Collects connecting player's name and ID (or IP)",STRING_VERSION); plugin_registercmd("admin_showme", "admin_showme", ACCESS_ALL, "admin_showme <target or ID or IP>: Shows all names on server for that ID or IP."); sType = getvar("sv_lan"); /* store type of server */ DatabaseLoad(); /* load database in to memory */ } return PLUGIN_CONTINUE; } /* called whenever a player connects */ public plugin_connect(HLUserName, HLIP, UserIndex) { if ( Error ) { /* Output error messages to each user who connects */ new Email[MAX_TEXT_LENGTH]; getstrvar("sv_contact", Email, MAX_TEXT_LENGTH); for (new i=0; i<Error; i++) { selfmessage(ErrorMsg[i]); } selfmessage("Contact the server admin"); if ( strlen(Email) ) { selfmessage(Email); } } else { strinit(INFO[UserIndex]); /* initialise player data */ strinit(NAME[UserIndex]); GREETED[UserIndex] = 0; if ( sType==1 ) { /* LAN Server */ new Data[MAX_DATA_LENGTH]; convert_string(HLIP, Data, MAX_DATA_LENGTH); strtok(Data, ":", INFO[UserIndex], MAX_DATA_LENGTH); /* Store IP Without port */ } } return PLUGIN_CONTINUE; } /* called whenever a player changes name or connects */ public plugin_info(HLOldName, HLNewName, UserIndex) { if ( !Error ) { new Temp[MAX_NAME_LENGTH]; convert_string(HLNewName, NAME[UserIndex], MAX_NAME_LENGTH); convert_string(HLOldName, Temp, MAX_NAME_LENGTH); if ( strcasecmp(NAME[UserIndex], Temp) ) { /* Insert quickly on a name change */ PL_TIMER[UserIndex] = set_timer("RecordUser", 1, 1, NAME[UserIndex]); } else { PL_TIMER[UserIndex] = set_timer("RecordUser", DELAY_TIME, 1, NAME[UserIndex]); } } return PLUGIN_CONTINUE; } /* called whenever a player disconnects */ public plugin_disconnect(HLUserName, UserIndex) { kill_timer(PL_TIMER[UserIndex]); return PLUGIN_CONTINUE; } /* Add Name and Info to database for User */ public DatabaseAdd(Index) { if ( strlen(INFO[Index]) ) { /* if no IP or ID, no addition to database made */ new Text[MAX_TEXT_LENGTH]; if ( Entries<MAX_ENTRIES ) { /* if Database is NOT full, add user to DB and save */ strcpy(DB_NAME[Entries], NAME[Index], MAX_NAME_LENGTH); strcpy(DB_INFO[Entries], INFO[Index], MAX_INFO_LENGTH); snprintf(Text, MAX_TEXT_LENGTH, "%s%s%s", INFO[Index], Separator, NAME[Index]); writefile(FILE[sType], Text); Entries++; } else { snprintf(Text, MAX_TEXT_LENGTH, "%s: Database is full. No more names will be recorded.", PLUGIN_NAME); say(Text); } } return PLUGIN_CONTINUE; } /* Checks database to see if name/info has a matching entry * iMatch==0 - doesn't list matches of names with INFO * iMatch==1 - lists all names matched with INFO * Function returns 1 if details already exist in the database */ public DatabaseCheck(UserIndex, iMatch) { new Count=0, Found=0; new Nick[MAX_NICKS][MAX_NAME_LENGTH]; new Text[MAX_TEXT_LENGTH]; for (new i=0; i<Entries && Count<MAX_NICKS; i++) { /* Collect in 'Nick' array, all previous names used */ if ( strcmp(DB_INFO[i], INFO[UserIndex])==0 ) { if ( strcasecmp(DB_NAME[i], NAME[UserIndex]) ) { strcpy(Nick[Count++], DB_NAME[i], MAX_NAME_LENGTH); } else { Found = 1; } } } if ( iMatch==0 ) { if ( Count>=MAX_NICKS && Found==0 ) { /* if maximum number of names reached, rename to first one used */ snprintf(Text, MAX_TEXT_LENGTH, "%s: Maximum nicknames exceeded on: %s", PLUGIN_NAME, NAME[UserIndex]); say(Text); say("Renaming to first used name on the server."); snprintf(Text, MAX_TEXT_LENGTH, "name ^"%s^"", Nick[0]); execclient(NAME[UserIndex], Text); Found = 1; } } else { if ( Count ) { snprintf(Text, MAX_TEXT_LENGTH, "%s is also known as:", NAME[UserIndex]); selfmessage(Text); for (new i=0; i<Count; i++) { selfmessage(Nick[i]); } } else { snprintf(Text, MAX_TEXT_LENGTH, "%s has only this name on the database", NAME[UserIndex]); selfmessage(Text); } } return Found; } /* load database from server */ public DatabaseLoad() { new Comment[] = ";"; new i=0, Line=0; new Text[MAX_TEXT_LENGTH]; new cl; cl = strlen(Comment); if ( fileexists(FILE[sType]) ) { while ( readfile(FILE[sType], Text, Line++, MAX_NAME_LENGTH) && i<MAX_ENTRIES ) { if ( strncmp(Text, Comment, cl)!=0 ) { if ( strtok(Text, Separator, DB_INFO[i], MAX_INFO_LENGTH)!=-1 ) { if ( strtokrest(DB_NAME[i], MAX_NAME_LENGTH)!=-1 ) { i++; } } } } } else { snprintf(Text, MAX_TEXT_LENGTH, "%s: file %s not found.", PLUGIN_NAME, FILE[sType]); say(Text); } Entries = i; return PLUGIN_CONTINUE; } /* * This function is delayed to allow for Authentication. * It is to greet the connected player on entry, then record * details. */ public RecordUser(Timer, WaitCount, RepeatCount, HLUser) { new UserIndex; new ID[MAX_INFO_LENGTH]; new User[MAX_NAME_LENGTH]; new Text[MAX_TEXT_LENGTH]; convert_string(HLUser, User, MAX_NAME_LENGTH); get_userindex(User, UserIndex); if ( sType==0 ) { /* if INTERNET server, record ID */ get_userAuthID(User, ID, MAX_INFO_LENGTH); if ( strlen(ID)==0 ) { /* if ID not assigned, delay again */ PL_TIMER[UserIndex] = set_timer("RecordUser", DELAY_TIME, 1, NAME[UserIndex]); return PLUGIN_CONTINUE; } else { strcpy(INFO[UserIndex], ID, MAX_INFO_LENGTH); } } if ( DatabaseCheck(UserIndex, 0)==0 ) { /* if details do not exist in database, add them */ DatabaseAdd(UserIndex); } if ( WelcomeMsg==1 && GREETED[UserIndex]==0 ) { /* display welcome message */ playsound(User, "scientist/greetings2.wav"); snprintf(Text, MAX_TEXT_LENGTH, "Greetings, %s", User); messageex(User, Text, print_tty); } GREETED[UserIndex] = 1; /* greet only once per connect */ return PLUGIN_CONTINUE; } /* Functions: User commands */ /* function for handling admin_showme command */ public admin_showme(HLCommand, HLData, HLUserName, UserIndex) { new Command[MAX_COMMAND_LENGTH]; new Data[MAX_DATA_LENGTH]; new TargetName[MAX_NAME_LENGTH]; new Text[MAX_TEXT_LENGTH]; new User[MAX_NAME_LENGTH]; new Index; convert_string(HLCommand, Command, MAX_COMMAND_LENGTH); convert_string(HLData, Data, MAX_DATA_LENGTH); convert_string(HLUserName, User, MAX_NAME_LENGTH); if ( check_user(Data)==1 ) { get_username(Data, TargetName, MAX_NAME_LENGTH); if ( check_immunity(TargetName)!=0 ) { snprintf(Text, MAX_TEXT_LENGTH, "Laf. %s is an admin. That's all private!", TargetName); selfmessage(Text); } else { get_userindex(TargetName, Index); strcpy(NAME[Index], TargetName, MAX_NAME_LENGTH); DatabaseCheck(Index, 1); } } else { selfmessage("Unrecognized player: "); selfmessage(Data); } return PLUGIN_HANDLED; }