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);
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 silc_rwlock_wrlock(client_entry->internal.lock);
485 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
486 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
488 /* Get user attributes */
489 tmp = silc_argument_get_arg_type(args, 11, &len);
491 if (client_entry->attrs)
492 silc_attribute_payload_list_free(client_entry->attrs);
493 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
496 silc_rwlock_unlock(client_entry->internal.lock);
498 /* Parse channel and channel user mode list */
500 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
501 silc_buffer_len(&channels));
503 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
507 /* Notify application */
508 silc_client_command_callback(cmd, client_entry, nickname, username,
509 realname, channel_list, mode, idle, fingerprint,
510 umodes, client_entry->attrs);
512 silc_client_unref_client(client, conn, client_entry);
514 silc_dlist_uninit(channel_list);
519 silc_fsm_next(fsm, silc_client_command_reply_processed);
520 return SILC_FSM_CONTINUE;
523 /******************************** WHOWAS ************************************/
525 /* Received reply for WHOWAS command. */
527 SILC_FSM_STATE(silc_client_command_reply_whowas)
529 SilcClientCommandContext cmd = fsm_context;
530 SilcClientConnection conn = cmd->conn;
531 SilcClient client = conn->client;
532 SilcCommandPayload payload = state_context;
533 SilcArgumentPayload args = silc_command_get_args(payload);
534 SilcClientEntry client_entry = NULL;
536 char *nickname, *username;
537 char *realname = NULL;
539 CHECK_STATUS("WHOWAS: ");
543 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
544 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
548 /* Get the client entry */
549 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
552 nickname = silc_argument_get_arg_type(args, 3, NULL);
553 username = silc_argument_get_arg_type(args, 4, NULL);
554 realname = silc_argument_get_arg_type(args, 5, NULL);
555 if (!nickname || !username) {
556 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
560 /* Notify application. We don't save any history information to any
561 cache. Just pass the data to the application. */
562 silc_client_command_callback(cmd, client_entry, nickname, username,
566 silc_client_unref_client(client, conn, client_entry);
567 silc_fsm_next(fsm, silc_client_command_reply_processed);
568 return SILC_FSM_CONTINUE;
571 /******************************** IDENTIFY **********************************/
573 /* Received reply for IDENTIFY command. */
575 SILC_FSM_STATE(silc_client_command_reply_identify)
577 SilcClientCommandContext cmd = fsm_context;
578 SilcClientConnection conn = cmd->conn;
579 SilcClient client = conn->client;
580 SilcCommandPayload payload = state_context;
581 SilcArgumentPayload args = silc_command_get_args(payload);
582 SilcClientEntry client_entry;
583 SilcServerEntry server_entry;
584 SilcChannelEntry channel_entry;
587 char *name = NULL, *info = NULL;
589 CHECK_STATUS("IDENTIFY: ");
593 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
594 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
599 name = silc_argument_get_arg_type(args, 3, &len);
600 info = silc_argument_get_arg_type(args, 4, &len);
604 SILC_LOG_DEBUG(("Received client information"));
606 /* Check if we have this client cached already. */
607 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
609 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
611 silc_client_add_client(client, conn, name, info, NULL,
614 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
617 silc_client_ref_client(client, conn, client_entry);
619 silc_client_update_client(client, conn, client_entry,
620 name, info, NULL, 0);
623 /* Notify application */
624 silc_client_command_callback(cmd, client_entry, name, info);
625 silc_client_unref_client(client, conn, client_entry);
629 SILC_LOG_DEBUG(("Received server information"));
631 /* Check if we have this server cached already. */
632 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
634 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
635 server_entry = silc_client_add_server(client, conn, name, info,
638 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
641 silc_client_ref_server(client, conn, server_entry);
643 silc_client_update_server(client, conn, server_entry, name, info);
645 server_entry->internal.resolve_cmd_ident = 0;
647 /* Notify application */
648 silc_client_command_callback(cmd, server_entry, name, info);
649 silc_client_unref_server(client, conn, server_entry);
652 case SILC_ID_CHANNEL:
653 SILC_LOG_DEBUG(("Received channel information"));
655 /* Check if we have this channel cached already. */
656 channel_entry = silc_client_get_channel_by_id(client, conn,
658 if (!channel_entry) {
659 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
662 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
666 /* Add new channel entry */
667 channel_entry = silc_client_add_channel(client, conn, name, 0,
669 if (!channel_entry) {
670 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
673 silc_client_ref_channel(client, conn, channel_entry);
676 /* Notify application */
677 silc_client_command_callback(cmd, channel_entry, name, info);
678 silc_client_unref_channel(client, conn, channel_entry);
683 silc_fsm_next(fsm, silc_client_command_reply_processed);
684 return SILC_FSM_CONTINUE;
687 /********************************** NICK ************************************/
689 /* Received reply for command NICK. */
691 SILC_FSM_STATE(silc_client_command_reply_nick)
693 SilcClientCommandContext cmd = fsm_context;
694 SilcClientConnection conn = cmd->conn;
695 SilcClient client = conn->client;
696 SilcCommandPayload payload = state_context;
697 SilcArgumentPayload args = silc_command_get_args(payload);
698 unsigned char *nick, *idp;
699 SilcUInt32 len, idp_len;
700 SilcClientID old_client_id;
704 CHECK_STATUS("Cannot set nickname: ");
707 /* Take received Client ID */
708 idp = silc_argument_get_arg_type(args, 2, &idp_len);
710 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
713 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
714 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
718 /* Take the new nickname */
719 nick = silc_argument_get_arg_type(args, 3, &len);
721 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
725 silc_rwlock_wrlock(conn->local_entry->internal.lock);
727 /* Change the nickname */
728 old_client_id = *conn->local_id;
729 if (!silc_client_change_nickname(client, conn, conn->local_entry,
730 nick, &id.u.client_id, idp, idp_len)) {
731 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
735 silc_rwlock_unlock(conn->local_entry->internal.lock);
737 /* Notify application */
738 silc_client_command_callback(cmd, conn->local_entry,
739 conn->local_entry->nickname, &old_client_id);
742 silc_fsm_next(fsm, silc_client_command_reply_processed);
743 return SILC_FSM_CONTINUE;
746 /********************************** LIST ************************************/
748 /* Received reply to the LIST command. */
750 SILC_FSM_STATE(silc_client_command_reply_list)
752 SilcClientCommandContext cmd = fsm_context;
753 SilcClientConnection conn = cmd->conn;
754 SilcClient client = conn->client;
755 SilcCommandPayload payload = state_context;
756 SilcArgumentPayload args = silc_command_get_args(payload);
757 unsigned char *tmp, *name, *topic;
758 SilcUInt32 usercount = 0;
759 SilcChannelEntry channel_entry = NULL;
763 CHECK_STATUS("Cannot list channels: ");
765 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
766 /* There were no channels in the network. */
767 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
768 silc_fsm_next(fsm, silc_client_command_reply_processed);
769 return SILC_FSM_CONTINUE;
774 name = silc_argument_get_arg_type(args, 3, NULL);
776 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
780 topic = silc_argument_get_arg_type(args, 4, NULL);
781 tmp = silc_argument_get_arg_type(args, 5, NULL);
783 SILC_GET32_MSB(usercount, tmp);
785 /* Check whether the channel exists, and add it to cache if it doesn't. */
786 channel_entry = silc_client_get_channel_by_id(client, conn,
788 if (!channel_entry) {
789 /* Add new channel entry */
790 channel_entry = silc_client_add_channel(client, conn, name, 0,
792 if (!channel_entry) {
793 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
796 silc_client_ref_channel(client, conn, channel_entry);
799 /* Notify application */
800 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
803 silc_client_unref_channel(client, conn, channel_entry);
804 silc_fsm_next(fsm, silc_client_command_reply_processed);
805 return SILC_FSM_CONTINUE;
808 /********************************* TOPIC ************************************/
810 /* Received reply to topic command. */
812 SILC_FSM_STATE(silc_client_command_reply_topic)
814 SilcClientCommandContext cmd = fsm_context;
815 SilcClientConnection conn = cmd->conn;
816 SilcClient client = conn->client;
817 SilcCommandPayload payload = state_context;
818 SilcArgumentPayload args = silc_command_get_args(payload);
819 SilcChannelEntry channel;
825 CHECK_STATUS("Cannot set topic: ");
828 /* Take Channel ID */
829 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
830 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
834 /* Get the channel entry */
835 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
837 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
841 silc_rwlock_wrlock(channel->internal.lock);
844 topic = silc_argument_get_arg_type(args, 3, &len);
846 silc_free(channel->topic);
847 channel->topic = silc_memdup(topic, len);
850 silc_rwlock_unlock(channel->internal.lock);
852 /* Notify application */
853 silc_client_command_callback(cmd, channel, channel->topic);
856 silc_fsm_next(fsm, silc_client_command_reply_processed);
857 return SILC_FSM_CONTINUE;
860 /********************************* INVITE ***********************************/
862 /* Received reply to invite command. */
864 SILC_FSM_STATE(silc_client_command_reply_invite)
866 SilcClientCommandContext cmd = fsm_context;
867 SilcClientConnection conn = cmd->conn;
868 SilcClient client = conn->client;
869 SilcCommandPayload payload = state_context;
870 SilcArgumentPayload args = silc_command_get_args(payload);
871 SilcChannelEntry channel;
874 SilcArgumentPayload invite_args = NULL;
878 CHECK_STATUS("Cannot invite: ");
881 /* Take Channel ID */
882 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
883 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
887 /* Get the channel entry */
888 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
890 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
894 /* Get the invite list */
895 tmp = silc_argument_get_arg_type(args, 3, &len);
897 invite_args = silc_argument_list_parse(tmp, len);
899 /* Notify application */
900 silc_client_command_callback(cmd, channel, invite_args);
903 silc_argument_payload_free(invite_args);
906 silc_fsm_next(fsm, silc_client_command_reply_processed);
907 return SILC_FSM_CONTINUE;
910 /********************************** KILL ************************************/
912 /* Received reply to the KILL command. */
914 SILC_FSM_STATE(silc_client_command_reply_kill)
916 SilcClientCommandContext cmd = fsm_context;
917 SilcClientConnection conn = cmd->conn;
918 SilcClient client = conn->client;
919 SilcCommandPayload payload = state_context;
920 SilcArgumentPayload args = silc_command_get_args(payload);
921 SilcClientEntry client_entry;
925 CHECK_STATUS("Cannot kill: ");
928 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
929 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
933 /* Get the client entry, if exists */
934 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
936 /* Notify application */
937 silc_client_command_callback(cmd, client_entry);
939 /* Remove the client */
941 silc_client_remove_from_channels(client, conn, client_entry);
942 silc_client_del_client(client, conn, client_entry);
943 silc_client_unref_client(client, conn, client_entry);
947 silc_fsm_next(fsm, silc_client_command_reply_processed);
948 return SILC_FSM_CONTINUE;
951 /********************************** INFO ************************************/
953 /* Received reply to INFO command. We receive the server ID and some
954 information about the server user requested. */
956 SILC_FSM_STATE(silc_client_command_reply_info)
958 SilcClientCommandContext cmd = fsm_context;
959 SilcClientConnection conn = cmd->conn;
960 SilcClient client = conn->client;
961 SilcCommandPayload payload = state_context;
962 SilcArgumentPayload args = silc_command_get_args(payload);
963 SilcServerEntry server;
964 char *server_name, *server_info;
968 CHECK_STATUS("Cannot get info: ");
972 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
973 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
977 /* Get server name */
978 server_name = silc_argument_get_arg_type(args, 3, NULL);
980 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
984 /* Get server info */
985 server_info = silc_argument_get_arg_type(args, 4, NULL);
987 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
991 /* See whether we have this server cached. If not create it. */
992 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
994 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
995 server = silc_client_add_server(client, conn, server_name,
996 server_info, &id.u.server_id);
999 silc_client_ref_server(client, conn, server);
1002 /* Notify application */
1003 silc_client_command_callback(cmd, server, server->server_name,
1004 server->server_info);
1005 silc_client_unref_server(client, conn, server);
1008 silc_fsm_next(fsm, silc_client_command_reply_processed);
1009 return SILC_FSM_CONTINUE;
1012 /********************************** STATS ***********************************/
1014 /* Received reply to STATS command. */
1016 SILC_FSM_STATE(silc_client_command_reply_stats)
1018 SilcClientCommandContext cmd = fsm_context;
1019 SilcCommandPayload payload = state_context;
1020 SilcArgumentPayload args = silc_command_get_args(payload);
1021 SilcClientStats stats;
1022 unsigned char *buf = NULL;
1023 SilcUInt32 buf_len = 0;
1028 CHECK_STATUS("Cannot get stats: ");
1032 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1033 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1037 /* Get statistics structure */
1038 memset(&stats, 0, sizeof(stats));
1039 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1041 silc_buffer_set(&b, buf, buf_len);
1042 silc_buffer_unformat(&b,
1043 SILC_STR_UI_INT(&stats.starttime),
1044 SILC_STR_UI_INT(&stats.uptime),
1045 SILC_STR_UI_INT(&stats.my_clients),
1046 SILC_STR_UI_INT(&stats.my_channels),
1047 SILC_STR_UI_INT(&stats.my_server_ops),
1048 SILC_STR_UI_INT(&stats.my_router_ops),
1049 SILC_STR_UI_INT(&stats.cell_clients),
1050 SILC_STR_UI_INT(&stats.cell_channels),
1051 SILC_STR_UI_INT(&stats.cell_servers),
1052 SILC_STR_UI_INT(&stats.clients),
1053 SILC_STR_UI_INT(&stats.channels),
1054 SILC_STR_UI_INT(&stats.servers),
1055 SILC_STR_UI_INT(&stats.routers),
1056 SILC_STR_UI_INT(&stats.server_ops),
1057 SILC_STR_UI_INT(&stats.router_ops),
1061 /* Notify application */
1062 silc_client_command_callback(cmd, &stats);
1065 silc_fsm_next(fsm, silc_client_command_reply_processed);
1066 return SILC_FSM_CONTINUE;
1069 /********************************** PING ************************************/
1071 /* Received reply to PING command. */
1073 SILC_FSM_STATE(silc_client_command_reply_ping)
1075 SilcClientCommandContext cmd = fsm_context;
1076 SilcClientConnection conn = cmd->conn;
1077 SilcClient client = conn->client;
1080 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1082 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1083 "Ping reply from %s: %d second%s", conn->remote_host,
1084 (int)diff, diff == 1 ? "" : "s");
1086 /* Notify application */
1087 silc_client_command_callback(cmd);
1089 silc_fsm_next(fsm, silc_client_command_reply_processed);
1090 return SILC_FSM_CONTINUE;
1093 /********************************** JOIN ************************************/
1095 /* Continue JOIN command reply processing after resolving unknown users */
1098 silc_client_command_reply_join_resolved(SilcClient client,
1099 SilcClientConnection conn,
1104 SilcClientCommandContext cmd = context;
1105 SilcChannelEntry channel = cmd->context;
1107 channel->internal.resolve_cmd_ident = 0;
1108 silc_client_unref_channel(client, conn, channel);
1110 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1114 /* Received reply for JOIN command. */
1116 SILC_FSM_STATE(silc_client_command_reply_join)
1118 SilcClientCommandContext cmd = fsm_context;
1119 SilcClientConnection conn = cmd->conn;
1120 SilcClient client = conn->client;
1121 SilcCommandPayload payload = state_context;
1122 SilcArgumentPayload args = silc_command_get_args(payload);
1123 SilcChannelEntry channel;
1124 SilcUInt32 mode = 0, len, list_count;
1125 char *topic, *tmp, *channel_name = NULL, *hmac;
1127 SilcBufferStruct client_id_list, client_mode_list, keyp;
1128 SilcHashTableList htl;
1133 CHECK_STATUS("Cannot join channel: ");
1136 /* Get channel name */
1137 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1138 if (!channel_name) {
1139 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1143 /* Get Channel ID */
1144 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1145 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1149 /* Check whether we have this channel entry already. */
1150 channel = silc_client_get_channel(client, conn, channel_name);
1152 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1153 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1155 /* Create new channel entry */
1156 channel = silc_client_add_channel(client, conn, channel_name,
1157 mode, &id.u.channel_id);
1159 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1162 silc_client_ref_channel(client, conn, channel);
1165 /* Get the list count */
1166 tmp = silc_argument_get_arg_type(args, 12, &len);
1168 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1171 SILC_GET32_MSB(list_count, tmp);
1173 /* Get Client ID list */
1174 tmp = silc_argument_get_arg_type(args, 13, &len);
1176 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1179 silc_buffer_set(&client_id_list, tmp, len);
1181 /* Resolve users we do not know about */
1182 if (!cmd->resolved) {
1183 cmd->resolved = TRUE;
1184 cmd->context = channel;
1185 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1186 silc_client_get_clients_by_list(
1187 client, conn, list_count, &client_id_list,
1188 silc_client_command_reply_join_resolved, cmd));
1192 /* Get client mode list */
1193 tmp = silc_argument_get_arg_type(args, 14, &len);
1195 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1198 silc_buffer_set(&client_mode_list, tmp, len);
1200 silc_rwlock_wrlock(channel->internal.lock);
1202 /* Add clients we received in the reply to the channel */
1203 for (i = 0; i < list_count; i++) {
1207 SilcClientEntry client_entry;
1210 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1212 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1216 SILC_GET32_MSB(mode, client_mode_list.data);
1218 /* Get client entry */
1219 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1220 if (!client_entry || !client_entry->internal.valid)
1223 /* Join client to the channel */
1224 silc_rwlock_wrlock(client_entry->internal.lock);
1225 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1226 silc_rwlock_unlock(client_entry->internal.lock);
1227 silc_client_unref_client(client, conn, client_entry);
1229 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1230 silc_rwlock_unlock(channel->internal.lock);
1233 if (!silc_buffer_pull(&client_mode_list, 4)) {
1234 silc_rwlock_unlock(channel->internal.lock);
1240 hmac = silc_argument_get_arg_type(args, 11, NULL);
1242 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1244 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1245 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1246 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1247 silc_rwlock_unlock(channel->internal.lock);
1252 /* Get channel mode */
1253 tmp = silc_argument_get_arg_type(args, 5, NULL);
1255 SILC_GET32_MSB(mode, tmp);
1256 channel->mode = mode;
1258 /* Get channel key and save it */
1259 tmp = silc_argument_get_arg_type(args, 7, &len);
1261 silc_buffer_set(&keyp, tmp, len);
1262 silc_client_save_channel_key(client, conn, &keyp, channel);
1266 topic = silc_argument_get_arg_type(args, 10, NULL);
1268 silc_free(channel->topic);
1269 channel->topic = silc_memdup(topic, strlen(topic));
1272 /* Get founder key */
1273 tmp = silc_argument_get_arg_type(args, 15, &len);
1275 if (channel->founder_key)
1276 silc_pkcs_public_key_free(channel->founder_key);
1277 channel->founder_key = NULL;
1278 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1281 /* Get user limit */
1282 tmp = silc_argument_get_arg_type(args, 17, &len);
1283 if (tmp && len == 4)
1284 SILC_GET32_MSB(channel->user_limit, tmp);
1285 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1286 channel->user_limit = 0;
1288 /* Get channel public key list */
1289 tmp = silc_argument_get_arg_type(args, 16, &len);
1291 silc_client_channel_save_public_keys(channel, tmp, len);
1293 /* Set current channel */
1294 conn->current_channel = channel;
1296 silc_rwlock_unlock(channel->internal.lock);
1298 cipher = (channel->internal.send_key ?
1299 silc_cipher_get_name(channel->internal.send_key) : NULL);
1300 silc_hash_table_list(channel->user_list, &htl);
1302 /* Notify application */
1303 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1304 topic, cipher, hmac, channel->founder_key,
1305 channel->channel_pubkeys, channel->user_limit);
1307 silc_hash_table_list_reset(&htl);
1308 silc_client_unref_channel(client, conn, channel);
1311 silc_fsm_next(fsm, silc_client_command_reply_processed);
1312 return SILC_FSM_CONTINUE;
1315 /********************************** MOTD ************************************/
1317 /* Received reply for MOTD command */
1319 SILC_FSM_STATE(silc_client_command_reply_motd)
1321 SilcClientCommandContext cmd = fsm_context;
1322 SilcClientConnection conn = cmd->conn;
1323 SilcClient client = conn->client;
1324 SilcCommandPayload payload = state_context;
1325 SilcArgumentPayload args = silc_command_get_args(payload);
1327 char *motd = NULL, *cp, line[256];
1330 CHECK_STATUS("Cannot get motd: ");
1333 if (silc_argument_get_arg_num(args) == 3) {
1334 motd = silc_argument_get_arg_type(args, 3, NULL);
1336 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1343 if (cp[i++] == '\n') {
1344 memset(line, 0, sizeof(line));
1345 silc_strncat(line, sizeof(line), cp, i - 1);
1352 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1361 /* Notify application */
1362 silc_client_command_callback(cmd, motd);
1365 silc_fsm_next(fsm, silc_client_command_reply_processed);
1366 return SILC_FSM_CONTINUE;
1369 /********************************** UMODE ***********************************/
1371 /* Received reply to the UMODE command. Save the current user mode */
1373 SILC_FSM_STATE(silc_client_command_reply_umode)
1375 SilcClientCommandContext cmd = fsm_context;
1376 SilcClientConnection conn = cmd->conn;
1377 SilcCommandPayload payload = state_context;
1378 SilcArgumentPayload args = silc_command_get_args(payload);
1380 SilcUInt32 mode, len;
1383 CHECK_STATUS("Cannot change mode: ");
1386 tmp = silc_argument_get_arg_type(args, 2, &len);
1387 if (!tmp || len != 4) {
1388 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1392 SILC_GET32_MSB(mode, tmp);
1393 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1394 conn->local_entry->mode = mode;
1395 silc_rwlock_unlock(conn->local_entry->internal.lock);
1397 /* Notify application */
1398 silc_client_command_callback(cmd, mode);
1401 silc_fsm_next(fsm, silc_client_command_reply_processed);
1402 return SILC_FSM_CONTINUE;
1405 /********************************** CMODE ***********************************/
1407 /* Received reply for CMODE command. */
1409 SILC_FSM_STATE(silc_client_command_reply_cmode)
1411 SilcClientCommandContext cmd = fsm_context;
1412 SilcClientConnection conn = cmd->conn;
1413 SilcClient client = conn->client;
1414 SilcCommandPayload payload = state_context;
1415 SilcArgumentPayload args = silc_command_get_args(payload);
1418 SilcChannelEntry channel;
1420 SilcPublicKey public_key = NULL;
1421 SilcDList channel_pubkeys = NULL;
1425 CHECK_STATUS("Cannot change mode: ");
1428 /* Take Channel ID */
1429 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1430 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1434 /* Get the channel entry */
1435 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1437 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1441 /* Get channel mode */
1442 tmp = silc_argument_get_arg_type(args, 3, &len);
1443 if (!tmp || len != 4) {
1444 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1448 /* Get founder public key */
1449 tmp = silc_argument_get_arg_type(args, 4, &len);
1451 silc_public_key_payload_decode(tmp, len, &public_key);
1453 silc_rwlock_wrlock(channel->internal.lock);
1456 SILC_GET32_MSB(mode, tmp);
1457 channel->mode = mode;
1459 /* Get user limit */
1460 tmp = silc_argument_get_arg_type(args, 6, &len);
1461 if (tmp && len == 4)
1462 SILC_GET32_MSB(channel->user_limit, tmp);
1463 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1464 channel->user_limit = 0;
1466 /* Get channel public key(s) */
1467 tmp = silc_argument_get_arg_type(args, 5, &len);
1469 silc_client_channel_save_public_keys(channel, tmp, len);
1471 silc_rwlock_unlock(channel->internal.lock);
1473 /* Notify application */
1474 silc_client_command_callback(cmd, channel, mode, public_key,
1475 channel_pubkeys, channel->user_limit);
1477 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1481 silc_pkcs_public_key_free(public_key);
1482 silc_fsm_next(fsm, silc_client_command_reply_processed);
1483 return SILC_FSM_CONTINUE;
1486 /********************************** CUMODE **********************************/
1488 /* Received reply for CUMODE command */
1490 SILC_FSM_STATE(silc_client_command_reply_cumode)
1492 SilcClientCommandContext cmd = fsm_context;
1493 SilcClientConnection conn = cmd->conn;
1494 SilcClient client = conn->client;
1495 SilcCommandPayload payload = state_context;
1496 SilcArgumentPayload args = silc_command_get_args(payload);
1497 SilcClientEntry client_entry;
1498 SilcChannelEntry channel;
1499 SilcChannelUser chu;
1500 unsigned char *modev;
1501 SilcUInt32 len, mode;
1505 CHECK_STATUS("Cannot change mode: ");
1508 /* Get channel mode */
1509 modev = silc_argument_get_arg_type(args, 2, &len);
1510 if (!modev || len != 4) {
1511 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1514 SILC_GET32_MSB(mode, modev);
1516 /* Take Channel ID */
1517 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1518 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1522 /* Get the channel entry */
1523 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1525 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1530 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1531 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1535 /* Get client entry */
1536 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1537 if (!client_entry) {
1538 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1543 silc_rwlock_wrlock(channel->internal.lock);
1544 chu = silc_client_on_channel(channel, client_entry);
1547 silc_rwlock_unlock(channel->internal.lock);
1549 /* Notify application */
1550 silc_client_command_callback(cmd, mode, channel, client_entry);
1552 silc_client_unref_client(client, conn, client_entry);
1555 silc_fsm_next(fsm, silc_client_command_reply_processed);
1556 return SILC_FSM_CONTINUE;
1559 /********************************** KICK ************************************/
1561 SILC_FSM_STATE(silc_client_command_reply_kick)
1563 SilcClientCommandContext cmd = fsm_context;
1564 SilcClientConnection conn = cmd->conn;
1565 SilcClient client = conn->client;
1566 SilcCommandPayload payload = state_context;
1567 SilcArgumentPayload args = silc_command_get_args(payload);
1568 SilcClientEntry client_entry;
1569 SilcChannelEntry channel;
1573 CHECK_STATUS("Cannot kick: ");
1576 /* Take Channel ID */
1577 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1578 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1582 /* Get the channel entry */
1583 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1585 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1590 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1591 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1595 /* Get client entry */
1596 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1597 if (!client_entry) {
1598 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1602 /* Notify application */
1603 silc_client_command_callback(cmd, channel, client_entry);
1605 silc_client_unref_client(client, conn, client_entry);
1608 silc_fsm_next(fsm, silc_client_command_reply_processed);
1609 return SILC_FSM_CONTINUE;
1612 /******************************** SILCOPER **********************************/
1614 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1616 SilcClientCommandContext cmd = fsm_context;
1617 SilcCommandPayload payload = state_context;
1618 SilcArgumentPayload args = silc_command_get_args(payload);
1621 CHECK_STATUS("Cannot change mode: ");
1624 /* Notify application */
1625 silc_client_command_callback(cmd);
1627 silc_fsm_next(fsm, silc_client_command_reply_processed);
1628 return SILC_FSM_CONTINUE;
1631 /********************************** OPER ************************************/
1633 SILC_FSM_STATE(silc_client_command_reply_oper)
1635 SilcClientCommandContext cmd = fsm_context;
1636 SilcCommandPayload payload = state_context;
1637 SilcArgumentPayload args = silc_command_get_args(payload);
1640 CHECK_STATUS("Cannot change mode: ");
1643 /* Notify application */
1644 silc_client_command_callback(cmd);
1646 silc_fsm_next(fsm, silc_client_command_reply_processed);
1647 return SILC_FSM_CONTINUE;
1650 /********************************* DETACH ***********************************/
1652 SILC_FSM_STATE(silc_client_command_reply_detach)
1654 SilcClientCommandContext cmd = fsm_context;
1655 SilcClientConnection conn = cmd->conn;
1656 SilcClient client = conn->client;
1657 SilcCommandPayload payload = state_context;
1658 SilcArgumentPayload args = silc_command_get_args(payload);
1662 CHECK_STATUS("Cannot detach: ");
1665 /* Get detachment data */
1666 detach = silc_client_get_detach_data(client, conn);
1668 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1672 /* Notify application */
1673 silc_client_command_callback(cmd, detach);
1674 silc_buffer_free(detach);
1677 silc_fsm_next(fsm, silc_client_command_reply_processed);
1678 return SILC_FSM_CONTINUE;
1681 /********************************** WATCH ***********************************/
1683 SILC_FSM_STATE(silc_client_command_reply_watch)
1685 SilcClientCommandContext cmd = fsm_context;
1686 SilcCommandPayload payload = state_context;
1687 SilcArgumentPayload args = silc_command_get_args(payload);
1690 CHECK_STATUS("Cannot set watch: ");
1693 /* Notify application */
1694 silc_client_command_callback(cmd);
1696 silc_fsm_next(fsm, silc_client_command_reply_processed);
1697 return SILC_FSM_CONTINUE;
1700 /*********************************** BAN ************************************/
1702 SILC_FSM_STATE(silc_client_command_reply_ban)
1704 SilcClientCommandContext cmd = fsm_context;
1705 SilcClientConnection conn = cmd->conn;
1706 SilcClient client = conn->client;
1707 SilcCommandPayload payload = state_context;
1708 SilcArgumentPayload args = silc_command_get_args(payload);
1709 SilcChannelEntry channel;
1712 SilcArgumentPayload invite_args = NULL;
1716 CHECK_STATUS("Cannot set ban: ");
1719 /* Take Channel ID */
1720 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1721 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1725 /* Get the channel entry */
1726 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1728 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1732 /* Get the invite list */
1733 tmp = silc_argument_get_arg_type(args, 3, &len);
1735 invite_args = silc_argument_list_parse(tmp, len);
1737 /* Notify application */
1738 silc_client_command_callback(cmd, channel, invite_args);
1741 silc_argument_payload_free(invite_args);
1744 silc_fsm_next(fsm, silc_client_command_reply_processed);
1745 return SILC_FSM_CONTINUE;
1748 /********************************** LEAVE ***********************************/
1750 /* Reply to LEAVE command. */
1752 SILC_FSM_STATE(silc_client_command_reply_leave)
1754 SilcClientCommandContext cmd = fsm_context;
1755 SilcClientConnection conn = cmd->conn;
1756 SilcClient client = conn->client;
1757 SilcCommandPayload payload = state_context;
1758 SilcArgumentPayload args = silc_command_get_args(payload);
1759 SilcChannelEntry channel;
1763 CHECK_STATUS("Cannot set leave: ");
1766 /* Get Channel ID */
1767 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1768 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1772 /* Get the channel entry */
1773 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1775 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1779 /* Remove us from this channel. */
1780 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1782 /* Notify application */
1783 silc_client_command_callback(cmd, channel);
1785 /* Now delete the channel. */
1786 silc_client_empty_channel(client, conn, channel);
1787 silc_client_del_channel(client, conn, channel);
1790 silc_fsm_next(fsm, silc_client_command_reply_processed);
1791 return SILC_FSM_CONTINUE;
1794 /********************************* USERS ************************************/
1796 /* Continue USERS command reply processing after resolving unknown users */
1799 silc_client_command_reply_users_resolved(SilcClient client,
1800 SilcClientConnection conn,
1805 SilcClientCommandContext cmd = context;
1806 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1810 /* Continue USERS command after resolving unknown channel */
1813 silc_client_command_reply_users_continue(SilcClient client,
1814 SilcClientConnection conn,
1819 SilcClientCommandContext cmd = context;
1822 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1823 SilcArgumentPayload args = silc_command_get_args(payload);
1825 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1826 ERROR_CALLBACK(cmd->status);
1827 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1830 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1833 /* Reply to USERS command. Received list of client ID's and theirs modes
1834 on the channel we requested. */
1836 SILC_FSM_STATE(silc_client_command_reply_users)
1838 SilcClientCommandContext cmd = fsm_context;
1839 SilcClientConnection conn = cmd->conn;
1840 SilcClient client = conn->client;
1841 SilcCommandPayload payload = state_context;
1842 SilcArgumentPayload args = silc_command_get_args(payload);
1844 SilcUInt32 tmp_len, list_count;
1845 SilcUInt16 idp_len, mode;
1846 SilcHashTableList htl;
1847 SilcBufferStruct client_id_list, client_mode_list;
1848 SilcChannelEntry channel = NULL;
1849 SilcClientEntry client_entry;
1854 CHECK_STATUS("Cannot get users: ");
1857 /* Get channel ID */
1858 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1859 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1863 /* Get channel entry */
1864 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1866 /* Resolve the channel from server */
1867 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1868 client, conn, &id.u.channel_id,
1869 silc_client_command_reply_users_continue, cmd));
1873 /* Get the list count */
1874 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1875 if (!tmp || tmp_len != 4) {
1876 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1879 SILC_GET32_MSB(list_count, tmp);
1881 /* Get Client ID list */
1882 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1884 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1887 silc_buffer_set(&client_id_list, tmp, tmp_len);
1889 /* Resolve users we do not know about */
1890 if (!cmd->resolved) {
1891 cmd->resolved = TRUE;
1892 silc_client_unref_channel(client, conn, channel);
1893 SILC_FSM_CALL(silc_client_get_clients_by_list(
1894 client, conn, list_count, &client_id_list,
1895 silc_client_command_reply_users_resolved, cmd));
1899 /* Get client mode list */
1900 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1902 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1905 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1907 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1909 silc_rwlock_wrlock(channel->internal.lock);
1911 /* Cache the received Client ID's and modes. */
1912 for (i = 0; i < list_count; i++) {
1913 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1915 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1919 SILC_GET32_MSB(mode, client_mode_list.data);
1921 /* Save the client on this channel. Unknown clients are ignored as they
1922 clearly do not exist since the resolving didn't find them. */
1923 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1924 if (client_entry && client_entry->internal.valid) {
1925 silc_rwlock_wrlock(client_entry->internal.lock);
1926 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1927 silc_rwlock_unlock(client_entry->internal.lock);
1929 silc_client_unref_client(client, conn, client_entry);
1931 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1932 silc_rwlock_unlock(channel->internal.lock);
1935 if (!silc_buffer_pull(&client_mode_list, 4)) {
1936 silc_rwlock_unlock(channel->internal.lock);
1941 /* Notify application */
1942 silc_hash_table_list(channel->user_list, &htl);
1943 silc_client_command_callback(cmd, channel, &htl);
1944 silc_hash_table_list_reset(&htl);
1947 silc_client_unref_channel(client, conn, channel);
1948 silc_fsm_next(fsm, silc_client_command_reply_processed);
1949 return SILC_FSM_CONTINUE;
1952 /********************************** GETKEY **********************************/
1954 /* Received command reply to GETKEY command. WE've received the remote
1955 client's public key. */
1957 SILC_FSM_STATE(silc_client_command_reply_getkey)
1959 SilcClientCommandContext cmd = fsm_context;
1960 SilcClientConnection conn = cmd->conn;
1961 SilcClient client = conn->client;
1962 SilcCommandPayload payload = state_context;
1963 SilcArgumentPayload args = silc_command_get_args(payload);
1964 SilcClientEntry client_entry;
1965 SilcServerEntry server_entry;
1968 SilcPublicKey public_key;
1972 CHECK_STATUS("Cannot get key: ");
1976 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1977 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1981 /* Get the public key */
1982 tmp = silc_argument_get_arg_type(args, 3, &len);
1984 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1987 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1988 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1992 if (id.type == SILC_ID_CLIENT) {
1993 /* Received client's public key */
1994 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1995 if (!client_entry) {
1996 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2000 silc_rwlock_wrlock(client_entry->internal.lock);
2002 /* Save fingerprint */
2003 if (!client_entry->fingerprint)
2004 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2005 client_entry->fingerprint);
2006 if (!client_entry->public_key) {
2007 client_entry->public_key = public_key;
2011 silc_rwlock_unlock(client_entry->internal.lock);
2013 /* Notify application */
2014 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2015 client_entry->public_key);
2016 silc_client_unref_client(client, conn, client_entry);
2017 } else if (id.type == SILC_ID_SERVER) {
2018 /* Received server's public key */
2019 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2020 if (!server_entry) {
2021 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2025 silc_rwlock_wrlock(server_entry->internal.lock);
2027 if (!server_entry->public_key) {
2028 server_entry->public_key = public_key;
2032 silc_rwlock_unlock(server_entry->internal.lock);
2034 /* Notify application */
2035 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2036 server_entry->public_key);
2037 silc_client_unref_server(client, conn, server_entry);
2042 silc_pkcs_public_key_free(public_key);
2043 silc_fsm_next(fsm, silc_client_command_reply_processed);
2044 return SILC_FSM_CONTINUE;
2047 /********************************** SERVICE *********************************/
2049 /* Reply to SERVICE command. */
2050 /* XXX incomplete */
2052 SILC_FSM_STATE(silc_client_command_reply_service)
2054 SilcClientCommandContext cmd = fsm_context;
2055 SilcCommandPayload payload = state_context;
2056 SilcArgumentPayload args = silc_command_get_args(payload);
2058 unsigned char *service_list, *name;
2061 CHECK_STATUS("Cannot get service: ");
2063 /* Get service list */
2064 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2066 /* Get requested service name */
2067 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2069 /* Notify application */
2070 silc_client_command_callback(cmd, service_list, name);
2072 silc_fsm_next(fsm, silc_client_command_reply_processed);
2073 return SILC_FSM_CONTINUE;
2076 /*********************************** QUIT ***********************************/
2078 /* QUIT command reply stub */
2080 SILC_FSM_STATE(silc_client_command_reply_quit)
2082 silc_fsm_next(fsm, silc_client_command_reply_processed);
2083 return SILC_FSM_CONTINUE;