5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Types and definitions ***************************/
27 /* Calls error command reply callback back to command sender. */
28 #define ERROR_CALLBACK(err) \
30 void *arg1 = NULL, *arg2 = NULL; \
31 if (cmd->status != SILC_STATUS_OK) \
32 silc_status_get_args(cmd->status, args, &arg1, &arg2); \
34 cmd->status = cmd->error = err; \
35 SILC_LOG_DEBUG(("Error in command reply: %s", \
36 silc_get_status_message(cmd->status))); \
37 silc_client_command_callback(cmd, arg1, arg2); \
41 #define CHECK_STATUS(msg) \
42 SILC_LOG_DEBUG(("%s", silc_get_command_name(cmd->cmd))); \
43 if (cmd->error != SILC_STATUS_OK) { \
45 SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_ERROR, \
46 msg "%s", silc_get_status_message(cmd->error)); \
47 ERROR_CALLBACK(cmd->error); \
48 silc_client_command_process_error(cmd, state_context, cmd->error); \
49 silc_fsm_next(fsm, silc_client_command_reply_processed); \
50 return SILC_FSM_CONTINUE; \
53 /* Check for correct arguments */
54 #define CHECK_ARGS(min, max) \
55 if (silc_argument_get_arg_num(args) < min || \
56 silc_argument_get_arg_num(args) > max) { \
57 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
58 silc_fsm_next(fsm, silc_client_command_reply_processed); \
59 return SILC_FSM_CONTINUE; \
62 #define SAY cmd->conn->client->internal->ops->say
64 /************************ Static utility functions **************************/
66 /* Delivers the command reply back to application */
69 silc_client_command_callback(SilcClientCommandContext cmd, ...)
71 SilcClientCommandReplyCallback cb;
77 /* Default reply callback */
80 cmd->conn->client->internal->ops->command_reply(
81 cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
87 list = cmd->reply_callbacks;
88 silc_list_start(list);
89 while ((cb = silc_list_get(list)))
90 if (!cb->do_not_call) {
92 cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
93 cmd->status, cmd->error, cb->context, cp);
100 /* Handles common error status types. */
102 static void silc_client_command_process_error(SilcClientCommandContext cmd,
103 SilcCommandPayload payload,
106 SilcClient client = cmd->conn->client;
107 SilcClientConnection conn = cmd->conn;
108 SilcArgumentPayload args = silc_command_get_args(payload);
111 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
112 SilcClientEntry client_entry;
114 /* Remove unknown client entry from cache */
115 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
118 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
120 silc_client_remove_from_channels(client, conn, client_entry);
121 silc_client_del_client(client, conn, client_entry);
122 silc_client_unref_client(client, conn, client_entry);
127 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
128 SilcChannelEntry channel;
130 /* Remove unknown client entry from cache */
131 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
134 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
136 silc_client_empty_channel(client, conn, channel);
137 silc_client_del_channel(client, conn, channel);
138 silc_client_unref_channel(client, conn, channel);
143 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
144 SilcServerEntry server_entry;
146 /* Remove unknown client entry from cache */
147 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
150 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
152 silc_client_del_server(client, conn, server_entry);
153 silc_client_unref_server(client, conn, server_entry);
159 /***************************** Command Reply ********************************/
161 /* Process received command reply packet */
163 SILC_FSM_STATE(silc_client_command_reply)
165 SilcClientConnection conn = fsm_context;
166 SilcPacket packet = state_context;
167 SilcClientCommandContext cmd;
168 SilcCommandPayload payload;
170 SilcUInt16 cmd_ident;
172 /* Get command reply payload from packet */
173 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
174 silc_packet_free(packet);
176 SILC_LOG_DEBUG(("Bad command reply packet"));
177 return SILC_FSM_FINISH;
180 cmd_ident = silc_command_get_ident(payload);
181 command = silc_command_get(payload);
183 /* Find the command pending reply */
184 silc_mutex_lock(conn->internal->lock);
185 silc_list_start(conn->internal->pending_commands);
186 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
187 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
188 && cmd->cmd_ident == cmd_ident) {
189 silc_list_del(conn->internal->pending_commands, cmd);
193 silc_mutex_unlock(conn->internal->lock);
196 SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
197 silc_get_command_name(command), cmd_ident));
198 silc_command_payload_free(payload);
199 return SILC_FSM_FINISH;
202 /* Signal command thread that command reply has arrived */
203 silc_fsm_set_state_context(&cmd->thread, payload);
204 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
205 silc_fsm_continue_sync(&cmd->thread);
207 return SILC_FSM_FINISH;
210 /* Wait here for command reply to arrive from remote host */
212 SILC_FSM_STATE(silc_client_command_reply_wait)
214 SilcClientCommandContext cmd = fsm_context;
216 SILC_LOG_DEBUG(("Wait for command reply"));
218 /** Wait for command reply */
219 silc_fsm_set_state_context(fsm, NULL);
220 silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
221 cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0);
222 return SILC_FSM_WAIT;
225 /* Timeout occurred while waiting command reply */
227 SILC_FSM_STATE(silc_client_command_reply_timeout)
229 SilcClientCommandContext cmd = fsm_context;
230 SilcClientConnection conn = cmd->conn;
231 SilcArgumentPayload args = NULL;
233 if (conn->internal->disconnected) {
234 SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
235 silc_list_del(conn->internal->pending_commands, cmd);
236 if (!cmd->called && cmd->cmd != SILC_COMMAND_PING)
237 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
238 return SILC_FSM_FINISH;
241 SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
243 /* Timeout, reply not received in timely fashion */
244 silc_list_del(conn->internal->pending_commands, cmd);
245 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
246 return SILC_FSM_FINISH;
249 /* Process received command reply payload */
251 SILC_FSM_STATE(silc_client_command_reply_process)
253 SilcClientCommandContext cmd = fsm_context;
254 SilcCommandPayload payload = state_context;
256 silc_command_get_status(payload, &cmd->status, &cmd->error);
259 case SILC_COMMAND_WHOIS:
261 silc_fsm_next(fsm, silc_client_command_reply_whois);
263 case SILC_COMMAND_WHOWAS:
265 silc_fsm_next(fsm, silc_client_command_reply_whowas);
267 case SILC_COMMAND_IDENTIFY:
269 silc_fsm_next(fsm, silc_client_command_reply_identify);
271 case SILC_COMMAND_NICK:
273 silc_fsm_next(fsm, silc_client_command_reply_nick);
275 case SILC_COMMAND_LIST:
277 silc_fsm_next(fsm, silc_client_command_reply_list);
279 case SILC_COMMAND_TOPIC:
281 silc_fsm_next(fsm, silc_client_command_reply_topic);
283 case SILC_COMMAND_INVITE:
285 silc_fsm_next(fsm, silc_client_command_reply_invite);
287 case SILC_COMMAND_QUIT:
289 silc_fsm_next(fsm, silc_client_command_reply_quit);
291 case SILC_COMMAND_KILL:
293 silc_fsm_next(fsm, silc_client_command_reply_kill);
295 case SILC_COMMAND_INFO:
297 silc_fsm_next(fsm, silc_client_command_reply_info);
299 case SILC_COMMAND_STATS:
301 silc_fsm_next(fsm, silc_client_command_reply_stats);
303 case SILC_COMMAND_PING:
305 silc_fsm_next(fsm, silc_client_command_reply_ping);
307 case SILC_COMMAND_OPER:
309 silc_fsm_next(fsm, silc_client_command_reply_oper);
311 case SILC_COMMAND_JOIN:
313 silc_fsm_next(fsm, silc_client_command_reply_join);
315 case SILC_COMMAND_MOTD:
317 silc_fsm_next(fsm, silc_client_command_reply_motd);
319 case SILC_COMMAND_UMODE:
321 silc_fsm_next(fsm, silc_client_command_reply_umode);
323 case SILC_COMMAND_CMODE:
325 silc_fsm_next(fsm, silc_client_command_reply_cmode);
327 case SILC_COMMAND_CUMODE:
329 silc_fsm_next(fsm, silc_client_command_reply_cumode);
331 case SILC_COMMAND_KICK:
333 silc_fsm_next(fsm, silc_client_command_reply_kick);
335 case SILC_COMMAND_BAN:
337 silc_fsm_next(fsm, silc_client_command_reply_ban);
339 case SILC_COMMAND_DETACH:
341 silc_fsm_next(fsm, silc_client_command_reply_detach);
343 case SILC_COMMAND_WATCH:
345 silc_fsm_next(fsm, silc_client_command_reply_watch);
347 case SILC_COMMAND_SILCOPER:
349 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
351 case SILC_COMMAND_LEAVE:
353 silc_fsm_next(fsm, silc_client_command_reply_leave);
355 case SILC_COMMAND_USERS:
357 silc_fsm_next(fsm, silc_client_command_reply_users);
359 case SILC_COMMAND_GETKEY:
361 silc_fsm_next(fsm, silc_client_command_reply_getkey);
363 case SILC_COMMAND_SERVICE:
365 silc_fsm_next(fsm, silc_client_command_reply_service);
368 return SILC_FSM_FINISH;
371 return SILC_FSM_CONTINUE;
374 /* Completes command reply processing */
376 SILC_FSM_STATE(silc_client_command_reply_processed)
378 SilcClientCommandContext cmd = fsm_context;
379 SilcClientConnection conn = cmd->conn;
380 SilcCommandPayload payload = state_context;
382 silc_command_payload_free(payload);
384 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
385 SILC_STATUS_IS_ERROR(cmd->status))
386 return SILC_FSM_FINISH;
388 /* Add back to pending command reply list */
389 silc_mutex_lock(conn->internal->lock);
390 cmd->resolved = FALSE;
391 silc_list_add(conn->internal->pending_commands, cmd);
392 silc_mutex_unlock(conn->internal->lock);
394 /** Wait more command payloads */
395 silc_fsm_next(fsm, silc_client_command_reply_wait);
396 return SILC_FSM_CONTINUE;
399 /******************************** WHOIS *************************************/
401 /* Received reply for WHOIS command. */
403 SILC_FSM_STATE(silc_client_command_reply_whois)
405 SilcClientCommandContext cmd = fsm_context;
406 SilcClientConnection conn = cmd->conn;
407 SilcClient client = conn->client;
408 SilcCommandPayload payload = state_context;
409 SilcArgumentPayload args = silc_command_get_args(payload);
410 SilcClientEntry client_entry = NULL;
411 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
412 SilcBufferStruct channels, ch_user_modes;
413 SilcBool has_channels = FALSE;
414 SilcDList channel_list = NULL;
416 char *nickname = NULL, *username = NULL, *realname = NULL;
417 unsigned char *fingerprint, *tmp;
419 CHECK_STATUS("WHOIS: ");
423 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
424 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
429 nickname = silc_argument_get_arg_type(args, 3, NULL);
430 username = silc_argument_get_arg_type(args, 4, NULL);
431 realname = silc_argument_get_arg_type(args, 5, NULL);
432 if (!nickname || !username || !realname) {
433 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
437 /* Get joined channel list */
438 memset(&channels, 0, sizeof(channels));
439 tmp = silc_argument_get_arg_type(args, 6, &len);
442 silc_buffer_set(&channels, tmp, len);
444 /* Get channel user mode list */
445 tmp = silc_argument_get_arg_type(args, 10, &len);
447 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
450 silc_buffer_set(&ch_user_modes, tmp, len);
454 tmp = silc_argument_get_arg_type(args, 7, &len);
456 SILC_GET32_MSB(mode, tmp);
459 tmp = silc_argument_get_arg_type(args, 8, &len);
461 SILC_GET32_MSB(idle, tmp);
463 /* Get fingerprint */
464 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
466 /* Check if we have this client cached already. */
467 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
469 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
471 silc_client_add_client(client, conn, nickname, username, realname,
472 &id.u.client_id, mode);
474 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
477 silc_client_ref_client(client, conn, client_entry);
479 silc_client_update_client(client, conn, client_entry,
480 nickname, username, realname, mode);
483 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
484 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
486 /* Get user attributes */
487 tmp = silc_argument_get_arg_type(args, 11, &len);
489 if (client_entry->attrs)
490 silc_attribute_payload_list_free(client_entry->attrs);
491 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
494 /* Parse channel and channel user mode list */
496 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
497 silc_buffer_len(&channels));
499 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
503 /* Notify application */
504 silc_client_command_callback(cmd, client_entry, nickname, username,
505 realname, channel_list, mode, idle, fingerprint,
506 umodes, client_entry->attrs);
508 silc_client_unref_client(client, conn, client_entry);
510 silc_dlist_uninit(channel_list);
515 silc_fsm_next(fsm, silc_client_command_reply_processed);
516 return SILC_FSM_CONTINUE;
519 /******************************** WHOWAS ************************************/
521 /* Received reply for WHOWAS command. */
523 SILC_FSM_STATE(silc_client_command_reply_whowas)
525 SilcClientCommandContext cmd = fsm_context;
526 SilcClientConnection conn = cmd->conn;
527 SilcClient client = conn->client;
528 SilcCommandPayload payload = state_context;
529 SilcArgumentPayload args = silc_command_get_args(payload);
530 SilcClientEntry client_entry = NULL;
532 char *nickname, *username;
533 char *realname = NULL;
535 CHECK_STATUS("WHOWAS: ");
539 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
540 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
544 /* Get the client entry */
545 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
548 nickname = silc_argument_get_arg_type(args, 3, NULL);
549 username = silc_argument_get_arg_type(args, 4, NULL);
550 realname = silc_argument_get_arg_type(args, 5, NULL);
551 if (!nickname || !username) {
552 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
556 /* Notify application. We don't save any history information to any
557 cache. Just pass the data to the application. */
558 silc_client_command_callback(cmd, client_entry, nickname, username,
562 silc_client_unref_client(client, conn, client_entry);
563 silc_fsm_next(fsm, silc_client_command_reply_processed);
564 return SILC_FSM_CONTINUE;
567 /******************************** IDENTIFY **********************************/
569 /* Received reply for IDENTIFY command. */
571 SILC_FSM_STATE(silc_client_command_reply_identify)
573 SilcClientCommandContext cmd = fsm_context;
574 SilcClientConnection conn = cmd->conn;
575 SilcClient client = conn->client;
576 SilcCommandPayload payload = state_context;
577 SilcArgumentPayload args = silc_command_get_args(payload);
578 SilcClientEntry client_entry;
579 SilcServerEntry server_entry;
580 SilcChannelEntry channel_entry;
583 char *name = NULL, *info = NULL;
585 CHECK_STATUS("IDENTIFY: ");
589 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
590 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
595 name = silc_argument_get_arg_type(args, 3, &len);
596 info = silc_argument_get_arg_type(args, 4, &len);
600 SILC_LOG_DEBUG(("Received client information"));
602 /* Check if we have this client cached already. */
603 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
605 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
607 silc_client_add_client(client, conn, name, info, NULL,
610 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
613 silc_client_ref_client(client, conn, client_entry);
615 silc_client_update_client(client, conn, client_entry,
616 name, info, NULL, 0);
619 /* Notify application */
620 silc_client_command_callback(cmd, client_entry, name, info);
621 silc_client_unref_client(client, conn, client_entry);
625 SILC_LOG_DEBUG(("Received server information"));
627 /* Check if we have this server cached already. */
628 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
630 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
631 server_entry = silc_client_add_server(client, conn, name, info,
634 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
637 silc_client_ref_server(client, conn, server_entry);
639 silc_client_update_server(client, conn, server_entry, name, info);
641 server_entry->internal.resolve_cmd_ident = 0;
643 /* Notify application */
644 silc_client_command_callback(cmd, server_entry, name, info);
645 silc_client_unref_server(client, conn, server_entry);
648 case SILC_ID_CHANNEL:
649 SILC_LOG_DEBUG(("Received channel information"));
651 /* Check if we have this channel cached already. */
652 channel_entry = silc_client_get_channel_by_id(client, conn,
654 if (!channel_entry) {
655 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
658 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
662 /* Add new channel entry */
663 channel_entry = silc_client_add_channel(client, conn, name, 0,
665 if (!channel_entry) {
666 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
669 silc_client_ref_channel(client, conn, channel_entry);
672 /* Notify application */
673 silc_client_command_callback(cmd, channel_entry, name, info);
674 silc_client_unref_channel(client, conn, channel_entry);
679 silc_fsm_next(fsm, silc_client_command_reply_processed);
680 return SILC_FSM_CONTINUE;
683 /********************************** NICK ************************************/
685 /* Received reply for command NICK. */
687 SILC_FSM_STATE(silc_client_command_reply_nick)
689 SilcClientCommandContext cmd = fsm_context;
690 SilcClientConnection conn = cmd->conn;
691 SilcClient client = conn->client;
692 SilcCommandPayload payload = state_context;
693 SilcArgumentPayload args = silc_command_get_args(payload);
694 unsigned char *nick, *idp;
695 SilcUInt32 len, idp_len;
696 SilcClientID old_client_id;
700 CHECK_STATUS("Cannot set nickname: ");
703 /* Take received Client ID */
704 idp = silc_argument_get_arg_type(args, 2, &idp_len);
706 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
709 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
710 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
714 /* Take the new nickname */
715 nick = silc_argument_get_arg_type(args, 3, &len);
717 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
721 /* Change the nickname */
722 old_client_id = *conn->local_id;
723 if (!silc_client_change_nickname(client, conn, conn->local_entry,
724 nick, &id.u.client_id, idp, idp_len)) {
725 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
729 /* Notify application */
730 silc_client_command_callback(cmd, conn->local_entry,
731 conn->local_entry->nickname, &old_client_id);
734 silc_fsm_next(fsm, silc_client_command_reply_processed);
735 return SILC_FSM_CONTINUE;
738 /********************************** LIST ************************************/
740 /* Received reply to the LIST command. */
742 SILC_FSM_STATE(silc_client_command_reply_list)
744 SilcClientCommandContext cmd = fsm_context;
745 SilcClientConnection conn = cmd->conn;
746 SilcClient client = conn->client;
747 SilcCommandPayload payload = state_context;
748 SilcArgumentPayload args = silc_command_get_args(payload);
749 unsigned char *tmp, *name, *topic;
750 SilcUInt32 usercount = 0;
751 SilcChannelEntry channel_entry = NULL;
755 CHECK_STATUS("Cannot list channels: ");
757 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
758 /* There were no channels in the network. */
759 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
760 silc_fsm_next(fsm, silc_client_command_reply_processed);
761 return SILC_FSM_CONTINUE;
766 name = silc_argument_get_arg_type(args, 3, NULL);
768 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
772 topic = silc_argument_get_arg_type(args, 4, NULL);
773 tmp = silc_argument_get_arg_type(args, 5, NULL);
775 SILC_GET32_MSB(usercount, tmp);
777 /* Check whether the channel exists, and add it to cache if it doesn't. */
778 channel_entry = silc_client_get_channel_by_id(client, conn,
780 if (!channel_entry) {
781 /* Add new channel entry */
782 channel_entry = silc_client_add_channel(client, conn, name, 0,
784 if (!channel_entry) {
785 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
788 silc_client_ref_channel(client, conn, channel_entry);
791 /* Notify application */
792 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
795 silc_client_unref_channel(client, conn, channel_entry);
796 silc_fsm_next(fsm, silc_client_command_reply_processed);
797 return SILC_FSM_CONTINUE;
800 /********************************* TOPIC ************************************/
802 /* Received reply to topic command. */
804 SILC_FSM_STATE(silc_client_command_reply_topic)
806 SilcClientCommandContext cmd = fsm_context;
807 SilcClientConnection conn = cmd->conn;
808 SilcClient client = conn->client;
809 SilcCommandPayload payload = state_context;
810 SilcArgumentPayload args = silc_command_get_args(payload);
811 SilcChannelEntry channel;
817 CHECK_STATUS("Cannot set topic: ");
820 /* Take Channel ID */
821 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
822 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
826 /* Get the channel entry */
827 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
829 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
834 topic = silc_argument_get_arg_type(args, 3, &len);
836 silc_free(channel->topic);
837 channel->topic = silc_memdup(topic, len);
840 /* Notify application */
841 silc_client_command_callback(cmd, channel, channel->topic);
844 silc_fsm_next(fsm, silc_client_command_reply_processed);
845 return SILC_FSM_CONTINUE;
848 /********************************* INVITE ***********************************/
850 /* Received reply to invite command. */
852 SILC_FSM_STATE(silc_client_command_reply_invite)
854 SilcClientCommandContext cmd = fsm_context;
855 SilcClientConnection conn = cmd->conn;
856 SilcClient client = conn->client;
857 SilcCommandPayload payload = state_context;
858 SilcArgumentPayload args = silc_command_get_args(payload);
859 SilcChannelEntry channel;
862 SilcArgumentPayload invite_args = NULL;
866 CHECK_STATUS("Cannot invite: ");
869 /* Take Channel ID */
870 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
871 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
875 /* Get the channel entry */
876 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
878 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
882 /* Get the invite list */
883 tmp = silc_argument_get_arg_type(args, 3, &len);
885 invite_args = silc_argument_list_parse(tmp, len);
887 /* Notify application */
888 silc_client_command_callback(cmd, channel, invite_args);
891 silc_argument_payload_free(invite_args);
894 silc_fsm_next(fsm, silc_client_command_reply_processed);
895 return SILC_FSM_CONTINUE;
898 /********************************** KILL ************************************/
900 /* Received reply to the KILL command. */
902 SILC_FSM_STATE(silc_client_command_reply_kill)
904 SilcClientCommandContext cmd = fsm_context;
905 SilcClientConnection conn = cmd->conn;
906 SilcClient client = conn->client;
907 SilcCommandPayload payload = state_context;
908 SilcArgumentPayload args = silc_command_get_args(payload);
909 SilcClientEntry client_entry;
913 CHECK_STATUS("Cannot kill: ");
916 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
917 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
921 /* Get the client entry, if exists */
922 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
924 /* Notify application */
925 silc_client_command_callback(cmd, client_entry);
927 /* Remove the client */
929 silc_client_remove_from_channels(client, conn, client_entry);
930 silc_client_del_client(client, conn, client_entry);
931 silc_client_unref_client(client, conn, client_entry);
935 silc_fsm_next(fsm, silc_client_command_reply_processed);
936 return SILC_FSM_CONTINUE;
939 /********************************** INFO ************************************/
941 /* Received reply to INFO command. We receive the server ID and some
942 information about the server user requested. */
944 SILC_FSM_STATE(silc_client_command_reply_info)
946 SilcClientCommandContext cmd = fsm_context;
947 SilcClientConnection conn = cmd->conn;
948 SilcClient client = conn->client;
949 SilcCommandPayload payload = state_context;
950 SilcArgumentPayload args = silc_command_get_args(payload);
951 SilcServerEntry server;
952 char *server_name, *server_info;
956 CHECK_STATUS("Cannot get info: ");
960 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
961 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
965 /* Get server name */
966 server_name = silc_argument_get_arg_type(args, 3, NULL);
968 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
972 /* Get server info */
973 server_info = silc_argument_get_arg_type(args, 4, NULL);
975 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
979 /* See whether we have this server cached. If not create it. */
980 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
982 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
983 server = silc_client_add_server(client, conn, server_name,
984 server_info, &id.u.server_id);
987 silc_client_ref_server(client, conn, server);
990 /* Notify application */
991 silc_client_command_callback(cmd, server, server->server_name,
992 server->server_info);
993 silc_client_unref_server(client, conn, server);
996 silc_fsm_next(fsm, silc_client_command_reply_processed);
997 return SILC_FSM_CONTINUE;
1000 /********************************** STATS ***********************************/
1002 /* Received reply to STATS command. */
1004 SILC_FSM_STATE(silc_client_command_reply_stats)
1006 SilcClientCommandContext cmd = fsm_context;
1007 SilcCommandPayload payload = state_context;
1008 SilcArgumentPayload args = silc_command_get_args(payload);
1009 SilcClientStats stats;
1010 unsigned char *buf = NULL;
1011 SilcUInt32 buf_len = 0;
1016 CHECK_STATUS("Cannot get stats: ");
1020 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1021 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1025 /* Get statistics structure */
1026 memset(&stats, 0, sizeof(stats));
1027 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1029 silc_buffer_set(&b, buf, buf_len);
1030 silc_buffer_unformat(&b,
1031 SILC_STR_UI_INT(&stats.starttime),
1032 SILC_STR_UI_INT(&stats.uptime),
1033 SILC_STR_UI_INT(&stats.my_clients),
1034 SILC_STR_UI_INT(&stats.my_channels),
1035 SILC_STR_UI_INT(&stats.my_server_ops),
1036 SILC_STR_UI_INT(&stats.my_router_ops),
1037 SILC_STR_UI_INT(&stats.cell_clients),
1038 SILC_STR_UI_INT(&stats.cell_channels),
1039 SILC_STR_UI_INT(&stats.cell_servers),
1040 SILC_STR_UI_INT(&stats.clients),
1041 SILC_STR_UI_INT(&stats.channels),
1042 SILC_STR_UI_INT(&stats.servers),
1043 SILC_STR_UI_INT(&stats.routers),
1044 SILC_STR_UI_INT(&stats.server_ops),
1045 SILC_STR_UI_INT(&stats.router_ops),
1049 /* Notify application */
1050 silc_client_command_callback(cmd, &stats);
1053 silc_fsm_next(fsm, silc_client_command_reply_processed);
1054 return SILC_FSM_CONTINUE;
1057 /********************************** PING ************************************/
1059 /* Received reply to PING command. */
1061 SILC_FSM_STATE(silc_client_command_reply_ping)
1063 SilcClientCommandContext cmd = fsm_context;
1064 SilcClientConnection conn = cmd->conn;
1065 SilcClient client = conn->client;
1068 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1070 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1071 "Ping reply from %s: %d second%s", conn->remote_host,
1072 (int)diff, diff == 1 ? "" : "s");
1074 /* Notify application */
1075 silc_client_command_callback(cmd);
1077 silc_fsm_next(fsm, silc_client_command_reply_processed);
1078 return SILC_FSM_CONTINUE;
1081 /********************************** JOIN ************************************/
1083 /* Continue JOIN command reply processing after resolving unknown users */
1086 silc_client_command_reply_join_resolved(SilcClient client,
1087 SilcClientConnection conn,
1092 SilcClientCommandContext cmd = context;
1093 SilcChannelEntry channel = cmd->context;
1095 channel->internal.resolve_cmd_ident = 0;
1096 silc_client_unref_channel(client, conn, channel);
1098 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1102 /* Received reply for JOIN command. */
1104 SILC_FSM_STATE(silc_client_command_reply_join)
1106 SilcClientCommandContext cmd = fsm_context;
1107 SilcClientConnection conn = cmd->conn;
1108 SilcClient client = conn->client;
1109 SilcCommandPayload payload = state_context;
1110 SilcArgumentPayload args = silc_command_get_args(payload);
1111 SilcChannelEntry channel;
1112 SilcUInt32 mode = 0, len, list_count;
1113 char *topic, *tmp, *channel_name = NULL, *hmac;
1115 SilcBufferStruct client_id_list, client_mode_list, keyp;
1116 SilcHashTableList htl;
1121 CHECK_STATUS("Cannot join channel: ");
1124 /* Get channel name */
1125 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1126 if (!channel_name) {
1127 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1131 /* Get Channel ID */
1132 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1133 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1137 /* Check whether we have this channel entry already. */
1138 channel = silc_client_get_channel(client, conn, channel_name);
1140 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1141 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1143 /* Create new channel entry */
1144 channel = silc_client_add_channel(client, conn, channel_name,
1145 mode, &id.u.channel_id);
1147 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1150 silc_client_ref_channel(client, conn, channel);
1153 /* Get the list count */
1154 tmp = silc_argument_get_arg_type(args, 12, &len);
1156 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1159 SILC_GET32_MSB(list_count, tmp);
1161 /* Get Client ID list */
1162 tmp = silc_argument_get_arg_type(args, 13, &len);
1164 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1167 silc_buffer_set(&client_id_list, tmp, len);
1169 /* Resolve users we do not know about */
1170 if (!cmd->resolved) {
1171 cmd->resolved = TRUE;
1172 cmd->context = channel;
1173 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1174 silc_client_get_clients_by_list(
1175 client, conn, list_count, &client_id_list,
1176 silc_client_command_reply_join_resolved, cmd));
1180 /* Get client mode list */
1181 tmp = silc_argument_get_arg_type(args, 14, &len);
1183 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1186 silc_buffer_set(&client_mode_list, tmp, len);
1188 /* Add clients we received in the reply to the channel */
1189 for (i = 0; i < list_count; i++) {
1193 SilcClientEntry client_entry;
1196 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1198 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1202 SILC_GET32_MSB(mode, client_mode_list.data);
1204 /* Get client entry */
1205 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1209 /* Join client to the channel */
1210 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1211 silc_client_unref_client(client, conn, client_entry);
1213 if (!silc_buffer_pull(&client_id_list, idp_len))
1215 if (!silc_buffer_pull(&client_mode_list, 4))
1220 hmac = silc_argument_get_arg_type(args, 11, NULL);
1222 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1224 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1225 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1226 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1231 /* Get channel mode */
1232 tmp = silc_argument_get_arg_type(args, 5, NULL);
1234 SILC_GET32_MSB(mode, tmp);
1235 channel->mode = mode;
1237 /* Get channel key and save it */
1238 tmp = silc_argument_get_arg_type(args, 7, &len);
1240 silc_buffer_set(&keyp, tmp, len);
1241 silc_client_save_channel_key(client, conn, &keyp, channel);
1245 topic = silc_argument_get_arg_type(args, 10, NULL);
1247 silc_free(channel->topic);
1248 channel->topic = silc_memdup(topic, strlen(topic));
1251 /* Get founder key */
1252 tmp = silc_argument_get_arg_type(args, 15, &len);
1254 if (channel->founder_key)
1255 silc_pkcs_public_key_free(channel->founder_key);
1256 channel->founder_key = NULL;
1257 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1260 /* Get user limit */
1261 tmp = silc_argument_get_arg_type(args, 17, &len);
1262 if (tmp && len == 4)
1263 SILC_GET32_MSB(channel->user_limit, tmp);
1264 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1265 channel->user_limit = 0;
1267 /* Get channel public key list */
1268 tmp = silc_argument_get_arg_type(args, 16, &len);
1270 channel->channel_pubkeys =
1271 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1273 /* Set current channel */
1274 conn->current_channel = channel;
1276 cipher = (channel->internal.send_key ?
1277 silc_cipher_get_name(channel->internal.send_key) : NULL);
1278 silc_hash_table_list(channel->user_list, &htl);
1280 /* Notify application */
1281 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1282 topic, cipher, hmac, channel->founder_key,
1283 channel->channel_pubkeys, channel->user_limit);
1285 silc_hash_table_list_reset(&htl);
1286 silc_client_unref_channel(client, conn, channel);
1289 silc_fsm_next(fsm, silc_client_command_reply_processed);
1290 return SILC_FSM_CONTINUE;
1293 /********************************** MOTD ************************************/
1295 /* Received reply for MOTD command */
1297 SILC_FSM_STATE(silc_client_command_reply_motd)
1299 SilcClientCommandContext cmd = fsm_context;
1300 SilcClientConnection conn = cmd->conn;
1301 SilcClient client = conn->client;
1302 SilcCommandPayload payload = state_context;
1303 SilcArgumentPayload args = silc_command_get_args(payload);
1305 char *motd = NULL, *cp, line[256];
1308 CHECK_STATUS("Cannot get motd: ");
1311 if (silc_argument_get_arg_num(args) == 3) {
1312 motd = silc_argument_get_arg_type(args, 3, NULL);
1314 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1321 if (cp[i++] == '\n') {
1322 memset(line, 0, sizeof(line));
1323 silc_strncat(line, sizeof(line), cp, i - 1);
1330 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1339 /* Notify application */
1340 silc_client_command_callback(cmd, motd);
1343 silc_fsm_next(fsm, silc_client_command_reply_processed);
1344 return SILC_FSM_CONTINUE;
1347 /********************************** UMODE ***********************************/
1349 /* Received reply to the UMODE command. Save the current user mode */
1351 SILC_FSM_STATE(silc_client_command_reply_umode)
1353 SilcClientCommandContext cmd = fsm_context;
1354 SilcClientConnection conn = cmd->conn;
1355 SilcCommandPayload payload = state_context;
1356 SilcArgumentPayload args = silc_command_get_args(payload);
1358 SilcUInt32 mode, len;
1361 CHECK_STATUS("Cannot change mode: ");
1364 tmp = silc_argument_get_arg_type(args, 2, &len);
1365 if (!tmp || len != 4) {
1366 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1370 SILC_GET32_MSB(mode, tmp);
1371 conn->local_entry->mode = mode;
1373 /* Notify application */
1374 silc_client_command_callback(cmd, mode);
1377 silc_fsm_next(fsm, silc_client_command_reply_processed);
1378 return SILC_FSM_CONTINUE;
1381 /********************************** CMODE ***********************************/
1383 /* Received reply for CMODE command. */
1385 SILC_FSM_STATE(silc_client_command_reply_cmode)
1387 SilcClientCommandContext cmd = fsm_context;
1388 SilcClientConnection conn = cmd->conn;
1389 SilcClient client = conn->client;
1390 SilcCommandPayload payload = state_context;
1391 SilcArgumentPayload args = silc_command_get_args(payload);
1394 SilcChannelEntry channel;
1396 SilcPublicKey public_key = NULL;
1397 SilcDList channel_pubkeys = NULL;
1401 CHECK_STATUS("Cannot change mode: ");
1404 /* Take Channel ID */
1405 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1406 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1410 /* Get the channel entry */
1411 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1413 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1417 /* Get channel mode */
1418 tmp = silc_argument_get_arg_type(args, 3, &len);
1419 if (!tmp || len != 4) {
1420 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1425 SILC_GET32_MSB(mode, tmp);
1426 channel->mode = mode;
1428 /* Get founder public key */
1429 tmp = silc_argument_get_arg_type(args, 4, &len);
1431 silc_public_key_payload_decode(tmp, len, &public_key);
1433 /* Get user limit */
1434 tmp = silc_argument_get_arg_type(args, 6, &len);
1435 if (tmp && len == 4)
1436 SILC_GET32_MSB(channel->user_limit, tmp);
1437 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1438 channel->user_limit = 0;
1440 /* Get channel public key(s) */
1441 tmp = silc_argument_get_arg_type(args, 5, &len);
1444 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1446 /* Notify application */
1447 silc_client_command_callback(cmd, channel, mode, public_key,
1448 channel_pubkeys, channel->user_limit);
1450 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1454 silc_pkcs_public_key_free(public_key);
1455 silc_fsm_next(fsm, silc_client_command_reply_processed);
1456 return SILC_FSM_CONTINUE;
1459 /********************************** CUMODE **********************************/
1461 /* Received reply for CUMODE command */
1463 SILC_FSM_STATE(silc_client_command_reply_cumode)
1465 SilcClientCommandContext cmd = fsm_context;
1466 SilcClientConnection conn = cmd->conn;
1467 SilcClient client = conn->client;
1468 SilcCommandPayload payload = state_context;
1469 SilcArgumentPayload args = silc_command_get_args(payload);
1470 SilcClientEntry client_entry;
1471 SilcChannelEntry channel;
1472 SilcChannelUser chu;
1473 unsigned char *modev;
1474 SilcUInt32 len, mode;
1478 CHECK_STATUS("Cannot change mode: ");
1481 /* Get channel mode */
1482 modev = silc_argument_get_arg_type(args, 2, &len);
1483 if (!modev || len != 4) {
1484 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1487 SILC_GET32_MSB(mode, modev);
1489 /* Take Channel ID */
1490 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1491 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1495 /* Get the channel entry */
1496 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1498 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1503 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1504 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1508 /* Get client entry */
1509 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1510 if (!client_entry) {
1511 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1516 chu = silc_client_on_channel(channel, client_entry);
1520 /* Notify application */
1521 silc_client_command_callback(cmd, mode, channel, client_entry);
1523 silc_client_unref_client(client, conn, client_entry);
1526 silc_fsm_next(fsm, silc_client_command_reply_processed);
1527 return SILC_FSM_CONTINUE;
1530 /********************************** KICK ************************************/
1532 SILC_FSM_STATE(silc_client_command_reply_kick)
1534 SilcClientCommandContext cmd = fsm_context;
1535 SilcClientConnection conn = cmd->conn;
1536 SilcClient client = conn->client;
1537 SilcCommandPayload payload = state_context;
1538 SilcArgumentPayload args = silc_command_get_args(payload);
1539 SilcClientEntry client_entry;
1540 SilcChannelEntry channel;
1544 CHECK_STATUS("Cannot kick: ");
1547 /* Take Channel ID */
1548 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1549 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1553 /* Get the channel entry */
1554 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1556 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1561 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1562 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1566 /* Get client entry */
1567 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1568 if (!client_entry) {
1569 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1573 /* Notify application */
1574 silc_client_command_callback(cmd, channel, client_entry);
1576 silc_client_unref_client(client, conn, client_entry);
1579 silc_fsm_next(fsm, silc_client_command_reply_processed);
1580 return SILC_FSM_CONTINUE;
1583 /******************************** SILCOPER **********************************/
1585 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1587 SilcClientCommandContext cmd = fsm_context;
1588 SilcCommandPayload payload = state_context;
1589 SilcArgumentPayload args = silc_command_get_args(payload);
1592 CHECK_STATUS("Cannot change mode: ");
1595 /* Notify application */
1596 silc_client_command_callback(cmd);
1598 silc_fsm_next(fsm, silc_client_command_reply_processed);
1599 return SILC_FSM_CONTINUE;
1602 /********************************** OPER ************************************/
1604 SILC_FSM_STATE(silc_client_command_reply_oper)
1606 SilcClientCommandContext cmd = fsm_context;
1607 SilcCommandPayload payload = state_context;
1608 SilcArgumentPayload args = silc_command_get_args(payload);
1611 CHECK_STATUS("Cannot change mode: ");
1614 /* Notify application */
1615 silc_client_command_callback(cmd);
1617 silc_fsm_next(fsm, silc_client_command_reply_processed);
1618 return SILC_FSM_CONTINUE;
1621 /********************************* DETACH ***********************************/
1623 SILC_FSM_STATE(silc_client_command_reply_detach)
1625 SilcClientCommandContext cmd = fsm_context;
1626 SilcClientConnection conn = cmd->conn;
1627 SilcClient client = conn->client;
1628 SilcCommandPayload payload = state_context;
1629 SilcArgumentPayload args = silc_command_get_args(payload);
1633 CHECK_STATUS("Cannot detach: ");
1636 /* Get detachment data */
1637 detach = silc_client_get_detach_data(client, conn);
1639 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1643 /* Notify application */
1644 silc_client_command_callback(cmd, detach);
1645 silc_buffer_free(detach);
1648 silc_fsm_next(fsm, silc_client_command_reply_processed);
1649 return SILC_FSM_CONTINUE;
1652 /********************************** WATCH ***********************************/
1654 SILC_FSM_STATE(silc_client_command_reply_watch)
1656 SilcClientCommandContext cmd = fsm_context;
1657 SilcCommandPayload payload = state_context;
1658 SilcArgumentPayload args = silc_command_get_args(payload);
1661 CHECK_STATUS("Cannot set watch: ");
1664 /* Notify application */
1665 silc_client_command_callback(cmd);
1667 silc_fsm_next(fsm, silc_client_command_reply_processed);
1668 return SILC_FSM_CONTINUE;
1671 /*********************************** BAN ************************************/
1673 SILC_FSM_STATE(silc_client_command_reply_ban)
1675 SilcClientCommandContext cmd = fsm_context;
1676 SilcClientConnection conn = cmd->conn;
1677 SilcClient client = conn->client;
1678 SilcCommandPayload payload = state_context;
1679 SilcArgumentPayload args = silc_command_get_args(payload);
1680 SilcChannelEntry channel;
1683 SilcArgumentPayload invite_args = NULL;
1687 CHECK_STATUS("Cannot set ban: ");
1690 /* Take Channel ID */
1691 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1692 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1696 /* Get the channel entry */
1697 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1699 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1703 /* Get the invite list */
1704 tmp = silc_argument_get_arg_type(args, 3, &len);
1706 invite_args = silc_argument_list_parse(tmp, len);
1708 /* Notify application */
1709 silc_client_command_callback(cmd, channel, invite_args);
1712 silc_argument_payload_free(invite_args);
1715 silc_fsm_next(fsm, silc_client_command_reply_processed);
1716 return SILC_FSM_CONTINUE;
1719 /********************************** LEAVE ***********************************/
1721 /* Reply to LEAVE command. */
1723 SILC_FSM_STATE(silc_client_command_reply_leave)
1725 SilcClientCommandContext cmd = fsm_context;
1726 SilcClientConnection conn = cmd->conn;
1727 SilcClient client = conn->client;
1728 SilcCommandPayload payload = state_context;
1729 SilcArgumentPayload args = silc_command_get_args(payload);
1730 SilcChannelEntry channel;
1734 CHECK_STATUS("Cannot set leave: ");
1737 /* Get Channel ID */
1738 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1739 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1743 /* Get the channel entry */
1744 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1746 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1750 /* Remove us from this channel. */
1751 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1753 /* Notify application */
1754 silc_client_command_callback(cmd, channel);
1756 /* Now delete the channel. */
1757 silc_client_empty_channel(client, conn, channel);
1758 silc_client_del_channel(client, conn, channel);
1761 silc_fsm_next(fsm, silc_client_command_reply_processed);
1762 return SILC_FSM_CONTINUE;
1765 /********************************* USERS ************************************/
1767 /* Continue USERS command reply processing after resolving unknown users */
1770 silc_client_command_reply_users_resolved(SilcClient client,
1771 SilcClientConnection conn,
1776 SilcClientCommandContext cmd = context;
1777 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1781 /* Continue USERS command after resolving unknown channel */
1784 silc_client_command_reply_users_continue(SilcClient client,
1785 SilcClientConnection conn,
1790 SilcClientCommandContext cmd = context;
1793 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1794 SilcArgumentPayload args = silc_command_get_args(payload);
1796 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1797 ERROR_CALLBACK(cmd->status);
1798 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1801 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1804 /* Reply to USERS command. Received list of client ID's and theirs modes
1805 on the channel we requested. */
1807 SILC_FSM_STATE(silc_client_command_reply_users)
1809 SilcClientCommandContext cmd = fsm_context;
1810 SilcClientConnection conn = cmd->conn;
1811 SilcClient client = conn->client;
1812 SilcCommandPayload payload = state_context;
1813 SilcArgumentPayload args = silc_command_get_args(payload);
1815 SilcUInt32 tmp_len, list_count;
1816 SilcUInt16 idp_len, mode;
1817 SilcHashTableList htl;
1818 SilcBufferStruct client_id_list, client_mode_list;
1819 SilcChannelEntry channel = NULL;
1820 SilcClientEntry client_entry;
1825 CHECK_STATUS("Cannot get users: ");
1828 /* Get channel ID */
1829 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1830 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1834 /* Get channel entry */
1835 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1837 /* Resolve the channel from server */
1838 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1839 client, conn, &id.u.channel_id,
1840 silc_client_command_reply_users_continue, cmd));
1844 /* Get the list count */
1845 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1846 if (!tmp || tmp_len != 4) {
1847 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1850 SILC_GET32_MSB(list_count, tmp);
1852 /* Get Client ID list */
1853 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1855 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1858 silc_buffer_set(&client_id_list, tmp, tmp_len);
1860 /* Resolve users we do not know about */
1861 if (!cmd->resolved) {
1862 cmd->resolved = TRUE;
1863 silc_client_unref_channel(client, conn, channel);
1864 SILC_FSM_CALL(silc_client_get_clients_by_list(
1865 client, conn, list_count, &client_id_list,
1866 silc_client_command_reply_users_resolved, cmd));
1870 /* Get client mode list */
1871 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1873 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1876 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1878 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1880 /* Cache the received Client ID's and modes. */
1881 for (i = 0; i < list_count; i++) {
1882 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1884 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1888 SILC_GET32_MSB(mode, client_mode_list.data);
1890 /* Save the client on this channel. Unknown clients are ignored as they
1891 clearly do not exist since the resolving didn't find them. */
1892 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1894 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1895 silc_client_unref_client(client, conn, client_entry);
1897 if (!silc_buffer_pull(&client_id_list, idp_len))
1899 if (!silc_buffer_pull(&client_mode_list, 4))
1903 /* Notify application */
1904 silc_hash_table_list(channel->user_list, &htl);
1905 silc_client_command_callback(cmd, channel, &htl);
1906 silc_hash_table_list_reset(&htl);
1909 silc_client_unref_channel(client, conn, channel);
1910 silc_fsm_next(fsm, silc_client_command_reply_processed);
1911 return SILC_FSM_CONTINUE;
1914 /********************************** GETKEY **********************************/
1916 /* Received command reply to GETKEY command. WE've received the remote
1917 client's public key. */
1919 SILC_FSM_STATE(silc_client_command_reply_getkey)
1921 SilcClientCommandContext cmd = fsm_context;
1922 SilcClientConnection conn = cmd->conn;
1923 SilcClient client = conn->client;
1924 SilcCommandPayload payload = state_context;
1925 SilcArgumentPayload args = silc_command_get_args(payload);
1926 SilcClientEntry client_entry;
1927 SilcServerEntry server_entry;
1930 SilcPublicKey public_key;
1934 CHECK_STATUS("Cannot get key: ");
1938 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1939 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1943 /* Get the public key */
1944 tmp = silc_argument_get_arg_type(args, 3, &len);
1946 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1949 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1950 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1954 if (id.type == SILC_ID_CLIENT) {
1955 /* Received client's public key */
1956 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1957 if (!client_entry) {
1958 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1962 /* Save fingerprint */
1963 if (!client_entry->fingerprint)
1964 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
1965 client_entry->fingerprint);
1966 if (!client_entry->public_key) {
1967 client_entry->public_key = public_key;
1971 /* Notify application */
1972 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1973 client_entry->public_key);
1974 silc_client_unref_client(client, conn, client_entry);
1975 } else if (id.type == SILC_ID_SERVER) {
1976 /* Received server's public key */
1977 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1978 if (!server_entry) {
1979 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1983 if (!server_entry->public_key) {
1984 server_entry->public_key = public_key;
1988 /* Notify application */
1989 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1990 server_entry->public_key);
1991 silc_client_unref_server(client, conn, server_entry);
1996 silc_pkcs_public_key_free(public_key);
1997 silc_fsm_next(fsm, silc_client_command_reply_processed);
1998 return SILC_FSM_CONTINUE;
2001 /********************************** SERVICE *********************************/
2003 /* Reply to SERVICE command. */
2004 /* XXX incomplete */
2006 SILC_FSM_STATE(silc_client_command_reply_service)
2008 SilcClientCommandContext cmd = fsm_context;
2009 SilcCommandPayload payload = state_context;
2010 SilcArgumentPayload args = silc_command_get_args(payload);
2012 unsigned char *service_list, *name;
2015 CHECK_STATUS("Cannot get service: ");
2017 /* Get service list */
2018 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2020 /* Get requested service name */
2021 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2023 /* Notify application */
2024 silc_client_command_callback(cmd, service_list, name);
2026 silc_fsm_next(fsm, silc_client_command_reply_processed);
2027 return SILC_FSM_CONTINUE;
2030 /*********************************** QUIT ***********************************/
2032 /* QUIT command reply stub */
2034 SILC_FSM_STATE(silc_client_command_reply_quit)
2036 silc_fsm_next(fsm, silc_client_command_reply_processed);
2037 return SILC_FSM_CONTINUE;