restructure configure so pkg-config derived SSL flags get used
[rofl0r-ixchat.git] / src / common / xchat.c
blob93ec0784665efb01b2c5119807a6eb22b2c40f82
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_MSPROXY
51 #include "msproxy.h"
52 #endif
54 #ifdef USE_LIBPROXY
55 #include <proxy.h>
56 #endif
58 GSList *popup_list = 0;
59 GSList *button_list = 0;
60 GSList *dlgbutton_list = 0;
61 GSList *command_list = 0;
62 GSList *ctcp_list = 0;
63 GSList *replace_list = 0;
64 GSList *sess_list = 0;
65 GSList *dcc_list = 0;
66 GSList *ignore_list = 0;
67 GSList *usermenu_list = 0;
68 GSList *urlhandler_list = 0;
69 GSList *tabmenu_list = 0;
71 static int in_xchat_exit = FALSE;
72 int xchat_is_quitting = FALSE;
73 /* command-line args */
74 int arg_dont_autoconnect = FALSE;
75 int arg_skip_plugins = FALSE;
76 char *arg_url = NULL;
77 char *arg_command = NULL;
78 gint arg_existing = FALSE;
80 #ifdef USE_DBUS
81 #include "dbus/dbus-client.h"
82 #include "dbus/dbus-plugin.h"
83 #endif /* USE_DBUS */
85 struct session *current_tab;
86 struct session *current_sess = 0;
87 struct xchatprefs prefs;
89 #ifdef USE_LIBPROXY
90 pxProxyFactory *libproxy_factory;
91 #endif
93 int
94 is_session (session * sess)
96 return g_slist_find (sess_list, sess) ? 1 : 0;
99 session *
100 find_dialog (server *serv, char *nick)
102 GSList *list = sess_list;
103 session *sess;
105 while (list)
107 sess = list->data;
108 if (sess->server == serv && sess->type == SESS_DIALOG)
110 if (!serv->p_cmp (nick, sess->channel))
111 return (sess);
113 list = list->next;
115 return 0;
118 session *
119 find_channel (server *serv, char *chan)
121 session *sess;
122 GSList *list = sess_list;
123 while (list)
125 sess = list->data;
126 if ((!serv || serv == sess->server) && sess->type != SESS_DIALOG)
128 if (!serv->p_cmp (chan, sess->channel))
129 return sess;
131 list = list->next;
133 return 0;
136 static void
137 lagcheck_update (void)
139 server *serv;
140 GSList *list = serv_list;
142 if (!prefs.lagometer)
143 return;
145 while (list)
147 serv = list->data;
148 if (serv->lag_sent)
149 fe_set_lag (serv, -1);
151 list = list->next;
155 void
156 lag_check (void)
158 server *serv;
159 GSList *list = serv_list;
160 unsigned long tim;
161 char tbuf[128];
162 time_t now = time (0);
163 int lag;
165 tim = make_ping_time ();
167 while (list)
169 serv = list->data;
170 if (serv->connected && serv->end_of_motd)
172 lag = now - serv->ping_recv;
173 if (prefs.pingtimeout && lag > prefs.pingtimeout && lag > 0)
175 sprintf (tbuf, "%d", lag);
176 EMIT_SIGNAL (XP_TE_PINGTIMEOUT, serv->server_session, tbuf, NULL,
177 NULL, NULL, 0);
178 if (prefs.autoreconnect)
179 serv->auto_reconnect (serv, FALSE, -1);
180 } else
182 snprintf (tbuf, sizeof (tbuf), "LAG%lu", tim);
183 serv->p_ping (serv, "", tbuf);
184 serv->lag_sent = tim;
185 fe_set_lag (serv, -1);
188 list = list->next;
192 static int
193 away_check (void)
195 session *sess;
196 GSList *list;
197 int full, sent, loop = 0;
199 if (!prefs.away_track || prefs.away_size_max < 1)
200 return 1;
202 doover:
203 /* request an update of AWAY status of 1 channel every 30 seconds */
204 full = TRUE;
205 sent = 0; /* number of WHOs (users) requested */
206 list = sess_list;
207 while (list)
209 sess = list->data;
211 if (sess->server->connected &&
212 sess->type == SESS_CHANNEL &&
213 sess->channel[0] &&
214 sess->total <= prefs.away_size_max)
216 if (!sess->done_away_check)
218 full = FALSE;
220 /* if we're under 31 WHOs, send another channels worth */
221 if (sent < 31 && !sess->doing_who)
223 sess->done_away_check = TRUE;
224 sess->doing_who = TRUE;
225 /* this'll send a WHO #channel */
226 sess->server->p_away_status (sess->server, sess->channel);
227 sent += sess->total;
232 list = list->next;
235 /* done them all, reset done_away_check to FALSE and start over unless we have away-notify */
236 if (full)
238 list = sess_list;
239 while (list)
241 sess = list->data;
242 if (!sess->server->have_awaynotify)
243 sess->done_away_check = FALSE;
244 list = list->next;
246 loop++;
247 if (loop < 2)
248 goto doover;
251 return 1;
254 static int
255 xchat_misc_checks (void) /* this gets called every 1/2 second */
257 static int count = 0;
258 #ifdef USE_MSPROXY
259 static int count2 = 0;
260 #endif
262 count++;
264 lagcheck_update (); /* every 500ms */
266 if (count % 2)
267 dcc_check_timeouts (); /* every 1 second */
269 if (count >= 60) /* every 30 seconds */
271 if (prefs.lagometer)
272 lag_check ();
273 count = 0;
276 #ifdef USE_MSPROXY
277 count2++;
278 if (count2 >= 720) /* 720 every 6 minutes */
280 msproxy_keepalive ();
281 count2 = 0;
283 #endif
285 return 1;
288 /* executed when the first irc window opens */
290 static void
291 irc_init (session *sess)
293 static int done_init = FALSE;
294 char buf[512];
296 if (done_init)
297 return;
299 done_init = TRUE;
301 plugin_add (sess, NULL, NULL, timer_plugin_init, NULL, NULL, FALSE);
303 #ifdef USE_PLUGIN
304 if (!arg_skip_plugins)
305 plugin_auto_load (sess); /* autoload ~/.xchat *.so */
306 #endif
308 #ifdef USE_DBUS
309 plugin_add (sess, NULL, NULL, dbus_plugin_init, NULL, NULL, FALSE);
310 #endif
312 if (prefs.notify_timeout)
313 notify_tag = fe_timeout_add (prefs.notify_timeout * 1000,
314 notify_checklist, 0);
316 fe_timeout_add (prefs.away_timeout * 1000, away_check, 0);
317 fe_timeout_add (500, xchat_misc_checks, 0);
319 if (arg_url != NULL)
321 snprintf (buf, sizeof (buf), "server %s", arg_url);
322 handle_command (sess, buf, FALSE);
323 g_free (arg_url); /* from GOption */
326 if (arg_command != NULL)
328 g_free (arg_command);
331 /* load -e ~/.xchat2/startup.txt */
332 snprintf (buf, sizeof (buf), "%s/%s", get_xdir_fs (), "startup.txt");
333 load_perform_file (sess, buf);
336 static session *
337 session_new (server *serv, char *from, int type, int focus)
339 session *sess;
341 sess = malloc (sizeof (struct session));
342 memset (sess, 0, sizeof (struct session));
344 sess->server = serv;
345 sess->logfd = -1;
346 sess->scrollfd = -1;
347 sess->type = type;
349 sess->alert_beep = SET_DEFAULT;
350 sess->alert_taskbar = SET_DEFAULT;
351 sess->alert_tray = SET_DEFAULT;
353 sess->text_hidejoinpart = SET_DEFAULT;
354 sess->text_logging = SET_DEFAULT;
355 sess->text_scrollback = SET_DEFAULT;
357 if (from != NULL)
358 safe_strcpy (sess->channel, from, CHANLEN);
360 sess_list = g_slist_prepend (sess_list, sess);
362 fe_new_window (sess, focus);
364 return sess;
367 session *
368 new_ircwindow (server *serv, char *name, int type, int focus)
370 session *sess;
372 switch (type)
374 case SESS_SERVER:
375 serv = server_new ();
376 if (prefs.use_server_tab)
377 sess = session_new (serv, name, SESS_SERVER, focus);
378 else
379 sess = session_new (serv, name, SESS_CHANNEL, focus);
380 serv->server_session = sess;
381 serv->front_session = sess;
382 break;
383 case SESS_DIALOG:
384 sess = session_new (serv, name, type, focus);
385 log_open_or_close (sess);
386 break;
387 default:
388 /* case SESS_CHANNEL:
389 case SESS_NOTICES:
390 case SESS_SNOTICES:*/
391 sess = session_new (serv, name, type, focus);
392 break;
395 irc_init (sess);
396 scrollback_load (sess);
397 chanopt_load (sess);
398 plugin_emit_dummy_print (sess, "Open Context");
400 return sess;
403 static void
404 exec_notify_kill (session * sess)
406 struct nbexec *re;
407 if (sess->running_exec != NULL)
409 re = sess->running_exec;
410 sess->running_exec = NULL;
411 kill (re->childpid, SIGKILL);
412 waitpid (re->childpid, NULL, WNOHANG);
413 fe_input_remove (re->iotag);
414 close (re->myfd);
415 if (re->linebuf)
416 free(re->linebuf);
417 free (re);
421 static void
422 send_quit_or_part (session * killsess)
424 int willquit = TRUE;
425 GSList *list;
426 session *sess;
427 server *killserv = killsess->server;
429 /* check if this is the last session using this server */
430 list = sess_list;
431 while (list)
433 sess = (session *) list->data;
434 if (sess->server == killserv && sess != killsess)
436 willquit = FALSE;
437 list = 0;
438 } else
439 list = list->next;
442 if (xchat_is_quitting)
443 willquit = TRUE;
445 if (killserv->connected)
447 if (willquit)
449 if (!killserv->sent_quit)
451 killserv->flush_queue (killserv);
452 server_sendquit (killsess);
453 killserv->sent_quit = TRUE;
455 } else
457 if (killsess->type == SESS_CHANNEL && killsess->channel[0] &&
458 !killserv->sent_quit)
460 server_sendpart (killserv, killsess->channel, 0);
466 void
467 session_free (session *killsess)
469 server *killserv = killsess->server;
470 session *sess;
471 GSList *list;
473 plugin_emit_dummy_print (killsess, "Close Context");
475 if (current_tab == killsess)
476 current_tab = NULL;
478 if (killserv->server_session == killsess)
479 killserv->server_session = NULL;
481 if (killserv->front_session == killsess)
483 /* front_session is closed, find a valid replacement */
484 killserv->front_session = NULL;
485 list = sess_list;
486 while (list)
488 sess = (session *) list->data;
489 if (sess != killsess && sess->server == killserv)
491 killserv->front_session = sess;
492 if (!killserv->server_session)
493 killserv->server_session = sess;
494 break;
496 list = list->next;
500 if (!killserv->server_session)
501 killserv->server_session = killserv->front_session;
503 sess_list = g_slist_remove (sess_list, killsess);
505 if (killsess->type == SESS_CHANNEL)
506 userlist_free (killsess);
508 exec_notify_kill (killsess);
510 log_close (killsess);
511 scrollback_close (killsess);
512 chanopt_save (killsess);
514 send_quit_or_part (killsess);
516 history_free (&killsess->history);
517 if (killsess->topic)
518 free (killsess->topic);
519 if (killsess->current_modes)
520 free (killsess->current_modes);
522 fe_session_callback (killsess);
524 if (current_sess == killsess)
526 current_sess = NULL;
527 if (sess_list)
528 current_sess = sess_list->data;
531 free (killsess);
533 if (!sess_list && !in_xchat_exit)
534 xchat_exit (); /* sess_list is empty, quit! */
536 list = sess_list;
537 while (list)
539 sess = (session *) list->data;
540 if (sess->server == killserv)
541 return; /* this server is still being used! */
542 list = list->next;
545 server_free (killserv);
548 static void
549 free_sessions (void)
551 GSList *list = sess_list;
553 while (list)
555 fe_close_window (list->data);
556 list = sess_list;
561 static char defaultconf_ctcp[] =
562 "NAME TIME\n" "CMD nctcp %s TIME %t\n\n"\
563 "NAME PING\n" "CMD nctcp %s PING %d\n\n";
565 static char defaultconf_replace[] =
566 "NAME teh\n" "CMD the\n\n";
567 /* "NAME r\n" "CMD are\n\n"\
568 "NAME u\n" "CMD you\n\n"*/
570 static char defaultconf_commands[] =
571 "NAME ACTION\n" "CMD me &2\n\n"\
572 "NAME AME\n" "CMD allchan me &2\n\n"\
573 "NAME ANICK\n" "CMD allserv nick &2\n\n"\
574 "NAME AMSG\n" "CMD allchan say &2\n\n"\
575 "NAME BANLIST\n" "CMD quote MODE %c +b\n\n"\
576 "NAME CHAT\n" "CMD dcc chat %2\n\n"\
577 "NAME DIALOG\n" "CMD query %2\n\n"\
578 "NAME DMSG\n" "CMD msg =%2 &3\n\n"\
579 "NAME EXIT\n" "CMD quit\n\n"\
580 "NAME GREP\n" "CMD lastlog -r &2\n\n"\
581 "NAME J\n" "CMD join &2\n\n"\
582 "NAME KILL\n" "CMD quote KILL %2 :&3\n\n"\
583 "NAME LEAVE\n" "CMD part &2\n\n"\
584 "NAME M\n" "CMD msg &2\n\n"\
585 "NAME ONOTICE\n" "CMD notice @%c &2\n\n"\
586 "NAME RAW\n" "CMD quote &2\n\n"\
587 "NAME SERVHELP\n" "CMD quote HELP\n\n"\
588 "NAME SPING\n" "CMD ping\n\n"\
589 "NAME SQUERY\n" "CMD quote SQUERY %2 :&3\n\n"\
590 "NAME SSLSERVER\n" "CMD server -ssl &2\n\n"\
591 "NAME SV\n" "CMD echo xchat %v %m\n\n"\
592 "NAME UMODE\n" "CMD mode %n &2\n\n"\
593 "NAME UPTIME\n" "CMD quote STATS u\n\n"\
594 "NAME VER\n" "CMD ctcp %2 VERSION\n\n"\
595 "NAME VERSION\n" "CMD ctcp %2 VERSION\n\n"\
596 "NAME WALLOPS\n" "CMD quote WALLOPS :&2\n\n"\
597 "NAME WII\n" "CMD quote WHOIS %2 %2\n\n";
599 static char defaultconf_urlhandlers[] =
600 "NAME Open Link in Opera\n" "CMD !opera -remote 'openURL(%s)'\n\n";
602 #ifdef USE_SIGACTION
603 /* Close and open log files on SIGUSR1. Usefull for log rotating */
605 static void
606 sigusr1_handler (int signal, siginfo_t *si, void *un)
608 GSList *list = sess_list;
609 session *sess;
611 while (list)
613 sess = list->data;
614 log_open_or_close (sess);
615 list = list->next;
619 /* Execute /SIGUSR2 when SIGUSR2 received */
621 static void
622 sigusr2_handler (int signal, siginfo_t *si, void *un)
624 session *sess = current_sess;
626 if (sess)
627 handle_command (sess, "SIGUSR2", FALSE);
629 #endif
631 static gint
632 xchat_auto_connect (gpointer userdata)
634 servlist_auto_connect (NULL);
635 return 0;
638 static void
639 xchat_init (void)
641 char buf[3068];
642 const char *cs = NULL;
644 #ifdef USE_SIGACTION
645 struct sigaction act;
647 /* ignore SIGPIPE's */
648 act.sa_handler = SIG_IGN;
649 act.sa_flags = 0;
650 sigemptyset (&act.sa_mask);
651 sigaction (SIGPIPE, &act, NULL);
653 /* Deal with SIGUSR1's & SIGUSR2's */
654 act.sa_sigaction = sigusr1_handler;
655 act.sa_flags = 0;
656 sigemptyset (&act.sa_mask);
657 sigaction (SIGUSR1, &act, NULL);
659 act.sa_sigaction = sigusr2_handler;
660 act.sa_flags = 0;
661 sigemptyset (&act.sa_mask);
662 sigaction (SIGUSR2, &act, NULL);
663 #else
664 /* good enough for these old systems */
665 signal (SIGPIPE, SIG_IGN);
666 #endif
668 if (g_get_charset (&cs))
669 prefs.utf8_locale = TRUE;
671 load_text_events ();
672 sound_load ();
673 notify_load ();
674 ignore_load ();
676 snprintf (buf, sizeof (buf),
677 "NAME %s~%s~\n" "CMD query %%s\n\n"\
678 "NAME %s~%s~\n" "CMD send %%s\n\n"\
679 "NAME %s~%s~\n" "CMD whois %%s %%s\n\n"\
680 "NAME %s~%s~\n" "CMD notify -n ASK %%s\n\n"\
682 "NAME SUB\n" "CMD %s\n\n"\
683 "NAME %s\n" "CMD op %%a\n\n"\
684 "NAME %s\n" "CMD deop %%a\n\n"\
685 "NAME SEP\n" "CMD \n\n"\
686 "NAME %s\n" "CMD voice %%a\n\n"\
687 "NAME %s\n" "CMD devoice %%a\n"\
688 "NAME SEP\n" "CMD \n\n"\
689 "NAME SUB\n" "CMD %s\n\n"\
690 "NAME %s\n" "CMD kick %%s\n\n"\
691 "NAME %s\n" "CMD ban %%s\n\n"\
692 "NAME SEP\n" "CMD \n\n"\
693 "NAME %s *!*@*.host\n""CMD ban %%s 0\n\n"\
694 "NAME %s *!*@domain\n""CMD ban %%s 1\n\n"\
695 "NAME %s *!*user@*.host\n""CMD ban %%s 2\n\n"\
696 "NAME %s *!*user@domain\n""CMD ban %%s 3\n\n"\
697 "NAME SEP\n" "CMD \n\n"\
698 "NAME %s *!*@*.host\n""CMD kickban %%s 0\n\n"\
699 "NAME %s *!*@domain\n""CMD kickban %%s 1\n\n"\
700 "NAME %s *!*user@*.host\n""CMD kickban %%s 2\n\n"\
701 "NAME %s *!*user@domain\n""CMD kickban %%s 3\n\n"\
702 "NAME ENDSUB\n" "CMD \n\n"\
703 "NAME ENDSUB\n" "CMD \n\n",
705 _("_Open Dialog Window"), "xchat-dialog",
706 _("_Send a File"), "gtk-floppy",
707 _("_User Info (WhoIs)"), "gtk-info",
708 _("_Add to Friends List"), "gtk-add",
709 _("O_perator Actions"),
711 _("Give Ops"),
712 _("Take Ops"),
713 _("Give Voice"),
714 _("Take Voice"),
716 _("Kick/Ban"),
717 _("Kick"),
718 _("Ban"),
719 _("Ban"),
720 _("Ban"),
721 _("Ban"),
722 _("Ban"),
723 _("KickBan"),
724 _("KickBan"),
725 _("KickBan"),
726 _("KickBan"));
728 list_loadconf ("popup.conf", &popup_list, buf);
730 snprintf (buf, sizeof (buf),
731 "NAME %s\n" "CMD part\n\n"
732 "NAME %s\n" "CMD getstr # join \"%s\"\n\n"
733 "NAME %s\n" "CMD quote LINKS\n\n"
734 "NAME %s\n" "CMD ping\n\n"
735 "NAME TOGGLE %s\n" "CMD irc_hide_version\n\n",
736 _("Leave Channel"),
737 _("Join Channel..."),
738 _("Enter Channel to Join:"),
739 _("Server Links"),
740 _("Ping Server"),
741 _("Hide Version"));
742 list_loadconf ("usermenu.conf", &usermenu_list, buf);
744 snprintf (buf, sizeof (buf),
745 "NAME %s\n" "CMD op %%a\n\n"
746 "NAME %s\n" "CMD deop %%a\n\n"
747 "NAME %s\n" "CMD ban %%s\n\n"
748 "NAME %s\n" "CMD getstr \"%s\" \"kick %%s\" \"%s\"\n\n"
749 "NAME %s\n" "CMD send %%s\n\n"
750 "NAME %s\n" "CMD query %%s\n\n",
751 _("Op"),
752 _("DeOp"),
753 _("Ban"),
754 _("Kick"),
755 _("bye"),
756 _("Enter reason to kick %s:"),
757 _("Sendfile"),
758 _("Dialog"));
759 list_loadconf ("buttons.conf", &button_list, buf);
761 snprintf (buf, sizeof (buf),
762 "NAME %s\n" "CMD whois %%s %%s\n\n"
763 "NAME %s\n" "CMD send %%s\n\n"
764 "NAME %s\n" "CMD dcc chat %%s\n\n"
765 "NAME %s\n" "CMD clear\n\n"
766 "NAME %s\n" "CMD ping %%s\n\n",
767 _("WhoIs"),
768 _("Send"),
769 _("Chat"),
770 _("Clear"),
771 _("Ping"));
772 list_loadconf ("dlgbuttons.conf", &dlgbutton_list, buf);
774 list_loadconf ("tabmenu.conf", &tabmenu_list, NULL);
775 list_loadconf ("ctcpreply.conf", &ctcp_list, defaultconf_ctcp);
776 list_loadconf ("commands.conf", &command_list, defaultconf_commands);
777 list_loadconf ("replace.conf", &replace_list, defaultconf_replace);
778 list_loadconf ("urlhandlers.conf", &urlhandler_list,
779 defaultconf_urlhandlers);
781 servlist_init (); /* load server list */
783 /* if we got a URL, don't open the server list GUI */
784 if (!prefs.slist_skip && !arg_url)
785 fe_serverlist_open (NULL);
787 /* turned OFF via -a arg */
788 if (!arg_dont_autoconnect)
790 /* do any auto connects */
791 if (!servlist_have_auto ()) /* if no new windows open .. */
793 /* and no serverlist gui ... */
794 if (prefs.slist_skip || arg_url)
795 /* we'll have to open one. */
796 new_ircwindow (NULL, NULL, SESS_SERVER, 0);
797 } else
799 fe_idle_add (xchat_auto_connect, NULL);
801 } else
803 if (prefs.slist_skip || arg_url)
804 new_ircwindow (NULL, NULL, SESS_SERVER, 0);
808 void
809 xchat_exit (void)
811 xchat_is_quitting = TRUE;
812 in_xchat_exit = TRUE;
813 plugin_kill_all ();
814 fe_cleanup ();
815 if (prefs.autosave)
817 save_config ();
818 if (prefs.save_pevents)
819 pevent_save (NULL);
821 if (prefs.autosave_url)
822 url_autosave ();
823 sound_save ();
824 notify_save ();
825 ignore_save ();
826 free_sessions ();
827 chanopt_save_all ();
828 servlist_cleanup ();
829 fe_exit ();
832 static int
833 child_handler (gpointer userdata)
835 int pid = GPOINTER_TO_INT (userdata);
837 if (waitpid (pid, 0, WNOHANG) == pid)
838 return 0; /* remove timeout handler */
839 return 1; /* keep the timeout handler */
842 void
843 xchat_exec (const char *cmd)
845 int pid = util_exec (cmd);
846 if (pid != -1)
847 /* zombie avoiding system. Don't ask! it has to be like this to work
848 with zvt (which overrides the default handler) */
849 fe_timeout_add (1000, child_handler, GINT_TO_POINTER (pid));
852 void
853 xchat_execv (char * const argv[])
855 int pid = util_execv (argv);
856 if (pid != -1)
857 /* zombie avoiding system. Don't ask! it has to be like this to work
858 with zvt (which overrides the default handler) */
859 fe_timeout_add (1000, child_handler, GINT_TO_POINTER (pid));
863 main (int argc, char *argv[])
865 int ret;
867 srand (time (0)); /* CL: do this only once! */
869 #ifdef SOCKS
870 SOCKSinit (argv[0]);
871 #endif
873 ret = fe_args (argc, argv);
874 if (ret != -1)
875 return ret;
877 #ifdef USE_DBUS
878 xchat_remote ();
879 #endif
881 load_config ();
883 #ifdef USE_LIBPROXY
884 libproxy_factory = px_proxy_factory_new();
885 #endif
887 fe_init ();
889 xchat_init ();
891 fe_main ();
893 #ifdef USE_LIBPROXY
894 px_proxy_factory_free(libproxy_factory);
895 #endif
897 #ifdef USE_DEBUG
898 xchat_mem_list ();
899 #endif
901 return 0;