remove all remaining WIN32 code
[rofl0r-ixchat.git] / src / common / xchat.c
blob2cdb7e9d424fed587bffa5cc2df6cec59e870610
1 /* X-Chat
2 * Copyright (C) 1998 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <time.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
27 #define WANTSOCKET
28 #include "inet.h"
30 #include <sys/wait.h>
31 #include <signal.h>
33 #include "xchat.h"
34 #include "fe.h"
35 #include "util.h"
36 #include "cfgfiles.h"
37 #include "chanopt.h"
38 #include "ignore.h"
39 #include "xchat-plugin.h"
40 #include "plugin.h"
41 #include "plugin-timer.h"
42 #include "notify.h"
43 #include "server.h"
44 #include "servlist.h"
45 #include "outbound.h"
46 #include "text.h"
47 #include "url.h"
48 #include "xchatc.h"
50 #ifdef USE_OPENSSL
51 #include <openssl/ssl.h> /* SSL_() */
52 #include "ssl.h"
53 #endif
55 #ifdef USE_MSPROXY
56 #include "msproxy.h"
57 #endif
59 #ifdef USE_LIBPROXY
60 #include <proxy.h>
61 #endif
63 GSList *popup_list = 0;
64 GSList *button_list = 0;
65 GSList *dlgbutton_list = 0;
66 GSList *command_list = 0;
67 GSList *ctcp_list = 0;
68 GSList *replace_list = 0;
69 GSList *sess_list = 0;
70 GSList *dcc_list = 0;
71 GSList *ignore_list = 0;
72 GSList *usermenu_list = 0;
73 GSList *urlhandler_list = 0;
74 GSList *tabmenu_list = 0;
76 static int in_xchat_exit = FALSE;
77 int xchat_is_quitting = FALSE;
78 /* command-line args */
79 int arg_dont_autoconnect = FALSE;
80 int arg_skip_plugins = FALSE;
81 char *arg_url = NULL;
82 char *arg_command = NULL;
83 gint arg_existing = FALSE;
85 #ifdef USE_DBUS
86 #include "dbus/dbus-client.h"
87 #include "dbus/dbus-plugin.h"
88 #endif /* USE_DBUS */
90 struct session *current_tab;
91 struct session *current_sess = 0;
92 struct xchatprefs prefs;
94 #ifdef USE_OPENSSL
95 SSL_CTX *ctx = NULL;
96 #endif
98 #ifdef USE_LIBPROXY
99 pxProxyFactory *libproxy_factory;
100 #endif
103 is_session (session * sess)
105 return g_slist_find (sess_list, sess) ? 1 : 0;
108 session *
109 find_dialog (server *serv, char *nick)
111 GSList *list = sess_list;
112 session *sess;
114 while (list)
116 sess = list->data;
117 if (sess->server == serv && sess->type == SESS_DIALOG)
119 if (!serv->p_cmp (nick, sess->channel))
120 return (sess);
122 list = list->next;
124 return 0;
127 session *
128 find_channel (server *serv, char *chan)
130 session *sess;
131 GSList *list = sess_list;
132 while (list)
134 sess = list->data;
135 if ((!serv || serv == sess->server) && sess->type != SESS_DIALOG)
137 if (!serv->p_cmp (chan, sess->channel))
138 return sess;
140 list = list->next;
142 return 0;
145 static void
146 lagcheck_update (void)
148 server *serv;
149 GSList *list = serv_list;
151 if (!prefs.lagometer)
152 return;
154 while (list)
156 serv = list->data;
157 if (serv->lag_sent)
158 fe_set_lag (serv, -1);
160 list = list->next;
164 void
165 lag_check (void)
167 server *serv;
168 GSList *list = serv_list;
169 unsigned long tim;
170 char tbuf[128];
171 time_t now = time (0);
172 int lag;
174 tim = make_ping_time ();
176 while (list)
178 serv = list->data;
179 if (serv->connected && serv->end_of_motd)
181 lag = now - serv->ping_recv;
182 if (prefs.pingtimeout && lag > prefs.pingtimeout && lag > 0)
184 sprintf (tbuf, "%d", lag);
185 EMIT_SIGNAL (XP_TE_PINGTIMEOUT, serv->server_session, tbuf, NULL,
186 NULL, NULL, 0);
187 if (prefs.autoreconnect)
188 serv->auto_reconnect (serv, FALSE, -1);
189 } else
191 snprintf (tbuf, sizeof (tbuf), "LAG%lu", tim);
192 serv->p_ping (serv, "", tbuf);
193 serv->lag_sent = tim;
194 fe_set_lag (serv, -1);
197 list = list->next;
201 static int
202 away_check (void)
204 session *sess;
205 GSList *list;
206 int full, sent, loop = 0;
208 if (!prefs.away_track || prefs.away_size_max < 1)
209 return 1;
211 doover:
212 /* request an update of AWAY status of 1 channel every 30 seconds */
213 full = TRUE;
214 sent = 0; /* number of WHOs (users) requested */
215 list = sess_list;
216 while (list)
218 sess = list->data;
220 if (sess->server->connected &&
221 sess->type == SESS_CHANNEL &&
222 sess->channel[0] &&
223 sess->total <= prefs.away_size_max)
225 if (!sess->done_away_check)
227 full = FALSE;
229 /* if we're under 31 WHOs, send another channels worth */
230 if (sent < 31 && !sess->doing_who)
232 sess->done_away_check = TRUE;
233 sess->doing_who = TRUE;
234 /* this'll send a WHO #channel */
235 sess->server->p_away_status (sess->server, sess->channel);
236 sent += sess->total;
241 list = list->next;
244 /* done them all, reset done_away_check to FALSE and start over */
245 if (full)
247 list = sess_list;
248 while (list)
250 sess = list->data;
251 sess->done_away_check = FALSE;
252 list = list->next;
254 loop++;
255 if (loop < 2)
256 goto doover;
259 return 1;
262 static int
263 xchat_misc_checks (void) /* this gets called every 1/2 second */
265 static int count = 0;
266 #ifdef USE_MSPROXY
267 static int count2 = 0;
268 #endif
270 count++;
272 lagcheck_update (); /* every 500ms */
274 if (count % 2)
275 dcc_check_timeouts (); /* every 1 second */
277 if (count >= 60) /* every 30 seconds */
279 if (prefs.lagometer)
280 lag_check ();
281 count = 0;
284 #ifdef USE_MSPROXY
285 count2++;
286 if (count2 >= 720) /* 720 every 6 minutes */
288 msproxy_keepalive ();
289 count2 = 0;
291 #endif
293 return 1;
296 /* executed when the first irc window opens */
298 static void
299 irc_init (session *sess)
301 static int done_init = FALSE;
302 char buf[512];
304 if (done_init)
305 return;
307 done_init = TRUE;
309 plugin_add (sess, NULL, NULL, timer_plugin_init, NULL, NULL, FALSE);
311 #ifdef USE_PLUGIN
312 if (!arg_skip_plugins)
313 plugin_auto_load (sess); /* autoload ~/.xchat *.so */
314 #endif
316 #ifdef USE_DBUS
317 plugin_add (sess, NULL, NULL, dbus_plugin_init, NULL, NULL, FALSE);
318 #endif
320 if (prefs.notify_timeout)
321 notify_tag = fe_timeout_add (prefs.notify_timeout * 1000,
322 notify_checklist, 0);
324 fe_timeout_add (prefs.away_timeout * 1000, away_check, 0);
325 fe_timeout_add (500, xchat_misc_checks, 0);
327 if (arg_url != NULL)
329 snprintf (buf, sizeof (buf), "server %s", arg_url);
330 handle_command (sess, buf, FALSE);
331 g_free (arg_url); /* from GOption */
334 if (arg_command != NULL)
336 g_free (arg_command);
339 /* load -e ~/.xchat2/startup.txt */
340 snprintf (buf, sizeof (buf), "%s/%s", get_xdir_fs (), "startup.txt");
341 load_perform_file (sess, buf);
344 static session *
345 session_new (server *serv, char *from, int type, int focus)
347 session *sess;
349 sess = malloc (sizeof (struct session));
350 memset (sess, 0, sizeof (struct session));
352 sess->server = serv;
353 sess->logfd = -1;
354 sess->scrollfd = -1;
355 sess->type = type;
357 sess->alert_beep = SET_DEFAULT;
358 sess->alert_taskbar = SET_DEFAULT;
359 sess->alert_tray = SET_DEFAULT;
361 sess->text_hidejoinpart = SET_DEFAULT;
362 sess->text_logging = SET_DEFAULT;
363 sess->text_scrollback = SET_DEFAULT;
365 if (from != NULL)
366 safe_strcpy (sess->channel, from, CHANLEN);
368 sess_list = g_slist_prepend (sess_list, sess);
370 fe_new_window (sess, focus);
372 return sess;
375 session *
376 new_ircwindow (server *serv, char *name, int type, int focus)
378 session *sess;
380 switch (type)
382 case SESS_SERVER:
383 serv = server_new ();
384 if (prefs.use_server_tab)
385 sess = session_new (serv, name, SESS_SERVER, focus);
386 else
387 sess = session_new (serv, name, SESS_CHANNEL, focus);
388 serv->server_session = sess;
389 serv->front_session = sess;
390 break;
391 case SESS_DIALOG:
392 sess = session_new (serv, name, type, focus);
393 log_open_or_close (sess);
394 break;
395 default:
396 /* case SESS_CHANNEL:
397 case SESS_NOTICES:
398 case SESS_SNOTICES:*/
399 sess = session_new (serv, name, type, focus);
400 break;
403 irc_init (sess);
404 scrollback_load (sess);
405 chanopt_load (sess);
406 plugin_emit_dummy_print (sess, "Open Context");
408 return sess;
411 static void
412 exec_notify_kill (session * sess)
414 struct nbexec *re;
415 if (sess->running_exec != NULL)
417 re = sess->running_exec;
418 sess->running_exec = NULL;
419 kill (re->childpid, SIGKILL);
420 waitpid (re->childpid, NULL, WNOHANG);
421 fe_input_remove (re->iotag);
422 close (re->myfd);
423 if (re->linebuf)
424 free(re->linebuf);
425 free (re);
429 static void
430 send_quit_or_part (session * killsess)
432 int willquit = TRUE;
433 GSList *list;
434 session *sess;
435 server *killserv = killsess->server;
437 /* check if this is the last session using this server */
438 list = sess_list;
439 while (list)
441 sess = (session *) list->data;
442 if (sess->server == killserv && sess != killsess)
444 willquit = FALSE;
445 list = 0;
446 } else
447 list = list->next;
450 if (xchat_is_quitting)
451 willquit = TRUE;
453 if (killserv->connected)
455 if (willquit)
457 if (!killserv->sent_quit)
459 killserv->flush_queue (killserv);
460 server_sendquit (killsess);
461 killserv->sent_quit = TRUE;
463 } else
465 if (killsess->type == SESS_CHANNEL && killsess->channel[0] &&
466 !killserv->sent_quit)
468 server_sendpart (killserv, killsess->channel, 0);
474 void
475 session_free (session *killsess)
477 server *killserv = killsess->server;
478 session *sess;
479 GSList *list;
481 plugin_emit_dummy_print (killsess, "Close Context");
483 if (current_tab == killsess)
484 current_tab = NULL;
486 if (killserv->server_session == killsess)
487 killserv->server_session = NULL;
489 if (killserv->front_session == killsess)
491 /* front_session is closed, find a valid replacement */
492 killserv->front_session = NULL;
493 list = sess_list;
494 while (list)
496 sess = (session *) list->data;
497 if (sess != killsess && sess->server == killserv)
499 killserv->front_session = sess;
500 if (!killserv->server_session)
501 killserv->server_session = sess;
502 break;
504 list = list->next;
508 if (!killserv->server_session)
509 killserv->server_session = killserv->front_session;
511 sess_list = g_slist_remove (sess_list, killsess);
513 if (killsess->type == SESS_CHANNEL)
514 userlist_free (killsess);
516 exec_notify_kill (killsess);
518 log_close (killsess);
519 scrollback_close (killsess);
520 chanopt_save (killsess);
522 send_quit_or_part (killsess);
524 history_free (&killsess->history);
525 if (killsess->topic)
526 free (killsess->topic);
527 if (killsess->current_modes)
528 free (killsess->current_modes);
530 fe_session_callback (killsess);
532 if (current_sess == killsess)
534 current_sess = NULL;
535 if (sess_list)
536 current_sess = sess_list->data;
539 free (killsess);
541 if (!sess_list && !in_xchat_exit)
542 xchat_exit (); /* sess_list is empty, quit! */
544 list = sess_list;
545 while (list)
547 sess = (session *) list->data;
548 if (sess->server == killserv)
549 return; /* this server is still being used! */
550 list = list->next;
553 server_free (killserv);
556 static void
557 free_sessions (void)
559 GSList *list = sess_list;
561 while (list)
563 fe_close_window (list->data);
564 list = sess_list;
569 static char defaultconf_ctcp[] =
570 "NAME TIME\n" "CMD nctcp %s TIME %t\n\n"\
571 "NAME PING\n" "CMD nctcp %s PING %d\n\n";
573 static char defaultconf_replace[] =
574 "NAME teh\n" "CMD the\n\n";
575 /* "NAME r\n" "CMD are\n\n"\
576 "NAME u\n" "CMD you\n\n"*/
578 static char defaultconf_commands[] =
579 "NAME ACTION\n" "CMD me &2\n\n"\
580 "NAME AME\n" "CMD allchan me &2\n\n"\
581 "NAME ANICK\n" "CMD allserv nick &2\n\n"\
582 "NAME AMSG\n" "CMD allchan say &2\n\n"\
583 "NAME BANLIST\n" "CMD quote MODE %c +b\n\n"\
584 "NAME CHAT\n" "CMD dcc chat %2\n\n"\
585 "NAME DIALOG\n" "CMD query %2\n\n"\
586 "NAME DMSG\n" "CMD msg =%2 &3\n\n"\
587 "NAME EXIT\n" "CMD quit\n\n"\
588 "NAME GREP\n" "CMD lastlog -r &2\n\n"\
589 "NAME J\n" "CMD join &2\n\n"\
590 "NAME KILL\n" "CMD quote KILL %2 :&3\n\n"\
591 "NAME LEAVE\n" "CMD part &2\n\n"\
592 "NAME M\n" "CMD msg &2\n\n"\
593 "NAME ONOTICE\n" "CMD notice @%c &2\n\n"\
594 "NAME RAW\n" "CMD quote &2\n\n"\
595 "NAME SERVHELP\n" "CMD quote HELP\n\n"\
596 "NAME SPING\n" "CMD ping\n\n"\
597 "NAME SQUERY\n" "CMD quote SQUERY %2 :&3\n\n"\
598 "NAME SSLSERVER\n" "CMD server -ssl &2\n\n"\
599 "NAME SV\n" "CMD echo xchat %v %m\n\n"\
600 "NAME UMODE\n" "CMD mode %n &2\n\n"\
601 "NAME UPTIME\n" "CMD quote STATS u\n\n"\
602 "NAME VER\n" "CMD ctcp %2 VERSION\n\n"\
603 "NAME VERSION\n" "CMD ctcp %2 VERSION\n\n"\
604 "NAME WALLOPS\n" "CMD quote WALLOPS :&2\n\n"\
605 "NAME WII\n" "CMD quote WHOIS %2 %2\n\n";
607 static char defaultconf_urlhandlers[] =
608 "NAME Open Link in Opera\n" "CMD !opera -remote 'openURL(%s)'\n\n";
610 #ifdef USE_SIGACTION
611 /* Close and open log files on SIGUSR1. Usefull for log rotating */
613 static void
614 sigusr1_handler (int signal, siginfo_t *si, void *un)
616 GSList *list = sess_list;
617 session *sess;
619 while (list)
621 sess = list->data;
622 log_open_or_close (sess);
623 list = list->next;
627 /* Execute /SIGUSR2 when SIGUSR2 received */
629 static void
630 sigusr2_handler (int signal, siginfo_t *si, void *un)
632 session *sess = current_sess;
634 if (sess)
635 handle_command (sess, "SIGUSR2", FALSE);
637 #endif
639 static gint
640 xchat_auto_connect (gpointer userdata)
642 servlist_auto_connect (NULL);
643 return 0;
646 static void
647 xchat_init (void)
649 char buf[3068];
650 const char *cs = NULL;
652 #ifdef USE_SIGACTION
653 struct sigaction act;
655 /* ignore SIGPIPE's */
656 act.sa_handler = SIG_IGN;
657 act.sa_flags = 0;
658 sigemptyset (&act.sa_mask);
659 sigaction (SIGPIPE, &act, NULL);
661 /* Deal with SIGUSR1's & SIGUSR2's */
662 act.sa_sigaction = sigusr1_handler;
663 act.sa_flags = 0;
664 sigemptyset (&act.sa_mask);
665 sigaction (SIGUSR1, &act, NULL);
667 act.sa_sigaction = sigusr2_handler;
668 act.sa_flags = 0;
669 sigemptyset (&act.sa_mask);
670 sigaction (SIGUSR2, &act, NULL);
671 #else
672 /* good enough for these old systems */
673 signal (SIGPIPE, SIG_IGN);
674 #endif
676 if (g_get_charset (&cs))
677 prefs.utf8_locale = TRUE;
679 load_text_events ();
680 sound_load ();
681 notify_load ();
682 ignore_load ();
684 snprintf (buf, sizeof (buf),
685 "NAME %s~%s~\n" "CMD query %%s\n\n"\
686 "NAME %s~%s~\n" "CMD send %%s\n\n"\
687 "NAME %s~%s~\n" "CMD whois %%s %%s\n\n"\
688 "NAME %s~%s~\n" "CMD notify -n ASK %%s\n\n"\
690 "NAME SUB\n" "CMD %s\n\n"\
691 "NAME %s\n" "CMD op %%a\n\n"\
692 "NAME %s\n" "CMD deop %%a\n\n"\
693 "NAME SEP\n" "CMD \n\n"\
694 "NAME %s\n" "CMD voice %%a\n\n"\
695 "NAME %s\n" "CMD devoice %%a\n"\
696 "NAME SEP\n" "CMD \n\n"\
697 "NAME SUB\n" "CMD %s\n\n"\
698 "NAME %s\n" "CMD kick %%s\n\n"\
699 "NAME %s\n" "CMD ban %%s\n\n"\
700 "NAME SEP\n" "CMD \n\n"\
701 "NAME %s *!*@*.host\n""CMD ban %%s 0\n\n"\
702 "NAME %s *!*@domain\n""CMD ban %%s 1\n\n"\
703 "NAME %s *!*user@*.host\n""CMD ban %%s 2\n\n"\
704 "NAME %s *!*user@domain\n""CMD ban %%s 3\n\n"\
705 "NAME SEP\n" "CMD \n\n"\
706 "NAME %s *!*@*.host\n""CMD kickban %%s 0\n\n"\
707 "NAME %s *!*@domain\n""CMD kickban %%s 1\n\n"\
708 "NAME %s *!*user@*.host\n""CMD kickban %%s 2\n\n"\
709 "NAME %s *!*user@domain\n""CMD kickban %%s 3\n\n"\
710 "NAME ENDSUB\n" "CMD \n\n"\
711 "NAME ENDSUB\n" "CMD \n\n",
713 _("_Open Dialog Window"), "xchat-dialog",
714 _("_Send a File"), "gtk-floppy",
715 _("_User Info (WhoIs)"), "gtk-info",
716 _("_Add to Friends List"), "gtk-add",
717 _("O_perator Actions"),
719 _("Give Ops"),
720 _("Take Ops"),
721 _("Give Voice"),
722 _("Take Voice"),
724 _("Kick/Ban"),
725 _("Kick"),
726 _("Ban"),
727 _("Ban"),
728 _("Ban"),
729 _("Ban"),
730 _("Ban"),
731 _("KickBan"),
732 _("KickBan"),
733 _("KickBan"),
734 _("KickBan"));
736 list_loadconf ("popup.conf", &popup_list, buf);
738 snprintf (buf, sizeof (buf),
739 "NAME %s\n" "CMD part\n\n"
740 "NAME %s\n" "CMD getstr # join \"%s\"\n\n"
741 "NAME %s\n" "CMD quote LINKS\n\n"
742 "NAME %s\n" "CMD ping\n\n"
743 "NAME TOGGLE %s\n" "CMD irc_hide_version\n\n",
744 _("Leave Channel"),
745 _("Join Channel..."),
746 _("Enter Channel to Join:"),
747 _("Server Links"),
748 _("Ping Server"),
749 _("Hide Version"));
750 list_loadconf ("usermenu.conf", &usermenu_list, buf);
752 snprintf (buf, sizeof (buf),
753 "NAME %s\n" "CMD op %%a\n\n"
754 "NAME %s\n" "CMD deop %%a\n\n"
755 "NAME %s\n" "CMD ban %%s\n\n"
756 "NAME %s\n" "CMD getstr \"%s\" \"kick %%s\" \"%s\"\n\n"
757 "NAME %s\n" "CMD send %%s\n\n"
758 "NAME %s\n" "CMD query %%s\n\n",
759 _("Op"),
760 _("DeOp"),
761 _("Ban"),
762 _("Kick"),
763 _("bye"),
764 _("Enter reason to kick %s:"),
765 _("Sendfile"),
766 _("Dialog"));
767 list_loadconf ("buttons.conf", &button_list, buf);
769 snprintf (buf, sizeof (buf),
770 "NAME %s\n" "CMD whois %%s %%s\n\n"
771 "NAME %s\n" "CMD send %%s\n\n"
772 "NAME %s\n" "CMD dcc chat %%s\n\n"
773 "NAME %s\n" "CMD clear\n\n"
774 "NAME %s\n" "CMD ping %%s\n\n",
775 _("WhoIs"),
776 _("Send"),
777 _("Chat"),
778 _("Clear"),
779 _("Ping"));
780 list_loadconf ("dlgbuttons.conf", &dlgbutton_list, buf);
782 list_loadconf ("tabmenu.conf", &tabmenu_list, NULL);
783 list_loadconf ("ctcpreply.conf", &ctcp_list, defaultconf_ctcp);
784 list_loadconf ("commands.conf", &command_list, defaultconf_commands);
785 list_loadconf ("replace.conf", &replace_list, defaultconf_replace);
786 list_loadconf ("urlhandlers.conf", &urlhandler_list,
787 defaultconf_urlhandlers);
789 servlist_init (); /* load server list */
791 /* if we got a URL, don't open the server list GUI */
792 if (!prefs.slist_skip && !arg_url)
793 fe_serverlist_open (NULL);
795 /* turned OFF via -a arg */
796 if (!arg_dont_autoconnect)
798 /* do any auto connects */
799 if (!servlist_have_auto ()) /* if no new windows open .. */
801 /* and no serverlist gui ... */
802 if (prefs.slist_skip || arg_url)
803 /* we'll have to open one. */
804 new_ircwindow (NULL, NULL, SESS_SERVER, 0);
805 } else
807 fe_idle_add (xchat_auto_connect, NULL);
809 } else
811 if (prefs.slist_skip || arg_url)
812 new_ircwindow (NULL, NULL, SESS_SERVER, 0);
816 void
817 xchat_exit (void)
819 xchat_is_quitting = TRUE;
820 in_xchat_exit = TRUE;
821 plugin_kill_all ();
822 fe_cleanup ();
823 if (prefs.autosave)
825 save_config ();
826 if (prefs.save_pevents)
827 pevent_save (NULL);
829 if (prefs.autosave_url)
830 url_autosave ();
831 sound_save ();
832 notify_save ();
833 ignore_save ();
834 free_sessions ();
835 chanopt_save_all ();
836 servlist_cleanup ();
837 fe_exit ();
840 static int
841 child_handler (gpointer userdata)
843 int pid = GPOINTER_TO_INT (userdata);
845 if (waitpid (pid, 0, WNOHANG) == pid)
846 return 0; /* remove timeout handler */
847 return 1; /* keep the timeout handler */
850 void
851 xchat_exec (const char *cmd)
853 int pid = util_exec (cmd);
854 if (pid != -1)
855 /* zombie avoiding system. Don't ask! it has to be like this to work
856 with zvt (which overrides the default handler) */
857 fe_timeout_add (1000, child_handler, GINT_TO_POINTER (pid));
860 void
861 xchat_execv (char * const argv[])
863 int pid = util_execv (argv);
864 if (pid != -1)
865 /* zombie avoiding system. Don't ask! it has to be like this to work
866 with zvt (which overrides the default handler) */
867 fe_timeout_add (1000, child_handler, GINT_TO_POINTER (pid));
871 main (int argc, char *argv[])
873 int ret;
875 srand (time (0)); /* CL: do this only once! */
877 #ifdef SOCKS
878 SOCKSinit (argv[0]);
879 #endif
881 ret = fe_args (argc, argv);
882 if (ret != -1)
883 return ret;
885 #ifdef USE_DBUS
886 xchat_remote ();
887 #endif
889 load_config ();
891 #ifdef USE_LIBPROXY
892 libproxy_factory = px_proxy_factory_new();
893 #endif
895 fe_init ();
897 xchat_init ();
899 fe_main ();
901 #ifdef USE_LIBPROXY
902 px_proxy_factory_free(libproxy_factory);
903 #endif
905 #ifdef USE_OPENSSL
906 if (ctx)
907 _SSL_context_free (ctx);
908 #endif
910 #ifdef USE_DEBUG
911 xchat_mem_list ();
912 #endif
914 return 0;