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);
1176 hmac = silc_argument_get_arg_type(args, 11, NULL);
1177 if (hmac && !silc_hmac_is_supported(hmac)) {
1179 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1180 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1181 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1182 silc_rwlock_unlock(channel->internal.lock);
1186 /* Get the list count */
1187 tmp = silc_argument_get_arg_type(args, 12, &len);
1189 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1192 SILC_GET32_MSB(list_count, tmp);
1194 /* Get Client ID list */
1195 tmp = silc_argument_get_arg_type(args, 13, &len);
1197 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1200 silc_buffer_set(&client_id_list, tmp, len);
1202 /* Resolve users we do not know about */
1203 if (!cmd->resolved) {
1204 cmd->resolved = TRUE;
1205 cmd->context = channel;
1206 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1207 silc_client_get_clients_by_list(
1208 client, conn, list_count, &client_id_list,
1209 silc_client_command_reply_join_resolved, cmd));
1213 /* Get client mode list */
1214 tmp = silc_argument_get_arg_type(args, 14, &len);
1216 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1219 silc_buffer_set(&client_mode_list, tmp, len);
1221 silc_rwlock_wrlock(channel->internal.lock);
1223 /* Add clients we received in the reply to the channel */
1224 for (i = 0; i < list_count; i++) {
1228 SilcClientEntry client_entry;
1231 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1233 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1237 SILC_GET32_MSB(mode, client_mode_list.data);
1239 /* Get client entry */
1240 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1241 if (client_entry && client_entry->internal.valid) {
1242 /* Join client to the channel */
1243 silc_rwlock_wrlock(client_entry->internal.lock);
1244 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1245 silc_rwlock_unlock(client_entry->internal.lock);
1247 silc_client_unref_client(client, conn, client_entry);
1249 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1250 silc_rwlock_unlock(channel->internal.lock);
1253 if (!silc_buffer_pull(&client_mode_list, 4)) {
1254 silc_rwlock_unlock(channel->internal.lock);
1259 /* Get channel mode */
1260 tmp = silc_argument_get_arg_type(args, 5, &len);
1261 if (tmp && len == 4)
1262 SILC_GET32_MSB(mode, tmp);
1263 channel->mode = mode;
1265 /* Get channel key and save it */
1266 tmp = silc_argument_get_arg_type(args, 7, &len);
1268 /* If channel key already exists on the channel then while resolving
1269 the user list we have already received new key from server. Don't
1270 replace it with this old key. */
1271 if (!channel->internal.send_key) {
1272 silc_buffer_set(&keyp, tmp, len);
1273 silc_client_save_channel_key(client, conn, &keyp, channel);
1278 topic = silc_argument_get_arg_type(args, 10, NULL);
1280 silc_free(channel->topic);
1281 channel->topic = silc_memdup(topic, strlen(topic));
1284 /* Get founder key */
1285 tmp = silc_argument_get_arg_type(args, 15, &len);
1287 if (channel->founder_key)
1288 silc_pkcs_public_key_free(channel->founder_key);
1289 channel->founder_key = NULL;
1290 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1293 /* Get user limit */
1294 tmp = silc_argument_get_arg_type(args, 17, &len);
1295 if (tmp && len == 4)
1296 SILC_GET32_MSB(channel->user_limit, tmp);
1297 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1298 channel->user_limit = 0;
1300 /* Get channel public key list */
1301 tmp = silc_argument_get_arg_type(args, 16, &len);
1303 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1305 /* Set current channel */
1306 conn->current_channel = channel;
1308 silc_rwlock_unlock(channel->internal.lock);
1310 cipher = (channel->internal.send_key ?
1311 silc_cipher_get_name(channel->internal.send_key) : NULL);
1312 silc_hash_table_list(channel->user_list, &htl);
1314 /* Notify application */
1315 silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
1316 topic, cipher, hmac, channel->founder_key,
1317 channel->channel_pubkeys, channel->user_limit);
1319 silc_hash_table_list_reset(&htl);
1320 silc_client_unref_channel(client, conn, channel);
1323 silc_fsm_next(fsm, silc_client_command_reply_processed);
1324 return SILC_FSM_CONTINUE;
1327 /********************************** MOTD ************************************/
1329 /* Received reply for MOTD command */
1331 SILC_FSM_STATE(silc_client_command_reply_motd)
1333 SilcClientCommandContext cmd = fsm_context;
1334 SilcClientConnection conn = cmd->conn;
1335 SilcClient client = conn->client;
1336 SilcCommandPayload payload = state_context;
1337 SilcArgumentPayload args = silc_command_get_args(payload);
1339 char *motd = NULL, *cp, line[256];
1342 CHECK_STATUS("Cannot get motd: ");
1345 if (silc_argument_get_arg_num(args) == 3) {
1346 motd = silc_argument_get_arg_type(args, 3, NULL);
1348 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1355 if (cp[i++] == '\n') {
1356 memset(line, 0, sizeof(line));
1357 silc_strncat(line, sizeof(line), cp, i - 1);
1364 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1373 /* Notify application */
1374 silc_client_command_callback(cmd, motd);
1377 silc_fsm_next(fsm, silc_client_command_reply_processed);
1378 return SILC_FSM_CONTINUE;
1381 /********************************** UMODE ***********************************/
1383 /* Received reply to the UMODE command. Save the current user mode */
1385 SILC_FSM_STATE(silc_client_command_reply_umode)
1387 SilcClientCommandContext cmd = fsm_context;
1388 SilcClientConnection conn = cmd->conn;
1389 SilcCommandPayload payload = state_context;
1390 SilcArgumentPayload args = silc_command_get_args(payload);
1392 SilcUInt32 mode, len;
1395 CHECK_STATUS("Cannot change mode: ");
1398 tmp = silc_argument_get_arg_type(args, 2, &len);
1399 if (!tmp || len != 4) {
1400 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1404 SILC_GET32_MSB(mode, tmp);
1405 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1406 conn->local_entry->mode = mode;
1407 silc_rwlock_unlock(conn->local_entry->internal.lock);
1409 /* Notify application */
1410 silc_client_command_callback(cmd, mode);
1413 silc_fsm_next(fsm, silc_client_command_reply_processed);
1414 return SILC_FSM_CONTINUE;
1417 /********************************** CMODE ***********************************/
1419 /* Received reply for CMODE command. */
1421 SILC_FSM_STATE(silc_client_command_reply_cmode)
1423 SilcClientCommandContext cmd = fsm_context;
1424 SilcClientConnection conn = cmd->conn;
1425 SilcClient client = conn->client;
1426 SilcCommandPayload payload = state_context;
1427 SilcArgumentPayload args = silc_command_get_args(payload);
1430 SilcChannelEntry channel = NULL;
1432 SilcPublicKey public_key = NULL;
1436 CHECK_STATUS("Cannot change mode: ");
1439 /* Take Channel ID */
1440 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1441 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1445 /* Get the channel entry */
1446 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1448 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1452 /* Get founder public key */
1453 tmp = silc_argument_get_arg_type(args, 4, &len);
1455 silc_public_key_payload_decode(tmp, len, &public_key);
1457 /* Get channel mode */
1458 tmp = silc_argument_get_arg_type(args, 3, &len);
1459 if (!tmp || len != 4) {
1460 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1463 SILC_GET32_MSB(mode, tmp);
1465 silc_rwlock_wrlock(channel->internal.lock);
1467 /* Get user limit */
1468 tmp = silc_argument_get_arg_type(args, 6, &len);
1469 if (tmp && len == 4)
1470 SILC_GET32_MSB(channel->user_limit, tmp);
1471 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1472 channel->user_limit = 0;
1474 /* Get channel public key(s) */
1475 tmp = silc_argument_get_arg_type(args, 5, &len);
1477 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1478 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
1479 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
1482 channel->mode = mode;
1484 silc_rwlock_unlock(channel->internal.lock);
1486 /* Notify application */
1487 silc_client_command_callback(cmd, channel, mode, public_key,
1488 channel->channel_pubkeys, channel->user_limit);
1491 silc_client_unref_channel(client, conn, channel);
1493 silc_pkcs_public_key_free(public_key);
1494 silc_fsm_next(fsm, silc_client_command_reply_processed);
1495 return SILC_FSM_CONTINUE;
1498 /********************************** CUMODE **********************************/
1500 /* Received reply for CUMODE command */
1502 SILC_FSM_STATE(silc_client_command_reply_cumode)
1504 SilcClientCommandContext cmd = fsm_context;
1505 SilcClientConnection conn = cmd->conn;
1506 SilcClient client = conn->client;
1507 SilcCommandPayload payload = state_context;
1508 SilcArgumentPayload args = silc_command_get_args(payload);
1509 SilcClientEntry client_entry;
1510 SilcChannelEntry channel = NULL;
1511 SilcChannelUser chu;
1512 unsigned char *modev;
1513 SilcUInt32 len, mode;
1517 CHECK_STATUS("Cannot change mode: ");
1520 /* Get channel mode */
1521 modev = silc_argument_get_arg_type(args, 2, &len);
1522 if (!modev || len != 4) {
1523 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1526 SILC_GET32_MSB(mode, modev);
1528 /* Take Channel ID */
1529 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1530 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1534 /* Get the channel entry */
1535 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1537 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1542 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1543 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1547 /* Get client entry */
1548 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1549 if (!client_entry) {
1550 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1555 silc_rwlock_wrlock(channel->internal.lock);
1556 chu = silc_client_on_channel(channel, client_entry);
1559 silc_rwlock_unlock(channel->internal.lock);
1561 /* Notify application */
1562 silc_client_command_callback(cmd, mode, channel, client_entry);
1564 silc_client_unref_client(client, conn, client_entry);
1567 silc_client_unref_channel(client, conn, channel);
1568 silc_fsm_next(fsm, silc_client_command_reply_processed);
1569 return SILC_FSM_CONTINUE;
1572 /********************************** KICK ************************************/
1574 SILC_FSM_STATE(silc_client_command_reply_kick)
1576 SilcClientCommandContext cmd = fsm_context;
1577 SilcClientConnection conn = cmd->conn;
1578 SilcClient client = conn->client;
1579 SilcCommandPayload payload = state_context;
1580 SilcArgumentPayload args = silc_command_get_args(payload);
1581 SilcClientEntry client_entry;
1582 SilcChannelEntry channel = NULL;
1586 CHECK_STATUS("Cannot kick: ");
1589 /* Take Channel ID */
1590 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1591 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1595 /* Get the channel entry */
1596 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1598 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1603 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1604 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1608 /* Get client entry */
1609 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1610 if (!client_entry) {
1611 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1615 /* Notify application */
1616 silc_client_command_callback(cmd, channel, client_entry);
1618 silc_client_unref_client(client, conn, client_entry);
1621 silc_client_unref_channel(client, conn, channel);
1622 silc_fsm_next(fsm, silc_client_command_reply_processed);
1623 return SILC_FSM_CONTINUE;
1626 /******************************** SILCOPER **********************************/
1628 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1630 SilcClientCommandContext cmd = fsm_context;
1631 SilcCommandPayload payload = state_context;
1632 SilcArgumentPayload args = silc_command_get_args(payload);
1635 CHECK_STATUS("Cannot change mode: ");
1639 cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1641 /* Notify application */
1642 silc_client_command_callback(cmd);
1644 silc_fsm_next(fsm, silc_client_command_reply_processed);
1645 return SILC_FSM_CONTINUE;
1648 /********************************** OPER ************************************/
1650 SILC_FSM_STATE(silc_client_command_reply_oper)
1652 SilcClientCommandContext cmd = fsm_context;
1653 SilcCommandPayload payload = state_context;
1654 SilcArgumentPayload args = silc_command_get_args(payload);
1657 CHECK_STATUS("Cannot change mode: ");
1661 cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1663 /* Notify application */
1664 silc_client_command_callback(cmd);
1666 silc_fsm_next(fsm, silc_client_command_reply_processed);
1667 return SILC_FSM_CONTINUE;
1670 /********************************* DETACH ***********************************/
1672 SILC_FSM_STATE(silc_client_command_reply_detach)
1674 SilcClientCommandContext cmd = fsm_context;
1675 SilcClientConnection conn = cmd->conn;
1676 SilcClient client = conn->client;
1677 SilcCommandPayload payload = state_context;
1678 SilcArgumentPayload args = silc_command_get_args(payload);
1682 CHECK_STATUS("Cannot detach: ");
1685 /* Get detachment data */
1686 detach = silc_client_get_detach_data(client, conn);
1688 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1692 /* Notify application */
1693 silc_client_command_callback(cmd, detach);
1694 silc_buffer_free(detach);
1697 silc_fsm_next(fsm, silc_client_command_reply_processed);
1698 return SILC_FSM_CONTINUE;
1701 /********************************** WATCH ***********************************/
1703 SILC_FSM_STATE(silc_client_command_reply_watch)
1705 SilcClientCommandContext cmd = fsm_context;
1706 SilcCommandPayload payload = state_context;
1707 SilcArgumentPayload args = silc_command_get_args(payload);
1710 CHECK_STATUS("Cannot set watch: ");
1713 /* Notify application */
1714 silc_client_command_callback(cmd);
1716 silc_fsm_next(fsm, silc_client_command_reply_processed);
1717 return SILC_FSM_CONTINUE;
1720 /*********************************** BAN ************************************/
1722 SILC_FSM_STATE(silc_client_command_reply_ban)
1724 SilcClientCommandContext cmd = fsm_context;
1725 SilcClientConnection conn = cmd->conn;
1726 SilcClient client = conn->client;
1727 SilcCommandPayload payload = state_context;
1728 SilcArgumentPayload args = silc_command_get_args(payload);
1729 SilcChannelEntry channel = NULL;
1732 SilcArgumentPayload invite_args = NULL;
1736 CHECK_STATUS("Cannot set ban: ");
1739 /* Take Channel ID */
1740 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1741 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1745 /* Get the channel entry */
1746 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1748 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1752 /* Get the invite list */
1753 tmp = silc_argument_get_arg_type(args, 3, &len);
1755 invite_args = silc_argument_list_parse(tmp, len);
1757 /* Notify application */
1758 silc_client_command_callback(cmd, channel, invite_args);
1761 silc_argument_payload_free(invite_args);
1764 silc_client_unref_channel(client, conn, channel);
1765 silc_fsm_next(fsm, silc_client_command_reply_processed);
1766 return SILC_FSM_CONTINUE;
1769 /********************************** LEAVE ***********************************/
1771 /* Reply to LEAVE command. */
1773 SILC_FSM_STATE(silc_client_command_reply_leave)
1775 SilcClientCommandContext cmd = fsm_context;
1776 SilcClientConnection conn = cmd->conn;
1777 SilcClient client = conn->client;
1778 SilcCommandPayload payload = state_context;
1779 SilcArgumentPayload args = silc_command_get_args(payload);
1780 SilcChannelEntry channel;
1786 CHECK_STATUS("Cannot set leave: ");
1789 /* Get Channel ID */
1790 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1791 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1795 /* Get the channel entry */
1796 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1798 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1802 /* Remove us from this channel. */
1803 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1805 /* Notify application */
1806 silc_client_command_callback(cmd, channel);
1808 /* Remove old keys and stuff. The channel may remain even after leaving
1809 but we want to remove these always. */
1810 if (channel->internal.send_key)
1811 silc_cipher_free(channel->internal.send_key);
1812 channel->internal.send_key = NULL;
1813 if (channel->internal.receive_key)
1814 silc_cipher_free(channel->internal.receive_key);
1815 channel->internal.receive_key = NULL;
1816 if (channel->internal.hmac)
1817 silc_hmac_free(channel->internal.hmac);
1818 channel->internal.hmac = NULL;
1819 if (channel->internal.old_channel_keys) {
1820 silc_dlist_start(channel->internal.old_channel_keys);
1821 while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
1822 silc_cipher_free(key);
1823 silc_dlist_uninit(channel->internal.old_channel_keys);
1825 channel->internal.old_channel_keys = NULL;
1826 if (channel->internal.old_hmacs) {
1827 silc_dlist_start(channel->internal.old_hmacs);
1828 while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
1829 silc_hmac_free(hmac);
1830 silc_dlist_uninit(channel->internal.old_hmacs);
1832 channel->internal.old_hmacs = NULL;
1834 /* Now delete the channel. */
1835 silc_client_empty_channel(client, conn, channel);
1836 silc_client_del_channel(client, conn, channel);
1839 silc_fsm_next(fsm, silc_client_command_reply_processed);
1840 return SILC_FSM_CONTINUE;
1843 /********************************* USERS ************************************/
1845 /* Continue USERS command reply processing after resolving unknown users */
1848 silc_client_command_reply_users_resolved(SilcClient client,
1849 SilcClientConnection conn,
1854 SilcClientCommandContext cmd = context;
1855 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1859 /* Continue USERS command after resolving unknown channel */
1862 silc_client_command_reply_users_continue(SilcClient client,
1863 SilcClientConnection conn,
1868 SilcClientCommandContext cmd = context;
1871 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1872 SilcArgumentPayload args = silc_command_get_args(payload);
1874 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1875 ERROR_CALLBACK(cmd->status);
1876 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1879 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1882 /* Reply to USERS command. Received list of client ID's and theirs modes
1883 on the channel we requested. */
1885 SILC_FSM_STATE(silc_client_command_reply_users)
1887 SilcClientCommandContext cmd = fsm_context;
1888 SilcClientConnection conn = cmd->conn;
1889 SilcClient client = conn->client;
1890 SilcCommandPayload payload = state_context;
1891 SilcArgumentPayload args = silc_command_get_args(payload);
1893 SilcUInt32 tmp_len, list_count, mode;
1895 SilcHashTableList htl;
1896 SilcBufferStruct client_id_list, client_mode_list;
1897 SilcChannelEntry channel = NULL;
1898 SilcClientEntry client_entry;
1903 CHECK_STATUS("Cannot get users: ");
1906 /* Get channel ID */
1907 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1908 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1912 /* Get channel entry */
1913 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1915 /* Resolve the channel from server */
1916 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1917 client, conn, &id.u.channel_id,
1918 silc_client_command_reply_users_continue, cmd));
1922 /* Get the list count */
1923 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1924 if (!tmp || tmp_len != 4) {
1925 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1928 SILC_GET32_MSB(list_count, tmp);
1930 /* Get Client ID list */
1931 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1933 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1936 silc_buffer_set(&client_id_list, tmp, tmp_len);
1938 /* Resolve users we do not know about */
1939 if (!cmd->resolved) {
1940 cmd->resolved = TRUE;
1941 silc_client_unref_channel(client, conn, channel);
1942 SILC_FSM_CALL(silc_client_get_clients_by_list(
1943 client, conn, list_count, &client_id_list,
1944 silc_client_command_reply_users_resolved, cmd));
1948 /* Get client mode list */
1949 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1951 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1954 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1956 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1958 silc_rwlock_wrlock(channel->internal.lock);
1960 /* Cache the received Client ID's and modes. */
1961 for (i = 0; i < list_count; i++) {
1962 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1964 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1968 SILC_GET32_MSB(mode, client_mode_list.data);
1970 /* Save the client on this channel. Unknown clients are ignored as they
1971 clearly do not exist since the resolving didn't find them. */
1972 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1973 if (client_entry && client_entry->internal.valid) {
1974 silc_rwlock_wrlock(client_entry->internal.lock);
1975 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1976 silc_rwlock_unlock(client_entry->internal.lock);
1978 silc_client_unref_client(client, conn, client_entry);
1980 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1981 silc_rwlock_unlock(channel->internal.lock);
1984 if (!silc_buffer_pull(&client_mode_list, 4)) {
1985 silc_rwlock_unlock(channel->internal.lock);
1990 silc_rwlock_unlock(channel->internal.lock);
1992 /* Notify application */
1993 silc_hash_table_list(channel->user_list, &htl);
1994 silc_client_command_callback(cmd, channel, &htl);
1995 silc_hash_table_list_reset(&htl);
1998 silc_client_unref_channel(client, conn, channel);
1999 silc_fsm_next(fsm, silc_client_command_reply_processed);
2000 return SILC_FSM_CONTINUE;
2003 /********************************** GETKEY **********************************/
2005 /* Received command reply to GETKEY command. WE've received the remote
2006 client's public key. */
2008 SILC_FSM_STATE(silc_client_command_reply_getkey)
2010 SilcClientCommandContext cmd = fsm_context;
2011 SilcClientConnection conn = cmd->conn;
2012 SilcClient client = conn->client;
2013 SilcCommandPayload payload = state_context;
2014 SilcArgumentPayload args = silc_command_get_args(payload);
2015 SilcClientEntry client_entry;
2016 SilcServerEntry server_entry;
2019 SilcPublicKey public_key;
2023 CHECK_STATUS("Cannot get key: ");
2027 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
2028 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2032 /* Get the public key */
2033 tmp = silc_argument_get_arg_type(args, 3, &len);
2035 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2038 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
2039 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
2040 "Cannot decode public key: malformed/unsupported public key");
2041 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2045 if (id.type == SILC_ID_CLIENT) {
2046 /* Received client's public key */
2047 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2048 if (!client_entry) {
2049 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2053 silc_rwlock_wrlock(client_entry->internal.lock);
2055 /* Save fingerprint */
2056 if (!client_entry->fingerprint)
2057 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2058 client_entry->fingerprint);
2059 if (!client_entry->public_key) {
2060 client_entry->public_key = public_key;
2064 silc_rwlock_unlock(client_entry->internal.lock);
2066 /* Notify application */
2067 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2068 client_entry->public_key);
2069 silc_client_unref_client(client, conn, client_entry);
2070 } else if (id.type == SILC_ID_SERVER) {
2071 /* Received server's public key */
2072 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2073 if (!server_entry) {
2074 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2078 silc_rwlock_wrlock(server_entry->internal.lock);
2080 if (!server_entry->public_key) {
2081 server_entry->public_key = public_key;
2085 silc_rwlock_unlock(server_entry->internal.lock);
2087 /* Notify application */
2088 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2089 server_entry->public_key);
2090 silc_client_unref_server(client, conn, server_entry);
2095 silc_pkcs_public_key_free(public_key);
2096 silc_fsm_next(fsm, silc_client_command_reply_processed);
2097 return SILC_FSM_CONTINUE;
2100 /********************************** SERVICE *********************************/
2102 /* Reply to SERVICE command. */
2103 /* XXX incomplete */
2105 SILC_FSM_STATE(silc_client_command_reply_service)
2107 SilcClientCommandContext cmd = fsm_context;
2108 SilcCommandPayload payload = state_context;
2109 SilcArgumentPayload args = silc_command_get_args(payload);
2111 unsigned char *service_list, *name;
2114 CHECK_STATUS("Cannot get service: ");
2116 /* Get service list */
2117 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2119 /* Get requested service name */
2120 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2122 /* Notify application */
2123 silc_client_command_callback(cmd, service_list, name);
2125 silc_fsm_next(fsm, silc_client_command_reply_processed);
2126 return SILC_FSM_CONTINUE;
2129 /*********************************** QUIT ***********************************/
2131 /* QUIT command reply stub */
2133 SILC_FSM_STATE(silc_client_command_reply_quit)
2135 silc_fsm_next(fsm, silc_client_command_reply_processed);
2136 return SILC_FSM_CONTINUE;