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_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 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. We continue
203 command reply processing synchronously because we save the command
204 payload into state context. No other reply may arrive to this command
205 while we're processing this reply. */
206 silc_fsm_set_state_context(&cmd->thread, payload);
207 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
208 silc_fsm_continue_sync(&cmd->thread);
210 return SILC_FSM_FINISH;
213 /* Wait here for command reply to arrive from remote host */
215 SILC_FSM_STATE(silc_client_command_reply_wait)
217 SilcClientCommandContext cmd = fsm_context;
219 SILC_LOG_DEBUG(("Wait for command reply"));
221 /** Wait for command reply */
222 silc_fsm_set_state_context(fsm, NULL);
223 silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
224 cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0);
225 return SILC_FSM_WAIT;
228 /* Timeout occurred while waiting command reply */
230 SILC_FSM_STATE(silc_client_command_reply_timeout)
232 SilcClientCommandContext cmd = fsm_context;
233 SilcClientConnection conn = cmd->conn;
234 SilcArgumentPayload args = NULL;
236 if (conn->internal->disconnected) {
237 SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
238 silc_list_del(conn->internal->pending_commands, cmd);
240 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
241 return SILC_FSM_FINISH;
244 SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
246 /* Timeout, reply not received in timely fashion */
247 silc_list_del(conn->internal->pending_commands, cmd);
248 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
249 return SILC_FSM_FINISH;
252 /* Process received command reply payload */
254 SILC_FSM_STATE(silc_client_command_reply_process)
256 SilcClientCommandContext cmd = fsm_context;
257 SilcCommandPayload payload = state_context;
259 silc_command_get_status(payload, &cmd->status, &cmd->error);
262 case SILC_COMMAND_WHOIS:
264 silc_fsm_next(fsm, silc_client_command_reply_whois);
266 case SILC_COMMAND_WHOWAS:
268 silc_fsm_next(fsm, silc_client_command_reply_whowas);
270 case SILC_COMMAND_IDENTIFY:
272 silc_fsm_next(fsm, silc_client_command_reply_identify);
274 case SILC_COMMAND_NICK:
276 silc_fsm_next(fsm, silc_client_command_reply_nick);
278 case SILC_COMMAND_LIST:
280 silc_fsm_next(fsm, silc_client_command_reply_list);
282 case SILC_COMMAND_TOPIC:
284 silc_fsm_next(fsm, silc_client_command_reply_topic);
286 case SILC_COMMAND_INVITE:
288 silc_fsm_next(fsm, silc_client_command_reply_invite);
290 case SILC_COMMAND_QUIT:
292 silc_fsm_next(fsm, silc_client_command_reply_quit);
294 case SILC_COMMAND_KILL:
296 silc_fsm_next(fsm, silc_client_command_reply_kill);
298 case SILC_COMMAND_INFO:
300 silc_fsm_next(fsm, silc_client_command_reply_info);
302 case SILC_COMMAND_STATS:
304 silc_fsm_next(fsm, silc_client_command_reply_stats);
306 case SILC_COMMAND_PING:
308 silc_fsm_next(fsm, silc_client_command_reply_ping);
310 case SILC_COMMAND_OPER:
312 silc_fsm_next(fsm, silc_client_command_reply_oper);
314 case SILC_COMMAND_JOIN:
316 silc_fsm_next(fsm, silc_client_command_reply_join);
318 case SILC_COMMAND_MOTD:
320 silc_fsm_next(fsm, silc_client_command_reply_motd);
322 case SILC_COMMAND_UMODE:
324 silc_fsm_next(fsm, silc_client_command_reply_umode);
326 case SILC_COMMAND_CMODE:
328 silc_fsm_next(fsm, silc_client_command_reply_cmode);
330 case SILC_COMMAND_CUMODE:
332 silc_fsm_next(fsm, silc_client_command_reply_cumode);
334 case SILC_COMMAND_KICK:
336 silc_fsm_next(fsm, silc_client_command_reply_kick);
338 case SILC_COMMAND_BAN:
340 silc_fsm_next(fsm, silc_client_command_reply_ban);
342 case SILC_COMMAND_DETACH:
344 silc_fsm_next(fsm, silc_client_command_reply_detach);
346 case SILC_COMMAND_WATCH:
348 silc_fsm_next(fsm, silc_client_command_reply_watch);
350 case SILC_COMMAND_SILCOPER:
352 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
354 case SILC_COMMAND_LEAVE:
356 silc_fsm_next(fsm, silc_client_command_reply_leave);
358 case SILC_COMMAND_USERS:
360 silc_fsm_next(fsm, silc_client_command_reply_users);
362 case SILC_COMMAND_GETKEY:
364 silc_fsm_next(fsm, silc_client_command_reply_getkey);
366 case SILC_COMMAND_SERVICE:
368 silc_fsm_next(fsm, silc_client_command_reply_service);
371 return SILC_FSM_FINISH;
374 return SILC_FSM_CONTINUE;
377 /* Completes command reply processing */
379 SILC_FSM_STATE(silc_client_command_reply_processed)
381 SilcClientCommandContext cmd = fsm_context;
382 SilcClientConnection conn = cmd->conn;
383 SilcCommandPayload payload = state_context;
385 silc_command_payload_free(payload);
387 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
388 SILC_STATUS_IS_ERROR(cmd->status))
389 return SILC_FSM_FINISH;
391 /* Add back to pending command reply list */
392 silc_mutex_lock(conn->internal->lock);
393 cmd->resolved = FALSE;
394 silc_list_add(conn->internal->pending_commands, cmd);
395 silc_mutex_unlock(conn->internal->lock);
397 /** Wait more command payloads */
398 silc_fsm_next(fsm, silc_client_command_reply_wait);
399 return SILC_FSM_CONTINUE;
402 /******************************** WHOIS *************************************/
404 /* Received reply for WHOIS command. */
406 SILC_FSM_STATE(silc_client_command_reply_whois)
408 SilcClientCommandContext cmd = fsm_context;
409 SilcClientConnection conn = cmd->conn;
410 SilcClient client = conn->client;
411 SilcCommandPayload payload = state_context;
412 SilcArgumentPayload args = silc_command_get_args(payload);
413 SilcClientEntry client_entry = NULL;
414 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
415 SilcBufferStruct channels, ch_user_modes;
416 SilcBool has_channels = FALSE;
417 SilcDList channel_list = NULL;
419 char *nickname = NULL, *username = NULL, *realname = NULL;
420 unsigned char *fingerprint, *tmp;
422 CHECK_STATUS("WHOIS: ");
426 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
427 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
432 nickname = silc_argument_get_arg_type(args, 3, NULL);
433 username = silc_argument_get_arg_type(args, 4, NULL);
434 realname = silc_argument_get_arg_type(args, 5, NULL);
435 if (!nickname || !username || !realname) {
436 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
440 /* Get joined channel list */
441 memset(&channels, 0, sizeof(channels));
442 tmp = silc_argument_get_arg_type(args, 6, &len);
445 silc_buffer_set(&channels, tmp, len);
447 /* Get channel user mode list */
448 tmp = silc_argument_get_arg_type(args, 10, &len);
450 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
453 silc_buffer_set(&ch_user_modes, tmp, len);
457 tmp = silc_argument_get_arg_type(args, 7, &len);
459 SILC_GET32_MSB(mode, tmp);
462 tmp = silc_argument_get_arg_type(args, 8, &len);
464 SILC_GET32_MSB(idle, tmp);
466 /* Get fingerprint */
467 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
469 /* Check if we have this client cached already. */
470 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
472 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
474 silc_client_add_client(client, conn, nickname, username, realname,
475 &id.u.client_id, mode);
477 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
480 silc_client_ref_client(client, conn, client_entry);
482 silc_client_update_client(client, conn, client_entry,
483 nickname, username, realname, mode);
486 silc_rwlock_wrlock(client_entry->internal.lock);
488 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
489 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
491 /* Get user attributes */
492 tmp = silc_argument_get_arg_type(args, 11, &len);
494 if (client_entry->attrs)
495 silc_attribute_payload_list_free(client_entry->attrs);
496 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
499 silc_rwlock_unlock(client_entry->internal.lock);
501 /* Parse channel and channel user mode list */
503 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
504 silc_buffer_len(&channels));
506 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
510 /* Notify application */
511 silc_client_command_callback(cmd, client_entry, nickname, username,
512 realname, channel_list, mode, idle, fingerprint,
513 umodes, client_entry->attrs);
515 silc_client_unref_client(client, conn, client_entry);
517 silc_channel_payload_list_free(channel_list);
522 silc_fsm_next(fsm, silc_client_command_reply_processed);
523 return SILC_FSM_CONTINUE;
526 /******************************** WHOWAS ************************************/
528 /* Received reply for WHOWAS command. */
530 SILC_FSM_STATE(silc_client_command_reply_whowas)
532 SilcClientCommandContext cmd = fsm_context;
533 SilcClientConnection conn = cmd->conn;
534 SilcClient client = conn->client;
535 SilcCommandPayload payload = state_context;
536 SilcArgumentPayload args = silc_command_get_args(payload);
537 SilcClientEntry client_entry = NULL;
539 char *nickname, *username;
540 char *realname = NULL;
542 CHECK_STATUS("WHOWAS: ");
546 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
547 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
551 /* Get the client entry */
552 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
555 nickname = silc_argument_get_arg_type(args, 3, NULL);
556 username = silc_argument_get_arg_type(args, 4, NULL);
557 realname = silc_argument_get_arg_type(args, 5, NULL);
558 if (!nickname || !username) {
559 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
563 /* Notify application. We don't save any history information to any
564 cache. Just pass the data to the application. */
565 silc_client_command_callback(cmd, client_entry, nickname, username,
569 silc_client_unref_client(client, conn, client_entry);
570 silc_fsm_next(fsm, silc_client_command_reply_processed);
571 return SILC_FSM_CONTINUE;
574 /******************************** IDENTIFY **********************************/
576 /* Received reply for IDENTIFY command. */
578 SILC_FSM_STATE(silc_client_command_reply_identify)
580 SilcClientCommandContext cmd = fsm_context;
581 SilcClientConnection conn = cmd->conn;
582 SilcClient client = conn->client;
583 SilcCommandPayload payload = state_context;
584 SilcArgumentPayload args = silc_command_get_args(payload);
585 SilcClientEntry client_entry;
586 SilcServerEntry server_entry;
587 SilcChannelEntry channel_entry;
590 char *name = NULL, *info = NULL;
592 CHECK_STATUS("IDENTIFY: ");
596 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
597 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
602 name = silc_argument_get_arg_type(args, 3, &len);
603 info = silc_argument_get_arg_type(args, 4, &len);
607 SILC_LOG_DEBUG(("Received client information"));
609 /* Check if we have this client cached already. */
610 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
612 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
614 silc_client_add_client(client, conn, name, info, NULL,
617 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
620 silc_client_ref_client(client, conn, client_entry);
622 silc_client_update_client(client, conn, client_entry,
623 name, info, NULL, 0);
626 /* Notify application */
627 silc_client_command_callback(cmd, client_entry, name, info);
628 silc_client_unref_client(client, conn, client_entry);
632 SILC_LOG_DEBUG(("Received server information"));
634 /* Check if we have this server cached already. */
635 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
637 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
638 server_entry = silc_client_add_server(client, conn, name, info,
641 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
644 silc_client_ref_server(client, conn, server_entry);
646 silc_client_update_server(client, conn, server_entry, name, info);
648 server_entry->internal.resolve_cmd_ident = 0;
650 /* Notify application */
651 silc_client_command_callback(cmd, server_entry, name, info);
652 silc_client_unref_server(client, conn, server_entry);
655 case SILC_ID_CHANNEL:
656 SILC_LOG_DEBUG(("Received channel information"));
658 /* Check if we have this channel cached already. */
659 channel_entry = silc_client_get_channel_by_id(client, conn,
661 if (!channel_entry) {
662 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
665 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
669 /* Add new channel entry */
670 channel_entry = silc_client_add_channel(client, conn, name, 0,
672 if (!channel_entry) {
673 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
676 silc_client_ref_channel(client, conn, channel_entry);
679 /* Notify application */
680 silc_client_command_callback(cmd, channel_entry, name, info);
681 silc_client_unref_channel(client, conn, channel_entry);
686 silc_fsm_next(fsm, silc_client_command_reply_processed);
687 return SILC_FSM_CONTINUE;
690 /********************************** NICK ************************************/
692 /* Received reply for command NICK. */
694 SILC_FSM_STATE(silc_client_command_reply_nick)
696 SilcClientCommandContext cmd = fsm_context;
697 SilcClientConnection conn = cmd->conn;
698 SilcClient client = conn->client;
699 SilcCommandPayload payload = state_context;
700 SilcArgumentPayload args = silc_command_get_args(payload);
701 unsigned char *nick, *idp;
702 SilcUInt32 len, idp_len;
703 SilcClientID old_client_id;
707 CHECK_STATUS("Cannot set nickname: ");
710 /* Take received Client ID */
711 idp = silc_argument_get_arg_type(args, 2, &idp_len);
713 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
716 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
717 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
721 /* Take the new nickname */
722 nick = silc_argument_get_arg_type(args, 3, &len);
724 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
728 silc_rwlock_wrlock(conn->local_entry->internal.lock);
730 /* Change the nickname */
731 old_client_id = *conn->local_id;
732 if (!silc_client_change_nickname(client, conn, conn->local_entry,
733 nick, &id.u.client_id, idp, idp_len)) {
734 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
738 silc_rwlock_unlock(conn->local_entry->internal.lock);
740 /* Notify application */
741 silc_client_command_callback(cmd, conn->local_entry,
742 conn->local_entry->nickname, &old_client_id);
745 silc_fsm_next(fsm, silc_client_command_reply_processed);
746 return SILC_FSM_CONTINUE;
749 /********************************** LIST ************************************/
751 /* Received reply to the LIST command. */
753 SILC_FSM_STATE(silc_client_command_reply_list)
755 SilcClientCommandContext cmd = fsm_context;
756 SilcClientConnection conn = cmd->conn;
757 SilcClient client = conn->client;
758 SilcCommandPayload payload = state_context;
759 SilcArgumentPayload args = silc_command_get_args(payload);
760 unsigned char *tmp, *name, *topic;
761 SilcUInt32 usercount = 0;
762 SilcChannelEntry channel_entry = NULL;
766 CHECK_STATUS("Cannot list channels: ");
768 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
769 /* There were no channels in the network. */
770 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
771 silc_fsm_next(fsm, silc_client_command_reply_processed);
772 return SILC_FSM_CONTINUE;
777 name = silc_argument_get_arg_type(args, 3, NULL);
779 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
783 topic = silc_argument_get_arg_type(args, 4, NULL);
784 tmp = silc_argument_get_arg_type(args, 5, NULL);
786 SILC_GET32_MSB(usercount, tmp);
788 /* Check whether the channel exists, and add it to cache if it doesn't. */
789 channel_entry = silc_client_get_channel_by_id(client, conn,
791 if (!channel_entry) {
792 /* Add new channel entry */
793 channel_entry = silc_client_add_channel(client, conn, name, 0,
795 if (!channel_entry) {
796 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
799 silc_client_ref_channel(client, conn, channel_entry);
802 /* Notify application */
803 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
806 silc_client_unref_channel(client, conn, channel_entry);
807 silc_fsm_next(fsm, silc_client_command_reply_processed);
808 return SILC_FSM_CONTINUE;
811 /********************************* TOPIC ************************************/
813 /* Received reply to topic command. */
815 SILC_FSM_STATE(silc_client_command_reply_topic)
817 SilcClientCommandContext cmd = fsm_context;
818 SilcClientConnection conn = cmd->conn;
819 SilcClient client = conn->client;
820 SilcCommandPayload payload = state_context;
821 SilcArgumentPayload args = silc_command_get_args(payload);
822 SilcChannelEntry channel;
828 CHECK_STATUS("Cannot set topic: ");
831 /* Take Channel ID */
832 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
833 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
837 /* Get the channel entry */
838 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
840 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
844 silc_rwlock_wrlock(channel->internal.lock);
847 topic = silc_argument_get_arg_type(args, 3, &len);
849 silc_free(channel->topic);
850 channel->topic = silc_memdup(topic, len);
853 silc_rwlock_unlock(channel->internal.lock);
855 /* Notify application */
856 silc_client_command_callback(cmd, channel, channel->topic);
859 silc_fsm_next(fsm, silc_client_command_reply_processed);
860 return SILC_FSM_CONTINUE;
863 /********************************* INVITE ***********************************/
865 /* Received reply to invite command. */
867 SILC_FSM_STATE(silc_client_command_reply_invite)
869 SilcClientCommandContext cmd = fsm_context;
870 SilcClientConnection conn = cmd->conn;
871 SilcClient client = conn->client;
872 SilcCommandPayload payload = state_context;
873 SilcArgumentPayload args = silc_command_get_args(payload);
874 SilcChannelEntry channel;
877 SilcArgumentPayload invite_args = NULL;
881 CHECK_STATUS("Cannot invite: ");
884 /* Take Channel ID */
885 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
886 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
890 /* Get the channel entry */
891 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
893 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
897 /* Get the invite list */
898 tmp = silc_argument_get_arg_type(args, 3, &len);
900 invite_args = silc_argument_list_parse(tmp, len);
902 /* Notify application */
903 silc_client_command_callback(cmd, channel, invite_args);
906 silc_argument_payload_free(invite_args);
909 silc_fsm_next(fsm, silc_client_command_reply_processed);
910 return SILC_FSM_CONTINUE;
913 /********************************** KILL ************************************/
915 /* Received reply to the KILL command. */
917 SILC_FSM_STATE(silc_client_command_reply_kill)
919 SilcClientCommandContext cmd = fsm_context;
920 SilcClientConnection conn = cmd->conn;
921 SilcClient client = conn->client;
922 SilcCommandPayload payload = state_context;
923 SilcArgumentPayload args = silc_command_get_args(payload);
924 SilcClientEntry client_entry;
928 CHECK_STATUS("Cannot kill: ");
931 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
932 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
936 /* Get the client entry, if exists */
937 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
939 /* Notify application */
940 silc_client_command_callback(cmd, client_entry);
942 /* Remove the client */
944 silc_client_remove_from_channels(client, conn, client_entry);
945 silc_client_del_client(client, conn, client_entry);
946 silc_client_unref_client(client, conn, client_entry);
950 silc_fsm_next(fsm, silc_client_command_reply_processed);
951 return SILC_FSM_CONTINUE;
954 /********************************** INFO ************************************/
956 /* Received reply to INFO command. We receive the server ID and some
957 information about the server user requested. */
959 SILC_FSM_STATE(silc_client_command_reply_info)
961 SilcClientCommandContext cmd = fsm_context;
962 SilcClientConnection conn = cmd->conn;
963 SilcClient client = conn->client;
964 SilcCommandPayload payload = state_context;
965 SilcArgumentPayload args = silc_command_get_args(payload);
966 SilcServerEntry server;
967 char *server_name, *server_info;
971 CHECK_STATUS("Cannot get info: ");
975 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
976 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
980 /* Get server name */
981 server_name = silc_argument_get_arg_type(args, 3, NULL);
983 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
987 /* Get server info */
988 server_info = silc_argument_get_arg_type(args, 4, NULL);
990 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
994 /* See whether we have this server cached. If not create it. */
995 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
997 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
998 server = silc_client_add_server(client, conn, server_name,
999 server_info, &id.u.server_id);
1002 silc_client_ref_server(client, conn, server);
1005 /* Notify application */
1006 silc_client_command_callback(cmd, server, server->server_name,
1007 server->server_info);
1008 silc_client_unref_server(client, conn, server);
1011 silc_fsm_next(fsm, silc_client_command_reply_processed);
1012 return SILC_FSM_CONTINUE;
1015 /********************************** STATS ***********************************/
1017 /* Received reply to STATS command. */
1019 SILC_FSM_STATE(silc_client_command_reply_stats)
1021 SilcClientCommandContext cmd = fsm_context;
1022 SilcCommandPayload payload = state_context;
1023 SilcArgumentPayload args = silc_command_get_args(payload);
1024 SilcClientStats stats;
1025 unsigned char *buf = NULL;
1026 SilcUInt32 buf_len = 0;
1031 CHECK_STATUS("Cannot get stats: ");
1035 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1036 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1040 /* Get statistics structure */
1041 memset(&stats, 0, sizeof(stats));
1042 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1044 silc_buffer_set(&b, buf, buf_len);
1045 silc_buffer_unformat(&b,
1046 SILC_STR_UI_INT(&stats.starttime),
1047 SILC_STR_UI_INT(&stats.uptime),
1048 SILC_STR_UI_INT(&stats.my_clients),
1049 SILC_STR_UI_INT(&stats.my_channels),
1050 SILC_STR_UI_INT(&stats.my_server_ops),
1051 SILC_STR_UI_INT(&stats.my_router_ops),
1052 SILC_STR_UI_INT(&stats.cell_clients),
1053 SILC_STR_UI_INT(&stats.cell_channels),
1054 SILC_STR_UI_INT(&stats.cell_servers),
1055 SILC_STR_UI_INT(&stats.clients),
1056 SILC_STR_UI_INT(&stats.channels),
1057 SILC_STR_UI_INT(&stats.servers),
1058 SILC_STR_UI_INT(&stats.routers),
1059 SILC_STR_UI_INT(&stats.server_ops),
1060 SILC_STR_UI_INT(&stats.router_ops),
1064 /* Notify application */
1065 silc_client_command_callback(cmd, &stats);
1068 silc_fsm_next(fsm, silc_client_command_reply_processed);
1069 return SILC_FSM_CONTINUE;
1072 /********************************** PING ************************************/
1074 /* Received reply to PING command. */
1076 SILC_FSM_STATE(silc_client_command_reply_ping)
1078 SilcClientCommandContext cmd = fsm_context;
1079 SilcClientConnection conn = cmd->conn;
1080 SilcClient client = conn->client;
1083 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1085 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1086 "Ping reply from %s: %d second%s", conn->remote_host,
1087 (int)diff, diff == 1 ? "" : "s");
1089 /* Notify application */
1090 silc_client_command_callback(cmd);
1092 silc_fsm_next(fsm, silc_client_command_reply_processed);
1093 return SILC_FSM_CONTINUE;
1096 /********************************** JOIN ************************************/
1098 /* Continue JOIN command reply processing after resolving unknown users */
1101 silc_client_command_reply_join_resolved(SilcClient client,
1102 SilcClientConnection conn,
1107 SilcClientCommandContext cmd = context;
1108 SilcChannelEntry channel = cmd->context;
1110 channel->internal.resolve_cmd_ident = 0;
1111 silc_client_unref_channel(client, conn, channel);
1113 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1117 /* Received reply for JOIN command. */
1119 SILC_FSM_STATE(silc_client_command_reply_join)
1121 SilcClientCommandContext cmd = fsm_context;
1122 SilcClientConnection conn = cmd->conn;
1123 SilcClient client = conn->client;
1124 SilcCommandPayload payload = state_context;
1125 SilcArgumentPayload args = silc_command_get_args(payload);
1126 SilcChannelEntry channel;
1127 SilcUInt32 mode = 0, len, list_count;
1128 char *topic, *tmp, *channel_name = NULL, *hmac;
1130 SilcBufferStruct client_id_list, client_mode_list, keyp;
1131 SilcHashTableList htl;
1136 CHECK_STATUS("Cannot join channel: ");
1139 /* Get channel name */
1140 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1141 if (!channel_name) {
1142 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1146 /* Get Channel ID */
1147 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1148 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1152 /* Check whether we have this channel entry already. */
1153 channel = silc_client_get_channel(client, conn, channel_name);
1155 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1156 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1158 /* Create new channel entry */
1159 channel = silc_client_add_channel(client, conn, channel_name,
1160 mode, &id.u.channel_id);
1162 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1165 silc_client_ref_channel(client, conn, channel);
1168 /* Get the list count */
1169 tmp = silc_argument_get_arg_type(args, 12, &len);
1171 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1174 SILC_GET32_MSB(list_count, tmp);
1176 /* Get Client ID list */
1177 tmp = silc_argument_get_arg_type(args, 13, &len);
1179 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1182 silc_buffer_set(&client_id_list, tmp, len);
1184 /* Resolve users we do not know about */
1185 if (!cmd->resolved) {
1186 cmd->resolved = TRUE;
1187 cmd->context = channel;
1188 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1189 silc_client_get_clients_by_list(
1190 client, conn, list_count, &client_id_list,
1191 silc_client_command_reply_join_resolved, cmd));
1195 /* Get client mode list */
1196 tmp = silc_argument_get_arg_type(args, 14, &len);
1198 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1201 silc_buffer_set(&client_mode_list, tmp, len);
1203 silc_rwlock_wrlock(channel->internal.lock);
1205 /* Add clients we received in the reply to the channel */
1206 for (i = 0; i < list_count; i++) {
1210 SilcClientEntry client_entry;
1213 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1215 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1219 SILC_GET32_MSB(mode, client_mode_list.data);
1221 /* Get client entry */
1222 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1223 if (client_entry && client_entry->internal.valid) {
1224 /* Join client to the channel */
1225 silc_rwlock_wrlock(client_entry->internal.lock);
1226 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1227 silc_rwlock_unlock(client_entry->internal.lock);
1229 silc_client_unref_client(client, conn, client_entry);
1231 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1232 silc_rwlock_unlock(channel->internal.lock);
1235 if (!silc_buffer_pull(&client_mode_list, 4)) {
1236 silc_rwlock_unlock(channel->internal.lock);
1242 hmac = silc_argument_get_arg_type(args, 11, NULL);
1244 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1246 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1247 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1248 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1249 silc_rwlock_unlock(channel->internal.lock);
1254 /* Get channel mode */
1255 tmp = silc_argument_get_arg_type(args, 5, &len);
1256 if (tmp && len == 4)
1257 SILC_GET32_MSB(mode, tmp);
1258 channel->mode = mode;
1260 /* Get channel key and save it */
1261 tmp = silc_argument_get_arg_type(args, 7, &len);
1263 silc_buffer_set(&keyp, tmp, len);
1264 silc_client_save_channel_key(client, conn, &keyp, channel);
1268 topic = silc_argument_get_arg_type(args, 10, NULL);
1270 silc_free(channel->topic);
1271 channel->topic = silc_memdup(topic, strlen(topic));
1274 /* Get founder key */
1275 tmp = silc_argument_get_arg_type(args, 15, &len);
1277 if (channel->founder_key)
1278 silc_pkcs_public_key_free(channel->founder_key);
1279 channel->founder_key = NULL;
1280 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1283 /* Get user limit */
1284 tmp = silc_argument_get_arg_type(args, 17, &len);
1285 if (tmp && len == 4)
1286 SILC_GET32_MSB(channel->user_limit, tmp);
1287 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1288 channel->user_limit = 0;
1290 /* Get channel public key list */
1291 tmp = silc_argument_get_arg_type(args, 16, &len);
1293 silc_client_channel_save_public_keys(channel, tmp, len);
1295 /* Set current channel */
1296 conn->current_channel = channel;
1298 silc_rwlock_unlock(channel->internal.lock);
1300 cipher = (channel->internal.send_key ?
1301 silc_cipher_get_name(channel->internal.send_key) : NULL);
1302 silc_hash_table_list(channel->user_list, &htl);
1304 /* Notify application */
1305 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1306 topic, cipher, hmac, channel->founder_key,
1307 channel->channel_pubkeys, channel->user_limit);
1309 silc_hash_table_list_reset(&htl);
1310 silc_client_unref_channel(client, conn, channel);
1313 silc_fsm_next(fsm, silc_client_command_reply_processed);
1314 return SILC_FSM_CONTINUE;
1317 /********************************** MOTD ************************************/
1319 /* Received reply for MOTD command */
1321 SILC_FSM_STATE(silc_client_command_reply_motd)
1323 SilcClientCommandContext cmd = fsm_context;
1324 SilcClientConnection conn = cmd->conn;
1325 SilcClient client = conn->client;
1326 SilcCommandPayload payload = state_context;
1327 SilcArgumentPayload args = silc_command_get_args(payload);
1329 char *motd = NULL, *cp, line[256];
1332 CHECK_STATUS("Cannot get motd: ");
1335 if (silc_argument_get_arg_num(args) == 3) {
1336 motd = silc_argument_get_arg_type(args, 3, NULL);
1338 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1345 if (cp[i++] == '\n') {
1346 memset(line, 0, sizeof(line));
1347 silc_strncat(line, sizeof(line), cp, i - 1);
1354 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1363 /* Notify application */
1364 silc_client_command_callback(cmd, motd);
1367 silc_fsm_next(fsm, silc_client_command_reply_processed);
1368 return SILC_FSM_CONTINUE;
1371 /********************************** UMODE ***********************************/
1373 /* Received reply to the UMODE command. Save the current user mode */
1375 SILC_FSM_STATE(silc_client_command_reply_umode)
1377 SilcClientCommandContext cmd = fsm_context;
1378 SilcClientConnection conn = cmd->conn;
1379 SilcCommandPayload payload = state_context;
1380 SilcArgumentPayload args = silc_command_get_args(payload);
1382 SilcUInt32 mode, len;
1385 CHECK_STATUS("Cannot change mode: ");
1388 tmp = silc_argument_get_arg_type(args, 2, &len);
1389 if (!tmp || len != 4) {
1390 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1394 SILC_GET32_MSB(mode, tmp);
1395 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1396 conn->local_entry->mode = mode;
1397 silc_rwlock_unlock(conn->local_entry->internal.lock);
1399 /* Notify application */
1400 silc_client_command_callback(cmd, mode);
1403 silc_fsm_next(fsm, silc_client_command_reply_processed);
1404 return SILC_FSM_CONTINUE;
1407 /********************************** CMODE ***********************************/
1409 /* Received reply for CMODE command. */
1411 SILC_FSM_STATE(silc_client_command_reply_cmode)
1413 SilcClientCommandContext cmd = fsm_context;
1414 SilcClientConnection conn = cmd->conn;
1415 SilcClient client = conn->client;
1416 SilcCommandPayload payload = state_context;
1417 SilcArgumentPayload args = silc_command_get_args(payload);
1420 SilcChannelEntry channel;
1422 SilcPublicKey public_key = NULL;
1423 SilcDList channel_pubkeys = NULL;
1427 CHECK_STATUS("Cannot change mode: ");
1430 /* Take Channel ID */
1431 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1432 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1436 /* Get the channel entry */
1437 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1439 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1443 /* Get founder public key */
1444 tmp = silc_argument_get_arg_type(args, 4, &len);
1446 silc_public_key_payload_decode(tmp, len, &public_key);
1448 /* Get channel mode */
1449 tmp = silc_argument_get_arg_type(args, 3, &len);
1450 if (!tmp || len != 4) {
1451 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1455 silc_rwlock_wrlock(channel->internal.lock);
1458 SILC_GET32_MSB(mode, tmp);
1459 channel->mode = mode;
1461 /* Get user limit */
1462 tmp = silc_argument_get_arg_type(args, 6, &len);
1463 if (tmp && len == 4)
1464 SILC_GET32_MSB(channel->user_limit, tmp);
1465 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1466 channel->user_limit = 0;
1468 /* Get channel public key(s) */
1469 tmp = silc_argument_get_arg_type(args, 5, &len);
1471 silc_client_channel_save_public_keys(channel, tmp, len);
1473 silc_rwlock_unlock(channel->internal.lock);
1475 /* Notify application */
1476 silc_client_command_callback(cmd, channel, mode, public_key,
1477 channel_pubkeys, channel->user_limit);
1479 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1483 silc_pkcs_public_key_free(public_key);
1484 silc_fsm_next(fsm, silc_client_command_reply_processed);
1485 return SILC_FSM_CONTINUE;
1488 /********************************** CUMODE **********************************/
1490 /* Received reply for CUMODE command */
1492 SILC_FSM_STATE(silc_client_command_reply_cumode)
1494 SilcClientCommandContext cmd = fsm_context;
1495 SilcClientConnection conn = cmd->conn;
1496 SilcClient client = conn->client;
1497 SilcCommandPayload payload = state_context;
1498 SilcArgumentPayload args = silc_command_get_args(payload);
1499 SilcClientEntry client_entry;
1500 SilcChannelEntry channel;
1501 SilcChannelUser chu;
1502 unsigned char *modev;
1503 SilcUInt32 len, mode;
1507 CHECK_STATUS("Cannot change mode: ");
1510 /* Get channel mode */
1511 modev = silc_argument_get_arg_type(args, 2, &len);
1512 if (!modev || len != 4) {
1513 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1516 SILC_GET32_MSB(mode, modev);
1518 /* Take Channel ID */
1519 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1520 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1524 /* Get the channel entry */
1525 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1527 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1532 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1533 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1537 /* Get client entry */
1538 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1539 if (!client_entry) {
1540 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1545 silc_rwlock_wrlock(channel->internal.lock);
1546 chu = silc_client_on_channel(channel, client_entry);
1549 silc_rwlock_unlock(channel->internal.lock);
1551 /* Notify application */
1552 silc_client_command_callback(cmd, mode, channel, client_entry);
1554 silc_client_unref_client(client, conn, client_entry);
1557 silc_fsm_next(fsm, silc_client_command_reply_processed);
1558 return SILC_FSM_CONTINUE;
1561 /********************************** KICK ************************************/
1563 SILC_FSM_STATE(silc_client_command_reply_kick)
1565 SilcClientCommandContext cmd = fsm_context;
1566 SilcClientConnection conn = cmd->conn;
1567 SilcClient client = conn->client;
1568 SilcCommandPayload payload = state_context;
1569 SilcArgumentPayload args = silc_command_get_args(payload);
1570 SilcClientEntry client_entry;
1571 SilcChannelEntry channel;
1575 CHECK_STATUS("Cannot kick: ");
1578 /* Take Channel ID */
1579 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1580 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1584 /* Get the channel entry */
1585 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1587 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1592 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1593 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1597 /* Get client entry */
1598 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1599 if (!client_entry) {
1600 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1604 /* Notify application */
1605 silc_client_command_callback(cmd, channel, client_entry);
1607 silc_client_unref_client(client, conn, client_entry);
1610 silc_fsm_next(fsm, silc_client_command_reply_processed);
1611 return SILC_FSM_CONTINUE;
1614 /******************************** SILCOPER **********************************/
1616 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1618 SilcClientCommandContext cmd = fsm_context;
1619 SilcCommandPayload payload = state_context;
1620 SilcArgumentPayload args = silc_command_get_args(payload);
1623 CHECK_STATUS("Cannot change mode: ");
1627 cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1629 /* Notify application */
1630 silc_client_command_callback(cmd);
1632 silc_fsm_next(fsm, silc_client_command_reply_processed);
1633 return SILC_FSM_CONTINUE;
1636 /********************************** OPER ************************************/
1638 SILC_FSM_STATE(silc_client_command_reply_oper)
1640 SilcClientCommandContext cmd = fsm_context;
1641 SilcCommandPayload payload = state_context;
1642 SilcArgumentPayload args = silc_command_get_args(payload);
1645 CHECK_STATUS("Cannot change mode: ");
1649 cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1651 /* Notify application */
1652 silc_client_command_callback(cmd);
1654 silc_fsm_next(fsm, silc_client_command_reply_processed);
1655 return SILC_FSM_CONTINUE;
1658 /********************************* DETACH ***********************************/
1660 SILC_FSM_STATE(silc_client_command_reply_detach)
1662 SilcClientCommandContext cmd = fsm_context;
1663 SilcClientConnection conn = cmd->conn;
1664 SilcClient client = conn->client;
1665 SilcCommandPayload payload = state_context;
1666 SilcArgumentPayload args = silc_command_get_args(payload);
1670 CHECK_STATUS("Cannot detach: ");
1673 /* Get detachment data */
1674 detach = silc_client_get_detach_data(client, conn);
1676 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1680 /* Notify application */
1681 silc_client_command_callback(cmd, detach);
1682 silc_buffer_free(detach);
1685 silc_fsm_next(fsm, silc_client_command_reply_processed);
1686 return SILC_FSM_CONTINUE;
1689 /********************************** WATCH ***********************************/
1691 SILC_FSM_STATE(silc_client_command_reply_watch)
1693 SilcClientCommandContext cmd = fsm_context;
1694 SilcCommandPayload payload = state_context;
1695 SilcArgumentPayload args = silc_command_get_args(payload);
1698 CHECK_STATUS("Cannot set watch: ");
1701 /* Notify application */
1702 silc_client_command_callback(cmd);
1704 silc_fsm_next(fsm, silc_client_command_reply_processed);
1705 return SILC_FSM_CONTINUE;
1708 /*********************************** BAN ************************************/
1710 SILC_FSM_STATE(silc_client_command_reply_ban)
1712 SilcClientCommandContext cmd = fsm_context;
1713 SilcClientConnection conn = cmd->conn;
1714 SilcClient client = conn->client;
1715 SilcCommandPayload payload = state_context;
1716 SilcArgumentPayload args = silc_command_get_args(payload);
1717 SilcChannelEntry channel;
1720 SilcArgumentPayload invite_args = NULL;
1724 CHECK_STATUS("Cannot set ban: ");
1727 /* Take Channel ID */
1728 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1729 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1733 /* Get the channel entry */
1734 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1736 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1740 /* Get the invite list */
1741 tmp = silc_argument_get_arg_type(args, 3, &len);
1743 invite_args = silc_argument_list_parse(tmp, len);
1745 /* Notify application */
1746 silc_client_command_callback(cmd, channel, invite_args);
1749 silc_argument_payload_free(invite_args);
1752 silc_fsm_next(fsm, silc_client_command_reply_processed);
1753 return SILC_FSM_CONTINUE;
1756 /********************************** LEAVE ***********************************/
1758 /* Reply to LEAVE command. */
1760 SILC_FSM_STATE(silc_client_command_reply_leave)
1762 SilcClientCommandContext cmd = fsm_context;
1763 SilcClientConnection conn = cmd->conn;
1764 SilcClient client = conn->client;
1765 SilcCommandPayload payload = state_context;
1766 SilcArgumentPayload args = silc_command_get_args(payload);
1767 SilcChannelEntry channel;
1771 CHECK_STATUS("Cannot set leave: ");
1774 /* Get Channel ID */
1775 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1776 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1780 /* Get the channel entry */
1781 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1783 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1787 /* Remove us from this channel. */
1788 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1790 /* Notify application */
1791 silc_client_command_callback(cmd, channel);
1793 /* Now delete the channel. */
1794 silc_client_empty_channel(client, conn, channel);
1795 silc_client_del_channel(client, conn, channel);
1798 silc_fsm_next(fsm, silc_client_command_reply_processed);
1799 return SILC_FSM_CONTINUE;
1802 /********************************* USERS ************************************/
1804 /* Continue USERS command reply processing after resolving unknown users */
1807 silc_client_command_reply_users_resolved(SilcClient client,
1808 SilcClientConnection conn,
1813 SilcClientCommandContext cmd = context;
1814 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1818 /* Continue USERS command after resolving unknown channel */
1821 silc_client_command_reply_users_continue(SilcClient client,
1822 SilcClientConnection conn,
1827 SilcClientCommandContext cmd = context;
1830 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1831 SilcArgumentPayload args = silc_command_get_args(payload);
1833 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1834 ERROR_CALLBACK(cmd->status);
1835 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1838 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1841 /* Reply to USERS command. Received list of client ID's and theirs modes
1842 on the channel we requested. */
1844 SILC_FSM_STATE(silc_client_command_reply_users)
1846 SilcClientCommandContext cmd = fsm_context;
1847 SilcClientConnection conn = cmd->conn;
1848 SilcClient client = conn->client;
1849 SilcCommandPayload payload = state_context;
1850 SilcArgumentPayload args = silc_command_get_args(payload);
1852 SilcUInt32 tmp_len, list_count;
1853 SilcUInt16 idp_len, mode;
1854 SilcHashTableList htl;
1855 SilcBufferStruct client_id_list, client_mode_list;
1856 SilcChannelEntry channel = NULL;
1857 SilcClientEntry client_entry;
1862 CHECK_STATUS("Cannot get users: ");
1865 /* Get channel ID */
1866 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1867 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1871 /* Get channel entry */
1872 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1874 /* Resolve the channel from server */
1875 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1876 client, conn, &id.u.channel_id,
1877 silc_client_command_reply_users_continue, cmd));
1881 /* Get the list count */
1882 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1883 if (!tmp || tmp_len != 4) {
1884 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1887 SILC_GET32_MSB(list_count, tmp);
1889 /* Get Client ID list */
1890 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1892 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1895 silc_buffer_set(&client_id_list, tmp, tmp_len);
1897 /* Resolve users we do not know about */
1898 if (!cmd->resolved) {
1899 cmd->resolved = TRUE;
1900 silc_client_unref_channel(client, conn, channel);
1901 SILC_FSM_CALL(silc_client_get_clients_by_list(
1902 client, conn, list_count, &client_id_list,
1903 silc_client_command_reply_users_resolved, cmd));
1907 /* Get client mode list */
1908 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1910 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1913 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1915 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1917 silc_rwlock_wrlock(channel->internal.lock);
1919 /* Cache the received Client ID's and modes. */
1920 for (i = 0; i < list_count; i++) {
1921 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1923 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1927 SILC_GET32_MSB(mode, client_mode_list.data);
1929 /* Save the client on this channel. Unknown clients are ignored as they
1930 clearly do not exist since the resolving didn't find them. */
1931 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1932 if (client_entry && client_entry->internal.valid) {
1933 silc_rwlock_wrlock(client_entry->internal.lock);
1934 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1935 silc_rwlock_unlock(client_entry->internal.lock);
1937 silc_client_unref_client(client, conn, client_entry);
1939 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1940 silc_rwlock_unlock(channel->internal.lock);
1943 if (!silc_buffer_pull(&client_mode_list, 4)) {
1944 silc_rwlock_unlock(channel->internal.lock);
1949 /* Notify application */
1950 silc_hash_table_list(channel->user_list, &htl);
1951 silc_client_command_callback(cmd, channel, &htl);
1952 silc_hash_table_list_reset(&htl);
1955 silc_client_unref_channel(client, conn, channel);
1956 silc_fsm_next(fsm, silc_client_command_reply_processed);
1957 return SILC_FSM_CONTINUE;
1960 /********************************** GETKEY **********************************/
1962 /* Received command reply to GETKEY command. WE've received the remote
1963 client's public key. */
1965 SILC_FSM_STATE(silc_client_command_reply_getkey)
1967 SilcClientCommandContext cmd = fsm_context;
1968 SilcClientConnection conn = cmd->conn;
1969 SilcClient client = conn->client;
1970 SilcCommandPayload payload = state_context;
1971 SilcArgumentPayload args = silc_command_get_args(payload);
1972 SilcClientEntry client_entry;
1973 SilcServerEntry server_entry;
1976 SilcPublicKey public_key;
1980 CHECK_STATUS("Cannot get key: ");
1984 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1985 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1989 /* Get the public key */
1990 tmp = silc_argument_get_arg_type(args, 3, &len);
1992 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1995 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1996 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2000 if (id.type == SILC_ID_CLIENT) {
2001 /* Received client's public key */
2002 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2003 if (!client_entry) {
2004 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2008 silc_rwlock_wrlock(client_entry->internal.lock);
2010 /* Save fingerprint */
2011 if (!client_entry->fingerprint)
2012 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2013 client_entry->fingerprint);
2014 if (!client_entry->public_key) {
2015 client_entry->public_key = public_key;
2019 silc_rwlock_unlock(client_entry->internal.lock);
2021 /* Notify application */
2022 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2023 client_entry->public_key);
2024 silc_client_unref_client(client, conn, client_entry);
2025 } else if (id.type == SILC_ID_SERVER) {
2026 /* Received server's public key */
2027 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2028 if (!server_entry) {
2029 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2033 silc_rwlock_wrlock(server_entry->internal.lock);
2035 if (!server_entry->public_key) {
2036 server_entry->public_key = public_key;
2040 silc_rwlock_unlock(server_entry->internal.lock);
2042 /* Notify application */
2043 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2044 server_entry->public_key);
2045 silc_client_unref_server(client, conn, server_entry);
2050 silc_pkcs_public_key_free(public_key);
2051 silc_fsm_next(fsm, silc_client_command_reply_processed);
2052 return SILC_FSM_CONTINUE;
2055 /********************************** SERVICE *********************************/
2057 /* Reply to SERVICE command. */
2058 /* XXX incomplete */
2060 SILC_FSM_STATE(silc_client_command_reply_service)
2062 SilcClientCommandContext cmd = fsm_context;
2063 SilcCommandPayload payload = state_context;
2064 SilcArgumentPayload args = silc_command_get_args(payload);
2066 unsigned char *service_list, *name;
2069 CHECK_STATUS("Cannot get service: ");
2071 /* Get service list */
2072 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2074 /* Get requested service name */
2075 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2077 /* Notify application */
2078 silc_client_command_callback(cmd, service_list, name);
2080 silc_fsm_next(fsm, silc_client_command_reply_processed);
2081 return SILC_FSM_CONTINUE;
2084 /*********************************** QUIT ***********************************/
2086 /* QUIT command reply stub */
2088 SILC_FSM_STATE(silc_client_command_reply_quit)
2090 silc_fsm_next(fsm, silc_client_command_reply_processed);
2091 return SILC_FSM_CONTINUE;