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.1.1.1 2000/06/27 11:36:56 priikone
24 * Importet from internal CVS/Added Log headers.
29 #include "clientincludes.h"
31 /* Client command list. */
32 SilcClientCommand silc_command_list[] =
34 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
35 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
36 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
37 SILC_CF_LAG | SILC_CF_REG, 3),
38 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
39 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
40 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
41 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 2),
42 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
43 SILC_CLIENT_CMD(kill, KILL, "KILL",
44 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
45 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
46 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
47 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
48 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
49 SILC_CLIENT_CMD(oper, OPER, "OPER",
50 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
51 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
52 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
53 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
54 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
55 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
56 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
57 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
58 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
59 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
60 SILC_CLIENT_CMD(die, DIE, "DIE",
61 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
62 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
63 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
64 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
65 SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
68 * Local. client specific commands
70 SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
71 SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
72 SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
73 SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
74 SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
75 SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
80 /* List of pending commands. */
81 SilcClientCommandPending *silc_command_pending = NULL;
83 /* Add new pending command to the list of pending commands. Currently
84 pending commands are executed from command replies, thus we can
85 execute any command after receiving some specific command reply.
87 The argument `reply_cmd' is the command reply from where the callback
88 function is to be called, thus, it IS NOT the command to be executed.
90 XXX: If needed in the future this support may be extended for
91 commands as well, when any command could be executed after executing
92 some specific command. */
94 void silc_client_command_pending(SilcCommand reply_cmd,
95 SilcClientCommandCallback callback,
98 SilcClientCommandPending *reply, *r;
100 reply = silc_calloc(1, sizeof(*reply));
101 reply->reply_cmd = reply_cmd;
102 reply->context = context;
103 reply->callback = callback;
105 if (silc_command_pending == NULL) {
106 silc_command_pending = reply;
110 for (r = silc_command_pending; r; r = r->next) {
111 if (r->next == NULL) {
118 /* Deletes pending command by reply command type. */
120 void silc_client_command_pending_del(SilcCommand reply_cmd)
122 SilcClientCommandPending *r, *tmp;
124 if (silc_command_pending) {
125 if (silc_command_pending->reply_cmd == reply_cmd) {
126 silc_free(silc_command_pending);
127 silc_command_pending = NULL;
131 for (r = silc_command_pending; r; r = r->next) {
132 if (r->next && r->next->reply_cmd == reply_cmd) {
134 r->next = r->next->next;
142 /* Free command context and its internals */
144 static void silc_client_command_free(SilcClientCommandContext cmd)
149 for (i = 0; i < cmd->argc; i++)
150 silc_free(cmd->argv[i]);
155 /* Command WHOIS. This command is used to query information about
158 SILC_CLIENT_CMD_FUNC(whois)
160 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
163 if (cmd->argc < 2 || cmd->argc > 3) {
164 silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
168 if (!cmd->client->current_win->sock) {
169 silc_say(cmd->client,
170 "You are not connected to a server, use /SERVER to connect");
174 buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
175 cmd->argc - 1, ++cmd->argv,
176 ++cmd->argv_lens, ++cmd->argv_types);
177 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
178 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
179 buffer->data, buffer->len, TRUE);
180 silc_buffer_free(buffer);
186 silc_client_command_free(cmd);
189 SILC_CLIENT_CMD_FUNC(whowas)
193 /* Command IDENTIFY. This command is used to query information about
194 specific user, especially ID's. */
196 SILC_CLIENT_CMD_FUNC(identify)
198 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
201 if (cmd->argc < 2 || cmd->argc > 3) {
202 silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
206 if (!cmd->client->current_win->sock) {
207 silc_say(cmd->client,
208 "You are not connected to a server, use /SERVER to connect");
212 buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
213 cmd->argc - 1, ++cmd->argv,
214 ++cmd->argv_lens, ++cmd->argv_types);
215 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
216 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
217 buffer->data, buffer->len, TRUE);
218 silc_buffer_free(buffer);
224 silc_client_command_free(cmd);
227 /* Command NICK. Shows current nickname/sets new nickname on current
230 SILC_CLIENT_CMD_FUNC(nick)
232 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
233 SilcClientWindow win = NULL;
237 silc_say(cmd->client,
238 "You are not connected to a server, use /SERVER to connect");
242 /* Show current nickname */
245 silc_say(cmd->client, "Your nickname is %s on server %s",
246 win->nickname, win->remote_host);
248 silc_say(cmd->client, "Your nickname is %s", win->nickname);
253 win = (SilcClientWindow)cmd->sock->user_data;
255 /* Set new nickname */
256 buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
257 cmd->argc - 1, ++cmd->argv,
258 ++cmd->argv_lens, ++cmd->argv_types);
259 silc_client_packet_send(cmd->client, cmd->sock,
260 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
261 buffer->data, buffer->len, TRUE);
262 silc_buffer_free(buffer);
267 silc_free(win->nickname);
268 win->nickname = strdup(cmd->argv[1]);
271 silc_client_command_free(cmd);
274 /* Command SERVER. Connects to remote SILC server. This is local command. */
276 SILC_CLIENT_CMD_FUNC(server)
278 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
283 /* Show current servers */
284 if (!cmd->client->current_win->sock) {
285 silc_say(cmd->client, "You are not connected to any server");
286 silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
293 /* See if port is included and then extract it */
294 if (strchr(cmd->argv[1], ':')) {
295 len = strcspn(cmd->argv[1], ":");
296 hostname = silc_calloc(len + 1, sizeof(char));
297 memcpy(hostname, cmd->argv[1], len);
298 port = atoi(cmd->argv[1] + 1 + len);
300 hostname = cmd->argv[1];
305 /* Connect asynchronously to not to block user interface */
306 silc_client_connect_to_server(cmd->client, port, hostname);
309 silc_client_command_free(cmd);
312 SILC_CLIENT_CMD_FUNC(list)
316 SILC_CLIENT_CMD_FUNC(topic)
320 SILC_CLIENT_CMD_FUNC(invite)
324 /* Command QUIT. Closes connection with current server. */
326 SILC_CLIENT_CMD_FUNC(quit)
328 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
331 if (!cmd->client->current_win->sock) {
332 silc_say(cmd->client,
333 "You are not connected to a server, use /SERVER to connect");
337 buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1,
338 ++cmd->argv, ++cmd->argv_lens,
340 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
341 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
342 buffer->data, buffer->len, TRUE);
343 silc_buffer_free(buffer);
348 /* Close connection */
349 silc_client_close_connection(cmd->client, cmd->sock);
350 cmd->client->screen->bottom_line->connection = NULL;
351 silc_screen_print_bottom_line(cmd->client->screen, 0);
353 silc_client_command_free(cmd);
356 SILC_CLIENT_CMD_FUNC(kill)
360 SILC_CLIENT_CMD_FUNC(info)
364 SILC_CLIENT_CMD_FUNC(connect)
368 SILC_CLIENT_CMD_FUNC(ping)
372 SILC_CLIENT_CMD_FUNC(oper)
376 SILC_CLIENT_CMD_FUNC(trace)
380 SILC_CLIENT_CMD_FUNC(notice)
384 /* Command JOIN. Joins to a channel. */
386 SILC_CLIENT_CMD_FUNC(join)
388 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
389 SilcClientWindow win = NULL;
390 SilcIDCache *id_cache = NULL;
393 #define CIDC(x) win->channel_id_cache[(x) - 32]
394 #define CIDCC(x) win->channel_id_cache_count[(x) - 32]
397 /* Show channels currently joined to */
398 if (!cmd->client->current_win->sock) {
399 silc_say(cmd->client, "No current channel for this window");
400 silc_say(cmd->client,
401 "You are not connected to a server, use /SERVER to connect");
409 if (!cmd->client->current_win->sock) {
410 silc_say(cmd->client,
411 "You are not connected to a server, use /SERVER to connect");
415 win = (SilcClientWindow)cmd->sock->user_data;
417 /* See if we have joined to the requested channel already */
418 silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), CIDCC(cmd->argv[1][0]),
419 cmd->argv[1], &id_cache);
422 silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
423 win->current_channel = (SilcChannelEntry)id_cache->context;
424 cmd->client->screen->bottom_line->channel = cmd->argv[1];
425 silc_screen_print_bottom_line(cmd->client->screen, 0);
429 /* Send JOIN command to the server */
430 buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
431 cmd->argc - 1, ++cmd->argv,
432 ++cmd->argv_lens, ++cmd->argv_types);
433 silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
434 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
435 buffer->data, buffer->len, TRUE);
436 silc_buffer_free(buffer);
442 silc_client_command_free(cmd);
447 SILC_CLIENT_CMD_FUNC(motd)
451 SILC_CLIENT_CMD_FUNC(umode)
455 SILC_CLIENT_CMD_FUNC(cmode)
459 SILC_CLIENT_CMD_FUNC(kick)
463 SILC_CLIENT_CMD_FUNC(restart)
467 SILC_CLIENT_CMD_FUNC(close)
471 SILC_CLIENT_CMD_FUNC(die)
475 SILC_CLIENT_CMD_FUNC(silcoper)
479 SILC_CLIENT_CMD_FUNC(leave)
483 SILC_CLIENT_CMD_FUNC(names)
491 /* HELP command. This is local command and shows help on SILC */
493 SILC_CLIENT_CMD_FUNC(help)
498 /* CLEAR command. This is local command and clears current output window */
500 SILC_CLIENT_CMD_FUNC(clear)
502 SilcClient client = (SilcClient)context;
504 assert(client->current_win != NULL);
505 wclear((WINDOW *)client->current_win->screen);
506 wrefresh((WINDOW *)client->current_win->screen);
509 /* VERSION command. This is local command and shows version of the client */
511 SILC_CLIENT_CMD_FUNC(version)
516 /* Command MSG. Sends private message to user or list of users. */
517 /* XXX supports only one destination */
519 SILC_CLIENT_CMD_FUNC(msg)
521 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
522 SilcClientWindow win = NULL;
523 SilcClient client = cmd->client;
525 SilcIDCache *id_cache;
526 unsigned int nick_len;
529 silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
533 if (!cmd->client->current_win->sock) {
534 silc_say(cmd->client,
535 "You are not connected to a server, use /SERVER to connect");
539 win = (SilcClientWindow)cmd->sock->user_data;
541 #define CIDC(x) win->client_id_cache[(x) - 32], \
542 win->client_id_cache_count[(x) - 32]
544 /* Find ID from cache */
545 if (silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1],
546 &id_cache) == FALSE) {
547 SilcClientCommandContext ctx;
550 SILC_LOG_DEBUG(("Requesting Client ID from server"));
552 /* No ID found. Do query from the server. The query is done by
553 sending simple IDENTIFY command to the server. */
554 ctx = silc_calloc(1, sizeof(*ctx));
555 ctx->client = client;
556 ctx->sock = cmd->sock;
557 memset(ident, 0, sizeof(ident));
558 snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
559 silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
560 &ctx->argv_types, &ctx->argc, 2);
561 silc_client_command_identify(ctx);
563 /* Mark this command to be pending command and to be executed after
564 we have received the IDENTIFY reply from server. */
565 silc_client_command_pending(SILC_COMMAND_IDENTIFY,
566 silc_client_command_msg, context);
570 /* Display the message for our eyes. */
571 silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
573 /* Send the private message */
574 silc_client_packet_send_private_message(client, cmd->sock, id_cache->context,
575 cmd->argv[2], cmd->argv_lens[2],
578 silc_client_command_free(cmd);
582 SILC_CLIENT_CMD_FUNC(away)