Memory leak fixes.
[silc.git] / apps / irssi / src / fe-text / silc.c
1 /*
2  irssi.c : irssi
3
4     Copyright (C) 1999-2000, 2007 Timo Sirainen
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "module.h"
22 #include "module-formats.h"
23 #include "modules-load.h"
24 #include "args.h"
25 #include "signals.h"
26 #include "levels.h"
27 #include "core.h"
28 #include "settings.h"
29 #include "session.h"
30
31 #include "printtext.h"
32 #include "fe-common-core.h"
33 #include "fe-common-silc.h"
34 #include "themes.h"
35
36 #include "term.h"
37 #include "gui-entry.h"
38 #include "mainwindows.h"
39 #include "gui-printtext.h"
40 #include "gui-readline.h"
41 #include "statusbar.h"
42 #include "gui-windows.h"
43 #include "textbuffer-reformat.h"
44
45 #include <signal.h>
46 #include <locale.h>
47
48 #ifdef HAVE_STATIC_PERL
49 void perl_core_init(void);
50 void perl_core_deinit(void);
51
52 void fe_perl_init(void);
53 void fe_perl_deinit(void);
54 #endif
55
56 void silc_init(void);
57 void silc_deinit(void);
58
59 void gui_expandos_init(void);
60 void gui_expandos_deinit(void);
61
62 void textbuffer_commands_init(void);
63 void textbuffer_commands_deinit(void);
64
65 void lastlog_init(void);
66 void lastlog_deinit(void);
67
68 void mainwindow_activity_init(void);
69 void mainwindow_activity_deinit(void);
70
71 void mainwindows_layout_init(void);
72 void mainwindows_layout_deinit(void);
73
74 void term_dummy_init(void);
75 void term_dummy_deinit(void);
76
77 static int dirty, full_redraw, dummy;
78
79 static GMainLoop *main_loop;
80 int quitting;
81 int quit_signalled;
82 int protocols_deinit;
83
84 static int display_firsttimer = FALSE;
85
86 /* Protocol exit signal to tell protocol has gone away.  Safe to quit. */
87
88 static void sig_protocol_exit(void)
89 {
90   protocols_deinit = TRUE;
91   if (!quitting && quit_signalled)
92     quitting = TRUE;
93 }
94
95 static void sig_exit(void)
96 {
97   quit_signalled = TRUE;
98
99   /* If protocol hasn't finished yet, wait untill it sends "chat protocol
100      deinit" signal. */
101   if (!protocols_deinit)
102     return;
103   quitting = TRUE;
104 }
105
106 /* redraw irssi's screen.. */
107 void irssi_redraw(void)
108 {
109         dirty = TRUE;
110         full_redraw = TRUE;
111 }
112
113 void irssi_set_dirty(void)
114 {
115         dirty = TRUE;
116 }
117
118 static void dirty_check(void)
119 {
120         if (!dirty || dummy)
121                 return;
122
123         term_resize_dirty();
124
125         if (full_redraw) {
126                 full_redraw = FALSE;
127
128                 /* first clear the screen so curses will be
129                    forced to redraw the screen */
130                 term_clear();
131                 term_refresh(NULL);
132
133                 mainwindows_redraw();
134                 statusbar_redraw(NULL, TRUE);
135         }
136
137         mainwindows_redraw_dirty();
138         statusbar_redraw_dirty();
139         term_refresh(NULL);
140
141         dirty = FALSE;
142 }
143
144 static void textui_init(void)
145 {
146 #ifdef SIGTRAP
147         struct sigaction act;
148
149         sigemptyset(&act.sa_mask);
150         act.sa_flags = 0;
151         act.sa_handler = SIG_IGN;
152         sigaction(SIGTRAP, &act, NULL);
153 #endif
154
155         irssi_gui = IRSSI_GUI_TEXT;
156         core_init();
157         silc_init();
158         fe_common_core_init();
159         fe_silc_init();
160
161         theme_register(gui_text_formats);
162         signal_add_last("gui exit", (SIGNAL_FUNC) sig_exit);
163         signal_add_last("chat protocol deinit",
164                         (SIGNAL_FUNC) sig_protocol_exit);
165 }
166
167 static void textui_finish_init(void)
168 {
169         quitting = FALSE;
170         quit_signalled = FALSE;
171         protocols_deinit = FALSE;
172
173         if (dummy)
174                 term_dummy_init();
175         else {
176                 term_refresh_freeze();
177                 textbuffer_init();
178                 textbuffer_view_init();
179                 textbuffer_commands_init();
180                 textbuffer_reformat_init();
181                 gui_expandos_init();
182                 gui_printtext_init();
183                 gui_readline_init();
184                 lastlog_init();
185                 mainwindows_init();
186                 mainwindow_activity_init();
187                 mainwindows_layout_init();
188                 gui_windows_init();
189                 statusbar_init();
190                 term_refresh_thaw();
191
192                 /* don't check settings with dummy mode */
193                 settings_check();
194         }
195
196         module_register("core", "fe-text");
197
198 #ifdef HAVE_STATIC_PERL
199         perl_core_init();
200         fe_perl_init();
201 #endif
202
203         dirty_check();
204
205         fe_common_core_finish_init();
206         signal_emit("irssi init finished", 0);
207 }
208
209 static void textui_deinit(void)
210 {
211         signal(SIGINT, SIG_DFL);
212
213         term_refresh_freeze();
214         while (modules != NULL)
215                 module_unload(modules->data);
216
217 #ifdef HAVE_STATIC_PERL
218         perl_core_deinit();
219         fe_perl_deinit();
220 #endif
221
222         dirty_check(); /* one last time to print any quit messages */
223         signal_remove("gui exit", (SIGNAL_FUNC) sig_exit);
224         signal_remove("chat protocol deinit", (SIGNAL_FUNC) sig_protocol_exit);
225
226         if (dummy)
227                 term_dummy_deinit();
228         else {
229                 lastlog_deinit();
230                 statusbar_deinit();
231                 gui_printtext_deinit();
232                 gui_readline_deinit();
233                 gui_windows_deinit();
234                 mainwindows_layout_deinit();
235                 mainwindow_activity_deinit();
236                 mainwindows_deinit();
237                 gui_expandos_deinit();
238                 textbuffer_reformat_deinit();
239                 textbuffer_commands_deinit();
240                 textbuffer_view_deinit();
241                 textbuffer_deinit();
242
243                 term_refresh_thaw();
244                 term_deinit();
245         }
246
247         theme_unregister();
248
249         fe_silc_deinit();
250         fe_common_core_deinit();
251         silc_deinit();
252         core_deinit();
253 }
254
255 static void check_oldcrap(void)
256 {
257         FILE *f;
258         char *path, str[256];
259         int found;
260
261         /* check that default.theme is up-to-date */
262         path = g_strdup_printf("%s/default.theme", get_irssi_dir());
263         f = fopen(path, "r+");
264         if (f == NULL) {
265                 g_free(path);
266                 return;
267         }
268         found = FALSE;
269         while (!found && fgets(str, sizeof(str), f) != NULL)
270                 found = strstr(str, "abstracts = ") != NULL;
271         fclose(f);
272
273         if (found) {
274                 g_free(path);
275                 return;
276         }
277
278         printf("\nYou seem to have old default.theme in "IRSSI_DIR_SHORT"/ directory.\n");
279         printf("Themeing system has changed a bit since last irssi release,\n");
280         printf("you should either delete your old default.theme or manually\n");
281         printf("merge it with the new default.theme.\n\n");
282         printf("Do you want to delete the old theme now? (Y/n)\n");
283
284         str[0] = '\0';
285         fgets(str, sizeof(str), stdin);
286         if (i_toupper(str[0]) == 'Y' || str[0] == '\n' || str[0] == '\0')
287                 remove(path);
288         g_free(path);
289 }
290
291 static void check_files(void)
292 {
293         struct stat statbuf;
294
295         if (stat(get_irssi_dir(), &statbuf) != 0) {
296                 /* ~/.irssi doesn't exist, first time running irssi */
297                 display_firsttimer = TRUE;
298         } else {
299                 check_oldcrap();
300         }
301 }
302
303 #ifdef WIN32
304 static void winsock_init(void)
305 {
306         WORD wVersionRequested;
307         WSADATA wsaData;
308
309         wVersionRequested = MAKEWORD(2, 2);
310
311         if (WSAStartup(wVersionRequested, &wsaData) != 0) {
312                 printf("Error initializing winsock\n");
313                 exit(1);
314         }
315 }
316 #endif
317
318 #ifdef USE_GC
319 #ifdef HAVE_GC_H
320 #  include <gc.h>
321 #else
322 #  include <gc/gc.h>
323 #endif
324
325 GMemVTable gc_mem_table = {
326         GC_malloc,
327         GC_realloc,
328         GC_free,
329
330         NULL, NULL, NULL
331 };
332 #endif
333
334 int main(int argc, char **argv)
335 {
336         static struct poptOption options[] = {
337 #if 0 /* --dummy is not available in SILC Client */
338                 { "dummy", 'd', POPT_ARG_NONE, &dummy, 0, "Use the dummy terminal mode", NULL },
339 #endif
340                 { NULL, '\0', 0, NULL }
341         };
342
343 #ifdef USE_GC
344         g_mem_set_vtable(&gc_mem_table);
345 #endif
346
347         srand(time(NULL));
348
349         dummy = FALSE;
350         quitting = FALSE;
351         quit_signalled = FALSE;
352         protocols_deinit = FALSE;
353         core_init_paths(argc, argv);
354
355         check_files();
356
357 #ifdef WIN32
358         winsock_init();
359 #endif
360 #ifdef HAVE_SOCKS
361         SOCKSinit(argv[0]);
362 #endif
363 #ifdef ENABLE_NLS
364         /* initialize the i18n stuff */
365         bindtextdomain(PACKAGE, LOCALEDIR);
366         textdomain(PACKAGE);
367 #endif
368
369         /* setlocale() must be called at the beginning before any calls that
370            affect it, especially regexps seem to break if they're generated
371            before t his call.
372
373            locales aren't actually used for anything else than autodetection
374            of UTF-8 currently..
375
376            furthermore to get the users's charset with g_get_charset() properly
377            you have to call setlocale(LC_ALL, "") */
378         setlocale(LC_ALL, "");
379
380         textui_init();
381         args_register(options);
382         args_execute(argc, argv);
383
384         if (!dummy && !term_init()) {
385                 fprintf(stderr, "Can't initialize screen handling, quitting.\n");
386                 fprintf(stderr, "You can still use the dummy mode with -d parameter\n");
387                 return 1;
388         }
389
390         textui_finish_init();
391         main_loop = g_main_new(TRUE);
392
393         /* Does the same as g_main_run(main_loop), except we
394            can call our dirty-checker after each iteration */
395         while (!quitting) {
396 #ifdef USE_GC
397                 GC_collect_a_little();
398 #endif
399                 if (!dummy) term_refresh_freeze();
400                 g_main_iteration(TRUE);
401                 if (!dummy) term_refresh_thaw();
402
403                 if (reload_config) {
404                         /* SIGHUP received, do /RELOAD */
405                         reload_config = FALSE;
406                         signal_emit("command reload", 1, "");
407                 }
408
409                 dirty_check();
410         }
411
412         g_main_destroy(main_loop);
413         textui_deinit();
414
415         session_upgrade(); /* if we /UPGRADEd, start the new process */
416         return 0;
417 }