summary refs log tree commit diff stats
path: root/data/icons/tree_dialog.png
blob: 9d2d500813c206d6735ea53e47ff2c56428ea0a6 (plain)
ofshex dumpascii
0000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 10 00 00 00 10 08 06 00 00 00 1f f3 ff .PNG........IHDR................
0020 61 00 00 00 06 62 4b 47 44 00 ff 00 ff 00 ff a0 bd a7 93 00 00 00 09 70 48 59 73 00 00 0b 13 00 a....bKGD..............pHYs.....
0040 00 0b 13 01 00 9a 9c 18 00 00 00 07 74 49 4d 45 07 d5 06 10 16 2c 10 6d 53 21 0b 00 00 00 35 74 ............tIME.....,.mS!....5t
0060 45 58 74 43 6f 6d 6d 65 6e 74 00 28 63 29 20 32 30 30 34 20 4a 61 6b 75 62 20 53 74 65 69 6e 65 EXtComment.(c).2004.Jakub.Steine
0080 72 0a 0a 43 72 65 61 74 65 64 20 77 69 74 68 20 54 68 65 20 47 49 4d 50 90 d9 8b 6f 00 00 02 db r..Created.with.The.GIMP...o....
00a0 49 44 41 54 38 cb 7d 93 4b 68 5c 75 14 c6 7f f7 de 99 7b 93 49 32 0d 49 3b a6 03 d6 34 4d 4c ed IDAT8.}.Kh\u......{.I2.I;...4ML.
00c0 22 d6 84 0a 9a 85 51 ea 58 51 f0 41 68 5d 8c 1b a5 a5 5b 0b 2d 82 2b 75 29 e8 4a dd b9 31 28 2e ".....Q.XQ.Ah]....[.-.+u).J..1(.
00e0 52 48 7c 16 85 10 22 14 a3 03 b1 2a 1a 32 98 47 33 99 38 93 cc e3 3e e6 ce ff 3e fe d7 4d 32 4d RH|..."....*.2.G3.8...>...>..M2M
0100 91 fa ad 0e 87 f3 7d 9c 73 3e 3e 85 03 c8 65 c9 de b0 f4 b7 0e a9 f2 a4 40 f1 8f 68 f2 e7 53 6d ......}.s>>...e.........@..h..Sm
0120 e1 77 63 53 bc cb 3d a0 1c 24 c7 12 b1 cb c6 58 66 5c 74 1e 41 36 4d 6c d3 92 f9 85 b9 d5 91 44 .wcS..=..$.....Xf\t.A6Ml.......D
0140 78 61 6c 8a dc ff 0a 7c f2 8a f1 fd 13 e7 9e 3f 5b f4 22 02 21 10 d6 36 5a cd 24 5e 2f 47 9d 4e xal....|.......?[.".!..6Z.$^/G.N
0160 4d 89 54 c5 51 64 74 03 58 3a b8 51 6c bf 28 89 e8 6c c5 93 34 6d 93 30 de 43 d2 75 08 cd 02 03 M.T.Qdt.X:.Ql.(..l..4m.0.C.u....
0180 e3 cf 28 dd 0f 3d 46 68 15 3b 9c 9d f2 8b 85 d9 a9 74 2e cb 37 fb 1b a9 fb 02 02 05 d7 ad 13 b8 ..(..=Fh.;.......t..7...........
01a0 bb c8 46 99 66 75 9b e1 a7 5e a2 6b f0 61 9c 7a 09 6b 27 8f 91 3a aa f6 8c 3e 3e 06 7c b4 cf 6b ..F.fu...^.k.a.z.k'..:...>>.|..k
01c0 09 ac 4b 7d 8d a6 87 eb 6b 58 95 0d 52 4d 93 e4 fd 43 08 d7 26 de 33 04 9a 81 bd 71 13 bd 7f 20 ..K}....kX..RM...C..&.3....q....
01e0 0e 3c 7a 97 40 66 72 22 9b a8 8d f4 cf 2d da 18 8a 42 5c ef 64 07 95 66 a3 8a 28 dd c2 2c 2c e1 .<z.@fr".....-...B\.d..f..(..,,.
0200 55 96 91 a8 b8 6e 63 05 a8 b6 7e 90 99 9c c8 02 9f 2a a3 36 6b 76 89 70 75 98 6a 69 11 bf b7 9b U....nc...~......*.6kv.pu.ji....
0220 c1 c2 16 46 6a 00 7b 7d 1e 2d 91 a2 d1 3e 18 b9 b7 b7 7a cb cd ee 75 a8 01 a0 9d 38 d5 ff eb e9 ...Fj.{}.-...>....z...u....8....
0240 61 87 50 29 f3 c0 f1 07 89 f5 29 d4 43 9d f6 e5 51 0a ff 54 18 4a ab 04 c9 63 78 c6 31 6a 55 a9 a.P)......).C...Q..T.J...cx.1jU.
0260 fc 38 5f d4 d7 76 8f a6 d3 87 33 d1 ad ad dc 7c cb 05 cf 77 01 d8 5c 29 61 fe 32 ce f1 37 5e e7 .8_..v....3....|...w..\)a.2..7^.
0280 f7 e9 cf f1 7f da e6 49 eb 33 2a b2 8b 7c 73 10 41 52 cb 3f 7d 0d ae 4f bf 9d 3d 73 c9 50 32 93 .......I.3*..|s.AR.?}..O..=s.P2.
02a0 13 d1 e9 61 07 d3 5d 05 c0 5e 78 99 47 ae bc c6 17 0b 9b a8 5a 9c 37 9f 4d 33 f3 f1 97 9c 3b 3f ...a..]..^x.G.......Z.7.M3....;?
02c0 4e d8 de c1 07 3f 6c 12 06 82 91 13 7d 04 d7 a7 ef b8 50 77 bb 10 c2 01 dd e2 b7 b5 3a 32 f4 91 N....?l.....}.....Pw........:2..
02e0 32 a0 86 ce d5 f7 2f 32 b3 01 79 4b 21 92 21 32 08 58 29 3a 77 db d8 9f 4a 91 d4 4f 82 d7 45 14 2...../2..yK!.!2.X):w...J..O..E.
0300 49 a2 30 40 06 1e 1f ce fe c5 df 5b 35 a2 c0 67 f6 e6 2a 32 0c 50 b5 d6 e5 a8 c0 ab 4b cb 1d e4 I.0@.......[5..g..*2.P......K...
0320 fe 68 e7 cf db 87 00 88 42 1f 80 44 a5 88 0c 04 df 2e ae b3 bc b1 8b 0c 3c 3a 6a 25 88 e4 7f b3 .h......B..D............<:j%....
0340 b0 87 78 f6 cc 25 cf 7b ee 05 64 04 7e a1 80 7f b8 8f 86 08 5b 03 6d 95 12 a2 37 45 2c a6 71 df ..x..%.{..d.~.......[.m...7E,.q.
0360 dc 57 77 b2 b0 07 5f 04 e2 3d e3 eb 99 ab 00 6d 7b cd 9e 7b 44 59 46 f2 9d 7f 01 cf a4 5a aa c2 .Ww..._..=.....m{..{DYF......Z..
0380 fa 16 60 00 00 00 00 49 45 4e 44 ae 42 60 82 ..`....IEND.B`.
n196' href='#n196'>196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
/* X-Chat
 * Copyright (C) 1998 Peter Zelezny.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>

#define WANTSOCKET
#include "inet.h"

#ifdef WIN32
#include <windows.h>
#else
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#endif

#include "hexchat.h"
#include "fe.h"
#include "util.h"
#include "cfgfiles.h"
#include "chanopt.h"
#include "ignore.h"
#include "hexchat-plugin.h"
#include "plugin.h"
#include "plugin-timer.h"
#include "notify.h"
#include "server.h"
#include "servlist.h"
#include "outbound.h"
#include "text.h"
#include "url.h"
#include "hexchatc.h"

#ifdef USE_OPENSSL
#include <openssl/ssl.h>		  /* SSL_() */
#include "ssl.h"
#endif

#ifdef USE_MSPROXY
#include "msproxy.h"
#endif

#ifdef USE_LIBPROXY
#include <proxy.h>
#endif

GSList *popup_list = 0;
GSList *button_list = 0;
GSList *dlgbutton_list = 0;
GSList *command_list = 0;
GSList *ctcp_list = 0;
GSList *replace_list = 0;
GSList *sess_list = 0;
GSList *dcc_list = 0;
GSList *ignore_list = 0;
GSList *usermenu_list = 0;
GSList *urlhandler_list = 0;
GSList *tabmenu_list = 0;

static int in_hexchat_exit = FALSE;
int hexchat_is_quitting = FALSE;
/* command-line args */
int arg_dont_autoconnect = FALSE;
int arg_skip_plugins = FALSE;
char *arg_url = NULL;
char *arg_command = NULL;
gint arg_existing = FALSE;

#ifdef USE_DBUS
#include "dbus/dbus-client.h"
#include "dbus/dbus-plugin.h"
#endif /* USE_DBUS */

struct session *current_tab;
struct session *current_sess = 0;
struct hexchatprefs prefs;

#ifdef USE_OPENSSL
SSL_CTX *ctx = NULL;
#endif

#ifdef USE_LIBPROXY
pxProxyFactory *libproxy_factory;
#endif

int
is_session (session * sess)
{
	return g_slist_find (sess_list, sess) ? 1 : 0;
}

session *
find_dialog (server *serv, char *nick)
{
	GSList *list = sess_list;
	session *sess;

	while (list)
	{
		sess = list->data;
		if (sess->server == serv && sess->type == SESS_DIALOG)
		{
			if (!serv->p_cmp (nick, sess->channel))
				return (sess);
		}
		list = list->next;
	}
	return 0;
}

session *
find_channel (server *serv, char *chan)
{
	session *sess;
	GSList *list = sess_list;
	while (list)
	{
		sess = list->data;
		if ((!serv || serv == sess->server) && sess->type != SESS_DIALOG)
		{
			if (!serv->p_cmp (chan, sess->channel))
				return sess;
		}
		list = list->next;
	}
	return 0;
}

static void
lagcheck_update (void)
{
	server *serv;
	GSList *list = serv_list;
	
	if (!prefs.hex_gui_lagometer)
		return;

	while (list)
	{
		serv = list->data;
		if (serv->lag_sent)
			fe_set_lag (serv, -1);

		list = list->next;
	}
}

void
lag_check (void)
{
	server *serv;
	GSList *list = serv_list;
	unsigned long tim;
	char tbuf[128];
	time_t now = time (0);
	int lag;

	tim = make_ping_time ();

	while (list)
	{
		serv = list->data;
		if (serv->connected && serv->end_of_motd)
		{
			lag = now - serv->ping_recv;
			if (prefs.hex_net_ping_timeout && lag > prefs.hex_net_ping_timeout && lag > 0)
			{
				sprintf (tbuf, "%d", lag);
				EMIT_SIGNAL (XP_TE_PINGTIMEOUT, serv->server_session, tbuf, NULL,
								 NULL, NULL, 0);
				if (prefs.hex_net_auto_reconnect)
					serv->auto_reconnect (serv, FALSE, -1);
			} else
			{
				snprintf (tbuf, sizeof (tbuf), "LAG%lu", tim);
				serv->p_ping (serv, "", tbuf);
				serv->lag_sent = tim;
				fe_set_lag (serv, -1);
			}
		}
		list = list->next;
	}
}

static int
away_check (void)
{
	session *sess;
	GSList *list;
	int full, sent, loop = 0;

	if (!prefs.hex_away_track || prefs.hex_away_size_max < 1)
		return 1;

doover:
	/* request an update of AWAY status of 1 channel every 30 seconds */
	full = TRUE;
	sent = 0;	/* number of WHOs (users) requested */
	list = sess_list;
	while (list)
	{
		sess = list->data;

		if (sess->server->connected &&
			 sess->type == SESS_CHANNEL &&
			 sess->channel[0] &&
			 sess->total <= prefs.hex_away_size_max)
		{
			if (!sess->done_away_check)
			{
				full = FALSE;

				/* if we're under 31 WHOs, send another channels worth */
				if (sent < 31 && !sess->doing_who)
				{
					sess->done_away_check = TRUE;
					sess->doing_who = TRUE;
					/* this'll send a WHO #channel */
					sess->server->p_away_status (sess->server, sess->channel);
					sent += sess->total;
				}
			}
		}

		list = list->next;
	}

	/* done them all, reset done_away_check to FALSE and start over */
	if (full)
	{
		list = sess_list;
		while (list)
		{
			sess = list->data;
			sess->done_away_check = FALSE;
			list = list->next;
		}
		loop++;
		if (loop < 2)
			goto doover;
	}

	return 1;
}

static int
hexchat_misc_checks (void)		/* this gets called every 1/2 second */
{
	static int count = 0;
#ifdef USE_MSPROXY
	static int count2 = 0;
#endif

	count++;

	lagcheck_update ();			/* every 500ms */

	if (count % 2)
		dcc_check_timeouts ();	/* every 1 second */

	if (count >= 60)				/* every 30 seconds */
	{
		if (prefs.hex_gui_lagometer)
			lag_check ();
		count = 0;
	}

#ifdef USE_MSPROXY	
	count2++;
	if (count2 >= 720)			/* 720 every 6 minutes */
	{
		msproxy_keepalive ();
		count2 = 0;
	}
#endif

	return 1;
}

/* executed when the first irc window opens */

static void
irc_init (session *sess)
{
	static int done_init = FALSE;
	char buf[512];

	if (done_init)
		return;

	done_init = TRUE;

	plugin_add (sess, NULL, NULL, timer_plugin_init, NULL, NULL, FALSE);

#ifdef USE_PLUGIN
	if (!arg_skip_plugins)
		plugin_auto_load (sess);	/* autoload ~/.xchat *.so */
#endif

#ifdef USE_DBUS
	plugin_add (sess, NULL, NULL, dbus_plugin_init, NULL, NULL, FALSE);
#endif

	if (prefs.hex_notify_timeout)
		notify_tag = fe_timeout_add (prefs.hex_notify_timeout * 1000,
											  notify_checklist, 0);

	fe_timeout_add (prefs.hex_away_timeout * 1000, away_check, 0);
	fe_timeout_add (500, hexchat_misc_checks, 0);

	if (arg_url != NULL)
	{
		snprintf (buf, sizeof (buf), "server %s", arg_url);
		handle_command (sess, buf, FALSE);
		g_free (arg_url);	/* from GOption */
	}

	if (arg_command != NULL)
	{
		g_free (arg_command);
	}

	/* load -e ~/.xchat2/startup.txt */
	snprintf (buf, sizeof (buf), "%s/%s", get_xdir_fs (), "startup.txt");
	load_perform_file (sess, buf);
}

static session *
session_new (server *serv, char *from, int type, int focus)
{
	session *sess;

	sess = malloc (sizeof (struct session));
	if (sess == NULL)
	{
		return NULL;
	}
	memset (sess, 0, sizeof (struct session));

	sess->server = serv;
	sess->logfd = -1;
	sess->scrollfd = -1;
	sess->type = type;

	sess->alert_beep = SET_DEFAULT;
	sess->alert_taskbar = SET_DEFAULT;
	sess->alert_tray = SET_DEFAULT;

	sess->text_hidejoinpart = SET_DEFAULT;
	sess->text_logging = SET_DEFAULT;
	sess->text_scrollback = SET_DEFAULT;

	if (from != NULL)
		safe_strcpy (sess->channel, from, CHANLEN);

	sess_list = g_slist_prepend (sess_list, sess);

	fe_new_window (sess, focus);

	return sess;
}

session *
new_ircwindow (server *serv, char *name, int type, int focus)
{
	session *sess;

	switch (type)
	{
	case SESS_SERVER:
		serv = server_new ();
		if (prefs.hex_gui_tab_server)
			sess = session_new (serv, name, SESS_SERVER, focus);
		else
			sess = session_new (serv, name, SESS_CHANNEL, focus);
		serv->server_session = sess;
		serv->front_session = sess;
		break;
	case SESS_DIALOG:
		sess = session_new (serv, name, type, focus);
		log_open_or_close (sess);
		break;
	default:
/*	case SESS_CHANNEL:
	case SESS_NOTICES:
	case SESS_SNOTICES:*/
		sess = session_new (serv, name, type, focus);
		break;
	}

	irc_init (sess);
	scrollback_load (sess);
	chanopt_load (sess);
	plugin_emit_dummy_print (sess, "Open Context");

	return sess;
}

static void
exec_notify_kill (session * sess)
{
#ifndef WIN32
	struct nbexec *re;
	if (sess->running_exec != NULL)
	{
		re = sess->running_exec;
		sess->running_exec = NULL;
		kill (re->childpid, SIGKILL);
		waitpid (re->childpid, NULL, WNOHANG);
		fe_input_remove (re->iotag);
		close (re->myfd);
		if (re->linebuf)
			free(re->linebuf);
		free (re);
	}
#endif
}

static void
send_quit_or_part (session * killsess)
{
	int willquit = TRUE;
	GSList *list;
	session *sess;
	server *killserv = killsess->server;

	/* check if this is the last session using this server */
	list = sess_list;
	while (list)
	{
		sess = (session *) list->data;
		if (sess->server == killserv && sess != killsess)
		{
			willquit = FALSE;
			list = 0;
		} else
			list = list->next;
	}

	if (hexchat_is_quitting)
		willquit = TRUE;

	if (killserv->connected)
	{
		if (willquit)
		{
			if (!killserv->sent_quit)
			{
				killserv->flush_queue (killserv);
				server_sendquit (killsess);
				killserv->sent_quit = TRUE;
			}
		} else
		{
			if (killsess->type == SESS_CHANNEL && killsess->channel[0] &&
				 !killserv->sent_quit)
			{
				server_sendpart (killserv, killsess->channel, 0);
			}
		}
	}
}

void
session_free (session *killsess)
{
	server *killserv = killsess->server;
	session *sess;
	GSList *list;

	plugin_emit_dummy_print (killsess, "Close Context");

	if (current_tab == killsess)
		current_tab = NULL;

	if (killserv->server_session == killsess)
		killserv->server_session = NULL;

	if (killserv->front_session == killsess)
	{
		/* front_session is closed, find a valid replacement */
		killserv->front_session = NULL;
		list = sess_list;
		while (list)
		{
			sess = (session *) list->data;
			if (sess != killsess && sess->server == killserv)
			{
				killserv->front_session = sess;
				if (!killserv->server_session)
					killserv->server_session = sess;
				break;
			}
			list = list->next;
		}
	}

	if (!killserv->server_session)
		killserv->server_session = killserv->front_session;

	sess_list = g_slist_remove (sess_list, killsess);

	if (killsess->type == SESS_CHANNEL)
		userlist_free (killsess);

	exec_notify_kill (killsess);

	log_close (killsess);
	scrollback_close (killsess);
	chanopt_save (killsess);

	send_quit_or_part (killsess);

	history_free (&killsess->history);
	if (killsess->topic)
		free (killsess->topic);
	if (killsess->current_modes)
		free (killsess->current_modes);

	fe_session_callback (killsess);

	if (current_sess == killsess)
	{
		current_sess = NULL;
		if (sess_list)
			current_sess = sess_list->data;
	}

	free (killsess);

	if (!sess_list && !in_hexchat_exit)
		hexchat_exit ();						/* sess_list is empty, quit! */

	list = sess_list;
	while (list)
	{
		sess = (session *) list->data;
		if (sess->server == killserv)
			return;					  /* this server is still being used! */
		list = list->next;
	}

	server_free (killserv);
}

static void
free_sessions (void)
{
	GSList *list = sess_list;

	while (list)
	{
		fe_close_window (list->data);
		list = sess_list;
	}
}


static char defaultconf_ctcp[] =
	"NAME TIME\n"				"CMD nctcp %s TIME %t\n\n"\
	"NAME PING\n"				"CMD nctcp %s PING %d\n\n";

static char defaultconf_replace[] =
	"NAME teh\n"				"CMD the\n\n";
/*	"NAME r\n"					"CMD are\n\n"\
	"NAME u\n"					"CMD you\n\n"*/

static char defaultconf_commands[] =
	"NAME ACTION\n"		"CMD me &2\n\n"\
	"NAME AME\n"			"CMD allchan me &2\n\n"\
	"NAME ANICK\n"			"CMD allserv nick &2\n\n"\
	"NAME AMSG\n"			"CMD allchan say &2\n\n"\
	"NAME BANLIST\n"		"CMD quote MODE %c +b\n\n"\
	"NAME CHAT\n"			"CMD dcc chat %2\n\n"\
	"NAME DIALOG\n"		"CMD query %2\n\n"\
	"NAME DMSG\n"			"CMD msg =%2 &3\n\n"\
	"NAME EXIT\n"			"CMD quit\n\n"\
	"NAME GREP\n"			"CMD lastlog -r -- &2\n\n"\
	"NAME IGNALL\n"			"CMD ignore %2!*@* ALL\n\n"\
	"NAME J\n"				"CMD join &2\n\n"\
	"NAME KILL\n"			"CMD quote KILL %2 :&3\n\n"\
	"NAME LEAVE\n"			"CMD part &2\n\n"\
	"NAME M\n"				"CMD msg &2\n\n"\
	"NAME ONOTICE\n"		"CMD notice @%c &2\n\n"\
	"NAME RAW\n"			"CMD quote &2\n\n"\
	"NAME SERVHELP\n"		"CMD quote HELP\n\n"\
	"NAME SPING\n"			"CMD ping\n\n"\
	"NAME SQUERY\n"		"CMD quote SQUERY %2 :&3\n\n"\
	"NAME SSLSERVER\n"	"CMD server -ssl &2\n\n"\
	"NAME SV\n"				"CMD echo HexChat %v %m\n\n"\
	"NAME UMODE\n"			"CMD mode %n &2\n\n"\
	"NAME UPTIME\n"		"CMD quote STATS u\n\n"\
	"NAME VER\n"			"CMD ctcp %2 VERSION\n\n"\
	"NAME VERSION\n"		"CMD ctcp %2 VERSION\n\n"\
	"NAME WALLOPS\n"		"CMD quote WALLOPS :&2\n\n"\
	"NAME WII\n"			"CMD quote WHOIS %2 %2\n\n";

static char defaultconf_urlhandlers[] =
		"NAME Open Link in Opera\n"		"CMD !opera -remote 'openURL(%s)'\n\n";

#ifdef USE_SIGACTION
/* Close and open log files on SIGUSR1. Usefull for log rotating */

static void 
sigusr1_handler (int signal, siginfo_t *si, void *un)
{
	GSList *list = sess_list;
	session *sess;

	while (list)
	{
		sess = list->data;
		log_open_or_close (sess);
		list = list->next;
	}
}

/* Execute /SIGUSR2 when SIGUSR2 received */

static void
sigusr2_handler (int signal, siginfo_t *si, void *un)
{
	session *sess = current_sess;

	if (sess)
		handle_command (sess, "SIGUSR2", FALSE);
}
#endif

static gint
xchat_auto_connect (gpointer userdata)
{
	servlist_auto_connect (NULL);
	return 0;
}

static void
xchat_init (void)
{
	char buf[3068];
	const char *cs = NULL;

#ifdef WIN32
	WSADATA wsadata;

#ifdef USE_IPV6
	if (WSAStartup(0x0202, &wsadata) != 0)
	{
		MessageBox (NULL, "Cannot find winsock 2.2+", "Error", MB_OK);
		exit (0);
	}
#else
	WSAStartup(0x0101, &wsadata);
#endif	/* !USE_IPV6 */
#endif	/* !WIN32 */

#ifdef USE_SIGACTION
	struct sigaction act;

	/* ignore SIGPIPE's */
	act.sa_handler = SIG_IGN;
	act.sa_flags = 0;
	sigemptyset (&act.sa_mask);
	sigaction (SIGPIPE, &act, NULL);

	/* Deal with SIGUSR1's & SIGUSR2's */
	act.sa_sigaction = sigusr1_handler;
	act.sa_flags = 0;
	sigemptyset (&act.sa_mask);
	sigaction (SIGUSR1, &act, NULL);

	act.sa_sigaction = sigusr2_handler;
	act.sa_flags = 0;
	sigemptyset (&act.sa_mask);
	sigaction (SIGUSR2, &act, NULL);
#else
#ifndef WIN32
	/* good enough for these old systems */
	signal (SIGPIPE, SIG_IGN);
#endif
#endif

	if (g_get_charset (&cs))
		prefs.utf8_locale = TRUE;

	load_text_events ();
	sound_load ();
	notify_load ();
	ignore_load ();

	snprintf (buf, sizeof (buf),
		"NAME %s~%s~\n"				"CMD query %%s\n\n"\
		"NAME %s~%s~\n"				"CMD send %%s\n\n"\
		"NAME %s~%s~\n"				"CMD whois %%s %%s\n\n"\
		"NAME %s~%s~\n"				"CMD notify -n ASK %%s\n\n"\
		"NAME %s~%s~\n"				"CMD ignore %%s!*@* ALL\n\n"\

		"NAME SUB\n"					"CMD %s\n\n"\
			"NAME %s\n"					"CMD op %%a\n\n"\
			"NAME %s\n"					"CMD deop %%a\n\n"\
			"NAME SEP\n"				"CMD \n\n"\
			"NAME %s\n"					"CMD voice %%a\n\n"\
			"NAME %s\n"					"CMD devoice %%a\n"\
			"NAME SEP\n"				"CMD \n\n"\
			"NAME SUB\n"				"CMD %s\n\n"\
				"NAME %s\n"				"CMD kick %%s\n\n"\
				"NAME %s\n"				"CMD ban %%s\n\n"\
				"NAME SEP\n"			"CMD \n\n"\
				"NAME %s *!*@*.host\n""CMD ban %%s 0\n\n"\
				"NAME %s *!*@domain\n""CMD ban %%s 1\n\n"\
				"NAME %s *!*user@*.host\n""CMD ban %%s 2\n\n"\
				"NAME %s *!*user@domain\n""CMD ban %%s 3\n\n"\
				"NAME SEP\n"			"CMD \n\n"\
				"NAME %s *!*@*.host\n""CMD kickban %%s 0\n\n"\
				"NAME %s *!*@domain\n""CMD kickban %%s 1\n\n"\
				"NAME %s *!*user@*.host\n""CMD kickban %%s 2\n\n"\
				"NAME %s *!*user@domain\n""CMD kickban %%s 3\n\n"\
			"NAME ENDSUB\n"			"CMD \n\n"\
		"NAME ENDSUB\n"				"CMD \n\n",

		_("_Open Dialog Window"), "gtk-go-up",
		_("_Send a File"), "gtk-floppy",
		_("_User Info (WhoIs)"), "gtk-info",
		_("_Add to Friends List"), "gtk-add",
		_("_Ignore"), "gtk-stop",
		_("O_perator Actions"),

		_("Give Ops"),
		_("Take Ops"),
		_("Give Voice"),
		_("Take Voice"),

		_("Kick/Ban"),
		_("Kick"),
		_("Ban"),
		_("Ban"),
		_("Ban"),
		_("Ban"),
		_("Ban"),
		_("KickBan"),
		_("KickBan"),
		_("KickBan"),
		_("KickBan"));

	list_loadconf ("popup.conf", &popup_list, buf);

	snprintf (buf, sizeof (buf),
		"NAME %s\n"				"CMD part\n\n"
		"NAME %s\n"				"CMD getstr # join \"%s\"\n\n"
		"NAME %s\n"				"CMD quote LINKS\n\n"
		"NAME %s\n"				"CMD ping\n\n"
		"NAME TOGGLE %s\n"	"CMD irc_hide_version\n\n",
				_("Leave Channel"),
				_("Join Channel..."),
				_("Enter Channel to Join:"),
				_("Server Links"),
				_("Ping Server"),
				_("Hide Version"));
	list_loadconf ("usermenu.conf", &usermenu_list, buf);

	snprintf (buf, sizeof (buf),
		"NAME %s\n"		"CMD op %%a\n\n"
		"NAME %s\n"		"CMD deop %%a\n\n"
		"NAME %s\n"		"CMD ban %%s\n\n"
		"NAME %s\n"		"CMD getstr \"%s\" \"kick %%s\" \"%s\"\n\n"
		"NAME %s\n"		"CMD send %%s\n\n"
		"NAME %s\n"		"CMD query %%s\n\n",
				_("Op"),
				_("DeOp"),
				_("Ban"),
				_("Kick"),
				_("bye"),
				_("Enter reason to kick %s:"),
				_("Sendfile"),
				_("Dialog"));
	list_loadconf ("buttons.conf", &button_list, buf);

	snprintf (buf, sizeof (buf),
		"NAME %s\n"				"CMD whois %%s %%s\n\n"
		"NAME %s\n"				"CMD send %%s\n\n"
		"NAME %s\n"				"CMD dcc chat %%s\n\n"
		"NAME %s\n"				"CMD clear\n\n"
		"NAME %s\n"				"CMD ping %%s\n\n",
				_("WhoIs"),
				_("Send"),
				_("Chat"),
				_("Clear"),
				_("Ping"));
	list_loadconf ("dlgbuttons.conf", &dlgbutton_list, buf);

	list_loadconf ("tabmenu.conf", &tabmenu_list, NULL);
	list_loadconf ("ctcpreply.conf", &ctcp_list, defaultconf_ctcp);
	list_loadconf ("commands.conf", &command_list, defaultconf_commands);
	list_loadconf ("replace.conf", &replace_list, defaultconf_replace);
	list_loadconf ("urlhandlers.conf", &urlhandler_list,
						defaultconf_urlhandlers);

	servlist_init ();							/* load server list */

	/* if we got a URL, don't open the server list GUI */
	if (!prefs.hex_gui_slist_skip && !arg_url)
		fe_serverlist_open (NULL);

	/* turned OFF via -a arg */
	if (!arg_dont_autoconnect)
	{
		/* do any auto connects */
		if (!servlist_have_auto ())	/* if no new windows open .. */
		{
			/* and no serverlist gui ... */
			if (prefs.hex_gui_slist_skip || arg_url)
				/* we'll have to open one. */
				new_ircwindow (NULL, NULL, SESS_SERVER, 0);
		} else
		{
			fe_idle_add (xchat_auto_connect, NULL);
		}
	} else
	{
		if (prefs.hex_gui_slist_skip || arg_url)
			new_ircwindow (NULL, NULL, SESS_SERVER, 0);
	}
}

void
hexchat_exit (void)
{
	hexchat_is_quitting = TRUE;
	in_hexchat_exit = TRUE;
	plugin_kill_all ();
	fe_cleanup ();

	save_config ();
	if (prefs.save_pevents)
	{
		pevent_save (NULL);
	}

	sound_save ();
	notify_save ();
	ignore_save ();
	free_sessions ();
	chanopt_save_all ();
	servlist_cleanup ();
	fe_exit ();
}

#ifndef WIN32

static int
child_handler (gpointer userdata)
{
	int pid = GPOINTER_TO_INT (userdata);

	if (waitpid (pid, 0, WNOHANG) == pid)
		return 0;					  /* remove timeout handler */
	return 1;						  /* keep the timeout handler */
}

#endif

void
hexchat_exec (const char *cmd)
{
#ifdef WIN32
	util_exec (cmd);
#else
	int pid = util_exec (cmd);
	if (pid != -1)
	/* zombie avoiding system. Don't ask! it has to be like this to work
      with zvt (which overrides the default handler) */
		fe_timeout_add (1000, child_handler, GINT_TO_POINTER (pid));
#endif
}

void
hexchat_execv (char * const argv[])
{
#ifdef WIN32
	util_execv (argv);
#else
	int pid = util_execv (argv);
	if (pid != -1)
	/* zombie avoiding system. Don't ask! it has to be like this to work
      with zvt (which overrides the default handler) */
		fe_timeout_add (1000, child_handler, GINT_TO_POINTER (pid));
#endif
}

#ifdef WIN32
static void
xchat_restore_window (HWND hexchat_window)
{
	/* ShowWindow (hexchat_window, SW_RESTORE); another way, but works worse */
	SendMessage (hexchat_window, WM_SYSCOMMAND, SC_RESTORE, 0);
	SetForegroundWindow (hexchat_window);
}

BOOL CALLBACK
enum_windows_impl (HWND current_window, LPARAM lParam)
{
	TCHAR window_name[8];
	TCHAR module_path[1024];
	ZeroMemory (&window_name, sizeof (window_name));

	if (!current_window)
	{
		return TRUE;
	}

	GetWindowText (current_window, window_name, 8);		/* name length + 1 */
	if (strcmp (window_name, "HexChat") == 0)
	{
		/* use a separate if block, this way we don't have to call GetWindowModuleFileName() for each hit */
		ZeroMemory (&module_path, sizeof (module_path));
		GetWindowModuleFileName (current_window, module_path, sizeof (module_path));

		if (strstr (module_path, "hexchat.exe"))	/* We've found it, stop */
		{
			xchat_restore_window (current_window);
			return FALSE;
		}
	}

	return TRUE;								/* Keep searching */

}
#endif

int
main (int argc, char *argv[])
{
	int ret;

#ifdef WIN32
	char hexchat_lang[13];	/* LC_ALL= plus 5 chars of hex_gui_lang and trailing \0 */
	HANDLE mutex;
#endif

	srand (time (0));	/* CL: do this only once! */

	load_config ();

#ifdef WIN32
	/* we MUST do this after load_config () AND before fe_init (thus gtk_init) otherwise it will fail */
	strcpy (hexchat_lang, "LC_ALL=");

	/* this must be ordered EXACTLY as langsmenu[] */
	switch (prefs.hex_gui_lang)
	{
		case 0:
			strcat (hexchat_lang, "af");
			break;
		case 1:
			strcat (hexchat_lang, "sq");
			break;
		case 2:
			strcat (hexchat_lang, "am");
			break;
		case 3:
			strcat (hexchat_lang, "ast");
			break;
		case 4:
			strcat (hexchat_lang, "az");
			break;
		case 5:
			strcat (hexchat_lang, "eu");
			break;
		case 6:
			strcat (hexchat_lang, "be");
			break;
		case 7:
			strcat (hexchat_lang, "bg");
			break;
		case 8:
			strcat (hexchat_lang, "ca");
			break;
		case 9:
			strcat (hexchat_lang, "zh_CN");
			break;
		case 10:
			strcat (hexchat_lang, "zh_TW");
			break;
		case 11:
			strcat (hexchat_lang, "cs");
			break;
		case 12:
			strcat (hexchat_lang, "da");
			break;
		case 13:
			strcat (hexchat_lang, "nl");
			break;
		case 14:
			strcat (hexchat_lang, "en_GB");
			break;
		case 15:
			strcat (hexchat_lang, "en");
			break;
		case 16:
			strcat (hexchat_lang, "et");
			break;
		case 17:
			strcat (hexchat_lang, "fi");
			break;
		case 18:
			strcat (hexchat_lang, "fr");
			break;
		case 19:
			strcat (hexchat_lang, "gl");
			break;
		case 20:
			strcat (hexchat_lang, "de");
			break;
		case 21:
			strcat (hexchat_lang, "el");
			break;
		case 22:
			strcat (hexchat_lang, "gu");
			break;
		case 23:
			strcat (hexchat_lang, "hi");
			break;
		case 24:
			strcat (hexchat_lang, "hu");
			break;
		case 25:
			strcat (hexchat_lang, "id");
			break;
		case 26:
			strcat (hexchat_lang, "it");
			break;
		case 27:
			strcat (hexchat_lang, "ja");
			break;
		case 28:
			strcat (hexchat_lang, "kn");
			break;
		case 29:
			strcat (hexchat_lang, "rw");
			break;
		case 30:
			strcat (hexchat_lang, "ko");
			break;
		case 31:
			strcat (hexchat_lang, "lv");
			break;
		case 32:
			strcat (hexchat_lang, "lt");
			break;
		case 33:
			strcat (hexchat_lang, "mk");
			break;
		case 34:
			strcat (hexchat_lang, "ml");
			break;
		case 35:
			strcat (hexchat_lang, "ms");
			break;
		case 36:
			strcat (hexchat_lang, "nb");
			break;
		case 37:
			strcat (hexchat_lang, "no");
			break;
		case 38:
			strcat (hexchat_lang, "pl");
			break;
		case 39:
			strcat (hexchat_lang, "pt");
			break;
		case 40:
			strcat (hexchat_lang, "pt_BR");
			break;
		case 41:
			strcat (hexchat_lang, "pa");
			break;
		case 42:
			strcat (hexchat_lang, "ru");
			break;
		case 43:
			strcat (hexchat_lang, "sr");
			break;
		case 44:
			strcat (hexchat_lang, "sk");
			break;
		case 45:
			strcat (hexchat_lang, "sl");
			break;
		case 46:
			strcat (hexchat_lang, "es");
			break;
		case 47:
			strcat (hexchat_lang, "sv");
			break;
		case 48:
			strcat (hexchat_lang, "th");
			break;
		case 49:
			strcat (hexchat_lang, "uk");
			break;
		case 50:
			strcat (hexchat_lang, "vi");
			break;
		case 51:
			strcat (hexchat_lang, "wa");
			break;
		default:
			strcat (hexchat_lang, "en");
			break;
	}

	putenv (hexchat_lang);

	if (prefs.hex_gui_single && !portable_mode ())
	{
		DWORD error;

		mutex = CreateMutex (NULL, TRUE, "Local\\hexchat");
		error = GetLastError ();

		if (error == ERROR_ALREADY_EXISTS || mutex == NULL)
		{
			/* restoring the HexChat window from the tray via the taskbar icon
			 * only works correctly when HexTray is used, but it's not a big deal
			 * since you can only minimize HexChat to tray via the taskbar if you
			 * use HexTray*/
			if (hextray_mode ())
			{
				/* FindWindow() doesn't support wildcards so we check all the open windows */
				EnumWindows (enum_windows_impl, (LPARAM) NULL);
				return 0;
			}
			else
			{
				return 1;
			}
		}
	}
#endif

#ifdef SOCKS
	SOCKSinit (argv[0]);
#endif

	ret = fe_args (argc, argv);
	if (ret != -1)
		return ret;
	
#ifdef USE_DBUS
	hexchat_remote ();
#endif

#ifdef USE_LIBPROXY
	libproxy_factory = px_proxy_factory_new();
#endif

	fe_init ();

	xchat_init ();

	fe_main ();

#ifdef USE_LIBPROXY
	px_proxy_factory_free(libproxy_factory);
#endif

#ifdef USE_OPENSSL
	if (ctx)
		_SSL_context_free (ctx);
#endif

#ifdef USE_DEBUG
	hexchat_mem_list ();
#endif

#ifdef WIN32
	WSACleanup ();

	if (prefs.hex_gui_single && !portable_mode ())
	{
		ReleaseMutex (mutex);
		CloseHandle (mutex);
	}
#endif

	return 0;
}