5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 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"
23 #include "client_internal.h"
25 /* Client command list. */
26 SilcClientCommand silc_command_list[] =
28 SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
29 SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
30 SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY",
31 SILC_CF_LAG | SILC_CF_REG, 3),
32 SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
33 SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
34 SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
35 SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
36 SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 2),
37 SILC_CLIENT_CMD(kill, KILL, "KILL",
38 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
39 SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
40 SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
41 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
42 SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
43 SILC_CLIENT_CMD(oper, OPER, "OPER",
44 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
45 SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 5),
46 SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
47 SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
48 SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
49 SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
50 SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 4),
51 SILC_CLIENT_CMD(restart, RESTART, "RESTART",
52 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
53 SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
54 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
55 SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
56 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
57 SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER",
58 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
59 SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
60 SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
62 { NULL, 0, NULL, 0, 0 },
65 #define SILC_NOT_CONNECTED(x, c) \
66 x->ops->say((x), (c), \
67 "You are not connected to a server, use /SERVER to connect");
69 /* Command operation that is called at the end of all commands.
71 #define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
72 cmd, TRUE, cmd->command->cmd)
74 /* Error to application. Usage: COMMAND_ERROR; */
75 #define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
76 cmd, FALSE, cmd->command->cmd)
78 /* Generic function to send any command. The arguments must be sent already
79 encoded into correct form and in correct order. */
81 void silc_client_send_command(SilcClient client, SilcClientConnection conn,
82 SilcCommand command, unsigned short ident,
83 unsigned int argc, ...)
90 packet = silc_command_payload_encode_vap(command, ident, argc, ap);
91 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
92 NULL, 0, NULL, NULL, packet->data,
94 silc_buffer_free(packet);
97 /* Finds and returns a pointer to the command list. Return NULL if the
98 command is not found. */
100 SilcClientCommand *silc_client_command_find(const char *name)
102 SilcClientCommand *cmd;
104 for (cmd = silc_command_list; cmd->name; cmd++) {
105 if (!strcmp(cmd->name, name))
112 /* Add new pending command to be executed when reply to a command has been
113 received. The `reply_cmd' is the command that will call the `callback'
114 with `context' when reply has been received. If `ident is non-zero
115 the `callback' will be executed when received reply with command
116 identifier `ident'. */
118 void silc_client_command_pending(SilcClientConnection conn,
119 SilcCommand reply_cmd,
120 unsigned short ident,
121 SilcClientPendingDestructor destructor,
122 SilcCommandCb callback,
125 SilcClientCommandPending *reply;
127 reply = silc_calloc(1, sizeof(*reply));
128 reply->reply_cmd = reply_cmd;
129 reply->ident = ident;
130 reply->context = context;
131 reply->callback = callback;
132 reply->destructor = destructor;
133 silc_dlist_add(conn->pending_commands, reply);
136 /* Deletes pending command by reply command type. */
138 void silc_client_command_pending_del(SilcClientConnection conn,
139 SilcCommand reply_cmd,
140 unsigned short ident)
142 SilcClientCommandPending *r;
144 silc_dlist_start(conn->pending_commands);
145 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
146 if (r->reply_cmd == reply_cmd && r->ident == ident) {
147 silc_dlist_del(conn->pending_commands, r);
153 /* Checks for pending commands and marks callbacks to be called from
154 the command reply function. Returns TRUE if there were pending command. */
156 int silc_client_command_pending_check(SilcClientConnection conn,
157 SilcClientCommandReplyContext ctx,
159 unsigned short ident)
161 SilcClientCommandPending *r;
163 silc_dlist_start(conn->pending_commands);
164 while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
165 if (r->reply_cmd == command && r->ident == ident) {
166 ctx->context = r->context;
167 ctx->callback = r->callback;
168 ctx->destructor = r->destructor;
177 /* Allocate Command Context */
179 SilcClientCommandContext silc_client_command_alloc()
181 SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
186 /* Free command context and its internals */
188 void silc_client_command_free(SilcClientCommandContext ctx)
191 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
193 if (ctx->users < 1) {
196 for (i = 0; i < ctx->argc; i++)
197 silc_free(ctx->argv[i]);
202 /* Duplicate Command Context by adding reference counter. The context won't
203 be free'd untill it hits zero. */
205 SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
208 SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
213 /* Pending command destructor. */
215 static void silc_client_command_destructor(void *context)
217 silc_client_command_free((SilcClientCommandContext)context);
220 /* silc_client_get_client completion callback */
221 void silc_client_command_completion(SilcClient client,
222 SilcClientConnection conn,
223 SilcClientEntry clients,
224 unsigned int clients_count,
230 /* Command WHOIS. This command is used to query information about
233 SILC_CLIENT_CMD_FUNC(whois)
235 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
236 SilcClientConnection conn = cmd->conn;
240 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
245 if (cmd->argc < 2 || cmd->argc > 3) {
246 cmd->client->ops->say(cmd->client, conn,
247 "Usage: /WHOIS <nickname>[@<server>] [<count>]");
252 buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
253 cmd->argc - 1, ++cmd->argv,
254 ++cmd->argv_lens, ++cmd->argv_types,
256 silc_client_packet_send(cmd->client, cmd->conn->sock,
257 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
258 buffer->data, buffer->len, TRUE);
259 silc_buffer_free(buffer);
264 /* Notify application */
268 silc_client_command_free(cmd);
271 /* Command WHOWAS. This command is used to query history information about
272 specific user that used to exist in the network. */
274 SILC_CLIENT_CMD_FUNC(whowas)
276 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
277 SilcClientConnection conn = cmd->conn;
281 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
286 if (cmd->argc < 2 || cmd->argc > 3) {
287 cmd->client->ops->say(cmd->client, conn,
288 "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
293 buffer = silc_command_payload_encode(SILC_COMMAND_WHOWAS,
294 cmd->argc - 1, ++cmd->argv,
295 ++cmd->argv_lens, ++cmd->argv_types,
297 silc_client_packet_send(cmd->client, cmd->conn->sock,
298 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
299 buffer->data, buffer->len, TRUE);
300 silc_buffer_free(buffer);
305 /* Notify application */
309 silc_client_command_free(cmd);
312 /* Command IDENTIFY. This command is used to query information about
313 specific user, especially ID's. */
315 SILC_CLIENT_CMD_FUNC(identify)
317 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
318 SilcClientConnection conn = cmd->conn;
322 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
327 if (cmd->argc < 2 || cmd->argc > 3) {
328 cmd->client->ops->say(cmd->client, conn,
329 "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
334 buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
335 cmd->argc - 1, ++cmd->argv,
336 ++cmd->argv_lens, ++cmd->argv_types,
338 silc_client_packet_send(cmd->client, cmd->conn->sock,
339 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
340 buffer->data, buffer->len, TRUE);
341 silc_buffer_free(buffer);
346 /* Notify application */
350 silc_client_command_free(cmd);
353 /* Command NICK. Shows current nickname/sets new nickname on current
356 SILC_CLIENT_CMD_FUNC(nick)
358 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
359 SilcClientConnection conn = cmd->conn;
363 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
368 if (!strcmp(conn->nickname, cmd->argv[1]))
371 /* Show current nickname */
374 cmd->client->ops->say(cmd->client, conn,
375 "Your nickname is %s on server %s",
376 conn->nickname, conn->remote_host);
378 cmd->client->ops->say(cmd->client, conn,
379 "Your nickname is %s", conn->nickname);
382 /* XXX Notify application */
387 /* Set new nickname */
388 buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
389 cmd->argc - 1, ++cmd->argv,
390 ++cmd->argv_lens, ++cmd->argv_types,
391 ++cmd->conn->cmd_ident);
392 silc_client_packet_send(cmd->client, cmd->conn->sock,
393 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
394 buffer->data, buffer->len, TRUE);
395 silc_buffer_free(buffer);
400 silc_free(conn->nickname);
401 conn->nickname = strdup(cmd->argv[1]);
403 /* Notify application */
407 silc_client_command_free(cmd);
410 SILC_CLIENT_CMD_FUNC(list)
414 /* Command TOPIC. Sets/shows topic on a channel. */
416 SILC_CLIENT_CMD_FUNC(topic)
418 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
419 SilcClientConnection conn = cmd->conn;
420 SilcIDCacheEntry id_cache = NULL;
421 SilcChannelEntry channel;
422 SilcBuffer buffer, idp;
426 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
431 if (cmd->argc < 2 || cmd->argc > 3) {
432 cmd->client->ops->say(cmd->client, conn,
433 "Usage: /TOPIC <channel> [<topic>]");
438 if (cmd->argv[1][0] == '*') {
439 if (!conn->current_channel) {
440 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
444 name = conn->current_channel->channel_name;
449 if (!conn->current_channel) {
450 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
455 /* Get the Channel ID of the channel */
456 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
457 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
462 channel = (SilcChannelEntry)id_cache->context;
464 /* Send TOPIC command to the server */
465 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
467 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 0, 2,
468 1, idp->data, idp->len,
470 strlen(cmd->argv[2]));
472 buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1,
473 1, idp->data, idp->len,
475 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
476 0, NULL, NULL, buffer->data, buffer->len, TRUE);
477 silc_buffer_free(buffer);
478 silc_buffer_free(idp);
480 /* Notify application */
484 silc_client_command_free(cmd);
487 /* Command INVITE. Invites specific client to join a channel. */
489 SILC_CLIENT_CMD_FUNC(invite)
491 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
492 SilcClient client = cmd->client;
493 SilcClientConnection conn = cmd->conn;
494 SilcClientEntry client_entry;
495 SilcChannelEntry channel_entry;
496 SilcBuffer buffer, clidp, chidp;
497 unsigned int num = 0;
498 char *nickname = NULL, *server = NULL;
501 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
506 if (cmd->argc != 3) {
507 cmd->client->ops->say(cmd->client, conn,
508 "Usage: /INVITE <nickname>[@<server>] <channel>");
513 /* Parse the typed nickname. */
514 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
515 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
520 /* Find client entry */
521 client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
529 /* Client entry not found, it was requested thus mark this to be
531 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
532 silc_client_command_destructor,
533 silc_client_command_invite,
534 silc_client_command_dup(cmd));
539 /* Find channel entry */
540 channel_entry = silc_client_get_channel(client, conn, cmd->argv[2]);
541 if (!channel_entry) {
542 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
548 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
549 chidp = silc_id_payload_encode(channel_entry->id, SILC_ID_CHANNEL);
550 buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 0, 2,
551 1, clidp->data, clidp->len,
552 2, chidp->data, chidp->len);
553 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
554 0, NULL, NULL, buffer->data, buffer->len, TRUE);
555 silc_buffer_free(buffer);
556 silc_buffer_free(clidp);
557 silc_buffer_free(chidp);
559 cmd->client->ops->say(cmd->client, conn,
560 "Inviting %s to channel %s", cmd->argv[1],
563 /* Notify application */
571 silc_client_command_free(cmd);
576 SilcClientConnection conn;
579 SILC_TASK_CALLBACK(silc_client_command_quit_cb)
581 QuitInternal q = (QuitInternal)context;
583 /* Close connection */
584 q->client->ops->disconnect(q->client, q->conn);
585 silc_client_close_connection(q->client, q->conn->sock->user_data);
590 /* Command QUIT. Closes connection with current server. */
592 SILC_CLIENT_CMD_FUNC(quit)
594 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
599 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
605 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
606 &cmd->argv[1], &cmd->argv_lens[1],
607 &cmd->argv_types[1], 0);
609 buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
610 NULL, NULL, NULL, 0);
611 silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
613 buffer->data, buffer->len, TRUE);
614 silc_buffer_free(buffer);
616 q = silc_calloc(1, sizeof(*q));
617 q->client = cmd->client;
620 /* We quit the connection with little timeout */
621 silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
622 silc_client_command_quit_cb, (void *)q,
623 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
625 /* Notify application */
629 silc_client_command_free(cmd);
632 /* Command KILL. Router operator can use this command to remove an client
633 fromthe SILC Network. */
635 SILC_CLIENT_CMD_FUNC(kill)
637 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
638 SilcClientConnection conn = cmd->conn;
639 SilcBuffer buffer, idp;
640 SilcClientEntry target;
641 unsigned int num = 0;
642 char *nickname = NULL, *server = NULL;
645 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
651 cmd->client->ops->say(cmd->client, conn,
652 "Usage: /KILL <nickname> [<comment>]");
657 /* Parse the typed nickname. */
658 if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
659 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
664 /* Get the target client */
665 target = silc_idlist_get_client(cmd->client, conn, nickname,
672 /* Client entry not found, it was requested thus mark this to be
674 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
676 silc_client_command_destructor,
677 silc_client_command_kill,
678 silc_client_command_dup(cmd));
683 /* Send the KILL command to the server */
684 idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
686 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
687 1, idp->data, idp->len);
689 buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
690 1, idp->data, idp->len,
692 strlen(cmd->argv[2]));
693 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
694 0, NULL, NULL, buffer->data, buffer->len, TRUE);
695 silc_buffer_free(buffer);
696 silc_buffer_free(idp);
698 /* Notify application */
701 /* Remove the client entry to be killed */
702 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
704 if (target->nickname)
705 silc_free(target->nickname);
707 silc_free(target->server);
709 silc_free(target->id);
710 if (target->send_key)
711 silc_cipher_free(target->send_key);
712 if (target->receive_key)
713 silc_cipher_free(target->receive_key);
721 silc_client_command_free(cmd);
724 /* Command INFO. Request information about specific server. If specific
725 server is not provided the current server is used. */
727 SILC_CLIENT_CMD_FUNC(info)
729 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
730 SilcClientConnection conn = cmd->conn;
735 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
741 name = strdup(conn->remote_host);
743 name = strdup(cmd->argv[1]);
745 /* Send the command */
746 buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
747 1, name, strlen(name));
748 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
749 0, NULL, NULL, buffer->data, buffer->len, TRUE);
750 silc_buffer_free(buffer);
752 /* Notify application */
756 silc_client_command_free(cmd);
759 /* Command PING. Sends ping to server. This is used to test the
760 communication channel. */
762 SILC_CLIENT_CMD_FUNC(ping)
764 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
765 SilcClientConnection conn = cmd->conn;
772 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
777 if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
778 name = strdup(conn->remote_host);
780 /* Send the command */
781 buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
782 1, conn->remote_id_data,
784 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
785 0, NULL, NULL, buffer->data, buffer->len, TRUE);
786 silc_buffer_free(buffer);
788 id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
791 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
796 /* Start counting time */
797 for (i = 0; i < conn->ping_count; i++) {
798 if (conn->ping[i].dest_id == NULL) {
799 conn->ping[i].start_time = time(NULL);
800 conn->ping[i].dest_id = id;
801 conn->ping[i].dest_name = name;
806 if (i >= conn->ping_count) {
807 i = conn->ping_count;
808 conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
809 conn->ping[i].start_time = time(NULL);
810 conn->ping[i].dest_id = id;
811 conn->ping[i].dest_name = name;
815 /* Notify application */
819 silc_client_command_free(cmd);
822 SILC_CLIENT_CMD_FUNC(notice)
826 /* Command JOIN. Joins to a channel. */
828 SILC_CLIENT_CMD_FUNC(join)
830 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
831 SilcClientConnection conn = cmd->conn;
832 SilcIDCacheEntry id_cache = NULL;
833 SilcBuffer buffer, idp;
836 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
842 /* Show channels currently joined to */
847 /* See if we have joined to the requested channel already */
848 if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
850 cmd->client->ops->say(cmd->client, conn,
851 "You are talking to channel %s", cmd->argv[1]);
852 conn->current_channel = (SilcChannelEntry)id_cache->context;
854 cmd->client->screen->bottom_line->channel = cmd->argv[1];
855 silc_screen_print_bottom_line(cmd->client->screen, 0);
860 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
862 /* Send JOIN command to the server */
865 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
866 1, cmd->argv[1], cmd->argv_lens[1],
867 2, idp->data, idp->len);
868 else if (cmd->argc == 3)
871 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
872 1, cmd->argv[1], cmd->argv_lens[1],
873 2, idp->data, idp->len,
874 3, cmd->argv[2], cmd->argv_lens[2]);
877 silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 4,
878 1, cmd->argv[1], cmd->argv_lens[1],
879 2, idp->data, idp->len,
880 3, cmd->argv[2], cmd->argv_lens[2],
881 4, cmd->argv[3], cmd->argv_lens[3]);
883 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
884 0, NULL, NULL, buffer->data, buffer->len, TRUE);
885 silc_buffer_free(buffer);
886 silc_buffer_free(idp);
888 /* Notify application */
892 silc_client_command_free(cmd);
895 /* MOTD command. Requests motd from server. */
897 SILC_CLIENT_CMD_FUNC(motd)
899 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
900 SilcClientConnection conn = cmd->conn;
904 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
909 if (cmd->argc < 1 || cmd->argc > 1) {
910 cmd->client->ops->say(cmd->client, conn,
916 /* Send TOPIC command to the server */
917 buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
918 2, conn->remote_host,
919 strlen(conn->remote_host));
920 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
921 0, NULL, NULL, buffer->data, buffer->len, TRUE);
922 silc_buffer_free(buffer);
924 /* Notify application */
928 silc_client_command_free(cmd);
931 /* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
932 modes as client cannot set itself server/router operator privileges. */
934 SILC_CLIENT_CMD_FUNC(umode)
936 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
937 SilcClientConnection conn = cmd->conn;
938 SilcBuffer buffer, idp;
939 unsigned char *cp, modebuf[4];
940 unsigned int mode, add, len;
944 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
950 cmd->client->ops->say(cmd->client, conn,
951 "Usage: /UMODE +|-<modes>");
956 mode = conn->local_entry->mode;
958 /* Are we adding or removing mode */
959 if (cmd->argv[1][0] == '-')
965 cp = cmd->argv[1] + 1;
967 for (i = 0; i < len; i++) {
972 mode |= SILC_UMODE_SERVER_OPERATOR;
973 mode |= SILC_UMODE_ROUTER_OPERATOR;
975 mode = SILC_UMODE_NONE;
980 mode |= SILC_UMODE_SERVER_OPERATOR;
982 mode &= ~SILC_UMODE_SERVER_OPERATOR;
986 mode |= SILC_UMODE_ROUTER_OPERATOR;
988 mode &= ~SILC_UMODE_ROUTER_OPERATOR;
997 idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
998 SILC_PUT32_MSB(mode, modebuf);
1000 /* Send the command packet. We support sending only one mode at once
1001 that requires an argument. */
1003 silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
1004 1, idp->data, idp->len,
1005 2, modebuf, sizeof(modebuf));
1006 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1007 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1008 silc_buffer_free(buffer);
1009 silc_buffer_free(idp);
1011 /* Notify application */
1015 silc_client_command_free(cmd);
1018 /* CMODE command. Sets channel mode. Modes that does not require any arguments
1019 can be set several at once. Those modes that require argument must be set
1020 separately (unless set with modes that does not require arguments). */
1022 SILC_CLIENT_CMD_FUNC(cmode)
1024 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1025 SilcClientConnection conn = cmd->conn;
1026 SilcChannelEntry channel;
1027 SilcBuffer buffer, chidp;
1028 unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
1029 unsigned int mode, add, type, len, arg_len = 0;
1033 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1038 if (cmd->argc < 3) {
1039 cmd->client->ops->say(cmd->client, conn,
1040 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
1045 if (cmd->argv[1][0] == '*') {
1046 if (!conn->current_channel) {
1047 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1052 channel = conn->current_channel;
1054 name = cmd->argv[1];
1056 channel = silc_client_get_channel(cmd->client, conn, name);
1058 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1064 mode = channel->mode;
1066 /* Are we adding or removing mode */
1067 if (cmd->argv[2][0] == '-')
1072 /* Argument type to be sent to server */
1076 cp = cmd->argv[2] + 1;
1078 for (i = 0; i < len; i++) {
1082 mode |= SILC_CHANNEL_MODE_PRIVATE;
1084 mode &= ~SILC_CHANNEL_MODE_PRIVATE;
1088 mode |= SILC_CHANNEL_MODE_SECRET;
1090 mode &= ~SILC_CHANNEL_MODE_SECRET;
1094 mode |= SILC_CHANNEL_MODE_PRIVKEY;
1096 mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
1100 mode |= SILC_CHANNEL_MODE_INVITE;
1102 mode &= ~SILC_CHANNEL_MODE_INVITE;
1106 mode |= SILC_CHANNEL_MODE_TOPIC;
1108 mode &= ~SILC_CHANNEL_MODE_TOPIC;
1113 mode |= SILC_CHANNEL_MODE_ULIMIT;
1115 ll = atoi(cmd->argv[3]);
1116 SILC_PUT32_MSB(ll, tmp);
1120 mode &= ~SILC_CHANNEL_MODE_ULIMIT;
1125 mode |= SILC_CHANNEL_MODE_PASSPHRASE;
1128 arg_len = cmd->argv_lens[3];
1130 mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
1135 mode |= SILC_CHANNEL_MODE_BAN;
1138 arg_len = cmd->argv_lens[3];
1140 mode &= ~SILC_CHANNEL_MODE_BAN;
1145 mode |= SILC_CHANNEL_MODE_INVITE_LIST;
1148 arg_len = cmd->argv_lens[3];
1150 mode &= ~SILC_CHANNEL_MODE_INVITE_LIST;
1155 mode |= SILC_CHANNEL_MODE_CIPHER;
1158 arg_len = cmd->argv_lens[3];
1160 mode &= ~SILC_CHANNEL_MODE_CIPHER;
1170 if (type && cmd->argc < 3) {
1175 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1176 SILC_PUT32_MSB(mode, modebuf);
1178 /* Send the command packet. We support sending only one mode at once
1179 that requires an argument. */
1182 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
1183 1, chidp->data, chidp->len,
1184 2, modebuf, sizeof(modebuf),
1185 type, arg, arg_len);
1188 silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
1189 1, chidp->data, chidp->len,
1190 2, modebuf, sizeof(modebuf));
1193 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1194 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1195 silc_buffer_free(buffer);
1196 silc_buffer_free(chidp);
1198 /* Notify application */
1202 silc_client_command_free(cmd);
1205 /* CUMODE command. Changes client's mode on a channel. */
1207 SILC_CLIENT_CMD_FUNC(cumode)
1209 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1210 SilcClientConnection conn = cmd->conn;
1211 SilcChannelEntry channel;
1212 SilcChannelUser chu;
1213 SilcClientEntry client_entry;
1214 SilcBuffer buffer, clidp, chidp;
1215 unsigned char *name, *cp, modebuf[4];
1216 unsigned int mode = 0, add, len;
1217 char *nickname = NULL, *server = NULL;
1218 unsigned int num = 0;
1222 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1227 if (cmd->argc < 4) {
1228 cmd->client->ops->say(cmd->client, conn,
1229 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
1234 if (cmd->argv[1][0] == '*') {
1235 if (!conn->current_channel) {
1236 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1241 channel = conn->current_channel;
1243 name = cmd->argv[1];
1245 channel = silc_client_get_channel(cmd->client, conn, name);
1247 cmd->client->ops->say(cmd->client, conn, "You are on that channel");
1253 /* Parse the typed nickname. */
1254 if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
1255 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1260 /* Find client entry */
1261 client_entry = silc_idlist_get_client(cmd->client, conn,
1262 nickname, server, num, TRUE);
1263 if (!client_entry) {
1264 /* Client entry not found, it was requested thus mark this to be
1266 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
1268 silc_client_command_destructor,
1269 silc_client_command_cumode,
1270 silc_client_command_dup(cmd));
1275 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1276 if (chu->client == client_entry) {
1282 /* Are we adding or removing mode */
1283 if (cmd->argv[2][0] == '-')
1289 cp = cmd->argv[2] + 1;
1291 for (i = 0; i < len; i++) {
1295 mode |= SILC_CHANNEL_UMODE_CHANFO;
1296 mode |= SILC_CHANNEL_UMODE_CHANOP;
1298 mode = SILC_CHANNEL_UMODE_NONE;
1303 mode |= SILC_CHANNEL_UMODE_CHANFO;
1305 mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1309 mode |= SILC_CHANNEL_UMODE_CHANOP;
1311 mode &= ~SILC_CHANNEL_UMODE_CHANOP;
1320 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1321 SILC_PUT32_MSB(mode, modebuf);
1322 clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1324 /* Send the command packet. We support sending only one mode at once
1325 that requires an argument. */
1326 buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3,
1327 1, chidp->data, chidp->len,
1329 3, clidp->data, clidp->len);
1331 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1332 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1333 silc_buffer_free(buffer);
1334 silc_buffer_free(chidp);
1335 silc_buffer_free(clidp);
1337 /* Notify application */
1342 silc_free(nickname);
1345 silc_client_command_free(cmd);
1348 /* KICK command. Kicks a client out of channel. */
1350 SILC_CLIENT_CMD_FUNC(kick)
1352 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1353 SilcClientConnection conn = cmd->conn;
1354 SilcIDCacheEntry id_cache = NULL;
1355 SilcChannelEntry channel;
1356 SilcBuffer buffer, idp, idp2;
1357 SilcClientEntry target;
1359 unsigned int num = 0;
1360 char *nickname = NULL, *server = NULL;
1363 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1368 if (cmd->argc < 3) {
1369 cmd->client->ops->say(cmd->client, conn,
1370 "Usage: /KICK <channel> <nickname> [<comment>]");
1375 if (cmd->argv[1][0] == '*') {
1376 if (!conn->current_channel) {
1377 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1381 name = conn->current_channel->channel_name;
1383 name = cmd->argv[1];
1386 if (!conn->current_channel) {
1387 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1392 /* Get the Channel ID of the channel */
1393 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1394 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1399 channel = (SilcChannelEntry)id_cache->context;
1401 /* Parse the typed nickname. */
1402 if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
1403 cmd->client->ops->say(cmd->client, conn, "Bad nickname");
1408 /* Get the target client */
1409 target = silc_idlist_get_client(cmd->client, conn, nickname,
1410 server, num, FALSE);
1412 cmd->client->ops->say(cmd->client, conn, "No such client: %s",
1418 /* Send KICK command to the server */
1419 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1420 idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
1422 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
1423 1, idp->data, idp->len,
1424 2, idp2->data, idp2->len);
1426 buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
1427 1, idp->data, idp->len,
1428 2, idp2->data, idp2->len,
1430 strlen(cmd->argv[3]));
1431 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1432 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1433 silc_buffer_free(buffer);
1434 silc_buffer_free(idp);
1435 silc_buffer_free(idp2);
1437 /* Notify application */
1442 silc_free(nickname);
1445 silc_client_command_free(cmd);
1448 /* OPER command. Used to obtain server operator privileges. */
1450 SILC_CLIENT_CMD_FUNC(oper)
1452 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1453 SilcClientConnection conn = cmd->conn;
1455 unsigned char *auth_data;
1459 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1464 if (cmd->argc < 2) {
1465 cmd->client->ops->say(cmd->client, conn,
1466 "Usage: /OPER <username> [<public key>]");
1471 if (cmd->argc == 3) {
1472 /* XXX Get public key */
1477 /* Get passphrase */
1479 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1485 /* Encode the authentication payload */
1486 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1487 auth_data, strlen(auth_data));
1490 buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
1492 strlen(cmd->argv[1]),
1493 2, auth->data, auth->len);
1494 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1495 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1497 silc_buffer_free(buffer);
1498 silc_buffer_free(auth);
1499 memset(auth_data, 0, strlen(auth_data));
1500 silc_free(auth_data);
1502 /* Notify application */
1506 silc_client_command_free(cmd);
1509 /* SILCOPER command. Used to obtain router operator privileges. */
1511 SILC_CLIENT_CMD_FUNC(silcoper)
1513 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1514 SilcClientConnection conn = cmd->conn;
1516 unsigned char *auth_data;
1520 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1525 if (cmd->argc < 2) {
1526 cmd->client->ops->say(cmd->client, conn,
1527 "Usage: /SILCOPER <username> [<public key>]");
1532 if (cmd->argc == 3) {
1533 /* XXX Get public key */
1538 /* Get passphrase */
1540 auth_data = cmd->client->ops->ask_passphrase(cmd->client, conn);
1546 /* Encode the authentication payload */
1547 auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
1548 auth_data, strlen(auth_data));
1551 buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
1553 strlen(cmd->argv[1]),
1554 2, auth->data, auth->len);
1555 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1556 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1558 silc_buffer_free(buffer);
1559 silc_buffer_free(auth);
1560 memset(auth_data, 0, strlen(auth_data));
1561 silc_free(auth_data);
1563 /* Notify application */
1567 silc_client_command_free(cmd);
1570 /* CONNECT command. Connects the server to another server. */
1572 SILC_CLIENT_CMD_FUNC(connect)
1574 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1575 SilcClientConnection conn = cmd->conn;
1577 unsigned char port[4];
1581 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1586 if (cmd->argc < 2) {
1587 cmd->client->ops->say(cmd->client, conn,
1588 "Usage: /CONNECT <server> [<port>]");
1593 if (cmd->argc == 3) {
1594 tmp = atoi(cmd->argv[2]);
1595 SILC_PUT32_MSB(tmp, port);
1599 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
1601 strlen(cmd->argv[1]),
1604 buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
1606 strlen(cmd->argv[1]));
1607 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1608 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1609 silc_buffer_free(buffer);
1611 /* Notify application */
1615 silc_client_command_free(cmd);
1618 SILC_CLIENT_CMD_FUNC(restart)
1622 /* CLOSE command. Close server connection to the remote server */
1624 SILC_CLIENT_CMD_FUNC(close)
1626 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1627 SilcClientConnection conn = cmd->conn;
1629 unsigned char port[4];
1633 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1638 if (cmd->argc < 2) {
1639 cmd->client->ops->say(cmd->client, conn,
1640 "Usage: /CLOSE <server> [<port>]");
1645 if (cmd->argc == 3) {
1646 tmp = atoi(cmd->argv[2]);
1647 SILC_PUT32_MSB(tmp, port);
1651 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
1653 strlen(cmd->argv[1]),
1656 buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
1658 strlen(cmd->argv[1]));
1659 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1660 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1661 silc_buffer_free(buffer);
1663 /* Notify application */
1667 silc_client_command_free(cmd);
1670 /* SHUTDOWN command. Shutdowns the server. */
1672 SILC_CLIENT_CMD_FUNC(shutdown)
1674 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1677 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1682 /* Send the command */
1683 silc_client_send_command(cmd->client, cmd->conn,
1684 SILC_COMMAND_SHUTDOWN, 0, 0);
1686 /* Notify application */
1690 silc_client_command_free(cmd);
1693 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
1695 SILC_CLIENT_CMD_FUNC(leave)
1697 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1698 SilcClientConnection conn = cmd->conn;
1699 SilcIDCacheEntry id_cache = NULL;
1700 SilcChannelEntry channel;
1701 SilcBuffer buffer, idp;
1705 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1710 if (cmd->argc != 2) {
1711 cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
1716 if (cmd->argv[1][0] == '*') {
1717 if (!conn->current_channel) {
1718 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1722 name = conn->current_channel->channel_name;
1724 name = cmd->argv[1];
1727 if (!conn->current_channel) {
1728 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1733 /* Get the Channel ID of the channel */
1734 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1735 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1740 channel = (SilcChannelEntry)id_cache->context;
1742 /* Send LEAVE command to the server */
1743 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1744 buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
1745 1, idp->data, idp->len);
1746 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
1747 0, NULL, NULL, buffer->data, buffer->len, TRUE);
1748 silc_buffer_free(buffer);
1749 silc_buffer_free(idp);
1751 /* We won't talk anymore on this channel */
1752 cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
1754 conn->current_channel = NULL;
1756 silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
1757 silc_free(channel->channel_name);
1758 silc_free(channel->id);
1759 silc_free(channel->key);
1760 silc_cipher_free(channel->channel_key);
1763 /* Notify application */
1767 silc_client_command_free(cmd);
1770 /* Command USERS. Requests the USERS of the clients joined on requested
1773 SILC_CLIENT_CMD_FUNC(users)
1775 SilcClientCommandContext cmd = (SilcClientCommandContext)context;
1776 SilcClientConnection conn = cmd->conn;
1777 SilcIDCacheEntry id_cache = NULL;
1778 SilcChannelEntry channel;
1779 SilcBuffer buffer, idp;
1780 char *name, *line = NULL;
1781 unsigned int line_len = 0;
1784 SILC_NOT_CONNECTED(cmd->client, cmd->conn);
1789 if (cmd->argc != 2) {
1790 cmd->client->ops->say(cmd->client, conn, "Usage: /USERS <channel>");
1795 if (cmd->argv[1][0] == '*') {
1796 if (!conn->current_channel) {
1797 cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
1801 name = conn->current_channel->channel_name;
1803 name = cmd->argv[1];
1806 if (!conn->current_channel) {
1807 cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
1812 /* Get the Channel ID of the channel */
1813 if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
1814 /* XXX should resolve the channel ID; LIST command */
1815 cmd->client->ops->say(cmd->client, conn,
1816 "You are not on that channel", name);
1821 channel = (SilcChannelEntry)id_cache->context;
1823 if (!cmd->pending) {
1824 /* Send USERS command to the server */
1825 idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
1826 buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
1827 ++conn->cmd_ident, 1,
1828 1, idp->data, idp->len);
1829 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1830 NULL, 0, NULL, NULL, buffer->data,
1832 silc_buffer_free(buffer);
1833 silc_buffer_free(idp);
1835 /* Register pending callback which will recall this command callback with
1836 same context and reprocesses the command. When reprocessing we actually
1837 display the information on the screen. */
1838 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
1839 silc_client_command_destructor,
1840 silc_client_command_users,
1841 silc_client_command_dup(cmd));
1842 cmd->pending = TRUE;
1847 /* Pending command. Now we've resolved the information from server and
1848 we are ready to display the information on screen. */
1850 SilcChannelUser chu;
1852 cmd->client->ops->say(cmd->client, conn, "Users on %s",
1853 channel->channel_name);
1855 line = silc_calloc(4096, sizeof(*line));
1857 silc_list_start(channel->clients);
1858 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1859 SilcClientEntry e = chu->client;
1860 char *m, tmp[80], len1;
1862 memset(line, 0, sizeof(line_len));
1864 if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) {
1866 line_len += strlen(e->nickname) + strlen(e->server) + 100;
1867 line = silc_calloc(line_len, sizeof(*line));
1870 memset(tmp, 0, sizeof(tmp));
1871 m = silc_client_chumode_char(chu->mode);
1873 strncat(line, " ", 1);
1874 strncat(line, e->nickname, strlen(e->nickname));
1875 strncat(line, e->server ? "@" : "", 1);
1879 len1 = strlen(e->server);
1880 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1882 len1 = strlen(line);
1884 memset(&line[29], 0, len1 - 29);
1886 for (i = 0; i < 30 - len1 - 1; i++)
1890 strncat(line, " H", 3);
1891 strcat(tmp, m ? m : "");
1892 strncat(line, tmp, strlen(tmp));
1894 if (strlen(tmp) < 5)
1895 for (i = 0; i < 5 - strlen(tmp); i++)
1898 strcat(line, e->username ? e->username : "");
1900 cmd->client->ops->say(cmd->client, conn, "%s", line);
1910 /* Notify application */
1914 silc_client_command_free(cmd);