void change_user_realname(User * user, const char *realname) { if (user->realname) free(user->realname); user->realname = sstrdup(realname); if (user->na && (nick_identified(user) || (!(user->na->nc->flags & NI_SECURE) && nick_recognized(user)))) { if (user->na->last_realname) free(user->na->last_realname); user->na->last_realname = sstrdup(realname); } if (debug) alog("debug: %s changes its realname to %s", user->nick, realname); }
/** * check_memos: See if the given user has any unread memos, and send a * NOTICE to that user if so (and if the appropriate flag is * set). * @param u User Struct * @return void */ void check_memos(User * u) { NickCore *nc; int i, newcnt = 0; if (!u) { if (debug) { alog("debug: check_memos called with NULL values"); } return; } if (!(nc = (u->na ? u->na->nc : NULL)) || !nick_recognized(u) || !(nc->flags & NI_MEMO_SIGNON)) { return; } for (i = 0; i < nc->memos.memocount; i++) { if (nc->memos.memos[i].flags & MF_UNREAD) newcnt++; } if (newcnt > 0) { notice_lang(s_MemoServ, u, newcnt == 1 ? MEMO_HAVE_NEW_MEMO : MEMO_HAVE_NEW_MEMOS, newcnt); if (newcnt == 1 && (nc->memos.memos[i - 1].flags & MF_UNREAD)) { notice_lang(s_MemoServ, u, MEMO_TYPE_READ_LAST, s_MemoServ); } else if (newcnt == 1) { for (i = 0; i < nc->memos.memocount; i++) { if (nc->memos.memos[i].flags & MF_UNREAD) break; } notice_lang(s_MemoServ, u, MEMO_TYPE_READ_NUM, s_MemoServ, nc->memos.memos[i].number); } else { notice_lang(s_MemoServ, u, MEMO_TYPE_LIST_NEW, s_MemoServ); } } if (nc->memos.memomax > 0 && nc->memos.memocount >= nc->memos.memomax) { if (nc->memos.memocount > nc->memos.memomax) notice_lang(s_MemoServ, u, MEMO_OVER_LIMIT, nc->memos.memomax); else notice_lang(s_MemoServ, u, MEMO_AT_LIMIT, nc->memos.memomax); } }
void update_host(User * user) { if (user->na && (nick_identified(user) || (!(user->na->nc->flags & NI_SECURE) && nick_recognized(user)))) { if (user->na->last_usermask) free(user->na->last_usermask); user->na->last_usermask = smalloc(strlen(common_get_vident(user)) + strlen(common_get_vhost(user)) + 2); sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user), common_get_vhost(user)); } if (debug) alog("debug: %s changes its host to %s", user->nick, common_get_vhost(user)); }
void change_user_username(User * user, const char *username) { if (user->vident) free(user->vident); user->vident = sstrdup(username); if (user->na && (nick_identified(user) || (!(user->na->nc->flags & NI_SECURE) && nick_recognized(user)))) { if (user->na->last_usermask) free(user->na->last_usermask); user->na->last_usermask = smalloc(strlen(common_get_vident(user)) + strlen(common_get_vhost(user)) + 2); sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user), common_get_vhost(user)); } if (debug) alog("debug: %s changes its username to %s", user->nick, username); }
/** * The /ms cancel command. * @param u The user who issued the command * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing. **/ int do_cancel(User * u) { int ischan; int isforbid; char *name = strtok(NULL, " "); MemoInfo *mi; if (!name) { syntax_error(s_MemoServ, u, "CANCEL", MEMO_CANCEL_SYNTAX); } else if (!nick_recognized(u)) { notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ); } else if (!(mi = getmemoinfo(name, &ischan, &isforbid))) { if (isforbid) { notice_lang(s_MemoServ, u, ischan ? CHAN_X_FORBIDDEN : NICK_X_FORBIDDEN, name); } else { notice_lang(s_MemoServ, u, ischan ? CHAN_X_NOT_REGISTERED : NICK_X_NOT_REGISTERED, name); } } else { int i; for (i = mi->memocount - 1; i >= 0; i--) { if ((mi->memos[i].flags & MF_UNREAD) && !stricmp(mi->memos[i].sender, u->na->nc->display) && (!(mi->memos[i].flags & MF_NOTIFYS))) { delmemo(mi, mi->memos[i].number); notice_lang(s_MemoServ, u, MEMO_CANCELLED, name); return MOD_CONT; } } notice_lang(s_MemoServ, u, MEMO_CANCEL_NONE); } return MOD_CONT; }
void run_cmd(const char *service, User *u, Command *list, const char *cmd, ChannelInfo *ci) { Command *c = lookup_cmd(list, cmd); int ulevel = 0; ulevel = check_cservice(u); if ( (ulevel == 0) && ci ) ulevel = get_access(u, ci); if ( ulevel == 0 ) if ( (stricmp(u->nick, ServicesRoot) == 0) && nick_recognized(u) ) ulevel = ACCLEV_GOD; if (c && c->routine) { if ( ((c->has_priv == NULL) || c->has_priv(u)) && (ulevel >= c->level) ) c->routine(u); else notice_lang(service, u, ACCESS_DENIED); } else { notice_lang(service, u, UNKNOWN_COMMAND_HELP, cmd, service); } }
/** * Adds a new user to anopes internal userlist. * * If the SVID passed is 2, the user will not be marked registered or requested to ID. * This is an addition to accomodate IRCds where we cannot determine this based on the NICK * or UID command. Some IRCd's keep +r on when changing nicks and do not use SVID (ex. InspIRCd 1.2). * Instead we get a METADATA command containing the accountname the user was last identified to. * Since this is received after the user is introduced to us we should not yet mark the user * as identified or ask him to identify. We will mark him as recognized for the time being and let * him keep his +r if he has it. * It is the responsibility of the protocol module to make sure that this is either invalidated, * or changed to identified. ~ Viper **/ User *do_nick(const char *source, char *nick, char *username, char *host, char *server, char *realname, time_t ts, uint32 svid, uint32 ip, char *vhost, char *uid) { User *user = NULL; char *tmp = NULL; NickAlias *old_na; /* Old nick rec */ int nc_changed = 1; /* Did nick core change? */ int status = 0; /* Status to apply */ char mask[USERMAX + HOSTMAX + 2]; char *logrealname; char *oldnick; if (!*source) { char ipbuf[16]; struct in_addr addr; if (ircd->nickvhost) { if (vhost) { if (!strcmp(vhost, "*")) { vhost = NULL; if (debug) alog("debug: new user�with no vhost in NICK command: %s", nick); } } } /* This is a new user; create a User structure for it. */ if (debug) alog("debug: new user: %s", nick); if (ircd->nickip) { addr.s_addr = htonl(ip); ntoa(addr, ipbuf, sizeof(ipbuf)); } if (LogUsers) { /** * Ugly swap routine for Flop's bug :) **/ if (realname) { tmp = strchr(realname, '%'); while (tmp) { *tmp = '-'; tmp = strchr(realname, '%'); } } logrealname = normalizeBuffer(realname); /** * End of ugly swap **/ if (ircd->nickvhost) { if (ircd->nickip) { alog("LOGUSERS: %s (%s@%s => %s) (%s) [%s] connected to the network (%s).", nick, username, host, (vhost ? vhost : "none"), logrealname, ipbuf, server); } else { alog("LOGUSERS: %s (%s@%s => %s) (%s) connected to the network (%s).", nick, username, host, (vhost ? vhost : "none"), logrealname, server); } } else { if (ircd->nickip) { alog("LOGUSERS: %s (%s@%s) (%s) [%s] connected to the network (%s).", nick, username, host, logrealname, ipbuf, server); } else { alog("LOGUSERS: %s (%s@%s) (%s) connected to the network (%s).", nick, username, host, logrealname, server); } } Anope_Free(logrealname); } /* We used to ignore the ~ which a lot of ircd's use to indicate no * identd response. That caused channel bans to break, so now we * just take what the server gives us. People are still encouraged * to read the RFCs and stop doing anything to usernames depending * on the result of an identd lookup. */ /* First check for AKILLs. */ /* DONT just return null if its an akill match anymore - yes its more efficent to, however, now that ircd's are * starting to use things like E/F lines, we cant be 100% sure the client will be removed from the network :/ * as such, create a user_struct, and if the client is removed, we'll delete it again when the QUIT notice * comes in from the ircd. **/ if (check_akill(nick, username, host, vhost, ipbuf)) { /* return NULL; */ } /** * DefCon AKILL system, if we want to akill all connecting user's here's where to do it * then force check_akill again on them... **/ /* don't akill on netmerges -Certus */ /* don't akill clients introduced by ulines. -Viper */ if (is_sync(findserver(servlist, server)) && checkDefCon(DEFCON_AKILL_NEW_CLIENTS) && !is_ulined(server)) { strncpy(mask, "*@", 3); strncat(mask, host, HOSTMAX); alog("DEFCON: adding akill for %s", mask); add_akill(NULL, mask, s_OperServ, time(NULL) + dotime(DefConAKILL), DefConAkillReason ? DefConAkillReason : "DEFCON AKILL"); if (check_akill(nick, username, host, vhost, ipbuf)) { /* return NULL; */ } } /* SGLINE */ if (ircd->sgline) { if (check_sgline(nick, realname)) return NULL; } /* SQLINE */ if (ircd->sqline) { if (check_sqline(nick, 0)) return NULL; } /* SZLINE */ if (ircd->szline && ircd->nickip) { if (check_szline(nick, ipbuf)) return NULL; } /* Now check for session limits */ if (LimitSessions && !is_ulined(server) && !add_session(nick, host, ipbuf)) return NULL; /* Allocate User structure and fill it in. */ user = new_user(nick); user->username = sstrdup(username); user->host = sstrdup(host); user->server = findserver(servlist, server); user->realname = sstrdup(realname); user->timestamp = ts; user->my_signon = time(NULL); user->chost = vhost ? sstrdup(vhost) : sstrdup(host); user->vhost = vhost ? sstrdup(vhost) : sstrdup(host); if (uid) { user->uid = sstrdup(uid); /* p10/ts6 stuff */ } else { user->uid = NULL; } user->vident = sstrdup(username); /* We now store the user's ip in the user_ struct, * because we will use it in serveral places -- DrStein */ if (ircd->nickip) { user->hostip = sstrdup(ipbuf); } else { user->hostip = NULL; } if (svid == 0) { display_news(user, NEWS_LOGON); display_news(user, NEWS_RANDOM); } if (svid == 2 && user->na) { /* We do not yet know if the user should be identified or not. * mark him as recognized for now. * It s up to the protocol module to make sure this either becomes ID'd or * is invalidated. ~ Viper */ if (debug) alog("debug: Marking %s as recognized..", user->nick); user->svid = 1; user->na->status |= NS_RECOGNIZED; nc_changed = 0; } else if (svid == ts && user->na) { /* Timestamp and svid match, and nick is registered; automagically identify the nick */ user->svid = svid; user->na->status |= NS_IDENTIFIED; check_memos(user); nc_changed = 0; /* Start nick tracking if available */ if (NSNickTracking) nsStartNickTracking(user); } else if (svid != 1) { /* Resets the svid because it doesn't match */ user->svid = 1; anope_cmd_svid_umode(user->nick, user->timestamp); } else { user->svid = 1; } send_event(EVENT_NEWNICK, 1, nick); } else { /* An old user changing nicks. */ if (UseTS6 && ircd->ts6) user = find_byuid(source); if (!user) user = finduser(source); if (!user) { alog("user: NICK from nonexistent nick %s", source); return NULL; } user->isSuperAdmin = 0; /* Dont let people nick change and stay SuperAdmins */ if (debug) alog("debug: %s changes nick to %s", source, nick); if (LogUsers) { logrealname = normalizeBuffer(user->realname); if (ircd->vhost) { alog("LOGUSERS: %s (%s@%s => %s) (%s) changed nick to %s (%s).", user->nick, user->username, user->host, (user->vhost ? user->vhost : "(none)"), logrealname, nick, user->server->name); } else { alog("LOGUSERS: %s (%s@%s) (%s) changed nick to %s (%s).", user->nick, user->username, user->host, logrealname, nick, user->server->name); } if (logrealname) { free(logrealname); } } user->timestamp = ts; if (stricmp(nick, user->nick) == 0) { /* No need to redo things */ change_user_nick(user, nick); nc_changed = 0; } else { /* Update this only if nicks aren't the same */ user->my_signon = time(NULL); old_na = user->na; if (old_na) { if (nick_recognized(user)) user->na->last_seen = time(NULL); status = old_na->status & NS_TRANSGROUP; cancel_user(user); } oldnick = sstrdup(user->nick); change_user_nick(user, nick); if ((old_na ? old_na->nc : NULL) == (user->na ? user->na->nc : NULL)) nc_changed = 0; if (!nc_changed && (user->na)) user->na->status |= status; else { anope_cmd_nc_change(user); } send_event(EVENT_CHANGE_NICK, 2, nick, oldnick); free(oldnick); } if (ircd->sqline) { if (!is_oper(user) && check_sqline(user->nick, 1)) return NULL; } } /* if (!*source) */ /* Check for nick tracking to bypass identification */ if (NSNickTracking && nsCheckNickTracking(user)) { user->na->status |= NS_IDENTIFIED; nc_changed = 0; } if (nc_changed || !nick_recognized(user)) { if (validate_user(user)) check_memos(user); } else { if (nick_identified(user)) { char tsbuf[16]; user->na->last_seen = time(NULL); if (user->na->last_usermask) free(user->na->last_usermask); user->na->last_usermask = smalloc(strlen(common_get_vident(user)) + strlen(common_get_vhost(user)) + 2); sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user), common_get_vhost(user)); snprintf(tsbuf, sizeof(tsbuf), "%lu", (unsigned long int) user->timestamp); anope_cmd_svid_umode2(user, tsbuf); alog("%s: %s!%s@%s automatically identified for nick %s", s_NickServ, user->nick, user->username, user->host, user->nick); } } /* Bahamut sets -r on every nick changes, so we must test it even if nc_changed == 0 */ if (ircd->check_nick_id) { if (nick_identified(user)) { char tsbuf[16]; snprintf(tsbuf, sizeof(tsbuf), "%lu", (unsigned long int) user->timestamp); anope_cmd_svid_umode3(user, tsbuf); } } return user; }
/** * The /cs register command. * @param u The user who issued the command * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing. **/ int do_register(User * u) { char *chan = strtok(NULL, " "); char *pass = strtok(NULL, " "); char *desc = strtok(NULL, ""); NickCore *nc; Channel *c; ChannelInfo *ci; struct u_chaninfolist *uc; int is_servadmin = is_services_admin(u); char founderpass[PASSMAX + 1]; char tmp_pass[PASSMAX]; if (readonly) { notice_lang(s_ChanServ, u, CHAN_REGISTER_DISABLED); return MOD_CONT; } if (checkDefCon(DEFCON_NO_NEW_CHANNELS)) { notice_lang(s_ChanServ, u, OPER_DEFCON_DENIED); return MOD_CONT; } if (!desc) { syntax_error(s_ChanServ, u, "REGISTER", CHAN_REGISTER_SYNTAX); } else if (*chan == '&') { notice_lang(s_ChanServ, u, CHAN_REGISTER_NOT_LOCAL); } else if (*chan != '#') { notice_lang(s_ChanServ, u, CHAN_SYMBOL_REQUIRED); } else if (!xanadu_valid_chan(chan)) { notice_lang(s_ChanServ, u, CHAN_X_INVALID, chan); } else if (!u->na || !(nc = u->na->nc)) { notice_lang(s_ChanServ, u, CHAN_MUST_REGISTER_NICK, s_NickServ); } else if (!nick_recognized(u)) { notice_lang(s_ChanServ, u, CHAN_MUST_IDENTIFY_NICK, s_NickServ, s_NickServ); } else if (!(c = findchan(chan))) { notice_lang(s_ChanServ, u, CHAN_REGISTER_NONE_CHANNEL, chan); } else if ((ci = cs_findchan(chan)) != NULL) { if (ci->flags & CI_VERBOTEN) { alog("%s: Attempt to register FORBIDden channel %s by %s!%s@%s", s_ChanServ, ci->name, u->nick, u->username, u->host); notice_lang(s_ChanServ, u, CHAN_MAY_NOT_BE_REGISTERED, chan); } else { notice_lang(s_ChanServ, u, CHAN_ALREADY_REGISTERED, chan); } } else if (!stricmp(chan, "#")) { notice_lang(s_ChanServ, u, CHAN_MAY_NOT_BE_REGISTERED, chan); } else if (!chan_has_user_status(c, u, CUS_OP)) { notice_lang(s_ChanServ, u, CHAN_MUST_BE_CHANOP); } else if (!is_servadmin && nc->channelmax > 0 && nc->channelcount >= nc->channelmax) { notice_lang(s_ChanServ, u, nc->channelcount > nc-> channelmax ? CHAN_EXCEEDED_CHANNEL_LIMIT : CHAN_REACHED_CHANNEL_LIMIT, nc->channelmax); } else if (stricmp(u->nick, pass) == 0 || (StrictPasswords && strlen(pass) < 5)) { notice_lang(s_ChanServ, u, MORE_OBSCURE_PASSWORD); } else if (!(ci = makechan(chan))) { alog("%s: makechan() failed for REGISTER %s", s_ChanServ, chan); notice_lang(s_ChanServ, u, CHAN_REGISTRATION_FAILED); } else if (strscpy(founderpass, pass, PASSMAX + 1), enc_encrypt_in_place(founderpass, PASSMAX) < 0) { alog("%s: Couldn't encrypt password for %s (REGISTER)", s_ChanServ, chan); notice_lang(s_ChanServ, u, CHAN_REGISTRATION_FAILED); delchan(ci); } else { c->ci = ci; ci->c = c; ci->bantype = CSDefBantype; ci->flags = CSDefFlags; ci->mlock_on = ircd->defmlock; ci->memos.memomax = MSMaxMemos; ci->last_used = ci->time_registered; ci->founder = nc; if (strlen(pass) > PASSMAX) notice_lang(s_ChanServ, u, PASSWORD_TRUNCATED, PASSMAX); memset(pass, 0, strlen(pass)); memcpy(ci->founderpass, founderpass, PASSMAX); ci->desc = sstrdup(desc); if (c->topic) { ci->last_topic = sstrdup(c->topic); strscpy(ci->last_topic_setter, c->topic_setter, NICKMAX); ci->last_topic_time = c->topic_time; } else { /* Set this to something, otherwise it will maliform the topic */ strscpy(ci->last_topic_setter, s_ChanServ, NICKMAX); } ci->bi = NULL; ci->botflags = BSDefFlags; ci->founder->channelcount++; alog("%s: Channel '%s' registered by %s!%s@%s", s_ChanServ, chan, u->nick, u->username, u->host); notice_lang(s_ChanServ, u, CHAN_REGISTERED, chan, u->nick); if(enc_decrypt(ci->founderpass,tmp_pass,PASSMAX) == 1) { notice_lang(s_ChanServ, u, CHAN_PASSWORD_IS, ci->founderpass); } uc = scalloc(sizeof(*uc), 1); uc->next = u->founder_chans; uc->prev = NULL; if (u->founder_chans) u->founder_chans->prev = uc; u->founder_chans = uc; uc->chan = ci; /* Implement new mode lock */ check_modes(c); /* On most ircds you do not receive the admin/owner mode till its registered */ if (ircd->admin) { xanadu_cmd_mode(s_ChanServ, chan, "%s %s", ircd->adminset, u->nick); } if (ircd->owner && ircd->ownerset) { xanadu_cmd_mode(s_ChanServ, chan, "%s %s", ircd->ownerset, u->nick); } send_event(EVENT_CHAN_REGISTERED, 1, chan); } return MOD_CONT; }
/** * Split from do_send, this way we can easily send a memo from any point. * * @param u User Struct * @param name Target of the memo * @param text Memo Text * @param z type see info * @param source Nickname of the alias the memo originates from. * 0 - reply to user * 1 - silent * 2 - silent with no delay timer * 3 - reply to user and request read receipt * @return void */ void memo_send_from(User * u, char *name, char *text, int z, char *source) { int ischan; int isforbid; Memo *m; MemoInfo *mi; time_t now = time(NULL); int is_servoper = is_services_oper(u); if (readonly) { notice_lang(s_MemoServ, u, MEMO_SEND_DISABLED); } else if (checkDefCon(DEFCON_NO_NEW_MEMOS)) { notice_lang(s_MemoServ, u, OPER_DEFCON_DENIED); return; } else if (!text) { if (z == 0) syntax_error(s_MemoServ, u, "SEND", MEMO_SEND_SYNTAX); if (z == 3) syntax_error(s_MemoServ, u, "RSEND", MEMO_RSEND_SYNTAX); } else if (!nick_recognized(u)) { if (z == 0 || z == 3) notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ); } else if (!(mi = getmemoinfo(name, &ischan, &isforbid))) { if (z == 0 || z == 3) { if (isforbid) { notice_lang(s_MemoServ, u, ischan ? CHAN_X_FORBIDDEN : NICK_X_FORBIDDEN, name); } else { notice_lang(s_MemoServ, u, ischan ? CHAN_X_NOT_REGISTERED : NICK_X_NOT_REGISTERED, name); } } } else if (z != 2 && MSSendDelay > 0 && u && u->lastmemosend + MSSendDelay > now && !is_servoper) { u->lastmemosend = now; if (z == 0) notice_lang(s_MemoServ, u, MEMO_SEND_PLEASE_WAIT, MSSendDelay); if (z == 3) notice_lang(s_MemoServ, u, MEMO_RSEND_PLEASE_WAIT, MSSendDelay); } else if (mi->memomax == 0 && !is_servoper) { if (z == 0 || z == 3) notice_lang(s_MemoServ, u, MEMO_X_GETS_NO_MEMOS, name); } else if (mi->memocount >= 32767 || (mi->memomax > 0 && mi->memocount >= mi->memomax && !is_servoper)) { if (z == 0 || z == 3) notice_lang(s_MemoServ, u, MEMO_X_HAS_TOO_MANY_MEMOS, name); } else { u->lastmemosend = now; mi->memocount++; mi->memos = srealloc(mi->memos, sizeof(Memo) * mi->memocount); m = &mi->memos[mi->memocount - 1]; strscpy(m->sender, source, NICKMAX); m->moduleData = NULL; if (mi->memocount > 1) { m->number = m[-1].number + 1; if (m->number < 1) { int i; for (i = 0; i < mi->memocount; i++) { mi->memos[i].number = i + 1; } } } else { m->number = 1; } m->time = time(NULL); m->text = sstrdup(text); m->flags = MF_UNREAD; #ifdef USE_MYSQL m->id = 0; #endif /* Set notify sent flag - DrStein */ if (z == 2) { m->flags |= MF_NOTIFYS; } /* Set receipt request flag */ if (z == 3) m->flags |= MF_RECEIPT; if (z == 0 || z == 3) notice_lang(s_MemoServ, u, MEMO_SENT, name); if (!ischan) { NickAlias *na; NickCore *nc = (findnick(name))->nc; if (MSNotifyAll) { if ((nc->flags & NI_MEMO_RECEIVE) && get_ignore(name) == NULL) { int i; for (i = 0; i < nc->aliases.count; i++) { na = nc->aliases.list[i]; if (na->u && nick_identified(na->u)) notice_lang(s_MemoServ, na->u, MEMO_NEW_MEMO_ARRIVED, source, s_MemoServ, m->number); } } else { if ((u = finduser(name)) && nick_identified(u) && (nc->flags & NI_MEMO_RECEIVE)) notice_lang(s_MemoServ, u, MEMO_NEW_MEMO_ARRIVED, source, s_MemoServ, m->number); } /* if (flags & MEMO_RECEIVE) */ } /* if (MSNotifyAll) */ /* let's get out the mail if set in the nickcore - certus */ if (nc->flags & NI_MEMO_MAIL) new_memo_mail(nc, m); } else { struct c_userlist *cu, *next; Channel *c; if (MSNotifyAll && (c = findchan(name))) { for (cu = c->users; cu; cu = next) { next = cu->next; if (check_access(cu->user, c->ci, CA_MEMO)) { if (cu->user->na && (cu->user->na->nc->flags & NI_MEMO_RECEIVE) && get_ignore(cu->user->nick) == NULL) { notice_lang(s_MemoServ, cu->user, MEMO_NEW_X_MEMO_ARRIVED, c->ci->name, s_MemoServ, c->ci->name, m->number); } } } } /* MSNotifyAll */ } /* if (!ischan) */ } /* if command is valid */ }