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 ? 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);
739 silc_rwlock_unlock(conn->local_entry->internal.lock);
741 /* Notify application */
742 silc_client_command_callback(cmd, conn->local_entry,
743 conn->local_entry->nickname, &old_client_id);
746 silc_fsm_next(fsm, silc_client_command_reply_processed);
747 return SILC_FSM_CONTINUE;
750 /********************************** LIST ************************************/
752 /* Received reply to the LIST command. */
754 SILC_FSM_STATE(silc_client_command_reply_list)
756 SilcClientCommandContext cmd = fsm_context;
757 SilcClientConnection conn = cmd->conn;
758 SilcClient client = conn->client;
759 SilcCommandPayload payload = state_context;
760 SilcArgumentPayload args = silc_command_get_args(payload);
761 unsigned char *tmp, *name, *topic;
762 SilcUInt32 usercount = 0;
763 SilcChannelEntry channel_entry = NULL;
767 CHECK_STATUS("Cannot list channels: ");
769 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
770 /* There were no channels in the network. */
771 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
772 silc_fsm_next(fsm, silc_client_command_reply_processed);
773 return SILC_FSM_CONTINUE;
778 name = silc_argument_get_arg_type(args, 3, NULL);
780 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
784 topic = silc_argument_get_arg_type(args, 4, NULL);
785 tmp = silc_argument_get_arg_type(args, 5, NULL);
787 SILC_GET32_MSB(usercount, tmp);
789 /* Check whether the channel exists, and add it to cache if it doesn't. */
790 channel_entry = silc_client_get_channel_by_id(client, conn,
792 if (!channel_entry) {
793 /* Add new channel entry */
794 channel_entry = silc_client_add_channel(client, conn, name, 0,
796 if (!channel_entry) {
797 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
800 silc_client_ref_channel(client, conn, channel_entry);
803 /* Notify application */
804 silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name,
808 silc_client_unref_channel(client, conn, channel_entry);
809 silc_fsm_next(fsm, silc_client_command_reply_processed);
810 return SILC_FSM_CONTINUE;
813 /********************************* TOPIC ************************************/
815 /* Received reply to topic command. */
817 SILC_FSM_STATE(silc_client_command_reply_topic)
819 SilcClientCommandContext cmd = fsm_context;
820 SilcClientConnection conn = cmd->conn;
821 SilcClient client = conn->client;
822 SilcCommandPayload payload = state_context;
823 SilcArgumentPayload args = silc_command_get_args(payload);
824 SilcChannelEntry channel;
830 CHECK_STATUS("Cannot set topic: ");
833 /* Take Channel ID */
834 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
835 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
839 /* Get the channel entry */
840 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
842 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
846 silc_rwlock_wrlock(channel->internal.lock);
849 topic = silc_argument_get_arg_type(args, 3, &len);
851 silc_free(channel->topic);
852 channel->topic = silc_memdup(topic, len);
855 silc_rwlock_unlock(channel->internal.lock);
857 /* Notify application */
858 silc_client_command_callback(cmd, channel, channel->topic);
861 silc_fsm_next(fsm, silc_client_command_reply_processed);
862 return SILC_FSM_CONTINUE;
865 /********************************* INVITE ***********************************/
867 /* Received reply to invite command. */
869 SILC_FSM_STATE(silc_client_command_reply_invite)
871 SilcClientCommandContext cmd = fsm_context;
872 SilcClientConnection conn = cmd->conn;
873 SilcClient client = conn->client;
874 SilcCommandPayload payload = state_context;
875 SilcArgumentPayload args = silc_command_get_args(payload);
876 SilcChannelEntry channel;
879 SilcArgumentPayload invite_args = NULL;
883 CHECK_STATUS("Cannot invite: ");
886 /* Take Channel ID */
887 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
888 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
892 /* Get the channel entry */
893 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
895 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
899 /* Get the invite list */
900 tmp = silc_argument_get_arg_type(args, 3, &len);
902 invite_args = silc_argument_list_parse(tmp, len);
904 /* Notify application */
905 silc_client_command_callback(cmd, channel, invite_args);
908 silc_argument_payload_free(invite_args);
911 silc_fsm_next(fsm, silc_client_command_reply_processed);
912 return SILC_FSM_CONTINUE;
915 /********************************** KILL ************************************/
917 /* Received reply to the KILL command. */
919 SILC_FSM_STATE(silc_client_command_reply_kill)
921 SilcClientCommandContext cmd = fsm_context;
922 SilcClientConnection conn = cmd->conn;
923 SilcClient client = conn->client;
924 SilcCommandPayload payload = state_context;
925 SilcArgumentPayload args = silc_command_get_args(payload);
926 SilcClientEntry client_entry;
930 CHECK_STATUS("Cannot kill: ");
933 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
934 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
938 /* Get the client entry, if exists */
939 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
941 /* Notify application */
942 silc_client_command_callback(cmd, client_entry);
944 /* Remove the client */
946 silc_client_remove_from_channels(client, conn, client_entry);
947 silc_client_del_client(client, conn, client_entry);
948 silc_client_unref_client(client, conn, client_entry);
952 silc_fsm_next(fsm, silc_client_command_reply_processed);
953 return SILC_FSM_CONTINUE;
956 /********************************** INFO ************************************/
958 /* Received reply to INFO command. We receive the server ID and some
959 information about the server user requested. */
961 SILC_FSM_STATE(silc_client_command_reply_info)
963 SilcClientCommandContext cmd = fsm_context;
964 SilcClientConnection conn = cmd->conn;
965 SilcClient client = conn->client;
966 SilcCommandPayload payload = state_context;
967 SilcArgumentPayload args = silc_command_get_args(payload);
968 SilcServerEntry server;
969 char *server_name, *server_info;
973 CHECK_STATUS("Cannot get info: ");
977 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
978 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
982 /* Get server name */
983 server_name = silc_argument_get_arg_type(args, 3, NULL);
985 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
989 /* Get server info */
990 server_info = silc_argument_get_arg_type(args, 4, NULL);
992 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
996 /* See whether we have this server cached. If not create it. */
997 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
999 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
1000 server = silc_client_add_server(client, conn, server_name,
1001 server_info, &id.u.server_id);
1004 silc_client_ref_server(client, conn, server);
1007 /* Notify application */
1008 silc_client_command_callback(cmd, server, server->server_name,
1009 server->server_info);
1010 silc_client_unref_server(client, conn, server);
1013 silc_fsm_next(fsm, silc_client_command_reply_processed);
1014 return SILC_FSM_CONTINUE;
1017 /********************************** STATS ***********************************/
1019 /* Received reply to STATS command. */
1021 SILC_FSM_STATE(silc_client_command_reply_stats)
1023 SilcClientCommandContext cmd = fsm_context;
1024 SilcCommandPayload payload = state_context;
1025 SilcArgumentPayload args = silc_command_get_args(payload);
1026 SilcClientStats stats;
1027 unsigned char *buf = NULL;
1028 SilcUInt32 buf_len = 0;
1033 CHECK_STATUS("Cannot get stats: ");
1037 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1038 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1042 /* Get statistics structure */
1043 memset(&stats, 0, sizeof(stats));
1044 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1046 silc_buffer_set(&b, buf, buf_len);
1047 silc_buffer_unformat(&b,
1048 SILC_STR_UI_INT(&stats.starttime),
1049 SILC_STR_UI_INT(&stats.uptime),
1050 SILC_STR_UI_INT(&stats.my_clients),
1051 SILC_STR_UI_INT(&stats.my_channels),
1052 SILC_STR_UI_INT(&stats.my_server_ops),
1053 SILC_STR_UI_INT(&stats.my_router_ops),
1054 SILC_STR_UI_INT(&stats.cell_clients),
1055 SILC_STR_UI_INT(&stats.cell_channels),
1056 SILC_STR_UI_INT(&stats.cell_servers),
1057 SILC_STR_UI_INT(&stats.clients),
1058 SILC_STR_UI_INT(&stats.channels),
1059 SILC_STR_UI_INT(&stats.servers),
1060 SILC_STR_UI_INT(&stats.routers),
1061 SILC_STR_UI_INT(&stats.server_ops),
1062 SILC_STR_UI_INT(&stats.router_ops),
1066 /* Notify application */
1067 silc_client_command_callback(cmd, &stats);
1070 silc_fsm_next(fsm, silc_client_command_reply_processed);
1071 return SILC_FSM_CONTINUE;
1074 /********************************** PING ************************************/
1076 /* Received reply to PING command. */
1078 SILC_FSM_STATE(silc_client_command_reply_ping)
1080 SilcClientCommandContext cmd = fsm_context;
1081 SilcClientConnection conn = cmd->conn;
1082 SilcClient client = conn->client;
1085 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1087 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1088 "Ping reply from %s: %d second%s", conn->remote_host,
1089 (int)diff, diff == 1 ? "" : "s");
1091 /* Notify application */
1092 silc_client_command_callback(cmd);
1094 silc_fsm_next(fsm, silc_client_command_reply_processed);
1095 return SILC_FSM_CONTINUE;
1098 /********************************** JOIN ************************************/
1100 /* Continue JOIN command reply processing after resolving unknown users */
1103 silc_client_command_reply_join_resolved(SilcClient client,
1104 SilcClientConnection conn,
1109 SilcClientCommandContext cmd = context;
1110 SilcChannelEntry channel = cmd->context;
1112 channel->internal.resolve_cmd_ident = 0;
1113 silc_client_unref_channel(client, conn, channel);
1115 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1119 /* Received reply for JOIN command. */
1121 SILC_FSM_STATE(silc_client_command_reply_join)
1123 SilcClientCommandContext cmd = fsm_context;
1124 SilcClientConnection conn = cmd->conn;
1125 SilcClient client = conn->client;
1126 SilcCommandPayload payload = state_context;
1127 SilcArgumentPayload args = silc_command_get_args(payload);
1128 SilcChannelEntry channel;
1129 SilcUInt32 mode = 0, len, list_count;
1130 char *topic, *tmp, *channel_name = NULL, *hmac;
1132 SilcBufferStruct client_id_list, client_mode_list, keyp;
1133 SilcHashTableList htl;
1138 CHECK_STATUS("Cannot join channel: ");
1141 /* Get channel name */
1142 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1143 if (!channel_name) {
1144 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1148 /* Get Channel ID */
1149 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1150 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1154 /* Check whether we have this channel entry already. */
1155 channel = silc_client_get_channel(client, conn, channel_name);
1157 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1158 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1160 /* Create new channel entry */
1161 channel = silc_client_add_channel(client, conn, channel_name,
1162 mode, &id.u.channel_id);
1164 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1167 silc_client_ref_channel(client, conn, channel);
1170 /* Get the list count */
1171 tmp = silc_argument_get_arg_type(args, 12, &len);
1173 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1176 SILC_GET32_MSB(list_count, tmp);
1178 /* Get Client ID list */
1179 tmp = silc_argument_get_arg_type(args, 13, &len);
1181 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1184 silc_buffer_set(&client_id_list, tmp, len);
1186 /* Resolve users we do not know about */
1187 if (!cmd->resolved) {
1188 cmd->resolved = TRUE;
1189 cmd->context = channel;
1190 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1191 silc_client_get_clients_by_list(
1192 client, conn, list_count, &client_id_list,
1193 silc_client_command_reply_join_resolved, cmd));
1197 /* Get client mode list */
1198 tmp = silc_argument_get_arg_type(args, 14, &len);
1200 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1203 silc_buffer_set(&client_mode_list, tmp, len);
1205 silc_rwlock_wrlock(channel->internal.lock);
1207 /* Add clients we received in the reply to the channel */
1208 for (i = 0; i < list_count; i++) {
1212 SilcClientEntry client_entry;
1215 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1217 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1221 SILC_GET32_MSB(mode, client_mode_list.data);
1223 /* Get client entry */
1224 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1225 if (client_entry && client_entry->internal.valid) {
1226 /* Join client to the channel */
1227 silc_rwlock_wrlock(client_entry->internal.lock);
1228 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1229 silc_rwlock_unlock(client_entry->internal.lock);
1231 silc_client_unref_client(client, conn, client_entry);
1233 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1234 silc_rwlock_unlock(channel->internal.lock);
1237 if (!silc_buffer_pull(&client_mode_list, 4)) {
1238 silc_rwlock_unlock(channel->internal.lock);
1244 hmac = silc_argument_get_arg_type(args, 11, NULL);
1246 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1248 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1249 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1250 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1251 silc_rwlock_unlock(channel->internal.lock);
1256 /* Get channel mode */
1257 tmp = silc_argument_get_arg_type(args, 5, &len);
1258 if (tmp && len == 4)
1259 SILC_GET32_MSB(mode, tmp);
1260 channel->mode = mode;
1262 /* Get channel key and save it */
1263 tmp = silc_argument_get_arg_type(args, 7, &len);
1265 silc_buffer_set(&keyp, tmp, len);
1266 silc_client_save_channel_key(client, conn, &keyp, channel);
1270 topic = silc_argument_get_arg_type(args, 10, NULL);
1272 silc_free(channel->topic);
1273 channel->topic = silc_memdup(topic, strlen(topic));
1276 /* Get founder key */
1277 tmp = silc_argument_get_arg_type(args, 15, &len);
1279 if (channel->founder_key)
1280 silc_pkcs_public_key_free(channel->founder_key);
1281 channel->founder_key = NULL;
1282 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1285 /* Get user limit */
1286 tmp = silc_argument_get_arg_type(args, 17, &len);
1287 if (tmp && len == 4)
1288 SILC_GET32_MSB(channel->user_limit, tmp);
1289 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1290 channel->user_limit = 0;
1292 /* Get channel public key list */
1293 tmp = silc_argument_get_arg_type(args, 16, &len);
1295 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1297 /* Set current channel */
1298 conn->current_channel = channel;
1300 silc_rwlock_unlock(channel->internal.lock);
1302 cipher = (channel->internal.send_key ?
1303 silc_cipher_get_name(channel->internal.send_key) : NULL);
1304 silc_hash_table_list(channel->user_list, &htl);
1306 /* Notify application */
1307 silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
1308 topic, cipher, hmac, channel->founder_key,
1309 channel->channel_pubkeys, channel->user_limit);
1311 silc_hash_table_list_reset(&htl);
1312 silc_client_unref_channel(client, conn, channel);
1315 silc_fsm_next(fsm, silc_client_command_reply_processed);
1316 return SILC_FSM_CONTINUE;
1319 /********************************** MOTD ************************************/
1321 /* Received reply for MOTD command */
1323 SILC_FSM_STATE(silc_client_command_reply_motd)
1325 SilcClientCommandContext cmd = fsm_context;
1326 SilcClientConnection conn = cmd->conn;
1327 SilcClient client = conn->client;
1328 SilcCommandPayload payload = state_context;
1329 SilcArgumentPayload args = silc_command_get_args(payload);
1331 char *motd = NULL, *cp, line[256];
1334 CHECK_STATUS("Cannot get motd: ");
1337 if (silc_argument_get_arg_num(args) == 3) {
1338 motd = silc_argument_get_arg_type(args, 3, NULL);
1340 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1347 if (cp[i++] == '\n') {
1348 memset(line, 0, sizeof(line));
1349 silc_strncat(line, sizeof(line), cp, i - 1);
1356 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1365 /* Notify application */
1366 silc_client_command_callback(cmd, motd);
1369 silc_fsm_next(fsm, silc_client_command_reply_processed);
1370 return SILC_FSM_CONTINUE;
1373 /********************************** UMODE ***********************************/
1375 /* Received reply to the UMODE command. Save the current user mode */
1377 SILC_FSM_STATE(silc_client_command_reply_umode)
1379 SilcClientCommandContext cmd = fsm_context;
1380 SilcClientConnection conn = cmd->conn;
1381 SilcCommandPayload payload = state_context;
1382 SilcArgumentPayload args = silc_command_get_args(payload);
1384 SilcUInt32 mode, len;
1387 CHECK_STATUS("Cannot change mode: ");
1390 tmp = silc_argument_get_arg_type(args, 2, &len);
1391 if (!tmp || len != 4) {
1392 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1396 SILC_GET32_MSB(mode, tmp);
1397 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1398 conn->local_entry->mode = mode;
1399 silc_rwlock_unlock(conn->local_entry->internal.lock);
1401 /* Notify application */
1402 silc_client_command_callback(cmd, mode);
1405 silc_fsm_next(fsm, silc_client_command_reply_processed);
1406 return SILC_FSM_CONTINUE;
1409 /********************************** CMODE ***********************************/
1411 /* Received reply for CMODE command. */
1413 SILC_FSM_STATE(silc_client_command_reply_cmode)
1415 SilcClientCommandContext cmd = fsm_context;
1416 SilcClientConnection conn = cmd->conn;
1417 SilcClient client = conn->client;
1418 SilcCommandPayload payload = state_context;
1419 SilcArgumentPayload args = silc_command_get_args(payload);
1422 SilcChannelEntry channel;
1424 SilcPublicKey public_key = NULL;
1428 CHECK_STATUS("Cannot change mode: ");
1431 /* Take Channel ID */
1432 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1433 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1437 /* Get the channel entry */
1438 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1440 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1444 /* Get founder public key */
1445 tmp = silc_argument_get_arg_type(args, 4, &len);
1447 silc_public_key_payload_decode(tmp, len, &public_key);
1449 /* Get channel mode */
1450 tmp = silc_argument_get_arg_type(args, 3, &len);
1451 if (!tmp || len != 4) {
1452 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1455 SILC_GET32_MSB(mode, tmp);
1457 silc_rwlock_wrlock(channel->internal.lock);
1459 /* Get user limit */
1460 tmp = silc_argument_get_arg_type(args, 6, &len);
1461 if (tmp && len == 4)
1462 SILC_GET32_MSB(channel->user_limit, tmp);
1463 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1464 channel->user_limit = 0;
1466 /* Get channel public key(s) */
1467 tmp = silc_argument_get_arg_type(args, 5, &len);
1469 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1470 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
1471 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
1474 channel->mode = mode;
1476 silc_rwlock_unlock(channel->internal.lock);
1478 /* Notify application */
1479 silc_client_command_callback(cmd, channel, mode, public_key,
1480 channel->channel_pubkeys, channel->user_limit);
1484 silc_pkcs_public_key_free(public_key);
1485 silc_fsm_next(fsm, silc_client_command_reply_processed);
1486 return SILC_FSM_CONTINUE;
1489 /********************************** CUMODE **********************************/
1491 /* Received reply for CUMODE command */
1493 SILC_FSM_STATE(silc_client_command_reply_cumode)
1495 SilcClientCommandContext cmd = fsm_context;
1496 SilcClientConnection conn = cmd->conn;
1497 SilcClient client = conn->client;
1498 SilcCommandPayload payload = state_context;
1499 SilcArgumentPayload args = silc_command_get_args(payload);
1500 SilcClientEntry client_entry;
1501 SilcChannelEntry channel;
1502 SilcChannelUser chu;
1503 unsigned char *modev;
1504 SilcUInt32 len, mode;
1508 CHECK_STATUS("Cannot change mode: ");
1511 /* Get channel mode */
1512 modev = silc_argument_get_arg_type(args, 2, &len);
1513 if (!modev || len != 4) {
1514 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1517 SILC_GET32_MSB(mode, modev);
1519 /* Take Channel ID */
1520 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1521 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1525 /* Get the channel entry */
1526 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1528 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1533 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1534 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1538 /* Get client entry */
1539 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1540 if (!client_entry) {
1541 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1546 silc_rwlock_wrlock(channel->internal.lock);
1547 chu = silc_client_on_channel(channel, client_entry);
1550 silc_rwlock_unlock(channel->internal.lock);
1552 /* Notify application */
1553 silc_client_command_callback(cmd, mode, channel, client_entry);
1555 silc_client_unref_client(client, conn, client_entry);
1558 silc_fsm_next(fsm, silc_client_command_reply_processed);
1559 return SILC_FSM_CONTINUE;
1562 /********************************** KICK ************************************/
1564 SILC_FSM_STATE(silc_client_command_reply_kick)
1566 SilcClientCommandContext cmd = fsm_context;
1567 SilcClientConnection conn = cmd->conn;
1568 SilcClient client = conn->client;
1569 SilcCommandPayload payload = state_context;
1570 SilcArgumentPayload args = silc_command_get_args(payload);
1571 SilcClientEntry client_entry;
1572 SilcChannelEntry channel;
1576 CHECK_STATUS("Cannot kick: ");
1579 /* Take Channel ID */
1580 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1581 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1585 /* Get the channel entry */
1586 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1588 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1593 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1594 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1598 /* Get client entry */
1599 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1600 if (!client_entry) {
1601 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1605 /* Notify application */
1606 silc_client_command_callback(cmd, channel, client_entry);
1608 silc_client_unref_client(client, conn, client_entry);
1611 silc_fsm_next(fsm, silc_client_command_reply_processed);
1612 return SILC_FSM_CONTINUE;
1615 /******************************** SILCOPER **********************************/
1617 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1619 SilcClientCommandContext cmd = fsm_context;
1620 SilcCommandPayload payload = state_context;
1621 SilcArgumentPayload args = silc_command_get_args(payload);
1624 CHECK_STATUS("Cannot change mode: ");
1628 cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1630 /* Notify application */
1631 silc_client_command_callback(cmd);
1633 silc_fsm_next(fsm, silc_client_command_reply_processed);
1634 return SILC_FSM_CONTINUE;
1637 /********************************** OPER ************************************/
1639 SILC_FSM_STATE(silc_client_command_reply_oper)
1641 SilcClientCommandContext cmd = fsm_context;
1642 SilcCommandPayload payload = state_context;
1643 SilcArgumentPayload args = silc_command_get_args(payload);
1646 CHECK_STATUS("Cannot change mode: ");
1650 cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1652 /* Notify application */
1653 silc_client_command_callback(cmd);
1655 silc_fsm_next(fsm, silc_client_command_reply_processed);
1656 return SILC_FSM_CONTINUE;
1659 /********************************* DETACH ***********************************/
1661 SILC_FSM_STATE(silc_client_command_reply_detach)
1663 SilcClientCommandContext cmd = fsm_context;
1664 SilcClientConnection conn = cmd->conn;
1665 SilcClient client = conn->client;
1666 SilcCommandPayload payload = state_context;
1667 SilcArgumentPayload args = silc_command_get_args(payload);
1671 CHECK_STATUS("Cannot detach: ");
1674 /* Get detachment data */
1675 detach = silc_client_get_detach_data(client, conn);
1677 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1681 /* Notify application */
1682 silc_client_command_callback(cmd, detach);
1683 silc_buffer_free(detach);
1686 silc_fsm_next(fsm, silc_client_command_reply_processed);
1687 return SILC_FSM_CONTINUE;
1690 /********************************** WATCH ***********************************/
1692 SILC_FSM_STATE(silc_client_command_reply_watch)
1694 SilcClientCommandContext cmd = fsm_context;
1695 SilcCommandPayload payload = state_context;
1696 SilcArgumentPayload args = silc_command_get_args(payload);
1699 CHECK_STATUS("Cannot set watch: ");
1702 /* Notify application */
1703 silc_client_command_callback(cmd);
1705 silc_fsm_next(fsm, silc_client_command_reply_processed);
1706 return SILC_FSM_CONTINUE;
1709 /*********************************** BAN ************************************/
1711 SILC_FSM_STATE(silc_client_command_reply_ban)
1713 SilcClientCommandContext cmd = fsm_context;
1714 SilcClientConnection conn = cmd->conn;
1715 SilcClient client = conn->client;
1716 SilcCommandPayload payload = state_context;
1717 SilcArgumentPayload args = silc_command_get_args(payload);
1718 SilcChannelEntry channel;
1721 SilcArgumentPayload invite_args = NULL;
1725 CHECK_STATUS("Cannot set ban: ");
1728 /* Take Channel ID */
1729 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1730 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1734 /* Get the channel entry */
1735 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1737 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1741 /* Get the invite list */
1742 tmp = silc_argument_get_arg_type(args, 3, &len);
1744 invite_args = silc_argument_list_parse(tmp, len);
1746 /* Notify application */
1747 silc_client_command_callback(cmd, channel, invite_args);
1750 silc_argument_payload_free(invite_args);
1753 silc_fsm_next(fsm, silc_client_command_reply_processed);
1754 return SILC_FSM_CONTINUE;
1757 /********************************** LEAVE ***********************************/
1759 /* Reply to LEAVE command. */
1761 SILC_FSM_STATE(silc_client_command_reply_leave)
1763 SilcClientCommandContext cmd = fsm_context;
1764 SilcClientConnection conn = cmd->conn;
1765 SilcClient client = conn->client;
1766 SilcCommandPayload payload = state_context;
1767 SilcArgumentPayload args = silc_command_get_args(payload);
1768 SilcChannelEntry channel;
1772 CHECK_STATUS("Cannot set leave: ");
1775 /* Get Channel ID */
1776 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1777 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1781 /* Get the channel entry */
1782 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1784 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1788 /* Remove us from this channel. */
1789 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1791 /* Notify application */
1792 silc_client_command_callback(cmd, channel);
1794 /* Now delete the channel. */
1795 silc_client_empty_channel(client, conn, channel);
1796 silc_client_del_channel(client, conn, channel);
1799 silc_fsm_next(fsm, silc_client_command_reply_processed);
1800 return SILC_FSM_CONTINUE;
1803 /********************************* USERS ************************************/
1805 /* Continue USERS command reply processing after resolving unknown users */
1808 silc_client_command_reply_users_resolved(SilcClient client,
1809 SilcClientConnection conn,
1814 SilcClientCommandContext cmd = context;
1815 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1819 /* Continue USERS command after resolving unknown channel */
1822 silc_client_command_reply_users_continue(SilcClient client,
1823 SilcClientConnection conn,
1828 SilcClientCommandContext cmd = context;
1831 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1832 SilcArgumentPayload args = silc_command_get_args(payload);
1834 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1835 ERROR_CALLBACK(cmd->status);
1836 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1839 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1842 /* Reply to USERS command. Received list of client ID's and theirs modes
1843 on the channel we requested. */
1845 SILC_FSM_STATE(silc_client_command_reply_users)
1847 SilcClientCommandContext cmd = fsm_context;
1848 SilcClientConnection conn = cmd->conn;
1849 SilcClient client = conn->client;
1850 SilcCommandPayload payload = state_context;
1851 SilcArgumentPayload args = silc_command_get_args(payload);
1853 SilcUInt32 tmp_len, list_count;
1854 SilcUInt16 idp_len, mode;
1855 SilcHashTableList htl;
1856 SilcBufferStruct client_id_list, client_mode_list;
1857 SilcChannelEntry channel = NULL;
1858 SilcClientEntry client_entry;
1863 CHECK_STATUS("Cannot get users: ");
1866 /* Get channel ID */
1867 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1868 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1872 /* Get channel entry */
1873 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1875 /* Resolve the channel from server */
1876 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1877 client, conn, &id.u.channel_id,
1878 silc_client_command_reply_users_continue, cmd));
1882 /* Get the list count */
1883 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1884 if (!tmp || tmp_len != 4) {
1885 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1888 SILC_GET32_MSB(list_count, tmp);
1890 /* Get Client ID list */
1891 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1893 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1896 silc_buffer_set(&client_id_list, tmp, tmp_len);
1898 /* Resolve users we do not know about */
1899 if (!cmd->resolved) {
1900 cmd->resolved = TRUE;
1901 silc_client_unref_channel(client, conn, channel);
1902 SILC_FSM_CALL(silc_client_get_clients_by_list(
1903 client, conn, list_count, &client_id_list,
1904 silc_client_command_reply_users_resolved, cmd));
1908 /* Get client mode list */
1909 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1911 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1914 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1916 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1918 silc_rwlock_wrlock(channel->internal.lock);
1920 /* Cache the received Client ID's and modes. */
1921 for (i = 0; i < list_count; i++) {
1922 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1924 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1928 SILC_GET32_MSB(mode, client_mode_list.data);
1930 /* Save the client on this channel. Unknown clients are ignored as they
1931 clearly do not exist since the resolving didn't find them. */
1932 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1933 if (client_entry && client_entry->internal.valid) {
1934 silc_rwlock_wrlock(client_entry->internal.lock);
1935 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1936 silc_rwlock_unlock(client_entry->internal.lock);
1938 silc_client_unref_client(client, conn, client_entry);
1940 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1941 silc_rwlock_unlock(channel->internal.lock);
1944 if (!silc_buffer_pull(&client_mode_list, 4)) {
1945 silc_rwlock_unlock(channel->internal.lock);
1950 /* Notify application */
1951 silc_hash_table_list(channel->user_list, &htl);
1952 silc_client_command_callback(cmd, channel, &htl);
1953 silc_hash_table_list_reset(&htl);
1956 silc_client_unref_channel(client, conn, channel);
1957 silc_fsm_next(fsm, silc_client_command_reply_processed);
1958 return SILC_FSM_CONTINUE;
1961 /********************************** GETKEY **********************************/
1963 /* Received command reply to GETKEY command. WE've received the remote
1964 client's public key. */
1966 SILC_FSM_STATE(silc_client_command_reply_getkey)
1968 SilcClientCommandContext cmd = fsm_context;
1969 SilcClientConnection conn = cmd->conn;
1970 SilcClient client = conn->client;
1971 SilcCommandPayload payload = state_context;
1972 SilcArgumentPayload args = silc_command_get_args(payload);
1973 SilcClientEntry client_entry;
1974 SilcServerEntry server_entry;
1977 SilcPublicKey public_key;
1981 CHECK_STATUS("Cannot get key: ");
1985 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1986 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1990 /* Get the public key */
1991 tmp = silc_argument_get_arg_type(args, 3, &len);
1993 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1996 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1997 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2001 if (id.type == SILC_ID_CLIENT) {
2002 /* Received client's public key */
2003 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2004 if (!client_entry) {
2005 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2009 silc_rwlock_wrlock(client_entry->internal.lock);
2011 /* Save fingerprint */
2012 if (!client_entry->fingerprint)
2013 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2014 client_entry->fingerprint);
2015 if (!client_entry->public_key) {
2016 client_entry->public_key = public_key;
2020 silc_rwlock_unlock(client_entry->internal.lock);
2022 /* Notify application */
2023 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2024 client_entry->public_key);
2025 silc_client_unref_client(client, conn, client_entry);
2026 } else if (id.type == SILC_ID_SERVER) {
2027 /* Received server's public key */
2028 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2029 if (!server_entry) {
2030 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2034 silc_rwlock_wrlock(server_entry->internal.lock);
2036 if (!server_entry->public_key) {
2037 server_entry->public_key = public_key;
2041 silc_rwlock_unlock(server_entry->internal.lock);
2043 /* Notify application */
2044 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2045 server_entry->public_key);
2046 silc_client_unref_server(client, conn, server_entry);
2051 silc_pkcs_public_key_free(public_key);
2052 silc_fsm_next(fsm, silc_client_command_reply_processed);
2053 return SILC_FSM_CONTINUE;
2056 /********************************** SERVICE *********************************/
2058 /* Reply to SERVICE command. */
2059 /* XXX incomplete */
2061 SILC_FSM_STATE(silc_client_command_reply_service)
2063 SilcClientCommandContext cmd = fsm_context;
2064 SilcCommandPayload payload = state_context;
2065 SilcArgumentPayload args = silc_command_get_args(payload);
2067 unsigned char *service_list, *name;
2070 CHECK_STATUS("Cannot get service: ");
2072 /* Get service list */
2073 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2075 /* Get requested service name */
2076 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2078 /* Notify application */
2079 silc_client_command_callback(cmd, service_list, name);
2081 silc_fsm_next(fsm, silc_client_command_reply_processed);
2082 return SILC_FSM_CONTINUE;
2085 /*********************************** QUIT ***********************************/
2087 /* QUIT command reply stub */
2089 SILC_FSM_STATE(silc_client_command_reply_quit)
2091 silc_fsm_next(fsm, silc_client_command_reply_processed);
2092 return SILC_FSM_CONTINUE;