/* stuff for the current channel */ #include #include #include #include #include #ifdef AIX #include #endif #include "eggdrop.h" #include "chan.h" extern char botuserhost[]; extern char botuser[]; extern char version[]; extern int serv; extern int memused; extern char botchan[]; extern char botserver[]; extern time_t online_since; extern int backgrd; extern int use_console; extern int con_chan; extern int term_z; extern int botserverport; extern char helpbot[]; extern char helpserver[]; extern int helpserverport; extern int learn_users; extern int helpsock; extern int mtot,htot; extern int dcc_total; extern struct dcc_t dcc[]; extern int use_info; extern int periodic_save; extern int share_users; extern int passive; extern char cx_file[]; extern int cx_line; extern char os[]; extern char ver[]; extern int ban_time; /* bot's nickname */ char botname[10]; /* bot's intended nickname (might have had to switch if nick was in use) */ char origbotname[10]; /* +o to oplisted people when they join? */ int op_on_join=1; /* be vengeful when people are bad? */ int revenge=1; /* if # servers on our side of a split falls below this, jump servers */ /* 0 = don't use this */ int min_servs=0; /* show joins/parts/quits in log? */ int log_joins=1; /* admin info */ char admin[121]; /* something we can dump to server to get ops? */ char gainops[121]; /* desired channel modes (future use) */ int desired_mode=0; /* use greetings in userfile? */ int greet=1; /* enforce bans by kicking banned people, etc? */ int enforce_bans=1; /* strict hostname matching (don't strip ~) */ int strict_host=0; /* expected channel key */ char chankey[121]=""; /* if 0, all bans are temporary */ int perm_bans=1; struct chan_t channel; char curchan[81]=""; char botchan[81]=""; int members=0; void check_lonely_channel(); /* make nick!~user@host into nick!user@host if necessary */ void fixfrom(s) char *s; { char nick[10],from[121]; if (strict_host) return; if (s==NULL) return; if (strchr(s,'@')==NULL) return; strcpy(from,s); splitnick(nick,from); if (from[0]=='~') strcpy(from,&from[1]); sprintf(s,"%s!%s",nick,from); } /* set the key */ void set_key(k) char *k; { context; nfree(channel.key); if (k==NULL) { channel.key=(char *)nmalloc(1); channel.key[0]=0; return; } channel.key=(char *)nmalloc(strlen(k)+1); strcpy(channel.key,k); } /* memory expected to be used by this module */ int expmem_chan() { int tot; banlist *b; tot=strlen(channel.key)+1+(sizeof(struct memstruct)*(members+1)); b=channel.ban; while (b!=NULL) { tot+=strlen(b->ban)+1; if (b->ban[0]) tot+=strlen(b->who)+1; tot+=sizeof(struct banstruct); b=b->next; } return tot; } /* dump status info out to dcc */ void tell_verbose_status(z,showchan) int z,showchan; { char s[81],s1[121],s2[81]; int i; time_t now,hr,min; memberlist *m; #ifdef RUSAGE struct rusage ru; #endif context; s[0]='+'; i=1; if (channel.mode&CHANINV) s[i++]='i'; if (channel.mode&CHANPRIV) s[i++]='p'; if (channel.mode&CHANSEC) s[i++]='s'; if (channel.mode&CHANMODER) s[i++]='m'; if (channel.mode&CHANTOPIC) s[i++]='t'; if (channel.mode&CHANNOMSG) s[i++]='n'; if (channel.key[0]) s[i++]='k'; if (channel.maxmembers>-1) s[i++]='l'; s[i]=0; if (channel.key[0]) sprintf(&s[strlen(s)]," %s",channel.key); if (channel.maxmembers>-1) sprintf(&s[strlen(s)]," %d",channel.maxmembers); #ifdef TCL tprintf(z,"I am %s, running %s (under %s/Tcl).\n",botname,ver,os); #else tprintf(z,"I am %s, running %s (under %s).\n",botname,ver,os); #endif if (admin[0]) tprintf(z,"Admin: %s\n",admin); if (curchan[0]) sprintf(s1,"Channel %s",curchan); else sprintf(s1,"Desiring channel %s",botchan); m=channel.member; while ((m->nick[0]) && (strcasecmp(m->nick,botname)!=0)) m=m->next; if (m->nick[0]!=0) if (!(m->flags&CHANOP)) { tprintf(z,"-> I'm not a chanop!\n"); if (gainops[0]) tprintf(serv,"%s\n",gainops); ask_tandem_for_ops(); } if (showchan) { int nn; i=count_users(); tprintf(z,"%s, %d member%s, %d user%s, mode %s (mem: %u)\n",s1,members, members==1?"":"s",i,i==1?"":"s",s,memused); for (i=0; istatus&STAT_GETTING) { nn=count_users2(dcc[i].u.tand->user); tprintf(z,"Downloading userlist from %s (got %d so far)\n", dcc[i].nick,nn); } if (dcc[i].u.tand->status&STAT_SENDING) { nn=count_users2(dcc[i].u.tand->user); tprintf(z,"Sending userlist to %s (%d to go)\n",dcc[i].nick,nn); } } } tprintf(z,"Server %s:%d\n",botserver,botserverport); if (helpbot[0]) { tprintf(z,"Helpbot '%s' on %s:%d\n",helpbot,helpserver,helpserverport); if (htot) tprintf(z,"Helpbot's queue is %d%% full.\n", (int)((float)(htot*100.0)/(float)MAXQMSG)); } if (mtot) tprintf(z,"Server queue is %d%% full.\n", (int)((float)(mtot*100.0)/(float)MAXQMSG)); now=time(NULL); now-=online_since; s[0]=0; if (now>86400) { /* days */ sprintf(s,"%d day",(int)(now/86400)); if ((int)(now/86400) >= 2) strcat(s,"s"); strcat(s,", "); now-=(((int)(now/86400))*86400); } hr=(int)(now/3600); now-=(hr*3600); min=(int)(now/60); sprintf(&s[strlen(s)],"%02d:%02d",hr,min); s1[0]=0; if (backgrd) strcpy(s1,"background, "); else { if (term_z) strcpy(s1,"terminal mode, "); if (con_chan) strcpy(s1,"status mode, "); } #ifdef RUSAGE getrusage(RUSAGE_SELF,&ru); hr=(int)((ru.ru_utime.tv_sec+ru.ru_stime.tv_sec)/60); /* actally min/sec */ min=(int)((ru.ru_utime.tv_sec+ru.ru_stime.tv_sec)-(hr*60)); sprintf(s2,"CPU %02d:%02d",hr,min); #else sprintf(s2,"CPU ???"); #endif tprintf(z,"Online for %s (running in %sconsole %s) %s\n",s,s1, use_console?"on":"off",s2); s1[0]=0; if (op_on_join) strcat(s1,"auto-op, "); if (revenge) strcat(s1,"revenge, "); if ((use_info) && (greet)) strcat(s1,"auto-greet, "); if (learn_users) strcat(s1,"learn users, "); if (periodic_save) strcat(s1,"slow save, "); if (share_users) { if (passive) strcat(s1,"passive share, "); else strcat(s1,"aggressive share, "); } if (s1[0]) s1[strlen(s1)-2]=0; else strcpy(s1,"none"); tprintf(z,"Mode(s): %s.\n",s1); } /* dump channel info out to dcc */ void tell_verbose_chan_info(z) int z; { char handle[20],s[81],s1[121]; int i; memberlist *m; time_t now; context; s[0]='+'; i=1; now=time(NULL); if (channel.mode&CHANINV) s[i++]='i'; if (channel.mode&CHANPRIV) s[i++]='p'; if (channel.mode&CHANSEC) s[i++]='s'; if (channel.mode&CHANMODER) s[i++]='m'; if (channel.mode&CHANTOPIC) s[i++]='t'; if (channel.mode&CHANNOMSG) s[i++]='n'; if (channel.key[0]) s[i++]='k'; if (channel.maxmembers>-1) s[i++]='l'; s[i]=0; if (channel.key[0]) sprintf(&s[strlen(s)]," %s",channel.key); if (channel.maxmembers>-1) sprintf(&s[strlen(s)]," %d",channel.maxmembers); if (curchan[0]) sprintf(s1,"Channel %s",curchan); else sprintf(s1,"Desiring channel %s",botchan); i=count_users(); tprintf(z,"%s, %d member%s, %d user%s, mode %s: (mem: %u)\n",s1,members, members==1?"":"s",i,i==1?"":"s",s,memused); m=channel.member; i=0; if (curchan[0]) while (m->nick[0]) { if (m->joined > 0) { strcpy(s,ctime(&(m->joined))); if ((time(NULL)-(m->joined)) > 86400) { strcpy(s1,&s[4]); strcpy(s,&s[8]); strcpy(&s[2],s1); s[5]=0; } else { strcpy(s,&s[11]); s[5]=0; } } else strcpy(s,"dunno"); sprintf(s1,"%s!%s",m->nick,m->userhost); get_handle_by_host(handle,s1); if (m->split > 0) tprintf(z,"%2d. %c%-9s %-9s (%s) <- netsplit, %lus\n",++i,m->flags& CHANOP?'@':(m->flags&CHANVOICE?'+':' '),m->nick,handle,s, now-(m->split)); else if (strcmp(m->nick,botname)==0) tprintf(z,"%2d. %c%-9s %-9s (%s) <- it's me!\n",++i,m->flags&CHANOP? '@':(m->flags&CHANVOICE?'+':' '),m->nick,handle,s); else tprintf(z,"%2d. %c%-9s %-9s (%s) %c%c%c%c %s\n",++i,m->flags&CHANOP? '@':(m->flags&CHANVOICE?'+':' '),m->nick,handle,s, match_master(s1)?'M':' ',match_op(s1)?'O':' ',match_deop(s1)? 'D':' ',match_friend(s1)?'F':' ',m->userhost); if (m->flags&FAKEOP) tprintf(z," (FAKE CHANOP GIVEN BY SERVER)\n"); m=m->next; } tprintf(z,"End of channel info.\n"); } int on_chan(handle) char *handle; { char s[161],h[21]; memberlist *m=channel.member; while (m->nick[0]) { sprintf(s,"%s!%s",m->nick,m->userhost); get_handle_by_host(h,s); if (strcasecmp(h,handle)==0) return 1; m=m->next; } return 0; } void tell_chanbans(z,k) int z,k; { banlist *b=channel.ban; char s[121],s1[81],fill[121]; time_t now; int min,sec; context; now=time(NULL); if (curchan[0]) { while (b->ban[0]) { if (!equals_ban(b->ban)) { strcpy(s,b->who); splitnick(s1,s); if (s1[0]) sprintf(fill,"%s (%s)",b->ban,s1); else if (strcasecmp(s,"existant")==0) sprintf(fill,"%s (%s)",b->ban,s); else sprintf(fill,"%s (server %s)",b->ban,s); if (b->timer != 0) { min=(now - b->timer)/60; sec=(now - b->timer)-(min*60); sprintf(s," (for %02d:%02d)",min,sec); strcat(fill,s); } tprintf(z,"* [%2d] %s\n",k++,fill); } b=b->next; } } if (k==1) tprintf(z,"(There are no bans, permanent or otherwise.)\n"); } int kill_chanban(z,k,which) int z,k,which; { banlist *b=channel.ban; context; if (k==0) k=1; while (b->ban[0]) { if (!equals_ban(b->ban)) { if (k==which) { add_mode('-','b',b->ban); tprintf(z,"Removed ban on '%s'.\n",b->ban); } k++; } b=b->next; } if (k<=which) { tprintf(z,"No such ban.\n"); return 0; } else return 1; } int kill_chanban_name(z,which) int z; char *which; { banlist *b=channel.ban; context; while (b->ban[0]) { if (strcasecmp(b->ban,which)==0) { add_mode('-','b',b->ban); tprintf(z,"Removed ban on '%s'.\n",b->ban); return 1; } b=b->next; } tprintf(z,"No such ban.\n"); return 0; } /* log the channel members */ void log_chan() { banlist *b; memberlist *m; char s1[121]; int chops=0,masters=0,ops=0,deops=0,bans=0; context; if (curchan[0]) { m=channel.member; while (m->nick[0]) { sprintf(s1,"%s!%s",m->nick,m->userhost); if (m->flags&CHANOP) chops++; if (match_master(s1)) masters++; if (match_op(s1)) ops++; if (match_deop(s1)) deops++; m=m->next; } b=channel.ban; while (b->ban[0]) { bans++; b=b->next; } log(LOG_MISC,"%2d member%s, %2d chop%s, %2do %2dm %2dd, %2d ban%s", members,members==1?" ":"s",chops,chops==1?" ":"s",ops,masters,deops, bans,bans==1?" ":"s"); } } /* dump channel info out to nick */ void tell_chan_info(nick) char *nick; { char s[81],s1[121]; int i,chops=0,masters=0,ops=0,deops=0; memberlist *m; banlist *b; context; s[0]='+'; i=1; if (channel.mode&CHANINV) s[i++]='i'; if (channel.mode&CHANPRIV) s[i++]='p'; if (channel.mode&CHANSEC) s[i++]='s'; if (channel.mode&CHANMODER) s[i++]='m'; if (channel.mode&CHANTOPIC) s[i++]='t'; if (channel.mode&CHANNOMSG) s[i++]='n'; if (channel.key[0]) s[i++]='k'; if (channel.maxmembers>-1) s[i++]='l'; s[i]=0; if (channel.key[0]) sprintf(&s[strlen(s)]," %s",channel.key); if (channel.maxmembers>-1) sprintf(&s[strlen(s)]," %d",channel.maxmembers); mprintf(serv,"NOTICE %s :I am %s, running %s.\n",nick,botname,version); if (curchan[0]) sprintf(s1,"Channel %s",curchan); else sprintf(s1,"Desiring channel %s",botchan); mprintf(serv,"NOTICE %s :%s, %d members, mode %s (mem: %u)\n",nick,s1, members,s,memused); m=channel.member; i=0; while (m->nick[0]) { sprintf(s1,"%s!%s",m->nick,m->userhost); if (m->flags&CHANOP) chops++; if (match_master(s1)) masters++; if (match_op(s1)) ops++; if (match_deop(s1)) deops++; m=m->next; } sprintf(s1,"NOTICE %s :%d chops, %d masterlist, %d oplist, %d deoplist,", nick,chops,masters,ops,deops); b=channel.ban; while (b->ban[0]) { i++; b=b->next; } mprintf(serv,"%s %d bans.\n",s1,i); } /* initialize out the channel record */ void init_channel() { context; channel.maxmembers=(-1); channel.mode=0; members=0; channel.key=(char *)nmalloc(1); channel.key[0]=0; channel.ban=(banlist *)nmalloc(sizeof(banlist)); channel.ban->ban=(char *)nmalloc(1); channel.ban->ban[0]=0; channel.ban->who=NULL; channel.ban->next=NULL; channel.member=(memberlist *)nmalloc(sizeof(memberlist)); channel.member->nick[0]=0; channel.member->next=NULL; } /* clear out channel data from memory */ void clear_channel() { memberlist *m,*m1; banlist *b,*b1; context; nfree(channel.key); m=channel.member; while (m!=NULL) { m1=m->next; nfree(m); m=m1; } b=channel.ban; while (b!=NULL) { b1=b->next; if (b->ban[0]) nfree(b->who); nfree(b->ban); nfree(b); b=b1; } init_channel(); } /* returns a pointer to a new channel member structure */ memberlist *newmember() { memberlist *x; x=channel.member; while (x->nick[0]) x=x->next; x->next=(memberlist *)nmalloc(sizeof(memberlist)); x->next->next=NULL; x->next->nick[0]=0; x->next->split=0L; members++; return x; } /* adds a ban to the list */ void newban(s,who) char *s; char *who; { banlist *b; context; b=channel.ban; while ((b->ban[0]) && (strcasecmp(b->ban,s)!=0)) b=b->next; if (b->ban[0]) return; /* already existant ban */ b->next=(banlist *)nmalloc(sizeof(banlist)); b->next->next=NULL; b->next->ban=(char *)nmalloc(1); b->next->ban[0]=0; nfree(b->ban); b->ban=(char *)nmalloc(strlen(s)+1); strcpy(b->ban,s); b->who=(char *)nmalloc(strlen(who)+1); strcpy(b->who,who); b->timer=time(NULL); } /* removes a nick from the channel member list (returns 1 if successful) */ int killmember(nick) char *nick; { memberlist *x,*old; context; x=channel.member; old=NULL; while ((x->nick[0]) && (strcasecmp(x->nick,nick)!=0)) { old=x; x=x->next; } if (x->nick[0]==0) return 0; if (old==NULL) channel.member=x->next; else old->next=x->next; nfree(x); members--; return 1; } /* removes a ban from the list */ int killban(s) char *s; { banlist *b,*old; context; b=channel.ban; old=NULL; while ((b->ban[0]) && (strcasecmp(b->ban,s)!=0)) { old=b; b=b->next; } if (b->ban[0]==0) return 0; if (old==NULL) channel.ban=b->next; else old->next=b->next; nfree(b->ban); nfree(b->who); nfree(b); return 1; } /* returns memberfields if the nick is in the member list */ memberlist *ismember(nick) char *nick; { memberlist *x; x=channel.member; while ((x->nick[0]) && (strcasecmp(x->nick,nick)!=0)) x=x->next; if (x->nick[0]==0) return NULL; return x; } /* returns true if this is one of the channel bans */ int isbanned(user) char *user; { banlist *b; context; b=channel.ban; while ((b->ban[0]) && (strcasecmp(b->ban,user)!=0)) b=b->next; if (b->ban[0]==0) return 0; return 1; } void getchanhost(nick,host) char *nick,*host; { memberlist *m; host[0]=0; m=ismember(nick); if (m==NULL) return; strcpy(host,m->userhost); } int is_split(nick) char *nick; { memberlist *m; m=ismember(nick); if (m==NULL) return 0; return (int)(m->split); } /* called only if perm-bans is off */ void check_expired_chanbans() { banlist *b; time_t now=time(NULL); if (!me_op()) return; /* can't do this if not op! */ context; b=channel.ban; while (b->ban[0]) { if (now - b->timer > 60*ban_time) { log(LOG_MISC,"Channel ban on %s expired.",b->ban); add_mode('-','b',b->ban); } b=b->next; } } /* kick anyone off the channel who matches a ban */ void kick_banned_members() { banlist *b; memberlist *m; char s[121]; context; if (!enforce_bans) return; b=channel.ban; while (b->ban[0]) { m=channel.member; while (m->nick[0]) { sprintf(s,"%s!%s",m->nick,m->userhost); if ((wild_match(b->ban,s)) && (strcasecmp(m->nick,botname)!=0)) tprintf(serv,"KICK %s %s :banned\n",curchan,m->nick); m=m->next; } b=b->next; } } /* kick everyone on the channel with matching hostmask that joined since the time stamp */ void kick_match_since(mask,timestamp) char *mask; time_t timestamp; { char s[121]; memberlist *m=channel.member; context; while (m->nick[0]) { sprintf(s,"%s!%s",m->nick,m->userhost); if ((wild_match(mask,s)) && (m->joined >= timestamp)) tprintf(serv,"KICK %s %s :lemmingbot\n",curchan,m->nick); m=m->next; } } /* resets the bans on the channel */ void resetbans() { banlist *b; context; if (!me_op()) return; /* can't do it */ /* remove bans we didn't put there */ b=channel.ban; while (b->ban[0]) { if (!equals_ban(b->ban)) add_mode('-','b',b->ban); b=b->next; } /* make sure the intended bans are still there */ recheck_bans(); } /* things to do when i just became a chanop: */ void recheck_channel() { memberlist *m; char s[121]; /* okay, sort through who needs to be deopped. */ context; m=channel.member; while (m->nick[0]) { sprintf(s,"%s!%s",m->nick,m->userhost); if ((match_deop(s)) && (match_op(s))) log(LOG_MISC,"User is +o and +d (please fix): %s",s); else { if ((m->flags&CHANOP) && (strcasecmp(m->nick,botname)!=0) && (match_deop(s))) add_mode('-','o',m->nick); if ((!(m->flags&CHANOP)) && (match_op(s)) && (op_on_join)) add_mode('+','o',m->nick); } if ((enforce_bans) && (match_ban(s)) && (strcasecmp(m->nick,botname)!=0)) tprintf(serv,"KICK %s %s :banned\n",curchan,m->nick); else if ((match_kick(s)) && (strcasecmp(m->nick,botname)!=0)) tprintf(serv,"KICK %s %s :...and thank you for playing.\n",curchan, m->nick); m=m->next; } recheck_bans(); recheck_chanmode(); } void newly_chanop() { recheck_channel(); /* find out the bans now */ tprintf(serv,"MODE %s +b\n",curchan); } /* am i a chanop? */ int me_op() { memberlist *mx; mx=ismember(botname); if (mx==NULL) return 0; if (mx->flags&CHANOP) return 1; else return 0; } /* reset the channel information */ void reset_chan_info() { clear_channel(); tprintf(serv,"WHO %s\n",curchan); tprintf(serv,"MODE %s\n",curchan); if (me_op()) newly_chanop(); } /* got 324: mode status */ void got324(from,msg) char *from,*msg; { int i=1; char *p,*q,msgg[81]; context; from[0]=from[0]; split(NULL,msg); split(NULL,msg); /* get rid of to & chan fields */ strcpy(msgg,msg); while (msg[i]!=0) { if (msg[i]=='i') channel.mode |= CHANINV; if (msg[i]=='p') channel.mode |= CHANPRIV; if (msg[i]=='s') channel.mode |= CHANSEC; if (msg[i]=='m') channel.mode |= CHANMODER; if (msg[i]=='t') channel.mode |= CHANTOPIC; if (msg[i]=='n') channel.mode |= CHANNOMSG; if (msg[i]=='k') { p=strchr(msg,' '); p++; q=strchr(p,' '); if (q!=NULL) { *q=0; channel.key=(char *)nmalloc(strlen(p)+1); strcpy(channel.key,p); strcpy(p,q+1); } else { channel.key=(char *)nmalloc(strlen(p)+1); strcpy(channel.key,p); *p=0; } } if (msg[i]=='l') { p=strchr(msg,' '); p++; q=strchr(p,' '); if (q!=NULL) { *q=0; channel.maxmembers=atoi(p); strcpy(p,q+1); } else { channel.maxmembers=atoi(p); *p=0; } } i++; } } /* got a 352: who info! */ void got352(from,msg) char *from,*msg; { char userhost[121],nick[10]; char s[121]; memberlist *m; int waschanop; context; split(NULL,msg); split(s,msg); from[0]=from[0]; if (strcasecmp(s,curchan)!=0) return; /* they're not on MY channel... */ split(userhost,msg); strcat(userhost,"@"); split(&userhost[strlen(userhost)],msg); split(NULL,msg); split(nick,msg); sprintf(s,"%s!%s",nick,userhost); fixfrom(s); splitnick(nick,s); strcpy(userhost,s); split(s,msg); m=ismember(nick); if (m==NULL) { m=newmember(); m->joined=0L; m->flags=0; m->split=0L; } strcpy(m->nick,nick); strcpy(m->userhost,userhost); if (strcasecmp(nick,botname)==0) strcpy(botuserhost,userhost); waschanop=me_op(); if (strchr(s,'@')!=NULL) m->flags |= CHANOP; else m->flags &= ~CHANOP; if (strchr(s,'+')!=NULL) m->flags |= CHANVOICE; else m->flags &= ~CHANVOICE; if ((strcasecmp(nick,botname)==0) && (!waschanop) && (me_op())) newly_chanop(); if ((strcasecmp(nick,botname)==0) && (!me_op()) && (gainops[0])) { tprintf(serv,"%s\n",gainops); ask_tandem_for_ops(); } sprintf(s,"%s!%s",nick,userhost); fixfrom(s); if ((m->flags&CHANOP) && (match_deop(s)) && (strcasecmp(nick,botname)!=0) && (me_op())) add_mode('-','o',nick); if ((match_ban(s)) && (strcasecmp(nick,botname)!=0) && (me_op()) && (enforce_bans)) tprintf(serv,"KICK %s %s :banned\n",curchan,nick); else if ((match_kick(s)) && (strcasecmp(nick,botname)!=0) && (me_op())) tprintf(serv,"KICK %s %s :...and thank you for playing.\n",curchan,nick); } /* got 367: ban info */ void got367(from,msg) char *from,*msg; { char s[121],who[81],*p; context; split(NULL,msg); split(NULL,msg); from[0]=from[0]; p=strchr(msg,' '); if (p!=NULL) { strcpy(s,msg); split(msg,s); split(who,s); newban(msg,who); } else newban(msg,"existant"); sprintf(s,"%s!%s",botname,botuserhost); if ((wild_match(msg,s)) && (me_op())) add_mode('-','b',msg); if ((match_op(msg)) && (me_op())) add_mode('-','b',msg); /* these will be flushed by 368: end of ban info (in chanprog.c) */ } /* got 251: lusers */ /* Yebor :there are 2258 users and 805 invisible on 127 servers */ void got251(from,msg) char *from,*msg; { int i; char servs[20]; split(NULL,msg); fixcolon(msg); from[0]=from[0]; for (i=0; i<8; i++) split(NULL,msg); split(servs,msg); if (strncmp(msg,"servers",7)!=0) return; /* was invalid format */ i=atoi(servs); if (min_servs==0) return; /* no minimum limit on servers */ if (isplit==0) killmember(nick); else if (strcasecmp(m->userhost,from)!=0) killmember(nick); else { m->split=0; if ((m->flags&CHANOP) && (me_op()) && (op_on_join)) add_mode('+','o',nick); log(LOG_CHAN,"%s (%s) returned to %s.",nick,from,chan); return; } } m=newmember(); m->joined=time(NULL); m->split=0L; m->flags=0; strcpy(m->nick,nick); strcpy(m->userhost,from); if (strcasecmp(nick,botname)==0) { /* it was us joining! */ log(LOG_CHAN|LOG_MISC,"%s joined %s.",nick,chan); strcpy(curchan,chan); tprintf(serv,"WHO %s\n",chan); tprintf(serv,"MODE %s\n",chan); /* can't get ban list till we're opped :( */ } else { log(LOG_CHAN,"%s (%s) joined %s.",nick,from,chan); sprintf(s,"%s!%s",nick,from); for (i=0; i126) || (s[i]==';')) { tprintf(serv,"KICK %s %s :bogus username\n",curchan,nick); return; } /* don't re-display greeting if they've been on the channel recently */ if ((greet) && (use_info) && (tnow-tt > 180)) showinfo(handle,nick); i=num_notes(handle); if (i) { hprintf(helpsock,"NOTICE %s :You have %d note%s waiting on %s's %s\n", nick,i,i==1?"":"s",botname,"party line."); } if ((me_op()) && (match_op(s)) && (op_on_join)) add_mode('+','o',nick); if ((me_op()) && (match_ban(s)) && (strcasecmp(nick,botname)!=0) && (enforce_bans)) { refresh_ban(s); tprintf(serv,"KICK %s %s :You are banned.\n",curchan,nick); } else if ((me_op()) && (match_kick(s)) && (strcasecmp(nick,botname)!=0)) tprintf(serv,"KICK %s %s :...and thank you for playing.\n",curchan,nick); } } /* part */ void gotpart(from,chan) char *from,*chan; { char nick[10]; context; update_laston(from); splitnick(nick,from); fixcolon(chan); killmember(nick); log(LOG_CHAN,"%s (%s) left %s.",nick,from,chan); /* if it was us, all hell breaks loose: */ if (strcasecmp(nick,botname)==0) { clear_channel(); curchan[0]=0; /* we're not here any more */ } else check_lonely_channel(); } /* kick */ void gotkick(from,msg) char *from,*msg; { char nick[10],chan[81],whodid[10],s[121],s1[121]; memberlist *m; static char kicknick[10]=""; static time_t kicktime=0L; static int kicks=0; context; split(chan,msg); /* needless channel info */ split(nick,msg); fixcolon(msg); splitnick(whodid,from); sprintf(s,"%s!%s",whodid,from); /* check for masskick */ if ((!match_friend(s)) && (!match_master(s)) && (strcasecmp(botname,whodid)!=0) && (strcasecmp(kicknick,whodid)==0)) { time_t tt=time(NULL); if (tt-kicktime <= 10) { kicks++; if (kicks>=3) { /* masskick */ tprintf(serv,"KICK %s %s :mass kick, go sit in a corner\n",curchan, whodid); kicks=0; kicknick[0]=0; kicktime=0L; } } else { kicks=1; kicktime=time(NULL); } } else { strcpy(kicknick,whodid); kicktime=time(NULL); kicks=1; } log(LOG_MODES,"%s kicked by %s: %s",nick,s,msg); if (strcasecmp(nick,botname)==0) { curchan[0]=0; tprintf(serv,"JOIN %s %s\n",botchan,chankey); clear_channel(); if (revenge) { unprog_op_and_deop(s,"kicked me off the channel"); /* ^put the kicker on the deop list : revenge */ } } else check_lonely_channel(); /* kicking an oplisted person? KICK THEM. */ m=ismember(nick); if (m!=NULL) { sprintf(s1,"%s!%s",m->nick,m->userhost); update_laston(s1); /* revenge on, kicker was not bot, kicker was not kickee, kickee was oplisted, and kicker was not (whew!) */ if ((match_op(s1)) && (revenge) && (strcasecmp(whodid,botname)!=0) && (!match_op(s)) && (strcasecmp(whodid,nick)!=0)) tprintf(serv,"KICK %s %s :don't kick my friends, bud\n",curchan,whodid); } killmember(nick); } /* nick change */ void gotnick(from,msg) char *from, *msg; { char nick[10],s[121]; memberlist *m; context; strcpy(s,from); splitnick(nick,s); fixcolon(msg); m=ismember(nick); if (m==NULL) return; /* confused server. */ log(LOG_CHAN,"Nick change: %s -> %s",m->nick,msg); strcpy(m->nick,msg); sprintf(s,"%s!%s",m->nick,m->userhost); update_laston(s); } /* signoff, similar to part */ void gotquit(from,msg) char *from,*msg; { char nick[10]; memberlist *m; context; update_laston(from); splitnick(nick,from); fixcolon(msg); if (wild_match("*.* *.*",msg)) { /* server split, dammit! */ m=ismember(nick); if (m!=NULL) { m->split=time(NULL); log(LOG_CHAN,"%s (%s) got netsplit.",nick,from); } } else { killmember(nick); log(LOG_CHAN,"%s (%s) left irc: %s",nick,from,msg); } check_lonely_channel(); } /* msg to xx everyone on the channel's info */ void show_all_info(who) char *who; { memberlist *m; char s[120],nick[20],also[512]; context; also[0]=0; m=channel.member; while (m->nick[0]) { sprintf(s,"%s!%s",m->nick,m->userhost); get_handle_by_host(nick,s); get_handle_info(nick,s); if (match_attr_handle(nick,USER_TANDEM)) s[0]=0; if (s[0]=='@') strcpy(s,&s[1]); if (s[0]) hprintf(helpsock,"NOTICE %s :[%9s] %s\n",who,m->nick,s); else { if (strcasecmp(m->nick,botname)==0) hprintf(helpsock,"NOTICE %s :[%9s] <-- I'm the bot, of course.\n", who,m->nick); else if ((match_attr_handle(nick,USER_TANDEM)) && (match_attr_handle(nick,BOT_SHARE))) hprintf(helpsock,"NOTICE %s :[%9s] <-- a fellow bot\n",who,m->nick); else { strcat(also,m->nick); strcat(also,", "); } } m=m->next; } if (also[0]) { also[strlen(also)-2]=0; hprintf(helpsock,"NOTICE %s :No info: %s\n",who,also); } } /* request from a user to kickban (over dcc) */ void user_kickban(z,nick) int z; char *nick; { memberlist *m; char s[121],s1[121],note[41]; int i; context; for (i=0; (inick,m->userhost); if (match_op(s)) { tprintf(z,"%s is a legal op.\n",nick); return; } if (match_master(s)) { tprintf(z,"%s is a bot master.\n",nick); return; } strcpy(s,m->userhost); maskhost(s,s1); sprintf(s,"*!*%s",&s1[2]); /* gotta add that extra '*' */ add_mode('+','b',s); tprintf(serv,"KICK %s %s :requested\n",curchan,m->nick); prog_ban(s,time(NULL),note); /* killmember(m->nick); */ tprintf(z,"Okay, done.\n"); } /* check for expired netsplit people */ void check_expired_splits() { memberlist *m; time_t now; context; now=time(NULL); m=channel.member; while (m->nick[0]) { if (m->split) { if (curchan[0]==0) killmember(m->nick); else if (now-(m->split) > 300) { log(LOG_CHAN,"%s (%s) got lost in the net-split.",m->nick, m->userhost); killmember(m->nick); } } m=m->next; } } void check_for_split() { /* called once a minute... but if we're the only one on the channel, we only wanna send out "lusers" once every 5 mins */ static count=4; context; if ((curchan[0]) && (members==1)) { count++; if (count>=5) { mprintf(serv,"LUSERS\n"); count=0; } } } /* if we're the only person on the channel, and we're not opped, might as well leave and rejoin */ /* if we're NOT the only person on the channel, but we're still not opped, demand ops */ void check_lonely_channel() { context; if ((curchan[0]) && (members==1) && (!me_op())) { tprintf(serv,"PART %s\n",curchan); tprintf(serv,"JOIN %s %s\n",botchan,chankey); log(LOG_MISC,"Attempting to regain chanop by recreating the channel."); } else if (!me_op()) { ask_tandem_for_ops(); if (gainops[0]) tprintf(serv,"%s\n",gainops); } } /* add a user who's on the channel */ void add_chan_user(nick,z) char *nick; int z; { memberlist *m; char s[121],s1[121]; context; if (curchan[0]==0) { tprintf(z,"I'm not on a channel!\n"); return; } m=ismember(nick); if (m==NULL) { tprintf(z,"%s is not on the channel.\n",nick); return; } if (is_user(nick)) { tprintf(z,"Already a user %s.\n",nick); return; } sprintf(s,"%s!%s",m->nick,m->userhost); maskhost(s,s1); tprintf(z,"Added [%s]%s with no password or flags.\n",m->nick,s1); adduser(m->nick,s1,"nopass",0); } /* op/deop on the fly per master's request */ void give_op(nick,z) char *nick; int z; { memberlist *m; char s[121]; context; if (curchan[0]==0) { tprintf(z,"I'm not on a channel!\n"); return; } m=ismember(nick); if (m==NULL) { tprintf(z,"%s is not on the channel.\n",nick); return; } sprintf(s,"%s!%s",m->nick,m->userhost); if (match_deop(s)) { tprintf(z,"%s is currently being auto-deopped.\n",m->nick); return; } add_mode('+','o',nick); tprintf(z,"Gave op to %s\n",nick); } void give_deop(nick,z) char *nick; int z; { memberlist *m; char s[121]; context; if (curchan[0]==0) { tprintf(z,"I'm not on a channel!\n"); return; } m=ismember(nick); if (m==NULL) { tprintf(z,"%s is not on the channel.\n",nick); return; } sprintf(s,"%s!%s",m->nick,m->userhost); if (match_op(s)) { tprintf(z,"%s is currently being auto-opped.\n",m->nick); return; } add_mode('-','o',nick); tprintf(z,"Took op from %s\n",nick); }