source: code/cmd.c@ 8bcfd50

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

'w' has been available for quite some time

  • 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
116 if (ISSETF(s->flags, ICB_SF_NOBEEP | ICB_SF_NOBEEP2)) {
117 icb_error(is, "User has nobeep enabled");
118 if (ISSETF(s->flags, ICB_SF_NOBEEP2))
119 icb_status(s, STATUS_NOBEEP,
120 "%s attempted to beep you", is->nick);
121 return;
122 }
123
124 icb_sendfmt(s, "%c%s", ICB_M_BEEP, is->nick);
125}
126
127void
128icb_cmd_boot(struct icb_session *is, char *arg)
129{
130 struct icb_group *ig;
131 struct icb_session *s;
132 char whom[ICB_MAXNICKLEN];
133
134 /* to boot or not to boot, that is the question */
135 ig = is->group;
136 if (!icb_ismod(ig, is)) {
137 icb_status(is, STATUS_NOTIFY, "Sorry, booting is a privilege "
138 "you don't possess");
139 return;
140 }
141
142 if (strlen(arg) == 0) {
143 icb_error(is, "Invalid user");
144 return;
145 }
146
147 icb_vis(whom, arg, ICB_MAXNICKLEN, VIS_SP);
148
149 /* who would be a target then? */
150 LIST_FOREACH(s, &ig->sess, entry) {
151 if (strcmp(s->nick, whom) == 0)
152 break;
153 }
154 if (s == NULL) {
155 icb_status(is, STATUS_NOTIFY, "No such user");
156 return;
157 }
158 if (s == is) {
159 icb_error(is, "Just quit, would you?");
160 return;
161 }
162
163 /* okay, here we go, but first, be polite and notify a user */
164 icb_status(s, STATUS_BOOT, "%s booted you", is->nick);
165 icb_status_group(s->group, s, STATUS_BOOT, "%s was booted", s->nick);
166 icbd_drop(s, "booted");
167}
168
169void
170icb_cmd_change(struct icb_session *is, char *arg)
171{
172 struct icb_group *ig;
173 struct icb_session *s;
174 char group[ICB_MAXGRPLEN];
175 int changing = 0;
176
177 if (strlen(arg) == 0) {
178 icb_error(is, "Invalid group name");
179 return;
180 }
181
182 icb_vis(group, arg, ICB_MAXGRPLEN, VIS_SP);
183
184 LIST_FOREACH(ig, &groups, entry) {
185 if (strcmp(ig->name, group) == 0)
186 break;
187 }
188 if (ig == NULL) {
189 if (!creategroups) {
190 icb_error(is, "Can't create new groups");
191 return;
192 } else {
193 if ((ig = icb_addgroup(is, group)) == NULL) {
194 icb_error(is, "Can't create group %s", group);
195 return;
196 }
197 icbd_log(NULL, LOG_DEBUG, "%s created group %s",
198 is->nick, group);
199 }
200 }
201
202 /* see if we're changing to the same group */
203 if (is->group && is->group == ig) {
204 icb_error(is, "You are already in that group");
205 return;
206 }
207
208 LIST_FOREACH(s, &ig->sess, entry) {
209 if (strcmp(s->nick, is->nick) == 0) {
210 icb_error(is, "Nick is already in use");
211 return;
212 }
213 }
214
215 if (is->group) {
216 changing = 1;
217 if (icb_ismod(is->group, is))
218 (void)icb_pass(is->group, is, NULL);
219 LIST_REMOVE(is, entry);
220 icb_status_group(is->group, NULL, STATUS_DEPART,
221 "%s (%s@%s) just left", is->nick, is->client, is->host);
222 }
223
224 is->group = ig;
225 LIST_INSERT_HEAD(&ig->sess, is, entry);
226
227 /* notify group */
228 icb_status_group(ig, is, changing ? STATUS_ARRIVE : STATUS_SIGNON,
229 "%s (%s@%s) entered group", is->nick, is->client, is->host);
230
231 /* acknowledge successful join */
232 icb_status(is, STATUS_STATUS, "You are now in group %s%s", ig->name,
233 icb_ismod(ig, is) ? " as moderator" : "");
234
235 /* send user a topic name */
236 if (strlen(ig->topic) > 0)
237 icb_status(is, STATUS_TOPIC, "The topic is: %s", ig->topic);
238}
239
240void
241icb_cmd_name(struct icb_session *is, char *arg)
242{
243 struct icb_group *ig = is->group;
244 struct icb_session *s;
245 char nick[ICB_MAXNICKLEN];
246
247 if (strlen(arg) == 0) {
248 icb_status(is, STATUS_NAME, "Your nickname is %s",
249 is->nick);
250 return;
251 }
252 if (strcasecmp(arg, "admin") == 0) {
253 icb_error(is, "Wuff wuff!");
254 return;
255 }
256 /* sanitize user input */
257 if (strlen(arg) > ICB_MAXNICKLEN)
258 arg[ICB_MAXNICKLEN - 1] = '\0';
259 icb_vis(nick, arg, ICB_MAXNICKLEN, VIS_SP);
260 LIST_FOREACH(s, &ig->sess, entry) {
261 if (strcmp(s->nick, nick) == 0) {
262 icb_error(is, "Nick is already in use");
263 return;
264 }
265 }
266 icb_status_group(ig, NULL, STATUS_NAME,
267 "%s changed nickname to %s", is->nick, nick);
268 strlcpy(is->nick, nick, sizeof is->nick);
269}
270
271void
272icb_cmd_nobeep(struct icb_session *is, char *arg)
273{
274 if (strlen(arg) == 0) {
275 /* fail if we have verbose turned on */
276 if (ISSETF(is->flags, ICB_SF_NOBEEP2)) {
277 icb_error(is, "Can't toggle your nobeep status");
278 return;
279 }
280 /* otherwise toggle the status */
281 if (ISSETF(is->flags, ICB_SF_NOBEEP))
282 CLRF(is->flags, ICB_SF_NOBEEP);
283 else
284 SETF(is->flags, ICB_SF_NOBEEP);
285 icb_status(is, STATUS_NOBEEP, "No-Beep %s",
286 ISSETF(is->flags, ICB_SF_NOBEEP) ? "on" : "off");
287 return;
288 }
289
290 if (strcmp(arg, "on") == 0) {
291 SETF(is->flags, ICB_SF_NOBEEP);
292 CLRF(is->flags, ICB_SF_NOBEEP2); /* can't be on and verbose */
293 icb_status(is, STATUS_NOBEEP, "No-Beep on");
294 } else if (strcmp(arg, "verbose") == 0) {
295 SETF(is->flags, ICB_SF_NOBEEP2);
296 CLRF(is->flags, ICB_SF_NOBEEP); /* can't be on and verbose */
297 icb_status(is, STATUS_NOBEEP, "No-Beep on (verbose)");
298 } else if (strcmp(arg, "off") == 0) {
299 CLRF(is->flags, ICB_SF_NOBEEP | ICB_SF_NOBEEP2);
300 icb_status(is, STATUS_NOBEEP, "No-Beep off");
301 } else
302 icb_error(is, "Invalid nobeep mode");
303}
304
305void
306icb_cmd_personal(struct icb_session *is, char *arg)
307{
308 char *p;
309
310 if ((p = strchr(arg, ' ')) == 0) {
311 icb_error(is, "Empty message");
312 return;
313 }
314 *p = '\0';
315 icb_privmsg(is, arg, ++p);
316}
317
318void
319icb_cmd_pass(struct icb_session *is, char *arg)
320{
321 struct icb_group *ig = is->group;
322 struct icb_session *s;
323 char whom[ICB_MAXNICKLEN];
324
325 if (!ig->mod) { /* if there is no mod, try grabbing it */
326 if (icb_modpermit(is, 0) && icb_pass(ig, ig->mod, is) < 0)
327 icb_error(is, "Acquiring group moderation failed.");
328 } else if (icb_ismod(ig, is)) {
329 if (strlen(arg) == 0) {
330 /* no argument: relinquish moderator */
331 (void)icb_pass(ig, ig->mod, NULL);
332 return;
333 }
334 icb_vis(whom, arg, ICB_MAXNICKLEN, VIS_SP);
335 LIST_FOREACH(s, &ig->sess, entry) {
336 if (strcmp(s->nick, whom) == 0)
337 break;
338 }
339 if (s == NULL) {
340 icb_status(is, STATUS_NOTIFY, "No such user");
341 return;
342 }
343 if (icb_modpermit(s, 0) && icb_pass(ig, ig->mod, s) < 0)
344 icb_error(s, "Acquiring group moderation failed.");
345 } else {
346 /*
347 * if group is moderated and we're not the moderator,
348 * but modtab is enabled, then check the permission
349 * and pass moderation if successful.
350 */
351 if (icb_modpermit(is, 1) && icb_pass(ig, ig->mod, is) < 0)
352 icb_error(is, "Acquiring group moderation failed.");
353 }
354}
355
356void
357icb_cmd_topic(struct icb_session *is, char *arg)
358{
359 struct icb_group *ig = is->group;
360 char topic[ICB_MAXTOPICLEN];
361
362 if (strlen(arg) == 0) { /* querying the topic */
363 if (strlen(ig->topic) > 0)
364 icb_status(is, STATUS_TOPIC, "The topic is: %s",
365 ig->topic);
366 else
367 icb_status(is, STATUS_TOPIC, "The topic is not set.");
368 } else { /* setting the topic */
369 if (!icb_ismod(ig, is)) {
370 icb_status(is, STATUS_NOTIFY, "Setting the topic is "
371 "only for moderators.");
372 return;
373 }
374 icb_vis(topic, arg, ICB_MAXTOPICLEN, 0);
375 strlcpy(ig->topic, topic, sizeof ig->topic);
376 icb_status_group(ig, NULL, STATUS_TOPIC,
377 "%s changed the topic to \"%s\"", is->nick, ig->topic);
378 }
379}
380
381void
382icb_cmd_who(struct icb_session *is, char *arg)
383{
384 struct icb_group *ig;
385 char group[ICB_MAXGRPLEN];
386
387 while (strlen(arg) && arg[0] == '-') { /* ignore options, for now */
388 /* ircII "set SHOW_CHANNEL_NAMES ON" uses /w -s */
389 while(arg[0] != ' ' && arg[0] != 0)
390 arg++;
391 if(arg[0] == ' ')
392 arg++;
393 }
394
395 if (strlen(arg) == 0)
396 return icb_who(is, NULL);
397
398 /* pidgin-icb treats '.' as the current group */
399 if (strlen(arg) == 1 && arg[0] == '.') {
400 icb_who(is, is->group);
401 return;
402 }
403
404 icb_vis(group, arg, ICB_MAXGRPLEN, VIS_SP);
405 LIST_FOREACH(ig, &groups, entry) {
406 if (strcmp(ig->name, group) == 0)
407 break;
408 }
409 if (ig == NULL) {
410 icb_error(is, "The group %s doesn't exist.", group);
411 return;
412 }
413 icb_who(is, ig);
414}
Note: See TracBrowser for help on using the repository browser.