void server_relay_private_message(struct Client* sptr, const char* name, const char* text) { struct Client* acptr; assert(0 != sptr); assert(0 != name); assert(0 != text); /* * nickname addressed? */ if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) { send_reply(sptr, SND_EXPLICIT | ERR_NOSUCHNICK, "* :Target left %s. " "Failed to deliver: [%.20s]", feature_str(FEAT_NETWORK), text); return; } if (!IsChannelService(sptr) && is_silenced(sptr, acptr)) { send_reply(sptr, ERR_SILENCED, cli_name(acptr)); return; } if (IsOnlyreg(acptr) && !IsRegnick(sptr)) { send_reply(sptr, RPL_MSGONLYREG, cli_name(acptr)); return; } if (MyUser(acptr)) add_target(acptr, sptr); sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text); }
void server_relay_private_notice(struct Client* sptr, const char* name, const char* text) { struct Client* acptr; assert(0 != sptr); assert(0 != name); assert(0 != text); /* * nickname addressed? */ if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) return; if (!IsChannelService(sptr) && is_silenced(sptr, acptr)) { send_reply(sptr, ERR_SILENCED, cli_name(acptr)); return; } if (IsOnlyreg(acptr) && !IsRegnick(sptr)) { send_reply(sptr, RPL_MSGONLYREG, cli_name(acptr)); return; } if (MyUser(acptr)) add_target(acptr, sptr); sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text); }
void relay_private_notice(struct Client* sptr, const char* name, const char* text) { struct Client* acptr; assert(0 != sptr); assert(0 != name); assert(0 != text); if (0 == (acptr = FindUser(name))) return; if (IsOnlyreg(acptr) && !IsRegnick(sptr)) { send_reply(sptr, RPL_MSGONLYREG, cli_name(acptr)); return; } if (!IsChannelService(acptr)) { if (check_target_limit(sptr, acptr, cli_name(acptr), 0)) { return; } if (is_silenced(sptr, acptr)) { send_reply(sptr, ERR_SILENCED, cli_name(acptr)); return; } } /* * deliver the message */ if (MyUser(acptr)) add_target(acptr, sptr); sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text); }
void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text) { struct Client* acptr; char* host; assert(0 != sptr); assert(0 != name); assert(0 != text); assert(0 != server); if (0 == (acptr = FindServer(server + 1))) return; /* * NICK[%host]@server addressed? See if <server> is me first */ if (!IsMe(acptr)) { sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text); return; } /* * Look for an user whose NICK is equal to <name> and then * check if it's hostname matches <host> and if it's a local * user. */ *server = '\0'; if ((host = strchr(name, '%'))) *host++ = '\0'; if (!(acptr = FindUser(name)) || !MyUser(acptr) || (!EmptyString(host) && 0 != match(host, cli_user(acptr)->realhost))) return; *server = '@'; if (host) *--host = '%'; if (!IsChannelService(sptr) && is_silenced(sptr, acptr)) { send_reply(sptr, ERR_SILENCED, cli_name(acptr)); return; } if (IsOnlyreg(acptr) && !IsRegnick(sptr)) send_reply(sptr, RPL_MSGONLYREG, cli_name(acptr)); else sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text); }
/* * ms_invite - server message handler * * parv[0] - sender prefix * parv[1] - user to invite * parv[2] - channel name * parv[3] - (optional) channel timestamp * * - INVITE now is accepted only if who does it is chanop (this of course * implies that channel must exist and he must be on it). * * - On the other side it IS processed even if channel is NOT invite only * leaving room for other enhancements like inviting banned ppl. -- Nemesi * * - Invite with no parameters now lists the channels you are invited to. * - Isomer 23 Oct 99 * * - Invite with too-late timestamp, or with no timestamp from a bursting * server, is silently discarded. - Entrope 19 Jan 05 */ int ms_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; struct Channel *chptr; time_t invite_ts; if (IsServer(sptr)) { /* * this will blow up if we get an invite from a server * we look for channel membership in sptr below. */ return protocol_violation(sptr,"Server attempting to invite"); } if (parc < 3 || EmptyString(parv[2])) { /* * should have been handled upstream, ignore it. */ protocol_violation(sptr,"Too few arguments to invite"); return need_more_params(sptr,"INVITE"); } if (!IsGlobalChannel(parv[2])) { /* * should not be sent */ return protocol_violation(sptr, "Invite to a non-standard channel %s",parv[2]); } if (!(acptr = FindUser(parv[1]))) { send_reply(sptr, ERR_NOSUCHNICK, parv[1]); return 0; } if (!(chptr = FindChannel(parv[2]))) { /* * allow invites to non existent channels, bleah * avoid JOIN, INVITE, PART abuse */ sendcmdto_one(sptr, CMD_INVITE, acptr, "%C :%s", acptr, parv[2]); return 0; } if (parc > 3) { invite_ts = atoi(parv[3]); if (invite_ts > chptr->creationtime) return 0; } else if (IsBurstOrBurstAck(cptr)) return 0; if (!IsChannelService(sptr) && !find_channel_member(sptr, chptr)) { send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname); return 0; } if (find_channel_member(acptr, chptr)) { send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname); return 0; } if (is_silenced(sptr, acptr)) return 0; if (MyConnect(acptr)) { add_invite(acptr, chptr); sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H", cli_name(acptr), chptr); } else { sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime); } if (feature_bool(FEAT_ANNOUNCE_INVITES)) { /* Announce to channel operators. */ sendcmdto_channel_butserv_butone(&his, get_error_numeric(RPL_ISSUEDINVITE)->str, NULL, chptr, sptr, SKIP_NONOPS, "%H %C %C :%C has been invited by %C", chptr, acptr, sptr, acptr, sptr); /* Announce to servers with channel operators. */ sendcmdto_channel_servers_butone(sptr, NULL, TOK_INVITE, chptr, acptr, SKIP_NONOPS, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime); } return 0; }
/* * m_invite - generic message handler * * parv[0] - sender prefix * parv[1] - user to invite * parv[2] - channel name * * - INVITE now is accepted only if who does it is chanop (this of course * implies that channel must exist and he must be on it). * * - On the other side it IS processed even if channel is NOT invite only * leaving room for other enhancements like inviting banned ppl. -- Nemesi * * - Invite with no parameters now lists the channels you are invited to. * - Isomer 23 Oct 99 */ int m_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; struct Channel *chptr; if (parc < 2 ) { /* * list the channels you have an invite to. */ struct SLink *lp; for (lp = cli_user(sptr)->invited; lp; lp = lp->next) send_reply(cptr, RPL_INVITELIST, lp->value.chptr->chname); send_reply(cptr, RPL_ENDOFINVITELIST); return 0; } if (parc < 3 || EmptyString(parv[2])) return need_more_params(sptr, "INVITE"); if (!(acptr = FindUser(parv[1]))) { send_reply(sptr, ERR_NOSUCHNICK, parv[1]); return 0; } if (is_silenced(sptr, acptr)) return 0; if (!IsChannelName(parv[2]) || !strIsIrcCh(parv[2]) || !(chptr = FindChannel(parv[2]))) { send_reply(sptr, ERR_NOSUCHCHANNEL, parv[2]); return 0; } if (!find_channel_member(sptr, chptr)) { send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname); return 0; } if (find_channel_member(acptr, chptr)) { send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname); return 0; } if (!is_chan_op(sptr, chptr)) { send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname); return 0; } /* If we get here, it was a VALID and meaningful INVITE */ if (check_target_limit(sptr, acptr, cli_name(acptr), 0)) return 0; send_reply(sptr, RPL_INVITING, cli_name(acptr), chptr->chname); if (cli_user(acptr)->away) send_reply(sptr, RPL_AWAY, cli_name(acptr), cli_user(acptr)->away); if (MyConnect(acptr)) { add_invite(acptr, chptr); sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H", cli_name(acptr), chptr); } else if (!IsLocalChannel(chptr->chname)) { sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime); } if (!IsLocalChannel(chptr->chname) || MyConnect(acptr)) { if (feature_bool(FEAT_ANNOUNCE_INVITES)) { /* Announce to channel operators. */ sendcmdto_channel_butserv_butone(&his, get_error_numeric(RPL_ISSUEDINVITE)->str, NULL, chptr, sptr, SKIP_NONOPS, "%H %C %C :%C has been invited by %C", chptr, acptr, sptr, acptr, sptr); /* Announce to servers with channel operators. */ sendcmdto_channel_servers_butone(sptr, NULL, TOK_INVITE, chptr, acptr, SKIP_NONOPS, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime); } } return 0; }
/** Send a (prefixed) command to all users on this channel, except for * \a one and those matching \a skip. * @warning \a pattern must not contain %v. * @param[in] from Client originating the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command. * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_NONOPS, SKIP_NONVOICES, SKIP_DEAF, SKIP_BURST. * @param[in] pattern Format string for command arguments. */ void sendcmdto_channel_butone(struct Client *from, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, unsigned char prefix, const char *pattern, ...) { struct Membership *member; struct VarData vd; struct MsgBuf *user_mb; struct MsgBuf *serv_mb; struct Client *service; const char *userfmt; const char *usercmd; vd.vd_format = pattern; /* Build buffer to send to users */ usercmd = cmd; userfmt = "%:#C %s %v"; if (skip & (SKIP_NONOPS | SKIP_NONHOPS | SKIP_NONVOICES)) { usercmd = MSG_NOTICE; if (skip & SKIP_NONVOICES) userfmt = "%:#C %s +%v"; else if (skip & SKIP_NONHOPS) userfmt = "%:#C %s %%%v"; else userfmt = "%:#C %s @%v"; } va_start(vd.vd_args, pattern); user_mb = msgq_make(0, userfmt, from, usercmd, &vd); va_end(vd.vd_args); /* Build buffer to send to servers */ va_start(vd.vd_args, pattern); serv_mb = msgq_make(&me, "%C %s %v", from, tok, &vd); va_end(vd.vd_args); /* send buffer along! */ bump_sentalong(one); for (member = to->members; member; member = member->next_member) { /* skip one, zombies, and deaf users... */ if (IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) || (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONHOPS && !IsChanOp(member) && !IsHalfOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !IsHalfOp(member) && !HasVoice(member)) || (skip & SKIP_BURST && IsBurstOrBurstAck(cli_from(member->user))) || (is_silenced(from, member->user, 1)) || cli_fd(cli_from(member->user)) < 0 || cli_sentalong(member->user) == sentalong_marker) continue; cli_sentalong(member->user) = sentalong_marker; if (MyConnect(member->user)) /* pick right buffer to send */ send_buffer(member->user, user_mb, 0); else send_buffer(member->user, serv_mb, 0); } /* Consult service forwarding table. */ if(GlobalForwards[prefix] && (service = FindServer(GlobalForwards[prefix])) && cli_sentalong(service) != sentalong_marker) { cli_sentalong(service) = sentalong_marker; send_buffer(service, serv_mb, 0); } msgq_clean(user_mb); msgq_clean(serv_mb); }
static int m_message(struct Client *cptr, struct Client *sptr, int parc, char *parv[], int notice) { struct Client *acptr; #ifdef NEED_TLD_FOR_MASS_NOTICE char *s; #endif struct Channel *chptr; char *nick, *server, *host; char errbuf[BUFSIZE]; const char *cmd; int type=0, msgs=0; #ifdef FLUD int flud; #endif cmd = notice ? MSG_NOTICE : MSG_PRIVATE; if (parc < 2 || *parv[1] == '\0') { sendto_one(sptr, form_str(ERR_NORECIPIENT), me.name, parv[0], cmd); return -1; } if (parc < 3 || *parv[2] == '\0') { sendto_one(sptr, form_str(ERR_NOTEXTTOSEND), me.name, parv[0]); return -1; } if (MyConnect(sptr)) { #ifdef ANTI_SPAMBOT #ifndef ANTI_SPAMBOT_WARN_ONLY /* if its a spambot, just ignore it */ if(sptr->join_leave_count >= MAX_JOIN_LEAVE_COUNT) return 0; #endif #endif #ifdef NO_DUPE_MULTI_MESSAGES if (strchr(parv[1],',')) parv[1] = canonize(parv[1]); #endif } /* ** channels are privmsg'd a lot more than other clients, moved up here ** plain old channel msg ? */ while(msgs < MAX_MULTI_MESSAGES) { if(!msgs) nick = strtok(parv[1], ","); else nick = strtok(NULL, ","); if(!nick && msgs == 0) nick = parv[1]; else if(!nick) break; if( IsChanPrefix(*nick) && (IsPerson(sptr) && (chptr = hash_find_channel(nick, NullChn)))) { #ifdef FLUD #ifdef DEATHFLUD if(!notice && check_for_ctcp(parv[2]) && check_for_flud(sptr, NULL, chptr, 1)) return 0; if((flud = check_for_spam(sptr, NULL, chptr, parv[2]))) { if (check_for_flud(sptr, NULL, chptr, flud)) return 0; } #else /* DEATHFLUD */ if(!notice) if(check_for_ctcp(parv[2])) check_for_flud(sptr, NULL, chptr, 1); #endif /* DEATHFLUD */ #endif /* FLUD */ /* * Channel color blocking. Usually set with the +c chanmode. * - Andre Guibert de Bruet <*****@*****.**> */ if(chptr->mode.mode & MODE_NOCOLOR) strip_colour(parv[2]); switch (can_send(sptr, chptr)) { case 0: sendto_channel_message_butone(cptr, sptr, chptr, cmd, parv[2]); break; case MODE_QUIETUNIDENT: if (!notice) sendto_one(sptr, form_str(ERR_QUIETUNIDENT), me.name, parv[0], nick); break; case MODE_MODERATED: if (chptr->mode.mode & MODE_OPMODERATE) { /* The flag MODE_OPMODERATE will instruct sendto_channel_type() * to put bare #channel in the message (instead of @#channel); * it will still be sent to ops and servers with ops only. * Strange things will happen if the user is not banned * remotely. * -- jilles */ sendto_channel_type(cptr, sptr, chptr, MODE_CHANOP | MODE_OPMODERATE, nick, cmd, parv[2]); } else { if (!notice) sendto_one(sptr, form_str(ERR_CANNOTSENDTOCHAN), me.name, parv[0], nick); } break; default: break; } msgs++; continue; } /* ** @# type of channel msg? */ if(*nick == '@') type = MODE_CHANOP; else if(*nick == '+') type = MODE_CHANOP|MODE_VOICE; if(type) { /* Strip if using DALnet chanop/voice prefix. */ if (*(nick+1) == '@' || *(nick+1) == '+') { nick++; *nick = '@'; type = MODE_CHANOP|MODE_VOICE; } /* suggested by Mortiis */ if(!*nick) /* if its a '\0' dump it, there is no recipient */ { sendto_one(sptr, form_str(ERR_NORECIPIENT), me.name, parv[0], cmd); return -1; } if (!IsPerson(sptr)) /* This means, servers can't send messages */ return -1; /* At this point, nick+1 should be a channel name i.e. #foo or &foo * if the channel is found, fine, if not report an error */ if ( (chptr = hash_find_channel(nick+1, NullChn)) ) { #ifdef FLUD #ifdef DEATHFLUD if(!notice && check_for_ctcp(parv[2]) && check_for_flud(sptr, NULL, chptr, 1)) return 0; if((flud = check_for_spam(sptr, NULL, chptr, parv[2]))) { if (check_for_flud(sptr, NULL, chptr, flud)) return 0; } #else /* DEATHFLUD */ if(!notice) if(check_for_ctcp(parv[2])) check_for_flud(sptr, NULL, chptr, 1); #endif /* DEATHFLUD */ #endif /* FLUD */ if (!is_chan_op(sptr,chptr)) { if (!notice) { sendto_one(sptr, form_str(ERR_CANNOTSENDTOCHAN), me.name, parv[0], nick); } msgs++; continue; } else { sendto_channel_type(cptr, sptr, chptr, type, nick+1, cmd, parv[2]); } } else { if (!IsServer(sptr)) sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; continue; } return 0; } /* ** nickname addressed? */ if ((acptr = find_person(nick, NULL))) { #ifdef FLUD #ifdef DEATHFLUD if(!notice && MyConnect(sptr) && check_for_ctcp(parv[2]) && check_for_flud(sptr, acptr, NULL, 1)) return 0; if(MyConnect(sptr) && (flud = check_for_spam(sptr, acptr, NULL, parv[2]))) { if (check_for_flud(sptr, acptr, NULL, flud)) return 0; } #else /* DEATHFLUD */ if(!notice && MyConnect(sptr)) if(check_for_ctcp(parv[2])) if(check_for_flud(sptr, acptr, NULL, 1)) return 0; #endif /* DEATHFLUD */ #endif /* FLUD */ #ifdef ANTI_DRONE_FLOOD if(MyConnect(acptr) && IsClient(sptr) && !NoFloodProtection(sptr) && DRONETIME) { if((acptr->first_received_message_time+DRONETIME) < CurrentTime) { acptr->received_number_of_privmsgs=1; acptr->first_received_message_time = CurrentTime; acptr->drone_noticed = 0; } else { if(acptr->received_number_of_privmsgs > DRONECOUNT) { if(acptr->drone_noticed == 0) /* tiny FSM */ { sendto_ops_flag(UMODE_BOTS, "Possible Drone Flooder %s [%s@%s] on %s target: %s", sptr->name, sptr->username, sptr->host, sptr->user->server, acptr->name); acptr->drone_noticed = 1; } /* heuristic here, if target has been getting a lot * of privmsgs from clients, and sendq is above halfway up * its allowed sendq, then throw away the privmsg, otherwise * let it through. This adds some protection, yet doesn't * DOS the client. * -Dianora */ if(DBufLength(&acptr->sendQ) > (get_sendq(acptr)/2UL)) { if(acptr->drone_noticed == 1) /* tiny FSM */ { sendto_ops_flag(UMODE_BOTS, "ANTI_DRONE_FLOOD SendQ protection activated for %s", acptr->name); sendto_one(acptr, ":%s NOTICE %s :*** Notice -- Server drone flood protection activated for %s", me.name, acptr->name, acptr->name); acptr->drone_noticed = 2; } } if(DBufLength(&acptr->sendQ) <= (get_sendq(acptr)/4UL)) { if(acptr->drone_noticed == 2) { sendto_one(acptr, ":%s NOTICE %s :*** Notice -- Server drone flood protection de-activated for %s", me.name, acptr->name, acptr->name); acptr->drone_noticed = 1; } } if(acptr->drone_noticed > 1) return 0; } else acptr->received_number_of_privmsgs++; } } #endif /* * Simple herustic here... If PRIVMSG is locked down via * F:noidprivmsg:1, then act like every client is +E. * Otherwise, assume the normal behaviour. All in a nice * single if statement. --nenolod */ if (MyClient(sptr) && sptr != acptr && (GlobalSetOptions.noidprivmsg != 0 || HasUmode(acptr,UMODE_BLOCK_NOTID)) && !HasUmode(sptr,UMODE_IDENTIFIED) && !sptr->user->servlogin[0] && !HasUmode(acptr,UMODE_DONTBLOCK) && !HasUmode(sptr,UMODE_DONTBLOCK)) { /* Replace errbuf with either the default or custom message, * then send the numeric on... * --nenolod */ if (GlobalSetOptions.noidprivmsg != 0 && GlobalSetOptions.noidprivmsg_notice[0]) { strncpy_irc(errbuf, GlobalSetOptions.noidprivmsg_notice, BUFSIZE); } else { ircsnprintf(errbuf, BUFSIZE, get_str(STR_NOTID_DEFAULT), nick); } sendto_one(sptr, form_str(ERR_BLOCKING_NOTID), me.name, parv[0], errbuf); return 0; } #ifdef SILENCE /* only check silence masks at the recipient's server -- jilles */ if (!MyConnect(acptr) || !is_silenced(sptr, acptr)) { #endif if (MyConnect(sptr) && acptr->user && (sptr != acptr)) { #ifdef NCTCP /* NCTCP (umode +C) checks -- PMA */ if (parv[2][0] == 1) /* is CTCP */ /* Huh? No way, NOCTCP means NOCTCP. */ /* if (!HasUmode(sptr,UMODE_IMMUNE) && */ /* !HasUmode(acptr,UMODE_IMMUNE)) */ if (HasUmode(acptr,UMODE_NOCTCP) || /* block to +C */ (notice && HasUmode(sptr,UMODE_NOCTCP))) /* block replies from +C */ return 0; /* kill it! */ #endif /* NCTCP */ if (!notice && acptr->user->away) sendto_one(sptr, form_str(RPL_AWAY), me.name, parv[0], acptr->name, acptr->user->away); } { /* here's where we actually send the message */ int is_ctcp = check_for_ctcp(parv[2]); int cap = is_ctcp ? CAP_IDENTIFY_CTCP : CAP_IDENTIFY_MSG; sendto_prefix_one(acptr, sptr, ":%s %s %s :%s%s", parv[0], cmd, nick, !(acptr->caps & cap) ? "" : (HasUmode(sptr, UMODE_IDENTIFIED) ? "+" : "-"), parv[2]); } #ifdef SILENCE } #endif msgs++; continue; } /* Everything below here should be reserved for opers * as pointed out by Mortiis, user%[email protected] * syntax could be used to flood without FLUD protection * its also a delightful way for non-opers to find users who * have changed nicks -Dianora * * Grrr it was pointed out to me that x@service is valid * for non-opers too, and wouldn't allow for flooding/stalking * -Dianora * * Valid or not, @servername is unacceptable, it reveals what server * a person is on. Auspexen only. * -- asuffield */ /* ** the following two cases allow masks in NOTICEs ** (for OPERs only) (with +M -- asuffield) ** ** Armin, 8Jun90 ([email protected]) */ if ((*nick == '$' || *nick == '>')) { if(!HasUmode(sptr,UMODE_MASSNOTICE)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); return -1; } #ifdef NEED_TLD_FOR_MASS_NOTICE if (!(s = (char *)strrchr(nick, '.'))) { sendto_one(sptr, form_str(ERR_NOTOPLEVEL), me.name, parv[0], nick); msgs++; continue; } while (*++s) if (*s == '.' || *s == '*' || *s == '?') break; if (*s == '*' || *s == '?') { sendto_one(sptr, form_str(ERR_WILDTOPLEVEL), me.name, parv[0], nick); msgs++; continue; } #endif /* NEED_TLD_FOR_MASS_NOTICE */ sendto_match_butone(IsServer(cptr) ? cptr : NULL, sptr, nick + 1, (*nick == '>') ? MATCH_HOST : MATCH_SERVER, ":%s %s %s :%s", parv[0], cmd, nick, parv[2]); msgs++; continue; } /* ** user[%host]@server addressed? */ if ((server = (char *)strchr(nick, '@')) && (acptr = find_server(server + 1))) { int count = 0; /* Disable the whole farping mess for non-auspexen * -- asuffield */ if (!HasUmode(sptr,UMODE_AUSPEX)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; continue; } /* Disable the user%host@server form for non-opers * -Dianora */ /* Disabled. This isn't very useful and I don't feel like mucking around with privs for it * -- asuffield */ if((char *)strchr(nick,'%')) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; continue; } /* ** Not destined for a user on me :-( */ if (!IsMe(acptr)) { sendto_one(acptr,":%s %s %s :%s", parv[0], cmd, nick, parv[2]); msgs++; continue; } *server = '\0'; /* special case opers@server */ /* We don't want this on OPN -- asuffield */ #if 0 if(!irccmp(nick,"opers") && SendWallops(sptr)) { sendto_realops("To opers: From %s: %s",sptr->name,parv[2]); msgs++; continue; } #endif if ((host = (char *)strchr(nick, '%'))) *host++ = '\0'; /* ** Look for users which match the destination host ** (no host == wildcard) and if one and one only is ** found connected to me, deliver message! */ acptr = find_userhost(nick, host, NULL, &count); if (server) *server = '@'; if (host) *--host = '%'; if (acptr) { if (count == 1) sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", parv[0], cmd, nick, parv[2]); else if (!notice) sendto_one(sptr, form_str(ERR_TOOMANYTARGETS), me.name, parv[0], nick, MAX_MULTI_MESSAGES); } if (acptr) { msgs++; continue; } } /* Let's not send these remotely for channels */ if (MyConnect(sptr) || (nick[0] != '#')) sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; } if (strtok(NULL, ",")) sendto_one(sptr, form_str(ERR_TOOMANYTARGETS), me.name, parv[0], cmd, MAX_MULTI_MESSAGES); return 0; }
void relay_private_message(struct Client *cptr, struct Client* sptr, const char* name, const char* text) { struct Client* acptr; static char *pmsg = NULL; static int last_length = 0; int len; assert(0 != sptr); assert(0 != name); assert(0 != text); if (0 == (acptr = FindUser(name))) { send_reply(sptr, ERR_NOSUCHNICK, name); return; } if (IsOnlyreg(acptr) && !IsRegnick(sptr)) { send_reply(sptr, RPL_MSGONLYREG, cli_name(acptr)); return; } if (!IsChannelService(acptr)) { if (check_target_limit(sptr, acptr, cli_name(acptr), 0)) { return; } if (is_silenced(sptr, acptr)) { send_reply(sptr, ERR_SILENCED, cli_name(acptr)); return; } } if (MyUser(cptr) && !es_representante(cptr)) { if ((len = strlen(text)+1) > last_length) { if (pmsg) free(pmsg); pmsg = (char *)MyMalloc(sizeof(char)*len); last_length = len; } strcpy(pmsg, text); correct_colors(pmsg); if (process_badwords(pmsg, BADWORDS_QUERY) != NULL) return; } /* * send away message if user away */ if (cli_user(acptr) && cli_user(acptr)->away) send_reply(sptr, RPL_AWAY, cli_name(acptr), cli_user(acptr)->away); /* * deliver the message */ if (MyUser(acptr)) add_target(acptr, sptr); sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text); }
void relay_directed_message(struct Client* sptr, char* name, char* server, const char* text) { struct Client* acptr; char* host; assert(0 != sptr); assert(0 != name); assert(0 != text); assert(0 != server); if (0 == (acptr = FindServer(server + 1))) { send_reply(sptr, ERR_NOSUCHNICK, name); return; } /* * NICK[%host]@server addressed? See if <server> is me first */ if (!IsMe(acptr)) { sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text); return; } /* * Look for an user whose NICK is equal to <name> and then * check if it's hostname matches <host> and if it's a local * user. */ *server = '\0'; if ((host = strchr(name, '%'))) *host++ = '\0'; /* As reported by Vampire-, it's possible to brute force finding users * by sending a message to each server and see which one succeeded. * This means we have to remove error reporting. Sigh. Better than * removing the ability to send directed messages to client servers * Thanks for the suggestion Vampire=. -- Isomer 2001-08-28 * Argh, /ping nick@server, disallow messages to non +k clients :/ I hate * this. -- Isomer 2001-09-16 */ if (!(acptr = FindUser(name)) || !MyUser(acptr) || (!EmptyString(host) && 0 != match(host, cli_user(acptr)->realhost)) || !IsChannelService(acptr)) { #if 0 send_reply(sptr, ERR_NOSUCHNICK, name); #endif return; } *server = '@'; if (host) *--host = '%'; if (!IsChannelService(sptr) && is_silenced(sptr, acptr)) { send_reply(sptr, ERR_SILENCED, cli_name(acptr)); return; } if (IsOnlyreg(acptr) && !IsRegnick(sptr)) send_reply(sptr, RPL_MSGONLYREG, cli_name(acptr)); else sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text); }
/* ** m_whois ** parv[0] = sender prefix ** parv[1] = nickname masklist */ int m_whois(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { static anUser UnknownUser = { NULL, /* next */ NULL, /* channel */ NULL, /* invited */ NULL, /* silence */ NULL, /* away */ 0, /* last */ 1, /* refcount */ 0, /* joined */ "<Unknown>" /* server */ }; static char rpl_oper[] = "an IRC Operator"; static char rpl_locop[] = "an IRC Operator - Local IRC Operator"; static char rpl_sadmin[] = "an IRC Operator - Services Administrator"; static char rpl_admin[] = "an IRC Operator - Server Administrator"; static char rpl_tadmin[] = "an IRC Operator - Technical Administrator"; static char rpl_nadmin[] = "an IRC Operator - Network Administrator"; Link *lp; anUser *user; struct Client *acptr, *a2cptr; aChannel *chptr; char *nick, *name; /* char *tmp; */ char *p = NULL; int found, len, mlen; static time_t last_used=0L; char *nick_match=NULL, *user_match=NULL, *host_match=NULL, *server_match=NULL; char *name_match=NULL; int found_mode; int hits = 0; char *mename = me.name; if(sptr->user && sptr->user->vlink) mename = sptr->user->vlink->name; if (parc < 2) { sendto_one(sptr, form_str(ERR_NONICKNAMEGIVEN), mename, parv[0]); return 0; } if(parc > 2) { if (hunt_server(cptr,sptr,":%s WHOIS %s :%s", 1,parc,parv) != HUNTED_ISME) return 0; parv[1] = parv[2]; } if(!IsAnOper(sptr) && !MyConnect(sptr)) /* pace non local requests */ { if((last_used + WHOIS_WAIT) > CurrentTime) { /* Unfortunately, returning anything to a non local * request =might= increase sendq to be usable in a split hack * Sorry gang ;-( - Dianora */ return 0; } else { last_used = CurrentTime; } } /* Multiple whois from remote hosts, can be used * to flood a server off. One could argue that multiple whois on * local server could remain. Lets think about that, for now * removing it totally. * -Dianora */ /* for (tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL) */ nick = parv[1]; p = strchr(parv[1],','); if(p) *p = '\0'; { int invis, member, wilds; found = 0; (void)collapse(nick); wilds = (nick[0]=='$' || strchr(nick, '?') || strchr(nick, '*')); /* ** We're no longer allowing remote users to generate ** requests with wildcards. */ if (wilds && !IsAnOper(sptr)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); return 0; } /* continue; */ /* If the nick doesn't have any wild cards in it, * then just pick it up from the hash table * - Dianora */ if(!wilds) { acptr = hash_find_client(nick,(struct Client *)NULL); if(!acptr) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; /* continue; */ } if(IsStealth(acptr)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); return 0; // Add by ^Stinger^ after the idea of Soldier (: } if(!IsPerson(acptr)) { sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; } /* continue; */ user = acptr->user ? acptr->user : &UnknownUser; name = (!*acptr->name) ? "?" : acptr->name; invis = IsInvisible(acptr); member = (user->channel) ? 1 : 0; a2cptr = find_server(user->server); sendto_one(sptr, form_str(RPL_WHOISUSER), mename, parv[0], name, acptr->username, acptr->host, acptr->info); if((IsOper(sptr) || (acptr == sptr)) && WhoisExtension) { sendto_one(sptr, form_str(RPL_WHOISREALHOST), mename, parv[0], name, acptr->realhost); } mlen = strlen(mename) + strlen(parv[0]) + 6 + strlen(name); *buf = '\0'; if (IsSsl(acptr)) { sendto_one(sptr, form_str(RPL_WHOISSECURE), mename, parv[0], parv[1]); } if(((!IsPrivate(acptr) || IsOper(sptr)) || (acptr==sptr)) && !IsStealth(acptr)) for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; if (ShowChannel(sptr, chptr)) { if (len + strlen(chptr->chname) > (size_t) BUFSIZE - 4 - mlen) { sendto_one(sptr, ":%s %d %s %s :%s", mename, RPL_WHOISCHANNELS, parv[0], name, buf); *buf = '\0'; len = 0; } found_mode = user_channel_mode(acptr, chptr); #ifdef HIDE_OPS if(is_chan_op(sptr,chptr)) #endif { if(found_mode & CHFL_CHANOP) *(buf + len++) = '@'; #ifdef HALFOPS else if (found_mode & CHFL_HALFOP) *(buf + len++) = '%'; #endif else if (found_mode & CHFL_VOICE) *(buf + len++) = '+'; } if (len) *(buf + len) = '\0'; (void)strcpy(buf + len, chptr->chname); len += strlen(chptr->chname); (void)strcat(buf + len, " "); len++; } } if (buf[0] != '\0') sendto_one(sptr, form_str(RPL_WHOISCHANNELS), mename, parv[0], name, buf); if(IsAnOper(sptr) || !HideServerOnWhois) { #ifdef SERVERHIDE if (!(IsAnOper(sptr) || acptr == sptr)) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, NetworkName, NetworkDesc); else #endif if(acptr->user && acptr->user->vlink) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->vlink->name, user->vlink->passwd); else { if(!IsService(acptr) || IsAnOper(sptr) || !HideServicesServer) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->server, a2cptr?a2cptr->info:"*Not On This Net*"); } } /* if(IsAnOper(sptr) || HideServerOnWhois) */ if (IsIdentified(acptr)) sendto_one(sptr, form_str(RPL_WHOISIDENTIFIED), mename, parv[0], name); if (IsHelper(acptr)) sendto_one(sptr, form_str(RPL_WHOISHELPOP), mename, parv[0], name); if(IsOper(sptr) && WhoisExtension) { sendto_one(sptr, form_str(RPL_WHOISMODE), mename, parv[0], name, get_mode_string(acptr)); } if (user->away) sendto_one(sptr, form_str(RPL_AWAY), mename, parv[0], name, user->away); if(!IsHideOper(acptr) || IsOper(sptr)) { if (IsNetAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_nadmin); else if (IsTechAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_tadmin); else if (IsSAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_sadmin); else if (IsAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_admin); else if (IsOper(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_oper); else if (IsLocOp(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_locop); } #ifdef WHOIS_NOTICE if ((IsOper(acptr)) && ((acptr)->umodes & UMODE_SPY) && (MyConnect(sptr)) && (IsPerson(sptr)) && (acptr != sptr) && !is_silenced(sptr, acptr)) sendto_one(acptr, ":%s NOTICE %s :*** Notice -- %s (%s@%s) is doing a /whois on you.", me.name, acptr->name, parv[0], sptr->username, sptr->realhost); #endif /* #ifdef WHOIS_NOTICE */ if ((acptr->user #ifdef SERVERHIDE && IsAnOper(sptr) #endif && MyConnect(acptr))) sendto_one(sptr, form_str(RPL_WHOISIDLE), mename, parv[0], name, CurrentTime - user->last, acptr->firsttime); sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; /* continue; */ } /* wild is true so here we go */ if(nick[0]==':') /* real name match */ { name_match = &nick[1]; nick_match = NULL; } else if(nick[0]=='$') /* server name match */ { server_match = &nick[1]; nick_match = NULL; } else { host_match = strchr(nick,'@'); if(host_match) { if(*host_match) *(host_match++) = '\0'; user_match=nick; if(host_match=='\0') host_match="*"; if(user_match=='\0') user_match="*"; } else nick_match = nick; } for (acptr = GlobalClientList; acptr; acptr = acptr->next) { if (IsServer(acptr)) continue; /* * I'm always last :-) and acptr->next == NULL!! */ if (IsMe(acptr)) break; /* * 'Rules' established for sending a WHOIS reply: * * * - if wildcards are being used dont send a reply if * the querier isnt any common channels and the * client in question is invisible and wildcards are * in use (allow exact matches only); * * - only send replies about common or public channels * the target user(s) are on; */ /* If its an unregistered client, ignore it, it can be "seen" on a /trace anyway -Dianora */ if(!IsRegistered(acptr)) continue; user = acptr->user ? acptr->user : &UnknownUser; name = (!*acptr->name) ? "?" : acptr->name; if( (server_match && !match(server_match, user->server)) || (nick_match && !match(nick, name)) || (host_match && !match(host_match, acptr->realhost) && !match(host_match, acptr->host)) || (user_match && !match(user_match, acptr->username)) || (name_match && !match(name_match, acptr->info)) ) continue; ++hits; a2cptr = find_server(user->server); sendto_one(sptr, form_str(RPL_WHOISUSER), mename, parv[0], name, acptr->username, IsOper(sptr) ? acptr->realhost : acptr->host, acptr->info); found = 1; mlen = strlen(mename) + strlen(parv[0]) + 6 + strlen(name); for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; if (ShowChannel(sptr, chptr)) { if (len + strlen(chptr->chname) > (size_t) BUFSIZE - 4 - mlen) { sendto_one(sptr, ":%s %d %s %s :%s", mename, RPL_WHOISCHANNELS, parv[0], name, buf); *buf = '\0'; len = 0; } found_mode = user_channel_mode(acptr, chptr); #ifdef HIDE_OPS if(is_chan_op(sptr,chptr)) #endif { if (found_mode & CHFL_CHANOP) *(buf + len++) = '@'; #ifdef HALFOPS else if (found_mode & CHFL_HALFOP) *(buf + len++) = '%'; #endif else if (found_mode & CHFL_VOICE) *(buf + len++) = '+'; } if (len) *(buf + len) = '\0'; (void)strcpy(buf + len, chptr->chname); len += strlen(chptr->chname); (void)strcat(buf + len, " "); len++; } } if (buf[0] != '\0') sendto_one(sptr, form_str(RPL_WHOISCHANNELS), mename, parv[0], name, buf); #ifdef SERVERHIDE if (!(IsAnOper(sptr) || acptr == sptr)) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, NetworkName, NetworkDesc); else #endif sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->server, a2cptr?a2cptr->info:"*Not On This Net*"); if (user->away) sendto_one(sptr, form_str(RPL_AWAY), mename, parv[0], name, user->away); if (IsNetAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_nadmin); else if (IsTechAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_tadmin); else if (IsSAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_sadmin); else if (IsAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_admin); else if (IsAnOper(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_oper); #ifdef WHOIS_NOTICE if ((MyOper(acptr)) && ((acptr)->umodes & UMODE_SPY) && (MyConnect(sptr)) && (IsPerson(sptr)) && (acptr != sptr)) sendto_one(acptr, ":%s NOTICE %s :*** Notice -- %s (%s@%s) is doing a /whois on you.", mename, acptr->name, parv[0], sptr->username, sptr->realhost); #endif /* #ifdef WHOIS_NOTICE */ if ((acptr->user #ifdef SERVERHIDE && IsAnOper(sptr) #endif && MyConnect(acptr))) sendto_one(sptr, form_str(RPL_WHOISIDLE), mename, parv[0], name, CurrentTime - user->last, acptr->firsttime); if(hits>50) { sendto_one(sptr,":%s NOTICE %s :Aborting /whois output as flood prevention", mename, sptr->name); break; } } if (!found) sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); else sendto_one(sptr,":%s NOTICE %s :This /whois matched \2%i\2 user(s)", mename, sptr->name,hits); /* if (p) p[-1] = ','; */ } sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; }