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;
1116 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1117 SilcArgumentPayload args = silc_command_get_args(payload);
1118 SilcUInt32 list_count;
1123 silc_snprintf(msg, sizeof(msg), "Error resolving channel %s user list",
1124 channel->channel_name);
1125 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, msg);
1127 tmp = silc_argument_get_arg_type(args, 12, NULL);
1129 SILC_GET32_MSB(list_count, tmp);
1130 if (list_count - silc_dlist_count(clients) > 5) {
1131 silc_snprintf(msg, sizeof(msg),
1132 "Channel %s user list was not fully resolved. "
1133 "The channel may not be fully synced.",
1134 channel->channel_name);
1135 SAY(client, conn, SILC_CLIENT_MESSAGE_WARNING, msg);
1140 channel->internal.resolve_cmd_ident = 0;
1141 silc_client_unref_channel(client, conn, channel);
1143 SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
1147 /* Received reply for JOIN command. */
1149 SILC_FSM_STATE(silc_client_command_reply_join)
1151 SilcClientCommandContext cmd = fsm_context;
1152 SilcClientConnection conn = cmd->conn;
1153 SilcClient client = conn->client;
1154 SilcCommandPayload payload = state_context;
1155 SilcArgumentPayload args = silc_command_get_args(payload);
1156 SilcChannelEntry channel;
1157 SilcUInt32 mode = 0, len, list_count;
1158 char *topic, *tmp, *channel_name = NULL, *hmac;
1160 SilcBufferStruct client_id_list, client_mode_list, keyp;
1161 SilcHashTableList htl;
1166 CHECK_STATUS("Cannot join channel: ");
1169 /* Get channel name */
1170 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1171 if (!channel_name) {
1172 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1176 /* Get Channel ID */
1177 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1178 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1182 /* Check whether we have this channel entry already. */
1183 channel = silc_client_get_channel(client, conn, channel_name);
1185 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1186 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1188 /* Create new channel entry */
1189 channel = silc_client_add_channel(client, conn, channel_name,
1190 mode, &id.u.channel_id);
1192 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1195 silc_client_ref_channel(client, conn, channel);
1198 /* Get the list count */
1199 tmp = silc_argument_get_arg_type(args, 12, &len);
1200 if (!tmp || len != 4) {
1201 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1204 SILC_GET32_MSB(list_count, tmp);
1206 /* Get Client ID list */
1207 tmp = silc_argument_get_arg_type(args, 13, &len);
1209 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1212 silc_buffer_set(&client_id_list, tmp, len);
1214 /* Resolve users we do not know about */
1215 if (!cmd->resolved) {
1216 cmd->resolved = TRUE;
1217 cmd->context = channel;
1218 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1219 silc_client_get_clients_by_list(
1220 client, conn, list_count, &client_id_list,
1221 silc_client_command_reply_join_resolved, cmd));
1225 /* Get client mode list */
1226 tmp = silc_argument_get_arg_type(args, 14, &len);
1228 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1231 silc_buffer_set(&client_mode_list, tmp, len);
1233 silc_rwlock_wrlock(channel->internal.lock);
1235 /* Add clients we received in the reply to the channel */
1236 for (i = 0; i < list_count; i++) {
1239 SilcClientEntry client_entry;
1242 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1244 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1248 SILC_GET32_MSB(mode, client_mode_list.data);
1250 /* Get client entry */
1251 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1252 if (client_entry && client_entry->internal.valid) {
1253 /* Join client to the channel */
1254 silc_rwlock_wrlock(client_entry->internal.lock);
1255 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1256 silc_rwlock_unlock(client_entry->internal.lock);
1258 silc_client_unref_client(client, conn, client_entry);
1260 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1261 silc_rwlock_unlock(channel->internal.lock);
1264 if (!silc_buffer_pull(&client_mode_list, 4)) {
1265 silc_rwlock_unlock(channel->internal.lock);
1271 hmac = silc_argument_get_arg_type(args, 11, NULL);
1273 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1275 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1276 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1277 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1278 silc_rwlock_unlock(channel->internal.lock);
1283 /* Get channel mode */
1284 tmp = silc_argument_get_arg_type(args, 5, &len);
1285 if (tmp && len == 4)
1286 SILC_GET32_MSB(mode, tmp);
1287 channel->mode = mode;
1289 /* Get channel key and save it */
1290 tmp = silc_argument_get_arg_type(args, 7, &len);
1292 /* If channel key already exists on the channel then while resolving
1293 the user list we have already received new key from server. Don't
1294 replace it with this old key. */
1295 if (!channel->internal.send_key) {
1296 silc_buffer_set(&keyp, tmp, len);
1297 silc_client_save_channel_key(client, conn, &keyp, channel);
1302 topic = silc_argument_get_arg_type(args, 10, NULL);
1304 silc_free(channel->topic);
1305 channel->topic = silc_memdup(topic, strlen(topic));
1308 /* Get founder key */
1309 tmp = silc_argument_get_arg_type(args, 15, &len);
1311 if (channel->founder_key)
1312 silc_pkcs_public_key_free(channel->founder_key);
1313 channel->founder_key = NULL;
1314 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1317 /* Get user limit */
1318 tmp = silc_argument_get_arg_type(args, 17, &len);
1319 if (tmp && len == 4)
1320 SILC_GET32_MSB(channel->user_limit, tmp);
1321 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1322 channel->user_limit = 0;
1324 /* Get channel public key list */
1325 tmp = silc_argument_get_arg_type(args, 16, &len);
1327 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1329 /* Set current channel */
1330 conn->current_channel = channel;
1332 silc_rwlock_unlock(channel->internal.lock);
1334 cipher = (channel->internal.send_key ?
1335 silc_cipher_get_name(channel->internal.send_key) : NULL);
1336 silc_hash_table_list(channel->user_list, &htl);
1338 /* Notify application */
1339 silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
1340 topic, cipher, hmac, channel->founder_key,
1341 channel->channel_pubkeys, channel->user_limit);
1343 silc_hash_table_list_reset(&htl);
1344 silc_client_unref_channel(client, conn, channel);
1347 silc_fsm_next(fsm, silc_client_command_reply_processed);
1348 return SILC_FSM_CONTINUE;
1351 /********************************** MOTD ************************************/
1353 /* Received reply for MOTD command */
1355 SILC_FSM_STATE(silc_client_command_reply_motd)
1357 SilcClientCommandContext cmd = fsm_context;
1358 SilcClientConnection conn = cmd->conn;
1359 SilcClient client = conn->client;
1360 SilcCommandPayload payload = state_context;
1361 SilcArgumentPayload args = silc_command_get_args(payload);
1363 char *motd = NULL, *cp, line[256];
1366 CHECK_STATUS("Cannot get motd: ");
1369 if (silc_argument_get_arg_num(args) == 3) {
1370 motd = silc_argument_get_arg_type(args, 3, NULL);
1372 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1379 if (cp[i++] == '\n') {
1380 memset(line, 0, sizeof(line));
1381 silc_strncat(line, sizeof(line), cp, i - 1);
1388 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1397 /* Notify application */
1398 silc_client_command_callback(cmd, motd);
1401 silc_fsm_next(fsm, silc_client_command_reply_processed);
1402 return SILC_FSM_CONTINUE;
1405 /********************************** UMODE ***********************************/
1407 /* Received reply to the UMODE command. Save the current user mode */
1409 SILC_FSM_STATE(silc_client_command_reply_umode)
1411 SilcClientCommandContext cmd = fsm_context;
1412 SilcClientConnection conn = cmd->conn;
1413 SilcCommandPayload payload = state_context;
1414 SilcArgumentPayload args = silc_command_get_args(payload);
1416 SilcUInt32 mode, len;
1419 CHECK_STATUS("Cannot change mode: ");
1422 tmp = silc_argument_get_arg_type(args, 2, &len);
1423 if (!tmp || len != 4) {
1424 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1428 SILC_GET32_MSB(mode, tmp);
1429 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1430 conn->local_entry->mode = mode;
1431 silc_rwlock_unlock(conn->local_entry->internal.lock);
1433 /* Notify application */
1434 silc_client_command_callback(cmd, mode);
1437 silc_fsm_next(fsm, silc_client_command_reply_processed);
1438 return SILC_FSM_CONTINUE;
1441 /********************************** CMODE ***********************************/
1443 /* Received reply for CMODE command. */
1445 SILC_FSM_STATE(silc_client_command_reply_cmode)
1447 SilcClientCommandContext cmd = fsm_context;
1448 SilcClientConnection conn = cmd->conn;
1449 SilcClient client = conn->client;
1450 SilcCommandPayload payload = state_context;
1451 SilcArgumentPayload args = silc_command_get_args(payload);
1454 SilcChannelEntry channel = NULL;
1456 SilcPublicKey public_key = NULL;
1460 CHECK_STATUS("Cannot change mode: ");
1463 /* Take Channel ID */
1464 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1465 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1469 /* Get the channel entry */
1470 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1472 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1476 /* Get founder public key */
1477 tmp = silc_argument_get_arg_type(args, 4, &len);
1479 silc_public_key_payload_decode(tmp, len, &public_key);
1481 /* Get channel mode */
1482 tmp = silc_argument_get_arg_type(args, 3, &len);
1483 if (!tmp || len != 4) {
1484 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1487 SILC_GET32_MSB(mode, tmp);
1489 silc_rwlock_wrlock(channel->internal.lock);
1491 /* Get user limit */
1492 tmp = silc_argument_get_arg_type(args, 6, &len);
1493 if (tmp && len == 4)
1494 SILC_GET32_MSB(channel->user_limit, tmp);
1495 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1496 channel->user_limit = 0;
1498 /* Get channel public key(s) */
1499 tmp = silc_argument_get_arg_type(args, 5, &len);
1501 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1502 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
1503 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
1506 channel->mode = mode;
1508 silc_rwlock_unlock(channel->internal.lock);
1510 /* Notify application */
1511 silc_client_command_callback(cmd, channel, mode, public_key,
1512 channel->channel_pubkeys, channel->user_limit);
1514 silc_rwlock_wrlock(channel->internal.lock);
1516 /* If founder key changed, update it */
1518 (!channel->founder_key ||
1519 !silc_pkcs_public_key_compare(public_key, channel->founder_key))) {
1520 if (channel->founder_key)
1521 silc_pkcs_public_key_free(channel->founder_key);
1522 channel->founder_key = public_key;
1526 silc_rwlock_unlock(channel->internal.lock);
1529 silc_client_unref_channel(client, conn, channel);
1531 silc_pkcs_public_key_free(public_key);
1532 silc_fsm_next(fsm, silc_client_command_reply_processed);
1533 return SILC_FSM_CONTINUE;
1536 /********************************** CUMODE **********************************/
1538 /* Received reply for CUMODE command */
1540 SILC_FSM_STATE(silc_client_command_reply_cumode)
1542 SilcClientCommandContext cmd = fsm_context;
1543 SilcClientConnection conn = cmd->conn;
1544 SilcClient client = conn->client;
1545 SilcCommandPayload payload = state_context;
1546 SilcArgumentPayload args = silc_command_get_args(payload);
1547 SilcClientEntry client_entry;
1548 SilcChannelEntry channel = NULL;
1549 SilcChannelUser chu;
1550 unsigned char *modev;
1551 SilcUInt32 len, mode;
1555 CHECK_STATUS("Cannot change mode: ");
1558 /* Get channel mode */
1559 modev = silc_argument_get_arg_type(args, 2, &len);
1560 if (!modev || len != 4) {
1561 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1564 SILC_GET32_MSB(mode, modev);
1566 /* Take Channel ID */
1567 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1568 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1572 /* Get the channel entry */
1573 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1575 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1580 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1581 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1585 /* Get client entry */
1586 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1587 if (!client_entry) {
1588 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1593 silc_rwlock_wrlock(channel->internal.lock);
1594 chu = silc_client_on_channel(channel, client_entry);
1597 silc_rwlock_unlock(channel->internal.lock);
1599 /* Notify application */
1600 silc_client_command_callback(cmd, mode, channel, client_entry);
1602 silc_client_unref_client(client, conn, client_entry);
1605 silc_client_unref_channel(client, conn, channel);
1606 silc_fsm_next(fsm, silc_client_command_reply_processed);
1607 return SILC_FSM_CONTINUE;
1610 /********************************** KICK ************************************/
1612 SILC_FSM_STATE(silc_client_command_reply_kick)
1614 SilcClientCommandContext cmd = fsm_context;
1615 SilcClientConnection conn = cmd->conn;
1616 SilcClient client = conn->client;
1617 SilcCommandPayload payload = state_context;
1618 SilcArgumentPayload args = silc_command_get_args(payload);
1619 SilcClientEntry client_entry;
1620 SilcChannelEntry channel = NULL;
1624 CHECK_STATUS("Cannot kick: ");
1627 /* Take Channel ID */
1628 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1629 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1633 /* Get the channel entry */
1634 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1636 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1641 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1642 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1646 /* Get client entry */
1647 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1648 if (!client_entry) {
1649 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1653 /* Notify application */
1654 silc_client_command_callback(cmd, channel, client_entry);
1656 silc_client_unref_client(client, conn, client_entry);
1659 silc_client_unref_channel(client, conn, channel);
1660 silc_fsm_next(fsm, silc_client_command_reply_processed);
1661 return SILC_FSM_CONTINUE;
1664 /******************************** SILCOPER **********************************/
1666 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1668 SilcClientCommandContext cmd = fsm_context;
1669 SilcCommandPayload payload = state_context;
1670 SilcArgumentPayload args = silc_command_get_args(payload);
1673 CHECK_STATUS("Cannot change mode: ");
1677 cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1679 /* Notify application */
1680 silc_client_command_callback(cmd);
1682 silc_fsm_next(fsm, silc_client_command_reply_processed);
1683 return SILC_FSM_CONTINUE;
1686 /********************************** OPER ************************************/
1688 SILC_FSM_STATE(silc_client_command_reply_oper)
1690 SilcClientCommandContext cmd = fsm_context;
1691 SilcCommandPayload payload = state_context;
1692 SilcArgumentPayload args = silc_command_get_args(payload);
1695 CHECK_STATUS("Cannot change mode: ");
1699 cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1701 /* Notify application */
1702 silc_client_command_callback(cmd);
1704 silc_fsm_next(fsm, silc_client_command_reply_processed);
1705 return SILC_FSM_CONTINUE;
1708 /********************************* DETACH ***********************************/
1710 SILC_FSM_STATE(silc_client_command_reply_detach)
1712 SilcClientCommandContext cmd = fsm_context;
1713 SilcClientConnection conn = cmd->conn;
1714 SilcClient client = conn->client;
1715 SilcCommandPayload payload = state_context;
1716 SilcArgumentPayload args = silc_command_get_args(payload);
1720 CHECK_STATUS("Cannot detach: ");
1723 /* Get detachment data */
1724 detach = silc_client_get_detach_data(client, conn);
1726 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1730 /* Notify application */
1731 silc_client_command_callback(cmd, detach);
1732 silc_buffer_free(detach);
1735 silc_fsm_next(fsm, silc_client_command_reply_processed);
1736 return SILC_FSM_CONTINUE;
1739 /********************************** WATCH ***********************************/
1741 SILC_FSM_STATE(silc_client_command_reply_watch)
1743 SilcClientCommandContext cmd = fsm_context;
1744 SilcCommandPayload payload = state_context;
1745 SilcArgumentPayload args = silc_command_get_args(payload);
1748 CHECK_STATUS("Cannot set watch: ");
1751 /* Notify application */
1752 silc_client_command_callback(cmd);
1754 silc_fsm_next(fsm, silc_client_command_reply_processed);
1755 return SILC_FSM_CONTINUE;
1758 /*********************************** BAN ************************************/
1760 SILC_FSM_STATE(silc_client_command_reply_ban)
1762 SilcClientCommandContext cmd = fsm_context;
1763 SilcClientConnection conn = cmd->conn;
1764 SilcClient client = conn->client;
1765 SilcCommandPayload payload = state_context;
1766 SilcArgumentPayload args = silc_command_get_args(payload);
1767 SilcChannelEntry channel = NULL;
1770 SilcArgumentPayload invite_args = NULL;
1774 CHECK_STATUS("Cannot set ban: ");
1777 /* Take Channel ID */
1778 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1779 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1783 /* Get the channel entry */
1784 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1786 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1790 /* Get the invite list */
1791 tmp = silc_argument_get_arg_type(args, 3, &len);
1793 invite_args = silc_argument_list_parse(tmp, len);
1795 /* Notify application */
1796 silc_client_command_callback(cmd, channel, invite_args);
1799 silc_argument_payload_free(invite_args);
1802 silc_client_unref_channel(client, conn, channel);
1803 silc_fsm_next(fsm, silc_client_command_reply_processed);
1804 return SILC_FSM_CONTINUE;
1807 /********************************** LEAVE ***********************************/
1809 /* Reply to LEAVE command. */
1811 SILC_FSM_STATE(silc_client_command_reply_leave)
1813 SilcClientCommandContext cmd = fsm_context;
1814 SilcClientConnection conn = cmd->conn;
1815 SilcClient client = conn->client;
1816 SilcCommandPayload payload = state_context;
1817 SilcArgumentPayload args = silc_command_get_args(payload);
1818 SilcChannelEntry channel;
1824 CHECK_STATUS("Cannot set leave: ");
1827 /* Get Channel ID */
1828 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1829 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1833 /* Get the channel entry */
1834 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1836 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1840 /* Remove us from this channel. */
1841 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1843 /* Notify application */
1844 silc_client_command_callback(cmd, channel);
1846 /* Remove old keys and stuff. The channel may remain even after leaving
1847 but we want to remove these always. */
1848 if (channel->internal.send_key)
1849 silc_cipher_free(channel->internal.send_key);
1850 channel->internal.send_key = NULL;
1851 if (channel->internal.receive_key)
1852 silc_cipher_free(channel->internal.receive_key);
1853 channel->internal.receive_key = NULL;
1854 if (channel->internal.hmac)
1855 silc_hmac_free(channel->internal.hmac);
1856 channel->internal.hmac = NULL;
1857 if (channel->internal.old_channel_keys) {
1858 silc_dlist_start(channel->internal.old_channel_keys);
1859 while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
1860 silc_cipher_free(key);
1861 silc_dlist_uninit(channel->internal.old_channel_keys);
1863 channel->internal.old_channel_keys = NULL;
1864 if (channel->internal.old_hmacs) {
1865 silc_dlist_start(channel->internal.old_hmacs);
1866 while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
1867 silc_hmac_free(hmac);
1868 silc_dlist_uninit(channel->internal.old_hmacs);
1870 channel->internal.old_hmacs = NULL;
1872 /* Now delete the channel. */
1873 silc_client_empty_channel(client, conn, channel);
1874 silc_client_del_channel(client, conn, channel);
1877 silc_fsm_next(fsm, silc_client_command_reply_processed);
1878 return SILC_FSM_CONTINUE;
1881 /********************************* USERS ************************************/
1883 /* Continue USERS command reply processing after resolving unknown users */
1886 silc_client_command_reply_users_resolved(SilcClient client,
1887 SilcClientConnection conn,
1892 SilcClientCommandContext cmd = context;
1893 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1897 /* Continue USERS command after resolving unknown channel */
1900 silc_client_command_reply_users_continue(SilcClient client,
1901 SilcClientConnection conn,
1906 SilcClientCommandContext cmd = context;
1909 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1910 SilcArgumentPayload args = silc_command_get_args(payload);
1912 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1913 ERROR_CALLBACK(cmd->status);
1914 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1917 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1920 /* Reply to USERS command. Received list of client ID's and theirs modes
1921 on the channel we requested. */
1923 SILC_FSM_STATE(silc_client_command_reply_users)
1925 SilcClientCommandContext cmd = fsm_context;
1926 SilcClientConnection conn = cmd->conn;
1927 SilcClient client = conn->client;
1928 SilcCommandPayload payload = state_context;
1929 SilcArgumentPayload args = silc_command_get_args(payload);
1931 SilcUInt32 tmp_len, list_count, mode;
1933 SilcHashTableList htl;
1934 SilcBufferStruct client_id_list, client_mode_list;
1935 SilcChannelEntry channel = NULL;
1936 SilcClientEntry client_entry;
1941 CHECK_STATUS("Cannot get users: ");
1944 /* Get channel ID */
1945 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1946 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1950 /* Get channel entry */
1951 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1953 /* Resolve the channel from server */
1954 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1955 client, conn, &id.u.channel_id,
1956 silc_client_command_reply_users_continue, cmd));
1960 /* Get the list count */
1961 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1962 if (!tmp || tmp_len != 4) {
1963 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1966 SILC_GET32_MSB(list_count, tmp);
1968 /* Get Client ID list */
1969 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1971 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1974 silc_buffer_set(&client_id_list, tmp, tmp_len);
1976 /* Resolve users we do not know about */
1977 if (!cmd->resolved) {
1978 cmd->resolved = TRUE;
1979 silc_client_unref_channel(client, conn, channel);
1980 SILC_FSM_CALL(silc_client_get_clients_by_list(
1981 client, conn, list_count, &client_id_list,
1982 silc_client_command_reply_users_resolved, cmd));
1986 /* Get client mode list */
1987 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1989 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1992 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1994 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1996 silc_rwlock_wrlock(channel->internal.lock);
1998 /* Cache the received Client ID's and modes. */
1999 for (i = 0; i < list_count; i++) {
2000 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
2002 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
2006 SILC_GET32_MSB(mode, client_mode_list.data);
2008 /* Save the client on this channel. Unknown clients are ignored as they
2009 clearly do not exist since the resolving didn't find them. */
2010 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2011 if (client_entry && client_entry->internal.valid) {
2012 silc_rwlock_wrlock(client_entry->internal.lock);
2013 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
2014 silc_rwlock_unlock(client_entry->internal.lock);
2016 silc_client_unref_client(client, conn, client_entry);
2018 if (!silc_buffer_pull(&client_id_list, idp_len)) {
2019 silc_rwlock_unlock(channel->internal.lock);
2022 if (!silc_buffer_pull(&client_mode_list, 4)) {
2023 silc_rwlock_unlock(channel->internal.lock);
2028 silc_rwlock_unlock(channel->internal.lock);
2030 /* Notify application */
2031 silc_hash_table_list(channel->user_list, &htl);
2032 silc_client_command_callback(cmd, channel, &htl);
2033 silc_hash_table_list_reset(&htl);
2036 silc_client_unref_channel(client, conn, channel);
2037 silc_fsm_next(fsm, silc_client_command_reply_processed);
2038 return SILC_FSM_CONTINUE;
2041 /********************************** GETKEY **********************************/
2043 /* Received command reply to GETKEY command. WE've received the remote
2044 client's public key. */
2046 SILC_FSM_STATE(silc_client_command_reply_getkey)
2048 SilcClientCommandContext cmd = fsm_context;
2049 SilcClientConnection conn = cmd->conn;
2050 SilcClient client = conn->client;
2051 SilcCommandPayload payload = state_context;
2052 SilcArgumentPayload args = silc_command_get_args(payload);
2053 SilcClientEntry client_entry;
2054 SilcServerEntry server_entry;
2057 SilcPublicKey public_key;
2061 CHECK_STATUS("Cannot get key: ");
2065 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
2066 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2070 /* Get the public key */
2071 tmp = silc_argument_get_arg_type(args, 3, &len);
2073 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2076 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
2077 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
2078 "Cannot decode public key: malformed/unsupported public key");
2079 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2083 if (id.type == SILC_ID_CLIENT) {
2084 /* Received client's public key */
2085 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2086 if (!client_entry) {
2087 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2091 silc_rwlock_wrlock(client_entry->internal.lock);
2093 /* Save fingerprint */
2094 if (!client_entry->fingerprint)
2095 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2096 client_entry->fingerprint);
2097 if (!client_entry->public_key) {
2098 client_entry->public_key = public_key;
2102 silc_rwlock_unlock(client_entry->internal.lock);
2104 /* Notify application */
2105 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2106 client_entry->public_key);
2107 silc_client_unref_client(client, conn, client_entry);
2108 } else if (id.type == SILC_ID_SERVER) {
2109 /* Received server's public key */
2110 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2111 if (!server_entry) {
2112 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2116 silc_rwlock_wrlock(server_entry->internal.lock);
2118 if (!server_entry->public_key) {
2119 server_entry->public_key = public_key;
2123 silc_rwlock_unlock(server_entry->internal.lock);
2125 /* Notify application */
2126 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2127 server_entry->public_key);
2128 silc_client_unref_server(client, conn, server_entry);
2133 silc_pkcs_public_key_free(public_key);
2134 silc_fsm_next(fsm, silc_client_command_reply_processed);
2135 return SILC_FSM_CONTINUE;
2138 /********************************** SERVICE *********************************/
2140 /* Reply to SERVICE command. */
2141 /* XXX incomplete */
2143 SILC_FSM_STATE(silc_client_command_reply_service)
2145 SilcClientCommandContext cmd = fsm_context;
2146 SilcCommandPayload payload = state_context;
2147 SilcArgumentPayload args = silc_command_get_args(payload);
2149 unsigned char *service_list, *name;
2152 CHECK_STATUS("Cannot get service: ");
2154 /* Get service list */
2155 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2157 /* Get requested service name */
2158 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2160 /* Notify application */
2161 silc_client_command_callback(cmd, service_list, name);
2163 silc_fsm_next(fsm, silc_client_command_reply_processed);
2164 return SILC_FSM_CONTINUE;
2167 /*********************************** QUIT ***********************************/
2169 /* QUIT command reply stub */
2171 SILC_FSM_STATE(silc_client_command_reply_quit)
2173 silc_fsm_next(fsm, silc_client_command_reply_processed);
2174 return SILC_FSM_CONTINUE;