Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / fe-common / core / printtext.c
1 /*
2  printtext.c : irssi
3
4     Copyright (C) 1999-2000 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 along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "module.h"
22 #include "module-formats.h"
23 #include "modules.h"
24 #include "signals.h"
25 #include "commands.h"
26 #include "settings.h"
27
28 #include "levels.h"
29 #include "servers.h"
30
31 #include "themes.h"
32 #include "fe-windows.h"
33 #include "printtext.h"
34
35 static int beep_msg_level, beep_when_away, beep_when_window_active;
36
37 static int signal_gui_print_text_finished;
38 static int signal_print_starting;
39 static int signal_print_text;
40 static int signal_print_format;
41
42 static int sending_print_starting;
43
44 static void print_line(TEXT_DEST_REC *dest, const char *text);
45
46 void printformat_module_dest_args(const char *module, TEXT_DEST_REC *dest,
47                                   int formatnum, va_list va)
48 {
49         char *arglist[MAX_FORMAT_PARAMS];
50         char buffer[DEFAULT_FORMAT_ARGLIST_SIZE];
51         FORMAT_REC *formats;
52
53         formats = g_hash_table_lookup(default_formats, module);
54         format_read_arglist(va, &formats[formatnum],
55                             arglist, sizeof(arglist)/sizeof(char *),
56                             buffer, sizeof(buffer));
57
58         printformat_module_dest_charargs(module, dest, formatnum, arglist);
59 }
60
61 void printformat_module_dest_charargs(const char *module, TEXT_DEST_REC *dest,
62                                       int formatnum, char **arglist)
63 {
64         THEME_REC *theme;
65         char *str;
66
67         theme = window_get_theme(dest->window);
68
69         if (!sending_print_starting) {
70                 sending_print_starting = TRUE;
71                 signal_emit_id(signal_print_starting, 1, dest);
72                 sending_print_starting = FALSE;
73         }
74
75         signal_emit_id(signal_print_format, 5, theme, module,
76                        dest, GINT_TO_POINTER(formatnum), arglist);
77
78         str = format_get_text_theme_charargs(theme, module, dest,
79                                              formatnum, arglist);
80         if (str != NULL && *str != '\0') print_line(dest, str);
81         g_free(str);
82 }
83
84 void printformat_module_dest(const char *module, TEXT_DEST_REC *dest,
85                              int formatnum, ...)
86 {
87         va_list va;
88
89         va_start(va, formatnum);
90         printformat_module_dest_args(module, dest, formatnum, va);
91         va_end(va);
92 }
93
94 void printformat_module_args(const char *module, void *server,
95                              const char *target, int level,
96                              int formatnum, va_list va)
97 {
98         TEXT_DEST_REC dest;
99
100         format_create_dest(&dest, server, target, level, NULL);
101         printformat_module_dest_args(module, &dest, formatnum, va);
102 }
103
104 void printformat_module(const char *module, void *server, const char *target,
105                         int level, int formatnum, ...)
106 {
107         va_list va;
108
109         va_start(va, formatnum);
110         printformat_module_args(module, server, target, level, formatnum, va);
111         va_end(va);
112 }
113
114 void printformat_module_window_args(const char *module, WINDOW_REC *window,
115                                     int level, int formatnum, va_list va)
116 {
117         TEXT_DEST_REC dest;
118
119         format_create_dest(&dest, NULL, NULL, level, window);
120         printformat_module_dest_args(module, &dest, formatnum, va);
121 }
122
123 void printformat_module_window(const char *module, WINDOW_REC *window,
124                                int level, int formatnum, ...)
125 {
126         va_list va;
127
128         va_start(va, formatnum);
129         printformat_module_window_args(module, window, level, formatnum, va);
130         va_end(va);
131 }
132
133 void printformat_module_gui_args(const char *module, int formatnum, va_list va)
134 {
135         TEXT_DEST_REC dest;
136         char *arglist[MAX_FORMAT_PARAMS];
137         char buffer[DEFAULT_FORMAT_ARGLIST_SIZE];
138         FORMAT_REC *formats;
139         char *str;
140
141         g_return_if_fail(module != NULL);
142
143         memset(&dest, 0, sizeof(dest));
144
145         formats = g_hash_table_lookup(default_formats, module);
146         format_read_arglist(va, &formats[formatnum],
147                             arglist, sizeof(arglist)/sizeof(char *),
148                             buffer, sizeof(buffer));
149
150         str = format_get_text_theme_charargs(window_get_theme(dest.window),
151                                              module, &dest,
152                                              formatnum, arglist);
153         if (*str != '\0') format_send_to_gui(&dest, str);
154         g_free(str);
155 }
156
157 void printformat_module_gui(const char *module, int formatnum, ...)
158 {
159         va_list va;
160
161         va_start(va, formatnum);
162         printformat_module_gui_args(module, formatnum, va);
163         va_end(va);
164 }
165
166 static void print_line(TEXT_DEST_REC *dest, const char *text)
167 {
168         THEME_REC *theme;
169         char *str, *tmp, *stripped;
170
171         g_return_if_fail(dest != NULL);
172         g_return_if_fail(text != NULL);
173         
174         theme = window_get_theme(dest->window);
175         tmp = format_get_level_tag(theme, dest);
176         str = !theme->info_eol ? format_add_linestart(text, tmp) :
177                 format_add_lineend(text, tmp);
178         g_free_not_null(tmp);
179         
180         /* send both the formatted + stripped (for logging etc.) */
181         stripped = strip_codes(str);
182         signal_emit_id(signal_print_text, 3, dest, str, stripped);
183         g_free_and_null(dest->hilight_color);
184
185         g_free(str);
186         g_free(stripped);
187 }
188
189 /* append string to `out', expand newlines. */
190 static void printtext_append_str(TEXT_DEST_REC *dest, GString *out,
191                                  const char *str)
192 {
193         while (*str != '\0') {
194                 if (*str != '\n')
195                         g_string_append_c(out, *str);
196                 else {
197                         print_line(dest, out->str);
198                         g_string_truncate(out, 0);
199                 }
200                 str++;
201         }
202 }
203
204 static char *printtext_get_args(TEXT_DEST_REC *dest, const char *str,
205                                 va_list va)
206 {
207         GString *out;
208         char *ret;
209
210         out = g_string_new(NULL);
211         for (; *str != '\0'; str++) {
212                 if (*str != '%') {
213                         g_string_append_c(out, *str);
214                         continue;
215                 }
216
217                 if (*++str == '\0')
218                         break;
219
220                 /* standard parameters */
221                 switch (*str) {
222                 case 's': {
223                         char *s = (char *) va_arg(va, char *);
224                         if (s && *s) printtext_append_str(dest, out, s);
225                         break;
226                 }
227                 case 'd': {
228                         int d = (int) va_arg(va, int);
229                         g_string_append_printf(out, "%d", d);
230                         break;
231                 }
232                 case 'f': {
233                         double f = (double) va_arg(va, double);
234                         g_string_append_printf(out, "%0.2f", f);
235                         break;
236                 }
237                 case 'u': {
238                         unsigned int d =
239                                 (unsigned int) va_arg(va, unsigned int);
240                         g_string_append_printf(out, "%u", d);
241                         break;
242                 }
243                 case 'l': {
244                         long d = (long) va_arg(va, long);
245
246                         if (*++str != 'd' && *str != 'u') {
247                                 g_string_append_printf(out, "%ld", d);
248                                 str--;
249                         } else {
250                                 if (*str == 'd')
251                                         g_string_append_printf(out, "%ld", d);
252                                 else
253                                         g_string_append_printf(out, "%lu", d);
254                         }
255                         break;
256                 }
257                 default:
258                         if (!format_expand_styles(out, &str, &dest->flags)) {
259                                 g_string_append_c(out, '%');
260                                 g_string_append_c(out, *str);
261                         }
262                         break;
263                 }
264         }
265
266         ret = out->str;
267         g_string_free(out, FALSE);
268         return ret;
269 }
270
271 static char *printtext_expand_formats(const char *str, int *flags)
272 {
273         GString *out;
274         char *ret;
275
276         out = g_string_new(NULL);
277         for (; *str != '\0'; str++) {
278                 if (*str != '%') {
279                         g_string_append_c(out, *str);
280                         continue;
281                 }
282
283                 if (*++str == '\0')
284                         break;
285
286                 if (!format_expand_styles(out, &str, flags)) {
287                         g_string_append_c(out, '%');
288                         g_string_append_c(out, *str);
289                 }
290         }
291
292         ret = out->str;
293         g_string_free(out, FALSE);
294         return ret;
295 }
296
297 static void printtext_dest_args(TEXT_DEST_REC *dest, const char *text, va_list va)
298 {
299         char *str;
300
301         if (!sending_print_starting) {
302                 sending_print_starting = TRUE;
303                 signal_emit_id(signal_print_starting, 1, dest);
304                 sending_print_starting = FALSE;
305         }
306
307         str = printtext_get_args(dest, text, va);
308         print_line(dest, str);
309         g_free(str);
310 }
311
312 void printtext_dest(TEXT_DEST_REC *dest, const char *text, ...)
313 {
314         va_list va;
315
316         va_start(va, text);
317         printtext_dest_args(dest, text, va);
318         va_end(va);
319 }
320
321 /* Write text to target - convert color codes */
322 void printtext(void *server, const char *target, int level, const char *text, ...)
323 {
324         TEXT_DEST_REC dest;
325         va_list va;
326
327         g_return_if_fail(text != NULL);
328
329         format_create_dest(&dest, server, target, level, NULL);
330
331         va_start(va, text);
332         printtext_dest_args(&dest, text, va);
333         va_end(va);
334 }
335
336 /* Like printtext(), but don't handle %s etc. */
337 void printtext_string(void *server, const char *target, int level, const char *text)
338 {
339         TEXT_DEST_REC dest;
340         char *str;
341
342         g_return_if_fail(text != NULL);
343
344         format_create_dest(&dest, server, target, level, NULL);
345
346         if (!sending_print_starting) {
347                 sending_print_starting = TRUE;
348                 signal_emit_id(signal_print_starting, 1, &dest);
349                 sending_print_starting = FALSE;
350         }
351
352         str = printtext_expand_formats(text, &dest.flags);
353         print_line(&dest, str);
354         g_free(str);
355 }
356
357 /* Like printtext_window(), but don't handle %s etc. */
358 void printtext_string_window(WINDOW_REC *window, int level, const char *text)
359 {
360         TEXT_DEST_REC dest;
361         char *str;
362
363         g_return_if_fail(text != NULL);
364
365         format_create_dest(&dest, NULL, NULL, level,
366                            window != NULL ? window : active_win);
367
368         if (!sending_print_starting) {
369                 sending_print_starting = TRUE;
370                 signal_emit_id(signal_print_starting, 1, &dest);
371                 sending_print_starting = FALSE;
372         }
373
374         str = printtext_expand_formats(text, &dest.flags);
375         print_line(&dest, str);
376         g_free(str);
377 }
378
379 void printtext_window(WINDOW_REC *window, int level, const char *text, ...)
380 {
381         TEXT_DEST_REC dest;
382         va_list va;
383
384         g_return_if_fail(text != NULL);
385
386         format_create_dest(&dest, NULL, NULL, level,
387                            window != NULL ? window : active_win);
388
389         va_start(va, text);
390         printtext_dest_args(&dest, text, va);
391         va_end(va);
392 }
393
394 void printtext_gui(const char *text)
395 {
396         TEXT_DEST_REC dest;
397         char *str;
398
399         g_return_if_fail(text != NULL);
400
401         memset(&dest, 0, sizeof(dest));
402
403         str = printtext_expand_formats(text, &dest.flags);
404         format_send_to_gui(&dest, str);
405         g_free(str);
406 }
407
408 static void msg_beep_check(TEXT_DEST_REC *dest)
409 {
410         if (dest->level != 0 && (dest->level & MSGLEVEL_NO_ACT) == 0 &&
411             (beep_msg_level & dest->level) &&
412             (beep_when_away || (dest->server != NULL &&
413                                 !dest->server->usermode_away)) &&
414             (beep_when_window_active || dest->window != active_win)) {
415                 signal_emit("beep", 0);
416         }
417 }
418
419 static void sig_print_text(TEXT_DEST_REC *dest, const char *text)
420 {
421         THEME_REC *theme;
422         char *str, *tmp;
423
424         g_return_if_fail(dest != NULL);
425         g_return_if_fail(text != NULL);
426
427         if (dest->window == NULL) {
428                 str = strip_codes(text);
429                 printf("NO WINDOWS: %s\n", str);
430                 g_free(str);
431                 return;
432         }
433
434         msg_beep_check(dest);
435
436         if ((dest->level & MSGLEVEL_NEVER) == 0)
437                 dest->window->last_line = time(NULL);
438
439         /* add timestamp/server tag here - if it's done in print_line()
440            it would be written to log files too */
441         theme = window_get_theme(dest->window);
442         tmp = format_get_line_start(theme, dest, time(NULL));
443         str = !theme->info_eol ? format_add_linestart(text, tmp) :
444                 format_add_lineend(text, tmp);
445
446         g_free_not_null(tmp);
447
448         format_send_to_gui(dest, str);
449         g_free(str);
450
451         signal_emit_id(signal_gui_print_text_finished, 1, dest->window);
452 }
453
454 void printtext_multiline(void *server, const char *target, int level,
455                          const char *format, const char *text)
456 {
457         char **lines, **tmp;
458
459         g_return_if_fail(format != NULL);
460         g_return_if_fail(text != NULL);
461
462         lines = g_strsplit(text, "\n", -1);
463         for (tmp = lines; *tmp != NULL; tmp++)
464                 printtext(NULL, NULL, level, format, *tmp);
465         g_strfreev(lines);
466 }
467
468 static void sig_gui_dialog(const char *type, const char *text)
469 {
470         char *format;
471
472         if (g_ascii_strcasecmp(type, "warning") == 0)
473                 format = "%_Warning:%_ %s";
474         else if (g_ascii_strcasecmp(type, "error") == 0)
475                 format = "%_Error:%_ %s";
476         else
477                 format = "%s";
478
479         printtext_multiline(NULL, NULL, MSGLEVEL_NEVER, format, text);
480 }
481
482 static void read_settings(void)
483 {
484         beep_msg_level = settings_get_level("beep_msg_level");
485         beep_when_away = settings_get_bool("beep_when_away");
486         beep_when_window_active = settings_get_bool("beep_when_window_active");
487 }
488
489 void printtext_init(void)
490 {
491         sending_print_starting = FALSE;
492         signal_gui_print_text_finished = signal_get_uniq_id("gui print text finished");
493         signal_print_starting = signal_get_uniq_id("print starting");
494         signal_print_text = signal_get_uniq_id("print text");
495         signal_print_format = signal_get_uniq_id("print format");
496
497         read_settings();
498         signal_add("print text", (SIGNAL_FUNC) sig_print_text);
499         signal_add("gui dialog", (SIGNAL_FUNC) sig_gui_dialog);
500         signal_add("setup changed", (SIGNAL_FUNC) read_settings);
501 }
502
503 void printtext_deinit(void)
504 {
505         signal_remove("print text", (SIGNAL_FUNC) sig_print_text);
506         signal_remove("gui dialog", (SIGNAL_FUNC) sig_gui_dialog);
507         signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
508 }