/* * wuzzah.c * * written and (c) 2001 by Sean Finney * * This program can be freely copied and redistributed under * the terms of the GNU General Public License, v2. For details * of said terms, please see the file COPYING * */ // Includes #include "includes.h" #include "buddies.h" #include "hashtable.h" #include "common.h" // Definitions // Macros // Function Prototypes void usage(void); void version(void); void wuzzah_whoami(void); void wuzzah_add_extrabuddies(const char *line, htable_t *ht); // Global (config) Variables // g_progname: the name of this program (basename(argv[0])) // g_infile: file to be read in // g_buddy_msg: message to be sent to buddy // g_status_msg: message to be displayed on local tty // g_write_users: whether or not to send users a message // g_sleep_interval: how long to sleep between polling utmp // g_whoami: local username // g_no_newline: don't hard-handedly add a newline to the mesg // g_eventcmd: a command to run when a buddy logs on/off wuzzah_config_t g_config; static const char *g_default_buddy_msg= "(wuzzah) %u says: \"shoutout to my homie %b.\""; static const char *g_default_status_msg= "(%d) %b %o %l from %h"; static const char *g_default_infile=".wuzzah"; static const int g_default_sleep_interval=1; struct option program_opts[] = { { "all-users",1,0,'a' }, { "exec-command",1,0,'c' }, { "help",0,0,'h' }, { "buddyfile",1,0,'f' }, { "no-buddyfile",0,0,'F'}, { "interval",1,0,'i' }, { "message",1,0,'m' }, { "no-newline",0,0,'n' }, { "process-once",0,0,'o' }, { "process-current",0,0,'p' }, { "silent",0,0,'q' }, { "status-message",1,0,'s' }, { "users",1,0,'u' }, { "version",0,0,'v' }, { "write-buddies",0,0,'w' }, { NULL, 0, 0, 0} }; extern char *optarg; extern int optind; // ---- MAIN ---- int main(int argc, char *argv[]){ htable_t *ht=NULL; process_args(argc, argv, &g_config); ht=bud_init_budtable(); wuzzah_whoami(); if(g_config.all_users){ bud_load_every_user(ht); } else { if(g_config.extrabuddies) wuzzah_add_extrabuddies(g_config.extrabuddies, ht); if(!g_config.noloadfile) bud_load(g_config.infile, ht); } if(ht->size==0){ fprintf(stderr, "%s: no buddies specified\n", g_config.progname); fprintf(stderr, "well, if you don't have any friends for\n"); fprintf(stderr, "me to watch, I'm going away!\n"); exit(1); } // let's do it once first, and not spam everyone when // we start up (hence 0). if(!g_config.process_current) bud_chk_utmpx(ht, -1); else bud_chk_utmpx(ht, g_config.write_users); // if we were only supposed to go once if(g_config.run_once) return 0; // otherwise... while(!sleep(g_config.sleep_interval)){ bud_chk_utmpx(ht, g_config.write_users); } return 0; } // ---- Other Functions ---- void process_args(int ac, char *av[], wuzzah_config_t *conf){ int c, len; char *homedir; optind=0; memset(conf, 0, sizeof(wuzzah_config_t)); conf->progname=av[0]=basename(av[0]); while(1){ c=getopt_long(ac, av, "ac:f:Fhi:m:nopqs:u:vw", program_opts, NULL); switch(c){ case 'a': conf->all_users=1; break; case 'c': conf->eventcmd=strdup(optarg); break; case 'f': conf->infile=strdup(optarg); break; case 'F': conf->noloadfile=1; break; case 'h': version(); usage(); exit(0); break; case 'i': conf->sleep_interval=atoi(optarg); break; case 'm': conf->buddy_msg=strdup(optarg); break; case 'n': conf->no_newline=1; break; case 'o': conf->run_once=1; case 'p': conf->process_current=1; break; case 'q': conf->write_users=0; break; case 's': conf->status_msg=strdup(optarg); break; case 'u': conf->extrabuddies=strdup(optarg); break; case 'v': version(); exit(0); break; case 'w': conf->write_users=1; break; } if(c==-1)break; } if(!conf->buddy_msg)conf->buddy_msg=g_default_buddy_msg; if(!conf->status_msg)conf->status_msg=g_default_status_msg; // if the userfile hasn't been specified, use ${HOME}/.wuzzah if(!conf->infile && !conf->noloadfile){ homedir=getenv("HOME"); len=strlen(homedir)+1+strlen(g_default_infile); // 1 for '/' conf->infile=(char*)malloc(sizeof(char)*(len+1)); strncpy(conf->infile, homedir, strlen(homedir)+1); strncat(conf->infile, "/", 1); strncat(conf->infile, g_default_infile, strlen(g_default_infile)); } if(!conf->sleep_interval) conf->sleep_interval=g_default_sleep_interval; } /* * gaaaah, my eyes, this is so ugly. please make me prettier without * losing any functionality... * */ int string_to_argv(const char *str, char **av[]){ int c=0, i=0, j=0, num_args=1, len=strlen(str), procd_str_pipe[2]; int arg_len=0, arg_max_len=0; short parsing_whitespace=1; char **argv=NULL, *tmp=strdup(str); FILE *p_write, *p_read; if(pipe(procd_str_pipe)) perror("opening pipe"); p_read=fdopen(procd_str_pipe[0], "r"); if(!p_read) perror("opening read end of pipe"); p_write=fdopen(procd_str_pipe[1], "w"); if(!p_write) perror("opening write end of pipe"); for(i=0;iarg_max_len)arg_max_len=arg_len; arg_len=0; fputc('\0', p_write); parsing_whitespace=1; } break; case '\'': if(parsing_whitespace) { num_args++; parsing_whitespace=0; } while(str[i+1] != '\'' || str[i] == '\\'){ if(++i > len){ fprintf(stderr, "error: unterminated '\n"); return -1; } if(str[i+1]=='\'' && str[i] == '\\') continue; else { arg_len++; fputc(str[i], p_write); } } i++; break; case '"': if(parsing_whitespace) { num_args++; parsing_whitespace=0; } while(str[i+1] != '"' || str[i] == '\\'){ if(++i > len){ fprintf(stderr, "error: unterminated \"\n"); return -1; } if(str[i+1]=='"' && str[i] == '\\') continue; else { arg_len++; fputc(str[i], p_write); } } i++; break; default: if(parsing_whitespace) { num_args++; parsing_whitespace=0; } arg_len++; fputc(str[i], p_write); break; } } fclose(p_write); argv=(char **)malloc(sizeof(char*)*(num_args+1)); memset(argv, 0, sizeof(char)*(num_args+1)); argv[0]=strdup(g_config.progname); for(i=1; ipw_name)+1)); strncpy(g_config.whoami, pwd->pw_name, (strlen(pwd->pw_name)+1)); } } void wuzzah_add_extrabuddies(const char *line, htable_t *ht){ int i=0, len=strlen(line); const char *head=line; char *buf=NULL; buf=(char*)malloc(sizeof(char)*(strlen(line)+1)); while((int)(head-line)0) { strncpy(buf, head, i); buf[i]='\0'; } else { strncpy(buf, head, strlen(head)); buf[strlen(head)]='\0'; } ht_insert(bud_create_buddy(buf), ht); head=&head[i+1]; } free(buf); } void version(void){ fprintf(stderr, "%s v%s\t-\twuuzzzaaah?\n", g_config.progname, PACKAGE_VERSION); fprintf(stderr, "copyright 2002 sean finney \n"); } void usage(void){ fprintf(stderr, "\nusage:\t"); fprintf(stderr, "%s [OPTIONS] ...\n", g_config.progname); fprintf(stderr, "" " -h, --help this informative usage summary :)\n" " -v, --version the current version and copyright\n\n" " -a, --all-users load and watch for all users\n" " -c, --exec-cmd=CMD evaluate/execute CMD with every login\n" " -f, --buddyfile=FILE use FILE as buddyfile, can be '-' for\n" " signifying to use stdin.\n" " -F, --no-buddyfile do not attempt to load the file which\n" " contains the list of buddies to watch\n" " -i, --interval=NUM sleep NUM seconds between each polling\n" " -m, --message=STRING use STRING as a message template to greet\n" " logged-in buddies. RTFM for more information\n" " -n, --no-newline don't end the various messages in newlines\n" " -o, --process-once exit after having scanned once through the\n" " records.\n" " -p, --process-current override wuzzah's default behavior and\n" " message/write/exec-cmd the users already\n" " logged in.\n" " -q, --silent don't message buddies when they log in\n" " -s, --status-message=STRING use STRING as a template for displaying the\n" " status of people logging in and out\n" " -u, --users=LIST adds LIST to the list of buddies for which\n" " to watch.\n" " -w, --write-budies be obnoxious and write your buddy every time\n" " you see him/her log in.\n" ); } void bail(char *reason, int exitval){ if(reason) fprintf(stderr, "%s: bailing: %s\n", g_config.progname, reason); exit(exitval); }