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(error) \
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 = error; \
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_process); \
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_process); \
59 return SILC_FSM_CONTINUE; \
62 #define SAY cmd->conn->client->internal->ops->say
64 /************************ Static utility functions **************************/
66 /* Delivers the command reply back to application */
69 silc_client_command_callback(SilcClientCommandContext cmd, ...)
71 SilcClientCommandReplyCallback cb;
76 /* Default reply callback */
79 cmd->conn->client->internal->ops->command_reply(
80 cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
86 silc_list_start(cmd->reply_callbacks);
87 while ((cb = silc_list_get(cmd->reply_callbacks)))
88 if (!cb->do_not_call) {
90 cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
91 cmd->status, cmd->error, cb->context, cp);
98 /* Handles common error status types. */
100 static void silc_client_command_process_error(SilcClientCommandContext cmd,
101 SilcCommandPayload payload,
104 SilcClient client = cmd->conn->client;
105 SilcClientConnection conn = cmd->conn;
106 SilcArgumentPayload args = silc_command_get_args(payload);
107 SilcClientEntry client_entry;
110 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
111 /* Remove unknown client entry from cache */
112 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
115 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
117 silc_client_unref_client(client, conn, client_entry);
118 silc_client_del_client(client, conn, client_entry);
123 /***************************** Command Reply ********************************/
125 /* Process received command reply packet */
127 SILC_FSM_STATE(silc_client_command_reply)
129 SilcClientConnection conn = fsm_context;
130 SilcPacket packet = state_context;
131 SilcClientCommandContext cmd;
132 SilcCommandPayload payload;
134 SilcUInt16 cmd_ident;
136 /* Get command reply payload from packet */
137 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
138 silc_packet_free(packet);
140 SILC_LOG_DEBUG(("Bad command reply packet"));
141 return SILC_FSM_FINISH;
144 cmd_ident = silc_command_get_ident(payload);
145 command = silc_command_get(payload);
147 /* Find the command pending reply */
148 silc_mutex_lock(conn->internal->lock);
149 silc_list_start(conn->internal->pending_commands);
150 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
151 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
152 && cmd->cmd_ident == cmd_ident) {
153 silc_list_del(conn->internal->pending_commands, cmd);
157 silc_mutex_unlock(conn->internal->lock);
160 SILC_LOG_DEBUG(("Unknown command reply"));
161 silc_command_payload_free(payload);
162 return SILC_FSM_FINISH;
165 /* Signal command thread that command reply has arrived */
166 silc_fsm_set_state_context(&cmd->thread, payload);
167 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
168 silc_fsm_continue_sync(&cmd->thread);
170 return SILC_FSM_FINISH;
173 /* Wait here for command reply to arrive from remote host */
175 SILC_FSM_STATE(silc_client_command_reply_wait)
177 SILC_LOG_DEBUG(("Wait for command reply"));
179 /** Wait for command reply */
180 silc_fsm_set_state_context(fsm, NULL);
181 silc_fsm_next_later(fsm, silc_client_command_reply_timeout, 20, 0);
182 return SILC_FSM_WAIT;
185 /* Timeout occurred while waiting command reply */
187 SILC_FSM_STATE(silc_client_command_reply_timeout)
189 SilcClientCommandContext cmd = fsm_context;
190 SilcArgumentPayload args = NULL;
192 /* Timeout, reply not received in timely fashion */
193 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
194 return SILC_FSM_FINISH;
197 /* Process received command reply payload */
199 SILC_FSM_STATE(silc_client_command_reply_process)
201 SilcClientCommandContext cmd = fsm_context;
202 SilcCommandPayload payload = state_context;
204 silc_command_get_status(payload, &cmd->status, &cmd->error);
207 case SILC_COMMAND_WHOIS:
209 silc_fsm_next(fsm, silc_client_command_reply_whois);
211 case SILC_COMMAND_WHOWAS:
213 silc_fsm_next(fsm, silc_client_command_reply_whowas);
215 case SILC_COMMAND_IDENTIFY:
217 silc_fsm_next(fsm, silc_client_command_reply_identify);
219 case SILC_COMMAND_NICK:
221 silc_fsm_next(fsm, silc_client_command_reply_nick);
223 case SILC_COMMAND_LIST:
225 silc_fsm_next(fsm, silc_client_command_reply_list);
227 case SILC_COMMAND_TOPIC:
229 silc_fsm_next(fsm, silc_client_command_reply_topic);
231 case SILC_COMMAND_INVITE:
233 silc_fsm_next(fsm, silc_client_command_reply_invite);
235 case SILC_COMMAND_QUIT:
237 silc_fsm_next(fsm, silc_client_command_reply_quit);
239 case SILC_COMMAND_KILL:
241 silc_fsm_next(fsm, silc_client_command_reply_kill);
243 case SILC_COMMAND_INFO:
245 silc_fsm_next(fsm, silc_client_command_reply_info);
247 case SILC_COMMAND_STATS:
249 silc_fsm_next(fsm, silc_client_command_reply_stats);
251 case SILC_COMMAND_PING:
253 silc_fsm_next(fsm, silc_client_command_reply_ping);
255 case SILC_COMMAND_OPER:
257 silc_fsm_next(fsm, silc_client_command_reply_oper);
259 case SILC_COMMAND_JOIN:
261 silc_fsm_next(fsm, silc_client_command_reply_join);
263 case SILC_COMMAND_MOTD:
265 silc_fsm_next(fsm, silc_client_command_reply_motd);
267 case SILC_COMMAND_UMODE:
269 silc_fsm_next(fsm, silc_client_command_reply_umode);
271 case SILC_COMMAND_CMODE:
273 silc_fsm_next(fsm, silc_client_command_reply_cmode);
275 case SILC_COMMAND_CUMODE:
277 silc_fsm_next(fsm, silc_client_command_reply_cumode);
279 case SILC_COMMAND_KICK:
281 silc_fsm_next(fsm, silc_client_command_reply_kick);
283 case SILC_COMMAND_BAN:
285 silc_fsm_next(fsm, silc_client_command_reply_ban);
287 case SILC_COMMAND_DETACH:
289 silc_fsm_next(fsm, silc_client_command_reply_detach);
291 case SILC_COMMAND_WATCH:
293 silc_fsm_next(fsm, silc_client_command_reply_watch);
295 case SILC_COMMAND_SILCOPER:
297 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
299 case SILC_COMMAND_LEAVE:
301 silc_fsm_next(fsm, silc_client_command_reply_leave);
303 case SILC_COMMAND_USERS:
305 silc_fsm_next(fsm, silc_client_command_reply_users);
307 case SILC_COMMAND_GETKEY:
309 silc_fsm_next(fsm, silc_client_command_reply_getkey);
311 case SILC_COMMAND_SERVICE:
313 silc_fsm_next(fsm, silc_client_command_reply_service);
316 return SILC_FSM_FINISH;
319 return SILC_FSM_CONTINUE;
322 /* Completes command reply processing */
324 SILC_FSM_STATE(silc_client_command_reply_processed)
326 SilcClientCommandContext cmd = fsm_context;
327 SilcClientConnection conn = cmd->conn;
328 SilcCommandPayload payload = state_context;
330 silc_command_payload_free(payload);
332 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
333 SILC_STATUS_IS_ERROR(cmd->status))
334 return SILC_FSM_FINISH;
336 /* Add back to pending command reply list */
337 silc_mutex_lock(conn->internal->lock);
338 cmd->resolved = FALSE;
339 silc_list_add(conn->internal->pending_commands, cmd);
340 silc_mutex_unlock(conn->internal->lock);
342 /** Wait more command payloads */
343 silc_fsm_next(fsm, silc_client_command_reply_wait);
344 return SILC_FSM_CONTINUE;
347 /******************************** WHOIS *************************************/
349 /* Received reply for WHOIS command. */
351 SILC_FSM_STATE(silc_client_command_reply_whois)
353 SilcClientCommandContext cmd = fsm_context;
354 SilcClientConnection conn = cmd->conn;
355 SilcClient client = conn->client;
356 SilcCommandPayload payload = state_context;
357 SilcArgumentPayload args = silc_command_get_args(payload);
358 SilcClientEntry client_entry = NULL;
359 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
360 SilcBufferStruct channels, ch_user_modes;
361 SilcBool has_channels = FALSE;
362 SilcDList channel_list = NULL;
364 char *nickname = NULL, *username = NULL, *realname = NULL;
365 unsigned char *fingerprint, *tmp;
367 CHECK_STATUS("WHOIS: ");
371 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
372 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
377 nickname = silc_argument_get_arg_type(args, 3, NULL);
378 username = silc_argument_get_arg_type(args, 4, NULL);
379 realname = silc_argument_get_arg_type(args, 5, NULL);
380 if (!nickname || !username || !realname) {
381 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
385 /* Get joined channel list */
386 memset(&channels, 0, sizeof(channels));
387 tmp = silc_argument_get_arg_type(args, 6, &len);
390 silc_buffer_set(&channels, tmp, len);
392 /* Get channel user mode list */
393 tmp = silc_argument_get_arg_type(args, 10, &len);
395 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
398 silc_buffer_set(&ch_user_modes, tmp, len);
402 tmp = silc_argument_get_arg_type(args, 7, &len);
404 SILC_GET32_MSB(mode, tmp);
407 tmp = silc_argument_get_arg_type(args, 8, &len);
409 SILC_GET32_MSB(idle, tmp);
411 /* Get fingerprint */
412 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
414 /* Check if we have this client cached already. */
415 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
417 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
419 silc_client_add_client(client, conn, nickname, username, realname,
420 &id.u.client_id, mode);
422 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
425 silc_client_ref_client(client, conn, client_entry);
427 silc_client_update_client(client, conn, client_entry,
428 nickname, username, realname, mode);
431 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
432 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
434 /* Get user attributes */
435 tmp = silc_argument_get_arg_type(args, 11, &len);
437 if (client_entry->attrs)
438 silc_attribute_payload_list_free(client_entry->attrs);
439 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
442 /* Parse channel and channel user mode list */
444 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
445 silc_buffer_len(&channels));
447 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
451 /* Notify application */
452 silc_client_command_callback(cmd, client_entry, nickname, username,
453 realname, channel_list, mode, idle, fingerprint,
454 umodes, client_entry->attrs);
456 silc_client_unref_client(client, conn, client_entry);
458 silc_dlist_uninit(channel_list);
463 silc_fsm_next(fsm, silc_client_command_reply_processed);
464 return SILC_FSM_CONTINUE;
467 /******************************** WHOWAS ************************************/
469 /* Received reply for WHOWAS command. */
471 SILC_FSM_STATE(silc_client_command_reply_whowas)
473 SilcClientCommandContext cmd = fsm_context;
474 SilcClientConnection conn = cmd->conn;
475 SilcClient client = conn->client;
476 SilcCommandPayload payload = state_context;
477 SilcArgumentPayload args = silc_command_get_args(payload);
478 SilcClientEntry client_entry = NULL;
480 char *nickname, *username;
481 char *realname = NULL;
483 CHECK_STATUS("WHOWAS: ");
487 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
488 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
492 /* Get the client entry */
493 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
496 nickname = silc_argument_get_arg_type(args, 3, NULL);
497 username = silc_argument_get_arg_type(args, 4, NULL);
498 realname = silc_argument_get_arg_type(args, 5, NULL);
499 if (!nickname || !username) {
500 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
504 /* Notify application. We don't save any history information to any
505 cache. Just pass the data to the application. */
506 silc_client_command_callback(cmd, client_entry, nickname, username,
510 silc_client_unref_client(client, conn, client_entry);
511 silc_fsm_next(fsm, silc_client_command_reply_processed);
512 return SILC_FSM_CONTINUE;
515 /******************************** IDENTIFY **********************************/
517 /* Received reply for IDENTIFY command. */
519 SILC_FSM_STATE(silc_client_command_reply_identify)
521 SilcClientCommandContext cmd = fsm_context;
522 SilcClientConnection conn = cmd->conn;
523 SilcClient client = conn->client;
524 SilcCommandPayload payload = state_context;
525 SilcArgumentPayload args = silc_command_get_args(payload);
526 SilcClientEntry client_entry;
527 SilcServerEntry server_entry;
528 SilcChannelEntry channel_entry;
531 char *name = NULL, *info = NULL;
533 CHECK_STATUS("IDENTIFY: ");
537 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
538 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
543 name = silc_argument_get_arg_type(args, 3, &len);
544 info = silc_argument_get_arg_type(args, 4, &len);
548 SILC_LOG_DEBUG(("Received client information"));
550 /* Check if we have this client cached already. */
551 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
553 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
555 silc_client_add_client(client, conn, name, info, NULL,
558 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
561 silc_client_ref_client(client, conn, client_entry);
563 silc_client_update_client(client, conn, client_entry,
564 name, info, NULL, 0);
567 /* Notify application */
568 silc_client_command_callback(cmd, client_entry, name, info);
569 silc_client_unref_client(client, conn, client_entry);
573 SILC_LOG_DEBUG(("Received server information"));
575 /* Check if we have this server cached already. */
576 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
578 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
579 server_entry = silc_client_add_server(client, conn, name, info,
582 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
586 silc_client_update_server(client, conn, server_entry, name, info);
588 server_entry->internal.resolve_cmd_ident = 0;
590 /* Notify application */
591 silc_client_command_callback(cmd, server_entry, name, info);
594 case SILC_ID_CHANNEL:
595 SILC_LOG_DEBUG(("Received channel information"));
597 /* Check if we have this channel cached already. */
598 channel_entry = silc_client_get_channel_by_id(client, conn,
600 if (!channel_entry) {
601 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
604 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
608 /* Add new channel entry */
609 channel_entry = silc_client_add_channel(client, conn, name, 0,
611 if (!channel_entry) {
612 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
617 /* Notify application */
618 silc_client_command_callback(cmd, channel_entry, name, info);
623 silc_fsm_next(fsm, silc_client_command_reply_processed);
624 return SILC_FSM_CONTINUE;
627 /********************************** NICK ************************************/
629 /* Received reply for command NICK. */
631 SILC_FSM_STATE(silc_client_command_reply_nick)
633 SilcClientCommandContext cmd = fsm_context;
634 SilcClientConnection conn = cmd->conn;
635 SilcClient client = conn->client;
636 SilcCommandPayload payload = state_context;
637 SilcArgumentPayload args = silc_command_get_args(payload);
638 unsigned char *tmp, *nick, *idp;
639 SilcUInt32 len, idp_len;
640 SilcClientID old_client_id;
644 CHECK_STATUS("Cannot set nickname: ");
647 old_client_id = *conn->local_id;
649 /* Take received Client ID */
650 idp = silc_argument_get_arg_type(args, 2, &idp_len);
652 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
655 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
656 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
660 /* Take the new nickname */
661 nick = silc_argument_get_arg_type(args, 3, &len);
663 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
667 /* Normalize nickname */
668 tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
670 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
674 /* Update the client entry */
675 silc_mutex_lock(conn->internal->lock);
676 if (!silc_idcache_update(conn->internal->client_cache,
677 conn->internal->local_entry,
678 &conn->local_entry->id,
680 conn->local_entry->nickname_normalized,
683 silc_mutex_unlock(conn->internal->lock);
684 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
687 silc_mutex_unlock(conn->internal->lock);
688 memset(conn->local_entry->nickname, 0, sizeof(conn->local_entry->nickname));
689 memcpy(conn->local_entry->nickname, nick, len);
690 conn->local_entry->nickname_normalized = tmp;
691 silc_buffer_enlarge(conn->internal->local_idp, idp_len);
692 silc_buffer_put(conn->internal->local_idp, idp, idp_len);
693 silc_client_nickname_format(client, conn, conn->local_entry);
694 silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id, 0, NULL);
696 /* Notify application */
697 silc_client_command_callback(cmd, conn->local_entry,
698 conn->local_entry->nickname, &old_client_id);
701 silc_fsm_next(fsm, silc_client_command_reply_processed);
702 return SILC_FSM_CONTINUE;
705 /********************************** LIST ************************************/
707 /* Received reply to the LIST command. */
709 SILC_FSM_STATE(silc_client_command_reply_list)
711 SilcClientCommandContext cmd = fsm_context;
712 SilcClientConnection conn = cmd->conn;
713 SilcClient client = conn->client;
714 SilcCommandPayload payload = state_context;
715 SilcArgumentPayload args = silc_command_get_args(payload);
716 unsigned char *tmp, *name, *topic;
717 SilcUInt32 usercount = 0;
718 SilcChannelEntry channel_entry;
722 CHECK_STATUS("Cannot list channels: ");
724 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
725 /* There were no channels in the network. */
726 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
727 silc_fsm_next(fsm, silc_client_command_reply_processed);
728 return SILC_FSM_CONTINUE;
733 name = silc_argument_get_arg_type(args, 3, NULL);
735 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
739 topic = silc_argument_get_arg_type(args, 4, NULL);
740 tmp = silc_argument_get_arg_type(args, 5, NULL);
742 SILC_GET32_MSB(usercount, tmp);
744 /* Check whether the channel exists, and add it to cache if it doesn't. */
745 channel_entry = silc_client_get_channel_by_id(client, conn,
747 if (!channel_entry) {
748 /* Add new channel entry */
749 channel_entry = silc_client_add_channel(client, conn, name, 0,
751 if (!channel_entry) {
752 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
757 /* Notify application */
758 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
761 silc_fsm_next(fsm, silc_client_command_reply_processed);
762 return SILC_FSM_CONTINUE;
765 /********************************* TOPIC ************************************/
767 /* Received reply to topic command. */
769 SILC_FSM_STATE(silc_client_command_reply_topic)
771 SilcClientCommandContext cmd = fsm_context;
772 SilcClientConnection conn = cmd->conn;
773 SilcClient client = conn->client;
774 SilcCommandPayload payload = state_context;
775 SilcArgumentPayload args = silc_command_get_args(payload);
776 SilcChannelEntry channel;
782 CHECK_STATUS("Cannot set topic: ");
785 /* Take Channel ID */
786 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
787 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
791 /* Get the channel entry */
792 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
794 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
799 topic = silc_argument_get_arg_type(args, 3, &len);
801 silc_free(channel->topic);
802 channel->topic = silc_memdup(topic, len);
805 /* Notify application */
806 silc_client_command_callback(cmd, channel, channel->topic);
809 silc_fsm_next(fsm, silc_client_command_reply_processed);
810 return SILC_FSM_CONTINUE;
813 /********************************* INVITE ***********************************/
815 /* Received reply to invite command. */
817 SILC_FSM_STATE(silc_client_command_reply_invite)
819 SilcClientCommandContext cmd = fsm_context;
820 SilcClientConnection conn = cmd->conn;
821 SilcClient client = conn->client;
822 SilcCommandPayload payload = state_context;
823 SilcArgumentPayload args = silc_command_get_args(payload);
824 SilcChannelEntry channel;
827 SilcArgumentPayload invite_args = NULL;
831 CHECK_STATUS("Cannot invite: ");
834 /* Take Channel ID */
835 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
836 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
840 /* Get the channel entry */
841 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
843 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
847 /* Get the invite list */
848 tmp = silc_argument_get_arg_type(args, 3, &len);
850 invite_args = silc_argument_list_parse(tmp, len);
852 /* Notify application */
853 silc_client_command_callback(cmd, channel, invite_args);
856 silc_argument_payload_free(invite_args);
859 silc_fsm_next(fsm, silc_client_command_reply_processed);
860 return SILC_FSM_CONTINUE;
863 /********************************** KILL ************************************/
865 /* Received reply to the KILL command. */
867 SILC_FSM_STATE(silc_client_command_reply_kill)
869 SilcClientCommandContext cmd = fsm_context;
870 SilcClientConnection conn = cmd->conn;
871 SilcClient client = conn->client;
872 SilcCommandPayload payload = state_context;
873 SilcArgumentPayload args = silc_command_get_args(payload);
874 SilcClientEntry client_entry;
878 CHECK_STATUS("Cannot kill: ");
881 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
882 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
886 /* Get the client entry, if exists */
887 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
889 /* Notify application */
890 silc_client_command_callback(cmd, client_entry);
892 /* Remove the client from all channels and free it */
894 silc_client_del_client(client, conn, client_entry);
895 silc_client_unref_client(client, conn, client_entry);
899 silc_fsm_next(fsm, silc_client_command_reply_processed);
900 return SILC_FSM_CONTINUE;
903 /********************************** INFO ************************************/
905 /* Received reply to INFO command. We receive the server ID and some
906 information about the server user requested. */
908 SILC_FSM_STATE(silc_client_command_reply_info)
910 SilcClientCommandContext cmd = fsm_context;
911 SilcClientConnection conn = cmd->conn;
912 SilcClient client = conn->client;
913 SilcCommandPayload payload = state_context;
914 SilcArgumentPayload args = silc_command_get_args(payload);
915 SilcServerEntry server;
916 char *server_name, *server_info;
920 CHECK_STATUS("Cannot get info: ");
924 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
925 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
929 /* Get server name */
930 server_name = silc_argument_get_arg_type(args, 3, NULL);
932 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
936 /* Get server info */
937 server_info = silc_argument_get_arg_type(args, 4, NULL);
939 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
943 /* See whether we have this server cached. If not create it. */
944 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
946 SILC_LOG_DEBUG(("New server entry"));
947 server = silc_client_add_server(client, conn, server_name,
948 server_info, &id.u.server_id);
953 /* Notify application */
954 silc_client_command_callback(cmd, server, server->server_name,
955 server->server_info);
958 silc_fsm_next(fsm, silc_client_command_reply_processed);
959 return SILC_FSM_CONTINUE;
962 /********************************** STATS ***********************************/
964 /* Received reply to STATS command. */
966 SILC_FSM_STATE(silc_client_command_reply_stats)
968 SilcClientCommandContext cmd = fsm_context;
969 SilcCommandPayload payload = state_context;
970 SilcArgumentPayload args = silc_command_get_args(payload);
971 SilcClientStats stats;
972 unsigned char *buf = NULL;
973 SilcUInt32 buf_len = 0;
978 CHECK_STATUS("Cannot get stats: ");
982 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
983 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
987 /* Get statistics structure */
988 memset(&stats, 0, sizeof(stats));
989 buf = silc_argument_get_arg_type(args, 3, &buf_len);
991 silc_buffer_set(&b, buf, buf_len);
992 silc_buffer_unformat(&b,
993 SILC_STR_UI_INT(&stats.starttime),
994 SILC_STR_UI_INT(&stats.uptime),
995 SILC_STR_UI_INT(&stats.my_clients),
996 SILC_STR_UI_INT(&stats.my_channels),
997 SILC_STR_UI_INT(&stats.my_server_ops),
998 SILC_STR_UI_INT(&stats.my_router_ops),
999 SILC_STR_UI_INT(&stats.cell_clients),
1000 SILC_STR_UI_INT(&stats.cell_channels),
1001 SILC_STR_UI_INT(&stats.cell_servers),
1002 SILC_STR_UI_INT(&stats.clients),
1003 SILC_STR_UI_INT(&stats.channels),
1004 SILC_STR_UI_INT(&stats.servers),
1005 SILC_STR_UI_INT(&stats.routers),
1006 SILC_STR_UI_INT(&stats.server_ops),
1007 SILC_STR_UI_INT(&stats.router_ops),
1011 /* Notify application */
1012 silc_client_command_callback(cmd, &stats);
1015 silc_fsm_next(fsm, silc_client_command_reply_processed);
1016 return SILC_FSM_CONTINUE;
1019 /********************************** PING ************************************/
1021 /* Received reply to PING command. */
1023 SILC_FSM_STATE(silc_client_command_reply_ping)
1025 SilcClientCommandContext cmd = fsm_context;
1026 SilcClientConnection conn = cmd->conn;
1027 SilcClient client = conn->client;
1030 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1032 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1033 "Ping reply from %s: %d second%s", conn->remote_host,
1034 (int)diff, diff == 1 ? "" : "s");
1036 /* Notify application */
1037 silc_client_command_callback(cmd);
1039 silc_fsm_next(fsm, silc_client_command_reply_processed);
1040 return SILC_FSM_CONTINUE;
1043 /********************************** JOIN ************************************/
1045 /* Continue JOIN command reply processing after resolving unknown users */
1048 silc_client_command_reply_join_resolved(SilcClient client,
1049 SilcClientConnection conn,
1054 SilcClientCommandContext cmd = context;
1055 SilcChannelEntry channel = cmd->context;
1057 channel->internal.resolve_cmd_ident = 0;
1058 silc_client_unref_channel(client, conn, channel);
1060 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1064 /* Received reply for JOIN command. */
1066 SILC_FSM_STATE(silc_client_command_reply_join)
1068 SilcClientCommandContext cmd = fsm_context;
1069 SilcClientConnection conn = cmd->conn;
1070 SilcClient client = conn->client;
1071 SilcCommandPayload payload = state_context;
1072 SilcArgumentPayload args = silc_command_get_args(payload);
1073 SilcChannelEntry channel;
1074 SilcUInt32 mode = 0, len, list_count;
1075 char *topic, *tmp, *channel_name = NULL, *hmac;
1077 SilcBufferStruct client_id_list, client_mode_list, keyp;
1078 SilcHashTableList htl;
1079 SilcDList chpks = NULL;
1084 CHECK_STATUS("Cannot join channel: ");
1087 /* Get channel name */
1088 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1089 if (!channel_name) {
1090 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1094 /* Get Channel ID */
1095 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1096 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1100 /* Check whether we have this channel entry already. */
1101 channel = silc_client_get_channel(client, conn, channel_name);
1103 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1104 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1106 /* Create new channel entry */
1107 channel = silc_client_add_channel(client, conn, channel_name,
1108 mode, &id.u.channel_id);
1110 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1113 silc_client_ref_channel(client, conn, channel);
1116 /* Get the list count */
1117 tmp = silc_argument_get_arg_type(args, 12, &len);
1119 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1122 SILC_GET32_MSB(list_count, tmp);
1124 /* Get Client ID list */
1125 tmp = silc_argument_get_arg_type(args, 13, &len);
1127 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1130 silc_buffer_set(&client_id_list, tmp, len);
1132 /* Resolve users we do not know about */
1133 if (!cmd->resolved) {
1134 cmd->resolved = TRUE;
1135 cmd->context = channel;
1136 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1137 silc_client_get_clients_by_list(
1138 client, conn, list_count, &client_id_list,
1139 silc_client_command_reply_join_resolved, cmd));
1143 /* Get client mode list */
1144 tmp = silc_argument_get_arg_type(args, 14, &len);
1146 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1149 silc_buffer_set(&client_mode_list, tmp, len);
1151 /* Add clients we received in the reply to the channel */
1152 for (i = 0; i < list_count; i++) {
1156 SilcClientEntry client_entry;
1159 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1161 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1165 SILC_GET32_MSB(mode, client_mode_list.data);
1167 SILC_LOG_DEBUG(("id %s", silc_id_render(&id.u.client_id, SILC_ID_CLIENT)));
1169 /* Get client entry */
1170 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1174 /* Join client to the channel */
1175 silc_client_add_to_channel(channel, client_entry, mode);
1176 silc_client_unref_client(client, conn, client_entry);
1178 if (!silc_buffer_pull(&client_id_list, idp_len))
1180 if (!silc_buffer_pull(&client_mode_list, 4))
1185 hmac = silc_argument_get_arg_type(args, 11, NULL);
1187 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1189 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1190 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1191 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1196 /* Get channel mode */
1197 tmp = silc_argument_get_arg_type(args, 5, NULL);
1199 SILC_GET32_MSB(mode, tmp);
1200 channel->mode = mode;
1202 /* Get channel key and save it */
1203 tmp = silc_argument_get_arg_type(args, 7, &len);
1205 silc_buffer_set(&keyp, tmp, len);
1206 silc_client_save_channel_key(client, conn, &keyp, channel);
1210 topic = silc_argument_get_arg_type(args, 10, NULL);
1212 silc_free(channel->topic);
1213 channel->topic = silc_memdup(topic, strlen(topic));
1216 /* Get founder key */
1217 tmp = silc_argument_get_arg_type(args, 15, &len);
1219 if (channel->founder_key)
1220 silc_pkcs_public_key_free(channel->founder_key);
1221 channel->founder_key = NULL;
1222 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1225 /* Get user limit */
1226 tmp = silc_argument_get_arg_type(args, 17, &len);
1227 if (tmp && len == 4)
1228 SILC_GET32_MSB(channel->user_limit, tmp);
1229 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1230 channel->user_limit = 0;
1232 /* Get channel public key list */
1233 tmp = silc_argument_get_arg_type(args, 16, &len);
1235 chpks = silc_argument_list_parse_decoded(tmp, len,
1236 SILC_ARGUMENT_PUBLIC_KEY);
1238 /* Set current channel */
1239 conn->current_channel = channel;
1241 cipher = (channel->internal.channel_key ?
1242 silc_cipher_get_name(channel->internal.channel_key) : NULL);
1243 silc_hash_table_list(channel->user_list, &htl);
1245 /* Notify application */
1246 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1247 topic, cipher, hmac, channel->founder_key,
1248 chpks, channel->user_limit);
1251 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
1252 silc_hash_table_list_reset(&htl);
1253 silc_client_unref_channel(client, conn, channel);
1256 silc_fsm_next(fsm, silc_client_command_reply_processed);
1257 return SILC_FSM_CONTINUE;
1260 /********************************** MOTD ************************************/
1262 /* Received reply for MOTD command */
1264 SILC_FSM_STATE(silc_client_command_reply_motd)
1266 SilcClientCommandContext cmd = fsm_context;
1267 SilcClientConnection conn = cmd->conn;
1268 SilcClient client = conn->client;
1269 SilcCommandPayload payload = state_context;
1270 SilcArgumentPayload args = silc_command_get_args(payload);
1272 char *motd = NULL, *cp, line[256];
1275 CHECK_STATUS("Cannot get motd: ");
1278 if (silc_argument_get_arg_num(args) == 3) {
1279 motd = silc_argument_get_arg_type(args, 3, NULL);
1281 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1288 if (cp[i++] == '\n') {
1289 memset(line, 0, sizeof(line));
1290 silc_strncat(line, sizeof(line), cp, i - 1);
1297 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1306 /* Notify application */
1307 silc_client_command_callback(cmd, motd);
1310 silc_fsm_next(fsm, silc_client_command_reply_processed);
1311 return SILC_FSM_CONTINUE;
1314 /********************************** UMODE ***********************************/
1316 /* Received reply to the UMODE command. Save the current user mode */
1318 SILC_FSM_STATE(silc_client_command_reply_umode)
1320 SilcClientCommandContext cmd = fsm_context;
1321 SilcClientConnection conn = cmd->conn;
1322 SilcCommandPayload payload = state_context;
1323 SilcArgumentPayload args = silc_command_get_args(payload);
1325 SilcUInt32 mode, len;
1328 CHECK_STATUS("Cannot change mode: ");
1331 tmp = silc_argument_get_arg_type(args, 2, &len);
1332 if (!tmp || len != 4) {
1333 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1337 SILC_GET32_MSB(mode, tmp);
1338 conn->local_entry->mode = mode;
1340 /* Notify application */
1341 silc_client_command_callback(cmd, mode);
1344 silc_fsm_next(fsm, silc_client_command_reply_processed);
1345 return SILC_FSM_CONTINUE;
1348 /********************************** CMODE ***********************************/
1350 /* Received reply for CMODE command. */
1352 SILC_FSM_STATE(silc_client_command_reply_cmode)
1354 SilcClientCommandContext cmd = fsm_context;
1355 SilcClientConnection conn = cmd->conn;
1356 SilcClient client = conn->client;
1357 SilcCommandPayload payload = state_context;
1358 SilcArgumentPayload args = silc_command_get_args(payload);
1361 SilcChannelEntry channel;
1363 SilcPublicKey public_key = NULL;
1364 SilcDList channel_pubkeys = NULL;
1368 CHECK_STATUS("Cannot change mode: ");
1371 /* Take Channel ID */
1372 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1373 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1377 /* Get the channel entry */
1378 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1380 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1384 /* Get channel mode */
1385 tmp = silc_argument_get_arg_type(args, 3, &len);
1386 if (!tmp || len != 4) {
1387 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1392 SILC_GET32_MSB(mode, tmp);
1393 channel->mode = mode;
1395 /* Get founder public key */
1396 tmp = silc_argument_get_arg_type(args, 4, &len);
1398 silc_public_key_payload_decode(tmp, len, &public_key);
1400 /* Get user limit */
1401 tmp = silc_argument_get_arg_type(args, 6, &len);
1402 if (tmp && len == 4)
1403 SILC_GET32_MSB(channel->user_limit, tmp);
1404 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1405 channel->user_limit = 0;
1407 /* Get channel public key(s) */
1408 tmp = silc_argument_get_arg_type(args, 5, &len);
1411 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1413 /* Notify application */
1414 silc_client_command_callback(cmd, channel, mode, public_key,
1415 channel_pubkeys, channel->user_limit);
1417 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1421 silc_pkcs_public_key_free(public_key);
1422 silc_fsm_next(fsm, silc_client_command_reply_processed);
1423 return SILC_FSM_CONTINUE;
1426 /********************************** CUMODE **********************************/
1428 /* Received reply for CUMODE command */
1430 SILC_FSM_STATE(silc_client_command_reply_cumode)
1432 SilcClientCommandContext cmd = fsm_context;
1433 SilcClientConnection conn = cmd->conn;
1434 SilcClient client = conn->client;
1435 SilcCommandPayload payload = state_context;
1436 SilcArgumentPayload args = silc_command_get_args(payload);
1437 SilcClientEntry client_entry;
1438 SilcChannelEntry channel;
1439 SilcChannelUser chu;
1440 unsigned char *modev;
1441 SilcUInt32 len, mode;
1445 CHECK_STATUS("Cannot change mode: ");
1448 /* Get channel mode */
1449 modev = silc_argument_get_arg_type(args, 2, &len);
1450 if (!modev || len != 4) {
1451 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1454 SILC_GET32_MSB(mode, modev);
1456 /* Take Channel ID */
1457 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1458 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1462 /* Get the channel entry */
1463 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1465 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1470 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1471 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1475 /* Get client entry */
1476 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1477 if (!client_entry) {
1478 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1483 chu = silc_client_on_channel(channel, client_entry);
1487 /* Notify application */
1488 silc_client_command_callback(cmd, mode, channel, client_entry);
1490 silc_client_unref_client(client, conn, client_entry);
1493 silc_fsm_next(fsm, silc_client_command_reply_processed);
1494 return SILC_FSM_CONTINUE;
1497 /********************************** KICK ************************************/
1499 SILC_FSM_STATE(silc_client_command_reply_kick)
1501 SilcClientCommandContext cmd = fsm_context;
1502 SilcClientConnection conn = cmd->conn;
1503 SilcClient client = conn->client;
1504 SilcCommandPayload payload = state_context;
1505 SilcArgumentPayload args = silc_command_get_args(payload);
1506 SilcClientEntry client_entry;
1507 SilcChannelEntry channel;
1511 CHECK_STATUS("Cannot kick: ");
1514 /* Take Channel ID */
1515 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1516 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1520 /* Get the channel entry */
1521 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1523 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1528 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1529 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1533 /* Get client entry */
1534 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1535 if (!client_entry) {
1536 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1540 /* Notify application */
1541 silc_client_command_callback(cmd, channel, client_entry);
1543 silc_client_unref_client(client, conn, client_entry);
1546 silc_fsm_next(fsm, silc_client_command_reply_processed);
1547 return SILC_FSM_CONTINUE;
1550 /******************************** SILCOPER **********************************/
1552 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1554 SilcClientCommandContext cmd = fsm_context;
1555 SilcCommandPayload payload = state_context;
1556 SilcArgumentPayload args = silc_command_get_args(payload);
1559 CHECK_STATUS("Cannot change mode: ");
1562 /* Notify application */
1563 silc_client_command_callback(cmd);
1565 silc_fsm_next(fsm, silc_client_command_reply_processed);
1566 return SILC_FSM_CONTINUE;
1569 /********************************** OPER ************************************/
1571 SILC_FSM_STATE(silc_client_command_reply_oper)
1573 SilcClientCommandContext cmd = fsm_context;
1574 SilcCommandPayload payload = state_context;
1575 SilcArgumentPayload args = silc_command_get_args(payload);
1578 CHECK_STATUS("Cannot change mode: ");
1581 /* Notify application */
1582 silc_client_command_callback(cmd);
1584 silc_fsm_next(fsm, silc_client_command_reply_processed);
1585 return SILC_FSM_CONTINUE;
1588 /********************************* DETACH ***********************************/
1590 SILC_FSM_STATE(silc_client_command_reply_detach)
1592 SilcClientCommandContext cmd = fsm_context;
1593 SilcClientConnection conn = cmd->conn;
1594 SilcClient client = conn->client;
1595 SilcCommandPayload payload = state_context;
1596 SilcArgumentPayload args = silc_command_get_args(payload);
1600 CHECK_STATUS("Cannot detach: ");
1603 /* Notify application */
1604 silc_client_command_callback(cmd);
1607 /* Generate the detachment data and deliver it to the client in the
1608 detach client operation */
1609 detach = silc_client_get_detach_data(client, conn);
1611 client->internal->ops->detach(client, conn, silc_buffer_data(detach),
1612 silc_buffer_len(detach));
1613 silc_buffer_free(detach);
1617 silc_fsm_next(fsm, silc_client_command_reply_processed);
1618 return SILC_FSM_CONTINUE;
1621 /********************************** WATCH ***********************************/
1623 SILC_FSM_STATE(silc_client_command_reply_watch)
1625 SilcClientCommandContext cmd = fsm_context;
1626 SilcCommandPayload payload = state_context;
1627 SilcArgumentPayload args = silc_command_get_args(payload);
1630 CHECK_STATUS("Cannot set watch: ");
1633 /* Notify application */
1634 silc_client_command_callback(cmd);
1636 silc_fsm_next(fsm, silc_client_command_reply_processed);
1637 return SILC_FSM_CONTINUE;
1640 /*********************************** BAN ************************************/
1642 SILC_FSM_STATE(silc_client_command_reply_ban)
1644 SilcClientCommandContext cmd = fsm_context;
1645 SilcClientConnection conn = cmd->conn;
1646 SilcClient client = conn->client;
1647 SilcCommandPayload payload = state_context;
1648 SilcArgumentPayload args = silc_command_get_args(payload);
1649 SilcChannelEntry channel;
1652 SilcArgumentPayload invite_args = NULL;
1656 CHECK_STATUS("Cannot set ban: ");
1659 /* Take Channel ID */
1660 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1661 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1665 /* Get the channel entry */
1666 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1668 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1672 /* Get the invite list */
1673 tmp = silc_argument_get_arg_type(args, 3, &len);
1675 invite_args = silc_argument_list_parse(tmp, len);
1677 /* Notify application */
1678 silc_client_command_callback(cmd, channel, invite_args);
1681 silc_argument_payload_free(invite_args);
1684 silc_fsm_next(fsm, silc_client_command_reply_processed);
1685 return SILC_FSM_CONTINUE;
1688 /********************************** LEAVE ***********************************/
1690 /* Reply to LEAVE command. */
1692 SILC_FSM_STATE(silc_client_command_reply_leave)
1694 SilcClientCommandContext cmd = fsm_context;
1695 SilcClientConnection conn = cmd->conn;
1696 SilcClient client = conn->client;
1697 SilcCommandPayload payload = state_context;
1698 SilcArgumentPayload args = silc_command_get_args(payload);
1699 SilcChannelEntry channel;
1703 CHECK_STATUS("Cannot set leave: ");
1706 /* Get Channel ID */
1707 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1708 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1712 /* Get the channel entry */
1713 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1715 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1719 /* Remove us from this channel. */
1720 silc_client_remove_from_channel(channel, conn->local_entry);
1722 /* Notify application */
1723 silc_client_command_callback(cmd, channel);
1725 /* Now delete the channel. */
1726 silc_client_del_channel(client, conn, channel);
1729 silc_fsm_next(fsm, silc_client_command_reply_processed);
1730 return SILC_FSM_CONTINUE;
1733 /********************************* USERS ************************************/
1735 /* Continue USERS command reply processing after resolving unknown users */
1738 silc_client_command_reply_users_resolved(SilcClient client,
1739 SilcClientConnection conn,
1744 SilcClientCommandContext cmd = context;
1745 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1749 /* Continue USERS command after resolving unknown channel */
1752 silc_client_command_reply_users_continue(SilcClient client,
1753 SilcClientConnection conn,
1758 SilcClientCommandContext cmd = context;
1761 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1762 SilcArgumentPayload args = silc_command_get_args(payload);
1764 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1765 ERROR_CALLBACK(cmd->status);
1766 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1769 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1772 /* Reply to USERS command. Received list of client ID's and theirs modes
1773 on the channel we requested. */
1775 SILC_FSM_STATE(silc_client_command_reply_users)
1777 SilcClientCommandContext cmd = fsm_context;
1778 SilcClientConnection conn = cmd->conn;
1779 SilcClient client = conn->client;
1780 SilcCommandPayload payload = state_context;
1781 SilcArgumentPayload args = silc_command_get_args(payload);
1783 SilcUInt32 tmp_len, list_count;
1784 SilcUInt16 idp_len, mode;
1785 SilcHashTableList htl;
1786 SilcBufferStruct client_id_list, client_mode_list;
1787 SilcChannelEntry channel;
1788 SilcClientEntry client_entry;
1793 CHECK_STATUS("Cannot get users: ");
1796 /* Get channel ID */
1797 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1798 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1802 /* Get channel entry */
1803 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1805 /* Resolve the channel from server */
1806 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1807 client, conn, &id.u.channel_id,
1808 silc_client_command_reply_users_continue, cmd));
1812 /* Get the list count */
1813 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1814 if (!tmp || tmp_len != 4) {
1815 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1818 SILC_GET32_MSB(list_count, tmp);
1820 /* Get Client ID list */
1821 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1823 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1826 silc_buffer_set(&client_id_list, tmp, tmp_len);
1828 /* Resolve users we do not know about */
1829 if (!cmd->resolved) {
1830 cmd->resolved = TRUE;
1831 SILC_FSM_CALL(silc_client_get_clients_by_list(
1832 client, conn, list_count, &client_id_list,
1833 silc_client_command_reply_users_resolved, cmd));
1837 /* Get client mode list */
1838 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1840 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1843 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1845 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1847 /* Cache the received Client ID's and modes. */
1848 for (i = 0; i < list_count; i++) {
1849 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1851 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1855 SILC_GET32_MSB(mode, client_mode_list.data);
1857 /* Save the client on this channel. Unknown clients are ignored as they
1858 clearly do not exist since the resolving didn't find them. */
1859 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1861 silc_client_add_to_channel(channel, client_entry, mode);
1862 silc_client_unref_client(client, conn, client_entry);
1864 if (!silc_buffer_pull(&client_id_list, idp_len))
1866 if (!silc_buffer_pull(&client_mode_list, 4))
1870 /* Notify application */
1871 silc_hash_table_list(channel->user_list, &htl);
1872 silc_client_command_callback(cmd, channel, &htl);
1873 silc_hash_table_list_reset(&htl);
1876 silc_fsm_next(fsm, silc_client_command_reply_processed);
1877 return SILC_FSM_CONTINUE;
1880 /********************************** GETKEY **********************************/
1882 /* Received command reply to GETKEY command. WE've received the remote
1883 client's public key. */
1885 SILC_FSM_STATE(silc_client_command_reply_getkey)
1887 SilcClientCommandContext cmd = fsm_context;
1888 SilcClientConnection conn = cmd->conn;
1889 SilcClient client = conn->client;
1890 SilcCommandPayload payload = state_context;
1891 SilcArgumentPayload args = silc_command_get_args(payload);
1892 SilcClientEntry client_entry;
1893 SilcServerEntry server_entry;
1896 SilcPublicKey public_key;
1900 CHECK_STATUS("Cannot get key: ");
1904 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1905 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1909 /* Get the public key */
1910 tmp = silc_argument_get_arg_type(args, 3, &len);
1912 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1915 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1916 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1920 if (id.type == SILC_ID_CLIENT) {
1921 /* Received client's public key */
1922 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1923 if (!client_entry) {
1924 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1928 /* Save fingerprint */
1929 if (!client_entry->fingerprint)
1930 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
1931 client_entry->fingerprint);
1932 if (!client_entry->public_key) {
1933 client_entry->public_key = public_key;
1937 /* Notify application */
1938 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1939 client_entry->public_key);
1940 silc_client_unref_client(client, conn, client_entry);
1941 } else if (id.type == SILC_ID_SERVER) {
1942 /* Received server's public key */
1943 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1944 if (!server_entry) {
1945 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1949 if (!server_entry->public_key) {
1950 server_entry->public_key = public_key;
1954 /* Notify application */
1955 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1956 server_entry->public_key);
1961 silc_pkcs_public_key_free(public_key);
1962 silc_fsm_next(fsm, silc_client_command_reply_processed);
1963 return SILC_FSM_CONTINUE;
1966 /********************************** SERVICE *********************************/
1968 /* Reply to SERVICE command. */
1969 /* XXX incomplete */
1971 SILC_FSM_STATE(silc_client_command_reply_service)
1973 SilcClientCommandContext cmd = fsm_context;
1974 SilcCommandPayload payload = state_context;
1975 SilcArgumentPayload args = silc_command_get_args(payload);
1977 unsigned char *service_list, *name;
1980 CHECK_STATUS("Cannot get service: ");
1982 /* Get service list */
1983 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
1985 /* Get requested service name */
1986 name = silc_argument_get_arg_type(args, 3, &tmp_len);
1988 /* Notify application */
1989 silc_client_command_callback(cmd, service_list, name);
1991 silc_fsm_next(fsm, silc_client_command_reply_processed);
1992 return SILC_FSM_CONTINUE;
1995 /*********************************** QUIT ***********************************/
1997 /* QUIT command reply stub */
1999 SILC_FSM_STATE(silc_client_command_reply_quit)
2001 silc_fsm_next(fsm, silc_client_command_reply_processed);
2002 return SILC_FSM_CONTINUE;