/* msgnotice.c -- handles: msgs & notices from user or channel simple ctcp requests and replies dprintf'ized, 18nov95 */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "eggdrop.h" #include "chan.h" #include "proto.h" /* SED and UTC are a big lie, but they'll never know */ #define CLIENTINFO "SED VERSION CLIENTINFO USERINFO ERRMSG FINGER TIME ACTION DCC UTC PING ECHO :Use CLIENTINFO to get more specific information" #define CLIENTINFO_SED "SED contains simple_encrypted_data" #define CLIENTINFO_VERSION "VERSION shows client type, version and environment" #define CLIENTINFO_CLIENTINFO "CLIENTINFO gives information about available CTCP commands" #define CLIENTINFO_USERINFO "USERINFO returns user settable information" #define CLIENTINFO_ERRMSG "ERRMSG returns error messages" #define CLIENTINFO_FINGER "FINGER shows real name, login name and idle time of user" #define CLIENTINFO_TIME "TIME tells you the time on the user's host" #define CLIENTINFO_ACTION "ACTION contains action descriptions for atmosphere" #define CLIENTINFO_DCC "DCC requests a direct_client_connection" #define CLIENTINFO_UTC "UTC substitutes the local timezone" #define CLIENTINFO_PING "PING returns the arguments it receives" #define CLIENTINFO_ECHO "ECHO returns the arguments it receives" extern int serv; extern int memused; extern int backgrd; extern int con_chan; extern int term_z; extern char botname[]; extern char version[]; extern struct dcc_t dcc[]; extern int dcc_total; extern char admin[]; extern char cx_file[]; extern int cx_line; extern int require_x; extern int require_p; extern int telnet_port; extern int waiting_for_awake; extern char origbotname[]; /* response to ctcp version requests */ char ctcp_version[121]="you suck, v1.0"; /* response to ctcp finger requests */ char ctcp_finger[121]="yer gonna lose that finger if you don't stop."; /* response to ctcp userinfo requests */ char ctcp_userinfo[121]="i'm cute, hung, and available"; /* ctcp embedded in a privmsg */ void gotctcp(ffrom,to,msg) char *ffrom,*to,*msg; { char from[UHOSTLEN],nick[NICKLEN],hand[10],code[512]; char *p; strcpy(from,ffrom); split(code,msg); splitnick(nick,from); if (code[0]==0) { strcpy(code,msg); msg[0]=0; } /* unquote if necessary */ p=strchr(msg,'\\'); while (p!=NULL) { if (*(p+1)=='a') *(p+1)=1; strcpy(p,p+1); p=strchr(msg,'\\'); } if ((to[0]=='$') || (strchr(to,'.')!=NULL)) { putlog(LOG_PUBLIC,to,"CTCP %s: %s from %s (%s) to %s",code,msg,nick,from, to); return; /* don't interpret */ } get_handle_by_host(hand,ffrom); if (check_tcl_ctcp(nick,from,hand,to,code,msg)) return; if ((strcmp(code,"PING")==0) && (strcmp(msg,"RELAY")==0)) waiting_for_awake=0; else if (strcasecmp(code,"FINGER")==0) mprintf(serv,"NOTICE %s :\001FINGER %s\001\n",nick,ctcp_finger); else if ((strcasecmp(code,"PING")==0) || (strcasecmp(code,"ECHO")==0) || (strcasecmp(code,"ERRMSG")==0)) mprintf(serv,"NOTICE %s :\001%s %s\001\n",nick,code,msg); else if (strcasecmp(code,"VERSION")==0) mprintf(serv,"NOTICE %s :\001VERSION %s\001\n",nick,ctcp_version); else if (strcasecmp(code,"USERINFO")==0) mprintf(serv,"NOTICE %s :\001USERINFO %s\001\n",nick,ctcp_userinfo); else if (strcasecmp(code,"CLIENTINFO")==0) { char *p,s[81]; p=NULL; if (!msg[0]) p=CLIENTINFO; else if (strcasecmp(msg,"sed")==0) p=CLIENTINFO_SED; else if (strcasecmp(msg,"version")==0) p=CLIENTINFO_VERSION; else if (strcasecmp(msg,"clientinfo")==0) p=CLIENTINFO_CLIENTINFO; else if (strcasecmp(msg,"userinfo")==0) p=CLIENTINFO_USERINFO; else if (strcasecmp(msg,"errmsg")==0) p=CLIENTINFO_ERRMSG; else if (strcasecmp(msg,"finger")==0) p=CLIENTINFO_FINGER; else if (strcasecmp(msg,"time")==0) p=CLIENTINFO_TIME; else if (strcasecmp(msg,"action")==0) p=CLIENTINFO_TIME; else if (strcasecmp(msg,"dcc")==0) p=CLIENTINFO_DCC; else if (strcasecmp(msg,"utc")==0) p=CLIENTINFO_UTC; else if (strcasecmp(msg,"ping")==0) p=CLIENTINFO_PING; else if (strcasecmp(msg,"echo")==0) p=CLIENTINFO_ECHO; if (p==NULL) { sprintf(s,"%s is not a valid function",msg); p=s; } mprintf(serv,"NOTICE %s :\001CLIENTINFO %s\001\n",nick,p); } else if (strcasecmp(code,"DCC")==0) gotdcc(nick,from,msg); else if (strcasecmp(code,"TIME")==0) { time_t tm=time(NULL); char tms[81]; strcpy(tms,ctime(&tm)); tms[strlen(tms)-1]=0; mprintf(serv,"NOTICE %s :\001TIME %s\001\n",nick,tms); } else if (strcasecmp(code,"CHAT")==0) { int atr=get_attr_host(ffrom); if ((atr & (USER_MASTER|USER_PARTY|USER_XFER)) || ((atr&USER_OP) && (!require_x || !require_p))) { if (!telnet_port) mprintf(serv,"NOTICE %s :\001ERROR no telnet port\001\n",nick); else mprintf(serv,"PRIVMSG %s :\001DCC CHAT chat %lu %u\001\n",nick, getmyip(),telnet_port); } } /* don't log DCC or AWAKE */ if ((strcasecmp(code,"DCC")!=0) && !((strcasecmp(code,"PING")==0) && (strcasecmp(msg,"RELAY")==0))) { if ((to[0]=='#') || (to[0]=='&') || (to[0]=='+')) { if (strcasecmp(code,"ACTION")==0) { putlog(LOG_PUBLIC,to,"Action: %s %s",nick,msg); } else { putlog(LOG_PUBLIC,to,"CTCP %s: %s from %s (%s) to %s",code,msg,nick, from,to); } update_idle(to,nick); } else { if (strcasecmp(code,"ACTION")==0) { putlog(LOG_MSGS,"*","Action to %s: %s %s",to,nick,msg); } else { putlog(LOG_MSGS,"*","CTCP %s: %s from %s (%s)",code,msg,nick,from); } } } } /* ctcp embedded in a notice */ void gotctcpreply(ffrom,to,msg) char *ffrom,*to,*msg; { char from[UHOSTLEN],nick[NICKLEN],hand[10],code[512]; char *p; strcpy(from,ffrom); split(code,msg); splitnick(nick,from); if (code[0]==0) { strcpy(code,msg); msg[0]=0; } /* unquote if necessary */ p=strchr(msg,'\\'); while (p!=NULL) { if (*(p+1)=='a') *(p+1)=1; strcpy(p,p+1); p=strchr(msg,'\\'); } if ((to[0]=='$') || (strchr(to,'.')!=NULL)) { putlog(LOG_PUBLIC,"*","CTCP reply %s: %s from %s (%s) to %s",code,msg, nick,from,to); return; /* don't even interpret into tcl */ } get_handle_by_host(hand,ffrom); if (check_tcl_ctcr(nick,from,hand,to,code,msg)) return; /* who cares? */ if ((to[0]=='#') || (to[0]=='&') || (to[0]=='+')) { putlog(LOG_PUBLIC,to,"CTCP reply %s: %s from %s (%s) to %s",code,msg,nick, from,to); update_idle(to,nick); } else { putlog(LOG_MSGS,"*","CTCP reply %s: %s from %s (%s) to %s",code,msg, nick,from,to); } } /* public msg on channel */ void gotpublic(from,to,msg) char *from,*to,*msg; { char nick[NICKLEN]; struct chanset_t *chan; chan=findchan(to); if (chan==NULL) return; detect_flood(from,chan,_PRIVMSG,1); splitnick(nick,from); if (check_tcl_pub(nick,from,to,msg)) return; check_tcl_pubm(nick,from,to,msg); putlog(LOG_PUBLIC,to,"<%s> %s",nick,msg); update_idle(to,nick); } /* public notice on channel */ void gotpublicnotice(from,to,msg) char *from,*to,*msg; { char nick[NICKLEN]; struct chanset_t *chan; chan=findchan(to); if (chan==NULL) return; detect_flood(from,chan,_NOTICE,1); splitnick(nick,from); putlog(LOG_PUBLIC,to,"-%s:%s- %s",nick,to,msg); update_idle(to,nick); } /* check for more than 8 control characters in a line */ /* this could indicate: beep flood CTCP avalanche */ int detect_avalanche(msg) char *msg; { int count=0; unsigned char *p; for (p=(unsigned char *)msg; (*p)&&(count<8); p++) if ((*p<32) && (*p!=22) && (*p!=2) && (*p!=31) && (*p!=15)) count++; /* ^ don't penalize for bold/reverse/underline */ if (count>=8) return 1; else return 0; } /* private message */ void gotmsg(from,msg) char *from,*msg; { char to[UHOSTLEN],nick[NICKLEN],ctcp[512]; char *p,*p1; context; split(to,msg); fixcolon(msg); if (detect_avalanche(msg)) { splitnick(nick,from); /* discard -- kick user if it was to the channel */ if ((to[0]=='&') || (to[0]=='#')) { tprintf(serv,"KICK %s %s :that was fun, let's do it again!\n", to,nick); } putlog(LOG_MODES,"*","Avalanche from %s!%s - ignoring",nick,from); p=strchr(from,'@'); if (p!=NULL) p++; else p=from; sprintf(ctcp,"*!*@%s",p); prog_ignore(ctcp,time(NULL),origbotname); return; } /* check for CTCP: */ p=strchr(msg,1); while (p!=NULL) { p++; p1=p; while ((*p != 1) && (*p != 0)) p++; if (*p==1) { *p=0; strcpy(ctcp,p1); strcpy(p1-1,p+1); } else { strcpy(ctcp,p1); strcpy(p1-1,p); } detect_flood(from,NULL,_CTCP,0); gotctcp(from,to,ctcp); p=strchr(msg,1); } if (msg[0]==0) return; /* oh. no msg. well forget it then! */ if ((to[0]=='#') || (to[0]=='&') || (to[0]=='+')) { /* it's a public msg */ gotpublic(from,to,msg); } else if ((to[0]=='$') || (strchr(to,'.')!=NULL)) { /* msg from oper */ detect_flood(from,NULL,_PRIVMSG,0); splitnick(nick,from); /* do not interpret as command */ putlog(LOG_MSGS|LOG_SERV,"*","[%s!%s to %s] %s",nick,from,to,msg); } else { detect_flood(from,NULL,_PRIVMSG,0); splitnick(nick,from); gotcmd(nick,from,msg); } } /* private notice */ void gotnotice(from,msg) char *from,*msg; { char to[UHOSTLEN],nick[NICKLEN],ctcp[512]; char *p,*p1; context; split(to,msg); fixcolon(msg); if (detect_avalanche(msg)) { splitnick(nick,from); /* discard -- kick user if it was to the channel */ if ((to[0]=='&') || (to[0]=='#')) { tprintf(serv,"KICK %s %s :that was fun, let's do it again!\n", to,nick); } putlog(LOG_MODES,"*","Avalanche from %s!%s",nick,from); return; } /* check for CTCP: */ p=strchr(msg,1); while (p!=NULL) { p++; p1=p; while ((*p != 1) && (*p != 0)) p++; if (*p==1) { *p=0; strcpy(ctcp,p1); strcpy(p1-1,p+1); } else { strcpy(ctcp,p1); strcpy(p1-1,p); } detect_flood(from,NULL,_CTCP,0); gotctcpreply(from,to,ctcp); p=strchr(msg,1); } if (msg[0]==0) return; /* oh. no msg. well forget it then! */ if ((to[0]=='#') || (to[0]=='&') || (to[0]=='+')) { /* it's a public msg */ gotpublicnotice(from,to,msg); } else if ((to[0]=='$') || (strchr(to,'.')!=NULL)) { /* msg from oper */ detect_flood(from,NULL,_NOTICE,0); splitnick(nick,from); putlog(LOG_MSGS|LOG_SERV,"*","-%s (%s) to %s- %s",nick,from,to,msg); } else { detect_flood(from,NULL,_NOTICE,0); splitnick(nick,from); /* server notice? */ if ((from[0]==0) || (nick[0]==0)) putlog(LOG_MSGS,"*","-NOTICE- %s",msg); else putlog(LOG_MSGS,"*","-%s (%s)- %s",nick,from,msg); } } /* error notice */ void goterror(from,msg) void *from,*msg; { fixcolon(msg); putlog(LOG_SERV|LOG_MSGS,"*","-ERROR- %s",msg); close(serv); serv=(-1); /* they're gonna disconnect anyway :) */ }