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 silc_client_del_client(client, conn, client_entry);
122 silc_client_unref_client(client, conn, client_entry);
127 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
128 SilcChannelEntry channel;
130 /* Remove unknown channel entry from cache */
131 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
134 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
136 silc_client_empty_channel(client, conn, channel);
137 silc_client_del_channel(client, conn, channel);
138 silc_client_unref_channel(client, conn, channel);
143 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
144 SilcServerEntry server_entry;
146 /* Remove unknown server entry from cache */
147 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
150 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
152 silc_client_del_server(client, conn, server_entry);
153 silc_client_unref_server(client, conn, server_entry);
159 /***************************** Command Reply ********************************/
161 /* Process received command reply packet */
163 SILC_FSM_STATE(silc_client_command_reply)
165 SilcClientConnection conn = fsm_context;
166 SilcPacket packet = state_context;
167 SilcClientCommandContext cmd;
168 SilcCommandPayload payload;
170 SilcUInt16 cmd_ident;
172 /* Get command reply payload from packet */
173 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
174 silc_packet_free(packet);
176 SILC_LOG_DEBUG(("Bad command reply packet"));
177 return SILC_FSM_FINISH;
180 cmd_ident = silc_command_get_ident(payload);
181 command = silc_command_get(payload);
183 /* Find the command pending reply */
184 silc_mutex_lock(conn->internal->lock);
185 silc_list_start(conn->internal->pending_commands);
186 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
187 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
188 && cmd->cmd_ident == cmd_ident) {
189 silc_list_del(conn->internal->pending_commands, cmd);
193 silc_mutex_unlock(conn->internal->lock);
196 SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
197 silc_get_command_name(command), cmd_ident));
198 silc_command_payload_free(payload);
199 return SILC_FSM_FINISH;
202 /* Signal command thread that command reply has arrived. We continue
203 command reply processing synchronously because we save the command
204 payload into state context. No other reply may arrive to this command
205 while we're processing this reply. */
206 silc_fsm_set_state_context(&cmd->thread, payload);
207 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
208 silc_fsm_continue_sync(&cmd->thread);
210 return SILC_FSM_FINISH;
213 /* Wait here for command reply to arrive from remote host */
215 SILC_FSM_STATE(silc_client_command_reply_wait)
217 SilcClientCommandContext cmd = fsm_context;
219 SILC_LOG_DEBUG(("Wait for command reply"));
221 /** Wait for command reply */
222 silc_fsm_set_state_context(fsm, NULL);
223 silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
224 cmd->cmd != SILC_COMMAND_PING ? 40 : 60, 0);
225 return SILC_FSM_WAIT;
228 /* Timeout occurred while waiting command reply */
230 SILC_FSM_STATE(silc_client_command_reply_timeout)
232 SilcClientCommandContext cmd = fsm_context;
233 SilcClientConnection conn = cmd->conn;
234 SilcArgumentPayload args = NULL;
236 if (conn->internal->disconnected) {
237 SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
238 silc_list_del(conn->internal->pending_commands, cmd);
240 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
241 return SILC_FSM_FINISH;
244 SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
246 /* Timeout, reply not received in timely fashion */
247 silc_list_del(conn->internal->pending_commands, cmd);
248 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
249 return SILC_FSM_FINISH;
252 /* Process received command reply payload */
254 SILC_FSM_STATE(silc_client_command_reply_process)
256 SilcClientCommandContext cmd = fsm_context;
257 SilcCommandPayload payload = state_context;
259 silc_command_get_status(payload, &cmd->status, &cmd->error);
262 case SILC_COMMAND_WHOIS:
264 silc_fsm_next(fsm, silc_client_command_reply_whois);
266 case SILC_COMMAND_WHOWAS:
268 silc_fsm_next(fsm, silc_client_command_reply_whowas);
270 case SILC_COMMAND_IDENTIFY:
272 silc_fsm_next(fsm, silc_client_command_reply_identify);
274 case SILC_COMMAND_NICK:
276 silc_fsm_next(fsm, silc_client_command_reply_nick);
278 case SILC_COMMAND_LIST:
280 silc_fsm_next(fsm, silc_client_command_reply_list);
282 case SILC_COMMAND_TOPIC:
284 silc_fsm_next(fsm, silc_client_command_reply_topic);
286 case SILC_COMMAND_INVITE:
288 silc_fsm_next(fsm, silc_client_command_reply_invite);
290 case SILC_COMMAND_QUIT:
292 silc_fsm_next(fsm, silc_client_command_reply_quit);
294 case SILC_COMMAND_KILL:
296 silc_fsm_next(fsm, silc_client_command_reply_kill);
298 case SILC_COMMAND_INFO:
300 silc_fsm_next(fsm, silc_client_command_reply_info);
302 case SILC_COMMAND_STATS:
304 silc_fsm_next(fsm, silc_client_command_reply_stats);
306 case SILC_COMMAND_PING:
308 silc_fsm_next(fsm, silc_client_command_reply_ping);
310 case SILC_COMMAND_OPER:
312 silc_fsm_next(fsm, silc_client_command_reply_oper);
314 case SILC_COMMAND_JOIN:
316 silc_fsm_next(fsm, silc_client_command_reply_join);
318 case SILC_COMMAND_MOTD:
320 silc_fsm_next(fsm, silc_client_command_reply_motd);
322 case SILC_COMMAND_UMODE:
324 silc_fsm_next(fsm, silc_client_command_reply_umode);
326 case SILC_COMMAND_CMODE:
328 silc_fsm_next(fsm, silc_client_command_reply_cmode);
330 case SILC_COMMAND_CUMODE:
332 silc_fsm_next(fsm, silc_client_command_reply_cumode);
334 case SILC_COMMAND_KICK:
336 silc_fsm_next(fsm, silc_client_command_reply_kick);
338 case SILC_COMMAND_BAN:
340 silc_fsm_next(fsm, silc_client_command_reply_ban);
342 case SILC_COMMAND_DETACH:
344 silc_fsm_next(fsm, silc_client_command_reply_detach);
346 case SILC_COMMAND_WATCH:
348 silc_fsm_next(fsm, silc_client_command_reply_watch);
350 case SILC_COMMAND_SILCOPER:
352 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
354 case SILC_COMMAND_LEAVE:
356 silc_fsm_next(fsm, silc_client_command_reply_leave);
358 case SILC_COMMAND_USERS:
360 silc_fsm_next(fsm, silc_client_command_reply_users);
362 case SILC_COMMAND_GETKEY:
364 silc_fsm_next(fsm, silc_client_command_reply_getkey);
366 case SILC_COMMAND_SERVICE:
368 silc_fsm_next(fsm, silc_client_command_reply_service);
371 return SILC_FSM_FINISH;
374 return SILC_FSM_CONTINUE;
377 /* Completes command reply processing */
379 SILC_FSM_STATE(silc_client_command_reply_processed)
381 SilcClientCommandContext cmd = fsm_context;
382 SilcClientConnection conn = cmd->conn;
383 SilcCommandPayload payload = state_context;
385 silc_command_payload_free(payload);
387 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
388 SILC_STATUS_IS_ERROR(cmd->status))
389 return SILC_FSM_FINISH;
391 /* Add back to pending command reply list */
392 silc_mutex_lock(conn->internal->lock);
393 cmd->resolved = FALSE;
394 silc_list_add(conn->internal->pending_commands, cmd);
395 silc_mutex_unlock(conn->internal->lock);
397 /** Wait more command payloads */
398 silc_fsm_next(fsm, silc_client_command_reply_wait);
399 return SILC_FSM_CONTINUE;
402 /******************************** WHOIS *************************************/
404 /* Received reply for WHOIS command. */
406 SILC_FSM_STATE(silc_client_command_reply_whois)
408 SilcClientCommandContext cmd = fsm_context;
409 SilcClientConnection conn = cmd->conn;
410 SilcClient client = conn->client;
411 SilcCommandPayload payload = state_context;
412 SilcArgumentPayload args = silc_command_get_args(payload);
413 SilcClientEntry client_entry = NULL;
414 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
415 SilcBufferStruct channels, ch_user_modes;
416 SilcBool has_channels = FALSE;
417 SilcDList channel_list = NULL;
419 char *nickname = NULL, *username = NULL, *realname = NULL;
420 unsigned char *fingerprint, *tmp;
422 CHECK_STATUS("WHOIS: ");
426 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
427 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
432 nickname = silc_argument_get_arg_type(args, 3, NULL);
433 username = silc_argument_get_arg_type(args, 4, NULL);
434 realname = silc_argument_get_arg_type(args, 5, NULL);
435 if (!nickname || !username || !realname) {
436 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
440 /* Get joined channel list */
441 memset(&channels, 0, sizeof(channels));
442 tmp = silc_argument_get_arg_type(args, 6, &len);
445 silc_buffer_set(&channels, tmp, len);
447 /* Get channel user mode list */
448 tmp = silc_argument_get_arg_type(args, 10, &len);
450 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
453 silc_buffer_set(&ch_user_modes, tmp, len);
457 tmp = silc_argument_get_arg_type(args, 7, &len);
459 SILC_GET32_MSB(mode, tmp);
462 tmp = silc_argument_get_arg_type(args, 8, &len);
464 SILC_GET32_MSB(idle, tmp);
466 /* Get fingerprint */
467 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
469 /* Check if we have this client cached already. */
470 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
472 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
474 silc_client_add_client(client, conn, nickname, username, realname,
475 &id.u.client_id, mode);
477 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
480 silc_client_ref_client(client, conn, client_entry);
482 silc_client_update_client(client, conn, client_entry,
483 nickname, username, realname, mode);
486 silc_rwlock_wrlock(client_entry->internal.lock);
488 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
489 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
491 /* Get user attributes */
492 tmp = silc_argument_get_arg_type(args, 11, &len);
494 if (client_entry->attrs)
495 silc_attribute_payload_list_free(client_entry->attrs);
496 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
499 silc_rwlock_unlock(client_entry->internal.lock);
501 /* Parse channel and channel user mode list */
503 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
504 silc_buffer_len(&channels));
506 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
510 /* Notify application */
511 silc_client_command_callback(cmd, client_entry, nickname, username,
512 realname, channel_list, mode, idle, fingerprint,
513 umodes, client_entry->attrs);
515 silc_client_unref_client(client, conn, client_entry);
517 silc_channel_payload_list_free(channel_list);
522 silc_fsm_next(fsm, silc_client_command_reply_processed);
523 return SILC_FSM_CONTINUE;
526 /******************************** WHOWAS ************************************/
528 /* Received reply for WHOWAS command. */
530 SILC_FSM_STATE(silc_client_command_reply_whowas)
532 SilcClientCommandContext cmd = fsm_context;
533 SilcClientConnection conn = cmd->conn;
534 SilcClient client = conn->client;
535 SilcCommandPayload payload = state_context;
536 SilcArgumentPayload args = silc_command_get_args(payload);
537 SilcClientEntry client_entry = NULL;
539 char *nickname, *username;
540 char *realname = NULL;
542 CHECK_STATUS("WHOWAS: ");
546 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
547 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
551 /* Get the client entry */
552 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
555 nickname = silc_argument_get_arg_type(args, 3, NULL);
556 username = silc_argument_get_arg_type(args, 4, NULL);
557 realname = silc_argument_get_arg_type(args, 5, NULL);
558 if (!nickname || !username) {
559 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
563 /* Notify application. We don't save any history information to any
564 cache. Just pass the data to the application. */
565 silc_client_command_callback(cmd, client_entry, nickname, username,
569 silc_client_unref_client(client, conn, client_entry);
570 silc_fsm_next(fsm, silc_client_command_reply_processed);
571 return SILC_FSM_CONTINUE;
574 /******************************** IDENTIFY **********************************/
576 /* Received reply for IDENTIFY command. */
578 SILC_FSM_STATE(silc_client_command_reply_identify)
580 SilcClientCommandContext cmd = fsm_context;
581 SilcClientConnection conn = cmd->conn;
582 SilcClient client = conn->client;
583 SilcCommandPayload payload = state_context;
584 SilcArgumentPayload args = silc_command_get_args(payload);
585 SilcClientEntry client_entry;
586 SilcServerEntry server_entry;
587 SilcChannelEntry channel_entry;
590 char *name = NULL, *info = NULL;
592 CHECK_STATUS("IDENTIFY: ");
596 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
597 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
602 name = silc_argument_get_arg_type(args, 3, &len);
603 info = silc_argument_get_arg_type(args, 4, &len);
607 SILC_LOG_DEBUG(("Received client information"));
609 /* Check if we have this client cached already. */
610 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
612 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
614 silc_client_add_client(client, conn, name, info, NULL,
617 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
620 silc_client_ref_client(client, conn, client_entry);
622 silc_client_update_client(client, conn, client_entry,
623 name, info, NULL, 0);
626 /* Notify application */
627 silc_client_command_callback(cmd, client_entry, name, info);
628 silc_client_unref_client(client, conn, client_entry);
632 SILC_LOG_DEBUG(("Received server information"));
634 /* Check if we have this server cached already. */
635 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
637 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
638 server_entry = silc_client_add_server(client, conn, name, info,
641 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
644 silc_client_ref_server(client, conn, server_entry);
646 silc_client_update_server(client, conn, server_entry, name, info);
648 server_entry->internal.resolve_cmd_ident = 0;
650 /* Notify application */
651 silc_client_command_callback(cmd, server_entry, name, info);
652 silc_client_unref_server(client, conn, server_entry);
655 case SILC_ID_CHANNEL:
656 SILC_LOG_DEBUG(("Received channel information"));
658 /* Check if we have this channel cached already. */
659 channel_entry = silc_client_get_channel_by_id(client, conn,
661 if (!channel_entry) {
662 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
665 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
669 /* Add new channel entry */
670 channel_entry = silc_client_add_channel(client, conn, name, 0,
672 if (!channel_entry) {
673 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
676 silc_client_ref_channel(client, conn, channel_entry);
679 /* Notify application */
680 silc_client_command_callback(cmd, channel_entry,
681 channel_entry->channel_name, info);
682 silc_client_unref_channel(client, conn, channel_entry);
687 silc_fsm_next(fsm, silc_client_command_reply_processed);
688 return SILC_FSM_CONTINUE;
691 /********************************** NICK ************************************/
693 /* Received reply for command NICK. */
695 SILC_FSM_STATE(silc_client_command_reply_nick)
697 SilcClientCommandContext cmd = fsm_context;
698 SilcClientConnection conn = cmd->conn;
699 SilcClient client = conn->client;
700 SilcCommandPayload payload = state_context;
701 SilcArgumentPayload args = silc_command_get_args(payload);
702 unsigned char *nick, *idp;
703 SilcUInt32 len, idp_len;
704 SilcClientID old_client_id;
708 CHECK_STATUS("Cannot set nickname: ");
711 /* Take received Client ID */
712 idp = silc_argument_get_arg_type(args, 2, &idp_len);
714 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
717 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
718 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
722 /* Take the new nickname */
723 nick = silc_argument_get_arg_type(args, 3, &len);
725 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
729 silc_rwlock_wrlock(conn->local_entry->internal.lock);
731 /* Change the nickname */
732 old_client_id = *conn->local_id;
733 if (!silc_client_change_nickname(client, conn, conn->local_entry,
734 nick, &id.u.client_id, idp, idp_len)) {
735 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
736 silc_rwlock_unlock(conn->local_entry->internal.lock);
740 silc_rwlock_unlock(conn->local_entry->internal.lock);
742 /* Notify application */
743 silc_client_command_callback(cmd, conn->local_entry,
744 conn->local_entry->nickname, &old_client_id);
747 silc_fsm_next(fsm, silc_client_command_reply_processed);
748 return SILC_FSM_CONTINUE;
751 /********************************** LIST ************************************/
753 /* Received reply to the LIST command. */
755 SILC_FSM_STATE(silc_client_command_reply_list)
757 SilcClientCommandContext cmd = fsm_context;
758 SilcClientConnection conn = cmd->conn;
759 SilcClient client = conn->client;
760 SilcCommandPayload payload = state_context;
761 SilcArgumentPayload args = silc_command_get_args(payload);
762 unsigned char *tmp, *name, *topic;
763 SilcUInt32 usercount = 0;
764 SilcChannelEntry channel_entry = NULL;
768 CHECK_STATUS("Cannot list channels: ");
770 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
771 /* There were no channels in the network. */
772 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
773 silc_fsm_next(fsm, silc_client_command_reply_processed);
774 return SILC_FSM_CONTINUE;
779 name = silc_argument_get_arg_type(args, 3, NULL);
781 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
785 topic = silc_argument_get_arg_type(args, 4, NULL);
786 tmp = silc_argument_get_arg_type(args, 5, NULL);
788 SILC_GET32_MSB(usercount, tmp);
790 /* Check whether the channel exists, and add it to cache if it doesn't. */
791 channel_entry = silc_client_get_channel_by_id(client, conn,
793 if (!channel_entry) {
794 /* Add new channel entry */
795 channel_entry = silc_client_add_channel(client, conn, name, 0,
797 if (!channel_entry) {
798 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
801 silc_client_ref_channel(client, conn, channel_entry);
804 /* Notify application */
805 silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name,
809 silc_client_unref_channel(client, conn, channel_entry);
810 silc_fsm_next(fsm, silc_client_command_reply_processed);
811 return SILC_FSM_CONTINUE;
814 /********************************* TOPIC ************************************/
816 /* Received reply to topic command. */
818 SILC_FSM_STATE(silc_client_command_reply_topic)
820 SilcClientCommandContext cmd = fsm_context;
821 SilcClientConnection conn = cmd->conn;
822 SilcClient client = conn->client;
823 SilcCommandPayload payload = state_context;
824 SilcArgumentPayload args = silc_command_get_args(payload);
825 SilcChannelEntry channel;
831 CHECK_STATUS("Cannot set topic: ");
834 /* Take Channel ID */
835 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
836 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
840 /* Get the channel entry */
841 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
843 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
847 silc_rwlock_wrlock(channel->internal.lock);
850 topic = silc_argument_get_arg_type(args, 3, &len);
852 silc_free(channel->topic);
853 channel->topic = silc_memdup(topic, len);
856 silc_rwlock_unlock(channel->internal.lock);
858 /* Notify application */
859 silc_client_command_callback(cmd, channel, channel->topic);
862 silc_fsm_next(fsm, silc_client_command_reply_processed);
863 return SILC_FSM_CONTINUE;
866 /********************************* INVITE ***********************************/
868 /* Received reply to invite command. */
870 SILC_FSM_STATE(silc_client_command_reply_invite)
872 SilcClientCommandContext cmd = fsm_context;
873 SilcClientConnection conn = cmd->conn;
874 SilcClient client = conn->client;
875 SilcCommandPayload payload = state_context;
876 SilcArgumentPayload args = silc_command_get_args(payload);
877 SilcChannelEntry channel;
880 SilcArgumentPayload invite_args = NULL;
884 CHECK_STATUS("Cannot invite: ");
887 /* Take Channel ID */
888 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
889 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
893 /* Get the channel entry */
894 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
896 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
900 /* Get the invite list */
901 tmp = silc_argument_get_arg_type(args, 3, &len);
903 invite_args = silc_argument_list_parse(tmp, len);
905 /* Notify application */
906 silc_client_command_callback(cmd, channel, invite_args);
909 silc_argument_payload_free(invite_args);
912 silc_fsm_next(fsm, silc_client_command_reply_processed);
913 return SILC_FSM_CONTINUE;
916 /********************************** KILL ************************************/
918 /* Received reply to the KILL command. */
920 SILC_FSM_STATE(silc_client_command_reply_kill)
922 SilcClientCommandContext cmd = fsm_context;
923 SilcClientConnection conn = cmd->conn;
924 SilcClient client = conn->client;
925 SilcCommandPayload payload = state_context;
926 SilcArgumentPayload args = silc_command_get_args(payload);
927 SilcClientEntry client_entry;
931 CHECK_STATUS("Cannot kill: ");
934 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
935 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
939 /* Get the client entry, if exists */
940 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
942 /* Notify application */
943 silc_client_command_callback(cmd, client_entry);
945 /* Remove the client */
947 silc_client_remove_from_channels(client, conn, client_entry);
948 silc_client_del_client(client, conn, client_entry);
949 silc_client_unref_client(client, conn, client_entry);
953 silc_fsm_next(fsm, silc_client_command_reply_processed);
954 return SILC_FSM_CONTINUE;
957 /********************************** INFO ************************************/
959 /* Received reply to INFO command. We receive the server ID and some
960 information about the server user requested. */
962 SILC_FSM_STATE(silc_client_command_reply_info)
964 SilcClientCommandContext cmd = fsm_context;
965 SilcClientConnection conn = cmd->conn;
966 SilcClient client = conn->client;
967 SilcCommandPayload payload = state_context;
968 SilcArgumentPayload args = silc_command_get_args(payload);
969 SilcServerEntry server;
970 char *server_name, *server_info;
974 CHECK_STATUS("Cannot get info: ");
978 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
979 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
983 /* Get server name */
984 server_name = silc_argument_get_arg_type(args, 3, NULL);
986 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
990 /* Get server info */
991 server_info = silc_argument_get_arg_type(args, 4, NULL);
993 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
997 /* See whether we have this server cached. If not create it. */
998 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1000 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
1001 server = silc_client_add_server(client, conn, server_name,
1002 server_info, &id.u.server_id);
1005 silc_client_ref_server(client, conn, server);
1008 /* Notify application */
1009 silc_client_command_callback(cmd, server, server->server_name,
1010 server->server_info);
1011 silc_client_unref_server(client, conn, server);
1014 silc_fsm_next(fsm, silc_client_command_reply_processed);
1015 return SILC_FSM_CONTINUE;
1018 /********************************** STATS ***********************************/
1020 /* Received reply to STATS command. */
1022 SILC_FSM_STATE(silc_client_command_reply_stats)
1024 SilcClientCommandContext cmd = fsm_context;
1025 SilcCommandPayload payload = state_context;
1026 SilcArgumentPayload args = silc_command_get_args(payload);
1027 SilcClientStats stats;
1028 unsigned char *buf = NULL;
1029 SilcUInt32 buf_len = 0;
1034 CHECK_STATUS("Cannot get stats: ");
1038 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1039 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1043 /* Get statistics structure */
1044 memset(&stats, 0, sizeof(stats));
1045 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1047 silc_buffer_set(&b, buf, buf_len);
1048 silc_buffer_unformat(&b,
1049 SILC_STR_UI_INT(&stats.starttime),
1050 SILC_STR_UI_INT(&stats.uptime),
1051 SILC_STR_UI_INT(&stats.my_clients),
1052 SILC_STR_UI_INT(&stats.my_channels),
1053 SILC_STR_UI_INT(&stats.my_server_ops),
1054 SILC_STR_UI_INT(&stats.my_router_ops),
1055 SILC_STR_UI_INT(&stats.cell_clients),
1056 SILC_STR_UI_INT(&stats.cell_channels),
1057 SILC_STR_UI_INT(&stats.cell_servers),
1058 SILC_STR_UI_INT(&stats.clients),
1059 SILC_STR_UI_INT(&stats.channels),
1060 SILC_STR_UI_INT(&stats.servers),
1061 SILC_STR_UI_INT(&stats.routers),
1062 SILC_STR_UI_INT(&stats.server_ops),
1063 SILC_STR_UI_INT(&stats.router_ops),
1067 /* Notify application */
1068 silc_client_command_callback(cmd, &stats);
1071 silc_fsm_next(fsm, silc_client_command_reply_processed);
1072 return SILC_FSM_CONTINUE;
1075 /********************************** PING ************************************/
1077 /* Received reply to PING command. */
1079 SILC_FSM_STATE(silc_client_command_reply_ping)
1081 SilcClientCommandContext cmd = fsm_context;
1082 SilcClientConnection conn = cmd->conn;
1083 SilcClient client = conn->client;
1086 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1088 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1089 "Ping reply from %s: %d second%s", conn->remote_host,
1090 (int)diff, diff == 1 ? "" : "s");
1092 /* Notify application */
1093 silc_client_command_callback(cmd);
1095 silc_fsm_next(fsm, silc_client_command_reply_processed);
1096 return SILC_FSM_CONTINUE;
1099 /********************************** JOIN ************************************/
1101 /* Continue JOIN command reply processing after resolving unknown users */
1104 silc_client_command_reply_join_resolved(SilcClient client,
1105 SilcClientConnection conn,
1110 SilcClientCommandContext cmd = context;
1111 SilcChannelEntry channel = cmd->context;
1113 channel->internal.resolve_cmd_ident = 0;
1114 silc_client_unref_channel(client, conn, channel);
1116 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1120 /* Received reply for JOIN command. */
1122 SILC_FSM_STATE(silc_client_command_reply_join)
1124 SilcClientCommandContext cmd = fsm_context;
1125 SilcClientConnection conn = cmd->conn;
1126 SilcClient client = conn->client;
1127 SilcCommandPayload payload = state_context;
1128 SilcArgumentPayload args = silc_command_get_args(payload);
1129 SilcChannelEntry channel;
1130 SilcUInt32 mode = 0, len, list_count;
1131 char *topic, *tmp, *channel_name = NULL, *hmac;
1133 SilcBufferStruct client_id_list, client_mode_list, keyp;
1134 SilcHashTableList htl;
1139 CHECK_STATUS("Cannot join channel: ");
1142 /* Get channel name */
1143 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1144 if (!channel_name) {
1145 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1149 /* Get Channel ID */
1150 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1151 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1155 /* Check whether we have this channel entry already. */
1156 channel = silc_client_get_channel(client, conn, channel_name);
1158 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1159 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1161 /* Create new channel entry */
1162 channel = silc_client_add_channel(client, conn, channel_name,
1163 mode, &id.u.channel_id);
1165 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1168 silc_client_ref_channel(client, conn, channel);
1171 /* Get the list count */
1172 tmp = silc_argument_get_arg_type(args, 12, &len);
1174 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1177 SILC_GET32_MSB(list_count, tmp);
1179 /* Get Client ID list */
1180 tmp = silc_argument_get_arg_type(args, 13, &len);
1182 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1185 silc_buffer_set(&client_id_list, tmp, len);
1187 /* Resolve users we do not know about */
1188 if (!cmd->resolved) {
1189 cmd->resolved = TRUE;
1190 cmd->context = channel;
1191 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1192 silc_client_get_clients_by_list(
1193 client, conn, list_count, &client_id_list,
1194 silc_client_command_reply_join_resolved, cmd));
1198 /* Get client mode list */
1199 tmp = silc_argument_get_arg_type(args, 14, &len);
1201 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1204 silc_buffer_set(&client_mode_list, tmp, len);
1206 silc_rwlock_wrlock(channel->internal.lock);
1208 /* Add clients we received in the reply to the channel */
1209 for (i = 0; i < list_count; i++) {
1213 SilcClientEntry client_entry;
1216 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1218 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1222 SILC_GET32_MSB(mode, client_mode_list.data);
1224 /* Get client entry */
1225 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1226 if (client_entry && client_entry->internal.valid) {
1227 /* Join client to the channel */
1228 silc_rwlock_wrlock(client_entry->internal.lock);
1229 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1230 silc_rwlock_unlock(client_entry->internal.lock);
1232 silc_client_unref_client(client, conn, client_entry);
1234 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1235 silc_rwlock_unlock(channel->internal.lock);
1238 if (!silc_buffer_pull(&client_mode_list, 4)) {
1239 silc_rwlock_unlock(channel->internal.lock);
1245 hmac = silc_argument_get_arg_type(args, 11, NULL);
1247 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1249 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1250 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1251 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1252 silc_rwlock_unlock(channel->internal.lock);
1257 /* Get channel mode */
1258 tmp = silc_argument_get_arg_type(args, 5, &len);
1259 if (tmp && len == 4)
1260 SILC_GET32_MSB(mode, tmp);
1261 channel->mode = mode;
1263 /* Get channel key and save it */
1264 tmp = silc_argument_get_arg_type(args, 7, &len);
1266 silc_buffer_set(&keyp, tmp, len);
1267 silc_client_save_channel_key(client, conn, &keyp, channel);
1271 topic = silc_argument_get_arg_type(args, 10, NULL);
1273 silc_free(channel->topic);
1274 channel->topic = silc_memdup(topic, strlen(topic));
1277 /* Get founder key */
1278 tmp = silc_argument_get_arg_type(args, 15, &len);
1280 if (channel->founder_key)
1281 silc_pkcs_public_key_free(channel->founder_key);
1282 channel->founder_key = NULL;
1283 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1286 /* Get user limit */
1287 tmp = silc_argument_get_arg_type(args, 17, &len);
1288 if (tmp && len == 4)
1289 SILC_GET32_MSB(channel->user_limit, tmp);
1290 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1291 channel->user_limit = 0;
1293 /* Get channel public key list */
1294 tmp = silc_argument_get_arg_type(args, 16, &len);
1296 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1298 /* Set current channel */
1299 conn->current_channel = channel;
1301 silc_rwlock_unlock(channel->internal.lock);
1303 cipher = (channel->internal.send_key ?
1304 silc_cipher_get_name(channel->internal.send_key) : NULL);
1305 silc_hash_table_list(channel->user_list, &htl);
1307 /* Notify application */
1308 silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
1309 topic, cipher, hmac, channel->founder_key,
1310 channel->channel_pubkeys, channel->user_limit);
1312 silc_hash_table_list_reset(&htl);
1313 silc_client_unref_channel(client, conn, channel);
1316 silc_fsm_next(fsm, silc_client_command_reply_processed);
1317 return SILC_FSM_CONTINUE;
1320 /********************************** MOTD ************************************/
1322 /* Received reply for MOTD command */
1324 SILC_FSM_STATE(silc_client_command_reply_motd)
1326 SilcClientCommandContext cmd = fsm_context;
1327 SilcClientConnection conn = cmd->conn;
1328 SilcClient client = conn->client;
1329 SilcCommandPayload payload = state_context;
1330 SilcArgumentPayload args = silc_command_get_args(payload);
1332 char *motd = NULL, *cp, line[256];
1335 CHECK_STATUS("Cannot get motd: ");
1338 if (silc_argument_get_arg_num(args) == 3) {
1339 motd = silc_argument_get_arg_type(args, 3, NULL);
1341 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1348 if (cp[i++] == '\n') {
1349 memset(line, 0, sizeof(line));
1350 silc_strncat(line, sizeof(line), cp, i - 1);
1357 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1366 /* Notify application */
1367 silc_client_command_callback(cmd, motd);
1370 silc_fsm_next(fsm, silc_client_command_reply_processed);
1371 return SILC_FSM_CONTINUE;
1374 /********************************** UMODE ***********************************/
1376 /* Received reply to the UMODE command. Save the current user mode */
1378 SILC_FSM_STATE(silc_client_command_reply_umode)
1380 SilcClientCommandContext cmd = fsm_context;
1381 SilcClientConnection conn = cmd->conn;
1382 SilcCommandPayload payload = state_context;
1383 SilcArgumentPayload args = silc_command_get_args(payload);
1385 SilcUInt32 mode, len;
1388 CHECK_STATUS("Cannot change mode: ");
1391 tmp = silc_argument_get_arg_type(args, 2, &len);
1392 if (!tmp || len != 4) {
1393 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1397 SILC_GET32_MSB(mode, tmp);
1398 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1399 conn->local_entry->mode = mode;
1400 silc_rwlock_unlock(conn->local_entry->internal.lock);
1402 /* Notify application */
1403 silc_client_command_callback(cmd, mode);
1406 silc_fsm_next(fsm, silc_client_command_reply_processed);
1407 return SILC_FSM_CONTINUE;
1410 /********************************** CMODE ***********************************/
1412 /* Received reply for CMODE command. */
1414 SILC_FSM_STATE(silc_client_command_reply_cmode)
1416 SilcClientCommandContext cmd = fsm_context;
1417 SilcClientConnection conn = cmd->conn;
1418 SilcClient client = conn->client;
1419 SilcCommandPayload payload = state_context;
1420 SilcArgumentPayload args = silc_command_get_args(payload);
1423 SilcChannelEntry channel;
1425 SilcPublicKey public_key = NULL;
1429 CHECK_STATUS("Cannot change mode: ");
1432 /* Take Channel ID */
1433 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1434 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1438 /* Get the channel entry */
1439 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1441 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1445 /* Get founder public key */
1446 tmp = silc_argument_get_arg_type(args, 4, &len);
1448 silc_public_key_payload_decode(tmp, len, &public_key);
1450 /* Get channel mode */
1451 tmp = silc_argument_get_arg_type(args, 3, &len);
1452 if (!tmp || len != 4) {
1453 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1456 SILC_GET32_MSB(mode, tmp);
1458 silc_rwlock_wrlock(channel->internal.lock);
1460 /* Get user limit */
1461 tmp = silc_argument_get_arg_type(args, 6, &len);
1462 if (tmp && len == 4)
1463 SILC_GET32_MSB(channel->user_limit, tmp);
1464 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1465 channel->user_limit = 0;
1467 /* Get channel public key(s) */
1468 tmp = silc_argument_get_arg_type(args, 5, &len);
1470 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1471 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
1472 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
1475 channel->mode = mode;
1477 silc_rwlock_unlock(channel->internal.lock);
1479 /* Notify application */
1480 silc_client_command_callback(cmd, channel, mode, public_key,
1481 channel->channel_pubkeys, channel->user_limit);
1485 silc_pkcs_public_key_free(public_key);
1486 silc_fsm_next(fsm, silc_client_command_reply_processed);
1487 return SILC_FSM_CONTINUE;
1490 /********************************** CUMODE **********************************/
1492 /* Received reply for CUMODE command */
1494 SILC_FSM_STATE(silc_client_command_reply_cumode)
1496 SilcClientCommandContext cmd = fsm_context;
1497 SilcClientConnection conn = cmd->conn;
1498 SilcClient client = conn->client;
1499 SilcCommandPayload payload = state_context;
1500 SilcArgumentPayload args = silc_command_get_args(payload);
1501 SilcClientEntry client_entry;
1502 SilcChannelEntry channel;
1503 SilcChannelUser chu;
1504 unsigned char *modev;
1505 SilcUInt32 len, mode;
1509 CHECK_STATUS("Cannot change mode: ");
1512 /* Get channel mode */
1513 modev = silc_argument_get_arg_type(args, 2, &len);
1514 if (!modev || len != 4) {
1515 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1518 SILC_GET32_MSB(mode, modev);
1520 /* Take Channel ID */
1521 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1522 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1526 /* Get the channel entry */
1527 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1529 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1534 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1535 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1539 /* Get client entry */
1540 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1541 if (!client_entry) {
1542 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1547 silc_rwlock_wrlock(channel->internal.lock);
1548 chu = silc_client_on_channel(channel, client_entry);
1551 silc_rwlock_unlock(channel->internal.lock);
1553 /* Notify application */
1554 silc_client_command_callback(cmd, mode, channel, client_entry);
1556 silc_client_unref_client(client, conn, client_entry);
1559 silc_fsm_next(fsm, silc_client_command_reply_processed);
1560 return SILC_FSM_CONTINUE;
1563 /********************************** KICK ************************************/
1565 SILC_FSM_STATE(silc_client_command_reply_kick)
1567 SilcClientCommandContext cmd = fsm_context;
1568 SilcClientConnection conn = cmd->conn;
1569 SilcClient client = conn->client;
1570 SilcCommandPayload payload = state_context;
1571 SilcArgumentPayload args = silc_command_get_args(payload);
1572 SilcClientEntry client_entry;
1573 SilcChannelEntry channel;
1577 CHECK_STATUS("Cannot kick: ");
1580 /* Take Channel ID */
1581 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1582 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1586 /* Get the channel entry */
1587 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1589 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1594 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1595 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1599 /* Get client entry */
1600 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1601 if (!client_entry) {
1602 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1606 /* Notify application */
1607 silc_client_command_callback(cmd, channel, client_entry);
1609 silc_client_unref_client(client, conn, client_entry);
1612 silc_fsm_next(fsm, silc_client_command_reply_processed);
1613 return SILC_FSM_CONTINUE;
1616 /******************************** SILCOPER **********************************/
1618 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1620 SilcClientCommandContext cmd = fsm_context;
1621 SilcCommandPayload payload = state_context;
1622 SilcArgumentPayload args = silc_command_get_args(payload);
1625 CHECK_STATUS("Cannot change mode: ");
1629 cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1631 /* Notify application */
1632 silc_client_command_callback(cmd);
1634 silc_fsm_next(fsm, silc_client_command_reply_processed);
1635 return SILC_FSM_CONTINUE;
1638 /********************************** OPER ************************************/
1640 SILC_FSM_STATE(silc_client_command_reply_oper)
1642 SilcClientCommandContext cmd = fsm_context;
1643 SilcCommandPayload payload = state_context;
1644 SilcArgumentPayload args = silc_command_get_args(payload);
1647 CHECK_STATUS("Cannot change mode: ");
1651 cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1653 /* Notify application */
1654 silc_client_command_callback(cmd);
1656 silc_fsm_next(fsm, silc_client_command_reply_processed);
1657 return SILC_FSM_CONTINUE;
1660 /********************************* DETACH ***********************************/
1662 SILC_FSM_STATE(silc_client_command_reply_detach)
1664 SilcClientCommandContext cmd = fsm_context;
1665 SilcClientConnection conn = cmd->conn;
1666 SilcClient client = conn->client;
1667 SilcCommandPayload payload = state_context;
1668 SilcArgumentPayload args = silc_command_get_args(payload);
1672 CHECK_STATUS("Cannot detach: ");
1675 /* Get detachment data */
1676 detach = silc_client_get_detach_data(client, conn);
1678 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1682 /* Notify application */
1683 silc_client_command_callback(cmd, detach);
1684 silc_buffer_free(detach);
1687 silc_fsm_next(fsm, silc_client_command_reply_processed);
1688 return SILC_FSM_CONTINUE;
1691 /********************************** WATCH ***********************************/
1693 SILC_FSM_STATE(silc_client_command_reply_watch)
1695 SilcClientCommandContext cmd = fsm_context;
1696 SilcCommandPayload payload = state_context;
1697 SilcArgumentPayload args = silc_command_get_args(payload);
1700 CHECK_STATUS("Cannot set watch: ");
1703 /* Notify application */
1704 silc_client_command_callback(cmd);
1706 silc_fsm_next(fsm, silc_client_command_reply_processed);
1707 return SILC_FSM_CONTINUE;
1710 /*********************************** BAN ************************************/
1712 SILC_FSM_STATE(silc_client_command_reply_ban)
1714 SilcClientCommandContext cmd = fsm_context;
1715 SilcClientConnection conn = cmd->conn;
1716 SilcClient client = conn->client;
1717 SilcCommandPayload payload = state_context;
1718 SilcArgumentPayload args = silc_command_get_args(payload);
1719 SilcChannelEntry channel;
1722 SilcArgumentPayload invite_args = NULL;
1726 CHECK_STATUS("Cannot set ban: ");
1729 /* Take Channel ID */
1730 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1731 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1735 /* Get the channel entry */
1736 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1738 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1742 /* Get the invite list */
1743 tmp = silc_argument_get_arg_type(args, 3, &len);
1745 invite_args = silc_argument_list_parse(tmp, len);
1747 /* Notify application */
1748 silc_client_command_callback(cmd, channel, invite_args);
1751 silc_argument_payload_free(invite_args);
1754 silc_fsm_next(fsm, silc_client_command_reply_processed);
1755 return SILC_FSM_CONTINUE;
1758 /********************************** LEAVE ***********************************/
1760 /* Reply to LEAVE command. */
1762 SILC_FSM_STATE(silc_client_command_reply_leave)
1764 SilcClientCommandContext cmd = fsm_context;
1765 SilcClientConnection conn = cmd->conn;
1766 SilcClient client = conn->client;
1767 SilcCommandPayload payload = state_context;
1768 SilcArgumentPayload args = silc_command_get_args(payload);
1769 SilcChannelEntry channel;
1773 CHECK_STATUS("Cannot set leave: ");
1776 /* Get Channel ID */
1777 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1778 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1782 /* Get the channel entry */
1783 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1785 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1789 /* Remove us from this channel. */
1790 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1792 /* Notify application */
1793 silc_client_command_callback(cmd, channel);
1795 /* Now delete the channel. */
1796 silc_client_empty_channel(client, conn, channel);
1797 silc_client_del_channel(client, conn, channel);
1800 silc_fsm_next(fsm, silc_client_command_reply_processed);
1801 return SILC_FSM_CONTINUE;
1804 /********************************* USERS ************************************/
1806 /* Continue USERS command reply processing after resolving unknown users */
1809 silc_client_command_reply_users_resolved(SilcClient client,
1810 SilcClientConnection conn,
1815 SilcClientCommandContext cmd = context;
1816 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1820 /* Continue USERS command after resolving unknown channel */
1823 silc_client_command_reply_users_continue(SilcClient client,
1824 SilcClientConnection conn,
1829 SilcClientCommandContext cmd = context;
1832 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1833 SilcArgumentPayload args = silc_command_get_args(payload);
1835 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1836 ERROR_CALLBACK(cmd->status);
1837 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1840 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1843 /* Reply to USERS command. Received list of client ID's and theirs modes
1844 on the channel we requested. */
1846 SILC_FSM_STATE(silc_client_command_reply_users)
1848 SilcClientCommandContext cmd = fsm_context;
1849 SilcClientConnection conn = cmd->conn;
1850 SilcClient client = conn->client;
1851 SilcCommandPayload payload = state_context;
1852 SilcArgumentPayload args = silc_command_get_args(payload);
1854 SilcUInt32 tmp_len, list_count;
1855 SilcUInt16 idp_len, mode;
1856 SilcHashTableList htl;
1857 SilcBufferStruct client_id_list, client_mode_list;
1858 SilcChannelEntry channel = NULL;
1859 SilcClientEntry client_entry;
1864 CHECK_STATUS("Cannot get users: ");
1867 /* Get channel ID */
1868 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1869 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1873 /* Get channel entry */
1874 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1876 /* Resolve the channel from server */
1877 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1878 client, conn, &id.u.channel_id,
1879 silc_client_command_reply_users_continue, cmd));
1883 /* Get the list count */
1884 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1885 if (!tmp || tmp_len != 4) {
1886 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1889 SILC_GET32_MSB(list_count, tmp);
1891 /* Get Client ID list */
1892 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1894 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1897 silc_buffer_set(&client_id_list, tmp, tmp_len);
1899 /* Resolve users we do not know about */
1900 if (!cmd->resolved) {
1901 cmd->resolved = TRUE;
1902 silc_client_unref_channel(client, conn, channel);
1903 SILC_FSM_CALL(silc_client_get_clients_by_list(
1904 client, conn, list_count, &client_id_list,
1905 silc_client_command_reply_users_resolved, cmd));
1909 /* Get client mode list */
1910 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1912 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1915 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1917 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1919 silc_rwlock_wrlock(channel->internal.lock);
1921 /* Cache the received Client ID's and modes. */
1922 for (i = 0; i < list_count; i++) {
1923 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1925 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1929 SILC_GET32_MSB(mode, client_mode_list.data);
1931 /* Save the client on this channel. Unknown clients are ignored as they
1932 clearly do not exist since the resolving didn't find them. */
1933 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1934 if (client_entry && client_entry->internal.valid) {
1935 silc_rwlock_wrlock(client_entry->internal.lock);
1936 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1937 silc_rwlock_unlock(client_entry->internal.lock);
1939 silc_client_unref_client(client, conn, client_entry);
1941 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1942 silc_rwlock_unlock(channel->internal.lock);
1945 if (!silc_buffer_pull(&client_mode_list, 4)) {
1946 silc_rwlock_unlock(channel->internal.lock);
1951 silc_rwlock_unlock(channel->internal.lock);
1953 /* Notify application */
1954 silc_hash_table_list(channel->user_list, &htl);
1955 silc_client_command_callback(cmd, channel, &htl);
1956 silc_hash_table_list_reset(&htl);
1959 silc_client_unref_channel(client, conn, channel);
1960 silc_fsm_next(fsm, silc_client_command_reply_processed);
1961 return SILC_FSM_CONTINUE;
1964 /********************************** GETKEY **********************************/
1966 /* Received command reply to GETKEY command. WE've received the remote
1967 client's public key. */
1969 SILC_FSM_STATE(silc_client_command_reply_getkey)
1971 SilcClientCommandContext cmd = fsm_context;
1972 SilcClientConnection conn = cmd->conn;
1973 SilcClient client = conn->client;
1974 SilcCommandPayload payload = state_context;
1975 SilcArgumentPayload args = silc_command_get_args(payload);
1976 SilcClientEntry client_entry;
1977 SilcServerEntry server_entry;
1980 SilcPublicKey public_key;
1984 CHECK_STATUS("Cannot get key: ");
1988 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1989 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1993 /* Get the public key */
1994 tmp = silc_argument_get_arg_type(args, 3, &len);
1996 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1999 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
2000 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2004 if (id.type == SILC_ID_CLIENT) {
2005 /* Received client's public key */
2006 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2007 if (!client_entry) {
2008 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2012 silc_rwlock_wrlock(client_entry->internal.lock);
2014 /* Save fingerprint */
2015 if (!client_entry->fingerprint)
2016 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2017 client_entry->fingerprint);
2018 if (!client_entry->public_key) {
2019 client_entry->public_key = public_key;
2023 silc_rwlock_unlock(client_entry->internal.lock);
2025 /* Notify application */
2026 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2027 client_entry->public_key);
2028 silc_client_unref_client(client, conn, client_entry);
2029 } else if (id.type == SILC_ID_SERVER) {
2030 /* Received server's public key */
2031 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2032 if (!server_entry) {
2033 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2037 silc_rwlock_wrlock(server_entry->internal.lock);
2039 if (!server_entry->public_key) {
2040 server_entry->public_key = public_key;
2044 silc_rwlock_unlock(server_entry->internal.lock);
2046 /* Notify application */
2047 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2048 server_entry->public_key);
2049 silc_client_unref_server(client, conn, server_entry);
2054 silc_pkcs_public_key_free(public_key);
2055 silc_fsm_next(fsm, silc_client_command_reply_processed);
2056 return SILC_FSM_CONTINUE;
2059 /********************************** SERVICE *********************************/
2061 /* Reply to SERVICE command. */
2062 /* XXX incomplete */
2064 SILC_FSM_STATE(silc_client_command_reply_service)
2066 SilcClientCommandContext cmd = fsm_context;
2067 SilcCommandPayload payload = state_context;
2068 SilcArgumentPayload args = silc_command_get_args(payload);
2070 unsigned char *service_list, *name;
2073 CHECK_STATUS("Cannot get service: ");
2075 /* Get service list */
2076 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2078 /* Get requested service name */
2079 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2081 /* Notify application */
2082 silc_client_command_callback(cmd, service_list, name);
2084 silc_fsm_next(fsm, silc_client_command_reply_processed);
2085 return SILC_FSM_CONTINUE;
2088 /*********************************** QUIT ***********************************/
2090 /* QUIT command reply stub */
2092 SILC_FSM_STATE(silc_client_command_reply_quit)
2094 silc_fsm_next(fsm, silc_client_command_reply_processed);
2095 return SILC_FSM_CONTINUE;