/* ** m_okick ** parv[0] = sender prefix ** parv[1] = channel ** parv[2] = client to kick ** parv[3] = kick comment */ static void m_okick(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *who; struct Channel *chptr; int chasing = 0; char *comment; char *name; char *p = NULL; char *user; static char buf[BUFSIZE]; if (*parv[2] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KICK"); return; } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); comment = (EmptyString(parv[3])) ? parv[2] : parv[3]; if (strlen(comment) > (size_t) TOPICLEN) comment[TOPICLEN] = '\0'; *buf = '\0'; if( (p = strchr(parv[1],',')) ) *p = '\0'; name = parv[1]; chptr = hash_find_channel(name); if (!chptr) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name); return; } if( (p = strchr(parv[2],',')) ) *p = '\0'; user = parv[2]; /* strtoken(&p2, parv[2], ","); */ if (!(who = find_chasing(source_p, user, &chasing))) { return; } if (IsMember(who, chptr)) { sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s", me.name, chptr->chname, who->name, comment); sendto_server(&me, chptr, NOCAPS, NOCAPS, ":%s KICK %s %s :%s", me.name, chptr->chname, who->name, comment); remove_user_from_channel(chptr, who); } }
/* * m_lljoin * parv[0] = sender prefix * parv[1] = channel * parv[2] = nick ("!nick" == cjoin) * parv[3] = key (optional) * * If a lljoin is received, from our uplink, join * the requested client to the given channel, or ignore it * if there is an error. * * Ok, the way this works. Leaf client tries to join a channel, * it doesn't exist so the join does a cburst request on behalf of the * client, and aborts that join. The cburst sjoin's the channel if it * exists on the hub, and sends back an LLJOIN to the leaf. Thats where * this is now.. * */ static void ms_lljoin(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *chname = NULL; char *nick = NULL; char *key = NULL; int flags; int i; struct Client *target_p; struct Channel *chptr; if (uplink && !IsCapable(uplink,CAP_LL)) { sendto_realops_flags(UMODE_ALL, L_ALL, "*** LLJOIN requested from non LL server %s", client_p->name); return; } chname = parv[1]; if(chname == NULL) return; nick = parv[2]; if(nick == NULL) return; if (parc >3) key = parv[3]; flags = 0; target_p = find_person(client_p, nick); if (!target_p) return; if (!MyClient(target_p)) return; if (!check_channel_name(chname, 0)) { sendto_gnotice_flags(UMODE_DEBUG, L_ALL, me.name, &me, NULL, "*** Too long or invalid channel name from %s: %s", target_p->name, chname); return; } chptr = make_channel(chname); flags = CHFL_CHANOP; if(!chptr) return; if (dlink_list_length(&chptr->members) == 0) flags = CHFL_CHANOP; else flags = 0; /* XXX in m_join.c :( */ /* check_spambot_warning(target_p, chname); */ /* They _could_ join a channel twice due to lag */ if(chptr) { if (IsMember(target_p, chptr)) /* already a member, ignore this */ return; } else { sendto_one(target_p, form_str(ERR_UNAVAILRESOURCE), me.name, nick, chptr->chname); return; } if ((i = can_join(target_p, chptr, key))) { sendto_one(target_p, form_str(i), me.name, nick, chptr->chname); return; } if ((dlink_list_length(&target_p->channel) >= ConfigChannel.max_chans_per_user) && (!IsOper(target_p) || (dlink_list_length(&target_p->channel) >= ConfigChannel.max_chans_per_user*3))) { sendto_one(target_p, form_str(ERR_TOOMANYCHANNELS), me.name, nick, chptr->chname ); return; } if (flags == CHFL_CHANOP) { chptr->channelts = CurrentTime; sendto_one(uplink, ":%s SJOIN %lu %s + :@%s", me.name, (unsigned long) chptr->channelts, chptr->chname, nick); } sendto_one(uplink, ":%s SJOIN %lu %s + :%s", me.name, (unsigned long) chptr->channelts, chptr->chname, nick); add_user_to_channel(chptr, target_p, flags, YES); sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); if (flags & CHFL_CHANOP) { chptr->mode.mode |= MODE_TOPICLIMIT; chptr->mode.mode |= MODE_NOPRIVMSGS; sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s MODE %s +nt", me.name, chptr->chname); sendto_one(uplink, ":%s MODE %s +nt", me.name, chptr->chname); } channel_member_names(target_p, chptr, 1); }
/* parse_resv() * * inputs - source_p, NULL supported * - thing to resv * - time_t if tkline * - reason * outputs - none * side effects - parse resv, create if valid */ static void parse_resv(struct Client *source_p, char *name, int tkline_time, char *reason) { if (IsChanPrefix(*name)) { struct MaskItem *conf = NULL; if ((conf = create_resv(name, reason, NULL)) == NULL) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A RESV has already been placed on channel: %s", name); return; } conf->setat = CurrentTime; SetConfDatabase(conf); if (tkline_time) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A %d minute %s RESV has been placed on channel: %s", tkline_time/60, (MyClient(source_p) ? "local" : "remote"), name); sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s has placed a %d minute %s RESV on channel: %s [%s]", get_oper_name(source_p), tkline_time/60, (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); ilog(LOG_TYPE_RESV, "%s added temporary %d min. RESV for [%s] [%s]", get_oper_name(source_p), (int)tkline_time/60, conf->name, conf->reason); conf->until = CurrentTime + tkline_time; } else { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A %s RESV has been placed on channel %s", (MyClient(source_p) ? "local" : "remote"), name); sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s has placed a %s RESV on channel %s : [%s]", get_oper_name(source_p), (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); ilog(LOG_TYPE_RESV, "%s added RESV for [%s] [%s]", get_oper_name(source_p), conf->name, conf->reason); } } else { struct MaskItem *conf = NULL; if (!valid_wild_card_simple(name)) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":Please include at least %u non-wildcard characters with the resv", ConfigGeneral.min_nonwildcard_simple); return; } if (!HasUMode(source_p, UMODE_ADMIN) && has_wildcards(name)) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":You must be an admin to perform a wildcard RESV"); return; } if ((conf = create_resv(name, reason, NULL)) == NULL) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A RESV has already been placed on nick %s", name); return; } conf->setat = CurrentTime; SetConfDatabase(conf); if (tkline_time) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A %d minute %s RESV has been placed on nick %s : [%s]", tkline_time/60, (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s has placed a %d minute %s RESV on nick %s : [%s]", get_oper_name(source_p), tkline_time/60, (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); ilog(LOG_TYPE_RESV, "%s added temporary %d min. RESV for [%s] [%s]", get_oper_name(source_p), (int)tkline_time/60, conf->name, conf->reason); conf->until = CurrentTime + tkline_time; } else { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A %s RESV has been placed on nick %s : [%s]", (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s has placed a %s RESV on nick %s : [%s]", get_oper_name(source_p), (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); ilog(LOG_TYPE_RESV, "%s added RESV for [%s] [%s]", get_oper_name(source_p), conf->name, conf->reason); } } }
/* m_topic() * parv[0] = sender prefix * parv[1] = channel name * parv[2] = new topic, if setting topic */ static void m_topic(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; char *p; struct Membership *ms; const char *from, *to; if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p)) { from = me.id; to = source_p->id; } else { from = me.name; to = source_p->name; } if ((p = strchr(parv[1], ',')) != NULL) *p = '\0'; if (EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), from, to, "TOPIC"); return; } if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if (IsChanPrefix(*parv[1])) { if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), from, to, parv[1]); return; } /* setting topic */ if (parc > 2) { if ((ms = find_channel_link(source_p, chptr)) == NULL && !IsService(source_p)) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, source_p->name, parv[1]); return; } if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP) || IsGod(source_p) || IsService(source_p)) { char topic_info[USERHOST_REPLYLEN]; if(!has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP) && IsGod(source_p) && MyClient(source_p) && (chptr->mode.mode & MODE_TOPICLIMIT) != 0) { char tmp[IRCD_BUFSIZE]; ircsprintf(tmp, "%s is using God mode: TOPIC %s %s", source_p->name, chptr->chname, parv[2]); sendto_gnotice_flags(UMODE_SERVNOTICE, L_ALL, me.name, &me, NULL, tmp); oftc_log(tmp); } ircsprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, parv[2], topic_info, CurrentTime); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", ID(source_p), chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_server(client_p, chptr, NOCAPS, CAP_TS6, ":%s TOPIC %s :%s", source_p->name, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), from, to, chptr->chname); } else /* only asking for topic */ { if (!SecretChannel(chptr) || IsMember(source_p, chptr)) { if (chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), from, to, chptr->chname); else { sendto_one(source_p, form_str(RPL_TOPIC), from, to, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), from, to, chptr->chname, chptr->topic_info, chptr->topic_time); } } else { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), from, to, chptr->chname); return; } } } else { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), from, to, parv[1]); } }
/* ** m_invite ** parv[0] - sender prefix ** parv[1] - user to invite ** parv[2] - channel name ** parv[3] - invite timestamp */ static void m_invite(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; struct Channel *chptr = NULL; struct Membership *ms = NULL; if (IsServer(source_p)) return; if (EmptyString(parv[2])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "INVITE"); return; } if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if ((target_p = find_person(client_p, parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]); return; } /* Do not send local channel invites to users if they are not on the * same server as the person sending the INVITE message. */ /* Possibly should be an error sent to source_p */ /* done .. there should be no problem because MyConnect(source_p) should * always be true if parse() and such is working correctly --is */ if (!MyConnect(target_p) && (*parv[2] == '&')) { if (ConfigServerHide.hide_servers == 0) sendto_one(source_p, form_str(ERR_USERNOTONSERV), me.name, source_p->name, target_p->name); return; } if ((chptr = hash_find_channel(parv[2])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, parv[2]); return; } if (MyConnect(source_p) && (ms = find_channel_link(source_p, chptr)) == NULL) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, source_p->name, chptr->chname); return; } if (MyConnect(source_p) && !has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP)) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, chptr->chname); return; } if ((chptr->mode.mode & MODE_OPERONLY)) { if (MyConnect(source_p) && !IsOper(source_p)) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, chptr->chname); return; } } if (IsMember(target_p, chptr)) { sendto_one(source_p, form_str(ERR_USERONCHANNEL), me.name, source_p->name, target_p->name, chptr->chname); return; } if (MyConnect(source_p)) { sendto_one(source_p, form_str(RPL_INVITING), me.name, source_p->name, target_p->name, chptr->chname); if (target_p->away) sendto_one(source_p, form_str(RPL_AWAY), me.name, source_p->name, target_p->name, target_p->away); } else if (parc > 3 && IsDigit(*parv[3])) if (atoi(parv[3]) > chptr->channelts) return; if (MyConnect(target_p)) { sendto_one(target_p, ":%s!%s@%s INVITE %s :%s", source_p->name, source_p->username, source_p->host, target_p->name, chptr->chname); if (chptr->mode.mode & MODE_INVITEONLY) { sendto_channel_local(CHFL_CHANOP|CHFL_HALFOP, 0, chptr, ":%s NOTICE %s :%s is inviting %s to %s.", me.name, chptr->chname, source_p->name, target_p->name, chptr->chname); sendto_channel_remote(source_p, client_p, CHFL_CHANOP|CHFL_HALFOP, NOCAPS, NOCAPS, chptr, ":%s NOTICE %s :%s is inviting %s to %s.", source_p->name, chptr->chname, source_p->name, target_p->name, chptr->chname); /* Add the invite if channel is +i */ add_invite(chptr, target_p); } } else if (target_p->from != client_p) sendto_one(target_p, ":%s INVITE %s %s %lu", ID_or_name(source_p, target_p->from), ID_or_name(target_p, target_p->from), chptr->chname, (unsigned long)chptr->channelts); }
/* ** m_kick ** parv[1] = channel ** parv[2] = client to kick ** parv[3] = kick comment */ static int m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct membership *msptr; struct Client *who; struct Channel *chptr; int chasing = 0; char *comment; const char *name; char *p = NULL; char text[10]; const char *user; static char buf[BUFSIZE]; int is_override = 0; if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); *buf = '\0'; if((p = strchr(parv[1], ','))) *p = '\0'; name = parv[1]; chptr = find_channel(name); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } user = parv[2]; /* strtoken(&p2, parv[2], ","); */ if(!(who = find_chasing(source_p, user, &chasing))) { return 0; } if(!IsServer(source_p)) { msptr = find_channel_membership(chptr, source_p); if((msptr == NULL) && MyConnect(source_p)) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(!can_kick_deop(msptr, find_channel_membership(chptr, who))) { if(MyConnect(source_p)) { if(IsOverride(source_p)) is_override = 1; else { sendto_one(source_p, ":%s 482 %s %s :You do not have the proper privileges to kick this user", me.name, source_p->name, name); return 0; } } /* If its a TS 0 channel, do it the old way */ else if(chptr->channelts == 0) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), get_id(&me, source_p), get_id(source_p, source_p), name); return 0; } } /* Its a user doing a kick, but is not showing as chanop locally * its also not a user ON -my- server, and the channel has a TS. * There are two cases we can get to this point then... * * 1) connect burst is happening, and for some reason a legit * op has sent a KICK, but the SJOIN hasn't happened yet or * been seen. (who knows.. due to lag...) * * 2) The channel is desynced. That can STILL happen with TS * * Now, the old code roger wrote, would allow the KICK to * go through. Thats quite legit, but lets weird things like * KICKS by users who appear not to be chanopped happen, * or even neater, they appear not to be on the channel. * This fits every definition of a desync, doesn't it? ;-) * So I will allow the KICK, otherwise, things are MUCH worse. * But I will warn it as a possible desync. * * -Dianora */ } if((p = strchr(parv[2], ','))) *p = '\0'; msptr = find_channel_membership(chptr, who); if(msptr != NULL) { if(MyClient(source_p) && IsService(who)) { sendto_one(source_p, form_str(ERR_ISCHANSERVICE), me.name, source_p->name, who->name, chptr->chname); return 0; } if(MyClient(source_p) && chptr->mode.mode & MODE_NOKICK) { sendto_one_numeric(source_p, ERR_NOKICK, form_str(ERR_NOKICK), chptr->chname); return 0; } if (MyClient(source_p) && chptr->mode.mode & MODE_NOOPERKICK && IsOper(who)) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Overriding KICK from %s on %s in %s (channel is +M)", source_p->name, who->name, chptr->chname); sendto_one_numeric(source_p, ERR_ISCHANSERVICE, "%s %s :Cannot kick IRC operators from that channel.", who->name, chptr->chname); return 0; } if(MyClient(source_p)) { hook_data_channel_approval hookdata; hookdata.client = source_p; hookdata.chptr = chptr; hookdata.target = who; hookdata.approved = 1; call_hook(h_can_kick, &hookdata); if (!hookdata.approved) return 0; } comment = LOCAL_COPY((EmptyString(parv[3])) ? who->name : parv[3]); if(strlen(comment) > (size_t) REASONLEN) comment[REASONLEN] = '\0'; if(is_override) { sendto_wallops_flags(UMODE_WALLOP, &me, "%s is overriding KICK [%s] on [%s] [%s]", get_oper_name(source_p), who->name, chptr->chname, comment); sendto_server(NULL, chptr, NOCAPS, NOCAPS, ":%s WALLOPS :%s is overriding KICK [%s] on [%s] [%s]", me.name, get_oper_name(source_p), who->name, chptr->chname, comment); } /* jdc * - In the case of a server kicking a user (i.e. CLEARCHAN), * the kick should show up as coming from the server which did * the kick. * - Personally, flame and I believe that server kicks shouldn't * be sent anyways. Just waiting for some oper to abuse it... */ if(IsServer(source_p)) sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s", source_p->name, name, who->name, comment); else sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s KICK %s %s :%s", source_p->name, source_p->username, source_p->host, name, who->name, comment); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s KICK %s %s :%s", use_id(source_p), chptr->chname, use_id(who), comment); remove_user_from_channel(msptr); rb_snprintf(text, sizeof(text), "K%s", who->id); /* we don't need to track NOREJOIN stuff unless it's our client being kicked */ if(MyClient(who) && chptr->mode.mode & MODE_NOREJOIN) channel_metadata_time_add(chptr, text, rb_current_time(), "KICKNOREJOIN"); } else if (MyClient(source_p)) sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), user, name); return 0; }
int m_scan_idle(struct Client *cptr, struct Client *sptr, int parc, char *parv[], char *varparv[]) { struct Client *ptr, *target = NULL; char *eptr, buffer[321]; int idle_time, check_time, len = 0, count = 0; if(MyClient(sptr) && !HasUmode(sptr, UMODE_USER_AUSPEX)) { if(SeesOperMessages(sptr)) sendto_one(sptr,":%s NOTICE %s :You have no a umode", me.name, parv[0]); else sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if(parc < 3) { if (!IsServer(sptr)) sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SCAN IDLE"); return 0; } idle_time = strtoul(parv[2], &eptr, 10); if(eptr == parv[2]) return 0; /* Store the timestamp which last_sent should be >= to save time */ check_time = CurrentTime - idle_time; /* If the query is for another server, pass it on and return. */ if(parc > 3) { if(MyClient(sptr) && !HasUmode(sptr, UMODE_REMOTEINFO)) { if(SeesOperMessages(sptr)) sendto_one(sptr,":%s NOTICE %s :You have no S umode(cannot send remote)", me.name, parv[0]); else sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if(!irccmp(parv[3], "GLOBAL") || !irccmp(parv[3], "*")) sendto_serv_butone(cptr, ":%s SCAN IDLE %d *", parv[0], idle_time); else if((target = find_server(parv[3])) == NULL) { sendto_one(sptr, form_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[3]); return 0; }else if(!IsMe(target)) { /* But only if the query is not on us... */ sendto_prefix_one(target, sptr, ":%s SCAN IDLE %d %s", parv[0], idle_time, target->name); return 0; } } buffer[0] = '\0'; for(ptr = local_cptr_list; ptr; ptr = ptr->next_local_client) { if(ptr->user->last_sent < check_time) continue; if(len + strlen(ptr->name) > 319) { buffer[len - 1] = '\0'; /* Strip the trailing space */ send_markup(sptr, &me, "SCAN-IDLE", "%d %s", idle_time, buffer); buffer[0] = '\0'; len = 0; } strcat(buffer, ptr->name); strcat(buffer, " "); len += strlen(ptr->name) + 1; count++; } if(buffer[0]) { buffer[len - 1] = '\0'; send_markup(sptr, &me, "SCAN-IDLE", "%d %s", idle_time, buffer); } send_markup(sptr, &me, "IDLE-END", "End of idle listing"); if(count > 0 || target || parc == 3) /* Don't give a summary for globals if no results matched */ send_markup(sptr, &me, "SCAN-SUMMARY", "%d matched", count); return 0; }
/* * m_mode - MODE command handler * parv[1] - channel */ static int m_mode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; int n = 2; const char *dest; int operspy = 0; dest = parv[1]; if(IsOperSpy(source_p) && *dest == '!') { dest++; operspy = 1; if(EmptyString(dest)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "MODE"); return 0; } } /* Now, try to find the channel in question */ if(!IsChanPrefix(*dest)) { /* if here, it has to be a non-channel name */ user_mode(client_p, source_p, parc, parv); return 0; } if(!check_channel_name(dest)) { sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[1]); return 0; } chptr = find_channel(dest); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } /* Now know the channel exists */ if(parc < n + 1) { if(operspy) report_operspy(source_p, "MODE", chptr->chname); sendto_one(source_p, form_str(RPL_CHANNELMODEIS), me.name, source_p->name, parv[1], operspy ? channel_modes(chptr, &me) : channel_modes(chptr, source_p)); sendto_one(source_p, form_str(RPL_CREATIONTIME), me.name, source_p->name, parv[1], chptr->channelts); } else { msptr = find_channel_membership(chptr, source_p); /* Finish the flood grace period... */ if(MyClient(source_p) && !IsFloodDone(source_p)) { if(!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0'))) flood_endgrace(source_p); } set_channel_mode(client_p, source_p, chptr, msptr, parc - n, parv + n); } return 0; }
/* * 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); } }
/*! \brief NICK command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = nickname */ static int m_nick(struct Client *source_p, int parc, char *parv[]) { char nick[NICKLEN + 1] = ""; struct Client *target_p = NULL; struct MaskItem *conf = NULL; assert(MyClient(source_p)); if (parc < 2 || EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN); return 0; } /* Mark end of grace period, to prevent nickflooding */ if (!IsFloodDone(source_p)) flood_endgrace(source_p); /* Terminate nick to NICKLEN */ strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ConfigServerInfo.max_nick_length + 1)); /* Check the nickname is ok */ if (!valid_nickname(nick, 1)) { sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, "Erroneous Nickname"); return 0; } if (!HasFlag(source_p, FLAGS_EXEMPTRESV) && !(HasUMode(source_p, UMODE_OPER) && HasOFlag(source_p, OPER_FLAG_NICK_RESV)) && (conf = find_matching_name_conf(CONF_NRESV, nick, NULL, NULL, 0))) { ++conf->count; sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, conf->reason); sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE, "Forbidding reserved nick %s from user %s", nick, get_client_name(source_p, HIDE_IP)); return 0; } if ((target_p = hash_find_client(nick)) == NULL) change_local_nick(source_p, nick); else if (target_p == source_p) { /* * If (target_p == source_p) the client is changing nicks between * equivalent nicknames ie: [nick] -> {nick} */ /* Check the nick isn't exactly the same */ if (strcmp(target_p->name, nick)) change_local_nick(source_p, nick); } else if (IsUnknown(target_p)) { /* * If the client that has the nick isn't registered yet (nick but no * user) then drop the unregged client */ exit_client(target_p, "Overridden by other sign on"); change_local_nick(source_p, nick); } else sendto_one_numeric(source_p, &me, ERR_NICKNAMEINUSE, target_p->name); return 0; }
/* * m_topic * parv[1] = channel name * parv[2] = new topic, if setting topic */ static int m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; char *p = NULL; const char *name; int operspy = 0; if((p = strchr(parv[1], ','))) *p = '\0'; name = parv[1]; if(IsOperAuspex(source_p) && parv[1][0] == '!') { name++; operspy = 1; if(EmptyString(name)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "TOPIC"); return 0; } } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsChannelName(name)) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } chptr = find_channel(name); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } /* setting topic */ if(parc > 2) { char topic_info[USERHOST_REPLYLEN]; char topic[BUFSIZE]; msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(MyClient(source_p) && !is_chanop_voiced(msptr) && !IsOper(source_p) && !add_channel_target(source_p, chptr)) { sendto_one(source_p, form_str(ERR_TARGCHANGE), me.name, source_p->name, chptr->chname); return 0; } if(MyClient(source_p) && !(((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || is_chanop(msptr)) && can_send(chptr, source_p, msptr))) { if(IsOverride(source_p)) sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is overriding TOPIC on [%s]", get_oper_name(source_p), chptr->chname); else { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), get_id(&me, source_p), get_id(source_p, source_p), name); return 0; } } rb_strlcpy(topic, parv[2], BUFSIZE); strip_colour(topic); rb_sprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, topic, topic_info, rb_current_time()); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", use_id(source_p), chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); } else if(MyClient(source_p)) { if(operspy) report_operspy(source_p, "TOPIC", chptr->chname); if(!IsMember(source_p, chptr) && SecretChannel(chptr) && !operspy) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, name); else { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } } return 0; }
/* change_local_nick() * * inputs - pointer to server * - pointer to client * - nick * output - * side effects - changes nick of a LOCAL user */ static void change_local_nick(struct Client *source_p, const char *nick) { int samenick = 0; assert(source_p->name[0] && !EmptyString(nick)); assert(MyClient(source_p)); /* * Client just changing his/her nick. If he/she is * on a channel, send note of change to all clients * on that channel. Propagate notice to other servers. */ if ((source_p->connection->nick.last_attempt + ConfigGeneral.max_nick_time) < CurrentTime) source_p->connection->nick.count = 0; if (ConfigGeneral.anti_nick_flood && !HasUMode(source_p, UMODE_OPER) && source_p->connection->nick.count > ConfigGeneral.max_nick_changes) { sendto_one_numeric(source_p, &me, ERR_NICKTOOFAST, nick, ConfigGeneral.max_nick_time); return; } source_p->connection->nick.last_attempt = CurrentTime; source_p->connection->nick.count++; samenick = !irccmp(source_p->name, nick); if (!samenick) { source_p->tsinfo = CurrentTime; clear_ban_cache_client(source_p); watch_check_hash(source_p, RPL_LOGOFF); if (HasUMode(source_p, UMODE_REGISTERED)) { unsigned int oldmodes = source_p->umodes; char modebuf[IRCD_BUFSIZE] = ""; DelUMode(source_p, UMODE_REGISTERED); send_umode(source_p, source_p, oldmodes, modebuf); } } sendto_realops_flags(UMODE_NCHANGE, L_ALL, SEND_NOTICE, "Nick change: From %s to %s [%s@%s]", source_p->name, nick, source_p->username, source_p->host); sendto_common_channels_local(source_p, 1, 0, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); whowas_add_history(source_p, 1); sendto_server(source_p, 0, 0, ":%s NICK %s :%lu", source_p->id, nick, (unsigned long)source_p->tsinfo); hash_del_client(source_p); strlcpy(source_p->name, nick, sizeof(source_p->name)); hash_add_client(source_p); if (!samenick) watch_check_hash(source_p, RPL_LOGON); /* fd_desc is long enough */ fd_note(&source_p->connection->fd, "Nick: %s", source_p->name); }
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; }
/* ** m_kill ** parv[0] = sender prefix ** parv[1] = kill victim(s) - comma separated list ** parv[2] = kill path */ DLLFUNC int m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; anUser *auser; char inpath[HOSTLEN * 2 + USERLEN + 5]; char *oinpath = get_client_name(cptr, FALSE); char *user, *path, *killer, *nick, *p, *s; int chasing = 0, kcount = 0; if (parc < 2 || *parv[1] == '\0') { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KILL"); return 0; } user = parv[1]; path = parv[2]; /* Either defined or NULL (parc >= 2!!) */ strlcpy(inpath, oinpath, sizeof inpath); #ifndef ROXnet if (IsServer(cptr) && (s = (char *)index(inpath, '.')) != NULL) *s = '\0'; /* Truncate at first "." */ #endif if (!IsPrivileged(cptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (IsAnOper(cptr)) { if (BadPtr(path)) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KILL"); return 0; } if (strlen(path) > (size_t)TOPICLEN) path[TOPICLEN] = '\0'; } if (MyClient(sptr)) user = (char *)canonize(user); for (p = NULL, nick = strtoken(&p, user, ","); nick; nick = strtoken(&p, NULL, ",")) { chasing = 0; if (!(acptr = find_client(nick, NULL))) { /* ** If the user has recently changed nick, we automaticly ** rewrite the KILL for this new nickname--this keeps ** servers in synch when nick change and kill collide */ if (!(acptr = get_history(nick, (long)KILLCHASETIMELIMIT))) { sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick); continue; } sendto_one(sptr, ":%s %s %s :*** KILL changed from %s to %s", me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", parv[0], nick, acptr->name); chasing = 1; } if ((!MyConnect(acptr) && MyClient(cptr) && !OPCanGKill(cptr)) || (MyConnect(acptr) && MyClient(cptr) && !OPCanLKill(cptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); continue; } if (IsServer(acptr) || IsMe(acptr)) { sendto_one(sptr, err_str(ERR_CANTKILLSERVER), me.name, parv[0]); continue; } if (!IsPerson(acptr)) { /* Nick exists but user is not registered yet: IOTW "doesn't exist". -- Syzop */ sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick); continue; } if (IsServices(acptr) && !(IsNetAdmin(sptr) || IsULine(sptr))) { sendto_one(sptr, err_str(ERR_KILLDENY), me.name, parv[0], parv[1]); return 0; } /* From here on, the kill is probably going to be successful. */ kcount++; if (!IsServer(sptr) && (kcount > MAXKILLS)) { sendto_one(sptr, ":%s %s %s :*** Too many targets, kill list was truncated. Maximum is %d.", me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", parv[0], MAXKILLS); break; } if (!IsServer(cptr)) { /* ** The kill originates from this server, initialize path. ** (In which case the 'path' may contain user suplied ** explanation ...or some nasty comment, sigh... >;-) ** ** ...!operhost!oper ** ...!operhost!oper (comment) */ strlcpy(inpath, GetHost(cptr), sizeof inpath); if (kcount < 2) { /* Only check the path the first time around, or it gets appended to itself. */ if (!BadPtr(path)) { (void)ircsprintf(buf, "%s%s (%s)", cptr->name, IsOper(sptr) ? "" : "(L)", path); path = buf; } else path = cptr->name; } } else if (BadPtr(path)) path = "*no-path*"; /* Bogus server sending??? */ /* ** Notify all *local* opers about the KILL (this includes the one ** originating the kill, if from this server--the special numeric ** reply message is not generated anymore). ** ** Note: "acptr->name" is used instead of "user" because we may ** have changed the target because of the nickname change. */ auser = acptr->user; sendto_snomask_normal(SNO_KILLS, "*** Notice -- Received KILL message for %s!%s@%s from %s Path: %s!%s", acptr->name, auser->username, IsHidden(acptr) ? auser->virthost : auser->realhost, parv[0], inpath, path); #if defined(USE_SYSLOG) && defined(SYSLOG_KILL) if (IsOper(sptr)) syslog(LOG_DEBUG, "KILL From %s For %s Path %s!%s", parv[0], acptr->name, inpath, path); #endif /* * By otherguy */ ircd_log (LOG_KILL, "KILL (%s) by %s(%s!%s)", make_nick_user_host (acptr->name, acptr->user->username, GetHost(acptr)), parv[0], inpath, path); /* ** And pass on the message to other servers. Note, that if KILL ** was changed, the message has to be sent to all links, also ** back. ** Suicide kills are NOT passed on --SRB */ if (!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr)) { sendto_serv_butone(cptr, ":%s KILL %s :%s!%s", parv[0], acptr->name, inpath, path); if (chasing && IsServer(cptr)) sendto_one(cptr, ":%s KILL %s :%s!%s", me.name, acptr->name, inpath, path); acptr->flags |= FLAGS_KILLED; } /* ** Tell the victim she/he has been zapped, but *only* if ** the victim is on current server--no sense in sending the ** notification chasing the above kill, it won't get far ** anyway (as this user don't exist there any more either) */ if (MyConnect(acptr)) sendto_prefix_one(acptr, sptr, ":%s KILL %s :%s!%s", parv[0], acptr->name, inpath, path); /* ** Set FLAGS_KILLED. This prevents exit_one_client from sending ** the unnecessary QUIT for this. (This flag should never be ** set in any other place) */ if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr)) (void)ircsprintf(buf2, "[%s] Local kill by %s (%s)", me.name, sptr->name, BadPtr(parv[2]) ? sptr->name : parv[2]); else { if ((killer = index(path, ' '))) { while ((killer >= path) && *killer && *killer != '!') killer--; if (!*killer) killer = path; else killer++; } else killer = path; (void)ircsprintf(buf2, "Killed (%s)", killer); } if (MyClient(sptr)) RunHook3(HOOKTYPE_LOCAL_KILL, sptr, acptr, parv[2]); if (exit_client(cptr, acptr, sptr, buf2) == FLUSH_BUFFER) return FLUSH_BUFFER; } return 0; }
/* * Note: At least at protocol level ERROR has only one parameter, * although this is called internally from other functions * --msa * * parv[0] = sender prefix * parv[*] = parameters */ void m_error(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { if (MyClient(source_p)) exit_client(client_p, source_p, source_p, "ERROR"); }
/* * 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 client_p * - 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_flags(int p_or_n, char *command, struct Client *client_p, struct Client *source_p, struct Channel *chptr, int flags, char *text) { struct Channel *vchan = NULL; char *chname = NULL; int type; char c; if (flags & MODE_VOICE) { type = ONLY_CHANOPS_HALFOPS_VOICED; c = '+'; } else if (flags & MODE_HALFOP) { type = ONLY_CHANOPS_HALFOPS; c = '%'; } else { type = ONLY_CHANOPS; c = '@'; } chname = RootChan(chptr)->chname; #ifdef VCHANS if (HasVchans(chptr)) vchan = map_vchan(chptr, source_p); #endif if (!vchan) vchan = chptr; if (NoColorChannel(vchan)) /*strip_color(text);*/ text = strip_color(text, 0); if (MyClient(source_p)) { /* idletime shouldnt be reset by notice --fl */ if ((p_or_n != NOTICE) && source_p->user) source_p->user->last = CurrentTime; sendto_channel_local_butone(source_p, type, vchan, ":%s!%s@%s %s %c%s :%s", source_p->name, source_p->username, source_p->host, command, c, chname, text); } else { /* * another good catch, lee. we never would echo to remote clients anyway, * so use slightly less intensive sendto_channel_local() */ sendto_channel_local(type, vchan, ":%s!%s@%s %s %c%s :%s", source_p->name, source_p->username, source_p->host, command, c, chname, text); } if (chptr->chname[0] == '&') return; sendto_channel_remote(source_p, client_p, type, CAP_CHW, CAP_UID, vchan, ":%s %s %c%s :%s", source_p->name, command, c, vchan->chname, text); sendto_channel_remote(source_p, client_p, type, CAP_CHW|CAP_UID, NOCAPS, vchan, ":%s %s %c%s :%s", ID(source_p), command, c, vchan->chname, text); /* non CAP_CHW servers? */ }
/* * do_svssno() * parv[0] - sender * parv[1] - username to change snomask for * parv[2] - snomasks to change * show_change determines whether to show the change to the user */ int do_svssno(aClient *cptr, aClient *sptr, int parc, char *parv[], int show_change) { char *p; aClient *acptr; int what = MODE_ADD, i; if (!IsULine(sptr)) return 0; if (parc < 2) return 0; if (parv[1][0] == '#') return 0; if (!(acptr = find_person(parv[1], NULL))) return 0; if (hunt_server_token(cptr, sptr, show_change ? MSG_SVS2SNO : MSG_SVSSNO, show_change ? TOK_SVS2SNO : TOK_SVSSNO, "%s %s", 1, parc, parv) != HUNTED_ISME) { return 0; } if (MyClient(acptr)) { if (parc == 2) acptr->user->snomask = 0; else { for (p = parv[2]; p && *p; p++) { switch (*p) { case '+': what = MODE_ADD; break; case '-': what = MODE_DEL; break; default: for (i = 0; i <= Snomask_highest; i++) { if (!Snomask_Table[i].flag) continue; if (*p == Snomask_Table[i].flag) { if (what == MODE_ADD) acptr->user->snomask |= Snomask_Table[i].mode; else acptr->user->snomask &= ~Snomask_Table[i].mode; } } } } } } if (show_change) sendto_one(acptr, rpl_str(RPL_SNOMASK), me.name, acptr->name, get_sno_str(acptr)); return 0; }
/* * msg_client * * 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 source (struct Client *) * - pointer to target_p target (struct Client *) * - pointer to text * output - NONE * side effects - message given channel either chanop or voice */ static void msg_client(int p_or_n, char *command, struct Client *source_p, struct Client *target_p, char *text) { if (MyClient(source_p)) { /* reset idle time for message only if its not to self * and its not a notice */ if ((p_or_n != NOTICE) && (source_p != target_p) && source_p->user) source_p->user->last = CurrentTime; if (IsSetSSLaccept(target_p)) { #ifdef HAVE_LIBCRYPTO int fd = source_p->localClient->fd; fde_t *F = (fd > -1)? &fd_table[fd] : NULL; if (F && !F->ssl) { #endif sendto_one(source_p, form_str(source_p,ERR_SSLACCEPTONLY), me.name, source_p->name, target_p->name); return; #ifdef HAVE_LIBCRYPTO } #endif } } if (MyConnect(source_p) && (p_or_n != NOTICE) && target_p->user && target_p->user->away) sendto_one(source_p, form_str(source_p,RPL_AWAY), me.name, source_p->name, target_p->name, target_p->user->away); if (MyClient(target_p)) { if (IsSetRegAccept(target_p) && !(source_p->svsflags & FLAGS_SVS_IDENT)) { if (p_or_n != NOTICE) sendto_one(source_p, form_str(source_p,ERR_REGACCEPTONLY), me.name, source_p->name, target_p->name); return; } if (ConfigFileEntry.spam_wait && (p_or_n != NOTICE) && ((target_p->localClient->last_join_time + ConfigFileEntry.spam_wait > CurrentTime) || (target_p->localClient->last_leave_time + ConfigFileEntry.spam_wait > CurrentTime))) { sendto_anywhere(source_p, target_p, "NOTICE %s :*** I'm joining/leaving a chan, please try again in a few seconds.", source_p->name); return; } if (!IsServer(source_p) && IsSetCallerId(target_p)) { /* Here is the anti-flood bot/spambot code -db */ if (accept_message(source_p, target_p) || (source_p == target_p) || find_z_conf((char *)source_p->user->server)) { sendto_one(target_p, ":%s!%s@%s %s %s :%s", source_p->name, source_p->username, source_p->host, command, target_p->name, translate(target_p, text)); } else { /* check for accept, flag recipient incoming message */ if (p_or_n != NOTICE) sendto_anywhere(source_p, target_p, "NOTICE %s :*** I'm in +g mode (server side ignore).", source_p->name); if ((target_p->localClient->last_caller_id_time + ConfigFileEntry.caller_id_wait) < CurrentTime) { if (p_or_n != NOTICE) sendto_anywhere(source_p, target_p, "NOTICE %s :*** I've been informed you messaged me.", source_p->name); sendto_one(target_p, ":%s NOTICE %s :*** Client %s [%s@%s] is messaging you and you are +g", me.name, target_p->name, source_p->name, source_p->username, source_p->host); target_p->localClient->last_caller_id_time = CurrentTime; } /* Only so opers can watch for floods */ (void)flood_attack_client(p_or_n, source_p, target_p); } } else { /* If the client is remote, we dont perform a special check for * flooding.. as we wouldnt block their message anyway.. this means * we dont give warnings.. we then check if theyre opered * (to avoid flood warnings), lastly if theyre our client * and flooding -- fl */ if (!MyClient(source_p) || IsOper(source_p) || (MyClient(source_p) && !flood_attack_client(p_or_n, source_p, target_p))) sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name, translate(target_p, text)); } } else /* The target is a remote user.. same things apply -- fl */ if (!MyClient(source_p) || IsOper(source_p) || (MyClient(source_p) && !flood_attack_client(p_or_n, source_p, target_p))) sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name, text); return; }
/* * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce * the need for complicated requests like WHOIS. It returns user/host * information only (no spurious AWAY labels or channels). */ static void m_userhost(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p; char buf[IRCD_BUFSIZE]; char response[NICKLEN * 2 + USERLEN + HOSTLEN + 30]; char *t; int i, n; /* loop counter */ int cur_len; int rl; cur_len = ircsprintf(buf, form_str(RPL_USERHOST), me.name, parv[0], ""); t = buf + cur_len; for(i = 0; i < 5; i++) { if(parv[i + 1] == NULL) break; if((target_p = find_person(client_p, parv[i + 1])) != NULL) { /* * Show real IP for USERHOST on yourself. * This is needed for things like mIRC, which do a server-based * lookup (USERHOST) to figure out what the clients' local IP * is. Useful for things like NAT, and dynamic dial-up users. */ /* * If a lazyleaf relayed us this request, we don't know * the clients real IP. * So, if you're on a lazyleaf, and you send a userhost * including your nick and the nick of someone not known to * the leaf, you'll get your spoofed IP. tough. */ if(MyClient(target_p) && (target_p == source_p)) { rl = ircsprintf(response, "%s%s=%c%s@%s ", target_p->name, IsOper(target_p) ? "*" : "", (target_p->away) ? '-' : '+', target_p->username, target_p->sockhost); } else { rl = ircsprintf(response, "%s%s=%c%s@%s ", target_p->name, IsOper(target_p) ? "*" : "", (target_p->away) ? '-' : '+', target_p->username, target_p->host); } if((rl + cur_len) < (IRCD_BUFSIZE - 10)) { ircsprintf(t, "%s", response); t += rl; cur_len += rl; } else break; } else if(!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL)) { t = buf; for(n = 0; n < 5; n++) { if(parv[n + 1]) { rl = ircsprintf(t, "%s ", parv[n + 1]); t += rl; } else break; } /* Relay upstream, and let hub reply */ sendto_one(uplink, ":%s USERHOST %s", parv[0], buf); return; } } sendto_one(source_p, "%s", buf); }
/* ** m_pong ** parv[0] = sender prefix ** parv[1] = origin ** parv[2] = destination */ int m_pong(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *acptr = NULL; char *origin, *destination; if (parc < 2 || *parv[1] == '\0') { sendto_one(sptr, form_str(ERR_NOORIGIN), me.name, parv[0]); return 0; } origin = parv[1]; destination = parv[2]; #ifdef HLC /* for HLC --fabulous */ if ((IsServer(cptr)) && (parv[2]) && (IsDigit(*parv[2]))) { sentping = 0; receivedat = atoi(parv[2]); } #endif /* Now attempt to route the PONG, comstud pointed out routable PING * is used for SPING. routable PING should also probably be left in * -Dianora * That being the case, we will route, but only for registered clients (a * case can be made to allow them only from servers). -Shadowfax */ if (!EmptyString(destination) && irccmp(destination, me.name) != 0 && IsRegistered(sptr)) { if ((acptr = find_client(destination, NULL)) || (acptr = find_server(destination))) sendto_one(acptr,":%s PONG %s %s", parv[0], origin, destination); else { sendto_one(sptr, form_str(ERR_NOSUCHSERVER), me.name, parv[0], destination); return 0; } } else { if (MyConnect(sptr)) { sptr->flags &= ~FLAGS_PINGSENT; #ifdef NEED_SPLITCODE #ifdef SPLIT_PONG if (IsServer(sptr)) got_server_pong = 1; #endif #endif if(MyClient(sptr) && cptr->user) check_idle_actions(cptr); } } return 0; }
static int me_svslogin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p, *exist_p; char nick[NICKLEN+1], login[NICKLEN+1]; char user[USERLEN+1], host[HOSTLEN+1]; int valid = 0; if(!(source_p->flags & FLAGS_SERVICE)) return 0; if((target_p = find_client(parv[1])) == NULL) return 0; if(!MyClient(target_p) && !IsUnknown(target_p)) return 0; if(clean_nick(parv[2])) { rb_strlcpy(nick, parv[2], NICKLEN + 1); valid |= NICK_VALID; } else if(*target_p->name) rb_strlcpy(nick, target_p->name, NICKLEN + 1); else strcpy(nick, "*"); if(clean_username(parv[3])) { rb_strlcpy(user, parv[3], USERLEN + 1); valid |= USER_VALID; } else rb_strlcpy(user, target_p->username, USERLEN + 1); if(clean_host(parv[4])) { rb_strlcpy(host, parv[4], HOSTLEN + 1); valid |= HOST_VALID; } else rb_strlcpy(host, target_p->host, HOSTLEN + 1); if(*parv[5] == '*') { if(target_p->user) rb_strlcpy(login, target_p->user->suser, NICKLEN + 1); else login[0] = '\0'; } else if(!strcmp(parv[5], "0")) login[0] = '\0'; else rb_strlcpy(login, parv[5], NICKLEN + 1); /* Login (mostly) follows nick rules. */ if(*login && !clean_nick(login)) return 0; if((exist_p = find_person(nick)) && target_p != exist_p) { char buf[BUFSIZE]; if(MyClient(exist_p)) sendto_one(exist_p, ":%s KILL %s :(Nickname regained by services)", me.name, exist_p->name); exist_p->flags |= FLAGS_KILLED; kill_client_serv_butone(NULL, exist_p, "%s (Nickname regained by services)", me.name); rb_snprintf(buf, sizeof(buf), "Killed (%s (Nickname regained by services))", me.name); exit_client(NULL, exist_p, &me, buf); } else if((exist_p = find_client(nick)) && IsUnknown(exist_p) && exist_p != target_p) { exit_client(NULL, exist_p, &me, "Overridden"); } if(*login) { /* Strip leading digits, unless it's purely numeric. */ const char *p = login; while(IsDigit(*p)) p++; if(!*p) p = login; sendto_one(target_p, form_str(RPL_LOGGEDIN), me.name, EmptyString(target_p->name) ? "*" : target_p->name, nick, user, host, p, p); } else sendto_one(target_p, form_str(RPL_LOGGEDOUT), me.name, EmptyString(target_p->name) ? "*" : target_p->name, nick, user, host); if(IsUnknown(target_p)) { struct User *user_p = make_user(target_p); if(valid & NICK_VALID) strcpy(target_p->preClient->spoofnick, nick); if(valid & USER_VALID) strcpy(target_p->preClient->spoofuser, user); if(valid & HOST_VALID) strcpy(target_p->preClient->spoofhost, host); rb_strlcpy(user_p->suser, login, NICKLEN + 1); } else { char note[NICKLEN + 10]; send_signon(NULL, target_p, nick, user, host, rb_current_time(), login); rb_snprintf(note, NICKLEN + 10, "Nick: %s", target_p->name); rb_note(target_p->localClient->F, note); } return 0; }
/* * parse a buffer. * * NOTE: parse() should not be called recusively by any other functions! */ int parse(aClient *cptr, char *pbuffer, char *bufend) { aClient *from = cptr; char *ch; char *s; size_t i; char* numeric = 0; unsigned int paramcount; struct Message *mptr; Debug((DEBUG_DEBUG, "Parsing %s: %s", get_client_name(cptr, TRUE), pbuffer)); if (IsDead(cptr)) return -1; s = sender; *s = '\0'; for (ch = pbuffer; *ch == ' '; ch++) /* skip spaces */ /* null statement */ ; para[0] = from->name; if (*ch == ':') { ch++; /* ** Copy the prefix to 'sender' assuming it terminates ** with SPACE (or NULL, which is an error, though). */ for (i = 0; *ch && *ch != ' '; i++ ) { if (i < (sizeof(sender)-1)) *s++ = *ch; /* leave room for NULL */ ch++; } *s = '\0'; i = 0; /* ** Actually, only messages coming from servers can have ** the prefix--prefix silently ignored, if coming from ** a user client... ** ** ...sigh, the current release "v2.2PL1" generates also ** null prefixes, at least to NOTIFY messages (e.g. it ** puts "sptr->nickname" as prefix from server structures ** where it's null--the following will handle this case ** as "no prefix" at all --msa (": NOTICE nick ...") */ if (*sender && IsServer(cptr)) { from = find_client(sender, (aClient *) NULL); if (!from || !match(from->name, sender)) from = find_server(sender); para[0] = sender; /* Hmm! If the client corresponding to the * prefix is not found--what is the correct * action??? Now, I will ignore the message * (old IRC just let it through as if the * prefix just wasn't there...) --msa */ if (!from) { sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Unknown prefix (%s) from (%s)", sender, cptr->name); Debug((DEBUG_ERROR, "Unknown prefix (%s)(%s) from (%s)", sender, pbuffer, cptr->name)); ServerStats->is_unpf++; remove_unknown(cptr, sender, pbuffer); return -1; } if (from->from != cptr) { ServerStats->is_wrdi++; Debug((DEBUG_ERROR, "Message (%s) coming from (%s)", buffer, cptr->name)); sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Message coming from (%s), but %s is at %s", cptr->name, from->name, from->from->name); return cancel_clients(cptr, from, pbuffer); } } while (*ch == ' ') ch++; } if (*ch == '\0') { ServerStats->is_empt++; Debug((DEBUG_NOTICE, "Empty message from host %s:%s", cptr->name, from->name)); if (IsServer(cptr)) sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Empty message from %s:%s", cptr->name, from->name); return(-1); } /* ** Extract the command code from the packet. Point s to the end ** of the command code and calculate the length using pointer ** arithmetic. Note: only need length for numerics and *all* ** numerics must have parameters and thus a space after the command ** code. -avalon * * ummm???? - Dianora */ if( *(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */ IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2)) ) { mptr = (struct Message *)NULL; numeric = ch; paramcount = MAXPARA; ServerStats->is_num++; s = ch + 3; /* I know this is ' ' from above if */ *s++ = '\0'; /* blow away the ' ', and point s to next part */ } else { s = strchr(ch, ' '); /* moved from above,now need it here */ if (s) *s++ = '\0'; mptr = tree_parse(ch); if (!mptr || !mptr->cmd) { /* * Note: Give error message *only* to recognized * persons. It's a nightmare situation to have * two programs sending "Unknown command"'s or * equivalent to each other at full blast.... * If it has got to person state, it at least * seems to be well behaving. Perhaps this message * should never be generated, though... --msa * Hm, when is the buffer empty -- if a command * code has been found ?? -Armin * * Same thing goes for remote commands. If their local * server accepted it, then we should not be sending * a warning message. */ if (pbuffer[0] != '\0') { if (IsPerson(from) && MyClient(from)) sendto_one(from, ":%s %d %s %s :Unknown command", me.name, ERR_UNKNOWNCOMMAND, from->name, ch); Debug((DEBUG_ERROR,"Unknown (%s) from %s", ch, get_client_name(cptr, TRUE))); } ServerStats->is_unco++; return(-1); } paramcount = mptr->parameters; i = bufend - ((s) ? s : ch); mptr->bytes += i; /* Allow only 1 msg per 2 seconds * (on average) to prevent dumping. * to keep the response rate up, * bursts of up to 5 msgs are allowed * -SRB * Opers can send 1 msg per second, burst of ~20 * -Taner */ if ((mptr->flags & 1) && !(IsServer(cptr))) { #ifdef NO_OPER_FLOOD #ifndef TRUE_NO_OPER_FLOOD /* note: both have to be defined for the real no-flood */ if (NoFloodProtection(cptr)) /* "randomly" (weighted) increase the since */ cptr->since += (cptr->receiveM % 5) ? 1 : 0; else #else if (!NoFloodProtection(cptr)) #endif #endif cptr->since += (2 + i / 120); } } /* ** Must the following loop really be so devious? On ** surface it splits the message to parameters from ** blank spaces. But, if paramcount has been reached, ** the rest of the message goes into this last parameter ** (about same effect as ":" has...) --msa */ /* Note initially true: s==NULL || *(s-1) == '\0' !! */ /* ZZZ hmmmmmmmm whats this then? */ #if 0 if (me.user) para[0] = sender; #endif i = 1; if (s) { if (paramcount > MAXPARA) paramcount = MAXPARA; for (;;) { while(*s == ' ') /* tabs are not considered space */ *s++ = '\0'; if(!*s) break; if (*s == ':') { /* ** The rest is single parameter--can ** include blanks also. */ para[i++] = s + 1; break; } else { para[i++] = s; if (i > paramcount) { break; } /* scan for end of string, either ' ' or '\0' */ while (IsNonEOS(*s)) s++; } } } para[i] = NULL; if (mptr == (struct Message *)NULL) return (do_numeric(numeric, cptr, from, i, para)); mptr->count++; /* patch to avoid server flooding from unregistered connects */ /* check allow_unregistered_use flag I've set up instead of function comparing *yech* - Dianora */ if (!IsRegistered(cptr) && !mptr->allow_unregistered_use ) { /* if its from a possible server connection * ignore it.. more than likely its a header thats sneaked through */ if(IsHandshake(cptr) || IsConnecting(cptr) || IsServer(cptr)) return -1; sendto_one(from, ":%s %d %s %s :Register first.", me.name, ERR_NOTREGISTERED, BadPtr(from->name) ? "*" : from->name, ch); return -1; } /* Silently drop the messages that can't be used in the honeypot */ if (IsHoneypot(cptr) && !mptr->allow_honeypot) return -1; /* Again, instead of function address comparing, see if * this function resets idle time as given from mptr * if IDLE_FROM_MSG is undefined, the sense of the flag is reversed. * i.e. if the flag is 0, then reset idle time, otherwise don't reset it. * * - Dianora */ if (IsRegisteredUser(from) && mptr->reset_idle) { /* If a local registered user, propagate anti-idle updates as needed */ if (MyClient(from) && from->user && ((from->user->last_sent + MAX_IDLE_DESYNC) < CurrentTime)) { #if 0 /* Note the misnamed message, this indicates that they are NOT idle */ #ifdef HAVE_LONG_LONG sendto_serv_butone(NULL, ":%s IDLE %s %.1lld", cptr->name, from->name, (long long)CurrentTime); #else sendto_serv_butone(NULL, ":%s IDLE %s %.1ld", cptr->name, from->name, (long)CurrentTime); #endif #endif from->user->last_sent = CurrentTime; } from->user->last = CurrentTime; } /* don't allow other commands while a list is blocked. since we treat them specially with respect to sendq. */ if ((IsDoingList(cptr)) && (*mptr->func != m_list)) return -1; return (*mptr->func)(cptr, from, i, para); }
/* * m_topic * parv[1] = channel name * parv[2] = new topic, if setting topic */ static int m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; char *p = NULL; const char *name; int operspy = 0; if((p = strchr(parv[1], ','))) *p = '\0'; name = parv[1]; if(IsOperSpy(source_p) && parv[1][0] == '!') { name++; operspy = 1; if(EmptyString(name)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "TOPIC"); return 0; } } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); chptr = find_channel(name); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } /* setting topic */ if(parc > 2) { msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(MyClient(source_p) && !is_chanop_voiced(msptr) && !IsOper(source_p) && !add_channel_target(source_p, chptr)) { sendto_one(source_p, form_str(ERR_TARGCHANGE), me.name, source_p->name, chptr->chname); return 0; } if(((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || get_channel_access(source_p, chptr, msptr, MODE_ADD, NULL) >= CHFL_CHANOP) && (!MyClient(source_p) || can_send(chptr, source_p, msptr))) { char topic[TOPICLEN + 1]; char topic_info[USERHOST_REPLYLEN]; rb_strlcpy(topic, parv[2], sizeof(topic)); rb_sprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); if (ConfigChannel.strip_topic_colors) strip_colour(topic); set_channel_topic(chptr, topic, topic_info, rb_current_time()); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", use_id(source_p), chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), get_id(&me, source_p), get_id(source_p, source_p), name); } else if(MyClient(source_p)) { if(operspy) report_operspy(source_p, "TOPIC", chptr->chname); if(!IsMember(source_p, chptr) && SecretChannel(chptr) && !operspy) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, name); else { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, (unsigned long)chptr->topic_time); } } 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) * 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) { int bpos = 0; char *p; for (i = 2; i < (parc - 1); i++) { buffer[bpos++] = ' '; for(p = parv[i]; *p; p++) buffer[bpos++] = *p; } buffer[bpos++] = ' '; buffer[bpos++] = ':'; for(p = parv[parc - 1]; *p; p++) buffer[bpos++] = *p; buffer[bpos] = '\0'; } for (; (nick = strtoken(&p, parv[1], ",")); parv[1] = NULL) { if ((acptr = find_client(nick, (aClient *) NULL))) { int dohide; /* * 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 */ #ifdef HIDE_NUMERIC_SOURCE dohide = MyClient(acptr) ? 1 : 0; #else dohide = 0; #endif if (!IsMe(acptr) && IsPerson(acptr)) sendto_prefix_one(acptr, dohide ? &me : sptr, ":%s %d %s%s", dohide ? me.name : 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 ((chptr = find_channel(nick, (aChannel *) NULL))) { int dohide; #ifdef HIDE_NUMERIC_SOURCE dohide = 1; #else dohide = 0; #endif sendto_channel_butserv(chptr, dohide ? &me : sptr, ":%s %d %s%s", dohide ? me.name : parv[0], numeric, chptr->chname, buffer); sendto_channel_remote_butone(cptr, sptr, chptr, parv[0], numeric, chptr->chname, buffer); } } return 0; }
static void serv_info(aClient *cptr, char *name) { static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :%u %u %s"; long sendK, receiveK, uptime; aClient *acptr; DLink *lp; int i = 0; sendK = receiveK = 0; for (lp = server_list; lp; lp = lp->next) { acptr = lp->value.cptr; #ifdef HIDEULINEDSERVS if (IsULine(acptr) && !IsAnOper(cptr)) continue; #endif sendK += acptr->sendK; receiveK += acptr->receiveK; sendto_one(cptr, Lformat, me.name, RPL_STATSLINKINFO, name, ( (MyClient(cptr) && IsAdmin(cptr)) ? get_client_name(acptr, FALSE) : get_client_name(acptr, HIDEME) ), (int) SBufLength(&acptr->sendQ), (int) acptr->sendM, (int) acptr->sendK, (int) acptr->receiveM, (int) acptr->receiveK, timeofday - acptr->firsttime, timeofday - acptr->since, IsServer(acptr) ? (DoesTS(acptr) ? "TS" : "NoTS") : "-"); if(RC4EncLink(acptr)) sendto_one(cptr, ":%s %d %s : - RC4 encrypted", me.name, RPL_STATSDEBUG, name); if(ZipOut(acptr)) { unsigned long ib, ob; double rat; zip_out_get_stats(acptr->serv->zip_out, &ib, &ob, &rat); if(ib) { sendto_one(cptr, ":%s %d %s : - [O] Zip inbytes %lu, " "outbytes %lu (%3.2f%%)", me.name, RPL_STATSDEBUG, name, ib, ob, rat); } } if(ZipIn(acptr)) { unsigned long ib, ob; double rat; zip_in_get_stats(acptr->serv->zip_in, &ib, &ob, &rat); if(ob) { sendto_one(cptr, ":%s %d %s : - [I] Zip inbytes %lu, " "outbytes %lu (%3.2f%%)", me.name, RPL_STATSDEBUG, name, ib, ob, rat); } } i++; } sendto_one(cptr, ":%s %d %s :%u total server%s", me.name, RPL_STATSDEBUG, name, i, (i == 1) ? "" : "s"); sendto_one(cptr, ":%s %d %s :Sent total : %7.2f %s", me.name, RPL_STATSDEBUG, name, _GMKv(sendK), _GMKs(sendK)); sendto_one(cptr, ":%s %d %s :Recv total : %7.2f %s", me.name, RPL_STATSDEBUG, name, _GMKv(receiveK), _GMKs(receiveK)); uptime = (timeofday - me.since); sendto_one(cptr, ":%s %d %s :Server send: %7.2f %s (%4.1f K/s total," " %4.1f K/s current)", me.name, RPL_STATSDEBUG, name, _GMKv(me.sendK), _GMKs(me.sendK), (float) ((float) me.sendK / (float) uptime), curSendK); sendto_one(cptr, ":%s %d %s :Server recv: %7.2f %s (%4.1f K/s total," " %4.1f K/s current)", me.name, RPL_STATSDEBUG, name, _GMKv(me.receiveK), _GMKs(me.receiveK), (float) ((float) me.receiveK / (float) uptime), curRecvK); }
static int m_cmessage(int p_or_n, const char *command, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; struct Channel *chptr; struct membership *msptr; if(!IsFloodDone(source_p)) flood_endgrace(source_p); if((target_p = find_named_person(parv[1])) == NULL) { if(p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), parv[1]); return 0; } if((chptr = find_channel(parv[2])) == NULL) { if(p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[2]); return 0; } if((msptr = find_channel_membership(chptr, source_p)) == NULL) { if(p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), chptr->chname); return 0; } if(!is_chanop_voiced(msptr)) { if(p_or_n != NOTICE) sendto_one(source_p, form_str(ERR_VOICENEEDED), me.name, source_p->name, chptr->chname); return 0; } if(!IsMember(target_p, chptr)) { if(p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), target_p->name, chptr->chname); return 0; } if(MyClient(target_p) && (IsSetCallerId(target_p) || (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])) && !accept_message(source_p, target_p) && !IsOper(source_p)) { if (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0]) { if (p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_NONONREG, form_str(ERR_NONONREG), target_p->name); return 0; } if(p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_TARGUMODEG, form_str(ERR_TARGUMODEG), target_p->name); if((target_p->localClient->last_caller_id_time + ConfigFileEntry.caller_id_wait) < rb_current_time()) { if(p_or_n != NOTICE) sendto_one_numeric(source_p, RPL_TARGNOTIFY, form_str(RPL_TARGNOTIFY), target_p->name); sendto_one(target_p, form_str(RPL_UMODEGMSG), me.name, target_p->name, source_p->name, source_p->username, source_p->host); target_p->localClient->last_caller_id_time = rb_current_time(); } return 0; } if(p_or_n != NOTICE) source_p->localClient->last = rb_current_time(); sendto_anywhere(target_p, source_p, command, ":%s", parv[3]); return 0; }
int m_alias(aClient *cptr, aClient *sptr, int parc, char *parv[], char *cmd) { ConfigItem_alias *alias; aClient *acptr; int ret; if (!(alias = Find_alias(cmd))) { sendto_one(sptr, ":%s %d %s %s :Unknown command", me.name, ERR_UNKNOWNCOMMAND, parv[0], cmd); return 0; } /* If it isn't an ALIAS_COMMAND, we require a paramter ... We check ALIAS_COMMAND LATER */ if (alias->type != ALIAS_COMMAND && (parc < 2 || *parv[1] == '\0')) { sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]); return -1; } if (alias->type == ALIAS_SERVICES) { if (SERVICES_NAME && (acptr = find_person(alias->nick, NULL))) { if (alias->spamfilter && (ret = dospamfilter(sptr, parv[1], SPAMF_USERMSG, alias->nick, 0, NULL)) < 0) return ret; sendto_one(acptr, ":%s PRIVMSG %s@%s :%s", parv[0], alias->nick, SERVICES_NAME, parv[1]); } else sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name, parv[0], alias->nick); } else if (alias->type == ALIAS_STATS) { if (STATS_SERVER && (acptr = find_person(alias->nick, NULL))) { if (alias->spamfilter && (ret = dospamfilter(sptr, parv[1], SPAMF_USERMSG, alias->nick, 0, NULL)) < 0) return ret; sendto_one(acptr, ":%s PRIVMSG %s@%s :%s", parv[0], alias->nick, STATS_SERVER, parv[1]); } else sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name, parv[0], alias->nick); } else if (alias->type == ALIAS_NORMAL) { if ((acptr = find_person(alias->nick, NULL))) { if (alias->spamfilter && (ret = dospamfilter(sptr, parv[1], SPAMF_USERMSG, alias->nick, 0, NULL)) < 0) return ret; if (MyClient(acptr)) sendto_one(acptr, ":%s!%s@%s PRIVMSG %s :%s", parv[0], sptr->user->username, GetHost(sptr), alias->nick, parv[1]); else sendto_one(acptr, ":%s PRIVMSG %s :%s", parv[0], alias->nick, parv[1]); } else sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], alias->nick); } else if (alias->type == ALIAS_CHANNEL) { aChannel *chptr; if ((chptr = find_channel(alias->nick, NULL))) { if (!can_send(sptr, chptr, parv[1], 0)) { if (alias->spamfilter && (ret = dospamfilter(sptr, parv[1], SPAMF_CHANMSG, chptr->chname, 0, NULL)) < 0) return ret; sendto_channelprefix_butone(sptr, sptr, chptr, PREFIX_ALL, ":%s PRIVMSG %s :%s", parv[0], chptr->chname, parv[1]); return 0; } } sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND), me.name, parv[0], cmd, "You may not use this command at this time"); } else if (alias->type == ALIAS_COMMAND) { ConfigItem_alias_format *format; char *ptr = ""; if (!(parc < 2 || *parv[1] == '\0')) ptr = parv[1]; for (format = alias->format; format; format = (ConfigItem_alias_format *)format->next) { if (regexec(&format->expr, ptr, 0, NULL, 0) == 0) { /* Parse the parameters */ int i = 0, j = 0, k = 1; char output[1024], current[1024]; char nums[4]; bzero(current, sizeof current); bzero(output, sizeof output); while(format->parameters[i] && j < 500) { k = 0; if (format->parameters[i] == '%') { i++; if (format->parameters[i] == '%') output[j++] = '%'; else if (isdigit(format->parameters[i])) { for(; isdigit(format->parameters[i]) && k < 2; i++, k++) { nums[k] = format->parameters[i]; } nums[k] = 0; i--; if (format->parameters[i+1] == '-') { strrangetok(ptr, current, ' ', atoi(nums),0); i++; } else strrangetok(ptr, current, ' ', atoi(nums), atoi(nums)); if (!*current) continue; if (j + strlen(current)+1 >= 500) break; strlcat(output, current, sizeof output); j += strlen(current); } else if (format->parameters[i] == 'n' || format->parameters[i] == 'N') { strlcat(output, parv[0], sizeof output); j += strlen(parv[0]); } else { output[j++] = '%'; output[j++] = format->parameters[i]; } i++; continue; } output[j++] = format->parameters[i++]; } output[j] = 0; /* Now check to make sure we have something to send */ if (strlen(output) == 0) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, cmd); return -1; } if (format->type == ALIAS_SERVICES) { if (SERVICES_NAME && (acptr = find_person(format->nick, NULL))) { if (alias->spamfilter && (ret = dospamfilter(sptr, output, SPAMF_USERMSG, format->nick, 0, NULL)) < 0) return ret; sendto_one(acptr, ":%s PRIVMSG %s@%s :%s", parv[0], format->nick, SERVICES_NAME, output); } else sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name, parv[0], format->nick); } else if (format->type == ALIAS_STATS) { if (STATS_SERVER && (acptr = find_person(format->nick, NULL))) { if (alias->spamfilter && (ret = dospamfilter(sptr, output, SPAMF_USERMSG, format->nick, 0, NULL)) < 0) return ret; sendto_one(acptr, ":%s PRIVMSG %s@%s :%s", parv[0], format->nick, STATS_SERVER, output); } else sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name, parv[0], format->nick); } else if (format->type == ALIAS_NORMAL) { if ((acptr = find_person(format->nick, NULL))) { if (alias->spamfilter && (ret = dospamfilter(sptr, output, SPAMF_USERMSG, format->nick, 0, NULL)) < 0) return ret; if (MyClient(acptr)) sendto_one(acptr, ":%s!%s@%s PRIVMSG %s :%s", parv[0], sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost, format->nick, output); else sendto_one(acptr, ":%s PRIVMSG %s :%s", parv[0], format->nick, output); } else sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], format->nick); } else if (format->type == ALIAS_CHANNEL) { aChannel *chptr; if ((chptr = find_channel(format->nick, NULL))) { if (!can_send(sptr, chptr, output, 0)) { if (alias->spamfilter && (ret = dospamfilter(sptr, output, SPAMF_CHANMSG, chptr->chname, 0, NULL)) < 0) return ret; sendto_channelprefix_butone(sptr, sptr, chptr, PREFIX_ALL, ":%s PRIVMSG %s :%s", parv[0], chptr->chname, parv[1]); return 0; } } sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND), me.name, parv[0], cmd, "You may not use this command at this time"); } else if (format->type == ALIAS_REAL) { int ret; char mybuf[500]; snprintf(mybuf, sizeof(mybuf), "%s %s", format->nick, output); if (recursive_alias) { sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND), me.name, parv[0], cmd, "You may not use this command at this time -- recursion"); return -1; } recursive_alias = 1; ret = parse(sptr, mybuf, mybuf+strlen(mybuf)); recursive_alias = 0; return ret; } break; } } return 0; } return 0; }
/* m_knock * parv[0] = sender prefix * parv[1] = channel * * The KNOCK command has the following syntax: * :<sender> KNOCK <channel> * * If a user is not banned from the channel they can use the KNOCK * command to have the server NOTICE the channel operators notifying * they would like to join. Helpful if the channel is invite-only, the * key is forgotten, or the channel is full (INVITE can bypass each one * of these conditions. Concept by Dianora <*****@*****.**> and written by * <anonymous> */ static int m_knock(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; char *p, *name; if(MyClient(source_p) && ConfigChannel.use_knock == 0) { sendto_one(source_p, form_str(ERR_KNOCKDISABLED), me.name, source_p->name); return 0; } name = LOCAL_COPY(parv[1]); /* dont allow one knock to multiple chans */ if((p = strchr(name, ','))) *p = '\0'; if(!IsChannelName(name)) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if((chptr = find_channel(name)) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if(IsMember(source_p, chptr)) { if(MyClient(source_p)) sendto_one(source_p, form_str(ERR_KNOCKONCHAN), me.name, source_p->name, name); return 0; } if(!((chptr->mode.mode & MODE_INVITEONLY) || (*chptr->mode.key) || (chptr->mode.limit && dlink_list_length(&chptr->members) >= (unsigned long)chptr->mode.limit))) { sendto_one_numeric(source_p, ERR_CHANOPEN, form_str(ERR_CHANOPEN), name); return 0; } /* cant knock to a +p channel */ if(HiddenChannel(chptr)) { sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN, form_str(ERR_CANNOTSENDTOCHAN), name); return 0; } if(MyClient(source_p)) { /* don't allow a knock if the user is banned */ if(is_banned(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN) { sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN, form_str(ERR_CANNOTSENDTOCHAN), name); return 0; } /* local flood protection: * allow one knock per user per knock_delay * allow one knock per channel per knock_delay_channel */ if(!IsOper(source_p) && (source_p->localClient->last_knock + ConfigChannel.knock_delay) > CurrentTime) { sendto_one(source_p, form_str(ERR_TOOMANYKNOCK), me.name, source_p->name, name, "user"); return 0; } else if((chptr->last_knock + ConfigChannel.knock_delay_channel) > CurrentTime) { sendto_one(source_p, form_str(ERR_TOOMANYKNOCK), me.name, source_p->name, name, "channel"); return 0; } /* ok, we actually can send the knock, tell client */ source_p->localClient->last_knock = CurrentTime; sendto_one(source_p, form_str(RPL_KNOCKDLVR), me.name, source_p->name, name); } chptr->last_knock = CurrentTime; if(ConfigChannel.use_knock) sendto_channel_local(ONLY_CHANOPS, chptr, form_str(RPL_KNOCK), me.name, name, name, source_p->name, source_p->username, source_p->host); sendto_server(client_p, chptr, CAP_KNOCK|CAP_TS6, NOCAPS, ":%s KNOCK %s", use_id(source_p), name); sendto_server(client_p, chptr, CAP_KNOCK, CAP_TS6, ":%s KNOCK %s", source_p->name, name); return 0; }
/* * m_die - DIE command handler */ int m_die(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client* acptr; int i; if (!MyClient(sptr) || !IsAnOper(sptr)) { sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (!IsOperDie(sptr)) { sendto_one(sptr,":%s NOTICE %s :You have no D flag", me.name, parv[0]); return 0; } if (parc < 2) { sendto_one(sptr,":%s NOTICE %s :Need server name /die %s", me.name,sptr->name,me.name); return 0; } else { if (irccmp(parv[1], me.name)) { sendto_one(sptr,":%s NOTICE %s :Mismatch on /die %s", me.name,sptr->name,me.name); return 0; } } for (i = 0; i <= highest_fd; i++) { if (!(acptr = local[i])) continue; if (IsClient(acptr)) { if(IsAnOper(acptr)) sendto_one(acptr, ":%s NOTICE %s :Server Terminating. %s", me.name, acptr->name, get_client_name(sptr, HIDE_IP)); else sendto_one(acptr, ":%s NOTICE %s :Server Terminating. %s", me.name, acptr->name, get_client_name(sptr, MASK_IP)); } else if (IsServer(acptr)) sendto_one(acptr, ":%s ERROR :Terminated by %s", me.name, get_client_name(sptr, MASK_IP)); } flush_connections(0); irclog(L_NOTICE, "Server terminated by %s", get_client_name(sptr, HIDE_IP)); /* * this is a normal exit, tell the os it's ok */ exit(0); /* NOT REACHED */ return 0; }
/* * * parc number of arguments ('sender' counted as one!) * 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... */ static void do_numeric(int numeric, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; struct Channel *chptr; if(parc < 2 || !IsServer(source_p)) return; /* 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. */ if(parc > 1) { char *t = buffer; /* Current position within the buffer */ int i; int tl; /* current length of presently being built string in t */ for (i = 2; i < (parc - 1); i++) { tl = sprintf(t, " %s", parv[i]); t += tl; } sprintf(t, " :%s", parv[parc - 1]); } if((target_p = find_client(parv[1])) != NULL) { if(IsMe(target_p)) { /* * We shouldn't get numerics sent to us, * any numerics we do get indicate a bug somewhere.. */ /* ugh. this is here because of nick collisions. when two servers * relink, they burst each other their nicks, then perform collides. * if there is a nick collision, BOTH servers will kill their own * nicks, and BOTH will kill the other servers nick, which wont exist, * because it will have been already killed by the local server. * * unfortunately, as we cant guarantee other servers will do the * "right thing" on a nick collision, we have to keep both kills. * ergo we need to ignore ERR_NOSUCHNICK. --fl_ */ /* quick comment. This _was_ tried. i.e. assume the other servers * will do the "right thing" and kill a nick that is colliding. * unfortunately, it did not work. --Dianora */ /* note, now we send PING on server connect, we can * also get ERR_NOSUCHSERVER.. */ if(numeric != ERR_NOSUCHNICK && numeric != ERR_NOSUCHSERVER) sendto_realops_snomask(SNO_GENERAL, L_ADMIN, "*** %s(via %s) sent a %03d numeric to me: %s", source_p->name, client_p->name, numeric, buffer); return; } else if(target_p->from == client_p) { /* This message changed direction (nick collision?) * ignore it. */ return; } /* csircd will send out unknown umode flag for +a (admin), drop it here. */ if(numeric == ERR_UMODEUNKNOWNFLAG && MyClient(target_p)) return; /* Fake it for server hiding, if its our client */ sendto_one(target_p, ":%s %03d %s%s", get_id(source_p, target_p), numeric, get_id(target_p, target_p), buffer); return; } else if((chptr = find_channel(parv[1])) != NULL) sendto_channel_flags(client_p, ALL_MEMBERS, source_p, chptr, "%03d %s%s", numeric, chptr->chname, buffer); }