static int try_local_join_chan(u_sourceinfo *si, char *chan, char *key) { u_chan *c, *fwd; u_chanuser *cu; bool created; int num; char *modes; /* verify entry */ if (!(c = u_chan_get_or_create(chan))) return u_user_num(si->u, ERR_NOSUCHCHANNEL, chan); created = c->ts == NOW.tv_sec; /* is this ok? */ if ((cu = u_chan_user_find(c, si->u)) != NULL) return 0; if ((num = u_entry_blocked(c, si->u, key)) != 0) { fwd = u_find_forward(c, si->u, key); if (fwd == NULL || u_chan_user_find(fwd, si->u)) return u_user_num(si->u, num, c); c = fwd; } /* perform join */ cu = u_chan_user_add(c, si->u); u_del_invite(c, si->u); if (created) cu->flags |= CU_PFX_OP; /* send messages */ u_sendto_chan(c, NULL, ST_USERS, ":%H JOIN %C", si->u, c); modes = u_chan_modes(c, 1); if (created) { u_log(LG_VERBOSE, "Channel %C %s created by %U", c, modes, si->u); u_conn_f(si->link, ":%S MODE %C %s", &me, c, modes); } if (!(c->flags & CHAN_LOCAL)) { if (c->members->size == 1) { u_sendto_servers(NULL, ":%S SJOIN %u %C %s :%s%U", &me, c->ts, c, modes, (cu->flags & CU_PFX_OP) ? "@" : "", si->u); } else { u_sendto_servers(NULL, ":%U JOIN %u %C +", si->u, c->ts, c); } } /* Credit them */ u_ratelimit_who_credit(si->u); u_chan_send_topic(c, si->u); u_chan_send_names(c, si->u); return 0; }
/* this function is carefully written to handle both local and remote users and servers. */ static int c_a_mode(u_sourceinfo *si, u_msg *msg) { char *target = msg->argv[0]; int parc; char **parv; u_chan *c; u_modes m; struct cmode_stacker_private stack; if (!strchr(CHANTYPES, *target)) { u_user *tu = u_user_by_ref(si->source, target); if (tu == NULL) { /* legacy chary behavior */ u_user_num(si->u, ERR_NOSUCHCHANNEL, target); } else if (si->u != tu) { u_user_num(si->u, ERR_USERSDONTMATCH); } else { return mode_user(si, msg->argv[1]); } return 0; } if (!(c = u_chan_get(target))) return u_user_num(si->u, ERR_NOSUCHCHANNEL, target); m.access = NULL; m.flags = 0; if (SRC_IS_LOCAL_USER(si)) { u_chanuser *cu = u_chan_user_find(c, si->u); if (msg->argc == 1) { return u_user_num(si->u, RPL_CHANNELMODEIS, c, u_chan_modes(c, !!cu)); } if (cu && (cu->flags & CU_PFX_OP)) m.access = cu; } else { /* source is local server or remote user/server */ m.flags |= MODE_FORCE_ALL; if (msg->argc == 1) return 0; } parc = msg->argc - 1; parv = msg->argv + 1; if (parc > 5) parc = 5; m.ctx = &cmodes; m.stacker = &cmode_stacker; m.setter = si; m.target = c; m.stack = &stack; u_mode_process(&m, parc, parv); if (SRC_IS_LOCAL_USER(si)) { if (m.errors & MODE_ERR_NO_ACCESS) u_src_num(si, ERR_CHANOPRIVSNEEDED, c); if (m.errors & MODE_ERR_NOT_OPER) u_src_num(si, ERR_NOPRIVILEGES); } return 0; }