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