source: code/cmd.c@ dab4135

Last change on this file since dab4135 was 7882a6f, checked in by Mike Belopuhov <mike@…>, 11 years ago

Get rid of the icbd callbacks interface

I believe the idea was initially to have both icb and irc in one
daemon but that's not going to happen.

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