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 ? 40 : 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, FALSE);
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;
1426 CHECK_STATUS("Cannot change mode: ");
1429 /* Take Channel ID */
1430 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1431 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1435 /* Get the channel entry */
1436 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1438 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1442 /* Get founder public key */
1443 tmp = silc_argument_get_arg_type(args, 4, &len);
1445 silc_public_key_payload_decode(tmp, len, &public_key);
1447 /* Get channel mode */
1448 tmp = silc_argument_get_arg_type(args, 3, &len);
1449 if (!tmp || len != 4) {
1450 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1453 SILC_GET32_MSB(mode, tmp);
1455 silc_rwlock_wrlock(channel->internal.lock);
1457 /* Get user limit */
1458 tmp = silc_argument_get_arg_type(args, 6, &len);
1459 if (tmp && len == 4)
1460 SILC_GET32_MSB(channel->user_limit, tmp);
1461 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1462 channel->user_limit = 0;
1464 /* Get channel public key(s) */
1465 tmp = silc_argument_get_arg_type(args, 5, &len);
1467 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1468 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
1469 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
1472 channel->mode = mode;
1474 silc_rwlock_unlock(channel->internal.lock);
1476 /* Notify application */
1477 silc_client_command_callback(cmd, channel, mode, public_key,
1478 channel->channel_pubkeys, channel->user_limit);
1482 silc_pkcs_public_key_free(public_key);
1483 silc_fsm_next(fsm, silc_client_command_reply_processed);
1484 return SILC_FSM_CONTINUE;
1487 /********************************** CUMODE **********************************/
1489 /* Received reply for CUMODE command */
1491 SILC_FSM_STATE(silc_client_command_reply_cumode)
1493 SilcClientCommandContext cmd = fsm_context;
1494 SilcClientConnection conn = cmd->conn;
1495 SilcClient client = conn->client;
1496 SilcCommandPayload payload = state_context;
1497 SilcArgumentPayload args = silc_command_get_args(payload);
1498 SilcClientEntry client_entry;
1499 SilcChannelEntry channel;
1500 SilcChannelUser chu;
1501 unsigned char *modev;
1502 SilcUInt32 len, mode;
1506 CHECK_STATUS("Cannot change mode: ");
1509 /* Get channel mode */
1510 modev = silc_argument_get_arg_type(args, 2, &len);
1511 if (!modev || len != 4) {
1512 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1515 SILC_GET32_MSB(mode, modev);
1517 /* Take Channel ID */
1518 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1519 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1523 /* Get the channel entry */
1524 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1526 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1531 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1532 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1536 /* Get client entry */
1537 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1538 if (!client_entry) {
1539 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1544 silc_rwlock_wrlock(channel->internal.lock);
1545 chu = silc_client_on_channel(channel, client_entry);
1548 silc_rwlock_unlock(channel->internal.lock);
1550 /* Notify application */
1551 silc_client_command_callback(cmd, mode, channel, client_entry);
1553 silc_client_unref_client(client, conn, client_entry);
1556 silc_fsm_next(fsm, silc_client_command_reply_processed);
1557 return SILC_FSM_CONTINUE;
1560 /********************************** KICK ************************************/
1562 SILC_FSM_STATE(silc_client_command_reply_kick)
1564 SilcClientCommandContext cmd = fsm_context;
1565 SilcClientConnection conn = cmd->conn;
1566 SilcClient client = conn->client;
1567 SilcCommandPayload payload = state_context;
1568 SilcArgumentPayload args = silc_command_get_args(payload);
1569 SilcClientEntry client_entry;
1570 SilcChannelEntry channel;
1574 CHECK_STATUS("Cannot kick: ");
1577 /* Take Channel ID */
1578 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1579 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1583 /* Get the channel entry */
1584 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1586 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1591 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1592 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1596 /* Get client entry */
1597 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1598 if (!client_entry) {
1599 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1603 /* Notify application */
1604 silc_client_command_callback(cmd, channel, client_entry);
1606 silc_client_unref_client(client, conn, client_entry);
1609 silc_fsm_next(fsm, silc_client_command_reply_processed);
1610 return SILC_FSM_CONTINUE;
1613 /******************************** SILCOPER **********************************/
1615 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1617 SilcClientCommandContext cmd = fsm_context;
1618 SilcCommandPayload payload = state_context;
1619 SilcArgumentPayload args = silc_command_get_args(payload);
1622 CHECK_STATUS("Cannot change mode: ");
1626 cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1628 /* Notify application */
1629 silc_client_command_callback(cmd);
1631 silc_fsm_next(fsm, silc_client_command_reply_processed);
1632 return SILC_FSM_CONTINUE;
1635 /********************************** OPER ************************************/
1637 SILC_FSM_STATE(silc_client_command_reply_oper)
1639 SilcClientCommandContext cmd = fsm_context;
1640 SilcCommandPayload payload = state_context;
1641 SilcArgumentPayload args = silc_command_get_args(payload);
1644 CHECK_STATUS("Cannot change mode: ");
1648 cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1650 /* Notify application */
1651 silc_client_command_callback(cmd);
1653 silc_fsm_next(fsm, silc_client_command_reply_processed);
1654 return SILC_FSM_CONTINUE;
1657 /********************************* DETACH ***********************************/
1659 SILC_FSM_STATE(silc_client_command_reply_detach)
1661 SilcClientCommandContext cmd = fsm_context;
1662 SilcClientConnection conn = cmd->conn;
1663 SilcClient client = conn->client;
1664 SilcCommandPayload payload = state_context;
1665 SilcArgumentPayload args = silc_command_get_args(payload);
1669 CHECK_STATUS("Cannot detach: ");
1672 /* Get detachment data */
1673 detach = silc_client_get_detach_data(client, conn);
1675 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1679 /* Notify application */
1680 silc_client_command_callback(cmd, detach);
1681 silc_buffer_free(detach);
1684 silc_fsm_next(fsm, silc_client_command_reply_processed);
1685 return SILC_FSM_CONTINUE;
1688 /********************************** WATCH ***********************************/
1690 SILC_FSM_STATE(silc_client_command_reply_watch)
1692 SilcClientCommandContext cmd = fsm_context;
1693 SilcCommandPayload payload = state_context;
1694 SilcArgumentPayload args = silc_command_get_args(payload);
1697 CHECK_STATUS("Cannot set watch: ");
1700 /* Notify application */
1701 silc_client_command_callback(cmd);
1703 silc_fsm_next(fsm, silc_client_command_reply_processed);
1704 return SILC_FSM_CONTINUE;
1707 /*********************************** BAN ************************************/
1709 SILC_FSM_STATE(silc_client_command_reply_ban)
1711 SilcClientCommandContext cmd = fsm_context;
1712 SilcClientConnection conn = cmd->conn;
1713 SilcClient client = conn->client;
1714 SilcCommandPayload payload = state_context;
1715 SilcArgumentPayload args = silc_command_get_args(payload);
1716 SilcChannelEntry channel;
1719 SilcArgumentPayload invite_args = NULL;
1723 CHECK_STATUS("Cannot set ban: ");
1726 /* Take Channel ID */
1727 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1728 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1732 /* Get the channel entry */
1733 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1735 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1739 /* Get the invite list */
1740 tmp = silc_argument_get_arg_type(args, 3, &len);
1742 invite_args = silc_argument_list_parse(tmp, len);
1744 /* Notify application */
1745 silc_client_command_callback(cmd, channel, invite_args);
1748 silc_argument_payload_free(invite_args);
1751 silc_fsm_next(fsm, silc_client_command_reply_processed);
1752 return SILC_FSM_CONTINUE;
1755 /********************************** LEAVE ***********************************/
1757 /* Reply to LEAVE command. */
1759 SILC_FSM_STATE(silc_client_command_reply_leave)
1761 SilcClientCommandContext cmd = fsm_context;
1762 SilcClientConnection conn = cmd->conn;
1763 SilcClient client = conn->client;
1764 SilcCommandPayload payload = state_context;
1765 SilcArgumentPayload args = silc_command_get_args(payload);
1766 SilcChannelEntry channel;
1770 CHECK_STATUS("Cannot set leave: ");
1773 /* Get Channel ID */
1774 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1775 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1779 /* Get the channel entry */
1780 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1782 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1786 /* Remove us from this channel. */
1787 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1789 /* Notify application */
1790 silc_client_command_callback(cmd, channel);
1792 /* Now delete the channel. */
1793 silc_client_empty_channel(client, conn, channel);
1794 silc_client_del_channel(client, conn, channel);
1797 silc_fsm_next(fsm, silc_client_command_reply_processed);
1798 return SILC_FSM_CONTINUE;
1801 /********************************* USERS ************************************/
1803 /* Continue USERS command reply processing after resolving unknown users */
1806 silc_client_command_reply_users_resolved(SilcClient client,
1807 SilcClientConnection conn,
1812 SilcClientCommandContext cmd = context;
1813 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1817 /* Continue USERS command after resolving unknown channel */
1820 silc_client_command_reply_users_continue(SilcClient client,
1821 SilcClientConnection conn,
1826 SilcClientCommandContext cmd = context;
1829 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1830 SilcArgumentPayload args = silc_command_get_args(payload);
1832 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1833 ERROR_CALLBACK(cmd->status);
1834 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1837 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1840 /* Reply to USERS command. Received list of client ID's and theirs modes
1841 on the channel we requested. */
1843 SILC_FSM_STATE(silc_client_command_reply_users)
1845 SilcClientCommandContext cmd = fsm_context;
1846 SilcClientConnection conn = cmd->conn;
1847 SilcClient client = conn->client;
1848 SilcCommandPayload payload = state_context;
1849 SilcArgumentPayload args = silc_command_get_args(payload);
1851 SilcUInt32 tmp_len, list_count;
1852 SilcUInt16 idp_len, mode;
1853 SilcHashTableList htl;
1854 SilcBufferStruct client_id_list, client_mode_list;
1855 SilcChannelEntry channel = NULL;
1856 SilcClientEntry client_entry;
1861 CHECK_STATUS("Cannot get users: ");
1864 /* Get channel ID */
1865 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1866 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1870 /* Get channel entry */
1871 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1873 /* Resolve the channel from server */
1874 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1875 client, conn, &id.u.channel_id,
1876 silc_client_command_reply_users_continue, cmd));
1880 /* Get the list count */
1881 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1882 if (!tmp || tmp_len != 4) {
1883 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1886 SILC_GET32_MSB(list_count, tmp);
1888 /* Get Client ID list */
1889 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1891 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1894 silc_buffer_set(&client_id_list, tmp, tmp_len);
1896 /* Resolve users we do not know about */
1897 if (!cmd->resolved) {
1898 cmd->resolved = TRUE;
1899 silc_client_unref_channel(client, conn, channel);
1900 SILC_FSM_CALL(silc_client_get_clients_by_list(
1901 client, conn, list_count, &client_id_list,
1902 silc_client_command_reply_users_resolved, cmd));
1906 /* Get client mode list */
1907 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1909 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1912 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1914 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1916 silc_rwlock_wrlock(channel->internal.lock);
1918 /* Cache the received Client ID's and modes. */
1919 for (i = 0; i < list_count; i++) {
1920 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1922 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1926 SILC_GET32_MSB(mode, client_mode_list.data);
1928 /* Save the client on this channel. Unknown clients are ignored as they
1929 clearly do not exist since the resolving didn't find them. */
1930 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1931 if (client_entry && client_entry->internal.valid) {
1932 silc_rwlock_wrlock(client_entry->internal.lock);
1933 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1934 silc_rwlock_unlock(client_entry->internal.lock);
1936 silc_client_unref_client(client, conn, client_entry);
1938 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1939 silc_rwlock_unlock(channel->internal.lock);
1942 if (!silc_buffer_pull(&client_mode_list, 4)) {
1943 silc_rwlock_unlock(channel->internal.lock);
1948 /* Notify application */
1949 silc_hash_table_list(channel->user_list, &htl);
1950 silc_client_command_callback(cmd, channel, &htl);
1951 silc_hash_table_list_reset(&htl);
1954 silc_client_unref_channel(client, conn, channel);
1955 silc_fsm_next(fsm, silc_client_command_reply_processed);
1956 return SILC_FSM_CONTINUE;
1959 /********************************** GETKEY **********************************/
1961 /* Received command reply to GETKEY command. WE've received the remote
1962 client's public key. */
1964 SILC_FSM_STATE(silc_client_command_reply_getkey)
1966 SilcClientCommandContext cmd = fsm_context;
1967 SilcClientConnection conn = cmd->conn;
1968 SilcClient client = conn->client;
1969 SilcCommandPayload payload = state_context;
1970 SilcArgumentPayload args = silc_command_get_args(payload);
1971 SilcClientEntry client_entry;
1972 SilcServerEntry server_entry;
1975 SilcPublicKey public_key;
1979 CHECK_STATUS("Cannot get key: ");
1983 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1984 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1988 /* Get the public key */
1989 tmp = silc_argument_get_arg_type(args, 3, &len);
1991 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1994 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1995 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1999 if (id.type == SILC_ID_CLIENT) {
2000 /* Received client's public key */
2001 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2002 if (!client_entry) {
2003 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2007 silc_rwlock_wrlock(client_entry->internal.lock);
2009 /* Save fingerprint */
2010 if (!client_entry->fingerprint)
2011 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2012 client_entry->fingerprint);
2013 if (!client_entry->public_key) {
2014 client_entry->public_key = public_key;
2018 silc_rwlock_unlock(client_entry->internal.lock);
2020 /* Notify application */
2021 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2022 client_entry->public_key);
2023 silc_client_unref_client(client, conn, client_entry);
2024 } else if (id.type == SILC_ID_SERVER) {
2025 /* Received server's public key */
2026 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2027 if (!server_entry) {
2028 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2032 silc_rwlock_wrlock(server_entry->internal.lock);
2034 if (!server_entry->public_key) {
2035 server_entry->public_key = public_key;
2039 silc_rwlock_unlock(server_entry->internal.lock);
2041 /* Notify application */
2042 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2043 server_entry->public_key);
2044 silc_client_unref_server(client, conn, server_entry);
2049 silc_pkcs_public_key_free(public_key);
2050 silc_fsm_next(fsm, silc_client_command_reply_processed);
2051 return SILC_FSM_CONTINUE;
2054 /********************************** SERVICE *********************************/
2056 /* Reply to SERVICE command. */
2057 /* XXX incomplete */
2059 SILC_FSM_STATE(silc_client_command_reply_service)
2061 SilcClientCommandContext cmd = fsm_context;
2062 SilcCommandPayload payload = state_context;
2063 SilcArgumentPayload args = silc_command_get_args(payload);
2065 unsigned char *service_list, *name;
2068 CHECK_STATUS("Cannot get service: ");
2070 /* Get service list */
2071 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2073 /* Get requested service name */
2074 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2076 /* Notify application */
2077 silc_client_command_callback(cmd, service_list, name);
2079 silc_fsm_next(fsm, silc_client_command_reply_processed);
2080 return SILC_FSM_CONTINUE;
2083 /*********************************** QUIT ***********************************/
2085 /* QUIT command reply stub */
2087 SILC_FSM_STATE(silc_client_command_reply_quit)
2089 silc_fsm_next(fsm, silc_client_command_reply_processed);
2090 return SILC_FSM_CONTINUE;