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