5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 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_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;
76 /* Default reply callback */
79 cmd->conn->client->internal->ops->command_reply(
80 cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
86 silc_list_start(cmd->reply_callbacks);
87 while ((cb = silc_list_get(cmd->reply_callbacks)))
88 if (!cb->do_not_call) {
90 cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
91 cmd->status, cmd->error, cb->context, cp);
98 /* Handles common error status types. */
100 static void silc_client_command_process_error(SilcClientCommandContext cmd,
101 SilcCommandPayload payload,
104 SilcClient client = cmd->conn->client;
105 SilcClientConnection conn = cmd->conn;
106 SilcArgumentPayload args = silc_command_get_args(payload);
107 SilcClientEntry client_entry;
110 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
111 /* Remove unknown client entry from cache */
112 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
115 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
117 silc_client_remove_from_channels(client, conn, client_entry);
118 silc_client_del_client(client, conn, client_entry);
119 silc_client_unref_client(client, conn, client_entry);
124 /***************************** Command Reply ********************************/
126 /* Process received command reply packet */
128 SILC_FSM_STATE(silc_client_command_reply)
130 SilcClientConnection conn = fsm_context;
131 SilcPacket packet = state_context;
132 SilcClientCommandContext cmd;
133 SilcCommandPayload payload;
135 SilcUInt16 cmd_ident;
137 /* Get command reply payload from packet */
138 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
139 silc_packet_free(packet);
141 SILC_LOG_DEBUG(("Bad command reply packet"));
142 return SILC_FSM_FINISH;
145 cmd_ident = silc_command_get_ident(payload);
146 command = silc_command_get(payload);
148 /* Find the command pending reply */
149 silc_mutex_lock(conn->internal->lock);
150 silc_list_start(conn->internal->pending_commands);
151 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
152 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
153 && cmd->cmd_ident == cmd_ident) {
154 silc_list_del(conn->internal->pending_commands, cmd);
158 silc_mutex_unlock(conn->internal->lock);
161 SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
162 silc_get_command_name(command), cmd_ident));
163 silc_command_payload_free(payload);
164 return SILC_FSM_FINISH;
167 /* Signal command thread that command reply has arrived */
168 silc_fsm_set_state_context(&cmd->thread, payload);
169 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
170 silc_fsm_continue_sync(&cmd->thread);
172 return SILC_FSM_FINISH;
175 /* Wait here for command reply to arrive from remote host */
177 SILC_FSM_STATE(silc_client_command_reply_wait)
179 SilcClientCommandContext cmd = fsm_context;
181 SILC_LOG_DEBUG(("Wait for command reply"));
183 /** Wait for command reply */
184 silc_fsm_set_state_context(fsm, NULL);
185 silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
186 cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0);
187 return SILC_FSM_WAIT;
190 /* Timeout occurred while waiting command reply */
192 SILC_FSM_STATE(silc_client_command_reply_timeout)
194 SilcClientCommandContext cmd = fsm_context;
195 SilcClientConnection conn = cmd->conn;
196 SilcArgumentPayload args = NULL;
198 SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
200 /* Timeout, reply not received in timely fashion */
201 silc_list_del(conn->internal->pending_commands, cmd);
202 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
203 return SILC_FSM_FINISH;
206 /* Process received command reply payload */
208 SILC_FSM_STATE(silc_client_command_reply_process)
210 SilcClientCommandContext cmd = fsm_context;
211 SilcCommandPayload payload = state_context;
213 silc_command_get_status(payload, &cmd->status, &cmd->error);
216 case SILC_COMMAND_WHOIS:
218 silc_fsm_next(fsm, silc_client_command_reply_whois);
220 case SILC_COMMAND_WHOWAS:
222 silc_fsm_next(fsm, silc_client_command_reply_whowas);
224 case SILC_COMMAND_IDENTIFY:
226 silc_fsm_next(fsm, silc_client_command_reply_identify);
228 case SILC_COMMAND_NICK:
230 silc_fsm_next(fsm, silc_client_command_reply_nick);
232 case SILC_COMMAND_LIST:
234 silc_fsm_next(fsm, silc_client_command_reply_list);
236 case SILC_COMMAND_TOPIC:
238 silc_fsm_next(fsm, silc_client_command_reply_topic);
240 case SILC_COMMAND_INVITE:
242 silc_fsm_next(fsm, silc_client_command_reply_invite);
244 case SILC_COMMAND_QUIT:
246 silc_fsm_next(fsm, silc_client_command_reply_quit);
248 case SILC_COMMAND_KILL:
250 silc_fsm_next(fsm, silc_client_command_reply_kill);
252 case SILC_COMMAND_INFO:
254 silc_fsm_next(fsm, silc_client_command_reply_info);
256 case SILC_COMMAND_STATS:
258 silc_fsm_next(fsm, silc_client_command_reply_stats);
260 case SILC_COMMAND_PING:
262 silc_fsm_next(fsm, silc_client_command_reply_ping);
264 case SILC_COMMAND_OPER:
266 silc_fsm_next(fsm, silc_client_command_reply_oper);
268 case SILC_COMMAND_JOIN:
270 silc_fsm_next(fsm, silc_client_command_reply_join);
272 case SILC_COMMAND_MOTD:
274 silc_fsm_next(fsm, silc_client_command_reply_motd);
276 case SILC_COMMAND_UMODE:
278 silc_fsm_next(fsm, silc_client_command_reply_umode);
280 case SILC_COMMAND_CMODE:
282 silc_fsm_next(fsm, silc_client_command_reply_cmode);
284 case SILC_COMMAND_CUMODE:
286 silc_fsm_next(fsm, silc_client_command_reply_cumode);
288 case SILC_COMMAND_KICK:
290 silc_fsm_next(fsm, silc_client_command_reply_kick);
292 case SILC_COMMAND_BAN:
294 silc_fsm_next(fsm, silc_client_command_reply_ban);
296 case SILC_COMMAND_DETACH:
298 silc_fsm_next(fsm, silc_client_command_reply_detach);
300 case SILC_COMMAND_WATCH:
302 silc_fsm_next(fsm, silc_client_command_reply_watch);
304 case SILC_COMMAND_SILCOPER:
306 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
308 case SILC_COMMAND_LEAVE:
310 silc_fsm_next(fsm, silc_client_command_reply_leave);
312 case SILC_COMMAND_USERS:
314 silc_fsm_next(fsm, silc_client_command_reply_users);
316 case SILC_COMMAND_GETKEY:
318 silc_fsm_next(fsm, silc_client_command_reply_getkey);
320 case SILC_COMMAND_SERVICE:
322 silc_fsm_next(fsm, silc_client_command_reply_service);
325 return SILC_FSM_FINISH;
328 return SILC_FSM_CONTINUE;
331 /* Completes command reply processing */
333 SILC_FSM_STATE(silc_client_command_reply_processed)
335 SilcClientCommandContext cmd = fsm_context;
336 SilcClientConnection conn = cmd->conn;
337 SilcCommandPayload payload = state_context;
339 silc_command_payload_free(payload);
341 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
342 SILC_STATUS_IS_ERROR(cmd->status))
343 return SILC_FSM_FINISH;
345 /* Add back to pending command reply list */
346 silc_mutex_lock(conn->internal->lock);
347 cmd->resolved = FALSE;
348 silc_list_add(conn->internal->pending_commands, cmd);
349 silc_mutex_unlock(conn->internal->lock);
351 /** Wait more command payloads */
352 silc_fsm_next(fsm, silc_client_command_reply_wait);
353 return SILC_FSM_CONTINUE;
356 /******************************** WHOIS *************************************/
358 /* Received reply for WHOIS command. */
360 SILC_FSM_STATE(silc_client_command_reply_whois)
362 SilcClientCommandContext cmd = fsm_context;
363 SilcClientConnection conn = cmd->conn;
364 SilcClient client = conn->client;
365 SilcCommandPayload payload = state_context;
366 SilcArgumentPayload args = silc_command_get_args(payload);
367 SilcClientEntry client_entry = NULL;
368 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
369 SilcBufferStruct channels, ch_user_modes;
370 SilcBool has_channels = FALSE;
371 SilcDList channel_list = NULL;
373 char *nickname = NULL, *username = NULL, *realname = NULL;
374 unsigned char *fingerprint, *tmp;
376 CHECK_STATUS("WHOIS: ");
380 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
381 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
386 nickname = silc_argument_get_arg_type(args, 3, NULL);
387 username = silc_argument_get_arg_type(args, 4, NULL);
388 realname = silc_argument_get_arg_type(args, 5, NULL);
389 if (!nickname || !username || !realname) {
390 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
394 /* Get joined channel list */
395 memset(&channels, 0, sizeof(channels));
396 tmp = silc_argument_get_arg_type(args, 6, &len);
399 silc_buffer_set(&channels, tmp, len);
401 /* Get channel user mode list */
402 tmp = silc_argument_get_arg_type(args, 10, &len);
404 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
407 silc_buffer_set(&ch_user_modes, tmp, len);
411 tmp = silc_argument_get_arg_type(args, 7, &len);
413 SILC_GET32_MSB(mode, tmp);
416 tmp = silc_argument_get_arg_type(args, 8, &len);
418 SILC_GET32_MSB(idle, tmp);
420 /* Get fingerprint */
421 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
423 /* Check if we have this client cached already. */
424 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
426 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
428 silc_client_add_client(client, conn, nickname, username, realname,
429 &id.u.client_id, mode);
431 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
434 silc_client_ref_client(client, conn, client_entry);
436 silc_client_update_client(client, conn, client_entry,
437 nickname, username, realname, mode);
440 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
441 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
443 /* Get user attributes */
444 tmp = silc_argument_get_arg_type(args, 11, &len);
446 if (client_entry->attrs)
447 silc_attribute_payload_list_free(client_entry->attrs);
448 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
451 /* Parse channel and channel user mode list */
453 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
454 silc_buffer_len(&channels));
456 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
460 /* Notify application */
461 silc_client_command_callback(cmd, client_entry, nickname, username,
462 realname, channel_list, mode, idle, fingerprint,
463 umodes, client_entry->attrs);
465 silc_client_unref_client(client, conn, client_entry);
467 silc_dlist_uninit(channel_list);
472 silc_fsm_next(fsm, silc_client_command_reply_processed);
473 return SILC_FSM_CONTINUE;
476 /******************************** WHOWAS ************************************/
478 /* Received reply for WHOWAS command. */
480 SILC_FSM_STATE(silc_client_command_reply_whowas)
482 SilcClientCommandContext cmd = fsm_context;
483 SilcClientConnection conn = cmd->conn;
484 SilcClient client = conn->client;
485 SilcCommandPayload payload = state_context;
486 SilcArgumentPayload args = silc_command_get_args(payload);
487 SilcClientEntry client_entry = NULL;
489 char *nickname, *username;
490 char *realname = NULL;
492 CHECK_STATUS("WHOWAS: ");
496 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
497 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
501 /* Get the client entry */
502 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
505 nickname = silc_argument_get_arg_type(args, 3, NULL);
506 username = silc_argument_get_arg_type(args, 4, NULL);
507 realname = silc_argument_get_arg_type(args, 5, NULL);
508 if (!nickname || !username) {
509 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
513 /* Notify application. We don't save any history information to any
514 cache. Just pass the data to the application. */
515 silc_client_command_callback(cmd, client_entry, nickname, username,
519 silc_client_unref_client(client, conn, client_entry);
520 silc_fsm_next(fsm, silc_client_command_reply_processed);
521 return SILC_FSM_CONTINUE;
524 /******************************** IDENTIFY **********************************/
526 /* Received reply for IDENTIFY command. */
528 SILC_FSM_STATE(silc_client_command_reply_identify)
530 SilcClientCommandContext cmd = fsm_context;
531 SilcClientConnection conn = cmd->conn;
532 SilcClient client = conn->client;
533 SilcCommandPayload payload = state_context;
534 SilcArgumentPayload args = silc_command_get_args(payload);
535 SilcClientEntry client_entry;
536 SilcServerEntry server_entry;
537 SilcChannelEntry channel_entry;
540 char *name = NULL, *info = NULL;
542 CHECK_STATUS("IDENTIFY: ");
546 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
547 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
552 name = silc_argument_get_arg_type(args, 3, &len);
553 info = silc_argument_get_arg_type(args, 4, &len);
557 SILC_LOG_DEBUG(("Received client information"));
559 /* Check if we have this client cached already. */
560 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
562 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
564 silc_client_add_client(client, conn, name, info, NULL,
567 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
570 silc_client_ref_client(client, conn, client_entry);
572 silc_client_update_client(client, conn, client_entry,
573 name, info, NULL, 0);
576 /* Notify application */
577 silc_client_command_callback(cmd, client_entry, name, info);
578 silc_client_unref_client(client, conn, client_entry);
582 SILC_LOG_DEBUG(("Received server information"));
584 /* Check if we have this server cached already. */
585 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
587 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
588 server_entry = silc_client_add_server(client, conn, name, info,
591 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
594 silc_client_ref_server(client, conn, server_entry);
596 silc_client_update_server(client, conn, server_entry, name, info);
598 server_entry->internal.resolve_cmd_ident = 0;
600 /* Notify application */
601 silc_client_command_callback(cmd, server_entry, name, info);
602 silc_client_unref_server(client, conn, server_entry);
605 case SILC_ID_CHANNEL:
606 SILC_LOG_DEBUG(("Received channel information"));
608 /* Check if we have this channel cached already. */
609 channel_entry = silc_client_get_channel_by_id(client, conn,
611 if (!channel_entry) {
612 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
615 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
619 /* Add new channel entry */
620 channel_entry = silc_client_add_channel(client, conn, name, 0,
622 if (!channel_entry) {
623 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
626 silc_client_ref_channel(client, conn, channel_entry);
629 /* Notify application */
630 silc_client_command_callback(cmd, channel_entry, name, info);
631 silc_client_unref_channel(client, conn, channel_entry);
636 silc_fsm_next(fsm, silc_client_command_reply_processed);
637 return SILC_FSM_CONTINUE;
640 /********************************** NICK ************************************/
642 /* Received reply for command NICK. */
644 SILC_FSM_STATE(silc_client_command_reply_nick)
646 SilcClientCommandContext cmd = fsm_context;
647 SilcClientConnection conn = cmd->conn;
648 SilcClient client = conn->client;
649 SilcCommandPayload payload = state_context;
650 SilcArgumentPayload args = silc_command_get_args(payload);
651 unsigned char *tmp, *nick, *idp;
652 SilcUInt32 len, idp_len;
653 SilcClientID old_client_id;
657 CHECK_STATUS("Cannot set nickname: ");
660 old_client_id = *conn->local_id;
662 /* Take received Client ID */
663 idp = silc_argument_get_arg_type(args, 2, &idp_len);
665 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
668 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
669 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
673 /* Take the new nickname */
674 nick = silc_argument_get_arg_type(args, 3, &len);
676 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
680 /* Normalize nickname */
681 tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
683 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
687 /* Update the client entry */
688 silc_mutex_lock(conn->internal->lock);
689 if (!silc_idcache_update(conn->internal->client_cache,
690 conn->internal->local_entry,
691 &id.u.client_id, tmp, TRUE)) {
693 silc_mutex_unlock(conn->internal->lock);
694 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
697 silc_mutex_unlock(conn->internal->lock);
698 memset(conn->local_entry->nickname, 0, sizeof(conn->local_entry->nickname));
699 memcpy(conn->local_entry->nickname, nick, len);
700 conn->local_entry->nickname_normalized = tmp;
701 silc_buffer_enlarge(conn->internal->local_idp, idp_len);
702 silc_buffer_put(conn->internal->local_idp, idp, idp_len);
703 silc_client_nickname_format(client, conn, conn->local_entry);
704 silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id, 0, NULL);
706 /* Notify application */
707 silc_client_command_callback(cmd, conn->local_entry,
708 conn->local_entry->nickname, &old_client_id);
711 silc_fsm_next(fsm, silc_client_command_reply_processed);
712 return SILC_FSM_CONTINUE;
715 /********************************** LIST ************************************/
717 /* Received reply to the LIST command. */
719 SILC_FSM_STATE(silc_client_command_reply_list)
721 SilcClientCommandContext cmd = fsm_context;
722 SilcClientConnection conn = cmd->conn;
723 SilcClient client = conn->client;
724 SilcCommandPayload payload = state_context;
725 SilcArgumentPayload args = silc_command_get_args(payload);
726 unsigned char *tmp, *name, *topic;
727 SilcUInt32 usercount = 0;
728 SilcChannelEntry channel_entry = NULL;
732 CHECK_STATUS("Cannot list channels: ");
734 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
735 /* There were no channels in the network. */
736 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
737 silc_fsm_next(fsm, silc_client_command_reply_processed);
738 return SILC_FSM_CONTINUE;
743 name = silc_argument_get_arg_type(args, 3, NULL);
745 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
749 topic = silc_argument_get_arg_type(args, 4, NULL);
750 tmp = silc_argument_get_arg_type(args, 5, NULL);
752 SILC_GET32_MSB(usercount, tmp);
754 /* Check whether the channel exists, and add it to cache if it doesn't. */
755 channel_entry = silc_client_get_channel_by_id(client, conn,
757 if (!channel_entry) {
758 /* Add new channel entry */
759 channel_entry = silc_client_add_channel(client, conn, name, 0,
761 if (!channel_entry) {
762 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
765 silc_client_ref_channel(client, conn, channel_entry);
768 /* Notify application */
769 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
772 silc_client_unref_channel(client, conn, channel_entry);
773 silc_fsm_next(fsm, silc_client_command_reply_processed);
774 return SILC_FSM_CONTINUE;
777 /********************************* TOPIC ************************************/
779 /* Received reply to topic command. */
781 SILC_FSM_STATE(silc_client_command_reply_topic)
783 SilcClientCommandContext cmd = fsm_context;
784 SilcClientConnection conn = cmd->conn;
785 SilcClient client = conn->client;
786 SilcCommandPayload payload = state_context;
787 SilcArgumentPayload args = silc_command_get_args(payload);
788 SilcChannelEntry channel;
794 CHECK_STATUS("Cannot set topic: ");
797 /* Take Channel ID */
798 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
799 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
803 /* Get the channel entry */
804 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
806 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
811 topic = silc_argument_get_arg_type(args, 3, &len);
813 silc_free(channel->topic);
814 channel->topic = silc_memdup(topic, len);
817 /* Notify application */
818 silc_client_command_callback(cmd, channel, channel->topic);
821 silc_fsm_next(fsm, silc_client_command_reply_processed);
822 return SILC_FSM_CONTINUE;
825 /********************************* INVITE ***********************************/
827 /* Received reply to invite command. */
829 SILC_FSM_STATE(silc_client_command_reply_invite)
831 SilcClientCommandContext cmd = fsm_context;
832 SilcClientConnection conn = cmd->conn;
833 SilcClient client = conn->client;
834 SilcCommandPayload payload = state_context;
835 SilcArgumentPayload args = silc_command_get_args(payload);
836 SilcChannelEntry channel;
839 SilcArgumentPayload invite_args = NULL;
843 CHECK_STATUS("Cannot invite: ");
846 /* Take Channel ID */
847 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
848 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
852 /* Get the channel entry */
853 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
855 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
859 /* Get the invite list */
860 tmp = silc_argument_get_arg_type(args, 3, &len);
862 invite_args = silc_argument_list_parse(tmp, len);
864 /* Notify application */
865 silc_client_command_callback(cmd, channel, invite_args);
868 silc_argument_payload_free(invite_args);
871 silc_fsm_next(fsm, silc_client_command_reply_processed);
872 return SILC_FSM_CONTINUE;
875 /********************************** KILL ************************************/
877 /* Received reply to the KILL command. */
879 SILC_FSM_STATE(silc_client_command_reply_kill)
881 SilcClientCommandContext cmd = fsm_context;
882 SilcClientConnection conn = cmd->conn;
883 SilcClient client = conn->client;
884 SilcCommandPayload payload = state_context;
885 SilcArgumentPayload args = silc_command_get_args(payload);
886 SilcClientEntry client_entry;
890 CHECK_STATUS("Cannot kill: ");
893 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
894 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
898 /* Get the client entry, if exists */
899 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
901 /* Notify application */
902 silc_client_command_callback(cmd, client_entry);
904 /* Remove the client from all channels and free it */
906 silc_client_remove_from_channels(client, conn, client_entry);
907 silc_client_del_client(client, conn, client_entry);
908 silc_client_unref_client(client, conn, client_entry);
912 silc_fsm_next(fsm, silc_client_command_reply_processed);
913 return SILC_FSM_CONTINUE;
916 /********************************** INFO ************************************/
918 /* Received reply to INFO command. We receive the server ID and some
919 information about the server user requested. */
921 SILC_FSM_STATE(silc_client_command_reply_info)
923 SilcClientCommandContext cmd = fsm_context;
924 SilcClientConnection conn = cmd->conn;
925 SilcClient client = conn->client;
926 SilcCommandPayload payload = state_context;
927 SilcArgumentPayload args = silc_command_get_args(payload);
928 SilcServerEntry server;
929 char *server_name, *server_info;
933 CHECK_STATUS("Cannot get info: ");
937 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
938 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
942 /* Get server name */
943 server_name = silc_argument_get_arg_type(args, 3, NULL);
945 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
949 /* Get server info */
950 server_info = silc_argument_get_arg_type(args, 4, NULL);
952 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
956 /* See whether we have this server cached. If not create it. */
957 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
959 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
960 server = silc_client_add_server(client, conn, server_name,
961 server_info, &id.u.server_id);
964 silc_client_ref_server(client, conn, server);
967 /* Notify application */
968 silc_client_command_callback(cmd, server, server->server_name,
969 server->server_info);
970 silc_client_unref_server(client, conn, server);
973 silc_fsm_next(fsm, silc_client_command_reply_processed);
974 return SILC_FSM_CONTINUE;
977 /********************************** STATS ***********************************/
979 /* Received reply to STATS command. */
981 SILC_FSM_STATE(silc_client_command_reply_stats)
983 SilcClientCommandContext cmd = fsm_context;
984 SilcCommandPayload payload = state_context;
985 SilcArgumentPayload args = silc_command_get_args(payload);
986 SilcClientStats stats;
987 unsigned char *buf = NULL;
988 SilcUInt32 buf_len = 0;
993 CHECK_STATUS("Cannot get stats: ");
997 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
998 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1002 /* Get statistics structure */
1003 memset(&stats, 0, sizeof(stats));
1004 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1006 silc_buffer_set(&b, buf, buf_len);
1007 silc_buffer_unformat(&b,
1008 SILC_STR_UI_INT(&stats.starttime),
1009 SILC_STR_UI_INT(&stats.uptime),
1010 SILC_STR_UI_INT(&stats.my_clients),
1011 SILC_STR_UI_INT(&stats.my_channels),
1012 SILC_STR_UI_INT(&stats.my_server_ops),
1013 SILC_STR_UI_INT(&stats.my_router_ops),
1014 SILC_STR_UI_INT(&stats.cell_clients),
1015 SILC_STR_UI_INT(&stats.cell_channels),
1016 SILC_STR_UI_INT(&stats.cell_servers),
1017 SILC_STR_UI_INT(&stats.clients),
1018 SILC_STR_UI_INT(&stats.channels),
1019 SILC_STR_UI_INT(&stats.servers),
1020 SILC_STR_UI_INT(&stats.routers),
1021 SILC_STR_UI_INT(&stats.server_ops),
1022 SILC_STR_UI_INT(&stats.router_ops),
1026 /* Notify application */
1027 silc_client_command_callback(cmd, &stats);
1030 silc_fsm_next(fsm, silc_client_command_reply_processed);
1031 return SILC_FSM_CONTINUE;
1034 /********************************** PING ************************************/
1036 /* Received reply to PING command. */
1038 SILC_FSM_STATE(silc_client_command_reply_ping)
1040 SilcClientCommandContext cmd = fsm_context;
1041 SilcClientConnection conn = cmd->conn;
1042 SilcClient client = conn->client;
1045 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1047 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1048 "Ping reply from %s: %d second%s", conn->remote_host,
1049 (int)diff, diff == 1 ? "" : "s");
1051 /* Notify application */
1052 silc_client_command_callback(cmd);
1054 silc_fsm_next(fsm, silc_client_command_reply_processed);
1055 return SILC_FSM_CONTINUE;
1058 /********************************** JOIN ************************************/
1060 /* Continue JOIN command reply processing after resolving unknown users */
1063 silc_client_command_reply_join_resolved(SilcClient client,
1064 SilcClientConnection conn,
1069 SilcClientCommandContext cmd = context;
1070 SilcChannelEntry channel = cmd->context;
1072 channel->internal.resolve_cmd_ident = 0;
1073 silc_client_unref_channel(client, conn, channel);
1075 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1079 /* Received reply for JOIN command. */
1081 SILC_FSM_STATE(silc_client_command_reply_join)
1083 SilcClientCommandContext cmd = fsm_context;
1084 SilcClientConnection conn = cmd->conn;
1085 SilcClient client = conn->client;
1086 SilcCommandPayload payload = state_context;
1087 SilcArgumentPayload args = silc_command_get_args(payload);
1088 SilcChannelEntry channel;
1089 SilcUInt32 mode = 0, len, list_count;
1090 char *topic, *tmp, *channel_name = NULL, *hmac;
1092 SilcBufferStruct client_id_list, client_mode_list, keyp;
1093 SilcHashTableList htl;
1094 SilcDList chpks = NULL;
1099 CHECK_STATUS("Cannot join channel: ");
1102 /* Get channel name */
1103 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1104 if (!channel_name) {
1105 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1109 /* Get Channel ID */
1110 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1111 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1115 /* Check whether we have this channel entry already. */
1116 channel = silc_client_get_channel(client, conn, channel_name);
1118 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1119 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1121 /* Create new channel entry */
1122 channel = silc_client_add_channel(client, conn, channel_name,
1123 mode, &id.u.channel_id);
1125 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1128 silc_client_ref_channel(client, conn, channel);
1131 /* Get the list count */
1132 tmp = silc_argument_get_arg_type(args, 12, &len);
1134 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1137 SILC_GET32_MSB(list_count, tmp);
1139 /* Get Client ID list */
1140 tmp = silc_argument_get_arg_type(args, 13, &len);
1142 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1145 silc_buffer_set(&client_id_list, tmp, len);
1147 /* Resolve users we do not know about */
1148 if (!cmd->resolved) {
1149 cmd->resolved = TRUE;
1150 cmd->context = channel;
1151 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1152 silc_client_get_clients_by_list(
1153 client, conn, list_count, &client_id_list,
1154 silc_client_command_reply_join_resolved, cmd));
1158 /* Get client mode list */
1159 tmp = silc_argument_get_arg_type(args, 14, &len);
1161 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1164 silc_buffer_set(&client_mode_list, tmp, len);
1166 /* Add clients we received in the reply to the channel */
1167 for (i = 0; i < list_count; i++) {
1171 SilcClientEntry client_entry;
1174 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1176 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1180 SILC_GET32_MSB(mode, client_mode_list.data);
1182 /* Get client entry */
1183 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1187 /* Join client to the channel */
1188 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1189 silc_client_unref_client(client, conn, client_entry);
1191 if (!silc_buffer_pull(&client_id_list, idp_len))
1193 if (!silc_buffer_pull(&client_mode_list, 4))
1198 hmac = silc_argument_get_arg_type(args, 11, NULL);
1200 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1202 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1203 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1204 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1209 /* Get channel mode */
1210 tmp = silc_argument_get_arg_type(args, 5, NULL);
1212 SILC_GET32_MSB(mode, tmp);
1213 channel->mode = mode;
1215 /* Get channel key and save it */
1216 tmp = silc_argument_get_arg_type(args, 7, &len);
1218 silc_buffer_set(&keyp, tmp, len);
1219 silc_client_save_channel_key(client, conn, &keyp, channel);
1223 topic = silc_argument_get_arg_type(args, 10, NULL);
1225 silc_free(channel->topic);
1226 channel->topic = silc_memdup(topic, strlen(topic));
1229 /* Get founder key */
1230 tmp = silc_argument_get_arg_type(args, 15, &len);
1232 if (channel->founder_key)
1233 silc_pkcs_public_key_free(channel->founder_key);
1234 channel->founder_key = NULL;
1235 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1238 /* Get user limit */
1239 tmp = silc_argument_get_arg_type(args, 17, &len);
1240 if (tmp && len == 4)
1241 SILC_GET32_MSB(channel->user_limit, tmp);
1242 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1243 channel->user_limit = 0;
1245 /* Get channel public key list */
1246 tmp = silc_argument_get_arg_type(args, 16, &len);
1248 chpks = silc_argument_list_parse_decoded(tmp, len,
1249 SILC_ARGUMENT_PUBLIC_KEY);
1251 /* Set current channel */
1252 conn->current_channel = channel;
1254 cipher = (channel->internal.channel_key ?
1255 silc_cipher_get_name(channel->internal.channel_key) : NULL);
1256 silc_hash_table_list(channel->user_list, &htl);
1258 /* Notify application */
1259 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1260 topic, cipher, hmac, channel->founder_key,
1261 chpks, channel->user_limit);
1264 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
1265 silc_hash_table_list_reset(&htl);
1266 silc_client_unref_channel(client, conn, channel);
1269 silc_fsm_next(fsm, silc_client_command_reply_processed);
1270 return SILC_FSM_CONTINUE;
1273 /********************************** MOTD ************************************/
1275 /* Received reply for MOTD command */
1277 SILC_FSM_STATE(silc_client_command_reply_motd)
1279 SilcClientCommandContext cmd = fsm_context;
1280 SilcClientConnection conn = cmd->conn;
1281 SilcClient client = conn->client;
1282 SilcCommandPayload payload = state_context;
1283 SilcArgumentPayload args = silc_command_get_args(payload);
1285 char *motd = NULL, *cp, line[256];
1288 CHECK_STATUS("Cannot get motd: ");
1291 if (silc_argument_get_arg_num(args) == 3) {
1292 motd = silc_argument_get_arg_type(args, 3, NULL);
1294 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1301 if (cp[i++] == '\n') {
1302 memset(line, 0, sizeof(line));
1303 silc_strncat(line, sizeof(line), cp, i - 1);
1310 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1319 /* Notify application */
1320 silc_client_command_callback(cmd, motd);
1323 silc_fsm_next(fsm, silc_client_command_reply_processed);
1324 return SILC_FSM_CONTINUE;
1327 /********************************** UMODE ***********************************/
1329 /* Received reply to the UMODE command. Save the current user mode */
1331 SILC_FSM_STATE(silc_client_command_reply_umode)
1333 SilcClientCommandContext cmd = fsm_context;
1334 SilcClientConnection conn = cmd->conn;
1335 SilcCommandPayload payload = state_context;
1336 SilcArgumentPayload args = silc_command_get_args(payload);
1338 SilcUInt32 mode, len;
1341 CHECK_STATUS("Cannot change mode: ");
1344 tmp = silc_argument_get_arg_type(args, 2, &len);
1345 if (!tmp || len != 4) {
1346 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1350 SILC_GET32_MSB(mode, tmp);
1351 conn->local_entry->mode = mode;
1353 /* Notify application */
1354 silc_client_command_callback(cmd, mode);
1357 silc_fsm_next(fsm, silc_client_command_reply_processed);
1358 return SILC_FSM_CONTINUE;
1361 /********************************** CMODE ***********************************/
1363 /* Received reply for CMODE command. */
1365 SILC_FSM_STATE(silc_client_command_reply_cmode)
1367 SilcClientCommandContext cmd = fsm_context;
1368 SilcClientConnection conn = cmd->conn;
1369 SilcClient client = conn->client;
1370 SilcCommandPayload payload = state_context;
1371 SilcArgumentPayload args = silc_command_get_args(payload);
1374 SilcChannelEntry channel;
1376 SilcPublicKey public_key = NULL;
1377 SilcDList channel_pubkeys = NULL;
1381 CHECK_STATUS("Cannot change mode: ");
1384 /* Take Channel ID */
1385 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1386 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1390 /* Get the channel entry */
1391 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1393 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1397 /* Get channel mode */
1398 tmp = silc_argument_get_arg_type(args, 3, &len);
1399 if (!tmp || len != 4) {
1400 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1405 SILC_GET32_MSB(mode, tmp);
1406 channel->mode = mode;
1408 /* Get founder public key */
1409 tmp = silc_argument_get_arg_type(args, 4, &len);
1411 silc_public_key_payload_decode(tmp, len, &public_key);
1413 /* Get user limit */
1414 tmp = silc_argument_get_arg_type(args, 6, &len);
1415 if (tmp && len == 4)
1416 SILC_GET32_MSB(channel->user_limit, tmp);
1417 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1418 channel->user_limit = 0;
1420 /* Get channel public key(s) */
1421 tmp = silc_argument_get_arg_type(args, 5, &len);
1424 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1426 /* Notify application */
1427 silc_client_command_callback(cmd, channel, mode, public_key,
1428 channel_pubkeys, channel->user_limit);
1430 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1434 silc_pkcs_public_key_free(public_key);
1435 silc_fsm_next(fsm, silc_client_command_reply_processed);
1436 return SILC_FSM_CONTINUE;
1439 /********************************** CUMODE **********************************/
1441 /* Received reply for CUMODE command */
1443 SILC_FSM_STATE(silc_client_command_reply_cumode)
1445 SilcClientCommandContext cmd = fsm_context;
1446 SilcClientConnection conn = cmd->conn;
1447 SilcClient client = conn->client;
1448 SilcCommandPayload payload = state_context;
1449 SilcArgumentPayload args = silc_command_get_args(payload);
1450 SilcClientEntry client_entry;
1451 SilcChannelEntry channel;
1452 SilcChannelUser chu;
1453 unsigned char *modev;
1454 SilcUInt32 len, mode;
1458 CHECK_STATUS("Cannot change mode: ");
1461 /* Get channel mode */
1462 modev = silc_argument_get_arg_type(args, 2, &len);
1463 if (!modev || len != 4) {
1464 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1467 SILC_GET32_MSB(mode, modev);
1469 /* Take Channel ID */
1470 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1471 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1475 /* Get the channel entry */
1476 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1478 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1483 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1484 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1488 /* Get client entry */
1489 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1490 if (!client_entry) {
1491 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1496 chu = silc_client_on_channel(channel, client_entry);
1500 /* Notify application */
1501 silc_client_command_callback(cmd, mode, channel, client_entry);
1503 silc_client_unref_client(client, conn, client_entry);
1506 silc_fsm_next(fsm, silc_client_command_reply_processed);
1507 return SILC_FSM_CONTINUE;
1510 /********************************** KICK ************************************/
1512 SILC_FSM_STATE(silc_client_command_reply_kick)
1514 SilcClientCommandContext cmd = fsm_context;
1515 SilcClientConnection conn = cmd->conn;
1516 SilcClient client = conn->client;
1517 SilcCommandPayload payload = state_context;
1518 SilcArgumentPayload args = silc_command_get_args(payload);
1519 SilcClientEntry client_entry;
1520 SilcChannelEntry channel;
1524 CHECK_STATUS("Cannot kick: ");
1527 /* Take Channel ID */
1528 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1529 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1533 /* Get the channel entry */
1534 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1536 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1541 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1542 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1546 /* Get client entry */
1547 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1548 if (!client_entry) {
1549 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1553 /* Notify application */
1554 silc_client_command_callback(cmd, channel, client_entry);
1556 silc_client_unref_client(client, conn, client_entry);
1559 silc_fsm_next(fsm, silc_client_command_reply_processed);
1560 return SILC_FSM_CONTINUE;
1563 /******************************** SILCOPER **********************************/
1565 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1567 SilcClientCommandContext cmd = fsm_context;
1568 SilcCommandPayload payload = state_context;
1569 SilcArgumentPayload args = silc_command_get_args(payload);
1572 CHECK_STATUS("Cannot change mode: ");
1575 /* Notify application */
1576 silc_client_command_callback(cmd);
1578 silc_fsm_next(fsm, silc_client_command_reply_processed);
1579 return SILC_FSM_CONTINUE;
1582 /********************************** OPER ************************************/
1584 SILC_FSM_STATE(silc_client_command_reply_oper)
1586 SilcClientCommandContext cmd = fsm_context;
1587 SilcCommandPayload payload = state_context;
1588 SilcArgumentPayload args = silc_command_get_args(payload);
1591 CHECK_STATUS("Cannot change mode: ");
1594 /* Notify application */
1595 silc_client_command_callback(cmd);
1597 silc_fsm_next(fsm, silc_client_command_reply_processed);
1598 return SILC_FSM_CONTINUE;
1601 /********************************* DETACH ***********************************/
1603 SILC_FSM_STATE(silc_client_command_reply_detach)
1605 SilcClientCommandContext cmd = fsm_context;
1606 SilcClientConnection conn = cmd->conn;
1607 SilcClient client = conn->client;
1608 SilcCommandPayload payload = state_context;
1609 SilcArgumentPayload args = silc_command_get_args(payload);
1613 CHECK_STATUS("Cannot detach: ");
1616 /* Notify application */
1617 silc_client_command_callback(cmd);
1620 /* Generate the detachment data and deliver it to the client in the
1621 detach client operation */
1622 detach = silc_client_get_detach_data(client, conn);
1624 client->internal->ops->detach(client, conn, silc_buffer_data(detach),
1625 silc_buffer_len(detach));
1626 silc_buffer_free(detach);
1630 silc_fsm_next(fsm, silc_client_command_reply_processed);
1631 return SILC_FSM_CONTINUE;
1634 /********************************** WATCH ***********************************/
1636 SILC_FSM_STATE(silc_client_command_reply_watch)
1638 SilcClientCommandContext cmd = fsm_context;
1639 SilcCommandPayload payload = state_context;
1640 SilcArgumentPayload args = silc_command_get_args(payload);
1643 CHECK_STATUS("Cannot set watch: ");
1646 /* Notify application */
1647 silc_client_command_callback(cmd);
1649 silc_fsm_next(fsm, silc_client_command_reply_processed);
1650 return SILC_FSM_CONTINUE;
1653 /*********************************** BAN ************************************/
1655 SILC_FSM_STATE(silc_client_command_reply_ban)
1657 SilcClientCommandContext cmd = fsm_context;
1658 SilcClientConnection conn = cmd->conn;
1659 SilcClient client = conn->client;
1660 SilcCommandPayload payload = state_context;
1661 SilcArgumentPayload args = silc_command_get_args(payload);
1662 SilcChannelEntry channel;
1665 SilcArgumentPayload invite_args = NULL;
1669 CHECK_STATUS("Cannot set ban: ");
1672 /* Take Channel ID */
1673 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1674 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1678 /* Get the channel entry */
1679 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1681 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1685 /* Get the invite list */
1686 tmp = silc_argument_get_arg_type(args, 3, &len);
1688 invite_args = silc_argument_list_parse(tmp, len);
1690 /* Notify application */
1691 silc_client_command_callback(cmd, channel, invite_args);
1694 silc_argument_payload_free(invite_args);
1697 silc_fsm_next(fsm, silc_client_command_reply_processed);
1698 return SILC_FSM_CONTINUE;
1701 /********************************** LEAVE ***********************************/
1703 /* Reply to LEAVE command. */
1705 SILC_FSM_STATE(silc_client_command_reply_leave)
1707 SilcClientCommandContext cmd = fsm_context;
1708 SilcClientConnection conn = cmd->conn;
1709 SilcClient client = conn->client;
1710 SilcCommandPayload payload = state_context;
1711 SilcArgumentPayload args = silc_command_get_args(payload);
1712 SilcChannelEntry channel;
1716 CHECK_STATUS("Cannot set leave: ");
1719 /* Get Channel ID */
1720 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1721 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1725 /* Get the channel entry */
1726 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1728 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1732 /* Remove us from this channel. */
1733 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1735 /* Notify application */
1736 silc_client_command_callback(cmd, channel);
1738 /* Now delete the channel. */
1739 silc_client_empty_channel(client, conn, channel);
1740 silc_client_del_channel(client, conn, channel);
1743 silc_fsm_next(fsm, silc_client_command_reply_processed);
1744 return SILC_FSM_CONTINUE;
1747 /********************************* USERS ************************************/
1749 /* Continue USERS command reply processing after resolving unknown users */
1752 silc_client_command_reply_users_resolved(SilcClient client,
1753 SilcClientConnection conn,
1758 SilcClientCommandContext cmd = context;
1759 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1763 /* Continue USERS command after resolving unknown channel */
1766 silc_client_command_reply_users_continue(SilcClient client,
1767 SilcClientConnection conn,
1772 SilcClientCommandContext cmd = context;
1775 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1776 SilcArgumentPayload args = silc_command_get_args(payload);
1778 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1779 ERROR_CALLBACK(cmd->status);
1780 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1783 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1786 /* Reply to USERS command. Received list of client ID's and theirs modes
1787 on the channel we requested. */
1789 SILC_FSM_STATE(silc_client_command_reply_users)
1791 SilcClientCommandContext cmd = fsm_context;
1792 SilcClientConnection conn = cmd->conn;
1793 SilcClient client = conn->client;
1794 SilcCommandPayload payload = state_context;
1795 SilcArgumentPayload args = silc_command_get_args(payload);
1797 SilcUInt32 tmp_len, list_count;
1798 SilcUInt16 idp_len, mode;
1799 SilcHashTableList htl;
1800 SilcBufferStruct client_id_list, client_mode_list;
1801 SilcChannelEntry channel;
1802 SilcClientEntry client_entry;
1807 CHECK_STATUS("Cannot get users: ");
1810 /* Get channel ID */
1811 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1812 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1816 /* Get channel entry */
1817 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1819 /* Resolve the channel from server */
1820 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1821 client, conn, &id.u.channel_id,
1822 silc_client_command_reply_users_continue, cmd));
1826 /* Get the list count */
1827 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1828 if (!tmp || tmp_len != 4) {
1829 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1832 SILC_GET32_MSB(list_count, tmp);
1834 /* Get Client ID list */
1835 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1837 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1840 silc_buffer_set(&client_id_list, tmp, tmp_len);
1842 /* Resolve users we do not know about */
1843 if (!cmd->resolved) {
1844 cmd->resolved = TRUE;
1845 SILC_FSM_CALL(silc_client_get_clients_by_list(
1846 client, conn, list_count, &client_id_list,
1847 silc_client_command_reply_users_resolved, cmd));
1851 /* Get client mode list */
1852 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1854 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1857 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1859 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1861 /* Cache the received Client ID's and modes. */
1862 for (i = 0; i < list_count; i++) {
1863 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1865 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1869 SILC_GET32_MSB(mode, client_mode_list.data);
1871 /* Save the client on this channel. Unknown clients are ignored as they
1872 clearly do not exist since the resolving didn't find them. */
1873 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1875 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1876 silc_client_unref_client(client, conn, client_entry);
1878 if (!silc_buffer_pull(&client_id_list, idp_len))
1880 if (!silc_buffer_pull(&client_mode_list, 4))
1884 /* Notify application */
1885 silc_hash_table_list(channel->user_list, &htl);
1886 silc_client_command_callback(cmd, channel, &htl);
1887 silc_hash_table_list_reset(&htl);
1890 silc_fsm_next(fsm, silc_client_command_reply_processed);
1891 return SILC_FSM_CONTINUE;
1894 /********************************** GETKEY **********************************/
1896 /* Received command reply to GETKEY command. WE've received the remote
1897 client's public key. */
1899 SILC_FSM_STATE(silc_client_command_reply_getkey)
1901 SilcClientCommandContext cmd = fsm_context;
1902 SilcClientConnection conn = cmd->conn;
1903 SilcClient client = conn->client;
1904 SilcCommandPayload payload = state_context;
1905 SilcArgumentPayload args = silc_command_get_args(payload);
1906 SilcClientEntry client_entry;
1907 SilcServerEntry server_entry;
1910 SilcPublicKey public_key;
1914 CHECK_STATUS("Cannot get key: ");
1918 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1919 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1923 /* Get the public key */
1924 tmp = silc_argument_get_arg_type(args, 3, &len);
1926 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1929 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1930 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1934 if (id.type == SILC_ID_CLIENT) {
1935 /* Received client's public key */
1936 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1937 if (!client_entry) {
1938 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1942 /* Save fingerprint */
1943 if (!client_entry->fingerprint)
1944 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
1945 client_entry->fingerprint);
1946 if (!client_entry->public_key) {
1947 client_entry->public_key = public_key;
1951 /* Notify application */
1952 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1953 client_entry->public_key);
1954 silc_client_unref_client(client, conn, client_entry);
1955 } else if (id.type == SILC_ID_SERVER) {
1956 /* Received server's public key */
1957 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1958 if (!server_entry) {
1959 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1963 if (!server_entry->public_key) {
1964 server_entry->public_key = public_key;
1968 /* Notify application */
1969 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1970 server_entry->public_key);
1971 silc_client_unref_server(client, conn, server_entry);
1976 silc_pkcs_public_key_free(public_key);
1977 silc_fsm_next(fsm, silc_client_command_reply_processed);
1978 return SILC_FSM_CONTINUE;
1981 /********************************** SERVICE *********************************/
1983 /* Reply to SERVICE command. */
1984 /* XXX incomplete */
1986 SILC_FSM_STATE(silc_client_command_reply_service)
1988 SilcClientCommandContext cmd = fsm_context;
1989 SilcCommandPayload payload = state_context;
1990 SilcArgumentPayload args = silc_command_get_args(payload);
1992 unsigned char *service_list, *name;
1995 CHECK_STATUS("Cannot get service: ");
1997 /* Get service list */
1998 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2000 /* Get requested service name */
2001 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2003 /* Notify application */
2004 silc_client_command_callback(cmd, service_list, name);
2006 silc_fsm_next(fsm, silc_client_command_reply_processed);
2007 return SILC_FSM_CONTINUE;
2010 /*********************************** QUIT ***********************************/
2012 /* QUIT command reply stub */
2014 SILC_FSM_STATE(silc_client_command_reply_quit)
2016 silc_fsm_next(fsm, silc_client_command_reply_processed);
2017 return SILC_FSM_CONTINUE;