/* * m_join * parv[0] = sender prefix * parv[1] = channel * parv[2] = channel password (key) */ static void m_join(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; char *name, *key = NULL; int i, flags = 0; char *p = NULL, *p2 = NULL; int successful_join_count = 0; /* Number of channels successfully joined */ if (*parv[1] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "JOIN"); return; } if (parc > 2) { key = strtoken(&p2, parv[2], ","); } for (name = strtoken(&p, parv[1], ","); name; key = (key) ? strtoken(&p2, NULL, ",") : NULL, name = strtoken(&p, NULL, ",")) { if(!check_channel_name(name)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char*)name); continue; } /* ** JOIN 0 sends out a part for all channels a user ** has joined. ** ** this should be either disabled or selectable in ** config file .. it's abused a lot more than it's ** used these days :/ --is */ if (*name == '0' && !atoi(name)) { if (source_p->user->channel.head == NULL) continue; do_join_0(&me,source_p); continue; } /* check it begins with # or & */ else if(!IsChannelName(name)) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, name); continue; } if(ConfigServerHide.disable_local_channels && (*name == '&')) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, name); continue; } /* check the length */ if (strlen(name) > CHANNELLEN) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, name); continue; } /* see if its resv'd */ if(find_channel_resv(name) && (!IsOper(source_p) || !ConfigChannel.no_oper_resvs)) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, source_p->name, name); sendto_realops_flags(UMODE_SPY, L_ALL, "User %s (%s@%s) is attempting to join locally juped channel %s", source_p->name, source_p->username, source_p->host, name); continue; } /* look for the channel */ if((chptr = hash_find_channel(name)) != NULL) { if(IsMember(source_p, chptr)) return; if(splitmode && !IsOper(source_p) && (*name != '&') && ConfigChannel.no_join_on_split) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, source_p->name, name); continue; } if (chptr->users == 0) flags = CHFL_CHANOP; else flags = 0; } else { if(splitmode && !IsOper(source_p) && (*name != '&') && (ConfigChannel.no_create_on_split || ConfigChannel.no_join_on_split)) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, source_p->name, name); continue; } flags = CHFL_CHANOP; } if ((source_p->user->joined >= ConfigChannel.max_chans_per_user) && (!IsOper(source_p) || (source_p->user->joined >= ConfigChannel.max_chans_per_user*3))) { sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS), me.name, parv[0], name); if(successful_join_count) source_p->localClient->last_join_time = CurrentTime; return; } if(flags == 0) /* if channel doesn't exist, don't penalize */ successful_join_count++; if(chptr == NULL) /* If I already have a chptr, no point doing this */ { chptr = get_or_create_channel(source_p, name, NULL); } if(chptr == NULL) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, parv[0], name); if(successful_join_count > 0) successful_join_count--; continue; } if (!IsOper(source_p)) check_spambot_warning(source_p, name); /* can_join checks for +i key, bans etc */ if ( (i = can_join(source_p, chptr, key)) ) { sendto_one(source_p, form_str(i), me.name, parv[0], name); if(successful_join_count > 0) successful_join_count--; continue; } /* add the user to the channel */ add_user_to_channel(chptr, source_p, flags); /* we send the user their join here, because we could have to * send a mode out next. */ sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", source_p->name, source_p->username, source_p->host, chptr->chname); /* if theyre joining opped (ie, new chan or joining one thats * persisting) then set timestamp to current, set +nt and * broadcast the sjoin with its old modes, or +nt. */ if (flags & CHFL_CHANOP) { char mbuf[MODEBUFLEN]; char pbuf[MODEBUFLEN]; chptr->channelts = CurrentTime; chptr->mode.mode |= MODE_TOPICLIMIT; chptr->mode.mode |= MODE_NOPRIVMSGS; sendto_channel_local(ONLY_CHANOPS, chptr, ":%s MODE %s +nt", me.name, chptr->chname); if(*chptr->chname == '#') { channel_modes(chptr, source_p, mbuf, pbuf); strlcat(mbuf, " ", sizeof(mbuf)); if(pbuf[0] != '\0') strlcat(mbuf, pbuf, sizeof(mbuf)); /* note: mbuf here will have a trailing space. we add one above, * and channel_modes() will leave a trailing space on pbuf if * its used --fl */ sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %lu %s %s:@%s", me.name, (unsigned long) chptr->channelts, chptr->chname, mbuf, parv[0]); } /* drop our +beI modes */ free_channel_list(&chptr->banlist); free_channel_list(&chptr->exceptlist); free_channel_list(&chptr->invexlist); } else { sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %lu %s + :%s", me.name, (unsigned long) chptr->channelts, chptr->chname, parv[0]); } del_invite(chptr, source_p); if (chptr->topic != NULL) { sendto_one(source_p, form_str(RPL_TOPIC), me.name, parv[0], chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, parv[0], chptr->chname, chptr->topic_info, chptr->topic_time); } channel_member_names(source_p, chptr, chptr->chname, 1); if(successful_join_count) source_p->localClient->last_join_time = CurrentTime; } }
/* * 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, msptr) >= CHFL_CHANOP) && (!MyClient(source_p) || can_send(chptr, source_p, msptr))) { char topic_info[USERHOST_REPLYLEN]; rb_sprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, parv[2], 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; }
/* * send_conf_options * * inputs - client pointer to send to * output - none * side effects - send config options to client */ static void send_conf_options(struct Client *source_p) { int i = 0; /* * Parse the info_table[] and do the magic. */ for(i = 0; info_table[i].name; i++) { switch (info_table[i].output_type) { /* * For "char *" references */ case OUTPUT_STRING: { const char *option = *(info_table[i].option.pstring); sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option ? option : "NONE", info_table[i].desc ? info_table[i].desc : "<none>"); break; } /* * For "char foo[]" references */ case OUTPUT_STRING_PTR: { const char *option = info_table[i].option.string; sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, EmptyString(option) ? "NONE" : option, info_table[i].desc ? info_table[i].desc : "<none>"); break; } /* * Output info_table[i].option as a decimal value. */ case OUTPUT_DECIMAL: { int option = *info_table[i].option.decimal_ptr; sendto_one(source_p, ":%s %d %s :%-30s %-5d [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option, info_table[i].desc ? info_table[i].desc : "<none>"); break; } /* * Output info_table[i].option as a decimal value. */ case OUTPUT_DECIMAL_RAW: { int option = info_table[i].option.decimal; sendto_one(source_p, ":%s %d %s :%-30s %-5d [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option, info_table[i].desc ? info_table[i].desc : "<none>"); break; } /* * Output info_table[i].option as "ON" or "OFF" */ case OUTPUT_BOOLEAN: { int option = *(info_table[i].option.decimal_ptr); sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option ? "ON" : "OFF", info_table[i].desc ? info_table[i].desc : "<none>"); break; } /* * Output info_table[i].option as "YES" or "NO" */ case OUTPUT_BOOLEAN_YN: { int option = *(info_table[i].option.decimal_ptr); sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option ? "YES" : "NO", info_table[i].desc ? info_table[i].desc : "<none>"); break; } case OUTPUT_BOOLEAN_RAW: { int option = info_table[i].option.decimal; sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option ? "ON" : "OFF", info_table[i].desc ? info_table[i].desc : "<none>"); break; } /* * Output info_table[i].option as "YES" or "NO" */ case OUTPUT_BOOLEAN_RAW_YN: { int option = info_table[i].option.decimal; sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option ? "YES" : "NO", info_table[i].desc ? info_table[i].desc : "<none>"); break; } case OUTPUT_BOOLEAN2: { int option = *info_table[i].option.decimal_ptr; sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", me.name, RPL_INFO, source_p->name, info_table[i].name, option ? ((option == 1) ? "MASK" : "YES") : "NO", info_table[i].desc ? info_table[i].desc : "<none>"); } /* switch (info_table[i].output_type) */ } } /* forloop */ sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), "io_type", rb_get_iotype(), "Method of Multiplexed I/O"); /* Don't send oper_only_umodes...it's a bit mask, we will have to decode it ** in order for it to show up properly to opers who issue INFO */ sendto_one_numeric(source_p, RPL_INFO, form_str(RPL_INFO), ""); }
static void ms_cburst(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *name; char *nick; const char *key; struct Channel *chptr; if (parc < 2 || *parv[1] == '\0' ) return; name = parv[1]; if (parc > 2) nick = parv[2]; else nick = NULL; if (parc > 3) key = parv[3]; else key = ""; #ifdef DEBUGLL sendto_gnotice_flags(UMODE_ALL, L_ALL, me.name, &me, NULL, "CBURST called by %s for %s %s %s", client_p->name, name, nick ? nick : "", key ? key : ""); #endif if ((chptr = hash_find_channel(name)) == NULL) { if ((!nick) || (nick && *nick != '!')) { if (!check_channel_name(name, 0)) { sendto_gnotice_flags(UMODE_DEBUG, L_ALL, me.name, &me, NULL, "*** Too long or invalid channel name from %s: %s", client_p->name, name); return; } chptr = make_channel(name); chptr->channelts = (time_t)(-1); /* highest possible TS so its always * over-ruled */ } else if(nick && *nick=='!') { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, nick+1, name); return; } } if (IsCapable(client_p,CAP_LL)) { burst_channel(client_p,chptr); if (nick) sendto_one(client_p, ":%s LLJOIN %s %s %s", me.name, name, nick, key); } else { sendto_gnotice_flags(UMODE_ALL, L_ALL, me.name, &me, NULL, "*** CBURST request received from non LL capable server! [%s]", client_p->name); } }
/* * mo_forcepart * parv[1] = forcepart victim * parv[2] = channels to part * parv[3] = reason */ static int mo_forcepart(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; const char *user, *channels, *reason; const char default_reason[] = "Leaving"; int chasing = 0; user = parv[1]; channels = parv[2]; if(!IsOperLocalForce(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "local_force"); return 0; } /* if target_p == NULL then let the oper know */ if((target_p = find_chasing(source_p, user, &chasing)) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, user); return 0; } if(EmptyString(channels)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "FORCEPART"); return 0; } if(EmptyString(parv[3])) reason = default_reason; else { char *s; s = LOCAL_COPY(parv[3]); if(strlen(s) > (size_t) REASONLEN) s[REASONLEN] = '\0'; reason = s; } if(!IsClient(target_p)) return 0; if(!MyClient(target_p) && (!IsOperGlobalForce(source_p))) { sendto_one_notice(source_p, ":Nick %s is not on your server and you do not have the global_force flag", target_p->name); return 0; } sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Received FORCEPART message for %s!%s@%s. From %s (Channels: %s)", target_p->name, target_p->username, target_p->host, source_p->name, channels); ilog(L_MAIN, "FORCEPART called for %s %s by %s!%s@%s (part reason %s)", user, channels, source_p->name, source_p->username, source_p->host, reason); if(!MyClient(target_p)) { struct Client *cptr = target_p->servptr; sendto_one(cptr, ":%s ENCAP %s FORCEPART %s :%s", get_id(source_p, cptr), cptr->name, get_id(target_p, cptr), channels); return 0; } forcepart_channels(client_p, source_p, target_p, channels, reason); return 0; }
/* * m_challenge - generate RSA challenge for wouldbe oper * parv[0] = sender prefix * parv[1] = operator to challenge for, or +response * */ static void m_challenge(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *challenge = NULL; struct MaskItem *conf = NULL; if (*parv[1] == '+') { /* Ignore it if we aren't expecting this... -A1kmm */ if (source_p->localClient->response == NULL) return; if (irccmp(source_p->localClient->response, ++parv[1])) { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name); failed_challenge_notice(source_p, source_p->localClient->auth_oper, "challenge failed"); return; } conf = find_exact_name_conf(CONF_OPER, source_p, source_p->localClient->auth_oper, NULL, NULL); if (conf == NULL) { /* XXX: logging */ sendto_one (source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name); return; } if (attach_conf(source_p, conf) != 0) { sendto_one(source_p,":%s NOTICE %s :Can't attach conf!", me.name, source_p->name); failed_challenge_notice(source_p, conf->name, "can't attach conf!"); return; } ++conf->count; oper_up(source_p); ilog(LOG_TYPE_OPER, "OPER %s by %s!%s@%s", source_p->localClient->auth_oper, source_p->name, source_p->username, source_p->host); MyFree(source_p->localClient->response); MyFree(source_p->localClient->auth_oper); source_p->localClient->response = NULL; source_p->localClient->auth_oper = NULL; return; } MyFree(source_p->localClient->response); MyFree(source_p->localClient->auth_oper); source_p->localClient->response = NULL; source_p->localClient->auth_oper = NULL; conf = find_exact_name_conf(CONF_OPER, source_p, parv[1], NULL, NULL); if (!conf) { sendto_one (source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name); conf = find_exact_name_conf(CONF_OPER, NULL, parv[1], NULL, NULL); failed_challenge_notice(source_p, parv[1], (conf != NULL) ? "host mismatch" : "no oper {} block"); return; } if (conf->rsa_public_key == NULL) { sendto_one (source_p, ":%s NOTICE %s :I'm sorry, PK authentication " "is not enabled for your oper{} block.", me.name, source_p->name); return; } if (!generate_challenge(&challenge, &(source_p->localClient->response), conf->rsa_public_key)) sendto_one(source_p, form_str(RPL_RSACHALLENGE), me.name, source_p->name, challenge); source_p->localClient->auth_oper = xstrdup(conf->name); MyFree(challenge); }
/* ** 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; }
/* * m_htm - HTM command handler * high traffic mode info */ int m_htm(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { char *command; if (!MyClient(sptr) || !IsOper(sptr)) { sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } sendto_one(sptr, ":%s NOTICE %s :HTM is %s(%d), %s. Max rate = %dk/s. Current = %.1fk/s recv, %.1fk/s sent", me.name, parv[0], LIFESUX ? "ON" : "OFF", LIFESUX, NOISYHTM ? "NOISY" : "QUIET", LRV, currlife, cursend); if (parc > 1) { command = parv[1]; if (!irccmp(command,"TO")) { if (parc > 2) { int new_value = atoi(parv[2]); if (new_value < 10) { sendto_one(sptr, ":%s NOTICE %s :\002Cannot set LRV < 10!\002", me.name, parv[0]); } else LRV = new_value; sendto_one(sptr, ":%s NOTICE %s :NEW Max rate = %dk/s. Current = %.1fk/s", me.name, parv[0], LRV, currlife); sendto_realops("%s!%s@%s set new HTM rate to %dk/s (%.1fk/s current)", parv[0], sptr->username, sptr->host, LRV, currlife); } else sendto_one(sptr, ":%s NOTICE %s :LRV command needs an integer parameter",me.name, parv[0]); } else { if (!irccmp(command,"ON")) { LIFESUX = 1; sendto_one(sptr, ":%s NOTICE %s :HTM is now ON.", me.name, parv[0]); sendto_ops("Entering high-traffic mode: Forced by %s!%s@%s", parv[0], sptr->username, sptr->host); LCF = 30; /* 30s */ } else if (!irccmp(command,"OFF")) { LIFESUX = 0; LCF = LOADCFREQ; sendto_one(sptr, ":%s NOTICE %s :HTM is now OFF.", me.name, parv[0]); sendto_ops("Resuming standard operation: Forced by %s!%s@%s", parv[0], sptr->username, sptr->host); } else if (!irccmp(command,"QUIET")) { sendto_ops("HTM is now QUIET"); NOISYHTM = NO; } else if (!irccmp(command,"NOISY")) { sendto_ops("HTM is now NOISY"); NOISYHTM = YES; } else sendto_one(sptr, ":%s NOTICE %s :Commands are:HTM [ON] [OFF] [TO int] [QUIET] [NOISY]", me.name, parv[0]); } } return 0; }
/* parse() * * given a raw buffer, parses it and generates parv, parc and sender */ void parse(struct Client *client_p, char *pbuffer, char *bufend) { struct Client *from = client_p; char *ch; char *s; char *end; int i = 1; char *numeric = 0; struct Message *mptr; s_assert(MyConnect(client_p)); if(IsAnyDead(client_p)) return; for(ch = pbuffer; *ch == ' '; ch++) /* skip spaces */ /* null statement */ ; if(from->name != NULL) para[0] = LOCAL_COPY(from->name); else para[0] = NULL; if(*ch == ':') { ch++; /* point sender to the sender param */ sender = ch; if((s = strchr(ch, ' '))) { *s = '\0'; s++; ch = s; } if(*sender && IsServer(client_p)) { from = find_client(sender); /* didnt find any matching client, issue a kill */ if(from == NULL) { ServerStats.is_unpf++; remove_unknown(client_p, sender, pbuffer); return; } para[0] = LOCAL_COPY(from->name); /* fake direction, hmm. */ if(from->from != client_p) { ServerStats.is_wrdi++; cancel_clients(client_p, from); return; } } while(*ch == ' ') ch++; } if(*ch == '\0') { ServerStats.is_empt++; return; } /* at this point there must be some sort of command parameter */ /* * 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 */ /* EOB is 3 chars long but is not a numeric */ if(*(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */ IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2))) { mptr = NULL; numeric = ch; 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 { int ii = 0; if((s = strchr(ch, ' '))) *s++ = '\0'; mptr = hash_parse(ch); /* no command or its encap only, error */ 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 */ if(pbuffer[0] != '\0') { if(IsClient(from)) sendto_one(from, form_str(ERR_UNKNOWNCOMMAND), me.name, from->name, ch); } ServerStats.is_unco++; return; } ii = bufend - ((s) ? s : ch); mptr->bytes += ii; } end = bufend - 1; /* XXX this should be done before parse() is called */ if(*end == '\n') *end-- = '\0'; if(*end == '\r') *end = '\0'; if(s != NULL) i = string_to_array(s, para); if(mptr == NULL) { do_numeric(numeric, client_p, from, i, para); return; } if(handle_command(mptr, client_p, from, i, /* XXX discards const!!! */ (const char **)para) < -1) { char *p; for(p = pbuffer; p <= end; p += 8) { /* HACK HACK */ /* Its expected this nasty code can be removed * or rewritten later if still needed. */ if((unsigned long)(p + 8) > (unsigned long)end) { for(; p <= end; p++) { ilog(L_MAIN, "%02x |%c", p[0], p[0]); } } else ilog(L_MAIN, "%02x %02x %02x %02x %02x %02x %02x %02x |%c%c%c%c%c%c%c%c", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); } } }
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) && !accept_message(source_p, target_p) && !IsOper(source_p)) { 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; }
/* ** m_whois ** parv[0] = sender prefix ** parv[1] = nickname masklist */ int m_whois(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { static anUser UnknownUser = { NULL, /* next */ NULL, /* channel */ NULL, /* invited */ NULL, /* silence */ NULL, /* away */ 0, /* last */ 1, /* refcount */ 0, /* joined */ "<Unknown>" /* server */ }; static char rpl_oper[] = "an IRC Operator"; static char rpl_locop[] = "an IRC Operator - Local IRC Operator"; static char rpl_sadmin[] = "an IRC Operator - Services Administrator"; static char rpl_admin[] = "an IRC Operator - Server Administrator"; static char rpl_tadmin[] = "an IRC Operator - Technical Administrator"; static char rpl_nadmin[] = "an IRC Operator - Network Administrator"; Link *lp; anUser *user; struct Client *acptr, *a2cptr; aChannel *chptr; char *nick, *name; /* char *tmp; */ char *p = NULL; int found, len, mlen; static time_t last_used=0L; char *nick_match=NULL, *user_match=NULL, *host_match=NULL, *server_match=NULL; char *name_match=NULL; int found_mode; int hits = 0; char *mename = me.name; if(sptr->user && sptr->user->vlink) mename = sptr->user->vlink->name; if (parc < 2) { sendto_one(sptr, form_str(ERR_NONICKNAMEGIVEN), mename, parv[0]); return 0; } if(parc > 2) { if (hunt_server(cptr,sptr,":%s WHOIS %s :%s", 1,parc,parv) != HUNTED_ISME) return 0; parv[1] = parv[2]; } if(!IsAnOper(sptr) && !MyConnect(sptr)) /* pace non local requests */ { if((last_used + WHOIS_WAIT) > CurrentTime) { /* Unfortunately, returning anything to a non local * request =might= increase sendq to be usable in a split hack * Sorry gang ;-( - Dianora */ return 0; } else { last_used = CurrentTime; } } /* Multiple whois from remote hosts, can be used * to flood a server off. One could argue that multiple whois on * local server could remain. Lets think about that, for now * removing it totally. * -Dianora */ /* for (tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL) */ nick = parv[1]; p = strchr(parv[1],','); if(p) *p = '\0'; { int invis, member, wilds; found = 0; (void)collapse(nick); wilds = (nick[0]=='$' || strchr(nick, '?') || strchr(nick, '*')); /* ** We're no longer allowing remote users to generate ** requests with wildcards. */ if (wilds && !IsAnOper(sptr)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); return 0; } /* continue; */ /* If the nick doesn't have any wild cards in it, * then just pick it up from the hash table * - Dianora */ if(!wilds) { acptr = hash_find_client(nick,(struct Client *)NULL); if(!acptr) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; /* continue; */ } if(IsStealth(acptr)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); return 0; // Add by ^Stinger^ after the idea of Soldier (: } if(!IsPerson(acptr)) { sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; } /* continue; */ user = acptr->user ? acptr->user : &UnknownUser; name = (!*acptr->name) ? "?" : acptr->name; invis = IsInvisible(acptr); member = (user->channel) ? 1 : 0; a2cptr = find_server(user->server); sendto_one(sptr, form_str(RPL_WHOISUSER), mename, parv[0], name, acptr->username, acptr->host, acptr->info); if((IsOper(sptr) || (acptr == sptr)) && WhoisExtension) { sendto_one(sptr, form_str(RPL_WHOISREALHOST), mename, parv[0], name, acptr->realhost); } mlen = strlen(mename) + strlen(parv[0]) + 6 + strlen(name); *buf = '\0'; if (IsSsl(acptr)) { sendto_one(sptr, form_str(RPL_WHOISSECURE), mename, parv[0], parv[1]); } if(((!IsPrivate(acptr) || IsOper(sptr)) || (acptr==sptr)) && !IsStealth(acptr)) for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; if (ShowChannel(sptr, chptr)) { if (len + strlen(chptr->chname) > (size_t) BUFSIZE - 4 - mlen) { sendto_one(sptr, ":%s %d %s %s :%s", mename, RPL_WHOISCHANNELS, parv[0], name, buf); *buf = '\0'; len = 0; } found_mode = user_channel_mode(acptr, chptr); #ifdef HIDE_OPS if(is_chan_op(sptr,chptr)) #endif { if(found_mode & CHFL_CHANOP) *(buf + len++) = '@'; #ifdef HALFOPS else if (found_mode & CHFL_HALFOP) *(buf + len++) = '%'; #endif else if (found_mode & CHFL_VOICE) *(buf + len++) = '+'; } if (len) *(buf + len) = '\0'; (void)strcpy(buf + len, chptr->chname); len += strlen(chptr->chname); (void)strcat(buf + len, " "); len++; } } if (buf[0] != '\0') sendto_one(sptr, form_str(RPL_WHOISCHANNELS), mename, parv[0], name, buf); if(IsAnOper(sptr) || !HideServerOnWhois) { #ifdef SERVERHIDE if (!(IsAnOper(sptr) || acptr == sptr)) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, NetworkName, NetworkDesc); else #endif if(acptr->user && acptr->user->vlink) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->vlink->name, user->vlink->passwd); else { if(!IsService(acptr) || IsAnOper(sptr) || !HideServicesServer) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->server, a2cptr?a2cptr->info:"*Not On This Net*"); } } /* if(IsAnOper(sptr) || HideServerOnWhois) */ if (IsIdentified(acptr)) sendto_one(sptr, form_str(RPL_WHOISIDENTIFIED), mename, parv[0], name); if (IsHelper(acptr)) sendto_one(sptr, form_str(RPL_WHOISHELPOP), mename, parv[0], name); if(IsOper(sptr) && WhoisExtension) { sendto_one(sptr, form_str(RPL_WHOISMODE), mename, parv[0], name, get_mode_string(acptr)); } if (user->away) sendto_one(sptr, form_str(RPL_AWAY), mename, parv[0], name, user->away); if(!IsHideOper(acptr) || IsOper(sptr)) { if (IsNetAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_nadmin); else if (IsTechAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_tadmin); else if (IsSAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_sadmin); else if (IsAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_admin); else if (IsOper(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_oper); else if (IsLocOp(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_locop); } #ifdef WHOIS_NOTICE if ((IsOper(acptr)) && ((acptr)->umodes & UMODE_SPY) && (MyConnect(sptr)) && (IsPerson(sptr)) && (acptr != sptr) && !is_silenced(sptr, acptr)) sendto_one(acptr, ":%s NOTICE %s :*** Notice -- %s (%s@%s) is doing a /whois on you.", me.name, acptr->name, parv[0], sptr->username, sptr->realhost); #endif /* #ifdef WHOIS_NOTICE */ if ((acptr->user #ifdef SERVERHIDE && IsAnOper(sptr) #endif && MyConnect(acptr))) sendto_one(sptr, form_str(RPL_WHOISIDLE), mename, parv[0], name, CurrentTime - user->last, acptr->firsttime); sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; /* continue; */ } /* wild is true so here we go */ if(nick[0]==':') /* real name match */ { name_match = &nick[1]; nick_match = NULL; } else if(nick[0]=='$') /* server name match */ { server_match = &nick[1]; nick_match = NULL; } else { host_match = strchr(nick,'@'); if(host_match) { if(*host_match) *(host_match++) = '\0'; user_match=nick; if(host_match=='\0') host_match="*"; if(user_match=='\0') user_match="*"; } else nick_match = nick; } for (acptr = GlobalClientList; acptr; acptr = acptr->next) { if (IsServer(acptr)) continue; /* * I'm always last :-) and acptr->next == NULL!! */ if (IsMe(acptr)) break; /* * 'Rules' established for sending a WHOIS reply: * * * - if wildcards are being used dont send a reply if * the querier isnt any common channels and the * client in question is invisible and wildcards are * in use (allow exact matches only); * * - only send replies about common or public channels * the target user(s) are on; */ /* If its an unregistered client, ignore it, it can be "seen" on a /trace anyway -Dianora */ if(!IsRegistered(acptr)) continue; user = acptr->user ? acptr->user : &UnknownUser; name = (!*acptr->name) ? "?" : acptr->name; if( (server_match && !match(server_match, user->server)) || (nick_match && !match(nick, name)) || (host_match && !match(host_match, acptr->realhost) && !match(host_match, acptr->host)) || (user_match && !match(user_match, acptr->username)) || (name_match && !match(name_match, acptr->info)) ) continue; ++hits; a2cptr = find_server(user->server); sendto_one(sptr, form_str(RPL_WHOISUSER), mename, parv[0], name, acptr->username, IsOper(sptr) ? acptr->realhost : acptr->host, acptr->info); found = 1; mlen = strlen(mename) + strlen(parv[0]) + 6 + strlen(name); for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; if (ShowChannel(sptr, chptr)) { if (len + strlen(chptr->chname) > (size_t) BUFSIZE - 4 - mlen) { sendto_one(sptr, ":%s %d %s %s :%s", mename, RPL_WHOISCHANNELS, parv[0], name, buf); *buf = '\0'; len = 0; } found_mode = user_channel_mode(acptr, chptr); #ifdef HIDE_OPS if(is_chan_op(sptr,chptr)) #endif { if (found_mode & CHFL_CHANOP) *(buf + len++) = '@'; #ifdef HALFOPS else if (found_mode & CHFL_HALFOP) *(buf + len++) = '%'; #endif else if (found_mode & CHFL_VOICE) *(buf + len++) = '+'; } if (len) *(buf + len) = '\0'; (void)strcpy(buf + len, chptr->chname); len += strlen(chptr->chname); (void)strcat(buf + len, " "); len++; } } if (buf[0] != '\0') sendto_one(sptr, form_str(RPL_WHOISCHANNELS), mename, parv[0], name, buf); #ifdef SERVERHIDE if (!(IsAnOper(sptr) || acptr == sptr)) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, NetworkName, NetworkDesc); else #endif sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->server, a2cptr?a2cptr->info:"*Not On This Net*"); if (user->away) sendto_one(sptr, form_str(RPL_AWAY), mename, parv[0], name, user->away); if (IsNetAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_nadmin); else if (IsTechAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_tadmin); else if (IsSAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_sadmin); else if (IsAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_admin); else if (IsAnOper(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_oper); #ifdef WHOIS_NOTICE if ((MyOper(acptr)) && ((acptr)->umodes & UMODE_SPY) && (MyConnect(sptr)) && (IsPerson(sptr)) && (acptr != sptr)) sendto_one(acptr, ":%s NOTICE %s :*** Notice -- %s (%s@%s) is doing a /whois on you.", mename, acptr->name, parv[0], sptr->username, sptr->realhost); #endif /* #ifdef WHOIS_NOTICE */ if ((acptr->user #ifdef SERVERHIDE && IsAnOper(sptr) #endif && MyConnect(acptr))) sendto_one(sptr, form_str(RPL_WHOISIDLE), mename, parv[0], name, CurrentTime - user->last, acptr->firsttime); if(hits>50) { sendto_one(sptr,":%s NOTICE %s :Aborting /whois output as flood prevention", mename, sptr->name); break; } } if (!found) sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); else sendto_one(sptr,":%s NOTICE %s :This /whois matched \2%i\2 user(s)", mename, sptr->name,hits); /* if (p) p[-1] = ','; */ } sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; }
static void me_sasl(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p, *agent_p; /* Let propagate if not addressed to us, or if broadcast. * Only SASL agents can answer global requests. */ if(strncmp(parv[2], me.id, 3)) return; if((target_p = find_id(parv[2])) == NULL) return; if((agent_p = find_id(parv[1])) == NULL) return; if(source_p != agent_p->servptr) /* WTF?! */ return; /* We only accept messages from SASL agents; these must have umode +S * (so the server must be listed in a service{} block). */ if(!IsService(agent_p)) return; /* Reject if someone has already answered. */ if(*target_p->localClient->sasl_agent && strncmp(parv[1], target_p->localClient->sasl_agent, IDLEN)) return; else if(!*target_p->localClient->sasl_agent) rb_strlcpy(target_p->localClient->sasl_agent, parv[1], IDLEN); if(*parv[3] == 'C') { sendto_one(target_p, "AUTHENTICATE %s", parv[4]); target_p->localClient->sasl_messages++; } else if(*parv[3] == 'D') { if(*parv[4] == 'F') { sendto_one(target_p, form_str(ERR_SASLFAIL), me.name, EmptyString(target_p->name) ? "*" : target_p->name); /* Failures with zero messages are just "unknown mechanism" errors; don't count those. */ if(target_p->localClient->sasl_messages > 0) { if(*target_p->name) { target_p->localClient->sasl_failures++; target_p->localClient->sasl_next_retry = rb_current_time() + (1 << MIN(target_p->localClient->sasl_failures + 5, 13)); } else if(throttle_add((struct sockaddr*)&target_p->localClient->ip)) { exit_client(target_p, target_p, &me, "Too many failed authentication attempts"); return; } } } else if(*parv[4] == 'S') { sendto_one(target_p, form_str(RPL_SASLSUCCESS), me.name, EmptyString(target_p->name) ? "*" : target_p->name); target_p->localClient->sasl_failures = 0; target_p->localClient->sasl_complete = 1; ServerStats.is_ssuc++; } *target_p->localClient->sasl_agent = '\0'; /* Blank the stored agent so someone else can answer */ target_p->localClient->sasl_messages = 0; } else if(*parv[3] == 'M') sendto_one(target_p, form_str(RPL_SASLMECHS), me.name, EmptyString(target_p->name) ? "*" : target_p->name, parv[4]); }
static void m_authenticate(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *agent_p = NULL; struct Client *saslserv_p = NULL; /* They really should use CAP for their own sake. */ if(!IsCapable(source_p, CLICAP_SASL)) return; if(source_p->localClient->sasl_next_retry > rb_current_time()) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, EmptyString(source_p->name) ? "*" : source_p->name, msgbuf_p->cmd); return; } if(strlen(client_p->id) == 3) { exit_client(client_p, client_p, client_p, "Mixing client and server protocol"); return; } saslserv_p = find_named_client(ConfigFileEntry.sasl_service); if(saslserv_p == NULL || !IsService(saslserv_p)) { sendto_one(source_p, form_str(ERR_SASLABORTED), me.name, EmptyString(source_p->name) ? "*" : source_p->name); return; } if(source_p->localClient->sasl_complete) { *source_p->localClient->sasl_agent = '\0'; source_p->localClient->sasl_complete = 0; } if(strlen(parv[1]) > 400) { sendto_one(source_p, form_str(ERR_SASLTOOLONG), me.name, EmptyString(source_p->name) ? "*" : source_p->name); return; } if(!*source_p->id) { /* Allocate a UID. */ strcpy(source_p->id, generate_uid()); add_to_id_hash(source_p->id, source_p); } if(*source_p->localClient->sasl_agent) agent_p = find_id(source_p->localClient->sasl_agent); if(agent_p == NULL) { sendto_one(saslserv_p, ":%s ENCAP %s SASL %s %s H %s %s", me.id, saslserv_p->servptr->name, source_p->id, saslserv_p->id, source_p->host, source_p->sockhost); if (source_p->certfp != NULL) sendto_one(saslserv_p, ":%s ENCAP %s SASL %s %s S %s %s", me.id, saslserv_p->servptr->name, source_p->id, saslserv_p->id, parv[1], source_p->certfp); else sendto_one(saslserv_p, ":%s ENCAP %s SASL %s %s S %s", me.id, saslserv_p->servptr->name, source_p->id, saslserv_p->id, parv[1]); rb_strlcpy(source_p->localClient->sasl_agent, saslserv_p->id, IDLEN); } else sendto_one(agent_p, ":%s ENCAP %s SASL %s %s C %s", me.id, agent_p->servptr->name, source_p->id, agent_p->id, parv[1]); source_p->localClient->sasl_out++; }
/* * m_forcejoin * parv[1] = user to force * parv[2] = channel to force them into */ static int mo_forcejoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; struct Channel *chptr; int type; char mode; char sjmode; char *newch; if(!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "forcejoin"); return 0; } if((hunt_server(client_p, source_p, ":%s FORCEJOIN %s %s", 1, parc, parv)) != HUNTED_ISME) return 0; /* if target_p is not existant, print message * to source_p and bail - scuzzy */ if((target_p = find_client(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]); return 0; } if(!IsClient(target_p)) return 0; /* select our modes from parv[2] if they exist... (chanop) */ if(*parv[2] == '@') { type = CHFL_CHANOP; mode = 'o'; sjmode = '@'; } else if(*parv[2] == '+') { type = CHFL_VOICE; mode = 'v'; sjmode = '+'; } else { type = CHFL_PEON; mode = sjmode = '\0'; } if(mode != '\0') parv[2]++; if((chptr = find_channel(parv[2])) != NULL) { if(IsMember(target_p, chptr)) { /* debugging is fun... */ sendto_one(source_p, ":%s NOTICE %s :*** Notice -- %s is already in %s", me.name, source_p->name, target_p->name, chptr->chname); return 0; } add_user_to_channel(chptr, target_p, type); sendto_server(target_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %ld %s + :%c%s", me.name, (long)chptr->channelts, chptr->chname, type ? sjmode : ' ', target_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); if(type) sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +%c %s", me.name, chptr->chname, mode, target_p->name); if(chptr->topic != NULL) { sendto_one(target_p, form_str(RPL_TOPIC), me.name, target_p->name, chptr->chname, chptr->topic->topic); sendto_one(target_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic->topic_info, chptr->topic->topic_time); } channel_member_names(chptr, target_p, 1); } else { newch = LOCAL_COPY(parv[2]); if(!check_channel_name(newch)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char *)newch); return 0; } /* channel name must begin with & or # */ if(!IsChannelName(newch)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char *)newch); return 0; } /* newch can't be longer than CHANNELLEN */ if(strlen(newch) > CHANNELLEN) { sendto_one(source_p, ":%s NOTICE %s :Channel name is too long", me.name, source_p->name); return 0; } chptr = get_or_create_channel(target_p, newch, NULL); add_user_to_channel(chptr, target_p, CHFL_CHANOP); /* send out a join, make target_p join chptr */ sendto_server(target_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %ld %s +nt :@%s", me.name, (long)chptr->channelts, chptr->chname, target_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); chptr->mode.mode |= MODE_TOPICLIMIT; chptr->mode.mode |= MODE_NOPRIVMSGS; sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +nt", me.name, chptr->chname); target_p->localClient->last_join_time = rb_time(); channel_member_names(chptr, target_p, 1); /* we do this to let the oper know that a channel was created, this will be * seen from the server handling the command instead of the server that * the oper is on. */ sendto_one(source_p, ":%s NOTICE %s :*** Notice -- Creating channel %s", me.name, source_p->name, chptr->chname); } return 0; }
/* ** m_away ** parv[1] = away message */ static int m_away(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(MyClient(source_p) && source_p->localClient->next_away && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsClient(source_p)) return 0; if(parc < 2 || EmptyString(parv[1])) { /* Marking as not away */ if(source_p->user->away != NULL) { /* we now send this only if they were away before --is */ sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY", use_id(source_p)); free_away(source_p); sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, ":%s!%s@%s AWAY", source_p->name, source_p->username, source_p->host); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_UNAWAY, form_str(RPL_UNAWAY)); return 0; } /* Rate limit this because it is sent to common channels. */ if (MyClient(source_p)) { if(!IsOper(source_p) && source_p->localClient->next_away > rb_current_time()) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "AWAY"); return 0; } if(source_p->localClient->next_away < rb_current_time() - ConfigFileEntry.away_interval) source_p->localClient->next_away = rb_current_time(); else source_p->localClient->next_away = rb_current_time() + ConfigFileEntry.away_interval; } if(source_p->user->away == NULL) allocate_away(source_p); if(strncmp(source_p->user->away, parv[1], AWAYLEN - 1)) { rb_strlcpy(source_p->user->away, parv[1], AWAYLEN); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY :%s", use_id(source_p), source_p->user->away); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_NOWAWAY, form_str(RPL_NOWAWAY)); sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, ":%s!%s@%s AWAY :%s", source_p->name, source_p->username, source_p->host, source_p->user->away); return 0; }
/* * handle_command * * inputs - pointer to message block * - pointer to client * - pointer to client message is from * - count of number of args * - pointer to argv[] array * output - -1 if error from server * side effects - */ static int handle_command(struct Message *mptr, struct Client *client_p, struct Client *from, int i, const char **hpara) { struct MessageEntry ehandler; MessageHandler handler = 0; static time_t last_warning; if(IsAnyDead(client_p)) return -1; if(IsServer(client_p)) mptr->rcount++; mptr->count++; /* New patch to avoid server flooding from unregistered connects - Pie-Man 07/27/2000 */ if(!IsRegistered(client_p)) { /* if its from a possible server connection * ignore it.. more than likely its a header thats sneaked through */ if(IsAnyServer(client_p) && !(mptr->flags & MFLG_UNREG)) return (1); } ehandler = mptr->handlers[from->handler]; handler = ehandler.handler; /* check right amount of params is passed... --is */ if(i < ehandler.min_para || (ehandler.min_para && EmptyString(hpara[ehandler.min_para - 1]))) { if(!IsServer(client_p)) { sendto_one(client_p, form_str(ERR_NEEDMOREPARAMS), me.name, EmptyString(client_p->name) ? "*" : client_p->name, mptr->cmd); if(MyClient(client_p)) return (1); else return (-1); } sendto_realops_flags(UMODE_ALL, L_ALL, "Dropping server %s due to (invalid) command '%s'" " with only %d arguments (expecting %d).", client_p->name, mptr->cmd, i, ehandler.min_para); ilog(L_SERVER, "Insufficient parameters (%d) for command '%s' from %s.", i, mptr->cmd, client_p->name); exit_client(client_p, client_p, client_p, "Not enough arguments to server command."); return (-1); } (*handler) (client_p, from, i, hpara); if(!IsAnyDead(client_p) && IsCork(client_p) && !IsCapable(client_p, CAP_ZIP)) { if(last_warning + 300 <= rb_time()) { sendto_realops_flags(UMODE_DEBUG, L_ALL, "Bug: client %s was left corked after command %s", client_p->name, mptr->cmd); last_warning = rb_time(); } client_p->localClient->cork_count = 0; send_pop_queue(client_p); } return (1); }
/* * 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; if((p = strchr(parv[1], ','))) *p = '\0'; if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsChannelName(parv[1])) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } chptr = find_channel(parv[1]); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); 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), parv[1]); return 0; } if((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || is_chanop(msptr)) { char topic_info[USERHOST_REPLYLEN]; rb_sprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, parv[2], topic_info, rb_time()); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", source_p->id, chptr->chname, chptr->topic == NULL ? "" : chptr->topic->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->topic); } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, parv[1]); } else if(MyClient(source_p)) { if(!IsMember(source_p, chptr) && SecretChannel(chptr)) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), parv[1]); return 0; } if(chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, parv[1]); else { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic->topic_info, chptr->topic->topic_time); } } return 0; }
int m_not_oper(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES)); return 0; }
/* * m_ison added by Darren Reed 13/8/91 to act as an efficent user indicator * with respect to cpu/bandwidth used. Implemented for NOTIFY feature in * clients. Designed to reduce number of whois requests. Can process * nicknames in batches as long as the maximum buffer length. * * format: * ISON :nicklist */ static void m_ison(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p; char *nick; char *p; char *current_insert_point, *current_insert_point2; int len; int i; int done = 0; current_insert_point2 = buf2; *buf2 = '\0'; ircsprintf(buf, form_str(RPL_ISON), me.name, parv[0]); len = strlen(buf); current_insert_point = buf + len; /* rfc1489 is ambigious about how to handle ISON * this should handle both interpretations. */ for (i = 1; i < parc; i++) { for (nick = strtoken(&p, parv[i], " "); nick; nick = strtoken(&p, NULL, " ")) { target_p = find_person(nick); if(target_p == NULL && (IsOper(source_p) || !ConfigServerHide.hide_servers)) { target_p = find_server(nick); } if(target_p != NULL) { len = strlen(target_p->name); if((current_insert_point + (len + 5)) < (buf + sizeof(buf))) { memcpy((void *) current_insert_point, (void *) target_p->name, len); current_insert_point += len; *current_insert_point++ = ' '; } else { done = 1; break; } } } if(done) break; } /* current_insert_point--; * Do NOT take out the trailing space, it breaks ircII * --Rodder */ *current_insert_point = '\0'; *current_insert_point2 = '\0'; sendto_one(source_p, "%s", buf); }
int m_registered(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { sendto_one(client_p, form_str(ERR_ALREADYREGISTRED), me.name, source_p->name); return 0; }
/* * send_conf_options * * inputs - client pointer to send to * output - none * side effects - send config options to client */ static void send_conf_options(struct Client *source_p) { Info *infoptr; int i = 0; /* * Now send them a list of all our configuration options * (mostly from config.h) */ for (infoptr = MyInformation; infoptr->name; infoptr++) { if(infoptr->intvalue) { sendto_one(source_p, ":%s %d %s :%-30s %-5d [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), infoptr->name, infoptr->intvalue, infoptr->desc); } else { sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), infoptr->name, infoptr->strvalue, infoptr->desc); } } /* * Parse the info_table[] and do the magic. */ for (i = 0; info_table[i].name; i++) { switch (info_table[i].output_type) { /* * For "char *" references */ case OUTPUT_STRING: { char *option = *((char **) info_table[i].option); sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option ? option : "NONE", info_table[i].desc ? info_table[i].desc : "<none>"); break; } /* * For "char foo[]" references */ case OUTPUT_STRING_PTR: { char *option = (char *) info_table[i].option; sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, EmptyString(option) ? "NONE" : option, info_table[i].desc ? info_table[i].desc : "<none>"); break; } /* * Output info_table[i].option as a decimal value. */ case OUTPUT_DECIMAL: { int option = *((int *) info_table[i].option); sendto_one(source_p, ":%s %d %s :%-30s %-5d [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option, info_table[i].desc ? info_table[i].desc : "<none>"); break; } /* * Output info_table[i].option as "ON" or "OFF" */ case OUTPUT_BOOLEAN: { int option = *((int *) info_table[i].option); sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option ? "ON" : "OFF", info_table[i].desc ? info_table[i].desc : "<none>"); break; } /* * Output info_table[i].option as "YES" or "NO" */ case OUTPUT_BOOLEAN_YN: { int option = *((int *) info_table[i].option); sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), info_table[i].name, option ? "YES" : "NO", info_table[i].desc ? info_table[i].desc : "<none>"); break; } case OUTPUT_BOOLEAN2: { int option = *((int *) info_table[i].option); sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]", me.name, RPL_INFO, source_p->name, info_table[i].name, option ? ((option == 1) ? "MASK" : "YES") : "NO", info_table[i].desc ? info_table[i].desc : "<none>"); } /* switch (info_table[i].output_type) */ } } /* forloop */ /* Don't send oper_only_umodes...it's a bit mask, we will have to decode it ** in order for it to show up properly to opers who issue INFO */ sendto_one_numeric(source_p, RPL_INFO, form_str(RPL_INFO), ""); }
/* ** mo_ojoin ** parv[0] = sender prefix ** parv[1] = channel */ static void mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr; int move_me = 0; /* admins only */ if (!IsOperAdmin(source_p)) { sendto_one(source_p, ":%s NOTICE %s :You have no A flag", me.name, parv[0]); return; } if (*parv[1] == '@' || *parv[1] == '+') { parv[1]++; move_me = 1; } chptr = hash_find_channel(parv[1]); if(chptr == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]); return; } if(IsMember(source_p, chptr)) { sendto_one(source_p, ":%s NOTICE %s :Please part %s before using OJOIN", me.name, source_p->name, parv[1]); return; } if (move_me == 1) parv[1]--; sendto_wallops_flags(UMODE_WALLOP, &me, "OJOIN called for [%s] by %s!%s@%s", parv[1], source_p->name, source_p->username, source_p->host); ilog(L_NOTICE, "OJOIN called for [%s] by %s!%s@%s", parv[1], source_p->name, source_p->username, source_p->host); if(*chptr->chname != '&') sendto_server(NULL, NULL, NOCAPS, NOCAPS, ":%s WALLOPS :OJOIN called for [%s] by %s!%s@%s", me.name, parv[1], source_p->name, source_p->username, source_p->host); if (*parv[1] == '@') { add_user_to_channel(chptr, source_p, CHFL_CHANOP); if(*chptr->chname != '&') sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %lu %s + :@%s", me.name, chptr->channelts, chptr->chname, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s", me.name, chptr->chname, source_p->name); } else if (*parv[1] == '+') { add_user_to_channel(chptr, source_p, CHFL_VOICE); if(*chptr->chname != '&') sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %lu %s + :+%s", me.name, chptr->channelts, chptr->chname, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s", me.name, chptr->chname, source_p->name); } else { add_user_to_channel(chptr, source_p, CHFL_PEON); if(*chptr->chname != '&') sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %lu %s + :%s", me.name, chptr->channelts, chptr->chname, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); } /* send the topic... */ if (chptr->topic != NULL) { 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); } source_p->localClient->last_join_time = CurrentTime; channel_member_names(chptr, source_p, 1); }
/* m_kick() * parv[0] = sender prefix * parv[1] = channel * parv[2] = client to kick * parv[3] = kick comment */ static void m_kick(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; const char *from, *to; struct Membership *ms = NULL; struct Membership *ms_target; if (!MyConnect(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 (*parv[2] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), from, to, "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'; name = parv[1]; while (*name == ',') name++; if ((p = strchr(name,',')) != NULL) *p = '\0'; if (!*name) return; if ((chptr = hash_find_channel(name)) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), from, to, name); return; } if (!IsServer(source_p)) { if ((ms = find_channel_link(source_p, chptr)) == NULL) { if (MyConnect(source_p)) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, source_p->name, name); return; } } if (!has_member_flags(ms, CHFL_CHANOWNER) && (chptr->mode.mode & MODE_PEACE)) { /* don't kick in +P mode. */ sendto_one(source_p, form_str(ERR_CHANPEACE), me.name, source_p->name, name); return; } if (!has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP|CHFL_CHANOWNER)) { /* was a user, not a server, and user isn't seen as a chanop here */ if (MyConnect(source_p)) { /* user on _my_ server, with no chanops.. so go away */ sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, name); return; } if (chptr->channelts == 0) { /* If its a TS 0 channel, do it the old way */ sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), from, to, name); return; } /* 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 */ } } user = parv[2]; while (*user == ',') user++; if ((p = strchr(user,',')) != NULL) *p = '\0'; if (!*user) return; if ((who = find_chasing(source_p, user, &chasing)) == NULL) return; if ((ms_target = find_channel_link(who, chptr)) != NULL) { /* half ops cannot kick other halfops, chanops or owners */ if (has_member_flags(ms, CHFL_HALFOP) && !has_member_flags(ms, CHFL_CHANOP)) { if ((has_member_flags(ms_target, CHFL_CHANOP|CHFL_HALFOP|CHFL_CHANOWNER))) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, name); return; } } /* 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, GET_CLIENT_HOST(source_p), name, who->name, comment); sendto_server(client_p, NULL, chptr, CAP_TS6, NOCAPS, NOFLAGS, ":%s KICK %s %s :%s", ID(source_p), chptr->chname, ID(who), comment); sendto_server(client_p, NULL, chptr, NOCAPS, CAP_TS6, NOFLAGS, ":%s KICK %s %s :%s", source_p->name, chptr->chname, who->name, comment); remove_user_from_channel(ms_target); } else sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), from, to, user, name); }
static int mo_testline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct ConfItem *aconf; struct ConfItem *resv_p; struct rb_sockaddr_storage ip; char user_trunc[USERLEN + 1], notildeuser_trunc[USERLEN + 1]; const char *name = NULL; const char *username = NULL; const char *host = NULL; char *mask; char *p; int host_mask; int type; int duration; char *puser, *phost, *reason, *operreason; char reasonbuf[BUFSIZE]; mask = LOCAL_COPY(parv[1]); if (IsChannelName(mask)) { resv_p = hash_find_resv(mask); if (resv_p != NULL) { sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, resv_p->hold ? 'q' : 'Q', resv_p->hold ? (long) ((resv_p->hold - rb_current_time()) / 60) : 0L, resv_p->host, resv_p->passwd); /* this is a false positive, so make sure it isn't counted in stats q * --nenolod */ resv_p->port--; } else sendto_one(source_p, form_str(RPL_NOTESTLINE), me.name, source_p->name, parv[1]); return 0; } if((p = strchr(mask, '!'))) { *p++ = '\0'; name = mask; mask = p; if(EmptyString(mask)) return 0; } if((p = strchr(mask, '@'))) { *p++ = '\0'; username = mask; host = p; if(EmptyString(host)) return 0; } else host = mask; /* parses as an IP, check for a dline */ if((type = parse_netmask(host, (struct sockaddr *)&ip, &host_mask)) != HM_HOST) { #ifdef RB_IPV6 if(type == HM_IPV6) aconf = find_dline((struct sockaddr *)&ip, AF_INET6); else #endif aconf = find_dline((struct sockaddr *)&ip, AF_INET); if(aconf && aconf->status & CONF_DLINE) { get_printable_kline(source_p, aconf, &phost, &reason, &puser, &operreason); rb_snprintf(reasonbuf, sizeof(reasonbuf), "%s%s%s", reason, operreason ? "|" : "", operreason ? operreason : ""); sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'd' : 'D', (aconf->flags & CONF_FLAGS_TEMPORARY) ? (long) ((aconf->hold - rb_current_time()) / 60) : 0L, phost, reasonbuf); return 0; } /* Otherwise, aconf is an exempt{} */ if(aconf == NULL && (duration = is_reject_ip((struct sockaddr *)&ip))) sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, '!', duration / 60, host, "Reject cache"); if(aconf == NULL && (duration = is_throttle_ip((struct sockaddr *)&ip))) sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, '!', duration / 60, host, "Throttled"); } if (username != NULL) { rb_strlcpy(user_trunc, username, sizeof user_trunc); rb_strlcpy(notildeuser_trunc, *username == '~' ? username + 1 : username, sizeof notildeuser_trunc); } else { rb_strlcpy(user_trunc, "dummy", sizeof user_trunc); rb_strlcpy(notildeuser_trunc, "dummy", sizeof notildeuser_trunc); } /* now look for a matching I/K/G */ if((aconf = find_address_conf(host, NULL, user_trunc, notildeuser_trunc, (type != HM_HOST) ? (struct sockaddr *)&ip : NULL, (type != HM_HOST) ? ( #ifdef RB_IPV6 (type == HM_IPV6) ? AF_INET6 : #endif AF_INET) : 0, NULL))) { static char buf[HOSTLEN+USERLEN+2]; if(aconf->status & CONF_KILL) { get_printable_kline(source_p, aconf, &phost, &reason, &puser, &operreason); rb_snprintf(buf, sizeof(buf), "%s@%s", puser, phost); rb_snprintf(reasonbuf, sizeof(reasonbuf), "%s%s%s", reason, operreason ? "|" : "", operreason ? operreason : ""); sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'k' : 'K', (aconf->flags & CONF_FLAGS_TEMPORARY) ? (long) ((aconf->hold - rb_current_time()) / 60) : 0L, buf, reasonbuf); return 0; } } /* they asked us to check a nick, so hunt for resvs.. */ if(name && (resv_p = find_nick_resv(name))) { sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, resv_p->hold ? 'q' : 'Q', resv_p->hold ? (long) ((resv_p->hold - rb_current_time()) / 60) : 0L, resv_p->host, resv_p->passwd); /* this is a false positive, so make sure it isn't counted in stats q * --nenolod */ resv_p->port--; return 0; } /* no matching resv, we can print the I: if it exists */ if(aconf && aconf->status & CONF_CLIENT) { sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE), aconf->info.name, EmptyString(aconf->spasswd) ? "<NULL>" : aconf->spasswd, show_iline_prefix(source_p, aconf, aconf->user), aconf->host, aconf->port, aconf->className); return 0; } /* nothing matches.. */ sendto_one(source_p, form_str(RPL_NOTESTLINE), me.name, source_p->name, parv[1]); return 0; }
/* * m_challenge - generate RSA challenge for wouldbe oper * parv[0] = sender prefix * parv[1] = operator to challenge for, or +response * */ static void m_challenge( struct Client *client_p, struct Client *source_p, int parc, char *parv[] ) { char * challenge; dlink_node *ptr; struct ConfItem *aconf, *oconf; if(!(source_p->user) || !source_p->localClient) return; /* if theyre an oper, reprint oper motd and ignore */ if(IsOper(source_p)) { sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, parv[0]); SendMessageFile(source_p, &ConfigFileEntry.opermotd); return; } if (*parv[1] == '+') { /* Ignore it if we aren't expecting this... -A1kmm */ if (!source_p->user->response) return; if (irccmp(source_p->user->response, ++parv[1])) { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name); log_foper(source_p, source_p->user->auth_oper); if(ConfigFileEntry.failed_oper_notice) sendto_realops_flags(UMODE_ALL, L_ALL, "Failed OPER attempt by %s (%s@%s)", source_p->name, source_p->username, source_p->host); return; } if ((aconf = find_conf_by_name(source_p->user->auth_oper, CONF_OPERATOR)) == NULL) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, parv[0]); log_foper(source_p, source_p->user->auth_oper); if(ConfigFileEntry.failed_oper_notice) sendto_realops_flags(UMODE_ALL, L_ALL, "Failed CHALLENGE attempt - host mismatch by %s (%s@%s)", source_p->name, source_p->username, source_p->host); return; } ptr = source_p->localClient->confs.head; oconf = ptr->data; detach_conf(source_p,oconf); if(attach_conf(source_p, aconf) != 0) { sendto_one(source_p,":%s NOTICE %s :Can't attach conf!", me.name,source_p->name); sendto_realops_flags(UMODE_ALL, L_ALL, "Failed CHALLENGE attempt by %s (%s@%s) can't attach conf!", source_p->name, source_p->username, source_p->host); log_foper(source_p, source_p->user->auth_oper); attach_conf(source_p, oconf); return; } oper_up(source_p, aconf); ilog(L_TRACE, "OPER %s by %s!%s@%s", source_p->user->auth_oper, source_p->name, source_p->username, source_p->host); log_oper(source_p, source_p->user->auth_oper); MyFree(source_p->user->response); MyFree(source_p->user->auth_oper); source_p->user->response = NULL; source_p->user->auth_oper = NULL; return; } MyFree(source_p->user->response); MyFree(source_p->user->auth_oper); source_p->user->response = NULL; source_p->user->auth_oper = NULL; if (!(aconf = find_conf_exact(parv[1], source_p->username, source_p->host, CONF_OPERATOR)) && !(aconf = find_conf_exact(parv[1], source_p->username, source_p->localClient->sockhost, CONF_OPERATOR))) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, parv[0]); log_foper(source_p, source_p->user->auth_oper); if(ConfigFileEntry.failed_oper_notice) sendto_realops_flags(UMODE_ALL, L_ALL, "Failed CHALLENGE attempt - host mismatch by %s (%s@%s)", source_p->name, source_p->username, source_p->host); return; } if(!aconf->rsa_public_key) { sendto_one(source_p, ":%s NOTICE %s :I'm sorry, PK authentication " "is not enabled for your oper{} block.", me.name, parv[0]); return; } if(!generate_challenge(&challenge, &(source_p->user->response), aconf->rsa_public_key)) { sendto_one(source_p, form_str(RPL_RSACHALLENGE), me.name, parv[0], challenge); } DupString(source_p->user->auth_oper, aconf->name); MyFree(challenge); return; }
int m_info(aClient *cptr, aClient *sptr, int parc, char *parv[]) { char **text = infotext; static time_t last_used=0L; Info *infoptr; if(IsServer(sptr)) return 0; if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME) { sendto_realops_flags(FLAGS_SPY, "info requested by %s (%s@%s) [%s]", sptr->name, sptr->username, sptr->host, sptr->user->server); if (!IsAnOper(sptr)) { /* reject non local requests */ if (!MyConnect(sptr)) return 0; if ((last_used + PACE_WAIT) > CurrentTime) { /* safe enough to give this on a local connect only */ sendto_one(sptr,form_str(RPL_LOAD2HI),me.name,parv[0]); return 0; } else last_used = CurrentTime; } /* if (!IsAnOper(sptr)) */ while (*text) sendto_one(sptr, form_str(RPL_INFO), me.name, parv[0], *text++); /* * Now send them a list of all our configuration options * (mostly from config.h) */ if (IsAnOper(sptr)) { sendto_one(sptr, form_str(RPL_INFO), me.name, parv[0], "Compile-time configuration options:"); for (infoptr = MyInformation; infoptr->name; infoptr++) { if (infoptr->intvalue) sendto_one(sptr, ":%s %d %s :%-30s %-5d [%-30s]", me.name, RPL_INFO, parv[0], infoptr->name, infoptr->intvalue, infoptr->desc); else sendto_one(sptr, ":%s %d %s :%-30s %-5s [%-30s]", me.name, RPL_INFO, parv[0], infoptr->name, infoptr->strvalue, infoptr->desc); } sendto_one(sptr, form_str(RPL_INFO), me.name, parv[0], ""); #ifndef SERVERHIDE sendto_one(sptr, ":%s %d %s :Compiled on [%s]", me.name, RPL_INFO, parv[0], platform); #endif sendto_one(sptr, form_str(RPL_INFO), me.name, parv[0], ""); } /* if (IsAnOper(sptr)) */ sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile #%s", me.name, RPL_INFO, parv[0], creation, generation); sendto_one(sptr, ":%s %d %s :On-line since %s", me.name, RPL_INFO, parv[0], myctime(me.firsttime)); sendto_one(sptr, form_str(RPL_ENDOFINFO), me.name, parv[0]); } /* if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME) */ return 0; } /* m_info() */
/* ** m_okick ** parv[1] = channel ** parv[2] = client to kick ** parv[3] = kick comment */ static int mo_okick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *who; struct Client *target_p; struct Channel *chptr; struct membership *msptr; int chasing = 0; char *comment; char *name; char *p = NULL; char *user; char text[10]; static char buf[BUFSIZE]; if(*parv[2] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "KICK"); return 0; } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); comment = (EmptyString(LOCAL_COPY(parv[3]))) ? LOCAL_COPY(parv[2]) : LOCAL_COPY(parv[3]); if(strlen(comment) > (size_t) TOPICLEN) comment[TOPICLEN] = '\0'; *buf = '\0'; if((p = strchr(parv[1], ','))) *p = '\0'; name = LOCAL_COPY(parv[1]); chptr = find_channel(name); if(!chptr) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if((p = strchr(parv[2], ','))) *p = '\0'; user = LOCAL_COPY(parv[2]); // strtoken(&p2, parv[2], ","); if(!(who = find_chasing(source_p, user, &chasing))) { return 0; } if((target_p = find_client(user)) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, user); return 0; } if((msptr = find_channel_membership(chptr, target_p)) == NULL) { sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), me.name, source_p->name, parv[1], parv[2]); return 0; } sendto_realops_snomask(SNO_GENERAL, L_ALL, "OKICK called for %s %s by %s!%s@%s", chptr->chname, target_p->name, source_p->name, source_p->username, source_p->host); ilog(L_MAIN, "OKICK called for %s %s by %s", chptr->chname, target_p->name, get_oper_name(source_p)); sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s", me.name, chptr->chname, who->name, comment); sendto_server(&me, chptr, CAP_TS6, NOCAPS, ":%s KICK %s %s :%s", me.id, chptr->chname, who->id, 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"); return 0; }
/* ** mo_forcenick ** parv[1] = forcenick victim ** parv[2] = new nickname */ static int mo_forcenick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p, *exist_p; const char *user; const char *newnick; user = parv[1]; /* You must be this tall to ride the ride */ if(!IsOperLocalForce(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "local_force"); return 0; } /* Truncate it so clean_nick doesn't spaz out */ if(!EmptyString(parv[2])) { char *s; s = LOCAL_COPY(parv[2]); if(strlen(s) > (size_t) NICKLEN) s[NICKLEN] = '\0'; newnick = s; } else { sendto_one_numeric(source_p, ERR_NONICKNAMEGIVEN, form_str(ERR_NONICKNAMEGIVEN), me.name, source_p->name); return 0; } /* Nick has to be clean or we'll have a protocol violation... */ if(!clean_nick(newnick)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, user, newnick); return 0; } /* Find the target... */ if((target_p = find_named_person(user)) == NULL) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "FORCENICK"); return 0; } /* If it's a server, sod it, changing its name is stupid... */ if(IsServer(target_p) || IsMe(target_p)) { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), user); return 0; } /* Do we have permission to send it globally? */ if(!MyClient(target_p) && (!IsOperGlobalForce(source_p))) { sendto_one_notice(source_p, ":Nick %s is not on your server and you do not have the global_force flag", target_p->name); return 0; } /* Check to see if the new nick exists */ if((exist_p = find_named_person(newnick)) != NULL) { /* Could just be a case shift */ if(irccmp(target_p->name, newnick)) { sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, user, newnick); return 0; } /* If it's the same nick, f**k it */ else if(!strcmp(target_p->name, newnick)) return 0; } sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Received FORCENICK message for %s!%s@%s. From %s (Newnick: %s)", target_p->name, target_p->username, target_p->orighost, source_p->name, newnick); ilog(L_MAIN, "FORCENICK called for [%s] by %s!%s@%s", target_p->name, source_p->name, source_p->username, source_p->host); sendto_one_notice(target_p, ":You have been forcenicked from %s to %s by %s", target_p->name, newnick, source_p->name); if(!MyClient(target_p)) { struct Client *cptr = target_p->servptr; sendto_one(cptr, ":%s ENCAP %s FORCENICK %s :%s", get_id(source_p, cptr), cptr->name, get_id(target_p, cptr), newnick); return 0; } change_nick(target_p, newnick); return 0; }
/* ** m_ltrace - LimitedTRACE... like m_trace() but doesn't return TRACEUSER, TRACEUNKNOWN, or TRACECLASS ** parv[0] = sender prefix ** parv[1] = servername */ int m_ltrace(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { int i; struct Client *acptr = NULL; char *tname; int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS]; int cnt = 0, wilds, dow; static time_t now; if (check_registered(sptr)) return 0; #ifdef SERVERHIDE if (!IsAnOper(sptr)) return 0; #endif if (parc > 2) if (hunt_server(cptr, sptr, ":%s LTRACE %s :%s", 2, parc, parv)) return 0; if (parc > 1) tname = parv[1]; else tname = me.name; switch (hunt_server(cptr, sptr, ":%s LTRACE :%s", 1, parc, parv)) { case HUNTED_PASS: /* note: gets here only if parv[1] exists */ { struct Client *ac2ptr; ac2ptr = next_client(GlobalClientList, tname); if (ac2ptr) sendto_one(sptr, form_str(RPL_TRACELINK), me.name, parv[0], ircd_version, debugmode, tname, ac2ptr->from->name); else sendto_one(sptr, form_str(RPL_TRACELINK), me.name, parv[0], ircd_version, debugmode, tname, "ac2ptr_is_NULL!!"); return 0; } case HUNTED_ISME: break; default: return 0; } if(MyClient(sptr)) sendto_realops_flags(FLAGS_SPY, "ltrace requested by %s (%s@%s) [%s]", sptr->name, sptr->username, sptr->host, sptr->user->server); doall = (parv[1] && (parc > 1)) ? match(tname, me.name): TRUE; wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?'); dow = wilds || doall; if(!IsAnOper(sptr) || !dow) /* non-oper traces must be full nicks */ /* lets also do this for opers tracing nicks */ { const char* name; const char* ip; int c_class; acptr = hash_find_client(tname,(struct Client *)NULL); if(!acptr || !IsPerson(acptr)) { /* this should only be reached if the matching target is this server */ sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0], tname); return 0; } name = get_client_name(acptr, FALSE); ip = inetntoa((char*) &acptr->ip); c_class = get_client_class(acptr); if (IsAnOper(acptr)) { sendto_one(sptr, form_str(RPL_TRACEOPERATOR), me.name, parv[0], c_class, name, IsAnOper(sptr)?ip:(IsIPHidden(acptr)?"255.255.255.255":ip), now - acptr->lasttime, (acptr->user)?(now - acptr->user->last):0); } sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0], tname); return 0; } for (i = 0; i < MAXCONNECTIONS; i++) link_s[i] = 0, link_u[i] = 0; if (dow && LIFESUX && !IsOper(sptr)) { sendto_one(sptr,form_str(RPL_LOAD2HI),me.name,parv[0]); return 0; } /* * Count up all the servers and clients in a downlink. */ if (doall) { for (acptr = GlobalClientList; acptr; acptr = acptr->next) { if (IsServer(acptr)) ++link_s[acptr->from->fd]; } } /* report all direct connections */ now = time(NULL); for (i = 0; i <= highest_fd; i++) { const char* name; const char* ip; int c_class; if (!(acptr = local[i])) /* Local Connection? */ continue; if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsAnOper(sptr)) && !IsAnOper(acptr) && (acptr != sptr)) continue; if (!doall && wilds && !match(tname, acptr->name)) continue; if (!dow && irccmp(tname, acptr->name)) continue; name = get_client_name(acptr, FALSE); ip = inetntoa((const char*) &acptr->ip); c_class = get_client_class(acptr); switch(acptr->status) { case STAT_HANDSHAKE: #ifdef HIDE_SERVERS_IPS name=get_client_name(acptr, MASK_IP); #endif sendto_one(sptr, form_str(RPL_TRACEHANDSHAKE), me.name, parv[0], c_class, name); cnt++; break; case STAT_CONNECTING: #ifdef HIDE_SERVERS_IPS name=get_client_name(acptr, MASK_IP); #endif sendto_one(sptr, form_str(RPL_TRACECONNECTING), me.name, parv[0], c_class, name); cnt++; break; case STAT_ME: break; case STAT_CLIENT: /* Well, most servers don't have a LOT of OPERs... let's show them too */ if ((IsAnOper(sptr) && (MyClient(sptr) || !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr)) { if (IsAnOper(acptr)) sendto_one(sptr, form_str(RPL_TRACEOPERATOR), me.name, parv[0], c_class, name, IsAnOper(sptr)?ip:(IsIPHidden(acptr)?"255.255.255.255":ip), now - acptr->lasttime, (acptr->user)?(now - acptr->user->last):0); cnt++; } break; case STAT_SERVER: #if 0 if (acptr->serv->user) sendto_one(sptr, form_str(RPL_TRACESERVER), me.name, parv[0], c_class, link_s[i], link_u[i], name, acptr->serv->by, acptr->serv->user->username, acptr->serv->user->host, now - acptr->lasttime); else #endif #ifdef HIDE_SERVERS_IPS name=get_client_name(acptr, MASK_IP); #endif sendto_one(sptr, form_str(RPL_TRACESERVER), me.name, parv[0], c_class, link_s[i], link_u[i], name, *(acptr->serv->by) ? acptr->serv->by : "*", "*", me.name, now - acptr->lasttime); cnt++; break; default: /* ...we actually shouldn't come here... --msa */ sendto_one(sptr, form_str(RPL_TRACENEWTYPE), me.name, parv[0], name); cnt++; break; } } /* * Add these lines to summarize the above which can get rather long * and messy when done remotely - Avalon */ if (!IsAnOper(sptr) || !cnt) { if (cnt) return 0; /* let the user have some idea that its at the end of the * trace */ sendto_one(sptr, form_str(RPL_TRACESERVER), me.name, parv[0], 0, link_s[me.fd], link_u[me.fd], me.name, "*", "*", me.name); sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0],tname); return 0; } sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0],tname); return 0; }
/* ** mo_ojoin ** parv[1] = channel */ static int mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; int move_me = 0; /* admins only */ if(!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin"); return 0; } if(*parv[1] == '@' || *parv[1] == '%' || *parv[1] == '+' || *parv[1] == '&' || *parv[1] == '~') { parv[1]++; move_me = 1; } if((chptr = find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } if(IsMember(source_p, chptr)) { sendto_one_notice(source_p, ":Please part %s before using OJOIN", parv[1]); return 0; } if(move_me == 1) parv[1]--; sendto_wallops_flags(UMODE_WALLOP, &me, "OJOIN called for %s by %s!%s@%s", parv[1], source_p->name, source_p->username, source_p->host); ilog(L_MAIN, "OJOIN called for %s by %s", parv[1], get_oper_name(source_p)); /* only sends stuff for #channels remotely */ sendto_server(NULL, chptr, NOCAPS, NOCAPS, ":%s WALLOPS :OJOIN called for %s by %s!%s@%s", me.name, parv[1], source_p->name, source_p->username, source_p->host); if(*parv[1] == '~' && ConfigChannel.use_owner) { add_user_to_channel(chptr, source_p, CHFL_OWNER); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :~%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +q %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '&' && ConfigChannel.use_admin) { add_user_to_channel(chptr, source_p, CHFL_ADMIN); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :!%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +a %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '@') { add_user_to_channel(chptr, source_p, CHFL_CHANOP); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :@%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '%' && ConfigChannel.use_halfop) { add_user_to_channel(chptr, source_p, CHFL_HALFOP); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :%s%s", me.id, (long) chptr->channelts, chptr->chname, "%", source_p->id); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +h %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '+') { add_user_to_channel(chptr, source_p, CHFL_VOICE); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :+%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s", me.name, chptr->chname, source_p->name); } else { add_user_to_channel(chptr, source_p, CHFL_PEON); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s JOIN %ld %s +", source_p->id, (long) chptr->channelts, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); } /* send the topic... */ if(chptr->topic != NULL) { 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); } source_p->localClient->last_join_time = rb_current_time(); channel_member_names(chptr, source_p, 1); return 0; }