Blob


1 /* $Id: irc.c,v 1.2 2015/08/20 17:29:16 dhartmei Exp $ */
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 */
33 #include <err.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include "irc.h"
38 #include "icb.h"
40 extern void scan(const char **, char *, size_t, const char *,
41 const char *);
42 extern void icbirc_quit(void);
43 extern int sync_write(int, const char *, int);
45 static void irc_cmd(char *, int, int);
47 static void irc_send_pong(int, const char *);
49 char irc_pass[256];
50 char irc_ident[256];
51 char irc_nick[256];
52 char irc_channel[256];
53 int in_irc_channel;
55 /*
56 * irc_recv() receives read(2) chunks and assembles complete lines, which are
57 * passed to irc_cmd(). Overlong lines are truncated after 65kB.
58 *
59 * XXX: argument checking is not as strong as for ICB (trusting the client)
60 *
61 */
63 void
64 irc_recv(const char *buf, unsigned len, int client_fd, int server_fd)
65 {
66 static char cmd[65535];
67 static unsigned off = 0;
69 while (len > 0) {
70 while (len > 0 && off < (sizeof(cmd) - 1) && *buf != '\n') {
71 cmd[off++] = *buf++;
72 len--;
73 }
74 if (off == (sizeof(cmd) - 1))
75 while (len > 0 && *buf != '\n') {
76 buf++;
77 len--;
78 }
79 /* off <= sizeof(cmd) - 1 */
80 if (len > 0 && *buf == '\n') {
81 buf++;
82 len--;
83 if (off > 0 && cmd[off - 1] == '\r')
84 cmd[off - 1] = 0;
85 else
86 cmd[off] = 0;
87 irc_cmd(cmd, client_fd, server_fd);
88 off = 0;
89 }
90 }
91 }
93 static void
94 irc_cmd(char *cmd, int client_fd, int server_fd)
95 {
96 if (!strncasecmp(cmd, "RAWICB ", 7)) {
97 icb_send_raw(server_fd, cmd + 7);
98 return;
99 }
101 char *argv[10], *p;
102 int argc = 1;
104 for (p = cmd, argv[0] = p; argc < 10 && (p = strchr(p, ' ')) != NULL;
105 argc++) {
106 *p = 0;
107 p++;
108 while (*p == ' ')
109 p++;
110 if (*p == ':') {
111 argv[argc] = p + 1;
112 argc++;
113 break;
115 argv[argc] = p;
118 if (!strcasecmp(argv[0], "PASS")) {
119 strlcpy(irc_pass, argv[1], sizeof(irc_pass));
120 } else if (!strcasecmp(argv[0], "USER")) {
121 strlcpy(irc_ident, argv[1], sizeof(irc_ident));
122 if (!icb_logged_in && irc_nick[0] && irc_ident[0])
123 icb_send_login(server_fd, irc_nick,
124 irc_ident, irc_pass);
125 } else if (!strcasecmp(argv[0], "NICK")) {
126 strlcpy(irc_nick, argv[1], sizeof(irc_nick));
127 if (icb_logged_in)
128 icb_send_name(server_fd, irc_nick);
129 else if (irc_nick[0] && irc_ident[0])
130 icb_send_login(server_fd, irc_nick,
131 irc_ident, irc_pass);
132 } else if (!strcasecmp(argv[0], "JOIN")) {
133 icb_send_group(server_fd,
134 argv[1] + (argv[1][0] == '#' ? 1 : 0));
135 } else if (!strcasecmp(argv[0], "PART")) {
136 in_irc_channel = 0;
137 } else if (!strcasecmp(argv[0], "PRIVMSG") ||
138 !strcasecmp(argv[0], "NOTICE")) {
139 char msg[8192];
140 unsigned i, j;
142 strlcpy(msg, argv[2], sizeof(msg));
143 /* strip \001 found in CTCP messages */
144 i = 0;
145 while (msg[i]) {
146 if (msg[i] == '\001') {
147 for (j = i; msg[j + 1]; ++j)
148 msg[j] = msg[j + 1];
149 msg[j] = 0;
150 } else
151 i++;
153 if (!strcmp(argv[1], irc_channel))
154 icb_send_openmsg(server_fd, msg);
155 else
156 icb_send_privmsg(server_fd, argv[1], msg);
157 } else if (!strcasecmp(argv[0], "MODE")) {
158 if (strcmp(argv[1], irc_channel))
159 return;
160 if (argc == 2)
161 icb_send_names(server_fd, irc_channel);
162 else {
163 if (strcmp(argv[2], "+o")) {
164 warnx("irc_cmd: invalid MODE args '%s'",
165 argv[2]);
166 return;
168 icb_send_pass(server_fd, argv[3]);
170 } else if (!strcasecmp(argv[0], "TOPIC")) {
171 if (strcmp(argv[1], irc_channel)) {
172 warnx("irc_cmd: invalid TOPIC channel '%s'",
173 argv[1]);
174 return;
176 icb_send_topic(server_fd, argv[2]);
177 } else if (!strcasecmp(argv[0], "LIST")) {
178 icb_send_list(server_fd);
179 } else if (!strcasecmp(argv[0], "NAMES")) {
180 icb_send_names(server_fd, argv[1]);
181 } else if (!strcasecmp(argv[0], "WHOIS")) {
182 icb_send_whois(server_fd, argv[1]);
183 } else if (!strcasecmp(argv[0], "WHO")) {
184 icb_send_who(server_fd, argv[1]);
185 } else if (!strcasecmp(argv[0], "KICK")) {
186 if (strcmp(argv[1], irc_channel)) {
187 warnx("irc_cmd: invalid KICK args '%s'", argv[1]);
188 return;
190 icb_send_boot(server_fd, argv[2]);
191 } else if (!strcasecmp(argv[0], "PING")) {
192 icb_send_noop(server_fd);
193 irc_send_pong(client_fd, argv[1]);
194 } else if (!strcasecmp(argv[0], "QUIT")) {
195 warnx("client QUIT");
196 icbirc_quit();
197 } else
198 warnx("irc_cmd: unknown command '%s'", argv[0]);
201 void
202 irc_send_notice(int fd, const char *format, ...)
204 char cmd[8192], msg[8192];
205 va_list ap;
207 va_start(ap, format);
208 vsnprintf(msg, sizeof(msg), format, ap);
209 va_end(ap);
210 snprintf(cmd, sizeof(cmd), "NOTICE %s\r\n", msg);
211 sync_write(fd, cmd, strlen(cmd));
214 void
215 irc_send_code(int fd, const char *from, const char *nick, const char *code,
216 const char *format, ...)
218 char cmd[8192], msg[8192];
219 va_list ap;
221 va_start(ap, format);
222 vsnprintf(msg, sizeof(msg), format, ap);
223 va_end(ap);
224 snprintf(cmd, sizeof(cmd), ":%s %s %s :%s\r\n", from, code, nick, msg);
225 sync_write(fd, cmd, strlen(cmd));
228 void
229 irc_send_msg(int fd, const char *src, const char *dst, const char *msg)
231 char cmd[8192];
233 snprintf(cmd, sizeof(cmd), ":%s PRIVMSG %s :%s\r\n", src, dst, msg);
234 sync_write(fd, cmd, strlen(cmd));
237 void
238 irc_send_join(int fd, const char *src, const char *dst)
240 char cmd[8192];
242 snprintf(cmd, sizeof(cmd), ":%s JOIN :%s\r\n", src, dst);
243 sync_write(fd, cmd, strlen(cmd));
244 in_irc_channel = 1;
247 void
248 irc_send_part(int fd, const char *src, const char *dst)
250 char cmd[8192];
252 snprintf(cmd, sizeof(cmd), ":%s PART :%s\r\n", src, dst);
253 sync_write(fd, cmd, strlen(cmd));
256 void
257 irc_send_pong(int fd, const char *daemon)
259 char cmd[8192];
261 snprintf(cmd, sizeof(cmd), "PONG %s\r\n", daemon);
262 sync_write(fd, cmd, strlen(cmd));