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;
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);
109 SilcClientEntry client_entry;
112 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
113 /* Remove unknown client entry from cache */
114 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
117 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
119 silc_client_remove_from_channels(client, conn, client_entry);
120 silc_client_del_client(client, conn, client_entry);
121 silc_client_unref_client(client, conn, client_entry);
126 /***************************** Command Reply ********************************/
128 /* Process received command reply packet */
130 SILC_FSM_STATE(silc_client_command_reply)
132 SilcClientConnection conn = fsm_context;
133 SilcPacket packet = state_context;
134 SilcClientCommandContext cmd;
135 SilcCommandPayload payload;
137 SilcUInt16 cmd_ident;
139 /* Get command reply payload from packet */
140 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
141 silc_packet_free(packet);
143 SILC_LOG_DEBUG(("Bad command reply packet"));
144 return SILC_FSM_FINISH;
147 cmd_ident = silc_command_get_ident(payload);
148 command = silc_command_get(payload);
150 /* Find the command pending reply */
151 silc_mutex_lock(conn->internal->lock);
152 silc_list_start(conn->internal->pending_commands);
153 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
154 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
155 && cmd->cmd_ident == cmd_ident) {
156 silc_list_del(conn->internal->pending_commands, cmd);
160 silc_mutex_unlock(conn->internal->lock);
163 SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
164 silc_get_command_name(command), cmd_ident));
165 silc_command_payload_free(payload);
166 return SILC_FSM_FINISH;
169 /* Signal command thread that command reply has arrived */
170 silc_fsm_set_state_context(&cmd->thread, payload);
171 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
172 silc_fsm_continue_sync(&cmd->thread);
174 return SILC_FSM_FINISH;
177 /* Wait here for command reply to arrive from remote host */
179 SILC_FSM_STATE(silc_client_command_reply_wait)
181 SilcClientCommandContext cmd = fsm_context;
183 SILC_LOG_DEBUG(("Wait for command reply"));
185 /** Wait for command reply */
186 silc_fsm_set_state_context(fsm, NULL);
187 silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
188 cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0);
189 return SILC_FSM_WAIT;
192 /* Timeout occurred while waiting command reply */
194 SILC_FSM_STATE(silc_client_command_reply_timeout)
196 SilcClientCommandContext cmd = fsm_context;
197 SilcClientConnection conn = cmd->conn;
198 SilcArgumentPayload args = NULL;
200 if (conn->internal->disconnected) {
201 SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
202 silc_list_del(conn->internal->pending_commands, cmd);
203 return SILC_FSM_FINISH;
206 SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
208 /* Timeout, reply not received in timely fashion */
209 silc_list_del(conn->internal->pending_commands, cmd);
210 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
211 return SILC_FSM_FINISH;
214 /* Process received command reply payload */
216 SILC_FSM_STATE(silc_client_command_reply_process)
218 SilcClientCommandContext cmd = fsm_context;
219 SilcCommandPayload payload = state_context;
221 silc_command_get_status(payload, &cmd->status, &cmd->error);
224 case SILC_COMMAND_WHOIS:
226 silc_fsm_next(fsm, silc_client_command_reply_whois);
228 case SILC_COMMAND_WHOWAS:
230 silc_fsm_next(fsm, silc_client_command_reply_whowas);
232 case SILC_COMMAND_IDENTIFY:
234 silc_fsm_next(fsm, silc_client_command_reply_identify);
236 case SILC_COMMAND_NICK:
238 silc_fsm_next(fsm, silc_client_command_reply_nick);
240 case SILC_COMMAND_LIST:
242 silc_fsm_next(fsm, silc_client_command_reply_list);
244 case SILC_COMMAND_TOPIC:
246 silc_fsm_next(fsm, silc_client_command_reply_topic);
248 case SILC_COMMAND_INVITE:
250 silc_fsm_next(fsm, silc_client_command_reply_invite);
252 case SILC_COMMAND_QUIT:
254 silc_fsm_next(fsm, silc_client_command_reply_quit);
256 case SILC_COMMAND_KILL:
258 silc_fsm_next(fsm, silc_client_command_reply_kill);
260 case SILC_COMMAND_INFO:
262 silc_fsm_next(fsm, silc_client_command_reply_info);
264 case SILC_COMMAND_STATS:
266 silc_fsm_next(fsm, silc_client_command_reply_stats);
268 case SILC_COMMAND_PING:
270 silc_fsm_next(fsm, silc_client_command_reply_ping);
272 case SILC_COMMAND_OPER:
274 silc_fsm_next(fsm, silc_client_command_reply_oper);
276 case SILC_COMMAND_JOIN:
278 silc_fsm_next(fsm, silc_client_command_reply_join);
280 case SILC_COMMAND_MOTD:
282 silc_fsm_next(fsm, silc_client_command_reply_motd);
284 case SILC_COMMAND_UMODE:
286 silc_fsm_next(fsm, silc_client_command_reply_umode);
288 case SILC_COMMAND_CMODE:
290 silc_fsm_next(fsm, silc_client_command_reply_cmode);
292 case SILC_COMMAND_CUMODE:
294 silc_fsm_next(fsm, silc_client_command_reply_cumode);
296 case SILC_COMMAND_KICK:
298 silc_fsm_next(fsm, silc_client_command_reply_kick);
300 case SILC_COMMAND_BAN:
302 silc_fsm_next(fsm, silc_client_command_reply_ban);
304 case SILC_COMMAND_DETACH:
306 silc_fsm_next(fsm, silc_client_command_reply_detach);
308 case SILC_COMMAND_WATCH:
310 silc_fsm_next(fsm, silc_client_command_reply_watch);
312 case SILC_COMMAND_SILCOPER:
314 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
316 case SILC_COMMAND_LEAVE:
318 silc_fsm_next(fsm, silc_client_command_reply_leave);
320 case SILC_COMMAND_USERS:
322 silc_fsm_next(fsm, silc_client_command_reply_users);
324 case SILC_COMMAND_GETKEY:
326 silc_fsm_next(fsm, silc_client_command_reply_getkey);
328 case SILC_COMMAND_SERVICE:
330 silc_fsm_next(fsm, silc_client_command_reply_service);
333 return SILC_FSM_FINISH;
336 return SILC_FSM_CONTINUE;
339 /* Completes command reply processing */
341 SILC_FSM_STATE(silc_client_command_reply_processed)
343 SilcClientCommandContext cmd = fsm_context;
344 SilcClientConnection conn = cmd->conn;
345 SilcCommandPayload payload = state_context;
347 silc_command_payload_free(payload);
349 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
350 SILC_STATUS_IS_ERROR(cmd->status))
351 return SILC_FSM_FINISH;
353 /* Add back to pending command reply list */
354 silc_mutex_lock(conn->internal->lock);
355 cmd->resolved = FALSE;
356 silc_list_add(conn->internal->pending_commands, cmd);
357 silc_mutex_unlock(conn->internal->lock);
359 /** Wait more command payloads */
360 silc_fsm_next(fsm, silc_client_command_reply_wait);
361 return SILC_FSM_CONTINUE;
364 /******************************** WHOIS *************************************/
366 /* Received reply for WHOIS command. */
368 SILC_FSM_STATE(silc_client_command_reply_whois)
370 SilcClientCommandContext cmd = fsm_context;
371 SilcClientConnection conn = cmd->conn;
372 SilcClient client = conn->client;
373 SilcCommandPayload payload = state_context;
374 SilcArgumentPayload args = silc_command_get_args(payload);
375 SilcClientEntry client_entry = NULL;
376 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
377 SilcBufferStruct channels, ch_user_modes;
378 SilcBool has_channels = FALSE;
379 SilcDList channel_list = NULL;
381 char *nickname = NULL, *username = NULL, *realname = NULL;
382 unsigned char *fingerprint, *tmp;
384 CHECK_STATUS("WHOIS: ");
388 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
389 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
394 nickname = silc_argument_get_arg_type(args, 3, NULL);
395 username = silc_argument_get_arg_type(args, 4, NULL);
396 realname = silc_argument_get_arg_type(args, 5, NULL);
397 if (!nickname || !username || !realname) {
398 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
402 /* Get joined channel list */
403 memset(&channels, 0, sizeof(channels));
404 tmp = silc_argument_get_arg_type(args, 6, &len);
407 silc_buffer_set(&channels, tmp, len);
409 /* Get channel user mode list */
410 tmp = silc_argument_get_arg_type(args, 10, &len);
412 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
415 silc_buffer_set(&ch_user_modes, tmp, len);
419 tmp = silc_argument_get_arg_type(args, 7, &len);
421 SILC_GET32_MSB(mode, tmp);
424 tmp = silc_argument_get_arg_type(args, 8, &len);
426 SILC_GET32_MSB(idle, tmp);
428 /* Get fingerprint */
429 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
431 /* Check if we have this client cached already. */
432 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
434 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
436 silc_client_add_client(client, conn, nickname, username, realname,
437 &id.u.client_id, mode);
439 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
442 silc_client_ref_client(client, conn, client_entry);
444 silc_client_update_client(client, conn, client_entry,
445 nickname, username, realname, mode);
448 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
449 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
451 /* Get user attributes */
452 tmp = silc_argument_get_arg_type(args, 11, &len);
454 if (client_entry->attrs)
455 silc_attribute_payload_list_free(client_entry->attrs);
456 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
459 /* Parse channel and channel user mode list */
461 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
462 silc_buffer_len(&channels));
464 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
468 /* Notify application */
469 silc_client_command_callback(cmd, client_entry, nickname, username,
470 realname, channel_list, mode, idle, fingerprint,
471 umodes, client_entry->attrs);
473 silc_client_unref_client(client, conn, client_entry);
475 silc_dlist_uninit(channel_list);
480 silc_fsm_next(fsm, silc_client_command_reply_processed);
481 return SILC_FSM_CONTINUE;
484 /******************************** WHOWAS ************************************/
486 /* Received reply for WHOWAS command. */
488 SILC_FSM_STATE(silc_client_command_reply_whowas)
490 SilcClientCommandContext cmd = fsm_context;
491 SilcClientConnection conn = cmd->conn;
492 SilcClient client = conn->client;
493 SilcCommandPayload payload = state_context;
494 SilcArgumentPayload args = silc_command_get_args(payload);
495 SilcClientEntry client_entry = NULL;
497 char *nickname, *username;
498 char *realname = NULL;
500 CHECK_STATUS("WHOWAS: ");
504 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
505 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
509 /* Get the client entry */
510 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
513 nickname = silc_argument_get_arg_type(args, 3, NULL);
514 username = silc_argument_get_arg_type(args, 4, NULL);
515 realname = silc_argument_get_arg_type(args, 5, NULL);
516 if (!nickname || !username) {
517 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
521 /* Notify application. We don't save any history information to any
522 cache. Just pass the data to the application. */
523 silc_client_command_callback(cmd, client_entry, nickname, username,
527 silc_client_unref_client(client, conn, client_entry);
528 silc_fsm_next(fsm, silc_client_command_reply_processed);
529 return SILC_FSM_CONTINUE;
532 /******************************** IDENTIFY **********************************/
534 /* Received reply for IDENTIFY command. */
536 SILC_FSM_STATE(silc_client_command_reply_identify)
538 SilcClientCommandContext cmd = fsm_context;
539 SilcClientConnection conn = cmd->conn;
540 SilcClient client = conn->client;
541 SilcCommandPayload payload = state_context;
542 SilcArgumentPayload args = silc_command_get_args(payload);
543 SilcClientEntry client_entry;
544 SilcServerEntry server_entry;
545 SilcChannelEntry channel_entry;
548 char *name = NULL, *info = NULL;
550 CHECK_STATUS("IDENTIFY: ");
554 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
555 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
560 name = silc_argument_get_arg_type(args, 3, &len);
561 info = silc_argument_get_arg_type(args, 4, &len);
565 SILC_LOG_DEBUG(("Received client information"));
567 /* Check if we have this client cached already. */
568 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
570 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
572 silc_client_add_client(client, conn, name, info, NULL,
575 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
578 silc_client_ref_client(client, conn, client_entry);
580 silc_client_update_client(client, conn, client_entry,
581 name, info, NULL, 0);
584 /* Notify application */
585 silc_client_command_callback(cmd, client_entry, name, info);
586 silc_client_unref_client(client, conn, client_entry);
590 SILC_LOG_DEBUG(("Received server information"));
592 /* Check if we have this server cached already. */
593 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
595 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
596 server_entry = silc_client_add_server(client, conn, name, info,
599 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
602 silc_client_ref_server(client, conn, server_entry);
604 silc_client_update_server(client, conn, server_entry, name, info);
606 server_entry->internal.resolve_cmd_ident = 0;
608 /* Notify application */
609 silc_client_command_callback(cmd, server_entry, name, info);
610 silc_client_unref_server(client, conn, server_entry);
613 case SILC_ID_CHANNEL:
614 SILC_LOG_DEBUG(("Received channel information"));
616 /* Check if we have this channel cached already. */
617 channel_entry = silc_client_get_channel_by_id(client, conn,
619 if (!channel_entry) {
620 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
623 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
627 /* Add new channel entry */
628 channel_entry = silc_client_add_channel(client, conn, name, 0,
630 if (!channel_entry) {
631 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
634 silc_client_ref_channel(client, conn, channel_entry);
637 /* Notify application */
638 silc_client_command_callback(cmd, channel_entry, name, info);
639 silc_client_unref_channel(client, conn, channel_entry);
644 silc_fsm_next(fsm, silc_client_command_reply_processed);
645 return SILC_FSM_CONTINUE;
648 /********************************** NICK ************************************/
650 /* Received reply for command NICK. */
652 SILC_FSM_STATE(silc_client_command_reply_nick)
654 SilcClientCommandContext cmd = fsm_context;
655 SilcClientConnection conn = cmd->conn;
656 SilcClient client = conn->client;
657 SilcCommandPayload payload = state_context;
658 SilcArgumentPayload args = silc_command_get_args(payload);
659 unsigned char *tmp, *nick, *idp;
660 SilcUInt32 len, idp_len;
661 SilcClientID old_client_id;
665 CHECK_STATUS("Cannot set nickname: ");
668 old_client_id = *conn->local_id;
670 /* Take received Client ID */
671 idp = silc_argument_get_arg_type(args, 2, &idp_len);
673 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
676 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
677 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
681 /* Take the new nickname */
682 nick = silc_argument_get_arg_type(args, 3, &len);
684 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
688 /* Normalize nickname */
689 tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
691 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
695 /* Update the client entry */
696 silc_mutex_lock(conn->internal->lock);
697 if (!silc_idcache_update(conn->internal->client_cache,
698 conn->internal->local_entry,
699 &id.u.client_id, tmp, TRUE)) {
701 silc_mutex_unlock(conn->internal->lock);
702 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
705 silc_mutex_unlock(conn->internal->lock);
706 memset(conn->local_entry->nickname, 0, sizeof(conn->local_entry->nickname));
707 memcpy(conn->local_entry->nickname, nick, len);
708 conn->local_entry->nickname_normalized = tmp;
709 silc_buffer_enlarge(conn->internal->local_idp, idp_len);
710 silc_buffer_put(conn->internal->local_idp, idp, idp_len);
711 silc_client_nickname_format(client, conn, conn->local_entry);
712 silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id, 0, NULL);
714 /* Notify application */
715 silc_client_command_callback(cmd, conn->local_entry,
716 conn->local_entry->nickname, &old_client_id);
719 silc_fsm_next(fsm, silc_client_command_reply_processed);
720 return SILC_FSM_CONTINUE;
723 /********************************** LIST ************************************/
725 /* Received reply to the LIST command. */
727 SILC_FSM_STATE(silc_client_command_reply_list)
729 SilcClientCommandContext cmd = fsm_context;
730 SilcClientConnection conn = cmd->conn;
731 SilcClient client = conn->client;
732 SilcCommandPayload payload = state_context;
733 SilcArgumentPayload args = silc_command_get_args(payload);
734 unsigned char *tmp, *name, *topic;
735 SilcUInt32 usercount = 0;
736 SilcChannelEntry channel_entry = NULL;
740 CHECK_STATUS("Cannot list channels: ");
742 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
743 /* There were no channels in the network. */
744 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
745 silc_fsm_next(fsm, silc_client_command_reply_processed);
746 return SILC_FSM_CONTINUE;
751 name = silc_argument_get_arg_type(args, 3, NULL);
753 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
757 topic = silc_argument_get_arg_type(args, 4, NULL);
758 tmp = silc_argument_get_arg_type(args, 5, NULL);
760 SILC_GET32_MSB(usercount, tmp);
762 /* Check whether the channel exists, and add it to cache if it doesn't. */
763 channel_entry = silc_client_get_channel_by_id(client, conn,
765 if (!channel_entry) {
766 /* Add new channel entry */
767 channel_entry = silc_client_add_channel(client, conn, name, 0,
769 if (!channel_entry) {
770 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
773 silc_client_ref_channel(client, conn, channel_entry);
776 /* Notify application */
777 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
780 silc_client_unref_channel(client, conn, channel_entry);
781 silc_fsm_next(fsm, silc_client_command_reply_processed);
782 return SILC_FSM_CONTINUE;
785 /********************************* TOPIC ************************************/
787 /* Received reply to topic command. */
789 SILC_FSM_STATE(silc_client_command_reply_topic)
791 SilcClientCommandContext cmd = fsm_context;
792 SilcClientConnection conn = cmd->conn;
793 SilcClient client = conn->client;
794 SilcCommandPayload payload = state_context;
795 SilcArgumentPayload args = silc_command_get_args(payload);
796 SilcChannelEntry channel;
802 CHECK_STATUS("Cannot set topic: ");
805 /* Take Channel ID */
806 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
807 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
811 /* Get the channel entry */
812 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
814 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
819 topic = silc_argument_get_arg_type(args, 3, &len);
821 silc_free(channel->topic);
822 channel->topic = silc_memdup(topic, len);
825 /* Notify application */
826 silc_client_command_callback(cmd, channel, channel->topic);
829 silc_fsm_next(fsm, silc_client_command_reply_processed);
830 return SILC_FSM_CONTINUE;
833 /********************************* INVITE ***********************************/
835 /* Received reply to invite command. */
837 SILC_FSM_STATE(silc_client_command_reply_invite)
839 SilcClientCommandContext cmd = fsm_context;
840 SilcClientConnection conn = cmd->conn;
841 SilcClient client = conn->client;
842 SilcCommandPayload payload = state_context;
843 SilcArgumentPayload args = silc_command_get_args(payload);
844 SilcChannelEntry channel;
847 SilcArgumentPayload invite_args = NULL;
851 CHECK_STATUS("Cannot invite: ");
854 /* Take Channel ID */
855 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
856 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
860 /* Get the channel entry */
861 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
863 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
867 /* Get the invite list */
868 tmp = silc_argument_get_arg_type(args, 3, &len);
870 invite_args = silc_argument_list_parse(tmp, len);
872 /* Notify application */
873 silc_client_command_callback(cmd, channel, invite_args);
876 silc_argument_payload_free(invite_args);
879 silc_fsm_next(fsm, silc_client_command_reply_processed);
880 return SILC_FSM_CONTINUE;
883 /********************************** KILL ************************************/
885 /* Received reply to the KILL command. */
887 SILC_FSM_STATE(silc_client_command_reply_kill)
889 SilcClientCommandContext cmd = fsm_context;
890 SilcClientConnection conn = cmd->conn;
891 SilcClient client = conn->client;
892 SilcCommandPayload payload = state_context;
893 SilcArgumentPayload args = silc_command_get_args(payload);
894 SilcClientEntry client_entry;
898 CHECK_STATUS("Cannot kill: ");
901 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
902 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
906 /* Get the client entry, if exists */
907 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
909 /* Notify application */
910 silc_client_command_callback(cmd, client_entry);
912 /* Remove the client from all channels and free it */
914 silc_client_remove_from_channels(client, conn, client_entry);
915 silc_client_del_client(client, conn, client_entry);
916 silc_client_unref_client(client, conn, client_entry);
920 silc_fsm_next(fsm, silc_client_command_reply_processed);
921 return SILC_FSM_CONTINUE;
924 /********************************** INFO ************************************/
926 /* Received reply to INFO command. We receive the server ID and some
927 information about the server user requested. */
929 SILC_FSM_STATE(silc_client_command_reply_info)
931 SilcClientCommandContext cmd = fsm_context;
932 SilcClientConnection conn = cmd->conn;
933 SilcClient client = conn->client;
934 SilcCommandPayload payload = state_context;
935 SilcArgumentPayload args = silc_command_get_args(payload);
936 SilcServerEntry server;
937 char *server_name, *server_info;
941 CHECK_STATUS("Cannot get info: ");
945 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
946 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
950 /* Get server name */
951 server_name = silc_argument_get_arg_type(args, 3, NULL);
953 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
957 /* Get server info */
958 server_info = silc_argument_get_arg_type(args, 4, NULL);
960 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
964 /* See whether we have this server cached. If not create it. */
965 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
967 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
968 server = silc_client_add_server(client, conn, server_name,
969 server_info, &id.u.server_id);
972 silc_client_ref_server(client, conn, server);
975 /* Notify application */
976 silc_client_command_callback(cmd, server, server->server_name,
977 server->server_info);
978 silc_client_unref_server(client, conn, server);
981 silc_fsm_next(fsm, silc_client_command_reply_processed);
982 return SILC_FSM_CONTINUE;
985 /********************************** STATS ***********************************/
987 /* Received reply to STATS command. */
989 SILC_FSM_STATE(silc_client_command_reply_stats)
991 SilcClientCommandContext cmd = fsm_context;
992 SilcCommandPayload payload = state_context;
993 SilcArgumentPayload args = silc_command_get_args(payload);
994 SilcClientStats stats;
995 unsigned char *buf = NULL;
996 SilcUInt32 buf_len = 0;
1001 CHECK_STATUS("Cannot get stats: ");
1005 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1006 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1010 /* Get statistics structure */
1011 memset(&stats, 0, sizeof(stats));
1012 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1014 silc_buffer_set(&b, buf, buf_len);
1015 silc_buffer_unformat(&b,
1016 SILC_STR_UI_INT(&stats.starttime),
1017 SILC_STR_UI_INT(&stats.uptime),
1018 SILC_STR_UI_INT(&stats.my_clients),
1019 SILC_STR_UI_INT(&stats.my_channels),
1020 SILC_STR_UI_INT(&stats.my_server_ops),
1021 SILC_STR_UI_INT(&stats.my_router_ops),
1022 SILC_STR_UI_INT(&stats.cell_clients),
1023 SILC_STR_UI_INT(&stats.cell_channels),
1024 SILC_STR_UI_INT(&stats.cell_servers),
1025 SILC_STR_UI_INT(&stats.clients),
1026 SILC_STR_UI_INT(&stats.channels),
1027 SILC_STR_UI_INT(&stats.servers),
1028 SILC_STR_UI_INT(&stats.routers),
1029 SILC_STR_UI_INT(&stats.server_ops),
1030 SILC_STR_UI_INT(&stats.router_ops),
1034 /* Notify application */
1035 silc_client_command_callback(cmd, &stats);
1038 silc_fsm_next(fsm, silc_client_command_reply_processed);
1039 return SILC_FSM_CONTINUE;
1042 /********************************** PING ************************************/
1044 /* Received reply to PING command. */
1046 SILC_FSM_STATE(silc_client_command_reply_ping)
1048 SilcClientCommandContext cmd = fsm_context;
1049 SilcClientConnection conn = cmd->conn;
1050 SilcClient client = conn->client;
1053 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1055 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1056 "Ping reply from %s: %d second%s", conn->remote_host,
1057 (int)diff, diff == 1 ? "" : "s");
1059 /* Notify application */
1060 silc_client_command_callback(cmd);
1062 silc_fsm_next(fsm, silc_client_command_reply_processed);
1063 return SILC_FSM_CONTINUE;
1066 /********************************** JOIN ************************************/
1068 /* Continue JOIN command reply processing after resolving unknown users */
1071 silc_client_command_reply_join_resolved(SilcClient client,
1072 SilcClientConnection conn,
1077 SilcClientCommandContext cmd = context;
1078 SilcChannelEntry channel = cmd->context;
1080 channel->internal.resolve_cmd_ident = 0;
1081 silc_client_unref_channel(client, conn, channel);
1083 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1087 /* Received reply for JOIN command. */
1089 SILC_FSM_STATE(silc_client_command_reply_join)
1091 SilcClientCommandContext cmd = fsm_context;
1092 SilcClientConnection conn = cmd->conn;
1093 SilcClient client = conn->client;
1094 SilcCommandPayload payload = state_context;
1095 SilcArgumentPayload args = silc_command_get_args(payload);
1096 SilcChannelEntry channel;
1097 SilcUInt32 mode = 0, len, list_count;
1098 char *topic, *tmp, *channel_name = NULL, *hmac;
1100 SilcBufferStruct client_id_list, client_mode_list, keyp;
1101 SilcHashTableList htl;
1102 SilcDList chpks = NULL;
1107 CHECK_STATUS("Cannot join channel: ");
1110 /* Get channel name */
1111 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1112 if (!channel_name) {
1113 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1117 /* Get Channel ID */
1118 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1119 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1123 /* Check whether we have this channel entry already. */
1124 channel = silc_client_get_channel(client, conn, channel_name);
1126 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1127 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1129 /* Create new channel entry */
1130 channel = silc_client_add_channel(client, conn, channel_name,
1131 mode, &id.u.channel_id);
1133 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1136 silc_client_ref_channel(client, conn, channel);
1139 /* Get the list count */
1140 tmp = silc_argument_get_arg_type(args, 12, &len);
1142 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1145 SILC_GET32_MSB(list_count, tmp);
1147 /* Get Client ID list */
1148 tmp = silc_argument_get_arg_type(args, 13, &len);
1150 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1153 silc_buffer_set(&client_id_list, tmp, len);
1155 /* Resolve users we do not know about */
1156 if (!cmd->resolved) {
1157 cmd->resolved = TRUE;
1158 cmd->context = channel;
1159 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1160 silc_client_get_clients_by_list(
1161 client, conn, list_count, &client_id_list,
1162 silc_client_command_reply_join_resolved, cmd));
1166 /* Get client mode list */
1167 tmp = silc_argument_get_arg_type(args, 14, &len);
1169 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1172 silc_buffer_set(&client_mode_list, tmp, len);
1174 /* Add clients we received in the reply to the channel */
1175 for (i = 0; i < list_count; i++) {
1179 SilcClientEntry client_entry;
1182 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1184 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1188 SILC_GET32_MSB(mode, client_mode_list.data);
1190 /* Get client entry */
1191 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1195 /* Join client to the channel */
1196 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1197 silc_client_unref_client(client, conn, client_entry);
1199 if (!silc_buffer_pull(&client_id_list, idp_len))
1201 if (!silc_buffer_pull(&client_mode_list, 4))
1206 hmac = silc_argument_get_arg_type(args, 11, NULL);
1208 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1210 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1211 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1212 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1217 /* Get channel mode */
1218 tmp = silc_argument_get_arg_type(args, 5, NULL);
1220 SILC_GET32_MSB(mode, tmp);
1221 channel->mode = mode;
1223 /* Get channel key and save it */
1224 tmp = silc_argument_get_arg_type(args, 7, &len);
1226 silc_buffer_set(&keyp, tmp, len);
1227 silc_client_save_channel_key(client, conn, &keyp, channel);
1231 topic = silc_argument_get_arg_type(args, 10, NULL);
1233 silc_free(channel->topic);
1234 channel->topic = silc_memdup(topic, strlen(topic));
1237 /* Get founder key */
1238 tmp = silc_argument_get_arg_type(args, 15, &len);
1240 if (channel->founder_key)
1241 silc_pkcs_public_key_free(channel->founder_key);
1242 channel->founder_key = NULL;
1243 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1246 /* Get user limit */
1247 tmp = silc_argument_get_arg_type(args, 17, &len);
1248 if (tmp && len == 4)
1249 SILC_GET32_MSB(channel->user_limit, tmp);
1250 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1251 channel->user_limit = 0;
1253 /* Get channel public key list */
1254 tmp = silc_argument_get_arg_type(args, 16, &len);
1256 chpks = silc_argument_list_parse_decoded(tmp, len,
1257 SILC_ARGUMENT_PUBLIC_KEY);
1259 /* Set current channel */
1260 conn->current_channel = channel;
1262 cipher = (channel->internal.channel_key ?
1263 silc_cipher_get_name(channel->internal.channel_key) : NULL);
1264 silc_hash_table_list(channel->user_list, &htl);
1266 /* Notify application */
1267 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1268 topic, cipher, hmac, channel->founder_key,
1269 chpks, channel->user_limit);
1272 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
1273 silc_hash_table_list_reset(&htl);
1274 silc_client_unref_channel(client, conn, channel);
1277 silc_fsm_next(fsm, silc_client_command_reply_processed);
1278 return SILC_FSM_CONTINUE;
1281 /********************************** MOTD ************************************/
1283 /* Received reply for MOTD command */
1285 SILC_FSM_STATE(silc_client_command_reply_motd)
1287 SilcClientCommandContext cmd = fsm_context;
1288 SilcClientConnection conn = cmd->conn;
1289 SilcClient client = conn->client;
1290 SilcCommandPayload payload = state_context;
1291 SilcArgumentPayload args = silc_command_get_args(payload);
1293 char *motd = NULL, *cp, line[256];
1296 CHECK_STATUS("Cannot get motd: ");
1299 if (silc_argument_get_arg_num(args) == 3) {
1300 motd = silc_argument_get_arg_type(args, 3, NULL);
1302 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1309 if (cp[i++] == '\n') {
1310 memset(line, 0, sizeof(line));
1311 silc_strncat(line, sizeof(line), cp, i - 1);
1318 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1327 /* Notify application */
1328 silc_client_command_callback(cmd, motd);
1331 silc_fsm_next(fsm, silc_client_command_reply_processed);
1332 return SILC_FSM_CONTINUE;
1335 /********************************** UMODE ***********************************/
1337 /* Received reply to the UMODE command. Save the current user mode */
1339 SILC_FSM_STATE(silc_client_command_reply_umode)
1341 SilcClientCommandContext cmd = fsm_context;
1342 SilcClientConnection conn = cmd->conn;
1343 SilcCommandPayload payload = state_context;
1344 SilcArgumentPayload args = silc_command_get_args(payload);
1346 SilcUInt32 mode, len;
1349 CHECK_STATUS("Cannot change mode: ");
1352 tmp = silc_argument_get_arg_type(args, 2, &len);
1353 if (!tmp || len != 4) {
1354 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1358 SILC_GET32_MSB(mode, tmp);
1359 conn->local_entry->mode = mode;
1361 /* Notify application */
1362 silc_client_command_callback(cmd, mode);
1365 silc_fsm_next(fsm, silc_client_command_reply_processed);
1366 return SILC_FSM_CONTINUE;
1369 /********************************** CMODE ***********************************/
1371 /* Received reply for CMODE command. */
1373 SILC_FSM_STATE(silc_client_command_reply_cmode)
1375 SilcClientCommandContext cmd = fsm_context;
1376 SilcClientConnection conn = cmd->conn;
1377 SilcClient client = conn->client;
1378 SilcCommandPayload payload = state_context;
1379 SilcArgumentPayload args = silc_command_get_args(payload);
1382 SilcChannelEntry channel;
1384 SilcPublicKey public_key = NULL;
1385 SilcDList channel_pubkeys = NULL;
1389 CHECK_STATUS("Cannot change mode: ");
1392 /* Take Channel ID */
1393 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1394 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1398 /* Get the channel entry */
1399 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1401 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1405 /* Get channel mode */
1406 tmp = silc_argument_get_arg_type(args, 3, &len);
1407 if (!tmp || len != 4) {
1408 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1413 SILC_GET32_MSB(mode, tmp);
1414 channel->mode = mode;
1416 /* Get founder public key */
1417 tmp = silc_argument_get_arg_type(args, 4, &len);
1419 silc_public_key_payload_decode(tmp, len, &public_key);
1421 /* Get user limit */
1422 tmp = silc_argument_get_arg_type(args, 6, &len);
1423 if (tmp && len == 4)
1424 SILC_GET32_MSB(channel->user_limit, tmp);
1425 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1426 channel->user_limit = 0;
1428 /* Get channel public key(s) */
1429 tmp = silc_argument_get_arg_type(args, 5, &len);
1432 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1434 /* Notify application */
1435 silc_client_command_callback(cmd, channel, mode, public_key,
1436 channel_pubkeys, channel->user_limit);
1438 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1442 silc_pkcs_public_key_free(public_key);
1443 silc_fsm_next(fsm, silc_client_command_reply_processed);
1444 return SILC_FSM_CONTINUE;
1447 /********************************** CUMODE **********************************/
1449 /* Received reply for CUMODE command */
1451 SILC_FSM_STATE(silc_client_command_reply_cumode)
1453 SilcClientCommandContext cmd = fsm_context;
1454 SilcClientConnection conn = cmd->conn;
1455 SilcClient client = conn->client;
1456 SilcCommandPayload payload = state_context;
1457 SilcArgumentPayload args = silc_command_get_args(payload);
1458 SilcClientEntry client_entry;
1459 SilcChannelEntry channel;
1460 SilcChannelUser chu;
1461 unsigned char *modev;
1462 SilcUInt32 len, mode;
1466 CHECK_STATUS("Cannot change mode: ");
1469 /* Get channel mode */
1470 modev = silc_argument_get_arg_type(args, 2, &len);
1471 if (!modev || len != 4) {
1472 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1475 SILC_GET32_MSB(mode, modev);
1477 /* Take Channel ID */
1478 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1479 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1483 /* Get the channel entry */
1484 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1486 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1491 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1492 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1496 /* Get client entry */
1497 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1498 if (!client_entry) {
1499 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1504 chu = silc_client_on_channel(channel, client_entry);
1508 /* Notify application */
1509 silc_client_command_callback(cmd, mode, channel, client_entry);
1511 silc_client_unref_client(client, conn, client_entry);
1514 silc_fsm_next(fsm, silc_client_command_reply_processed);
1515 return SILC_FSM_CONTINUE;
1518 /********************************** KICK ************************************/
1520 SILC_FSM_STATE(silc_client_command_reply_kick)
1522 SilcClientCommandContext cmd = fsm_context;
1523 SilcClientConnection conn = cmd->conn;
1524 SilcClient client = conn->client;
1525 SilcCommandPayload payload = state_context;
1526 SilcArgumentPayload args = silc_command_get_args(payload);
1527 SilcClientEntry client_entry;
1528 SilcChannelEntry channel;
1532 CHECK_STATUS("Cannot kick: ");
1535 /* Take Channel ID */
1536 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1537 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1541 /* Get the channel entry */
1542 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1544 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1549 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1550 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1554 /* Get client entry */
1555 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1556 if (!client_entry) {
1557 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1561 /* Notify application */
1562 silc_client_command_callback(cmd, channel, client_entry);
1564 silc_client_unref_client(client, conn, client_entry);
1567 silc_fsm_next(fsm, silc_client_command_reply_processed);
1568 return SILC_FSM_CONTINUE;
1571 /******************************** SILCOPER **********************************/
1573 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1575 SilcClientCommandContext cmd = fsm_context;
1576 SilcCommandPayload payload = state_context;
1577 SilcArgumentPayload args = silc_command_get_args(payload);
1580 CHECK_STATUS("Cannot change mode: ");
1583 /* Notify application */
1584 silc_client_command_callback(cmd);
1586 silc_fsm_next(fsm, silc_client_command_reply_processed);
1587 return SILC_FSM_CONTINUE;
1590 /********************************** OPER ************************************/
1592 SILC_FSM_STATE(silc_client_command_reply_oper)
1594 SilcClientCommandContext cmd = fsm_context;
1595 SilcCommandPayload payload = state_context;
1596 SilcArgumentPayload args = silc_command_get_args(payload);
1599 CHECK_STATUS("Cannot change mode: ");
1602 /* Notify application */
1603 silc_client_command_callback(cmd);
1605 silc_fsm_next(fsm, silc_client_command_reply_processed);
1606 return SILC_FSM_CONTINUE;
1609 /********************************* DETACH ***********************************/
1611 SILC_FSM_STATE(silc_client_command_reply_detach)
1613 SilcClientCommandContext cmd = fsm_context;
1614 SilcClientConnection conn = cmd->conn;
1615 SilcClient client = conn->client;
1616 SilcCommandPayload payload = state_context;
1617 SilcArgumentPayload args = silc_command_get_args(payload);
1621 CHECK_STATUS("Cannot detach: ");
1624 /* Notify application */
1625 silc_client_command_callback(cmd);
1628 /* Generate the detachment data and deliver it to the client in the
1629 detach client operation */
1630 detach = silc_client_get_detach_data(client, conn);
1632 client->internal->ops->detach(client, conn, silc_buffer_data(detach),
1633 silc_buffer_len(detach));
1634 silc_buffer_free(detach);
1638 silc_fsm_next(fsm, silc_client_command_reply_processed);
1639 return SILC_FSM_CONTINUE;
1642 /********************************** WATCH ***********************************/
1644 SILC_FSM_STATE(silc_client_command_reply_watch)
1646 SilcClientCommandContext cmd = fsm_context;
1647 SilcCommandPayload payload = state_context;
1648 SilcArgumentPayload args = silc_command_get_args(payload);
1651 CHECK_STATUS("Cannot set watch: ");
1654 /* Notify application */
1655 silc_client_command_callback(cmd);
1657 silc_fsm_next(fsm, silc_client_command_reply_processed);
1658 return SILC_FSM_CONTINUE;
1661 /*********************************** BAN ************************************/
1663 SILC_FSM_STATE(silc_client_command_reply_ban)
1665 SilcClientCommandContext cmd = fsm_context;
1666 SilcClientConnection conn = cmd->conn;
1667 SilcClient client = conn->client;
1668 SilcCommandPayload payload = state_context;
1669 SilcArgumentPayload args = silc_command_get_args(payload);
1670 SilcChannelEntry channel;
1673 SilcArgumentPayload invite_args = NULL;
1677 CHECK_STATUS("Cannot set ban: ");
1680 /* Take Channel ID */
1681 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1682 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1686 /* Get the channel entry */
1687 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1689 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1693 /* Get the invite list */
1694 tmp = silc_argument_get_arg_type(args, 3, &len);
1696 invite_args = silc_argument_list_parse(tmp, len);
1698 /* Notify application */
1699 silc_client_command_callback(cmd, channel, invite_args);
1702 silc_argument_payload_free(invite_args);
1705 silc_fsm_next(fsm, silc_client_command_reply_processed);
1706 return SILC_FSM_CONTINUE;
1709 /********************************** LEAVE ***********************************/
1711 /* Reply to LEAVE command. */
1713 SILC_FSM_STATE(silc_client_command_reply_leave)
1715 SilcClientCommandContext cmd = fsm_context;
1716 SilcClientConnection conn = cmd->conn;
1717 SilcClient client = conn->client;
1718 SilcCommandPayload payload = state_context;
1719 SilcArgumentPayload args = silc_command_get_args(payload);
1720 SilcChannelEntry channel;
1724 CHECK_STATUS("Cannot set leave: ");
1727 /* Get Channel ID */
1728 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1729 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1733 /* Get the channel entry */
1734 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1736 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1740 /* Remove us from this channel. */
1741 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1743 /* Notify application */
1744 silc_client_command_callback(cmd, channel);
1746 /* Now delete the channel. */
1747 silc_client_empty_channel(client, conn, channel);
1748 silc_client_del_channel(client, conn, channel);
1751 silc_fsm_next(fsm, silc_client_command_reply_processed);
1752 return SILC_FSM_CONTINUE;
1755 /********************************* USERS ************************************/
1757 /* Continue USERS command reply processing after resolving unknown users */
1760 silc_client_command_reply_users_resolved(SilcClient client,
1761 SilcClientConnection conn,
1766 SilcClientCommandContext cmd = context;
1767 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1771 /* Continue USERS command after resolving unknown channel */
1774 silc_client_command_reply_users_continue(SilcClient client,
1775 SilcClientConnection conn,
1780 SilcClientCommandContext cmd = context;
1783 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1784 SilcArgumentPayload args = silc_command_get_args(payload);
1786 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1787 ERROR_CALLBACK(cmd->status);
1788 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1791 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1794 /* Reply to USERS command. Received list of client ID's and theirs modes
1795 on the channel we requested. */
1797 SILC_FSM_STATE(silc_client_command_reply_users)
1799 SilcClientCommandContext cmd = fsm_context;
1800 SilcClientConnection conn = cmd->conn;
1801 SilcClient client = conn->client;
1802 SilcCommandPayload payload = state_context;
1803 SilcArgumentPayload args = silc_command_get_args(payload);
1805 SilcUInt32 tmp_len, list_count;
1806 SilcUInt16 idp_len, mode;
1807 SilcHashTableList htl;
1808 SilcBufferStruct client_id_list, client_mode_list;
1809 SilcChannelEntry channel;
1810 SilcClientEntry client_entry;
1815 CHECK_STATUS("Cannot get users: ");
1818 /* Get channel ID */
1819 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1820 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1824 /* Get channel entry */
1825 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1827 /* Resolve the channel from server */
1828 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1829 client, conn, &id.u.channel_id,
1830 silc_client_command_reply_users_continue, cmd));
1834 /* Get the list count */
1835 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1836 if (!tmp || tmp_len != 4) {
1837 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1840 SILC_GET32_MSB(list_count, tmp);
1842 /* Get Client ID list */
1843 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1845 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1848 silc_buffer_set(&client_id_list, tmp, tmp_len);
1850 /* Resolve users we do not know about */
1851 if (!cmd->resolved) {
1852 cmd->resolved = TRUE;
1853 SILC_FSM_CALL(silc_client_get_clients_by_list(
1854 client, conn, list_count, &client_id_list,
1855 silc_client_command_reply_users_resolved, cmd));
1859 /* Get client mode list */
1860 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1862 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1865 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1867 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1869 /* Cache the received Client ID's and modes. */
1870 for (i = 0; i < list_count; i++) {
1871 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1873 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1877 SILC_GET32_MSB(mode, client_mode_list.data);
1879 /* Save the client on this channel. Unknown clients are ignored as they
1880 clearly do not exist since the resolving didn't find them. */
1881 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1883 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1884 silc_client_unref_client(client, conn, client_entry);
1886 if (!silc_buffer_pull(&client_id_list, idp_len))
1888 if (!silc_buffer_pull(&client_mode_list, 4))
1892 /* Notify application */
1893 silc_hash_table_list(channel->user_list, &htl);
1894 silc_client_command_callback(cmd, channel, &htl);
1895 silc_hash_table_list_reset(&htl);
1898 silc_fsm_next(fsm, silc_client_command_reply_processed);
1899 return SILC_FSM_CONTINUE;
1902 /********************************** GETKEY **********************************/
1904 /* Received command reply to GETKEY command. WE've received the remote
1905 client's public key. */
1907 SILC_FSM_STATE(silc_client_command_reply_getkey)
1909 SilcClientCommandContext cmd = fsm_context;
1910 SilcClientConnection conn = cmd->conn;
1911 SilcClient client = conn->client;
1912 SilcCommandPayload payload = state_context;
1913 SilcArgumentPayload args = silc_command_get_args(payload);
1914 SilcClientEntry client_entry;
1915 SilcServerEntry server_entry;
1918 SilcPublicKey public_key;
1922 CHECK_STATUS("Cannot get key: ");
1926 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1927 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1931 /* Get the public key */
1932 tmp = silc_argument_get_arg_type(args, 3, &len);
1934 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1937 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1938 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1942 if (id.type == SILC_ID_CLIENT) {
1943 /* Received client's public key */
1944 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1945 if (!client_entry) {
1946 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1950 /* Save fingerprint */
1951 if (!client_entry->fingerprint)
1952 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
1953 client_entry->fingerprint);
1954 if (!client_entry->public_key) {
1955 client_entry->public_key = public_key;
1959 /* Notify application */
1960 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1961 client_entry->public_key);
1962 silc_client_unref_client(client, conn, client_entry);
1963 } else if (id.type == SILC_ID_SERVER) {
1964 /* Received server's public key */
1965 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1966 if (!server_entry) {
1967 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1971 if (!server_entry->public_key) {
1972 server_entry->public_key = public_key;
1976 /* Notify application */
1977 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1978 server_entry->public_key);
1979 silc_client_unref_server(client, conn, server_entry);
1984 silc_pkcs_public_key_free(public_key);
1985 silc_fsm_next(fsm, silc_client_command_reply_processed);
1986 return SILC_FSM_CONTINUE;
1989 /********************************** SERVICE *********************************/
1991 /* Reply to SERVICE command. */
1992 /* XXX incomplete */
1994 SILC_FSM_STATE(silc_client_command_reply_service)
1996 SilcClientCommandContext cmd = fsm_context;
1997 SilcCommandPayload payload = state_context;
1998 SilcArgumentPayload args = silc_command_get_args(payload);
2000 unsigned char *service_list, *name;
2003 CHECK_STATUS("Cannot get service: ");
2005 /* Get service list */
2006 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2008 /* Get requested service name */
2009 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2011 /* Notify application */
2012 silc_client_command_callback(cmd, service_list, name);
2014 silc_fsm_next(fsm, silc_client_command_reply_processed);
2015 return SILC_FSM_CONTINUE;
2018 /*********************************** QUIT ***********************************/
2020 /* QUIT command reply stub */
2022 SILC_FSM_STATE(silc_client_command_reply_quit)
2024 silc_fsm_next(fsm, silc_client_command_reply_processed);
2025 return SILC_FSM_CONTINUE;