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.
22 #include "clientlibincludes.h"
24 /* Client command list. */
25 SilcClientCommand silc_command_list[] =
27 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
28 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
29 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
30 SILC_CF_LAG | SILC_CF_REG, 3),
31 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
32 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
33 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
34 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
35 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
36 SILC_CLIENT_CMD(kill, KILL, "KILL",
37 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
38 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
39 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
40 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
41 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
42 SILC_CLIENT_CMD(oper, OPER, "OPER",
43 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
44 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 4),
45 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
46 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
47 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
48 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
49 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
50 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
51 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
52 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
53 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
54 SILC_CLIENT_CMD(die, DIE, "DIE",
55 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
56 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
57 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
58 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
59 SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
61 { NULL, 0, NULL, 0, 0 },
64 #define SILC_NOT_CONNECTED(x, c) \
65 x->ops->say((x), (c), \
66 "You are not connected to a server, use /SERVER to connect");
68 /* Command operation that is called at the end of all commands.
70 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
71 cmd, TRUE, cmd->command->cmd)
73 /* Error to application. Usage: COMMAND_ERROR; */
74 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
75 cmd, FALSE, cmd->command->cmd)
77 /* Generic function to send any command. The arguments must be sent already
78 encoded into correct form in correct order. */
80 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
81 SilcCommand command, unsigned short ident,
82 unsigned int argc, ...)
89 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
90 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
91 NULL, 0, NULL, NULL, packet->data,
93 silc_buffer_free(packet);
96 /* Finds and returns a pointer to the command list. Return NULL if the
97 command is not found. */
99 SilcClientCommand *silc_client_command_find(const char *name)
101 SilcClientCommand *cmd;
103 for (cmd = silc_command_list; cmd->name; cmd++) {
104 if (!strcmp(cmd->name, name))
111 /* Add new pending command to be executed when reply to a command has been
112 received. The `reply_cmd' is the command that will call the `callback'
113 with `context' when reply has been received. If `ident is non-zero
114 the `callback' will be executed when received reply with command
115 identifier `ident'. */
117 void silc_client_command_pending(SilcClientConnection conn,
118 SilcCommand reply_cmd,
119 unsigned short ident,
120 SilcCommandCb callback,
123 SilcClientCommandPending *reply;
125 reply = silc_calloc(1, sizeof(*reply));
126 reply->reply_cmd = reply_cmd;
127 reply->ident = ident;
128 reply->context = context;
129 reply->callback = callback;
130 silc_dlist_add(conn->pending_commands, reply);
133 /* Deletes pending command by reply command type. */
135 void silc_client_command_pending_del(SilcClientConnection conn,
136 SilcCommand reply_cmd,
137 unsigned short ident)
139 SilcClientCommandPending *r;
141 silc_dlist_start(conn->pending_commands);
142 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
143 if (r->reply_cmd == reply_cmd && r->ident == ident) {
144 silc_dlist_del(conn->pending_commands, r);
150 /* Checks for pending commands and marks callbacks to be called from
151 the command reply function. Returns TRUE if there were pending command. */
153 int silc_client_command_pending_check(SilcClientConnection conn,
154 SilcClientCommandReplyContext ctx,
156 unsigned short ident)
158 SilcClientCommandPending *r;
160 silc_dlist_start(conn->pending_commands);
161 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
162 if (r->reply_cmd == command && r->ident == ident) {
163 ctx->context = r->context;
164 ctx->callback = r->callback;
173 /* Free command context and its internals */
175 void silc_client_command_free(SilcClientCommandContext cmd)
180 for (i = 0; i < cmd->argc; i++)
181 silc_free(cmd->argv[i]);
186 /* Command WHOIS. This command is used to query information about
189 SILC_CLIENT_CMD_FUNC(whois)
191 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
192 SilcClientConnection conn = cmd->conn;
196 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
201 if (cmd->argc < 2 || cmd->argc > 3) {
202 cmd->client->ops->say(cmd->client, conn,
203 "Usage: /WHOIS <nickname>[@<server>] [<count>]");
208 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
209 cmd->argc - 1, ++cmd->argv,
210 ++cmd->argv_lens, ++cmd->argv_types,
212 silc_client_packet_send(cmd->client, cmd->conn->sock,
213 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
214 buffer->data, buffer->len, TRUE);
215 silc_buffer_free(buffer);
220 /* Notify application */
224 silc_client_command_free(cmd);
227 SILC_CLIENT_CMD_FUNC(whowas)
231 /* Command IDENTIFY. This command is used to query information about
232 specific user, especially ID's. */
234 SILC_CLIENT_CMD_FUNC(identify)
236 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
237 SilcClientConnection conn = cmd->conn;
241 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
246 if (cmd->argc < 2 || cmd->argc > 3) {
247 cmd->client->ops->say(cmd->client, conn,
248 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
253 buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
254 cmd->argc - 1, ++cmd->argv,
255 ++cmd->argv_lens, ++cmd->argv_types,
257 silc_client_packet_send(cmd->client, cmd->conn->sock,
258 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
259 buffer->data, buffer->len, TRUE);
260 silc_buffer_free(buffer);
265 /* Notify application */
269 silc_client_command_free(cmd);
272 /* Command NICK. Shows current nickname/sets new nickname on current
275 SILC_CLIENT_CMD_FUNC(nick)
277 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
278 SilcClientConnection conn = cmd->conn;
282 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
287 if (!strcmp(conn->nickname, cmd->argv[1]))
290 /* Show current nickname */
293 cmd->client->ops->say(cmd->client, conn,
294 "Your nickname is %s on server %s",
295 conn->nickname, conn->remote_host);
297 cmd->client->ops->say(cmd->client, conn,
298 "Your nickname is %s", conn->nickname);
301 /* XXX Notify application */
306 /* Set new nickname */
307 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
308 cmd->argc - 1, ++cmd->argv,
309 ++cmd->argv_lens, ++cmd->argv_types,
311 silc_client_packet_send(cmd->client, cmd->conn->sock,
312 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
313 buffer->data, buffer->len, TRUE);
314 silc_buffer_free(buffer);
319 silc_free(conn->nickname);
320 conn->nickname = strdup(cmd->argv[1]);
322 /* Notify application */
326 silc_client_command_free(cmd);
329 SILC_CLIENT_CMD_FUNC(list)
333 /* Command TOPIC. Sets/shows topic on a channel. */
335 SILC_CLIENT_CMD_FUNC(topic)
337 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
338 SilcClientConnection conn = cmd->conn;
339 SilcIDCacheEntry id_cache = NULL;
340 SilcChannelEntry channel;
341 SilcBuffer buffer, idp;
345 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
350 if (cmd->argc < 2 || cmd->argc > 3) {
351 cmd->client->ops->say(cmd->client, conn,
352 "Usage: /TOPIC <channel> [<topic>]");
357 if (cmd->argv[1][0] == '*') {
358 if (!conn->current_channel) {
359 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
363 name = conn->current_channel->channel_name;
368 if (!conn->current_channel) {
369 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
374 /* Get the Channel ID of the channel */
375 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
376 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
381 channel = (SilcChannelEntry)id_cache->context;
383 /* Send TOPIC command to the server */
384 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
386 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 0, 2,
387 1, idp->data, idp->len,
389 strlen(cmd->argv[2]));
391 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1,
392 1, idp->data, idp->len,
394 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
395 0, NULL, NULL, buffer->data, buffer->len, TRUE);
396 silc_buffer_free(buffer);
397 silc_buffer_free(idp);
399 /* Notify application */
403 silc_client_command_free(cmd);
406 /* Command INVITE. Invites specific client to join a channel. */
408 SILC_CLIENT_CMD_FUNC(invite)
410 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
411 SilcClient client = cmd->client;
412 SilcClientConnection conn = cmd->conn;
413 SilcClientEntry client_entry;
414 SilcChannelEntry channel_entry;
415 SilcBuffer buffer, clidp, chidp;
416 unsigned int num = 0;
417 char *nickname = NULL, *server = NULL;
420 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
425 if (cmd->argc != 3) {
426 cmd->client->ops->say(cmd->client, conn,
427 "Usage: /INVITE <nickname>[@<server>] <channel>");
432 /* Parse the typed nickname. */
433 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
434 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
439 /* Find client entry */
440 client_entry = silc_idlist_get_client(client, conn, nickname, server, num);
447 /* Client entry not found, it was requested thus mark this to be
449 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 0,
450 silc_client_command_invite, context);
454 /* Find channel entry */
455 channel_entry = silc_idlist_get_channel(client, conn, cmd->argv[2]);
456 if (!channel_entry) {
457 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
463 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
464 chidp = silc_id_payload_encode(channel_entry->id, SILC_ID_CHANNEL);
465 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 0, 2,
466 1, clidp->data, clidp->len,
467 2, chidp->data, chidp->len);
468 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
469 0, NULL, NULL, buffer->data, buffer->len, TRUE);
470 silc_buffer_free(buffer);
471 silc_buffer_free(clidp);
472 silc_buffer_free(chidp);
474 cmd->client->ops->say(cmd->client, conn,
475 "Inviting %s to channel %s", cmd->argv[1],
478 /* Notify application */
482 silc_client_command_free(cmd);
485 /* Command QUIT. Closes connection with current server. */
487 SILC_CLIENT_CMD_FUNC(quit)
489 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
493 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
498 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
499 ++cmd->argv, ++cmd->argv_lens,
500 ++cmd->argv_types, 0);
501 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
503 buffer->data, buffer->len, TRUE);
504 silc_buffer_free(buffer);
509 /* Close connection */
510 silc_client_close_connection(cmd->client, cmd->conn->sock);
511 cmd->client->ops->disconnect(cmd->client, cmd->conn);
513 /* Notify application */
517 silc_client_command_free(cmd);
520 SILC_CLIENT_CMD_FUNC(kill)
524 /* Command INFO. Request information about specific server. If specific
525 server is not provided the current server is used. */
527 SILC_CLIENT_CMD_FUNC(info)
529 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
530 SilcClientConnection conn = cmd->conn;
535 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
541 name = strdup(conn->remote_host);
543 name = strdup(cmd->argv[1]);
545 /* Send the command */
546 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
547 1, name, strlen(name));
548 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
549 0, NULL, NULL, buffer->data, buffer->len, TRUE);
550 silc_buffer_free(buffer);
552 /* Notify application */
556 silc_client_command_free(cmd);
559 SILC_CLIENT_CMD_FUNC(connect)
563 /* Command PING. Sends ping to server. This is used to test the
564 communication channel. */
566 SILC_CLIENT_CMD_FUNC(ping)
568 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
569 SilcClientConnection conn = cmd->conn;
576 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
581 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
582 name = strdup(conn->remote_host);
584 /* Send the command */
585 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
586 1, conn->remote_id_data,
588 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
589 0, NULL, NULL, buffer->data, buffer->len, TRUE);
590 silc_buffer_free(buffer);
592 id = silc_id_str2id(conn->remote_id_data, SILC_ID_SERVER);
594 /* Start counting time */
595 for (i = 0; i < conn->ping_count; i++) {
596 if (conn->ping[i].dest_id == NULL) {
597 conn->ping[i].start_time = time(NULL);
598 conn->ping[i].dest_id = id;
599 conn->ping[i].dest_name = name;
604 if (i >= conn->ping_count) {
605 i = conn->ping_count;
606 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
607 conn->ping[i].start_time = time(NULL);
608 conn->ping[i].dest_id = id;
609 conn->ping[i].dest_name = name;
613 /* Notify application */
617 silc_client_command_free(cmd);
620 SILC_CLIENT_CMD_FUNC(oper)
624 SILC_CLIENT_CMD_FUNC(trace)
628 SILC_CLIENT_CMD_FUNC(notice)
632 /* Command JOIN. Joins to a channel. */
634 SILC_CLIENT_CMD_FUNC(join)
636 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
637 SilcClientConnection conn = cmd->conn;
638 SilcIDCacheEntry id_cache = NULL;
639 SilcBuffer buffer, idp;
642 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
648 /* Show channels currently joined to */
653 /* See if we have joined to the requested channel already */
654 if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
656 cmd->client->ops->say(cmd->client, conn,
657 "You are talking to channel %s", cmd->argv[1]);
658 conn->current_channel = (SilcChannelEntry)id_cache->context;
660 cmd->client->screen->bottom_line->channel = cmd->argv[1];
661 silc_screen_print_bottom_line(cmd->client->screen, 0);
666 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
668 /* Send JOIN command to the server */
671 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
672 1, cmd->argv[1], cmd->argv_lens[1],
673 2, idp->data, idp->len);
674 else if (cmd->argc == 3)
677 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
678 1, cmd->argv[1], cmd->argv_lens[1],
679 2, idp->data, idp->len,
680 3, cmd->argv[2], cmd->argv_lens[2]);
683 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
684 1, cmd->argv[1], cmd->argv_lens[1],
685 2, idp->data, idp->len,
686 3, cmd->argv[2], cmd->argv_lens[2],
687 4, cmd->argv[3], cmd->argv_lens[3]);
689 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
690 0, NULL, NULL, buffer->data, buffer->len, TRUE);
691 silc_buffer_free(buffer);
692 silc_buffer_free(idp);
694 /* Notify application */
698 silc_client_command_free(cmd);
701 /* MOTD command. Requests motd from server. */
703 SILC_CLIENT_CMD_FUNC(motd)
705 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
706 SilcClientConnection conn = cmd->conn;
710 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
715 if (cmd->argc < 1 || cmd->argc > 1) {
716 cmd->client->ops->say(cmd->client, conn,
722 /* Send TOPIC command to the server */
723 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
724 2, conn->remote_host,
725 strlen(conn->remote_host));
726 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
727 0, NULL, NULL, buffer->data, buffer->len, TRUE);
728 silc_buffer_free(buffer);
730 /* Notify application */
734 silc_client_command_free(cmd);
737 /* UMODE. Set user mode in SILC. */
739 SILC_CLIENT_CMD_FUNC(umode)
744 /* CMODE command. Sets channel mode. Modes that does not require any arguments
745 can be set several at once. Those modes that require argument must be set
746 separately (unless set with modes that does not require arguments). */
748 SILC_CLIENT_CMD_FUNC(cmode)
750 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
751 SilcClientConnection conn = cmd->conn;
752 SilcChannelEntry channel;
753 SilcBuffer buffer, chidp;
754 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
755 unsigned int mode, add, type, len, arg_len = 0;
759 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
765 cmd->client->ops->say(cmd->client, conn,
766 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
771 if (cmd->argv[1][0] == '*') {
772 if (!conn->current_channel) {
773 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
778 channel = conn->current_channel;
782 channel = silc_idlist_get_channel(cmd->client, conn, name);
784 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
790 mode = channel->mode;
792 /* Are we adding or removing mode */
793 if (cmd->argv[2][0] == '-')
798 /* Argument type to be sent to server */
802 cp = cmd->argv[2] + 1;
804 for (i = 0; i < len; i++) {
808 mode |= SILC_CHANNEL_MODE_PRIVATE;
810 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
814 mode |= SILC_CHANNEL_MODE_SECRET;
816 mode &= ~SILC_CHANNEL_MODE_SECRET;
820 mode |= SILC_CHANNEL_MODE_PRIVKEY;
822 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
826 mode |= SILC_CHANNEL_MODE_INVITE;
828 mode &= ~SILC_CHANNEL_MODE_INVITE;
832 mode |= SILC_CHANNEL_MODE_TOPIC;
834 mode &= ~SILC_CHANNEL_MODE_TOPIC;
839 mode |= SILC_CHANNEL_MODE_ULIMIT;
841 ll = atoi(cmd->argv[3]);
842 SILC_PUT32_MSB(ll, tmp);
846 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
851 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
854 arg_len = cmd->argv_lens[3];
856 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
861 mode |= SILC_CHANNEL_MODE_BAN;
864 arg_len = cmd->argv_lens[3];
866 mode &= ~SILC_CHANNEL_MODE_BAN;
871 mode |= SILC_CHANNEL_MODE_INVITE_LIST;
874 arg_len = cmd->argv_lens[3];
876 mode &= ~SILC_CHANNEL_MODE_INVITE_LIST;
881 mode |= SILC_CHANNEL_MODE_CIPHER;
884 arg_len = cmd->argv_lens[3];
886 mode &= ~SILC_CHANNEL_MODE_CIPHER;
896 if (type && cmd->argc < 3) {
901 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
902 SILC_PUT32_MSB(mode, modebuf);
904 /* Send the command packet. We support sending only one mode at once
905 that requires an argument. */
908 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
909 1, chidp->data, chidp->len,
910 2, modebuf, sizeof(modebuf),
914 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
915 1, chidp->data, chidp->len,
916 2, modebuf, sizeof(modebuf));
919 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
920 0, NULL, NULL, buffer->data, buffer->len, TRUE);
921 silc_buffer_free(buffer);
922 silc_buffer_free(chidp);
924 /* Notify application */
928 silc_client_command_free(cmd);
931 /* CUMODE command. Changes client's mode on a channel. */
933 SILC_CLIENT_CMD_FUNC(cumode)
935 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
936 SilcClientConnection conn = cmd->conn;
937 SilcChannelEntry channel;
939 SilcClientEntry client_entry;
940 SilcBuffer buffer, clidp, chidp;
941 unsigned char *name, *cp, modebuf[4];
942 unsigned int mode = 0, add, len;
943 char *nickname = NULL, *server = NULL;
944 unsigned int num = 0;
948 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
954 cmd->client->ops->say(cmd->client, conn,
955 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
960 if (cmd->argv[1][0] == '*') {
961 if (!conn->current_channel) {
962 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
967 channel = conn->current_channel;
971 channel = silc_idlist_get_channel(cmd->client, conn, name);
973 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
979 /* Parse the typed nickname. */
980 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
981 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
986 /* Find client entry */
987 client_entry = silc_idlist_get_client(cmd->client, conn,
988 nickname, server, num);
990 /* Client entry not found, it was requested thus mark this to be
992 silc_client_command_pending(conn, SILC_COMMAND_CUMODE, 0,
993 silc_client_command_cumode, context);
997 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
998 if (chu->client == client_entry) {
1004 /* Are we adding or removing mode */
1005 if (cmd->argv[2][0] == '-')
1011 cp = cmd->argv[2] + 1;
1013 for (i = 0; i < len; i++) {
1017 mode |= SILC_CHANNEL_UMODE_CHANFO;
1018 mode |= SILC_CHANNEL_UMODE_CHANOP;
1020 mode = SILC_CHANNEL_UMODE_NONE;
1025 mode |= SILC_CHANNEL_UMODE_CHANFO;
1027 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1031 mode |= SILC_CHANNEL_UMODE_CHANOP;
1033 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1042 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1043 SILC_PUT32_MSB(mode, modebuf);
1044 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1046 /* Send the command packet. We support sending only one mode at once
1047 that requires an argument. */
1048 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3,
1049 1, chidp->data, chidp->len,
1051 3, clidp->data, clidp->len);
1053 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1054 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1055 silc_buffer_free(buffer);
1056 silc_buffer_free(chidp);
1057 silc_buffer_free(clidp);
1059 /* Notify application */
1063 silc_client_command_free(cmd);
1066 /* KICK command. Kicks a client out of channel. */
1068 SILC_CLIENT_CMD_FUNC(kick)
1070 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1071 SilcClientConnection conn = cmd->conn;
1075 SILC_CLIENT_CMD_FUNC(restart)
1079 SILC_CLIENT_CMD_FUNC(close)
1083 SILC_CLIENT_CMD_FUNC(die)
1087 SILC_CLIENT_CMD_FUNC(silcoper)
1091 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1093 SILC_CLIENT_CMD_FUNC(leave)
1095 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1096 SilcClientConnection conn = cmd->conn;
1097 SilcIDCacheEntry id_cache = NULL;
1098 SilcChannelEntry channel;
1099 SilcBuffer buffer, idp;
1103 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1108 if (cmd->argc != 2) {
1109 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1114 if (cmd->argv[1][0] == '*') {
1115 if (!conn->current_channel) {
1116 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1120 name = conn->current_channel->channel_name;
1122 name = cmd->argv[1];
1125 if (!conn->current_channel) {
1126 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1131 /* Get the Channel ID of the channel */
1132 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1133 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1138 channel = (SilcChannelEntry)id_cache->context;
1140 /* Send LEAVE command to the server */
1141 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1142 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1143 1, idp->data, idp->len);
1144 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1145 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1146 silc_buffer_free(buffer);
1147 silc_buffer_free(idp);
1149 /* We won't talk anymore on this channel */
1150 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1152 conn->current_channel = NULL;
1154 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1155 silc_free(channel->channel_name);
1156 silc_free(channel->id);
1157 silc_free(channel->key);
1158 silc_cipher_free(channel->channel_key);
1161 /* Notify application */
1165 silc_client_command_free(cmd);
1168 /* Command USERS. Requests the USERS of the clients joined on requested
1171 SILC_CLIENT_CMD_FUNC(users)
1173 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1174 SilcClientConnection conn = cmd->conn;
1175 SilcIDCacheEntry id_cache = NULL;
1176 SilcChannelEntry channel;
1177 SilcBuffer buffer, idp;
1181 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1186 if (cmd->argc != 2) {
1187 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1192 if (cmd->argv[1][0] == '*') {
1193 if (!conn->current_channel) {
1194 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1198 name = conn->current_channel->channel_name;
1200 name = cmd->argv[1];
1203 if (!conn->current_channel) {
1204 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1209 /* Get the Channel ID of the channel */
1210 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1211 /* XXX should resolve the channel ID; LIST command */
1212 cmd->client->ops->say(cmd->client, conn,
1213 "You are not on that channel", name);
1218 channel = (SilcChannelEntry)id_cache->context;
1220 if (!cmd->pending) {
1221 /* Send USERS command to the server */
1222 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1223 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 0, 1,
1224 1, idp->data, idp->len);
1225 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1226 NULL, 0, NULL, NULL, buffer->data,
1228 silc_buffer_free(buffer);
1229 silc_buffer_free(idp);
1231 /* Register pending callback which will recall this command callback with
1232 same context and reprocesses the command. When reprocessing we actually
1233 display the information on the screen. */
1234 silc_client_command_pending(conn, SILC_COMMAND_USERS, 0,
1235 silc_client_command_users, context);
1236 cmd->pending = TRUE;
1241 /* Pending command. Now we've resolved the information from server and
1242 we are ready to display the information on screen. */
1244 SilcChannelUser chu;
1246 cmd->client->ops->say(cmd->client, conn, "Users on %s",
1247 channel->channel_name);
1249 silc_list_start(channel->clients);
1250 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1251 SilcClientEntry e = chu->client;
1252 char *m, tmp[80], line[80], len1;
1254 memset(line, 0, sizeof(line));
1255 memset(tmp, 0, sizeof(tmp));
1256 m = silc_client_chumode_char(chu->mode);
1259 strcat(line, e->nickname);
1260 strcat(line, e->server ? "@" : "");
1264 len1 = strlen(e->server);
1265 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1267 len1 = strlen(line);
1269 memset(&line[29], 0, len1 - 29);
1271 for (i = 0; i < 30 - len1 - 1; i++)
1276 strcat(tmp, m ? m : "");
1279 if (strlen(tmp) < 5)
1280 for (i = 0; i < 5 - strlen(tmp); i++)
1283 strcat(line, e->username ? e->username : "");
1285 cmd->client->ops->say(cmd->client, conn, "%s", line);
1292 /* Notify application */
1296 silc_client_command_free(cmd);