Added SILC Thread Queue API
[crypto.git] / apps / irssi / src / fe-text / lastlog.c
1 /*
2  lastlog.c : irssi
3
4     Copyright (C) 1999-2001 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 "signals.h"
23 #include "commands.h"
24 #include "misc.h"
25 #include "levels.h"
26 #include "settings.h"
27
28 #include "module-formats.h"
29 #include "printtext.h"
30
31 #include "gui-windows.h"
32 #include "gui-printtext.h"
33
34 #define DEFAULT_LASTLOG_BEFORE 3
35 #define DEFAULT_LASTLOG_AFTER 3
36 #define MAX_LINES_WITHOUT_FORCE 1000
37
38 static void window_lastlog_clear(WINDOW_REC *window)
39 {
40         TEXT_BUFFER_VIEW_REC *view;
41         LINE_REC *line, *next;
42
43         term_refresh_freeze();
44         view = WINDOW_GUI(window)->view;
45         line = textbuffer_view_get_lines(view);
46
47         while (line != NULL) {
48                 next = line->next;
49
50                 if (line->info.level & MSGLEVEL_LASTLOG)
51                         textbuffer_view_remove_line(view, line);
52                 line = next;
53         }
54         textbuffer_view_redraw(view);
55         term_refresh_thaw();
56 }
57
58 /* Only unknown keys in `optlist' should be levels.
59    Returns -1 if unknown option was given. */
60 int cmd_options_get_level(const char *cmd, GHashTable *optlist)
61 {
62         GSList *list, *tmp, *next;
63         int level, retlevel;
64
65         /* get all the options, then remove the known ones. there should
66            be only one left - the server tag. */
67         list = hashtable_get_keys(optlist);
68         if (cmd != NULL) {
69                 for (tmp = list; tmp != NULL; tmp = next) {
70                         char *option = tmp->data;
71                         next = tmp->next;
72
73                         if (command_have_option(cmd, option))
74                                 list = g_slist_remove(list, option);
75                 }
76         }
77
78         retlevel = 0;
79         while (list != NULL) {
80                 level = level_get(list->data);
81                 if (level == 0) {
82                         /* unknown option */
83                         signal_emit("error command", 2,
84                                     GINT_TO_POINTER(CMDERR_OPTION_UNKNOWN),
85                                     list->data);
86                         retlevel = -1;
87                         break;
88                 }
89
90                 retlevel |= level;
91                 list = g_slist_remove(list, list->data);
92         }
93
94         return retlevel;
95 }
96
97 static void show_lastlog(const char *searchtext, GHashTable *optlist,
98                          int start, int count, int fhandle)
99 {
100         WINDOW_REC *window;
101         LINE_REC *startline;
102         GList *list, *tmp;
103         GString *line;
104         char *str;
105         int level, before, after, len;
106
107         level = cmd_options_get_level("lastlog", optlist);
108         if (level == -1) return; /* error in options */
109         if (level == 0) level = MSGLEVEL_ALL;
110
111         if (g_hash_table_lookup(optlist, "clear") != NULL) {
112                 window_lastlog_clear(active_win);
113                 if (*searchtext == '\0')
114                         return;
115         }
116
117         /* which window's lastlog to look at? */
118         window = active_win;
119         str = g_hash_table_lookup(optlist, "window");
120         if (str != NULL) {
121                 window = is_numeric(str, '\0') ?
122                         window_find_refnum(atoi(str)) :
123                         window_find_item(NULL, str);
124                 if (window == NULL) {
125                         printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
126                                     TXT_REFNUM_NOT_FOUND, str);
127                         return;
128                 }
129         }
130
131         if (g_hash_table_lookup(optlist, "new") != NULL)
132                 startline = textbuffer_view_get_bookmark(WINDOW_GUI(window)->view, "lastlog_last_check");
133         else if (g_hash_table_lookup(optlist, "away") != NULL)
134                 startline = textbuffer_view_get_bookmark(WINDOW_GUI(window)->view, "lastlog_last_away");
135         else
136                 startline = NULL;
137
138         if (startline == NULL)
139                 startline = textbuffer_view_get_lines(WINDOW_GUI(window)->view);
140
141         str = g_hash_table_lookup(optlist, "#");
142         if (str != NULL) {
143                 before = after = atoi(str);
144         } else {
145                 str = g_hash_table_lookup(optlist, "before");
146                 before = str == NULL ? 0 : *str != '\0' ?
147                         atoi(str) : DEFAULT_LASTLOG_BEFORE;
148
149                 str = g_hash_table_lookup(optlist, "after");
150                 if (str == NULL) str = g_hash_table_lookup(optlist, "a");
151                 after = str == NULL ? 0 : *str != '\0' ?
152                         atoi(str) : DEFAULT_LASTLOG_AFTER;
153         }
154
155         list = textbuffer_find_text(WINDOW_GUI(window)->view->buffer, startline,
156                                     level, MSGLEVEL_LASTLOG,
157                                     searchtext, before, after,
158                                     g_hash_table_lookup(optlist, "regexp") != NULL,
159                                     g_hash_table_lookup(optlist, "word") != NULL,
160                                     g_hash_table_lookup(optlist, "case") != NULL);
161
162         len = g_list_length(list);
163         if (count <= 0)
164                 tmp = list;
165         else {
166                 int pos = len-count-start;
167                 if (pos < 0) pos = 0;
168
169                 tmp = pos > len ? NULL : g_list_nth(list, pos);
170                 len = g_list_length(tmp);
171         }
172
173         if (g_hash_table_lookup(optlist, "count") != NULL) {
174                 printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
175                                    TXT_LASTLOG_COUNT, len);
176                 g_list_free(list);
177                 return;
178         }
179
180         if (len > MAX_LINES_WITHOUT_FORCE && fhandle == -1 &&
181             g_hash_table_lookup(optlist, "force") == NULL) {
182                 printformat_window(active_win,
183                                    MSGLEVEL_CLIENTNOTICE|MSGLEVEL_LASTLOG,
184                                    TXT_LASTLOG_TOO_LONG, len);
185                 g_list_free(list);
186                 return;
187         }
188
189         if (fhandle == -1 && g_hash_table_lookup(optlist, "-") == NULL)
190                 printformat(NULL, NULL, MSGLEVEL_LASTLOG, TXT_LASTLOG_START);
191
192         line = g_string_new(NULL);
193         while (tmp != NULL && (count < 0 || count > 0)) {
194                 LINE_REC *rec = tmp->data;
195
196                 if (rec == NULL) {
197                         if (tmp->next == NULL)
198                                 break;
199                         if (fhandle != -1) {
200                                 write(fhandle, "--\n", 3);
201                         } else {
202                                 printformat_window(active_win,
203                                                    MSGLEVEL_LASTLOG,
204                                                    TXT_LASTLOG_SEPARATOR);
205                         }
206                         tmp = tmp->next;
207                         continue;
208                 }
209
210                 /* get the line text */
211                 textbuffer_line2text(rec, fhandle == -1, line);
212                 if (!settings_get_bool("timestamps")) {
213                         struct tm *tm = localtime(&rec->info.time);
214                         char timestamp[10];
215
216                         g_snprintf(timestamp, sizeof(timestamp),
217                                    "%02d:%02d ",
218                                    tm->tm_hour, tm->tm_min);
219                         g_string_prepend(line, timestamp);
220                 }
221
222                 /* write to file/window */
223                 if (fhandle != -1) {
224                         write(fhandle, line->str, line->len);
225                         write(fhandle, "\n", 1);
226                 } else {
227                         printtext_window(active_win, MSGLEVEL_LASTLOG,
228                                          "%s", line->str);
229                 }
230
231                 count--;
232                 tmp = tmp->next;
233         }
234         g_string_free(line, TRUE);
235
236         if (fhandle == -1 && g_hash_table_lookup(optlist, "-") == NULL)
237                 printformat(NULL, NULL, MSGLEVEL_LASTLOG, TXT_LASTLOG_END);
238
239         textbuffer_view_set_bookmark_bottom(WINDOW_GUI(window)->view,
240                                             "lastlog_last_check");
241
242         textbuffer_line_unref_list(WINDOW_GUI(window)->view->buffer, list);
243         g_list_free(list);
244 }
245
246 /* SYNTAX: LASTLOG [-] [-file <filename>] [-window <ref#|name>] [-new | -away]
247                    [-<level> -<level...>] [-clear] [-count] [-case]
248                    [-regexp | -word] [-before [<#>]] [-after [<#>]]
249                    [-<# before+after>] [<pattern>] [<count> [<start>]] */
250 static void cmd_lastlog(const char *data)
251 {
252         GHashTable *optlist;
253         char *text, *countstr, *start, *fname;
254         void *free_arg;
255         int count, fhandle;
256
257         g_return_if_fail(data != NULL);
258
259         if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_OPTIONS |
260                             PARAM_FLAG_UNKNOWN_OPTIONS, "lastlog", &optlist,
261                             &text, &countstr, &start))
262                 return;
263
264         if (*start == '\0' && is_numeric(text, 0) && *text != '0' &&
265             (*countstr == '\0' || is_numeric(countstr, 0))) {
266                 start = countstr;
267                 countstr = text;
268                 text = "";
269         }
270         count = atoi(countstr);
271         if (count == 0) count = -1;
272
273         /* target where to print it */
274         fhandle = -1;
275         fname = g_hash_table_lookup(optlist, "file");
276         if (fname != NULL) {
277                 fname = convert_home(fname);
278                 fhandle = open(fname, O_WRONLY | O_APPEND | O_CREAT,
279                                octal2dec(settings_get_int("log_create_mode")));
280                 g_free(fname);
281         }
282
283         if (fname != NULL && fhandle == -1) {
284                 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
285                           "%s", g_strerror(errno));
286         } else {
287                 show_lastlog(text, optlist, atoi(start), count, fhandle);
288                 if (fhandle != -1)
289                         close(fhandle);
290         }
291
292         cmd_params_free(free_arg);
293 }
294
295 void lastlog_init(void)
296 {
297         command_bind("lastlog", NULL, (SIGNAL_FUNC) cmd_lastlog);
298
299         command_set_options("lastlog", "!- # force clear -file -window new away word regexp case count @a @after @before");
300 }
301
302 void lastlog_deinit(void)
303 {
304         command_unbind("lastlog", (SIGNAL_FUNC) cmd_lastlog);
305 }