1 /* $Id: icb.c,v 1.3 2015/08/21 19:01:12 dhartmei Exp $ */
2
3 /*
4 * Copyright (c) 2003-2004 Daniel Hartmeier
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33 #if 0
34 static const char rcsid[] = "$Id: icb.c,v 1.3 2015/08/21 19:01:12 dhartmei Exp $";
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include "icb.h"
41 #include "irc.h"
42
43 extern int sync_write(int, const char *, int);
44
45 static unsigned char icb_args(const unsigned char *, unsigned char, char [255][255]);
46 static void icb_cmd(const unsigned char *, unsigned char, int, int);
47 static void icb_ico(int, const char *);
48 static void icb_iwl(int, const char *, const char *, long,
49 long, const char *, const char *);
50 static void icb_send_hw(int, const char *);
51
52 extern int terminate_client;
53 int icb_logged_in = 0;
54
55 static char icb_protolevel[256];
56 static char icb_hostid[256];
57 static char icb_serverid[256];
58 static char icb_moderator[256];
59 enum { imode_none, imode_list, imode_names, imode_whois, imode_who };
60 static int imode = imode_none;
61 static char icurgroup[256];
62 static char igroup[256];
63 static char inick[256];
64 static char ihostmask[256];
65 static unsigned off;
66
67 /*
68 * A single ICB packet consists of a length byte, a command byte and
69 * variable arguments. The length includes command and arguments, but
70 * not the length byte itself. Since length is at most 255, the entire
71 * packet is at most 256 bytes long.
72 *
73 * icb_recv() gets passed read(2) chunks and assembles a complete packet
74 * (including the length byte) in cmd. Once complete, the packet is
75 * passed to icb_cmd() without the length byte. Hence, arguments to
76 * icb_cmd() are at most 255 bytes long.
77 *
78 * icb_cmd() skips the command byte and passes only the variable
79 * arguments to icb_args(). Hence, arguments to icb_args() are at most
80 * 254 octects long.
81 *
82 * Variable arguments consist of zero or more strings separated by
83 * \001 characters. The strings need not be null-terminated and may
84 * be empty. Hence, there can be at most 255 strings and a string can
85 * be at most 254 bytes long. icb_args() fills the array argument,
86 * null-terminating each argument.
87 *
88 * This (together with the comments below) should be convincing proof
89 * that the char [255][255] as well as the unsigned char variables
90 * cannot overflow.
91 *
92 * Further argument parsing in icb_cmd() and icb_ico() relies on the
93 * fact that any argument can be at most 255 bytes long (including
94 * null-termination).
95 *
96 * The icb_send_*() functions may get arbitrarily long arguments from
97 * IRC, they may generate packets of at most 256 bytes size. Overlong
98 * arguments are truncated, except for open and personal messages,
99 * which are split across multiple packets, if needed (generating
100 * separate messages on ICB).
101 *
102 * The ICB protocol definition is not very clear about null-termination
103 * of arguments for packets generated by the client. Without any
104 * termination, at least one common server implementation shows a
105 * buffer re-use bug. Terminating all arguments, however, causes
106 * another server implementation to refuse certain commands. The
107 * best approach seems to be to null-terminate only the last
108 * argument. Where the code below violates that rule, that was done
109 * intentionally after testing.
110 *
111 */
112
113 void
scan(const unsigned char ** s,char * d,size_t siz,const char * skip,const char * term)114 scan(const unsigned char **s, char *d, size_t siz, const char *skip, const char *term)
115 {
116 while (**s && strchr(skip, **s) != NULL)
117 (*s)++;
118 while (**s && strchr(term, **s) == NULL) {
119 if (siz > 1) {
120 *d++ = **s;
121 siz--;
122 }
123 (*s)++;
124 }
125 if (siz > 0)
126 *d = 0;
127 }
128
129 void
icb_init(void)130 icb_init(void)
131 {
132 memset(icb_protolevel, 0, sizeof(icb_protolevel));
133 memset(icb_hostid, 0, sizeof(icb_hostid));
134 memset(icb_serverid, 0, sizeof(icb_serverid));
135 memset(icb_moderator, 0, sizeof(icb_moderator));
136 imode = imode_none;
137 memset(icurgroup, 0, sizeof(icurgroup));
138 memset(igroup, 0, sizeof(igroup));
139 memset(inick, 0, sizeof(inick));
140 memset(ihostmask, 0, sizeof(ihostmask));
141 off = 0;
142 }
143
144 void
icb_recv(const char * buf,unsigned len,int fd,int server_fd)145 icb_recv(const char *buf, unsigned len, int fd, int server_fd)
146 {
147 static unsigned char cmd[256];
148
149 while (len > 0) {
150 if (off == 0) {
151 cmd[off++] = *buf++;
152 /* 0 < cmd[0] <= 255 */
153 len--;
154 }
155 /* off > 0, 0 < cmd[0] <= 255 */
156 while (len > 0 && (off - 1) < cmd[0]) {
157 cmd[off++] = *buf++;
158 len--;
159 }
160 /* len == 0 || (off - 1) == cmd[0] */
161 if ((off - 1) == cmd[0]) {
162 icb_cmd(cmd + 1, off - 1 /* <= 255 */, fd, server_fd);
163 off = 0;
164 }
165 }
166 }
167
168 static unsigned char
icb_args(const unsigned char * data,unsigned char len,char args[255][255])169 icb_args(const unsigned char *data, unsigned char len, char args[255][255])
170 {
171 unsigned char i = 0, j = 0, k = 0;
172
173 /* 0 < len < 255 */
174 while (i < len) {
175 /* 0 <= i, j, k < 255 */
176 if (data[i] == '\001') {
177 args[j++][k] = 0;
178 k = 0;
179 } else if (data[i] == '\r' || data[i] == '\n')
180 args[j][k++] = '?';
181 else
182 args[j][k++] = data[i];
183 i++;
184 }
185 /* i, j, k < 255 */
186 if (k > 0)
187 args[j++][k] = 0;
188 /* j <= 255 */
189 for (i = j; i < 255; ++i)
190 args[i][0] = 0;
191 return (j);
192 }
193
194 static void
icb_cmd(const unsigned char * cmd,unsigned char len,int fd,int server_fd)195 icb_cmd(const unsigned char *cmd, unsigned char len, int fd, int server_fd)
196 {
197 char args[255][255];
198 const unsigned char *a = (unsigned char *)args[1];
199 unsigned char i, j;
200 char s[8192];
201
202 if (len == 0)
203 return;
204
205 /* 0 < len <= 255 */
206 i = icb_args(cmd + 1, len - 1 /* < 255 */, args);
207 /* 0 <= i <= 255 */
208 switch (cmd[0]) {
209 case 'a': /* Login OK */
210 irc_send_code(fd, icb_hostid, irc_nick, "001",
211 "Welcome to icbirc %s", irc_nick);
212 irc_send_code(fd, icb_hostid, irc_nick, "002",
213 "Your host is %s running %s protocol %s",
214 icb_hostid, icb_serverid, icb_protolevel);
215 /* some clients really want to see a MOTD */
216 irc_send_code(fd, icb_hostid, irc_nick, "375",
217 "ICB server: %s", icb_serverid);
218 irc_send_code(fd, icb_hostid, irc_nick, "376",
219 "End of MOTD");
220 icb_logged_in = 1;
221 break;
222 case 'b': /* Open Message */
223 if (!in_irc_channel) {
224 irc_send_join(fd, irc_nick, irc_channel);
225 icb_send_names(server_fd, irc_channel);
226 }
227 irc_send_msg(fd, args[0], irc_channel, args[1]);
228 break;
229 case 'c': /* Personal Message */
230 irc_send_msg(fd, args[0], irc_nick, args[1]);
231 break;
232 case 'd': /* Status Message */
233 if (!strcmp(args[0], "Status") && !strncmp(args[1],
234 "You are now in group ", 21)) {
235 if (irc_channel[0])
236 irc_send_part(fd, irc_nick, irc_channel);
237 irc_channel[0] = '#';
238 a += 21;
239 scan(&a, irc_channel + 1, sizeof(irc_channel) - 1,
240 " ", " ");
241 irc_send_join(fd, irc_nick, irc_channel);
242 icb_send_names(server_fd, irc_channel);
243 } else if (!strcmp(args[0], "Arrive") ||
244 !strcmp(args[0], "Sign-on")) {
245 char nick[256], host[256];
246
247 scan(&a, nick, sizeof(nick), " ", " ");
248 scan(&a, host, sizeof(host), " (", ")");
249 snprintf(s, sizeof(s), "%s!%s", nick, host);
250 irc_send_join(fd, s, irc_channel);
251 } else if (!strcmp(args[0], "Depart")) {
252 char nick[256], host[256];
253
254 scan(&a, nick, sizeof(nick), " ", " ");
255 scan(&a, host, sizeof(host), " (", ")");
256 snprintf(s, sizeof(s), "%s!%s", nick, host);
257 irc_send_part(fd, s, irc_channel);
258 } else if (!strcmp(args[0], "Sign-off")) {
259 char nick[256], host[256], reason[256];
260
261 scan(&a, nick, sizeof(nick), " ", " ");
262 scan(&a, host, sizeof(host), " (", ")");
263 scan(&a, reason, sizeof(reason), " )", "");
264 if (strlen(reason) > 0 &&
265 reason[strlen(reason) - 1] == '.')
266 reason[strlen(reason) - 1] = 0;
267 snprintf(s, sizeof(s), ":%s!%s QUIT :%s\r\n",
268 nick, host, reason);
269 sync_write(fd, s, strlen(s));
270 } else if (!strcmp(args[0], "Name")) {
271 char old_nick[256], new_nick[256];
272
273 scan(&a, old_nick, sizeof(old_nick), " ", " ");
274 if (strncmp((const char *)a, " changed nickname to ", 21))
275 return;
276 a += 21;
277 scan(&a, new_nick, sizeof(new_nick), " ", " ");
278 snprintf(s, sizeof(s), ":%s NICK :%s\r\n",
279 old_nick, new_nick);
280 sync_write(fd, s, strlen(s));
281 if (!strcmp(old_nick, irc_nick))
282 strlcpy(irc_nick, new_nick,
283 sizeof(irc_nick));
284 } else if (!strcmp(args[0], "Topic")) {
285 char nick[256], topic[256];
286
287 scan(&a, nick, sizeof(nick), " ", " ");
288 if (strncmp((const char *)a, " changed the topic to \"", 23))
289 return;
290 a += 23;
291 scan(&a, topic, sizeof(topic), "", "\"");
292 snprintf(s, sizeof(s), ":%s TOPIC %s :%s\r\n",
293 nick, irc_channel, topic);
294 sync_write(fd, s, strlen(s));
295 } else if (!strcmp(args[0], "Pass")) {
296 char old_mod[256], new_mod[256];
297
298 scan(&a, old_mod, sizeof(old_mod), " ", " ");
299 if (!strncmp((const char *)a, " has passed moderation to ", 26)) {
300 a += 26;
301 scan(&a, new_mod, sizeof(new_mod), " ", " ");
302 snprintf(s, sizeof(s),
303 ":%s MODE %s -o+o %s %s\r\n",
304 old_mod, irc_channel, old_mod, new_mod);
305 } else if (!strcmp((const char *)a, " is now mod.")) {
306 snprintf(s, sizeof(s),
307 ":%s MODE %s +o %s\r\n",
308 icb_hostid, irc_channel, old_mod);
309 } else
310 return;
311 sync_write(fd, s, strlen(s));
312 strlcpy(icb_moderator, new_mod, sizeof(icb_moderator));
313 } else if (!strcmp(args[0], "Boot")) {
314 char nick[256];
315
316 scan(&a, nick, sizeof(nick), " ", " ");
317 if (strcmp((const char *)a, " was booted."))
318 return;
319 snprintf(s, sizeof(s), ":%s KICK %s %s :booted\r\n",
320 icb_moderator, irc_channel, nick);
321 sync_write(fd, s, strlen(s));
322 } else
323 irc_send_notice(fd, "ICB Status Message: %s: %s",
324 args[0], args[1]);
325 break;
326 case 'e': /* Error Message */
327 irc_send_notice(fd, "ICB Error Message: %s", args[0]);
328 break;
329 case 'f': /* Important Message */
330 irc_send_notice(fd, "ICB Important Message: %s: %s",
331 args[0], args[1]);
332 break;
333 case 'g': /* Exit */
334 irc_send_notice(fd, "ICB Exit");
335 printf("server Exit\n");
336 terminate_client = 1;
337 break;
338 case 'i': /* Command Output */
339 if (!strcmp(args[0], "co")) {
340 for (j = 1; j < i; ++j)
341 icb_ico(fd, args[j]);
342 } else if (!strcmp(args[0], "wl")) {
343 icb_iwl(fd, args[1], args[2], atol(args[3]),
344 atol(args[5]), args[6], args[7]);
345 } else if (!strcmp(args[0], "wh")) {
346 /* display whois header, deprecated */
347 } else
348 irc_send_notice(fd, "ICB Command Output: %s: %u args",
349 args[0], i - 1);
350 break;
351 case 'j': /* Protocol */
352 strlcpy(icb_protolevel, args[0], sizeof(icb_protolevel));
353 strlcpy(icb_hostid, args[1], sizeof(icb_hostid));
354 strlcpy(icb_serverid, args[2], sizeof(icb_serverid));
355 break;
356 case 'k': /* Beep */
357 irc_send_notice(fd, "ICB Beep from %s", args[0]);
358 break;
359 case 'l': /* Ping */
360 irc_send_notice(fd, "ICB Ping '%s'", args[0]);
361 break;
362 case 'm': /* Pong */
363 irc_send_notice(fd, "ICB Pong '%s'", args[0]);
364 break;
365 case 'n': /* No-op */
366 irc_send_notice(fd, "ICB No-op");
367 break;
368 default:
369 irc_send_notice(fd, "ICB unknown command %d: %u args",
370 (int)cmd[0], i);
371 }
372 }
373
374 static void
icb_iwl(int fd,const char * flags,const char * nick,long idle,long signon,const char * ident,const char * host)375 icb_iwl(int fd, const char *flags, const char *nick, long idle,
376 long signon, const char *ident, const char *host)
377 {
378 char s[8192];
379 int chanop = strchr(flags, 'm') != NULL;
380
381 if (imode == imode_whois && !strcmp(nick, inick)) {
382 snprintf(s, sizeof(s), ":%s 311 %s %s %s %s * :\r\n",
383 icb_hostid, irc_nick, nick, ident, host);
384 sync_write(fd, s, strlen(s));
385 if (icurgroup[0]) {
386 snprintf(s, sizeof(s), ":%s 319 %s %s :%s%s\r\n",
387 icb_hostid, irc_nick, nick, chanop ? "@" : "",
388 icurgroup);
389 sync_write(fd, s, strlen(s));
390 }
391 snprintf(s, sizeof(s), ":%s 312 %s %s %s :\r\n",
392 icb_hostid, irc_nick, nick, icb_hostid);
393 sync_write(fd, s, strlen(s));
394 snprintf(s, sizeof(s), ":%s 317 %s %s %ld %ld :seconds idle, "
395 "signon time\r\n",
396 icb_hostid, irc_nick, nick, idle, signon);
397 sync_write(fd, s, strlen(s));
398 snprintf(s, sizeof(s), ":%s 318 %s %s :End of /WHOIS list.\r\n",
399 icb_hostid, irc_nick, nick);
400 sync_write(fd, s, strlen(s));
401 } else if (imode == imode_names && !strcmp(icurgroup, igroup)) {
402 snprintf(s, sizeof(s), ":%s 353 %s @ %s :%s%s \r\n",
403 icb_hostid, irc_nick, icurgroup, chanop ? "@" : "", nick);
404 sync_write(fd, s, strlen(s));
405 snprintf(s, sizeof(s), ":%s 352 %s %s %s %s %s %s H :5 %s\r\n",
406 icb_hostid, irc_nick, icurgroup, nick, host, icb_hostid,
407 nick, ident);
408 sync_write(fd, s, strlen(s));
409 } else if (imode == imode_who) {
410 int match;
411
412 if (ihostmask[0] == '#')
413 match = !strcmp(icurgroup, ihostmask);
414 else {
415 char hostmask[1024];
416
417 snprintf(hostmask, sizeof(hostmask), "%s!%s@%s",
418 nick, ident, host);
419 match = strstr(hostmask, ihostmask) != NULL;
420 }
421 if (match) {
422 snprintf(s, sizeof(s), ":%s 352 %s %s %s %s %s %s "
423 "H :5 %s\r\n",
424 icb_hostid, irc_nick, icurgroup, nick, host,
425 icb_hostid, nick, ident);
426 sync_write(fd, s, strlen(s));
427 }
428 }
429
430 if (chanop && !strcmp(icurgroup, irc_channel))
431 strlcpy(icb_moderator, nick, sizeof(icb_moderator));
432 }
433
434 static void
icb_ico(int fd,const char * arg)435 icb_ico(int fd, const char *arg)
436 {
437 char s[8192];
438
439 if (!strncmp(arg, "Group: ", 7)) {
440 char group[256];
441 int i = 0;
442 char *topic;
443
444 arg += 7;
445 group[i++] = '#';
446 while (*arg && *arg != ' ')
447 group[i++] = *arg++;
448 group[i] = 0;
449 strlcpy(icurgroup, group, sizeof(icurgroup));
450 topic = strstr(arg, "Topic: ");
451 if (topic == NULL)
452 topic = "(None)";
453 else
454 topic += 7;
455 if (imode == imode_list) {
456 snprintf(s, sizeof(s), ":%s 322 %s %s 1 :%s\r\n",
457 icb_hostid, irc_nick, group, topic);
458 sync_write(fd, s, strlen(s));
459 } else if (imode == imode_names &&
460 !strcmp(icurgroup, igroup)) {
461 snprintf(s, sizeof(s), ":%s 332 %s %s :%s\r\n",
462 icb_hostid, irc_nick, icurgroup, topic);
463 sync_write(fd, s, strlen(s));
464 }
465 } else if (!strncmp(arg, "Total: ", 7)) {
466 if (imode == imode_list) {
467 snprintf(s, sizeof(s), ":%s 323 %s :End of /LIST\r\n",
468 icb_hostid, irc_nick);
469 sync_write(fd, s, strlen(s));
470 } else if (imode == imode_names) {
471 snprintf(s, sizeof(s), ":%s 366 %s %s :End of "
472 "/NAMES list.\r\n",
473 icb_hostid, irc_nick, igroup);
474 sync_write(fd, s, strlen(s));
475 } else if (imode == imode_who) {
476 snprintf(s, sizeof(s), ":%s 315 %s %s :End of "
477 "/WHO list.\r\n",
478 icb_hostid, irc_nick, ihostmask);
479 sync_write(fd, s, strlen(s));
480 }
481 imode = imode_none;
482 } else if (strcmp(arg, " "))
483 irc_send_notice(fd, "*** Unknown ico: %s", arg);
484 }
485
486 #define MAX_MSG_SIZE 246
487
488 void
icb_send_login(int fd,const char * nick,const char * ident,const char * group)489 icb_send_login(int fd, const char *nick, const char *ident, const char *group)
490 {
491 char cmd[256];
492 unsigned off = 1;
493 const char *login_cmd = "login";
494
495 cmd[off++] = 'a';
496 while (*ident && off < MAX_MSG_SIZE)
497 cmd[off++] = *ident++;
498 cmd[off++] = '\001';
499 while (*nick && off < MAX_MSG_SIZE)
500 cmd[off++] = *nick++;
501 cmd[off++] = '\001';
502 while (*group && off < MAX_MSG_SIZE)
503 cmd[off++] = *group++;
504 cmd[off++] = '\001';
505 while (*login_cmd)
506 cmd[off++] = *login_cmd++;
507 cmd[off++] = '\001';
508 cmd[off++] = '\001';
509 cmd[off++] = '\001';
510 cmd[0] = off - 1;
511 sync_write(fd, cmd, off);
512 }
513
514 void
icb_send_openmsg(int fd,const char * msg)515 icb_send_openmsg(int fd, const char *msg)
516 {
517 unsigned char cmd[256];
518 unsigned off;
519
520 while (*msg) {
521 off = 1;
522 cmd[off++] = 'b';
523 while (*msg && off < MAX_MSG_SIZE)
524 cmd[off++] = *msg++;
525 cmd[off++] = 0;
526 cmd[0] = off - 1;
527 /* cmd[0] <= MAX_MSG_SIZE */
528 sync_write(fd, (const char *)cmd, off);
529 }
530 }
531
532 void
icb_send_privmsg(int fd,const char * nick,const char * msg)533 icb_send_privmsg(int fd, const char *nick, const char *msg)
534 {
535 unsigned char cmd[256];
536 unsigned off;
537
538 while (*msg) {
539 const char *n = nick;
540
541 off = 1;
542 cmd[off++] = 'h';
543 cmd[off++] = 'm';
544 cmd[off++] = '\001';
545 while (*n && off < MAX_MSG_SIZE)
546 cmd[off++] = *n++;
547 cmd[off++] = ' ';
548 while (*msg && off < MAX_MSG_SIZE)
549 cmd[off++] = *msg++;
550 cmd[off++] = 0;
551 cmd[0] = off - 1;
552 /* cmd[0] <= MAX_MSG_SIZE */
553 sync_write(fd, (const char *)cmd, off);
554 }
555 }
556
557 void
icb_send_group(int fd,const char * group)558 icb_send_group(int fd, const char *group)
559 {
560 char cmd[256];
561 unsigned off = 1;
562
563 cmd[off++] = 'h';
564 cmd[off++] = 'g';
565 cmd[off++] = '\001';
566 while (*group && off < MAX_MSG_SIZE)
567 cmd[off++] = *group++;
568 cmd[off++] = 0;
569 cmd[0] = off - 1;
570 sync_write(fd, cmd, off);
571 }
572
573 static void
icb_send_hw(int fd,const char * arg)574 icb_send_hw(int fd, const char *arg)
575 {
576 char cmd[256];
577 unsigned off = 1;
578
579 icurgroup[0] = 0;
580 cmd[off++] = 'h';
581 cmd[off++] = 'w';
582 cmd[off++] = '\001';
583 while (*arg && off < MAX_MSG_SIZE)
584 cmd[off++] = *arg++;
585 cmd[off++] = 0;
586 cmd[0] = off - 1;
587 sync_write(fd, cmd, off);
588 }
589
590 void
icb_send_list(int fd)591 icb_send_list(int fd)
592 {
593 if (imode != imode_none)
594 return;
595 imode = imode_list;
596 icb_send_hw(fd, "-g");
597 }
598
599 void
icb_send_names(int fd,const char * group)600 icb_send_names(int fd, const char *group)
601 {
602 if (imode != imode_none)
603 return;
604 imode = imode_names;
605 strlcpy(igroup, group, sizeof(igroup));
606 icb_send_hw(fd, "");
607 }
608
609 void
icb_send_whois(int fd,const char * nick)610 icb_send_whois(int fd, const char *nick)
611 {
612 if (imode != imode_none)
613 return;
614 imode = imode_whois;
615 strlcpy(inick, nick, sizeof(inick));
616 icb_send_hw(fd, "");
617 }
618
619 void
icb_send_who(int fd,const char * hostmask)620 icb_send_who(int fd, const char *hostmask)
621 {
622 if (imode != imode_none)
623 return;
624 imode = imode_who;
625 strlcpy(ihostmask, hostmask, sizeof(ihostmask));
626 icb_send_hw(fd, "");
627 }
628
629 void
icb_send_pass(int fd,const char * nick)630 icb_send_pass(int fd, const char *nick)
631 {
632 char cmd[256];
633 unsigned off = 1;
634 const char *pass_cmd = "pass";
635
636 cmd[off++] = 'h';
637 while (*pass_cmd)
638 cmd[off++] = *pass_cmd++;
639 cmd[off++] = '\001';
640 while (*nick && off < MAX_MSG_SIZE)
641 cmd[off++] = *nick++;
642 cmd[off++] = 0;
643 cmd[0] = off - 1;
644 sync_write(fd, cmd, off);
645 }
646
647 void
icb_send_topic(int fd,const char * topic)648 icb_send_topic(int fd, const char *topic)
649 {
650 char cmd[256];
651 unsigned off = 1;
652 const char *topic_cmd = "topic";
653
654 cmd[off++] = 'h';
655 while (*topic_cmd)
656 cmd[off++] = *topic_cmd++;
657 cmd[off++] = '\001';
658 while (*topic && off < MAX_MSG_SIZE)
659 cmd[off++] = *topic++;
660 cmd[off++] = 0;
661 cmd[0] = off - 1;
662 sync_write(fd, cmd, off);
663 }
664
665 void
icb_send_boot(int fd,const char * nick)666 icb_send_boot(int fd, const char *nick)
667 {
668 char cmd[256];
669 unsigned off = 1;
670 const char *boot_cmd = "boot";
671
672 cmd[off++] = 'h';
673 while (*boot_cmd)
674 cmd[off++] = *boot_cmd++;
675 cmd[off++] = '\001';
676 while (*nick && off < MAX_MSG_SIZE)
677 cmd[off++] = *nick++;
678 cmd[off++] = 0;
679 cmd[0] = off - 1;
680 sync_write(fd, cmd, off);
681 }
682
683 void
icb_send_name(int fd,const char * nick)684 icb_send_name(int fd, const char *nick)
685 {
686 char cmd[256];
687 unsigned off = 1;
688 const char *name_cmd = "name";
689
690 cmd[off++] = 'h';
691 while (*name_cmd)
692 cmd[off++] = *name_cmd++;
693 cmd[off++] = '\001';
694 while (*nick && off < MAX_MSG_SIZE)
695 cmd[off++] = *nick++;
696 cmd[off++] = 0;
697 cmd[0] = off - 1;
698 sync_write(fd, cmd, off);
699 }
700
701 void
icb_send_raw(int fd,const char * data)702 icb_send_raw(int fd, const char *data)
703 {
704 char cmd[256];
705 unsigned off = 1;
706
707 while (*data && off < MAX_MSG_SIZE) {
708 if (*data == ',')
709 cmd[off++] = '\001';
710 else if (*data == '\\')
711 cmd[off++] = 0;
712 else
713 cmd[off++] = *data;
714 data++;
715 }
716 cmd[off++] = 0;
717 cmd[0] = off - 1;
718 sync_write(fd, cmd, off);
719 }
720
721 void
icb_send_noop(int fd)722 icb_send_noop(int fd)
723 {
724 char cmd[256];
725 unsigned off = 1;
726
727 cmd[off++] = 'n';
728 cmd[off++] = 0;
729 cmd[0] = off - 1;
730 sync_write(fd, cmd, off);
731 }
732