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 channel 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 server 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,
681 channel_entry->channel_name, info);
682 silc_client_unref_channel(client, conn, channel_entry);
687 silc_fsm_next(fsm, silc_client_command_reply_processed);
688 return SILC_FSM_CONTINUE;
691 /********************************** NICK ************************************/
693 /* Received reply for command NICK. */
695 SILC_FSM_STATE(silc_client_command_reply_nick)
697 SilcClientCommandContext cmd = fsm_context;
698 SilcClientConnection conn = cmd->conn;
699 SilcClient client = conn->client;
700 SilcCommandPayload payload = state_context;
701 SilcArgumentPayload args = silc_command_get_args(payload);
702 unsigned char *nick, *idp;
703 SilcUInt32 len, idp_len;
704 SilcClientID old_client_id;
708 CHECK_STATUS("Cannot set nickname: ");
711 /* Take received Client ID */
712 idp = silc_argument_get_arg_type(args, 2, &idp_len);
714 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
717 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
718 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
722 /* Take the new nickname */
723 nick = silc_argument_get_arg_type(args, 3, &len);
725 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
729 silc_rwlock_wrlock(conn->local_entry->internal.lock);
731 /* Change the nickname */
732 old_client_id = *conn->local_id;
733 if (!silc_client_change_nickname(client, conn, conn->local_entry,
734 nick, &id.u.client_id, idp, idp_len)) {
735 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
736 silc_rwlock_unlock(conn->local_entry->internal.lock);
740 silc_rwlock_unlock(conn->local_entry->internal.lock);
742 /* Notify application */
743 silc_client_command_callback(cmd, conn->local_entry,
744 conn->local_entry->nickname, &old_client_id);
747 silc_fsm_next(fsm, silc_client_command_reply_processed);
748 return SILC_FSM_CONTINUE;
751 /********************************** LIST ************************************/
753 /* Received reply to the LIST command. */
755 SILC_FSM_STATE(silc_client_command_reply_list)
757 SilcClientCommandContext cmd = fsm_context;
758 SilcClientConnection conn = cmd->conn;
759 SilcClient client = conn->client;
760 SilcCommandPayload payload = state_context;
761 SilcArgumentPayload args = silc_command_get_args(payload);
762 unsigned char *tmp, *name, *topic;
763 SilcUInt32 usercount = 0;
764 SilcChannelEntry channel_entry = NULL;
768 CHECK_STATUS("Cannot list channels: ");
770 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
771 /* There were no channels in the network. */
772 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
773 silc_fsm_next(fsm, silc_client_command_reply_processed);
774 return SILC_FSM_CONTINUE;
779 name = silc_argument_get_arg_type(args, 3, NULL);
781 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
785 topic = silc_argument_get_arg_type(args, 4, NULL);
786 tmp = silc_argument_get_arg_type(args, 5, NULL);
788 SILC_GET32_MSB(usercount, tmp);
790 /* Check whether the channel exists, and add it to cache if it doesn't. */
791 channel_entry = silc_client_get_channel_by_id(client, conn,
793 if (!channel_entry) {
794 /* Add new channel entry */
795 channel_entry = silc_client_add_channel(client, conn, name, 0,
797 if (!channel_entry) {
798 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
801 silc_client_ref_channel(client, conn, channel_entry);
804 /* Notify application */
805 silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name,
809 silc_client_unref_channel(client, conn, channel_entry);
810 silc_fsm_next(fsm, silc_client_command_reply_processed);
811 return SILC_FSM_CONTINUE;
814 /********************************* TOPIC ************************************/
816 /* Received reply to topic command. */
818 SILC_FSM_STATE(silc_client_command_reply_topic)
820 SilcClientCommandContext cmd = fsm_context;
821 SilcClientConnection conn = cmd->conn;
822 SilcClient client = conn->client;
823 SilcCommandPayload payload = state_context;
824 SilcArgumentPayload args = silc_command_get_args(payload);
825 SilcChannelEntry channel = NULL;
831 CHECK_STATUS("Cannot set topic: ");
834 /* Take Channel ID */
835 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
836 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
840 /* Get the channel entry */
841 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
843 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
847 silc_rwlock_wrlock(channel->internal.lock);
850 topic = silc_argument_get_arg_type(args, 3, &len);
852 silc_free(channel->topic);
853 channel->topic = silc_memdup(topic, len);
856 silc_rwlock_unlock(channel->internal.lock);
858 /* Notify application */
859 silc_client_command_callback(cmd, channel, channel->topic);
862 silc_client_unref_channel(client, conn, channel);
863 silc_fsm_next(fsm, silc_client_command_reply_processed);
864 return SILC_FSM_CONTINUE;
867 /********************************* INVITE ***********************************/
869 /* Received reply to invite command. */
871 SILC_FSM_STATE(silc_client_command_reply_invite)
873 SilcClientCommandContext cmd = fsm_context;
874 SilcClientConnection conn = cmd->conn;
875 SilcClient client = conn->client;
876 SilcCommandPayload payload = state_context;
877 SilcArgumentPayload args = silc_command_get_args(payload);
878 SilcChannelEntry channel = NULL;
881 SilcArgumentPayload invite_args = NULL;
885 CHECK_STATUS("Cannot invite: ");
888 /* Take Channel ID */
889 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
890 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
894 /* Get the channel entry */
895 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
897 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
901 /* Get the invite list */
902 tmp = silc_argument_get_arg_type(args, 3, &len);
904 invite_args = silc_argument_list_parse(tmp, len);
906 /* Notify application */
907 silc_client_command_callback(cmd, channel, invite_args);
910 silc_argument_payload_free(invite_args);
913 silc_client_unref_channel(client, conn, channel);
914 silc_fsm_next(fsm, silc_client_command_reply_processed);
915 return SILC_FSM_CONTINUE;
918 /********************************** KILL ************************************/
920 /* Received reply to the KILL command. */
922 SILC_FSM_STATE(silc_client_command_reply_kill)
924 SilcClientCommandContext cmd = fsm_context;
925 SilcClientConnection conn = cmd->conn;
926 SilcClient client = conn->client;
927 SilcCommandPayload payload = state_context;
928 SilcArgumentPayload args = silc_command_get_args(payload);
929 SilcClientEntry client_entry;
933 CHECK_STATUS("Cannot kill: ");
936 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
937 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
941 /* Get the client entry, if exists */
942 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
944 /* Notify application */
945 silc_client_command_callback(cmd, client_entry);
947 /* Remove the client */
949 silc_client_remove_from_channels(client, conn, client_entry);
950 silc_client_del_client(client, conn, client_entry);
951 silc_client_unref_client(client, conn, client_entry);
955 silc_fsm_next(fsm, silc_client_command_reply_processed);
956 return SILC_FSM_CONTINUE;
959 /********************************** INFO ************************************/
961 /* Received reply to INFO command. We receive the server ID and some
962 information about the server user requested. */
964 SILC_FSM_STATE(silc_client_command_reply_info)
966 SilcClientCommandContext cmd = fsm_context;
967 SilcClientConnection conn = cmd->conn;
968 SilcClient client = conn->client;
969 SilcCommandPayload payload = state_context;
970 SilcArgumentPayload args = silc_command_get_args(payload);
971 SilcServerEntry server;
972 char *server_name, *server_info;
976 CHECK_STATUS("Cannot get info: ");
980 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
981 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
985 /* Get server name */
986 server_name = silc_argument_get_arg_type(args, 3, NULL);
988 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
992 /* Get server info */
993 server_info = silc_argument_get_arg_type(args, 4, NULL);
995 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
999 /* See whether we have this server cached. If not create it. */
1000 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1002 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
1003 server = silc_client_add_server(client, conn, server_name,
1004 server_info, &id.u.server_id);
1007 silc_client_ref_server(client, conn, server);
1010 /* Notify application */
1011 silc_client_command_callback(cmd, server, server->server_name,
1012 server->server_info);
1013 silc_client_unref_server(client, conn, server);
1016 silc_fsm_next(fsm, silc_client_command_reply_processed);
1017 return SILC_FSM_CONTINUE;
1020 /********************************** STATS ***********************************/
1022 /* Received reply to STATS command. */
1024 SILC_FSM_STATE(silc_client_command_reply_stats)
1026 SilcClientCommandContext cmd = fsm_context;
1027 SilcCommandPayload payload = state_context;
1028 SilcArgumentPayload args = silc_command_get_args(payload);
1029 SilcClientStats stats;
1030 unsigned char *buf = NULL;
1031 SilcUInt32 buf_len = 0;
1036 CHECK_STATUS("Cannot get stats: ");
1040 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1041 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1045 /* Get statistics structure */
1046 memset(&stats, 0, sizeof(stats));
1047 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1049 silc_buffer_set(&b, buf, buf_len);
1050 silc_buffer_unformat(&b,
1051 SILC_STR_UI_INT(&stats.starttime),
1052 SILC_STR_UI_INT(&stats.uptime),
1053 SILC_STR_UI_INT(&stats.my_clients),
1054 SILC_STR_UI_INT(&stats.my_channels),
1055 SILC_STR_UI_INT(&stats.my_server_ops),
1056 SILC_STR_UI_INT(&stats.my_router_ops),
1057 SILC_STR_UI_INT(&stats.cell_clients),
1058 SILC_STR_UI_INT(&stats.cell_channels),
1059 SILC_STR_UI_INT(&stats.cell_servers),
1060 SILC_STR_UI_INT(&stats.clients),
1061 SILC_STR_UI_INT(&stats.channels),
1062 SILC_STR_UI_INT(&stats.servers),
1063 SILC_STR_UI_INT(&stats.routers),
1064 SILC_STR_UI_INT(&stats.server_ops),
1065 SILC_STR_UI_INT(&stats.router_ops),
1069 /* Notify application */
1070 silc_client_command_callback(cmd, &stats);
1073 silc_fsm_next(fsm, silc_client_command_reply_processed);
1074 return SILC_FSM_CONTINUE;
1077 /********************************** PING ************************************/
1079 /* Received reply to PING command. */
1081 SILC_FSM_STATE(silc_client_command_reply_ping)
1083 SilcClientCommandContext cmd = fsm_context;
1084 SilcClientConnection conn = cmd->conn;
1085 SilcClient client = conn->client;
1088 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1090 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1091 "Ping reply from %s: %d second%s", conn->remote_host,
1092 (int)diff, diff == 1 ? "" : "s");
1094 /* Notify application */
1095 silc_client_command_callback(cmd);
1097 silc_fsm_next(fsm, silc_client_command_reply_processed);
1098 return SILC_FSM_CONTINUE;
1101 /********************************** JOIN ************************************/
1103 /* Continue JOIN command reply processing after resolving unknown users */
1106 silc_client_command_reply_join_resolved(SilcClient client,
1107 SilcClientConnection conn,
1112 SilcClientCommandContext cmd = context;
1113 SilcChannelEntry channel = cmd->context;
1114 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1115 SilcArgumentPayload args = silc_command_get_args(payload);
1116 SilcUInt32 list_count;
1121 silc_snprintf(msg, sizeof(msg), "Error resolving channel %s user list",
1122 channel->channel_name);
1123 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, msg);
1125 tmp = silc_argument_get_arg_type(args, 12, NULL);
1127 SILC_GET32_MSB(list_count, tmp);
1128 if (list_count - silc_dlist_count(clients) > 5) {
1129 silc_snprintf(msg, sizeof(msg),
1130 "Channel %s user list was not fully resolved. "
1131 "The channel may not be fully synced.",
1132 channel->channel_name);
1133 SAY(client, conn, SILC_CLIENT_MESSAGE_WARNING, msg);
1138 channel->internal.resolve_cmd_ident = 0;
1139 silc_client_unref_channel(client, conn, channel);
1141 SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
1145 /* Received reply for JOIN command. */
1147 SILC_FSM_STATE(silc_client_command_reply_join)
1149 SilcClientCommandContext cmd = fsm_context;
1150 SilcClientConnection conn = cmd->conn;
1151 SilcClient client = conn->client;
1152 SilcCommandPayload payload = state_context;
1153 SilcArgumentPayload args = silc_command_get_args(payload);
1154 SilcChannelEntry channel;
1155 SilcUInt32 mode = 0, len, list_count;
1156 char *topic, *tmp, *channel_name = NULL, *hmac;
1158 SilcBufferStruct client_id_list, client_mode_list, keyp;
1159 SilcHashTableList htl;
1164 CHECK_STATUS("Cannot join channel: ");
1167 /* Get channel name */
1168 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1169 if (!channel_name) {
1170 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1174 /* Get Channel ID */
1175 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1176 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1180 /* Check whether we have this channel entry already. */
1181 channel = silc_client_get_channel(client, conn, channel_name);
1183 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1184 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1186 /* Create new channel entry */
1187 channel = silc_client_add_channel(client, conn, channel_name,
1188 mode, &id.u.channel_id);
1190 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1193 silc_client_ref_channel(client, conn, channel);
1196 /* Get the list count */
1197 tmp = silc_argument_get_arg_type(args, 12, &len);
1198 if (!tmp || len != 4) {
1199 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1202 SILC_GET32_MSB(list_count, tmp);
1204 /* Get Client ID list */
1205 tmp = silc_argument_get_arg_type(args, 13, &len);
1207 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1210 silc_buffer_set(&client_id_list, tmp, len);
1212 /* Resolve users we do not know about */
1213 if (!cmd->resolved) {
1214 cmd->resolved = TRUE;
1215 cmd->context = channel;
1216 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1217 silc_client_get_clients_by_list(
1218 client, conn, list_count, &client_id_list,
1219 silc_client_command_reply_join_resolved, cmd));
1223 /* Get client mode list */
1224 tmp = silc_argument_get_arg_type(args, 14, &len);
1226 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1229 silc_buffer_set(&client_mode_list, tmp, len);
1231 silc_rwlock_wrlock(channel->internal.lock);
1233 /* Add clients we received in the reply to the channel */
1234 for (i = 0; i < list_count; i++) {
1237 SilcClientEntry client_entry;
1240 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1242 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1246 SILC_GET32_MSB(mode, client_mode_list.data);
1248 /* Get client entry */
1249 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1250 if (client_entry && client_entry->internal.valid) {
1251 /* Join client to the channel */
1252 silc_rwlock_wrlock(client_entry->internal.lock);
1253 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1254 silc_rwlock_unlock(client_entry->internal.lock);
1256 silc_client_unref_client(client, conn, client_entry);
1258 if (!silc_buffer_pull(&client_id_list, idp_len)) {
1259 silc_rwlock_unlock(channel->internal.lock);
1262 if (!silc_buffer_pull(&client_mode_list, 4)) {
1263 silc_rwlock_unlock(channel->internal.lock);
1269 hmac = silc_argument_get_arg_type(args, 11, NULL);
1271 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1273 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1274 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1275 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1276 silc_rwlock_unlock(channel->internal.lock);
1281 /* Get channel mode */
1282 tmp = silc_argument_get_arg_type(args, 5, &len);
1283 if (tmp && len == 4)
1284 SILC_GET32_MSB(mode, tmp);
1285 channel->mode = mode;
1287 /* Get channel key and save it */
1288 tmp = silc_argument_get_arg_type(args, 7, &len);
1290 /* If channel key already exists on the channel then while resolving
1291 the user list we have already received new key from server. Don't
1292 replace it with this old key. */
1293 if (!channel->internal.send_key) {
1294 silc_buffer_set(&keyp, tmp, len);
1295 silc_client_save_channel_key(client, conn, &keyp, channel);
1300 topic = silc_argument_get_arg_type(args, 10, NULL);
1302 silc_free(channel->topic);
1303 channel->topic = silc_memdup(topic, strlen(topic));
1306 /* Get founder key */
1307 tmp = silc_argument_get_arg_type(args, 15, &len);
1309 if (channel->founder_key)
1310 silc_pkcs_public_key_free(channel->founder_key);
1311 channel->founder_key = NULL;
1312 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1315 /* Get user limit */
1316 tmp = silc_argument_get_arg_type(args, 17, &len);
1317 if (tmp && len == 4)
1318 SILC_GET32_MSB(channel->user_limit, tmp);
1319 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1320 channel->user_limit = 0;
1322 /* Get channel public key list */
1323 tmp = silc_argument_get_arg_type(args, 16, &len);
1325 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1327 /* Set current channel */
1328 conn->current_channel = channel;
1330 silc_rwlock_unlock(channel->internal.lock);
1332 cipher = (channel->internal.send_key ?
1333 silc_cipher_get_name(channel->internal.send_key) : NULL);
1334 silc_hash_table_list(channel->user_list, &htl);
1336 /* Notify application */
1337 silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
1338 topic, cipher, hmac, channel->founder_key,
1339 channel->channel_pubkeys, channel->user_limit);
1341 silc_hash_table_list_reset(&htl);
1342 silc_client_unref_channel(client, conn, channel);
1345 silc_fsm_next(fsm, silc_client_command_reply_processed);
1346 return SILC_FSM_CONTINUE;
1349 /********************************** MOTD ************************************/
1351 /* Received reply for MOTD command */
1353 SILC_FSM_STATE(silc_client_command_reply_motd)
1355 SilcClientCommandContext cmd = fsm_context;
1356 SilcClientConnection conn = cmd->conn;
1357 SilcClient client = conn->client;
1358 SilcCommandPayload payload = state_context;
1359 SilcArgumentPayload args = silc_command_get_args(payload);
1361 char *motd = NULL, *cp, line[256];
1364 CHECK_STATUS("Cannot get motd: ");
1367 if (silc_argument_get_arg_num(args) == 3) {
1368 motd = silc_argument_get_arg_type(args, 3, NULL);
1370 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1377 if (cp[i++] == '\n') {
1378 memset(line, 0, sizeof(line));
1379 silc_strncat(line, sizeof(line), cp, i - 1);
1386 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1395 /* Notify application */
1396 silc_client_command_callback(cmd, motd);
1399 silc_fsm_next(fsm, silc_client_command_reply_processed);
1400 return SILC_FSM_CONTINUE;
1403 /********************************** UMODE ***********************************/
1405 /* Received reply to the UMODE command. Save the current user mode */
1407 SILC_FSM_STATE(silc_client_command_reply_umode)
1409 SilcClientCommandContext cmd = fsm_context;
1410 SilcClientConnection conn = cmd->conn;
1411 SilcCommandPayload payload = state_context;
1412 SilcArgumentPayload args = silc_command_get_args(payload);
1414 SilcUInt32 mode, len;
1417 CHECK_STATUS("Cannot change mode: ");
1420 tmp = silc_argument_get_arg_type(args, 2, &len);
1421 if (!tmp || len != 4) {
1422 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1426 SILC_GET32_MSB(mode, tmp);
1427 silc_rwlock_wrlock(conn->local_entry->internal.lock);
1428 conn->local_entry->mode = mode;
1429 silc_rwlock_unlock(conn->local_entry->internal.lock);
1431 /* Notify application */
1432 silc_client_command_callback(cmd, mode);
1435 silc_fsm_next(fsm, silc_client_command_reply_processed);
1436 return SILC_FSM_CONTINUE;
1439 /********************************** CMODE ***********************************/
1441 /* Received reply for CMODE command. */
1443 SILC_FSM_STATE(silc_client_command_reply_cmode)
1445 SilcClientCommandContext cmd = fsm_context;
1446 SilcClientConnection conn = cmd->conn;
1447 SilcClient client = conn->client;
1448 SilcCommandPayload payload = state_context;
1449 SilcArgumentPayload args = silc_command_get_args(payload);
1452 SilcChannelEntry channel = NULL;
1454 SilcPublicKey public_key = NULL;
1458 CHECK_STATUS("Cannot change mode: ");
1461 /* Take Channel ID */
1462 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1463 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1467 /* Get the channel entry */
1468 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1470 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1474 /* Get founder public key */
1475 tmp = silc_argument_get_arg_type(args, 4, &len);
1477 silc_public_key_payload_decode(tmp, len, &public_key);
1479 /* Get channel mode */
1480 tmp = silc_argument_get_arg_type(args, 3, &len);
1481 if (!tmp || len != 4) {
1482 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1485 SILC_GET32_MSB(mode, tmp);
1487 silc_rwlock_wrlock(channel->internal.lock);
1489 /* Get user limit */
1490 tmp = silc_argument_get_arg_type(args, 6, &len);
1491 if (tmp && len == 4)
1492 SILC_GET32_MSB(channel->user_limit, tmp);
1493 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1494 channel->user_limit = 0;
1496 /* Get channel public key(s) */
1497 tmp = silc_argument_get_arg_type(args, 5, &len);
1499 silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1500 else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
1501 silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
1504 channel->mode = mode;
1506 silc_rwlock_unlock(channel->internal.lock);
1508 /* Notify application */
1509 silc_client_command_callback(cmd, channel, mode, public_key,
1510 channel->channel_pubkeys, channel->user_limit);
1512 silc_rwlock_wrlock(channel->internal.lock);
1514 /* If founder key changed, update it */
1516 (!channel->founder_key ||
1517 !silc_pkcs_public_key_compare(public_key, channel->founder_key))) {
1518 if (channel->founder_key)
1519 silc_pkcs_public_key_free(channel->founder_key);
1520 channel->founder_key = public_key;
1524 silc_rwlock_unlock(channel->internal.lock);
1527 silc_client_unref_channel(client, conn, channel);
1529 silc_pkcs_public_key_free(public_key);
1530 silc_fsm_next(fsm, silc_client_command_reply_processed);
1531 return SILC_FSM_CONTINUE;
1534 /********************************** CUMODE **********************************/
1536 /* Received reply for CUMODE command */
1538 SILC_FSM_STATE(silc_client_command_reply_cumode)
1540 SilcClientCommandContext cmd = fsm_context;
1541 SilcClientConnection conn = cmd->conn;
1542 SilcClient client = conn->client;
1543 SilcCommandPayload payload = state_context;
1544 SilcArgumentPayload args = silc_command_get_args(payload);
1545 SilcClientEntry client_entry;
1546 SilcChannelEntry channel = NULL;
1547 SilcChannelUser chu;
1548 unsigned char *modev;
1549 SilcUInt32 len, mode;
1553 CHECK_STATUS("Cannot change mode: ");
1556 /* Get channel mode */
1557 modev = silc_argument_get_arg_type(args, 2, &len);
1558 if (!modev || len != 4) {
1559 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1562 SILC_GET32_MSB(mode, modev);
1564 /* Take Channel ID */
1565 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1566 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1570 /* Get the channel entry */
1571 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1573 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1578 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1579 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1583 /* Get client entry */
1584 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1585 if (!client_entry) {
1586 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1591 silc_rwlock_wrlock(channel->internal.lock);
1592 chu = silc_client_on_channel(channel, client_entry);
1595 silc_rwlock_unlock(channel->internal.lock);
1597 /* Notify application */
1598 silc_client_command_callback(cmd, mode, channel, client_entry);
1600 silc_client_unref_client(client, conn, client_entry);
1603 silc_client_unref_channel(client, conn, channel);
1604 silc_fsm_next(fsm, silc_client_command_reply_processed);
1605 return SILC_FSM_CONTINUE;
1608 /********************************** KICK ************************************/
1610 SILC_FSM_STATE(silc_client_command_reply_kick)
1612 SilcClientCommandContext cmd = fsm_context;
1613 SilcClientConnection conn = cmd->conn;
1614 SilcClient client = conn->client;
1615 SilcCommandPayload payload = state_context;
1616 SilcArgumentPayload args = silc_command_get_args(payload);
1617 SilcClientEntry client_entry;
1618 SilcChannelEntry channel = NULL;
1622 CHECK_STATUS("Cannot kick: ");
1625 /* Take Channel ID */
1626 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1627 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1631 /* Get the channel entry */
1632 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1634 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1639 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1640 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1644 /* Get client entry */
1645 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1646 if (!client_entry) {
1647 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1651 /* Notify application */
1652 silc_client_command_callback(cmd, channel, client_entry);
1654 silc_client_unref_client(client, conn, client_entry);
1657 silc_client_unref_channel(client, conn, channel);
1658 silc_fsm_next(fsm, silc_client_command_reply_processed);
1659 return SILC_FSM_CONTINUE;
1662 /******************************** SILCOPER **********************************/
1664 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1666 SilcClientCommandContext cmd = fsm_context;
1667 SilcCommandPayload payload = state_context;
1668 SilcArgumentPayload args = silc_command_get_args(payload);
1671 CHECK_STATUS("Cannot change mode: ");
1675 cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1677 /* Notify application */
1678 silc_client_command_callback(cmd);
1680 silc_fsm_next(fsm, silc_client_command_reply_processed);
1681 return SILC_FSM_CONTINUE;
1684 /********************************** OPER ************************************/
1686 SILC_FSM_STATE(silc_client_command_reply_oper)
1688 SilcClientCommandContext cmd = fsm_context;
1689 SilcCommandPayload payload = state_context;
1690 SilcArgumentPayload args = silc_command_get_args(payload);
1693 CHECK_STATUS("Cannot change mode: ");
1697 cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1699 /* Notify application */
1700 silc_client_command_callback(cmd);
1702 silc_fsm_next(fsm, silc_client_command_reply_processed);
1703 return SILC_FSM_CONTINUE;
1706 /********************************* DETACH ***********************************/
1708 SILC_FSM_STATE(silc_client_command_reply_detach)
1710 SilcClientCommandContext cmd = fsm_context;
1711 SilcClientConnection conn = cmd->conn;
1712 SilcClient client = conn->client;
1713 SilcCommandPayload payload = state_context;
1714 SilcArgumentPayload args = silc_command_get_args(payload);
1718 CHECK_STATUS("Cannot detach: ");
1721 /* Get detachment data */
1722 detach = silc_client_get_detach_data(client, conn);
1724 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1728 /* Notify application */
1729 silc_client_command_callback(cmd, detach);
1730 silc_buffer_free(detach);
1733 silc_fsm_next(fsm, silc_client_command_reply_processed);
1734 return SILC_FSM_CONTINUE;
1737 /********************************** WATCH ***********************************/
1739 SILC_FSM_STATE(silc_client_command_reply_watch)
1741 SilcClientCommandContext cmd = fsm_context;
1742 SilcCommandPayload payload = state_context;
1743 SilcArgumentPayload args = silc_command_get_args(payload);
1746 CHECK_STATUS("Cannot set watch: ");
1749 /* Notify application */
1750 silc_client_command_callback(cmd);
1752 silc_fsm_next(fsm, silc_client_command_reply_processed);
1753 return SILC_FSM_CONTINUE;
1756 /*********************************** BAN ************************************/
1758 SILC_FSM_STATE(silc_client_command_reply_ban)
1760 SilcClientCommandContext cmd = fsm_context;
1761 SilcClientConnection conn = cmd->conn;
1762 SilcClient client = conn->client;
1763 SilcCommandPayload payload = state_context;
1764 SilcArgumentPayload args = silc_command_get_args(payload);
1765 SilcChannelEntry channel = NULL;
1768 SilcArgumentPayload invite_args = NULL;
1772 CHECK_STATUS("Cannot set ban: ");
1775 /* Take Channel ID */
1776 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1777 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1781 /* Get the channel entry */
1782 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1784 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1788 /* Get the invite list */
1789 tmp = silc_argument_get_arg_type(args, 3, &len);
1791 invite_args = silc_argument_list_parse(tmp, len);
1793 /* Notify application */
1794 silc_client_command_callback(cmd, channel, invite_args);
1797 silc_argument_payload_free(invite_args);
1800 silc_client_unref_channel(client, conn, channel);
1801 silc_fsm_next(fsm, silc_client_command_reply_processed);
1802 return SILC_FSM_CONTINUE;
1805 /********************************** LEAVE ***********************************/
1807 /* Reply to LEAVE command. */
1809 SILC_FSM_STATE(silc_client_command_reply_leave)
1811 SilcClientCommandContext cmd = fsm_context;
1812 SilcClientConnection conn = cmd->conn;
1813 SilcClient client = conn->client;
1814 SilcCommandPayload payload = state_context;
1815 SilcArgumentPayload args = silc_command_get_args(payload);
1816 SilcChannelEntry channel;
1822 CHECK_STATUS("Cannot set leave: ");
1825 /* Get Channel ID */
1826 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1827 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1831 /* Get the channel entry */
1832 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1834 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1838 /* Remove us from this channel. */
1839 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1841 /* Notify application */
1842 silc_client_command_callback(cmd, channel);
1844 /* Remove old keys and stuff. The channel may remain even after leaving
1845 but we want to remove these always. */
1846 if (channel->internal.send_key)
1847 silc_cipher_free(channel->internal.send_key);
1848 channel->internal.send_key = NULL;
1849 if (channel->internal.receive_key)
1850 silc_cipher_free(channel->internal.receive_key);
1851 channel->internal.receive_key = NULL;
1852 if (channel->internal.hmac)
1853 silc_hmac_free(channel->internal.hmac);
1854 channel->internal.hmac = NULL;
1855 if (channel->internal.old_channel_keys) {
1856 silc_dlist_start(channel->internal.old_channel_keys);
1857 while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
1858 silc_cipher_free(key);
1859 silc_dlist_uninit(channel->internal.old_channel_keys);
1861 channel->internal.old_channel_keys = NULL;
1862 if (channel->internal.old_hmacs) {
1863 silc_dlist_start(channel->internal.old_hmacs);
1864 while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
1865 silc_hmac_free(hmac);
1866 silc_dlist_uninit(channel->internal.old_hmacs);
1868 channel->internal.old_hmacs = NULL;
1870 /* Now delete the channel. */
1871 silc_client_empty_channel(client, conn, channel);
1872 silc_client_del_channel(client, conn, channel);
1875 silc_fsm_next(fsm, silc_client_command_reply_processed);
1876 return SILC_FSM_CONTINUE;
1879 /********************************* USERS ************************************/
1881 /* Continue USERS command reply processing after resolving unknown users */
1884 silc_client_command_reply_users_resolved(SilcClient client,
1885 SilcClientConnection conn,
1890 SilcClientCommandContext cmd = context;
1891 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1895 /* Continue USERS command after resolving unknown channel */
1898 silc_client_command_reply_users_continue(SilcClient client,
1899 SilcClientConnection conn,
1904 SilcClientCommandContext cmd = context;
1907 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1908 SilcArgumentPayload args = silc_command_get_args(payload);
1910 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1911 ERROR_CALLBACK(cmd->status);
1912 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1915 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1918 /* Reply to USERS command. Received list of client ID's and theirs modes
1919 on the channel we requested. */
1921 SILC_FSM_STATE(silc_client_command_reply_users)
1923 SilcClientCommandContext cmd = fsm_context;
1924 SilcClientConnection conn = cmd->conn;
1925 SilcClient client = conn->client;
1926 SilcCommandPayload payload = state_context;
1927 SilcArgumentPayload args = silc_command_get_args(payload);
1929 SilcUInt32 tmp_len, list_count, mode;
1931 SilcHashTableList htl;
1932 SilcBufferStruct client_id_list, client_mode_list;
1933 SilcChannelEntry channel = NULL;
1934 SilcClientEntry client_entry;
1939 CHECK_STATUS("Cannot get users: ");
1942 /* Get channel ID */
1943 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1944 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1948 /* Get channel entry */
1949 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1951 /* Resolve the channel from server */
1952 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1953 client, conn, &id.u.channel_id,
1954 silc_client_command_reply_users_continue, cmd));
1958 /* Get the list count */
1959 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1960 if (!tmp || tmp_len != 4) {
1961 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1964 SILC_GET32_MSB(list_count, tmp);
1966 /* Get Client ID list */
1967 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1969 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1972 silc_buffer_set(&client_id_list, tmp, tmp_len);
1974 /* Resolve users we do not know about */
1975 if (!cmd->resolved) {
1976 cmd->resolved = TRUE;
1977 silc_client_unref_channel(client, conn, channel);
1978 SILC_FSM_CALL(silc_client_get_clients_by_list(
1979 client, conn, list_count, &client_id_list,
1980 silc_client_command_reply_users_resolved, cmd));
1984 /* Get client mode list */
1985 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1987 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1990 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1992 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1994 silc_rwlock_wrlock(channel->internal.lock);
1996 /* Cache the received Client ID's and modes. */
1997 for (i = 0; i < list_count; i++) {
1998 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
2000 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
2004 SILC_GET32_MSB(mode, client_mode_list.data);
2006 /* Save the client on this channel. Unknown clients are ignored as they
2007 clearly do not exist since the resolving didn't find them. */
2008 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2009 if (client_entry && client_entry->internal.valid) {
2010 silc_rwlock_wrlock(client_entry->internal.lock);
2011 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
2012 silc_rwlock_unlock(client_entry->internal.lock);
2014 silc_client_unref_client(client, conn, client_entry);
2016 if (!silc_buffer_pull(&client_id_list, idp_len)) {
2017 silc_rwlock_unlock(channel->internal.lock);
2020 if (!silc_buffer_pull(&client_mode_list, 4)) {
2021 silc_rwlock_unlock(channel->internal.lock);
2026 silc_rwlock_unlock(channel->internal.lock);
2028 /* Notify application */
2029 silc_hash_table_list(channel->user_list, &htl);
2030 silc_client_command_callback(cmd, channel, &htl);
2031 silc_hash_table_list_reset(&htl);
2034 silc_client_unref_channel(client, conn, channel);
2035 silc_fsm_next(fsm, silc_client_command_reply_processed);
2036 return SILC_FSM_CONTINUE;
2039 /********************************** GETKEY **********************************/
2041 /* Received command reply to GETKEY command. WE've received the remote
2042 client's public key. */
2044 SILC_FSM_STATE(silc_client_command_reply_getkey)
2046 SilcClientCommandContext cmd = fsm_context;
2047 SilcClientConnection conn = cmd->conn;
2048 SilcClient client = conn->client;
2049 SilcCommandPayload payload = state_context;
2050 SilcArgumentPayload args = silc_command_get_args(payload);
2051 SilcClientEntry client_entry;
2052 SilcServerEntry server_entry;
2055 SilcPublicKey public_key;
2059 CHECK_STATUS("Cannot get key: ");
2063 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
2064 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2068 /* Get the public key */
2069 tmp = silc_argument_get_arg_type(args, 3, &len);
2071 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2074 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
2075 SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
2076 "Cannot decode public key: malformed/unsupported public key");
2077 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2081 if (id.type == SILC_ID_CLIENT) {
2082 /* Received client's public key */
2083 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2084 if (!client_entry) {
2085 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2089 silc_rwlock_wrlock(client_entry->internal.lock);
2091 /* Save fingerprint */
2092 if (!client_entry->fingerprint)
2093 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2094 client_entry->fingerprint);
2095 if (!client_entry->public_key) {
2096 client_entry->public_key = public_key;
2100 silc_rwlock_unlock(client_entry->internal.lock);
2102 /* Notify application */
2103 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2104 client_entry->public_key);
2105 silc_client_unref_client(client, conn, client_entry);
2106 } else if (id.type == SILC_ID_SERVER) {
2107 /* Received server's public key */
2108 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2109 if (!server_entry) {
2110 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2114 silc_rwlock_wrlock(server_entry->internal.lock);
2116 if (!server_entry->public_key) {
2117 server_entry->public_key = public_key;
2121 silc_rwlock_unlock(server_entry->internal.lock);
2123 /* Notify application */
2124 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2125 server_entry->public_key);
2126 silc_client_unref_server(client, conn, server_entry);
2131 silc_pkcs_public_key_free(public_key);
2132 silc_fsm_next(fsm, silc_client_command_reply_processed);
2133 return SILC_FSM_CONTINUE;
2136 /********************************** SERVICE *********************************/
2138 /* Reply to SERVICE command. */
2139 /* XXX incomplete */
2141 SILC_FSM_STATE(silc_client_command_reply_service)
2143 SilcClientCommandContext cmd = fsm_context;
2144 SilcCommandPayload payload = state_context;
2145 SilcArgumentPayload args = silc_command_get_args(payload);
2147 unsigned char *service_list, *name;
2150 CHECK_STATUS("Cannot get service: ");
2152 /* Get service list */
2153 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2155 /* Get requested service name */
2156 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2158 /* Notify application */
2159 silc_client_command_callback(cmd, service_list, name);
2161 silc_fsm_next(fsm, silc_client_command_reply_processed);
2162 return SILC_FSM_CONTINUE;
2165 /*********************************** QUIT ***********************************/
2167 /* QUIT command reply stub */
2169 SILC_FSM_STATE(silc_client_command_reply_quit)
2171 silc_fsm_next(fsm, silc_client_command_reply_processed);
2172 return SILC_FSM_CONTINUE;