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