source: code/cmd.c@ 67f3e60

Last change on this file since 67f3e60 was ec3eb38, checked in by Mike Belopuhov <mike@…>, 10 years ago

Bitch if trying to beep yourself

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