addition of silc.css
[crypto.git] / apps / irssi / src / fe-common / core / fe-core-commands.c
1 /*
2  fe-core-commands.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 "module-formats.h"
23 #include "signals.h"
24 #include "commands.h"
25 #include "levels.h"
26 #include "misc.h"
27 #include "line-split.h"
28 #include "settings.h"
29 #include "irssi-version.h"
30
31 #include "fe-windows.h"
32 #include "printtext.h"
33
34 #define PASTE_CHECK_SPEED 200 /* 0.2 sec */
35
36 static int ret_texts[] = {
37         TXT_OPTION_UNKNOWN,
38         TXT_OPTION_AMBIGUOUS,
39         TXT_OPTION_MISSING_ARG,
40         TXT_COMMAND_UNKNOWN,
41         TXT_COMMAND_AMBIGUOUS,
42         -1,
43         TXT_NOT_ENOUGH_PARAMS,
44         TXT_NOT_CONNECTED,
45         TXT_NOT_JOINED,
46         TXT_CHAN_NOT_FOUND,
47         TXT_CHAN_NOT_SYNCED,
48         TXT_NOT_GOOD_IDEA
49 };
50
51 /* keep the whole command line here temporarily. we need it in
52    "default command" event handler, but there we don't know if the start of
53    the line had one or two command chars, and which one.. */
54 static const char *current_cmdline;
55 static int hide_output;
56
57 static GTimeVal time_command_last, time_command_now;
58 static int last_command_cmd, command_cmd;
59
60 /* SYNTAX: ECHO [-current] [-window <name>] [-level <level>] <text> */
61 static void cmd_echo(const char *data, void *server, WI_ITEM_REC *item)
62 {
63         WINDOW_REC *window;
64         GHashTable *optlist;
65         char *msg, *levelstr, *winname;
66         void *free_arg;
67         int level;
68
69         g_return_if_fail(data != NULL);
70
71         if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
72                             PARAM_FLAG_GETREST, "echo", &optlist, &msg))
73                 return;
74
75         levelstr = g_hash_table_lookup(optlist, "level");
76         level = levelstr == NULL ? 0 :
77                 level2bits(g_hash_table_lookup(optlist, "level"));
78         if (level == 0) level = MSGLEVEL_CRAP;
79
80         winname = g_hash_table_lookup(optlist, "window");
81         window = winname == NULL ? NULL :
82                 is_numeric(winname, '\0') ?
83                 window_find_refnum(atoi(winname)) :
84                 window_find_item(NULL, winname);
85         if (window == NULL) window = active_win;
86
87         printtext_window(window, level, "%s", msg);
88         cmd_params_free(free_arg);
89 }
90
91 /* SYNTAX: VERSION */
92 static void cmd_version(char *data)
93 {
94         g_return_if_fail(data != NULL);
95
96         if (*data == '\0') {
97                 printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
98                           "Client: "PACKAGE" " IRSSI_VERSION);
99         }
100 }
101
102 /* SYNTAX: CAT <file> */
103 static void cmd_cat(const char *data)
104 {
105         LINEBUF_REC *buffer = NULL;
106         char *fname, *fposstr;
107         char tmpbuf[1024], *str;
108         void *free_arg;
109         int f, ret, recvlen, fpos;
110
111         if (!cmd_get_params(data, &free_arg, 2, &fname, &fposstr))
112                 return;
113
114         fname = convert_home(fname);
115         fpos = atoi(fposstr);
116         cmd_params_free(free_arg);
117
118         f = open(fname, O_RDONLY);
119         g_free(fname);
120
121         if (f == -1) {
122                 /* file not found */
123                 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
124                           "%s", g_strerror(errno));
125                 return;
126         }
127
128         lseek(f, fpos, SEEK_SET);
129         do {
130                 recvlen = read(f, tmpbuf, sizeof(tmpbuf));
131
132                 ret = line_split(tmpbuf, recvlen, &str, &buffer);
133                 if (ret > 0)
134                         printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "%s", str);
135         } while (ret > 0);
136         line_split_free(buffer);
137
138         close(f);
139 }
140
141 /* SYNTAX: BEEP */
142 static void cmd_beep(void)
143 {
144         signal_emit("beep", 0);
145 }
146
147 static void sig_stop(void)
148 {
149         signal_stop();
150 }
151
152 static void event_command(const char *data)
153 {
154         const char *cmdchar;
155
156         /* save current command line */
157         current_cmdline = data;
158
159         /* for detecting if we're pasting text */
160         time_command_last = time_command_now;
161         last_command_cmd = command_cmd;
162
163         g_get_current_time(&time_command_now);
164         command_cmd = strchr(settings_get_str("cmdchars"), *data) != NULL;
165
166         /* /^command hides the output of the command */
167         cmdchar = strchr(settings_get_str("cmdchars"), *data);
168         if (cmdchar != NULL && (data[1] == '^' ||
169                                 (data[1] == *cmdchar && data[2] == '^'))) {
170                 hide_output = TRUE;
171                 signal_add_first("print starting", (SIGNAL_FUNC) sig_stop);
172                 signal_add_first("print format", (SIGNAL_FUNC) sig_stop);
173                 signal_add_first("print text stripped", (SIGNAL_FUNC) sig_stop);
174                 signal_add_first("print text", (SIGNAL_FUNC) sig_stop);
175         }
176 }
177
178 static void event_command_last(const char *data)
179 {
180         if (hide_output) {
181                 hide_output = FALSE;
182                 signal_remove("print starting", (SIGNAL_FUNC) sig_stop);
183                 signal_remove("print format", (SIGNAL_FUNC) sig_stop);
184                 signal_remove("print text stripped", (SIGNAL_FUNC) sig_stop);
185                 signal_remove("print text", (SIGNAL_FUNC) sig_stop);
186         }
187 }
188
189 static void event_default_command(const char *data, void *server,
190                                   WI_ITEM_REC *item)
191 {
192         const char *cmdchars, *ptr;
193         char *cmd, *p;
194         long diff;
195
196         cmdchars = settings_get_str("cmdchars");
197
198         ptr = data;
199         while (*ptr != '\0' && *ptr != ' ') {
200                 if (strchr(cmdchars, *ptr)) {
201                         /* command character inside command .. we probably
202                            want to send this text to channel. for example
203                            when pasting a path /usr/bin/xxx. */
204                         signal_emit("send text", 3, current_cmdline, server, item);
205                         return;
206                 }
207                 ptr++;
208         }
209
210         /* maybe we're copy+pasting text? check how long it was since the
211            last line */
212         diff = get_timeval_diff(&time_command_now, &time_command_last);
213         if (item != NULL && !last_command_cmd && diff < PASTE_CHECK_SPEED) {
214                 signal_emit("send text", 3, current_cmdline, active_win->active_server, active_win->active);
215                 command_cmd = FALSE;
216                 return;
217         }
218
219         /* get the command part of the line, send "error command" signal */
220         cmd = g_strdup(data);
221         p = strchr(cmd, ' ');
222         if (p != NULL) *p = '\0';
223
224         signal_emit("error command", 2, GINT_TO_POINTER(CMDERR_UNKNOWN), cmd);
225
226         g_free(cmd);
227 }
228
229 static void event_cmderror(void *errorp, const char *arg)
230 {
231         int error;
232
233         error = GPOINTER_TO_INT(errorp);
234         if (error == CMDERR_ERRNO) {
235                 /* errno is special */
236                 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", g_strerror(errno));
237         } else {
238                 /* others */
239                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, ret_texts[error + -CMDERR_OPTION_UNKNOWN], arg);
240         }
241 }
242
243 static void event_list_subcommands(const char *command)
244 {
245         GSList *tmp;
246         GString *str;
247         int len;
248
249         str = g_string_new(NULL);
250
251         len = strlen(command);
252         for (tmp = commands; tmp != NULL; tmp = tmp->next) {
253                 COMMAND_REC *rec = tmp->data;
254
255                 if (g_strncasecmp(rec->cmd, command, len) == 0 &&
256                     rec->cmd[len] == ' ' &&
257                     strchr(rec->cmd+len+1, ' ') == NULL) {
258                         g_string_sprintfa(str, "%s ", rec->cmd+len+1);
259                 }
260         }
261
262         if (str->len != 0) {
263                 g_string_truncate(str, str->len-1);
264                 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str->str);
265         }
266
267         g_string_free(str, TRUE);
268 }
269
270 void fe_core_commands_init(void)
271 {
272         hide_output = FALSE;
273
274         command_cmd = FALSE;
275         memset(&time_command_now, 0, sizeof(GTimeVal));
276
277         command_bind("echo", NULL, (SIGNAL_FUNC) cmd_echo);
278         command_bind("version", NULL, (SIGNAL_FUNC) cmd_version);
279         command_bind("cat", NULL, (SIGNAL_FUNC) cmd_cat);
280         command_bind("beep", NULL, (SIGNAL_FUNC) cmd_beep);
281
282         signal_add("send command", (SIGNAL_FUNC) event_command);
283         signal_add_last("send command", (SIGNAL_FUNC) event_command_last);
284         signal_add("default command", (SIGNAL_FUNC) event_default_command);
285         signal_add("error command", (SIGNAL_FUNC) event_cmderror);
286         signal_add("list subcommands", (SIGNAL_FUNC) event_list_subcommands);
287
288         command_set_options("echo", "current +level +window");
289 }
290
291 void fe_core_commands_deinit(void)
292 {
293         command_unbind("echo", (SIGNAL_FUNC) cmd_echo);
294         command_unbind("version", (SIGNAL_FUNC) cmd_version);
295         command_unbind("cat", (SIGNAL_FUNC) cmd_cat);
296         command_unbind("beep", (SIGNAL_FUNC) cmd_beep);
297
298         signal_remove("send command", (SIGNAL_FUNC) event_command);
299         signal_remove("send command", (SIGNAL_FUNC) event_command_last);
300         signal_remove("default command", (SIGNAL_FUNC) event_default_command);
301         signal_remove("error command", (SIGNAL_FUNC) event_cmderror);
302         signal_remove("list subcommands", (SIGNAL_FUNC) event_list_subcommands);
303 }