/* msg_channel() * * inputs - flag privmsg or notice * - pointer to command "PRIVMSG" or "NOTICE" * - pointer to source_p * - pointer to channel * output - NONE * side effects - message given channel */ static void msg_channel(int p_or_n, const char *command, struct Client *source_p, struct Channel *chptr, const char *text) { int result = 0; /* Chanops and voiced can flood their own channel with impunity */ if ((result = can_send(chptr, source_p, NULL, text)) < 0) { if (result == CAN_SEND_OPV || !flood_attack_channel(p_or_n, source_p, chptr)) sendto_channel_butone(source_p, source_p, chptr, 0, "%s %s :%s", command, chptr->name, text); } else { if (p_or_n != NOTICE) { if (result == ERR_NOCTRLSONCHAN) sendto_one_numeric(source_p, &me, ERR_NOCTRLSONCHAN, chptr->name, text); else if (result == ERR_NEEDREGGEDNICK) sendto_one_numeric(source_p, &me, ERR_NEEDREGGEDNICK, chptr->name); else sendto_one_numeric(source_p, &me, ERR_CANNOTSENDTOCHAN, chptr->name); } } }
/* msg_channel_flags() * * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC * say NOTICE must not auto reply * - pointer to source_p * - pointer to channel * - flags * - pointer to text to send * output - NONE * side effects - message given channel either chanop or voice */ static void msg_channel(int p_or_n, struct Client *source_p, struct Channel *chptr, unsigned int flags, const char *text) { unsigned int type = 0; const char *prefix = ""; if (flags & CHFL_VOICE) { type = CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE; prefix = "+"; } else if (flags & CHFL_HALFOP) { type = CHFL_CHANOP | CHFL_HALFOP; prefix = "%"; } else if (flags & CHFL_CHANOP) { type = CHFL_CHANOP; prefix = "@"; } /* Chanops and voiced can flood their own channel with impunity */ int ret = can_send(chptr, source_p, NULL, text, p_or_n == NOTICE); if (ret < 0) { if (ret == CAN_SEND_OPV || !flood_attack_channel(p_or_n, source_p, chptr)) sendto_channel_butone(source_p, source_p, chptr, type, "%s %s%s :%s", command[p_or_n], prefix, chptr->name, text); } else if (p_or_n != NOTICE) sendto_one_numeric(source_p, &me, ret, chptr->name, text); }
/* * * parc number of arguments ('sender' counted as one!) * parv[0] pointer to 'sender' (may point to empty string) (not used) * parv[1]..parv[parc-1] * pointers to additional parameters, this is a NULL * terminated list (parv[parc] == NULL). * * *WARNING* * Numerics are mostly error reports. If there is something * wrong with the message, just *DROP* it! Don't even think of * sending back a neat error message -- big danger of creating * a ping pong error message... * * Rewritten by Nemesi, Jan 1999, to support numeric nicks in parv[1] * * Called when we get a numeric message from a remote _server_ and we are * supposed to forward it somewhere. Note that we always ignore numerics sent * to 'me' and simply drop the message if we can't handle with this properly: * the savvy approach is NEVER generate an error in response to an... error :) */ static void parse_handle_numeric(unsigned int numeric, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; struct Channel *chptr = NULL; /* * Avoid trash, we need it to come from a server and have a target */ if (parc < 2 || !IsServer(source_p)) return; /* * Who should receive this message ? Will we do something with it ? * Note that we use findUser functions, so the target can't be neither * a server, nor a channel (?) nor a list of targets (?) .. u2.10 * should never generate numeric replies to non-users anyway * Ahem... it can be a channel actually, csc bots use it :\ --Nem */ if (IsChanPrefix(*parv[1])) chptr = hash_find_channel(parv[1]); else target_p = find_person(source_p, parv[1]); if ((target_p == NULL || target_p->from == source_p->from) && chptr == NULL) return; /* * Remap low number numerics, not that I understand WHY.. --Nemesi */ /* * Numerics below 100 talk about the current 'connection', you're not * connected to a remote server so it doesn't make sense to send them * remotely - but the information they contain may be useful, so we * remap them up. Weird, but true. -- Isomer */ if (numeric < 100) numeric += 100; if (target_p) { /* Fake it for server hiding, if it's our client */ if ((ConfigServerHide.hide_servers || IsHidden(source_p)) && MyConnect(target_p) && !HasUMode(target_p, UMODE_OPER)) sendto_one_numeric(target_p, &me, numeric | SND_EXPLICIT, "%s", parv[2]); else sendto_one_numeric(target_p, source_p, numeric | SND_EXPLICIT, "%s", parv[2]); } else sendto_channel_butone(source_p, source_p, chptr, 0, "%u %s %s", numeric, chptr->name, parv[2]); }
/* msg_channel_flags() * * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC * say NOTICE must not auto reply * - pointer to command, "PRIVMSG" or "NOTICE" * - pointer to source_p * - pointer to channel * - flags * - pointer to text to send * output - NONE * side effects - message given channel either chanop or voice */ static void msg_channel(int p_or_n, const char *command, struct Client *source_p, struct Channel *chptr, unsigned int flags, const char *text) { int result = 0; unsigned int type = 0; const char *prefix = ""; if (flags & CHFL_VOICE) { type = CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE; prefix = "+"; } else if (flags & CHFL_HALFOP) { type = CHFL_CHANOP | CHFL_HALFOP; prefix = "%"; } else if (flags & CHFL_CHANOP) { type = CHFL_CHANOP; prefix = "@"; } /* Chanops and voiced can flood their own channel with impunity */ if ((result = can_send(chptr, source_p, NULL, text)) < 0) { if (result == CAN_SEND_OPV || !flood_attack_channel(p_or_n, source_p, chptr)) sendto_channel_butone(source_p, source_p, chptr, type, "%s %s%s :%s", command, prefix, chptr->name, text); } else { if (p_or_n != NOTICE) { if (result == ERR_NOCTRLSONCHAN) sendto_one_numeric(source_p, &me, ERR_NOCTRLSONCHAN, chptr->name, text); else if (result == ERR_NOCTCP) sendto_one_numeric(source_p, &me, ERR_NOCTCP, chptr->name, text); else if (result == ERR_NEEDREGGEDNICK) sendto_one_numeric(source_p, &me, ERR_NEEDREGGEDNICK, chptr->name); else sendto_one_numeric(source_p, &me, ERR_CANNOTSENDTOCHAN, chptr->name); } } }
/* msg_channel() * * inputs - flag privmsg or notice * - pointer to command "PRIVMSG" or "NOTICE" * - pointer to client_p * - pointer to source_p * - pointer to channel * output - NONE * side effects - message given channel */ static void msg_channel(int p_or_n, const char *command, struct Client *client_p, struct Client *source_p, struct Channel *chptr, char *text) { int result; if(MyClient(source_p)) { /* idle time shouldnt be reset by notices --fl */ if(p_or_n != NOTICE) source_p->localClient->last = CurrentTime; } #ifndef STATIC_MODULES execute_callback(channel_message, source_p, chptr, text); #endif /* chanops and voiced can flood their own channel with impunity */ if((result = can_send(chptr, source_p, NULL, text, p_or_n)) > 0) { if(result == CAN_SEND_OPV || !flood_attack_channel(p_or_n, source_p, chptr, chptr->chname)) { sendto_channel_butone(client_p, source_p, chptr, command, ":%s", text); } } else { if(p_or_n != NOTICE) { if(result == CAN_SEND_NOREGNICK) sendto_one(source_p, form_str(ERR_NEEDREGGEDNICK), ID_or_name(&me, client_p), ID_or_name(source_p, client_p), chptr->chname, "speak in"); else if(result == CAN_SEND_NOCTRLS) sendto_one(source_p, form_str(ERR_NOCTRLSONCHAN), ID_or_name(&me, client_p), ID_or_name(source_p, client_p), chptr->chname, text); else if(result == CAN_SEND_NOCTCP) sendto_one(source_p, form_str(ERR_NOCTCP), ID_or_name(&me, client_p), ID_or_name(source_p, client_p), chptr->chname, "channel", text); else sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN), ID_or_name(&me, client_p), ID_or_name(source_p, client_p), chptr->chname); } } }
/* * msg_channel * * inputs - flag privmsg or notice * - pointer to command "PRIVMSG" or "NOTICE" * - pointer to client_p * - pointer to source_p * - pointer to channel * output - NONE * side effects - message given channel */ static void msg_channel(int p_or_n, char *command, struct Client *client_p, struct Client *source_p, struct Channel *chptr, char *text) { struct Channel *vchan = NULL; char *chname = NULL; int result; chname = RootChan(chptr)->chname; #ifdef VCHANS if (HasVchans(chptr)) vchan = map_vchan(chptr, source_p); #endif if (!vchan) vchan = chptr; if (MyClient(source_p)) { /* idle time shouldnt be reset by notices --fl */ if ((p_or_n != NOTICE) && source_p->user) source_p->user->last = CurrentTime; } /* chanops and voiced can flood their own channel with impunity */ if ((result = can_send(vchan, source_p))) { if (result == CAN_SEND_NOTREG) { if (p_or_n != NOTICE) sendto_one(source_p, form_str(source_p,ERR_CANNOTSENDNOTREG), me.name, source_p->name, chname); return; } if (result == CAN_SEND_OPV || !flood_attack_channel(p_or_n, source_p, vchan, chname)) { dlink_node *ptr; struct Ban *banptr; char strbuf[BUFSIZE+1], buf[TOPICLEN+1]; char *word, *subst, *p = buf; int drop = 0; if (MyClient(source_p) && IsPerson(source_p)) if (!is_chan_op(vchan, source_p) && NoRepeatChannel(vchan)) if (check_repeat(source_p, vchan, text)) { sendto_one(source_p, form_str(source_p,ERR_NOREPEATING), me.name, source_p->name, chname); return; } if (NoColorChannel(vchan)) /*strip_color(text);*/ text = strip_color(text, 0); strncpy(strbuf, text, BUFSIZE)[BUFSIZE] = 0; if (MyClient(source_p) && IsPerson(source_p)) if (!is_chan_op(vchan, source_p)) for (ptr = vchan->substlist.head; ptr; ptr = ptr->next, p = buf) { banptr = ptr->data; strncpy(buf, banptr->banstr, TOPICLEN)[TOPICLEN] = 0; while (*p) if (*p++ == '$') *(p-1) = ' '; subst = strchr(buf, '/'); if (subst) { *subst++ = 0; word = buf; if (strstr(strbuf, word) && !irccmp(subst, "&")) drop = 1; replace(strbuf, word, subst, BUFSIZE); strbuf[BUFSIZE] = 0; } } if (!drop) { if (PaceChannel(vchan) && (vchan->msgs < MAX_PACEMSG)) add_pace_msg(vchan, client_p, source_p, command, strbuf); else sendto_channel_butone(client_p, source_p, vchan, command, ":%s", strbuf); } } } else { if (p_or_n != NOTICE) sendto_one(source_p, form_str(source_p,ERR_CANNOTSENDTOCHAN), me.name, source_p->name, chname); } }
/* ** DoNumeric (replacement for the old do_numeric) ** ** parc number of arguments ('sender' counted as one!) ** parv[0] pointer to 'sender' (may point to empty string) (not used) ** parv[1]..parv[parc-1] ** pointers to additional parameters, this is a NULL ** terminated list (parv[parc] == NULL). ** ** *WARNING* ** Numerics are mostly error reports. If there is something ** wrong with the message, just *DROP* it! Don't even think of ** sending back a neat error message -- big danger of creating ** a ping pong error message... */ int do_numeric(int numeric, aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; aChannel *chptr; char *nick, *p; int i; /* Is this an outgoing connect, and we get a numeric 451 (not registered) back for the * magic command __PANGPANG__ and we did not send a SERVER message yet? * Then this means we are dealing with an Unreal server <3.2.9 and we should send the * SERVER command right now. */ if (!IsServer(sptr) && !IsPerson(sptr) && (numeric == 451) && (parc > 2) && strstr(parv[1], "__PANGPANG__") && IsHandshake(cptr) && sptr->serv && !IsServerSent(sptr)) { send_server_message(sptr); return 0; } if (parc < 1 || !IsServer(sptr)) return 0; /* Remap low number numerics. */ if (numeric < 100) numeric += 100; /* ** Prepare the parameter portion of the message into 'buffer'. ** (Because the buffer is twice as large as the message buffer ** for the socket, no overflow can occur here... ...on current ** assumptions--bets are off, if these are changed --msa) ** Note: if buffer is non-empty, it will begin with SPACE. */ buffer[0] = '\0'; if (parc > 2) { /* * For strlcat nazis, please read above */ for (i = 2; i < (parc - 1); i++) { (void)strcat(buffer, " "); (void)strcat(buffer, parv[i]); } (void)strcat(buffer, " :"); (void)strcat(buffer, parv[parc - 1]); } else sendto_realops("do_numeric( %i, %s, %s, %i, { %s, %s } )!", numeric, cptr->name, sptr->name, parc, parv[0], parv[1] ? parv[1] : "<null>"); for (; (nick = strtoken(&p, parv[1], ",")); parv[1] = NULL) { if ((acptr = find_client(nick, (aClient *)NULL))) { /* ** Drop to bit bucket if for me... ** ...one might consider sendto_ops ** here... --msa ** And so it was done. -avalon ** And regretted. Dont do it that way. Make sure ** it goes only to non-servers. -avalon ** Check added to make sure servers don't try to loop ** with numerics which can happen with nick collisions. ** - Avalon */ if (!IsMe(acptr) && IsPerson(acptr)) { /* Added for .U3.2. drop remote 'You are not on ** that channel', we should be synced anyway, ** and this is an annoying message with TSpre7 ** still on the net; would result in numeric 442 for ** every KICK... Can be removed when TSpre7 is gone. ** --Run if (numeric==ERR_NOTONCHANNEL) return 0; */ sendto_prefix_one(acptr, sptr, ":%s %d %s%s", parv[0], numeric, nick, buffer); } else if (IsServer(acptr) && acptr->from != cptr) sendto_prefix_one(acptr, sptr, ":%s %d %s%s", parv[0], numeric, nick, buffer); } else if ((acptr = find_server_quick(nick))) { if (!IsMe(acptr) && acptr->from != cptr) sendto_prefix_one(acptr, sptr, ":%s %d %s%s", parv[0], numeric, nick, buffer); } else if ((chptr = find_channel(nick, (aChannel *)NULL))) sendto_channel_butone(cptr, sptr, chptr, ":%s %d %s%s", parv[0], numeric, chptr->chname, buffer); } return 0; }
/* ** DoNumeric (replacement for the old do_numeric) ** ** parc number of arguments ('sender' counted as one!) ** parv[0] pointer to 'sender' (may point to empty string) (not used) ** parv[1]..parv[parc-1] ** pointers to additional parameters, this is a NULL ** terminated list (parv[parc] == NULL). ** ** *WARNING* ** Numerics are mostly error reports. If there is something ** wrong with the message, just *DROP* it! Don't even think of ** sending back a neat error message -- big danger of creating ** a ping pong error message... */ int do_numeric(int numeric, aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; aChannel *chptr; char *nick, *p; int i; if (parc < 1 || !IsServer(sptr)) return 0; /* Remap low number numerics. */ if (numeric < 100) numeric += 100; /* ** Prepare the parameter portion of the message into 'buffer'. ** (Because the buffer is twice as large as the message buffer ** for the socket, no overflow can occur here... ...on current ** assumptions--bets are off, if these are changed --msa) ** Note: if buffer is non-empty, it will begin with SPACE. */ buffer[0] = '\0'; if (parc > 1) { for (i = 2; i < (parc - 1); i++) { strcat(buffer, " "); strcat(buffer, parv[i]); } strcat(buffer, " :"); strcat(buffer, parv[parc-1]); } for (; (nick = strtok_r(parv[1], ",", &p)); parv[1] = NULL) { if ((acptr = find_client(nick, (aClient *)NULL))) { /* ** Drop to bit bucket if for me... ** ...one might consider sendto_ops ** here... --msa ** And so it was done. -avalon ** And regretted. Dont do it that way. Make sure ** it goes only to non-servers. -avalon ** Check added to make sure servers don't try to loop ** with numerics which can happen with nick collisions. ** - Avalon */ if (!IsMe(acptr) && IsPerson(acptr)) { /* Added for .U3.2. drop remote 'You are not on ** that channel', we should be synced anyway, ** and this is an annoying message with TSpre7 ** still on the net; would result in numeric 442 for ** every KICK... Can be removed when TSpre7 is gone. ** --Run */ if (numeric==ERR_NOTONCHANNEL) return 0; sendto_prefix_one(acptr, sptr,":%s %d %s%s", parv[0], numeric, nick, buffer); } else if (IsServer(acptr) && acptr->from != cptr) sendto_prefix_one(acptr, sptr,":%s %d %s%s", parv[0], numeric, nick, buffer); } else if ((acptr = find_server(nick, (aClient *)NULL))) { if (!IsMe(acptr) && acptr->from != cptr) sendto_prefix_one(acptr, sptr,":%s %d %s%s", parv[0], numeric, nick, buffer); } else if ((chptr = find_channel(nick, (aChannel *)NULL))) sendto_channel_butone(cptr,sptr,chptr,":%s %d %s%s", parv[0], numeric, chptr->chname, buffer); } return 0; }