From 1a75c8e1be58a25510642605dcd40c5c65e9c3f3 Mon Sep 17 00:00:00 2001 From: Berke Viktor Date: Wed, 24 Oct 2012 21:33:02 +0200 Subject: A lot more rebranding --- src/common/hexchat.c | 1207 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1207 insertions(+) create mode 100644 src/common/hexchat.c (limited to 'src/common/hexchat.c') diff --git a/src/common/hexchat.c b/src/common/hexchat.c new file mode 100644 index 00000000..66612a30 --- /dev/null +++ b/src/common/hexchat.c @@ -0,0 +1,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 +#include +#include +#include +#include +#include + +#define WANTSOCKET +#include "inet.h" + +#ifdef WIN32 +#include +#else +#include +#include +#include +#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 /* SSL_() */ +#include "ssl.h" +#endif + +#ifdef USE_MSPROXY +#include "msproxy.h" +#endif + +#ifdef USE_LIBPROXY +#include +#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_xchat_exit = FALSE; +int xchat_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 +xchat_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, xchat_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 (xchat_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_xchat_exit) + xchat_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 xchat %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 +xchat_exit (void) +{ + xchat_is_quitting = TRUE; + in_xchat_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 +xchat_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 +xchat_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 xchat_window) +{ + /* ShowWindow (xchat_window, SW_RESTORE); another way, but works worse */ + SendMessage (xchat_window, WM_SYSCOMMAND, SC_RESTORE, 0); + SetForegroundWindow (xchat_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 XChat window from the tray via the taskbar icon + * only works correctly when X-Tray is used, but it's not a big deal + * since you can only minimize XChat to tray via the taskbar if you + * use X-Tray*/ + if (hextray_mode ()) + { + /* FindWindow() doesn't support wildcards so we check all the open windows */ + EnumWindows (enum_windows_impl, 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 + xchat_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 + xchat_mem_list (); +#endif + +#ifdef WIN32 + WSACleanup (); + + if (prefs.hex_gui_single && !portable_mode ()) + { + ReleaseMutex (mutex); + CloseHandle (mutex); + } +#endif + + return 0; +} -- cgit 1.4.1