Blame


1 d23d2886 2023-07-30 op /*
2 a29564dd 2023-08-20 op * Copyright (c) 2023 Omar Polo <op@openbsd.org>
3 d23d2886 2023-07-30 op * Copyright (c) 2003-2004 Daniel Hartmeier
4 d23d2886 2023-07-30 op * All rights reserved.
5 d23d2886 2023-07-30 op *
6 d23d2886 2023-07-30 op * Redistribution and use in source and binary forms, with or without
7 d23d2886 2023-07-30 op * modification, are permitted provided that the following conditions
8 d23d2886 2023-07-30 op * are met:
9 d23d2886 2023-07-30 op *
10 d23d2886 2023-07-30 op * - Redistributions of source code must retain the above copyright
11 d23d2886 2023-07-30 op * notice, this list of conditions and the following disclaimer.
12 d23d2886 2023-07-30 op * - Redistributions in binary form must reproduce the above
13 d23d2886 2023-07-30 op * copyright notice, this list of conditions and the following
14 d23d2886 2023-07-30 op * disclaimer in the documentation and/or other materials provided
15 d23d2886 2023-07-30 op * with the distribution.
16 d23d2886 2023-07-30 op *
17 d23d2886 2023-07-30 op * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 d23d2886 2023-07-30 op * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 d23d2886 2023-07-30 op * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 d23d2886 2023-07-30 op * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 d23d2886 2023-07-30 op * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 d23d2886 2023-07-30 op * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 d23d2886 2023-07-30 op * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 d23d2886 2023-07-30 op * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 d23d2886 2023-07-30 op * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 d23d2886 2023-07-30 op * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 d23d2886 2023-07-30 op * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 d23d2886 2023-07-30 op * POSSIBILITY OF SUCH DAMAGE.
29 d23d2886 2023-07-30 op *
30 d23d2886 2023-07-30 op */
31 d23d2886 2023-07-30 op
32 a3ace556 2023-08-01 op #include <err.h>
33 d23d2886 2023-07-30 op #include <stdarg.h>
34 d23d2886 2023-07-30 op #include <stdio.h>
35 d23d2886 2023-07-30 op #include <string.h>
36 fe009782 2023-08-01 op
37 d23d2886 2023-07-30 op #include "irc.h"
38 d23d2886 2023-07-30 op #include "icb.h"
39 d23d2886 2023-07-30 op
40 d23d2886 2023-07-30 op extern void scan(const char **, char *, size_t, const char *,
41 d23d2886 2023-07-30 op const char *);
42 c8394ca1 2023-08-01 op extern void icbirc_quit(void);
43 d23d2886 2023-07-30 op extern int sync_write(int, const char *, int);
44 d23d2886 2023-07-30 op
45 3c9ac033 2023-07-30 op static void irc_cmd(char *, int, int);
46 d23d2886 2023-07-30 op
47 d23d2886 2023-07-30 op static void irc_send_pong(int, const char *);
48 d23d2886 2023-07-30 op
49 d23d2886 2023-07-30 op char irc_pass[256];
50 d23d2886 2023-07-30 op char irc_ident[256];
51 d23d2886 2023-07-30 op char irc_nick[256];
52 d23d2886 2023-07-30 op char irc_channel[256];
53 d23d2886 2023-07-30 op int in_irc_channel;
54 5b30aca6 2024-02-14 op int in_cap;
55 d23d2886 2023-07-30 op
56 d23d2886 2023-07-30 op /*
57 d23d2886 2023-07-30 op * irc_recv() receives read(2) chunks and assembles complete lines, which are
58 d23d2886 2023-07-30 op * passed to irc_cmd(). Overlong lines are truncated after 65kB.
59 d23d2886 2023-07-30 op *
60 d23d2886 2023-07-30 op * XXX: argument checking is not as strong as for ICB (trusting the client)
61 d23d2886 2023-07-30 op *
62 d23d2886 2023-07-30 op */
63 d23d2886 2023-07-30 op
64 d23d2886 2023-07-30 op void
65 d23d2886 2023-07-30 op irc_recv(const char *buf, unsigned len, int client_fd, int server_fd)
66 d23d2886 2023-07-30 op {
67 d23d2886 2023-07-30 op static char cmd[65535];
68 d23d2886 2023-07-30 op static unsigned off = 0;
69 d23d2886 2023-07-30 op
70 d23d2886 2023-07-30 op while (len > 0) {
71 d23d2886 2023-07-30 op while (len > 0 && off < (sizeof(cmd) - 1) && *buf != '\n') {
72 d23d2886 2023-07-30 op cmd[off++] = *buf++;
73 d23d2886 2023-07-30 op len--;
74 d23d2886 2023-07-30 op }
75 d23d2886 2023-07-30 op if (off == (sizeof(cmd) - 1))
76 d23d2886 2023-07-30 op while (len > 0 && *buf != '\n') {
77 d23d2886 2023-07-30 op buf++;
78 d23d2886 2023-07-30 op len--;
79 d23d2886 2023-07-30 op }
80 d23d2886 2023-07-30 op /* off <= sizeof(cmd) - 1 */
81 d23d2886 2023-07-30 op if (len > 0 && *buf == '\n') {
82 d23d2886 2023-07-30 op buf++;
83 d23d2886 2023-07-30 op len--;
84 d23d2886 2023-07-30 op if (off > 0 && cmd[off - 1] == '\r')
85 d23d2886 2023-07-30 op cmd[off - 1] = 0;
86 d23d2886 2023-07-30 op else
87 d23d2886 2023-07-30 op cmd[off] = 0;
88 d23d2886 2023-07-30 op irc_cmd(cmd, client_fd, server_fd);
89 d23d2886 2023-07-30 op off = 0;
90 d23d2886 2023-07-30 op }
91 d23d2886 2023-07-30 op }
92 d23d2886 2023-07-30 op }
93 d23d2886 2023-07-30 op
94 d23d2886 2023-07-30 op static void
95 5b30aca6 2024-02-14 op irc_complete_registration(int server_fd)
96 5b30aca6 2024-02-14 op {
97 5b30aca6 2024-02-14 op if (icb_logged_in || *irc_nick == '\0' || *irc_ident == '\0')
98 5b30aca6 2024-02-14 op return;
99 5b30aca6 2024-02-14 op if (in_cap)
100 5b30aca6 2024-02-14 op return;
101 5b30aca6 2024-02-14 op icb_send_login(server_fd, irc_nick, irc_ident, irc_pass);
102 5b30aca6 2024-02-14 op }
103 5b30aca6 2024-02-14 op
104 5b30aca6 2024-02-14 op static void
105 3c9ac033 2023-07-30 op irc_cmd(char *cmd, int client_fd, int server_fd)
106 d23d2886 2023-07-30 op {
107 de58afd7 2023-09-04 op char *argv[10], *p;
108 de58afd7 2023-09-04 op int argc = 1;
109 de58afd7 2023-09-04 op
110 3c9ac033 2023-07-30 op if (!strncasecmp(cmd, "RAWICB ", 7)) {
111 3c9ac033 2023-07-30 op icb_send_raw(server_fd, cmd + 7);
112 3c9ac033 2023-07-30 op return;
113 3c9ac033 2023-07-30 op }
114 3c9ac033 2023-07-30 op
115 3c9ac033 2023-07-30 op for (p = cmd, argv[0] = p; argc < 10 && (p = strchr(p, ' ')) != NULL;
116 3c9ac033 2023-07-30 op argc++) {
117 7a8dd0b7 2023-09-04 op *p++ = '\0';
118 3c9ac033 2023-07-30 op while (*p == ' ')
119 3c9ac033 2023-07-30 op p++;
120 3c9ac033 2023-07-30 op if (*p == ':') {
121 3c9ac033 2023-07-30 op argv[argc] = p + 1;
122 3c9ac033 2023-07-30 op argc++;
123 3c9ac033 2023-07-30 op break;
124 3c9ac033 2023-07-30 op }
125 3c9ac033 2023-07-30 op argv[argc] = p;
126 3c9ac033 2023-07-30 op }
127 3c9ac033 2023-07-30 op
128 3c9ac033 2023-07-30 op if (!strcasecmp(argv[0], "PASS")) {
129 3c9ac033 2023-07-30 op strlcpy(irc_pass, argv[1], sizeof(irc_pass));
130 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "USER")) {
131 3c9ac033 2023-07-30 op strlcpy(irc_ident, argv[1], sizeof(irc_ident));
132 5b30aca6 2024-02-14 op irc_complete_registration(server_fd);
133 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "NICK")) {
134 3c9ac033 2023-07-30 op strlcpy(irc_nick, argv[1], sizeof(irc_nick));
135 d23d2886 2023-07-30 op if (icb_logged_in)
136 d23d2886 2023-07-30 op icb_send_name(server_fd, irc_nick);
137 d23d2886 2023-07-30 op else if (irc_nick[0] && irc_ident[0])
138 d23d2886 2023-07-30 op icb_send_login(server_fd, irc_nick,
139 d23d2886 2023-07-30 op irc_ident, irc_pass);
140 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "JOIN")) {
141 3c9ac033 2023-07-30 op icb_send_group(server_fd,
142 3c9ac033 2023-07-30 op argv[1] + (argv[1][0] == '#' ? 1 : 0));
143 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "PART")) {
144 d23d2886 2023-07-30 op in_irc_channel = 0;
145 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "PRIVMSG") ||
146 3c9ac033 2023-07-30 op !strcasecmp(argv[0], "NOTICE")) {
147 d23d2886 2023-07-30 op char msg[8192];
148 d23d2886 2023-07-30 op unsigned i, j;
149 d23d2886 2023-07-30 op
150 3c9ac033 2023-07-30 op strlcpy(msg, argv[2], sizeof(msg));
151 d23d2886 2023-07-30 op /* strip \001 found in CTCP messages */
152 d23d2886 2023-07-30 op i = 0;
153 d23d2886 2023-07-30 op while (msg[i]) {
154 d23d2886 2023-07-30 op if (msg[i] == '\001') {
155 d23d2886 2023-07-30 op for (j = i; msg[j + 1]; ++j)
156 d23d2886 2023-07-30 op msg[j] = msg[j + 1];
157 d23d2886 2023-07-30 op msg[j] = 0;
158 d23d2886 2023-07-30 op } else
159 d23d2886 2023-07-30 op i++;
160 d23d2886 2023-07-30 op }
161 3c9ac033 2023-07-30 op if (!strcmp(argv[1], irc_channel))
162 3c9ac033 2023-07-30 op icb_send_openmsg(server_fd, msg);
163 d23d2886 2023-07-30 op else
164 3c9ac033 2023-07-30 op icb_send_privmsg(server_fd, argv[1], msg);
165 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "MODE")) {
166 3c9ac033 2023-07-30 op if (strcmp(argv[1], irc_channel))
167 3c9ac033 2023-07-30 op return;
168 3c9ac033 2023-07-30 op if (argc == 2)
169 3c9ac033 2023-07-30 op icb_send_names(server_fd, irc_channel);
170 3c9ac033 2023-07-30 op else {
171 3c9ac033 2023-07-30 op if (strcmp(argv[2], "+o")) {
172 ed972677 2023-08-01 op warnx("irc_cmd: invalid MODE args '%s'",
173 3c9ac033 2023-07-30 op argv[2]);
174 d23d2886 2023-07-30 op return;
175 d23d2886 2023-07-30 op }
176 3c9ac033 2023-07-30 op icb_send_pass(server_fd, argv[3]);
177 d23d2886 2023-07-30 op }
178 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "TOPIC")) {
179 3c9ac033 2023-07-30 op if (strcmp(argv[1], irc_channel)) {
180 ed972677 2023-08-01 op warnx("irc_cmd: invalid TOPIC channel '%s'",
181 3c9ac033 2023-07-30 op argv[1]);
182 d23d2886 2023-07-30 op return;
183 d23d2886 2023-07-30 op }
184 3c9ac033 2023-07-30 op icb_send_topic(server_fd, argv[2]);
185 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "LIST")) {
186 d23d2886 2023-07-30 op icb_send_list(server_fd);
187 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "NAMES")) {
188 3c9ac033 2023-07-30 op icb_send_names(server_fd, argv[1]);
189 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "WHOIS")) {
190 3c9ac033 2023-07-30 op icb_send_whois(server_fd, argv[1]);
191 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "WHO")) {
192 3c9ac033 2023-07-30 op icb_send_who(server_fd, argv[1]);
193 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "KICK")) {
194 3c9ac033 2023-07-30 op if (strcmp(argv[1], irc_channel)) {
195 ed972677 2023-08-01 op warnx("irc_cmd: invalid KICK args '%s'", argv[1]);
196 d23d2886 2023-07-30 op return;
197 d23d2886 2023-07-30 op }
198 3c9ac033 2023-07-30 op icb_send_boot(server_fd, argv[2]);
199 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "PING")) {
200 d23d2886 2023-07-30 op icb_send_noop(server_fd);
201 3c9ac033 2023-07-30 op irc_send_pong(client_fd, argv[1]);
202 3c9ac033 2023-07-30 op } else if (!strcasecmp(argv[0], "QUIT")) {
203 ed972677 2023-08-01 op warnx("client QUIT");
204 c8394ca1 2023-08-01 op icbirc_quit();
205 a224c741 2023-08-20 op } else if (!strcasecmp(argv[0], "CAP")) {
206 a224c741 2023-08-20 op if (!strcasecmp(argv[1], "LS")) {
207 5b30aca6 2024-02-14 op in_cap = 1;
208 ec348780 2024-02-14 op printf("CAP * LS :\n");
209 a224c741 2023-08-20 op fflush(stdout);
210 a224c741 2023-08-20 op } else if (!strcasecmp(argv[1], "REQ")) {
211 5b30aca6 2024-02-14 op in_cap = 1;
212 a224c741 2023-08-20 op printf("CAP * NAK :%s\n", argv[2]);
213 a224c741 2023-08-20 op fflush(stdout);
214 5b30aca6 2024-02-14 op } else if (!strcasecmp(argv[1], "END")) {
215 5b30aca6 2024-02-14 op in_cap = 0;
216 5b30aca6 2024-02-14 op irc_complete_registration(server_fd);
217 5b30aca6 2024-02-14 op } else
218 a224c741 2023-08-20 op warnx("irc_cmd: unknown command 'CAP %s'", argv[1]);
219 d23d2886 2023-07-30 op } else
220 ed972677 2023-08-01 op warnx("irc_cmd: unknown command '%s'", argv[0]);
221 d23d2886 2023-07-30 op }
222 d23d2886 2023-07-30 op
223 d23d2886 2023-07-30 op void
224 d23d2886 2023-07-30 op irc_send_notice(int fd, const char *format, ...)
225 d23d2886 2023-07-30 op {
226 d23d2886 2023-07-30 op char cmd[8192], msg[8192];
227 d23d2886 2023-07-30 op va_list ap;
228 d23d2886 2023-07-30 op
229 d23d2886 2023-07-30 op va_start(ap, format);
230 d23d2886 2023-07-30 op vsnprintf(msg, sizeof(msg), format, ap);
231 d23d2886 2023-07-30 op va_end(ap);
232 d23d2886 2023-07-30 op snprintf(cmd, sizeof(cmd), "NOTICE %s\r\n", msg);
233 d23d2886 2023-07-30 op sync_write(fd, cmd, strlen(cmd));
234 d23d2886 2023-07-30 op }
235 d23d2886 2023-07-30 op
236 d23d2886 2023-07-30 op void
237 d23d2886 2023-07-30 op irc_send_code(int fd, const char *from, const char *nick, const char *code,
238 d23d2886 2023-07-30 op const char *format, ...)
239 d23d2886 2023-07-30 op {
240 d23d2886 2023-07-30 op char cmd[8192], msg[8192];
241 d23d2886 2023-07-30 op va_list ap;
242 d23d2886 2023-07-30 op
243 d23d2886 2023-07-30 op va_start(ap, format);
244 d23d2886 2023-07-30 op vsnprintf(msg, sizeof(msg), format, ap);
245 d23d2886 2023-07-30 op va_end(ap);
246 d23d2886 2023-07-30 op snprintf(cmd, sizeof(cmd), ":%s %s %s :%s\r\n", from, code, nick, msg);
247 d23d2886 2023-07-30 op sync_write(fd, cmd, strlen(cmd));
248 d23d2886 2023-07-30 op }
249 d23d2886 2023-07-30 op
250 d23d2886 2023-07-30 op void
251 d23d2886 2023-07-30 op irc_send_msg(int fd, const char *src, const char *dst, const char *msg)
252 d23d2886 2023-07-30 op {
253 d23d2886 2023-07-30 op char cmd[8192];
254 d23d2886 2023-07-30 op
255 d23d2886 2023-07-30 op snprintf(cmd, sizeof(cmd), ":%s PRIVMSG %s :%s\r\n", src, dst, msg);
256 d23d2886 2023-07-30 op sync_write(fd, cmd, strlen(cmd));
257 d23d2886 2023-07-30 op }
258 d23d2886 2023-07-30 op
259 d23d2886 2023-07-30 op void
260 d23d2886 2023-07-30 op irc_send_join(int fd, const char *src, const char *dst)
261 d23d2886 2023-07-30 op {
262 d23d2886 2023-07-30 op char cmd[8192];
263 d23d2886 2023-07-30 op
264 d23d2886 2023-07-30 op snprintf(cmd, sizeof(cmd), ":%s JOIN :%s\r\n", src, dst);
265 d23d2886 2023-07-30 op sync_write(fd, cmd, strlen(cmd));
266 d23d2886 2023-07-30 op in_irc_channel = 1;
267 d23d2886 2023-07-30 op }
268 d23d2886 2023-07-30 op
269 d23d2886 2023-07-30 op void
270 d23d2886 2023-07-30 op irc_send_part(int fd, const char *src, const char *dst)
271 d23d2886 2023-07-30 op {
272 d23d2886 2023-07-30 op char cmd[8192];
273 d23d2886 2023-07-30 op
274 d23d2886 2023-07-30 op snprintf(cmd, sizeof(cmd), ":%s PART :%s\r\n", src, dst);
275 d23d2886 2023-07-30 op sync_write(fd, cmd, strlen(cmd));
276 d23d2886 2023-07-30 op }
277 d23d2886 2023-07-30 op
278 d23d2886 2023-07-30 op void
279 d23d2886 2023-07-30 op irc_send_pong(int fd, const char *daemon)
280 d23d2886 2023-07-30 op {
281 d23d2886 2023-07-30 op char cmd[8192];
282 d23d2886 2023-07-30 op
283 d23d2886 2023-07-30 op snprintf(cmd, sizeof(cmd), "PONG %s\r\n", daemon);
284 d23d2886 2023-07-30 op sync_write(fd, cmd, strlen(cmd));
285 d23d2886 2023-07-30 op }