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 client 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 client 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 ? 25 : 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_dlist_uninit(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, name, info);
681 silc_client_unref_channel(client, conn, channel_entry);
686 silc_fsm_next(fsm, silc_client_command_reply_processed);
687 return SILC_FSM_CONTINUE;
690 /********************************** NICK ************************************/
692 /* Received reply for command NICK. */
694 SILC_FSM_STATE(silc_client_command_reply_nick)
696 SilcClientCommandContext cmd = fsm_context;
697 SilcClientConnection conn = cmd->conn;
698 SilcClient client = conn->client;
699 SilcCommandPayload payload = state_context;
700 SilcArgumentPayload args = silc_command_get_args(payload);
701 unsigned char *nick, *idp;
702 SilcUInt32 len, idp_len;
703 SilcClientID old_client_id;
707 CHECK_STATUS("Cannot set nickname: ");
710 /* Take received Client ID */
711 idp = silc_argument_get_arg_type(args, 2, &idp_len);
713 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
716 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
717 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
721 /* Take the new nickname */
722 nick = silc_argument_get_arg_type(args, 3, &len);
724 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
728 silc_rwlock_wrlock(conn->local_entry->internal.lock);
730 /* Change the nickname */
731 old_client_id = *conn->local_id;
732 if (!silc_client_change_nickname(client, conn, conn->local_entry,
733 nick, &id.u.client_id, idp, idp_len)) {
734 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
738 silc_rwlock_unlock(conn->local_entry->internal.lock);
740 /* Notify application */
741 silc_client_command_callback(cmd, conn->local_entry,
742 conn->local_entry->nickname, &old_client_id);
745 silc_fsm_next(fsm, silc_client_command_reply_processed);
746 return SILC_FSM_CONTINUE;
749 /********************************** LIST ************************************/
751 /* Received reply to the LIST command. */
753 SILC_FSM_STATE(silc_client_command_reply_list)
755 SilcClientCommandContext cmd = fsm_context;
756 SilcClientConnection conn = cmd->conn;
757 SilcClient client = conn->client;
758 SilcCommandPayload payload = state_context;
759 SilcArgumentPayload args = silc_command_get_args(payload);
760 unsigned char *tmp, *name, *topic;
761 SilcUInt32 usercount = 0;
762 SilcChannelEntry channel_entry = NULL;
766 CHECK_STATUS("Cannot list channels: ");
768 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
769 /* There were no channels in the network. */
770 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
771 silc_fsm_next(fsm, silc_client_command_reply_processed);
772 return SILC_FSM_CONTINUE;
777 name = silc_argument_get_arg_type(args, 3, NULL);
779 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
783 topic = silc_argument_get_arg_type(args, 4, NULL);
784 tmp = silc_argument_get_arg_type(args, 5, NULL);
786 SILC_GET32_MSB(usercount, tmp);
788 /* Check whether the channel exists, and add it to cache if it doesn't. */
789 channel_entry = silc_client_get_channel_by_id(client, conn,
791 if (!channel_entry) {
792 /* Add new channel entry */
793 channel_entry = silc_client_add_channel(client, conn, name, 0,
795 if (!channel_entry) {
796 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
799 silc_client_ref_channel(client, conn, channel_entry);
802 /* Notify application */
803 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
806 silc_client_unref_channel(client, conn, channel_entry);
807 silc_fsm_next(fsm, silc_client_command_reply_processed);
808 return SILC_FSM_CONTINUE;
811 /********************************* TOPIC ************************************/
813 /* Received reply to topic command. */
815 SILC_FSM_STATE(silc_client_command_reply_topic)
817 SilcClientCommandContext cmd = fsm_context;
818 SilcClientConnection conn = cmd->conn;
819 SilcClient client = conn->client;
820 SilcCommandPayload payload = state_context;
821 SilcArgumentPayload args = silc_command_get_args(payload);
822 SilcChannelEntry channel;
828 CHECK_STATUS("Cannot set topic: ");
831 /* Take Channel ID */
832 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
833 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
837 /* Get the channel entry */
838 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
840 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
844 silc_rwlock_wrlock(channel->internal.lock);
847 topic = silc_argument_get_arg_type(args, 3, &len);
849 silc_free(channel->topic);
850 channel->topic = silc_memdup(topic, len);
853 silc_rwlock_unlock(channel->internal.lock);
855 /* Notify application */
856 silc_client_command_callback(cmd, channel, channel->topic);
859 silc_fsm_next(fsm, silc_client_command_reply_processed);
860 return SILC_FSM_CONTINUE;
863 /********************************* INVITE ***********************************/
865 /* Received reply to invite command. */
867 SILC_FSM_STATE(silc_client_command_reply_invite)
869 SilcClientCommandContext cmd = fsm_context;
870 SilcClientConnection conn = cmd->conn;
871 SilcClient client = conn->client;
872 SilcCommandPayload payload = state_context;
873 SilcArgumentPayload args = silc_command_get_args(payload);
874 SilcChannelEntry channel;
877 SilcArgumentPayload invite_args = NULL;
881 CHECK_STATUS("Cannot invite: ");
884 /* Take Channel ID */
885 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
886 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
890 /* Get the channel entry */
891 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
893 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
897 /* Get the invite list */
898 tmp = silc_argument_get_arg_type(args, 3, &len);
900 invite_args = silc_argument_list_parse(tmp, len);
902 /* Notify application */
903 silc_client_command_callback(cmd, channel, invite_args);
906 silc_argument_payload_free(invite_args);
909 silc_fsm_next(fsm, silc_client_command_reply_processed);
910 return SILC_FSM_CONTINUE;
913 /********************************** KILL ************************************/
915 /* Received reply to the KILL command. */
917 SILC_FSM_STATE(silc_client_command_reply_kill)
919 SilcClientCommandContext cmd = fsm_context;
920 SilcClientConnection conn = cmd->conn;
921 SilcClient client = conn->client;
922 SilcCommandPayload payload = state_context;
923 SilcArgumentPayload args = silc_command_get_args(payload);
924 SilcClientEntry client_entry;
928 CHECK_STATUS("Cannot kill: ");
931 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
932 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
936 /* Get the client entry, if exists */
937 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
939 /* Notify application */
940 silc_client_command_callback(cmd, client_entry);
942 /* Remove the client */
944 silc_client_remove_from_channels(client, conn, client_entry);
945 silc_client_del_client(client, conn, client_entry);
946 silc_client_unref_client(client, conn, client_entry);
950 silc_fsm_next(fsm, silc_client_command_reply_processed);
951 return SILC_FSM_CONTINUE;
954 /********************************** INFO ************************************/
956 /* Received reply to INFO command. We receive the server ID and some
957 information about the server user requested. */
959 SILC_FSM_STATE(silc_client_command_reply_info)
961 SilcClientCommandContext cmd = fsm_context;
962 SilcClientConnection conn = cmd->conn;
963 SilcClient client = conn->client;
964 SilcCommandPayload payload = state_context;
965 SilcArgumentPayload args = silc_command_get_args(payload);
966 SilcServerEntry server;
967 char *server_name, *server_info;
971 CHECK_STATUS("Cannot get info: ");
975 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
976 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
980 /* Get server name */
981 server_name = silc_argument_get_arg_type(args, 3, NULL);
983 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
987 /* Get server info */
988 server_info = silc_argument_get_arg_type(args, 4, NULL);
990 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
994 /* See whether we have this server cached. If not create it. */
995 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
997 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
998 server = silc_client_add_server(client, conn, server_name,
999 server_info, &id.u.server_id);
1002 silc_client_ref_server(client, conn, server);
1005 /* Notify application */
1006 silc_client_command_callback(cmd, server, server->server_name,
1007 server->server_info);
1008 silc_client_unref_server(client, conn, server);
1011 silc_fsm_next(fsm, silc_client_command_reply_processed);
1012 return SILC_FSM_CONTINUE;
1015 /********************************** STATS ***********************************/
1017 /* Received reply to STATS command. */
1019 SILC_FSM_STATE(silc_client_command_reply_stats)
1021 SilcClientCommandContext cmd = fsm_context;
1022 SilcCommandPayload payload = state_context;
1023 SilcArgumentPayload args = silc_command_get_args(payload);
1024 SilcClientStats stats;
1025 unsigned char *buf = NULL;
1026 SilcUInt32 buf_len = 0;
1031 CHECK_STATUS("Cannot get stats: ");
1035 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1036 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1040 /* Get statistics structure */
1041 memset(&stats, 0, sizeof(stats));
1042 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1044 silc_buffer_set(&b, buf, buf_len);
1045 silc_buffer_unformat(&b,
1046 SILC_STR_UI_INT(&stats.starttime),
1047 SILC_STR_UI_INT(&stats.uptime),
1048 SILC_STR_UI_INT(&stats.my_clients),
1049 SILC_STR_UI_INT(&stats.my_channels),
1050 SILC_STR_UI_INT(&stats.my_server_ops),
1051 SILC_STR_UI_INT(&stats.my_router_ops),
1052 SILC_STR_UI_INT(&stats.cell_clients),
1053 SILC_STR_UI_INT(&stats.cell_channels),
1054 SILC_STR_UI_INT(&stats.cell_servers),
1055 SILC_STR_UI_INT(&stats.clients),
1056 SILC_STR_UI_INT(&stats.channels),
1057 SILC_STR_UI_INT(&stats.servers),
1058 SILC_STR_UI_INT(&stats.routers),
1059 SILC_STR_UI_INT(&stats.server_ops),
1060 SILC_STR_UI_INT(&stats.router_ops),
1064 /* Notify application */
1065 silc_client_command_callback(cmd, &stats);
1068 silc_fsm_next(fsm, silc_client_command_reply_processed);
1069 return SILC_FSM_CONTINUE;
1072 /********************************** PING ************************************/
1074 /* Received reply to PING command. */
1076 SILC_FSM_STATE(silc_client_command_reply_ping)
1078 SilcClientCommandContext cmd = fsm_context;
1079 SilcClientConnection conn = cmd->conn;
1080 SilcClient client = conn->client;
1083 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1085 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1086 "Ping reply from %s: %d second%s", conn->remote_host,
1087 (int)diff, diff == 1 ? "" : "s");
1089 /* Notify application */
1090 silc_client_command_callback(cmd);
1092 silc_fsm_next(fsm, silc_client_command_reply_processed);
1093 return SILC_FSM_CONTINUE;
1096 /********************************** JOIN ************************************/
1098 /* Continue JOIN command reply processing after resolving unknown users */
1101 silc_client_command_reply_join_resolved(SilcClient client,
1102 SilcClientConnection conn,
1107 SilcClientCommandContext cmd = context;
1108 SilcChannelEntry channel = cmd->context;
1110 channel->internal.resolve_cmd_ident = 0;
1111 silc_client_unref_channel(client, conn, channel);
1113 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1117 /* Received reply for JOIN command. */
1119 SILC_FSM_STATE(silc_client_command_reply_join)
1121 SilcClientCommandContext cmd = fsm_context;
1122 SilcClientConnection conn = cmd->conn;
1123 SilcClient client = conn->client;
1124 SilcCommandPayload payload = state_context;
1125 SilcArgumentPayload args = silc_command_get_args(payload);
1126 SilcChannelEntry channel;
1127 SilcUInt32 mode = 0, len, list_count;
1128 char *topic, *tmp, *channel_name = NULL, *hmac;
1130 SilcBufferStruct client_id_list, client_mode_list, keyp;
1131 SilcHashTableList htl;
1136 CHECK_STATUS("Cannot join channel: ");
1139 /* Get channel name */
1140 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1141 if (!channel_name) {
1142 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1146 /* Get Channel ID */
1147 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1148 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1152 /* Check whether we have this channel entry already. */
1153 channel = silc_client_get_channel(client, conn, channel_name);
1155 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1156 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1158 /* Create new channel entry */
1159 channel = silc_client_add_channel(client, conn, channel_name,
1160 mode, &id.u.channel_id);
1162 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1165 silc_client_ref_channel(client, conn, channel);
1168 /* Get the list count */
1169 tmp = silc_argument_get_arg_type(args, 12, &len);
1171 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1174 SILC_GET32_MSB(list_count, tmp);
1176 /* Get Client ID list */
1177 tmp = silc_argument_get_arg_type(args, 13, &len);
1179 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1182 silc_buffer_set(&client_id_list, tmp, len);
1184 /* Resolve users we do not know about */
1185 if (!cmd->resolved) {
1186 cmd->resolved = TRUE;
1187 cmd->context = channel;
1188 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1189 silc_client_get_clients_by_list(
1190 client, conn, list_count, &client_id_list,
1191 silc_client_command_reply_join_resolved, cmd));
1195 /* Get client mode list */
1196 tmp = silc_argument_get_arg_type(args, 14, &len);
1198 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1201 silc_buffer_set(&client_mode_list, tmp, len);
1203 silc_rwlock_wrlock(channel->internal.lock);
1205 /* Add clients we received in the reply to the channel */
1206 for (i = 0; i < list_count; i++) {
1210 SilcClientEntry client_entry;
1213 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1215 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1219 SILC_GET32_MSB(mode, client_mode_list.data);
1221 /* Get client entry */
1222 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1223 if (client_entry && client_entry->internal.valid) {
1224 /* Join client to the channel */
1225 silc_rwlock_wrlock(client_entry->internal.lock);
1226 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1227 silc_rwlock_unlock(client_entry->internal.lock);
1229 silc_client_unref_client(client, conn, client_entry);
1231 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1232 silc_rwlock_unlock(channel->internal.lock);
1235 if (!silc_buffer_pull(&client_mode_list, 4)) {
1236 silc_rwlock_unlock(channel->internal.lock);
1242 hmac = silc_argument_get_arg_type(args, 11, NULL);
1244 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1246 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1247 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1248 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1249 silc_rwlock_unlock(channel->internal.lock);
1254 /* Get channel mode */
1255 tmp = silc_argument_get_arg_type(args, 5, NULL);
1257 SILC_GET32_MSB(mode, tmp);
1258 channel->mode = mode;
1260 /* Get channel key and save it */
1261 tmp = silc_argument_get_arg_type(args, 7, &len);
1263 silc_buffer_set(&keyp, tmp, len);
1264 silc_client_save_channel_key(client, conn, &keyp, channel);
1268 topic = silc_argument_get_arg_type(args, 10, NULL);
1270 silc_free(channel->topic);
1271 channel->topic = silc_memdup(topic, strlen(topic));
1274 /* Get founder key */
1275 tmp = silc_argument_get_arg_type(args, 15, &len);
1277 if (channel->founder_key)
1278 silc_pkcs_public_key_free(channel->founder_key);
1279 channel->founder_key = NULL;
1280 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1283 /* Get user limit */
1284 tmp = silc_argument_get_arg_type(args, 17, &len);
1285 if (tmp && len == 4)
1286 SILC_GET32_MSB(channel->user_limit, tmp);
1287 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1288 channel->user_limit = 0;
1290 /* Get channel public key list */
1291 tmp = silc_argument_get_arg_type(args, 16, &len);
1293 silc_client_channel_save_public_keys(channel, tmp, len);
1295 /* Set current channel */
1296 conn->current_channel = channel;
1298 silc_rwlock_unlock(channel->internal.lock);
1300 cipher = (channel->internal.send_key ?
1301 silc_cipher_get_name(channel->internal.send_key) : NULL);
1302 silc_hash_table_list(channel->user_list, &htl);
1304 /* Notify application */
1305 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1306 topic, cipher, hmac, channel->founder_key,
1307 channel->channel_pubkeys, channel->user_limit);
1309 silc_hash_table_list_reset(&htl);
1310 silc_client_unref_channel(client, conn, channel);
1313 silc_fsm_next(fsm, silc_client_command_reply_processed);
1314 return SILC_FSM_CONTINUE;
1317 /********************************** MOTD ************************************/
1319 /* Received reply for MOTD command */
1321 SILC_FSM_STATE(silc_client_command_reply_motd)
1323 SilcClientCommandContext cmd = fsm_context;
1324 SilcClientConnection conn = cmd->conn;
1325 SilcClient client = conn->client;
1326 SilcCommandPayload payload = state_context;
1327 SilcArgumentPayload args = silc_command_get_args(payload);
1329 char *motd = NULL, *cp, line[256];
1332 CHECK_STATUS("Cannot get motd: ");
1335 if (silc_argument_get_arg_num(args) == 3) {
1336 motd = silc_argument_get_arg_type(args, 3, NULL);
1338 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1345 if (cp[i++] == '\n') {
1346 memset(line, 0, sizeof(line));
1347 silc_strncat(line, sizeof(line), cp, i - 1);
1354 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1363 /* Notify application */
1364 silc_client_command_callback(cmd, motd);
1367 silc_fsm_next(fsm, silc_client_command_reply_processed);
1368 return SILC_FSM_CONTINUE;
1371 /********************************** UMODE ***********************************/
1373 /* Received reply to the UMODE command. Save the current user mode */
1375 SILC_FSM_STATE(silc_client_command_reply_umode)
1377 SilcClientCommandContext cmd = fsm_context;
1378 SilcClientConnection conn = cmd->conn;
1379 SilcCommandPayload payload = state_context;
1380 SilcArgumentPayload args = silc_command_get_args(payload);
1382 SilcUInt32 mode, len;
1385 CHECK_STATUS("Cannot change mode: ");
1388 tmp = silc_argument_get_arg_type(args, 2, &len);
1389 if (!tmp || len != 4) {
1390 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1394 SILC_GET32_MSB(mode, tmp);
1395 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1396 conn->local_entry->mode = mode;
1397 silc_rwlock_unlock(conn->local_entry->internal.lock);
1399 /* Notify application */
1400 silc_client_command_callback(cmd, mode);
1403 silc_fsm_next(fsm, silc_client_command_reply_processed);
1404 return SILC_FSM_CONTINUE;
1407 /********************************** CMODE ***********************************/
1409 /* Received reply for CMODE command. */
1411 SILC_FSM_STATE(silc_client_command_reply_cmode)
1413 SilcClientCommandContext cmd = fsm_context;
1414 SilcClientConnection conn = cmd->conn;
1415 SilcClient client = conn->client;
1416 SilcCommandPayload payload = state_context;
1417 SilcArgumentPayload args = silc_command_get_args(payload);
1420 SilcChannelEntry channel;
1422 SilcPublicKey public_key = NULL;
1423 SilcDList channel_pubkeys = NULL;
1427 CHECK_STATUS("Cannot change mode: ");
1430 /* Take Channel ID */
1431 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1432 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1436 /* Get the channel entry */
1437 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1439 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1443 /* Get channel mode */
1444 tmp = silc_argument_get_arg_type(args, 3, &len);
1445 if (!tmp || len != 4) {
1446 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1450 /* Get founder public key */
1451 tmp = silc_argument_get_arg_type(args, 4, &len);
1453 silc_public_key_payload_decode(tmp, len, &public_key);
1455 silc_rwlock_wrlock(channel->internal.lock);
1458 SILC_GET32_MSB(mode, tmp);
1459 channel->mode = mode;
1461 /* Get user limit */
1462 tmp = silc_argument_get_arg_type(args, 6, &len);
1463 if (tmp && len == 4)
1464 SILC_GET32_MSB(channel->user_limit, tmp);
1465 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1466 channel->user_limit = 0;
1468 /* Get channel public key(s) */
1469 tmp = silc_argument_get_arg_type(args, 5, &len);
1471 silc_client_channel_save_public_keys(channel, tmp, len);
1473 silc_rwlock_unlock(channel->internal.lock);
1475 /* Notify application */
1476 silc_client_command_callback(cmd, channel, mode, public_key,
1477 channel_pubkeys, channel->user_limit);
1479 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1483 silc_pkcs_public_key_free(public_key);
1484 silc_fsm_next(fsm, silc_client_command_reply_processed);
1485 return SILC_FSM_CONTINUE;
1488 /********************************** CUMODE **********************************/
1490 /* Received reply for CUMODE command */
1492 SILC_FSM_STATE(silc_client_command_reply_cumode)
1494 SilcClientCommandContext cmd = fsm_context;
1495 SilcClientConnection conn = cmd->conn;
1496 SilcClient client = conn->client;
1497 SilcCommandPayload payload = state_context;
1498 SilcArgumentPayload args = silc_command_get_args(payload);
1499 SilcClientEntry client_entry;
1500 SilcChannelEntry channel;
1501 SilcChannelUser chu;
1502 unsigned char *modev;
1503 SilcUInt32 len, mode;
1507 CHECK_STATUS("Cannot change mode: ");
1510 /* Get channel mode */
1511 modev = silc_argument_get_arg_type(args, 2, &len);
1512 if (!modev || len != 4) {
1513 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1516 SILC_GET32_MSB(mode, modev);
1518 /* Take Channel ID */
1519 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1520 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1524 /* Get the channel entry */
1525 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1527 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1532 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1533 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1537 /* Get client entry */
1538 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1539 if (!client_entry) {
1540 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1545 silc_rwlock_wrlock(channel->internal.lock);
1546 chu = silc_client_on_channel(channel, client_entry);
1549 silc_rwlock_unlock(channel->internal.lock);
1551 /* Notify application */
1552 silc_client_command_callback(cmd, mode, channel, client_entry);
1554 silc_client_unref_client(client, conn, client_entry);
1557 silc_fsm_next(fsm, silc_client_command_reply_processed);
1558 return SILC_FSM_CONTINUE;
1561 /********************************** KICK ************************************/
1563 SILC_FSM_STATE(silc_client_command_reply_kick)
1565 SilcClientCommandContext cmd = fsm_context;
1566 SilcClientConnection conn = cmd->conn;
1567 SilcClient client = conn->client;
1568 SilcCommandPayload payload = state_context;
1569 SilcArgumentPayload args = silc_command_get_args(payload);
1570 SilcClientEntry client_entry;
1571 SilcChannelEntry channel;
1575 CHECK_STATUS("Cannot kick: ");
1578 /* Take Channel ID */
1579 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1580 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1584 /* Get the channel entry */
1585 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1587 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1592 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1593 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1597 /* Get client entry */
1598 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1599 if (!client_entry) {
1600 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1604 /* Notify application */
1605 silc_client_command_callback(cmd, channel, client_entry);
1607 silc_client_unref_client(client, conn, client_entry);
1610 silc_fsm_next(fsm, silc_client_command_reply_processed);
1611 return SILC_FSM_CONTINUE;
1614 /******************************** SILCOPER **********************************/
1616 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1618 SilcClientCommandContext cmd = fsm_context;
1619 SilcCommandPayload payload = state_context;
1620 SilcArgumentPayload args = silc_command_get_args(payload);
1623 CHECK_STATUS("Cannot change mode: ");
1626 /* Notify application */
1627 silc_client_command_callback(cmd);
1629 silc_fsm_next(fsm, silc_client_command_reply_processed);
1630 return SILC_FSM_CONTINUE;
1633 /********************************** OPER ************************************/
1635 SILC_FSM_STATE(silc_client_command_reply_oper)
1637 SilcClientCommandContext cmd = fsm_context;
1638 SilcCommandPayload payload = state_context;
1639 SilcArgumentPayload args = silc_command_get_args(payload);
1642 CHECK_STATUS("Cannot change mode: ");
1645 /* Notify application */
1646 silc_client_command_callback(cmd);
1648 silc_fsm_next(fsm, silc_client_command_reply_processed);
1649 return SILC_FSM_CONTINUE;
1652 /********************************* DETACH ***********************************/
1654 SILC_FSM_STATE(silc_client_command_reply_detach)
1656 SilcClientCommandContext cmd = fsm_context;
1657 SilcClientConnection conn = cmd->conn;
1658 SilcClient client = conn->client;
1659 SilcCommandPayload payload = state_context;
1660 SilcArgumentPayload args = silc_command_get_args(payload);
1664 CHECK_STATUS("Cannot detach: ");
1667 /* Get detachment data */
1668 detach = silc_client_get_detach_data(client, conn);
1670 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1674 /* Notify application */
1675 silc_client_command_callback(cmd, detach);
1676 silc_buffer_free(detach);
1679 silc_fsm_next(fsm, silc_client_command_reply_processed);
1680 return SILC_FSM_CONTINUE;
1683 /********************************** WATCH ***********************************/
1685 SILC_FSM_STATE(silc_client_command_reply_watch)
1687 SilcClientCommandContext cmd = fsm_context;
1688 SilcCommandPayload payload = state_context;
1689 SilcArgumentPayload args = silc_command_get_args(payload);
1692 CHECK_STATUS("Cannot set watch: ");
1695 /* Notify application */
1696 silc_client_command_callback(cmd);
1698 silc_fsm_next(fsm, silc_client_command_reply_processed);
1699 return SILC_FSM_CONTINUE;
1702 /*********************************** BAN ************************************/
1704 SILC_FSM_STATE(silc_client_command_reply_ban)
1706 SilcClientCommandContext cmd = fsm_context;
1707 SilcClientConnection conn = cmd->conn;
1708 SilcClient client = conn->client;
1709 SilcCommandPayload payload = state_context;
1710 SilcArgumentPayload args = silc_command_get_args(payload);
1711 SilcChannelEntry channel;
1714 SilcArgumentPayload invite_args = NULL;
1718 CHECK_STATUS("Cannot set ban: ");
1721 /* Take Channel ID */
1722 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1723 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1727 /* Get the channel entry */
1728 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1730 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1734 /* Get the invite list */
1735 tmp = silc_argument_get_arg_type(args, 3, &len);
1737 invite_args = silc_argument_list_parse(tmp, len);
1739 /* Notify application */
1740 silc_client_command_callback(cmd, channel, invite_args);
1743 silc_argument_payload_free(invite_args);
1746 silc_fsm_next(fsm, silc_client_command_reply_processed);
1747 return SILC_FSM_CONTINUE;
1750 /********************************** LEAVE ***********************************/
1752 /* Reply to LEAVE command. */
1754 SILC_FSM_STATE(silc_client_command_reply_leave)
1756 SilcClientCommandContext cmd = fsm_context;
1757 SilcClientConnection conn = cmd->conn;
1758 SilcClient client = conn->client;
1759 SilcCommandPayload payload = state_context;
1760 SilcArgumentPayload args = silc_command_get_args(payload);
1761 SilcChannelEntry channel;
1765 CHECK_STATUS("Cannot set leave: ");
1768 /* Get Channel ID */
1769 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1770 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1774 /* Get the channel entry */
1775 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1777 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1781 /* Remove us from this channel. */
1782 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1784 /* Notify application */
1785 silc_client_command_callback(cmd, channel);
1787 /* Now delete the channel. */
1788 silc_client_empty_channel(client, conn, channel);
1789 silc_client_del_channel(client, conn, channel);
1792 silc_fsm_next(fsm, silc_client_command_reply_processed);
1793 return SILC_FSM_CONTINUE;
1796 /********************************* USERS ************************************/
1798 /* Continue USERS command reply processing after resolving unknown users */
1801 silc_client_command_reply_users_resolved(SilcClient client,
1802 SilcClientConnection conn,
1807 SilcClientCommandContext cmd = context;
1808 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1812 /* Continue USERS command after resolving unknown channel */
1815 silc_client_command_reply_users_continue(SilcClient client,
1816 SilcClientConnection conn,
1821 SilcClientCommandContext cmd = context;
1824 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1825 SilcArgumentPayload args = silc_command_get_args(payload);
1827 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1828 ERROR_CALLBACK(cmd->status);
1829 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1832 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1835 /* Reply to USERS command. Received list of client ID's and theirs modes
1836 on the channel we requested. */
1838 SILC_FSM_STATE(silc_client_command_reply_users)
1840 SilcClientCommandContext cmd = fsm_context;
1841 SilcClientConnection conn = cmd->conn;
1842 SilcClient client = conn->client;
1843 SilcCommandPayload payload = state_context;
1844 SilcArgumentPayload args = silc_command_get_args(payload);
1846 SilcUInt32 tmp_len, list_count;
1847 SilcUInt16 idp_len, mode;
1848 SilcHashTableList htl;
1849 SilcBufferStruct client_id_list, client_mode_list;
1850 SilcChannelEntry channel = NULL;
1851 SilcClientEntry client_entry;
1856 CHECK_STATUS("Cannot get users: ");
1859 /* Get channel ID */
1860 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1861 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1865 /* Get channel entry */
1866 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1868 /* Resolve the channel from server */
1869 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1870 client, conn, &id.u.channel_id,
1871 silc_client_command_reply_users_continue, cmd));
1875 /* Get the list count */
1876 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1877 if (!tmp || tmp_len != 4) {
1878 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1881 SILC_GET32_MSB(list_count, tmp);
1883 /* Get Client ID list */
1884 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1886 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1889 silc_buffer_set(&client_id_list, tmp, tmp_len);
1891 /* Resolve users we do not know about */
1892 if (!cmd->resolved) {
1893 cmd->resolved = TRUE;
1894 silc_client_unref_channel(client, conn, channel);
1895 SILC_FSM_CALL(silc_client_get_clients_by_list(
1896 client, conn, list_count, &client_id_list,
1897 silc_client_command_reply_users_resolved, cmd));
1901 /* Get client mode list */
1902 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1904 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1907 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1909 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1911 silc_rwlock_wrlock(channel->internal.lock);
1913 /* Cache the received Client ID's and modes. */
1914 for (i = 0; i < list_count; i++) {
1915 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1917 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1921 SILC_GET32_MSB(mode, client_mode_list.data);
1923 /* Save the client on this channel. Unknown clients are ignored as they
1924 clearly do not exist since the resolving didn't find them. */
1925 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1926 if (client_entry && client_entry->internal.valid) {
1927 silc_rwlock_wrlock(client_entry->internal.lock);
1928 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1929 silc_rwlock_unlock(client_entry->internal.lock);
1931 silc_client_unref_client(client, conn, client_entry);
1933 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1934 silc_rwlock_unlock(channel->internal.lock);
1937 if (!silc_buffer_pull(&client_mode_list, 4)) {
1938 silc_rwlock_unlock(channel->internal.lock);
1943 /* Notify application */
1944 silc_hash_table_list(channel->user_list, &htl);
1945 silc_client_command_callback(cmd, channel, &htl);
1946 silc_hash_table_list_reset(&htl);
1949 silc_client_unref_channel(client, conn, channel);
1950 silc_fsm_next(fsm, silc_client_command_reply_processed);
1951 return SILC_FSM_CONTINUE;
1954 /********************************** GETKEY **********************************/
1956 /* Received command reply to GETKEY command. WE've received the remote
1957 client's public key. */
1959 SILC_FSM_STATE(silc_client_command_reply_getkey)
1961 SilcClientCommandContext cmd = fsm_context;
1962 SilcClientConnection conn = cmd->conn;
1963 SilcClient client = conn->client;
1964 SilcCommandPayload payload = state_context;
1965 SilcArgumentPayload args = silc_command_get_args(payload);
1966 SilcClientEntry client_entry;
1967 SilcServerEntry server_entry;
1970 SilcPublicKey public_key;
1974 CHECK_STATUS("Cannot get key: ");
1978 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1979 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1983 /* Get the public key */
1984 tmp = silc_argument_get_arg_type(args, 3, &len);
1986 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1989 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1990 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1994 if (id.type == SILC_ID_CLIENT) {
1995 /* Received client's public key */
1996 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1997 if (!client_entry) {
1998 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2002 silc_rwlock_wrlock(client_entry->internal.lock);
2004 /* Save fingerprint */
2005 if (!client_entry->fingerprint)
2006 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2007 client_entry->fingerprint);
2008 if (!client_entry->public_key) {
2009 client_entry->public_key = public_key;
2013 silc_rwlock_unlock(client_entry->internal.lock);
2015 /* Notify application */
2016 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2017 client_entry->public_key);
2018 silc_client_unref_client(client, conn, client_entry);
2019 } else if (id.type == SILC_ID_SERVER) {
2020 /* Received server's public key */
2021 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2022 if (!server_entry) {
2023 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2027 silc_rwlock_wrlock(server_entry->internal.lock);
2029 if (!server_entry->public_key) {
2030 server_entry->public_key = public_key;
2034 silc_rwlock_unlock(server_entry->internal.lock);
2036 /* Notify application */
2037 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2038 server_entry->public_key);
2039 silc_client_unref_server(client, conn, server_entry);
2044 silc_pkcs_public_key_free(public_key);
2045 silc_fsm_next(fsm, silc_client_command_reply_processed);
2046 return SILC_FSM_CONTINUE;
2049 /********************************** SERVICE *********************************/
2051 /* Reply to SERVICE command. */
2052 /* XXX incomplete */
2054 SILC_FSM_STATE(silc_client_command_reply_service)
2056 SilcClientCommandContext cmd = fsm_context;
2057 SilcCommandPayload payload = state_context;
2058 SilcArgumentPayload args = silc_command_get_args(payload);
2060 unsigned char *service_list, *name;
2063 CHECK_STATUS("Cannot get service: ");
2065 /* Get service list */
2066 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2068 /* Get requested service name */
2069 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2071 /* Notify application */
2072 silc_client_command_callback(cmd, service_list, name);
2074 silc_fsm_next(fsm, silc_client_command_reply_processed);
2075 return SILC_FSM_CONTINUE;
2078 /*********************************** QUIT ***********************************/
2080 /* QUIT command reply stub */
2082 SILC_FSM_STATE(silc_client_command_reply_quit)
2084 silc_fsm_next(fsm, silc_client_command_reply_processed);
2085 return SILC_FSM_CONTINUE;