/* users.c -- handles: testing and enforcing bans and ignores adding and removing bans and ignores listing bans and ignores auto-linking bots sending and receiving a userfile from a bot listing users ('.whois' and '.match') reading the user file dprintf'ized, 9nov95 */ /* bans: ::[+:]: expire-time: timestamp when the ban was made, or 0 for permanent time-added: when the ban was first created last-active: last time ban was enforced */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include "eggdrop.h" #include "users.h" #include "chan.h" #include "proto.h" extern char botname[]; extern char botuser[]; extern char botuserhost[]; extern int serv; extern struct dcc_t dcc[]; extern int dcc_total; extern int noshare; extern struct userrec *userlist,*lastuser,*banu,*ignu; extern char cx_file[]; extern int cx_line; extern char origbotname[]; extern char SBUF[]; extern struct chanset_t *chanset; /* where the user records are stored */ char userfile[121]=""; /* how many minutes will bans last? */ int ban_time=60; /* how many minutes will ignores last? */ int ignore_time=10; /* ignores are stored as 'hostmask:timer' */ int match_ignore(user) char *user; { struct userrec *u; struct eggqueue *q; char hst[121],s[161]; u=get_user_by_handle(userlist,IGNORE_NAME); if (u==NULL) return 0; q=u->host; while (q!=NULL) { strcpy(s,q->item); splitc(hst,s,':'); if (wild_match(hst,user)) return 1; q=q->next; } return 0; } /* returns 1 if temporary ban, 2 if permban, 0 if not a ban at all */ int u_equals_ban(u,user) struct userrec *u; char *user; { struct eggqueue *q; char hst[121],s[256]; q=u->host; while (q!=NULL) { strcpy(s,q->item); splitc(hst,s,':'); if (strcasecmp(hst,user)==0) { if (atol(s)>0) return 1; else return 2; } q=q->next; } return 0; /* not equal */ } int equals_ban(user) char *user; { struct userrec *u; u=get_user_by_handle(userlist,BAN_NAME); if (u==NULL) return 0; return u_equals_ban(u,user); } int u_match_ban(u,user) struct userrec *u; char *user; { struct eggqueue *q; char hst[121],s[256]; q=u->host; while (q!=NULL) { strcpy(s,q->item); splitc(hst,s,':'); if (wild_match(hst,user)) return 1; q=q->next; } return 0; } int match_ban(user) char *user; { struct userrec *u; u=get_user_by_handle(userlist,BAN_NAME); if (u==NULL) return 0; return u_match_ban(u,user); } /* if any bans match this wildcard expression, refresh them on the channel */ void refresh_ban_kick(chan,user,nick) char *user,*nick; struct chanset_t *chan; { struct userrec *u; struct eggqueue *q; char hst[121],s[256],ts[21],s1[161]; time_t expire_time,time_added=(time_t)0L,last_active=(time_t)0L; char *p; static char lastban[161]=""; static time_t lastbantime=(unsigned long)0L; int cycle=0; u=get_user_by_handle(userlist,BAN_NAME); while (u!=NULL) { q=u->host; while ((q!=NULL) && (strcmp(q->item,"none")!=0)) { strcpy(s,q->item); splitc(hst,s,':'); if (wild_match(hst,user)) { /* check if this is repetitive */ if ((strcasecmp(hst,lastban)==0) && (lastbantime >= time(NULL)-60)) { putlog(LOG_MISC,chan->name, "Desync on %s, %s should be banned (leaving it alone)", chan->name,nick); lastbantime=time(NULL); return; } lastbantime=time(NULL); strcpy(lastban,hst); add_mode(chan,'-','o',nick); /* guess it can't hurt */ add_mode(chan,'+','b',hst); flush_mode(chan); /* do it IMMEDIATELY */ splitc(ts,s,':'); expire_time=(time_t)atol(ts); if (s[0]=='+') { /* strip off new timestamps */ strcpy(s,&s[1]); splitc(ts,s,':'); time_added=(time_t)atol(ts); splitc(ts,s,':'); last_active=(time_t)atol(ts); sprintf(s1,"%s:%lu:+%lu:%lu:%s",hst,expire_time,time_added, time(NULL),s); chg_q(q,s1); /* (update last-active timestamp) */ } if ((s[0]) && (strchr(s,'~')!=NULL) && (strchr(s,':')!=NULL)) { /* ban reason stored */ splitc(NULL,s,'~'); /* crafty Fred1 method to dispose of nick */ p=strchr(s,'~'); while (p!=NULL) { *p=' '; p=strchr(s,'~'); } p=strchr(s,'`'); while (p!=NULL) { *p=','; p=strchr(s,'`'); } mprintf(serv,"KICK %s %s :banned: %s\n",chan->name,nick,s); } else mprintf(serv,"KICK %s %s :You are banned.\n",chan->name,nick); } q=q->next; } cycle++; if (cycle==1) u=chan->bans; else u=NULL; } } int u_unprog_ban(u,who) struct userrec *u; char *who; { int i,j; struct eggqueue *q; char s[256],hst[121]; context; i=0; if (atoi(who)) { j=atoi(who); q=u->host; while ((j>0) && (q!=NULL)) { if (strcmp(q->item,"none")!=0) j--; if (j>0) q=q->next; } if (q!=NULL) { strcpy(s,q->item); splitc(who,s,':'); if (!who[0]) strcpy(who,s); u->host=del_q(q->item,u->host,&i); } else return j-atoi(who); } else { /* find matching host, if there is one */ q=u->host; while ((q!=NULL) && (!i)) { strcpy(s,q->item); splitc(hst,s,':'); if (!hst[0]) strcpy(hst,s); if (strcasecmp(who,hst)==0) u->host=del_q(q->item,u->host,&i); q=q->next; } } if (i) { if (!noshare) { /* distribute chan bans differently */ if (strcasecmp(u->handle,BAN_NAME)==0) shareout("-ban %s\n",who); else shareout("-banchan %s %s\n",u->info,who); } } return i; } int unprog_ban(who) char *who; { struct userrec *u; int i; u=get_user_by_handle(userlist,BAN_NAME); if (u==NULL) return 0; i=u_unprog_ban(u,who); if (u->host==NULL) deluser(BAN_NAME); return i; } int unprog_ignore(who) char *who; { struct userrec *u; int i,j; struct eggqueue *q; char s[161],hst[121]; context; u=get_user_by_handle(userlist,IGNORE_NAME); i=0; if (u==NULL) return 0; if (atoi(who)) { j=atoi(who)-1; q=u->host; while (j>0) { if (q!=NULL) q=q->next; j--; } if (q!=NULL) { strcpy(s,q->item); splitc(who,s,':'); u->host=del_q(q->item,u->host,&i); } } else { /* find the matching host, if there is one */ q=u->host; while ((q!=NULL) && (!i)) { strcpy(s,q->item); splitc(hst,s,':'); context; if (strcasecmp(who,hst)==0) u->host=del_q(q->item,u->host,&i); q=q->next; } } if (i) { if (u->host == NULL) deluser(IGNORE_NAME); if (!noshare) shareout("-ignore %s\n",who); } return i; } void u_prog_ban(u,whom,t,note) struct userrec *u; char *whom,*note; time_t t; { char s[161],who[161],*p,oldnote[121]; time_t now=time(NULL); context; sprintf(s,"%s!%s",botname,botuserhost); strcpy(who,whom); /* choke check: fix broken bans (must have '!' and '@') */ if ((strchr(who,'!')==NULL) && (strchr(who,'@')==NULL)) { strcat(who,"!*@*"); } else if (strchr(who,'@')==NULL) { strcat(who,"@*"); } else if (strchr(who,'!')==NULL) { char *p=strchr(who,'@'),s1[161]; strcpy(s1,p); *p=0; strcat(who,"!*"); strcat(who,s1); } if (wild_match(who,s)) { putlog(LOG_MISC,"*","Wanted to ban myself: deflected."); return; } if (u_equals_ban(u,who)) u_unprog_ban(u,who); /* remove old ban */ /* new format: */ sprintf(s,"%s:%lu:+%lu:%lu",who,t,now,now); if (note[0]) { strcpy(oldnote,note); /* remove spaces & commas */ p=strchr(note,' '); while (p!=NULL) { *p='~'; p=strchr(note,' '); } p=strchr(note,','); while (p!=NULL) { *p='`'; p=strchr(note,','); } strcat(s,":"); strcat(s,note); } else oldnote[0]=0; if (t!=0) { t=(now-t); if (t==0) t=1; } u->host=add_q(s,u->host); if (!noshare) { if (strcasecmp(u->handle,BAN_NAME)==0) shareout("+ban %s %lu %s\n",who,t,oldnote); else shareout("+banchan %s %lu %s %s\n",who,t,u->info,oldnote); } strcpy(note,oldnote); } void prog_ban(whom,t,note) char *whom,*note; time_t t; { struct userrec *u; u=get_user_by_handle(userlist,BAN_NAME); if (u==NULL) { userlist=adduser(userlist,BAN_NAME,"none","nopass",0); u=get_user_by_handle(userlist,BAN_NAME); } u_prog_ban(u,whom,t,note); } void prog_ignore(who,t,from) char *who; time_t t; char *from; { struct userrec *u; char s[161]; time_t now=time(NULL); context; u=get_user_by_handle(userlist,IGNORE_NAME); sprintf(s,"%s:%lu:%s",who,t,from); if (t!=0) { t=(now-t); if (t==0) t=1; } if (u==NULL) { userlist=adduser(userlist,IGNORE_NAME,s,"nopass",0); if (!noshare) shareout("+ignore %s %lu\n",who,t); return; } u->host=add_q(s,u->host); if (!noshare) shareout("+ignore %s %lu\n",who,t); } void tell_bans(idx,show_inact,match) int idx,show_inact; char *match; { struct userrec *u; struct eggqueue *q; int i,j,k=1,hidn=0,cycle; char s[256],hst[121],note[121],ts[21],dates[81],*p; time_t expire_time,time_added,last_active,now; struct chanset_t *chan; chan=findchan(dcc[idx].u.chat->con_chan); if (chan==NULL) return; if (show_inact) dprintf(idx,"Global bans: (! = not active on %s)\n",chan->name); else dprintf(idx,"Global bans:\n"); u=get_user_by_handle(userlist,BAN_NAME); now=time(NULL); cycle=0; while (u!=NULL) { if (cycle==1) { if (show_inact) dprintf(idx,"Channel bans for %s: (! = not active, * = not placed by bot)\n", chan->name); else dprintf(idx,"Channel bans for %s: (* = not placed by bot)\n", chan->name); } q=u->host; while ((q!=NULL) && (strcasecmp(q->item,"none")!=0)) { strcpy(s,q->item); splitc(hst,s,':'); splitc(ts,s,':'); expire_time=(time_t)atol(ts); if (s[0]=='+') { /* extended format */ strcpy(s,&s[1]); splitc(ts,s,':'); time_added=(time_t)atol(ts); splitc(ts,s,':'); last_active=(time_t)atol(ts); daysago(now,time_added,note); sprintf(dates,"Created %s",note); if (time_added < last_active) { strcat(dates,", last used "); daysago(now,last_active,note); strcat(dates,note); } } else { time_added=(time_t)0L; last_active=(time_t)0L; dates[0]=0; } strcpy(note,s); if (expire_time==0) strcpy(s,"(perm)"); else { i=now-expire_time; j=(i/60); i=i%60; s[0]=0; sprintf(s,"(active %d:%02d)",j,i); } if (note[0]) { /* fix spaces & commas */ p=strchr(note,'~'); while (p!=NULL) { *p=' '; p=strchr(note,'~'); } p=strchr(note,'`'); while (p!=NULL) { *p=','; p=strchr(note,'`'); } } if (match[0]) { if ((wild_match(match,hst)) || (wild_match(match,note))) { if (isbanned(chan,hst)) dprintf(idx," [%3d] %s %s\n",k,hst,s); else dprintf(idx,"! [%3d] %s %s\n",k,hst,s); dprintf(idx," %s\n",note); if (dates[0]) dprintf(idx," %s\n",dates); } k++; } else { if (isbanned(chan,hst)) { dprintf(idx," [%3d] %s %s\n",k++,hst,s); dprintf(idx," %s\n",note); if (dates[0]) dprintf(idx," %s\n",dates); } else { if (show_inact) { dprintf(idx,"! [%3d] %s %s\n",k++,hst,s); dprintf(idx," %s\n",note); if (dates[0]) dprintf(idx," %s\n",dates); } else { k++; hidn=1; } /* skip it */ } } q=q->next; } if (cycle==0) { u=chan->bans; cycle++; } else u=NULL; } tell_chanbans(chan,idx,k,match); if ((!show_inact) && (hidn)) dprintf(idx,"Use '.bans all' to see the total list.\n"); } /* list the ignores and how long they've been active */ void tell_ignores(idx) int idx; { struct userrec *u; struct eggqueue *q; int i,j,k=1; time_t tt,ti; char s[161],hst[121],s1[81]; u=get_user_by_handle(userlist,IGNORE_NAME); tt=time(NULL); if (u==NULL) { dprintf(idx,"No ignores.\n"); return; } q=u->host; if (q==NULL) dprintf(idx,"No ignores.\n"); dprintf(idx,"Currently ignoring:\n"); while (q!=NULL) { strcpy(s,q->item); splitc(hst,s,':'); ti=atol(s); if (ti==0) strcpy(s1,"(perm)"); else { i=tt-ti; j=(i/60); i=i%60; s1[0]=0; sprintf(s1,"(active %d:%02d)",j,i); } splitc(NULL,s,':'); dprintf(idx," [%2d] (%-9s) %s %s\n",k++,s,hst,s1); q=q->next; } } /* check for expired timed-ignores */ void check_expired_ignores() { struct userrec *u; struct eggqueue *q; char s[161],hst[121]; time_t tt,ti; context; u=get_user_by_handle(userlist,IGNORE_NAME); tt=time(NULL); if (u==NULL) return; q=u->host; if (q==NULL) return; while (q!=NULL) { strcpy(s,q->item); splitc(hst,s,':'); ti=atol(s); if (ti!=0L) if (tt-ti >= 60*ignore_time) { /* expired */ putlog(LOG_MISC,"*","No longer ignoring %s (automatically expired)",hst); unprog_ignore(hst); u=get_user_by_handle(userlist,IGNORE_NAME); if (u!=NULL) q=u->host; /* start over, check for more */ } if ((u!=NULL) && (q!=NULL)) q=q->next; else q=NULL; } } /* check for expired timed-bans */ void check_expired_bans() { struct userrec *u; struct eggqueue *q; char s[256],hst[121]; time_t tt,ti; char note[41]; struct chanset_t *chan; context; u=get_user_by_handle(userlist,BAN_NAME); tt=time(NULL); if (u==NULL) return; q=u->host; if (q==NULL) return; while (q!=NULL) { strcpy(s,q->item); splitc(hst,s,':'); splitc(note,s,':'); ti=atoi(note); if ((ti!=0L) && (tt-ti >= 60*ban_time)) { /* expired: 1 hr later */ putlog(LOG_MISC,"*","No longer banning %s (automatically expired)",hst); chan=chanset; while (chan!=NULL) { add_mode(chan,'-','b',hst); chan=chan->next; } unprog_ban(hst); u=get_user_by_handle(userlist,BAN_NAME); if (u!=NULL) q=u->host; /* start over, check for more */ else q=NULL; } else q=q->next; } /* check for specific channel-domain bans expiring */ chan=chanset; while (chan!=NULL) { q=chan->bans->host; while ((q!=NULL) && (strcmp(q->item,"none")!=0)) { strcpy(s,q->item); splitc(hst,s,':'); splitc(note,s,':'); ti=atoi(note); if ((ti!=0L) && (tt-ti >= 60*ban_time)) { putlog(LOG_MISC,chan->name,"No longer banning %s on %s (expired)", hst,chan->name); add_mode(chan,'-','b',hst); u_unprog_ban(chan->bans,hst); q=chan->bans->host; } else q=q->next; } chan=chan->next; } } /* see if there are any bots that need to be linked */ /* priority is: +sh (highest), +h, +a (lowest) */ /* only link ONE +h bot at a time */ /* only link ONE +a bot at a time, and only if the +h are unreachable, and then keep trying for the +h bot(s) */ void auto_link_tandem(start) char *start; { struct userrec *u=userlist,*autc=NULL; static int cycle=0; int got_hub=0,got_alt=0,linked,ready=0,i; context; if (start==NULL) { ready=1; cycle=0; } /* new run through the user list */ while (u!=NULL) { if ((flags_eq(USER_BOT|BOT_HUB,u->flags)) || (flags_eq(USER_BOT|BOT_ALT,u->flags))) { linked=0; for (i=0; ihandle)==0) { if (dcc[i].type==DCC_TANDEM) linked=1; if (dcc[i].type==DCC_TANDEM_NEW) linked=1; if (dcc[i].type==DCC_FORK) if (dcc[i].u.fork->type==DCC_TANDEM) linked=1; } } /* check for possibility that share-bot IS linked in... but not to me */ if ((!linked) && (in_chain(u->handle)) && (u->flags&BOT_SHARE) && (strcasecmp(origbotname,u->handle)!=0)) { int q=nextbot(u->handle); tprintf(dcc[q].sock,"unlink %s %s %s\n",origbotname,lastbot(u->handle), u->handle); /* once unlinking is done, i'll try to autoconnect later */ } /* is this a HUB we have linked? */ if ((u->flags&BOT_HUB) && (linked)) { got_hub=1; if ((autc!=NULL) && (autc->flags&BOT_HUB) && !(autc->flags&BOT_SHARE)) { /* great... already have a hub bot in line to be linked */ /* start over from there */ u=autc; linked=1; autc=NULL; } } /* is this an ALT we have linked? */ if ((u->flags&BOT_ALT) && (linked)) got_alt=1; /* don't link anything if we have our +h bot */ if ((got_hub) && !(u->flags&BOT_SHARE)) linked=1; /* if we've got an alt linked, don't link another one */ if ((got_alt) && (u->flags&BOT_ALT)) linked=1; if ((!linked) && (u->flags&BOT_ALT) && (in_chain(u->handle))) linked=1; if ((!linked) && (ready)) { if (autc==NULL) autc=u; else if ((u->flags&BOT_HUB) && !(autc->flags&BOT_HUB) && (cycle==0)) autc=u; /* hub priority over alt (except 2nd cycle) */ else if ((u->flags&BOT_SHARE) && !(autc->flags&BOT_SHARE)) autc=u; /* share bots get priority */ } /* did we make it where we're supposed to start? yay! */ if (!ready) if (strcasecmp(u->handle,start)==0) ready=1; } if ((u->flags&USER_BOT) && (u->flags&BOT_REJECT)) if (in_chain(u->handle)) { /* get rid of nasty reject bot */ reject_bot(u->handle); } u=u->next; if ((u==NULL) && (autc==NULL) && (cycle==0)) { /* end of 1st run of userlist -- no succeses */ /* try again, this time go for +a */ cycle++; u=userlist; } } if ((got_hub) && (cycle==0)) autc=NULL; if (((got_hub) || (got_alt)) && (cycle==1)) autc=NULL; if (autc!=NULL) tandem_link("",-1,autc->handle); /* try autoconnect */ } /* erase old user list, switch to new one */ void finish_share(idx) int idx; { struct userrec *u; int i,j=0; for (i=0; istatus&=~STAT_GETTING; /* copy the bots over */ u=dup_userlist(1); /* read the rest in */ if (!readuserfile(dcc[idx].u.xfer->filename,&u)) { putlog(LOG_MISC,"*","CAN'T READ NEW USERFILE"); return; } unlink(dcc[idx].u.xfer->filename); /* done with you! */ putlog(LOG_MISC,"*","Userlist transfer complete; switched over."); clear_userlist(userlist); userlist=u; clear_chanlist(); lastuser=banu=ignu=NULL; } /* begin the user transfer process */ void start_sending_users(idx) int idx; { struct userrec *u; char s[121]; int i; context; sprintf(s,".share.user%lu",time(NULL)); u=dup_userlist(0); /* only non-bots */ write_tmp_userfile(s,u); clear_userlist(u); i=raw_dcc_send(s,"*users","(users)",s); if (i>0) return; /* abort */ dcc[idx].u.tand->status|=STAT_SENDING; i=dcc_total-1; strcpy(dcc[i].host,dcc[idx].nick); /* store bot's nick */ tprintf(dcc[idx].sock,"ufsend %lu %d %lu\n",getmyip(),dcc[i].port, dcc[i].u.xfer->length); } /* update a user's last signon, by host */ void update_laston(host) char *host; { struct userrec *u; u=get_user_by_host(host); if (u==NULL) return; u->laston=time(NULL); } /* return laston time */ void get_handle_laston(nick,n) char *nick; time_t *n; { struct userrec *u; u=get_user_by_handle(userlist,nick); if (u==NULL) *n=0L; else *n = u->laston; } void set_handle_laston(nick,n) char *nick; time_t n; { struct userrec *u; u=get_user_by_handle(userlist,nick); if (u==NULL) return; u->laston=n; } void set_handle_laston2(bu,nick,n) struct userrec *bu; char *nick; time_t n; { struct userrec *u; u=get_user_by_handle(bu,nick); if (u==NULL) return; u->laston=n; } /* since i was getting a ban list, i assume i'm chop */ /* recheck_bans makes sure that all who are 'banned' on the userlist are actually in fact banned on the channel */ void recheck_bans(chan) struct chanset_t *chan; { struct userrec *u; struct eggqueue *q; char s[256],hst[121]; context; if (chan->stat&CHAN_DYNAMICBANS) return; u=get_user_by_handle(userlist,BAN_NAME); if (u==NULL) return; q=u->host; while ((q!=NULL) && (strcmp(q->item,"none")!=0)) { strcpy(s,q->item); splitc(hst,s,':'); if (!hst[0]) strcpy(hst,s); if (!isbanned(chan,hst)) add_mode(chan,'+','b',hst); q=q->next; } } /* find info line for a user and display it if there is one */ void showinfo(chan,who,nick) char *who,*nick; struct chanset_t *chan; { char s[121]; if (get_attr_handle(who) & USER_BOT) return; get_handle_info(who,s); if (s[0]=='@') strcpy(s,&s[1]); if (s[0]) mprintf(serv,"PRIVMSG %s :[%s] %s\n",chan->name,nick,s); } void tell_user(idx,u,master) int idx; struct userrec *u; int master; { char s[81],s1[81],host[81]; struct eggqueue *q; time_t now; if (strcmp(u->handle,BAN_NAME)==0) { dprintf(idx,"[ban list] -> use '.bans'\n"); return; } if (strcmp(u->handle,IGNORE_NAME)==0) { dprintf(idx,"[ignore list] -> use '.ignores'\n"); return; } flags2str(u->flags,s); if (u->laston == 0L) strcpy(s1,"never"); else { now=time(NULL)-(u->laston); strcpy(s1,ctime(&(u->laston))); if (now>86400) { s1[7]=0; strcpy(&s1[11],&s1[4]); strcpy(s1,&s1[8]); } else { s1[16]=0; strcpy(s1,&s1[11]); } } strcpy(host,u->host->item); if (strlen(host)>33) { strcpy(host,"(see below)"); q=u->host; } else q=u->host->next; dprintf(idx,"%-10s%-35s%-5s%-18s%s\n",u->handle,host,(strcasecmp(u->pass, "nopass")==0)?"no":"yes",s,s1); s[0]=0; while (q!=NULL) { if (!s[0]) sprintf(s," %s",q->item); else { if (strlen(s)+strlen(q->item)+2>70) { dprintf(idx,"%s\n",s); sprintf(s," %s",q->item); } else { strcat(s,", "); strcat(s,q->item); } } q=q->next; } if (s[0]) dprintf(idx,"%s\n",s); if ((master) && (u->comment!=NULL)) dprintf(idx," COMMENT: %s\n",u->comment); if (u->email!=NULL) dprintf(idx," EMAIL: %s\n",u->email); if (u->flags&USER_BOT) { if (u->info!=NULL) dprintf(idx," ADDRESS: %s\n",u->info); } else { if (u->info!=NULL) dprintf(idx," INFO: %s\n",u->info); } } /* show user by ident */ void tell_user_ident(idx,id,master) int idx; char *id; int master; { struct userrec *u; u=get_user_by_handle(userlist,id); if (u==NULL) u=get_user_by_host(id); if (u==NULL) { dprintf(idx,"Can't find anyone matching that.\n"); return; } dprintf(idx,"HANDLE HOSTMASK(S) PASS ATTR LAST\n"); tell_user(idx,u,master); } /* match string: wildcard to match nickname or hostmasks */ /* +attr to find all with attr */ void tell_users_match(idx,mtch,start,limit,master) int idx; char *mtch; int start,limit,master; { struct userrec *u=userlist; int fnd=0,cnt; struct eggqueue *q; dprintf(idx,"*** Matching '%s':\n",mtch); cnt=0; dprintf(idx,"HANDLE HOSTMASK(S) PASS ATTR LAST\n"); if (start>1) dprintf(idx,"(skipping first %d)\n",start-1); while (u!=NULL) { if (mtch[0]=='+') { fnd=str2flags(&mtch[1]); if ((u->flags&fnd)==fnd) { cnt++; if ((cnt<=limit) && (cnt>=start)) tell_user(idx,u,master); if (cnt==limit+1) dprintf(idx,"(more than %d matches; list truncated)\n",limit); } } else if (wild_match(mtch,u->handle)) { cnt++; if ((cnt<=limit) && (cnt>=start)) tell_user(idx,u,master); if (cnt==limit+1) dprintf(idx,"(more than %d matches; list truncated)\n",limit); } else { fnd=0; q=u->host; while (q!=NULL) { if ((wild_match(mtch,q->item)) && (!fnd)) { cnt++; fnd=1; if ((cnt<=limit) && (cnt>=start)) tell_user(idx,u,master); if (cnt==limit+1) dprintf(idx,"(more than %d matches; list truncated)\n",limit); } q=q->next; } } u=u->next; } dprintf(idx,"--- Found %d match%s.\n",cnt,cnt==1?"":"es"); } int readuserfile(file,ret) char *file; struct userrec **ret; { char *p,s[181],lasthand[20],host[181],attr[181],pass[181],code[181]; FILE *f; unsigned int flags; struct userrec *bu; context; bu=(*ret); if (bu==userlist) { clear_chanlist(); lastuser=banu=ignu=NULL; } lasthand[0]=0; f=fopen(file,"r"); if (f==NULL) return 0; noshare=1; context; while (!feof(f)) { fgets(s,180,f); if (!feof(f)) { rmspace(s); if ((s[0]!='#') && (s[0]!=';') && (s[0])) { nsplit(code,s); rmspace(code); rmspace(s); if (strcasecmp(code,"-")==0) { if (lasthand[0]) { p=strchr(s,','); while (p!=NULL) { splitc(code,s,','); rmspace(code); rmspace(s); if (code[0]) addhost_by_handle2(bu,lasthand,code); p=strchr(s,','); } if (s[0]) addhost_by_handle2(bu,lasthand,s); } } else if (strcasecmp(code,"+")==0) { if (lasthand[0]) { set_handle_email(bu,lasthand,s); } } else if (strcasecmp(code,"*")==0) { if (lasthand[0]) { set_handle_dccdir(bu,lasthand,s); } } else if (strcasecmp(code,"=")==0) { if (lasthand[0]) { set_handle_comment(bu,lasthand,s); } } else if (strcasecmp(code,":")==0) { if (lasthand[0]) { set_handle_info(bu,lasthand,s); } } else if (strcasecmp(code,".")==0) { if (lasthand[0]) { add_handle_xtra(bu,lasthand,s); } } else { nsplit(host,s); rmspace(host); rmspace(s); nsplit(pass,s); rmspace(pass); rmspace(s); nsplit(attr,s); rmspace(attr); rmspace(s); if ((!s[0]) || (!attr[0]) || (!pass[0]) || (!host[0])) { putlog(LOG_MISC,"*","* Corrupt user record '%s'!",code); lasthand[0]=0; } else if (is_user2(bu,code)) { putlog(LOG_MISC,"*","* Duplicate user record '%s'!",code); lasthand[0]=0; } else { flags=str2flags(attr); strcpy(lasthand,code); if (strcasecmp(host,"$placeholder$")==0) host[0]=0; if (strcasecmp(host,"none")==0) host[0]=0; if (strlen(code)>9) code[9]=0; if (strlen(pass)>9) pass[9]=0; bu=adduser(bu,code,host,pass,flags); set_handle_laston2(bu,code,atol(s)); } } } } } noshare=0; context; fclose(f); (*ret)=bu; return 1; }