source: code/cmd.c@ 96a2e31

Last change on this file since 96a2e31 was 383d37b, checked in by Mike Belopuhov <mike@…>, 11 years ago

don't allow to boot yourself

  • Property mode set to 100644
File size: 10.0 KB
Line 
1/*
2 * Copyright (c) 2009, 2010, 2013 Mike Belopuhov
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <sys/param.h>
18#include <sys/queue.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <syslog.h>
23#include <unistd.h>
24#include <vis.h>
25#include <event.h>
26
27#include "icb.h"
28#include "icbd.h"
29
30extern int creategroups;
31
32void icb_cmd_help(struct icb_session *, char *);
33void icb_cmd_beep(struct icb_session *, char *);
34void icb_cmd_boot(struct icb_session *, char *);
35void icb_cmd_change(struct icb_session *, char *);
36void icb_cmd_name(struct icb_session *, char *);
37void icb_cmd_nobeep(struct icb_session *, char *);
38void icb_cmd_personal(struct icb_session *, char *);
39void icb_cmd_pass(struct icb_session *, char *);
40void icb_cmd_topic(struct icb_session *, char *);
41void icb_cmd_who(struct icb_session *, char *);
42
43void *
44icb_cmd_lookup(char *cmd)
45{
46 struct {
47 const char *cmd;
48 void (*handler)(struct icb_session *, char *);
49 } cmdtab[] = {
50 { "?", icb_cmd_help },
51 { "beep", icb_cmd_beep },
52 { "boot", icb_cmd_boot },
53 { "g", icb_cmd_change },
54 { "m", icb_cmd_personal },
55 { "msg", icb_cmd_personal },
56 { "name", icb_cmd_name },
57 { "nobeep", icb_cmd_nobeep },
58 { "pass", icb_cmd_pass },
59 { "topic", icb_cmd_topic },
60 { "w", icb_cmd_who },
61 { NULL, NULL }
62 };
63 int i;
64
65 for (i = 0; cmdtab[i].cmd != NULL; i++)
66 if (strcasecmp(cmdtab[i].cmd, cmd) == 0)
67 return (cmdtab[i].handler);
68 return (NULL);
69}
70
71void
72icb_cmd_help(struct icb_session *is, char *arg __attribute__((unused)))
73{
74 icb_status(is, STATUS_HELP, "Server supports following commands:");
75 icb_status(is, STATUS_HELP, "beep boot g m name nobeep pass topic");
76}
77
78void
79icb_cmd_beep(struct icb_session *is, char *arg)
80{
81 struct icb_group *ig = is->group;
82 struct icb_session *s;
83 char whom[ICB_MAXNICKLEN];
84
85 if (strlen(arg) == 0) {
86 icb_error(is, "Invalid user");
87 return;
88 }
89
90 icb_vis(whom, arg, ICB_MAXNICKLEN, VIS_SP);
91
92 LIST_FOREACH(s, &ig->sess, entry) {
93 if (strcmp(s->nick, whom) == 0)
94 break;
95 }
96 if (s == NULL) {
97 icb_status(is, STATUS_NOTIFY, "%s is not signed on", whom);
98 return;
99 }
100
101 if (ISSETF(s->flags, ICB_SF_NOBEEP | ICB_SF_NOBEEP2)) {
102 icb_error(is, "User has nobeep enabled");
103 if (ISSETF(s->flags, ICB_SF_NOBEEP2))
104 icb_status(s, STATUS_NOBEEP,
105 "%s attempted to beep you", is->nick);
106 return;
107 }
108
109 icb_sendfmt(s, "%c%s", ICB_M_BEEP, is->nick);
110}
111
112void
113icb_cmd_boot(struct icb_session *is, char *arg)
114{
115 struct icb_group *ig;
116 struct icb_session *s;
117 char whom[ICB_MAXNICKLEN];
118
119 /* to boot or not to boot, that is the question */
120 ig = is->group;
121 if (!icb_ismod(ig, is)) {
122 icb_status(is, STATUS_NOTIFY, "Sorry, booting is a privilege "
123 "you don't possess");
124 return;
125 }
126
127 if (strlen(arg) == 0) {
128 icb_error(is, "Invalid user");
129 return;
130 }
131
132 icb_vis(whom, arg, ICB_MAXNICKLEN, VIS_SP);
133
134 /* who would be a target then? */
135 LIST_FOREACH(s, &ig->sess, entry) {
136 if (strcmp(s->nick, whom) == 0)
137 break;
138 }
139 if (s == NULL) {
140 icb_status(is, STATUS_NOTIFY, "No such user");
141 return;
142 }
143 if (s == is) {
144 icb_error(is, "Just quit, would you?");
145 return;
146 }
147
148 /* okay, here we go, but first, be polite and notify a user */
149 icb_status(s, STATUS_BOOT, "%s booted you", is->nick);
150 icb_status_group(s->group, s, STATUS_BOOT, "%s was booted", s->nick);
151 icbd_drop(s, "booted");
152}
153
154void
155icb_cmd_change(struct icb_session *is, char *arg)
156{
157 struct icb_group *ig;
158 struct icb_session *s;
159 char group[ICB_MAXGRPLEN];
160 int changing = 0;
161
162 if (strlen(arg) == 0) {
163 icb_error(is, "Invalid group");
164 return;
165 }
166
167 icb_vis(group, arg, ICB_MAXGRPLEN, VIS_SP);
168
169 LIST_FOREACH(ig, &groups, entry) {
170 if (strcmp(ig->name, group) == 0)
171 break;
172 }
173 if (ig == NULL) {
174 if (!creategroups) {
175 icb_error(is, "Invalid group");
176 return;
177 } else {
178 if ((ig = icb_addgroup(is, group, NULL)) == NULL) {
179 icb_error(is, "Can't create group");
180 return;
181 }
182 icbd_log(NULL, LOG_DEBUG, "%s created group %s",
183 is->nick, group);
184 }
185 }
186
187 /* see if we're changing to the same group */
188 if (is->group && is->group == ig) {
189 icb_error(is, "You are already in that group");
190 return;
191 }
192
193 LIST_FOREACH(s, &ig->sess, entry) {
194 if (strcmp(s->nick, is->nick) == 0) {
195 icb_error(is, "Nick is already in use");
196 return;
197 }
198 }
199
200 if (is->group) {
201 changing = 1;
202 if (icb_ismod(is->group, is))
203 (void)icb_pass(is->group, is, NULL);
204 LIST_REMOVE(is, entry);
205 icb_status_group(is->group, NULL, STATUS_DEPART,
206 "%s (%s@%s) just left", is->nick, is->client, is->host);
207 }
208
209 is->group = ig;
210 LIST_INSERT_HEAD(&ig->sess, is, entry);
211
212 /* notify group */
213 icb_status_group(ig, is, changing ? STATUS_ARRIVE : STATUS_SIGNON,
214 "%s (%s@%s) entered group", is->nick, is->client, is->host);
215
216 /* acknowledge successful join */
217 icb_status(is, STATUS_STATUS, "You are now in group %s%s", ig->name,
218 icb_ismod(ig, is) ? " as moderator" : "");
219
220 /* send user a topic name */
221 if (strlen(ig->topic) > 0)
222 icb_status(is, STATUS_TOPIC, "The topic is: %s", ig->topic);
223}
224
225void
226icb_cmd_name(struct icb_session *is, char *arg)
227{
228 struct icb_group *ig = is->group;
229 struct icb_session *s;
230 char nick[ICB_MAXNICKLEN];
231
232 if (strlen(arg) == 0) {
233 icb_status(is, STATUS_NAME, "Your nickname is %s",
234 is->nick);
235 return;
236 }
237 if (strcasecmp(arg, "admin") == 0) {
238 icb_error(is, "Wuff wuff!");
239 return;
240 }
241 /* sanitize user input */
242 if (strlen(arg) > ICB_MAXNICKLEN)
243 arg[ICB_MAXNICKLEN - 1] = '\0';
244 icb_vis(nick, arg, ICB_MAXNICKLEN, VIS_SP);
245 LIST_FOREACH(s, &ig->sess, entry) {
246 if (strcmp(s->nick, nick) == 0) {
247 icb_error(is, "Nick is already in use");
248 return;
249 }
250 }
251 icb_status_group(ig, NULL, STATUS_NAME,
252 "%s changed nickname to %s", is->nick, nick);
253 strlcpy(is->nick, nick, sizeof is->nick);
254}
255
256void
257icb_cmd_nobeep(struct icb_session *is, char *arg)
258{
259 if (strlen(arg) == 0) {
260 /* fail if we have verbose turned on */
261 if (ISSETF(is->flags, ICB_SF_NOBEEP2)) {
262 icb_error(is, "Can't toggle your nobeep status");
263 return;
264 }
265 /* otherwise toggle the status */
266 if (ISSETF(is->flags, ICB_SF_NOBEEP))
267 CLRF(is->flags, ICB_SF_NOBEEP);
268 else
269 SETF(is->flags, ICB_SF_NOBEEP);
270 icb_status(is, STATUS_NOBEEP, "No-Beep %s",
271 ISSETF(is->flags, ICB_SF_NOBEEP) ? "on" : "off");
272 return;
273 }
274
275 if (strcmp(arg, "on") == 0) {
276 SETF(is->flags, ICB_SF_NOBEEP);
277 CLRF(is->flags, ICB_SF_NOBEEP2); /* can't be on and verbose */
278 icb_status(is, STATUS_NOBEEP, "No-Beep on");
279 } else if (strcmp(arg, "verbose") == 0) {
280 SETF(is->flags, ICB_SF_NOBEEP2);
281 CLRF(is->flags, ICB_SF_NOBEEP); /* can't be on and verbose */
282 icb_status(is, STATUS_NOBEEP, "No-Beep on (verbose)");
283 } else if (strcmp(arg, "off") == 0) {
284 CLRF(is->flags, ICB_SF_NOBEEP | ICB_SF_NOBEEP2);
285 icb_status(is, STATUS_NOBEEP, "No-Beep off");
286 } else
287 icb_error(is, "Invalid nobeep mode");
288}
289
290void
291icb_cmd_personal(struct icb_session *is, char *arg)
292{
293 char *p;
294
295 if ((p = strchr(arg, ' ')) == 0) {
296 icb_error(is, "Empty message");
297 return;
298 }
299 *p = '\0';
300 icb_privmsg(is, arg, ++p);
301}
302
303void
304icb_cmd_pass(struct icb_session *is, char *arg)
305{
306 struct icb_group *ig = is->group;
307 struct icb_session *s;
308 char whom[ICB_MAXNICKLEN];
309
310 if (!ig->mod) { /* if there is no mod, try grabbing it */
311 if (icb_modpermit(is, 0) && icb_pass(ig, ig->mod, is) < 0)
312 icb_error(is, "Acquiring group moderation failed.");
313 } else if (icb_ismod(ig, is)) {
314 if (strlen(arg) == 0) {
315 /* no argument: relinquish moderator */
316 (void)icb_pass(ig, ig->mod, NULL);
317 return;
318 }
319 icb_vis(whom, arg, ICB_MAXNICKLEN, VIS_SP);
320 LIST_FOREACH(s, &ig->sess, entry) {
321 if (strcmp(s->nick, whom) == 0)
322 break;
323 }
324 if (s == NULL) {
325 icb_status(is, STATUS_NOTIFY, "No such user");
326 return;
327 }
328 if (icb_modpermit(s, 0) && icb_pass(ig, ig->mod, s) < 0)
329 icb_error(s, "Acquiring group moderation failed.");
330 } else {
331 /*
332 * if group is moderated and we're not the moderator,
333 * but modtab is enabled, then check the permission
334 * and pass moderation if successful.
335 */
336 if (icb_modpermit(is, 1) && icb_pass(ig, ig->mod, is) < 0)
337 icb_error(is, "Acquiring group moderation failed.");
338 }
339}
340
341void
342icb_cmd_topic(struct icb_session *is, char *arg)
343{
344 struct icb_group *ig = is->group;
345 char topic[ICB_MAXTOPICLEN];
346
347 if (strlen(arg) == 0) { /* querying the topic */
348 if (strlen(ig->topic) > 0)
349 icb_status(is, STATUS_TOPIC, "The topic is: %s",
350 ig->topic);
351 else
352 icb_status(is, STATUS_TOPIC, "The topic is not set.");
353 } else { /* setting the topic */
354 if (!icb_ismod(ig, is)) {
355 icb_status(is, STATUS_NOTIFY, "Setting the topic is "
356 "only for moderators.");
357 return;
358 }
359 icb_vis(topic, arg, ICB_MAXTOPICLEN, 0);
360 strlcpy(ig->topic, topic, sizeof ig->topic);
361 icb_status_group(ig, NULL, STATUS_TOPIC,
362 "%s changed the topic to \"%s\"", is->nick, ig->topic);
363 }
364}
365
366void
367icb_cmd_who(struct icb_session *is, char *arg)
368{
369 struct icb_group *ig;
370 char group[ICB_MAXGRPLEN];
371
372 while (strlen(arg) && arg[0] == '-') { /* ignore options, for now */
373 /* ircII "set SHOW_CHANNEL_NAMES ON" uses /w -s */
374 while(arg[0] != ' ' && arg[0] != 0)
375 arg++;
376 if(arg[0] == ' ')
377 arg++;
378 }
379
380 if (strlen(arg) == 0)
381 return icb_who(is, NULL);
382
383 /* pidgin-icb treats '.' as the current group */
384 if (strlen(arg) == 1 && arg[0] == '.') {
385 icb_who(is, is->group);
386 return;
387 }
388
389 icb_vis(group, arg, ICB_MAXGRPLEN, VIS_SP);
390 LIST_FOREACH(ig, &groups, entry) {
391 if (strcmp(ig->name, group) == 0)
392 break;
393 }
394 if (ig == NULL) {
395 icb_error(is, "The group %s doesn't exist.", group);
396 return;
397 }
398 icb_who(is, ig);
399}
Note: See TracBrowser for help on using the repository browser.