5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2014 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Types and definitions ***************************/
27 /* Calls error command reply callback back to command sender. */
28 #define ERROR_CALLBACK(err) \
30 void *arg1 = NULL, *arg2 = NULL; \
31 if (cmd->status != SILC_STATUS_OK) \
32 silc_status_get_args(cmd->status, args, &arg1, &arg2); \
34 cmd->status = cmd->error = err; \
35 SILC_LOG_DEBUG(("Error in command reply: %s", \
36 silc_get_status_message(cmd->status))); \
37 silc_client_command_callback(cmd, arg1, arg2); \
41 #define CHECK_STATUS(msg) \
42 SILC_LOG_DEBUG(("%s", silc_get_command_name(cmd->cmd))); \
43 if (cmd->error != SILC_STATUS_OK) { \
45 SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, \
46 msg "%s", silc_get_status_message(cmd->error)); \
47 ERROR_CALLBACK(cmd->error); \
48 silc_client_command_process_error(cmd, state_context, cmd->error); \
49 silc_fsm_next(fsm, silc_client_command_reply_processed); \
50 return SILC_FSM_CONTINUE; \
53 /* Check for correct arguments */
54 #define CHECK_ARGS(min, max) \
55 if (silc_argument_get_arg_num(args) < min || \
56 silc_argument_get_arg_num(args) > max) { \
57 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
58 silc_fsm_next(fsm, silc_client_command_reply_processed); \
59 return SILC_FSM_CONTINUE; \
62 #define SAY cmd->conn->client->internal->ops->say
64 /************************ Static utility functions **************************/
66 /* Delivers the command reply back to application */
69 silc_client_command_callback(SilcClientCommandContext cmd, ...)
71 SilcClientCommandReplyCallback cb;
77 /* Default reply callback */
80 cmd->conn->client->internal->ops->command_reply(
81 cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
87 list = cmd->reply_callbacks;
88 silc_list_start(list);
89 while ((cb = silc_list_get(list)))
90 if (!cb->do_not_call) {
92 cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
93 cmd->status, cmd->error, cb->context, cp);
100 /* Handles common error status types. */
102 static void silc_client_command_process_error(SilcClientCommandContext cmd,
103 SilcCommandPayload payload,
106 SilcClient client = cmd->conn->client;
107 SilcClientConnection conn = cmd->conn;
108 SilcArgumentPayload args = silc_command_get_args(payload);
111 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
112 SilcClientEntry client_entry;
114 /* Remove unknown client entry from cache */
115 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
118 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
120 silc_client_remove_from_channels(client, conn, client_entry);
121 client_entry->internal.valid = FALSE;
122 silc_client_del_client(client, conn, client_entry);
123 silc_client_unref_client(client, conn, client_entry);
128 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
129 SilcChannelEntry channel;
131 /* Remove unknown channel entry from cache */
132 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
135 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
137 silc_client_empty_channel(client, conn, channel);
138 silc_client_del_channel(client, conn, channel);
139 silc_client_unref_channel(client, conn, channel);
144 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
145 SilcServerEntry server_entry;
147 /* Remove unknown server entry from cache */
148 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
151 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
153 silc_client_del_server(client, conn, server_entry);
154 silc_client_unref_server(client, conn, server_entry);
160 /***************************** Command Reply ********************************/
162 /* Process received command reply packet */
164 SILC_FSM_STATE(silc_client_command_reply)
166 SilcClientConnection conn = fsm_context;
167 SilcPacket packet = state_context;
168 SilcClientCommandContext cmd;
169 SilcCommandPayload payload;
171 SilcUInt16 cmd_ident;
173 /* Get command reply payload from packet */
174 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
175 silc_packet_free(packet);
177 SILC_LOG_DEBUG(("Bad command reply packet"));
178 return SILC_FSM_FINISH;
181 cmd_ident = silc_command_get_ident(payload);
182 command = silc_command_get(payload);
184 /* Find the command pending reply */
185 silc_mutex_lock(conn->internal->lock);
186 silc_list_start(conn->internal->pending_commands);
187 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
188 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
189 && cmd->cmd_ident == cmd_ident) {
190 silc_list_del(conn->internal->pending_commands, cmd);
194 silc_mutex_unlock(conn->internal->lock);
197 SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
198 silc_get_command_name(command), cmd_ident));
199 silc_command_payload_free(payload);
200 return SILC_FSM_FINISH;
203 /* Signal command thread that command reply has arrived. We continue
204 command reply processing synchronously because we save the command
205 payload into state context. No other reply may arrive to this command
206 while we're processing this reply. */
207 silc_fsm_set_state_context(&cmd->thread, payload);
208 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
209 silc_fsm_continue_sync(&cmd->thread);
211 return SILC_FSM_FINISH;
214 /* Wait here for command reply to arrive from remote host */
216 SILC_FSM_STATE(silc_client_command_reply_wait)
218 SilcClientCommandContext cmd = fsm_context;
220 SILC_LOG_DEBUG(("Wait for command reply"));
222 /** Wait for command reply */
223 silc_fsm_set_state_context(fsm, NULL);
224 silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
225 cmd->cmd != SILC_COMMAND_PING ? 40 : 60, 0);
226 return SILC_FSM_WAIT;
229 /* Timeout occurred while waiting command reply */
231 SILC_FSM_STATE(silc_client_command_reply_timeout)
233 SilcClientCommandContext cmd = fsm_context;
234 SilcClientConnection conn = cmd->conn;
235 SilcArgumentPayload args = NULL;
237 if (conn->internal->disconnected) {
238 SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
239 silc_list_del(conn->internal->pending_commands, cmd);
241 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
242 return SILC_FSM_FINISH;
245 SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
247 /* Timeout, reply not received in timely fashion */
248 silc_list_del(conn->internal->pending_commands, cmd);
249 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
250 return SILC_FSM_FINISH;
253 /* Process received command reply payload */
255 SILC_FSM_STATE(silc_client_command_reply_process)
257 SilcClientCommandContext cmd = fsm_context;
258 SilcCommandPayload payload = state_context;
260 silc_command_get_status(payload, &cmd->status, &cmd->error);
263 case SILC_COMMAND_WHOIS:
265 silc_fsm_next(fsm, silc_client_command_reply_whois);
267 case SILC_COMMAND_WHOWAS:
269 silc_fsm_next(fsm, silc_client_command_reply_whowas);
271 case SILC_COMMAND_IDENTIFY:
273 silc_fsm_next(fsm, silc_client_command_reply_identify);
275 case SILC_COMMAND_NICK:
277 silc_fsm_next(fsm, silc_client_command_reply_nick);
279 case SILC_COMMAND_LIST:
281 silc_fsm_next(fsm, silc_client_command_reply_list);
283 case SILC_COMMAND_TOPIC:
285 silc_fsm_next(fsm, silc_client_command_reply_topic);
287 case SILC_COMMAND_INVITE:
289 silc_fsm_next(fsm, silc_client_command_reply_invite);
291 case SILC_COMMAND_QUIT:
293 silc_fsm_next(fsm, silc_client_command_reply_quit);
295 case SILC_COMMAND_KILL:
297 silc_fsm_next(fsm, silc_client_command_reply_kill);
299 case SILC_COMMAND_INFO:
301 silc_fsm_next(fsm, silc_client_command_reply_info);
303 case SILC_COMMAND_STATS:
305 silc_fsm_next(fsm, silc_client_command_reply_stats);
307 case SILC_COMMAND_PING:
309 silc_fsm_next(fsm, silc_client_command_reply_ping);
311 case SILC_COMMAND_OPER:
313 silc_fsm_next(fsm, silc_client_command_reply_oper);
315 case SILC_COMMAND_JOIN:
317 silc_fsm_next(fsm, silc_client_command_reply_join);
319 case SILC_COMMAND_MOTD:
321 silc_fsm_next(fsm, silc_client_command_reply_motd);
323 case SILC_COMMAND_UMODE:
325 silc_fsm_next(fsm, silc_client_command_reply_umode);
327 case SILC_COMMAND_CMODE:
329 silc_fsm_next(fsm, silc_client_command_reply_cmode);
331 case SILC_COMMAND_CUMODE:
333 silc_fsm_next(fsm, silc_client_command_reply_cumode);
335 case SILC_COMMAND_KICK:
337 silc_fsm_next(fsm, silc_client_command_reply_kick);
339 case SILC_COMMAND_BAN:
341 silc_fsm_next(fsm, silc_client_command_reply_ban);
343 case SILC_COMMAND_DETACH:
345 silc_fsm_next(fsm, silc_client_command_reply_detach);
347 case SILC_COMMAND_WATCH:
349 silc_fsm_next(fsm, silc_client_command_reply_watch);
351 case SILC_COMMAND_SILCOPER:
353 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
355 case SILC_COMMAND_LEAVE:
357 silc_fsm_next(fsm, silc_client_command_reply_leave);
359 case SILC_COMMAND_USERS:
361 silc_fsm_next(fsm, silc_client_command_reply_users);
363 case SILC_COMMAND_GETKEY:
365 silc_fsm_next(fsm, silc_client_command_reply_getkey);
367 case SILC_COMMAND_SERVICE:
369 silc_fsm_next(fsm, silc_client_command_reply_service);
372 return SILC_FSM_FINISH;
375 return SILC_FSM_CONTINUE;
378 /* Completes command reply processing */
380 SILC_FSM_STATE(silc_client_command_reply_processed)
382 SilcClientCommandContext cmd = fsm_context;
383 SilcClientConnection conn = cmd->conn;
384 SilcCommandPayload payload = state_context;
386 silc_command_payload_free(payload);
388 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
389 SILC_STATUS_IS_ERROR(cmd->status))
390 return SILC_FSM_FINISH;
392 /* Add back to pending command reply list */
393 silc_mutex_lock(conn->internal->lock);
394 cmd->resolved = FALSE;
395 silc_list_add(conn->internal->pending_commands, cmd);
396 silc_mutex_unlock(conn->internal->lock);
398 /** Wait more command payloads */
399 silc_fsm_next(fsm, silc_client_command_reply_wait);
400 return SILC_FSM_CONTINUE;
403 /******************************** WHOIS *************************************/
405 /* Received reply for WHOIS command. */
407 SILC_FSM_STATE(silc_client_command_reply_whois)
409 SilcClientCommandContext cmd = fsm_context;
410 SilcClientConnection conn = cmd->conn;
411 SilcClient client = conn->client;
412 SilcCommandPayload payload = state_context;
413 SilcArgumentPayload args = silc_command_get_args(payload);
414 SilcClientEntry client_entry = NULL;
415 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
416 SilcBufferStruct channels, ch_user_modes;
417 SilcBool has_channels = FALSE;
418 SilcDList channel_list = NULL;
420 char *nickname = NULL, *username = NULL, *realname = NULL;
421 unsigned char *fingerprint, *tmp;
423 CHECK_STATUS("WHOIS: ");
427 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
428 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
433 nickname = silc_argument_get_arg_type(args, 3, NULL);
434 username = silc_argument_get_arg_type(args, 4, NULL);
435 realname = silc_argument_get_arg_type(args, 5, NULL);
436 if (!nickname || !username || !realname) {
437 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
441 /* Get joined channel list */
442 memset(&channels, 0, sizeof(channels));
443 tmp = silc_argument_get_arg_type(args, 6, &len);
446 silc_buffer_set(&channels, tmp, len);
448 /* Get channel user mode list */
449 tmp = silc_argument_get_arg_type(args, 10, &len);
451 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
454 silc_buffer_set(&ch_user_modes, tmp, len);
458 tmp = silc_argument_get_arg_type(args, 7, &len);
460 SILC_GET32_MSB(mode, tmp);
463 tmp = silc_argument_get_arg_type(args, 8, &len);
465 SILC_GET32_MSB(idle, tmp);
467 /* Get fingerprint */
468 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
470 /* Check if we have this client cached already. */
471 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
473 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
475 silc_client_add_client(client, conn, nickname, username, realname,
476 &id.u.client_id, mode);
478 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
481 silc_client_ref_client(client, conn, client_entry);
483 silc_client_update_client(client, conn, client_entry,
484 nickname, username, realname, mode);
487 silc_rwlock_wrlock(client_entry->internal.lock);
489 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
490 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
492 /* Get user attributes */
493 tmp = silc_argument_get_arg_type(args, 11, &len);
495 if (client_entry->attrs)
496 silc_attribute_payload_list_free(client_entry->attrs);
497 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
500 silc_rwlock_unlock(client_entry->internal.lock);
502 /* Parse channel and channel user mode list */
504 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
505 silc_buffer_len(&channels));
507 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
511 /* Notify application */
512 silc_client_command_callback(cmd, client_entry, nickname, username,
513 realname, channel_list, mode, idle, fingerprint,
514 umodes, client_entry->attrs);
516 silc_client_unref_client(client, conn, client_entry);
518 silc_channel_payload_list_free(channel_list);
523 silc_fsm_next(fsm, silc_client_command_reply_processed);
524 return SILC_FSM_CONTINUE;
527 /******************************** WHOWAS ************************************/
529 /* Received reply for WHOWAS command. */
531 SILC_FSM_STATE(silc_client_command_reply_whowas)
533 SilcClientCommandContext cmd = fsm_context;
534 SilcClientConnection conn = cmd->conn;
535 SilcClient client = conn->client;
536 SilcCommandPayload payload = state_context;
537 SilcArgumentPayload args = silc_command_get_args(payload);
538 SilcClientEntry client_entry = NULL;
540 char *nickname, *username;
541 char *realname = NULL;
543 CHECK_STATUS("WHOWAS: ");
547 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
548 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
552 /* Get the client entry */
553 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
556 nickname = silc_argument_get_arg_type(args, 3, NULL);
557 username = silc_argument_get_arg_type(args, 4, NULL);
558 realname = silc_argument_get_arg_type(args, 5, NULL);
559 if (!nickname || !username) {
560 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
564 /* Notify application. We don't save any history information to any
565 cache. Just pass the data to the application. */
566 silc_client_command_callback(cmd, client_entry, nickname, username,
570 silc_client_unref_client(client, conn, client_entry);
571 silc_fsm_next(fsm, silc_client_command_reply_processed);
572 return SILC_FSM_CONTINUE;
575 /******************************** IDENTIFY **********************************/
577 /* Received reply for IDENTIFY command. */
579 SILC_FSM_STATE(silc_client_command_reply_identify)
581 SilcClientCommandContext cmd = fsm_context;
582 SilcClientConnection conn = cmd->conn;
583 SilcClient client = conn->client;
584 SilcCommandPayload payload = state_context;
585 SilcArgumentPayload args = silc_command_get_args(payload);
586 SilcClientEntry client_entry;
587 SilcServerEntry server_entry;
588 SilcChannelEntry channel_entry;
591 char *name = NULL, *info = NULL;
593 CHECK_STATUS("IDENTIFY: ");
597 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
598 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
603 name = silc_argument_get_arg_type(args, 3, &len);
604 info = silc_argument_get_arg_type(args, 4, &len);
608 SILC_LOG_DEBUG(("Received client information"));
610 /* Check if we have this client cached already. */
611 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
613 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
615 silc_client_add_client(client, conn, name, info, NULL,
618 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
621 silc_client_ref_client(client, conn, client_entry);
623 silc_client_update_client(client, conn, client_entry,
624 name, info, NULL, 0);
627 /* Notify application */
628 silc_client_command_callback(cmd, client_entry, name, info);
629 silc_client_unref_client(client, conn, client_entry);
633 SILC_LOG_DEBUG(("Received server information"));
635 /* Check if we have this server cached already. */
636 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
638 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
639 server_entry = silc_client_add_server(client, conn, name, info,
642 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
645 silc_client_ref_server(client, conn, server_entry);
647 silc_client_update_server(client, conn, server_entry, name, info);
649 server_entry->internal.resolve_cmd_ident = 0;
651 /* Notify application */
652 silc_client_command_callback(cmd, server_entry, name, info);
653 silc_client_unref_server(client, conn, server_entry);
656 case SILC_ID_CHANNEL:
657 SILC_LOG_DEBUG(("Received channel information"));
659 /* Check if we have this channel cached already. */
660 channel_entry = silc_client_get_channel_by_id(client, conn,
662 if (!channel_entry) {
663 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
666 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
670 /* Add new channel entry */
671 channel_entry = silc_client_add_channel(client, conn, name, 0,
673 if (!channel_entry) {
674 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
677 silc_client_ref_channel(client, conn, channel_entry);
680 /* Notify application */
681 silc_client_command_callback(cmd, channel_entry,
682 channel_entry->channel_name, info);
683 silc_client_unref_channel(client, conn, channel_entry);
688 silc_fsm_next(fsm, silc_client_command_reply_processed);
689 return SILC_FSM_CONTINUE;
692 /********************************** NICK ************************************/
694 /* Received reply for command NICK. */
696 SILC_FSM_STATE(silc_client_command_reply_nick)
698 SilcClientCommandContext cmd = fsm_context;
699 SilcClientConnection conn = cmd->conn;
700 SilcClient client = conn->client;
701 SilcCommandPayload payload = state_context;
702 SilcArgumentPayload args = silc_command_get_args(payload);
703 unsigned char *nick, *idp;
704 SilcUInt32 len, idp_len;
705 SilcClientID old_client_id;
709 CHECK_STATUS("Cannot set nickname: ");
712 /* Take received Client ID */
713 idp = silc_argument_get_arg_type(args, 2, &idp_len);
715 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
718 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
719 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
723 /* Take the new nickname */
724 nick = silc_argument_get_arg_type(args, 3, &len);
726 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
730 silc_rwlock_wrlock(conn->local_entry->internal.lock);
732 /* Change the nickname */
733 old_client_id = *conn->local_id;
734 if (!silc_client_change_nickname(client, conn, conn->local_entry,
735 nick, &id.u.client_id, idp, idp_len)) {
736 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
737 silc_rwlock_unlock(conn->local_entry->internal.lock);
741 /* All auto-generated private message keys must be rekeyed because
742 we changed nick and others may not know about it. */
743 conn->internal->ake_generation++;
744 SILC_LOG_DEBUG(("AKE keys will be rekeyed, generation %u",
745 conn->internal->ake_generation));
747 silc_rwlock_unlock(conn->local_entry->internal.lock);
749 /* Notify application */
750 silc_client_command_callback(cmd, conn->local_entry,
751 conn->local_entry->nickname, &old_client_id);
754 silc_fsm_next(fsm, silc_client_command_reply_processed);
755 return SILC_FSM_CONTINUE;
758 /********************************** LIST ************************************/
760 /* Received reply to the LIST command. */
762 SILC_FSM_STATE(silc_client_command_reply_list)
764 SilcClientCommandContext cmd = fsm_context;
765 SilcClientConnection conn = cmd->conn;
766 SilcClient client = conn->client;
767 SilcCommandPayload payload = state_context;
768 SilcArgumentPayload args = silc_command_get_args(payload);
769 unsigned char *tmp, *name, *topic;
770 SilcUInt32 usercount = 0;
771 SilcChannelEntry channel_entry = NULL;
775 CHECK_STATUS("Cannot list channels: ");
777 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
778 /* There were no channels in the network. */
779 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
780 silc_fsm_next(fsm, silc_client_command_reply_processed);
781 return SILC_FSM_CONTINUE;
786 name = silc_argument_get_arg_type(args, 3, NULL);
788 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
792 topic = silc_argument_get_arg_type(args, 4, NULL);
793 tmp = silc_argument_get_arg_type(args, 5, NULL);
795 SILC_GET32_MSB(usercount, tmp);
797 /* Check whether the channel exists, and add it to cache if it doesn't. */
798 channel_entry = silc_client_get_channel_by_id(client, conn,
800 if (!channel_entry) {
801 /* Add new channel entry */
802 channel_entry = silc_client_add_channel(client, conn, name, 0,
804 if (!channel_entry) {
805 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
808 silc_client_ref_channel(client, conn, channel_entry);
811 /* Notify application */
812 silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name,
816 silc_client_unref_channel(client, conn, channel_entry);
817 silc_fsm_next(fsm, silc_client_command_reply_processed);
818 return SILC_FSM_CONTINUE;
821 /********************************* TOPIC ************************************/
823 /* Received reply to topic command. */
825 SILC_FSM_STATE(silc_client_command_reply_topic)
827 SilcClientCommandContext cmd = fsm_context;
828 SilcClientConnection conn = cmd->conn;
829 SilcClient client = conn->client;
830 SilcCommandPayload payload = state_context;
831 SilcArgumentPayload args = silc_command_get_args(payload);
832 SilcChannelEntry channel = NULL;
838 CHECK_STATUS("Cannot set topic: ");
841 /* Take Channel ID */
842 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
843 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
847 /* Get the channel entry */
848 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
850 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
854 silc_rwlock_wrlock(channel->internal.lock);
857 topic = silc_argument_get_arg_type(args, 3, &len);
859 silc_free(channel->topic);
860 channel->topic = silc_memdup(topic, len);
863 silc_rwlock_unlock(channel->internal.lock);
865 /* Notify application */
866 silc_client_command_callback(cmd, channel, channel->topic);
869 silc_client_unref_channel(client, conn, channel);
870 silc_fsm_next(fsm, silc_client_command_reply_processed);
871 return SILC_FSM_CONTINUE;
874 /********************************* INVITE ***********************************/
876 /* Received reply to invite command. */
878 SILC_FSM_STATE(silc_client_command_reply_invite)
880 SilcClientCommandContext cmd = fsm_context;
881 SilcClientConnection conn = cmd->conn;
882 SilcClient client = conn->client;
883 SilcCommandPayload payload = state_context;
884 SilcArgumentPayload args = silc_command_get_args(payload);
885 SilcChannelEntry channel = NULL;
888 SilcArgumentPayload invite_args = NULL;
892 CHECK_STATUS("Cannot invite: ");
895 /* Take Channel ID */
896 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
897 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
901 /* Get the channel entry */
902 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
904 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
908 /* Get the invite list */
909 tmp = silc_argument_get_arg_type(args, 3, &len);
911 invite_args = silc_argument_list_parse(tmp, len);
913 /* Notify application */
914 silc_client_command_callback(cmd, channel, invite_args);
917 silc_argument_payload_free(invite_args);
920 silc_client_unref_channel(client, conn, channel);
921 silc_fsm_next(fsm, silc_client_command_reply_processed);
922 return SILC_FSM_CONTINUE;
925 /********************************** KILL ************************************/
927 /* Received reply to the KILL command. */
929 SILC_FSM_STATE(silc_client_command_reply_kill)
931 SilcClientCommandContext cmd = fsm_context;
932 SilcClientConnection conn = cmd->conn;
933 SilcClient client = conn->client;
934 SilcCommandPayload payload = state_context;
935 SilcArgumentPayload args = silc_command_get_args(payload);
936 SilcClientEntry client_entry;
940 CHECK_STATUS("Cannot kill: ");
943 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
944 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
948 /* Get the client entry, if exists */
949 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
951 /* Notify application */
952 silc_client_command_callback(cmd, client_entry);
954 /* Remove the client */
956 silc_client_remove_from_channels(client, conn, client_entry);
957 client_entry->internal.valid = FALSE;
958 silc_client_del_client(client, conn, client_entry);
959 silc_client_unref_client(client, conn, client_entry);
963 silc_fsm_next(fsm, silc_client_command_reply_processed);
964 return SILC_FSM_CONTINUE;
967 /********************************** INFO ************************************/
969 /* Received reply to INFO command. We receive the server ID and some
970 information about the server user requested. */
972 SILC_FSM_STATE(silc_client_command_reply_info)
974 SilcClientCommandContext cmd = fsm_context;
975 SilcClientConnection conn = cmd->conn;
976 SilcClient client = conn->client;
977 SilcCommandPayload payload = state_context;
978 SilcArgumentPayload args = silc_command_get_args(payload);
979 SilcServerEntry server;
980 char *server_name, *server_info;
984 CHECK_STATUS("Cannot get info: ");
988 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
989 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
993 /* Get server name */
994 server_name = silc_argument_get_arg_type(args, 3, NULL);
996 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1000 /* Get server info */
1001 server_info = silc_argument_get_arg_type(args, 4, NULL);
1003 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1007 /* See whether we have this server cached. If not create it. */
1008 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1010 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
1011 server = silc_client_add_server(client, conn, server_name,
1012 server_info, &id.u.server_id);
1015 silc_client_ref_server(client, conn, server);
1018 /* Notify application */
1019 silc_client_command_callback(cmd, server, server->server_name,
1020 server->server_info);
1021 silc_client_unref_server(client, conn, server);
1024 silc_fsm_next(fsm, silc_client_command_reply_processed);
1025 return SILC_FSM_CONTINUE;
1028 /********************************** STATS ***********************************/
1030 /* Received reply to STATS command. */
1032 SILC_FSM_STATE(silc_client_command_reply_stats)
1034 SilcClientCommandContext cmd = fsm_context;
1035 SilcCommandPayload payload = state_context;
1036 SilcArgumentPayload args = silc_command_get_args(payload);
1037 SilcClientStats stats;
1038 unsigned char *buf = NULL;
1039 SilcUInt32 buf_len = 0;
1044 CHECK_STATUS("Cannot get stats: ");
1048 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1049 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1053 /* Get statistics structure */
1054 memset(&stats, 0, sizeof(stats));
1055 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1057 silc_buffer_set(&b, buf, buf_len);
1058 silc_buffer_unformat(&b,
1059 SILC_STR_UI_INT(&stats.starttime),
1060 SILC_STR_UI_INT(&stats.uptime),
1061 SILC_STR_UI_INT(&stats.my_clients),
1062 SILC_STR_UI_INT(&stats.my_channels),
1063 SILC_STR_UI_INT(&stats.my_server_ops),
1064 SILC_STR_UI_INT(&stats.my_router_ops),
1065 SILC_STR_UI_INT(&stats.cell_clients),
1066 SILC_STR_UI_INT(&stats.cell_channels),
1067 SILC_STR_UI_INT(&stats.cell_servers),
1068 SILC_STR_UI_INT(&stats.clients),
1069 SILC_STR_UI_INT(&stats.channels),
1070 SILC_STR_UI_INT(&stats.servers),
1071 SILC_STR_UI_INT(&stats.routers),
1072 SILC_STR_UI_INT(&stats.server_ops),
1073 SILC_STR_UI_INT(&stats.router_ops),
1077 /* Notify application */
1078 silc_client_command_callback(cmd, &stats);
1081 silc_fsm_next(fsm, silc_client_command_reply_processed);
1082 return SILC_FSM_CONTINUE;
1085 /********************************** PING ************************************/
1087 /* Received reply to PING command. */
1089 SILC_FSM_STATE(silc_client_command_reply_ping)
1091 SilcClientCommandContext cmd = fsm_context;
1092 SilcClientConnection conn = cmd->conn;
1093 SilcClient client = conn->client;
1096 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1098 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1099 "Ping reply from %s: %d second%s", conn->remote_host,
1100 (int)diff, diff == 1 ? "" : "s");
1102 /* Notify application */
1103 silc_client_command_callback(cmd);
1105 silc_fsm_next(fsm, silc_client_command_reply_processed);
1106 return SILC_FSM_CONTINUE;
1109 /********************************** JOIN ************************************/
1111 /* Continue JOIN command reply processing after resolving unknown users */
1114 silc_client_command_reply_join_resolved(SilcClient client,
1115 SilcClientConnection conn,
1120 SilcClientCommandContext cmd = context;
1121 SilcChannelEntry channel = cmd->context;
1123 channel->internal.resolve_cmd_ident = 0;
1124 silc_client_unref_channel(client, conn, channel);
1126 SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
1130 /* Received reply for JOIN command. */
1132 SILC_FSM_STATE(silc_client_command_reply_join)
1134 SilcClientCommandContext cmd = fsm_context;
1135 SilcClientConnection conn = cmd->conn;
1136 SilcClient client = conn->client;
1137 SilcCommandPayload payload = state_context;
1138 SilcArgumentPayload args = silc_command_get_args(payload);
1139 SilcChannelEntry channel;
1140 SilcUInt32 mode = 0, len, list_count;
1141 char *topic, *tmp, *channel_name = NULL, *hmac;
1143 SilcBufferStruct client_id_list, client_mode_list, keyp;
1144 SilcHashTableList htl;
1149 CHECK_STATUS("Cannot join channel: ");
1152 /* Get channel name */
1153 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1154 if (!channel_name) {
1155 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1159 /* Get Channel ID */
1160 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1161 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1165 /* Check whether we have this channel entry already. */
1166 channel = silc_client_get_channel(client, conn, channel_name);
1168 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1169 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1171 /* Create new channel entry */
1172 channel = silc_client_add_channel(client, conn, channel_name,
1173 mode, &id.u.channel_id);
1175 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1178 silc_client_ref_channel(client, conn, channel);
1182 hmac = silc_argument_get_arg_type(args, 11, NULL);
1183 if (hmac && !silc_hmac_is_supported(hmac)) {
1185 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1186 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1187 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1188 silc_rwlock_unlock(channel->internal.lock);
1192 /* Get the list count */
1193 tmp = silc_argument_get_arg_type(args, 12, &len);
1195 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1198 SILC_GET32_MSB(list_count, tmp);
1200 /* Get Client ID list */
1201 tmp = silc_argument_get_arg_type(args, 13, &len);
1203 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1206 silc_buffer_set(&client_id_list, tmp, len);
1208 /* Resolve users we do not know about */
1209 if (!cmd->resolved) {
1210 cmd->resolved = TRUE;
1211 cmd->context = channel;
1212 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1213 silc_client_get_clients_by_list(
1214 client, conn, list_count, &client_id_list,
1215 silc_client_command_reply_join_resolved, cmd));
1219 /* Get client mode list */
1220 tmp = silc_argument_get_arg_type(args, 14, &len);
1222 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1225 silc_buffer_set(&client_mode_list, tmp, len);
1227 silc_rwlock_wrlock(channel->internal.lock);
1229 /* Add clients we received in the reply to the channel */
1230 for (i = 0; i < list_count; i++) {
1234 SilcClientEntry client_entry;
1237 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1239 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1243 SILC_GET32_MSB(mode, client_mode_list.data);
1245 /* Get client entry */
1246 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1247 if (client_entry && client_entry->internal.valid) {
1248 /* Join client to the channel */
1249 silc_rwlock_wrlock(client_entry->internal.lock);
1250 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1251 silc_rwlock_unlock(client_entry->internal.lock);
1253 silc_client_unref_client(client, conn, client_entry);
1255 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1256 silc_rwlock_unlock(channel->internal.lock);
1259 if (!silc_buffer_pull(&client_mode_list, 4)) {
1260 silc_rwlock_unlock(channel->internal.lock);
1265 /* Get channel mode */
1266 tmp = silc_argument_get_arg_type(args, 5, &len);
1267 if (tmp && len == 4)
1268 SILC_GET32_MSB(mode, tmp);
1269 channel->mode = mode;
1271 /* Get channel key and save it */
1272 tmp = silc_argument_get_arg_type(args, 7, &len);
1274 /* If channel key already exists on the channel then while resolving
1275 the user list we have already received new key from server. Don't
1276 replace it with this old key. */
1277 if (!channel->internal.send_key) {
1278 silc_buffer_set(&keyp, tmp, len);
1279 silc_client_save_channel_key(client, conn, &keyp, channel);
1284 topic = silc_argument_get_arg_type(args, 10, NULL);
1286 silc_free(channel->topic);
1287 channel->topic = silc_memdup(topic, strlen(topic));
1290 /* Get founder key */
1291 tmp = silc_argument_get_arg_type(args, 15, &len);
1293 if (channel->founder_key)
1294 silc_pkcs_public_key_free(channel->founder_key);
1295 channel->founder_key = NULL;
1296 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1299 /* Get user limit */
1300 tmp = silc_argument_get_arg_type(args, 17, &len);
1301 if (tmp && len == 4)
1302 SILC_GET32_MSB(channel->user_limit, tmp);
1303 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1304 channel->user_limit = 0;
1306 /* Get channel public key list */
1307 tmp = silc_argument_get_arg_type(args, 16, &len);
1309 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1311 /* Set current channel */
1312 conn->current_channel = channel;
1314 silc_rwlock_unlock(channel->internal.lock);
1316 cipher = (channel->internal.send_key ?
1317 silc_cipher_get_name(channel->internal.send_key) : NULL);
1318 silc_hash_table_list(channel->user_list, &htl);
1320 /* Notify application */
1321 silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
1322 topic, cipher, hmac, channel->founder_key,
1323 channel->channel_pubkeys, channel->user_limit);
1325 silc_hash_table_list_reset(&htl);
1326 silc_client_unref_channel(client, conn, channel);
1329 silc_fsm_next(fsm, silc_client_command_reply_processed);
1330 return SILC_FSM_CONTINUE;
1333 /********************************** MOTD ************************************/
1335 /* Received reply for MOTD command */
1337 SILC_FSM_STATE(silc_client_command_reply_motd)
1339 SilcClientCommandContext cmd = fsm_context;
1340 SilcClientConnection conn = cmd->conn;
1341 SilcClient client = conn->client;
1342 SilcCommandPayload payload = state_context;
1343 SilcArgumentPayload args = silc_command_get_args(payload);
1345 char *motd = NULL, *cp, line[256];
1348 CHECK_STATUS("Cannot get motd: ");
1351 if (silc_argument_get_arg_num(args) == 3) {
1352 motd = silc_argument_get_arg_type(args, 3, NULL);
1354 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1361 if (cp[i++] == '\n') {
1362 memset(line, 0, sizeof(line));
1363 silc_strncat(line, sizeof(line), cp, i - 1);
1370 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1379 /* Notify application */
1380 silc_client_command_callback(cmd, motd);
1383 silc_fsm_next(fsm, silc_client_command_reply_processed);
1384 return SILC_FSM_CONTINUE;
1387 /********************************** UMODE ***********************************/
1389 /* Received reply to the UMODE command. Save the current user mode */
1391 SILC_FSM_STATE(silc_client_command_reply_umode)
1393 SilcClientCommandContext cmd = fsm_context;
1394 SilcClientConnection conn = cmd->conn;
1395 SilcCommandPayload payload = state_context;
1396 SilcArgumentPayload args = silc_command_get_args(payload);
1398 SilcUInt32 mode, len;
1401 CHECK_STATUS("Cannot change mode: ");
1404 tmp = silc_argument_get_arg_type(args, 2, &len);
1405 if (!tmp || len != 4) {
1406 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1410 SILC_GET32_MSB(mode, tmp);
1411 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1412 conn->local_entry->mode = mode;
1413 silc_rwlock_unlock(conn->local_entry->internal.lock);
1415 /* Notify application */
1416 silc_client_command_callback(cmd, mode);
1419 silc_fsm_next(fsm, silc_client_command_reply_processed);
1420 return SILC_FSM_CONTINUE;
1423 /********************************** CMODE ***********************************/
1425 /* Received reply for CMODE command. */
1427 SILC_FSM_STATE(silc_client_command_reply_cmode)
1429 SilcClientCommandContext cmd = fsm_context;
1430 SilcClientConnection conn = cmd->conn;
1431 SilcClient client = conn->client;
1432 SilcCommandPayload payload = state_context;
1433 SilcArgumentPayload args = silc_command_get_args(payload);
1436 SilcChannelEntry channel = NULL;
1438 SilcPublicKey public_key = NULL;
1442 CHECK_STATUS("Cannot change mode: ");
1445 /* Take Channel ID */
1446 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1447 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1451 /* Get the channel entry */
1452 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1454 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1458 /* Get founder public key */
1459 tmp = silc_argument_get_arg_type(args, 4, &len);
1461 silc_public_key_payload_decode(tmp, len, &public_key);
1463 /* Get channel mode */
1464 tmp = silc_argument_get_arg_type(args, 3, &len);
1465 if (!tmp || len != 4) {
1466 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1469 SILC_GET32_MSB(mode, tmp);
1471 silc_rwlock_wrlock(channel->internal.lock);
1473 /* Get user limit */
1474 tmp = silc_argument_get_arg_type(args, 6, &len);
1475 if (tmp && len == 4)
1476 SILC_GET32_MSB(channel->user_limit, tmp);
1477 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1478 channel->user_limit = 0;
1480 /* Get channel public key(s) */
1481 tmp = silc_argument_get_arg_type(args, 5, &len);
1483 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1484 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
1485 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
1488 channel->mode = mode;
1490 silc_rwlock_unlock(channel->internal.lock);
1492 /* Notify application */
1493 silc_client_command_callback(cmd, channel, mode, public_key,
1494 channel->channel_pubkeys, channel->user_limit);
1497 silc_client_unref_channel(client, conn, channel);
1499 silc_pkcs_public_key_free(public_key);
1500 silc_fsm_next(fsm, silc_client_command_reply_processed);
1501 return SILC_FSM_CONTINUE;
1504 /********************************** CUMODE **********************************/
1506 /* Received reply for CUMODE command */
1508 SILC_FSM_STATE(silc_client_command_reply_cumode)
1510 SilcClientCommandContext cmd = fsm_context;
1511 SilcClientConnection conn = cmd->conn;
1512 SilcClient client = conn->client;
1513 SilcCommandPayload payload = state_context;
1514 SilcArgumentPayload args = silc_command_get_args(payload);
1515 SilcClientEntry client_entry;
1516 SilcChannelEntry channel = NULL;
1517 SilcChannelUser chu;
1518 unsigned char *modev;
1519 SilcUInt32 len, mode;
1523 CHECK_STATUS("Cannot change mode: ");
1526 /* Get channel mode */
1527 modev = silc_argument_get_arg_type(args, 2, &len);
1528 if (!modev || len != 4) {
1529 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1532 SILC_GET32_MSB(mode, modev);
1534 /* Take Channel ID */
1535 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1536 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1540 /* Get the channel entry */
1541 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1543 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1548 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1549 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1553 /* Get client entry */
1554 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1555 if (!client_entry) {
1556 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1561 silc_rwlock_wrlock(channel->internal.lock);
1562 chu = silc_client_on_channel(channel, client_entry);
1565 silc_rwlock_unlock(channel->internal.lock);
1567 /* Notify application */
1568 silc_client_command_callback(cmd, mode, channel, client_entry);
1570 silc_client_unref_client(client, conn, client_entry);
1573 silc_client_unref_channel(client, conn, channel);
1574 silc_fsm_next(fsm, silc_client_command_reply_processed);
1575 return SILC_FSM_CONTINUE;
1578 /********************************** KICK ************************************/
1580 SILC_FSM_STATE(silc_client_command_reply_kick)
1582 SilcClientCommandContext cmd = fsm_context;
1583 SilcClientConnection conn = cmd->conn;
1584 SilcClient client = conn->client;
1585 SilcCommandPayload payload = state_context;
1586 SilcArgumentPayload args = silc_command_get_args(payload);
1587 SilcClientEntry client_entry;
1588 SilcChannelEntry channel = NULL;
1592 CHECK_STATUS("Cannot kick: ");
1595 /* Take Channel ID */
1596 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1597 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1601 /* Get the channel entry */
1602 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1604 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1609 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1610 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1614 /* Get client entry */
1615 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1616 if (!client_entry) {
1617 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1621 /* Notify application */
1622 silc_client_command_callback(cmd, channel, client_entry);
1624 silc_client_unref_client(client, conn, client_entry);
1627 silc_client_unref_channel(client, conn, channel);
1628 silc_fsm_next(fsm, silc_client_command_reply_processed);
1629 return SILC_FSM_CONTINUE;
1632 /******************************** SILCOPER **********************************/
1634 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1636 SilcClientCommandContext cmd = fsm_context;
1637 SilcCommandPayload payload = state_context;
1638 SilcArgumentPayload args = silc_command_get_args(payload);
1641 CHECK_STATUS("Cannot change mode: ");
1645 cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1647 /* Notify application */
1648 silc_client_command_callback(cmd);
1650 silc_fsm_next(fsm, silc_client_command_reply_processed);
1651 return SILC_FSM_CONTINUE;
1654 /********************************** OPER ************************************/
1656 SILC_FSM_STATE(silc_client_command_reply_oper)
1658 SilcClientCommandContext cmd = fsm_context;
1659 SilcCommandPayload payload = state_context;
1660 SilcArgumentPayload args = silc_command_get_args(payload);
1663 CHECK_STATUS("Cannot change mode: ");
1667 cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1669 /* Notify application */
1670 silc_client_command_callback(cmd);
1672 silc_fsm_next(fsm, silc_client_command_reply_processed);
1673 return SILC_FSM_CONTINUE;
1676 /********************************* DETACH ***********************************/
1678 SILC_FSM_STATE(silc_client_command_reply_detach)
1680 SilcClientCommandContext cmd = fsm_context;
1681 SilcClientConnection conn = cmd->conn;
1682 SilcClient client = conn->client;
1683 SilcCommandPayload payload = state_context;
1684 SilcArgumentPayload args = silc_command_get_args(payload);
1688 CHECK_STATUS("Cannot detach: ");
1691 /* Get detachment data */
1692 detach = silc_client_get_detach_data(client, conn);
1694 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1698 /* Notify application */
1699 silc_client_command_callback(cmd, detach);
1700 silc_buffer_free(detach);
1703 silc_fsm_next(fsm, silc_client_command_reply_processed);
1704 return SILC_FSM_CONTINUE;
1707 /********************************** WATCH ***********************************/
1709 SILC_FSM_STATE(silc_client_command_reply_watch)
1711 SilcClientCommandContext cmd = fsm_context;
1712 SilcCommandPayload payload = state_context;
1713 SilcArgumentPayload args = silc_command_get_args(payload);
1716 CHECK_STATUS("Cannot set watch: ");
1719 /* Notify application */
1720 silc_client_command_callback(cmd);
1722 silc_fsm_next(fsm, silc_client_command_reply_processed);
1723 return SILC_FSM_CONTINUE;
1726 /*********************************** BAN ************************************/
1728 SILC_FSM_STATE(silc_client_command_reply_ban)
1730 SilcClientCommandContext cmd = fsm_context;
1731 SilcClientConnection conn = cmd->conn;
1732 SilcClient client = conn->client;
1733 SilcCommandPayload payload = state_context;
1734 SilcArgumentPayload args = silc_command_get_args(payload);
1735 SilcChannelEntry channel = NULL;
1738 SilcArgumentPayload invite_args = NULL;
1742 CHECK_STATUS("Cannot set ban: ");
1745 /* Take Channel ID */
1746 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1747 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1751 /* Get the channel entry */
1752 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1754 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1758 /* Get the invite list */
1759 tmp = silc_argument_get_arg_type(args, 3, &len);
1761 invite_args = silc_argument_list_parse(tmp, len);
1763 /* Notify application */
1764 silc_client_command_callback(cmd, channel, invite_args);
1767 silc_argument_payload_free(invite_args);
1770 silc_client_unref_channel(client, conn, channel);
1771 silc_fsm_next(fsm, silc_client_command_reply_processed);
1772 return SILC_FSM_CONTINUE;
1775 /********************************** LEAVE ***********************************/
1777 /* Reply to LEAVE command. */
1779 SILC_FSM_STATE(silc_client_command_reply_leave)
1781 SilcClientCommandContext cmd = fsm_context;
1782 SilcClientConnection conn = cmd->conn;
1783 SilcClient client = conn->client;
1784 SilcCommandPayload payload = state_context;
1785 SilcArgumentPayload args = silc_command_get_args(payload);
1786 SilcChannelEntry channel;
1792 CHECK_STATUS("Cannot set leave: ");
1795 /* Get Channel ID */
1796 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1797 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1801 /* Get the channel entry */
1802 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1804 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1808 /* Remove us from this channel. */
1809 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1811 /* Notify application */
1812 silc_client_command_callback(cmd, channel);
1814 /* Remove old keys and stuff. The channel may remain even after leaving
1815 but we want to remove these always. */
1816 if (channel->internal.send_key)
1817 silc_cipher_free(channel->internal.send_key);
1818 channel->internal.send_key = NULL;
1819 if (channel->internal.receive_key)
1820 silc_cipher_free(channel->internal.receive_key);
1821 channel->internal.receive_key = NULL;
1822 if (channel->internal.hmac)
1823 silc_hmac_free(channel->internal.hmac);
1824 channel->internal.hmac = NULL;
1825 if (channel->internal.old_channel_keys) {
1826 silc_dlist_start(channel->internal.old_channel_keys);
1827 while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
1828 silc_cipher_free(key);
1829 silc_dlist_uninit(channel->internal.old_channel_keys);
1831 channel->internal.old_channel_keys = NULL;
1832 if (channel->internal.old_hmacs) {
1833 silc_dlist_start(channel->internal.old_hmacs);
1834 while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
1835 silc_hmac_free(hmac);
1836 silc_dlist_uninit(channel->internal.old_hmacs);
1838 channel->internal.old_hmacs = NULL;
1840 /* Now delete the channel. */
1841 silc_client_empty_channel(client, conn, channel);
1842 silc_client_del_channel(client, conn, channel);
1845 silc_fsm_next(fsm, silc_client_command_reply_processed);
1846 return SILC_FSM_CONTINUE;
1849 /********************************* USERS ************************************/
1851 /* Continue USERS command reply processing after resolving unknown users */
1854 silc_client_command_reply_users_resolved(SilcClient client,
1855 SilcClientConnection conn,
1860 SilcClientCommandContext cmd = context;
1861 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1865 /* Continue USERS command after resolving unknown channel */
1868 silc_client_command_reply_users_continue(SilcClient client,
1869 SilcClientConnection conn,
1874 SilcClientCommandContext cmd = context;
1877 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1878 SilcArgumentPayload args = silc_command_get_args(payload);
1880 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1881 ERROR_CALLBACK(cmd->status);
1882 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1885 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1888 /* Reply to USERS command. Received list of client ID's and theirs modes
1889 on the channel we requested. */
1891 SILC_FSM_STATE(silc_client_command_reply_users)
1893 SilcClientCommandContext cmd = fsm_context;
1894 SilcClientConnection conn = cmd->conn;
1895 SilcClient client = conn->client;
1896 SilcCommandPayload payload = state_context;
1897 SilcArgumentPayload args = silc_command_get_args(payload);
1899 SilcUInt32 tmp_len, list_count, mode;
1901 SilcHashTableList htl;
1902 SilcBufferStruct client_id_list, client_mode_list;
1903 SilcChannelEntry channel = NULL;
1904 SilcClientEntry client_entry;
1909 CHECK_STATUS("Cannot get users: ");
1912 /* Get channel ID */
1913 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1914 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1918 /* Get channel entry */
1919 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1921 /* Resolve the channel from server */
1922 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1923 client, conn, &id.u.channel_id,
1924 silc_client_command_reply_users_continue, cmd));
1928 /* Get the list count */
1929 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1930 if (!tmp || tmp_len != 4) {
1931 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1934 SILC_GET32_MSB(list_count, tmp);
1936 /* Get Client ID list */
1937 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1939 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1942 silc_buffer_set(&client_id_list, tmp, tmp_len);
1944 /* Resolve users we do not know about */
1945 if (!cmd->resolved) {
1946 cmd->resolved = TRUE;
1947 silc_client_unref_channel(client, conn, channel);
1948 SILC_FSM_CALL(silc_client_get_clients_by_list(
1949 client, conn, list_count, &client_id_list,
1950 silc_client_command_reply_users_resolved, cmd));
1954 /* Get client mode list */
1955 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1957 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1960 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1962 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1964 silc_rwlock_wrlock(channel->internal.lock);
1966 /* Cache the received Client ID's and modes. */
1967 for (i = 0; i < list_count; i++) {
1968 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1970 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1974 SILC_GET32_MSB(mode, client_mode_list.data);
1976 /* Save the client on this channel. Unknown clients are ignored as they
1977 clearly do not exist since the resolving didn't find them. */
1978 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1979 if (client_entry && client_entry->internal.valid) {
1980 silc_rwlock_wrlock(client_entry->internal.lock);
1981 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1982 silc_rwlock_unlock(client_entry->internal.lock);
1984 silc_client_unref_client(client, conn, client_entry);
1986 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1987 silc_rwlock_unlock(channel->internal.lock);
1990 if (!silc_buffer_pull(&client_mode_list, 4)) {
1991 silc_rwlock_unlock(channel->internal.lock);
1996 silc_rwlock_unlock(channel->internal.lock);
1998 /* Notify application */
1999 silc_hash_table_list(channel->user_list, &htl);
2000 silc_client_command_callback(cmd, channel, &htl);
2001 silc_hash_table_list_reset(&htl);
2004 silc_client_unref_channel(client, conn, channel);
2005 silc_fsm_next(fsm, silc_client_command_reply_processed);
2006 return SILC_FSM_CONTINUE;
2009 /********************************** GETKEY **********************************/
2011 /* Received command reply to GETKEY command. WE've received the remote
2012 client's public key. */
2014 SILC_FSM_STATE(silc_client_command_reply_getkey)
2016 SilcClientCommandContext cmd = fsm_context;
2017 SilcClientConnection conn = cmd->conn;
2018 SilcClient client = conn->client;
2019 SilcCommandPayload payload = state_context;
2020 SilcArgumentPayload args = silc_command_get_args(payload);
2021 SilcClientEntry client_entry;
2022 SilcServerEntry server_entry;
2025 SilcPublicKey public_key = NULL;
2029 CHECK_STATUS("Cannot get key: ");
2033 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
2034 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2038 /* Get the public key */
2039 tmp = silc_argument_get_arg_type(args, 3, &len);
2041 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2044 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
2045 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
2046 "Cannot decode public key: malformed/unsupported public key");
2047 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2051 if (id.type == SILC_ID_CLIENT) {
2052 /* Received client's public key */
2053 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2054 if (!client_entry) {
2055 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2059 silc_rwlock_wrlock(client_entry->internal.lock);
2061 /* Save fingerprint */
2062 if (!client_entry->fingerprint)
2063 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2064 client_entry->fingerprint);
2065 if (!client_entry->public_key) {
2066 client_entry->public_key = public_key;
2070 silc_rwlock_unlock(client_entry->internal.lock);
2072 /* Notify application */
2073 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2074 client_entry->public_key);
2075 silc_client_unref_client(client, conn, client_entry);
2076 } else if (id.type == SILC_ID_SERVER) {
2077 /* Received server's public key */
2078 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2079 if (!server_entry) {
2080 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2084 silc_rwlock_wrlock(server_entry->internal.lock);
2086 if (!server_entry->public_key) {
2087 server_entry->public_key = public_key;
2091 silc_rwlock_unlock(server_entry->internal.lock);
2093 /* Notify application */
2094 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2095 server_entry->public_key);
2096 silc_client_unref_server(client, conn, server_entry);
2101 silc_pkcs_public_key_free(public_key);
2102 silc_fsm_next(fsm, silc_client_command_reply_processed);
2103 return SILC_FSM_CONTINUE;
2106 /********************************** SERVICE *********************************/
2108 /* Reply to SERVICE command. */
2109 /* XXX incomplete */
2111 SILC_FSM_STATE(silc_client_command_reply_service)
2113 SilcClientCommandContext cmd = fsm_context;
2114 SilcCommandPayload payload = state_context;
2115 SilcArgumentPayload args = silc_command_get_args(payload);
2117 unsigned char *service_list, *name;
2120 CHECK_STATUS("Cannot get service: ");
2122 /* Get service list */
2123 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2125 /* Get requested service name */
2126 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2128 /* Notify application */
2129 silc_client_command_callback(cmd, service_list, name);
2131 silc_fsm_next(fsm, silc_client_command_reply_processed);
2132 return SILC_FSM_CONTINUE;
2135 /*********************************** QUIT ***********************************/
2137 /* QUIT command reply stub */
2139 SILC_FSM_STATE(silc_client_command_reply_quit)
2141 silc_fsm_next(fsm, silc_client_command_reply_processed);
2142 return SILC_FSM_CONTINUE;