Annotation of ircnowd/src/ngircd/irc-op.c, Revision 1.1.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