Now inbound_cap_ls() can enable extensions when a bouncer uses a namespace for the...
[rofl0r-ixchat.git] / src / common / xchat.c
blob6208db0b1efa5d686e261616e618fa215b234a5a
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 unless we have away-notify */
245 if (full)
247 list = sess_list;
248 while (list)
250 sess = list->data;
251 if (!sess->server->have_awaynotify)
252 sess->done_away_check = FALSE;
253 list = list->next;
255 loop++;
256 if (loop < 2)
257 goto doover;
260 return 1;
263 static int
264 xchat_misc_checks (void) /* this gets called every 1/2 second */
266 static int count = 0;
267 #ifdef USE_MSPROXY
268 static int count2 = 0;
269 #endif
271 count++;
273 lagcheck_update (); /* every 500ms */
275 if (count % 2)
276 dcc_check_timeouts (); /* every 1 second */
278 if (count >= 60) /* every 30 seconds */
280 if (prefs.lagometer)
281 lag_check ();
282 count = 0;
285 #ifdef USE_MSPROXY
286 count2++;
287 if (count2 >= 720) /* 720 every 6 minutes */
289 msproxy_keepalive ();
290 count2 = 0;
292 #endif
294 return 1;
297 /* executed when the first irc window opens */
299 static void
300 irc_init (session *sess)
302 static int done_init = FALSE;
303 char buf[512];
305 if (done_init)
306 return;
308 done_init = TRUE;
310 plugin_add (sess, NULL, NULL, timer_plugin_init, NULL, NULL, FALSE);
312 #ifdef USE_PLUGIN
313 if (!arg_skip_plugins)
314 plugin_auto_load (sess); /* autoload ~/.xchat *.so */
315 #endif
317 #ifdef USE_DBUS
318 plugin_add (sess, NULL, NULL, dbus_plugin_init, NULL, NULL, FALSE);
319 #endif
321 if (prefs.notify_timeout)
322 notify_tag = fe_timeout_add (prefs.notify_timeout * 1000,
323 notify_checklist, 0);
325 fe_timeout_add (prefs.away_timeout * 1000, away_check, 0);
326 fe_timeout_add (500, xchat_misc_checks, 0);
328 if (arg_url != NULL)
330 snprintf (buf, sizeof (buf), "server %s", arg_url);
331 handle_command (sess, buf, FALSE);
332 g_free (arg_url); /* from GOption */
335 if (arg_command != NULL)
337 g_free (arg_command);
340 /* load -e ~/.xchat2/startup.txt */
341 snprintf (buf, sizeof (buf), "%s/%s", get_xdir_fs (), "startup.txt");
342 load_perform_file (sess, buf);
345 static session *
346 session_new (server *serv, char *from, int type, int focus)
348 session *sess;
350 sess = malloc (sizeof (struct session));
351 memset (sess, 0, sizeof (struct session));
353 sess->server = serv;
354 sess->logfd = -1;
355 sess->scrollfd = -1;
356 sess->type = type;
358 sess->alert_beep = SET_DEFAULT;
359 sess->alert_taskbar = SET_DEFAULT;
360 sess->alert_tray = SET_DEFAULT;
362 sess->text_hidejoinpart = SET_DEFAULT;
363 sess->text_logging = SET_DEFAULT;
364 sess->text_scrollback = SET_DEFAULT;
366 if (from != NULL)
367 safe_strcpy (sess->channel, from, CHANLEN);
369 sess_list = g_slist_prepend (sess_list, sess);
371 fe_new_window (sess, focus);
373 return sess;
376 session *
377 new_ircwindow (server *serv, char *name, int type, int focus)
379 session *sess;
381 switch (type)
383 case SESS_SERVER:
384 serv = server_new ();
385 if (prefs.use_server_tab)
386 sess = session_new (serv, name, SESS_SERVER, focus);
387 else
388 sess = session_new (serv, name, SESS_CHANNEL, focus);
389 serv->server_session = sess;
390 serv->front_session = sess;
391 break;
392 case SESS_DIALOG:
393 sess = session_new (serv, name, type, focus);
394 log_open_or_close (sess);
395 break;
396 default:
397 /* case SESS_CHANNEL:
398 case SESS_NOTICES:
399 case SESS_SNOTICES:*/
400 sess = session_new (serv, name, type, focus);
401 break;
404 irc_init (sess);
405 scrollback_load (sess);
406 chanopt_load (sess);
407 plugin_emit_dummy_print (sess, "Open Context");
409 return sess;
412 static void
413 exec_notify_kill (session * sess)
415 struct nbexec *re;
416 if (sess->running_exec != NULL)
418 re = sess->running_exec;
419 sess->running_exec = NULL;
420 kill (re->childpid, SIGKILL);
421 waitpid (re->childpid, NULL, WNOHANG);
422 fe_input_remove (re->iotag);
423 close (re->myfd);
424 if (re->linebuf)
425 free(re->linebuf);
426 free (re);
430 static void
431 send_quit_or_part (session * killsess)
433 int willquit = TRUE;
434 GSList *list;
435 session *sess;
436 server *killserv = killsess->server;
438 /* check if this is the last session using this server */
439 list = sess_list;
440 while (list)
442 sess = (session *) list->data;
443 if (sess->server == killserv && sess != killsess)
445 willquit = FALSE;
446 list = 0;
447 } else
448 list = list->next;
451 if (xchat_is_quitting)
452 willquit = TRUE;
454 if (killserv->connected)
456 if (willquit)
458 if (!killserv->sent_quit)
460 killserv->flush_queue (killserv);
461 server_sendquit (killsess);
462 killserv->sent_quit = TRUE;
464 } else
466 if (killsess->type == SESS_CHANNEL && killsess->channel[0] &&
467 !killserv->sent_quit)
469 server_sendpart (killserv, killsess->channel, 0);
475 void
476 session_free (session *killsess)
478 server *killserv = killsess->server;
479 session *sess;
480 GSList *list;
482 plugin_emit_dummy_print (killsess, "Close Context");
484 if (current_tab == killsess)
485 current_tab = NULL;
487 if (killserv->server_session == killsess)
488 killserv->server_session = NULL;
490 if (killserv->front_session == killsess)
492 /* front_session is closed, find a valid replacement */
493 killserv->front_session = NULL;
494 list = sess_list;
495 while (list)
497 sess = (session *) list->data;
498 if (sess != killsess && sess->server == killserv)
500 killserv->front_session = sess;
501 if (!killserv->server_session)
502 killserv->server_session = sess;
503 break;
505 list = list->next;
509 if (!killserv->server_session)
510 killserv->server_session = killserv->front_session;
512 sess_list = g_slist_remove (sess_list, killsess);
514 if (killsess->type == SESS_CHANNEL)
515 userlist_free (killsess);
517 exec_notify_kill (killsess);
519 log_close (killsess);
520 scrollback_close (killsess);
521 chanopt_save (killsess);
523 send_quit_or_part (killsess);
525 history_free (&killsess->history);
526 if (killsess->topic)
527 free (killsess->topic);
528 if (killsess->current_modes)
529 free (killsess->current_modes);
531 fe_session_callback (killsess);
533 if (current_sess == killsess)
535 current_sess = NULL;
536 if (sess_list)
537 current_sess = sess_list->data;
540 free (killsess);
542 if (!sess_list && !in_xchat_exit)
543 xchat_exit (); /* sess_list is empty, quit! */
545 list = sess_list;
546 while (list)
548 sess = (session *) list->data;
549 if (sess->server == killserv)
550 return; /* this server is still being used! */
551 list = list->next;
554 server_free (killserv);
557 static void
558 free_sessions (void)
560 GSList *list = sess_list;
562 while (list)
564 fe_close_window (list->data);
565 list = sess_list;
570 static char defaultconf_ctcp[] =
571 "NAME TIME\n" "CMD nctcp %s TIME %t\n\n"\
572 "NAME PING\n" "CMD nctcp %s PING %d\n\n";
574 static char defaultconf_replace[] =
575 "NAME teh\n" "CMD the\n\n";
576 /* "NAME r\n" "CMD are\n\n"\
577 "NAME u\n" "CMD you\n\n"*/
579 static char defaultconf_commands[] =
580 "NAME ACTION\n" "CMD me &2\n\n"\
581 "NAME AME\n" "CMD allchan me &2\n\n"\
582 "NAME ANICK\n" "CMD allserv nick &2\n\n"\
583 "NAME AMSG\n" "CMD allchan say &2\n\n"\
584 "NAME BANLIST\n" "CMD quote MODE %c +b\n\n"\
585 "NAME CHAT\n" "CMD dcc chat %2\n\n"\
586 "NAME DIALOG\n" "CMD query %2\n\n"\
587 "NAME DMSG\n" "CMD msg =%2 &3\n\n"\
588 "NAME EXIT\n" "CMD quit\n\n"\
589 "NAME GREP\n" "CMD lastlog -r &2\n\n"\
590 "NAME J\n" "CMD join &2\n\n"\
591 "NAME KILL\n" "CMD quote KILL %2 :&3\n\n"\
592 "NAME LEAVE\n" "CMD part &2\n\n"\
593 "NAME M\n" "CMD msg &2\n\n"\
594 "NAME ONOTICE\n" "CMD notice @%c &2\n\n"\
595 "NAME RAW\n" "CMD quote &2\n\n"\
596 "NAME SERVHELP\n" "CMD quote HELP\n\n"\
597 "NAME SPING\n" "CMD ping\n\n"\
598 "NAME SQUERY\n" "CMD quote SQUERY %2 :&3\n\n"\
599 "NAME SSLSERVER\n" "CMD server -ssl &2\n\n"\
600 "NAME SV\n" "CMD echo xchat %v %m\n\n"\
601 "NAME UMODE\n" "CMD mode %n &2\n\n"\
602 "NAME UPTIME\n" "CMD quote STATS u\n\n"\
603 "NAME VER\n" "CMD ctcp %2 VERSION\n\n"\
604 "NAME VERSION\n" "CMD ctcp %2 VERSION\n\n"\
605 "NAME WALLOPS\n" "CMD quote WALLOPS :&2\n\n"\
606 "NAME WII\n" "CMD quote WHOIS %2 %2\n\n";
608 static char defaultconf_urlhandlers[] =
609 "NAME Open Link in Opera\n" "CMD !opera -remote 'openURL(%s)'\n\n";
611 #ifdef USE_SIGACTION
612 /* Close and open log files on SIGUSR1. Usefull for log rotating */
614 static void
615 sigusr1_handler (int signal, siginfo_t *si, void *un)
617 GSList *list = sess_list;
618 session *sess;
620 while (list)
622 sess = list->data;
623 log_open_or_close (sess);
624 list = list->next;
628 /* Execute /SIGUSR2 when SIGUSR2 received */
630 static void
631 sigusr2_handler (int signal, siginfo_t *si, void *un)
633 session *sess = current_sess;
635 if (sess)
636 handle_command (sess, "SIGUSR2", FALSE);
638 #endif
640 static gint
641 xchat_auto_connect (gpointer userdata)
643 servlist_auto_connect (NULL);
644 return 0;
647 static void
648 xchat_init (void)
650 char buf[3068];
651 const char *cs = NULL;
653 #ifdef USE_SIGACTION
654 struct sigaction act;
656 /* ignore SIGPIPE's */
657 act.sa_handler = SIG_IGN;
658 act.sa_flags = 0;
659 sigemptyset (&act.sa_mask);
660 sigaction (SIGPIPE, &act, NULL);
662 /* Deal with SIGUSR1's & SIGUSR2's */
663 act.sa_sigaction = sigusr1_handler;
664 act.sa_flags = 0;
665 sigemptyset (&act.sa_mask);
666 sigaction (SIGUSR1, &act, NULL);
668 act.sa_sigaction = sigusr2_handler;
669 act.sa_flags = 0;
670 sigemptyset (&act.sa_mask);
671 sigaction (SIGUSR2, &act, NULL);
672 #else
673 /* good enough for these old systems */
674 signal (SIGPIPE, SIG_IGN);
675 #endif
677 if (g_get_charset (&cs))
678 prefs.utf8_locale = TRUE;
680 load_text_events ();
681 sound_load ();
682 notify_load ();
683 ignore_load ();
685 snprintf (buf, sizeof (buf),
686 "NAME %s~%s~\n" "CMD query %%s\n\n"\
687 "NAME %s~%s~\n" "CMD send %%s\n\n"\
688 "NAME %s~%s~\n" "CMD whois %%s %%s\n\n"\
689 "NAME %s~%s~\n" "CMD notify -n ASK %%s\n\n"\
691 "NAME SUB\n" "CMD %s\n\n"\
692 "NAME %s\n" "CMD op %%a\n\n"\
693 "NAME %s\n" "CMD deop %%a\n\n"\
694 "NAME SEP\n" "CMD \n\n"\
695 "NAME %s\n" "CMD voice %%a\n\n"\
696 "NAME %s\n" "CMD devoice %%a\n"\
697 "NAME SEP\n" "CMD \n\n"\
698 "NAME SUB\n" "CMD %s\n\n"\
699 "NAME %s\n" "CMD kick %%s\n\n"\
700 "NAME %s\n" "CMD ban %%s\n\n"\
701 "NAME SEP\n" "CMD \n\n"\
702 "NAME %s *!*@*.host\n""CMD ban %%s 0\n\n"\
703 "NAME %s *!*@domain\n""CMD ban %%s 1\n\n"\
704 "NAME %s *!*user@*.host\n""CMD ban %%s 2\n\n"\
705 "NAME %s *!*user@domain\n""CMD ban %%s 3\n\n"\
706 "NAME SEP\n" "CMD \n\n"\
707 "NAME %s *!*@*.host\n""CMD kickban %%s 0\n\n"\
708 "NAME %s *!*@domain\n""CMD kickban %%s 1\n\n"\
709 "NAME %s *!*user@*.host\n""CMD kickban %%s 2\n\n"\
710 "NAME %s *!*user@domain\n""CMD kickban %%s 3\n\n"\
711 "NAME ENDSUB\n" "CMD \n\n"\
712 "NAME ENDSUB\n" "CMD \n\n",
714 _("_Open Dialog Window"), "xchat-dialog",
715 _("_Send a File"), "gtk-floppy",
716 _("_User Info (WhoIs)"), "gtk-info",
717 _("_Add to Friends List"), "gtk-add",
718 _("O_perator Actions"),
720 _("Give Ops"),
721 _("Take Ops"),
722 _("Give Voice"),
723 _("Take Voice"),
725 _("Kick/Ban"),
726 _("Kick"),
727 _("Ban"),
728 _("Ban"),
729 _("Ban"),
730 _("Ban"),
731 _("Ban"),
732 _("KickBan"),
733 _("KickBan"),
734 _("KickBan"),
735 _("KickBan"));
737 list_loadconf ("popup.conf", &popup_list, buf);
739 snprintf (buf, sizeof (buf),
740 "NAME %s\n" "CMD part\n\n"
741 "NAME %s\n" "CMD getstr # join \"%s\"\n\n"
742 "NAME %s\n" "CMD quote LINKS\n\n"
743 "NAME %s\n" "CMD ping\n\n"
744 "NAME TOGGLE %s\n" "CMD irc_hide_version\n\n",
745 _("Leave Channel"),
746 _("Join Channel..."),
747 _("Enter Channel to Join:"),
748 _("Server Links"),
749 _("Ping Server"),
750 _("Hide Version"));
751 list_loadconf ("usermenu.conf", &usermenu_list, buf);
753 snprintf (buf, sizeof (buf),
754 "NAME %s\n" "CMD op %%a\n\n"
755 "NAME %s\n" "CMD deop %%a\n\n"
756 "NAME %s\n" "CMD ban %%s\n\n"
757 "NAME %s\n" "CMD getstr \"%s\" \"kick %%s\" \"%s\"\n\n"
758 "NAME %s\n" "CMD send %%s\n\n"
759 "NAME %s\n" "CMD query %%s\n\n",
760 _("Op"),
761 _("DeOp"),
762 _("Ban"),
763 _("Kick"),
764 _("bye"),
765 _("Enter reason to kick %s:"),
766 _("Sendfile"),
767 _("Dialog"));
768 list_loadconf ("buttons.conf", &button_list, buf);
770 snprintf (buf, sizeof (buf),
771 "NAME %s\n" "CMD whois %%s %%s\n\n"
772 "NAME %s\n" "CMD send %%s\n\n"
773 "NAME %s\n" "CMD dcc chat %%s\n\n"
774 "NAME %s\n" "CMD clear\n\n"
775 "NAME %s\n" "CMD ping %%s\n\n",
776 _("WhoIs"),
777 _("Send"),
778 _("Chat"),
779 _("Clear"),
780 _("Ping"));
781 list_loadconf ("dlgbuttons.conf", &dlgbutton_list, buf);
783 list_loadconf ("tabmenu.conf", &tabmenu_list, NULL);
784 list_loadconf ("ctcpreply.conf", &ctcp_list, defaultconf_ctcp);
785 list_loadconf ("commands.conf", &command_list, defaultconf_commands);
786 list_loadconf ("replace.conf", &replace_list, defaultconf_replace);
787 list_loadconf ("urlhandlers.conf", &urlhandler_list,
788 defaultconf_urlhandlers);
790 servlist_init (); /* load server list */
792 /* if we got a URL, don't open the server list GUI */
793 if (!prefs.slist_skip && !arg_url)
794 fe_serverlist_open (NULL);
796 /* turned OFF via -a arg */
797 if (!arg_dont_autoconnect)
799 /* do any auto connects */
800 if (!servlist_have_auto ()) /* if no new windows open .. */
802 /* and no serverlist gui ... */
803 if (prefs.slist_skip || arg_url)
804 /* we'll have to open one. */
805 new_ircwindow (NULL, NULL, SESS_SERVER, 0);
806 } else
808 fe_idle_add (xchat_auto_connect, NULL);
810 } else
812 if (prefs.slist_skip || arg_url)
813 new_ircwindow (NULL, NULL, SESS_SERVER, 0);
817 void
818 xchat_exit (void)
820 xchat_is_quitting = TRUE;
821 in_xchat_exit = TRUE;
822 plugin_kill_all ();
823 fe_cleanup ();
824 if (prefs.autosave)
826 save_config ();
827 if (prefs.save_pevents)
828 pevent_save (NULL);
830 if (prefs.autosave_url)
831 url_autosave ();
832 sound_save ();
833 notify_save ();
834 ignore_save ();
835 free_sessions ();
836 chanopt_save_all ();
837 servlist_cleanup ();
838 fe_exit ();
841 static int
842 child_handler (gpointer userdata)
844 int pid = GPOINTER_TO_INT (userdata);
846 if (waitpid (pid, 0, WNOHANG) == pid)
847 return 0; /* remove timeout handler */
848 return 1; /* keep the timeout handler */
851 void
852 xchat_exec (const char *cmd)
854 int pid = util_exec (cmd);
855 if (pid != -1)
856 /* zombie avoiding system. Don't ask! it has to be like this to work
857 with zvt (which overrides the default handler) */
858 fe_timeout_add (1000, child_handler, GINT_TO_POINTER (pid));
861 void
862 xchat_execv (char * const argv[])
864 int pid = util_execv (argv);
865 if (pid != -1)
866 /* zombie avoiding system. Don't ask! it has to be like this to work
867 with zvt (which overrides the default handler) */
868 fe_timeout_add (1000, child_handler, GINT_TO_POINTER (pid));
872 main (int argc, char *argv[])
874 int ret;
876 srand (time (0)); /* CL: do this only once! */
878 #ifdef SOCKS
879 SOCKSinit (argv[0]);
880 #endif
882 ret = fe_args (argc, argv);
883 if (ret != -1)
884 return ret;
886 #ifdef USE_DBUS
887 xchat_remote ();
888 #endif
890 load_config ();
892 #ifdef USE_LIBPROXY
893 libproxy_factory = px_proxy_factory_new();
894 #endif
896 fe_init ();
898 xchat_init ();
900 fe_main ();
902 #ifdef USE_LIBPROXY
903 px_proxy_factory_free(libproxy_factory);
904 #endif
906 #ifdef USE_OPENSSL
907 if (ctx)
908 _SSL_context_free (ctx);
909 #endif
911 #ifdef USE_DEBUG
912 xchat_mem_list ();
913 #endif
915 return 0;