2 fe-core-commands.c : irssi
4 Copyright (C) 1999-2001 Timo Sirainen
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.
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.
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.
23 #include "module-formats.h"
29 #include "irssi-version.h"
32 #include "fe-windows.h"
33 #include "printtext.h"
35 #define PASTE_CHECK_SPEED 200 /* 0.2 sec */
37 static int ret_texts[] = {
40 TXT_OPTION_MISSING_ARG,
42 TXT_COMMAND_AMBIGUOUS,
44 TXT_NOT_ENOUGH_PARAMS,
57 int command_hide_output;
59 /* keep the whole command line here temporarily. we need it in
60 "default command" event handler, but there we don't know if the start of
61 the line had one or two command chars, and which one.. */
62 static const char *current_cmdline;
64 static GTimeVal time_command_last, time_command_now;
65 static int last_command_cmd, command_cmd;
67 /* SYNTAX: ECHO [-current] [-window <name>] [-level <level>] <text> */
68 static void cmd_echo(const char *data, void *server, WI_ITEM_REC *item)
72 char *msg, *levelstr, *winname;
76 g_return_if_fail(data != NULL);
78 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
79 PARAM_FLAG_GETREST, "echo", &optlist, &msg))
82 levelstr = g_hash_table_lookup(optlist, "level");
83 level = levelstr == NULL ? 0 :
84 level2bits(g_hash_table_lookup(optlist, "level"), NULL);
85 if (level == 0) level = MSGLEVEL_CRAP;
87 winname = g_hash_table_lookup(optlist, "window");
88 window = winname == NULL ? NULL :
89 is_numeric(winname, '\0') ?
90 window_find_refnum(atoi(winname)) :
91 window_find_item(NULL, winname);
92 if (window == NULL) window = active_win;
94 printtext_window(window, level, "%s", msg);
95 cmd_params_free(free_arg);
99 static void cmd_version(char *data)
103 g_return_if_fail(data != NULL);
106 g_snprintf(time, sizeof(time), "%04d", IRSSI_VERSION_TIME);
107 printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
108 "Client: "PACKAGE" " IRSSI_VERSION" (%d %s)",
109 IRSSI_VERSION_DATE, time);
113 /* SYNTAX: CAT <file> */
114 static void cmd_cat(const char *data)
116 char *fname, *fposstr;
123 if (!cmd_get_params(data, &free_arg, 2, &fname, &fposstr))
126 fname = convert_home(fname);
127 fpos = atoi(fposstr);
128 cmd_params_free(free_arg);
130 handle = g_io_channel_new_file(fname, "r", NULL);
133 if (handle == NULL) {
135 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
136 "%s", g_strerror(errno));
140 g_io_channel_set_encoding(handle, NULL, NULL);
141 g_io_channel_seek_position(handle, fpos, G_SEEK_SET, NULL);
142 buf = g_string_sized_new(512);
143 while (g_io_channel_read_line_string(handle, buf, &tpos, NULL) == G_IO_STATUS_NORMAL) {
144 buf->str[tpos] = '\0';
145 printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP |
146 MSGLEVEL_NEVER, "%s", buf->str);
148 g_string_free(buf, TRUE);
150 g_io_channel_unref(handle);
154 static void cmd_beep(void)
156 signal_emit("beep", 0);
159 static void cmd_nick(const char *data, SERVER_REC *server)
161 g_return_if_fail(data != NULL);
163 if (*data != '\0') return;
164 if (server == NULL || !server->connected)
165 cmd_return_error(CMDERR_NOT_CONNECTED);
167 /* display current nick */
168 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_YOUR_NICK, server->nick);
173 static void cmd_uptime(char *data)
177 g_return_if_fail(data != NULL);
180 uptime = time(NULL) - client_start_time;
181 printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
182 "Uptime: %ldd %ldh %ldm %lds",
183 uptime/3600/24, uptime/3600%24,
184 uptime/60%60, uptime%60);
188 static void sig_stop(void)
193 static void event_command(const char *data)
197 /* save current command line */
198 current_cmdline = data;
200 /* for detecting if we're pasting text */
201 time_command_last = time_command_now;
202 last_command_cmd = command_cmd;
204 g_get_current_time(&time_command_now);
205 command_cmd = *data != '\0' &&
206 strchr(settings_get_str("cmdchars"), *data) != NULL;
208 /* /^command hides the output of the command */
209 cmdchar = *data == '\0' ? NULL :
210 strchr(settings_get_str("cmdchars"), *data);
211 if (cmdchar != NULL && (data[1] == '^' ||
212 (data[1] == *cmdchar && data[2] == '^'))
213 && !command_hide_output++) {
214 signal_add_first("print starting", (SIGNAL_FUNC) sig_stop);
215 signal_add_first("print format", (SIGNAL_FUNC) sig_stop);
216 signal_add_first("print text", (SIGNAL_FUNC) sig_stop);
220 static void event_command_last(const char *data)
222 if (command_hide_output && !--command_hide_output) {
223 signal_remove("print starting", (SIGNAL_FUNC) sig_stop);
224 signal_remove("print format", (SIGNAL_FUNC) sig_stop);
225 signal_remove("print text", (SIGNAL_FUNC) sig_stop);
229 static void event_default_command(const char *data, void *server,
232 const char *cmdchars, *ptr;
236 cmdchars = settings_get_str("cmdchars");
239 while (*ptr != '\0' && *ptr != ' ') {
240 if (strchr(cmdchars, *ptr)) {
241 /* command character inside command .. we probably
242 want to send this text to channel. for example
243 when pasting a path /usr/bin/xxx. */
244 signal_emit("send text", 3, current_cmdline, server, item);
250 /* maybe we're copy+pasting text? check how long it was since the
252 diff = get_timeval_diff(&time_command_now, &time_command_last);
253 if (item != NULL && !last_command_cmd && diff < PASTE_CHECK_SPEED) {
254 signal_emit("send text", 3, current_cmdline, active_win->active_server, active_win->active);
259 /* get the command part of the line, send "error command" signal */
260 cmd = g_strdup(data);
261 p = strchr(cmd, ' ');
262 if (p != NULL) *p = '\0';
264 signal_emit("error command", 2, GINT_TO_POINTER(CMDERR_UNKNOWN), cmd);
269 static void event_cmderror(void *errorp, const char *arg)
273 error = GPOINTER_TO_INT(errorp);
274 if (error == CMDERR_ERRNO) {
275 /* errno is special */
276 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", g_strerror(errno));
279 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, ret_texts[error + -CMDERR_OPTION_UNKNOWN], arg);
283 static void event_list_subcommands(const char *command)
289 str = g_string_new(NULL);
291 len = strlen(command);
292 for (tmp = commands; tmp != NULL; tmp = tmp->next) {
293 COMMAND_REC *rec = tmp->data;
295 if (g_strncasecmp(rec->cmd, command, len) == 0 &&
296 rec->cmd[len] == ' ' &&
297 strchr(rec->cmd+len+1, ' ') == NULL) {
298 g_string_append_printf(str, "%s ", rec->cmd+len+1);
303 g_string_truncate(str, str->len-1);
304 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str->str);
307 g_string_free(str, TRUE);
310 void fe_core_commands_init(void)
312 command_hide_output = 0;
315 memset(&time_command_now, 0, sizeof(GTimeVal));
317 command_bind("echo", NULL, (SIGNAL_FUNC) cmd_echo);
318 command_bind("version", NULL, (SIGNAL_FUNC) cmd_version);
319 command_bind("cat", NULL, (SIGNAL_FUNC) cmd_cat);
320 command_bind("beep", NULL, (SIGNAL_FUNC) cmd_beep);
321 command_bind("uptime", NULL, (SIGNAL_FUNC) cmd_uptime);
322 command_bind_first("nick", NULL, (SIGNAL_FUNC) cmd_nick);
324 signal_add("send command", (SIGNAL_FUNC) event_command);
325 signal_add_last("send command", (SIGNAL_FUNC) event_command_last);
326 signal_add("default command", (SIGNAL_FUNC) event_default_command);
327 signal_add("error command", (SIGNAL_FUNC) event_cmderror);
328 signal_add("list subcommands", (SIGNAL_FUNC) event_list_subcommands);
330 command_set_options("echo", "current +level +window");
333 void fe_core_commands_deinit(void)
335 command_unbind("echo", (SIGNAL_FUNC) cmd_echo);
336 command_unbind("version", (SIGNAL_FUNC) cmd_version);
337 command_unbind("cat", (SIGNAL_FUNC) cmd_cat);
338 command_unbind("beep", (SIGNAL_FUNC) cmd_beep);
339 command_unbind("uptime", (SIGNAL_FUNC) cmd_uptime);
340 command_unbind("nick", (SIGNAL_FUNC) cmd_nick);
342 signal_remove("send command", (SIGNAL_FUNC) event_command);
343 signal_remove("send command", (SIGNAL_FUNC) event_command_last);
344 signal_remove("default command", (SIGNAL_FUNC) event_default_command);
345 signal_remove("error command", (SIGNAL_FUNC) event_cmderror);
346 signal_remove("list subcommands", (SIGNAL_FUNC) event_list_subcommands);