1 /*
2  * ctcp.c:handles the client-to-client protocol(ctcp).
3  *
4  * Written By Michael Sandrof
5  * Copyright(c) 1990, 1995 Michael Sandroff and others
6  * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
7  *
8  * Serious cleanup by jfn (August 1996)
9  */
10 
11 
12 #include "irc.h"
13 static char cvsrevision[] = "$Id: ctcp.c 432 2013-11-07 03:00:24Z tcava $";
14 CVS_REVISION(ctcp_c)
15 #include "struct.h"
16 
17 #include <pwd.h>
18 
19 
20 #ifdef HAVE_UNAME
21 # include <sys/utsname.h>
22 #endif
23 
24 #include <stdarg.h>
25 
26 #include "encrypt.h"
27 #include "ctcp.h"
28 #include "dcc.h"
29 #include "commands.h"
30 #include "flood.h"
31 #include "hook.h"
32 #include "if.h"
33 #include "ignore.h"
34 #include "ircaux.h"
35 #include "lastlog.h"
36 #include "list.h"
37 #include "names.h"
38 #include "output.h"
39 #include "parse.h"
40 #include "server.h"
41 #include "status.h"
42 #include "vars.h"
43 #include "window.h"
44 #include "cdcc.h"
45 #include "misc.h"
46 #include "userlist.h"
47 #include "hash2.h"
48 
49 #ifdef WANT_TCL
50 #include "tcl_bx.h"
51 #endif
52 
53 #define MAIN_SOURCE
54 #include "modval.h"
55 
56 /*
57  * ctcp_entry: the format for each ctcp function.   note that the function
58  * described takes 4 parameters, a pointer to the ctcp entry, who the message
59  * was from, who the message was to (nickname, channel, etc), and the rest of
60  * the ctcp message.  it can return null, or it can return a malloced string
61  * that will be inserted into the oringal message at the point of the ctcp.
62  * if null is returned, nothing is added to the original message
63  */
64 
65 /* forward declarations for the built in CTCP functions */
66 static	char	*do_sed 	(CtcpEntry *, char *, char *, char *);
67 static	char	*do_version 	(CtcpEntry *, char *, char *, char *);
68 static	char	*do_clientinfo 	(CtcpEntry *, char *, char *, char *);
69 static	char	*do_ping 	(CtcpEntry *, char *, char *, char *);
70 static	char	*do_echo 	(CtcpEntry *, char *, char *, char *);
71 static	char	*do_userinfo 	(CtcpEntry *, char *, char *, char *);
72 static	char	*do_finger 	(CtcpEntry *, char *, char *, char *);
73 static	char	*do_time 	(CtcpEntry *, char *, char *, char *);
74 static	char	*do_atmosphere 	(CtcpEntry *, char *, char *, char *);
75 static	char	*do_dcc 	(CtcpEntry *, char *, char *, char *);
76 static	char	*do_utc 	(CtcpEntry *, char *, char *, char *);
77 static	char	*do_dcc_reply 	(CtcpEntry *, char *, char *, char *);
78 static	char	*do_ping_reply 	(CtcpEntry *, char *, char *, char *);
79 static	char	*do_bdcc 	(CtcpEntry *, char *, char *, char *);
80 static	char	*do_cinvite 	(CtcpEntry *, char *, char *, char *);
81 static	char	*do_whoami 	(CtcpEntry *, char *, char *, char *);
82 static	char	*do_ctcpops 	(CtcpEntry *, char *, char *, char *);
83 static	char	*do_ctcpunban 	(CtcpEntry *, char *, char *, char *);
84 static	char	*do_botlink 	(CtcpEntry *, char *, char *, char *);
85 static	char	*do_ctcp_uptime	(CtcpEntry *, char *, char *, char *);
86 static	char	*do_ctcpident	(CtcpEntry *, char *, char *, char *);
87 
88 static CtcpEntry ctcp_cmd[] =
89 {
90 	{ "SED",	CTCP_SED, 	CTCP_INLINE | CTCP_NOLIMIT,
91 		"contains simple_encrypted_data",
92 		do_sed, 	do_sed },
93 	{ "UTC",	CTCP_UTC, 	CTCP_INLINE | CTCP_NOLIMIT,
94 		"substitutes the local timezone",
95 		do_utc, 	do_utc },
96 	{ "ACTION",	CTCP_ACTION, 	CTCP_SPECIAL | CTCP_NOLIMIT,
97 		"contains action descriptions for atmosphere",
98 		do_atmosphere, 	do_atmosphere },
99 
100 	{ "DCC",	CTCP_DCC, 	CTCP_SPECIAL,
101 		"requests a direct_client_connection",
102 		do_dcc, 	do_dcc_reply },
103 
104 	{ "CDCC",	CTCP_CDCC, 	CTCP_SPECIAL | CTCP_TELLUSER,
105 		"checks cdcc info for you",
106 		do_bdcc,	NULL },
107 	{ "BDCC",	CTCP_CDCC1, 	CTCP_SPECIAL | CTCP_TELLUSER,
108 		"checks cdcc info for you",
109 		do_bdcc,	NULL },
110 	{ "XDCC",	CTCP_CDCC2, 	CTCP_SPECIAL | CTCP_TELLUSER,
111 		"checks cdcc info for you",
112 		do_bdcc,	NULL },
113 
114 	{ "VERSION",	CTCP_VERSION,	CTCP_REPLY | CTCP_TELLUSER,
115 		"shows client type, version and environment",
116 		do_version, 	NULL },
117 
118 	{ "CLIENTINFO",	CTCP_CLIENTINFO,CTCP_REPLY | CTCP_TELLUSER,
119 		"gives information about available CTCP commands",
120 		do_clientinfo, 	NULL },
121 	{ "USERINFO",	CTCP_USERINFO, 	CTCP_REPLY | CTCP_TELLUSER,
122 		"returns user settable information",
123 		do_userinfo, 	NULL },
124 	{ "ERRMSG",	CTCP_ERRMSG, 	CTCP_REPLY | CTCP_TELLUSER,
125 		"returns error messages",
126 		do_echo, 	NULL },
127 	{ "FINGER",	CTCP_FINGER, 	CTCP_REPLY | CTCP_TELLUSER,
128 		"shows real name, login name and idle time of user",
129 		do_finger, 	NULL },
130 	{ "TIME",	CTCP_TIME, 	CTCP_REPLY | CTCP_TELLUSER,
131 		"tells you the time on the user's host",
132 		do_time, 	NULL },
133 	{ "PING", 	CTCP_PING, 	CTCP_REPLY | CTCP_TELLUSER,
134 		"returns the arguments it receives",
135 		do_ping, 	do_ping_reply },
136 	{ "ECHO", 	CTCP_ECHO, 	CTCP_REPLY | CTCP_TELLUSER,
137 		"returns the arguments it receives",
138 		do_echo, 	NULL },
139 
140 	{ "INVITE",	CTCP_INVITE, 	CTCP_SPECIAL,
141 		"invite to channel specified",
142 		 do_cinvite, 	NULL },
143 	{ "WHOAMI",	CTCP_WHOAMI,	CTCP_SPECIAL,
144 		"user list information",
145 		do_whoami,	NULL },
146 	{ "OP",		CTCP_OPS,	CTCP_SPECIAL,
147 		"ops the person if on userlist",
148 		do_ctcpops,	NULL },
149 	{ "OPS",	CTCP_OPS,	CTCP_SPECIAL,
150 		 "ops the person if on userlist",
151 		do_ctcpops,	NULL },
152 	{ "UNBAN",	CTCP_UNBAN,	CTCP_SPECIAL,
153 		"unbans the person from channel",
154 		do_ctcpunban,	NULL },
155 	{ "IDENT",	CTCP_IDENT,	CTCP_SPECIAL,
156 		"change userhost of userlist",
157 		do_ctcpident,	NULL },
158 	{ "XLINK",	CTCP_BOTLINK,	CTCP_SPECIAL,
159 		"x-filez rule",
160 		do_botlink,	NULL },
161 
162 	{ "UPTIME",	CTCP_UPTIME,	CTCP_SPECIAL,
163 		"my uptime",
164 		do_ctcp_uptime, NULL },
165 
166 	{ NULL,		CTCP_CUSTOM,	CTCP_REPLY | CTCP_TELLUSER,
167 		NULL,
168 		NULL, NULL }
169 };
170 
171 #ifdef WANT_DLL
172 CtcpEntryDll *dll_ctcp = NULL;
173 #endif
174 
175 
176 /* CDE do ops and unban logging */
177 
178 static char	*ctcp_type[] =
179 {
180 	"PRIVMSG",
181 	"NOTICE"
182 };
183 
184 /* This is set to one if we parsed an SED */
185 int     sed = 0;
186 
187 /*
188  * in_ctcp_flag is set to true when IRCII is handling a CTCP request.  This
189  * is used by the ctcp() sending function to force NOTICEs to be used in any
190  * CTCP REPLY
191  */
192 int	in_ctcp_flag = 0;
193 
194 #define CTCP_HANDLER(x) \
195 	static char * x (CtcpEntry *ctcp, char *from, char *to, char *cmd)
196 
197 /**************************** CTCP PARSERS ****************************/
198 
199 /********** INLINE EXPANSION CTCPS ***************/
200 
201 
202 #ifdef WANT_USERLIST
print_ctcp(char * from,char * uh,char * to,char * str,char * cmd)203 void print_ctcp(char *from, char *uh, char *to, char *str, char *cmd)
204 {
205 	put_it("%s", convert_output_format(fget_string_var(is_channel(to)?FORMAT_CTCP_CLOAK_FUNC_FSET:FORMAT_CTCP_CLOAK_FUNC_USER_FSET),
206 		"%s %s %s %s %s %s",update_clock(GET_TIME), from, uh, to, str, *cmd? cmd : empty_string));
207 }
208 
log_denied(char * type,char * from,char * uh,char * to,char * cmd)209 void log_denied(char *type, char *from, char *uh, char *to, char *cmd)
210 {
211 	logmsg(LOG_CTCP, from, 0, "%s %s %s [%s]", type, "! Access Denied from ", uh, cmd);
212 }
213 #endif
214 
CTCP_HANDLER(do_ctcpident)215 CTCP_HANDLER(do_ctcpident)
216 {
217 #if defined(WANT_USERLIST)
218 UserList *ThisNick = NULL;
219 char *nick, *passwd = NULL;
220 char *channel = "*";
221 int ok = 0;
222 	print_ctcp(from, FromUserHost, to, "IDENT ", cmd);
223 	if (is_channel(to))
224 		return NULL;
225 	nick = next_arg(cmd, &cmd);
226 	passwd = next_arg(cmd, &cmd);
227 	if (cmd && *cmd)
228 		channel = next_arg(cmd, &cmd);
229 	ThisNick = lookup_userlevelc(nick, "*", channel, passwd);
230 	if (nick && passwd && ThisNick && ThisNick->password)
231 	{
232 		if (!checkpass(passwd, ThisNick->password))
233 		{
234 			char *bang = NULL;
235 			char *u, *h;
236 			ok = 1;
237 			bang = LOCAL_COPY(FromUserHost);
238 			u = bang;
239 			if ((h = strchr(bang, '@')))
240 				*h++ = 0;
241 			if (!h || !*h)
242 				return NULL;
243 			malloc_sprintf(&ThisNick->host, "*%s@%s", clear_server_flags(u), cluster(h));
244 		}
245 	}
246 	if (!ok && !get_int_var(CLOAK_VAR))
247 		log_denied("IDENT", from, FromUserHost, to, cmd);
248 	else if (ok || (ThisNick && (ThisNick->flags & ADD_CTCP)))
249 	{
250 		if (get_int_var(SEND_CTCP_MSG_VAR))
251 			send_to_server("NOTICE %s :UserHost updated to %s", from, FromUserHost);
252 		logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s", "IDENT", from, FromUserHost);
253 	}
254 #endif
255 	return NULL;
256 }
257 
258 
259 
260 
261 /* parse a remote ctcp CDCC command */
CTCP_HANDLER(do_bdcc)262 CTCP_HANDLER(do_bdcc)
263 {
264 #ifdef WANT_CDCC
265 	int i;
266 	char *secure = NULL;
267 extern	pack *offerlist;
268 extern	remote_cmd remote[];
269 	char *rest, *arg, *temp = NULL;
270 
271 	if ((check_ignore(from, FromUserHost, to, IGNORE_CDCC, NULL) == IGNORED))
272 		return NULL;
273 
274 	if (!offerlist || !get_int_var(CDCC_VAR))
275 		return NULL;
276 
277 	if ((secure = get_string_var(CDCC_SECURITY_VAR)))
278 	{
279 		UserList *tmp;
280 		char *pass = NULL;
281 /* workaround for var.c which had a int for a var */
282 		if (*secure == '0' && strlen(secure) == 1)
283 			goto got_good_pass1;
284 		if (cmd && *cmd)
285 			pass = strrchr(cmd, ' ');
286 		if (pass && *pass)
287 		{
288 			pass++;
289 			if (*pass && !my_stricmp(pass, secure))
290 			{
291 				*pass-- = 0;
292 				goto got_good_pass1;
293 			}
294 		}
295 #if defined(WANT_USERLIST)
296 		if (!(tmp = lookup_userlevelc("*", FromUserHost, "*", NULL)) || !(tmp->flags & ADD_DCC))
297 			return NULL;
298 #else
299 		return NULL;
300 #endif
301 	}
302 
303 got_good_pass1:
304 	temp = LOCAL_COPY(cmd);
305 	arg = next_arg(temp, &temp);
306 	if (!arg)
307 		return NULL;
308 	rest = temp;
309 	for (i = 0; *remote[i].name; i++)
310 	{
311 		if (!my_stricmp(arg, remote[i].name))
312 		{
313 			remote[i].function(from, rest);
314 			return NULL;
315 		}
316 	}
317 	send_to_server("NOTICE %s :try /ctcp %s cdcc help", from, get_server_nickname(from_server));
318 #endif
319 	return NULL;
320 }
321 
CTCP_HANDLER(do_botlink)322 CTCP_HANDLER(do_botlink)
323 {
324 #if !defined(BITCHX_LITE)
325 #ifdef WANT_USERLIST
326 char *nick = NULL, *password = NULL, *port = NULL;
327 	nick = next_arg(cmd, &cmd);
328 	password = next_arg(cmd, &cmd);
329 	port = next_arg(cmd, &cmd);
330 	print_ctcp(from, FromUserHost, to, "XLINK ", cmd);
331 	if (nick && password)
332 	{
333 		char *t = NULL;
334 		UserList *n = NULL;
335 		if (get_string_var(BOT_PASSWD_VAR) || (n = lookup_userlevelc(nick, FromUserHost, "*", password)))
336 		{
337 			char *pass;
338 			if (!n)
339 				pass = get_string_var(BOT_PASSWD_VAR);
340 			else
341 				pass = n->password;
342 			if (pass && !my_stricmp(pass, password))
343 			{
344 				if (port)
345 					malloc_sprintf(&t, "%s -p %s -e %s", nick, port, password);
346 				else
347 					malloc_sprintf(&t, "%s -e %s", nick, password);
348 				dcc_chat("BOT", t);
349 				new_free(&t);
350 				set_int_var(BOT_MODE_VAR, 1);
351 				logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s to %s [%s]", "XLINK", from, FromUserHost, to, cmd?cmd:empty_string);
352 			} else
353 				log_denied("XLINK", from, FromUserHost, to, cmd);
354 		} else
355 			log_denied("XLINK", from, FromUserHost, to, cmd);
356 	}
357 	else
358 	{
359 		log_denied("XLINK", from, FromUserHost, to, cmd);
360 		return m_sprintf("Invalid Bot Link request %s %s %s", nick?nick:"null", password?password:"-", port?port:"*");
361 	}
362 #endif
363 #endif
364 
365 	return NULL;
366 }
367 
CTCP_HANDLER(do_cinvite)368 CTCP_HANDLER(do_cinvite)
369 {
370 #ifdef WANT_USERLIST
371 UserList *tmp;
372 char *channel;
373 char *password = NULL;
374 ChannelList *chan;
375 int serv = from_server;
376 	print_ctcp(from, FromUserHost, to, "Invite to ", cmd);
377 	channel = next_arg(cmd, &cmd);
378 	if (cmd && *cmd)
379 		password = next_arg(cmd, &cmd);
380 
381 	if (is_channel(to) || !channel || (channel && *channel && !is_channel(channel)))
382 		return NULL;
383 
384 	tmp = lookup_userlevelc("*", FromUserHost, channel, password);
385 	chan = prepare_command(&serv, channel, PC_SILENT);
386 	if (chan && tmp && (tmp->flags & ADD_INVITE) && (check_channel_match(tmp->channels, channel)))
387 	{
388 		if (tmp->password && !password)
389 		{
390 			log_denied("INVITE", from, FromUserHost, to, cmd);
391 			return NULL;
392 		}
393 		if (im_on_channel(channel, from_server) && is_chanop(channel, get_server_nickname(from_server)))
394 		{
395 			if (chan->key)
396 				my_send_to_server(serv, "NOTICE %s :\002Ctcp-inviting you to %s. Key is [%s]\002", from, channel, chan->key);
397 			else
398 				my_send_to_server(serv, "NOTICE %s :\002Ctcp-inviting you to %s\002", from, channel);
399 			my_send_to_server(serv, "INVITE %s %s", from, channel);
400 			logmsg(LOG_CTCP, from, 0, "Successful INVITE from %s!%s to %s", from, FromUserHost, channel);
401 		}
402 		else
403 		{
404 			if (get_int_var(SEND_CTCP_MSG_VAR))
405 				my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel);
406 			log_denied("INVITE", from, FromUserHost, to, cmd);
407 		}
408 	}
409 	else if (!get_int_var(CLOAK_VAR) || (tmp && (tmp->flags & ADD_CTCP)))
410 	{
411 		if (!chan)
412 		{
413 			if (get_int_var(SEND_CTCP_MSG_VAR))
414 				my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on that channel", from, version);
415 			log_denied("INVITE", from, FromUserHost, to, cmd);
416 		}
417 		else
418 		{
419 			if (get_int_var(SEND_CTCP_MSG_VAR))
420 				my_send_to_server(serv, "NOTICE %s :\002%s\002: Access Denied", from, version);
421 			log_denied("INVITE", from, FromUserHost, to, cmd);
422 		}
423 	}
424 	else
425 		log_denied("INVITE", from, FromUserHost, to, cmd);
426 #endif
427 	return NULL;
428 }
429 
CTCP_HANDLER(do_whoami)430 CTCP_HANDLER(do_whoami)
431 {
432 #ifdef WANT_USERLIST
433 UserList *Nick = NULL;
434 	print_ctcp(from, FromUserHost, to, "WhoAmI", cmd);
435 	if (is_channel(to))
436 		return NULL;
437 
438 	Nick = lookup_userlevelc("*", FromUserHost, "*", NULL);
439 	if (Nick && Nick->flags)
440 	{
441 		send_to_server("NOTICE %s :\002%s\002: Userlevel - %s ",from, version, convert_flags_to_str(Nick->flags));
442 		send_to_server("NOTICE %s :\002%s\002: Host Mask - %s Channels Allowed - %s   %s",
443 			from, version, Nick->host, Nick->channels, Nick->password?"Password Required":empty_string);
444 		logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s to %s", "WHOAMI", from, FromUserHost, to);
445 	}
446 	else if (!get_int_var(CLOAK_VAR) || (Nick && (Nick->flags & ADD_CTCP)))
447 	{
448 		send_to_server("NOTICE %s :\002%s\002: Access Denied", from, version);
449 		if (get_int_var(SEND_CTCP_MSG_VAR))
450 			log_denied("WHOAMI", from, FromUserHost, to, cmd);
451 	} else 	if (get_int_var(SEND_CTCP_MSG_VAR))
452 		log_denied("WHOAMI", from, FromUserHost, to, cmd);
453 #endif
454 	return NULL;
455 }
456 
CTCP_HANDLER(do_ctcp_uptime)457 CTCP_HANDLER(do_ctcp_uptime)
458 {
459 #ifdef WANT_USERLIST
460 UserList *Nick = NULL;
461 	print_ctcp(from, FromUserHost, to, "Uptime", cmd);
462 	Nick = lookup_userlevelc("*", FromUserHost, "*", NULL);
463 	if (Nick)
464 	{
465 		send_to_server("NOTICE %s :\002%s\002: Current Uptime is %s", from, version, convert_time(now-start_time));
466 		logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s to %s", "UPTIME", from, FromUserHost, to);
467 	} else 	if (get_int_var(SEND_CTCP_MSG_VAR))
468 		log_denied("UPTIME", from, FromUserHost, to, cmd);
469 #endif
470 	return NULL;
471 }
472 
CTCP_HANDLER(do_ctcpops)473 CTCP_HANDLER(do_ctcpops)
474 {
475 #ifdef WANT_USERLIST
476 UserList *Nick = NULL;
477 char *channel;
478 char *password = NULL;
479 ChannelList *chan;
480 int serv = from_server;
481 	print_ctcp(from, FromUserHost, to, "Ops on", cmd);
482 
483 	if (is_channel(to))
484 		return NULL;
485 	channel = next_arg(cmd, &cmd);
486 	if (!channel || !*channel)
487 		return NULL;
488 	if (cmd && *cmd)
489 		password = next_arg(cmd, &cmd);
490 	Nick = lookup_userlevelc("*", FromUserHost, channel, password);
491 	chan = prepare_command(&serv, channel, PC_SILENT);
492 	if (chan && get_cset_int_var(chan->csets, USERLIST_CSET) && Nick)
493 	{
494 		if (Nick->flags & ADD_OPS)
495 		{
496 			if (Nick->password && !password)
497 			{
498 				log_denied("OPS", from, FromUserHost, to, cmd);
499 				return NULL;
500 			}
501 			if (im_on_channel(channel, from_server) && is_chanop(channel, get_server_nickname(from_server)))
502 			{
503 				my_send_to_server(serv, "MODE %s +o %s", channel, from);
504 				logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s", "OPS", from, FromUserHost);
505 			}
506 			else
507 			{
508 				if (get_int_var(SEND_CTCP_MSG_VAR))
509 					my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel);
510 				log_denied("OPS", from, FromUserHost, to, cmd);
511 			}
512 		}
513 		else if (Nick->flags & ADD_VOICE)
514 		{
515 			if (im_on_channel(channel, from_server) && is_chanop(channel, get_server_nickname(from_server)))
516 			{
517 				my_send_to_server(serv, "MODE %s +v %s", channel, from);
518 				logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s", "VOICE", from, FromUserHost);
519 			}
520 			else
521 			{
522 				if (get_int_var(SEND_CTCP_MSG_VAR))
523 					my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel);
524 				log_denied("OPS", from, FromUserHost, to, cmd);
525 			}
526 		}
527 		else
528 		{
529 			if ((!get_int_var(CLOAK_VAR) || (Nick && (Nick->flags & ADD_CTCP))) && get_int_var(SEND_CTCP_MSG_VAR))
530 				my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel?channel:empty_string);
531 			log_denied("OPS", from, FromUserHost, to, cmd);
532 		}
533 	}
534 	else if (!get_int_var(CLOAK_VAR) || (Nick && (Nick->flags & ADD_CTCP)))
535 	{
536 		if (get_int_var(SEND_CTCP_MSG_VAR))
537 			my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel?channel:empty_string);
538 		log_denied("OPS", from, FromUserHost, to, cmd);
539 	}
540 #endif
541 	return NULL;
542 }
543 
CTCP_HANDLER(do_ctcpunban)544 CTCP_HANDLER(do_ctcpunban)
545 {
546 #ifdef WANT_USERLIST
547 UserList *Nick = NULL;
548 char *channel;
549 char *password = NULL;
550 char ban[BIG_BUFFER_SIZE];
551 ChannelList *chan;
552 int server;
553 
554 	print_ctcp(from, FromUserHost, to, "UnBan on ", cmd);
555 
556 	if (is_channel(to))
557 		return NULL;
558 
559 	channel = next_arg(cmd, &cmd);
560 	if (!channel || !*channel)
561 		return NULL;
562 	if (cmd && *cmd)
563 		password = next_arg(cmd, &cmd);
564 
565 	Nick = lookup_userlevelc("*", FromUserHost, channel, password);
566 	chan = prepare_command(&server, channel, PC_SILENT);
567 
568 	if (chan && get_cset_int_var(chan->csets, USERLIST_CSET) && Nick && (Nick->flags & ADD_UNBAN))
569 	{
570 		BanList *b = NULL;
571 		if (Nick->password && !password)
572 		{
573 			log_denied("UNBAN", from, FromUserHost, to, cmd);
574 			return NULL;
575 		}
576 		sprintf(ban, "%s!%s", from, FromUserHost);
577 		if (chan && chan->have_op)
578 		{
579 			if ((b = ban_is_on_channel(ban, chan)))
580 			{
581 				my_send_to_server(server, "MODE %s -b %s", channel, b->ban);
582 				logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s on %s", "UNBAN", from, FromUserHost, channel);
583 			}
584 			else
585 			{
586 				if (get_int_var(SEND_CTCP_MSG_VAR))
587 					my_send_to_server(server, "NOTICE %s :\002%s\002: you %s are not banned on %s", from, version, ban, channel);
588 				log_denied("OPS", from, FromUserHost, to, cmd);
589 			}
590 		}
591 		else
592 		{
593 			my_send_to_server(server, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel);
594 			log_denied("OPS", from, FromUserHost, to, cmd);
595 		}
596 	}
597 	else if (!get_int_var(CLOAK_VAR) || (Nick && (Nick->flags & ADD_CTCP)))
598 	{
599 		if (!chan)
600 			my_send_to_server(server, "NOTICE %s :\002%s\002: I'm not on that channel", from, version);
601 		else
602 			my_send_to_server(server, "NOTICE %s :\002%s\002: Access Denied", from, version);
603 		log_denied("OPS", from, FromUserHost, to, cmd);
604 	}
605 #endif
606 	return NULL;
607 }
608 
609 
610 
611 /*
612  * do_sed: Performs the Simple Encrypted Data trasfer for ctcp.  Returns in a
613  * malloc string the decryped message (if a key is set for that user) or the
614  * text "[ENCRYPTED MESSAGE]"
615  */
CTCP_HANDLER(do_sed)616 CTCP_HANDLER(do_sed)
617 {
618 	char	*key = NULL,
619 		*crypt_who;
620 	char	*ret = NULL, *ret2 = NULL;
621 
622 	if (*from == '=')
623 		crypt_who = from;
624 	if (my_stricmp(to, get_server_nickname(from_server)))
625 		crypt_who = to;
626 	else
627 		crypt_who = from;
628 
629 	if ((key = is_crypted(crypt_who)))
630 		ret = decrypt_msg(cmd, key);
631 
632 	if (!key || !ret)
633 		malloc_strcpy(&ret2, "[ENCRYPTED MESSAGE]");
634 	else
635 	{
636 		/*
637 		 * There might be a CTCP message in there,
638 		 * so we see if we can find it.
639 		 */
640 		ret2 = m_strdup(do_ctcp(from, to, ret));
641 		sed = 1;
642 	}
643 
644 	new_free(&ret);
645 	return ret2;
646 }
647 
CTCP_HANDLER(do_utc)648 CTCP_HANDLER(do_utc)
649 {
650 
651 	if (get_int_var(CLOAK_VAR))
652 		return m_strdup(empty_string);
653 	if (!cmd || !*cmd)
654 		return m_strdup(empty_string);
655 
656 	return m_strdup(my_ctime(my_atol(cmd)));
657 }
658 
659 
660 /*
661  * do_atmosphere: does the CTCP ACTION command --- done by lynX
662  * Changed this to make the default look less offensive to people
663  * who don't like it and added a /on ACTION. This is more in keeping
664  * with the design philosophy behind IRCII
665  */
CTCP_HANDLER(do_atmosphere)666 CTCP_HANDLER(do_atmosphere)
667 {
668 	const char *old_message_from;
669 	unsigned long old_message_level;
670 	int ac_reply;
671 	char *ptr1 = cmd;
672 
673 	if (!cmd || !*cmd)
674 		return NULL;
675 
676 	if ((ac_reply = check_auto_reply(cmd)))
677 		addtabkey(from,"msg", 1);
678 
679 	save_display_target(&old_message_from, &old_message_level);
680 	logmsg(LOG_ACTION, from, 0, "%s %s", to, cmd);
681 
682 	if (is_channel(to))
683 	{
684 		int r = 0;
685 		ChannelList *chan = NULL;
686 		chan = lookup_channel(to, from_server, CHAN_NOUNLINK);
687 		do_logchannel(LOG_CTCP, chan, "%s %s %s %s", from, FromUserHost, to, cmd);
688 #ifdef WANT_USERLIST
689 		r = (lookup_userlevelc("*", FromUserHost, to, NULL)) ? 1 : 0;
690 #endif
691 		set_display_target(to, LOG_ACTION);
692 		if (do_hook(ACTION_LIST, "%s %s %s", from, to, cmd))
693 		{
694 			char *s;
695 	s = fget_string_var((ac_reply && r)?FORMAT_ACTION_USER_AR_FSET :
696 		ac_reply ? FORMAT_ACTION_OTHER_AR_FSET :
697 		r ? FORMAT_ACTION_USER_FSET :FORMAT_ACTION_OTHER_FSET);
698 			if (is_current_channel(to, from_server, 0))
699 			{
700 	s = fget_string_var((r && ac_reply)?FORMAT_ACTION_USER_AR_FSET:
701 		(ac_reply) ? FORMAT_ACTION_AR_FSET:
702 		r ? FORMAT_ACTION_USER_FSET : FORMAT_ACTION_CHANNEL_FSET);
703 				put_it("%s", convert_output_format(s, "%s %s %s %s %s",update_clock(GET_TIME), from, FromUserHost, to, ptr1));
704 			}
705 			else
706 				put_it("%s", convert_output_format(s, "%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, to, ptr1));
707 		}
708 	}
709 	else
710 	{
711 		set_display_target(from, LOG_ACTION);
712 		if (do_hook(ACTION_LIST, "%s %s %s", from, to, cmd))
713 			put_it("%s", convert_output_format(fget_string_var(ac_reply?FORMAT_ACTION_AR_FSET:FORMAT_ACTION_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, to, ptr1));
714 	}
715 
716 	restore_display_target(old_message_from, old_message_level);
717 	return NULL;
718 }
719 
720 /*
721  * do_dcc: Records data on an incoming DCC offer. Makes sure it's a
722  *	user->user CTCP, as channel DCCs don't make any sense whatsoever
723  */
CTCP_HANDLER(do_dcc)724 CTCP_HANDLER(do_dcc)
725 {
726 	char	*type;
727 	char	*description = NULL;
728 	char	*inetaddr = NULL;
729 	char	*port = NULL;
730 	char	*size = NULL;
731 	char	*extra_flags = NULL;
732 	if (my_stricmp(to, get_server_nickname(from_server)))
733 		return NULL;
734 	if (!(type = next_arg(cmd, &cmd)))
735 		return NULL;
736 #if 1
737 	if (!(description = new_next_arg(cmd, &cmd)) || !*description)
738 		return NULL;
739 	if     (!(inetaddr = next_arg(cmd, &cmd)) ||
740 		!(port = next_arg(cmd, &cmd)))
741 			return NULL;
742 
743 	size = next_arg(cmd, &cmd);
744 	extra_flags = next_arg(cmd, &cmd);
745 #else
746 	size = last_arg(&cmd);
747 	port = last_arg(&cmd);
748 	inetaddr = last_arg(&cmd);
749 	if (!size || !port || !inetaddr || !description)
750 		return NULL;
751 #endif
752 	register_dcc_type(from, type, description, inetaddr, port, size, extra_flags, FromUserHost, NULL);
753 	return NULL;
754 }
755 
756 /*************** REPLY-GENERATING CTCPS *****************/
757 
758 /*
759  * do_clientinfo: performs the CLIENTINFO CTCP.  If cmd is empty, returns the
760  * list of all CTCPs currently recognized by IRCII.  If an arg is supplied,
761  * it returns specific information on that CTCP.  If a matching CTCP is not
762  * found, an ERRMSG ctcp is returned
763  */
CTCP_HANDLER(do_clientinfo)764 CTCP_HANDLER(do_clientinfo)
765 {
766 	int	i;
767 #ifdef WANT_DLL
768 	CtcpEntryDll *dll = NULL;
769 #endif
770 
771 	if (get_int_var(CLOAK_VAR))
772 		return NULL;
773 	if (cmd && *cmd)
774 	{
775 #ifdef WANT_DLL
776 		for (dll = dll_ctcp; dll; dll = dll->next)
777 		{
778 			if (!my_stricmp(cmd, dll->name))
779 			{
780 				send_ctcp(CTCP_NOTICE, from, CTCP_CLIENTINFO,
781 					"%s %s",
782 					dll->name, dll->desc?dll->desc:"none");
783 				return NULL;
784 			}
785 		}
786 #endif
787 		for (i = 0; i < NUMBER_OF_CTCPS; i++)
788 		{
789 			if (!my_stricmp(cmd, ctcp_cmd[i].name))
790 			{
791 				send_ctcp(CTCP_NOTICE, from, CTCP_CLIENTINFO,
792 					"%s %s",
793 					ctcp_cmd[i].name, ctcp_cmd[i].desc);
794 				return NULL;
795 			}
796 		}
797 		send_ctcp(CTCP_NOTICE, from, CTCP_ERRMSG,
798 				"%s: %s is not a valid function",
799 				ctcp_cmd[CTCP_CLIENTINFO].name, cmd);
800 	}
801 	else
802 	{
803 		char buffer[BIG_BUFFER_SIZE];
804 
805 		*buffer = '\0';
806 		for (i = 0; i < NUMBER_OF_CTCPS; i++)
807 		{
808 			strlcat(buffer, ctcp_cmd[i].name, sizeof buffer);
809 			strlcat(buffer, space, sizeof buffer);
810 		}
811 #ifdef WANT_DLL
812 		for (dll = dll_ctcp; dll; dll = dll->next)
813 		{
814 			strlcat(buffer, dll->name, sizeof buffer);
815 			strlcat(buffer, space, sizeof buffer);
816 		}
817 #endif
818 		send_ctcp(CTCP_NOTICE, from, CTCP_CLIENTINFO,
819 			"%s :Use CLIENTINFO <COMMAND> to get more specific information",
820 			buffer);
821 	}
822 	return NULL;
823 }
824 
825 /* do_version: does the CTCP VERSION command */
CTCP_HANDLER(do_version)826 CTCP_HANDLER(do_version)
827 {
828 	char	*tmp;
829 	char	*version_reply = NULL;
830 extern	char	tcl_versionstr[];
831 	/*
832 	 * The old way seemed lame to me... let's show system name and
833 	 * release information as well.  This will surely help out
834 	 * experts/gurus answer newbie questions.  -- Jake [WinterHawk] Khuon
835 	 *
836 	 * For the paranoid, UNAME_HACK hides the gory details of your OS.
837 	 */
838 
839 
840 #if defined(HAVE_UNAME) && !defined(UNAME_HACK)
841 	struct utsname un;
842 	char	*the_unix,
843 		*the_version;
844 
845 	if (get_int_var(AUTOKICK_ON_VERSION_VAR))
846 	{
847 		char *channel = get_current_channel_by_refnum(0);
848 		if (channel)
849 		{
850 			ChannelList *chan;
851 			if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
852 			{
853 				NickList *nick;
854 				if ((nick = find_nicklist_in_channellist(from, chan, 0)) && !isme(from))
855 					send_to_server("KICK %s %s :%s", channel, from, "/VER is lame");
856 			}
857 		}
858 		return NULL;
859 	}
860 	if (get_int_var(CLOAK_VAR))
861 		return NULL;
862 	if (uname(&un) < 0)
863 	{
864 		the_version = empty_string;
865 		the_unix = "unknown";
866 	}
867 	else
868 	{
869 		the_version = un.release;
870 		the_unix = un.sysname;
871 	}
872 	malloc_strcpy(&version_reply, stripansicodes(convert_output_format(fget_string_var(FORMAT_VERSION_FSET), "%s %s %s %s %s", irc_version, internal_version, the_unix, the_version, tcl_versionstr)));
873 	send_ctcp(CTCP_NOTICE, from, CTCP_VERSION, "%s :%s", version_reply,
874 #else
875 	if (get_int_var(AUTOKICK_ON_VERSION_VAR))
876 	{
877 		char *channel = get_current_channel_by_refnum(0);
878 		if (channel)
879 		{
880 			ChannelList *chan;
881 			if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
882 			{
883 				NickList *nick;
884 				if ((nick = find_nicklist_in_channellist(from, chan, 0)))
885 					send_to_server("KICK %s %s :%s", channel, from, "/VER is lame");
886 			}
887 		}
888 		return NULL;
889 	}
890 	if (get_int_var(CLOAK_VAR))
891 		return NULL;
892 	malloc_strcpy(&version_reply, stripansicodes(convert_output_format(fget_string_var(FORMAT_VERSION_FSET), "%s %s %s %s %s", irc_version, internal_version, "*IX", "�", tcl_versionstr)));
893 	send_ctcp(CTCP_NOTICE, from, CTCP_VERSION, "%s :%s", version_reply,
894 #endif
895 		(tmp = get_string_var(CLIENTINFO_VAR)) ?  tmp : IRCII_COMMENT);
896 	new_free(&version_reply);
897 	return NULL;
898 }
899 
900 /* do_time: does the CTCP TIME command --- done by Veggen */
CTCP_HANDLER(do_time)901 CTCP_HANDLER(do_time)
902 {
903 
904 
905 	if (get_int_var(CLOAK_VAR))
906 		return NULL;
907 	send_ctcp(CTCP_NOTICE, from, CTCP_TIME,
908 			"%s", my_ctime(now));
909 	return NULL;
910 }
911 
912 /* do_userinfo: does the CTCP USERINFO command */
CTCP_HANDLER(do_userinfo)913 CTCP_HANDLER(do_userinfo)
914 {
915 
916 
917 	if (get_int_var(CLOAK_VAR))
918 		return NULL;
919 	send_ctcp(CTCP_NOTICE, from, CTCP_USERINFO,
920 			"%s", get_string_var(USERINFO_VAR));
921 	return NULL;
922 }
923 
924 /*
925  * do_echo: does the CTCP ERRMSG and CTCP ECHO commands. Does
926  * not send an error for ERRMSG and if the CTCP was sent to a channel.
927  */
CTCP_HANDLER(do_echo)928 CTCP_HANDLER(do_echo)
929 {
930 
931 
932 	if (get_int_var(CLOAK_VAR))
933 		return NULL;
934 	if (!is_channel(to))
935 	{
936 		if (strlen(cmd) > 60)
937 		{
938 			yell("WARNING ctcp echo request longer than 60 chars. truncating");
939 			cmd[60] = 0;
940 		}
941 		send_ctcp(CTCP_NOTICE, from, ctcp->id, "%s", cmd);
942 	}
943 	return NULL;
944 }
945 
CTCP_HANDLER(do_ping)946 CTCP_HANDLER(do_ping)
947 {
948 
949 
950 	if (get_int_var(CLOAK_VAR) == 2)
951 		return NULL;
952 	send_ctcp(CTCP_NOTICE, from, CTCP_PING, "%s", cmd ? cmd : empty_string);
953 	return NULL;
954 }
955 
956 
957 /*
958  * Does the CTCP FINGER reply
959  */
CTCP_HANDLER(do_finger)960 CTCP_HANDLER(do_finger)
961 {
962 	struct	passwd	*pwd;
963 	time_t	diff;
964 	char	*tmp;
965 	char	*ctcpuser,
966 		*ctcpfinger;
967 const	char	*my_host;
968 
969 
970 	if (get_int_var(CLOAK_VAR))
971 		return NULL;
972 	if ((my_host = get_server_userhost(from_server)) && strchr(my_host, '@'))
973 		my_host = strchr(my_host, '@') + 1;
974 	else
975 		my_host = hostname;
976 
977 	diff = now - idle_time;
978 
979 	if (!(pwd = getpwuid(getuid())))
980 		return NULL;
981 
982 #ifndef GECOS_DELIMITER
983 #define GECOS_DELIMITER ','
984 #endif
985 
986 	if ((tmp = strchr(pwd->pw_gecos, GECOS_DELIMITER)) != NULL)
987 		*tmp = '\0';
988 
989 /*
990  * Three optionsn for handling CTCP replies
991  *  + Fascist Bastard Way -- normal, non-hackable fashion
992  *  + Winterhawk way (default) -- allows hacking through IRCUSER and
993  *	IRCFINGER environment variables
994  *  + hop way -- returns a blank always
995  */
996 	/*
997 	 * It would be pretty pointless to allow for customisable
998 	 * usernames if they can track via IRCNAME from the
999 	 * /etc/passwd file...  We therefore need to either disable
1000 	 * CTCP_FINGER or also make it customisable.  Let's do the
1001 	 * latter because it invokes less suspicion in the long run
1002 	 *				-- Jake [WinterHawk] Khuon
1003 	 */
1004 	if (!(ctcpuser = getenv("IRCUSER")))
1005 		ctcpuser = pwd->pw_name;
1006 	if (!(ctcpfinger = getenv("IRCFINGER")))
1007 		ctcpfinger = pwd->pw_gecos;
1008 
1009 	send_ctcp(CTCP_NOTICE, from, CTCP_FINGER,
1010 		"%s (%s@%s) Idle %ld second%s",
1011 		ctcpfinger, ctcpuser, my_host, diff, plural(diff));
1012 	return NULL;
1013 }
1014 
1015 
1016 /*
1017  * If we recieve a CTCP DCC REJECT in a notice, then we want to remove
1018  * the offending DCC request
1019  */
CTCP_HANDLER(do_dcc_reply)1020 CTCP_HANDLER(do_dcc_reply)
1021 {
1022 	char *subcmd = NULL;
1023 	char *type = NULL;
1024 
1025 	if (is_channel(to))
1026 		return NULL;
1027 
1028 	if (cmd && *cmd)
1029 		subcmd = next_arg(cmd, &cmd);
1030 	if (cmd && *cmd)
1031 		type = next_arg(cmd, &cmd);
1032 
1033 	if (subcmd && type && cmd && !strcmp(subcmd, "REJECT"))
1034 		dcc_reject (from, type, cmd);
1035 
1036 	return NULL;
1037 }
1038 
1039 
1040 /*
1041  * Handles CTCP PING replies.
1042  */
CTCP_HANDLER(do_ping_reply)1043 CTCP_HANDLER(do_ping_reply)
1044 {
1045 	char *sec, *usec = NULL;
1046 	struct timeval t;
1047 	time_t tsec = 0, tusec = 0, orig;
1048 
1049 	if (!cmd || !*cmd)
1050 		return NULL;		/* This is a fake -- cant happen. */
1051 
1052 	orig = my_atol(cmd);
1053 
1054 	get_time(&t);
1055 	if (orig < start_time || orig > t.tv_sec)
1056 		return NULL;
1057 
1058        /* We've already checked 'cmd' here, so its safe. */
1059         sec = cmd;
1060 	tsec = t.tv_sec - my_atol(sec);
1061 
1062 	if ((usec = strchr(sec, ' ')))
1063 	{
1064 		*usec++ = 0;
1065 		tusec = t.tv_usec - my_atol(usec);
1066 	}
1067 
1068 	/*
1069 	 * 'cmd', a variable passed in from do_notice_ctcp()
1070 	 * points to a buffer which is MUCH larger than the
1071 	 * string 'cmd' points at.  So this is safe, even
1072 	 * if it looks "unsafe".
1073 	 */
1074 	sprintf(cmd, "%5.3f seconds", (float)(tsec + (tusec / 1000000.0)));
1075 	return NULL;
1076 }
1077 
1078 
1079 /************************************************************************/
1080 /*
1081  * do_ctcp: a re-entrant form of a CTCP parser.  The old one was lame,
1082  * so i took a hatchet to it so it didnt suck.
1083  */
do_ctcp(char * from,char * to,char * str)1084 extern 	char *do_ctcp (char *from, char *to, char *str)
1085 {
1086 	int 	flag;
1087 
1088 	char 	local_ctcp_buffer [BIG_BUFFER_SIZE + 1],
1089 		the_ctcp          [IRCD_BUFFER_SIZE + 1],
1090 		last              [IRCD_BUFFER_SIZE + 1];
1091 	char	*ctcp_command,
1092 		*ctcp_argument;
1093 	int	i;
1094 	char	*ptr = NULL;
1095 	int	allow_ctcp_reply = 1;
1096 
1097 #ifdef WANT_DLL
1098 	CtcpEntryDll  *dll = NULL;
1099 #endif
1100 	int delim_char = charcount(str, CTCP_DELIM_CHAR);
1101 
1102 	if (delim_char < 2)
1103 		return str;             /* No CTCPs. */
1104 
1105 	if (delim_char > 8)
1106 		allow_ctcp_reply = 0;   /* Historical limit of 4 CTCPs */
1107 
1108 
1109 	flag = check_ignore(from, FromUserHost, to, IGNORE_CTCPS, NULL);
1110 
1111 	in_ctcp_flag++;
1112 	strlcpy(local_ctcp_buffer, str, sizeof local_ctcp_buffer - 2);
1113 
1114 	for (;;strlcat(local_ctcp_buffer, last, sizeof local_ctcp_buffer - 2))
1115 	{
1116 		split_CTCP(local_ctcp_buffer, the_ctcp, last);
1117 
1118 		if (!*the_ctcp)
1119 			break;		/* all done! */
1120 		/*
1121 		 * Apply some integrety rules:
1122 		 * -- If we've already replied to a CTCP, ignore it.
1123 		 * -- If user is ignoring sender, ignore it.
1124 		 * -- If we're being flooded, ignore it.
1125 		 * -- If CTCP was a global msg, ignore it.
1126 		 */
1127 
1128 		/*
1129 		 * Yes, this intentionally ignores "unlimited" CTCPs like
1130 		 * UTC and SED.  Ultimately, we have to make sure that
1131 		 * CTCP expansions dont overrun any buffers that might
1132 		 * contain this string down the road.  So by allowing up to
1133 		 * 4 CTCPs, we know we cant overflow -- but if we have more
1134 		 * than 40, it might overflow, and its probably a spam, so
1135 		 * no need to shed tears over ignoring them.  Also makes
1136 		 * the sanity checking much simpler.
1137 		 */
1138 		if (!allow_ctcp_reply)
1139 			continue;
1140 
1141 		/*
1142 		 * Check to see if the user is ignoring person.
1143 		 */
1144 
1145 		if (flag == IGNORED)
1146 		{
1147 			allow_ctcp_reply = 0;
1148 			continue;
1149 		}
1150 
1151 		ctcp_command = the_ctcp;
1152 		ctcp_argument = strchr(the_ctcp, ' ');
1153 		if (ctcp_argument)
1154 			*ctcp_argument++ = 0;
1155 		else
1156 			ctcp_argument = empty_string;
1157 
1158 		/* Set up the window level/logging */
1159 		if (im_on_channel(to, from_server))
1160 			set_display_target(to, LOG_CTCP);
1161 		else
1162 			set_display_target(from, LOG_CTCP);
1163 
1164 		/* Global messages -- just drop the CTCP */
1165 		if (*to == '$' || (*to == '#' && !lookup_channel(to, from_server, 0)))
1166 		{
1167 			allow_ctcp_reply = 0;
1168 			continue;
1169 		}
1170 #ifdef WANT_DLL
1171 		/* Find the correct CTCP and run it. */
1172 		for (dll = dll_ctcp; dll; dll = dll->next)
1173 			if (!strcmp(dll->name, ctcp_command))
1174 				break;
1175 #endif
1176 		for (i = 0; i < NUMBER_OF_CTCPS; i++)
1177 			if (!strcmp(ctcp_command, ctcp_cmd[i].name))
1178 				break;
1179 
1180 		/* Set up the window level/logging */
1181 		if (im_on_channel(to, from_server))
1182 			set_display_target(to, LOG_CTCP);
1183 		else
1184 			set_display_target(NULL, LOG_CTCP);
1185 
1186 #ifdef WANT_DLL
1187 		if (!dll && ctcp_cmd[i].id == CTCP_ACTION)
1188 			check_flooding(from, CTCP_ACTION_FLOOD, ctcp_argument, is_channel(to)?to:NULL);
1189 		else if (!dll && ctcp_cmd[i].id == CTCP_DCC)
1190 			check_flooding(from, CTCP_FLOOD, ctcp_argument, is_channel(to)?to:NULL);
1191 #else
1192 		if (ctcp_cmd[i].id == CTCP_ACTION)
1193 			check_flooding(from, CTCP_ACTION_FLOOD, ctcp_argument, is_channel(to)?to:NULL);
1194 		else if (ctcp_cmd[i].id == CTCP_DCC)
1195 			check_flooding(from, CTCP_FLOOD, ctcp_argument, is_channel(to)?to:NULL);
1196 #endif
1197 		else
1198 		{
1199 			check_flooding(from, CTCP_FLOOD, ctcp_argument, is_channel(to)?to:NULL);
1200 			if (get_int_var(NO_CTCP_FLOOD_VAR) && (now - get_server_last_ctcp_time(from_server) < get_int_var(CTCP_DELAY_VAR)))
1201 			{
1202 				if (get_int_var(FLOOD_WARNING_VAR))
1203 					put_it("%s", convert_output_format(fget_string_var(FORMAT_FLOOD_FSET), "%s %s %s %s %s", update_clock(GET_TIME),ctcp_command,from, FromUserHost, to));
1204 				set_server_last_ctcp_time(from_server, time(NULL));
1205 				allow_ctcp_reply = 0;
1206 				continue;
1207 			}
1208 		}
1209 		/* Did the CTCP search work? */
1210 #ifdef WANT_DLL
1211 		if (i == NUMBER_OF_CTCPS && !dll)
1212 #else
1213 		if (i == NUMBER_OF_CTCPS)
1214 #endif
1215 		{
1216 			/*
1217 			 * Offer it to the user.
1218 			 * Maybe they know what to do with it.
1219 			 */
1220 #ifdef WANT_TCL
1221 			if (check_tcl_ctcp(from, FromUserHost, from, to, ctcp_command, ctcp_argument))
1222 				continue;
1223 #endif
1224 
1225 			if (do_hook(CTCP_LIST, "%s %s %s %s", from, to, ctcp_command, ctcp_argument) && allow_ctcp_reply)
1226 			{
1227 				if (get_int_var(CTCP_VERBOSE_VAR))
1228 				{
1229 #ifdef WANT_USERLIST
1230 					if (lookup_userlevelc("*", FromUserHost, "*", NULL))
1231 						put_it("%s", convert_output_format(fget_string_var(get_int_var(CLOAK_VAR)? FORMAT_CTCP_CLOAK_UNKNOWN_USER_FSET:FORMAT_CTCP_UNKNOWN_USER_FSET),
1232 							"%s %s %s %s %s %s",update_clock(GET_TIME), from, FromUserHost, to, ctcp_command, *ctcp_argument? ctcp_argument : empty_string));
1233 					else
1234 #endif
1235 						put_it("%s", convert_output_format(fget_string_var(get_int_var(CLOAK_VAR)? FORMAT_CTCP_CLOAK_UNKNOWN_FSET:FORMAT_CTCP_UNKNOWN_FSET),
1236 							"%s %s %s %s %s %s",update_clock(GET_TIME), from, FromUserHost, to, ctcp_command, *ctcp_argument? ctcp_argument : empty_string));
1237 				}
1238 
1239 				add_last_type(&last_ctcp[0], 1, from, FromUserHost, to, ctcp_command);
1240 			}
1241 			allow_ctcp_reply = 0;
1242 			continue;
1243 		}
1244 
1245 #ifdef WANT_TCL
1246 		check_tcl_ctcp(from, FromUserHost, from, to, ctcp_command, ctcp_argument);
1247 #endif
1248 
1249 #ifdef WANT_DLL
1250 		if (dll)
1251 			ptr = (dll->func) (dll, from, to, ctcp_argument);
1252 		else
1253 #endif
1254 			ptr = ctcp_cmd[i].func(ctcp_cmd + i, from, to, ctcp_argument);
1255 
1256 #ifdef WANT_DLL
1257 		if (!(ctcp_cmd[i].flag & CTCP_NOLIMIT) || (dll && !(dll->flag & CTCP_NOLIMIT)))
1258 #else
1259 		if (!(ctcp_cmd[i].flag & CTCP_NOLIMIT))
1260 #endif
1261 		{
1262 			set_server_last_ctcp_time(from_server, time(NULL));
1263 			allow_ctcp_reply = 0;
1264 		}
1265 
1266 		/*
1267 		 * We've only gotten to this point if its a valid CTCP
1268 		 * query and we decided to parse it.
1269 		 */
1270 
1271 		/* If its an inline CTCP paste it back in */
1272 #ifdef WANT_DLL
1273 		if ((ctcp_cmd[i].flag & CTCP_INLINE) || (dll && (dll->flag & CTCP_INLINE)))
1274 			strlcat(local_ctcp_buffer, ptr, sizeof local_ctcp_buffer);
1275 #else
1276 		if ((ctcp_cmd[i].flag & CTCP_INLINE))
1277 			strlcat(local_ctcp_buffer, ptr, sizeof local_ctcp_buffer);
1278 #endif
1279 		/* If its interesting, tell the user. */
1280 #ifdef WANT_DLL
1281 		if ((ctcp_cmd[i].flag & CTCP_TELLUSER) || (dll && (dll->flag & CTCP_TELLUSER)))
1282 #else
1283 		if ((ctcp_cmd[i].flag & CTCP_TELLUSER))
1284 #endif
1285 		{
1286 			if (do_hook(CTCP_LIST, "%s %s %s %s", from, to, ctcp_command, ctcp_argument))
1287 			{
1288 				if (get_int_var(CTCP_VERBOSE_VAR))
1289 #ifdef WANT_USERLIST
1290 					put_it("%s", convert_output_format(fget_string_var((!lookup_userlevelc("*",FromUserHost, "*", NULL))? get_int_var(CLOAK_VAR)?FORMAT_CTCP_CLOAK_FSET:FORMAT_CTCP_FSET:get_int_var(CLOAK_VAR)?FORMAT_CTCP_CLOAK_USER_FSET:FORMAT_CTCP_USER_FSET),
1291 						"%s %s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, to, ctcp_command, *ctcp_argument? ctcp_argument : empty_string));
1292 #else
1293 					put_it("%s", convert_output_format(fget_string_var((get_int_var(CLOAK_VAR)?FORMAT_CTCP_CLOAK_FSET:FORMAT_CTCP_FSET)),
1294 						"%s %s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, to, ctcp_command, *ctcp_argument? ctcp_argument : empty_string));
1295 #endif
1296 				add_last_type(&last_ctcp[0], 1, from, FromUserHost, to, ctcp_command);
1297 			}
1298 		}
1299 
1300 		new_free(&ptr);
1301 	}
1302 
1303 	/* Reset the window level/logging */
1304 	reset_display_target();
1305 
1306 	in_ctcp_flag--;
1307 	strlcpy(str, local_ctcp_buffer, BIG_BUFFER_SIZE);
1308 	return str;
1309 }
1310 
1311 
1312 
1313 /*
1314  * do_notice_ctcp: a re-entrant form of a CTCP reply parser.
1315  */
do_notice_ctcp(char * from,char * to,char * str)1316 extern 	char *do_notice_ctcp (char *from, char *to, char *str)
1317 {
1318 	int 	flag;
1319 	char 	local_ctcp_buffer [BIG_BUFFER_SIZE + 1],
1320 		the_ctcp          [IRCD_BUFFER_SIZE + 1],
1321 		last              [IRCD_BUFFER_SIZE + 1];
1322 	char	*ctcp_command,
1323 		*ctcp_argument;
1324 	int	i;
1325 	char	*ptr;
1326 	char	*tbuf = NULL;
1327 	int	allow_ctcp_reply = 1;
1328 
1329 #ifdef WANT_DLL
1330 	CtcpEntryDll  *dll = NULL;
1331 #endif
1332 
1333 	int delim_char = charcount(str, CTCP_DELIM_CHAR);
1334 
1335 	if (delim_char < 2)
1336 		return str;		/* No CTCPs. */
1337 	if (delim_char > 8)
1338 		allow_ctcp_reply = 0;	/* Ignore all the CTCPs. */
1339 
1340 	flag = check_ignore(from, FromUserHost, to, IGNORE_CTCPS, NULL);
1341 	if (!in_ctcp_flag)
1342 		in_ctcp_flag = -1;
1343 
1344 	tbuf = stripansi(str);
1345 	strlcpy(local_ctcp_buffer, tbuf, sizeof local_ctcp_buffer - 2);
1346 	new_free(&tbuf);
1347 
1348 	for (;;strlcat(local_ctcp_buffer, last, sizeof local_ctcp_buffer - 2))
1349 	{
1350 		split_CTCP(local_ctcp_buffer, the_ctcp, last);
1351 		if (!*the_ctcp)
1352 			break;		/* all done! */
1353 
1354 		if (!allow_ctcp_reply)
1355 			continue;
1356 
1357 		if (flag == IGNORED)
1358 		{
1359 			allow_ctcp_reply = 0;
1360 			continue;
1361 		}
1362 
1363 		/* Global messages -- just drop the CTCP */
1364 		if (*to == '$' || (*to == '#' && !lookup_channel(to, from_server, 0)))
1365 		{
1366 			allow_ctcp_reply = 0;
1367 			continue;
1368 		}
1369 
1370 		ctcp_command = the_ctcp;
1371 		ctcp_argument = strchr(the_ctcp, ' ');
1372 		if (ctcp_argument)
1373 			*ctcp_argument++ = 0;
1374 		else
1375 			ctcp_argument = empty_string;
1376 
1377 #ifdef WANT_DLL
1378 		/* Find the correct CTCP and run it. */
1379 		for (dll = dll_ctcp; dll; dll = dll->next)
1380 			if (!strcmp(dll->name, ctcp_command))
1381 				break;
1382 #endif
1383 		/* Find the correct CTCP and run it. */
1384 		for (i = 0; i < NUMBER_OF_CTCPS; i++)
1385 			if (!strcmp(ctcp_command, ctcp_cmd[i].name))
1386 				break;
1387 
1388 		/*
1389 		 * If we've already parsed one, and there is a limit
1390 		 * on this CTCP, then just punt it.
1391 		 */
1392 #ifdef WANT_DLL
1393 		if (i < NUMBER_OF_CTCPS && !dll && ctcp_cmd[i].repl)
1394 #else
1395 		if (i < NUMBER_OF_CTCPS && ctcp_cmd[i].repl)
1396 #endif
1397 		{
1398 			if ((ptr = ctcp_cmd[i].repl(ctcp_cmd + i, from, to, ctcp_argument)))
1399 			{
1400 				strlcat(local_ctcp_buffer, ptr, sizeof local_ctcp_buffer);
1401 				new_free(&ptr);
1402 				continue;
1403 			}
1404 		}
1405 #ifdef WANT_DLL
1406 		if (dll && dll->repl)
1407 		{
1408 			if ((ptr = dll->repl(dll, from, to, ctcp_argument)))
1409 			{
1410 				strlcat(local_ctcp_buffer, ptr, sizeof local_ctcp_buffer);
1411 				new_free(&ptr);
1412 				continue;
1413 			}
1414 		}
1415 #endif
1416 #ifdef WANT_TCL
1417 		check_tcl_ctcr(from, FromUserHost, from, to, ctcp_command, ctcp_argument?ctcp_argument:empty_string);
1418 #endif
1419 		/* Set up the window level/logging */
1420 		set_display_target(from, LOG_CTCP);
1421 		/* Toss it at the user.  */
1422 		if (do_hook(CTCP_REPLY_LIST, "%s %s %s", from, ctcp_command, ctcp_argument))
1423 		{
1424 			put_it("%s", convert_output_format(fget_string_var(FORMAT_CTCP_REPLY_FSET),"%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, ctcp_command, ctcp_argument));
1425 			add_last_type(&last_ctcp_reply[0], 1, from, FromUserHost, ctcp_command, ctcp_argument);
1426 		}
1427 
1428 		allow_ctcp_reply = 0;
1429 	}
1430 
1431 	if (in_ctcp_flag == -1)
1432 		in_ctcp_flag = 0;
1433 	/* Reset the window level/logging */
1434 	reset_display_target();
1435 
1436 	strlcpy(str, local_ctcp_buffer, BIG_BUFFER_SIZE);
1437 	return str;
1438 }
1439 
1440 
1441 
1442 /* in_ctcp: simply returns the value of the ctcp flag */
in_ctcp(void)1443 extern int	in_ctcp (void) { return (in_ctcp_flag); }
1444 
1445 
1446 
1447 /*
1448  * This is no longer directly sends information to its target.
1449  * As part of a larger attempt to consolidate all data transmission
1450  * into send_text, this function was modified so as to use send_text().
1451  * This function can send both direct CTCP requests, as well as the
1452  * appropriate CTCP replies.  By its use of send_text(), it can send
1453  * CTCPs to DCC CHAT and irc nickname peers, and handles encryption
1454  * transparantly.  This greatly reduces the logic, complexity, and
1455  * possibility for error in this function.
1456  */
send_ctcp(int type,char * to,int datatag,char * format,...)1457 extern	void	send_ctcp (int type, char *to, int datatag, char *format, ...)
1458 {
1459 	char putbuf [BIG_BUFFER_SIZE + 1],
1460 	     *putbuf2;
1461 	int len;
1462 
1463 	if ((len = IRCD_BUFFER_SIZE - (12 + strlen(to))) < 0)
1464 		return;
1465 
1466 	if (len < strlen(ctcp_cmd[datatag].name) + 3)
1467 		return;
1468 
1469 	putbuf2 = alloca(len);
1470 
1471 	if (format)
1472 	{
1473 		va_list args;
1474 		va_start(args, format);
1475 		vsnprintf(putbuf, BIG_BUFFER_SIZE, format, args);
1476 		va_end(args);
1477 
1478 		do_hook(SEND_CTCP_LIST, "%s %s %s %s",
1479 				ctcp_type[type], to,
1480 				ctcp_cmd[datatag].name, putbuf);
1481 		snprintf(putbuf2, len, "%c%s %s%c",
1482 				CTCP_DELIM_CHAR,
1483 				ctcp_cmd[datatag].name, putbuf,
1484 				CTCP_DELIM_CHAR);
1485 	}
1486 	else
1487 	{
1488 		do_hook(SEND_CTCP_LIST, "%s %s %s",
1489 				ctcp_type[type], to,
1490 				ctcp_cmd[datatag].name);
1491 		snprintf(putbuf2, len, "%c%s%c",
1492 				CTCP_DELIM_CHAR,
1493 				ctcp_cmd[datatag].name,
1494 				CTCP_DELIM_CHAR);
1495 	}
1496 
1497 	putbuf2[len - 2] = CTCP_DELIM_CHAR;
1498 	putbuf2[len - 1] = 0;
1499 	send_text(to, putbuf2, ctcp_type[type], 0, 0);
1500 }
1501 
1502 
1503 /*
1504  * quote_it: This quotes the given string making it sendable via irc.  A
1505  * pointer to the length of the data is required and the data need not be
1506  * null terminated (it can contain nulls).  Returned is a malloced, null
1507  * terminated string.
1508  */
ctcp_quote_it(char * str,int len)1509 extern 	char	*ctcp_quote_it (char *str, int len)
1510 {
1511 	char	buffer[BIG_BUFFER_SIZE + 1];
1512 	char	*ptr;
1513 	int	i;
1514 
1515 	ptr = buffer;
1516 	for (i = 0; i < len; i++)
1517 	{
1518 		switch (str[i])
1519 		{
1520 			case CTCP_DELIM_CHAR:	*ptr++ = CTCP_QUOTE_CHAR;
1521 						*ptr++ = 'a';
1522 						break;
1523 			case '\n':		*ptr++ = CTCP_QUOTE_CHAR;
1524 						*ptr++ = 'n';
1525 						break;
1526 			case '\r':		*ptr++ = CTCP_QUOTE_CHAR;
1527 						*ptr++ = 'r';
1528 						break;
1529 			case CTCP_QUOTE_CHAR:	*ptr++ = CTCP_QUOTE_CHAR;
1530 						*ptr++ = CTCP_QUOTE_CHAR;
1531 						break;
1532 			case '\0':		*ptr++ = CTCP_QUOTE_CHAR;
1533 						*ptr++ = '0';
1534 						break;
1535 			default:		*ptr++ = str[i];
1536 						break;
1537 		}
1538 	}
1539 	*ptr = '\0';
1540 	return m_strdup(buffer);
1541 }
1542 
1543 /*
1544  * ctcp_unquote_it: This takes a null terminated string that had previously
1545  * been quoted using ctcp_quote_it and unquotes it.  Returned is a malloced
1546  * space pointing to the unquoted string.  NOTE: a trailing null is added for
1547  * convenied, but the returned data may contain nulls!.  The len is modified
1548  * to contain the size of the data returned.
1549  */
ctcp_unquote_it(char * str,int * len)1550 extern	char	*ctcp_unquote_it (char *str, int *len)
1551 {
1552 	char	*buffer;
1553 	char	*ptr;
1554 	char	c;
1555 	int	i,
1556 		new_size = 0;
1557 
1558 	buffer = (char *) new_malloc((sizeof(char) * *len) + 1);
1559 	ptr = buffer;
1560 	i = 0;
1561 	while (i < *len)
1562 	{
1563 		if ((c = str[i++]) == CTCP_QUOTE_CHAR)
1564 		{
1565 			switch (c = str[i++])
1566 			{
1567 				case CTCP_QUOTE_CHAR:
1568 					*ptr++ = CTCP_QUOTE_CHAR;
1569 					break;
1570 				case 'a':
1571 					*ptr++ = CTCP_DELIM_CHAR;
1572 					break;
1573 				case 'n':
1574 					*ptr++ = '\n';
1575 					break;
1576 				case 'r':
1577 					*ptr++ = '\r';
1578 					break;
1579 				case '0':
1580 					*ptr++ = '\0';
1581 					break;
1582 				default:
1583 					*ptr++ = c;
1584 					break;
1585 			}
1586 		}
1587 		else
1588 			*ptr++ = c;
1589 		new_size++;
1590 	}
1591 	*ptr = '\0';
1592 	*len = new_size;
1593 	return (buffer);
1594 }
1595 
get_ctcp_val(char * str)1596 int get_ctcp_val (char *str)
1597 {
1598 	int i;
1599 
1600 	for (i = 0; i < NUMBER_OF_CTCPS; i++)
1601 		if (!strcmp(str, ctcp_cmd[i].name))
1602 			return i;
1603 
1604 	/*
1605 	 * This is *dangerous*, but it works.  The only place that
1606 	 * calls this function is edit.c:ctcp(), and it immediately
1607 	 * calls send_ctcp().  So the pointer that is being passed
1608 	 * to us is globally allocated at a level higher then ctcp().
1609 	 * so it wont be bogus until some time after ctcp() returns,
1610 	 * but at that point, we dont care any more.
1611 	 */
1612 	ctcp_cmd[CTCP_CUSTOM].name = str;
1613 	return CTCP_CUSTOM;
1614 }
1615 
1616 
1617 
1618 /*
1619  * XXXX -- some may call this a hack, but if youve got a better
1620  * way to handle this job, id love to use it.
1621  */
BX_split_CTCP(char * raw_message,char * ctcp_dest,char * after_ctcp)1622 void BX_split_CTCP(char *raw_message, char *ctcp_dest, char *after_ctcp)
1623 {
1624 	char *ctcp_start, *ctcp_end;
1625 
1626 	*ctcp_dest = *after_ctcp = 0;
1627 	ctcp_start = strchr(raw_message, CTCP_DELIM_CHAR);
1628 	if (!ctcp_start)
1629 		return;		/* No CTCPs present. */
1630 
1631 	*ctcp_start++ = 0;
1632 	ctcp_end = strchr(ctcp_start, CTCP_DELIM_CHAR);
1633 	if (!ctcp_end)
1634 	{
1635 		*--ctcp_start = CTCP_DELIM_CHAR;
1636 		return;		/* Thats _not_ a CTCP. */
1637 	}
1638 
1639 	*ctcp_end++ = 0;
1640 	strlcpy(ctcp_dest, ctcp_start, IRCD_BUFFER_SIZE - 2);
1641 	strlcpy(after_ctcp, ctcp_end, IRCD_BUFFER_SIZE - 2);
1642 
1643 	return;		/* All done! */
1644 }
1645