----------------------------------------------------------------------- Login History v1.0 by Xerves (November 29 2001) Xerves is the admin/owner of Rafermand (mud.rafermand.net port 3002) Website: http://www.rafermand.net Contact: xerves@rafermand.net ----------------------------------------------------------------------- Was always curious why there was no history list of people who have logged in easily available from the mud to view. It is nice to see how logged in and at what time (so I thought atleast). So here is some code that you can add to the last command to make this work nice TIPS: Make sure you can read/write/delete in your /system directory because it will try to do so to a file or two in there. There is all a defined number in mud.h for file size (#Define LAST_FILE_SIZE 500). This defines the maximum amount of entries that can be in the file. If you wish to make this larger just increase this number, or decrease it to make it smaller. It is a good idea to limit the size because the file is read directly from the HD each time it is looked at and put into memory, then removed from memory. It can cause a bit of system performance degrade if you have people looking at thousands and thousands of lines. Suggested help file addition.... Syntax: last <# of entries OR \'-1\' for all entries OR \'today\' for all of today's entries> Can be used to see the most recent people who have logged in. This feature has 3 arguments. - Can supply the maximum amount to show (last 20) - Can type -1 to show all connections in the file (last -1) - Can type today to show all of today's connections (last today) -------------------------------------------------------------- Files beind modified: mud.h tables.c save.c comm.c -------------------------------------------------------------- 1. mud.h Find #define MAX_INBUF_SIZE 1024 Below it Place this #define LAST_FILE_SIZE 500 //maximum entries in the last file Find /* tables.c */ Below it Place this void read_last_file args((CHAR_DATA *ch, int count)); void write_last_file args((char *entry)); Find #define IMM_HOST_FILE SYSTEM_DIR "immortal.host" /* For stoping hackers */ Below it add the following lines #define LAST_LIST SYSTEM_DIR "last.lst" //last list #define LAST_TEMP_LIST SYSTEM_DIR "ltemp.lst" //temp file for the last list so the data can be copyover over 2. tables.c At the top, add the following include if you do not have it. #include <ctype.h> Anywhere in the file place these 3 functions. void copy_files_contents(FILE *fsource, FILE *fdestination) { int ch; int cnt = 1; for (;;) { ch = fgetc( fsource ); if (!feof(fsource)) { fputc( ch, fdestination); if (ch == '\n') { cnt++; if (cnt >= LAST_FILE_SIZE) //limit size of this file please :-) break; } } else break; } } void write_last_file(char *entry) { FILE *fpout; FILE *fptemp; char filename[MAX_INPUT_LENGTH]; char tempname[MAX_INPUT_LENGTH]; sprintf(filename, "%s", LAST_LIST); sprintf(tempname, "%s", LAST_TEMP_LIST); if ((fptemp = fopen(tempname, "w")) == NULL) { bug("Cannot open: %s for writing", tempname); return; } fprintf(fptemp, "%s\n", entry); //adds new entry to top of the file if ((fpout = fopen(filename, "r")) != NULL) { copy_files_contents(fpout, fptemp); //copy the rest to the file fclose(fpout); //close the files since writing is done } fclose(fptemp); if (remove(filename) != 0 && fopen(filename, "r") != NULL) { bug("Do not have permission to delete the %s file", filename); return; } if (rename(tempname, filename) != 0) { bug("Do not have permission to rename the %s file", tempname); return; } return; } void read_last_file(CHAR_DATA *ch, int count, char *name) { FILE *fpout; char filename[MAX_INPUT_LENGTH]; char charname[100]; int cnt = 0; int letter = 0; char *ln; char *c; char d, e; struct tm *tme; time_t now; char day[MAX_INPUT_LENGTH]; char sday[5]; int fnd = 0; sprintf(filename, "%s", LAST_LIST); if ((fpout = fopen(filename, "r")) == NULL) { send_to_char("There is no last file to look at.\n\r", ch); return; } for (;;) { if (feof(fpout)) { fclose(fpout); ch_printf(ch, "---------------------------------------------------------------------------\n\r%d Entries Listed.\n\r", cnt); return; } else { if (count == -2 || ++cnt <= count || count == -1) { ln = fread_line(fpout); strcpy(charname, ""); if (name) //looking for a certain name { c = ln; for (;;) { if (isalpha(*c) && !isspace(*c)) { charname[letter] = *c; letter++; c++; } else { charname[letter] = '\0'; if (!str_cmp(charname, name)) { ch_printf(ch, "%s", ln); letter = 0; strcpy(charname, ""); break; } else { if (!feof(fpout)) { fread_line(fpout); c = ln; letter = 0; strcpy(charname, ""); continue; } else { cnt--; break; } } } } } else if (count == -2) //only today's entries { c = ln; now = time(0); tme = localtime(&now); strftime(day, 10, "%d", tme); for (;;) { if (!isdigit(*c)) { c++; } else { d = *c; c++; e = *c; sprintf(sday, "%c%c", d, e); if (!str_cmp(sday, day)) { fnd = 1; cnt++; ch_printf(ch, "%s", ln); break; } else { if (fnd == 1) { fclose(fpout); ch_printf(ch, "---------------------------------------------------------------------------\n\r%d Entries Listed.\n\r", cnt); return; } else break; } } } } else { ch_printf(ch, "%s", ln); } } else { fclose(fpout); ch_printf(ch, "--------------------------------------------------------------------------\n\r%d Entries Listed.\n\r", count); return; } } } } 3. Save.c Replace do_last with the following void do_last(CHAR_DATA * ch, char *argument) { char buf[MAX_STRING_LENGTH]; char arg[MAX_INPUT_LENGTH]; char name[MAX_INPUT_LENGTH]; struct stat fst; argument = one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Usage: last <playername>\n\r", ch); send_to_char("Usage: last <# of entries OR \'-1\' for all entries OR \'today\' for all of today's entries>\n\r", ch); send_to_char("Usage: last <playername> <count>\n\r", ch); return; } if (get_trust(ch) < LEVEL_ASCENDANT) { set_char_color(AT_IMMORT, ch); send_to_char("Their godly glow prevents you from getting a good look.\n\r", ch); return; } if (isdigit(arg[0]) || atoi(arg) == -1 || !str_cmp(arg, "today")) //View list instead of players { send_to_char("&w&RName Time Host/Ip\n\r&c&w---------------------------------------------------------------------------\n\r", ch); if (!str_cmp(arg, "today")) read_last_file(ch, -2, NULL); else read_last_file(ch, atoi(arg), NULL); return; } strcpy(name, capitalize(arg)); if (argument[0] != '\0') { send_to_char("&w&RName Time Host/Ip\n\r&c&w---------------------------------------------------------------------------\n\r", ch); read_last_file(ch, atoi(argument), name); return; } sprintf(buf, "%s%c/%s", PLAYER_DIR, tolower(arg[0]), name); if (stat(buf, &fst) != -1) sprintf(buf, "%s was last on: %s\r", name, ctime(&fst.st_mtime)); else sprintf(buf, "%s was not found.\n\r", name); send_to_char(buf, ch); } 4. Comm.c In CASE CON_GET_OLD_PASSWORD find these lines of code sprintf(log_buf, "%s@%s(%s) has connected.", ch->pcdata->filename, d->host, d->user); if (ch->level < LEVEL_IMM) { /*to_channel( log_buf, CHANNEL_MONITOR, "Monitor", ch->level ); */ log_string_plus(log_buf, LOG_COMM, sysdata.log_level); } else log_string_plus(log_buf, LOG_COMM, ch->level); Directly after that add these lines { struct tm *tme; time_t now; char day[50]; now = time(0); tme = localtime(&now); strftime(day, 50, "%a %b %d %H:%M:%S %Y", tme); sprintf(log_buf, "%-20s %-24s %s", ch->pcdata->filename, day, d->host); write_last_file(log_buf); } ------------------------------------------------------------------------------------------------------------------------------ Well that is it, after you get done you need to make clean and recompile the code. Once you do that, you can restart the mud and it will start logging all the new people who login. The file will be /system/last.lst. The file will keep itself to 500 lines unless you change the variable in mud.h (see the TIPS section above). Once that is in play, you are good to go, and I hope it helps out. If you have any ideas on things to add or you add something to this snippet, please contact me so perhaps it can be appended to this snippet :-) --------Xerves - Onwer/Coder of Rafermand (Code Base FeaR 2.0)