5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 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 silc_rwlock_unlock(conn->local_entry->internal.lock);
743 /* Notify application */
744 silc_client_command_callback(cmd, conn->local_entry,
745 conn->local_entry->nickname, &old_client_id);
748 silc_fsm_next(fsm, silc_client_command_reply_processed);
749 return SILC_FSM_CONTINUE;
752 /********************************** LIST ************************************/
754 /* Received reply to the LIST command. */
756 SILC_FSM_STATE(silc_client_command_reply_list)
758 SilcClientCommandContext cmd = fsm_context;
759 SilcClientConnection conn = cmd->conn;
760 SilcClient client = conn->client;
761 SilcCommandPayload payload = state_context;
762 SilcArgumentPayload args = silc_command_get_args(payload);
763 unsigned char *tmp, *name, *topic;
764 SilcUInt32 usercount = 0;
765 SilcChannelEntry channel_entry = NULL;
769 CHECK_STATUS("Cannot list channels: ");
771 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
772 /* There were no channels in the network. */
773 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
774 silc_fsm_next(fsm, silc_client_command_reply_processed);
775 return SILC_FSM_CONTINUE;
780 name = silc_argument_get_arg_type(args, 3, NULL);
782 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
786 topic = silc_argument_get_arg_type(args, 4, NULL);
787 tmp = silc_argument_get_arg_type(args, 5, NULL);
789 SILC_GET32_MSB(usercount, tmp);
791 /* Check whether the channel exists, and add it to cache if it doesn't. */
792 channel_entry = silc_client_get_channel_by_id(client, conn,
794 if (!channel_entry) {
795 /* Add new channel entry */
796 channel_entry = silc_client_add_channel(client, conn, name, 0,
798 if (!channel_entry) {
799 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
802 silc_client_ref_channel(client, conn, channel_entry);
805 /* Notify application */
806 silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name,
810 silc_client_unref_channel(client, conn, channel_entry);
811 silc_fsm_next(fsm, silc_client_command_reply_processed);
812 return SILC_FSM_CONTINUE;
815 /********************************* TOPIC ************************************/
817 /* Received reply to topic command. */
819 SILC_FSM_STATE(silc_client_command_reply_topic)
821 SilcClientCommandContext cmd = fsm_context;
822 SilcClientConnection conn = cmd->conn;
823 SilcClient client = conn->client;
824 SilcCommandPayload payload = state_context;
825 SilcArgumentPayload args = silc_command_get_args(payload);
826 SilcChannelEntry channel = NULL;
832 CHECK_STATUS("Cannot set topic: ");
835 /* Take Channel ID */
836 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
837 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
841 /* Get the channel entry */
842 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
844 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
848 silc_rwlock_wrlock(channel->internal.lock);
851 topic = silc_argument_get_arg_type(args, 3, &len);
853 silc_free(channel->topic);
854 channel->topic = silc_memdup(topic, len);
857 silc_rwlock_unlock(channel->internal.lock);
859 /* Notify application */
860 silc_client_command_callback(cmd, channel, channel->topic);
863 silc_client_unref_channel(client, conn, channel);
864 silc_fsm_next(fsm, silc_client_command_reply_processed);
865 return SILC_FSM_CONTINUE;
868 /********************************* INVITE ***********************************/
870 /* Received reply to invite command. */
872 SILC_FSM_STATE(silc_client_command_reply_invite)
874 SilcClientCommandContext cmd = fsm_context;
875 SilcClientConnection conn = cmd->conn;
876 SilcClient client = conn->client;
877 SilcCommandPayload payload = state_context;
878 SilcArgumentPayload args = silc_command_get_args(payload);
879 SilcChannelEntry channel = NULL;
882 SilcArgumentPayload invite_args = NULL;
886 CHECK_STATUS("Cannot invite: ");
889 /* Take Channel ID */
890 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
891 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
895 /* Get the channel entry */
896 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
898 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
902 /* Get the invite list */
903 tmp = silc_argument_get_arg_type(args, 3, &len);
905 invite_args = silc_argument_list_parse(tmp, len);
907 /* Notify application */
908 silc_client_command_callback(cmd, channel, invite_args);
911 silc_argument_payload_free(invite_args);
914 silc_client_unref_channel(client, conn, channel);
915 silc_fsm_next(fsm, silc_client_command_reply_processed);
916 return SILC_FSM_CONTINUE;
919 /********************************** KILL ************************************/
921 /* Received reply to the KILL command. */
923 SILC_FSM_STATE(silc_client_command_reply_kill)
925 SilcClientCommandContext cmd = fsm_context;
926 SilcClientConnection conn = cmd->conn;
927 SilcClient client = conn->client;
928 SilcCommandPayload payload = state_context;
929 SilcArgumentPayload args = silc_command_get_args(payload);
930 SilcClientEntry client_entry;
934 CHECK_STATUS("Cannot kill: ");
937 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
938 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
942 /* Get the client entry, if exists */
943 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
945 /* Notify application */
946 silc_client_command_callback(cmd, client_entry);
948 /* Remove the client */
950 silc_client_remove_from_channels(client, conn, client_entry);
951 client_entry->internal.valid = FALSE;
952 silc_client_del_client(client, conn, client_entry);
953 silc_client_unref_client(client, conn, client_entry);
957 silc_fsm_next(fsm, silc_client_command_reply_processed);
958 return SILC_FSM_CONTINUE;
961 /********************************** INFO ************************************/
963 /* Received reply to INFO command. We receive the server ID and some
964 information about the server user requested. */
966 SILC_FSM_STATE(silc_client_command_reply_info)
968 SilcClientCommandContext cmd = fsm_context;
969 SilcClientConnection conn = cmd->conn;
970 SilcClient client = conn->client;
971 SilcCommandPayload payload = state_context;
972 SilcArgumentPayload args = silc_command_get_args(payload);
973 SilcServerEntry server;
974 char *server_name, *server_info;
978 CHECK_STATUS("Cannot get info: ");
982 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
983 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
987 /* Get server name */
988 server_name = silc_argument_get_arg_type(args, 3, NULL);
990 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
994 /* Get server info */
995 server_info = silc_argument_get_arg_type(args, 4, NULL);
997 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1001 /* See whether we have this server cached. If not create it. */
1002 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1004 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
1005 server = silc_client_add_server(client, conn, server_name,
1006 server_info, &id.u.server_id);
1009 silc_client_ref_server(client, conn, server);
1012 /* Notify application */
1013 silc_client_command_callback(cmd, server, server->server_name,
1014 server->server_info);
1015 silc_client_unref_server(client, conn, server);
1018 silc_fsm_next(fsm, silc_client_command_reply_processed);
1019 return SILC_FSM_CONTINUE;
1022 /********************************** STATS ***********************************/
1024 /* Received reply to STATS command. */
1026 SILC_FSM_STATE(silc_client_command_reply_stats)
1028 SilcClientCommandContext cmd = fsm_context;
1029 SilcCommandPayload payload = state_context;
1030 SilcArgumentPayload args = silc_command_get_args(payload);
1031 SilcClientStats stats;
1032 unsigned char *buf = NULL;
1033 SilcUInt32 buf_len = 0;
1038 CHECK_STATUS("Cannot get stats: ");
1042 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1043 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1047 /* Get statistics structure */
1048 memset(&stats, 0, sizeof(stats));
1049 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1051 silc_buffer_set(&b, buf, buf_len);
1052 silc_buffer_unformat(&b,
1053 SILC_STR_UI_INT(&stats.starttime),
1054 SILC_STR_UI_INT(&stats.uptime),
1055 SILC_STR_UI_INT(&stats.my_clients),
1056 SILC_STR_UI_INT(&stats.my_channels),
1057 SILC_STR_UI_INT(&stats.my_server_ops),
1058 SILC_STR_UI_INT(&stats.my_router_ops),
1059 SILC_STR_UI_INT(&stats.cell_clients),
1060 SILC_STR_UI_INT(&stats.cell_channels),
1061 SILC_STR_UI_INT(&stats.cell_servers),
1062 SILC_STR_UI_INT(&stats.clients),
1063 SILC_STR_UI_INT(&stats.channels),
1064 SILC_STR_UI_INT(&stats.servers),
1065 SILC_STR_UI_INT(&stats.routers),
1066 SILC_STR_UI_INT(&stats.server_ops),
1067 SILC_STR_UI_INT(&stats.router_ops),
1071 /* Notify application */
1072 silc_client_command_callback(cmd, &stats);
1075 silc_fsm_next(fsm, silc_client_command_reply_processed);
1076 return SILC_FSM_CONTINUE;
1079 /********************************** PING ************************************/
1081 /* Received reply to PING command. */
1083 SILC_FSM_STATE(silc_client_command_reply_ping)
1085 SilcClientCommandContext cmd = fsm_context;
1086 SilcClientConnection conn = cmd->conn;
1087 SilcClient client = conn->client;
1090 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1092 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1093 "Ping reply from %s: %d second%s", conn->remote_host,
1094 (int)diff, diff == 1 ? "" : "s");
1096 /* Notify application */
1097 silc_client_command_callback(cmd);
1099 silc_fsm_next(fsm, silc_client_command_reply_processed);
1100 return SILC_FSM_CONTINUE;
1103 /********************************** JOIN ************************************/
1105 /* Continue JOIN command reply processing after resolving unknown users */
1108 silc_client_command_reply_join_resolved(SilcClient client,
1109 SilcClientConnection conn,
1114 SilcClientCommandContext cmd = context;
1115 SilcChannelEntry channel = cmd->context;
1117 channel->internal.resolve_cmd_ident = 0;
1118 silc_client_unref_channel(client, conn, channel);
1120 SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
1124 /* Received reply for JOIN command. */
1126 SILC_FSM_STATE(silc_client_command_reply_join)
1128 SilcClientCommandContext cmd = fsm_context;
1129 SilcClientConnection conn = cmd->conn;
1130 SilcClient client = conn->client;
1131 SilcCommandPayload payload = state_context;
1132 SilcArgumentPayload args = silc_command_get_args(payload);
1133 SilcChannelEntry channel;
1134 SilcUInt32 mode = 0, len, list_count;
1135 char *topic, *tmp, *channel_name = NULL, *hmac;
1137 SilcBufferStruct client_id_list, client_mode_list, keyp;
1138 SilcHashTableList htl;
1143 CHECK_STATUS("Cannot join channel: ");
1146 /* Get channel name */
1147 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1148 if (!channel_name) {
1149 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1153 /* Get Channel ID */
1154 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1155 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1159 /* Check whether we have this channel entry already. */
1160 channel = silc_client_get_channel(client, conn, channel_name);
1162 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1163 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1165 /* Create new channel entry */
1166 channel = silc_client_add_channel(client, conn, channel_name,
1167 mode, &id.u.channel_id);
1169 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1172 silc_client_ref_channel(client, conn, channel);
1175 /* Get the list count */
1176 tmp = silc_argument_get_arg_type(args, 12, &len);
1178 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1181 SILC_GET32_MSB(list_count, tmp);
1183 /* Get Client ID list */
1184 tmp = silc_argument_get_arg_type(args, 13, &len);
1186 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1189 silc_buffer_set(&client_id_list, tmp, len);
1191 /* Resolve users we do not know about */
1192 if (!cmd->resolved) {
1193 cmd->resolved = TRUE;
1194 cmd->context = channel;
1195 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1196 silc_client_get_clients_by_list(
1197 client, conn, list_count, &client_id_list,
1198 silc_client_command_reply_join_resolved, cmd));
1202 /* Get client mode list */
1203 tmp = silc_argument_get_arg_type(args, 14, &len);
1205 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1208 silc_buffer_set(&client_mode_list, tmp, len);
1210 silc_rwlock_wrlock(channel->internal.lock);
1212 /* Add clients we received in the reply to the channel */
1213 for (i = 0; i < list_count; i++) {
1217 SilcClientEntry client_entry;
1220 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1222 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1226 SILC_GET32_MSB(mode, client_mode_list.data);
1228 /* Get client entry */
1229 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1230 if (client_entry && client_entry->internal.valid) {
1231 /* Join client to the channel */
1232 silc_rwlock_wrlock(client_entry->internal.lock);
1233 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1234 silc_rwlock_unlock(client_entry->internal.lock);
1236 silc_client_unref_client(client, conn, client_entry);
1238 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1239 silc_rwlock_unlock(channel->internal.lock);
1242 if (!silc_buffer_pull(&client_mode_list, 4)) {
1243 silc_rwlock_unlock(channel->internal.lock);
1249 hmac = silc_argument_get_arg_type(args, 11, NULL);
1251 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1253 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1254 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1255 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1256 silc_rwlock_unlock(channel->internal.lock);
1261 /* Get channel mode */
1262 tmp = silc_argument_get_arg_type(args, 5, &len);
1263 if (tmp && len == 4)
1264 SILC_GET32_MSB(mode, tmp);
1265 channel->mode = mode;
1267 /* Get channel key and save it */
1268 tmp = silc_argument_get_arg_type(args, 7, &len);
1270 /* If channel key already exists on the channel then while resolving
1271 the user list we have already received new key from server. Don't
1272 replace it with this old key. */
1273 if (!channel->internal.send_key) {
1274 silc_buffer_set(&keyp, tmp, len);
1275 silc_client_save_channel_key(client, conn, &keyp, channel);
1280 topic = silc_argument_get_arg_type(args, 10, NULL);
1282 silc_free(channel->topic);
1283 channel->topic = silc_memdup(topic, strlen(topic));
1286 /* Get founder key */
1287 tmp = silc_argument_get_arg_type(args, 15, &len);
1289 if (channel->founder_key)
1290 silc_pkcs_public_key_free(channel->founder_key);
1291 channel->founder_key = NULL;
1292 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1295 /* Get user limit */
1296 tmp = silc_argument_get_arg_type(args, 17, &len);
1297 if (tmp && len == 4)
1298 SILC_GET32_MSB(channel->user_limit, tmp);
1299 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1300 channel->user_limit = 0;
1302 /* Get channel public key list */
1303 tmp = silc_argument_get_arg_type(args, 16, &len);
1305 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1307 /* Set current channel */
1308 conn->current_channel = channel;
1310 silc_rwlock_unlock(channel->internal.lock);
1312 cipher = (channel->internal.send_key ?
1313 silc_cipher_get_name(channel->internal.send_key) : NULL);
1314 silc_hash_table_list(channel->user_list, &htl);
1316 /* Notify application */
1317 silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
1318 topic, cipher, hmac, channel->founder_key,
1319 channel->channel_pubkeys, channel->user_limit);
1321 silc_hash_table_list_reset(&htl);
1322 silc_client_unref_channel(client, conn, channel);
1325 silc_fsm_next(fsm, silc_client_command_reply_processed);
1326 return SILC_FSM_CONTINUE;
1329 /********************************** MOTD ************************************/
1331 /* Received reply for MOTD command */
1333 SILC_FSM_STATE(silc_client_command_reply_motd)
1335 SilcClientCommandContext cmd = fsm_context;
1336 SilcClientConnection conn = cmd->conn;
1337 SilcClient client = conn->client;
1338 SilcCommandPayload payload = state_context;
1339 SilcArgumentPayload args = silc_command_get_args(payload);
1341 char *motd = NULL, *cp, line[256];
1344 CHECK_STATUS("Cannot get motd: ");
1347 if (silc_argument_get_arg_num(args) == 3) {
1348 motd = silc_argument_get_arg_type(args, 3, NULL);
1350 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1357 if (cp[i++] == '\n') {
1358 memset(line, 0, sizeof(line));
1359 silc_strncat(line, sizeof(line), cp, i - 1);
1366 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1375 /* Notify application */
1376 silc_client_command_callback(cmd, motd);
1379 silc_fsm_next(fsm, silc_client_command_reply_processed);
1380 return SILC_FSM_CONTINUE;
1383 /********************************** UMODE ***********************************/
1385 /* Received reply to the UMODE command. Save the current user mode */
1387 SILC_FSM_STATE(silc_client_command_reply_umode)
1389 SilcClientCommandContext cmd = fsm_context;
1390 SilcClientConnection conn = cmd->conn;
1391 SilcCommandPayload payload = state_context;
1392 SilcArgumentPayload args = silc_command_get_args(payload);
1394 SilcUInt32 mode, len;
1397 CHECK_STATUS("Cannot change mode: ");
1400 tmp = silc_argument_get_arg_type(args, 2, &len);
1401 if (!tmp || len != 4) {
1402 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1406 SILC_GET32_MSB(mode, tmp);
1407 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1408 conn->local_entry->mode = mode;
1409 silc_rwlock_unlock(conn->local_entry->internal.lock);
1411 /* Notify application */
1412 silc_client_command_callback(cmd, mode);
1415 silc_fsm_next(fsm, silc_client_command_reply_processed);
1416 return SILC_FSM_CONTINUE;
1419 /********************************** CMODE ***********************************/
1421 /* Received reply for CMODE command. */
1423 SILC_FSM_STATE(silc_client_command_reply_cmode)
1425 SilcClientCommandContext cmd = fsm_context;
1426 SilcClientConnection conn = cmd->conn;
1427 SilcClient client = conn->client;
1428 SilcCommandPayload payload = state_context;
1429 SilcArgumentPayload args = silc_command_get_args(payload);
1432 SilcChannelEntry channel = NULL;
1434 SilcPublicKey public_key = NULL;
1438 CHECK_STATUS("Cannot change mode: ");
1441 /* Take Channel ID */
1442 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1443 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1447 /* Get the channel entry */
1448 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1450 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1454 /* Get founder public key */
1455 tmp = silc_argument_get_arg_type(args, 4, &len);
1457 silc_public_key_payload_decode(tmp, len, &public_key);
1459 /* Get channel mode */
1460 tmp = silc_argument_get_arg_type(args, 3, &len);
1461 if (!tmp || len != 4) {
1462 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1465 SILC_GET32_MSB(mode, tmp);
1467 silc_rwlock_wrlock(channel->internal.lock);
1469 /* Get user limit */
1470 tmp = silc_argument_get_arg_type(args, 6, &len);
1471 if (tmp && len == 4)
1472 SILC_GET32_MSB(channel->user_limit, tmp);
1473 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1474 channel->user_limit = 0;
1476 /* Get channel public key(s) */
1477 tmp = silc_argument_get_arg_type(args, 5, &len);
1479 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1480 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
1481 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
1484 channel->mode = mode;
1486 silc_rwlock_unlock(channel->internal.lock);
1488 /* Notify application */
1489 silc_client_command_callback(cmd, channel, mode, public_key,
1490 channel->channel_pubkeys, channel->user_limit);
1493 silc_client_unref_channel(client, conn, channel);
1495 silc_pkcs_public_key_free(public_key);
1496 silc_fsm_next(fsm, silc_client_command_reply_processed);
1497 return SILC_FSM_CONTINUE;
1500 /********************************** CUMODE **********************************/
1502 /* Received reply for CUMODE command */
1504 SILC_FSM_STATE(silc_client_command_reply_cumode)
1506 SilcClientCommandContext cmd = fsm_context;
1507 SilcClientConnection conn = cmd->conn;
1508 SilcClient client = conn->client;
1509 SilcCommandPayload payload = state_context;
1510 SilcArgumentPayload args = silc_command_get_args(payload);
1511 SilcClientEntry client_entry;
1512 SilcChannelEntry channel = NULL;
1513 SilcChannelUser chu;
1514 unsigned char *modev;
1515 SilcUInt32 len, mode;
1519 CHECK_STATUS("Cannot change mode: ");
1522 /* Get channel mode */
1523 modev = silc_argument_get_arg_type(args, 2, &len);
1524 if (!modev || len != 4) {
1525 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1528 SILC_GET32_MSB(mode, modev);
1530 /* Take Channel ID */
1531 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1532 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1536 /* Get the channel entry */
1537 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1539 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1544 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1545 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1549 /* Get client entry */
1550 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1551 if (!client_entry) {
1552 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1557 silc_rwlock_wrlock(channel->internal.lock);
1558 chu = silc_client_on_channel(channel, client_entry);
1561 silc_rwlock_unlock(channel->internal.lock);
1563 /* Notify application */
1564 silc_client_command_callback(cmd, mode, channel, client_entry);
1566 silc_client_unref_client(client, conn, client_entry);
1569 silc_client_unref_channel(client, conn, channel);
1570 silc_fsm_next(fsm, silc_client_command_reply_processed);
1571 return SILC_FSM_CONTINUE;
1574 /********************************** KICK ************************************/
1576 SILC_FSM_STATE(silc_client_command_reply_kick)
1578 SilcClientCommandContext cmd = fsm_context;
1579 SilcClientConnection conn = cmd->conn;
1580 SilcClient client = conn->client;
1581 SilcCommandPayload payload = state_context;
1582 SilcArgumentPayload args = silc_command_get_args(payload);
1583 SilcClientEntry client_entry;
1584 SilcChannelEntry channel = NULL;
1588 CHECK_STATUS("Cannot kick: ");
1591 /* Take Channel ID */
1592 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1593 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1597 /* Get the channel entry */
1598 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1600 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1605 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1606 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1610 /* Get client entry */
1611 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1612 if (!client_entry) {
1613 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1617 /* Notify application */
1618 silc_client_command_callback(cmd, channel, client_entry);
1620 silc_client_unref_client(client, conn, client_entry);
1623 silc_client_unref_channel(client, conn, channel);
1624 silc_fsm_next(fsm, silc_client_command_reply_processed);
1625 return SILC_FSM_CONTINUE;
1628 /******************************** SILCOPER **********************************/
1630 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1632 SilcClientCommandContext cmd = fsm_context;
1633 SilcCommandPayload payload = state_context;
1634 SilcArgumentPayload args = silc_command_get_args(payload);
1637 CHECK_STATUS("Cannot change mode: ");
1641 cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1643 /* Notify application */
1644 silc_client_command_callback(cmd);
1646 silc_fsm_next(fsm, silc_client_command_reply_processed);
1647 return SILC_FSM_CONTINUE;
1650 /********************************** OPER ************************************/
1652 SILC_FSM_STATE(silc_client_command_reply_oper)
1654 SilcClientCommandContext cmd = fsm_context;
1655 SilcCommandPayload payload = state_context;
1656 SilcArgumentPayload args = silc_command_get_args(payload);
1659 CHECK_STATUS("Cannot change mode: ");
1663 cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1665 /* Notify application */
1666 silc_client_command_callback(cmd);
1668 silc_fsm_next(fsm, silc_client_command_reply_processed);
1669 return SILC_FSM_CONTINUE;
1672 /********************************* DETACH ***********************************/
1674 SILC_FSM_STATE(silc_client_command_reply_detach)
1676 SilcClientCommandContext cmd = fsm_context;
1677 SilcClientConnection conn = cmd->conn;
1678 SilcClient client = conn->client;
1679 SilcCommandPayload payload = state_context;
1680 SilcArgumentPayload args = silc_command_get_args(payload);
1684 CHECK_STATUS("Cannot detach: ");
1687 /* Get detachment data */
1688 detach = silc_client_get_detach_data(client, conn);
1690 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1694 /* Notify application */
1695 silc_client_command_callback(cmd, detach);
1696 silc_buffer_free(detach);
1699 silc_fsm_next(fsm, silc_client_command_reply_processed);
1700 return SILC_FSM_CONTINUE;
1703 /********************************** WATCH ***********************************/
1705 SILC_FSM_STATE(silc_client_command_reply_watch)
1707 SilcClientCommandContext cmd = fsm_context;
1708 SilcCommandPayload payload = state_context;
1709 SilcArgumentPayload args = silc_command_get_args(payload);
1712 CHECK_STATUS("Cannot set watch: ");
1715 /* Notify application */
1716 silc_client_command_callback(cmd);
1718 silc_fsm_next(fsm, silc_client_command_reply_processed);
1719 return SILC_FSM_CONTINUE;
1722 /*********************************** BAN ************************************/
1724 SILC_FSM_STATE(silc_client_command_reply_ban)
1726 SilcClientCommandContext cmd = fsm_context;
1727 SilcClientConnection conn = cmd->conn;
1728 SilcClient client = conn->client;
1729 SilcCommandPayload payload = state_context;
1730 SilcArgumentPayload args = silc_command_get_args(payload);
1731 SilcChannelEntry channel = NULL;
1734 SilcArgumentPayload invite_args = NULL;
1738 CHECK_STATUS("Cannot set ban: ");
1741 /* Take Channel ID */
1742 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1743 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1747 /* Get the channel entry */
1748 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1750 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1754 /* Get the invite list */
1755 tmp = silc_argument_get_arg_type(args, 3, &len);
1757 invite_args = silc_argument_list_parse(tmp, len);
1759 /* Notify application */
1760 silc_client_command_callback(cmd, channel, invite_args);
1763 silc_argument_payload_free(invite_args);
1766 silc_client_unref_channel(client, conn, channel);
1767 silc_fsm_next(fsm, silc_client_command_reply_processed);
1768 return SILC_FSM_CONTINUE;
1771 /********************************** LEAVE ***********************************/
1773 /* Reply to LEAVE command. */
1775 SILC_FSM_STATE(silc_client_command_reply_leave)
1777 SilcClientCommandContext cmd = fsm_context;
1778 SilcClientConnection conn = cmd->conn;
1779 SilcClient client = conn->client;
1780 SilcCommandPayload payload = state_context;
1781 SilcArgumentPayload args = silc_command_get_args(payload);
1782 SilcChannelEntry channel;
1788 CHECK_STATUS("Cannot set leave: ");
1791 /* Get Channel ID */
1792 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1793 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1797 /* Get the channel entry */
1798 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1800 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1804 /* Remove us from this channel. */
1805 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1807 /* Notify application */
1808 silc_client_command_callback(cmd, channel);
1810 /* Remove old keys and stuff. The channel may remain even after leaving
1811 but we want to remove these always. */
1812 if (channel->internal.send_key)
1813 silc_cipher_free(channel->internal.send_key);
1814 channel->internal.send_key = NULL;
1815 if (channel->internal.receive_key)
1816 silc_cipher_free(channel->internal.receive_key);
1817 channel->internal.receive_key = NULL;
1818 if (channel->internal.hmac)
1819 silc_hmac_free(channel->internal.hmac);
1820 channel->internal.hmac = NULL;
1821 if (channel->internal.old_channel_keys) {
1822 silc_dlist_start(channel->internal.old_channel_keys);
1823 while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
1824 silc_cipher_free(key);
1825 silc_dlist_uninit(channel->internal.old_channel_keys);
1827 channel->internal.old_channel_keys = NULL;
1828 if (channel->internal.old_hmacs) {
1829 silc_dlist_start(channel->internal.old_hmacs);
1830 while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
1831 silc_hmac_free(hmac);
1832 silc_dlist_uninit(channel->internal.old_hmacs);
1834 channel->internal.old_hmacs = NULL;
1836 /* Now delete the channel. */
1837 silc_client_empty_channel(client, conn, channel);
1838 silc_client_del_channel(client, conn, channel);
1841 silc_fsm_next(fsm, silc_client_command_reply_processed);
1842 return SILC_FSM_CONTINUE;
1845 /********************************* USERS ************************************/
1847 /* Continue USERS command reply processing after resolving unknown users */
1850 silc_client_command_reply_users_resolved(SilcClient client,
1851 SilcClientConnection conn,
1856 SilcClientCommandContext cmd = context;
1857 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1861 /* Continue USERS command after resolving unknown channel */
1864 silc_client_command_reply_users_continue(SilcClient client,
1865 SilcClientConnection conn,
1870 SilcClientCommandContext cmd = context;
1873 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1874 SilcArgumentPayload args = silc_command_get_args(payload);
1876 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1877 ERROR_CALLBACK(cmd->status);
1878 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1881 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1884 /* Reply to USERS command. Received list of client ID's and theirs modes
1885 on the channel we requested. */
1887 SILC_FSM_STATE(silc_client_command_reply_users)
1889 SilcClientCommandContext cmd = fsm_context;
1890 SilcClientConnection conn = cmd->conn;
1891 SilcClient client = conn->client;
1892 SilcCommandPayload payload = state_context;
1893 SilcArgumentPayload args = silc_command_get_args(payload);
1895 SilcUInt32 tmp_len, list_count, mode;
1897 SilcHashTableList htl;
1898 SilcBufferStruct client_id_list, client_mode_list;
1899 SilcChannelEntry channel = NULL;
1900 SilcClientEntry client_entry;
1905 CHECK_STATUS("Cannot get users: ");
1908 /* Get channel ID */
1909 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1910 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1914 /* Get channel entry */
1915 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1917 /* Resolve the channel from server */
1918 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1919 client, conn, &id.u.channel_id,
1920 silc_client_command_reply_users_continue, cmd));
1924 /* Get the list count */
1925 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1926 if (!tmp || tmp_len != 4) {
1927 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1930 SILC_GET32_MSB(list_count, tmp);
1932 /* Get Client ID list */
1933 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1935 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1938 silc_buffer_set(&client_id_list, tmp, tmp_len);
1940 /* Resolve users we do not know about */
1941 if (!cmd->resolved) {
1942 cmd->resolved = TRUE;
1943 silc_client_unref_channel(client, conn, channel);
1944 SILC_FSM_CALL(silc_client_get_clients_by_list(
1945 client, conn, list_count, &client_id_list,
1946 silc_client_command_reply_users_resolved, cmd));
1950 /* Get client mode list */
1951 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1953 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1956 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1958 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1960 silc_rwlock_wrlock(channel->internal.lock);
1962 /* Cache the received Client ID's and modes. */
1963 for (i = 0; i < list_count; i++) {
1964 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1966 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1970 SILC_GET32_MSB(mode, client_mode_list.data);
1972 /* Save the client on this channel. Unknown clients are ignored as they
1973 clearly do not exist since the resolving didn't find them. */
1974 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1975 if (client_entry && client_entry->internal.valid) {
1976 silc_rwlock_wrlock(client_entry->internal.lock);
1977 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1978 silc_rwlock_unlock(client_entry->internal.lock);
1980 silc_client_unref_client(client, conn, client_entry);
1982 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1983 silc_rwlock_unlock(channel->internal.lock);
1986 if (!silc_buffer_pull(&client_mode_list, 4)) {
1987 silc_rwlock_unlock(channel->internal.lock);
1992 silc_rwlock_unlock(channel->internal.lock);
1994 /* Notify application */
1995 silc_hash_table_list(channel->user_list, &htl);
1996 silc_client_command_callback(cmd, channel, &htl);
1997 silc_hash_table_list_reset(&htl);
2000 silc_client_unref_channel(client, conn, channel);
2001 silc_fsm_next(fsm, silc_client_command_reply_processed);
2002 return SILC_FSM_CONTINUE;
2005 /********************************** GETKEY **********************************/
2007 /* Received command reply to GETKEY command. WE've received the remote
2008 client's public key. */
2010 SILC_FSM_STATE(silc_client_command_reply_getkey)
2012 SilcClientCommandContext cmd = fsm_context;
2013 SilcClientConnection conn = cmd->conn;
2014 SilcClient client = conn->client;
2015 SilcCommandPayload payload = state_context;
2016 SilcArgumentPayload args = silc_command_get_args(payload);
2017 SilcClientEntry client_entry;
2018 SilcServerEntry server_entry;
2021 SilcPublicKey public_key;
2025 CHECK_STATUS("Cannot get key: ");
2029 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
2030 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2034 /* Get the public key */
2035 tmp = silc_argument_get_arg_type(args, 3, &len);
2037 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2040 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
2041 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
2042 "Cannot decode public key: malformed/unsupported public key");
2043 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2047 if (id.type == SILC_ID_CLIENT) {
2048 /* Received client's public key */
2049 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2050 if (!client_entry) {
2051 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2055 silc_rwlock_wrlock(client_entry->internal.lock);
2057 /* Save fingerprint */
2058 if (!client_entry->fingerprint)
2059 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2060 client_entry->fingerprint);
2061 if (!client_entry->public_key) {
2062 client_entry->public_key = public_key;
2066 silc_rwlock_unlock(client_entry->internal.lock);
2068 /* Notify application */
2069 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2070 client_entry->public_key);
2071 silc_client_unref_client(client, conn, client_entry);
2072 } else if (id.type == SILC_ID_SERVER) {
2073 /* Received server's public key */
2074 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2075 if (!server_entry) {
2076 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2080 silc_rwlock_wrlock(server_entry->internal.lock);
2082 if (!server_entry->public_key) {
2083 server_entry->public_key = public_key;
2087 silc_rwlock_unlock(server_entry->internal.lock);
2089 /* Notify application */
2090 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2091 server_entry->public_key);
2092 silc_client_unref_server(client, conn, server_entry);
2097 silc_pkcs_public_key_free(public_key);
2098 silc_fsm_next(fsm, silc_client_command_reply_processed);
2099 return SILC_FSM_CONTINUE;
2102 /********************************** SERVICE *********************************/
2104 /* Reply to SERVICE command. */
2105 /* XXX incomplete */
2107 SILC_FSM_STATE(silc_client_command_reply_service)
2109 SilcClientCommandContext cmd = fsm_context;
2110 SilcCommandPayload payload = state_context;
2111 SilcArgumentPayload args = silc_command_get_args(payload);
2113 unsigned char *service_list, *name;
2116 CHECK_STATUS("Cannot get service: ");
2118 /* Get service list */
2119 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2121 /* Get requested service name */
2122 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2124 /* Notify application */
2125 silc_client_command_callback(cmd, service_list, name);
2127 silc_fsm_next(fsm, silc_client_command_reply_processed);
2128 return SILC_FSM_CONTINUE;
2131 /*********************************** QUIT ***********************************/
2133 /* QUIT command reply stub */
2135 SILC_FSM_STATE(silc_client_command_reply_quit)
2137 silc_fsm_next(fsm, silc_client_command_reply_processed);
2138 return SILC_FSM_CONTINUE;