/*\ * * This code by Sasha (Gentoo) - * Written for use with The Abbey codeset. * * * Problems, bug reports, and flames should be mailed promptly * to: sasha@midnightrealm.org * * LAST.C - A somewhat improved[1] Last List, both cosmetically * and functionally, particularly concerning sorting * logins and logouts. One of the technical advantages * is less memory use, since it doesn't use a (by-default) * 200-element array and attempt to do FIFO wrapping * with it. * * [1] By some conceptions, it's not improved, just changed. * But then, it's really up to you whether you like the * original or this one better, no? * * -------------------------------- * * Installation Instructions (for PG+ or similar) [1] * ================================================== * * PRE) If this file doesn't have a '.c' extension, rename it * so it does! * * 1) Put this file in your 'src' directory and add * 'last.o' to the Makefile (OBJS =) section. If * this is not the correct procedure for your codebase, * do whatever you must to work out the dependencies as * you normally would when adding another .c file. * If a 'last.o' is already there, leave it alone. * Then, do: make depend ... * * 2) In include/proto.h or similar, add these two lines: * * extern void destruct_last_list( void ); * extern void add_last_stamp( player * ); * * 2) In the close_down() function (glue.c), before the * line that says 'close_down_socket()', add this: * * destruct_last_list( ); * * 3) In the plists.c function finish_player_login() * (Stock PG+ 1.0.10 line 1493), find the line that * says: stampLogin(p->name); * REMOVE this line, along with the surrounding * #ifdef LAST and #endif. * * 4) In parse.c, function process_players(), find the line * (Stock PG+ 1.0.10 line 917) that * says: stampLogout(scan->name); * Replace this line with: * * add_last_stamp( scan ); * * 5) Make sure that these lines exist somewhere in your code, be * it include/config.h or include/autoconfig.h or whatever. * * #define LAST 1 * #define LAST_SHOW 10 * * The second line may be a constant other than 10, but * something reasonable at any rate. * THE CODE WILL NOT WORK WITHOUT THIS!!!!! * * 6) In include/clist.h, find the line (187?) that says: * extern command_func viewLast; * and replace this with: * * extern command_func view_last_list; * * 7) Also in include/clist.h, find the line (832?) that says: * {"last", viewLast, BASE, 0, 1, 0, MISCc}, * and replace this with: * * {"last", view_last_list, 0, 0, 1, 0, MISCc}, * * [1] NOTE NOTE NOTE: These may not be the complete * instructions for putting this code into your talker! * This is intended only as a basic overview of the * procedures. * \*/ #include "include/config.h" # ifdef LAST #include #include #include #include #include #include "include/player.h" #include "include/proto.h" # define _ABBEY_LAST_C #define IS_STAFF(p) ((p->residency & PSU) || (p->residency & LOWER_ADMIN) || \ (p->residency & ASU) || (p->residency & HCADMIN) || \ (p->residency & SU) || (p->residency & ADMIN)) typedef struct last_entry_s { char name [ MAX_NAME ]; char site [ MAX_INET_ADDR ]; time_t log_in; time_t log_out; struct last_entry_s *last, *next; } last_entry; static last_entry *last_list = NULL; static last_entry *last_node = NULL; /* economical */ static int num_entries = 0; static last_entry *new_last_node( void ) { last_entry *new_entry; new_entry = (last_entry *) malloc( sizeof(last_entry) ); if( !new_entry ) { /* Let's not handle errors, just like EW* does. */ exit( EXIT_FAILURE ); } memset( new_entry, 0, sizeof(last_entry) ); if( last_list ) last_list->last = new_entry; else last_node = new_entry; new_entry->next = last_list; last_list = new_entry; return( new_entry ); } static void delete_last_node( last_entry *le ) { if( le == last_list ) last_list = le->next; if( le->last ) le->last->next = le->next; if( le->next ) le->next->last = le->last; FREE( le ); } void destruct_last_list( void ) { last_entry *le; for( le = last_list; le != NULL; le = le->next ) { delete_last_node( le ); } } void add_last_stamp( player *p ) { last_entry *le; if( num_entries == LAST_SHOW ) { /* Some may argue that it's silly to optimise by keeping a pointer to the last node. Traversing a small linked list can't be ALL that taxing. Oh well. Optimisation is a virtue of mine. */ le = last_node->last; delete_last_node( last_node ); last_node = le; } else num_entries ++; le = new_last_node( ); strncpy( le->name, p->name, MAX_NAME - 1 ); strncpy( le->site, p->inet_addr, MAX_INET_ADDR - 1 ); le->log_in = (time_t) p->on_since; le->log_out = time( 0 ); } static char *duration_or_site( player *p, last_entry *le ) { if( !IS_STAFF(p) ) { static char log_in_dur [ 25 ]; static char log_out_dur [ 25 ]; strftime( log_in_dur, 25, "%H:%M:%S (%b %d) - ", localtime(&le->log_in) ); strftime( log_out_dur, 25, "%H:%M:%S (%b %d)", localtime(&le->log_out) ); return( strcat(log_in_dur, log_out_dur) ); } else { return( le->site ); } } /* If you are not staff, the time the person was on through the time they were off is shown. Otherwise, the site of the client is displayed in that same field. Hey, it was your choice to use this code ... */ void view_last_list( player *p, char *str ) { last_entry *le; char *oldstack = stack; char *mid; int shown = 0; time_t avg_log_duration = 0; int to_show = LAST_SHOW; if( *str ) { to_show = atoi( str ); if( !to_show || to_show > LAST_SHOW ) { tell_player( p, "Invalid number of entries to show.\n" ); return; } } if( IS_STAFF(p) ) mid = "Site"; else mid = "Login/Logout"; strcpy( stack, "+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+\n" ); stack = strchr( stack, 0 ); sprintf( stack, " [Name] [%-12s] " "[Duration]\n\n", mid ); stack = strchr( stack, 0 ); if( last_list ) { for( le = last_list; le != NULL && to_show; le = le->next ) { time_t tm_diff = ( le->log_out - le->log_in ); avg_log_duration += tm_diff; sprintf( stack, " %-20s %-40s %03d.%02d:%02d\n", le->name, duration_or_site(p, le), (int) (tm_diff/3600), (int) ((tm_diff/60)%60), (int) (tm_diff%60) ); stack = strchr( stack, 0 ); shown ++; to_show --; } } if( last_list ) { avg_log_duration /= shown; sprintf( stack, "\n (Entries shown: %d - " "Average login duration: %03d.%02d:%02d)\n", shown, (int) (avg_log_duration/3600), (int) ((avg_log_duration/60)%60), (int) (avg_log_duration%60) ); stack = strchr( stack, 0 ); } if( !last_list || !shown ) { strcpy( stack, " No entries shown.\n" ); stack = strchr( stack, 0 ); } strcpy( stack, "+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+\n" ); stack = end_string( stack ); if( (shown + 6) > TERM_LINES ) pager( p, oldstack ); else tell_player( p, oldstack ); stack = oldstack; } void last_version( void ) { sprintf( stack, " -=> New last connections list (by Gentoo) enabled.\n" ); stack = strchr( stack, 0 ); } # endif /* LAST */