Annotation of ircnowd/src/ngircd/irc-op.c, Revision 1.1
1.1 ! tomglok 1: /*
! 2: * ngIRCd -- The Next Generation IRC Daemon
! 3: * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify
! 6: * it under the terms of the GNU General Public License as published by
! 7: * the Free Software Foundation; either version 2 of the License, or
! 8: * (at your option) any later version.
! 9: * Please read the file COPYING, README and AUTHORS for more information.
! 10: */
! 11:
! 12: #include "portab.h"
! 13:
! 14: /**
! 15: * @file
! 16: * Channel operator commands
! 17: */
! 18:
! 19: #include <assert.h>
! 20: #include <string.h>
! 21:
! 22: #include "conn.h"
! 23: #include "channel.h"
! 24: #include "irc-macros.h"
! 25: #include "irc-write.h"
! 26: #include "lists.h"
! 27: #include "log.h"
! 28: #include "messages.h"
! 29: #include "parse.h"
! 30:
! 31: #include "irc-op.h"
! 32:
! 33: /* Local functions */
! 34:
! 35: static bool
! 36: try_kick(CLIENT *peer, CLIENT* from, const char *nick, const char *channel,
! 37: const char *reason)
! 38: {
! 39: CLIENT *target = Client_Search(nick);
! 40:
! 41: if (!target)
! 42: return IRC_WriteErrClient(from, ERR_NOSUCHNICK_MSG,
! 43: Client_ID(from), nick);
! 44:
! 45: Channel_Kick(peer, target, from, channel, reason);
! 46: return true;
! 47: }
! 48:
! 49: /* Global functions */
! 50:
! 51: /**
! 52: * Handler for the IRC command "KICK".
! 53: *
! 54: * @param Client The client from which this command has been received.
! 55: * @param Req Request structure with prefix and all parameters.
! 56: * @return CONNECTED or DISCONNECTED.
! 57: */
! 58: GLOBAL bool
! 59: IRC_KICK(CLIENT *Client, REQUEST *Req)
! 60: {
! 61: CLIENT *from;
! 62: char *itemList = Req->argv[0];
! 63: const char* currentNick, *currentChannel, *reason;
! 64: unsigned int channelCount = 1;
! 65: unsigned int nickCount = 1;
! 66:
! 67: assert( Client != NULL );
! 68: assert( Req != NULL );
! 69:
! 70: _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
! 71:
! 72: while (*itemList) {
! 73: if (*itemList == ',') {
! 74: *itemList = '\0';
! 75: channelCount++;
! 76: }
! 77: itemList++;
! 78: }
! 79:
! 80: itemList = Req->argv[1];
! 81: while (*itemList) {
! 82: if (*itemList == ',') {
! 83: *itemList = '\0';
! 84: nickCount++;
! 85: }
! 86: itemList++;
! 87: }
! 88:
! 89: reason = Req->argc == 3 ? Req->argv[2] : Client_ID(from);
! 90: currentNick = Req->argv[1];
! 91: currentChannel = Req->argv[0];
! 92: if (channelCount == 1) {
! 93: while (nickCount > 0) {
! 94: if (!try_kick(Client, from, currentNick,
! 95: currentChannel, reason))
! 96: return false;
! 97:
! 98: while (*currentNick)
! 99: currentNick++;
! 100:
! 101: currentNick++;
! 102: nickCount--;
! 103: }
! 104: } else if (channelCount == nickCount) {
! 105: while (nickCount > 0) {
! 106: if (!try_kick(Client, from, currentNick,
! 107: currentChannel, reason))
! 108: return false;
! 109:
! 110: while (*currentNick)
! 111: currentNick++;
! 112:
! 113: while (*currentChannel)
! 114: currentChannel++;
! 115:
! 116: currentNick++;
! 117: currentChannel++;
! 118: nickCount--;
! 119: }
! 120: } else {
! 121: return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
! 122: Client_ID(Client), Req->command);
! 123: }
! 124: return true;
! 125: } /* IRC_KICK */
! 126:
! 127: /**
! 128: * Handler for the IRC command "INVITE".
! 129: *
! 130: * @param Client The client from which this command has been received.
! 131: * @param Req Request structure with prefix and all parameters.
! 132: * @return CONNECTED or DISCONNECTED.
! 133: */
! 134: GLOBAL bool
! 135: IRC_INVITE(CLIENT *Client, REQUEST *Req)
! 136: {
! 137: CHANNEL *chan;
! 138: CLIENT *target, *from;
! 139: const char *colon_if_necessary;
! 140: bool remember = false;
! 141:
! 142: assert( Client != NULL );
! 143: assert( Req != NULL );
! 144:
! 145: _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
! 146:
! 147: /* Search user */
! 148: target = Client_Search(Req->argv[0]);
! 149: if (!target || (Client_Type(target) != CLIENT_USER))
! 150: return IRC_WriteErrClient(from, ERR_NOSUCHNICK_MSG,
! 151: Client_ID(Client), Req->argv[0]);
! 152:
! 153: if (Req->argv[1][0] == '&') {
! 154: /* Local channel. Make sure the target user is on this server! */
! 155: if (Client_Conn(target) == NONE)
! 156: return IRC_WriteErrClient(from, ERR_USERNOTONSERV_MSG,
! 157: Client_ID(Client),
! 158: Req->argv[0]);
! 159: }
! 160:
! 161: chan = Channel_Search(Req->argv[1]);
! 162: if (chan) {
! 163: /* Channel exists. Is the user a valid member of the channel? */
! 164: if (!Channel_IsMemberOf(chan, from))
! 165: return IRC_WriteErrClient(from, ERR_NOTONCHANNEL_MSG,
! 166: Client_ID(Client),
! 167: Req->argv[1]);
! 168:
! 169: /* Is the channel "invite-disallow"? */
! 170: if (Channel_HasMode(chan, 'V'))
! 171: return IRC_WriteErrClient(from, ERR_NOINVITE_MSG,
! 172: Client_ID(from),
! 173: Channel_Name(chan));
! 174:
! 175: /* Is the channel "invite-only"? */
! 176: if (Channel_HasMode(chan, 'i')) {
! 177: /* Yes. The user issuing the INVITE command must be
! 178: * channel owner/admin/operator/halfop! */
! 179: if (!Channel_UserHasMode(chan, from, 'q') &&
! 180: !Channel_UserHasMode(chan, from, 'a') &&
! 181: !Channel_UserHasMode(chan, from, 'o') &&
! 182: !Channel_UserHasMode(chan, from, 'h'))
! 183: return IRC_WriteErrClient(from,
! 184: ERR_CHANOPRIVSNEEDED_MSG,
! 185: Client_ID(from),
! 186: Channel_Name(chan));
! 187: remember = true;
! 188: }
! 189:
! 190: /* Is the target user already member of the channel? */
! 191: if (Channel_IsMemberOf(chan, target))
! 192: return IRC_WriteErrClient(from, ERR_USERONCHANNEL_MSG,
! 193: Client_ID(from),
! 194: Req->argv[0], Req->argv[1]);
! 195:
! 196: /* If the target user is banned on that channel: remember invite */
! 197: if (Lists_Check(Channel_GetListBans(chan), target))
! 198: remember = true;
! 199:
! 200: if (remember) {
! 201: /* We must remember this invite */
! 202: if (!Channel_AddInvite(chan, Client_MaskCloaked(target),
! 203: true, Client_ID(from)))
! 204: return CONNECTED;
! 205: }
! 206: }
! 207:
! 208: LogDebug("User \"%s\" invites \"%s\" to \"%s\" ...", Client_Mask(from),
! 209: Req->argv[0], Req->argv[1]);
! 210:
! 211: /*
! 212: * RFC 2812 states:
! 213: * 'There is no requirement that the channel [..] must exist or be a
! 214: * valid channel'. The problem with this is that this allows the
! 215: * "channel" to contain spaces, in which case we must prefix its name
! 216: * with a colon to make it clear that it is only a single argument.
! 217: */
! 218: colon_if_necessary = strchr(Req->argv[1], ' ') ? ":":"";
! 219: /* Inform target client */
! 220: IRC_WriteStrClientPrefix(target, from, "INVITE %s %s%s", Req->argv[0],
! 221: colon_if_necessary, Req->argv[1]);
! 222:
! 223: if (Client_Conn(target) > NONE) {
! 224: /* The target user is local, so we have to send the status code */
! 225: if (!IRC_WriteStrClientPrefix(from, target, RPL_INVITING_MSG,
! 226: Client_ID(from), Req->argv[0],
! 227: colon_if_necessary, Req->argv[1]))
! 228: return DISCONNECTED;
! 229:
! 230: if (Client_HasMode(target, 'a') &&
! 231: !IRC_WriteStrClient(from, RPL_AWAY_MSG, Client_ID(from),
! 232: Client_ID(target), Client_Away(target)))
! 233: return DISCONNECTED;
! 234: }
! 235: return CONNECTED;
! 236: } /* IRC_INVITE */
! 237:
! 238: /* -eof- */
CVSweb