5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2014 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_COMMAND_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 client_entry->internal.valid = FALSE;
122 silc_client_del_client(client, conn, client_entry);
123 silc_client_unref_client(client, conn, client_entry);
128 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
129 SilcChannelEntry channel;
131 /* Remove unknown channel entry from cache */
132 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
135 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
137 silc_client_empty_channel(client, conn, channel);
138 silc_client_del_channel(client, conn, channel);
139 silc_client_unref_channel(client, conn, channel);
144 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
145 SilcServerEntry server_entry;
147 /* Remove unknown server entry from cache */
148 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
151 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
153 silc_client_del_server(client, conn, server_entry);
154 silc_client_unref_server(client, conn, server_entry);
160 /***************************** Command Reply ********************************/
162 /* Process received command reply packet */
164 SILC_FSM_STATE(silc_client_command_reply)
166 SilcClientConnection conn = fsm_context;
167 SilcPacket packet = state_context;
168 SilcClientCommandContext cmd;
169 SilcCommandPayload payload;
171 SilcUInt16 cmd_ident;
173 /* Get command reply payload from packet */
174 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
175 silc_packet_free(packet);
177 SILC_LOG_DEBUG(("Bad command reply packet"));
178 return SILC_FSM_FINISH;
181 cmd_ident = silc_command_get_ident(payload);
182 command = silc_command_get(payload);
184 /* Find the command pending reply */
185 silc_mutex_lock(conn->internal->lock);
186 silc_list_start(conn->internal->pending_commands);
187 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
188 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
189 && cmd->cmd_ident == cmd_ident) {
190 silc_list_del(conn->internal->pending_commands, cmd);
194 silc_mutex_unlock(conn->internal->lock);
197 SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
198 silc_get_command_name(command), cmd_ident));
199 silc_command_payload_free(payload);
200 return SILC_FSM_FINISH;
203 /* Signal command thread that command reply has arrived. We continue
204 command reply processing synchronously because we save the command
205 payload into state context. No other reply may arrive to this command
206 while we're processing this reply. */
207 silc_fsm_set_state_context(&cmd->thread, payload);
208 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
209 silc_fsm_continue_sync(&cmd->thread);
211 return SILC_FSM_FINISH;
214 /* Wait here for command reply to arrive from remote host */
216 SILC_FSM_STATE(silc_client_command_reply_wait)
218 SilcClientCommandContext cmd = fsm_context;
220 SILC_LOG_DEBUG(("Wait for command reply"));
222 /** Wait for command reply */
223 silc_fsm_set_state_context(fsm, NULL);
224 silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
225 cmd->cmd != SILC_COMMAND_PING ? 40 : 60, 0);
226 return SILC_FSM_WAIT;
229 /* Timeout occurred while waiting command reply */
231 SILC_FSM_STATE(silc_client_command_reply_timeout)
233 SilcClientCommandContext cmd = fsm_context;
234 SilcClientConnection conn = cmd->conn;
235 SilcArgumentPayload args = NULL;
237 if (conn->internal->disconnected) {
238 SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
239 silc_list_del(conn->internal->pending_commands, cmd);
241 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
242 return SILC_FSM_FINISH;
245 SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
247 /* Timeout, reply not received in timely fashion */
248 silc_list_del(conn->internal->pending_commands, cmd);
249 cmd->status = SILC_STATUS_OK;
250 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
251 return SILC_FSM_FINISH;
254 /* Process received command reply payload */
256 SILC_FSM_STATE(silc_client_command_reply_process)
258 SilcClientCommandContext cmd = fsm_context;
259 SilcCommandPayload payload = state_context;
261 silc_command_get_status(payload, &cmd->status, &cmd->error);
264 case SILC_COMMAND_WHOIS:
266 silc_fsm_next(fsm, silc_client_command_reply_whois);
268 case SILC_COMMAND_WHOWAS:
270 silc_fsm_next(fsm, silc_client_command_reply_whowas);
272 case SILC_COMMAND_IDENTIFY:
274 silc_fsm_next(fsm, silc_client_command_reply_identify);
276 case SILC_COMMAND_NICK:
278 silc_fsm_next(fsm, silc_client_command_reply_nick);
280 case SILC_COMMAND_LIST:
282 silc_fsm_next(fsm, silc_client_command_reply_list);
284 case SILC_COMMAND_TOPIC:
286 silc_fsm_next(fsm, silc_client_command_reply_topic);
288 case SILC_COMMAND_INVITE:
290 silc_fsm_next(fsm, silc_client_command_reply_invite);
292 case SILC_COMMAND_QUIT:
294 silc_fsm_next(fsm, silc_client_command_reply_quit);
296 case SILC_COMMAND_KILL:
298 silc_fsm_next(fsm, silc_client_command_reply_kill);
300 case SILC_COMMAND_INFO:
302 silc_fsm_next(fsm, silc_client_command_reply_info);
304 case SILC_COMMAND_STATS:
306 silc_fsm_next(fsm, silc_client_command_reply_stats);
308 case SILC_COMMAND_PING:
310 silc_fsm_next(fsm, silc_client_command_reply_ping);
312 case SILC_COMMAND_OPER:
314 silc_fsm_next(fsm, silc_client_command_reply_oper);
316 case SILC_COMMAND_JOIN:
318 silc_fsm_next(fsm, silc_client_command_reply_join);
320 case SILC_COMMAND_MOTD:
322 silc_fsm_next(fsm, silc_client_command_reply_motd);
324 case SILC_COMMAND_UMODE:
326 silc_fsm_next(fsm, silc_client_command_reply_umode);
328 case SILC_COMMAND_CMODE:
330 silc_fsm_next(fsm, silc_client_command_reply_cmode);
332 case SILC_COMMAND_CUMODE:
334 silc_fsm_next(fsm, silc_client_command_reply_cumode);
336 case SILC_COMMAND_KICK:
338 silc_fsm_next(fsm, silc_client_command_reply_kick);
340 case SILC_COMMAND_BAN:
342 silc_fsm_next(fsm, silc_client_command_reply_ban);
344 case SILC_COMMAND_DETACH:
346 silc_fsm_next(fsm, silc_client_command_reply_detach);
348 case SILC_COMMAND_WATCH:
350 silc_fsm_next(fsm, silc_client_command_reply_watch);
352 case SILC_COMMAND_SILCOPER:
354 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
356 case SILC_COMMAND_LEAVE:
358 silc_fsm_next(fsm, silc_client_command_reply_leave);
360 case SILC_COMMAND_USERS:
362 silc_fsm_next(fsm, silc_client_command_reply_users);
364 case SILC_COMMAND_GETKEY:
366 silc_fsm_next(fsm, silc_client_command_reply_getkey);
368 case SILC_COMMAND_SERVICE:
370 silc_fsm_next(fsm, silc_client_command_reply_service);
373 return SILC_FSM_FINISH;
376 return SILC_FSM_CONTINUE;
379 /* Completes command reply processing */
381 SILC_FSM_STATE(silc_client_command_reply_processed)
383 SilcClientCommandContext cmd = fsm_context;
384 SilcClientConnection conn = cmd->conn;
385 SilcCommandPayload payload = state_context;
387 silc_command_payload_free(payload);
389 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
390 SILC_STATUS_IS_ERROR(cmd->status))
391 return SILC_FSM_FINISH;
393 /* Add back to pending command reply list */
394 silc_mutex_lock(conn->internal->lock);
395 cmd->resolved = FALSE;
396 silc_list_add(conn->internal->pending_commands, cmd);
397 silc_mutex_unlock(conn->internal->lock);
399 /** Wait more command payloads */
400 silc_fsm_next(fsm, silc_client_command_reply_wait);
401 return SILC_FSM_CONTINUE;
404 /******************************** WHOIS *************************************/
406 /* Received reply for WHOIS command. */
408 SILC_FSM_STATE(silc_client_command_reply_whois)
410 SilcClientCommandContext cmd = fsm_context;
411 SilcClientConnection conn = cmd->conn;
412 SilcClient client = conn->client;
413 SilcCommandPayload payload = state_context;
414 SilcArgumentPayload args = silc_command_get_args(payload);
415 SilcClientEntry client_entry = NULL;
416 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
417 SilcBufferStruct channels, ch_user_modes;
418 SilcBool has_channels = FALSE;
419 SilcDList channel_list = NULL;
421 char *nickname = NULL, *username = NULL, *realname = NULL;
422 unsigned char *fingerprint, *tmp;
424 CHECK_STATUS("WHOIS: ");
428 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
429 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
434 nickname = silc_argument_get_arg_type(args, 3, NULL);
435 username = silc_argument_get_arg_type(args, 4, NULL);
436 realname = silc_argument_get_arg_type(args, 5, NULL);
437 if (!nickname || !username || !realname) {
438 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
442 /* Get joined channel list */
443 memset(&channels, 0, sizeof(channels));
444 tmp = silc_argument_get_arg_type(args, 6, &len);
447 silc_buffer_set(&channels, tmp, len);
449 /* Get channel user mode list */
450 tmp = silc_argument_get_arg_type(args, 10, &len);
452 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
455 silc_buffer_set(&ch_user_modes, tmp, len);
459 tmp = silc_argument_get_arg_type(args, 7, &len);
461 SILC_GET32_MSB(mode, tmp);
464 tmp = silc_argument_get_arg_type(args, 8, &len);
466 SILC_GET32_MSB(idle, tmp);
468 /* Get fingerprint */
469 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
471 /* Check if we have this client cached already. */
472 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
474 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
476 silc_client_add_client(client, conn, nickname, username, realname,
477 &id.u.client_id, mode);
479 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
482 silc_client_ref_client(client, conn, client_entry);
484 silc_client_update_client(client, conn, client_entry,
485 nickname, username, realname, mode);
488 silc_rwlock_wrlock(client_entry->internal.lock);
490 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
491 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
493 /* Get user attributes */
494 tmp = silc_argument_get_arg_type(args, 11, &len);
496 if (client_entry->attrs)
497 silc_attribute_payload_list_free(client_entry->attrs);
498 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
501 silc_rwlock_unlock(client_entry->internal.lock);
503 /* Parse channel and channel user mode list */
505 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
506 silc_buffer_len(&channels));
508 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
512 /* Notify application */
513 silc_client_command_callback(cmd, client_entry, nickname, username,
514 realname, channel_list, mode, idle, fingerprint,
515 umodes, client_entry->attrs);
517 silc_client_unref_client(client, conn, client_entry);
519 silc_channel_payload_list_free(channel_list);
524 silc_fsm_next(fsm, silc_client_command_reply_processed);
525 return SILC_FSM_CONTINUE;
528 /******************************** WHOWAS ************************************/
530 /* Received reply for WHOWAS command. */
532 SILC_FSM_STATE(silc_client_command_reply_whowas)
534 SilcClientCommandContext cmd = fsm_context;
535 SilcClientConnection conn = cmd->conn;
536 SilcClient client = conn->client;
537 SilcCommandPayload payload = state_context;
538 SilcArgumentPayload args = silc_command_get_args(payload);
539 SilcClientEntry client_entry = NULL;
541 char *nickname, *username;
542 char *realname = NULL;
544 CHECK_STATUS("WHOWAS: ");
548 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
549 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
553 /* Get the client entry */
554 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
557 nickname = silc_argument_get_arg_type(args, 3, NULL);
558 username = silc_argument_get_arg_type(args, 4, NULL);
559 realname = silc_argument_get_arg_type(args, 5, NULL);
560 if (!nickname || !username) {
561 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
565 /* Notify application. We don't save any history information to any
566 cache. Just pass the data to the application. */
567 silc_client_command_callback(cmd, client_entry, nickname, username,
571 silc_client_unref_client(client, conn, client_entry);
572 silc_fsm_next(fsm, silc_client_command_reply_processed);
573 return SILC_FSM_CONTINUE;
576 /******************************** IDENTIFY **********************************/
578 /* Received reply for IDENTIFY command. */
580 SILC_FSM_STATE(silc_client_command_reply_identify)
582 SilcClientCommandContext cmd = fsm_context;
583 SilcClientConnection conn = cmd->conn;
584 SilcClient client = conn->client;
585 SilcCommandPayload payload = state_context;
586 SilcArgumentPayload args = silc_command_get_args(payload);
587 SilcClientEntry client_entry;
588 SilcServerEntry server_entry;
589 SilcChannelEntry channel_entry;
592 char *name = NULL, *info = NULL;
594 CHECK_STATUS("IDENTIFY: ");
598 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
599 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
604 name = silc_argument_get_arg_type(args, 3, &len);
605 info = silc_argument_get_arg_type(args, 4, &len);
609 SILC_LOG_DEBUG(("Received client information"));
611 /* Check if we have this client cached already. */
612 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
614 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
616 silc_client_add_client(client, conn, name, info, NULL,
619 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
622 silc_client_ref_client(client, conn, client_entry);
624 silc_client_update_client(client, conn, client_entry,
625 name, info, NULL, 0);
628 /* Notify application */
629 silc_client_command_callback(cmd, client_entry, name, info);
630 silc_client_unref_client(client, conn, client_entry);
634 SILC_LOG_DEBUG(("Received server information"));
636 /* Check if we have this server cached already. */
637 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
639 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
640 server_entry = silc_client_add_server(client, conn, name, info,
643 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
646 silc_client_ref_server(client, conn, server_entry);
648 silc_client_update_server(client, conn, server_entry, name, info);
650 server_entry->internal.resolve_cmd_ident = 0;
652 /* Notify application */
653 silc_client_command_callback(cmd, server_entry, name, info);
654 silc_client_unref_server(client, conn, server_entry);
657 case SILC_ID_CHANNEL:
658 SILC_LOG_DEBUG(("Received channel information"));
660 /* Check if we have this channel cached already. */
661 channel_entry = silc_client_get_channel_by_id(client, conn,
663 if (!channel_entry) {
664 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
667 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
671 /* Add new channel entry */
672 channel_entry = silc_client_add_channel(client, conn, name, 0,
674 if (!channel_entry) {
675 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
678 silc_client_ref_channel(client, conn, channel_entry);
681 /* Notify application */
682 silc_client_command_callback(cmd, channel_entry,
683 channel_entry->channel_name, info);
684 silc_client_unref_channel(client, conn, channel_entry);
689 silc_fsm_next(fsm, silc_client_command_reply_processed);
690 return SILC_FSM_CONTINUE;
693 /********************************** NICK ************************************/
695 /* Received reply for command NICK. */
697 SILC_FSM_STATE(silc_client_command_reply_nick)
699 SilcClientCommandContext cmd = fsm_context;
700 SilcClientConnection conn = cmd->conn;
701 SilcClient client = conn->client;
702 SilcCommandPayload payload = state_context;
703 SilcArgumentPayload args = silc_command_get_args(payload);
704 unsigned char *nick, *idp;
705 SilcUInt32 len, idp_len;
706 SilcClientID old_client_id;
710 CHECK_STATUS("Cannot set nickname: ");
713 /* Take received Client ID */
714 idp = silc_argument_get_arg_type(args, 2, &idp_len);
716 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
719 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
720 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
724 /* Take the new nickname */
725 nick = silc_argument_get_arg_type(args, 3, &len);
727 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
731 silc_rwlock_wrlock(conn->local_entry->internal.lock);
733 /* Change the nickname */
734 old_client_id = *conn->local_id;
735 if (!silc_client_change_nickname(client, conn, conn->local_entry,
736 nick, &id.u.client_id, idp, idp_len)) {
737 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
738 silc_rwlock_unlock(conn->local_entry->internal.lock);
742 /* All auto-generated private message keys must be rekeyed because
743 we changed nick and others may not know about it. */
744 conn->internal->ake_generation++;
745 SILC_LOG_DEBUG(("AKE keys will be rekeyed, generation %u",
746 conn->internal->ake_generation));
748 silc_rwlock_unlock(conn->local_entry->internal.lock);
750 /* Notify application */
751 silc_client_command_callback(cmd, conn->local_entry,
752 conn->local_entry->nickname, &old_client_id);
755 silc_fsm_next(fsm, silc_client_command_reply_processed);
756 return SILC_FSM_CONTINUE;
759 /********************************** LIST ************************************/
761 /* Received reply to the LIST command. */
763 SILC_FSM_STATE(silc_client_command_reply_list)
765 SilcClientCommandContext cmd = fsm_context;
766 SilcClientConnection conn = cmd->conn;
767 SilcClient client = conn->client;
768 SilcCommandPayload payload = state_context;
769 SilcArgumentPayload args = silc_command_get_args(payload);
770 unsigned char *tmp, *name, *topic;
771 SilcUInt32 usercount = 0;
772 SilcChannelEntry channel_entry = NULL;
776 CHECK_STATUS("Cannot list channels: ");
778 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
779 /* There were no channels in the network. */
780 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
781 silc_fsm_next(fsm, silc_client_command_reply_processed);
782 return SILC_FSM_CONTINUE;
787 name = silc_argument_get_arg_type(args, 3, NULL);
789 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
793 topic = silc_argument_get_arg_type(args, 4, NULL);
794 tmp = silc_argument_get_arg_type(args, 5, NULL);
796 SILC_GET32_MSB(usercount, tmp);
798 /* Check whether the channel exists, and add it to cache if it doesn't. */
799 channel_entry = silc_client_get_channel_by_id(client, conn,
801 if (!channel_entry) {
802 /* Add new channel entry */
803 channel_entry = silc_client_add_channel(client, conn, name, 0,
805 if (!channel_entry) {
806 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
809 silc_client_ref_channel(client, conn, channel_entry);
812 /* Notify application */
813 silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name,
817 silc_client_unref_channel(client, conn, channel_entry);
818 silc_fsm_next(fsm, silc_client_command_reply_processed);
819 return SILC_FSM_CONTINUE;
822 /********************************* TOPIC ************************************/
824 /* Received reply to topic command. */
826 SILC_FSM_STATE(silc_client_command_reply_topic)
828 SilcClientCommandContext cmd = fsm_context;
829 SilcClientConnection conn = cmd->conn;
830 SilcClient client = conn->client;
831 SilcCommandPayload payload = state_context;
832 SilcArgumentPayload args = silc_command_get_args(payload);
833 SilcChannelEntry channel = NULL;
839 CHECK_STATUS("Cannot set topic: ");
842 /* Take Channel ID */
843 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
844 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
848 /* Get the channel entry */
849 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
851 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
855 silc_rwlock_wrlock(channel->internal.lock);
858 topic = silc_argument_get_arg_type(args, 3, &len);
860 silc_free(channel->topic);
861 channel->topic = silc_memdup(topic, len);
864 silc_rwlock_unlock(channel->internal.lock);
866 /* Notify application */
867 silc_client_command_callback(cmd, channel, channel->topic);
870 silc_client_unref_channel(client, conn, channel);
871 silc_fsm_next(fsm, silc_client_command_reply_processed);
872 return SILC_FSM_CONTINUE;
875 /********************************* INVITE ***********************************/
877 /* Received reply to invite command. */
879 SILC_FSM_STATE(silc_client_command_reply_invite)
881 SilcClientCommandContext cmd = fsm_context;
882 SilcClientConnection conn = cmd->conn;
883 SilcClient client = conn->client;
884 SilcCommandPayload payload = state_context;
885 SilcArgumentPayload args = silc_command_get_args(payload);
886 SilcChannelEntry channel = NULL;
889 SilcArgumentPayload invite_args = NULL;
893 CHECK_STATUS("Cannot invite: ");
896 /* Take Channel ID */
897 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
898 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
902 /* Get the channel entry */
903 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
905 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
909 /* Get the invite list */
910 tmp = silc_argument_get_arg_type(args, 3, &len);
912 invite_args = silc_argument_list_parse(tmp, len);
914 /* Notify application */
915 silc_client_command_callback(cmd, channel, invite_args);
918 silc_argument_payload_free(invite_args);
921 silc_client_unref_channel(client, conn, channel);
922 silc_fsm_next(fsm, silc_client_command_reply_processed);
923 return SILC_FSM_CONTINUE;
926 /********************************** KILL ************************************/
928 /* Received reply to the KILL command. */
930 SILC_FSM_STATE(silc_client_command_reply_kill)
932 SilcClientCommandContext cmd = fsm_context;
933 SilcClientConnection conn = cmd->conn;
934 SilcClient client = conn->client;
935 SilcCommandPayload payload = state_context;
936 SilcArgumentPayload args = silc_command_get_args(payload);
937 SilcClientEntry client_entry;
941 CHECK_STATUS("Cannot kill: ");
944 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
945 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
949 /* Get the client entry, if exists */
950 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
952 /* Notify application */
953 silc_client_command_callback(cmd, client_entry);
955 /* Remove the client */
957 silc_client_remove_from_channels(client, conn, client_entry);
958 client_entry->internal.valid = FALSE;
959 silc_client_del_client(client, conn, client_entry);
960 silc_client_unref_client(client, conn, client_entry);
964 silc_fsm_next(fsm, silc_client_command_reply_processed);
965 return SILC_FSM_CONTINUE;
968 /********************************** INFO ************************************/
970 /* Received reply to INFO command. We receive the server ID and some
971 information about the server user requested. */
973 SILC_FSM_STATE(silc_client_command_reply_info)
975 SilcClientCommandContext cmd = fsm_context;
976 SilcClientConnection conn = cmd->conn;
977 SilcClient client = conn->client;
978 SilcCommandPayload payload = state_context;
979 SilcArgumentPayload args = silc_command_get_args(payload);
980 SilcServerEntry server;
981 char *server_name, *server_info;
985 CHECK_STATUS("Cannot get info: ");
989 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
990 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
994 /* Get server name */
995 server_name = silc_argument_get_arg_type(args, 3, NULL);
997 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1001 /* Get server info */
1002 server_info = silc_argument_get_arg_type(args, 4, NULL);
1004 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1008 /* See whether we have this server cached. If not create it. */
1009 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1011 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
1012 server = silc_client_add_server(client, conn, server_name,
1013 server_info, &id.u.server_id);
1016 silc_client_ref_server(client, conn, server);
1019 /* Notify application */
1020 silc_client_command_callback(cmd, server, server->server_name,
1021 server->server_info);
1022 silc_client_unref_server(client, conn, server);
1025 silc_fsm_next(fsm, silc_client_command_reply_processed);
1026 return SILC_FSM_CONTINUE;
1029 /********************************** STATS ***********************************/
1031 /* Received reply to STATS command. */
1033 SILC_FSM_STATE(silc_client_command_reply_stats)
1035 SilcClientCommandContext cmd = fsm_context;
1036 SilcCommandPayload payload = state_context;
1037 SilcArgumentPayload args = silc_command_get_args(payload);
1038 SilcClientStats stats;
1039 unsigned char *buf = NULL;
1040 SilcUInt32 buf_len = 0;
1045 CHECK_STATUS("Cannot get stats: ");
1049 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1050 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1054 /* Get statistics structure */
1055 memset(&stats, 0, sizeof(stats));
1056 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1058 silc_buffer_set(&b, buf, buf_len);
1059 silc_buffer_unformat(&b,
1060 SILC_STR_UI_INT(&stats.starttime),
1061 SILC_STR_UI_INT(&stats.uptime),
1062 SILC_STR_UI_INT(&stats.my_clients),
1063 SILC_STR_UI_INT(&stats.my_channels),
1064 SILC_STR_UI_INT(&stats.my_server_ops),
1065 SILC_STR_UI_INT(&stats.my_router_ops),
1066 SILC_STR_UI_INT(&stats.cell_clients),
1067 SILC_STR_UI_INT(&stats.cell_channels),
1068 SILC_STR_UI_INT(&stats.cell_servers),
1069 SILC_STR_UI_INT(&stats.clients),
1070 SILC_STR_UI_INT(&stats.channels),
1071 SILC_STR_UI_INT(&stats.servers),
1072 SILC_STR_UI_INT(&stats.routers),
1073 SILC_STR_UI_INT(&stats.server_ops),
1074 SILC_STR_UI_INT(&stats.router_ops),
1078 /* Notify application */
1079 silc_client_command_callback(cmd, &stats);
1082 silc_fsm_next(fsm, silc_client_command_reply_processed);
1083 return SILC_FSM_CONTINUE;
1086 /********************************** PING ************************************/
1088 /* Received reply to PING command. */
1090 SILC_FSM_STATE(silc_client_command_reply_ping)
1092 SilcClientCommandContext cmd = fsm_context;
1093 SilcClientConnection conn = cmd->conn;
1094 SilcClient client = conn->client;
1097 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1099 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1100 "Ping reply from %s: %d second%s", conn->remote_host,
1101 (int)diff, diff == 1 ? "" : "s");
1103 /* Notify application */
1104 silc_client_command_callback(cmd);
1106 silc_fsm_next(fsm, silc_client_command_reply_processed);
1107 return SILC_FSM_CONTINUE;
1110 /********************************** JOIN ************************************/
1112 /* Continue JOIN command reply processing after resolving unknown users */
1115 silc_client_command_reply_join_resolved(SilcClient client,
1116 SilcClientConnection conn,
1121 SilcClientCommandContext cmd = context;
1122 SilcChannelEntry channel = cmd->context;
1124 channel->internal.resolve_cmd_ident = 0;
1125 silc_client_unref_channel(client, conn, channel);
1127 SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
1131 /* Received reply for JOIN command. */
1133 SILC_FSM_STATE(silc_client_command_reply_join)
1135 SilcClientCommandContext cmd = fsm_context;
1136 SilcClientConnection conn = cmd->conn;
1137 SilcClient client = conn->client;
1138 SilcCommandPayload payload = state_context;
1139 SilcArgumentPayload args = silc_command_get_args(payload);
1140 SilcChannelEntry channel;
1141 SilcUInt32 mode = 0, len, list_count;
1142 char *topic, *tmp, *channel_name = NULL, *hmac;
1144 SilcBufferStruct client_id_list, client_mode_list, keyp;
1145 SilcHashTableList htl;
1150 CHECK_STATUS("Cannot join channel: ");
1153 /* Get channel name */
1154 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1155 if (!channel_name) {
1156 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1160 /* Get Channel ID */
1161 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1162 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1166 /* Check whether we have this channel entry already. */
1167 channel = silc_client_get_channel(client, conn, channel_name);
1169 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1170 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1172 /* Create new channel entry */
1173 channel = silc_client_add_channel(client, conn, channel_name,
1174 mode, &id.u.channel_id);
1176 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1179 silc_client_ref_channel(client, conn, channel);
1183 hmac = silc_argument_get_arg_type(args, 11, NULL);
1184 if (hmac && !silc_hmac_is_supported(hmac)) {
1186 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1187 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1188 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1189 silc_rwlock_unlock(channel->internal.lock);
1193 /* Get the list count */
1194 tmp = silc_argument_get_arg_type(args, 12, &len);
1196 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1199 SILC_GET32_MSB(list_count, tmp);
1201 /* Get Client ID list */
1202 tmp = silc_argument_get_arg_type(args, 13, &len);
1204 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1207 silc_buffer_set(&client_id_list, tmp, len);
1209 /* Resolve users we do not know about */
1210 if (!cmd->resolved) {
1211 cmd->resolved = TRUE;
1212 cmd->context = channel;
1213 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1214 silc_client_get_clients_by_list(
1215 client, conn, list_count, &client_id_list,
1216 silc_client_command_reply_join_resolved, cmd));
1220 /* Get client mode list */
1221 tmp = silc_argument_get_arg_type(args, 14, &len);
1223 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1226 silc_buffer_set(&client_mode_list, tmp, len);
1228 silc_rwlock_wrlock(channel->internal.lock);
1230 /* Add clients we received in the reply to the channel */
1231 for (i = 0; i < list_count; i++) {
1235 SilcClientEntry client_entry;
1238 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1240 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1244 SILC_GET32_MSB(mode, client_mode_list.data);
1246 /* Get client entry */
1247 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1248 if (client_entry && client_entry->internal.valid) {
1249 /* Join client to the channel */
1250 silc_rwlock_wrlock(client_entry->internal.lock);
1251 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1252 silc_rwlock_unlock(client_entry->internal.lock);
1254 silc_client_unref_client(client, conn, client_entry);
1256 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1257 silc_rwlock_unlock(channel->internal.lock);
1260 if (!silc_buffer_pull(&client_mode_list, 4)) {
1261 silc_rwlock_unlock(channel->internal.lock);
1266 /* Get channel mode */
1267 tmp = silc_argument_get_arg_type(args, 5, &len);
1268 if (tmp && len == 4)
1269 SILC_GET32_MSB(mode, tmp);
1270 channel->mode = mode;
1272 /* Get channel key and save it */
1273 tmp = silc_argument_get_arg_type(args, 7, &len);
1275 /* If channel key already exists on the channel then while resolving
1276 the user list we have already received new key from server. Don't
1277 replace it with this old key. */
1278 if (!channel->internal.send_key) {
1279 silc_buffer_set(&keyp, tmp, len);
1280 silc_client_save_channel_key(client, conn, &keyp, channel);
1285 topic = silc_argument_get_arg_type(args, 10, NULL);
1287 silc_free(channel->topic);
1288 channel->topic = silc_memdup(topic, strlen(topic));
1291 /* Get founder key */
1292 tmp = silc_argument_get_arg_type(args, 15, &len);
1294 if (channel->founder_key)
1295 silc_pkcs_public_key_free(channel->founder_key);
1296 channel->founder_key = NULL;
1297 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1300 /* Get user limit */
1301 tmp = silc_argument_get_arg_type(args, 17, &len);
1302 if (tmp && len == 4)
1303 SILC_GET32_MSB(channel->user_limit, tmp);
1304 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1305 channel->user_limit = 0;
1307 /* Get channel public key list */
1308 tmp = silc_argument_get_arg_type(args, 16, &len);
1310 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1312 /* Set current channel */
1313 conn->current_channel = channel;
1315 silc_rwlock_unlock(channel->internal.lock);
1317 cipher = (channel->internal.send_key ?
1318 silc_cipher_get_name(channel->internal.send_key) : NULL);
1319 silc_hash_table_list(channel->user_list, &htl);
1321 /* Notify application */
1322 silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
1323 topic, cipher, hmac, channel->founder_key,
1324 channel->channel_pubkeys, channel->user_limit);
1326 silc_hash_table_list_reset(&htl);
1327 silc_client_unref_channel(client, conn, channel);
1330 silc_fsm_next(fsm, silc_client_command_reply_processed);
1331 return SILC_FSM_CONTINUE;
1334 /********************************** MOTD ************************************/
1336 /* Received reply for MOTD command */
1338 SILC_FSM_STATE(silc_client_command_reply_motd)
1340 SilcClientCommandContext cmd = fsm_context;
1341 SilcClientConnection conn = cmd->conn;
1342 SilcClient client = conn->client;
1343 SilcCommandPayload payload = state_context;
1344 SilcArgumentPayload args = silc_command_get_args(payload);
1346 char *motd = NULL, *cp, line[256];
1349 CHECK_STATUS("Cannot get motd: ");
1352 if (silc_argument_get_arg_num(args) == 3) {
1353 motd = silc_argument_get_arg_type(args, 3, NULL);
1355 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1362 if (cp[i++] == '\n') {
1363 memset(line, 0, sizeof(line));
1364 silc_strncat(line, sizeof(line), cp, i - 1);
1371 SAY(client, conn, SILC_CLIENT_MESSAGE_AUDIT, "%s", line);
1380 /* Notify application */
1381 silc_client_command_callback(cmd, motd);
1384 silc_fsm_next(fsm, silc_client_command_reply_processed);
1385 return SILC_FSM_CONTINUE;
1388 /********************************** UMODE ***********************************/
1390 /* Received reply to the UMODE command. Save the current user mode */
1392 SILC_FSM_STATE(silc_client_command_reply_umode)
1394 SilcClientCommandContext cmd = fsm_context;
1395 SilcClientConnection conn = cmd->conn;
1396 SilcCommandPayload payload = state_context;
1397 SilcArgumentPayload args = silc_command_get_args(payload);
1399 SilcUInt32 mode, len;
1402 CHECK_STATUS("Cannot change mode: ");
1405 tmp = silc_argument_get_arg_type(args, 2, &len);
1406 if (!tmp || len != 4) {
1407 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1411 SILC_GET32_MSB(mode, tmp);
1412 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1413 conn->local_entry->mode = mode;
1414 silc_rwlock_unlock(conn->local_entry->internal.lock);
1416 /* Notify application */
1417 silc_client_command_callback(cmd, mode);
1420 silc_fsm_next(fsm, silc_client_command_reply_processed);
1421 return SILC_FSM_CONTINUE;
1424 /********************************** CMODE ***********************************/
1426 /* Received reply for CMODE command. */
1428 SILC_FSM_STATE(silc_client_command_reply_cmode)
1430 SilcClientCommandContext cmd = fsm_context;
1431 SilcClientConnection conn = cmd->conn;
1432 SilcClient client = conn->client;
1433 SilcCommandPayload payload = state_context;
1434 SilcArgumentPayload args = silc_command_get_args(payload);
1437 SilcChannelEntry channel = NULL;
1439 SilcPublicKey public_key = NULL;
1443 CHECK_STATUS("Cannot change mode: ");
1446 /* Take Channel ID */
1447 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1448 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1452 /* Get the channel entry */
1453 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1455 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1459 /* Get founder public key */
1460 tmp = silc_argument_get_arg_type(args, 4, &len);
1462 silc_public_key_payload_decode(tmp, len, &public_key);
1464 /* Get channel mode */
1465 tmp = silc_argument_get_arg_type(args, 3, &len);
1466 if (!tmp || len != 4) {
1467 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1470 SILC_GET32_MSB(mode, tmp);
1472 silc_rwlock_wrlock(channel->internal.lock);
1474 /* Get user limit */
1475 tmp = silc_argument_get_arg_type(args, 6, &len);
1476 if (tmp && len == 4)
1477 SILC_GET32_MSB(channel->user_limit, tmp);
1478 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1479 channel->user_limit = 0;
1481 /* Get channel public key(s) */
1482 tmp = silc_argument_get_arg_type(args, 5, &len);
1484 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1485 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
1486 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
1489 channel->mode = mode;
1491 silc_rwlock_unlock(channel->internal.lock);
1493 /* Notify application */
1494 silc_client_command_callback(cmd, channel, mode, public_key,
1495 channel->channel_pubkeys, channel->user_limit);
1498 silc_client_unref_channel(client, conn, channel);
1500 silc_pkcs_public_key_free(public_key);
1501 silc_fsm_next(fsm, silc_client_command_reply_processed);
1502 return SILC_FSM_CONTINUE;
1505 /********************************** CUMODE **********************************/
1507 /* Received reply for CUMODE command */
1509 SILC_FSM_STATE(silc_client_command_reply_cumode)
1511 SilcClientCommandContext cmd = fsm_context;
1512 SilcClientConnection conn = cmd->conn;
1513 SilcClient client = conn->client;
1514 SilcCommandPayload payload = state_context;
1515 SilcArgumentPayload args = silc_command_get_args(payload);
1516 SilcClientEntry client_entry;
1517 SilcChannelEntry channel = NULL;
1518 SilcChannelUser chu;
1519 unsigned char *modev;
1520 SilcUInt32 len, mode;
1524 CHECK_STATUS("Cannot change mode: ");
1527 /* Get channel mode */
1528 modev = silc_argument_get_arg_type(args, 2, &len);
1529 if (!modev || len != 4) {
1530 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1533 SILC_GET32_MSB(mode, modev);
1535 /* Take Channel ID */
1536 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1537 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1541 /* Get the channel entry */
1542 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1544 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1549 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1550 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1554 /* Get client entry */
1555 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1556 if (!client_entry) {
1557 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1562 silc_rwlock_wrlock(channel->internal.lock);
1563 chu = silc_client_on_channel(channel, client_entry);
1566 silc_rwlock_unlock(channel->internal.lock);
1568 /* Notify application */
1569 silc_client_command_callback(cmd, mode, channel, client_entry);
1571 silc_client_unref_client(client, conn, client_entry);
1574 silc_client_unref_channel(client, conn, channel);
1575 silc_fsm_next(fsm, silc_client_command_reply_processed);
1576 return SILC_FSM_CONTINUE;
1579 /********************************** KICK ************************************/
1581 SILC_FSM_STATE(silc_client_command_reply_kick)
1583 SilcClientCommandContext cmd = fsm_context;
1584 SilcClientConnection conn = cmd->conn;
1585 SilcClient client = conn->client;
1586 SilcCommandPayload payload = state_context;
1587 SilcArgumentPayload args = silc_command_get_args(payload);
1588 SilcClientEntry client_entry;
1589 SilcChannelEntry channel = NULL;
1593 CHECK_STATUS("Cannot kick: ");
1596 /* Take Channel ID */
1597 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1598 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1602 /* Get the channel entry */
1603 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1605 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1610 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1611 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1615 /* Get client entry */
1616 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1617 if (!client_entry) {
1618 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1622 /* Notify application */
1623 silc_client_command_callback(cmd, channel, client_entry);
1625 silc_client_unref_client(client, conn, client_entry);
1628 silc_client_unref_channel(client, conn, channel);
1629 silc_fsm_next(fsm, silc_client_command_reply_processed);
1630 return SILC_FSM_CONTINUE;
1633 /******************************** SILCOPER **********************************/
1635 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1637 SilcClientCommandContext cmd = fsm_context;
1638 SilcCommandPayload payload = state_context;
1639 SilcArgumentPayload args = silc_command_get_args(payload);
1642 CHECK_STATUS("Cannot change mode: ");
1646 cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1648 /* Notify application */
1649 silc_client_command_callback(cmd);
1651 silc_fsm_next(fsm, silc_client_command_reply_processed);
1652 return SILC_FSM_CONTINUE;
1655 /********************************** OPER ************************************/
1657 SILC_FSM_STATE(silc_client_command_reply_oper)
1659 SilcClientCommandContext cmd = fsm_context;
1660 SilcCommandPayload payload = state_context;
1661 SilcArgumentPayload args = silc_command_get_args(payload);
1664 CHECK_STATUS("Cannot change mode: ");
1668 cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1670 /* Notify application */
1671 silc_client_command_callback(cmd);
1673 silc_fsm_next(fsm, silc_client_command_reply_processed);
1674 return SILC_FSM_CONTINUE;
1677 /********************************* DETACH ***********************************/
1679 SILC_FSM_STATE(silc_client_command_reply_detach)
1681 SilcClientCommandContext cmd = fsm_context;
1682 SilcClientConnection conn = cmd->conn;
1683 SilcClient client = conn->client;
1684 SilcCommandPayload payload = state_context;
1685 SilcArgumentPayload args = silc_command_get_args(payload);
1689 CHECK_STATUS("Cannot detach: ");
1692 /* Get detachment data */
1693 detach = silc_client_get_detach_data(client, conn);
1695 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1699 /* Notify application */
1700 silc_client_command_callback(cmd, detach);
1701 silc_buffer_free(detach);
1704 silc_fsm_next(fsm, silc_client_command_reply_processed);
1705 return SILC_FSM_CONTINUE;
1708 /********************************** WATCH ***********************************/
1710 SILC_FSM_STATE(silc_client_command_reply_watch)
1712 SilcClientCommandContext cmd = fsm_context;
1713 SilcCommandPayload payload = state_context;
1714 SilcArgumentPayload args = silc_command_get_args(payload);
1717 CHECK_STATUS("Cannot set watch: ");
1720 /* Notify application */
1721 silc_client_command_callback(cmd);
1723 silc_fsm_next(fsm, silc_client_command_reply_processed);
1724 return SILC_FSM_CONTINUE;
1727 /*********************************** BAN ************************************/
1729 SILC_FSM_STATE(silc_client_command_reply_ban)
1731 SilcClientCommandContext cmd = fsm_context;
1732 SilcClientConnection conn = cmd->conn;
1733 SilcClient client = conn->client;
1734 SilcCommandPayload payload = state_context;
1735 SilcArgumentPayload args = silc_command_get_args(payload);
1736 SilcChannelEntry channel = NULL;
1739 SilcArgumentPayload invite_args = NULL;
1743 CHECK_STATUS("Cannot set ban: ");
1746 /* Take Channel ID */
1747 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1748 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1752 /* Get the channel entry */
1753 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1755 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1759 /* Get the invite list */
1760 tmp = silc_argument_get_arg_type(args, 3, &len);
1762 invite_args = silc_argument_list_parse(tmp, len);
1764 /* Notify application */
1765 silc_client_command_callback(cmd, channel, invite_args);
1768 silc_argument_payload_free(invite_args);
1771 silc_client_unref_channel(client, conn, channel);
1772 silc_fsm_next(fsm, silc_client_command_reply_processed);
1773 return SILC_FSM_CONTINUE;
1776 /********************************** LEAVE ***********************************/
1778 /* Reply to LEAVE command. */
1780 SILC_FSM_STATE(silc_client_command_reply_leave)
1782 SilcClientCommandContext cmd = fsm_context;
1783 SilcClientConnection conn = cmd->conn;
1784 SilcClient client = conn->client;
1785 SilcCommandPayload payload = state_context;
1786 SilcArgumentPayload args = silc_command_get_args(payload);
1787 SilcChannelEntry channel;
1793 CHECK_STATUS("Cannot set leave: ");
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 the channel entry */
1803 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1805 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1809 /* Remove us from this channel. */
1810 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1812 /* Notify application */
1813 silc_client_command_callback(cmd, channel);
1815 /* Remove old keys and stuff. The channel may remain even after leaving
1816 but we want to remove these always. */
1817 if (channel->internal.send_key)
1818 silc_cipher_free(channel->internal.send_key);
1819 channel->internal.send_key = NULL;
1820 if (channel->internal.receive_key)
1821 silc_cipher_free(channel->internal.receive_key);
1822 channel->internal.receive_key = NULL;
1823 if (channel->internal.hmac)
1824 silc_hmac_free(channel->internal.hmac);
1825 channel->internal.hmac = NULL;
1826 if (channel->internal.old_channel_keys) {
1827 silc_dlist_start(channel->internal.old_channel_keys);
1828 while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
1829 silc_cipher_free(key);
1830 silc_dlist_uninit(channel->internal.old_channel_keys);
1832 channel->internal.old_channel_keys = NULL;
1833 if (channel->internal.old_hmacs) {
1834 silc_dlist_start(channel->internal.old_hmacs);
1835 while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
1836 silc_hmac_free(hmac);
1837 silc_dlist_uninit(channel->internal.old_hmacs);
1839 channel->internal.old_hmacs = NULL;
1841 /* Now delete the channel. */
1842 silc_client_empty_channel(client, conn, channel);
1843 silc_client_del_channel(client, conn, channel);
1846 silc_fsm_next(fsm, silc_client_command_reply_processed);
1847 return SILC_FSM_CONTINUE;
1850 /********************************* USERS ************************************/
1852 /* Continue USERS command reply processing after resolving unknown users */
1855 silc_client_command_reply_users_resolved(SilcClient client,
1856 SilcClientConnection conn,
1861 SilcClientCommandContext cmd = context;
1862 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1866 /* Continue USERS command after resolving unknown channel */
1869 silc_client_command_reply_users_continue(SilcClient client,
1870 SilcClientConnection conn,
1875 SilcClientCommandContext cmd = context;
1878 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1879 SilcArgumentPayload args = silc_command_get_args(payload);
1881 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1882 ERROR_CALLBACK(cmd->status);
1883 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1886 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1889 /* Reply to USERS command. Received list of client ID's and theirs modes
1890 on the channel we requested. */
1892 SILC_FSM_STATE(silc_client_command_reply_users)
1894 SilcClientCommandContext cmd = fsm_context;
1895 SilcClientConnection conn = cmd->conn;
1896 SilcClient client = conn->client;
1897 SilcCommandPayload payload = state_context;
1898 SilcArgumentPayload args = silc_command_get_args(payload);
1900 SilcUInt32 tmp_len, list_count, mode;
1902 SilcHashTableList htl;
1903 SilcBufferStruct client_id_list, client_mode_list;
1904 SilcChannelEntry channel = NULL;
1905 SilcClientEntry client_entry;
1910 CHECK_STATUS("Cannot get users: ");
1913 /* Get channel ID */
1914 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1915 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1919 /* Get channel entry */
1920 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1922 /* Resolve the channel from server */
1923 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1924 client, conn, &id.u.channel_id,
1925 silc_client_command_reply_users_continue, cmd));
1929 /* Get the list count */
1930 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1931 if (!tmp || tmp_len != 4) {
1932 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1935 SILC_GET32_MSB(list_count, tmp);
1937 /* Get Client ID list */
1938 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1940 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1943 silc_buffer_set(&client_id_list, tmp, tmp_len);
1945 /* Resolve users we do not know about */
1946 if (!cmd->resolved) {
1947 cmd->resolved = TRUE;
1948 silc_client_unref_channel(client, conn, channel);
1949 SILC_FSM_CALL(silc_client_get_clients_by_list(
1950 client, conn, list_count, &client_id_list,
1951 silc_client_command_reply_users_resolved, cmd));
1955 /* Get client mode list */
1956 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1958 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1961 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1963 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1965 silc_rwlock_wrlock(channel->internal.lock);
1967 /* Cache the received Client ID's and modes. */
1968 for (i = 0; i < list_count; i++) {
1969 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1971 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1975 SILC_GET32_MSB(mode, client_mode_list.data);
1977 /* Save the client on this channel. Unknown clients are ignored as they
1978 clearly do not exist since the resolving didn't find them. */
1979 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1980 if (client_entry && client_entry->internal.valid) {
1981 silc_rwlock_wrlock(client_entry->internal.lock);
1982 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1983 silc_rwlock_unlock(client_entry->internal.lock);
1985 silc_client_unref_client(client, conn, client_entry);
1987 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1988 silc_rwlock_unlock(channel->internal.lock);
1991 if (!silc_buffer_pull(&client_mode_list, 4)) {
1992 silc_rwlock_unlock(channel->internal.lock);
1997 silc_rwlock_unlock(channel->internal.lock);
1999 /* Notify application */
2000 silc_hash_table_list(channel->user_list, &htl);
2001 silc_client_command_callback(cmd, channel, &htl);
2002 silc_hash_table_list_reset(&htl);
2005 silc_client_unref_channel(client, conn, channel);
2006 silc_fsm_next(fsm, silc_client_command_reply_processed);
2007 return SILC_FSM_CONTINUE;
2010 /********************************** GETKEY **********************************/
2012 /* Received command reply to GETKEY command. WE've received the remote
2013 client's public key. */
2015 SILC_FSM_STATE(silc_client_command_reply_getkey)
2017 SilcClientCommandContext cmd = fsm_context;
2018 SilcClientConnection conn = cmd->conn;
2019 SilcClient client = conn->client;
2020 SilcCommandPayload payload = state_context;
2021 SilcArgumentPayload args = silc_command_get_args(payload);
2022 SilcClientEntry client_entry;
2023 SilcServerEntry server_entry;
2026 SilcPublicKey public_key = NULL;
2030 CHECK_STATUS("Cannot get key: ");
2034 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
2035 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2039 /* Get the public key */
2040 tmp = silc_argument_get_arg_type(args, 3, &len);
2042 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2045 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
2046 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
2047 "Cannot decode public key: malformed/unsupported public key");
2048 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2052 if (id.type == SILC_ID_CLIENT) {
2053 /* Received client's public key */
2054 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2055 if (!client_entry) {
2056 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2060 silc_rwlock_wrlock(client_entry->internal.lock);
2062 /* Save fingerprint */
2063 if (!client_entry->fingerprint)
2064 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2065 client_entry->fingerprint);
2066 if (!client_entry->public_key) {
2067 client_entry->public_key = public_key;
2071 silc_rwlock_unlock(client_entry->internal.lock);
2073 /* Notify application */
2074 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2075 client_entry->public_key);
2076 silc_client_unref_client(client, conn, client_entry);
2077 } else if (id.type == SILC_ID_SERVER) {
2078 /* Received server's public key */
2079 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2080 if (!server_entry) {
2081 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2085 silc_rwlock_wrlock(server_entry->internal.lock);
2087 if (!server_entry->public_key) {
2088 server_entry->public_key = public_key;
2092 silc_rwlock_unlock(server_entry->internal.lock);
2094 /* Notify application */
2095 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2096 server_entry->public_key);
2097 silc_client_unref_server(client, conn, server_entry);
2102 silc_pkcs_public_key_free(public_key);
2103 silc_fsm_next(fsm, silc_client_command_reply_processed);
2104 return SILC_FSM_CONTINUE;
2107 /********************************** SERVICE *********************************/
2109 /* Reply to SERVICE command. */
2110 /* XXX incomplete */
2112 SILC_FSM_STATE(silc_client_command_reply_service)
2114 SilcClientCommandContext cmd = fsm_context;
2115 SilcCommandPayload payload = state_context;
2116 SilcArgumentPayload args = silc_command_get_args(payload);
2118 unsigned char *service_list, *name;
2121 CHECK_STATUS("Cannot get service: ");
2123 /* Get service list */
2124 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2126 /* Get requested service name */
2127 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2129 /* Notify application */
2130 silc_client_command_callback(cmd, service_list, name);
2132 silc_fsm_next(fsm, silc_client_command_reply_processed);
2133 return SILC_FSM_CONTINUE;
2136 /*********************************** QUIT ***********************************/
2138 /* QUIT command reply stub */
2140 SILC_FSM_STATE(silc_client_command_reply_quit)
2142 silc_fsm_next(fsm, silc_client_command_reply_processed);
2143 return SILC_FSM_CONTINUE;