/* ** m_info ** parv[0] = sender prefix ** parv[1] = servername */ static int m_info(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { static time_t last_used = 0L; if((last_used + ConfigFileEntry.pace_wait) > rb_current_time()) { /* safe enough to give this on a local connect only */ sendto_one_numeric(source_p, s_RPL(RPL_LOAD2HI), "INFO"); sendto_one_numeric(source_p, s_RPL(RPL_ENDOFINFO)); return 0; } else last_used = rb_current_time(); if(hunt_server(client_p, source_p, ":%s INFO :%s", 1, parc, parv) != HUNTED_ISME) return 0; info_spy(source_p); SetCork(source_p); send_info_text(source_p); send_birthdate_online_time(source_p); ClearCork(source_p); sendto_one_numeric(source_p, s_RPL(RPL_ENDOFINFO)); return 0; }
/* * send_info_text * * inputs - client pointer to send info text to * output - none * side effects - info text is sent to client */ static void send_info_text(struct Client *source_p) { const char **text; ratbox_infotext(&text); while(*text) { sendto_one_numeric(source_p, s_RPL(RPL_INFO), *text++); } sendto_one_numeric(source_p, s_RPL(RPL_INFO), ""); }
static int m_ison(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; char *nick; char *p; char buf[IRCD_BUFSIZE]; int i; memset(buf, 0, sizeof(buf)); for(i = 1; i < parc; i++) { char *cs = LOCAL_COPY(parv[i]); for(nick = rb_strtok_r(cs, " ", &p); nick; nick = rb_strtok_r(NULL, " ", &p)) { target_p = find_named_client(nick); if(target_p != NULL) { rb_strlcat(buf, target_p->name, sizeof(buf)); rb_strlcat(buf, " ", sizeof(buf)); } } } sendto_one_numeric(source_p, s_RPL(RPL_ISON), buf); 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++; 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_numeric(client_p, s_RPL(ERR_NEEDMOREPARAMS), 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); } if(handler == NULL) /* module hasn't set a handler, just use m_ignore */ handler = m_ignore; (*handler) (client_p, from, i, hpara); if(!IsAnyDead(client_p) && IsCork(client_p) && !IsCapable(client_p, CAP_ZIP)) { if(last_warning + 300 <= rb_current_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_current_time(); } client_p->localClient->cork_count = 0; send_pop_queue(client_p); } return (1); }
static int mo_testgecos(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct ConfItem *aconf; if(!(aconf = find_xline(parv[1], 0))) { sendto_one_numeric(source_p, s_RPL(RPL_NOTESTLINE), parv[1]); return 0; } sendto_one_numeric(source_p, s_RPL(RPL_TESTLINE), (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'x' : 'X', (aconf->flags & CONF_FLAGS_TEMPORARY) ? (time_t)((aconf->hold - rb_current_time()) / 60) : (time_t)0L, aconf->host, aconf->passwd); return 0; }
static int mo_adminwall(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(!IsAdmin(source_p)) { sendto_one_numeric(source_p, s_RPL(ERR_NOPRIVS), "adminwall"); return 0; } sendto_wallops_flags(UMODE_ADMIN, source_p, "ADMINWALL - %s", parv[1]); sendto_match_servs(source_p, "*", CAP_ENCAP, NOCAPS, "ENCAP * ADMINWALL :%s", parv[1]); return 0; }
/* ** m_motd ** parv[0] = sender prefix ** parv[1] = servername */ static int m_motd(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { static time_t last_used = 0; if((last_used + ConfigFileEntry.pace_wait) > rb_current_time()) { /* safe enough to give this on a local connect only */ sendto_one_numeric(source_p, s_RPL(RPL_LOAD2HI), "MOTD"); sendto_one_numeric(source_p, s_RPL(RPL_ENDOFMOTD)); return 0; } else last_used = rb_current_time(); if(hunt_server(client_p, source_p, ":%s MOTD :%s", 1, parc, parv) != HUNTED_ISME) return 0; motd_spy(source_p); send_user_motd(source_p); return 0; }
static int m_cap(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct clicap_cmd *cmd; if(!(cmd = bsearch(parv[1], clicap_cmdlist, sizeof(clicap_cmdlist) / sizeof(struct clicap_cmd), sizeof(struct clicap_cmd), (bqcmp) clicap_cmd_search))) { sendto_one_numeric(source_p, s_RPL(ERR_INVALIDCAPCMD), parv[1]); return 0; } (cmd->func) (source_p, parv[2]); return 0; }
/* * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce * the need for complicated requests like WHOIS. It returns user/host * information only (no spurious AWAY labels or channels). */ static int m_userhost(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; char response[IRCD_BUFSIZE]; int i; memset(response, 0, sizeof(response)); /* XXX why 5 here? */ for(i = 1; i <= 5; i++) { if(parc < i + 1) break; if((target_p = find_person(parv[i])) != NULL) { /* * Show real IP for USERHOST on yourself. * This is needed for things like mIRC, which do a server-based * lookup (USERHOST) to figure out what the clients' local IP * is. Useful for things like NAT, and dynamic dial-up users. */ if(MyClient(target_p) && (target_p == source_p)) { rb_snprintf_append(response, sizeof(response), "%s%s=%c%s@%s ", target_p->name, IsOper(target_p) ? "*" : "", (target_p->user->away) ? '-' : '+', target_p->username, target_p->sockhost); } else { rb_snprintf_append(response, sizeof(response), "%s%s=%c%s@%s ", target_p->name, IsOper(target_p) ? "*" : "", (target_p->user->away) ? '-' : '+', target_p->username, target_p->host); } } } sendto_one_numeric(source_p, s_RPL(RPL_USERHOST), response); return 0; }
int m_unregistered(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { /* bit of a hack. * I don't =really= want to waste a bit in a flag * number_of_nick_changes is only really valid after the client * is fully registered.. */ if(IsAnyServer(client_p)) return 0; if(client_p->localClient->number_of_nick_changes == 0) { sendto_one_numeric(client_p, s_RPL(ERR_NOTREGISTERED)); client_p->localClient->number_of_nick_changes++; } return 0; }
/* ** mo_info ** parv[0] = sender prefix ** parv[1] = servername */ static int mo_info(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(hunt_server(client_p, source_p, ":%s INFO :%s", 1, parc, parv) == HUNTED_ISME) { info_spy(source_p); SetCork(source_p); send_info_text(source_p); if(IsOper(source_p)) { send_conf_options(source_p); sendto_one(source_p, ":%s %d %s :%s", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), rb_lib_version()); } send_birthdate_online_time(source_p); ClearCork(source_p); sendto_one_numeric(source_p, s_RPL(RPL_ENDOFINFO)); } return 0; }
.handlers[OPER_HANDLER] = { .handler = mo_die }, }; mapi_clist_av1 die_clist[] = { &die_msgtab, NULL }; DECLARE_MODULE_AV1(die, NULL, NULL, die_clist, NULL, NULL, "$Revision$"); /* * mo_die - DIE command handler */ static int mo_die(struct Client *client_p __unused, struct Client *source_p, int parc, const char *parv[]) { if(!IsOperDie(source_p)) { sendto_one_numeric(source_p, s_RPL(ERR_NOPRIVS), "die"); return 0; } if(parc < 2 || EmptyString(parv[1])) { sendto_one_notice(source_p, ":Need server name /die %s", me.name); return 0; } else if(irccmp(parv[1], me.name)) { sendto_one_notice(source_p, ":Mismatch on /die %s", me.name); return 0; } ircd_shutdown(get_client_name(source_p, HIDE_IP));
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; const char *name = NULL; const char *username = NULL; const char *host = NULL; char *mask; char *p; int host_mask; int type; mask = LOCAL_COPY(parv[1]); if(IsChannelName(mask)) { resv_p = hash_find_resv(mask); if(resv_p != NULL) { sendto_one_numeric(source_p, s_RPL(RPL_TESTLINE), (resv_p->flags & CONF_FLAGS_TEMPORARY) ? 'q' : 'Q', (resv_p->flags & CONF_FLAGS_TEMPORARY) ? (time_t)((resv_p->hold - rb_current_time ()) / 60) : (time_t)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_numeric(source_p, s_RPL(RPL_NOTESTLINE), 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) { aconf = find_dline((struct sockaddr *) &ip); if(aconf && aconf->status & CONF_DLINE) { sendto_one_numeric(source_p, s_RPL(RPL_TESTLINE), (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'd' : 'D', (aconf->flags & CONF_FLAGS_TEMPORARY) ? (time_t)((aconf->hold - rb_current_time()) / 60) : (time_t)0L, aconf->host, aconf->passwd); return 0; } } /* now look for a matching I/K/G */ if((aconf = find_address_conf(host, NULL, username ? username : "******", (type != HM_HOST) ? (struct sockaddr *) &ip : NULL, (type != HM_HOST) ? ( #ifdef RB_IPV6 (type == HM_IPV6) ? AF_INET6 : #endif AF_INET) : 0))) { char buf[HOSTLEN + USERLEN + 2]; if(aconf->status & CONF_KILL) { snprintf(buf, sizeof(buf), "%s@%s", aconf->user, aconf->host); sendto_one_numeric(source_p, s_RPL(RPL_TESTLINE), (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'k' : 'K', (aconf->flags & CONF_FLAGS_TEMPORARY) ? (time_t)((aconf->hold - rb_current_time()) / 60) : (time_t)0L, buf, aconf->passwd); return 0; } else if(aconf->status & CONF_GLINE) { snprintf(buf, sizeof(buf), "%s@%s", aconf->user, aconf->host); sendto_one_numeric(source_p, s_RPL(RPL_TESTLINE), 'G', (time_t)((aconf->hold - rb_current_time()) / 60), buf, aconf->passwd); return 0; } } /* they asked us to check a nick, so hunt for resvs.. */ if(name && (resv_p = find_nick_resv(name))) { sendto_one_numeric(source_p, s_RPL(RPL_TESTLINE), (resv_p->flags & CONF_FLAGS_TEMPORARY) ? 'q' : 'Q', (resv_p->flags & CONF_FLAGS_TEMPORARY) ? (time_t)((resv_p->hold - rb_current_time()) / 60) : (time_t)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, s_RPL(RPL_STATSILINE), aconf->info.name, show_iline_prefix(source_p, aconf, aconf->user), aconf->host, aconf->port, get_class_name(aconf)); return 0; } /* nothing matches.. */ sendto_one_numeric(source_p, s_RPL(RPL_NOTESTLINE), parv[1]); return 0; }
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_numeric(source_p, s_RPL(ERR_VOICENEEDED), 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_numeric(target_p, s_RPL(RPL_UMODEGMSG), 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; }
/* 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; static char *para[MAXPARA + 2]; static char *sender; 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_any_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_find_data(HASH_COMMAND, ch); /* no command or its encap only, error */ if(mptr == NULL || mptr->cmd == NULL) { /* * 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_numeric(from, s_RPL(ERR_UNKNOWNCOMMAND), 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'; /* ugh. so rb_string_to_array isn't brain damaged like the original one * however..so accomdate the old behavior, pass ¶[1] * and add + 1 to i...the rest of this mess can e fixed */ if(s != NULL) i = rb_string_to_array(s, ¶[1], MAXPARA) + 1; 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 **)(uintptr_t) 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]); } } }
int m_registered(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { sendto_one_numeric(client_p, s_RPL(ERR_ALREADYREGISTRED)); 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, s_RPL(RPL_INFO), ""); }
/* ** mo_ojoin ** parv[0] = sender prefix ** 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_numeric(source_p, s_RPL(ERR_NOPRIVS), "ojoin"); return 0; } if(*parv[1] == '@' || *parv[1] == '+') { parv[1]++; move_me = 1; } if((chptr = find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, s_RPL(ERR_NOSUCHCHANNEL), parv[1]); return 0; } 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 0; } if(move_me == 1) parv[1]--; if(*parv[1] == '@') { add_user_to_channel(chptr, source_p, CHFL_CHANOP); sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %ld %s + :@%s", me.name, (long)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); sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %ld %s + :+%s", me.name, (long)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); sendto_server(client_p, chptr, NOCAPS, NOCAPS, ":%s SJOIN %ld %s + :%s", me.name, (long)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_numeric(source_p, s_RPL(RPL_TOPIC), chptr->chname, chptr->topic->topic); sendto_one_numeric(source_p, s_RPL(RPL_TOPICWHOTIME), chptr->chname, chptr->topic->topic_info, chptr->topic->topic_time); } source_p->localClient->last_join_time = rb_current_time(); channel_member_names(chptr, source_p, 1); return 0; }