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