1 /*
2  *  Copyright Colten Edwards (c) 1996
3  */
4 #include "irc.h"
5 static char cvsrevision[] = "$Id: misc.c 511 2014-10-21 12:21:24Z keaston $";
6 CVS_REVISION(misc_c)
7 
8 #ifdef HAVE_LIBIPHLPAPI
9 #define WIN32_LEAN_AND_MEAN
10 #include <windows.h>
11 #include <iphlpapi.h>
12 #endif
13 
14 #include <stdio.h>
15 #include <ctype.h>
16 
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <signal.h>
20 
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #ifndef __OPENNT
24 #include <sys/resource.h>
25 #endif
26 #include <unistd.h>
27 
28 #if defined(sparc) && defined(sun4c)
29 #include <sys/rusage.h>
30 #endif
31 
32 #include "struct.h"
33 
34 #include "server.h"
35 #include "dcc.h"
36 #include "commands.h"
37 #include "encrypt.h"
38 #include "vars.h"
39 #include "ircaux.h"
40 #include "lastlog.h"
41 #include "window.h"
42 #include "screen.h"
43 #include "who.h"
44 #include "hook.h"
45 #include "input.h"
46 #include "ignore.h"
47 #include "keys.h"
48 #include "names.h"
49 #include "alias.h"
50 #include "history.h"
51 #include "funny.h"
52 #include "ctcp.h"
53 #include "output.h"
54 #include "exec.h"
55 #include "notify.h"
56 #include "numbers.h"
57 #include "status.h"
58 #include "list.h"
59 #include "timer.h"
60 #include "userlist.h"
61 #include "misc.h"
62 #include "gui.h"
63 #include "cdns.h"
64 #include "flood.h"
65 #include "parse.h"
66 #include "whowas.h"
67 #include "hash2.h"
68 #include "cset.h"
69 #include "if.h"
70 #define MAIN_SOURCE
71 #include "modval.h"
72 
73 #ifdef GUI
74 extern int guiipc[2];
75 extern int newscrollerpos, lastscrollerpos, lastscrollerwindow;
76 #endif
77 
78 
79 extern int user_count;
80 extern int shit_count;
81 extern int bot_count;
82 extern int in_server_ping;
83 
84 int serv_action = 0;
85 
86 #ifndef WANT_CHELP
87 int in_chelp = 0;
88 #endif
89 
90 LastMsg last_msg[MAX_LAST_MSG+1] = { { NULL } };
91 LastMsg last_dcc[MAX_LAST_MSG+1] = { { NULL } };
92 LastMsg last_notice[MAX_LAST_MSG+1] = { { NULL } };
93 LastMsg last_servermsg[MAX_LAST_MSG+1] = { { NULL } };
94 LastMsg last_sent_msg[MAX_LAST_MSG+1] = {{ NULL }};
95 LastMsg last_sent_notice[MAX_LAST_MSG+1] = {{ NULL }};
96 LastMsg last_sent_topic[2] = {{ NULL }};
97 LastMsg last_sent_wall[2] = {{ NULL }};
98 LastMsg last_topic[2] =  {{ NULL }};
99 LastMsg last_wall[MAX_LAST_MSG+1] =  {{ NULL }};
100 LastMsg last_invite_channel[2] = {{ NULL }};
101 LastMsg last_ctcp[2] = {{ NULL }};
102 LastMsg last_ctcp_reply[2] = {{ NULL }};
103 LastMsg last_sent_ctcp[2] = {{ NULL }};
104 LastMsg last_sent_dcc[MAX_LAST_MSG+1] = {{ NULL }};
105 
106 extern int in_cparse;
107 
108 
109 ChannelList *idlechan_list = NULL;
110 
111 extern NickTab *tabkey_array, *autoreply_array;
112 
113 
114 extern Ignore *ignored_nicks;
115 
116 #ifdef REVERSE_WHITE_BLACK
117 char *color_str[] = {
118 "","","","","","","","",
119 "","","","","","","","", "",
120 "", "", "","", "","","", "",
121 "", "", "","", "","","", "",
122 "", "", "", ""};
123 
124 #else
125 
126 char *color_str[] = {
127 "","","","","","","","",
128 "","","","","","","","", "",
129 "", "", "","", "","","", "",
130 "", "", "","", "","","", "",
131 "", "", "", ""};
132 #endif
133 
134 
135 va_list VA_NULL = {0,};
136 
137 char *awaymsg = NULL;
138 
convert_time(time_t ltime)139 char *convert_time (time_t ltime)
140 {
141 	unsigned long days = 0,hours = 0,minutes = 0,seconds = 0;
142 	static char buffer[40];
143 
144 
145 	*buffer = '\0';
146 	seconds = ltime % 60;
147 	ltime = (ltime - seconds) / 60;
148 	minutes = ltime%60;
149 	ltime = (ltime - minutes) / 60;
150 	hours = ltime % 24;
151 	days = (ltime - hours) / 24;
152 	sprintf(buffer, "%2lud %2luh %2lum %2lus", days, hours, minutes, seconds);
153 	return(*buffer ? buffer : empty_string);
154 }
155 
BUILT_IN_COMMAND(do_uptime)156 BUILT_IN_COMMAND(do_uptime)
157 {
158 
159 #ifdef ONLY_STD_CHARS
160 	put_it("%s",convert_output_format("%G--[ %WBitchX%g-%wClient%g-%RStatistics %G]------------------------------------------",NULL));
161 	put_it("%s",convert_output_format("%G| %CClient Version: %W$0 $1","%s %s", irc_version, internal_version));
162 	put_it("%s",convert_output_format("%G| %CClient Running Since %W$0-","%s",my_ctime(start_time)));
163 	put_it("%s",convert_output_format("%G| %CClient Uptime: %W$0-","%s",convert_time(now-start_time)));
164 	put_it("%s",convert_output_format("%G| %CCurrent UserName: %W$0-","%s", username));
165 	put_it("%s",convert_output_format("%G| %CCurrent RealName: %W$0-","%s", realname));
166 	put_it("%s",convert_output_format("%G| %CLast Recv Message: %W$0-","%s",last_msg[0].last_msg?last_msg[0].last_msg:"None"));
167 	put_it("%s",convert_output_format("%G| %CLast Recv Notice: %W$0-","%s",last_notice[0].last_msg?last_notice[0].last_msg:"None"));
168 	put_it("%s",convert_output_format("%G| %CLast Sent Msg: %W$0-","%s",last_sent_msg[0].last_msg?last_sent_msg[0].last_msg:"None"));
169 	put_it("%s",convert_output_format("%G| %CLast Sent Notice: %W$0-","%s",last_sent_notice[0].last_msg?last_sent_notice[0].last_msg:"None"));
170 	put_it("%s",convert_output_format("%G| %CLast Channel invited to: %R$0-","%s",invite_channel?invite_channel:"None"));
171 	put_it("%s",convert_output_format("%G| %cTotal Users on Userlist: %K[%R$0%K]","%d",user_count));
172 	put_it("%s",convert_output_format("%G| %cTotal Users on Shitlist: %K[%R$0%K]","%d",shit_count));
173 
174 #else
175 	put_it("%s",convert_output_format("%G��[ %WBitchX%g�%wClient%g�%RStatistics %G]����---%g�--��%K-%g�����--%G�--��%K-%g�������--- %K--%g  -",NULL));
176 	put_it("%s",convert_output_format("%G| %CClient Version: %W$0 $1","%s %s", irc_version, internal_version));
177 	put_it("%s",convert_output_format("%G� %CClient Running Since %W$0-","%s",my_ctime(start_time)));
178 	put_it("%s",convert_output_format("%G| %CClient Uptime: %W$0-","%s",convert_time(now-start_time)));
179 	put_it("%s",convert_output_format("%G� %CCurrent UserName: %W$0-","%s", username));
180 	put_it("%s",convert_output_format("%G: %CCurrent RealName: %W$0-","%s", realname));
181 	put_it("%s",convert_output_format("%G. %CLast Recv Message: %W$0-","%s",last_msg[0].last_msg?last_msg[0].last_msg:"None"));
182 	put_it("%s",convert_output_format("%G: %CLast Recv Notice: %W$0-","%s",last_notice[0].last_msg?last_notice[0].last_msg:"None"));
183 	put_it("%s",convert_output_format("%G. %CLast Sent Msg: %W$0-","%s",last_sent_msg[0].last_msg?last_sent_msg[0].last_msg:"None"));
184 	put_it("%s",convert_output_format("%G: %CLast Sent Notice: %W$0-","%s",last_sent_notice[0].last_msg?last_sent_notice[0].last_msg:"None"));
185 	put_it("%s",convert_output_format("%G� %CLast Channel invited to: %R$0-","%s",invite_channel?invite_channel:"None"));
186 	put_it("%s",convert_output_format("%G| %cTotal Users on Userlist: %K[%R$0%K]","%d",user_count));
187 	put_it("%s",convert_output_format("%G� %cTotal Users on Shitlist: %K[%R$0%K]","%d",shit_count));
188 
189 #endif
190 }
191 
192 /* extern_write -- controls whether others may write to our terminal or not. */
193 /* This is basically stolen from bsd -- so its under the bsd copyright */
BUILT_IN_COMMAND(extern_write)194 BUILT_IN_COMMAND(extern_write)
195 {
196 	char *tty;
197 	struct stat sbuf;
198 	const int OTHER_WRITE = 020;
199 	int on = 0;
200 
201 	if (!(tty = ttyname(2)))
202 	{
203 		yell("Error in ttyname()");
204 		return;
205 	}
206 	if (stat(tty, &sbuf) < 0)
207 	{
208 		yell("Error in stat()");
209 		return;
210 	}
211 	if (!args || !*args)
212 	{
213 		if (sbuf.st_mode & 020)
214 			bitchsay("Mesg is \002On\002");
215 		else
216 			bitchsay("Mesg is \002Off\002");
217 		return;
218 	}
219 	if (!my_stricmp(args, "ON") || !my_stricmp(args, "YES"))
220 		on = 1;
221 	else if (!my_stricmp(args, "OFF") || !my_stricmp(args, "NO"))
222 		on = 0;
223 	else
224 		return;
225 
226 	switch (on)
227 	{
228 		case 1 :
229 			if (chmod(tty, sbuf.st_mode | OTHER_WRITE) < 0)
230 			{
231 				yell("Sorry, couldnt set your tty's mode");
232 				return;
233 			}
234 			bitchsay("Mesg is \002On\002");
235 			break;
236 		case 0 :
237 			if (chmod(tty, sbuf.st_mode &~ OTHER_WRITE) < 0)
238 			{
239 				yell("Sorry, couldnt set your tty's mode");
240 				return;
241 			}
242 			bitchsay("Mesg is \002Off\002");
243 			break;
244 	}
245 
246 }
247 
248 
check_serverlag(void)249 int check_serverlag(void)
250 {
251 	int i;
252 
253 	for (i = 0; i < server_list_size(); i++)
254 	{
255 		if (is_server_connected(i) && now != get_server_lagtime(i))
256 		{
257 			set_server_lagtime(i, now);
258 			my_send_to_server(i, "PING %s %s", get_server_nickname(i), get_server_itsname(i));
259 			in_server_ping++;
260 			set_server_lag(i, -1);
261 		}
262 	}
263 
264 	return 0;
265 }
266 
timer_unban(void * args,char * sub)267 int timer_unban (void *args, char *sub)
268 {
269 	char *p = (char *)args;
270 	char *channel;
271 	ChannelList *chan, *chan2;
272 	char *ban;
273 	char *serv;
274 	int server = from_server;
275 
276 	serv = next_arg(p, &p);
277 	if (my_atol(serv) != server)
278 		server = my_atol(serv);
279 	if (server < 0 || server > server_list_size() || !is_server_connected(server))
280 		server = from_server;
281 	channel = next_arg(p, &p);
282 	ban = next_arg(p, &p);
283 
284 	chan2 = get_server_channels(server);
285 	if ((chan = (ChannelList *)find_in_list((List **)&chan2, channel, 0)) && ban_is_on_channel(ban, chan))
286 		my_send_to_server(server, "MODE %s -b %s", channel, ban);
287 	new_free(&serv); new_free(&sub);
288 	return 0;
289 }
290 
timer_idlekick(void * args,char * sub)291 int timer_idlekick (void *args, char *sub)
292 {
293 char *channel = (char *)args;
294 ChannelList *tmp = NULL;
295 int kick_count = 0;
296 UserList *user = NULL;
297 
298 
299 	if (channel && (tmp = lookup_channel(channel, from_server, CHAN_NOUNLINK)) && tmp->have_op && tmp->max_idle && tmp->check_idle)
300 	{
301 		NickList *nick;
302 		for (nick = next_nicklist(tmp, NULL); nick; nick = next_nicklist(tmp, nick))
303 		{
304 			if (!my_stricmp(nick->nick, get_server_nickname(from_server)))
305 				continue;
306 			if ((nick_isop(nick) || nick_isvoice(nick)) && !get_cset_int_var(tmp->csets, KICK_OPS_CSET))
307 				continue;
308 			if ((user=nick->userlist) && check_channel_match(user->channels, channel))
309 				continue;
310 			if (now - nick->idle_time >= tmp->max_idle)
311 			{
312 				if (kick_count <= get_int_var(MAX_IDLEKICKS_VAR))
313 				{
314 					char *p = NULL;
315 					malloc_sprintf(&p, "%s %s*!*%s", channel, nick->nick, nick->host);
316 					send_to_server("MODE %s +b %s*!*%s", channel, nick->nick, nick->host);
317 					send_to_server("KICK %s %s :\002%s\002: (Idle Channel User)", channel, nick->nick, version);
318 					add_timer(0, empty_string, 60 * 1000, 1, timer_unban, m_sprintf("%d %s", from_server, p), NULL, current_window->refnum, "idle-kick");
319 					new_free(&p);
320 				}
321 				else
322 					break;
323 				kick_count++;
324 			}
325 		}
326 	}
327 	if (tmp && tmp->max_idle && tmp->check_idle)
328 		add_timer(0, empty_string, get_int_var(IDLE_CHECK_VAR) * 1000, 1, timer_idlekick, channel, NULL, current_window->refnum, "idle-kick");
329 	else
330 		new_free(&channel);
331 	new_free(&sub);
332 	return 0;
333 }
334 
BUILT_IN_COMMAND(addidle)335 BUILT_IN_COMMAND(addidle)
336 {
337 time_t default_idle = 10 * 60;
338 char *channel = NULL, *p;
339 time_t seconds = 0;
340 ChannelList *tmp, *new = NULL;
341 
342 
343 	if ((p = next_arg(args, &args)))
344 	{
345 		malloc_strcpy(&channel, make_channel(p));
346 		if (!channel)
347 			return;
348 		if (args && *args)
349 			seconds = atol(args);
350 
351 		if (seconds < default_idle)
352 			seconds = default_idle;
353 
354 		if (!(new = (ChannelList *)find_in_list((List **)&idlechan_list, channel, 0)))
355 		{
356 			new = (ChannelList *)new_malloc(sizeof(ChannelList));
357 			malloc_strcpy(&new->channel, channel);
358 			add_to_list((List **)&idlechan_list, (List *)new);
359 		}
360 		new->max_idle = seconds;
361 		new->check_idle = (my_strnicmp(command, "UN", 2) == 0) ? 0: 1;
362 
363 		if (!new->check_idle)
364 		{
365 			bitchsay("Idle checking turned %s for %s",on_off(new->check_idle), channel);
366 			if ((tmp = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
367 				tmp->check_idle = tmp->max_idle = 0;
368 			new->max_idle = 0;
369 		}
370 		else
371 		{
372 			if ((tmp = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
373 			{
374 				if (new && new->check_idle)
375 				{
376 					tmp->max_idle = new->max_idle;
377 					tmp->check_idle = new->check_idle;
378 					add_timer(0, empty_string, get_int_var(IDLE_CHECK_VAR) * 1000, 1, timer_idlekick, channel, NULL, current_window->refnum, "idle-check");
379 					bitchsay("Idle checking turned %s for %s %d mins",on_off(tmp->check_idle), channel, (int)(tmp->max_idle/60));
380 				}
381 			}
382 		}
383 		new_free(&channel);
384 	}
385 }
386 
BUILT_IN_COMMAND(showidle)387 BUILT_IN_COMMAND(showidle)
388 {
389 ChannelList *tmp;
390 char *channel = NULL;
391 int count = 0;
392 NickList *nick, *ntmp;
393 time_t ltime;
394 int server;
395 int sorted = 0;
396 	while (args && *args)
397 	{
398 		if (!args || !*args)
399 			break;
400 		if ((*args == '-') && !my_strnicmp(args, "-sort", 3))
401 		{
402 			next_arg(args, &args);
403 			sorted = NICKSORT_NONE;
404 		}
405 		else if (!my_strnicmp(args, "nick", 3) && sorted)
406 		{
407 			next_arg(args, &args);
408 			sorted = NICKSORT_NICK;
409 		}
410 		else if (!my_strnicmp(args, "host", 3) && sorted)
411 		{
412 			next_arg(args, &args);
413 			sorted = NICKSORT_HOST;
414 		}
415 		else if (!my_strnicmp(args, "time", 3) && sorted)
416 		{
417 			next_arg(args, &args);
418 			sorted = NICKSORT_TIME;
419 		}
420 		else if (!my_strnicmp(args, "ip", 2) && sorted)
421 		{
422 			next_arg(args, &args);
423 			sorted = NICKSORT_IP;
424 		}
425 		else
426 			channel = next_arg(args, &args);
427 	}
428 	if (!(tmp = prepare_command(&server, channel, NO_OP)))
429 		return;
430 
431 	ntmp = sorted_nicklist(tmp, sorted);
432 	for (nick = ntmp; nick; nick = nick->next)
433 	{
434 		if (!count && do_hook(SHOWIDLE_HEADER_LIST, "%s %lu", tmp->channel, (unsigned long)tmp->max_idle))
435 			put_it("%s", convert_output_format("$G %W$a%n: Idle check for %W$0%n Max Idle Time %K[%W$1- %K]", "%s %s", tmp->channel, convert_time(tmp->max_idle)));
436 		ltime = now - nick->idle_time;
437 #ifdef WANT_USERLIST
438 		if (do_hook(SHOWIDLE_LIST, "%s %s %d %lu", nick->nick, nick->host, find_user_level(nick->nick, nick->host, tmp->channel), (unsigned long)ltime))
439 #else
440 		if (do_hook(SHOWIDLE_LIST, "%s %s %d %lu", nick->nick, nick->host, 0, (unsigned long)ltime))
441 #endif
442 			put_it("%s", convert_output_format("$[20]0 Idle%W: %K[%n$1- %K]", "%s %s", nick->nick, convert_time(ltime)));
443 		count++;
444 	}
445 	if (count)
446 		do_hook(SHOWIDLE_FOOTER_LIST, "%s", "End of idlelist");
447 	clear_sorted_nicklist(&ntmp);
448 }
449 
BUILT_IN_COMMAND(kickidle)450 BUILT_IN_COMMAND(kickidle)
451 {
452 char *channel = NULL;
453 ChannelList *tmp;
454 int kick_count = 0;
455 int server = from_server;
456 
457 
458 	if (args && *args)
459 		channel = next_arg(args, &args);
460 
461 	if ((tmp = prepare_command(&server, channel, NEED_OP)) && tmp->max_idle)
462 	{
463 		NickList *nick;
464 		for (nick = next_nicklist(tmp, NULL); nick; nick = next_nicklist(tmp, nick))
465 		{
466 			if (!my_stricmp(nick->nick, get_server_nickname(from_server)))
467 				continue;
468 			if (nick->userlist && check_channel_match(nick->userlist->channels, tmp->channel))
469 				continue;
470 			if (nick_isop(nick))
471 				continue;
472 			if (now - nick->idle_time >= tmp->max_idle)
473 			{
474 				if (kick_count <= get_int_var(MAX_IDLEKICKS_VAR))
475 					my_send_to_server(server, "KICK %s %s :\002%s\002: (Idle Channel User)", tmp->channel, nick->nick, version);
476 				else
477 					bitchsay(" found idle user %-12s channel %s", nick->nick, tmp->channel);
478 				kick_count++;
479 			}
480 		}
481 	}
482 }
483 
save_idle(FILE * output)484 void save_idle(FILE *output)
485 {
486 ChannelList *chan;
487 int count = 0;
488 
489 
490 	if (!output)
491 		return;
492 	if (idlechan_list)
493 	{
494 		fprintf(output, "# %s Idle Channel list\n", version);
495 		for (chan = idlechan_list; chan; chan = chan->next)
496 		{
497 			if (chan->max_idle)
498 			{
499 				fprintf(output, "ADDIDLE %s %d\n", chan->channel, (int)chan->max_idle);
500 				count++;
501 			}
502 		}
503 	}
504 	if (count && do_hook(SAVEFILE_LIST, "Idle %d", count))
505 		bitchsay("Saved %d Idle channels", count);
506 }
507 
BUILT_IN_COMMAND(channel_stats)508 BUILT_IN_COMMAND(channel_stats)
509 {
510 ChannelList *new = NULL;
511 char *channel = NULL;
512 WhowasChanList *new1 = NULL;
513 int numircops = 0;
514 int usershere = 0;
515 int usersaway = 0;
516 int chanops = 0;
517 int chanunop = 0;
518 char *ircops = NULL;
519 int server = -1;
520 int max_hops = 0;
521 
522 NickList *l;
523 unsigned long	nick_mem = 0,
524 		ban_mem = 0;
525 BanList *b;
526 
527 
528 
529 
530 	if (args && *args)
531 	{
532 		channel = next_arg(args, &args);
533 		if (my_strnicmp(channel, "-ALL", strlen(channel)))
534 		{
535 			if (!(channel = make_channel(channel)))
536 				return;
537 			if (!(new = prepare_command(&server, channel, PC_SILENT)))
538 				if ((channel && !(new1 = check_whowas_chan_buffer(channel, -1, 0))))
539 					return;
540 		}
541 		else
542 		{
543 
544 			int stats_ops= 0, stats_dops = 0, stats_bans = 0, stats_unbans = 0;
545 			int stats_topics = 0, stats_kicks = 0, stats_pubs = 0, stats_parts = 0;
546 			int stats_signoffs = 0, stats_joins = 0;
547 			int total_nicks = 0, max_nicks = 0, total_bans = 0, max_bans = 0;
548 			int stats_sops = 0, stats_sdops = 0, stats_sbans = 0, stats_sunbans = 0;
549 
550 			NickList *l;
551 			BanList *b;
552 			unsigned long chan_mem = 0;
553 			channel =  NULL;
554 
555 			if (from_server != -1)
556 			{
557 				for (new = get_server_channels(from_server); new; new = new->next)
558 				{
559 					if (!channel)
560 						malloc_strcpy(&channel, new->channel);
561 					else
562 					{
563 						malloc_strcat(&channel, ",");
564 						malloc_strcat(&channel, new->channel);
565 					}
566 					for (l = next_nicklist(new, NULL); l; l = next_nicklist(new, l))
567 					{
568 						if (nick_isaway(l))
569 							usersaway++;
570 						else
571 							usershere++;
572 						if (nick_isircop(l))
573 						{
574 							numircops++;
575 							malloc_strcat(&ircops, " (");
576 							malloc_strcat(&ircops, l->nick);
577 							malloc_strcat(&ircops, ")");
578 						}
579 						if (nick_isop(l))
580 							chanops++;
581 						else
582 							chanunop++;
583 						nick_mem += sizeof(NickList);
584 						if (l->serverhops > max_hops)
585 							max_hops = l->serverhops;
586 					}
587 					for (b = new->bans; b; b = b->next)
588 						ban_mem += sizeof(BanList);
589 					chan_mem += sizeof(ChannelList);
590 					stats_ops += new->stats_ops;
591 					stats_dops += new->stats_dops;
592 					stats_bans += new->stats_bans;
593 					stats_unbans += new->stats_unbans;
594 					stats_topics += new->stats_topics;
595 					stats_kicks += new->stats_kicks;
596 					stats_pubs += new->stats_pubs;
597 					stats_parts += new->stats_parts;
598 					stats_signoffs += new->stats_signoffs;
599 					stats_joins += new->stats_joins;
600 
601 					total_nicks += new->totalnicks;
602 					max_nicks += new->maxnicks;
603 					total_bans += new->totalbans;
604 					max_bans += new->maxbans;
605 					stats_sops += new->stats_sops;
606 					stats_sdops += new->stats_sdops;
607 					stats_sbans += new->stats_sbans;
608 					stats_sunbans += new->stats_sunbans;
609 				}
610 			}
611 			if (!ircops)
612 				malloc_strcat(&ircops, empty_string);
613 if (do_hook(CHANNEL_STATS_LIST, "%s %s %s %lu %lu %lu %lu %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %d %s",
614 	channel, empty_string, empty_string,
615 	nick_mem+chan_mem+ban_mem, nick_mem,
616 	(unsigned long)sizeof(ChannelList),ban_mem,
617 	stats_ops, stats_dops, stats_bans, stats_unbans,
618 	stats_topics, stats_kicks, stats_pubs, stats_parts,
619 	stats_signoffs, stats_joins, total_bans, max_bans,
620 	stats_sops, stats_sdops,stats_sbans, stats_sunbans,
621 	usershere, usersaway, chanops, chanunop,total_nicks,max_nicks,
622 	numircops, max_hops, ircops))
623 {
624 put_it("%s", convert_output_format("$G %CInformation for channels %K: %W$0", "%s", channel));
625 put_it("%s", convert_output_format("     MEM usage%K:%w Total%K:%w %c$0 bytes   %K[%cNicks $1 b Chan $2 b Bans $3 b%K]", "%d %d %d %d", (int)(nick_mem+chan_mem+ban_mem), (int)nick_mem, (int)sizeof(ChannelList), (int)ban_mem));
626 put_it("%s", convert_output_format("Ops        %K[%W$[-5]0%K]%w  De-Ops     %K[%W$[-5]1%K]%w  Bans       %K[%W$[-5]2%K]%w  Unbans     %K[%W$[-5]3%K]%w", "%u %u %u %u", stats_ops, stats_dops, stats_bans, stats_unbans));
627 put_it("%s", convert_output_format("Topics     %K[%W$[-5]0%K]%w  Kicks      %K[%W$[-5]1%K]%w  Publics    %K[%W$[-5]2%K]%w  Parts      %K[%W$[-5]3%K]%w", "%u %u %u %u", stats_topics, stats_kicks, stats_pubs, stats_parts));
628 put_it("%s", convert_output_format("Signoffs   %C[%W$[-5]0%K]%w  Joins      %K[%W$[-5]1%K]%w  TotalBans  %K[%W$[-5]2%K]%w  MaxBans    %K[%W$[-5]3%K]%w", "%u %u %u %u", stats_signoffs, stats_joins, total_bans, max_bans));
629 put_it("%s", convert_output_format("ServOps    %K[%W$[-5]0%K]%w  ServDeop   %K[%W$[-5]1%K]%w  ServBans   %K[%W$[-5]2%K]%w  ServUB     %K[%W$[-5]3%K]%w", "%u %u %u %u", stats_sops, stats_sdops,stats_sbans, stats_sunbans));
630 put_it("%s", convert_output_format("Users Here %K[%W$[-5]0%K]%w  Users Away %K[%W$[-5]1%K]%w  Opped      %K[%W$[-5]2%K]%w  Unopped    %K[%W$[-5]3%K]%w", "%u %u %u %u", usershere, usersaway, chanops, chanunop));
631 put_it("%s", convert_output_format("TotalNicks %K[%W$[-5]0%K]%w  MaxNicks   %K[%W$[-5]1%K]%w  ServerHops %K[%W$[-5]2%K]%w", "%d %d %d", total_nicks,max_nicks, max_hops));
632 put_it("%s", convert_output_format("IRCops     %K[%W$[3]0%K]%w$1-", "%d %s", numircops, ircops));
633 }
634 			new_free(&ircops);
635 			new_free(&channel);
636 			return;
637 		}
638 	}
639 	else
640 	{
641 		if (!(new = prepare_command(&server, channel, PC_SILENT)))
642 			if ((channel && !(new1 = check_whowas_chan_buffer(channel, -1, 0))))
643 				return;
644 	}
645 
646 	if (!new && new1)
647 		new = new1->channellist;
648 	if (!new)
649 	{
650 		bitchsay("Try joining a channel first");
651 		return;
652 	}
653 	if (new)
654 	{
655 		for (l = next_nicklist(new, NULL); l; l = next_nicklist(new, l))
656 		{
657 			nick_mem += sizeof(NickList);
658 			if (nick_isaway(l))
659 				usersaway++;
660 			else
661 				usershere++;
662 			if (nick_isircop(l))
663 			{
664 				numircops++;
665 				malloc_strcat(&ircops, " (");
666 				malloc_strcat(&ircops, l->nick);
667 				malloc_strcat(&ircops, ")");
668 			}
669 			if (nick_isop(l))
670 				chanops++;
671 			else
672 				chanunop++;
673 			if (l->serverhops > max_hops)
674 				max_hops = l->serverhops;
675 		}
676 		for (b = new->bans; b; b = b->next)
677 			ban_mem += sizeof(BanList);
678 	}
679 	if (!ircops)
680 		malloc_strcat(&ircops, empty_string);
681 	if (do_hook(CHANNEL_STATS_LIST, "%s %s %s %ld %ld %ld %ld %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %d %s",
682 		new->channel, my_ctime(new->channel_create.tv_sec), convert_time(now-new->join_time.tv_sec),
683 		nick_mem+sizeof(ChannelList)+ban_mem, nick_mem,
684 		(unsigned long)sizeof(ChannelList),ban_mem,
685 		new->stats_ops, new->stats_dops, new->stats_bans, new->stats_unbans,
686 		new->stats_topics, new->stats_kicks, new->stats_pubs, new->stats_parts,
687 		new->stats_signoffs, new->stats_joins, new->totalbans, new->maxbans,
688 		new->stats_sops, new->stats_sdops,new->stats_sbans, new->stats_sunbans,
689 		usershere, usersaway, chanops, chanunop,new->totalnicks,new->maxnicks,
690 		numircops, max_hops, ircops))
691 	{
692 put_it("%s", convert_output_format("$G %CInformation for channel %K: %W$0", "%s", new->channel));
693 put_it("%s", convert_output_format("$G %CChannel created %K: %W$0 $1 $2 $3%n in memory %W$4-", "%s %s", convert_time(now-new->channel_create.tv_sec), my_ctime(new->join_time.tv_sec)));
694 
695 put_it("%s", convert_output_format("     MEM usage%K:%w Total%K:%w %c$0 bytes   %K[%cNicks $1 b Chan $2 b Bans $3 b%K]", "%d %d %d %d", (int)(nick_mem+sizeof(ChannelList)+ban_mem), (int)nick_mem, (int)sizeof(ChannelList), (int)ban_mem));
696 put_it("%s", convert_output_format("Ops        %K[%W$[-5]0%K]%w  De-Ops     %K[%W$[-5]1%K]%w  Bans       %K[%W$[-5]2%K]%w  Unbans     %K[%W$[-5]3%K]%w", "%u %u %u %u", new->stats_ops, new->stats_dops, new->stats_bans, new->stats_unbans));
697 put_it("%s", convert_output_format("Topics     %K[%W$[-5]0%K]%w  Kicks      %K[%W$[-5]1%K]%w  Publics    %K[%W$[-5]2%K]%w  Parts      %K[%W$[-5]3%K]%w", "%u %u %u %u", new->stats_topics, new->stats_kicks, new->stats_pubs, new->stats_parts));
698 put_it("%s", convert_output_format("Signoffs   %K[%W$[-5]0%K]%w  Joins      %K[%W$[-5]1%K]%w  TotalBans  %K[%W$[-5]2%K]%w  MaxBans    %K[%W$[-5]3%K]%w", "%u %u %u %u", new->stats_signoffs, new->stats_joins, new->totalbans, new->maxbans));
699 put_it("%s", convert_output_format("ServOps    %K[%W$[-5]0%K]%w  ServDeop   %K[%W$[-5]1%K]%w  ServBans   %K[%W$[-5]2%K]%w  ServUB     %K[%W$[-5]3%K]%w", "%u %u %u %u", new->stats_sops, new->stats_sdops,new->stats_sbans, new->stats_sunbans));
700 put_it("%s", convert_output_format("Users Here %K[%W$[-5]0%K]%w  Users Away %K[%W$[-5]1%K]%w  Opped      %K[%W$[-5]2%K]%w  Unopped    %K[%W$[-5]3%K]%w", "%u %u %u %u", usershere, usersaway, chanops, chanunop));
701 put_it("%s", convert_output_format("TotalNicks %K[%W$[-5]0%K]%w  MaxNicks   %K[%W$[-5]1%K]%w  ServerHops %K[%W$[-5]2%K]%w", "%d %d %d", new->totalnicks,new->maxnicks, max_hops));
702 put_it("%s", convert_output_format("IRCops     %K[%W$[3]0%K]%w$1-", "%d %s", numircops, ircops));
703 
704 put_it("%s", convert_output_format("  %CThere is %R$0%C limit and limit checking is %R$1-", "%s %s", new->limit ? ltoa(new->limit): "no", new->tog_limit?"Enabled":"Disabled"));
705 put_it("%s", convert_output_format("  %CIdle user check is %K[%R$0-%K]", "%s", new->check_idle?"Enabled":"Disabled"));
706 /*put_it("%s", convert_output_format("$G End of channel stats for $0", "%s", new->channel));*/
707 			/* wtf is do_scan in the channel struct */
708 	}
709 	new_free(&ircops);
710 
711 }
712 
update_stats(int what,NickList * nick,ChannelList * chan,int splitter)713 void update_stats(int what, NickList *nick, ChannelList *chan, int splitter)
714 {
715 time_t this_time = now;
716 int t = 0;
717 
718 
719 	if (!chan || !chan->channel)
720 		return;
721 
722 	switch (what)
723 	{
724 		case KICKLIST:
725 		{
726 			chan->stats_kicks++;
727 			chan->totalnicks--;
728 			if (nick) nick->stat_kicks++;
729 			break;
730 		}
731 
732 		case LEAVELIST:
733 		{
734 			chan->stats_parts++;
735 			chan->totalnicks--;
736 			break;
737 		}
738 		case JOINLIST:
739 		{
740 			chan->stats_joins++;
741 			chan->totalnicks++;
742 			if (chan->totalnicks > chan->maxnicks)
743 			{
744 				chan->maxnicks = chan->totalnicks;
745 				chan->maxnickstime = this_time;
746 			}
747 			if (!splitter)
748 			{
749 				if (chan->have_op && is_other_flood(chan, nick, JOIN_FLOOD, &t))
750 				{
751 					if (get_cset_int_var(chan->csets, JOINFLOOD_CSET) && get_cset_int_var(chan->csets, KICK_ON_JOINFLOOD_CSET) && !nick->kickcount++)
752 					{
753 						char *t1, *host, *banstr;
754 						t1 = LOCAL_COPY(nick->host);
755 						host = strchr(t1, '@');
756 						*host++ = 0;
757 						banstr = ban_it(nick->nick, t1, host, nick->ip);
758 						send_to_server("MODE %s -o+b %s %s", chan->channel, nick->nick, banstr);
759 						send_to_server("KICK %s %s :\002Join flood\002 (%d joins in %dsecs of %dsecs)", chan->channel, nick->nick, get_cset_int_var(chan->csets, KICK_ON_JOINFLOOD_CSET)/*chan->set_kick_on_joinflood*/, t, get_cset_int_var(chan->csets, JOINFLOOD_TIME_CSET));
760 						if (get_int_var(AUTO_UNBAN_VAR))
761 							add_timer(0, empty_string, get_int_var(AUTO_UNBAN_VAR) * 1000, 1, timer_unban, m_sprintf("%d %s %s", from_server, chan->channel, banstr), NULL, current_window->refnum, "join-flood");
762 					}
763 				}
764 			}
765 			break;
766 		}
767 		case CHANNELSIGNOFFLIST:
768 		{
769 			chan->stats_signoffs++;
770 			chan->totalnicks--;
771 			break;
772 		}
773 		case PUBLICLIST:
774 		case PUBLICOTHERLIST:
775 		case PUBLICNOTICELIST:
776 		case NOTICELIST:
777 		{
778 			chan->stats_pubs++;
779 			if (nick)
780 			{
781 				nick->stat_pub++;
782 				nick->idle_time = this_time;
783 			}
784 			break;
785 		}
786 		case TOPICLIST:
787 		{
788 			chan->stats_topics++;
789 			break;
790 		}
791 		case MODEOPLIST:
792 			if (splitter)
793 				chan->stats_sops++;
794 			else
795 			{
796 				if (nick) nick->stat_ops++;
797 				chan->stats_ops++;
798 			}
799 			break;
800 		case MODEHOPLIST:
801 			if (splitter)
802 				chan->stats_shops++;
803 			else
804 			{
805 				if (nick) nick->stat_hops++;
806 				chan->stats_hops++;
807 			}
808 			break;
809 		case MODEDEHOPLIST:
810 			if (splitter)
811 				chan->stats_sdehops++;
812 			else
813 			{
814 				if (nick) nick->stat_dhops++;
815 				chan->stats_dhops++;
816 			}
817 			break;
818 		case MODEDEOPLIST:
819 			if (splitter)
820 				chan->stats_sdops++;
821 			else
822 			{
823 				chan->stats_dops++;
824 				if (nick) nick->stat_dops++;
825 			}
826 
827 			if (chan->have_op && is_other_flood(chan, nick, DEOP_FLOOD, &t))
828 			{
829 				if (get_cset_int_var(chan->csets, DEOP_ON_DEOPFLOOD_CSET) < get_cset_int_var(chan->csets, KICK_ON_DEOPFLOOD_CSET))
830 					send_to_server("MODE %s -o %s", chan->channel, nick->nick);
831 				else if (!nick->kickcount++)
832 					send_to_server("KICK %s %s :\002De-op flood\002 (%d de-ops in %dsecs of %dsecs)", chan->channel, nick->nick, get_cset_int_var(chan->csets, KICK_ON_DEOPFLOOD_CSET), t, get_cset_int_var(chan->csets, DEOPFLOOD_TIME_CSET));
833 			}
834 			break;
835 		case MODEBANLIST:
836 			if (splitter)
837 				chan->stats_sbans++;
838 			else
839 			{
840 				if (nick) nick->stat_bans++;
841 				chan->stats_bans++;
842 			}
843 			chan->totalbans++;
844 			if (chan->stats_bans > chan->maxbans)
845 			{
846 				chan->maxbans = chan->stats_bans;
847 				chan->maxbanstime = this_time;
848 			}
849 			break;
850 		case MODEUNBANLIST:
851 			if (splitter)
852 				chan->stats_sunbans++;
853 			else
854 			{
855 				if (nick) nick->stat_unbans++;
856 				chan->stats_unbans++;
857 			}
858 			if (chan->totalbans) chan->totalbans--;
859 			break;
860 		default:
861 			break;
862 	}
863 }
864 
clear_server_flags(char * userhost)865 char *clear_server_flags (char *userhost)
866 {
867 register char *uh = userhost;
868 	while(uh && (*uh == '~' || *uh == '#' || *uh == '+' || *uh == '-' || *uh == '=' || *uh == '^'))
869 		uh++;
870 	return uh;
871 }
872 
873 
874 #ifndef BITCHX_LITE
875 
876 static char newline1[BIG_BUFFER_SIZE+1];
877 /*
878  * (max server send) and max mirc color change is 256
879  * so 256 * 8 should give us a safety margin for hackers.
880  * BIG_BUFFER is 1024 * 3 is 3072 whereas 256*8 is 2048
881  */
882 
883 
884 #if 0
885 char *mircansi(unsigned char *line)
886 {
887 /* mconv v1.00 (c) copyright 1996 Ananda, all rights reserved.	*/
888 /* -----------------------------------------------------------	*/
889 /* mIRC->ansi color code convertor:	12.26.96		*/
890 /* map of mIRC color values to ansi color codes			*/
891 /* format: ansi fg color	ansi bg color			*/
892 /* modified Colten Edwards 					*/
893 struct {
894 	char *fg, *bg;
895 } codes[16] = {
896 
897 	{ "",   ""        },      /* white                */
898 	{ "",   ""        },      /* black (grey for us)  */
899 	{ "",   ""        },      /* blue                 */
900 	{ "",   ""        },      /* green                */
901 	{ "",   ""        },      /* red                  */
902 	{ "",   ""        },      /* brown                */
903 
904 	{ "",   ""        },      /* magenta              */
905 	{ "",   ""        },      /* bright red           */
906 	{ "",   ""        },      /* yellow               */
907 
908 	{ "",   ""            },      /* bright green         */
909 	{ "",   ""            },      /* cyan                 */
910 	{ "",   ""            },      /* bright cyan          */
911 	{ "",   ""            },      /* bright blue          */
912 	{ "",   ""            },      /* bright magenta       */
913 	{ "",   ""            },      /* dark grey            */
914 	{ "",   ""            }       /* grey                 */
915 };
916 	register unsigned char *sptr = line, *dptr = newline1;
917 	short code;
918 
919 	if (!*line)
920 		return empty_string;
921 	*newline1 = 0;
922 	while (*sptr) {
923 		if (*sptr == '' && isdigit(sptr[1]))
924 		{
925 			sptr++;
926 			code = atoi(sptr);
927 			if (code > 15 || code <= 0)
928 				continue;
929 			while (isdigit(*sptr))
930 				sptr++;
931 			strcpy(dptr, codes[code].fg);
932 			while (*dptr) dptr++;
933 			if (*sptr == ',')
934 			{
935 				sptr++;
936 				code = atoi(sptr);
937 				if (code >= 0 && code <= 15)
938 				{
939 					strcpy(dptr, codes[code].bg);
940 					while (*dptr) dptr++;
941 				}
942 				while (isdigit(*sptr))
943 					sptr++;
944 			}
945 		}
946 		else if (*sptr == '')
947 		{
948 			strcpy(dptr, "");
949 			while(*dptr) dptr++;
950 			sptr++;
951 		}
952 		else *dptr++ = *sptr++;
953 	}
954 	*dptr = 0;
955 	return (char *)newline1;
956 }
957 #else
mircansi(const char * line)958 char *mircansi(const char *line)
959 {
960 /* mconv v1.00 (c) copyright 1996 Ananda, all rights reserved.	*/
961 /* -----------------------------------------------------------	*/
962 /* mIRC->ansi color code convertor:	12.26.96		*/
963 /* map of mIRC color values to ansi color codes			*/
964 /* format: ansi fg color	ansi bg color			*/
965 /* modified Colten Edwards 					*/
966 	static const struct {
967 		const char *fg, *bg;
968 	} codes[16] = {
969 		{ "\x1b[1;37m", "\x1b[47m" },      /* white                */
970 		{ "\x1b[0;30m", "\x1b[40m" },      /* black (grey for us)  */
971 		{ "\x1b[0;34m", "\x1b[44m" },      /* blue                 */
972 		{ "\x1b[0;32m", "\x1b[42m" },      /* green                */
973 		{ "\x1b[0;31m", "\x1b[41m" },      /* red                  */
974 		{ "\x1b[0;33m", "\x1b[43m" },      /* brown                */
975 		{ "\x1b[0;35m", "\x1b[45m" },      /* magenta              */
976 		{ "\x1b[1;31m", "\x1b[41m" },      /* bright red           */
977 		{ "\x1b[1;33m", "\x1b[43m" },      /* yellow               */
978 		{ "\x1b[1;32m", "\x1b[42m" },      /* bright green         */
979 		{ "\x1b[0;36m", "\x1b[46m" },      /* cyan                 */
980 		{ "\x1b[1;36m", "\x1b[46m" },      /* bright cyan          */
981 		{ "\x1b[1;34m", "\x1b[44m" },      /* bright blue          */
982 		{ "\x1b[1;35m", "\x1b[45m" },      /* bright magenta       */
983 		{ "\x1b[1;30m", "\x1b[40m" },      /* dark grey            */
984 		{ "\x1b[0;37m", "\x1b[47m" }       /* grey                 */
985 	};
986 
987 	const char *sptr = line;
988 	char *dptr = newline1;
989 	unsigned code;
990 
991 	if (!*line)
992 		return empty_string;
993 
994 	while (*sptr)
995 	{
996 		if (*sptr == '\x03')
997 		{
998 			sptr++;
999 
1000 			if (isdigit((unsigned char)*sptr))
1001 			{
1002 				/* ^C followed by digit*/
1003 				code = *sptr - '0';
1004 				sptr++;
1005 
1006 				if (isdigit((unsigned char)*sptr)) {
1007 					code = code * 10 + *sptr - '0';
1008 					sptr++;
1009 				}
1010 
1011 				code = code % 16;
1012 				strcpy(dptr, codes[code].fg);
1013 				while (*dptr)
1014 					dptr++;
1015 
1016 				/* Do not consume , if not followed by digit */
1017 				if (sptr[0] == ',' && isdigit((unsigned char)sptr[1]))
1018 				{
1019 					code = sptr[1] - '0';
1020 					sptr += 2;
1021 
1022 					if (isdigit ((unsigned char)*sptr)) {
1023 						code = code * 10 + *sptr - '0';
1024 						sptr++;
1025 					}
1026 
1027 					code = code % 16;
1028 					strcpy(dptr, codes[code].bg);
1029 					while (*dptr)
1030 						dptr++;
1031 				}
1032 			}
1033 			else
1034 			{
1035 				/* ^C not followed by digit - assume end of color */
1036 				strcpy(dptr, "\x1b[0m");
1037 				while (*dptr)
1038 					dptr++;
1039 			}
1040 		}
1041 		else
1042 			*dptr++ = *sptr++;
1043 	}
1044 	*dptr = 0;
1045 
1046 	return newline1;
1047 }
1048 #endif
1049 
1050 /* Borrowed with permission from FLiER */
stripansicodes(const char * line)1051 char *stripansicodes(const char *line)
1052 {
1053 	const char *tstr = line;
1054 	char *nstr = newline1;
1055 	int gotansi = 0;
1056 
1057 	while (*tstr)
1058 	{
1059 		/* Note that we use '\x9b' here, rather than 0x9b, because the
1060 		 * former will have the correct value whether or not char is
1061 		 * signed.
1062 		 */
1063 		if (*tstr == '\x1b' || *tstr == '\x9b')
1064 			gotansi = 1;
1065 		if (gotansi && isalpha((unsigned char)*tstr))
1066 			gotansi = 0;
1067 		else if (!gotansi)
1068 		{
1069 			*nstr = *tstr;
1070 			nstr++;
1071 		}
1072 		tstr++;
1073 	}
1074 	*nstr = 0;
1075 	return newline1;
1076 }
1077 #else
stripansicodes(const char * line)1078 char *stripansicodes(const char *line)
1079 {
1080 	return line;
1081 }
mircansi(unsigned char * line)1082 char *mircansi(unsigned char *line)
1083 {
1084 	return line;
1085 }
1086 #endif
1087 
stripansi(unsigned char * line)1088 char *stripansi(unsigned char *line)
1089 {
1090 register unsigned char    *cp;
1091 unsigned char *newline;
1092 	newline = m_strdup(line);
1093 	for (cp = newline; *cp; cp++)
1094 		if ((*cp < 31 && *cp > 13))
1095 			if (*cp != 1 && *cp != 15 && *cp !=22 && *cp != 0x9b)
1096 				*cp = (*cp & 127) | 64;
1097 	return (char *)newline;
1098 }
1099 
1100 
check_split(char * nick,char * reason)1101 int check_split(char *nick, char *reason)
1102 {
1103 char *bogus = get_string_var(FAKE_SPLIT_PATS_VAR);
1104 char *Reason;
1105 
1106 	Reason = LOCAL_COPY(reason);
1107 	if (word_count(Reason) > 3)
1108 		goto fail_split;
1109 	if (wild_match("%.% %.%", Reason) && !strstr(Reason, "))") )
1110 	{
1111 		char *host1 = next_arg(Reason, &Reason);
1112 		char *host2 = next_arg(Reason, &Reason);
1113 		char *x = NULL;
1114 
1115 		if (!my_stricmp(host1, host2))
1116 			goto fail_split;
1117 		if (wild_match(host1, "*..*") || wild_match(host2, "*..*"))
1118 			goto fail_split;
1119 		if ((x = strrchr(host1, '.')))
1120 			x++;
1121 		if (!x || strlen(x) < 2 || strlen(x) > 3)
1122 			goto fail_split;
1123 		if ((x = strrchr(host2, '.')))
1124 			x++;
1125 		if (!x || strlen(x) < 2 || strlen(x) > 3)
1126 			goto fail_split;
1127 
1128 		if (bogus)
1129 		{
1130 			char *copy = NULL;
1131 			char *b_check;
1132 			copy = LOCAL_COPY(bogus);
1133 			while((b_check = next_arg(copy, &copy)))
1134 			{
1135 				if (wild_match(b_check, host1) || wild_match(b_check, host2))
1136 					goto fail_split;
1137 			}
1138 		}
1139 		return 1;
1140 	}
1141 fail_split:
1142 	return 0;
1143 }
1144 
clear_array(NickTab ** tmp,char * nick)1145 void clear_array(NickTab **tmp, char *nick)
1146 {
1147 NickTab *t, *q;
1148 
1149 	if (nick)
1150 	{
1151 		if ((t = (NickTab *)remove_from_list((List **)tmp, nick)))
1152 		{
1153 			new_free(&t->nick);
1154 			new_free(&t->type);
1155 			new_free((char **)&t);
1156 		}
1157 		return;
1158 	}
1159 	for (t = *tmp; t; )
1160 	{
1161 		q = t->next;
1162 		new_free(&t->nick);
1163 		new_free(&t->type);
1164 		new_free((char **)&t);
1165 		t = q;
1166 	}
1167 	*tmp = NULL;
1168 }
1169 
1170 
BUILT_IN_COMMAND(clear_tab)1171 BUILT_IN_COMMAND(clear_tab)
1172 {
1173 NickTab **tmp = &tabkey_array;
1174 char *nick = NULL;
1175 	if (command && *command && !my_stricmp(command, "CLEARAUTO"))
1176 		tmp = &autoreply_array;
1177 	if (args && *args)
1178 	{
1179 		while ((nick = next_arg(args, &args)))
1180 			clear_array(tmp, nick);
1181 		return;
1182 	}
1183 	clear_array(tmp, nick);
1184 }
1185 
BX_userage(char * command,char * use)1186 void BX_userage(char *command, char *use)
1187 {
1188 	if (command)
1189 	{
1190 		if (do_hook(USAGE_LIST, "%s %s", command, use ? use : "No Help Available for this command"))
1191 			put_it("%s", convert_output_format(fget_string_var(FORMAT_USAGE_FSET), "%s %s", command, convert_output_format(use ? use : "%WNo Help available for this command", NULL, NULL)));
1192 	}
1193 	else
1194 		put_it("Please return the command you just typed to #bitchx on efnet");
1195 }
1196 
BX_random_str(int min,int max)1197 char *BX_random_str(int min, int max)
1198 {
1199 	int i, ii;
1200 	static char str[IRCD_BUFFER_SIZE/4+1];
1201 
1202 	while ((i = getrandom(MIN(min, max), MAX(min, max))) > IRCD_BUFFER_SIZE/4)
1203 		;
1204 	for (ii = 0; ii < i; ii++)
1205 		str[ii] = (char) getrandom(97, 122);
1206 	str[ii] = '\0';
1207 	return str;
1208 }
1209 
1210 
check_auto_away(time_t idlet)1211 void check_auto_away(time_t idlet)
1212 {
1213 	int i;
1214 	char *msg = NULL;
1215 	int auto_away_time = get_int_var(AUTO_AWAY_TIME_VAR);
1216 	int idle_mins = auto_away_time / 60;
1217 
1218 	if (!auto_away_time || !get_int_var(AUTO_AWAY_VAR) || idlet < auto_away_time)
1219 		return;
1220 
1221 	if (awaymsg)
1222 		malloc_sprintf(&msg, "%s: [%d mins]", convert_output_format(awaymsg, NULL), idle_mins);
1223 	else
1224 		malloc_sprintf(&msg, "Auto-Away after %d mins", idle_mins);
1225 
1226 	for (i = 0; i < server_list_size(); i++)
1227 		if (is_server_connected(i) && !get_server_away(i))
1228 			set_server_away(i, msg, 0);
1229 
1230 	update_all_status(current_window, NULL, 0);
1231 	new_free(&msg);
1232 }
1233 
1234 /*char *logfile[] = { "tcl.log", "msg.log", NULL };*/
1235 
1236 /* putlog(level,channel_name,format,...);  */
putlog(int type,...)1237 void putlog(int type, ...)
1238 {
1239 #ifdef PUBLIC_ACCESS
1240 		return;
1241 #else
1242 va_list va;
1243 time_t	t;
1244 char	*format,
1245 	*chname,
1246 	*logfilen = NULL,
1247 	s[BIG_BUFFER_SIZE+1],
1248 	s1[40],
1249 	s2[BIG_BUFFER_SIZE+1];
1250 FILE	*f;
1251 	if (!get_int_var(BOT_LOG_VAR))
1252 		return;
1253 	if (!(logfilen = get_string_var(BOT_LOGFILE_VAR)))
1254 		return;
1255 
1256 	va_start(va, type);
1257 	t = now;
1258 	strftime(s1, 30, "%I:%M%p", localtime(&t));
1259 	chname=va_arg(va,char *);
1260 	format=va_arg(va,char *);
1261 	vsprintf(s,format,va);
1262 
1263 	if (!*s)
1264 		strcpy(s2,empty_string);
1265 	else
1266 		sprintf(s2,"[%s] %s",s1,s);
1267 
1268 	if (chname && *chname =='*')
1269 	{
1270 		if ((f=fopen(logfilen, "a+")) != NULL)
1271 		{
1272 			fprintf(f,"%s\n",s2);
1273 			fclose(f);
1274 		}
1275 	}
1276 #endif
1277 }
1278 
rename_file(char * old_file,char ** new_file)1279 int rename_file(char *old_file, char **new_file)
1280 {
1281 	FILE *fp;
1282 	char *c, *tmp = NULL;
1283 	char buffer[BIG_BUFFER_SIZE];
1284 
1285 	c = alloca(10);
1286 	sprintf(c, "%03i.", getrandom(0, 999));
1287 	if (get_string_var(DCC_DLDIR_VAR))
1288 		malloc_sprintf(&tmp, "%s/%s", get_string_var(DCC_DLDIR_VAR), c);
1289 	else
1290 		malloc_sprintf(&tmp, "%s", c);
1291 
1292 	malloc_strcat(&tmp, *new_file);
1293 	strlcpy(buffer, *new_file, sizeof buffer);
1294 	while ((fp = fopen(tmp, "r")) != NULL)
1295 	{
1296 		fclose(fp);
1297 		sprintf(c, "%03i.", getrandom(0, 999));
1298 		if (get_string_var(DCC_DLDIR_VAR))
1299 			malloc_sprintf(&tmp, "%s/%s", get_string_var(DCC_DLDIR_VAR), c);
1300 		else
1301 			malloc_sprintf(&tmp, "%s", c);
1302 		malloc_strcat(&tmp, buffer);
1303 	}
1304 	if (fp != NULL)
1305 		fclose(fp);
1306 	malloc_sprintf(new_file, "%s", c);
1307 	malloc_strcat(new_file, buffer);
1308 	new_free(&tmp);
1309 	return 0;
1310 }
1311 
isme(char * nick)1312 int isme(char *nick)
1313 {
1314 	return ((my_stricmp(nick, get_server_nickname(from_server)) == 0) ? 1 : 0);
1315 }
1316 
1317 
1318 enum REDIR_TYPES { PRIVMSG = 0, KICK, TOPIC, WALL, WALLOP, NOTICE, KBOOT, KILL, DCC, LIST};
1319 void userhost_ban(UserhostItem *stuff, char *nick1, char *args);
1320 
redirect_msg(char * to,enum REDIR_TYPES what,char * str,int showansi)1321 int redirect_msg(char *to, enum REDIR_TYPES what, char *str, int showansi)
1322 {
1323 char *new_str;
1324 	if (showansi)
1325 		new_str = str;
1326 	else
1327 		new_str = stripansicodes(str);
1328 	switch(what)
1329 	{
1330 		case PRIVMSG:
1331 			if (is_channel(to))
1332 				put_it("%s", convert_output_format(fget_string_var(FORMAT_SEND_PUBLIC_FSET), "%s %s %s %s", update_clock(GET_TIME), to, get_server_nickname(from_server), new_str));
1333 			else if ((*to == '=') && dcc_activechat(to+1))
1334 				;
1335 			else
1336 				put_it("%s", convert_output_format(fget_string_var(FORMAT_SEND_MSG_FSET), "%s %s %s %s", update_clock(GET_TIME), to, get_server_nickname(from_server), new_str));
1337 			if ((*to == '=') && dcc_activechat(to+1))
1338 				dcc_chat_transmit(to+1, new_str, new_str, "PRIVMSG", 1);
1339 			else
1340 				send_to_server("PRIVMSG %s :%s", to, new_str);
1341 			break;
1342 		case KILL:
1343 			send_to_server("KILL %s :%s", to, new_str);
1344 			break;
1345 		case KBOOT:
1346 			userhostbase(to, userhost_ban, 1, "%s", get_current_channel_by_refnum(0));
1347 		case KICK:
1348 			send_to_server("KICK %s %s :%s", get_current_channel_by_refnum(0), to, new_str);
1349 			break;
1350 		case TOPIC:
1351 			send_to_server("TOPIC %s :%s", to, new_str);
1352 			break;
1353 		case WALL:
1354 		{
1355 			ChanWallOp(NULL, new_str, NULL, NULL);
1356 			break;
1357 		}
1358 		case WALLOP:
1359 			put_it("!! %s", str);
1360 			send_to_server("WALLOPS :%s", new_str);
1361 			break;
1362 		case NOTICE:
1363 			put_it("%s", convert_output_format(fget_string_var(FORMAT_SEND_NOTICE_FSET), "%s %s %s %s", update_clock(GET_TIME), to, get_server_nickname(from_server), new_str));
1364 			send_to_server("NOTICE %s :%s", to, new_str);
1365 			break;
1366 		case LIST:
1367 		default:
1368 			break;
1369 	}
1370 	return 1;
1371 }
1372 
BUILT_IN_COMMAND(do_dirlasttype)1373 BUILT_IN_COMMAND(do_dirlasttype)
1374 {
1375 	char *channel = NULL; int count = -1;
1376 	LastMsg *t = NULL;
1377 	char *form = NULL;
1378 	char *sform;
1379 	int numargs = 5;
1380 	int size = 1;
1381 	int len = strlen(command);
1382 	int showansi = 0;
1383 	enum REDIR_TYPES what = PRIVMSG;
1384 
1385 	if (!my_strnicmp(command, "RELCR", 5))
1386 	{
1387 		t = &last_ctcp_reply[0];
1388 		form = fget_string_var(FORMAT_CTCP_REPLY_FSET);
1389 		sform = "%s %s %s %s %s";
1390 		if (len == 6 && command[len-1] == 'T')
1391 			what = TOPIC;
1392 	}
1393 	else if (!my_strnicmp(command, "RELC", 4))
1394 	{
1395 		t = &last_sent_ctcp[0];
1396 		form = fget_string_var(FORMAT_SEND_CTCP_FSET);
1397 		sform = "%s %s %s %s %s";
1398 		if (len > 4 && command[len-1] == 'T')
1399 			what = TOPIC;
1400 	}
1401 	else if (!my_strnicmp(command, "RELD", 4))
1402 	{
1403 		t = &last_dcc[0];
1404 		size = MAX_LAST_MSG;
1405 		form = fget_string_var(FORMAT_DCC_CHAT_FSET);
1406 		sform = "%s %s %s %s";
1407 		if (len > 4 && command[len-1] == 'T')
1408 			what = TOPIC;
1409 		numargs = 4;
1410 	}
1411 	else if (!my_strnicmp(command, "RELSD", 5))
1412 	{
1413 		t = &last_sent_dcc[0];
1414 		size = MAX_LAST_MSG;
1415 		form = fget_string_var(FORMAT_DCC_CHAT_FSET);
1416 		sform = "%s %s %s %s";
1417 		if (len > 5 && command[len-1] == 'T')
1418 			what = TOPIC;
1419 		numargs = 4;
1420 	}
1421 	else if (!my_strnicmp(command, "RELI", 4))
1422 	{
1423 		t = &last_invite_channel[0];
1424 		form = fget_string_var(FORMAT_INVITE_FSET);
1425 		numargs = 4;
1426 		sform = "%s %s %s";
1427 		if (len > 4 && command[len-1] == 'T')
1428 			what = TOPIC;
1429 	}
1430 	else if (!my_strnicmp(command, "RELM", 4))
1431 	{
1432 		/* ??? */
1433 		t = &last_msg[0]; size = MAX_LAST_MSG;
1434 		form = fget_string_var(FORMAT_RELM_FSET);
1435 		sform = "%s %s %s %s %s";
1436 		if (len > 4 && command[len-1] == 'T')
1437 			what = TOPIC;
1438 	}
1439 	else if (!my_strnicmp(command, "RELN", 4))
1440 	{
1441 		/* ??? */
1442 		t = &last_notice[0]; size = MAX_LAST_MSG;
1443 		form = fget_string_var(FORMAT_RELN_FSET);
1444 		sform = "%s %s %s %s %s";
1445 		if (len > 4 && command[len-1] == 'T')
1446 			what = TOPIC;
1447 	}
1448 	else if (!my_strnicmp(command, "RELSM", 5))
1449 	{
1450 		/* ??? */
1451 		t = &last_sent_msg[0]; size = MAX_LAST_MSG;
1452 		form = fget_string_var(FORMAT_RELSM_FSET);
1453 		sform = "%s %s %s %s %s";
1454 		if (len > 5 && command[len-1] == 'T')
1455 			what = TOPIC;
1456 	}
1457 	else if (!my_strnicmp(command, "RELSN", 5))
1458 	{
1459 		/* ??? */
1460 		t = &last_sent_notice[0]; size = MAX_LAST_MSG;
1461 		form = fget_string_var(FORMAT_SEND_NOTICE_FSET);
1462 		sform = "%s %s %s %s";
1463 		numargs = 4;
1464 		if (len > 5 && command[len-1] == 'T')
1465 			what = TOPIC;
1466 	}
1467 	else if (!my_strnicmp(command, "RELST", 5))
1468 	{
1469 		/* ??? */
1470 		t = &last_sent_topic[0];
1471 		form = fget_string_var(FORMAT_TOPIC_FSET);
1472 		sform = "%s %s %s";
1473 		numargs = 2;
1474 		if (len > 5 && command[len-1] == 'T')
1475 			what = TOPIC;
1476 	}
1477 	else if (!my_strnicmp(command, "RELSW", 5))
1478 	{
1479 		/* ??? */
1480 		t = &last_sent_wall[0];
1481 		form = fget_string_var(FORMAT_WALLOP_FSET);
1482 		sform = "%s %s %s %s %s";
1483 		if (len > 5 && command[len-1] == 'T')
1484 			what = TOPIC;
1485 	}
1486 	else if (!my_strnicmp(command, "RELS", 4))
1487 	{
1488 		t = &last_servermsg[0]; size = MAX_LAST_MSG;
1489 		form = fget_string_var(FORMAT_RELS_FSET);
1490 		sform = "%s %s %s %s";
1491 		numargs = 4;
1492 		if (len > 4 && command[len-1] == 'T')
1493 			what = TOPIC;
1494 	}
1495 	else if (!my_strnicmp(command, "RELT", 4))
1496 	{
1497 		/* ??? */
1498 		t = &last_topic[0];
1499 		form = fget_string_var(FORMAT_TOPIC_FSET);
1500 		sform = "%s %s %s";
1501 		numargs = 2;
1502 		if (len > 4 && command[len-1] == 'T')
1503 			what = TOPIC;
1504 	}
1505 	else if (!my_strnicmp(command, "RELW", 4))
1506 	{
1507 		/* ??? */
1508 		t = &last_wall[0];
1509 		size = MAX_LAST_MSG;
1510 		form = fget_string_var(FORMAT_WALLOP_FSET);
1511 		sform = "%s %s %s %s";
1512 		numargs = 4;
1513 		if (len > 4 && command[len-1] == 'T')
1514 			what = TOPIC;
1515 	}
1516 	else
1517 	{
1518 		what = LIST; size = MAX_LAST_MSG;
1519 		t = &last_msg[0];
1520 		for (count = size - 1; count != -1; count--)
1521 		{
1522 			if (t[count].last_msg)
1523 				put_it("%2d %s", count, convert_output_format(fget_string_var(FORMAT_RELM_FSET), "%s %s %s %s %s", t[count].time, t[count].from, t[count].uh, t[count].to, t[count].last_msg));
1524 		}
1525 		return;
1526 	}
1527 
1528 	while (args && *args)
1529 	{
1530 		char *comm;
1531 		if (!(comm = next_arg(args, &args)))
1532 			break;
1533 		if (!my_strnicmp(comm, "-list", strlen(comm)))
1534 		{
1535 			for (count = size - 1; count != -1; count--)
1536 			{
1537 				if (!t[count].last_msg)
1538 					continue;
1539 				switch(numargs)
1540 				{
1541 					case 2:
1542 						put_it("%2d %s", count, convert_output_format(form, sform, t[count].time, t[count].to, t[count].last_msg));
1543 						break;
1544 					case 3:
1545 						put_it("%2d %s", count, convert_output_format(form, sform, t[count].time, t[count].from, t[count].last_msg));
1546 						break;
1547 					case 4:
1548 						put_it("%2d %s", count, convert_output_format(form, sform, t[count].time, t[count].from, t[count].to, t[count].last_msg));
1549 						break;
1550 					case 5:
1551 						put_it("%2d %s", count, convert_output_format(form, sform, t[count].time, t[count].from, t[count].uh, t[count].to, t[count].last_msg));
1552 				}
1553 			}
1554 			return;
1555 		}
1556 		else if (!my_strnicmp(comm, "-kick", strlen(comm)))
1557 			what = KICK;
1558 		else if (!my_strnicmp(comm, "-wall", strlen(comm)))
1559 			what = WALL;
1560 		else if (!my_strnicmp(comm, "-wallop", strlen(comm)))
1561 			what = WALLOP;
1562 		else if (!my_strnicmp(comm, "-msg", strlen(comm)))
1563 			what = PRIVMSG;
1564 		else if (!my_strnicmp(comm, "-notice", strlen(comm)))
1565 			what = NOTICE;
1566 		else if (!my_strnicmp(comm, "-topic", strlen(comm)))
1567 			what = TOPIC;
1568 		else if (!my_strnicmp(comm, "-kboot", strlen(comm)))
1569 			what = KBOOT;
1570 		else if (!my_strnicmp(comm, "-kill", strlen(comm)))
1571 			what = KILL;
1572 		else if (!my_strnicmp(comm, "-ansi", strlen(comm)))
1573 			showansi++;
1574 		else if (!my_strnicmp(comm, "-num", strlen(comm)))
1575 		{
1576 			comm = next_arg(args, &args);
1577 			if (is_number(comm))
1578 			{
1579 				count = my_atol(comm);
1580 				if (count < 0)
1581 					count *= -1;
1582 			}
1583 			else
1584 				channel = comm;
1585 		}
1586 		else
1587 			channel = comm;
1588 
1589 		if (count > size)
1590 			count = size;
1591 	}
1592 	if (count == -1)
1593 		count = 0;
1594 	if (!channel)
1595 		channel = get_target_by_refnum(0);
1596 	if (channel || what == WALLOP)
1597 	{
1598 		char *p = NULL;
1599 		if (!t[count].last_msg)
1600 		{
1601 			bitchsay("No such msg #%d for /%s received", count, command);
1602 			return;
1603 		}
1604 		switch(numargs)
1605 		{
1606 			case 2:
1607 				malloc_strcpy(&p, convert_output_format(form, sform, t[count].time, t[count].to, t[count].last_msg));
1608 				break;
1609 			case 3:
1610 				malloc_strcpy(&p, convert_output_format(form, sform, t[count].time, t[count].from, t[count].last_msg));
1611 				break;
1612 			case 4:
1613 				malloc_strcpy(&p, convert_output_format(form, sform, t[count].time, t[count].from, t[count].to, t[count].last_msg));
1614 				break;
1615 			case 5:
1616 				malloc_strcpy(&p, convert_output_format(form, sform, t[count].time, t[count].from, t[count].uh, t[count].to, t[count].last_msg));
1617 		}
1618 		redirect_msg(channel, what, p, showansi);
1619 		new_free(&p);
1620 	}
1621 	else
1622 		bitchsay("Can not %s what you requested", command);
1623 }
1624 
1625 /*
1626  * Wallop   Sends NOTICE to all ops of Current Channel!
1627  */
BUILT_IN_COMMAND(ChanWallOp)1628 BUILT_IN_COMMAND(ChanWallOp)
1629 {
1630 	char *channel = NULL;
1631 	char *chops = NULL;
1632 	char *include = NULL;
1633 	char *exclude = NULL;
1634 	ChannelList *chan;
1635 	NickList *tmp;
1636 	int ver = 0;
1637 	int enable_all = 0;
1638 
1639 	char	buffer[BIG_BUFFER_SIZE + 1];
1640 
1641 	if (!args || (args && !*args))
1642 		return;
1643 
1644 	if (get_current_channel_by_refnum(0))
1645 	{
1646 		int count = 0;
1647 		int i = 0;
1648 		char *nick = NULL;
1649 		malloc_strcpy(&channel, get_current_channel_by_refnum(0));
1650 		chan = lookup_channel(channel, current_window->server, 0);
1651 		if (((ver = get_server_version(current_window->server)) == Server2_8hybrid6))
1652 			enable_all = 1;
1653 		else if (((ver = get_server_version(current_window->server)) < Server_u2_8))
1654 		{
1655 			while (args && (*args == '-' || *args == '+'))
1656 			{
1657 				nick = next_arg(args, &args);
1658 				if (*nick == '-')
1659 				{
1660 					malloc_strcat(&exclude, nick+1);
1661 					malloc_strcat(&exclude, space);
1662 				}
1663 				else
1664 				{
1665 					malloc_strcat(&include, nick+1);
1666 					malloc_strcat(&include, space);
1667 				}
1668 			}
1669 		}
1670 		if (!args || !*args)
1671 		{
1672 			bitchsay("NO Wallmsg included");
1673 			new_free(&exclude);
1674 			new_free(&include);
1675 			new_free(&channel);
1676 		}
1677 		set_display_target(channel, LOG_WALL);
1678 		sprintf(buffer, "[\002BX-Wall\002/\002%s\002] %s", channel, args);
1679 		if (ver >= Server_u2_10 || enable_all)
1680 		{
1681 			send_to_server(enable_all?"NOTICE @%s :%s":"WALLCHOPS %s :%s", channel, buffer);
1682 			put_it("%s", convert_output_format(fget_string_var(FORMAT_BWALL_FSET), "%s %s %s %s %s", update_clock(GET_TIME), channel, "*", "*", args));
1683 			add_last_type(&last_sent_wall[0], 1, NULL, NULL, channel, buffer);
1684 			new_free(&channel);
1685 			reset_display_target();
1686 			return;
1687 		}
1688 		for (tmp = next_nicklist(chan, NULL); tmp; tmp = next_nicklist(chan, tmp))
1689 		{
1690 			if (!my_stricmp(tmp->nick, get_server_nickname(from_server)))
1691 				continue;
1692 			if (exclude && stristr(exclude, tmp->nick))
1693 				continue;
1694 			if (nick_isop(tmp) || (include && stristr(include, tmp->nick)))
1695 			{
1696 				if (chops)
1697 					malloc_strcat(&chops, ",");
1698 				malloc_strcat(&chops, tmp->nick);
1699 				count++;
1700 			}
1701 			if (count >= 8 && chops)
1702 			{
1703 				send_to_server("%s %s :%s", "NOTICE", chops, buffer);
1704 				i+=count;
1705 				count = 0;
1706 				new_free(&chops);
1707 			}
1708 		}
1709 		i+=count;
1710 		if (chops)
1711 			send_to_server("%s %s :%s", "NOTICE", chops, buffer);
1712 		if (i)
1713 		{
1714 			put_it("%s", convert_output_format(fget_string_var(FORMAT_BWALL_FSET), "%s %s %s %s %s", update_clock(GET_TIME), channel, "*", "*", args));
1715 			add_last_type(&last_sent_wall[0], 1, NULL, NULL, channel, buffer);
1716 			if (exclude)
1717 				bitchsay("Excluded <%s> from wallmsg", exclude);
1718 			if (include)
1719 				bitchsay("Included <%s> in wallmsg", include);
1720 		}
1721 		else
1722 			put_it("%s", convert_output_format("$G No ops on $0", "%s", channel));
1723 		reset_display_target();
1724 	}
1725 	else
1726 		say("No Current Channel for this Window.");
1727 	new_free(&include);
1728 	new_free(&channel);
1729 	new_free(&chops);
1730 	new_free(&exclude);
1731 }
1732 
log_toggle(int flag,ChannelList * chan)1733 void log_toggle(int flag, ChannelList *chan)
1734 {
1735 	char *logfile;
1736 
1737 	if (((logfile = get_string_var(MSGLOGFILE_VAR)) == NULL) || !get_string_var(CTOOLZ_DIR_VAR))
1738 	{
1739 		bitchsay("You must set the MSGLOGFILE and CTOOLZ_DIR variables first!");
1740 		set_int_var(MSGLOG_VAR, 0);
1741 		return;
1742 	}
1743 	logmsg(LOG_CURRENT, NULL, flag ? 1 : 2, NULL);
1744 }
1745 
are_you_opped(char * channel)1746 int are_you_opped(char *channel)
1747 {
1748 	return is_chanop(channel, get_server_nickname(from_server));
1749 }
1750 
error_not_opped(const char * channel)1751 void error_not_opped(const char *channel)
1752 {
1753 	set_display_target(channel, LOG_CRAP);
1754 	say("You're not opped on %s", channel);
1755 	reset_display_target();
1756 }
1757 
freadln(FILE * stream,char * lin)1758 int freadln(FILE *stream, char *lin)
1759 {
1760 	char *p;
1761 
1762 	do
1763 		p = fgets(lin, IRCD_BUFFER_SIZE/4, stream);
1764 	while (p && (*lin == '#'));
1765 
1766 	if (!p)
1767 		return 0;
1768 	chop(lin, 1);
1769 	if (!*lin)
1770 		return 0;
1771 	return 1;
1772 }
1773 
randreason(char * filename)1774 char *randreason(char *filename)
1775 {
1776 	int count, min, i;
1777 	FILE *bleah;
1778 	char *f = NULL;
1779 	static char buffer[IRCD_BUFFER_SIZE/4 + 1];
1780 
1781 	min = 1;
1782 	count = 0;
1783 
1784 	buffer[0] = '\0';
1785 	f = m_strdup(filename);
1786 	if (filename && (bleah = uzfopen(&f, get_string_var(LOAD_PATH_VAR), 0)))
1787 	{
1788 		while (!feof(bleah))
1789 			if (freadln(bleah, buffer))
1790 				count++;
1791 		if (!count)
1792 		{
1793 			strcpy(buffer, "No Reason");
1794 			new_free(&f);
1795 			return buffer;
1796 		}
1797 		i = getrandom(1, count);
1798 		count = 0;
1799 		fclose(bleah);
1800 		bleah = uzfopen(&f, get_string_var(LOAD_PATH_VAR), 0);
1801 		while (!feof(bleah) && (count < i))
1802 			if (freadln(bleah, buffer))
1803 				count++;
1804 		fclose(bleah);
1805 	}
1806 	new_free(&f);
1807 	if (*buffer)
1808 		return buffer;
1809 	return NULL;
1810 }
1811 
get_reason(char * nick,char * file)1812 char *get_reason(char *nick, char *file)
1813 {
1814 	char *temp;
1815 	char *filename = NULL;
1816 	if (file && *file)
1817 		malloc_strcpy(&filename, file);
1818 	else
1819 		malloc_sprintf(&filename, "%s", DEFAULT_BITCHX_KICK_FILE);
1820 	temp = randreason(filename);
1821 	new_free(&filename);
1822 	if ((!temp || !*temp) && get_string_var(DEFAULT_REASON_VAR))
1823 		temp = get_string_var(DEFAULT_REASON_VAR);
1824 	return (stripansicodes(convert_output_format(temp, "%s %s", nick? nick: "error", get_server_nickname(from_server) )));
1825 }
1826 
get_realname(char * nick)1827 char *get_realname(char *nick)
1828 {
1829 	char *temp;
1830 	char *filename = NULL;
1831 
1832 	malloc_sprintf(&filename, "%s", DEFAULT_BITCHX_IRCNAME_FILE);
1833 	temp = randreason(filename);
1834 	new_free(&filename);
1835 	if ((!temp || !*temp))
1836 		temp = "Who cares?";
1837 	return (stripansicodes(convert_output_format(temp, "%s %s", nick? nick: "error", get_server_nickname(from_server) )));
1838 }
1839 
get_signoffreason(char * nick)1840 char *get_signoffreason(char *nick)
1841 {
1842 	char *temp;
1843 	char *filename = NULL;
1844 
1845 	malloc_sprintf(&filename, "%s", DEFAULT_BITCHX_QUIT_FILE);
1846 	temp = randreason(filename);
1847 	new_free(&filename);
1848 	if (!temp || !*temp)
1849 		temp = "$0 has no reason";
1850 	return (stripansicodes(convert_output_format(temp, "%s %s", nick? nick: "error", get_server_nickname(from_server))));
1851 }
1852 
1853 #ifdef WANT_NSLOOKUP
1854 
auto_nslookup(struct reslist * rptr)1855 void auto_nslookup(struct reslist *rptr)
1856 {
1857 NickList *nick;
1858 ChannelList *chan;
1859 struct in_addr ip;
1860 
1861 	if ((chan = lookup_channel(rptr->channel, rptr->server, 0)))
1862 	{
1863 		if ((nick = find_nicklist_in_channellist(rptr->nick, chan, 0)))
1864 		{
1865 			if (rptr->re_he.h_addr_list[0].s_addr)
1866 			{
1867 				bcopy(&rptr->re_he.h_addr_list[0], (char *)&ip, sizeof(ip));
1868 				nick->ip = m_strdup(inet_ntoa(ip));
1869 #ifdef WANT_USERLIST
1870 				check_auto(chan->channel, nick, chan);
1871 #endif
1872 			}
1873 			else if (++nick->ip_count < 2)
1874 				do_nslookup(rptr->host, rptr->nick, rptr->user, rptr->channel, rptr->server, auto_nslookup, NULL);
1875 #ifdef PANA_DEBUG
1876 			else
1877 				put_it("got here. nslookup failure %s!%s", nick->nick, nick->host);
1878 #endif
1879 		}
1880 	}
1881 	return;
1882 }
1883 
print_ns_succede(struct reslist * rptr)1884 void print_ns_succede(struct reslist *rptr)
1885 {
1886 char *u, *n, *h;
1887 char buffer[BIG_BUFFER_SIZE];
1888 struct in_addr ip;
1889 	u = rptr->user ? rptr->user : empty_string;
1890 	h = rptr->host;
1891 	n = rptr->nick ? rptr->nick : empty_string;
1892 	if (rptr->command)
1893 	{
1894 		int i;
1895 		if (rptr->nick && rptr->user)
1896 			sprintf(buffer, "%s!%s@%s ", n, u, h);
1897 		else
1898 			sprintf(buffer, "%s ", h);
1899 		for (i = 0; rptr->re_he.h_addr_list[i].s_addr; i++)
1900 		{
1901 			bcopy(&rptr->re_he.h_addr_list[i], (char *)&ip, sizeof(ip));
1902 			BX_strpcat(buffer, "%s ", inet_ntoa(ip));
1903 			if (strlen(buffer) > 490)
1904 				break;
1905 		}
1906 		parse_line("NSLOOKUP", rptr->command, buffer, 0, 0, 1);
1907 		return;
1908 	}
1909 	if (do_hook(NSLOOKUP_LIST, "%s %s %s %s %s", h, rptr->re_he.h_name?rptr->re_he.h_name:empty_string, (char *)inet_ntoa(rptr->re_he.h_addr_list[0]), n, u))
1910 	{
1911 		int i;
1912 		*buffer = 0;
1913 		if (rptr->nick && rptr->user)
1914 			bitchsay("[%s!%s@%s]: %s", n, u, h, rptr->re_he.h_name ? rptr->re_he.h_name: "invalid hostname");
1915 		else
1916 			bitchsay("%s is %s (%s)", h, rptr->re_he.h_name ? rptr->re_he.h_name:"invalid hostname", (char *)inet_ntoa(rptr->re_he.h_addr_list[0]));
1917 		for (i = 0; rptr->re_he.h_addr_list[i].s_addr; i++)
1918 		{
1919 			bcopy(&rptr->re_he.h_addr_list[i], (char *)&ip, sizeof(ip));
1920 			BX_strpcat(buffer, "[%s] ", inet_ntoa(ip));
1921 			if (strlen(buffer) > 490)
1922 				break;
1923 		}
1924 		bitchsay("IPs: %s", buffer);
1925 	        for (i = 0; rptr->re_he.h_aliases[i]; i++)
1926 			bitchsay("\talias %d = %s", i+1, rptr->re_he.h_aliases[i]);
1927 	}
1928 }
1929 
print_ns_fail(struct reslist * rptr)1930 void print_ns_fail(struct reslist *rptr)
1931 {
1932 	if (rptr->command)
1933 	{
1934 		char buffer[BIG_BUFFER_SIZE];
1935 		if (rptr->nick && rptr->user)
1936 			sprintf(buffer, "%s!%s@%s ", rptr->nick, rptr->user, rptr->host);
1937 		else
1938 			sprintf(buffer, "%s ", rptr->host);
1939 		parse_line("NSLOOKUP", rptr->command, buffer, 0, 0, 1);
1940 		return;
1941 	}
1942 	if (do_hook(NSLOOKUP_LIST, "%s %s %s", rptr->host, rptr->nick?rptr->nick:empty_string, rptr->user?rptr->user:empty_string))
1943 	{
1944 		if (rptr->nick && rptr->user)
1945 			bitchsay("nslookup of %s!%s@%s failed.", rptr->nick, rptr->user, rptr->host);
1946 		else
1947 			bitchsay("nslookup of host %s failed.", rptr->host);
1948 	}
1949 }
1950 #ifdef THREAD
1951 
1952 /* Threaded generic callback to convert from Sheik's
1953  * return format to the one that is already used in
1954  * BitchX to maintain threaded and non-threaded
1955  * compatibility.
1956  */
cdns_generic_callback(DNS_QUEUE * dns)1957 void cdns_generic_callback(DNS_QUEUE *dns)
1958 {
1959 	struct reslist *info = dns->callinfo;
1960 
1961 	if(!info)
1962 		return;
1963 
1964     if(dns->hostentr)
1965 		memcpy(&info->re_he, dns->hostentr, sizeof(struct hent));
1966 
1967 	if(info->func)
1968 		info->func(info);
1969 	else if(dns->out)
1970 		print_ns_succede(info);
1971 	else
1972 		print_ns_fail(info);
1973 
1974 	new_free(&info->nick);
1975 	new_free(&info->user);
1976 	new_free(&info->host);
1977 	new_free(&info->channel);
1978 	new_free(&info->command);
1979 	new_free(&info);
1980 }
1981 
1982 /* Not entirely sure how to handle this at the moment */
ar_rename_nick(char * old_nick,char * new_nick,int server)1983 void ar_rename_nick(char *old_nick, char *new_nick, int server)
1984 {
1985 }
1986 
1987 #else
1988 
1989 
1990 /*
1991  * arlib.c (C)opyright 1993 Darren Reed. All rights reserved.
1992  * This file may not be distributed without the author's permission in any
1993  * shape or form. The author takes no responsibility for any damage or loss
1994  * of property which results from the use of this software.
1995  * heavily modified for use in a irc client.
1996  */
1997 
1998 #if !defined( __APPLE__ )
1999 /* On some systems, eg OpenBSD, we have to define BIND_4_COMPAT to get
2000  * nameser_compat.h included, to get the "old" bind interface. */
2001   #if !defined( BIND_4_COMPAT )
2002     #define BIND_4_COMPAT
2003   #endif
2004 #else
2005 /* After one too many bongs some developer at Apple decided to rename this
2006  * macro for no good reason. */
2007   #if !defined( BIND_8_COMPAT )
2008     #define BIND_8_COMPAT
2009   #endif
2010 #endif
2011 
2012 #include <stdio.h>
2013 #include <fcntl.h>
2014 #include <signal.h>
2015 #include <sys/types.h>
2016 #include <sys/time.h>
2017 #include <sys/socket.h>
2018 #include <netinet/in.h>
2019 #include <netdb.h>
2020 #include <arpa/nameser.h>
2021 #include <resolv.h>
2022 
2023 #define HOSTLEN 100
2024 extern	int	h_errno;
2025 static	char	ar_hostbuf[HOSTLEN+1], ar_domainname[HOSTLEN+1];
2026 static	char	ar_dot[] = ".";
2027 static	int	ar_resfd = -1, ar_vc = 0;
2028 static	struct	reslist	*ar_last = NULL, *ar_first = NULL;
2029 
2030 
2031 static	int	do_query_name(struct resinfo *, char *, register struct reslist *, char *, char *, char *, char *, int , void (*func)(), char *);
2032 static	int	do_query_number(struct resinfo *, char *, register struct reslist *, char *, char *, char *, char *, int , void (*func)(), char *);
2033 static	int	ar_resend_query(struct reslist *);
2034 
2035 #define MAX_RETRIES 4
2036 
2037 #ifndef HFIXEDSZ
2038 #define HFIXEDSZ 12
2039 #endif
2040 
2041 #ifndef INT32SZ
2042 #define INT32SZ 4
2043 #endif
2044 
2045 
2046 /*
2047  * Statistics structure.
2048  */
2049 static	struct	resstats {
2050 	int	re_errors;
2051 	int	re_nu_look;
2052 	int	re_na_look;
2053 	int	re_replies;
2054 	int	re_requests;
2055 	int	re_resends;
2056 	int	re_sent;
2057 	int	re_timeouts;
2058 } ar_reinfo;
2059 
2060 #ifdef HAVE_LIBIPHLPAPI
2061 
ar_get_windows_dns(void)2062 void ar_get_windows_dns(void)
2063 {
2064 	DWORD ret;
2065 	ULONG buflen = 0;
2066 	FIXED_INFO *buf;
2067 
2068 	ret = GetNetworkParams(NULL, &buflen);
2069 	if (ret != ERROR_BUFFER_OVERFLOW)
2070 		return;
2071 
2072 	buf = new_malloc(buflen);
2073 
2074 	ret = GetNetworkParams(buf, &buflen);
2075 	if (ret == NO_ERROR)
2076 	{
2077 		_res.nscount = 1;
2078 		_res.nsaddr_list[0].sin_family = AF_INET;
2079 		_res.nsaddr_list[0].sin_addr.s_addr = inet_addr(buf->DnsServerList.IpAddress.String);
2080 		_res.nsaddr_list[0].sin_port = htons(53);
2081 	}
2082 
2083 	new_free(&buf);
2084 	return;
2085 }
2086 #endif /* HAVE_LIBIPHLPAPI */
2087 
2088 /*
2089  * ar_init
2090  *
2091  * Initializes the various ARLIB internal varilables and related DNS
2092  * options for res_init().
2093  *
2094  * Returns 0 or the socket opened for use with talking to name servers
2095  * if 0 is passed or ARES_INITSOCK is set.
2096  */
ar_init(int op)2097 int	ar_init(int op)
2098 {
2099 	int	ret = 0;
2100 
2101 	if (!op)
2102 		return ar_resfd;
2103 	if (op & ARES_INITLIST)
2104 	{
2105 		memset(&ar_reinfo, 0, sizeof(ar_reinfo));
2106 		ar_first = ar_last = NULL;
2107 	}
2108 
2109 	if (op & ARES_CALLINIT && !(_res.options & RES_INIT))
2110 	{
2111 		ret = res_init();
2112 		(void)strcpy(ar_domainname, ar_dot);
2113 		(void)strncat(ar_domainname, _res.defdname, HOSTLEN-2);
2114 #ifdef HAVE_LIBIPHLPAPI
2115 		/* The Cygwin resolver library doesn't fill out _res.nsaddr_list
2116 		 * and sets _res.nscount to -1 if there's no /etc/resolv.conf file,
2117 		 * so we try fetching the first DNS server address ourselves. */
2118 		if (_res.nscount < 1)
2119 			ar_get_windows_dns();
2120 #endif
2121 		if (_res.nscount < 1)
2122 		{
2123 			/* Try falling back to the Google public DNS */
2124 			_res.nscount = 1;
2125 			_res.nsaddr_list[0].sin_family = AF_INET;
2126 			_res.nsaddr_list[0].sin_addr.s_addr = inet_addr("8.8.8.8");
2127 			_res.nsaddr_list[0].sin_port = htons(53);
2128 		}
2129 	}
2130 
2131 	if (op & ARES_INITSOCK)
2132 		ret = ar_resfd = ar_open();
2133 
2134 	if (op & ARES_INITDEBG)
2135 		_res.options |= RES_DEBUG;
2136 	return ret;
2137 }
2138 
2139 /*
2140  * ar_open
2141  *
2142  * Open a socket to talk to a name server with.
2143  * Check _res.options to see if we use a TCP or UDP socket.
2144  */
ar_open(void)2145 int	ar_open(void)
2146 {
2147 	if (ar_resfd > -1)
2148 		return ar_resfd;
2149 
2150 	if (_res.options & RES_USEVC)
2151 	{
2152 		struct	sockaddr_in *sip;
2153 		int	i = 0;
2154 
2155 		sip = _res.nsaddr_list;
2156 		ar_vc = 1;
2157 		ar_resfd = socket(AF_INET, SOCK_STREAM, 0);
2158 
2159 		/*
2160 		 * Try each name server listed in sequence until we
2161 		 * succeed or run out.
2162 		 */
2163 		while (connect(ar_resfd, (struct sockaddr *)sip++,
2164 				sizeof(struct sockaddr)))
2165 		{
2166 			(void)close(ar_resfd);
2167 			ar_resfd = -1;
2168 			if (i >= _res.nscount)
2169 				break;
2170 			ar_resfd = socket(AF_INET, SOCK_STREAM, 0);
2171 		}
2172 	}
2173 	else
2174 	{
2175 		int on = 0;
2176 		ar_resfd = socket(AF_INET, SOCK_DGRAM, 0);
2177 
2178 		if (ar_resfd > -1)
2179 			(void) setsockopt(ar_resfd, SOL_SOCKET, SO_BROADCAST,(char *)&on, sizeof(on));
2180 	}
2181 
2182 	if (ar_resfd < 0)
2183 		return -1;
2184 
2185 	if (set_non_blocking(ar_resfd) < 0)
2186 	{
2187 		(void)close(ar_resfd);
2188 		ar_resfd = -1;
2189 	}
2190 
2191 	return new_open(ar_resfd);
2192 }
2193 
2194 /*
2195  * ar_close
2196  *
2197  * Closes and flags the ARLIB socket as closed.
2198  */
ar_close(void)2199 void	ar_close(void)
2200 {
2201 	new_close(ar_resfd);
2202 	ar_resfd = -1;
2203 	return;
2204 }
2205 
2206 /*
2207  * ar_add_request
2208  *
2209  * Add a new DNS query to the end of the query list.
2210  */
ar_add_request(struct reslist * new)2211 static	int	ar_add_request(struct reslist *new)
2212 {
2213 	if (!new)
2214 		return -1;
2215 	if (!ar_first)
2216 		ar_first = ar_last = new;
2217 	else
2218 	{
2219 		ar_last->re_next = new;
2220 		ar_last = new;
2221 	}
2222 	new->re_next = NULL;
2223 	ar_reinfo.re_requests++;
2224 	return 0;
2225 }
2226 
2227 /*
2228  * ar_remrequest
2229  *
2230  * Remove a request from the list. This must also free any memory that has
2231  * been allocated for temporary storage of DNS results.
2232  *
2233  * Returns -1 if there are anyy problems removing the requested structure
2234  * or 0 if the remove is successful.
2235  */
ar_remrequest(struct reslist * old)2236 static	int	ar_remrequest(struct reslist *old)
2237 {
2238 	struct	reslist	*rptr, *r2ptr;
2239 	register char	**s;
2240 
2241 	if (!old)
2242 		return -1;
2243 	for (rptr = ar_first, r2ptr = NULL; rptr; rptr = rptr->re_next)
2244 	{
2245 		if (rptr == old)
2246 			break;
2247 		r2ptr = rptr;
2248 	}
2249 
2250 	if (!rptr)
2251 		return -1;
2252 	if (rptr == ar_first)
2253 		ar_first = ar_first->re_next;
2254 	else if (rptr == ar_last)
2255 	{
2256 		if ((ar_last = r2ptr))
2257 			ar_last->re_next = NULL;
2258 	}
2259 	else
2260 		r2ptr->re_next = rptr->re_next;
2261 
2262 	if (!ar_first)
2263 		ar_last = ar_first;
2264 	if (rptr->re_he.h_name)
2265 		new_free(&rptr->re_he.h_name);
2266 	if ((s = rptr->re_he.h_aliases))
2267 	{
2268 		for (; *s; s++)
2269 			new_free(s);
2270 	}
2271 	if (rptr->re_rinfo.ri_ptr)
2272 		new_free(&rptr->re_rinfo.ri_ptr);
2273 
2274 	new_free(&rptr->nick);
2275 	new_free(&rptr->user);
2276 	new_free(&rptr->host);
2277 	new_free(&rptr->channel);
2278 	new_free(&rptr->command);
2279 	new_free(&rptr);
2280 
2281 	return 0;
2282 }
2283 
2284 /*
2285  * ar_make_request
2286  *
2287  * Create a DNS query recorded for the request being made and place it on the
2288  * current list awaiting replies.  Initialization of the record with set
2289  * values should also be done.
2290  */
ar_make_request(register struct resinfo * resi,char * nick,char * user,char * h,char * chan,int server,void (* func)(),char * command)2291 static	struct	reslist	*ar_make_request(register struct resinfo *resi, char *nick, char *user, char *h, char *chan, int server, void (*func)(), char *command)
2292 {
2293 	register struct	reslist	*rptr;
2294 	register struct resinfo *rp;
2295 
2296 	rptr = (struct reslist *)new_malloc(sizeof(struct reslist));
2297 	rp = &rptr->re_rinfo;
2298 
2299 	rptr->re_next    = NULL; /* where NULL is non-zero ;) */
2300 	rptr->re_sentat  = now;
2301 	rptr->re_retries = MAX_RETRIES;/*_res.retry + 2;*/
2302 	rptr->re_sends = 1;
2303 	rptr->re_resend  = 1;
2304 	rptr->re_timeout = rptr->re_sentat + _res.retrans;
2305 	rptr->re_he.h_name = NULL;
2306 	rptr->re_he.h_addrtype   = AF_INET;
2307 	rptr->re_he.h_aliases[0] = NULL;
2308 	rp->ri_ptr = resi->ri_ptr;
2309 	rp->ri_size = resi->ri_size;
2310 	if (nick)
2311 		malloc_strcpy(&rptr->nick, nick);
2312 	if (user)
2313 		malloc_strcpy(&rptr->user, user);
2314 	if (h)
2315 		malloc_strcpy(&rptr->host, h);
2316 	if (chan)
2317 		rptr->channel = m_strdup(chan);
2318 	if (command)
2319 		rptr->command = m_strdup(command);
2320 	rptr->server = server;
2321 	if (func)
2322 		rptr->func = func;
2323 	(void)ar_add_request(rptr);
2324 
2325 	return rptr;
2326 }
2327 
ar_rename_nick(char * old_nick,char * new_nick,int server)2328 void ar_rename_nick(char *old_nick, char *new_nick, int server)
2329 {
2330 	register struct reslist *rptr;
2331 	for (rptr = ar_first; rptr; rptr = rptr->re_next)
2332 	{
2333 		if (!rptr->nick) continue;
2334 		if (!strcmp(rptr->nick, old_nick) && rptr->server == server)
2335 			malloc_strcpy(&rptr->nick, new_nick);
2336 	}
2337 }
2338 
2339 /*
2340  * ar_timeout
2341  *
2342  * Remove queries from the list which have been there too long without
2343  * being resolved.
2344  */
ar_timeout(time_t now,char * info,int size,void (* func)(struct reslist *))2345 long	ar_timeout(time_t now, char *info, int size, void (*func)(struct reslist *) )
2346 {
2347 	register struct	reslist	*rptr, *r2ptr;
2348 	register long	next = 0;
2349 
2350 	for (rptr = ar_first, r2ptr = NULL; rptr; rptr = r2ptr)
2351 	{
2352 		r2ptr = rptr->re_next;
2353 		if (now >= rptr->re_timeout)
2354 		{
2355 			/*
2356 			 * If the timeout for the query has been exceeded,
2357 			 * then resend the query if we still have some
2358 			 * 'retry credit' and reset the timeout. If we have
2359 			 * used it all up, then remove the request.
2360 			 */
2361 			if (--rptr->re_retries <= 0)
2362 			{
2363 				ar_reinfo.re_timeouts++;
2364 				if (info && rptr->re_rinfo.ri_ptr)
2365 					bcopy(rptr->re_rinfo.ri_ptr, info,
2366 						MIN(rptr->re_rinfo.ri_size, size));
2367 				if (rptr->func)
2368 					(*rptr->func)(rptr);
2369 				else if (func)
2370 					(*func)(rptr);
2371 				(void)ar_remrequest(rptr);
2372 				return now;
2373 			}
2374 			else
2375 			{
2376 				rptr->re_sends++;
2377 				rptr->re_sentat = now;
2378 				rptr->re_timeout = now + _res.retrans;
2379 				(void)ar_resend_query(rptr);
2380 			}
2381 		}
2382 		if (!next || rptr->re_timeout < next)
2383 			next = rptr->re_timeout;
2384 	}
2385 	return next;
2386 }
2387 
2388 /*
2389  * ar_send_res_msg
2390  *
2391  * When sending queries to nameservers listed in the resolv.conf file,
2392  * don't send a query to every one, but increase the number sent linearly
2393  * to match the number of resends. This increase only occurs if there are
2394  * multiple nameserver entries in the resolv.conf file.
2395  * The return value is the number of messages successfully sent to
2396  * nameservers or -1 if no successful sends.
2397  */
ar_send_res_msg(char * msg,int len,int rcount)2398 static	int	ar_send_res_msg(char *msg, int len, int rcount)
2399 {
2400 	register int	i;
2401 	int	sent = 0;
2402 
2403 	if (!msg)
2404 		return -1;
2405 
2406 	rcount = (_res.nscount > rcount) ? rcount : _res.nscount;
2407 	if (_res.options & RES_PRIMARY)
2408 		rcount = 1;
2409 	if (!rcount)
2410 		rcount = 1;
2411 	if (ar_vc)
2412 	    {
2413 		ar_reinfo.re_sent++;
2414 		sent++;
2415 		if (write(ar_resfd, msg, len) == -1)
2416 		    {
2417 			int errtmp = errno;
2418 			ar_close();
2419 			errno = errtmp;
2420 		    }
2421 	    }
2422 	else
2423 		for (i = 0; i < rcount; i++)
2424 		{
2425 			_res.nsaddr_list[i].sin_family = AF_INET;
2426 			if (sendto(ar_resfd, msg, len, 0,
2427 				   (struct sockaddr *)&(_res.nsaddr_list[i]),
2428 				sizeof(struct sockaddr_in)) == len)
2429 			{
2430 				ar_reinfo.re_sent++;
2431 				sent++;
2432 			}
2433 		}
2434 	return (sent) ? sent : -1;
2435 }
2436 
2437 /*
2438  * ar_find_id
2439  *
2440  * find a dns query record by the id (id is determined by dn_mkquery)
2441  */
ar_find_id(int id)2442 static	struct	reslist	*ar_find_id(int id)
2443 {
2444 	register struct	reslist	*rptr;
2445 
2446 	for (rptr = ar_first; rptr; rptr = rptr->re_next)
2447 		if (rptr->re_id == id)
2448 			return rptr;
2449 	return NULL;
2450 }
2451 
2452 /*
2453  * ar_delete
2454  *
2455  * Delete a request from the waiting list if it has a data pointer which
2456  * matches the one passed.
2457  */
ar_delete(char * ptr,int size)2458 int	ar_delete(char *ptr, int size)
2459 {
2460 	register struct	reslist	*rptr;
2461 	register struct	reslist	*r2ptr;
2462 	int	removed = 0;
2463 
2464 	for (rptr = ar_first; rptr; rptr = r2ptr)
2465 	    {
2466 		r2ptr = rptr->re_next;
2467 		if (rptr->re_rinfo.ri_ptr && ptr && size &&
2468 		    memcmp(rptr->re_rinfo.ri_ptr, ptr, size) == 0)
2469 		    {
2470 			(void)ar_remrequest(rptr);
2471 			removed++;
2472 		    }
2473 	    }
2474 	return removed;
2475 }
2476 
2477 /*
2478  * ar_query_name
2479  *
2480  * generate a query based on class, type and name.
2481  */
ar_query_name(char * name,int class,int type,struct reslist * rptr)2482 static	int	ar_query_name(char *name, int class, int type, struct reslist *rptr)
2483 {
2484 	static	char buf[MAXPACKET];
2485 	int	r,s;
2486 	HEADER	*hptr;
2487 
2488 	memset(buf, 0, sizeof(buf));
2489 	r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
2490 			buf, sizeof(buf));
2491 	if (r <= 0)
2492 	    {
2493 		h_errno = NO_RECOVERY;
2494 		return r;
2495 	    }
2496 	hptr = (HEADER *)buf;
2497 	rptr->re_id = ntohs(hptr->id);
2498 
2499 	s = ar_send_res_msg(buf, r, rptr->re_sends);
2500 
2501 	if (s == -1)
2502 	    {
2503 		h_errno = TRY_AGAIN;
2504 		return -1;
2505 	    }
2506 	else
2507 		rptr->re_sent += s;
2508 	return 0;
2509 }
2510 
2511 /*
2512  * ar_gethostbyname
2513  *
2514  * Replacement library function call to gethostbyname().  This one, however,
2515  * doesn't return the record being looked up but just places the query in the
2516  * queue to await answers.
2517  */
ar_gethostbyname(char * name,char * info,int size,char * nick,char * user,char * h,char * chan,int server,void (* func)(),char * command)2518 int	ar_gethostbyname(char *name, char *info, int size, char *nick, char *user, char *h, char *chan, int server, void (*func)(), char *command)
2519 {
2520 	char	host[HOSTLEN+1];
2521 	struct	resinfo	resi;
2522 	register struct resinfo *rp = &resi;
2523 
2524 	if (size && info)
2525 	{
2526 		rp->ri_ptr = (char *)new_malloc(size+1);
2527 		if (*info)
2528 			bcopy(info, rp->ri_ptr, size);
2529 		rp->ri_size = size;
2530 	}
2531 	else
2532 		memset((char *)rp, 0, sizeof(resi));
2533 	ar_reinfo.re_na_look++;
2534 	(void)strncpy(host, name, 64);
2535 	host[64] = '\0';
2536 
2537 	return (do_query_name(rp, host, NULL, nick, user, h, chan, server, func, command));
2538 }
2539 
do_query_name(struct resinfo * resi,char * name,register struct reslist * rptr,char * nick,char * user,char * h,char * chan,int server,void (* func)(),char * command)2540 static	int	do_query_name(struct resinfo *resi, char *name, register struct reslist *rptr, char *nick, char *user, char *h, char *chan, int server, void (*func)(), char *command)
2541 {
2542 	char	hname[HOSTLEN];
2543 	int	len;
2544 
2545 	len = strlen((char *)strncpy(hname, name, sizeof(hname)-1));
2546 
2547 	if (rptr && (hname[len-1] != '.'))
2548 	{
2549 		(void)strncat(hname, ar_dot, sizeof(hname)-len-1);
2550 		/*
2551 		 * NOTE: The logical relationship between DNSRCH and DEFNAMES
2552 		 * is implies. ie no DEFNAES, no DNSRCH.
2553 		 */
2554 		if ((_res.options & (RES_DEFNAMES|RES_DNSRCH)) ==
2555 		    (RES_DEFNAMES|RES_DNSRCH))
2556 		{
2557 			if (_res.dnsrch[(int)rptr->re_srch])
2558 				(void)strncat(hname, _res.dnsrch[(int)rptr->re_srch],
2559 					sizeof(hname) - ++len -1);
2560 		}
2561 		else if (_res.options & RES_DEFNAMES)
2562 			(void)strncat(hname, ar_domainname, sizeof(hname) - len -1);
2563 	}
2564 
2565 	/*
2566 	 * Store the name passed as the one to lookup and generate other host
2567 	 * names to pass onto the nameserver(s) for lookups.
2568 	 */
2569 	if (!rptr)
2570 	{
2571 		rptr = ar_make_request(resi, nick, user, h, chan, server, func, command);
2572 		rptr->re_type = T_A;
2573 		(void)strncpy(rptr->re_name, name, sizeof(rptr->re_name)-1);
2574 	}
2575 	return (ar_query_name(hname, C_IN, T_A, rptr));
2576 }
2577 
2578 /*
2579  * ar_gethostbyaddr
2580  *
2581  * Generates a query for a given IP address.
2582  */
ar_gethostbyaddr(char * addr,char * info,int size,char * nick,char * user,char * h,char * chan,int server,void (* func)(),char * command)2583 int	ar_gethostbyaddr(char *addr, char *info, int size, char *nick, char *user, char *h, char *chan, int server, void (*func)(), char *command)
2584 {
2585 	struct	resinfo	resi;
2586 	register struct resinfo *rp = &resi;
2587 
2588 	if (size && info)
2589 	{
2590 		rp->ri_ptr = (char *)new_malloc(size+1);
2591 		if (*info)
2592 			bcopy(info, rp->ri_ptr, size);
2593 		rp->ri_size = size;
2594 	}
2595 	else
2596 		memset((char *)rp, 0, sizeof(resi));
2597 	ar_reinfo.re_nu_look++;
2598 	return (do_query_number(rp, addr, NULL, nick, user, h, chan, server, func, command));
2599 }
2600 
2601 /*
2602  * do_query_number
2603  *
2604  * Use this to do reverse IP# lookups.
2605  */
do_query_number(struct resinfo * resi,char * numb,register struct reslist * rptr,char * nick,char * user,char * h,char * chan,int server,void (* func)(),char * command)2606 static	int	do_query_number(struct resinfo *resi, char *numb, register struct reslist *rptr, char *nick, char *user, char *h, char *chan, int server, void (*func)(), char *command)
2607 {
2608 	register unsigned char	*cp;
2609 	static	char	ipbuf[32];
2610 
2611 	/*
2612 	 * Generate name in the "in-addr.arpa" domain.  No addings bits to this
2613 	 * name to get more names to query!.
2614 	 */
2615 	cp = (unsigned char *)numb;
2616 	(void)sprintf(ipbuf,"%u.%u.%u.%u.in-addr.arpa.",
2617 			(unsigned int)(cp[3]), (unsigned int)(cp[2]),
2618 			(unsigned int)(cp[1]), (unsigned int)(cp[0]));
2619 
2620 	if (!rptr)
2621 	    {
2622 		rptr = ar_make_request(resi, nick, user, h, chan, server, func, command);
2623 		rptr->re_type = T_PTR;
2624 		rptr->re_he.h_length = sizeof(struct in_addr);
2625 		memcpy((char *)&rptr->re_addr, numb, rptr->re_he.h_length);
2626 		memcpy((char *)&rptr->re_he.h_addr_list[0].s_addr, numb,
2627 			rptr->re_he.h_length);
2628 	    }
2629 	return (ar_query_name(ipbuf, C_IN, T_PTR, rptr));
2630 }
2631 
2632 /*
2633  * ar_resent_query
2634  *
2635  * resends a query.
2636  */
ar_resend_query(struct reslist * rptr)2637 static	int	ar_resend_query(struct reslist *rptr)
2638 {
2639 	if (!rptr->re_resend)
2640 		return -1;
2641 
2642 	switch(rptr->re_type)
2643 	{
2644 	case T_PTR:
2645 		ar_reinfo.re_resends++;
2646 		return do_query_number(NULL, (char *)&rptr->re_addr, rptr, NULL, NULL, NULL, NULL, -1, NULL, NULL);
2647 	case T_A:
2648 		ar_reinfo.re_resends++;
2649 		return do_query_name(NULL, rptr->re_name, rptr, NULL, NULL, NULL, NULL, -1, NULL, NULL);
2650 	default:
2651 		break;
2652 	}
2653 
2654 	return -1;
2655 }
2656 
2657 /*
2658  * ar_procanswer
2659  *
2660  * process an answer received from a nameserver.
2661  */
ar_procanswer(struct reslist * rptr,HEADER * hptr,char * buf,char * eob)2662 static	int	ar_procanswer(struct reslist *rptr, HEADER *hptr, char *buf, char *eob)
2663 {
2664 	char	*cp, **alias;
2665 	int	class, type, dlen, len, ans = 0, n;
2666 	unsigned int ttl, dr, *adr;
2667 	struct	hent	*hp;
2668 
2669 	cp = buf + HFIXEDSZ;
2670 	adr = (unsigned int *)rptr->re_he.h_addr_list;
2671 
2672 	while (*adr)
2673 		adr++;
2674 
2675 	alias = rptr->re_he.h_aliases;
2676 	while (*alias)
2677 		alias++;
2678 
2679 	hp = &rptr->re_he;
2680 
2681 
2682 	/*
2683 	 * Skip over the original question.
2684 	 */
2685 #ifndef __QNX__
2686 	/* QNX doesn't seem to have this function, not sure
2687 	 * what it does at the moment but I may change this
2688 	 * in the future. - Brian
2689 	 */
2690 	while (hptr->qdcount-- > 0)
2691 		cp += dn_skipname(cp, eob) + QFIXEDSZ;
2692 #endif
2693 	/*
2694 	 * proccess each answer sent to us. blech.
2695 	 */
2696 	while (hptr->ancount-- > 0 && cp < eob) {
2697 		n = dn_expand(buf, eob, cp, ar_hostbuf, sizeof(ar_hostbuf)-1);
2698 		cp += n;
2699 		if (n <= 0)
2700 			return ans;
2701 
2702 		ans++;
2703 		/*
2704 		 * 'skip' past the general dns crap (ttl, class, etc) to get
2705 		 * the pointer to the right spot.  Some of thse are actually
2706 		 * useful so its not a good idea to skip past in one big jump.
2707 		 */
2708 		GETSHORT(type, cp);
2709 		GETSHORT(class, cp);
2710 		GETLONG(ttl, cp);
2711 		GETSHORT(dlen, cp);
2712 		rptr->re_type = type;
2713 
2714 		switch(type)
2715 		{
2716 		case T_A :
2717 			if (dlen != sizeof(struct in_addr))
2718 				return 0;
2719 			rptr->re_he.h_length = dlen;
2720 			if (ans == 1)
2721 				rptr->re_he.h_addrtype=(class == C_IN) ?
2722 							AF_INET : AF_UNSPEC;
2723 			memcpy(&dr, cp, dlen);
2724 			*adr++ = dr;
2725 			*adr = 0;
2726 			cp += dlen;
2727 			len = strlen(ar_hostbuf);
2728 			if (!rptr->re_he.h_name)
2729 				malloc_strcpy(&rptr->re_he.h_name, ar_hostbuf);
2730 			break;
2731 		case T_PTR :
2732 			if ((n = dn_expand(buf, eob, cp, ar_hostbuf,
2733 					   sizeof(ar_hostbuf)-1 )) < 0)
2734 			    {
2735 				cp += n;
2736 				continue;
2737 			    }
2738 			ar_hostbuf[HOSTLEN] = 0;
2739 			cp += n;
2740 			len = strlen(ar_hostbuf)+1;
2741 			/*
2742 			 * copy the returned hostname into the host name
2743 			 * or alias field if there is a known hostname
2744 			 * already.
2745 			 */
2746 			if (!rptr->re_he.h_name)
2747 				malloc_strcpy(&rptr->re_he.h_name, ar_hostbuf);
2748 			else
2749 			{
2750 				*alias = (char *)new_malloc(len);
2751 				strcpy(*alias++, ar_hostbuf);
2752 				*alias = NULL;
2753 			}
2754 			break;
2755 		case T_CNAME :
2756 			cp += dlen;
2757 			if (alias >= &(rptr->re_he.h_aliases[MAXALIASES-1]))
2758 				continue;
2759 			n = strlen(ar_hostbuf)+1;
2760 			*alias = (char *)new_malloc(n);
2761 			(void)strcpy(*alias++, ar_hostbuf);
2762 			*alias = NULL;
2763 			break;
2764 		default :
2765 			cp += dlen;
2766 			break;
2767 		}
2768 	}
2769 
2770 	return ans;
2771 }
2772 
2773 /*
2774  * ar_answer
2775  *
2776  * Get an answer from a DNS server and process it.  If a query is found to
2777  * which no answer has been given to yet, copy its 'info' structure back
2778  * to where "reip" points and return a pointer to the hostent structure.
2779  */
ar_answer(char * reip,int size,void (* func)(struct reslist *))2780 struct	hostent	*ar_answer(char *reip, int size, void (*func)(struct reslist *) )
2781 {
2782 	static	char	ar_rcvbuf[HFIXEDSZ + MAXPACKET];
2783 	static	struct	hostent	ar_host;
2784 
2785 	HEADER	hptr;
2786 	struct	reslist	*rptr = NULL;
2787 	struct hostent *hp;
2788 	char **s;
2789 	unsigned long	*adr;
2790 	int	rc, i, n, a;
2791 
2792 	rc = recv(ar_resfd, ar_rcvbuf, sizeof(ar_rcvbuf), 0);
2793 	if (rc <= 0)
2794 		goto getres_err;
2795 
2796 	ar_reinfo.re_replies++;
2797 /*	hptr = (HEADER *)ar_rcvbuf;*/
2798 	memcpy(&hptr, ar_rcvbuf, sizeof(HEADER));
2799 
2800 	/*
2801 	 * convert things to be in the right order.
2802 	 */
2803 	hptr.id = ntohs(hptr.id);
2804 	hptr.ancount = ntohs(hptr.ancount);
2805 	hptr.arcount = ntohs(hptr.arcount);
2806 	hptr.nscount = ntohs(hptr.nscount);
2807 	hptr.qdcount = ntohs(hptr.qdcount);
2808 	/*
2809 	 * response for an id which we have already received an answer for
2810 	 * just ignore this response.
2811 	 */
2812 	rptr = ar_find_id(hptr.id);
2813 	if (!rptr)
2814 		goto getres_err;
2815 
2816 	if ((hptr.rcode != NOERROR) || (hptr.ancount == 0))
2817 	    {
2818 		switch (hptr.rcode)
2819 		{
2820 		case NXDOMAIN:
2821 			h_errno = HOST_NOT_FOUND;
2822 			break;
2823 		case SERVFAIL:
2824 			h_errno = TRY_AGAIN;
2825 			break;
2826 		case NOERROR:
2827 			h_errno = NO_DATA;
2828 			break;
2829 		case FORMERR:
2830 		case NOTIMP:
2831 		case REFUSED:
2832 		default:
2833 			h_errno = NO_RECOVERY;
2834 			break;
2835 		}
2836 		ar_reinfo.re_errors++;
2837 		/*
2838 		** If a bad error was returned, we stop here and dont send
2839 		** send any more (no retries granted).
2840 		*/
2841 		if (h_errno != TRY_AGAIN)
2842 		    {
2843 			rptr->re_resend = 0;
2844 			rptr->re_retries = 0;
2845 		    }
2846 		goto getres_err;
2847 	    }
2848 
2849 	a = ar_procanswer(rptr, &hptr, ar_rcvbuf, ar_rcvbuf+rc);
2850 
2851 	if ((rptr->re_type == T_PTR) && (_res.options & RES_CHECKPTR))
2852 	    {
2853 		/*
2854 		 * For reverse lookups on IP#'s, lookup the name that is given
2855 		 * for the ip# and return with that as the official result.
2856 		 * -avalon
2857 		 */
2858 		rptr->re_type = T_A;
2859 		/*
2860 		 * Clean out the list of addresses already set, even though
2861 		 * there should only be one :)
2862 		 */
2863 		adr = (unsigned long *)rptr->re_he.h_addr_list;
2864 		while (*adr)
2865 			*adr++ = 0L;
2866 		/*
2867 		 * Lookup the name that we were given for the ip#
2868 		 */
2869 		ar_reinfo.re_na_look++;
2870 		(void)strncpy(rptr->re_name, rptr->re_he.h_name,
2871 			sizeof(rptr->re_name)-1);
2872 		rptr->re_he.h_name = NULL;
2873 		rptr->re_retries = MAX_RETRIES;/*_res.retry + 2;*/
2874 		rptr->re_sends = 1;
2875 		rptr->re_resend = 1;
2876 		if (rptr->re_he.h_name)
2877 			new_free(&rptr->re_he.h_name);
2878 		ar_reinfo.re_na_look++;
2879 		(void)ar_query_name(rptr->re_name, C_IN, T_A, rptr);
2880 		return NULL;
2881 	    }
2882 
2883 	if (reip && rptr->re_rinfo.ri_ptr && size)
2884 		memcpy(reip, rptr->re_rinfo.ri_ptr,
2885 			MIN(rptr->re_rinfo.ri_size, size));
2886 
2887 	/*
2888 	 * Clean up structure from previous usage.
2889 	 */
2890 	hp = &ar_host;
2891 	if (hp->h_name)
2892 		new_free(&hp->h_name);
2893 	if ((s = hp->h_aliases))
2894 	{
2895 		while (*s)
2896 		{
2897 			new_free(s);
2898 			s++;
2899 		}
2900 		new_free(&hp->h_aliases);
2901 	}
2902 	if ((s = hp->h_addr_list))
2903 	{
2904 
2905 		while (*s)
2906 		{
2907 			new_free(s);
2908 			s++;
2909 		}
2910 		new_free(&hp->h_addr_list);
2911 		hp->h_addr_list = NULL;
2912 	}
2913 	memset ((char *)hp, 0, sizeof(*hp));
2914 	/*
2915 	 * Setup and copy details for the structure we return a pointer to.
2916 	 */
2917 	hp->h_addrtype = AF_INET;
2918 	hp->h_length = sizeof(struct in_addr);
2919 	malloc_strcpy(&hp->h_name, rptr->re_he.h_name);
2920 	/*
2921 	 * Count IP#'s.
2922 	 */
2923 	for (i = 0, n = 0; i < MAXADDRS; i++, n++)
2924 		if (!rptr->re_he.h_addr_list[i].s_addr)
2925 			break;
2926 	s = hp->h_addr_list = (char **)new_malloc((n + 1) * sizeof(char *));
2927 	if (n)
2928 	{
2929 		*s = (char *)new_malloc(sizeof(struct in_addr));
2930 		memcpy(*s, (char *)&rptr->re_he.h_addr_list[0].s_addr,
2931 			sizeof(struct in_addr));
2932 		s++;
2933 		for (i = 1; i < n; i++, s++)
2934 		{
2935 			*s = (char *)new_malloc(sizeof(struct in_addr));
2936 			memcpy(*s, (char *)&rptr->re_he.h_addr_list[i].s_addr,
2937 				sizeof(struct in_addr));
2938 		}
2939 	}
2940 	*s = NULL;
2941 	/*
2942 	 * Count CNAMEs
2943 	 */
2944 	for (i = 0, n = 0; i < MAXADDRS; i++, n++)
2945 		if (!rptr->re_he.h_aliases[i])
2946 			break;
2947 	s = hp->h_aliases = (char **)new_malloc((n + 1) * sizeof(char *));
2948 	for (i = 0; i < n; i++)
2949 	{
2950 		*s++ = rptr->re_he.h_aliases[i];
2951 		rptr->re_he.h_aliases[i] = NULL;
2952 	}
2953 	*s = NULL;
2954 	if (rptr->func)
2955 		(*rptr->func)(rptr);
2956 	else if (func)
2957 		(*func)(rptr);
2958 	if (a > 0)
2959 		(void)ar_remrequest(rptr);
2960 	else
2961 		if (!rptr->re_sent)
2962 			(void)ar_remrequest(rptr);
2963 	return hp;
2964 
2965 getres_err:
2966 	if (rptr)
2967 	{
2968 		if (reip && rptr->re_rinfo.ri_ptr && size)
2969 			memcpy(reip, rptr->re_rinfo.ri_ptr,
2970 				MIN(rptr->re_rinfo.ri_size, size));
2971 		if ((h_errno != TRY_AGAIN) &&
2972 		    ((_res.options & (RES_DNSRCH|RES_DEFNAMES)) ==
2973 		     (RES_DNSRCH|RES_DEFNAMES) ))
2974 			if (_res.dnsrch[(int)rptr->re_srch])
2975 			{
2976 				rptr->re_retries = MAX_RETRIES; /*_res.retry + 2;*/
2977 				rptr->re_sends = 1;
2978 				rptr->re_resend = 1;
2979 				(void)ar_resend_query(rptr);
2980 				rptr->re_srch++;
2981 			}
2982 		return NULL;
2983 	}
2984 	return NULL;
2985 }
2986 
2987 static int ar_seq = 0;
2988 static int ar_lookup = 0;
2989 
2990 #endif /* THREAD */
2991 #endif /* WANT_NSLOOKUP */
2992 
set_nslookupfd(fd_set * rd)2993 void set_nslookupfd(fd_set *rd)
2994 {
2995 #ifdef WANT_NSLOOKUP
2996 #ifdef THREAD
2997 	set_dns_output_fd(rd);
2998 #else
2999 int s;
3000 	if ((s = ar_init(0)) != -1)
3001 		FD_SET(s, rd);
3002 #endif /* THREAD */
3003 #endif /* WANT_NSLOOKUP */
3004 }
3005 
print_nslookup(fd_set * rd)3006 long print_nslookup(fd_set *rd)
3007 {
3008 #ifdef WANT_NSLOOKUP
3009 #ifdef THREAD
3010 	dns_check(rd);
3011 #else
3012 struct hostent *hp = NULL;
3013 int ar_del = 0;
3014 int s;
3015 	if ((s = ar_init(0)) == -1)
3016 		return -1;
3017 	if (!(FD_ISSET(s, rd)))
3018 	{
3019 		unsigned long when = 0;
3020 		when = ar_timeout(now, (char *)&ar_del, sizeof(ar_del), print_ns_fail);
3021 		if (ar_del)
3022 			ar_lookup--;
3023 		return when;
3024 	}
3025 	if ((hp = ar_answer((char *)&ar_del, sizeof(ar_del), print_ns_succede)))
3026 	{
3027 		char **s;
3028 		ar_lookup--;
3029 		new_free(&hp->h_name);
3030 		if ((s = hp->h_aliases))
3031 		{
3032 			while (*s)
3033 			{
3034 				new_free(s);
3035 				s++;
3036 			}
3037 			new_free(&hp->h_aliases);
3038 		}
3039 		if ((s = hp->h_addr_list))
3040 		{
3041 			while (*s)
3042 			{
3043 				new_free(s);
3044 				s++;
3045 			}
3046 			new_free(&hp->h_addr_list);
3047 		}
3048 	}
3049 #endif /* THREAD */
3050 #endif /* WANT_NSLOOKUP */
3051 	return -1;
3052 }
3053 
do_nslookup(char * host,char * nick,char * user,char * chan,int server,void (* func)(),char * command)3054 char *do_nslookup(char *host, char *nick, char *user, char *chan, int server, void (*func)(), char *command)
3055 {
3056 #ifdef WANT_NSLOOKUP
3057 #ifdef THREAD
3058 	struct reslist *info = new_malloc(sizeof(struct reslist));
3059 
3060     info->host = m_strdup(host);
3061 	info->nick = m_strdup(nick);
3062 	info->user = m_strdup(user);
3063 	info->channel = m_strdup(chan);
3064     if(command)
3065 		info->command = m_strdup(command);
3066     info->server = server;
3067     info->func = func;
3068 
3069 	add_to_dns_queue(host, cdns_generic_callback, NULL, info, DNS_URGENT);
3070 #else
3071 struct in_addr temp1;
3072 
3073 	if (!host)
3074 		return NULL;
3075 
3076 	if ((ar_init(0) == -1))
3077 		ar_init(ARES_INITLIST|ARES_INITSOCK|ARES_CALLINIT);
3078 
3079 	ar_lookup++;
3080 	if (isdigit((unsigned char)*(host + strlen(host) - 1)))
3081 	{
3082 		ar_seq++;
3083 		temp1.s_addr = inet_addr(host);
3084 		ar_gethostbyaddr((char *)&temp1.s_addr, (char *)&ar_seq, sizeof(ar_seq), nick, user, host, chan, server, func, command);
3085 	}
3086 	else
3087 	{
3088 		ar_seq++;
3089 		ar_gethostbyname(host, (char *)&ar_seq, sizeof(ar_seq), nick, user, host, chan, server, func, command);
3090 	}
3091 #endif /* THREAD */
3092 #endif /* WANT_NSLOOKUP */
3093 	return NULL;
3094 }
3095 
3096 #ifdef WANT_NSLOOKUP
userhost_nsl(UserhostItem * stuff,char * nick,char * args)3097 void userhost_nsl(UserhostItem *stuff, char *nick, char *args)
3098 {
3099 	char *nsl = NULL;
3100 
3101 	if (!stuff || !stuff->nick || !nick || !strcmp(stuff->user, "<UNKNOWN>") || my_stricmp(stuff->nick, nick))
3102 	{
3103 		say("No information for %s", nick);
3104 		return;
3105 	}
3106 	if(args)
3107 	{
3108 		nsl = LOCAL_COPY(args);
3109 		next_arg(nsl, &nsl);
3110 	}
3111 	nsl = do_nslookup(stuff->host, stuff->nick, stuff->user, NULL, from_server, NULL, (nsl && *nsl) ? nsl : NULL);
3112 }
3113 #endif
3114 
BUILT_IN_COMMAND(nslookup)3115 BUILT_IN_COMMAND(nslookup)
3116 {
3117 #ifdef WANT_NSLOOKUP
3118 	char	*host,
3119 		*hostname,
3120 		*cmd = NULL;
3121 	int count = 0;
3122 	while ((host = next_arg(args, &args)))
3123 	{
3124 		if (count == 0)
3125 			bitchsay("Checking tables...");
3126 		if (*host == '-' || *host == '/')
3127 		{
3128 			host++;
3129 
3130 			if (host && !my_stricmp(host, "cmd"))
3131 			{
3132 				if (!(cmd = next_expr(&args, '{')))
3133 					bitchsay("Need {...} for -CMD arguement");
3134 				else
3135 					host = next_arg(args, &args);
3136 			}
3137 		}
3138 		if (!host || !*host)
3139 			break;
3140 		if (!strchr(host, '.'))
3141 			userhostbase(host, userhost_nsl, 1, "%s%s%s", host, cmd ? space:empty_string, cmd?cmd:empty_string);
3142 		else
3143 			hostname = do_nslookup(host, NULL, NULL, NULL, from_server, NULL, cmd ? cmd : NULL);
3144 		count++;
3145 	}
3146 #else
3147 	put_it("This command is disabled in this client");
3148 #endif
3149 }
3150 
3151 
rights(char * string,int num)3152 char *rights(char *string, int num)
3153 {
3154 	if (strlen(string) < num)
3155 		return string;
3156 	return (string + strlen(string) - num);
3157 }
3158 
numchar(char * string,char c)3159 int numchar(char *string, char c)
3160 {
3161 	int num = 0;
3162 
3163 	while (*string)
3164 	{
3165 		if (tolower(*string) == tolower(c))
3166 			num++;
3167 		string++;
3168 	}
3169 	return num;
3170 }
3171 
cluster(char * hostname)3172 char *cluster (char *hostname)
3173 {
3174 	static char result[IRCD_BUFFER_SIZE/4 + 1];
3175 	char temphost[BIG_BUFFER_SIZE + 1];
3176 	char *host;
3177 	char *atsign;
3178 
3179 	if (!hostname)
3180 		return NULL;
3181 
3182 	*result = 0;
3183 	atsign = strchr(hostname, '@');
3184 	if (atsign) {
3185 		if (*hostname == '~') {
3186 			strcpy(result, "~*@");
3187 		} else {
3188 			size_t ident_len = atsign - hostname;
3189 
3190 			if (ident_len <= 9) {
3191 				/* copy ident@ */
3192 				strncat(result, hostname, ident_len + 1);
3193 			} else {
3194 				strncat(result, hostname, 8);
3195 				strcat(result, "*@");
3196 			}
3197 		}
3198 		hostname = atsign + 1;
3199 	}
3200 
3201 	strlcpy(temphost, hostname, sizeof temphost);
3202 	host = temphost;
3203 
3204 	if (*host && isdigit((unsigned char)*(host + strlen(host) - 1)))
3205 	{
3206 		/* Thanks icebreak for this small patch which fixes this function */
3207                 int i;
3208                 char *tmp;
3209                 char count = 0;
3210 
3211                 tmp = host;
3212                 while((tmp - host) < strlen(host))
3213                 {
3214 	                if((tmp = strchr(tmp,'.')) == NULL)
3215 				break;
3216         	        count++;
3217                 	tmp++;
3218                 }
3219                 tmp = host;
3220                 for (i = 0; i < count; i++)
3221                         tmp = strchr(tmp, '.') + 1;
3222                 *tmp = '\0';
3223                 strlcat(result, host, sizeof result);
3224                 strlcat(result, "*", sizeof result);
3225 	}
3226 	else
3227 	{
3228 		char *tmp;
3229 		int num;
3230 
3231 		num = 1;
3232 		tmp = rights(host, 3);
3233 		if (my_stricmp(tmp, "com") &&
3234 		    my_stricmp(tmp, "edu") &&
3235 		    my_stricmp(tmp, "net") &&
3236 		    (stristr(host, "com") ||
3237 		     stristr(host, "edu")))
3238 			num = 2;
3239 		while (host && *host && (numchar(host, '.') > num))
3240 		{
3241 			if ((host = strchr(host, '.')) != NULL)
3242 				host++;
3243 			else
3244 				return (char *) NULL;
3245 		}
3246 
3247 		/* We don't need strlcat for these first two, because
3248 		 * at this point the maximum length of the string in
3249 		 * result is 11 */
3250 		strcat(result, "*");
3251 		if (my_stricmp(host, temphost))
3252 			strcat(result, ".");
3253 		strlcat(result, host, sizeof result);
3254 	}
3255 	return result;
3256 }
3257 
3258 
3259 
3260 
3261 struct _sock_manager
3262 {
3263 	int init;
3264 	int count;
3265 	int max_fd;
3266 	SocketList sockets[FD_SETSIZE];
3267 } sock_manager =  {0, 0, -1, {{ 0, 0, 0, NULL, 0, 0, NULL, NULL, NULL }}};
3268 
3269 #define SOCKET_TIMEOUT 120
3270 
3271 
3272 #ifdef GUI
checkmenu(MenuList * check,int menuid)3273 char *checkmenu(MenuList *check, int menuid)
3274 {
3275 MenuList *tmpml;
3276 MenuStruct *tmpms;
3277 char *tmpalias;
3278 
3279 	tmpml=check;
3280 	while(tmpml!=NULL)
3281 	{
3282 		if (tmpml->menutype==GUISUBMENU || tmpml->menutype==GUISHARED || tmpml->menutype==GUIBRKSUBMENU)
3283 		{
3284 			tmpms = (MenuStruct *)findmenu(tmpml->submenu);
3285 			if ((tmpalias=checkmenu(tmpms->menuorigin, menuid))!=NULL)
3286 				return tmpalias;
3287 		}
3288 		if (tmpml->menuid==menuid)
3289 			return tmpml->alias;
3290 		tmpml=tmpml->next;
3291 	}
3292 	return NULL;
3293 }
3294 
scan_gui(fd_set * rd)3295 void scan_gui(fd_set *rd)
3296 {
3297 	unsigned int guicmd[2];
3298 	extern MenuStruct *morigin;
3299 	extern unsigned long menucmd;
3300 	extern char *codeptr, *paramptr;
3301 	MenuStruct *tmpms;
3302 	int newpos, cursb;
3303 	char *alias;
3304 	Window *scrollwin, *newfocuswindow;
3305 	float bleah;
3306 	Screen *newfocusscreen;
3307 
3308 #ifdef __EMXPM__
3309 	extern int just_resized;
3310 	extern Screen *just_resized_screen;
3311 
3312 	if(just_resized == 1)
3313 		WinSendMsg(just_resized_screen->hwndFrame, 0x041e, 0, 0);
3314 #endif
3315 
3316 	/* Read the data from the pipe and decide what to do */
3317 	if(FD_ISSET(guiipc[0], rd))
3318 	{
3319 		read(guiipc[0], (void *)guicmd, sizeof(unsigned int) * 2);
3320 		switch(guicmd[0])
3321 		{
3322 		case EVMENU:
3323 			tmpms = morigin;
3324 			while(tmpms!=NULL)
3325 			{
3326 				if((alias=checkmenu(tmpms->menuorigin, menucmd))!=NULL)
3327 				{
3328 					int save_server = from_server;
3329 					Window *this_window = get_window_by_refnum((int)guicmd[1]);
3330 
3331 					if(this_window)
3332 						from_server = this_window->server;
3333 					make_window_current(this_window);
3334 					parse_line(NULL, alias, empty_string, 0, 0, 1);
3335 
3336 					from_server = save_server;
3337 					break;
3338 				}
3339 				tmpms=tmpms->next;
3340 			}
3341 			break;
3342 		case EVFOCUS:
3343 			gui_flush();
3344 			newfocuswindow=get_window_by_refnum((int)guicmd[1]);
3345 			if(newfocuswindow)
3346 				newfocusscreen=newfocuswindow->screen;
3347 			else
3348 				newfocusscreen=NULL;
3349 			if (newfocusscreen && newfocusscreen->current_window)
3350 			{
3351 				make_window_current(newfocusscreen->current_window);
3352 				output_screen=last_input_screen=newfocusscreen;
3353 				reset_display_target();
3354 				set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 1);
3355 			}
3356 			update_input(UPDATE_ALL);
3357 			break;
3358 		case EVTITLE:
3359 			xterm_settitle();
3360 			break;
3361 		case EVREFRESH:
3362 			refresh_window_screen(get_window_by_refnum((int)guicmd[1]));
3363 			break;
3364 		case EVSTRACK:
3365 			if(newscrollerpos != lastscrollerpos || lastscrollerwindow != (int)guicmd[1])
3366 			{
3367 				lastscrollerpos=newscrollerpos;
3368 				lastscrollerwindow=(int)guicmd[1];
3369 				scrollwin=get_window_by_refnum((int)guicmd[1]);
3370 				bleah = get_int_var(SCROLLBACK_VAR);
3371 				newpos = (int)(((bleah-newscrollerpos) / bleah) * (scrollwin->display_buffer_size - scrollwin->display_size)) + scrollwin->display_size;
3372 				cursb = scrollwin->distance_from_display;
3373 				if (newpos > cursb)
3374 					scrollback_backwards_lines(newpos-cursb);
3375 				if (newpos < cursb)
3376 					scrollback_forwards_lines(cursb-newpos);
3377 			}
3378 			break;
3379 		case EVSUP:
3380 			scrollback_backwards_lines(1);
3381 			break;
3382 		case EVSDOWN:
3383 			scrollback_forwards_lines(1);
3384 			break;
3385 		case EVSUPPG:
3386 			scrollback_backwards((char)NULL, NULL);
3387 			break;
3388 		case EVSDOWNPG:
3389 			scrollback_forwards((char)NULL, NULL);
3390 			break;
3391 		case EVKEY:
3392 			{
3393 				int old_server = from_server;
3394 
3395 				if(current_window)
3396 					from_server = current_window->server;
3397 
3398 				wm_process((int)guicmd[1]);
3399 
3400 				from_server = old_server;
3401 			}
3402 			break;
3403 		case EVFILE:
3404 			if(codeptr && *codeptr && paramptr)
3405 			{
3406 				make_window_current(get_window_by_refnum((int)guicmd[1]));
3407 				parse_line(NULL, codeptr, paramptr, 0, 0, 1);
3408 				new_free(&codeptr);
3409 				new_free(&paramptr);
3410 			}
3411 			break;
3412 #ifdef GTK
3413 		case EVPASTE:
3414 			gtk_main_paste((int)guicmd[1]);
3415 			break;
3416 		case EVDELETE:
3417 			scrollwin=get_window_by_refnum((int)guicmd[1]);
3418 			if(scrollwin && scrollwin->screen)
3419 				kill_screen(scrollwin->screen);
3420 			break;
3421 #endif
3422 		}
3423 	}
3424 }
3425 #endif
3426 
read_clonelist(int s)3427 void read_clonelist(int s)
3428 {
3429 char buffer[IRCD_BUFFER_SIZE + 1];
3430 char *str = buffer;
3431 	switch(dgets(str, s, 0, IRCD_BUFFER_SIZE, NULL))
3432 	{
3433 		case -1:
3434 		{
3435 			do_hook(SOCKET_LIST, "%d %s %d", s, sock_manager.sockets[s].server, sock_manager.sockets[s].port);
3436 			close_socketread(s);
3437 			break;
3438 		}
3439 		case 0:
3440 			break;
3441 		default:
3442 		{
3443 			if ((buffer[strlen(buffer)-1] == '\r') || (buffer[strlen(buffer)-1] == '\n'))
3444 				buffer[strlen(buffer)-1] = 0;
3445 			if ((buffer[strlen(buffer)-1] == '\r') || (buffer[strlen(buffer)-1] == '\n'))
3446 				buffer[strlen(buffer)-1] = 0;
3447 			if (*buffer)
3448 				do_hook(SOCKET_LIST, "%d %s %d %s", s, sock_manager.sockets[s].server, sock_manager.sockets[s].port, buffer);
3449 		}
3450 	}
3451 }
3452 
read_clonenotify(int s)3453 void read_clonenotify(int s)
3454 {
3455 unsigned long flags = 0;
3456 	flags = get_socketflags(s);
3457 	do_hook(SOCKET_NOTIFY_LIST, "%d %s %d %d", s, sock_manager.sockets[s].server, sock_manager.sockets[s].port, (unsigned int)flags);
3458 }
3459 
BX_set_socketflags(int s,unsigned long flags)3460 unsigned long BX_set_socketflags(int s, unsigned long flags)
3461 {
3462 	if (check_socket(s))
3463 	{
3464 		sock_manager.sockets[s].flags = flags;
3465 		return sock_manager.sockets[s].flags;
3466 	}
3467 	return 0;
3468 }
3469 
BX_get_socketflags(int s)3470 unsigned long BX_get_socketflags(int s)
3471 {
3472 	if (check_socket(s))
3473 		return sock_manager.sockets[s].flags;
3474 	return 0;
3475 }
3476 
get_socketserver(int s)3477 char *get_socketserver(int s)
3478 {
3479 	if (check_socket(s))
3480 		return sock_manager.sockets[s].server;
3481 	return NULL;
3482 }
3483 
BX_get_socketinfo(int s)3484 void *BX_get_socketinfo(int s)
3485 {
3486 	if (check_socket(s))
3487 		return sock_manager.sockets[s].info;
3488 	return NULL;
3489 }
3490 
BX_set_socketinfo(int s,void * info)3491 void BX_set_socketinfo(int s, void *info)
3492 {
3493 	if (check_socket(s))
3494 		sock_manager.sockets[s].info = info;
3495 }
3496 
BX_get_max_fd(void)3497 int BX_get_max_fd(void)
3498 {
3499 	return sock_manager.max_fd + 1;
3500 }
3501 
BX_add_socketread(int s,int port,unsigned long flags,char * server,void (* func_read)(int),void (* func_write)(int))3502 int BX_add_socketread(int s, int port, unsigned long flags, char *server, void (*func_read)(int), void (*func_write)(int))
3503 {
3504 	if (!sock_manager.init)
3505 	{
3506 		fd_set rd;
3507 		FD_ZERO(&rd);
3508 		set_socket_read(&rd, &rd);
3509 	}
3510 	if (s >= FD_SETSIZE)
3511 	{
3512 		yell("File descriptor limit reached, dropping new socket.");
3513 		close(s);
3514 		return -1;
3515 	}
3516 	if (s > sock_manager.max_fd)
3517 		sock_manager.max_fd = s;
3518 	sock_manager.count++;
3519 	sock_manager.sockets[s].is_read = s;
3520 	sock_manager.sockets[s].port = port;
3521 	sock_manager.sockets[s].flags = flags;
3522 	if (server)
3523 		sock_manager.sockets[s].server = m_strdup(server);
3524 	sock_manager.sockets[s].func_read = func_read;
3525 	sock_manager.sockets[s].func_write = func_write;
3526 	new_open(s);
3527 	return s;
3528 }
3529 
BX_set_socketwrite(int s)3530 int BX_set_socketwrite(int s)
3531 {
3532 	if (s >= FD_SETSIZE)
3533 		return -1;
3534 	if (s > sock_manager.max_fd)
3535 		sock_manager.max_fd = s;
3536 	sock_manager.sockets[s].is_write = s;
3537 	new_open_write(s);
3538 	return s;
3539 }
3540 
BX_add_sockettimeout(int s,time_t timeout,void * func)3541 void BX_add_sockettimeout(int s, time_t timeout, void *func)
3542 {
3543 	if (timeout < 0)
3544 	{
3545 		timeout = get_int_var(CONNECT_TIMEOUT_VAR);
3546 		if (timeout <= 0)
3547 			timeout = SOCKET_TIMEOUT;
3548 	}
3549 	if (timeout)
3550 		sock_manager.sockets[s].time = now + timeout;
3551 	else
3552 		sock_manager.sockets[s].time = 0;
3553 	sock_manager.sockets[s].cleanup = func;
3554 }
3555 
BX_close_socketread(int s)3556 void BX_close_socketread(int s)
3557 {
3558 	if (!sock_manager.count)
3559 		return;
3560 	if (sock_manager.sockets[s].is_read)
3561 	{
3562 		new_free(&sock_manager.sockets[s].server);
3563 		if (sock_manager.sockets[s].is_write)
3564 			new_close_write(s);
3565 		new_close(s);
3566 		memset(&sock_manager.sockets[s], 0, sizeof(SocketList));
3567 		sock_manager.count--;
3568 		if (s == sock_manager.max_fd)
3569 		{
3570 			int i;
3571 			sock_manager.max_fd = -1;
3572 			for (i = 0; i < FD_SETSIZE; i++)
3573 				if (sock_manager.sockets[i].is_read)
3574 					sock_manager.max_fd = i;
3575 				else if( sock_manager.sockets[i].is_write)
3576 					sock_manager.max_fd = i;
3577 		}
3578 	}
3579 }
3580 
BX_check_socket(int s)3581 int BX_check_socket(int s)
3582 {
3583 	if (s != -1 && sock_manager.count && sock_manager.sockets[s].is_read)
3584 		return 1;
3585 	return 0;
3586 }
3587 
check_dcc_socket(int s)3588 int check_dcc_socket(int s)
3589 {
3590 	if (sock_manager.count && sock_manager.sockets[s].is_read && sock_manager.sockets[s].info)
3591 	{
3592 		if ( ((dcc_struct_type *)sock_manager.sockets[s].info)->struct_type == DCC_STRUCT_TYPE)
3593 			return 1;
3594 	}
3595 	return 0;
3596 }
3597 
BX_write_sockets(int s,unsigned char * str,int len,int nl)3598 int BX_write_sockets(int s, unsigned char *str, int len, int nl)
3599 {
3600 	if (s < 1)
3601 		return -1;
3602 	if (nl)
3603 	{
3604 		unsigned char *buf;
3605 		buf = alloca(strlen(str)+4);
3606 		strcpy(buf, str);
3607 		strcat(buf, "\r\n");
3608 		len += 2;
3609 		return write(s, buf, len);
3610 	}
3611 	return write(s, str, len);
3612 }
3613 
BX_read_sockets(int s,unsigned char * str,int len)3614 int BX_read_sockets(int s, unsigned char *str, int len)
3615 {
3616 	if (s < 1)
3617 		return -1;
3618 	return read(s, str, len);
3619 }
3620 
set_socket_read(fd_set * rd,fd_set * wr)3621 void set_socket_read (fd_set *rd, fd_set *wr)
3622 {
3623 register int i;
3624 static int socket_init = 0;
3625 	if (!socket_init)
3626 	{
3627 		memset(&sock_manager, 0, sizeof(sock_manager));
3628 		socket_init++;
3629 		sock_manager.init++;
3630 	}
3631 	if (!sock_manager.count) return;
3632 	for (i = 0; i < sock_manager.max_fd + 1; i++)
3633 	{
3634 		if (sock_manager.sockets[i].is_read)
3635 			FD_SET(sock_manager.sockets[i].is_read, rd);
3636 		if (sock_manager.sockets[i].is_write)
3637 			FD_SET(sock_manager.sockets[i].is_write, wr);
3638 	}
3639 }
3640 
scan_sockets(fd_set * rd,fd_set * wr)3641 void scan_sockets(fd_set *rd, fd_set *wr)
3642 {
3643 register int i;
3644 time_t t = now;
3645 	if (!sock_manager.count) return;
3646 	for (i = 0; i < sock_manager.max_fd+1; i++)
3647 	{
3648 		if (sock_manager.sockets[i].is_read && FD_ISSET(sock_manager.sockets[i].is_read, rd))
3649 			(sock_manager.sockets[i].func_read) (sock_manager.sockets[i].is_read);
3650 		if (sock_manager.sockets[i].func_write && sock_manager.sockets[i].is_write && FD_ISSET(sock_manager.sockets[i].is_write, wr))
3651 			(sock_manager.sockets[i].func_write) (sock_manager.sockets[i].is_write);
3652 		if (sock_manager.sockets[i].time && (t >= sock_manager.sockets[i].time))
3653 		{
3654 			if (sock_manager.sockets[i].cleanup)
3655 				(sock_manager.sockets[i].cleanup)(i);
3656 			else
3657 				close_socketread(i);
3658 		}
3659 	}
3660 }
3661 
BX_get_socket(int s)3662 SocketList *BX_get_socket(int s)
3663 {
3664 	if (check_socket(s))
3665 		return &sock_manager.sockets[s];
3666 	return NULL;
3667 }
3668 
3669 extern int dgets_errno;
3670 
read_netfinger(int s)3671 void read_netfinger(int s)
3672 {
3673 char tmpstr[BIG_BUFFER_SIZE+1];
3674 register unsigned char *p = tmpstr;
3675 	*tmpstr = 0;
3676 	switch(dgets(tmpstr, s, 0, BIG_BUFFER_SIZE, NULL))
3677 	{
3678 		case 0:
3679 			break;
3680 		case -1:
3681 			if (do_hook(SOCKET_LIST, "%d %d %s Remote closed connection", s, sock_manager.sockets[s].port, sock_manager.sockets[s].server))
3682 			{
3683 				if (dgets_errno == -1)
3684 					bitchsay("Remote closed connection");
3685 			}
3686 			close_socketread(s);
3687 			break;
3688 		default:
3689 		{
3690 			chop(tmpstr, 1);
3691 			while (*p)
3692 			{
3693 				switch(*p)
3694 				{
3695 					case 0210:
3696 					case 0211:
3697 					case 0212:
3698 					case 0214:
3699 						*p -= 0200;
3700 						break;
3701 					case 0x9b:
3702 					case '\t':
3703 						break;
3704 					case '\n':
3705 					case '\r':
3706 						*p = '\0';
3707 						break;
3708 					default:
3709 						if (!isprint(*p))
3710 							*p = (*p & 0x7f) | 0x40;
3711 						break;
3712 				}
3713 				p++;
3714 			}
3715 			if (do_hook(SOCKET_LIST, "%d %d %s %s", s, sock_manager.sockets[s].port, sock_manager.sockets[s].server, tmpstr))
3716 				put_it("%s", tmpstr);
3717 		}
3718 	}
3719 }
3720 
netfinger(char * name)3721 void netfinger (char *name)
3722 {
3723 	char *host = NULL;
3724 	unsigned short port = 79;
3725 	int s;
3726 
3727 	if (name)
3728 	{
3729 		if ((host = strrchr(name, '@')))
3730 			*host++ = 0;
3731 		else
3732 			host = name;
3733 	}
3734 	if (!host || !*host)
3735 	{
3736 		say("Invalid @host or user@host.");
3737 		return;
3738 	}
3739 
3740 	if (name && *name)
3741 	{
3742 		if ((s = connect_by_number(host, &port, SERVICE_CLIENT, PROTOCOL_TCP, 1)) < 0)
3743 		{
3744 			bitchsay("Finger connect error on %s@%s", name?name:empty_string, host);
3745 			return;
3746 		}
3747 		if ((add_socketread(s, port, 0, name, read_netfinger, NULL)) > -1)
3748 		{
3749 			write_sockets(s, name, strlen(name), 1);
3750 			add_sockettimeout(s, 120, NULL);
3751 		} else
3752 			close_socketread(s);
3753 	}
3754 	return;
3755 }
3756 
start_finger(UserhostItem * stuff,char * nick,char * args)3757 void start_finger (UserhostItem *stuff, char *nick, char *args)
3758 {
3759 	char *finger_userhost = NULL;
3760 	char *str;
3761 	if (!stuff || !stuff->nick || !nick || !strcmp(stuff->user, "<UNKNOWN>") || my_stricmp(stuff->nick, nick))
3762 	{
3763 		say("No information for %s", nick);
3764 		return;
3765 	}
3766 	finger_userhost = m_opendup(stuff->user, "@", stuff->host, NULL);
3767 	str = finger_userhost;
3768 	str = clear_server_flags(finger_userhost);
3769 	say("Launching finger for %s (%s)", nick, finger_userhost);
3770 	netfinger(str);
3771 	new_free(&finger_userhost);
3772 }
3773 
BUILT_IN_COMMAND(finger)3774 BUILT_IN_COMMAND(finger)
3775 {
3776 	char *userhost;
3777 
3778 	if ((userhost = next_arg(args, &args)))
3779 	{
3780 		if (!strchr(userhost, '@'))
3781 		{
3782 			userhostbase(userhost, start_finger, 1, "%s", userhost);
3783 			return;
3784 		}
3785 		netfinger(userhost);
3786 	}
3787 }
3788 
handle_socket_connect(int rc)3789 static void handle_socket_connect(int rc)
3790 {
3791 struct servent *serv;
3792 struct sockaddr_foobar	addr;
3793 struct hostent *host;
3794 char buf[128], *hostname = buf;
3795         socklen_t             address_len;
3796 
3797 	address_len = sizeof(struct sockaddr_foobar);
3798         if ((getpeername(rc, (struct sockaddr *) &addr, &address_len)) != -1)
3799 	{
3800 		serv = getservbyport(addr.sf_port,"tcp");
3801 		strcpy(hostname, "unknown");
3802 		if (addr.sf_family == AF_INET)
3803 		{
3804 			address_len = sizeof(struct in_addr);
3805 			if ((host = gethostbyaddr((char *)&addr.sf_addr, address_len, AF_INET)))
3806 				hostname = (char *)host->h_name;
3807 			else
3808 				hostname = inet_ntoa(addr.sf_addr);
3809 		}
3810 #ifdef IPV6
3811 		else
3812 		{
3813 			if (getnameinfo((struct sockaddr*) &addr, sizeof(struct sockaddr_foobar), hostname, 128, NULL, 0, 0))
3814 				hostname = (char *)inet_ntop(AF_INET6, (void*) &(addr.sf_addr6), buf, 128);
3815 		}
3816 #endif
3817 		put_it("Hostname %s port %d is running (%s)", hostname, htons(addr.sf_port), serv == NULL? "UNKNOWN":serv->s_name);
3818 	}
3819 	close_socketread(rc);
3820 }
3821 
scan(char * remote_host,int low_port,int high_port,struct sockaddr_foobar * host)3822 static int scan(char *remote_host, int low_port, int high_port, struct sockaddr_foobar *host)
3823 {
3824 	unsigned short int port;
3825 	int rc;
3826 	if (low_port == 0) low_port = 1;
3827 	for (port = low_port;port <= high_port;port++)
3828 	{
3829 		if ((rc = connect_by_number(remote_host, &port, SERVICE_CLIENT, PROTOCOL_TCP, 1)) < 0)
3830 			continue;
3831 		if ((add_socketread(rc, port, 0, NULL, handle_socket_connect, NULL)) > -1)
3832 			add_sockettimeout(rc, 120, NULL);
3833 		else
3834 			close_socketread(rc);
3835 	}
3836 
3837 	return 1;
3838 }
3839 
userhost_scanport(UserhostItem * stuff,char * nick,char * args)3840 void userhost_scanport(UserhostItem *stuff, char *nick, char *args)
3841 {
3842 char	*t;
3843 int	low_port = 0,
3844 	high_port = 0;
3845 struct	sockaddr_foobar *host; /* gee, and what's this one for? */
3846 
3847         if (!stuff || !stuff->nick || !nick || !strcmp(stuff->user, "<UNKNOWN>") || my_stricmp(stuff->nick, nick))
3848         {
3849         	bitchsay("No such nick [%s] found", nick);
3850                 return;
3851         }
3852 	next_arg(args, &args);
3853 	t = next_arg(args, &args);
3854 	low_port = atol(t);
3855 	t = next_arg(args, &args);
3856 	high_port = atol(t);
3857 	if ((host = resolv(stuff->host)))
3858 	{
3859 		bitchsay("Scanning %s ports %d to %d", stuff->host, low_port, high_port);
3860 		scan(stuff->host, low_port, high_port, host);
3861 		return;
3862 	}
3863 	bitchsay("Cannot resolv host %s for %s", stuff->host, stuff->nick);
3864 }
3865 
BUILT_IN_COMMAND(findports)3866 BUILT_IN_COMMAND(findports)
3867 {
3868 char *remote_host;
3869 int low_port = 6660;
3870 int high_port = 7000;
3871 struct sockaddr_foobar *host;
3872 
3873 
3874 	if (args && *args)
3875 	{
3876 		char *tmp = NULL;
3877 		remote_host = next_arg(args, &args);
3878 		if (args && *args)
3879 		{
3880 			tmp = next_arg(args, &args);
3881 			low_port = strtoul(tmp, NULL, 10);
3882 			if (args && *args)
3883 			{
3884 				tmp = next_arg(args, &args);
3885 				high_port = strtoul(tmp, NULL, 10);
3886 			}
3887 			else
3888 				high_port = low_port;
3889 		}
3890 		if (strchr(remote_host, '.') || strchr(remote_host, ':'))
3891 		{
3892 			if ((host = resolv(remote_host)))
3893 			{
3894 				bitchsay("Scanning %s's tcp ports %d through %d",remote_host, low_port,high_port);
3895 				scan(remote_host, low_port, high_port, host);
3896 			} else
3897 				bitchsay("No such host %s", remote_host);
3898 		}
3899 		else
3900 			userhostbase(remote_host, userhost_scanport, 1, "%s %d %d", remote_host, low_port, high_port);
3901 	}
3902 	return;
3903 }
3904 
userhost_ignore(UserhostItem * stuff,char * nick1,char * args)3905 void userhost_ignore (UserhostItem *stuff, char *nick1, char *args)
3906 {
3907 	char *p, *arg;
3908 	char *nick = NULL, *user = NULL, *host = NULL;
3909 	int old_window_display;
3910 	char ignorebuf[BIG_BUFFER_SIZE+1];
3911 	Ignore *igptr, *igtmp;
3912 	WhowasList *whowas;
3913 
3914 	arg = next_arg(args, &args);
3915 	if (!stuff || !stuff->nick || !nick1 || !strcmp(stuff->user, "<UNKNOWN>") || my_stricmp(stuff->nick, nick1))
3916 	{
3917                 if ((whowas = check_whowas_nick_buffer(nick1, arg, 0)))
3918 		{
3919 			bitchsay("Using WhoWas info for %s of %s ", arg, nick1);
3920 			user = host; host = strchr(host, '@'); *host++ = 0;
3921 			nick = whowas->nicklist->nick;
3922 		}
3923 		else
3924 		{
3925 			say("No match for user %s", nick1);
3926 			return;
3927 		}
3928 	}
3929 	else
3930 	{
3931 		user = clear_server_flags(stuff->user);
3932 		host = stuff->host; nick = stuff->nick;
3933 	}
3934 	if (!arg || !*arg || !my_stricmp(arg, "+HOST"))
3935 		sprintf(ignorebuf, "*!*@%s ALL -CRAP -PUBLIC", cluster(host));
3936 	else if (!my_stricmp(arg, "+USER"))
3937 		sprintf(ignorebuf, "*%s@%s ALL -CRAP -PUBLIC", user, cluster(host));
3938 	else if (!my_stricmp(arg, "-USER") || !my_stricmp(arg, "-HOST"))
3939 	{
3940 		int found = 0;
3941 		if (!my_stricmp(arg, "-HOST"))
3942 			sprintf(ignorebuf, "*!*@%s", cluster(host));
3943 		else
3944 			sprintf(ignorebuf, "%s!%s@%s", nick, user, host);
3945 		igptr = ignored_nicks;
3946 		while (igptr != NULL)
3947 		{
3948 			igtmp = igptr->next;
3949 			if (wild_match(igptr->nick, ignorebuf) ||
3950 			    wild_match(nick, igptr->nick))
3951 			{
3952 				sprintf(ignorebuf, "%s NONE", igptr->nick);
3953 				old_window_display = window_display;
3954 				window_display = 0;
3955 				ignore(NULL, ignorebuf, ignorebuf, NULL);
3956 				window_display = old_window_display;
3957 				bitchsay("Unignored %s!%s@%s", nick, user, host);
3958 				found++;
3959 			}
3960 			igptr = igtmp;
3961 		}
3962 		if (!found)
3963 			bitchsay("No ignore matching %s found", nick);
3964 		return;
3965 	}
3966 	old_window_display = window_display;
3967 	window_display = 0;
3968 	ignore(NULL, ignorebuf, ignorebuf, NULL);
3969 	if ((arg = next_arg(args, &args)))
3970 	{
3971 		char tmp[BIG_BUFFER_SIZE+1];
3972 		sprintf(tmp, "%s ^IGNORE %s NONE", arg, ignorebuf);
3973 		timercmd("TIMER", tmp, NULL, NULL);
3974 	}
3975 	window_display = old_window_display;
3976 	if ((p = strchr(ignorebuf, ' ')))
3977 		*p = 0;
3978 	say("Now ignoring ALL except CRAP and PUBLIC from %s", ignorebuf);
3979 	return;
3980 }
3981 
BUILT_IN_COMMAND(reset)3982 BUILT_IN_COMMAND(reset)
3983 {
3984 	refresh_screen(0, NULL);
3985 }
3986 
3987 
3988 extern char *channel_key (char *);
BUILT_IN_COMMAND(cycle)3989 BUILT_IN_COMMAND(cycle)
3990 {
3991 	char *to = NULL;
3992 	int server = from_server;
3993 	ChannelList *chan;
3994 
3995 	if (args && *args)
3996 		to = make_channel(next_arg(args, &args));
3997 
3998 	if (!(chan = prepare_command(&server, to, NO_OP)))
3999 		return;
4000 	my_send_to_server(server, "PART %s\nJOIN %s%s%s", chan->channel, chan->channel, chan->key?space:empty_string, chan->key?chan->key:empty_string);
4001 }
4002 
4003 
do_newuser(char * command,char * args,char * subargs)4004 int do_newuser(char *command, char *args, char *subargs)
4005 {
4006 char *newusername = NULL;
4007 	if ((newusername = next_arg(args, &args)))
4008 	{
4009 #ifdef IDENT_FAKE
4010 		FILE *outfile;
4011 		char *p = NULL, *q = NULL;
4012 		malloc_sprintf(&p, "~/%s", get_string_var(IDENT_HACK_VAR));
4013 		q = expand_twiddle(p);
4014 		if (!(outfile = fopen(q,"w")))
4015 			return 0;
4016 #ifdef CIDENTD
4017 		fprintf(outfile,"hideme\nmynameis %s\n", newusername);
4018 #else
4019 		fprintf(outfile,"%s", newusername);
4020 #endif
4021 		fclose(outfile);
4022 #endif
4023 		strlcpy(username, newusername, sizeof username);
4024 		if (subargs && *subargs)
4025                         strlcpy(realname, subargs, sizeof realname);
4026 #ifdef IDENT_FAKE
4027 		new_free(&p); new_free(&q);
4028 #endif
4029 		reconnect_cmd(NULL, newusername, NULL, NULL);
4030 	}
4031 	else
4032 		return 0;
4033 	return 1;
4034 }
4035 
BUILT_IN_COMMAND(newnick)4036 BUILT_IN_COMMAND(newnick)
4037 {
4038 	char *newnick, *newusername;
4039 
4040 	if ((newnick = next_arg(args, &args)) &&
4041 	    (newusername = next_arg(args, &args)))
4042 		do_newuser(newnick, newusername, args);
4043 	else
4044 		say("You must specify a nick and username");
4045 }
4046 
4047 
BUILT_IN_COMMAND(newuser)4048 BUILT_IN_COMMAND(newuser)
4049 {
4050 	char *newusername;
4051 
4052 	if ((newusername = next_arg(args, &args)))
4053 	{
4054 		if ((do_newuser(NULL, newusername, args)))
4055 			say("You must specify a username.");
4056 	}
4057 }
4058 
BUILT_IN_COMMAND(do_ig)4059 BUILT_IN_COMMAND(do_ig)
4060 {
4061 	char *nick;
4062 	char ignore_type[6];
4063 	int got_ignore_type = 0;
4064 	int need_time = 0;
4065 	if (!args || !*args)
4066 		goto bad_ignore;
4067 
4068 	while ((nick = next_arg(args, &args)))
4069 	{
4070 		if (!nick || !*nick)
4071 			goto bad_ignore;
4072 		if (*nick == '-' || *nick == '+')
4073 		{
4074 			if (!my_stricmp(nick, "-USER") || !my_stricmp(nick, "+HOST") || !my_stricmp(nick, "+USER") || !my_stricmp(nick, "-HOST"))
4075 				strcpy(ignore_type, nick);
4076 			if (!args || !*args)
4077 				goto bad_ignore;
4078 			got_ignore_type++;
4079 			continue;
4080 		}
4081 		else if (!got_ignore_type)
4082 		{
4083 			if (command && !my_strnicmp(command, "IGH",3))
4084 				strcpy(ignore_type, "+HOST");
4085 			else if (command && !my_strnicmp(command, "IG",2))
4086 				strcpy(ignore_type, "+USER");
4087 			if (command && !my_strnicmp(command, "UNIGH", 5))
4088 				strcpy(ignore_type, "-HOST");
4089 			else if (command && !my_strnicmp(command, "UNIG", 4))
4090 				strcpy(ignore_type, "-USER");
4091 			if (command && toupper(command[strlen(command)-1]) == 'T')
4092 				need_time ++;
4093 		}
4094 		if (need_time)
4095 			userhostbase(nick, userhost_ignore, 1, "%s %d", ignore_type, get_int_var(IGNORE_TIME_VAR));
4096 		else
4097 			userhostbase(nick, userhost_ignore, 1, "%s", ignore_type);
4098 	}
4099 bad_ignore:
4100 	return;
4101 }
4102 
put_user(const NickList * nick,const char * channel)4103 void put_user(const NickList *nick, const char *channel)
4104 {
4105 	char *users_format;
4106 
4107 	if (nick->userlist)
4108 		users_format = fget_string_var(FORMAT_USERS_USER_FSET);
4109 	else if (nick->shitlist)
4110 		users_format = fget_string_var(FORMAT_USERS_SHIT_FSET);
4111 	else
4112 		users_format = fget_string_var(FORMAT_USERS_FSET);
4113 
4114 	put_it("%s", convert_output_format(users_format, "%s %s %s %s %d %c",
4115 #ifdef WANT_USERLIST
4116 		nick->userlist ? convert_flags(nick->userlist->flags) : nick->shitlist?ltoa(nick->shitlist->level):"n/a",
4117 #else
4118 		"n/a",
4119 #endif
4120 		channel, nick->nick,
4121 		nick->host, nick->serverhops,
4122 		nick_isop(nick) ? '@' : nick_isvoice(nick)? 'v' : ' '));
4123 }
4124 
BUILT_IN_COMMAND(users)4125 BUILT_IN_COMMAND(users)
4126 {
4127 ChannelList *chan;
4128 NickList *nicks;
4129 NickList *sortl = NULL;
4130 char	*to = NULL,
4131 	*spec = "*!*@*",
4132 	*temp1 = NULL;
4133 char	modebuf[BIG_BUFFER_SIZE + 1];
4134 char	msgbuf[BIG_BUFFER_SIZE +1];
4135 int	count = 0,
4136 	ops = 0,
4137 	msg = 0,
4138 	num_kicks = 0,
4139 	hook = 0,
4140 	not =  0,
4141 	server = from_server,
4142 	sorted = NICKSORT_NORMAL;
4143 
4144 	*msgbuf = 0;
4145 	*modebuf = 0;
4146 
4147 	while (args && *args)
4148 	{
4149 		if (!args || !*args)
4150 			break;
4151 		temp1 = next_arg(args, &args);
4152 		if (temp1 && *temp1 == '-')
4153 		{
4154 			if (!my_strnicmp(temp1, "-ops", strlen(temp1)))
4155 				ops = 1;
4156 			else if (!my_strnicmp(temp1, "-nonops", strlen(temp1)))
4157 				ops = 2;
4158 			else if (!my_strnicmp(temp1, "-msg", strlen(temp1)))
4159 				msg = 1;
4160 			else if (!my_strnicmp(temp1, "-notice", strlen(temp1)))
4161 				msg = 2;
4162 			else if (!my_strnicmp(temp1, "-nkill", strlen(temp1)))
4163 				msg = 3;
4164 			else if (!my_strnicmp(temp1, "-kill", strlen(temp1)))
4165 				msg = 4;
4166 			else if (!my_strnicmp(temp1, "-kick", strlen(temp1)))
4167 				msg = 5;
4168 			else if (!my_strnicmp(temp1, "-stats", strlen(temp1)))
4169 				msg = 6;
4170 			else if (!my_strnicmp(temp1, "-ips", strlen(temp1)))
4171 				msg = 7;
4172 			else if (!my_strnicmp(temp1, "-sort", strlen(temp1)) && args && *args)
4173 			{
4174 				if (!my_strnicmp(args, "none", 4))
4175 					sorted = NICKSORT_NONE;
4176 				else if (!my_strnicmp(args, "host", 4))
4177 					sorted = NICKSORT_HOST;
4178 				else if (!my_strnicmp(args, "nick", 4))
4179 					sorted = NICKSORT_NICK;
4180 				else if (!my_strnicmp(args, "ip", 3))
4181 					sorted = NICKSORT_IP;
4182 				else if (!my_strnicmp(args, "time", 3))
4183 					sorted = NICKSORT_TIME;
4184 				if (sorted != NICKSORT_NORMAL)
4185 					next_arg(args, &args);
4186 			}
4187 			else if (strpbrk(temp1, "*!@."))
4188 			{
4189 				spec = temp1+1;
4190 				not = 1;
4191 			}
4192 		}
4193 		else if (temp1 && is_channel(temp1))
4194 			to = temp1;
4195 		else if (temp1 && strpbrk(temp1, "*!@."))
4196 			spec = temp1;
4197 		else
4198 		{
4199 			if (args && *args)
4200 				temp1[strlen(temp1)] = ' ';
4201 			args = temp1;
4202 			break;
4203 		}
4204 	}
4205 	if (!spec || !*spec)
4206 		spec = "*!*@*";
4207 	if (!(chan = prepare_command(&server, to, NO_OP)))
4208 	{
4209 		bitchsay(to?"Not on that channel %s":"No such channel %s", to?to:empty_string);
4210 		return;
4211 	}
4212 	set_display_target(chan->channel, LOG_CRAP);
4213 	if (command && !my_stricmp(command, "CHOPS"))
4214 		ops = 1;
4215 	if (command && !my_stricmp(command, "NOPS"))
4216 		ops = 2;
4217 
4218 	if ((msg == 1 || msg == 2) && (!args || !*args))
4219 	{
4220 		say("No message given");
4221 		reset_display_target();
4222 		return;
4223 	}
4224 
4225 	switch (msg)
4226 	{
4227 		case 6:
4228 			if (do_hook(STAT_HEADER_LIST, "%s %s %s %s %s", "Nick", "dops", "kicks","nicks","publics"))
4229 				put_it("Nick        dops  kicks  nicks  publics");
4230 			break;
4231 		case 0:
4232 		{
4233 			char *f;
4234 			if ((f = fget_string_var(FORMAT_USERS_TITLE_FSET)))
4235 				put_it("%s", convert_output_format(f, "%s %s", update_clock(GET_TIME), chan->channel));
4236 		}
4237 		default:
4238 			break;
4239 	}
4240 
4241 	sortl = sorted_nicklist(chan, sorted);
4242 	for (nicks = sortl; nicks; nicks = nicks->next)
4243 	{
4244 		sprintf(modebuf, "%s!%s", nicks->nick,
4245 		      nicks->host ? nicks->host : "<UNKNOWN@UNKNOWN>");
4246 		if (msg == 7 && nicks->ip)
4247 		{
4248 			strcat(modebuf, space);
4249 			strcat(modebuf, nicks->ip);
4250 		}
4251 		if (((!not && wild_match(spec, modebuf)) || (not && !wild_match(spec, modebuf))) &&
4252 					(!ops ||
4253 					 ((ops == 1) && nick_isop(nicks)) ||
4254 					 ((ops == 2) && !nick_isop(nicks)) ))
4255 		{
4256 			switch(msg)
4257 			{
4258 				case 3: /* nokill */
4259 					count--;
4260 					break;
4261 				case 4: /* kill */
4262 				{
4263 					if (!isme(nicks->nick))
4264 						my_send_to_server(server, "KILL %s :%s (%i", nicks->nick,
4265 							       args && *args ? args : get_reason(nicks->nick, NULL),
4266 							       count + 1);
4267 					else
4268 						count--;
4269 					break;
4270 				}
4271 				case 5:	 /* mass kick */
4272 				{
4273 					if (!isme(nicks->nick))
4274 					{
4275 						if (*msgbuf)
4276 							strcat(msgbuf, ",");
4277 						strcat(msgbuf, nicks->nick);
4278 						num_kicks++;
4279 					} else
4280 						count--;
4281 					if ((get_int_var(NUM_KICKS_VAR) && (num_kicks == get_int_var(NUM_KICKS_VAR))) || strlen(msgbuf) >= 450)
4282 					{
4283 						my_send_to_server(server, "KICK %s %s :%s", chan->channel,
4284 							       msgbuf, (args && *args) ? args :
4285 							       "-=punt=-");
4286 						*msgbuf = 0;
4287 						num_kicks = 0;
4288 					}
4289 					break;
4290 				}
4291 				case 6:
4292 				{
4293 					if (!isme(nicks->nick))
4294 					{
4295 						if (do_hook(STAT_LIST, "%s %d %d %d %d", nicks->nick, nicks->dopcount, nicks->kickcount,
4296 							nicks->nickcount, nicks->floodcount))
4297 							put_it("%-10s  %4d   %4d   %4d     %4d",
4298 								nicks->nick, nicks->dopcount, nicks->kickcount,
4299 								nicks->nickcount, nicks->floodcount);
4300 					}
4301 					break;
4302 				}
4303 				case 7:
4304 					if (do_hook(USERS_IP_LIST, "%s %s %s", nicks->nick, nicks->host, nicks->ip?nicks->ip:"Unknown"))
4305 						put_it("%s!%s = %s", nicks->nick, nicks->host, nicks->ip?nicks->ip:"Unknown");
4306 					break;
4307 				case 1:
4308 				case 2:
4309 				{
4310 					if (*msgbuf)
4311 						strcat(msgbuf, ",");
4312 					strcat(msgbuf, nicks->nick);
4313 					if (strlen(msgbuf)+strlen(args) >= 490)
4314 					{
4315 						put_it("%s", convert_output_format(fget_string_var((msg == 1)?FORMAT_SEND_MSG_FSET:FORMAT_SEND_NOTICE_FSET), "%s %s %s %s", update_clock(GET_TIME),msgbuf, get_server_nickname(from_server), args));
4316 						my_send_to_server(server, "%s %s :%s", (msg == 1) ? "PRIVMSG" : "NOTICE", msgbuf, args);
4317 						*msgbuf = 0;
4318 					}
4319 					break;
4320 				}
4321 				default:
4322 				{
4323 					if (!count && do_hook(USERS_HEADER_LIST, "%s %s %s %s %s %s %s", "Level", "aop", "prot", "Channel", "Nick", "+o", "UserHost") && fget_string_var(FORMAT_USERS_HEADER_FSET))
4324 						put_it("%s", convert_output_format(fget_string_var(FORMAT_USERS_HEADER_FSET), "%s", chan->channel));
4325 
4326 					if ((hook = do_hook(USERS_LIST, "%lu %s %s %s %d %c",
4327 						nicks->userlist ? nicks->userlist->flags:nicks->shitlist?nicks->shitlist->level:0,
4328 						chan->channel, nicks->nick,
4329 						nicks->host, nicks->serverhops,
4330 						nick_isop(nicks) ? '@' : nick_isvoice(nicks) ? 'v' :' ')))
4331 					{
4332 						put_user(nicks, chan->channel);
4333 					}
4334 				}
4335 			}
4336 			count++;
4337 		}
4338 		else if (msg == 3)
4339 		{
4340 			count++;
4341 			if (!isme(nicks->nick))
4342 			{
4343 				my_send_to_server(server, "KILL %s :%s (%i", nicks->nick,
4344 					       args && *args ? args : get_reason(nicks->nick, NULL),
4345 					       count);
4346 			}
4347 			else
4348 				count--;
4349 		}
4350 	}
4351 	clear_sorted_nicklist(&sortl);
4352 	if (!msg && do_hook(USERS_FOOTER_LIST, "%s", "End of Users"))
4353 		;
4354 	else if (msg == 6 && do_hook(STAT_FOOTER_LIST, "%s", "End of stats"))
4355 		;
4356 	else if (!count)
4357 	{
4358 		if (chan)
4359 		{
4360 			if (!command)
4361 				say("No match of %s on %s", spec, chan->channel);
4362 			else
4363 				say("There are no [\002%s\002] on %s", command, chan->channel);
4364 		}
4365 	}
4366 	else if (!msg && !hook)
4367 		bitchsay("End of UserList on %s %d counted", chan->channel, count);
4368 
4369 	if (count && *msgbuf)
4370 	{
4371 		switch(msg)
4372 		{
4373 			case 1:
4374 			case 2:
4375 			{
4376 				put_it("%s", convert_output_format(fget_string_var((msg == 1)?FORMAT_SEND_MSG_FSET:FORMAT_SEND_NOTICE_FSET), "%s %s %s %s", update_clock(GET_TIME),msgbuf, get_server_nickname(from_server), args));
4377 				my_send_to_server(server, "%s %s :%s", (msg == 1) ? "PRIVMSG" : "NOTICE", msgbuf, args);
4378 				break;
4379 			}
4380 			case 5:
4381 			{
4382 				if (chan)
4383 				my_send_to_server(server, "KICK %s %s :%s", chan->channel,
4384 					       msgbuf, (args && *args) ? args : "-=punt=-");
4385 			}
4386 			default:
4387 				break;
4388 		}
4389 	}
4390 	reset_display_target();
4391 
4392 }
4393 
caps_fucknut(register unsigned char * crap)4394 int caps_fucknut (register unsigned char *crap)
4395 {
4396 	int total = 0, allcaps = 0;
4397 /* removed from ComStud client */
4398 	while (*crap)
4399 	{
4400 		if (isalpha(*crap))
4401 		{
4402 			total++;
4403 			if (isupper(*crap))
4404 				allcaps++;
4405 		}
4406 		crap++;
4407 	}
4408 	if (total > 12)
4409 	{
4410 		if ( ((unsigned int)(((float) allcaps / (float) total) * 100) >= 75))
4411 			return (1);
4412 	}
4413 	return (0);
4414 }
4415 
char_fucknut(register unsigned char * crap,char looking,int max)4416 int char_fucknut (register unsigned char *crap, char looking, int max)
4417 {
4418 	int total = strlen(crap), allchar = 0;
4419 
4420 	while (*crap)
4421 	{
4422 		if ((*crap == looking))
4423 		{
4424 			crap++;
4425 			while(*crap && *crap != looking)
4426 			{
4427 				allchar++;
4428 				crap++;
4429 			}
4430 		}
4431 		if (*crap)
4432 			crap++;
4433 	}
4434 	if (total > 12)
4435 	{
4436 		if ( ((unsigned int)(((float) allchar / (float) total) * 100)) >= 75)
4437 			return (1);
4438 	}
4439 	return (0);
4440 }
4441 
4442 
make_timestamp(int do_timestamp,char * timestr)4443 static char *make_timestamp(int do_timestamp, char *timestr)
4444 {
4445 static char time_str[61];
4446 	if (do_timestamp && timestr)
4447 	{
4448 		struct tm timeval;
4449 		*time_str = 0;
4450 		timeval = *localtime(&now);
4451 		strftime(time_str, 60, timestr, &timeval);
4452 		return time_str;
4453 	}
4454 	return empty_string;
4455 }
4456 
4457 static int cparse_recurse = -1;
4458 #ifndef BITCHX_LITE
4459 #define MAX_RECURSE 5
4460 #else
4461 #define MAX_RECURSE 3
4462 #endif
4463 #define RECURSE_CPARSE
4464 
4465 /* One buffer for each recursive invocation.  We also keep track of the
4466  * buffer size, so that it can be resized when necessary.
4467  */
4468 static char *cof_buffer[MAX_RECURSE + 1] = { NULL };
4469 static size_t cof_buffer_sz[MAX_RECURSE + 1 ] = { 0 };
4470 #define COF_BUFFER_HEADROOM 100
4471 #define COF_BUFFER_FREE(p) (cof_buffer[cparse_recurse] + cof_buffer_sz[cparse_recurse] - (p))
4472 
convert_output_format_raw(const char * format,const char * str,va_list args)4473 char *convert_output_format_raw(const char *format, const char *str, va_list args)
4474 {
4475 char buffer2[5*BIG_BUFFER_SIZE+1];
4476 enum color_attributes this_color = BLACK;
4477 char *s;
4478 char *copy = NULL;
4479 char *tmpc = NULL;
4480 register char *p;
4481 int old_who_level = who_level;
4482 int bold = 0;
4483 
4484 #ifdef WANT_CHELP
4485 extern int in_chelp;
4486 #endif
4487 
4488 int arg_flags;
4489 char color_mod[] = "kbgcrmywKBGCRMYWn";
4490 char *c_mod = color_mod;
4491 int do_timestamp = get_int_var(TIMESTAMP_VAR);
4492 char *timestamp_str = get_string_var(TIMESTAMP_STRING_VAR);
4493 
4494 	if (!format)
4495 		return empty_string;
4496 	copy = LOCAL_COPY(format);
4497 
4498 
4499     cparse_recurse++;
4500 
4501 	if (cparse_recurse > MAX_RECURSE)
4502 	{
4503 		yell("cparse_recurse() recursed too many times!  this should never happen!");
4504 		return empty_string;
4505 	}
4506 
4507 	*buffer2 = 0;
4508 	if (str)
4509 	{
4510 		memset(buffer2, 0, sizeof buffer2);
4511 		p = (char *)str;
4512 		while(p && *p)
4513 		{
4514 			if (*p == '%')
4515 			{
4516 				switch(*++p)
4517 				{
4518 				case 's':
4519 				{
4520 					char *q, *s = (char *)va_arg(args, char *);
4521 #ifdef RECURSE_CPARSE
4522 					char buff[(5 * BIG_BUFFER_SIZE)+1];
4523 					q = buff;
4524 					while (s && *s)
4525 					{
4526 						if (*s == '%')
4527 							*q++ = '%';
4528 						else if (*s == '$')
4529 							*q++ = '$';
4530 						*q++ = *s++;
4531 					}
4532 					*q = 0;
4533 					if (*buff)
4534 						strcat(buffer2, buff);
4535 #else
4536 					if (s)
4537 						strcat(buffer2, s);
4538 #endif
4539 					break;
4540 				}
4541 				case 'd':
4542 				{
4543 					int d = (int) va_arg(args, int);
4544 					strlcat(buffer2, ltoa((long)d), 5 * BIG_BUFFER_SIZE);
4545 					break;
4546 				}
4547 				case 'c':
4548 				{
4549 					char c = (char )va_arg(args, int);
4550 #ifdef RECURSE_CPARSE
4551                     if (c == '%')
4552                         buffer2[strlen(buffer2)] = '%';
4553                     else if (c == '$')
4554                         buffer2[strlen(buffer2)] = '$';
4555 #endif
4556 					buffer2[strlen(buffer2)] = c;
4557 					break;
4558 				}
4559 				case 'u':
4560 				{
4561 					unsigned int d = (unsigned int) va_arg(args, unsigned int);
4562 					strlcat(buffer2, ltoa(d), 5 * BIG_BUFFER_SIZE);
4563 					break;
4564 				}
4565 				case 'l':
4566 				{
4567 					unsigned long d = (unsigned long) va_arg(args, unsigned long);
4568 					strlcat(buffer2, ltoa(d), 5 * BIG_BUFFER_SIZE);
4569 					break;
4570 				}
4571 				case '%':
4572 				{
4573 					buffer2[strlen(buffer2)] = '%';
4574 					p++;
4575 					break;
4576 				}
4577 				default:
4578 					strlcat(buffer2, "%", 5 * BIG_BUFFER_SIZE);
4579 					buffer2[strlen(buffer2)] = *p;
4580 				}
4581 				p++;
4582 			}
4583 			else
4584 			{
4585 				buffer2[strlen(buffer2)] = *p;
4586 				p++;
4587 			}
4588 		}
4589 	}
4590 	else if (str)
4591 		strlcpy(buffer2, str, 5 * BIG_BUFFER_SIZE);
4592 
4593     if (!cof_buffer[cparse_recurse])
4594     {
4595         cof_buffer_sz[cparse_recurse] = BIG_BUFFER_SIZE;
4596         cof_buffer[cparse_recurse] = new_malloc(cof_buffer_sz[cparse_recurse]);
4597     }
4598 
4599 	s = cof_buffer[cparse_recurse];
4600     *s = 0;
4601 
4602 	tmpc = copy;
4603 	if (!tmpc)
4604 		goto done;
4605 	while (*tmpc)
4606 	{
4607         /* Ensure some headroom is available in the buffer */
4608         if (COF_BUFFER_FREE(s) < COF_BUFFER_HEADROOM)
4609         {
4610             size_t s_pos = s - cof_buffer[cparse_recurse];
4611 
4612             cof_buffer_sz[cparse_recurse] += BIG_BUFFER_SIZE;
4613             RESIZE(cof_buffer[cparse_recurse], char, cof_buffer_sz[cparse_recurse]);
4614 
4615             s = cof_buffer[cparse_recurse] + s_pos;
4616         }
4617 
4618 		if (*tmpc == '%')
4619 		{
4620 			char *cs;
4621 			tmpc++;
4622 			this_color = BLACK;
4623 			if (*tmpc == '\0')
4624 			{
4625 				*s++ = '%';
4626 				continue;
4627 			}
4628 			if (*tmpc == '%')
4629 			{
4630 				*s++ = *tmpc++;
4631 				continue;
4632 			}
4633 			if (isdigit((unsigned char)*tmpc))
4634 			{
4635 				char background_mod[] = "01234567";
4636 				char *blah = background_mod;
4637 				if ((cs = strchr(background_mod, *tmpc)))
4638 				{
4639 					this_color = (cs - blah) + (bold ? BACK_BBLACK : BACK_BLACK);
4640 					bold = 0;
4641 				}
4642 				else if (*tmpc == '8')
4643 				{
4644 					this_color = REVERSE_COLOR;
4645 					bold = 0;
4646 				}
4647 				else
4648 				{
4649 					this_color = BOLD_COLOR;
4650 					bold ^= 1;
4651 				}
4652 			}
4653 			else if ((cs = strchr(color_mod, *tmpc)))
4654 				this_color = (cs - c_mod);
4655 			else if (*tmpc == 'F')
4656 				this_color = BLINK_COLOR;
4657 			else if (*tmpc == 'U')
4658 				this_color = UNDERLINE_COLOR;
4659 			else if (*tmpc == 'A')
4660 				this_color = (int) (((float)UNDERLINE_COLOR * rand())/RAND_MAX);
4661 			else if (*tmpc == 'P')
4662 				this_color = MAGENTAB;
4663 			else if (*tmpc == 'p')
4664 				this_color = MAGENTA;
4665 			else if (*tmpc == '@')
4666 			{
4667 				strlcpy(s, make_timestamp(do_timestamp, timestamp_str), COF_BUFFER_FREE(s));
4668 				while(*s) s++;
4669 				tmpc++;
4670 				continue;
4671 			}
4672 #if 1
4673 /* do we really wanna do this? */
4674 			else if (*tmpc == '^') /* ibmpc charset */
4675 			{
4676 				strlcpy(s, "\033(U", COF_BUFFER_FREE(s));
4677 				while(*s) s++;
4678 				tmpc++;
4679 				continue;
4680 			}
4681 			else if (*tmpc == '&') /* latin1 charset */
4682 			{
4683 				strlcpy(s, "\033(B", COF_BUFFER_FREE(s));
4684 				while(*s) s++;
4685 				tmpc++;
4686 				continue;
4687 			}
4688 			else if (*tmpc == '$') /* custom charset */
4689 			{
4690 				strlcpy(s, "\033(K", COF_BUFFER_FREE(s));
4691 				while(*s) s++;
4692 				tmpc++;
4693 				continue;
4694 			}
4695 #endif
4696 			else
4697 			{
4698 				*s++ = *tmpc;
4699 				continue;
4700 			}
4701 			strlcpy(s, color_str[this_color], COF_BUFFER_FREE(s));
4702 			while (*s) s++;
4703 			tmpc++;
4704 			continue;
4705 		}
4706 		else if (*tmpc == '$' && !in_chelp && cparse_recurse < MAX_RECURSE)
4707 		{
4708 			char *new_str = NULL;
4709 			tmpc++;
4710 			if (*tmpc == '\0')
4711 			{
4712 				*s++ = '$';
4713 				continue;
4714 			}
4715 			if (*tmpc == '$')
4716 			{
4717 				*s++ = *tmpc++;
4718 				continue;
4719 			}
4720 
4721 			in_cparse++;
4722 			tmpc = alias_special_char(&new_str, tmpc, buffer2, NULL, &arg_flags);
4723 			in_cparse--;
4724 
4725 			if (new_str)
4726             {
4727                 char *subformat;
4728 #ifdef RECURSE_CPARSE
4729 				subformat = convert_output_format_raw((const char *)new_str, NULL, VA_NULL);
4730 #else
4731                 subformat = new_str;
4732 #endif
4733                 /* Ensure sufficient buffer space */
4734                 if (COF_BUFFER_FREE(s) < strlen(subformat) + 1)
4735                 {
4736                     size_t s_pos = s - cof_buffer[cparse_recurse];
4737 
4738                     cof_buffer_sz[cparse_recurse] += BIG_BUFFER_SIZE + strlen(subformat);
4739                     RESIZE(cof_buffer[cparse_recurse], char, cof_buffer_sz[cparse_recurse]);
4740 
4741                     s = cof_buffer[cparse_recurse] + s_pos;
4742                 }
4743 
4744 				strlcpy(s, subformat, COF_BUFFER_FREE(s));
4745 			    new_free(&new_str);
4746 			    while (*s) { s++; }
4747             }
4748 			if (!tmpc) break;
4749 			continue;
4750 		} else
4751 			*s = *tmpc;
4752 		tmpc++; s++;
4753 	}
4754 	*s = 0;
4755 
4756 done:
4757 	s = cof_buffer[cparse_recurse];
4758 	who_level = old_who_level;
4759 	cparse_recurse--;
4760 
4761 	return s;
4762 }
4763 
BX_convert_output_format(const char * format,const char * str,...)4764 char *BX_convert_output_format(const char *format, const char *str, ...)
4765 {
4766 	char *s;
4767 	int old_alias_debug = alias_debug;
4768 	va_list args;
4769 
4770 	alias_debug = 0;
4771 	va_start(args, str);
4772 	s = convert_output_format_raw(format, str, args);
4773 	va_end(args);
4774 	if (*s)
4775 		strcat(s, color_str[NO_COLOR]);
4776 	alias_debug = old_alias_debug;
4777 	return s;
4778 }
4779 
4780 #define RAW_BUFFER_SIZE (MAX_RECURSE * BIG_BUFFER_SIZE * 2)
convert_output_format2(const char * str)4781 char *convert_output_format2(const char *str)
4782 {
4783 unsigned char buffer[RAW_BUFFER_SIZE+1];
4784 unsigned char buffer2[RAW_BUFFER_SIZE+1];
4785 register unsigned char *s;
4786 char *copy = NULL;
4787 char *tmpc = NULL;
4788 int arg_flags;
4789 
4790 	if (!str)
4791 		return m_strdup(empty_string);
4792 
4793 	memset(buffer, 0, BIG_BUFFER_SIZE);
4794         strlcpy(buffer2, str, RAW_BUFFER_SIZE);
4795 	copy = tmpc = buffer2;
4796         s = buffer;
4797 	while (*tmpc)
4798 	{
4799 		if (*tmpc == '$')
4800 		{
4801 			char *new_str = NULL;
4802 			tmpc++;
4803 			in_cparse++;
4804 			tmpc = alias_special_char(&new_str, tmpc, copy, NULL, &arg_flags);
4805 			in_cparse--;
4806 			if (new_str)
4807 #ifdef RECURSE_CPARSE
4808 				strlcat(s, convert_output_format(new_str, NULL, NULL), RAW_BUFFER_SIZE);
4809 #else
4810 				strlcat(s, new_str, RAW_BUFFER_SIZE);
4811 #endif
4812                         s = s + (strlen(new_str));
4813 			new_free(&new_str);
4814 			if (!tmpc) break;
4815 			continue;
4816 		} else
4817 			*s = *tmpc;
4818 		tmpc++; s++;
4819 	}
4820 	*s = 0;
4821 	return m_strdup(buffer);
4822 }
4823 
add_last_type(LastMsg * array,int size,char * from,char * uh,char * to,char * str)4824 void add_last_type (LastMsg *array, int size, char *from, char *uh, char *to, char *str)
4825 {
4826 int i;
4827 	for (i = size - 1; i > 0; i--)
4828 	{
4829 
4830 		malloc_strcpy(&array[i].last_msg, array[i - 1].last_msg);
4831 		malloc_strcpy(&array[i].from, array[i - 1].from);
4832 		malloc_strcpy(&array[i].uh, array[i - 1].uh);
4833 		malloc_strcpy(&array[i].to, array[i - 1].to);
4834 		malloc_strcpy(&array[i].time, array[i - 1].time);
4835 	}
4836 	malloc_strcpy(&array->last_msg, str);
4837 	malloc_strcpy(&array->from, from);
4838 	malloc_strcpy(&array->to, to);
4839 	malloc_strcpy(&array->uh, uh);
4840 	malloc_strcpy(&array->time, update_clock(GET_TIME));
4841 }
4842 
check_last_type(LastMsg * array,int size,char * from,char * uh)4843 int check_last_type(LastMsg *array, int size, char *from, char *uh)
4844 {
4845 int i;
4846 	for (i = 0; i < size-1; i++)
4847 	{
4848 		if (array[i].from && array[i].uh && !my_stricmp(from, array[i].from) && !my_stricmp(uh, array[i].uh))
4849 			return 1;
4850 	}
4851 	return 0;
4852 }
4853 
matchmcommand(char * origline,int count)4854 int matchmcommand(char *origline,int count)
4855 {
4856     int  startnum=0;
4857     int  endnum=0;
4858     char *tmpstr;
4859     char tmpbuf[IRCD_BUFFER_SIZE];
4860 
4861 	strncpy(tmpbuf,origline, IRCD_BUFFER_SIZE-1);
4862 	tmpstr=tmpbuf;
4863 	if (*tmpstr=='*') return(1);
4864 	while (tmpstr && *tmpstr)
4865 	{
4866 		startnum=0;
4867 		endnum=0;
4868 		if (tmpstr && *tmpstr && *tmpstr=='-')
4869 		{
4870 			while (tmpstr && *tmpstr && !isdigit((unsigned char)*tmpstr))
4871 				tmpstr++;
4872 			endnum=atoi(tmpstr);
4873 			startnum=1;
4874 			while (tmpstr && *tmpstr && isdigit((unsigned char)*tmpstr))
4875 				tmpstr++;
4876 		}
4877 		else
4878 		{
4879 			while (tmpstr && *tmpstr && !isdigit((unsigned char)*tmpstr))
4880 				tmpstr++;
4881 			startnum=atoi(tmpstr);
4882 			while (tmpstr && *tmpstr && isdigit((unsigned char)*tmpstr))
4883 				tmpstr++;
4884 			if (tmpstr && *tmpstr && *tmpstr=='-') {
4885 				while (tmpstr && *tmpstr && !isdigit((unsigned char)*tmpstr))
4886 					tmpstr++;
4887 				endnum=atoi(tmpstr);
4888 				if (!endnum)
4889 					endnum=1000;
4890 				while (tmpstr && *tmpstr && isdigit((unsigned char)*tmpstr))
4891 					tmpstr++;
4892 			}
4893 		}
4894 		if (count==startnum || (count>=startnum && count<=endnum))
4895 			return(1);
4896 	}
4897 	if (count==startnum || (count>=startnum && count<=endnum))
4898 		return(1);
4899 	return(0);
4900 }
4901 
BX_prepare_command(int * active_server,char * channel,int flags)4902 ChannelList *BX_prepare_command(int *active_server, char *channel, int flags)
4903 {
4904 int server = 0;
4905 ChannelList *chan = NULL;
4906 	int need_op;
4907 
4908 	if (!channel) {
4909 		channel = get_current_channel_by_refnum(0);
4910 
4911 		if (!channel) {
4912 			if (flags != PC_SILENT) {
4913 				if (current_window)
4914 					message_to(current_window->refnum);
4915 				bitchsay("You're not on a channel!");
4916 				message_to(0);
4917 			}
4918 			return NULL;
4919 		}
4920 	}
4921 	server = current_window->server;
4922 	*active_server = server;
4923 	if (!(chan = lookup_channel(channel, server, 0)))
4924 	{
4925 		if (flags != PC_SILENT) {
4926 			if (current_window)
4927 				message_to(current_window->refnum);
4928 			bitchsay("You're not on the channel: %s", channel);
4929 			message_to(0);
4930 		}
4931 		return NULL;
4932 	}
4933 
4934 	need_op = flags == NEED_OP || (flags == PC_TOPIC && (chan->mode & MODE_TOPIC));
4935 	if (need_op && !chan->have_op && !chan->hop)
4936 	{
4937 		error_not_opped(chan->channel);
4938 		return NULL;
4939 	}
4940 	return chan;
4941 }
4942 
BX_make_channel(char * chan)4943 char *BX_make_channel (char *chan)
4944 {
4945 static char buffer[IRCD_BUFFER_SIZE+1];
4946 	*buffer = 0;
4947 	if (!chan)
4948 		return NULL;
4949         if (*chan != '#' && *chan != '&' && *chan != '+' && *chan != '!')
4950 		snprintf(buffer, IRCD_BUFFER_SIZE-2, "#%s", chan);
4951 	else
4952 		strlcpy(buffer, chan, sizeof buffer);
4953 	return buffer;
4954 }
4955 
4956 
4957 extern int timed_server (void *, char *);
check_server_connect(int server)4958 void check_server_connect(int server)
4959 {
4960 #ifndef NON_BLOCKING_CONNECTS
4961 	if (!get_int_var(AUTO_RECONNECT_VAR))
4962 		return;
4963 	if (server == -2)
4964 		return;
4965 	if ((server == -1) || (!get_server_in_timed(server) && get_server_lastmsg(server) + 50 < now))
4966 	{
4967 		if (!timer_callback_exists(timed_server))
4968 		{
4969 			add_timer(0, empty_string, 10 * 1000, 1, timed_server, m_strdup(ltoa(server)), NULL, current_window->refnum, "reconnect");
4970 			set_server_in_timed(server, get_server_in_timed(server)+1);
4971 		}
4972 	}
4973 #endif
4974 }
4975 
country(const char * hostname)4976 const char *country(const char *hostname)
4977 {
4978 #ifndef BITCHX_LITE
4979 static const struct {
4980 	const char *code;
4981 	const char *country;
4982 } domain[] = {
4983 	{"AC", "Ascension Island" },
4984 	{"AD", "Andorra" },
4985 	{"AE", "United Arab Emirates" },
4986 	{"AF", "Afghanistan" },
4987 	{"AG", "Antigua and Barbuda" },
4988 	{"AI", "Anguilla" },
4989 	{"AL", "Albania" },
4990 	{"AM", "Armenia" },
4991 	{"AN", "Netherlands Antilles" },
4992 	{"AO", "Angola" },
4993 	{"AQ", "Antarctica (BURRR!)" },
4994 	{"AR", "Argentina" },
4995 	{"AS", "American Samoa" },
4996 	{"AT", "Austria" },
4997 	{"AU", "Australia" },
4998 	{"AW", "Aruba" },
4999 	{"AX", "Aland" },
5000 	{"AZ", "Azerbaijan" },
5001 	{"BA", "Bosnia and Herzegovina" },
5002 	{"BB", "Barbados" },
5003 	{"BD", "Bangladesh" },
5004 	{"BE", "Belgium" },
5005 	{"BF", "Burkina Faso" },
5006 	{"BG", "Bulgaria" },
5007 	{"BH", "Bahrain" },
5008 	{"BI", "Burundi" },
5009 	{"BJ", "Benin" },
5010 	{"BM", "Bermuda" },
5011 	{"BN", "Brunei Darussalam" },
5012 	{"BO", "Bolivia" },
5013 	{"BR", "Brazil" },
5014 	{"BS", "Bahamas" },
5015 	{"BT", "Bhutan" },
5016 	{"BV", "Bouvet Island" },
5017 	{"BW", "Botswana" },
5018 	{"BY", "Belarus" },
5019 	{"BZ", "Belize" },
5020 	{"CA", "Canada (pHEAR)" },
5021 	{"CC", "Cocos (Keeling) Islands" },
5022 	{"CD", "Congo-Kinshasa" },
5023 	{"CF", "Central African Republic" },
5024 	{"CG", "Congo-Brazzaville" },
5025 	{"CH", "Switzerland" },
5026 	{"CI", "Cote D'Ivoire" },
5027 	{"CK", "Cook Islands" },
5028 	{"CL", "Chile" },
5029 	{"CM", "Cameroon" },
5030 	{"CN", "China" },
5031 	{"CO", "Colombia" },
5032 	{"CR", "Costa Rica" },
5033 	{"CU", "Cuba" },
5034 	{"CV", "Cape Verde" },
5035 	{"CW", "Curacao" },
5036 	{"CX", "Christmas Island" },
5037 	{"CY", "Cyprus" },
5038 	{"CZ", "Czech Republic" },
5039 	{"DE", "Germany" },
5040 	{"DJ", "Djibouti" },
5041 	{"DK", "Denmark" },
5042 	{"DM", "Dominica" },
5043 	{"DO", "Dominican Republic" },
5044 	{"DZ", "Algeria" },
5045 	{"EC", "Ecuador" },
5046 	{"EE", "Estonia" },
5047 	{"EG", "Egypt" },
5048 	{"EH", "Western Sahara" },
5049 	{"ER", "Eritrea" },
5050 	{"ES", "Spain" },
5051 	{"ET", "Ethiopia" },
5052 	{"EU", "European Union" },
5053 	{"FI", "Finland" },
5054 	{"FJ", "Fiji" },
5055 	{"FK", "Falkland Islands" },
5056 	{"FM", "Micronesia" },
5057 	{"FO", "Faroe Islands" },
5058 	{"FR", "France" },
5059 	{"GA", "Gabon" },
5060 	{"GB", "Great Britain" },
5061 	{"GD", "Grenada" },
5062 	{"GE", "Georgia" },
5063 	{"GF", "French Guiana" },
5064 	{"GG", "Guernsey" },
5065 	{"GH", "Ghana" },
5066 	{"GI", "Gibraltar" },
5067 	{"GL", "Greenland" },
5068 	{"GM", "Gambia" },
5069 	{"GN", "Guinea" },
5070 	{"GP", "Guadeloupe" },
5071 	{"GQ", "Equatorial Guinea" },
5072 	{"GR", "Greece" },
5073 	{"GS", "S. Georgia and S. Sandwich Isles" },
5074 	{"GT", "Guatemala" },
5075 	{"GU", "Guam" },
5076 	{"GW", "Guinea-Bissau" },
5077 	{"GY", "Guyana" },
5078 	{"HK", "Hong Kong" },
5079 	{"HM", "Heard and McDonald Islands" },
5080 	{"HN", "Honduras" },
5081 	{"HR", "Croatia" },
5082 	{"HT", "Haiti" },
5083 	{"HU", "Hungary" },
5084 	{"ID", "Indonesia" },
5085 	{"IE", "Ireland" },
5086 	{"IL", "Israel" },
5087 	{"IM", "Isle of Man" },
5088 	{"IN", "India" },
5089 	{"IO", "British Indian Ocean Territory" },
5090 	{"IQ", "Iraq" },
5091 	{"IR", "Iran" },
5092 	{"IS", "Iceland" },
5093 	{"IT", "Italy" },
5094 	{"JE", "Jersey" },
5095 	{"JM", "Jamaica" },
5096 	{"JO", "Jordan" },
5097 	{"JP", "Japan" },
5098 	{"KE", "Kenya" },
5099 	{"KG", "Kyrgyzstan" },
5100 	{"KH", "Cambodia" },
5101 	{"KI", "Kiribati" },
5102 	{"KM", "Comoros" },
5103 	{"KN", "St. Kitts and Nevis" },
5104 	{"KP", "North Korea" },
5105 	{"KR", "South Korea" },
5106 	{"KW", "Kuwait" },
5107 	{"KY", "Cayman Islands" },
5108 	{"KZ", "Kazakstan" },
5109 	{"LA", "Laos" },
5110 	{"LB", "Lebanon" },
5111 	{"LC", "St. Lucia" },
5112 	{"LI", "Liechtenstein" },
5113 	{"LK", "Sri Lanka" },
5114 	{"LR", "Liberia" },
5115 	{"LS", "Lesotho" },
5116 	{"LT", "Lithuania" },
5117 	{"LU", "Luxembourg" },
5118 	{"LV", "Latvia" },
5119 	{"LY", "Libya" },
5120 	{"MA", "Morocco" },
5121 	{"MC", "Monaco" },
5122 	{"MD", "Moldova" },
5123 	{"ME", "Montenegro" },
5124 	{"MG", "Madagascar" },
5125 	{"MH", "Marshall Islands" },
5126 	{"MK", "Macedonia" },
5127 	{"ML", "Mali" },
5128 	{"MM", "Myanmar" },
5129 	{"MN", "Mongolia" },
5130 	{"MO", "Macau" },
5131 	{"MP", "Northern Mariana Islands" },
5132 	{"MQ", "Martinique" },
5133 	{"MR", "Mauritania" },
5134 	{"MS", "Montserrat" },
5135 	{"MT", "Malta" },
5136 	{"MU", "Mauritius" },
5137 	{"MV", "Maldives" },
5138 	{"MW", "Malawi" },
5139 	{"MX", "Mexico" },
5140 	{"MY", "Malaysia" },
5141 	{"MZ", "Mozambique" },
5142 	{"NA", "Namibia" },
5143 	{"NC", "New Caledonia" },
5144 	{"NE", "Niger" },
5145 	{"NF", "Norfolk Island" },
5146 	{"NG", "Nigeria" },
5147 	{"NI", "Nicaragua" },
5148 	{"NL", "Netherlands" },
5149 	{"NO", "Norway" },
5150 	{"NP", "Nepal" },
5151 	{"NR", "Nauru" },
5152 	{"NU", "Niue" },
5153 	{"NZ", "New Zealand" },
5154 	{"OM", "Oman" },
5155 	{"PA", "Panama" },
5156 	{"PE", "Peru" },
5157 	{"PF", "French Polynesia" },
5158 	{"PG", "Papua New Guinea" },
5159 	{"PH", "Philippines" },
5160 	{"PK", "Pakistan" },
5161 	{"PL", "Poland" },
5162 	{"PM", "St. Pierre and Miquelon" },
5163 	{"PN", "Pitcairn Island" },
5164 	{"PR", "Puerto Rico" },
5165 	{"PS", "Palestinian Territories" },
5166 	{"PT", "Portugal" },
5167 	{"PW", "Palau" },
5168 	{"PY", "Paraguay" },
5169 	{"QA", "Qatar" },
5170 	{"RE", "Reunion Island" },
5171 	{"RO", "Romania" },
5172 	{"RS", "Serbia" },
5173 	{"RU", "Russian Federation (pHEAR)" },
5174 	{"RW", "Rwanda" },
5175 	{"SA", "Saudi Arabia" },
5176 	{"SB", "Solomon Islands" },
5177 	{"SC", "Seychelles" },
5178 	{"SD", "Sudan" },
5179 	{"SE", "Sweden" },
5180 	{"SG", "Singapore" },
5181 	{"SH", "St. Helena" },
5182 	{"SI", "Slovenia" },
5183 	{"SJ", "Svalbard and Jan Mayen Islands" },
5184 	{"SK", "Slovakia" },
5185 	{"SL", "Sierra Leone" },
5186 	{"SM", "San Marino" },
5187 	{"SN", "Senegal" },
5188 	{"SO", "Somalia" },
5189 	{"SR", "Suriname" },
5190 	{"ST", "Sao Tome and Principe" },
5191 	{"SU", "Former USSR (pHEAR)" },
5192 	{"SV", "El Salvador" },
5193 	{"SX", "Sint Maarten" },
5194 	{"SY", "Syria" },
5195 	{"SZ", "Swaziland" },
5196 	{"TC", "Turks and Caicos Islands" },
5197 	{"TD", "Chad" },
5198 	{"TF", "French Southern Territories" },
5199 	{"TG", "Togo" },
5200 	{"TH", "Thailand" },
5201 	{"TJ", "Tajikistan" },
5202 	{"TK", "Tokelau" },
5203 	{"TL", "East Timor" },
5204 	{"TM", "Turkmenistan" },
5205 	{"TN", "Tunisia" },
5206 	{"TO", "Tonga" },
5207 	{"TP", "East Timor" },
5208 	{"TR", "Turkey" },
5209 	{"TT", "Trinidad and Tobago" },
5210 	{"TV", "Tuvalu" },
5211 	{"TW", "Taiwan" },
5212 	{"TZ", "Tanzania" },
5213 	{"UA", "Ukraine" },
5214 	{"UG", "Uganda" },
5215 	{"UK", "United Kingdom" },
5216 	{"UM", "US Minor Outlying Islands" },
5217 	{"US", "United States of America" },
5218 	{"UY", "Uruguay" },
5219 	{"UZ", "Uzbekistan" },
5220 	{"VA", "Vatican City" },
5221 	{"VC", "St. Vincent and the Grenadines" },
5222 	{"VE", "Venezuela" },
5223 	{"VG", "British Virgin Islands" },
5224 	{"VI", "US Virgin Islands" },
5225 	{"VN", "Vietnam" },
5226 	{"VU", "Vanuatu" },
5227 	{"WF", "Wallis and Futuna Islands" },
5228 	{"WS", "Western Samoa" },
5229 	{"YE", "Yemen" },
5230 	{"YT", "Mayotte" },
5231 	{"YU", "Yugoslavia" },
5232 	{"ZA", "South Africa" },
5233 	{"ZM", "Zambia" },
5234 	{"ZR", "Zaire" },
5235 	{"ZW", "Zimbabwe" },
5236 	{"AERO", "Air Transport Industry" },
5237 	{"ARPA", "Reverse DNS" },
5238 	{"ASIA", "Asia-Pacific" },
5239 	{"BIZ", "Business" },
5240 	{"CAT", "Catalan Language" },
5241 	{"COOP", "Cooperative Association" },
5242 	{"COM", "Commercial" },
5243 	{"EDU", "Educational Institution" },
5244 	{"GOV", "United States Government" },
5245 	{"INFO", "Informational" },
5246 	{"INT", "International" },
5247 	{"JOBS", "Employment Advertisements" },
5248 	{"MIL", "United States Military" },
5249 	{"MOBI", "Mobile Device" },
5250 	{"MUSEUM", "Museum" },
5251 	{"NET", "Network" },
5252 	{"NAME", "Individuals" },
5253 	{"ORG", "Organization" },
5254 	{"PRO", "Professional" },
5255 	{"TEL", "Contact Information" },
5256 	{"TRAVEL", "Travel Industry" },
5257 	{"XXX", "Porn" },
5258 	{NULL, NULL}
5259 };
5260 	const char *p;
5261 	int i = 0;
5262 
5263 	if (!hostname || !*hostname || isdigit((unsigned char)hostname[strlen(hostname)-1]))
5264 		return "unknown";
5265 	if ((p = strrchr(hostname, '.')))
5266 		p++;
5267 	else
5268 		p = hostname;
5269 	for (i = 0; domain[i].code; i++)
5270 		if (!my_stricmp(p, domain[i].code))
5271 			return domain[i].country;
5272 #endif
5273 	return "unknown";
5274 }
5275 
5276