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 "serverincludes.h"
23 #include "server_internal.h"
24 #include "command_reply.h"
26 /* All functions that call the COMMAND_CHECK_STATUS or the
27 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
29 #define COMMAND_CHECK_STATUS \
31 SILC_LOG_DEBUG(("Start")); \
32 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
33 if (status != SILC_STATUS_OK) \
37 #define COMMAND_CHECK_STATUS_LIST \
39 SILC_LOG_DEBUG(("Start")); \
40 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
41 if (status != SILC_STATUS_OK && \
42 status != SILC_STATUS_LIST_START && \
43 status != SILC_STATUS_LIST_ITEM && \
44 status != SILC_STATUS_LIST_END) \
48 /* Server command reply list. Not all commands have reply function as
49 they are never sent by server. More maybe added later if need appears. */
50 SilcServerCommandReply silc_command_reply_list[] =
52 SILC_SERVER_CMD_REPLY(whois, WHOIS),
53 SILC_SERVER_CMD_REPLY(whowas, WHOWAS),
54 SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
55 SILC_SERVER_CMD_REPLY(info, INFO),
56 SILC_SERVER_CMD_REPLY(motd, MOTD),
57 SILC_SERVER_CMD_REPLY(join, JOIN),
58 SILC_SERVER_CMD_REPLY(users, USERS),
59 SILC_SERVER_CMD_REPLY(getkey, GETKEY),
64 /* Process received command reply. */
66 void silc_server_command_reply_process(SilcServer server,
67 SilcSocketConnection sock,
70 SilcServerCommandReply *cmd;
71 SilcServerCommandReplyContext ctx;
72 SilcCommandPayload payload;
76 SILC_LOG_DEBUG(("Start"));
78 /* Get command reply payload from packet */
79 payload = silc_command_payload_parse(buffer);
81 /* Silently ignore bad reply packet */
82 SILC_LOG_DEBUG(("Bad command reply packet"));
86 /* Allocate command reply context. This must be free'd by the
87 command reply routine receiving it. */
88 ctx = silc_calloc(1, sizeof(*ctx));
90 ctx->sock = silc_socket_dup(sock);
91 ctx->payload = payload;
92 ctx->args = silc_command_get_args(ctx->payload);
93 ident = silc_command_get_ident(ctx->payload);
95 /* Check for pending commands and mark to be exeucted */
96 silc_server_command_pending_check(server, ctx,
97 silc_command_get(ctx->payload), ident);
99 /* Execute command reply */
100 command = silc_command_get(ctx->payload);
101 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
102 if (cmd->cmd == command)
105 if (cmd == NULL || !cmd->cb) {
106 silc_server_command_reply_free(ctx);
113 /* Free command reply context and its internals. */
115 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
118 silc_command_free_payload(cmd->payload);
120 silc_socket_free(cmd->sock); /* Decrease the reference counter */
125 /* Caches the received WHOIS information. */
128 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
130 SilcServer server = cmd->server;
131 unsigned char *tmp, *id_data;
132 char *nickname, *username, *realname, *servername = NULL;
133 SilcClientID *client_id;
134 SilcClientEntry client;
137 uint32 mode = 0, len, id_len;
139 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
140 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
141 username = silc_argument_get_arg_type(cmd->args, 4, &len);
142 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
143 if (!id_data || !nickname || !username || !realname) {
144 SILC_LOG_ERROR(("Incomplete WHOIS info: %s %s %s",
145 nickname ? nickname : "",
146 username ? username : "",
147 realname ? realname : ""));
151 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
153 SILC_GET32_MSB(mode, tmp);
155 client_id = silc_id_payload_parse_id(id_data, id_len);
159 /* Check if we have this client cached already. */
161 client = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
163 client = silc_idlist_find_client_by_id(server->global_list, client_id,
169 /* If router did not find such Client ID in its lists then this must
170 be bogus client or some router in the net is buggy. */
171 if (server->server_type == SILC_ROUTER)
174 /* Take hostname out of nick string if it includes it. */
175 if (strchr(nickname, '@')) {
176 int len = strcspn(nickname, "@");
177 nick = silc_calloc(len + 1, sizeof(char));
178 servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
179 memcpy(nick, nickname, len);
180 memcpy(servername, nickname + len + 1, strlen(nickname) - len);
182 nick = strdup(nickname);
185 /* We don't have that client anywhere, add it. The client is added
186 to global list since server didn't have it in the lists so it must be
188 client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
190 strdup(realname), client_id,
191 cmd->sock->user_data, NULL);
195 client->data.registered = TRUE;
197 client->servername = servername;
199 /* We have the client already, update the data */
201 SILC_LOG_DEBUG(("Updating client data"));
203 /* Take hostname out of nick string if it includes it. */
204 if (strchr(nickname, '@')) {
205 int len = strcspn(nickname, "@");
206 nick = silc_calloc(len + 1, sizeof(char));
207 servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
208 memcpy(nick, nickname, len);
209 memcpy(servername, nickname + len + 1, strlen(nickname) - len);
211 nick = strdup(nickname);
214 if (client->nickname)
215 silc_free(client->nickname);
216 if (client->username)
217 silc_free(client->username);
218 if (client->userinfo)
219 silc_free(client->userinfo);
221 client->nickname = nick;
222 client->username = strdup(username);
223 client->userinfo = strdup(realname);
225 client->servername = servername;
227 /* Remove the old cache entry and create a new one */
228 silc_idcache_del_by_context(global ? server->global_list->clients :
229 server->local_list->clients, client);
230 silc_idcache_add(global ? server->global_list->clients :
231 server->local_list->clients, nick, strlen(nick),
232 client->id, client, FALSE);
233 silc_free(client_id);
239 /* Reiceved reply for WHOIS command. We sent the whois request to our
240 primary router, if we are normal server, and thus has now received reply
241 to the command. We will figure out what client originally sent us the
242 command and will send the reply to it. If we are router we will figure
243 out who server sent us the command and send reply to that one. */
245 SILC_SERVER_CMD_REPLY_FUNC(whois)
247 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
248 SilcCommandStatus status;
250 COMMAND_CHECK_STATUS_LIST;
252 if (!silc_server_command_reply_whois_save(cmd))
255 /* Pending callbacks are not executed if this was an list entry */
256 if (status != SILC_STATUS_OK &&
257 status != SILC_STATUS_LIST_END) {
258 silc_server_command_reply_free(cmd);
263 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
264 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
265 silc_server_command_reply_free(cmd);
268 /* Caches the received WHOWAS information for a short period of time. */
271 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
273 SilcServer server = cmd->server;
275 unsigned char *id_data;
276 char *nickname, *username, *realname, *servername = NULL;
277 SilcClientID *client_id;
278 SilcClientEntry client;
279 SilcIDCacheEntry cache = NULL;
283 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
284 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
285 username = silc_argument_get_arg_type(cmd->args, 4, &len);
286 if (!id_data || !nickname || !username)
289 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
291 client_id = silc_id_payload_parse_id(id_data, id_len);
295 /* Check if we have this client cached already. */
297 client = silc_idlist_find_client_by_id(server->local_list, client_id,
300 client = silc_idlist_find_client_by_id(server->global_list,
306 /* If router did not find such Client ID in its lists then this must
307 be bogus client or some router in the net is buggy. */
308 if (server->server_type == SILC_ROUTER)
311 /* Take hostname out of nick string if it includes it. */
312 if (strchr(nickname, '@')) {
313 int len = strcspn(nickname, "@");
314 nick = silc_calloc(len + 1, sizeof(char));
315 servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
316 memcpy(nick, nickname, len);
317 memcpy(servername, nickname + len + 1, strlen(nickname) - len);
319 nick = strdup(nickname);
322 /* We don't have that client anywhere, add it. The client is added
323 to global list since server didn't have it in the lists so it must be
325 client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
326 strdup(username), strdup(realname),
327 silc_id_dup(client_id, SILC_ID_CLIENT),
328 cmd->sock->user_data, NULL);
332 client->data.registered = FALSE;
333 client = silc_idlist_find_client_by_id(server->global_list,
335 cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
336 client->servername = servername;
338 /* We have the client already, update the data */
340 /* Take hostname out of nick string if it includes it. */
341 if (strchr(nickname, '@')) {
342 int len = strcspn(nickname, "@");
343 nick = silc_calloc(len + 1, sizeof(char));
344 servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
345 memcpy(nick, nickname, len);
346 memcpy(servername, nickname + len + 1, strlen(nickname) - len);
348 nick = strdup(nickname);
351 if (client->nickname)
352 silc_free(client->nickname);
353 if (client->username)
354 silc_free(client->username);
356 client->nickname = nick;
357 client->username = strdup(username);
358 client->servername = servername;
360 /* Remove the old cache entry and create a new one */
361 silc_idcache_del_by_context(global ? server->global_list->clients :
362 server->local_list->clients, client);
363 silc_idcache_add(global ? server->global_list->clients :
364 server->local_list->clients, nick, strlen(nick),
365 client->id, client, FALSE);
368 silc_free(client_id);
373 /* Received reply for WHOWAS command. Cache the client information only for
374 a short period of time. */
376 SILC_SERVER_CMD_REPLY_FUNC(whowas)
378 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
379 SilcCommandStatus status;
381 COMMAND_CHECK_STATUS_LIST;
383 if (!silc_server_command_reply_whowas_save(cmd))
386 /* Pending callbacks are not executed if this was an list entry */
387 if (status != SILC_STATUS_OK &&
388 status != SILC_STATUS_LIST_END) {
389 silc_server_command_reply_free(cmd);
394 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
395 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
396 silc_server_command_reply_free(cmd);
399 /* Caches the received IDENTIFY information. */
402 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
404 SilcServer server = cmd->server;
406 unsigned char *id_data;
407 char *nickname, *username;
408 SilcClientID *client_id;
409 SilcClientEntry client;
413 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
414 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
415 username = silc_argument_get_arg_type(cmd->args, 4, &len);
419 client_id = silc_id_payload_parse_id(id_data, id_len);
423 /* Check if we have this client cached already. */
425 client = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
427 client = silc_idlist_find_client_by_id(server->global_list, client_id,
433 /* If router did not find such Client ID in its lists then this must
434 be bogus client or some router in the net is buggy. */
435 if (server->server_type == SILC_ROUTER)
438 /* Take hostname out of nick string if it includes it. */
440 if (strchr(nickname, '@')) {
441 int len = strcspn(nickname, "@");
442 nick = silc_calloc(len + 1, sizeof(char));
443 memcpy(nick, nickname, len);
445 nick = strdup(nickname);
449 /* We don't have that client anywhere, add it. The client is added
450 to global list since server didn't have it in the lists so it must be
452 client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
453 username ? strdup(username) : NULL, NULL,
454 client_id, cmd->sock->user_data, NULL);
455 client->data.registered = TRUE;
457 /* We have the client already, update the data */
459 SILC_LOG_DEBUG(("Updating client data"));
461 /* Take hostname out of nick string if it includes it. */
463 if (strchr(nickname, '@')) {
464 int len = strcspn(nickname, "@");
465 nick = silc_calloc(len + 1, sizeof(char));
466 memcpy(nick, nickname, len);
468 nick = strdup(nickname);
472 if (nickname && client->nickname)
473 silc_free(client->nickname);
476 client->nickname = nick;
478 if (username && client->username) {
479 silc_free(client->username);
480 client->username = strdup(username);
483 /* Remove the old cache entry and create a new one */
485 silc_idcache_del_by_context(global ? server->global_list->clients :
486 server->local_list->clients, client);
487 silc_idcache_add(global ? server->global_list->clients :
488 server->local_list->clients, nick, strlen(nick),
489 client->id, client, FALSE);
491 silc_free(client_id);
497 /* Received reply for forwarded IDENTIFY command. We have received the
498 requested identify information now and we will cache it. After this we
499 will call the pending command so that the requestee gets the information
502 SILC_SERVER_CMD_REPLY_FUNC(identify)
504 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
505 SilcCommandStatus status;
507 COMMAND_CHECK_STATUS_LIST;
509 if (!silc_server_command_reply_identify_save(cmd))
512 /* Pending callbacks are not executed if this was an list entry */
513 if (status != SILC_STATUS_OK &&
514 status != SILC_STATUS_LIST_END) {
515 silc_server_command_reply_free(cmd);
520 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
521 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
522 silc_server_command_reply_free(cmd);
525 /* Received reply fro INFO command. Cache the server and its information */
527 SILC_SERVER_CMD_REPLY_FUNC(info)
529 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
530 SilcServer server = cmd->server;
531 SilcCommandStatus status;
532 SilcServerEntry entry;
533 SilcServerID *server_id;
535 unsigned char *tmp, *name;
537 COMMAND_CHECK_STATUS;
540 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
543 server_id = silc_id_payload_parse_id(tmp, tmp_len);
548 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
552 entry = silc_idlist_find_server_by_id(server->local_list, server_id, NULL);
554 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
557 /* Add the server to global list */
558 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
559 entry = silc_idlist_add_server(server->global_list, name, 0,
560 server_id, NULL, NULL);
562 silc_free(server_id);
568 /* Get the info string */
569 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
573 entry->server_info = tmp ? strdup(tmp) : NULL;
576 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
577 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
578 silc_server_command_reply_free(cmd);
581 /* Received reply fro MOTD command. */
583 SILC_SERVER_CMD_REPLY_FUNC(motd)
585 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
586 SilcServer server = cmd->server;
587 SilcCommandStatus status;
588 SilcServerEntry entry = NULL;
589 SilcServerID *server_id;
593 COMMAND_CHECK_STATUS;
596 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
599 server_id = silc_id_payload_parse_id(tmp, tmp_len);
603 entry = silc_idlist_find_server_by_id(server->local_list, server_id, NULL);
605 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
612 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
619 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
620 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
621 silc_server_command_reply_free(cmd);
627 /* Received reply for forwarded JOIN command. Router has created or joined
628 the client to the channel. We save some channel information locally
631 SILC_SERVER_CMD_REPLY_FUNC(join)
633 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
634 SilcServer server = cmd->server;
635 SilcIDCacheEntry cache = NULL;
636 SilcCommandStatus status;
638 SilcClientID *client_id = NULL;
639 SilcChannelEntry entry;
640 SilcHmac hmac = NULL;
641 uint32 id_len, len, list_count;
642 unsigned char *id_string;
643 char *channel_name, *tmp;
644 uint32 mode, created;
645 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
647 COMMAND_CHECK_STATUS;
649 /* Get channel name */
650 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
655 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
660 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
663 client_id = silc_id_payload_parse_id(tmp, len);
668 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
671 SILC_GET32_MSB(mode, tmp);
673 /* Get created boolean value */
674 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
677 SILC_GET32_MSB(created, tmp);
678 if (created != 0 && created != 1)
681 /* Get channel key */
682 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
684 keyp = silc_buffer_alloc(len);
685 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
686 silc_buffer_put(keyp, tmp, len);
689 id = silc_id_payload_parse_id(id_string, id_len);
694 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
696 if (!silc_hmac_alloc(tmp, NULL, &hmac))
700 /* Get the list count */
701 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
704 SILC_GET32_MSB(list_count, tmp);
706 /* Get Client ID list */
707 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
711 client_id_list = silc_buffer_alloc(len);
712 silc_buffer_pull_tail(client_id_list, len);
713 silc_buffer_put(client_id_list, tmp, len);
715 /* Get client mode list */
716 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
720 client_mode_list = silc_buffer_alloc(len);
721 silc_buffer_pull_tail(client_mode_list, len);
722 silc_buffer_put(client_mode_list, tmp, len);
724 /* See whether we already have the channel. */
725 entry = silc_idlist_find_channel_by_name(server->local_list,
726 channel_name, &cache);
728 /* Add new channel */
730 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
731 (created == 0 ? "existing" : "created"), channel_name,
732 silc_id_render(id, SILC_ID_CHANNEL)));
734 /* Add the channel to our local list. */
735 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
736 SILC_CHANNEL_MODE_NONE, id,
737 server->router, NULL, hmac);
743 /* The entry exists. */
745 silc_free(cache->id);
747 cache->id = entry->id;
749 /* Remove the founder auth data if the mode is not set but we have
751 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
752 silc_pkcs_public_key_free(entry->founder_key);
753 if (entry->founder_passwd) {
754 silc_free(entry->founder_passwd);
755 entry->founder_passwd = NULL;
760 if (entry->hmac_name && hmac) {
761 silc_free(entry->hmac_name);
762 entry->hmac_name = strdup(hmac->hmac->name);
765 /* Get the ban list */
766 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
769 silc_free(entry->ban_list);
770 entry->ban_list = silc_calloc(len, sizeof(*entry->ban_list));
771 memcpy(entry->ban_list, tmp, len);
774 /* Get the invite list */
775 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
777 if (entry->invite_list)
778 silc_free(entry->invite_list);
779 entry->invite_list = silc_calloc(len, sizeof(*entry->invite_list));
780 memcpy(entry->invite_list, tmp, len);
784 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
787 silc_free(entry->topic);
788 entry->topic = strdup(tmp);
791 /* If channel was not created we know there is global users on the
793 entry->global_users = (created == 0 ? TRUE : FALSE);
795 /* If channel was just created the mask must be zero */
796 if (!entry->global_users && mode) {
797 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
798 "new channel, forcing it to zero", cmd->sock->hostname));
802 /* Save channel mode */
805 /* Save channel key */
806 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
807 silc_server_save_channel_key(server, keyp, entry);
809 silc_buffer_free(keyp);
811 /* Save the users to the channel */
812 silc_server_save_users_on_channel(server, cmd->sock, entry,
813 client_id, client_id_list,
814 client_mode_list, list_count);
817 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
818 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
820 silc_free(client_id);
821 silc_server_command_reply_free(cmd);
824 silc_buffer_free(client_id_list);
825 if (client_mode_list)
826 silc_buffer_free(client_mode_list);
829 SILC_SERVER_CMD_REPLY_FUNC(users)
831 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
832 SilcServer server = cmd->server;
833 SilcCommandStatus status;
834 SilcChannelEntry channel;
835 SilcChannelID *channel_id = NULL;
836 SilcBuffer client_id_list;
837 SilcBuffer client_mode_list;
842 COMMAND_CHECK_STATUS;
845 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
848 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
852 /* Get channel entry */
853 channel = silc_idlist_find_channel_by_id(server->local_list,
856 channel = silc_idlist_find_channel_by_id(server->global_list,
862 /* Get the list count */
863 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
866 SILC_GET32_MSB(list_count, tmp);
868 /* Get Client ID list */
869 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
873 client_id_list = silc_buffer_alloc(tmp_len);
874 silc_buffer_pull_tail(client_id_list, tmp_len);
875 silc_buffer_put(client_id_list, tmp, tmp_len);
877 /* Get client mode list */
878 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
882 client_mode_list = silc_buffer_alloc(tmp_len);
883 silc_buffer_pull_tail(client_mode_list, tmp_len);
884 silc_buffer_put(client_mode_list, tmp, tmp_len);
886 /* Save the users to the channel */
887 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
888 client_id_list, client_mode_list,
891 silc_buffer_free(client_id_list);
892 silc_buffer_free(client_mode_list);
895 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
896 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
897 silc_free(channel_id);
898 silc_server_command_reply_free(cmd);
901 SILC_SERVER_CMD_REPLY_FUNC(getkey)
903 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
904 SilcServer server = cmd->server;
905 SilcCommandStatus status;
906 SilcClientEntry client = NULL;
907 SilcServerEntry server_entry = NULL;
908 SilcClientID *client_id = NULL;
909 SilcServerID *server_id = NULL;
911 unsigned char *tmp, *pk;
914 SilcIDPayload idp = NULL;
916 SilcPublicKey public_key = NULL;
918 COMMAND_CHECK_STATUS;
920 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
923 idp = silc_id_payload_parse_data(tmp, len);
927 /* Get the public key payload */
928 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
932 /* Decode the public key */
934 SILC_GET16_MSB(pk_len, tmp);
935 SILC_GET16_MSB(type, tmp + 2);
938 if (type != SILC_SKE_PK_TYPE_SILC)
941 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
944 id_type = silc_id_payload_get_type(idp);
945 if (id_type == SILC_ID_CLIENT) {
946 client_id = silc_id_payload_get_id(idp);
948 client = silc_idlist_find_client_by_id(server->local_list, client_id,
951 client = silc_idlist_find_client_by_id(server->global_list,
957 client->data.public_key = public_key;
958 } else if (id_type == SILC_ID_SERVER) {
959 server_id = silc_id_payload_get_id(idp);
961 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
964 server_entry = silc_idlist_find_server_by_id(server->global_list,
970 server_entry->data.public_key = public_key;
976 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
977 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
979 silc_id_payload_free(idp);
980 silc_free(client_id);
981 silc_free(server_id);
983 silc_pkcs_public_key_free(public_key);
984 silc_server_command_reply_free(cmd);