/****************************************************************************** afk v1.1 Copyright (C) 2000 by Daniel Lowe. Displays amusing and useful information while away from the keyboard. Compilation: gcc afk.c -o afk -ltermcap Changes: 1.1 - Now checks email using the same method as bash. Added idle kickoff for truly inactive users. Clears screen using termcap. 1.0 - First version. ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_IDLE_SEX 14400 struct user_entry { struct user_entry *next; struct user_entry *prev; char name[UT_NAMESIZE + 1]; char marked; }; struct user_entry *g_users = NULL; char my_name[UT_NAMESIZE + 1] = ""; struct termios orig_term_settings; off_t last_email_size = 0; time_t last_email_time = 0; char* email_file = NULL; void init_terminal( void ) { struct termios changes; int flags; char str[127]; char *c = str; char *term_type; tcgetattr( STDIN_FILENO,&orig_term_settings ); changes = orig_term_settings; changes.c_lflag &= ~(ICANON|ECHO); changes.c_oflag |= OFILL; tcsetattr(STDIN_FILENO,TCSADRAIN,&changes ); flags = fcntl( STDIN_FILENO,F_GETFL,0 ); flags |= O_NONBLOCK; fcntl( STDIN_FILENO,F_SETFL,flags ); term_type = getenv( "TERM" ); if ( term_type && tgetent( NULL,term_type ) > 0 ) printf( "%s",tgetstr( "cl",&c ) ); } int touch_user( char *name ) { struct user_entry *cur_entry = g_users; struct user_entry *the_entry = NULL; if ( !strcmp( my_name,name ) ) return 0; while ( cur_entry && strcmp( cur_entry->name,name ) ) cur_entry = cur_entry->next; if ( cur_entry ) { cur_entry->marked = 1; return 0; } else { the_entry = (struct user_entry *)malloc( sizeof(struct user_entry) ); strncpy( the_entry->name,name,14 ); the_entry->marked = 1; the_entry->next = g_users; the_entry->prev = NULL; if ( g_users ) g_users->prev = the_entry; g_users = the_entry; return 1; } } void clear_marks( void ) { struct user_entry *cur_entry = g_users; while ( cur_entry ) { cur_entry->marked = 0; cur_entry = cur_entry->next; } } void find_unmarked( void ) { struct user_entry *cur_entry = g_users; struct user_entry *next_entry; char datestr[25]; time_t cur_time; while ( cur_entry ) { next_entry = cur_entry->next; if ( !cur_entry->marked ) { cur_time = time( NULL ); strftime( datestr,25,"%H:%M:%S",localtime( &cur_time ) ); printf( "[%s] %s logged out.\n",datestr,cur_entry->name ); fflush( NULL ); if ( cur_entry->next ) cur_entry->next->prev = cur_entry->prev; if ( cur_entry->prev ) cur_entry->prev->next = cur_entry->next; else g_users = cur_entry->next; free( cur_entry ); } cur_entry = next_entry; } } void check_mail( void ) { struct stat f_stat; time_t now = time( NULL ); char datestr[25]; if ( email_file == NULL ) return; if ( stat( email_file,&f_stat ) < 0 ) return; strftime( datestr,25,"%H:%M:%S",localtime( &now ) ); if ( last_email_time && f_stat.st_mtime > last_email_time ) { if ( ( last_email_size && f_stat.st_size > last_email_size ) && ( f_stat.st_atime < f_stat.st_mtime ) ) printf( "\a[%s] new mail received.\n",datestr ); } last_email_size = f_stat.st_size; last_email_time = f_stat.st_mtime; } int main( int argc,char **argv ) { struct utmp *u; struct passwd *pw_entry; char datestr[9]; char username[UT_NAMESIZE + 1]; long start_time = time( NULL ); if ( argc > 1 ) { fprintf( stderr,"Usage: afk [-v][-h]\nafk v1.1\n" ); exit( 0 ); } // Initialize the terminal so we can do the "quit by pressing any key" bit init_terminal(); // Get our own username - we're not displaying ourselves pw_entry = getpwuid( getuid() ); strncpy( my_name,pw_entry->pw_name,UT_NAMESIZE ); // Initialize the user table utmpname(UTMP_FILE); setutent(); clear_marks(); while ( ( u = getutent() ) != NULL ) { // Make sure we have null termination on the user name strncpy( username,u->ut_user,UT_NAMESIZE ); if ( u->ut_type == USER_PROCESS && touch_user( u->ut_user ) ) { strftime( datestr,25,"%H:%M:%S",localtime( &u->ut_time ) ); printf( "[%s] %s is online.\n",datestr,u->ut_user ); fflush( NULL ); } } endutent(); // Initialize the mail checking email_file = getenv( "MAIL" ); check_mail(); // Loop until user presses a key while ( getchar() == -1 && ( time(NULL) - start_time < MAX_IDLE_SEX ) ) { fd_set in_set; struct timeval sleep_time = { 1,0 }; FD_ZERO( &in_set ); FD_SET( 0,&in_set ); select( 1,&in_set,NULL,NULL,&sleep_time ); if ( FD_ISSET( 0,&in_set ) ) continue; setutent(); clear_marks(); while ( ( u = getutent() ) ) { if ( u->ut_type == USER_PROCESS && touch_user( u->ut_user ) ) { strftime( datestr,25,"%H:%M:%S",localtime( &u->ut_time ) ); printf( "\a[%s] %s logged in.\n",datestr,u->ut_user ); fflush( NULL ); } } endutent(); find_unmarked(); check_mail(); } // Inform the guy when he's being kicked off for idling if ( time(NULL) - start_time >= MAX_IDLE_SEX ) printf( "You have been idle, and are pulled into the shell.\n" ); // Restore the terminal settings tcsetattr( STDIN_FILENO,TCSADRAIN,&orig_term_settings ); return 0; }