Blob


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