#include "buddies.h"
char* bud_expand_fmt(const bud_utrec_t *bud, const char *fmt_string);
static int bud_hash_buddy(void *o){
char *c=((buddy_t*)o)->name;
int i, hash=0;
for(i=0;i<strlen(c);i++){
hash=hash<<1;
hash+=((char*)c)[i];
}
return hash;
}
static int bud_hash_login(void *o){
char *c=((bud_utrec_t*)o)->u->ut_line;
int i,hash=0;
for(i=0;i<strlen(c);i++){
hash=hash<<1;
hash+=((char*)c)[i];
}
return hash;
}
static int bud_comp_buddy(void *o1, void *o2){
return strncmp(((buddy_t*)o1)->name, ((buddy_t*)o2)->name,
__UT_NAMESIZE);
}
static int bud_comp_login(void *o1, void *o2){
bud_utrec_t *b1=(bud_utrec_t*)o1, *b2=(bud_utrec_t*)o2;
return strncmp(b1->u->ut_line, b2->u->ut_line, __UT_LINESIZE);
}
htable_t *bud_init_budtable(void){
return ht_init(BUDDY_HT_SIZE, bud_hash_buddy, bud_comp_buddy);
}
int bud_load(const char *fn, htable_t *ht){
char *line_buf=NULL;
int line_buf_size=4, buf_offset=0, len=0;
buddy_t *next_buddy=NULL;
wuzzah_config_t *bconf=NULL;
FILE *buds=NULL;
// initialize the hashtable of buddies
if (g_config.noloadfile) return 0;
else if(strcmp(fn, "-")==0) buds=stdin;
else buds=fopen(fn, "r");
if(!buds){
fprintf(stderr, "unable to open %s! (%s)\n", fn,
strerror(errno));
next_buddy=bud_create_buddy(g_config.whoami);
fprintf(stderr, "defaulting to just watching yourself...\n");
ht_insert(next_buddy, ht);
return 0;
}
line_buf=(char*)malloc(sizeof(char)*line_buf_size);
while(!feof(buds)){
// first make sure we get a whole line
if(!fgets(line_buf+buf_offset, line_buf_size-len, buds))break;
len=strlen(line_buf);
if(strcspn(line_buf, "\n") == len && !feof(buds)){
buf_offset=len;
line_buf_size *= 2;
line_buf=(char*)realloc(line_buf, line_buf_size);
continue;
}
next_buddy=bud_create_buddy(line_buf);
if(ht_find(next_buddy, ht)){
fprintf(stderr,
"%s: warning: duplicate buddy %s\n",
g_config.progname, next_buddy->name);
} else ht_insert(next_buddy, ht);
// reset some variables
len=buf_offset=0;
bconf=NULL;
}
return 0;
}
void bud_load_every_user(htable_t *ht){
struct passwd *pw=NULL;
buddy_t *next_buddy=NULL;
setpwent();
pw=getpwent();
while(pw){
next_buddy=bud_create_buddy(pw->pw_name);
ht_insert(next_buddy, ht);
pw=getpwent();
}
endpwent();
}
// what's going on:
//
// - for each buddy in ht
// - for each bud_utrec_t in buddy's login ht
// - set the 'verify' field to logged out
//
// - initialize the utmpx records
// - for each record in utmpx
// - if it's a USER_PROCESS
// - if ut_user is in buddy ht
// - if buddy's login ht already has ut_line
// - set verify field to logged in
// - else (they've logged in)
// - add the record, with verify=logged in
//
// - for each buddy in ht
// - for each bud_utrec_t in buddy's login ht
// - if verify == logged out (they've logged out)
// - remove from login ht
//
//
void bud_chk_utmpx(htable_t *buddy_table, short write_users){
ht_list_t *budlist_root,*budlist, *utlist_root,*utlist;
STRUCT_UTMPX *u;
// below are for quick lookups in the respective ht's
// (all i need to do is fill in the fields that are used
// for the hash and comp functions)
buddy_t *budptr=NULL, tmpbud;
bud_utrec_t *recptr=NULL, tmprec;
budlist_root=ht_iter(buddy_table);
budlist=budlist_root;
while(budlist){
utlist_root=ht_iter(((buddy_t*)budlist->info)->logins);
utlist=utlist_root;
while(utlist){
((bud_utrec_t*)utlist->info)->verified=B_LOGGED_OUT;
utlist=utlist->lptr;
}
ht_free_iter(utlist_root);
budlist=budlist->lptr;
}
ht_free_iter(budlist_root);
SETUTXENT();
u=GETUTXENT();
while(u){
if(IS_USER_PROCESS(u)){
tmpbud.name=u->ut_user;
budptr=ht_find(&tmpbud, buddy_table);
if(budptr){
tmprec.u=u;
recptr=NULL;
recptr=ht_find(&tmprec, budptr->logins);
if(recptr){
recptr->verified=B_UNCHANGED;
} else {
recptr=MSTRUCT(bud_utrec_t);
recptr->u=MSTRUCT(STRUCT_UTMPX);
memcpy(recptr->u, u,
sizeof(STRUCT_UTMPX));
recptr->verified=B_LOGGED_IN;
ht_insert(recptr, budptr->logins);
}
}
}
u=GETUTXENT();
}
ENDUTXENT();
budlist_root=ht_iter(buddy_table);
budlist=budlist_root;
while(budlist){
budptr=(buddy_t*)budlist->info;
utlist_root=ht_iter(budptr->logins);
utlist=utlist_root;
while(utlist){
recptr=(bud_utrec_t*)utlist->info;
event(budptr, recptr, write_users);
if(recptr->verified==B_LOGGED_OUT)
ht_remove(recptr, budptr->logins);
utlist=utlist->lptr;
}
ht_free_iter(utlist_root);
budlist=budlist->lptr;
}
ht_free_iter(budlist_root);
return;
}
char* bud_expand_fmt(const bud_utrec_t *bud, const char *fmt_string){
int buf_fd[2], buf_size=0, amt=0, i, h_len=0;
char *hname=NULL, *out_str=NULL;
time_t tp;
struct tm *tm_p;
FILE *buf;
struct hostent *hent;
struct in_addr in;
if(!bud || !fmt_string) return NULL;
if(pipe(buf_fd)!=0){
perror("unable to alloc pipe in bud_expand_fmt");
return NULL;
}
buf=fdopen(buf_fd[1], "w");
if(!buf){
perror("unable to attach file ptr in bud_expand_fmt");
return NULL;
}
tp=time(NULL);
tm_p=localtime(&tp);
for(i=0;i<strlen(fmt_string);i++){
if(fmt_string[i]!='%') amt=fprintf(buf, "%c", fmt_string[i]);
else if(i < strlen(fmt_string) - 1){
i++;
switch(fmt_string[i]){
case 'a': amt=fprintf(buf, "\a"); break;
case 'b':
amt=fprintf(buf, "%s", bud->u->ut_user);
break;
case 'd':
amt=fprintf(buf, "%02d:%02d:%02d",
tm_p->tm_hour,
tm_p->tm_min, tm_p->tm_sec);
break;
case 'h':
h_len=UTMPX_HOSTLEN(bud->u);
if(h_len == 0){
amt=fprintf(buf, "localhost");
} else {
hname=(char*)malloc(sizeof(char*)*(h_len+1));
memcpy(hname,
UTMPX_HOSTNAME(bud->u), h_len);
hname[h_len] = '\0';
amt=fprintf(buf, "%s", hname);
free(hname);
}
break;
case 'H':
h_len=UTMPX_HOSTLEN(bud->u);
if(h_len == 0){
amt=fprintf(buf, "127.0.0.1");
} else {
hname=(char*)malloc(sizeof(char*)*(h_len+1));
memcpy(hname,
UTMPX_HOSTNAME(bud->u), h_len);
hname[h_len] = '\0';
hent=gethostbyname(hname);
if(!hent) amt=fprintf(buf, "n/a");
else {
memcpy(&in,
hent->h_addr_list[0],
sizeof(struct in_addr));
hname=inet_ntoa(in);
amt=fprintf(buf, "%s", hname);
}
free(hname);
}
break;
case 'l':
amt=fprintf(buf, "%-8s", bud->u->ut_line);
break;
case 'm':
if(g_config.write_users) amt=fprintf(buf, "messaging");
else amt=fprintf(buf, "not messaging");
break;
case 'n': amt=fprintf(buf, "\n"); break;
case 'o':
if(bud->verified==B_LOGGED_IN)
amt=fprintf(buf, "logged on ");
else if(bud->verified==B_LOGGED_OUT)
amt=fprintf(buf, "logged off");
else amt=fprintf(buf, "bummin'");
break;
case 'u': amt=fprintf(buf, "%s", g_config.whoami); break;
default:
amt=fprintf(buf, "%c", fmt_string[i]);
break;
}
}
if(amt>0) buf_size+=amt;
else if(amt==-1) perror("error writing to pipe");
}
if(!g_config.no_newline) {
amt=fprintf(buf, "\n");
if(amt>0) buf_size+=amt;
else if(amt==-1) perror("error writing to pipe");
}
if(fclose(buf)!=0) perror("error closing pipe");
out_str=(char*)malloc(sizeof(char)*(buf_size+2));
amt=read(buf_fd[0], out_str, sizeof(char)*(buf_size));
out_str[amt]='\0';
if(close(buf_fd[0])!=0) perror("error closing pipe");
return out_str;
}
int argvify(int *cmd_argc, char **cmd_argv[], const char *cmdline){
int i=0, num_args=1, cmd_len=strlen(cmdline);
char **argv=NULL, *next_arg=NULL, *cmd_copy=strdup(cmdline);
if(strtok(cmd_copy, " \t\n")) num_args++;
else {
fprintf(stderr, "argvify: unable to parse string!\n");
return -1;
}
while(strtok(NULL, " \t\n")) num_args++;
argv=(char **)malloc(sizeof(char*)*(num_args+1));
if(!argv) { perror("argvify"); return -1; }
else memset(argv, 0, sizeof(char*)*(num_args+1));
argv[0]=strdup(g_config.progname);
next_arg=cmd_copy;
for(i=1; i<num_args; i++){
while(next_arg[0]=='\0') next_arg+=sizeof(char);
argv[i] = strdup(next_arg);
next_arg=memchr(next_arg, '\0',cmd_len-(next_arg-cmd_copy));
}
argv[num_args]=NULL;
*(cmd_argv)=argv;
*(cmd_argc)=num_args-1;
free(cmd_copy);
return 0;
}
buddy_t* bud_create_buddy(const char *line){
char *line_buf=strdup(line);
buddy_t *next_buddy=MSTRUCT(buddy_t);
short colon=0, len=0;
int ac, i;
char **av=NULL;
wuzzah_config_t *bconf=NULL;
// now check for a per-user config
len=strlen(line_buf);
colon=strcspn(line_buf, ":");
if(colon<len-1) {
line_buf[colon]='\0';
bconf=MSTRUCT(wuzzah_config_t);
ac=string_to_argv(&line_buf[colon+1], &av);
if(ac == -1) bail("error parsing config file\n", 1);
else if(ac){
process_args(ac, av, bconf);
for(i=0;i<ac;i++){
free(av[i]);
}
free(av);
}
}
// now fill in all the data and insert into the ht
if(line_buf[len-1]=='\n') line_buf[len-1]='\0';
next_buddy->name=strdup(line_buf);
next_buddy->conf=bconf;
next_buddy->logins=ht_init(BUDDY_HT_SIZE,
bud_hash_login, bud_comp_login);
free(line_buf);
return next_buddy;
}
syntax highlighted by Code2HTML, v. 0.9.1