/* mode dumps */ #define _MODE #if HAVE_CONFIG_H #include #endif #include #include #include #include "eggdrop.h" #include "users.h" #include "chan.h" #include "proto.h" /* buffer for storing mode changes by the bot */ char pls[41]=""; char mns[41]=""; char key[121]=""; char rmkey[121]=""; int limit=(-1); /* data for detecting mass deops */ char deopnick[10]=""; time_t deoptime=0L; int deops=0; /* reversing this mode? */ int reversing=0; /* modes the bot should protect positive */ int mode_pls_prot=0; /* modes the bot should protect negative */ int mode_mns_prot=0; /* channel limit to protect */ int limit_prot=(-1); /* channel key to protect */ char key_prot[121]=""; /* reop a +o user if they get deopped? */ int protect_ops=1; /* forbid bans to be made by users directly */ int forbid_bans=0; extern int serv; extern char curchan[]; extern struct chan_t channel; extern int helpsock; #ifdef TCL extern char need_op[]; #else extern char gainops[]; #endif extern char botname[]; extern char botuserhost[]; extern char botuser[]; extern int revenge; extern char cx_file[]; extern int cx_line; extern int perm_bans; extern int bitch; extern char origbotname[]; extern char SBUF[]; #define PLUS 1 #define MINUS 2 #define CHOP 4 #define BAN 8 #define VOICE 16 /* mode changes that require parameters */ struct { char *op; char type; } cmode[3]={ {NULL,0}, {NULL,0}, {NULL,0} }; void flush_mode() { char *p,*post; int i,ok=0; context; p=SBUF; post=&SBUF[512]; *p=0; *post=0; if (pls[0]) *p++='+'; for (i=0; i126)) bogus=1; if ((bogus) && (strcasecmp(nick,botname)!=0)) { log(LOG_MODES,"Bogus channel key!"); tprintf(serv,"KICK %s %s :bogus channel key\n",curchan,nick); } if ((reversing) || (bogus) || ((mode_mns_prot&CHANKEY) && (!(atr&USER_MASTER)))) add_mode('-','k',key); } void got_op(nick,from,who,atr1) char *nick,*from,*who; int atr1; { memberlist *m; char s[121]; int atr; context; m=ismember(who); if (m==NULL) { log(LOG_MISC,"* Mode change on nonexistant %s!",who); tprintf(serv,"WHO %s\n",who); return; } sprintf(s,"%s!%s",m->nick,m->userhost); atr=get_attr_host(s); if ((!me_op()) && (strcasecmp(who,botname)==0)) newly_chanop(); else if ((me_op()) && (strcasecmp(who,botname)!=0) && (!(m->flags & SENTDEOP))) { if ((bitch) && (!(atr & USER_OP)) && (!(atr1 & USER_MASTER))) { add_mode('-','o',who); m->flags|=SENTDEOP; } else if ((atr&USER_DEOP) && (!(atr&USER_OP)) && (!(atr1&USER_MASTER))) { add_mode('-','o',who); m->flags|=SENTDEOP; } else if (reversing) { add_mode('-','o',who); m->flags|=SENTDEOP; } } else if ((reversing) && (!(m->flags & SENTDEOP)) && (strcasecmp(who,botname)!=0)) { add_mode('-','o',who); m->flags|=SENTDEOP; } if (nick[0]==0) { /* server op! */ if ((!(atr & (USER_OP|USER_FRIEND|USER_MASTER))) && (!(m->flags&CHANOP)) && (!(m->flags&SENTDEOP)) && (me_op())) { add_mode('-','o',who); m->flags|=(FAKEOP|SENTDEOP); } } else m->flags&=~FAKEOP; m->flags|=CHANOP; m->flags&=~SENTOP; } void got_deop(nick,from,who,atr1) char *nick,*from,*who; int atr1; { memberlist *m; char s[161],s1[161],s2[161]; int atr; context; m=ismember(who); if (m==NULL) { log(LOG_MISC,"* Mode change on nonexistant %s!",who); tprintf(serv,"WHO %s\n",who); return; } sprintf(s,"%s!%s",m->nick,m->userhost); fixfrom(s); sprintf(s1,"%s!%s",nick,from); atr=get_attr_host(s); if ((me_op()) && (atr & (USER_OP|USER_FRIEND)) && (!(atr & USER_DEOP)) && (strcasecmp(nick,botname)!=0) && (strcasecmp(who,nick)!=0) && (!(m->flags & SENTOP)) && (protect_ops) && (m->flags & CHANOP)) { /* deop'd someone on my oplist */ if (!(atr1 & USER_MASTER)) { /* op her */ add_mode('+','o',who); m->flags|=SENTOP; } else if (reversing) { add_mode('+','o',who); m->flags|=SENTOP; } if ((atr1 & (USER_MASTER|USER_FRIEND|USER_OP) == 0) && (revenge)) { sprintf(s2,"deopped %s",s); unprog_op_and_deop(s1,s2); /* punish bad guy */ } } /* check for mass deop */ if ((atr1 & (USER_MASTER|USER_FRIEND|USER_BOT) == 0) && (strcasecmp(nick,botname)!=0)) { if (strcasecmp(nick,deopnick)==0) { time_t tx=time(NULL); if (tx-deoptime <= 10) { deops++; if (deops>=3) { log(LOG_MODES,"Mass deop by %s",s1); tprintf(serv,"KICK %s %s :mass deop, go sit in a corner\n",curchan, nick); deopnick[0]=0; deoptime=0L; deops=0; } } else { deoptime=time(NULL); deops=1; } } else { strcpy(deopnick,nick); deoptime=time(NULL); deops=1; } } /* having op hides your +v status -- so now that someone's lost ops, check to see if they have +v */ if (!(m->flags&CHANVOICE)) tprintf(serv,"WHO %s\n",m->nick); if ((strcasecmp(who,botname)==0) && (revenge)) { /* deopped ME! take revenge */ if (atr1 & (USER_MASTER|USER_FRIEND) == 0) unprog_op_and_deop(s1,"deopped me"); #ifdef TCL if (need_op[0]) do_tcl("need-op",need_op); #else if (gainops[0]) tprintf(serv,"%s\n",gainops); #endif ask_tandem_for_ops(); } m->flags&=~(FAKEOP|CHANOP|SENTDEOP); } void got_ban(nick,from,who,atr) char *nick,*from,*who; int atr; { char me[161],s[161],s1[161]; int check=1,i,bogus; memberlist *m; context; sprintf(me,"%s!%s",botname,botuserhost); sprintf(s,"%s!%s",nick,from); newban(who,s); bogus=0; if (strcasecmp(nick,botname)!=0) { /* it's not my ban */ if ((forbid_bans) && (!(atr&USER_BOT)) && (!(atr&USER_MASTER))) { mprintf(serv,"PRIVMSG %s :You may not place bans directly.\n",nick); add_mode('-','b',who); return; } for (i=0; i126)) bogus=1; if (bogus) { if (atr & (USER_MASTER|USER_FRIEND)) { /* fix their bogus ban */ int ok=0; strcpy(s1,who); for (i=0; i126)) s1[i]='?'; if ((s1[i]!='?') && (s1[i]!='*') && (s1[i]!='!') && (s1[i]!='@')) ok=1; } add_mode('-','b',who); flush_mode(); /* only re-add it if it has something besides wildcards */ if (ok) add_mode('+','b',s1); } else { add_mode('-','b',who); tprintf(serv,"KICK %s %s :bogus ban\n",curchan,nick); } return; } if ((wild_match(who,me)) && (me_op())) add_mode('-','b',who); /* ^ don't really feel like being banned today, thank you! */ else if (!(atr & USER_MASTER)) { /* don't contradict master 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 (wild_match(who,s1)) { int tatr=get_attr_host(s1); if (tatr&(USER_OP|USER_FRIEND|USER_MASTER)) { add_mode('-','b',who); check=0; } } m=m->next; } if (check) kick_match_ban(who); } else kick_match_ban(who); } else kick_match_ban(who); /* is it a server ban from nowhere? */ /* uncomment the following line to remove all server bans */ /* if ((!nick[0]) && (!equals_ban(who)) && (check)) add_mode('-','b',who); else */ if (reversing) add_mode('-','b',who); } void got_unban(nick,from,who,atr) char *nick,*from,*who; int atr; { int i,bogus; killban(who); bogus=0; for (i=0; i126)) bogus=1; if ((bogus) && (strcasecmp(nick,botname)!=0) && (!isbanned(who)) && (atr & (USER_OP|USER_FRIEND|USER_MASTER) == 0)) { tprintf(serv,"KICK %s %s :bogus ban\n",curchan,nick); return; } if ((equals_ban(who)) && (me_op()) && (perm_bans)) { /* that's a permban! */ if (atr & (USER_MASTER|USER_OP)) { hprintf(helpsock,"NOTICE %s :That's in my permban list. You need %s\n", nick,"to use '-ban' in dcc chat if you want it gone for good."); } else add_mode('+','b',who); } if (reversing) add_mode('+','b',who); } #ifdef TCL #define modechg(x,y) { \ char ms[3]; \ ms[0]=(pos==1)?'+':'-'; ms[1]=y; ms[2]=0; \ check_tcl_mode(nick,from,hand,ms); \ if (pos==1) channel.mode|=(x); else channel.mode&=~(x); \ if (((reversing) || ((pos==1)&&(mode_mns_prot&(x))) || \ ((pos==-1)&&(mode_pls_prot&(x)))) && (!(atr&USER_MASTER))) \ add_mode((pos==1)?'-':'+',y,""); \ } #else #define modechg(x,y) { \ if (pos==1) channel.mode|=(x); else channel.mode&=~(x); \ if (((reversing) || ((pos==1)&&(mode_mns_prot&(x))) || \ ((pos==-1)&&(mode_pls_prot&(x)))) && (!(atr&USER_MASTER))) \ add_mode((pos==1)?'-':'+',y,""); \ } #endif /* TCL */ /* a pain in the ass: mode changes */ void gotmode(from,msg) char *from,*msg; { char nick[10],hand[10],chan[121],op[121],chg[81],s[161]; int pos=0,i,atr; memberlist *m; context; split(chan,msg); nsplit(chg,msg); reversing=0; /* discard usermode changes, and +channels don't have modes: */ if ((chan[0]!='#') && (chan[0]!='&')) return; log(LOG_MODES,"Mode change '%s %s' by %s",chg,msg,from); atr=get_attr_host(from); get_handle_by_host(hand,from); splitnick(nick,from); i=0; m=ismember(nick); if (m!=NULL) if ((m->flags&FAKEOP) && (me_op())) { log(LOG_MODES,"Mode change by fake op! Reversing..."); tprintf(serv,"KICK %s %s :abusing ill-gained server ops\n",curchan,nick); reversing=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]=='a') modechg(CHANANON,'a'); if (chg[i]=='l') { if (pos==-1) { #ifdef TCL check_tcl_mode(nick,from,hand,"-l"); #endif if ((reversing) && (channel.maxmembers!=(-1))) { sprintf(s,"%d",channel.maxmembers); add_mode('+','l',s); } else if ((limit_prot!=(-1)) && (!(atr&USER_MASTER))) { sprintf(s,"%d",limit_prot); add_mode('+','l',s); } channel.maxmembers=(-1); } else { nsplit(op,msg); channel.maxmembers=atoi(op); #ifdef TCL { char ms[21]; sprintf(ms,"+l %d",channel.maxmembers); check_tcl_mode(nick,from,hand,ms); } #endif if ((reversing) || ((mode_mns_prot&CHANLIMIT)&&(!(atr&USER_MASTER)))) { if (channel.maxmembers==0) add_mode('+','l',"23"); add_mode('-','l',""); } } } if (chg[i]=='k') { nsplit(op,msg); #ifdef TCL { char ms[121]; sprintf(ms,"%ck %s",(pos==1)?'+':'-',op); check_tcl_mode(nick,from,hand,ms); } #endif if (pos==1) got_key(nick,from,op,atr); else { if ((reversing) && (channel.key[0])) add_mode('+','k',channel.key); else if ((key_prot[0]) && (!(atr&USER_MASTER))) add_mode('+','k',key_prot); set_key(NULL); } } if (chg[i]=='o') { nsplit(op,msg); #ifdef TCL { char ms[121]; sprintf(ms,"%co %s",(pos==1)?'+':'-',op); check_tcl_mode(nick,from,hand,ms); } #endif if (pos==1) got_op(nick,from,op,atr); else got_deop(nick,from,op,atr); } if (chg[i]=='v') { nsplit(op,msg); m=ismember(op); if (m==NULL) { log(LOG_MISC,"* Mode change on nonexistant %s!",op); tprintf(serv,"WHO %s\n",op); } else { #ifdef TCL char ms[121]; sprintf(ms,"%cv %s",(pos==1)?'+':'-',op); check_tcl_mode(nick,from,hand,ms); #endif if (pos==1) { m->flags|=CHANVOICE; if (reversing) add_mode('-','v',op); } else { m->flags&=~CHANVOICE; if (reversing) add_mode('+','v',op); } } } if (chg[i]=='b') { nsplit(op,msg); #ifdef TCL { char ms[121]; sprintf(ms,"%cb %s",(pos==1)?'+':'-',op); check_tcl_mode(nick,from,hand,ms); } #endif if (pos==1) got_ban(nick,from,op,atr); else got_unban(nick,from,op,atr); } i++; } } /* interpret configfile setting for modes to protect */ #define protmode(x) { \ mode_pls_prot&=(~(x)); mode_mns_prot&=(~(x)); \ if (pos==1) mode_pls_prot|=(x); else mode_mns_prot|=(x); \ } void set_mode_protect(set) char *set; { int i,pos=1; char s[121],s1[121]; context; nsplit(s,set); /* clear old modes */ mode_mns_prot=mode_pls_prot=0; limit_prot=(-1); key_prot[0]=0; for (i=0; i