5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
23 * Revision 1.2 2000/06/27 19:38:40 priikone
24 * Added missing goto flag.
26 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
27 * Importet from internal CVS/Added Log headers.
32 #include "clientincludes.h"
34 /* Client command list. */
35 SilcClientCommand silc_command_list[] =
37 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
38 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
39 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
40 SILC_CF_LAG | SILC_CF_REG, 3),
41 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
42 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
43 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
44 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 2),
45 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
46 SILC_CLIENT_CMD(kill, KILL, "KILL",
47 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
48 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
49 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
50 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
51 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
52 SILC_CLIENT_CMD(oper, OPER, "OPER",
53 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
54 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
55 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
56 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
57 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
58 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
59 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
60 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
61 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
62 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
63 SILC_CLIENT_CMD(die, DIE, "DIE",
64 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
65 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
66 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
67 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
68 SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
71 * Local. client specific commands
73 SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
74 SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
75 SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
76 SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
77 SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
78 SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
83 /* List of pending commands. */
84 SilcClientCommandPending *silc_command_pending = NULL;
86 /* Add new pending command to the list of pending commands. Currently
87 pending commands are executed from command replies, thus we can
88 execute any command after receiving some specific command reply.
90 The argument `reply_cmd' is the command reply from where the callback
91 function is to be called, thus, it IS NOT the command to be executed.
93 XXX: If needed in the future this support may be extended for
94 commands as well, when any command could be executed after executing
95 some specific command. */
97 void silc_client_command_pending(SilcCommand reply_cmd,
98 SilcClientCommandCallback callback,
101 SilcClientCommandPending *reply, *r;
103 reply = silc_calloc(1, sizeof(*reply));
104 reply->reply_cmd = reply_cmd;
105 reply->context = context;
106 reply->callback = callback;
108 if (silc_command_pending == NULL) {
109 silc_command_pending = reply;
113 for (r = silc_command_pending; r; r = r->next) {
114 if (r->next == NULL) {
121 /* Deletes pending command by reply command type. */
123 void silc_client_command_pending_del(SilcCommand reply_cmd)
125 SilcClientCommandPending *r, *tmp;
127 if (silc_command_pending) {
128 if (silc_command_pending->reply_cmd == reply_cmd) {
129 silc_free(silc_command_pending);
130 silc_command_pending = NULL;
134 for (r = silc_command_pending; r; r = r->next) {
135 if (r->next && r->next->reply_cmd == reply_cmd) {
137 r->next = r->next->next;
145 /* Free command context and its internals */
147 static void silc_client_command_free(SilcClientCommandContext cmd)
152 for (i = 0; i < cmd->argc; i++)
153 silc_free(cmd->argv[i]);
158 /* Command WHOIS. This command is used to query information about
161 SILC_CLIENT_CMD_FUNC(whois)
163 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
166 if (cmd->argc < 2 || cmd->argc > 3) {
167 silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
171 if (!cmd->client->current_win->sock) {
172 silc_say(cmd->client,
173 "You are not connected to a server, use /SERVER to connect");
177 buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
178 cmd->argc - 1, ++cmd->argv,
179 ++cmd->argv_lens, ++cmd->argv_types);
180 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
181 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
182 buffer->data, buffer->len, TRUE);
183 silc_buffer_free(buffer);
189 silc_client_command_free(cmd);
192 SILC_CLIENT_CMD_FUNC(whowas)
196 /* Command IDENTIFY. This command is used to query information about
197 specific user, especially ID's. */
199 SILC_CLIENT_CMD_FUNC(identify)
201 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
204 if (cmd->argc < 2 || cmd->argc > 3) {
205 silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
209 if (!cmd->client->current_win->sock) {
210 silc_say(cmd->client,
211 "You are not connected to a server, use /SERVER to connect");
215 buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
216 cmd->argc - 1, ++cmd->argv,
217 ++cmd->argv_lens, ++cmd->argv_types);
218 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
219 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
220 buffer->data, buffer->len, TRUE);
221 silc_buffer_free(buffer);
227 silc_client_command_free(cmd);
230 /* Command NICK. Shows current nickname/sets new nickname on current
233 SILC_CLIENT_CMD_FUNC(nick)
235 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
236 SilcClientWindow win = NULL;
240 silc_say(cmd->client,
241 "You are not connected to a server, use /SERVER to connect");
245 /* Show current nickname */
248 silc_say(cmd->client, "Your nickname is %s on server %s",
249 win->nickname, win->remote_host);
251 silc_say(cmd->client, "Your nickname is %s", win->nickname);
256 win = (SilcClientWindow)cmd->sock->user_data;
258 /* Set new nickname */
259 buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
260 cmd->argc - 1, ++cmd->argv,
261 ++cmd->argv_lens, ++cmd->argv_types);
262 silc_client_packet_send(cmd->client, cmd->sock,
263 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
264 buffer->data, buffer->len, TRUE);
265 silc_buffer_free(buffer);
270 silc_free(win->nickname);
271 win->nickname = strdup(cmd->argv[1]);
274 silc_client_command_free(cmd);
277 /* Command SERVER. Connects to remote SILC server. This is local command. */
279 SILC_CLIENT_CMD_FUNC(server)
281 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
286 /* Show current servers */
287 if (!cmd->client->current_win->sock) {
288 silc_say(cmd->client, "You are not connected to any server");
289 silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
296 /* See if port is included and then extract it */
297 if (strchr(cmd->argv[1], ':')) {
298 len = strcspn(cmd->argv[1], ":");
299 hostname = silc_calloc(len + 1, sizeof(char));
300 memcpy(hostname, cmd->argv[1], len);
301 port = atoi(cmd->argv[1] + 1 + len);
303 hostname = cmd->argv[1];
308 /* Connect asynchronously to not to block user interface */
309 silc_client_connect_to_server(cmd->client, port, hostname);
312 silc_client_command_free(cmd);
315 SILC_CLIENT_CMD_FUNC(list)
319 SILC_CLIENT_CMD_FUNC(topic)
323 SILC_CLIENT_CMD_FUNC(invite)
327 /* Command QUIT. Closes connection with current server. */
329 SILC_CLIENT_CMD_FUNC(quit)
331 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
334 if (!cmd->client->current_win->sock) {
335 silc_say(cmd->client,
336 "You are not connected to a server, use /SERVER to connect");
340 buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1,
341 ++cmd->argv, ++cmd->argv_lens,
343 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
344 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
345 buffer->data, buffer->len, TRUE);
346 silc_buffer_free(buffer);
351 /* Close connection */
352 silc_client_close_connection(cmd->client, cmd->sock);
353 cmd->client->screen->bottom_line->connection = NULL;
354 silc_screen_print_bottom_line(cmd->client->screen, 0);
357 silc_client_command_free(cmd);
360 SILC_CLIENT_CMD_FUNC(kill)
364 SILC_CLIENT_CMD_FUNC(info)
368 SILC_CLIENT_CMD_FUNC(connect)
372 SILC_CLIENT_CMD_FUNC(ping)
376 SILC_CLIENT_CMD_FUNC(oper)
380 SILC_CLIENT_CMD_FUNC(trace)
384 SILC_CLIENT_CMD_FUNC(notice)
388 /* Command JOIN. Joins to a channel. */
390 SILC_CLIENT_CMD_FUNC(join)
392 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
393 SilcClientWindow win = NULL;
394 SilcIDCache *id_cache = NULL;
397 #define CIDC(x) win->channel_id_cache[(x) - 32]
398 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
401 /* Show channels currently joined to */
402 if (!cmd->client->current_win->sock) {
403 silc_say(cmd->client, "No current channel for this window");
404 silc_say(cmd->client,
405 "You are not connected to a server, use /SERVER to connect");
413 if (!cmd->client->current_win->sock) {
414 silc_say(cmd->client,
415 "You are not connected to a server, use /SERVER to connect");
419 win = (SilcClientWindow)cmd->sock->user_data;
421 /* See if we have joined to the requested channel already */
422 silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), CIDCC(cmd->argv[1][0]),
423 cmd->argv[1], &id_cache);
426 silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
427 win->current_channel = (SilcChannelEntry)id_cache->context;
428 cmd->client->screen->bottom_line->channel = cmd->argv[1];
429 silc_screen_print_bottom_line(cmd->client->screen, 0);
433 /* Send JOIN command to the server */
434 buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
435 cmd->argc - 1, ++cmd->argv,
436 ++cmd->argv_lens, ++cmd->argv_types);
437 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
438 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
439 buffer->data, buffer->len, TRUE);
440 silc_buffer_free(buffer);
446 silc_client_command_free(cmd);
451 SILC_CLIENT_CMD_FUNC(motd)
455 SILC_CLIENT_CMD_FUNC(umode)
459 SILC_CLIENT_CMD_FUNC(cmode)
463 SILC_CLIENT_CMD_FUNC(kick)
467 SILC_CLIENT_CMD_FUNC(restart)
471 SILC_CLIENT_CMD_FUNC(close)
475 SILC_CLIENT_CMD_FUNC(die)
479 SILC_CLIENT_CMD_FUNC(silcoper)
483 SILC_CLIENT_CMD_FUNC(leave)
487 SILC_CLIENT_CMD_FUNC(names)
495 /* HELP command. This is local command and shows help on SILC */
497 SILC_CLIENT_CMD_FUNC(help)
502 /* CLEAR command. This is local command and clears current output window */
504 SILC_CLIENT_CMD_FUNC(clear)
506 SilcClient client = (SilcClient)context;
508 assert(client->current_win != NULL);
509 wclear((WINDOW *)client->current_win->screen);
510 wrefresh((WINDOW *)client->current_win->screen);
513 /* VERSION command. This is local command and shows version of the client */
515 SILC_CLIENT_CMD_FUNC(version)
520 /* Command MSG. Sends private message to user or list of users. */
521 /* XXX supports only one destination */
523 SILC_CLIENT_CMD_FUNC(msg)
525 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
526 SilcClientWindow win = NULL;
527 SilcClient client = cmd->client;
529 SilcIDCache *id_cache;
530 unsigned int nick_len;
533 silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
537 if (!cmd->client->current_win->sock) {
538 silc_say(cmd->client,
539 "You are not connected to a server, use /SERVER to connect");
543 win = (SilcClientWindow)cmd->sock->user_data;
545 #define CIDC(x) win->client_id_cache[(x) - 32], \
546 win->client_id_cache_count[(x) - 32]
548 /* Find ID from cache */
549 if (silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1],
550 &id_cache) == FALSE) {
551 SilcClientCommandContext ctx;
554 SILC_LOG_DEBUG(("Requesting Client ID from server"));
556 /* No ID found. Do query from the server. The query is done by
557 sending simple IDENTIFY command to the server. */
558 ctx = silc_calloc(1, sizeof(*ctx));
559 ctx->client = client;
560 ctx->sock = cmd->sock;
561 memset(ident, 0, sizeof(ident));
562 snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
563 silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
564 &ctx->argv_types, &ctx->argc, 2);
565 silc_client_command_identify(ctx);
567 /* Mark this command to be pending command and to be executed after
568 we have received the IDENTIFY reply from server. */
569 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
570 silc_client_command_msg, context);
574 /* Display the message for our eyes. */
575 silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
577 /* Send the private message */
578 silc_client_packet_send_private_message(client, cmd->sock, id_cache->context,
579 cmd->argv[2], cmd->argv_lens[2],
582 silc_client_command_free(cmd);
586 SILC_CLIENT_CMD_FUNC(away)