/* stuff for the current channel */ #include #include #include #include #include "eggdrop.h" extern char bothost[]; 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 spymode; extern int spypub; extern int learn_users; extern int helpsock; extern int mtot,htot; /* 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; typedef struct memstruct { char nick[10]; char userhost[81]; time_t joined; unsigned char flags; time_t split; /* in case they were just netsplit */ struct memstruct *next; } memberlist; #define CHANOP 1 #define CHANVOICE 2 #define FAKEOP 4 typedef struct banstruct { char *ban; char *who; struct banstruct *next; } banlist; struct { memberlist *member; banlist *ban; char *key; char mode; int maxmembers; } channel; char curchan[81]=""; char botchan[81]=""; int members=0; #define CHANINV 1 /* +i */ #define CHANPRIV 2 /* +p */ #define CHANSEC 4 /* +s */ #define CHANMODER 8 /* +m */ #define CHANTOPIC 16 /* +t */ #define CHANNOMSG 32 /* +n */ /* make nick!~user@host into nick!user@host if necessary */ void fixfrom(s) char *s; { char nick[10],from[121]; 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); } /* 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]; int i; time_t now,hr,min; memberlist *m; 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); tprintf(z,"I am %s, running %s.\n",botname,version); 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); } if (showchan) tprintf(z,"%s, %d members, mode %s (mem: %u)\n",s1,members,s,memused); 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 (term_z) strcpy(s1,"terminal mode, "); if (con_chan) strcpy(s1,"channel display, "); tprintf(z,"Online for %s (running in %sground, %sconsole %s)\n",s, backgrd?"back":"fore",s1,use_console?"on":"off"); s1[0]=0; if (spymode) { if (spypub) strcat(s1,"spying all, "); else strcat(s1,"spying, "); } if (op_on_join) strcat(s1,"auto-op, "); if (revenge) strcat(s1,"revenge, "); if (greet) strcat(s1,"auto-greet, "); if (learn_users) strcat(s1,"learn users, "); 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,showbans) int z,showbans; { char handle[20],s[81],s1[121]; int i; memberlist *m; banlist *b; time_t now; 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); tprintf(z,"%s, %d members, mode %s: (mem: %u)\n",s1,members,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; } b=channel.ban; if ((curchan[0]) && (showbans)) { char show[121],fill[81];; strcpy(show,"Bans: "); while (b->ban[0]) { if (strcmp(show,"Bans: ")!=0) strcat(show,", "); 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 (strlen(fill)+strlen(show) < 70) strcat(show,fill); else { tprintf(z,"%s\n",show); sprintf(show," %s",fill); } b=b->next; } if (!(channel.ban->ban[0])) strcat(show,"None."); tprintf(z,"%s\n",show); } tprintf(z,"End of channel info.\n"); } /* 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; 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; } console("%2d members, %2d[%2d] chops, %2d masters, %2d deops, %2d bans", members,chops,ops,masters,deops,bans); } } /* 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; 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,"PRIVMSG %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,"PRIVMSG %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,"PRIVMSG %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() { 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; 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; 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); } /* removes a nick from the channel member list (returns 1 if successful) */ int killmember(nick) char *nick; { memberlist *x,*old; 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; 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; b=channel.ban; while ((b->ban[0]) && (strcasecmp(b->ban,user)!=0)) b=b->next; if (b->ban[0]==0) return 0; return 1; } /* resets the bans on the channel */ void resetbans() { banlist *b; 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_deban(b->ban); b=b->next; } /* make sure the intended bans are still there */ recheck_bans(); } /* when possibly doing a lot of deops, use this to minimize flooding */ /* "stacks" deops, then dumps and resets at 3 */ void add_mode(nick,plus) char *nick; char plus; { static char deoplist[161]=""; static int deopcnt=0; static char deopmode[10]=""; static char last='+'; if (nick[0]!='@') { deopcnt++; if (deoplist[0]) strcat(deoplist," "); if (deopmode[0]==0) { deopmode[1]=0; deopmode[0]=plus; last=plus; } if (plus!=last) { deopmode[strlen(deopmode)+1]=0; deopmode[strlen(deopmode)]=plus; } strcat(deoplist,nick); strcat(deopmode,"o"); last=plus; } if ((deopcnt==3) || (nick[0]=='@')) { if (deopcnt) tprintf(serv,"MODE %s %s %s\n",curchan,deopmode,deoplist); deopmode[0]=0; deoplist[0]=0; deopcnt=0; last='+'; } } void add_deop(nick) char *nick; { add_mode(nick,'-'); } void add_op(nick) char *nick; { add_mode(nick,'+'); } void flush_deop() { add_mode("@",'@'); } /* 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. */ m=channel.member; while (m->nick[0]) { sprintf(s,"%s!%s",m->nick,m->userhost); if ((match_deop(s)) && (match_op(s))) console("!!! ERROR: OP AND DEOP: %s",s); else { if ((m->flags&CHANOP) && (strcasecmp(m->nick,botname)!=0) && (match_deop(s))) add_deop(m->nick); if ((!(m->flags&CHANOP)) && (match_op(s)) && (op_on_join)) add_op(m->nick); } if ((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(); flush_deop(); } 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]; 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++; } /* printf("*** Channel is mode %s\n",msgg); */ } /* got a 352: who info! */ void got352(from,msg) char *from,*msg; { char userhost[121],nick[10]; char s[121]; memberlist *m; int waschanop; 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); 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); sprintf(s,"%s!%s",nick,userhost); fixfrom(s); if ((m->flags&CHANOP) && (match_deop(s)) && (strcasecmp(nick,botname)!=0) && (me_op())) add_deop(nick); if ((match_ban(s)) && (strcasecmp(nick,botname)!=0) && (me_op())) 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); flush_deop(); } /* got 367: ban info */ void got367(from,msg) char *from,*msg; { char s[121],who[81],*p; 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@%s",botname,botuser,bothost); if ((wild_match(msg,s)) && (me_op())) add_deban(msg); if ((match_op(msg)) && (me_op())) add_deban(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_op(nick); flush_deop(); } if (log_joins) console("%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 (log_joins) console("%s (%s) joined %s.",nick,from,chan); if (strcasecmp(nick,botname)==0) { /* it was us joining! */ 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 { char handle[20]; sprintf(s,"%s!%s",nick,from); get_handle_by_host(handle,s); if (greet) showinfo(handle,nick); if ((me_op()) && (match_op(s)) && (op_on_join)) tprintf(serv,"MODE %s +o %s\n",curchan,nick); if ((me_op()) && (match_ban(s)) && (strcasecmp(nick,botname)!=0)) tprintf(serv,"KICK %s %s :avoiding ban\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]; update_laston(from); splitnick(nick,from); fixcolon(chan); killmember(nick); /* if it was us, all hell breaks loose: */ if (strcasecmp(nick,botname)==0) { clear_channel(); curchan[0]=0; /* we're not here any more */ } if (log_joins) console("%s (%s) left %s.",nick,from,chan); } /* kick */ void gotkick(from,msg) char *from,*msg; { char nick[10],chan[81],whodid[10],s[121],s1[121]; memberlist *m; split(chan,msg); /* needless channel info */ split(nick,msg); fixcolon(msg); splitnick(whodid,from); console("%s kicked by %s!%s: %s",nick,whodid,from,msg); sprintf(s,"%s!%s",whodid,from); if (strcasecmp(nick,botname)==0) { curchan[0]=0; tprintf(serv,"JOIN %s\n",botchan); clear_channel(); if (revenge) { unprog_op_and_deop(s,"kicked me off the channel"); /* ^put the kicker on the deop list : revenge */ } } /* 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; strcpy(s,from); splitnick(nick,s); fixcolon(msg); m=ismember(nick); if (m==NULL) return; /* confused server. */ if (log_joins) console("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; 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); if (log_joins) console("%s (%s) got netsplit.",nick,from); } } else { killmember(nick); if (log_joins) console("%s (%s) left irc: %s",nick,from,msg); } } #define modechg(x,y) { \ if (pos==1) channel.mode|=(x); else channel.mode&=~(x); \ if (reverse) sprintf(&rvstr[strlen(rvstr)-1],"%c%c", \ pos?'-':'+',y); \ } /* this is a REAL pain in the ass: mode */ void gotmode(from,msg) char *from,*msg; { char nick[10],s[81],chan[81],chg[81],op[81]; int pos=0,i=0; memberlist *m; char s1[81]; int reverse=0; char rvstr[81]; split(chan,msg); split(chg,msg); rvstr[0]=0; console("Mode change '%s %s' by %s",chg,msg,from); if (chg[0]==0) { strcpy(chg,msg); msg[0]=0; } splitnick(nick,from); m=ismember(nick); if (m!=NULL) if ((m->flags&FAKEOP) && (me_op())) { console("Mode change by fake op! Reversing..."); tprintf(serv,"KICK %s %s :abusing ill-gained server op\n",curchan,nick); reverse=1; } while (chg[i]!=0) { if (chg[i]=='+') pos=1; if (chg[i]=='-') pos=-1; if (chg[i]=='i') modechg(CHANINV,'i'); if (chg[i]=='p') modechg(CHANPRIV,'p'); if (chg[i]=='s') modechg(CHANSEC,'s'); if (chg[i]=='m') modechg(CHANMODER,'m'); if (chg[i]=='t') modechg(CHANTOPIC,'t'); if (chg[i]=='n') modechg(CHANNOMSG,'n'); if (chg[i]=='l') { if (pos==-1) { if ((reverse) && (channel.maxmembers!=(-1))) sprintf(&rvstr[strlen(rvstr)],"+l %d ",channel.maxmembers); channel.maxmembers=(-1); } else { split(op,msg); if (op[0]==0) { strcpy(op,msg); msg[0]=0; } channel.maxmembers=atoi(op); if (reverse) strcat(rvstr,"-l"); } } if (chg[i]=='k') { split(op,msg); if (op[0]==0) { strcpy(op,msg); msg[0]=0; } if (pos==-1) { if ((reverse) && (channel.key[0])) sprintf(&rvstr[strlen(rvstr)],"+k %s ",channel.key); nfree(channel.key); channel.key=(char *)nmalloc(1); channel.key[0]=0; } else { nfree(channel.key); channel.key=(char *)nmalloc(strlen(op)+1); strcpy(channel.key,op); if (reverse) sprintf(&rvstr[strlen(rvstr)],"-k %s ",channel.key); } } if (chg[i]=='o') { split(op,msg); if (op[0]==0) { strcpy(op,msg); msg[0]=0; } m=ismember(op); if (m==NULL) { console("!!! MODE CHANGE ON NONEXISTANT %s",op); /* now fix the damage: */ tprintf(serv,"who %s\n",op); } else { sprintf(s,"%s!%s",m->nick,m->userhost); fixfrom(s); if (pos==1) { if ((!me_op()) && (strcasecmp(op,botname)==0)) newly_chanop(); if ((me_op()) && (match_deop(s)) && (strcasecmp(op,botname)!=0) && (!match_op(s))) add_deop(op); else if (reverse) add_deop(op); if (nick[0]==0) /* server op!! */ if ((!match_op(s)) && (!match_friend(s)) && (!(m->flags&CHANOP))) { add_deop(op); m->flags|=FAKEOP; } m->flags|=CHANOP; } else { m->flags&=~CHANOP; m->flags&=~FAKEOP; if ((me_op()) && (match_op(s)) && (!match_deop(s)) && (strcasecmp(nick,botname)!=0) && (strcasecmp(op,nick)!=0)) { sprintf(s,"%s!%s",nick,from); if (!match_master(s)) add_op(op); /* op our guy */ else if (reverse) add_op(op); if ((!match_master(s)) && (!match_friend(s)) && (!match_op(s)) && (revenge)) { sprintf(s1,"deopped %s",op); unprog_op_and_deop(s,s1); /* add bad guy to deop list */ } } if (!(m->flags&CHANVOICE)) tprintf(serv,"WHO %s\n",m->nick); if ((strcasecmp(op,botname)==0) && (revenge)) { /* they deop'd ME! next time i'm op'd, i'll deop them */ sprintf(s,"%s!%s",nick,from); if (!match_master(s)) unprog_op_and_deop(s,"deopped me"); if (gainops[0]) tprintf(serv,"%s\n",gainops); } } } } if (chg[i]=='v') { split(op,msg); if (op[0]==0) { strcpy(op,msg); msg[0]=0; } m=ismember(op); if (m==NULL) { console("!!! MODE CHANGE ON NONEXISTANT %s",op); } else { if (pos==1) { m->flags|=CHANVOICE; if (reverse) sprintf(&rvstr[strlen(rvstr)],"-v %s ",op); } else { m->flags&=~CHANVOICE; if (reverse) sprintf(&rvstr[strlen(rvstr)],"+v %s ",op); } } } if (rvstr[0]) tprintf(serv,"MODE %s %s\n",curchan,rvstr); if (chg[i]=='b') { split(op,msg); if (op[0]==0) { strcpy(op,msg); msg[0]=0; } sprintf(s,"%s!%s@%s",botname,botuser,bothost); if (pos==1) { sprintf(s1,"%s!%s",nick,from); newban(op,s1); if (strcasecmp(nick,botname)!=0) { /* (if it's not my ban:) */ /* check for ban against ME! */ if ((wild_match(op,s)) && (me_op())) add_deban(op); if (!match_master(s1)) { /* don't contradict master's bans */ /* banning an oplisted person who's on the channel? */ m=channel.member; while (m->nick[0]) { sprintf(s1,"%s!%s",m->nick,m->userhost); if ((match_op(s1)) && (wild_match(op,s1))) add_deban(op); m=m->next; } } } if (reverse) add_deban(op); } else { killban(op); /* ban that i wanted? */ if ((equals_ban(op)) && (me_op())) { sprintf(s,"%s!%s",nick,from); if ((match_master(s)) || (match_op(s))) { mprintf(serv,"PRIVMSG %s :That's in the permaban list. It %s%s\n", nick,"will probably be reinstated eventually by normal ", "bot maintenance unless you use '-ban' in dcc chat."); } else add_ban(op); } if (reverse) add_ban(op); } } i++; } flush_deop(); flush_ban(); } /* msg to xx everyone on the channel's info */ void show_all_info(who) char *who; { memberlist *m; char s[120],nick[20]; m=channel.member; while (m->nick[0]) { get_handle_by_host(nick,m->userhost); get_handle_info(nick,s); if (s[0]) hprintf(helpsock,"NOTICE %s :[%9s] %s\n",who,m->nick,s); else hprintf(helpsock,"NOTICE %s :[%9s] (No info.)\n",who,m->nick); m=m->next; } } /* request from a user to kickban (over dcc) */ void user_kickban(z,nick) int z; char *nick; { memberlist *m; char s[121],s1[121],user[121],*p,c; if (curchan[0]==0) { tprintf(z,"I'm not on a channel!\n"); return; } if (strcasecmp(nick,botname)==0) { tprintf(z,"You're trying to pull a Run?\n"); return; } m=ismember(nick); if (m==NULL) { tprintf(z,"Not on channel: %s\n",nick); return; } sprintf(s,"%s!%s",m->nick,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(user,m->userhost); p=strchr(user,'@'); *p=0; c=m->userhost[strlen(m->userhost)-1]; if ((c>='0') && (c<='9')) { /* ip address! */ strcpy(s1,m->userhost); p=strrchr(s1,'.'); if (p!=NULL) strcpy(p+1,"*"); } else { p=strchr(m->userhost,'.'); if (p!=NULL) sprintf(s1,"*%s",p+1); else strcpy(s1,m->userhost); } sprintf(s,"*!*%s@%s",user,s1); tprintf(serv,"MODE %s -o+b %s %s\n",curchan,m->nick,s); tprintf(serv,"KICK %s %s :requested\n",curchan,m->nick); prog_ban(s); /* killmember(m->nick); */ tprintf(z,"Okay, done.\n"); } /* check for expired netsplit people */ void check_expired_splits() { memberlist *m; time_t now; 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) { if (log_joins) console("%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; 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 */ void check_lonely_channel() { if ((curchan[0]) && (members==1) && (!me_op())) { tprintf(serv,"PART %s\n",curchan); tprintf(serv,"JOIN %s\n",botchan); console("Attempting to regain chanop by recreating the channel."); } } /* op/deop on the fly per master's request */ void give_op(nick,z) char *nick; int z; { memberlist *m; char s[121]; 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_op(nick); flush_deop(); tprintf(z,"Gave op to %s\n",nick); } void give_deop(nick,z) char *nick; int z; { memberlist *m; char s[121]; 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_deop(nick); flush_deop(); tprintf(z,"Took op from %s\n",nick); }