/* * m_kick - generic message handler * * parv[0] = sender prefix * parv[1] = channel * parv[2] = client to kick * parv[parc-1] = kick comment */ int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *who; struct Channel *chptr; struct Membership *member = 0; char *name, *comment; ClrFlag(sptr, FLAG_TS8); if (parc < 3 || *parv[1] == '\0') return need_more_params(sptr, "KICK"); name = parv[1]; /* simple checks */ if (!(chptr = get_channel(sptr, name, CGT_NO_CREATE))) return send_reply(sptr, ERR_NOSUCHCHANNEL, name); if (!is_chan_op(sptr, chptr) && !is_half_op(sptr, chptr)) return send_reply(sptr, ERR_CHANOPRIVSNEEDED, name); if (!(who = find_chasing(sptr, parv[2], 0))) return 0; /* find_chasing sends the reply for us */ /* Don't allow the channel service to be kicked */ /* * ASUKA_X: * Allow +X'ed users to kick +k'ed, but not U-lined services. * --Bigfoot */ if (IsChannelService(who) && IsService(cli_user(who)->server)) return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname, "a network service"); if (IsChannelService(who) && !IsXtraOp(sptr) && (who!=sptr)) return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname, "an IRC operator"); /* Don't allow halfops to kick chanops */ if (is_chan_op(who, chptr) && is_half_op(sptr, chptr) && !is_chan_op(sptr, chptr)) return send_reply(sptr, ERR_HALFCANTKICKOP, name); /* Prevent kicking opers from local channels -DM- */ if (IsLocalChannel(chptr->chname) && HasPriv(who, PRIV_DEOP_LCHAN)) return send_reply(sptr, ERR_ISOPERLCHAN, cli_name(who), chptr->chname); /* check if kicked user is actually on the channel */ if (!(member = find_member_link(chptr, who)) || IsZombie(member)) return send_reply(sptr, ERR_USERNOTINCHANNEL, cli_name(who), chptr->chname); /* We rely on ircd_snprintf to truncate the comment */ comment = EmptyString(parv[parc - 1]) ? parv[0] : parv[parc - 1]; if (!IsLocalChannel(name)) sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who, comment); sendcmdto_channel_butserv_butone((IsServer(sptr) ? &me : sptr), CMD_KICK, chptr, NULL, 0, "%H %C :%s", chptr, who, comment); make_zombie(member, who, cptr, sptr, chptr); return 0; }
/* * ms_svshost - SVSHOST command handler * parv[0] = sender prefix * parv[1] = remote server * parv[2] = client nick * parv[3] = vhost to spoof */ static void ms_svshost(struct Client* client_p, struct Client* source_p, int parc, char* parv[]) { char *flag; struct Client *victim; struct Channel *chptr, *top_chptr, *banchans[100]; static char comment[] = "Spoofing with vhost..."; static char urbanned[] = "You are banned"; char modebuf[MODEBUFLEN], parabuf[MODEBUFLEN]; int hide_or_not; dlink_node *ptr; int i, num = 0; if (ServerInfo.gateway && get_bridge_token(client_p)) return; if (hunt_server(client_p, source_p, ":%s SVSHOST %s %s :%s", 1, parc, parv) != HUNTED_ISME) return; if (!find_z_conf(parv[0])) return; victim = find_client(parv[2]); if (victim && !IsServer(victim) && MyConnect(victim)) { extern int introduce_client(struct Client *, struct Client *, struct User *, char *); sendto_server(NULL, victim, NULL, NOCAPS, NOCAPS, NOFLAGS, ":%s QUIT :%s", victim->name, comment); /* sendto_common_channels_local(victim, ":%s!%s@%s QUIT :%s", victim->name, victim->username, victim->host, comment);*/ /* ++current_serial; not needed i suppose */ if (victim->user->channel.head) for (ptr = victim->user->channel.head; ptr; ptr = ptr->next) { chptr = (struct Channel *)ptr->data; sendto_channel_local_butone(victim, ALL_MEMBERS, chptr, ":%s!%s@%s QUIT :%s", victim->name, victim->username, victim->host, comment); } strncpy(victim->host, parv[3], HOSTLEN)[HOSTLEN] = 0; sendto_one(victim, ":%s NOTICE %s :*** Notice -- Spoofing your host as %s", me.name, victim->name, victim->host); if (victim->user->channel.head) for (ptr = victim->user->channel.head; ptr; ptr = ptr->next) { chptr = (struct Channel *)ptr->data; #ifdef VCHANS top_chptr = RootChan(chptr); #else top_chptr = chptr; #endif if (is_banned(chptr, victim) & (CHFL_BAN|CHFL_DENY)) { sendto_one(victim, ":%s KICK %s %s :%s", me.name, top_chptr->chname, victim->name, urbanned); /*remove_user_from_channel(chptr, victim);*/ banchans[num++] = chptr; continue; } if (is_chan_op(chptr, victim)) flag = "+o"; #ifdef HALFOPS else if (is_half_op(chptr, victim)) flag = "+h"; #endif else if (is_voiced(chptr, victim)) flag = "+v"; else flag = ""; #ifdef REQUIRE_OANDV if (find_user_link(&chptr->chanops_voiced, victim)) flag = "+ov"; #endif sendto_channel_local_butone(victim, ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", victim->name, victim->username, victim->host, top_chptr->chname); #ifdef ANONOPS if (chptr->mode.mode & MODE_HIDEOPS) hide_or_not = ONLY_CHANOPS_HALFOPS; else #endif hide_or_not = ALL_MEMBERS; if (flag[0]) sendto_channel_local_butone(victim, hide_or_not, chptr, ":%s MODE %s %s %s %s", me.name, top_chptr->chname, flag, victim->name, flag[2]? victim->name : ""); } for (i=0; i < num; i++) remove_user_from_channel(banchans[i], victim); introduce_client(NULL, victim, victim->user, victim->name); victim->lazyLinkClientExists = 0; /* force introducing to LL servers below... */ if (victim->user->channel.head) for (ptr = victim->user->channel.head; ptr; ptr = ptr->next) { chptr = (struct Channel *)ptr->data; if (is_chan_op(chptr, victim)) flag = "@"; #ifdef HALFOPS else if (is_half_op(chptr, victim)) flag = "%"; #endif else if (is_voiced(chptr, victim)) flag = "+"; else flag = ""; #ifdef REQUIRE_OANDV if (find_user_link(&chptr->chanops_voiced, victim)) flag = "@+"; #endif channel_modes(chptr, victim, modebuf, parabuf); sendto_server(NULL, victim, chptr, NOCAPS, NOCAPS, LL_ICLIENT|LL_ICHAN, ":%s SJOIN %lu %s %s %s :%s%s", me.name, (unsigned long)chptr->channelts, chptr->chname, modebuf, parabuf, flag, victim->name); } } }
void checkClient(struct Client *sptr, struct Client *acptr) { struct Channel *chptr; struct Membership *lp; char outbuf[BUFSIZE]; char *privs; time_t nowr; /* Header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "user", acptr->cli_name); send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Nick:: %s (%s%s)", acptr->cli_name, NumNick(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (MyUser(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Signed on:: %s", myctime(acptr->cli_firsttime)); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Timestamp:: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " User/Hostmask:: %s@%s (%s)", acptr->cli_user->username, acptr->cli_user->host, ircd_ntoa((const char*) &(cli_ip(acptr)))); send_reply(sptr, RPL_DATASTR, outbuf); if (((feature_int(FEAT_HOST_HIDING_STYLE) == 1) ? HasHiddenHost(acptr) : IsHiddenHost(acptr)) || IsSetHost(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Real User/Host:: %s@%s", acptr->cli_user->realusername, acptr->cli_user->realhost); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Real Name:: %s%c", cli_info(acptr), COLOR_OFF); send_reply(sptr, RPL_DATASTR, outbuf); if (IsService(cli_user(acptr)->server)) { if (acptr) send_reply(sptr, RPL_DATASTR, " Status:: Network Service"); else if (IsAdmin(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: IRC Administrator (service)"); else if (IsAnOper(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator (service)"); else send_reply(sptr, RPL_DATASTR, " Status:: Client (service)"); } else if (IsAdmin(acptr)) { send_reply(sptr, RPL_DATASTR, " Status:: IRC Administrator"); } else if (IsAnOper(acptr)) { send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator"); } else { send_reply(sptr, RPL_DATASTR, " Status:: Client"); } if (MyUser(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Class:: %s", get_client_class(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } privs = client_print_privs(acptr); if (strlen(privs) > 1) client_check_privs(acptr, sptr); ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected to:: %s", cli_name(acptr->cli_user->server)); send_reply(sptr, RPL_DATASTR, outbuf); if (cli_version(acptr)) { if (strlen(cli_version(acptr)) > 0) { ircd_snprintf(0, outbuf, sizeof(outbuf), " CTCP Version:: %s", cli_version(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } if (cli_user(acptr) && !EmptyString(cli_user(acptr)->swhois)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " SWHOIS:: %s", cli_user(acptr)->swhois); send_reply(sptr, RPL_DATASTR, outbuf); } if (cli_webirc(acptr)) { if (strlen(cli_webirc(acptr)) > 0) { ircd_snprintf(0, outbuf, sizeof(outbuf), " WebIRC:: %s", cli_webirc(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } if (cli_sslclifp(acptr) && (strlen(cli_sslclifp(acptr)) > 0)) { ircd_snprintf(0, outbuf, sizeof(outbuf), "SSL Fingerprint:: %s", cli_sslclifp(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } if (MyUser(acptr)) get_eflags(sptr, acptr); /* +s (SERV_NOTICE) is not relayed to us from remote servers, * so we cannot tell if a remote client has that mode set. * And hacking it onto the end of the output of umode_str is EVIL BAD AND WRONG * (and breaks if the user is +r) so we won't do that either. */ if (strlen(umode_str(acptr)) < 1) strcpy(outbuf, " Umode(s):: <none>"); else ircd_snprintf(0, outbuf, sizeof(outbuf), " Umode(s):: +%s", umode_str(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (acptr->cli_user->joined == 0) send_reply(sptr, RPL_DATASTR, " Channel(s):: <none>"); else if (acptr->cli_user->joined > 50) { /* NB. As a sanity check, we DO NOT show the individual channels the * client is on if it is on > 50 channels. This is to prevent the ircd * barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine * an Oper would want to see every single channel 'x' client is on anyway if * they are on *that* many). */ ircd_snprintf(0, outbuf, sizeof(outbuf), " Channel(s):: - (total: %u)", acptr->cli_user->joined); send_reply(sptr, RPL_DATASTR, outbuf); } else { char chntext[BUFSIZE]; int len = strlen(" Channel(s):: "); int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name); *chntext = '\0'; strcpy(chntext, " Channel(s):: "); for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) { chptr = lp->channel; if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) { send_reply(sptr, RPL_DATASTR, chntext); *chntext = '\0'; strcpy(chntext, " Channel(s):: "); len = strlen(chntext); } if (IsDeaf(acptr)) *(chntext + len++) = '-'; if (is_chan_op(acptr, chptr)) *(chntext + len++) = '@'; if (is_half_op(acptr, chptr)) *(chntext + len++) = '%'; if (IsOper(sptr) && !ShowChannel(sptr,chptr)) *(chntext + len++) = '*'; if (IsZombie(lp)) *(chntext + len++) = '!'; if (len) *(chntext + len) = '\0'; strcpy(chntext + len, chptr->chname); len += strlen(chptr->chname); strcat(chntext + len, " "); len++; } if (chntext[0] != '\0') send_reply(sptr, RPL_DATASTR, chntext); } /* If client processing command ISN'T target (or a registered * Network Service), show idle time since the last time we * parsed something. */ if (MyUser(acptr) && !(IsService(acptr) == -1) && !(strCasediff(acptr->cli_name, sptr->cli_name) == 0)) { nowr = CurrentTime - acptr->cli_user->last; ircd_snprintf(0, outbuf, sizeof(outbuf), " Idle for:: %d days, %02ld:%02ld:%02ld", nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60); send_reply(sptr, RPL_DATASTR, outbuf); } /* Away message (if applicable) */ if (acptr->cli_user->away) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Away message:: %s", acptr->cli_user->away); send_reply(sptr, RPL_DATASTR, outbuf); } /* If local user.. */ if (MyUser(acptr)) { send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Ports:: %d -> %d (client -> server)", cli_port(acptr), cli_listener(acptr)->port); send_reply(sptr, RPL_DATASTR, outbuf); if (feature_bool(FEAT_CHECK_EXTENDED)) { /* Note: sendq = receiveq for a client (it makes sense really) */ ircd_snprintf(0, outbuf, sizeof(outbuf), " Data sent:: %u.%0.3u Kb (%u protocol messages)", cli_receiveK(acptr), cli_receiveB(acptr), cli_receiveM(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " Data received:: %u.%0.3u Kb (%u protocol messages)", cli_sendK(acptr), cli_sendB(acptr), cli_sendM(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " receiveQ size:: %d bytes (max. %d bytes)", DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " sendQ size:: %d bytes (max. %d bytes)", DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } /* Send 'END OF CHECK' message */ send_reply(sptr, RPL_ENDOFCHECK, " "); }
signed int checkHostmask(struct Client *sptr, char *hoststr, int flags) { struct Client *acptr; struct Channel *chptr; struct Membership *lp; int count = 0, found = 0, cidr_check_bits = 0; char outbuf[BUFSIZE]; char targhost[NICKLEN + USERLEN + HOSTLEN + 3], curhost[NICKLEN + USERLEN + HOSTLEN + 3]; char nickm[NICKLEN + 1], userm[USERLEN + 1], hostm[HOSTLEN + 1]; char *p = NULL; struct in_addr cidr_check; strcpy(nickm,"*"); strcpy(userm,"*"); strcpy(hostm,"*"); if (!strchr(hoststr, '!') && !strchr(hoststr, '@')) ircd_strncpy(hostm,hoststr,HOSTLEN); else { if ((p = strchr(hoststr, '@'))) { *p++ = '\0'; if (*p) ircd_strncpy(hostm,p, HOSTLEN); } /* Get the nick!user mask */ if ((p = strchr(hoststr, '!'))) { *p++ = '\0'; if (*p) ircd_strncpy(userm,p,USERLEN); if (*hoststr) ircd_strncpy(nickm,hoststr,NICKLEN); } else if (*hoststr) { /* Durz: We should only do the following *IF* the hoststr has not already been * copied into hostm (ie. neither ! or @ specified).. otherwise, when we do * /quote check *.barrysworld.com - we end up with targhost as: *!*.barryswo@*.barrysworld.com */ ircd_strncpy(userm,hoststr,USERLEN); } } if ((p = strchr(hostm, '/')) || inet_aton(hostm, &cidr_check)) { if (p) *p = '\0'; if (inet_aton(hostm, &cidr_check)) { cidr_check_bits = p ? atoi(p + 1) : 32; if ((cidr_check_bits >= 0) && (cidr_check_bits <= 32)) { flags |= CHECK_CIDRMASK; cidr_check.s_addr &= NETMASK(cidr_check_bits); } } if (p) *p = '/'; } /* Copy formatted string into "targhost" buffer */ ircd_snprintf(0, targhost, sizeof(targhost), "%s!%s@%s", nickm, userm, hostm); targhost[sizeof(targhost) - 1] = '\0'; /* Note: we have to exclude the last client struct as it is not a real client * structure, and therefore any attempt to access elements in it would cause * a segfault. */ for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) { /* Dont process if acptr is a unregistered client, a server or a ping */ if (!IsRegistered(acptr) || IsServer(acptr)) continue; if (IsMe(acptr)) /* Always the last acptr record */ break; if(count > feature_int(FEAT_MAX_CHECK_OUTPUT)) { /* sanity stuff */ ircd_snprintf(0, outbuf, sizeof(outbuf), "More than %d results, truncating...", count); send_reply(sptr, RPL_DATASTR, outbuf); send_reply(sptr, RPL_ENDOFCHECK, " "); break; } /* Copy host info into buffer */ curhost[0] = '\0'; ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->realusername, acptr->cli_user->realhost); if (flags & CHECK_CIDRMASK) { if (((cli_ip(acptr).s_addr & NETMASK(cidr_check_bits)) == cidr_check.s_addr) && !match(nickm, acptr->cli_name) && (!match(userm, acptr->cli_user->realusername) || !match(userm, acptr->cli_user->username))) found = 1; } else { if(match((const char*)targhost,(const char*)curhost) == 0) found = 1; else { curhost[0] = '\0'; ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->username, acptr->cli_user->host); if(match((const char*)targhost,(const char*)curhost) == 0) found = 1; } } if (found == 1) { found = 0; /* reset that so it doesn't get crazy go nuts */ /* Show header if we've found at least 1 record */ if (count == 0) { /* Output header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "host", targhost); send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), "%s %-*s%-*s%s", "No.", (NICKLEN + 2 ), "Nick", (USERLEN + 2), "User", "Host"); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), "%-4d %-*s%-*s%s", (count+1), (NICKLEN + 2), acptr->cli_name, (USERLEN + 2), acptr->cli_user->realusername, (flags & CHECK_SHOWIPS) ? ircd_ntoa((const char*)&(cli_ip(acptr))) : acptr->cli_user->realhost); send_reply(sptr, RPL_DATASTR, outbuf); /* Show channel output (if applicable) - the 50 channel limit sanity check * is specifically to prevent coredumping when someone lamely tries to /check * Q or some other channel service... */ if (flags & CHECK_CHECKCHAN) { if (acptr->cli_user->joined > 0 && acptr->cli_user->joined <= 50) { char chntext[BUFSIZE]; int len = strlen(" on channels: "); int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name); *chntext = '\0'; strcpy(chntext, " on channels: "); for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) { chptr = lp->channel; if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) { send_reply(sptr, RPL_DATASTR, chntext); *chntext = '\0'; strcpy(chntext, " on channels: "); len = strlen(chntext); } if (IsDeaf(acptr)) *(chntext + len++) = '-'; if (is_chan_op(acptr, chptr)) *(chntext + len++) = '@'; if (is_half_op(acptr, chptr)) *(chntext + len++) = '%'; if (IsOper(sptr) && !ShowChannel(sptr,chptr)) *(chntext + len++) = '*'; else if (has_voice(acptr, chptr)) *(chntext + len++) = '+'; else if (IsZombie(lp)) *(chntext + len++) = '!'; if (len) *(chntext + len) = '\0'; strcpy(chntext + len, chptr->chname); len += strlen(chptr->chname); strcat(chntext + len, " "); len++; } if (chntext[0] != '\0') send_reply(sptr, RPL_DATASTR, chntext); send_reply(sptr, RPL_DATASTR, " "); } } count++; } } if (count > 0) { send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), "Matching records found:: %d", count); send_reply(sptr, RPL_DATASTR, outbuf); send_reply(sptr, RPL_ENDOFCHECK, " "); } return count; }
/* * m_invite - generic message handler * * parv[0] - sender prefix * parv[1] - user to invite * parv[2] - channel name * * - INVITE now is accepted only if who does it is chanop (this of course * implies that channel must exist and he must be on it). * * - On the other side it IS processed even if channel is NOT invite only * leaving room for other enhancements like inviting banned ppl. -- Nemesi * * - Invite with no parameters now lists the channels you are invited to. * - Isomer 23 Oct 99 */ int m_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; struct Channel *chptr; if (parc < 2 ) { /* * list the channels you have an invite to. */ struct SLink *lp; for (lp = cli_user(sptr)->invited; lp; lp = lp->next) send_reply(cptr, RPL_INVITELIST, lp->value.chptr->chname); send_reply(cptr, RPL_ENDOFINVITELIST); return 0; } if (parc < 3 || EmptyString(parv[2])) return need_more_params(sptr, "INVITE"); if (!(acptr = FindUser(parv[1]))) { send_reply(sptr, ERR_NOSUCHNICK, parv[1]); return 0; } if (is_silenced(sptr, acptr) && !is_silence_exempted(sptr, acptr)) return 0; clean_channelname(parv[2]); if (!IsChannelPrefix(*parv[2])) return 0; /* bad channel name */ if (!IsChannelName(parv[2]) || HasCntrl(parv[2])) { send_reply(sptr, ERR_NOSUCHCHANNEL, parv[2]); return 0; } if (!(chptr = FindChannel(parv[2]))) { send_reply(sptr, ERR_NOTONCHANNEL, parv[2]); return 0; } if (!find_channel_member(sptr, chptr)) { send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname); return 0; } if (find_channel_member(acptr, chptr)) { send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname); return 0; } if (!is_chan_op(sptr, chptr) && !is_half_op(sptr, chptr)) { send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname); return 0; } /* If we get here, it was a VALID and meaningful INVITE */ if (IsAccountOnly(acptr) && !IsAccount(sptr) && !IsOper(sptr)) { send_reply(sptr, ERR_ACCOUNTONLY, cli_name(acptr), "INVITE"); return 0; } if (IsPrivDeaf(acptr) && !IsOper(sptr)) { send_reply(sptr, ERR_PRIVDEAF, cli_name(sptr), "INVITE", cli_name(acptr)); return 0; } if (IsCommonChansOnly(acptr) && !IsAnOper(sptr) && !common_chan_count(acptr, sptr, 1)) { send_reply(sptr, ERR_COMMONCHANSONLY, cli_name(acptr), "INVITE"); return 0; } if (check_target_limit(sptr, acptr, cli_name(acptr), 0)) return 0; send_reply(sptr, RPL_INVITING, cli_name(acptr), chptr->chname); if (cli_user(acptr)->away) send_reply(sptr, RPL_AWAY, cli_name(acptr), cli_user(acptr)->away); if (MyConnect(acptr)) { add_invite(acptr, chptr); sendcmdto_one(sptr, CMD_INVITE, acptr, "%s :%H", cli_name(acptr), chptr); } else { sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime); } if (!IsLocalChannel(chptr->chname) || MyConnect(acptr)) { if (feature_bool(FEAT_ANNOUNCE_INVITES)) { /* Announce to channel operators. */ sendcmdto_channel_butserv_butone(feature_bool(FEAT_HIS_HIDEWHO) ? &his : &me, get_error_numeric(RPL_ISSUEDINVITE)->str, NULL, chptr, sptr, SKIP_NONOPS, "%H %C %C :%C has been invited by %C", chptr, acptr, sptr, acptr, sptr); /* Announce to servers with channel operators. */ sendcmdto_channel_servers_butone(sptr, NULL, TOK_INVITE, chptr, acptr, SKIP_NONOPS, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime); } } return 0; }