5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Types and definitions ***************************/
27 /* Calls error command reply callback back to command sender. */
28 #define ERROR_CALLBACK(err) \
30 void *arg1 = NULL, *arg2 = NULL; \
31 if (cmd->status != SILC_STATUS_OK) \
32 silc_status_get_args(cmd->status, args, &arg1, &arg2); \
34 cmd->status = cmd->error = err; \
35 SILC_LOG_DEBUG(("Error in command reply: %s", \
36 silc_get_status_message(cmd->status))); \
37 silc_client_command_callback(cmd, arg1, arg2); \
41 #define CHECK_STATUS(msg) \
42 SILC_LOG_DEBUG(("%s", silc_get_command_name(cmd->cmd))); \
43 if (cmd->error != SILC_STATUS_OK) { \
45 SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_ERROR, \
46 msg "%s", silc_get_status_message(cmd->error)); \
47 ERROR_CALLBACK(cmd->error); \
48 silc_client_command_process_error(cmd, state_context, cmd->error); \
49 silc_fsm_next(fsm, silc_client_command_reply_processed); \
50 return SILC_FSM_CONTINUE; \
53 /* Check for correct arguments */
54 #define CHECK_ARGS(min, max) \
55 if (silc_argument_get_arg_num(args) < min || \
56 silc_argument_get_arg_num(args) > max) { \
57 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
58 silc_fsm_next(fsm, silc_client_command_reply_processed); \
59 return SILC_FSM_CONTINUE; \
62 #define SAY cmd->conn->client->internal->ops->say
64 /************************ Static utility functions **************************/
66 /* Delivers the command reply back to application */
69 silc_client_command_callback(SilcClientCommandContext cmd, ...)
71 SilcClientCommandReplyCallback cb;
76 /* Default reply callback */
79 cmd->conn->client->internal->ops->command_reply(
80 cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
86 silc_list_start(cmd->reply_callbacks);
87 while ((cb = silc_list_get(cmd->reply_callbacks)))
88 if (!cb->do_not_call) {
90 cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
91 cmd->status, cmd->error, cb->context, cp);
98 /* Handles common error status types. */
100 static void silc_client_command_process_error(SilcClientCommandContext cmd,
101 SilcCommandPayload payload,
104 SilcClient client = cmd->conn->client;
105 SilcClientConnection conn = cmd->conn;
106 SilcArgumentPayload args = silc_command_get_args(payload);
107 SilcClientEntry client_entry;
110 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
111 /* Remove unknown client entry from cache */
112 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
115 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
117 silc_client_remove_from_channels(client, conn, client_entry);
118 silc_client_del_client(client, conn, client_entry);
119 silc_client_unref_client(client, conn, client_entry);
124 /***************************** Command Reply ********************************/
126 /* Process received command reply packet */
128 SILC_FSM_STATE(silc_client_command_reply)
130 SilcClientConnection conn = fsm_context;
131 SilcPacket packet = state_context;
132 SilcClientCommandContext cmd;
133 SilcCommandPayload payload;
135 SilcUInt16 cmd_ident;
137 /* Get command reply payload from packet */
138 payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
139 silc_packet_free(packet);
141 SILC_LOG_DEBUG(("Bad command reply packet"));
142 return SILC_FSM_FINISH;
145 cmd_ident = silc_command_get_ident(payload);
146 command = silc_command_get(payload);
148 /* Find the command pending reply */
149 silc_mutex_lock(conn->internal->lock);
150 silc_list_start(conn->internal->pending_commands);
151 while ((cmd = silc_list_get(conn->internal->pending_commands))) {
152 if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
153 && cmd->cmd_ident == cmd_ident) {
154 silc_list_del(conn->internal->pending_commands, cmd);
158 silc_mutex_unlock(conn->internal->lock);
161 SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
162 silc_get_command_name(command), cmd_ident));
163 silc_command_payload_free(payload);
164 return SILC_FSM_FINISH;
167 /* Signal command thread that command reply has arrived */
168 silc_fsm_set_state_context(&cmd->thread, payload);
169 silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
170 silc_fsm_continue_sync(&cmd->thread);
172 return SILC_FSM_FINISH;
175 /* Wait here for command reply to arrive from remote host */
177 SILC_FSM_STATE(silc_client_command_reply_wait)
179 SilcClientCommandContext cmd = fsm_context;
181 SILC_LOG_DEBUG(("Wait for command reply"));
183 /** Wait for command reply */
184 silc_fsm_set_state_context(fsm, NULL);
185 silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
186 cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0);
187 return SILC_FSM_WAIT;
190 /* Timeout occurred while waiting command reply */
192 SILC_FSM_STATE(silc_client_command_reply_timeout)
194 SilcClientCommandContext cmd = fsm_context;
195 SilcClientConnection conn = cmd->conn;
196 SilcArgumentPayload args = NULL;
198 if (conn->internal->disconnected) {
199 SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
200 silc_list_del(conn->internal->pending_commands, cmd);
201 return SILC_FSM_FINISH;
204 SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
206 /* Timeout, reply not received in timely fashion */
207 silc_list_del(conn->internal->pending_commands, cmd);
208 ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
209 return SILC_FSM_FINISH;
212 /* Process received command reply payload */
214 SILC_FSM_STATE(silc_client_command_reply_process)
216 SilcClientCommandContext cmd = fsm_context;
217 SilcCommandPayload payload = state_context;
219 silc_command_get_status(payload, &cmd->status, &cmd->error);
222 case SILC_COMMAND_WHOIS:
224 silc_fsm_next(fsm, silc_client_command_reply_whois);
226 case SILC_COMMAND_WHOWAS:
228 silc_fsm_next(fsm, silc_client_command_reply_whowas);
230 case SILC_COMMAND_IDENTIFY:
232 silc_fsm_next(fsm, silc_client_command_reply_identify);
234 case SILC_COMMAND_NICK:
236 silc_fsm_next(fsm, silc_client_command_reply_nick);
238 case SILC_COMMAND_LIST:
240 silc_fsm_next(fsm, silc_client_command_reply_list);
242 case SILC_COMMAND_TOPIC:
244 silc_fsm_next(fsm, silc_client_command_reply_topic);
246 case SILC_COMMAND_INVITE:
248 silc_fsm_next(fsm, silc_client_command_reply_invite);
250 case SILC_COMMAND_QUIT:
252 silc_fsm_next(fsm, silc_client_command_reply_quit);
254 case SILC_COMMAND_KILL:
256 silc_fsm_next(fsm, silc_client_command_reply_kill);
258 case SILC_COMMAND_INFO:
260 silc_fsm_next(fsm, silc_client_command_reply_info);
262 case SILC_COMMAND_STATS:
264 silc_fsm_next(fsm, silc_client_command_reply_stats);
266 case SILC_COMMAND_PING:
268 silc_fsm_next(fsm, silc_client_command_reply_ping);
270 case SILC_COMMAND_OPER:
272 silc_fsm_next(fsm, silc_client_command_reply_oper);
274 case SILC_COMMAND_JOIN:
276 silc_fsm_next(fsm, silc_client_command_reply_join);
278 case SILC_COMMAND_MOTD:
280 silc_fsm_next(fsm, silc_client_command_reply_motd);
282 case SILC_COMMAND_UMODE:
284 silc_fsm_next(fsm, silc_client_command_reply_umode);
286 case SILC_COMMAND_CMODE:
288 silc_fsm_next(fsm, silc_client_command_reply_cmode);
290 case SILC_COMMAND_CUMODE:
292 silc_fsm_next(fsm, silc_client_command_reply_cumode);
294 case SILC_COMMAND_KICK:
296 silc_fsm_next(fsm, silc_client_command_reply_kick);
298 case SILC_COMMAND_BAN:
300 silc_fsm_next(fsm, silc_client_command_reply_ban);
302 case SILC_COMMAND_DETACH:
304 silc_fsm_next(fsm, silc_client_command_reply_detach);
306 case SILC_COMMAND_WATCH:
308 silc_fsm_next(fsm, silc_client_command_reply_watch);
310 case SILC_COMMAND_SILCOPER:
312 silc_fsm_next(fsm, silc_client_command_reply_silcoper);
314 case SILC_COMMAND_LEAVE:
316 silc_fsm_next(fsm, silc_client_command_reply_leave);
318 case SILC_COMMAND_USERS:
320 silc_fsm_next(fsm, silc_client_command_reply_users);
322 case SILC_COMMAND_GETKEY:
324 silc_fsm_next(fsm, silc_client_command_reply_getkey);
326 case SILC_COMMAND_SERVICE:
328 silc_fsm_next(fsm, silc_client_command_reply_service);
331 return SILC_FSM_FINISH;
334 return SILC_FSM_CONTINUE;
337 /* Completes command reply processing */
339 SILC_FSM_STATE(silc_client_command_reply_processed)
341 SilcClientCommandContext cmd = fsm_context;
342 SilcClientConnection conn = cmd->conn;
343 SilcCommandPayload payload = state_context;
345 silc_command_payload_free(payload);
347 if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
348 SILC_STATUS_IS_ERROR(cmd->status))
349 return SILC_FSM_FINISH;
351 /* Add back to pending command reply list */
352 silc_mutex_lock(conn->internal->lock);
353 cmd->resolved = FALSE;
354 silc_list_add(conn->internal->pending_commands, cmd);
355 silc_mutex_unlock(conn->internal->lock);
357 /** Wait more command payloads */
358 silc_fsm_next(fsm, silc_client_command_reply_wait);
359 return SILC_FSM_CONTINUE;
362 /******************************** WHOIS *************************************/
364 /* Received reply for WHOIS command. */
366 SILC_FSM_STATE(silc_client_command_reply_whois)
368 SilcClientCommandContext cmd = fsm_context;
369 SilcClientConnection conn = cmd->conn;
370 SilcClient client = conn->client;
371 SilcCommandPayload payload = state_context;
372 SilcArgumentPayload args = silc_command_get_args(payload);
373 SilcClientEntry client_entry = NULL;
374 SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
375 SilcBufferStruct channels, ch_user_modes;
376 SilcBool has_channels = FALSE;
377 SilcDList channel_list = NULL;
379 char *nickname = NULL, *username = NULL, *realname = NULL;
380 unsigned char *fingerprint, *tmp;
382 CHECK_STATUS("WHOIS: ");
386 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
387 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
392 nickname = silc_argument_get_arg_type(args, 3, NULL);
393 username = silc_argument_get_arg_type(args, 4, NULL);
394 realname = silc_argument_get_arg_type(args, 5, NULL);
395 if (!nickname || !username || !realname) {
396 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
400 /* Get joined channel list */
401 memset(&channels, 0, sizeof(channels));
402 tmp = silc_argument_get_arg_type(args, 6, &len);
405 silc_buffer_set(&channels, tmp, len);
407 /* Get channel user mode list */
408 tmp = silc_argument_get_arg_type(args, 10, &len);
410 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
413 silc_buffer_set(&ch_user_modes, tmp, len);
417 tmp = silc_argument_get_arg_type(args, 7, &len);
419 SILC_GET32_MSB(mode, tmp);
422 tmp = silc_argument_get_arg_type(args, 8, &len);
424 SILC_GET32_MSB(idle, tmp);
426 /* Get fingerprint */
427 fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
429 /* Check if we have this client cached already. */
430 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
432 SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
434 silc_client_add_client(client, conn, nickname, username, realname,
435 &id.u.client_id, mode);
437 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
440 silc_client_ref_client(client, conn, client_entry);
442 silc_client_update_client(client, conn, client_entry,
443 nickname, username, realname, mode);
446 if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
447 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
449 /* Get user attributes */
450 tmp = silc_argument_get_arg_type(args, 11, &len);
452 if (client_entry->attrs)
453 silc_attribute_payload_list_free(client_entry->attrs);
454 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
457 /* Parse channel and channel user mode list */
459 channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
460 silc_buffer_len(&channels));
462 silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
466 /* Notify application */
467 silc_client_command_callback(cmd, client_entry, nickname, username,
468 realname, channel_list, mode, idle, fingerprint,
469 umodes, client_entry->attrs);
471 silc_client_unref_client(client, conn, client_entry);
473 silc_dlist_uninit(channel_list);
478 silc_fsm_next(fsm, silc_client_command_reply_processed);
479 return SILC_FSM_CONTINUE;
482 /******************************** WHOWAS ************************************/
484 /* Received reply for WHOWAS command. */
486 SILC_FSM_STATE(silc_client_command_reply_whowas)
488 SilcClientCommandContext cmd = fsm_context;
489 SilcClientConnection conn = cmd->conn;
490 SilcClient client = conn->client;
491 SilcCommandPayload payload = state_context;
492 SilcArgumentPayload args = silc_command_get_args(payload);
493 SilcClientEntry client_entry = NULL;
495 char *nickname, *username;
496 char *realname = NULL;
498 CHECK_STATUS("WHOWAS: ");
502 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
503 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
507 /* Get the client entry */
508 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
511 nickname = silc_argument_get_arg_type(args, 3, NULL);
512 username = silc_argument_get_arg_type(args, 4, NULL);
513 realname = silc_argument_get_arg_type(args, 5, NULL);
514 if (!nickname || !username) {
515 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
519 /* Notify application. We don't save any history information to any
520 cache. Just pass the data to the application. */
521 silc_client_command_callback(cmd, client_entry, nickname, username,
525 silc_client_unref_client(client, conn, client_entry);
526 silc_fsm_next(fsm, silc_client_command_reply_processed);
527 return SILC_FSM_CONTINUE;
530 /******************************** IDENTIFY **********************************/
532 /* Received reply for IDENTIFY command. */
534 SILC_FSM_STATE(silc_client_command_reply_identify)
536 SilcClientCommandContext cmd = fsm_context;
537 SilcClientConnection conn = cmd->conn;
538 SilcClient client = conn->client;
539 SilcCommandPayload payload = state_context;
540 SilcArgumentPayload args = silc_command_get_args(payload);
541 SilcClientEntry client_entry;
542 SilcServerEntry server_entry;
543 SilcChannelEntry channel_entry;
546 char *name = NULL, *info = NULL;
548 CHECK_STATUS("IDENTIFY: ");
552 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
553 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
558 name = silc_argument_get_arg_type(args, 3, &len);
559 info = silc_argument_get_arg_type(args, 4, &len);
563 SILC_LOG_DEBUG(("Received client information"));
565 /* Check if we have this client cached already. */
566 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
568 SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
570 silc_client_add_client(client, conn, name, info, NULL,
573 ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
576 silc_client_ref_client(client, conn, client_entry);
578 silc_client_update_client(client, conn, client_entry,
579 name, info, NULL, 0);
582 /* Notify application */
583 silc_client_command_callback(cmd, client_entry, name, info);
584 silc_client_unref_client(client, conn, client_entry);
588 SILC_LOG_DEBUG(("Received server information"));
590 /* Check if we have this server cached already. */
591 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
593 SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
594 server_entry = silc_client_add_server(client, conn, name, info,
597 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
600 silc_client_ref_server(client, conn, server_entry);
602 silc_client_update_server(client, conn, server_entry, name, info);
604 server_entry->internal.resolve_cmd_ident = 0;
606 /* Notify application */
607 silc_client_command_callback(cmd, server_entry, name, info);
608 silc_client_unref_server(client, conn, server_entry);
611 case SILC_ID_CHANNEL:
612 SILC_LOG_DEBUG(("Received channel information"));
614 /* Check if we have this channel cached already. */
615 channel_entry = silc_client_get_channel_by_id(client, conn,
617 if (!channel_entry) {
618 SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
621 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
625 /* Add new channel entry */
626 channel_entry = silc_client_add_channel(client, conn, name, 0,
628 if (!channel_entry) {
629 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
632 silc_client_ref_channel(client, conn, channel_entry);
635 /* Notify application */
636 silc_client_command_callback(cmd, channel_entry, name, info);
637 silc_client_unref_channel(client, conn, channel_entry);
642 silc_fsm_next(fsm, silc_client_command_reply_processed);
643 return SILC_FSM_CONTINUE;
646 /********************************** NICK ************************************/
648 /* Received reply for command NICK. */
650 SILC_FSM_STATE(silc_client_command_reply_nick)
652 SilcClientCommandContext cmd = fsm_context;
653 SilcClientConnection conn = cmd->conn;
654 SilcClient client = conn->client;
655 SilcCommandPayload payload = state_context;
656 SilcArgumentPayload args = silc_command_get_args(payload);
657 unsigned char *tmp, *nick, *idp;
658 SilcUInt32 len, idp_len;
659 SilcClientID old_client_id;
663 CHECK_STATUS("Cannot set nickname: ");
666 old_client_id = *conn->local_id;
668 /* Take received Client ID */
669 idp = silc_argument_get_arg_type(args, 2, &idp_len);
671 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
674 if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
675 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
679 /* Take the new nickname */
680 nick = silc_argument_get_arg_type(args, 3, &len);
682 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
686 /* Normalize nickname */
687 tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
689 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
693 /* Update the client entry */
694 silc_mutex_lock(conn->internal->lock);
695 if (!silc_idcache_update(conn->internal->client_cache,
696 conn->internal->local_entry,
697 &id.u.client_id, tmp, TRUE)) {
699 silc_mutex_unlock(conn->internal->lock);
700 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
703 silc_mutex_unlock(conn->internal->lock);
704 memset(conn->local_entry->nickname, 0, sizeof(conn->local_entry->nickname));
705 memcpy(conn->local_entry->nickname, nick, len);
706 conn->local_entry->nickname_normalized = tmp;
707 silc_buffer_enlarge(conn->internal->local_idp, idp_len);
708 silc_buffer_put(conn->internal->local_idp, idp, idp_len);
709 silc_client_nickname_format(client, conn, conn->local_entry);
710 silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id, 0, NULL);
712 /* Notify application */
713 silc_client_command_callback(cmd, conn->local_entry,
714 conn->local_entry->nickname, &old_client_id);
717 silc_fsm_next(fsm, silc_client_command_reply_processed);
718 return SILC_FSM_CONTINUE;
721 /********************************** LIST ************************************/
723 /* Received reply to the LIST command. */
725 SILC_FSM_STATE(silc_client_command_reply_list)
727 SilcClientCommandContext cmd = fsm_context;
728 SilcClientConnection conn = cmd->conn;
729 SilcClient client = conn->client;
730 SilcCommandPayload payload = state_context;
731 SilcArgumentPayload args = silc_command_get_args(payload);
732 unsigned char *tmp, *name, *topic;
733 SilcUInt32 usercount = 0;
734 SilcChannelEntry channel_entry = NULL;
738 CHECK_STATUS("Cannot list channels: ");
740 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
741 /* There were no channels in the network. */
742 silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
743 silc_fsm_next(fsm, silc_client_command_reply_processed);
744 return SILC_FSM_CONTINUE;
749 name = silc_argument_get_arg_type(args, 3, NULL);
751 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
755 topic = silc_argument_get_arg_type(args, 4, NULL);
756 tmp = silc_argument_get_arg_type(args, 5, NULL);
758 SILC_GET32_MSB(usercount, tmp);
760 /* Check whether the channel exists, and add it to cache if it doesn't. */
761 channel_entry = silc_client_get_channel_by_id(client, conn,
763 if (!channel_entry) {
764 /* Add new channel entry */
765 channel_entry = silc_client_add_channel(client, conn, name, 0,
767 if (!channel_entry) {
768 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
771 silc_client_ref_channel(client, conn, channel_entry);
774 /* Notify application */
775 silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
778 silc_client_unref_channel(client, conn, channel_entry);
779 silc_fsm_next(fsm, silc_client_command_reply_processed);
780 return SILC_FSM_CONTINUE;
783 /********************************* TOPIC ************************************/
785 /* Received reply to topic command. */
787 SILC_FSM_STATE(silc_client_command_reply_topic)
789 SilcClientCommandContext cmd = fsm_context;
790 SilcClientConnection conn = cmd->conn;
791 SilcClient client = conn->client;
792 SilcCommandPayload payload = state_context;
793 SilcArgumentPayload args = silc_command_get_args(payload);
794 SilcChannelEntry channel;
800 CHECK_STATUS("Cannot set topic: ");
803 /* Take Channel ID */
804 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
805 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
809 /* Get the channel entry */
810 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
812 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
817 topic = silc_argument_get_arg_type(args, 3, &len);
819 silc_free(channel->topic);
820 channel->topic = silc_memdup(topic, len);
823 /* Notify application */
824 silc_client_command_callback(cmd, channel, channel->topic);
827 silc_fsm_next(fsm, silc_client_command_reply_processed);
828 return SILC_FSM_CONTINUE;
831 /********************************* INVITE ***********************************/
833 /* Received reply to invite command. */
835 SILC_FSM_STATE(silc_client_command_reply_invite)
837 SilcClientCommandContext cmd = fsm_context;
838 SilcClientConnection conn = cmd->conn;
839 SilcClient client = conn->client;
840 SilcCommandPayload payload = state_context;
841 SilcArgumentPayload args = silc_command_get_args(payload);
842 SilcChannelEntry channel;
845 SilcArgumentPayload invite_args = NULL;
849 CHECK_STATUS("Cannot invite: ");
852 /* Take Channel ID */
853 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
854 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
858 /* Get the channel entry */
859 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
861 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
865 /* Get the invite list */
866 tmp = silc_argument_get_arg_type(args, 3, &len);
868 invite_args = silc_argument_list_parse(tmp, len);
870 /* Notify application */
871 silc_client_command_callback(cmd, channel, invite_args);
874 silc_argument_payload_free(invite_args);
877 silc_fsm_next(fsm, silc_client_command_reply_processed);
878 return SILC_FSM_CONTINUE;
881 /********************************** KILL ************************************/
883 /* Received reply to the KILL command. */
885 SILC_FSM_STATE(silc_client_command_reply_kill)
887 SilcClientCommandContext cmd = fsm_context;
888 SilcClientConnection conn = cmd->conn;
889 SilcClient client = conn->client;
890 SilcCommandPayload payload = state_context;
891 SilcArgumentPayload args = silc_command_get_args(payload);
892 SilcClientEntry client_entry;
896 CHECK_STATUS("Cannot kill: ");
899 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
900 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
904 /* Get the client entry, if exists */
905 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
907 /* Notify application */
908 silc_client_command_callback(cmd, client_entry);
910 /* Remove the client from all channels and free it */
912 silc_client_remove_from_channels(client, conn, client_entry);
913 silc_client_del_client(client, conn, client_entry);
914 silc_client_unref_client(client, conn, client_entry);
918 silc_fsm_next(fsm, silc_client_command_reply_processed);
919 return SILC_FSM_CONTINUE;
922 /********************************** INFO ************************************/
924 /* Received reply to INFO command. We receive the server ID and some
925 information about the server user requested. */
927 SILC_FSM_STATE(silc_client_command_reply_info)
929 SilcClientCommandContext cmd = fsm_context;
930 SilcClientConnection conn = cmd->conn;
931 SilcClient client = conn->client;
932 SilcCommandPayload payload = state_context;
933 SilcArgumentPayload args = silc_command_get_args(payload);
934 SilcServerEntry server;
935 char *server_name, *server_info;
939 CHECK_STATUS("Cannot get info: ");
943 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
944 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
948 /* Get server name */
949 server_name = silc_argument_get_arg_type(args, 3, NULL);
951 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
955 /* Get server info */
956 server_info = silc_argument_get_arg_type(args, 4, NULL);
958 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
962 /* See whether we have this server cached. If not create it. */
963 server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
965 SILC_LOG_DEBUG(("Add new server entry (INFO)"));
966 server = silc_client_add_server(client, conn, server_name,
967 server_info, &id.u.server_id);
970 silc_client_ref_server(client, conn, server);
973 /* Notify application */
974 silc_client_command_callback(cmd, server, server->server_name,
975 server->server_info);
976 silc_client_unref_server(client, conn, server);
979 silc_fsm_next(fsm, silc_client_command_reply_processed);
980 return SILC_FSM_CONTINUE;
983 /********************************** STATS ***********************************/
985 /* Received reply to STATS command. */
987 SILC_FSM_STATE(silc_client_command_reply_stats)
989 SilcClientCommandContext cmd = fsm_context;
990 SilcCommandPayload payload = state_context;
991 SilcArgumentPayload args = silc_command_get_args(payload);
992 SilcClientStats stats;
993 unsigned char *buf = NULL;
994 SilcUInt32 buf_len = 0;
999 CHECK_STATUS("Cannot get stats: ");
1003 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1004 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1008 /* Get statistics structure */
1009 memset(&stats, 0, sizeof(stats));
1010 buf = silc_argument_get_arg_type(args, 3, &buf_len);
1012 silc_buffer_set(&b, buf, buf_len);
1013 silc_buffer_unformat(&b,
1014 SILC_STR_UI_INT(&stats.starttime),
1015 SILC_STR_UI_INT(&stats.uptime),
1016 SILC_STR_UI_INT(&stats.my_clients),
1017 SILC_STR_UI_INT(&stats.my_channels),
1018 SILC_STR_UI_INT(&stats.my_server_ops),
1019 SILC_STR_UI_INT(&stats.my_router_ops),
1020 SILC_STR_UI_INT(&stats.cell_clients),
1021 SILC_STR_UI_INT(&stats.cell_channels),
1022 SILC_STR_UI_INT(&stats.cell_servers),
1023 SILC_STR_UI_INT(&stats.clients),
1024 SILC_STR_UI_INT(&stats.channels),
1025 SILC_STR_UI_INT(&stats.servers),
1026 SILC_STR_UI_INT(&stats.routers),
1027 SILC_STR_UI_INT(&stats.server_ops),
1028 SILC_STR_UI_INT(&stats.router_ops),
1032 /* Notify application */
1033 silc_client_command_callback(cmd, &stats);
1036 silc_fsm_next(fsm, silc_client_command_reply_processed);
1037 return SILC_FSM_CONTINUE;
1040 /********************************** PING ************************************/
1042 /* Received reply to PING command. */
1044 SILC_FSM_STATE(silc_client_command_reply_ping)
1046 SilcClientCommandContext cmd = fsm_context;
1047 SilcClientConnection conn = cmd->conn;
1048 SilcClient client = conn->client;
1051 diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1053 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1054 "Ping reply from %s: %d second%s", conn->remote_host,
1055 (int)diff, diff == 1 ? "" : "s");
1057 /* Notify application */
1058 silc_client_command_callback(cmd);
1060 silc_fsm_next(fsm, silc_client_command_reply_processed);
1061 return SILC_FSM_CONTINUE;
1064 /********************************** JOIN ************************************/
1066 /* Continue JOIN command reply processing after resolving unknown users */
1069 silc_client_command_reply_join_resolved(SilcClient client,
1070 SilcClientConnection conn,
1075 SilcClientCommandContext cmd = context;
1076 SilcChannelEntry channel = cmd->context;
1078 channel->internal.resolve_cmd_ident = 0;
1079 silc_client_unref_channel(client, conn, channel);
1081 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1085 /* Received reply for JOIN command. */
1087 SILC_FSM_STATE(silc_client_command_reply_join)
1089 SilcClientCommandContext cmd = fsm_context;
1090 SilcClientConnection conn = cmd->conn;
1091 SilcClient client = conn->client;
1092 SilcCommandPayload payload = state_context;
1093 SilcArgumentPayload args = silc_command_get_args(payload);
1094 SilcChannelEntry channel;
1095 SilcUInt32 mode = 0, len, list_count;
1096 char *topic, *tmp, *channel_name = NULL, *hmac;
1098 SilcBufferStruct client_id_list, client_mode_list, keyp;
1099 SilcHashTableList htl;
1100 SilcDList chpks = NULL;
1105 CHECK_STATUS("Cannot join channel: ");
1108 /* Get channel name */
1109 channel_name = silc_argument_get_arg_type(args, 2, NULL);
1110 if (!channel_name) {
1111 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1115 /* Get Channel ID */
1116 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1117 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1121 /* Check whether we have this channel entry already. */
1122 channel = silc_client_get_channel(client, conn, channel_name);
1124 if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1125 silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1127 /* Create new channel entry */
1128 channel = silc_client_add_channel(client, conn, channel_name,
1129 mode, &id.u.channel_id);
1131 ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1134 silc_client_ref_channel(client, conn, channel);
1137 /* Get the list count */
1138 tmp = silc_argument_get_arg_type(args, 12, &len);
1140 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1143 SILC_GET32_MSB(list_count, tmp);
1145 /* Get Client ID list */
1146 tmp = silc_argument_get_arg_type(args, 13, &len);
1148 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1151 silc_buffer_set(&client_id_list, tmp, len);
1153 /* Resolve users we do not know about */
1154 if (!cmd->resolved) {
1155 cmd->resolved = TRUE;
1156 cmd->context = channel;
1157 SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1158 silc_client_get_clients_by_list(
1159 client, conn, list_count, &client_id_list,
1160 silc_client_command_reply_join_resolved, cmd));
1164 /* Get client mode list */
1165 tmp = silc_argument_get_arg_type(args, 14, &len);
1167 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1170 silc_buffer_set(&client_mode_list, tmp, len);
1172 /* Add clients we received in the reply to the channel */
1173 for (i = 0; i < list_count; i++) {
1177 SilcClientEntry client_entry;
1180 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1182 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1186 SILC_GET32_MSB(mode, client_mode_list.data);
1188 /* Get client entry */
1189 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1193 /* Join client to the channel */
1194 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1195 silc_client_unref_client(client, conn, client_entry);
1197 if (!silc_buffer_pull(&client_id_list, idp_len))
1199 if (!silc_buffer_pull(&client_mode_list, 4))
1204 hmac = silc_argument_get_arg_type(args, 11, NULL);
1206 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1208 SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1209 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1210 ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1215 /* Get channel mode */
1216 tmp = silc_argument_get_arg_type(args, 5, NULL);
1218 SILC_GET32_MSB(mode, tmp);
1219 channel->mode = mode;
1221 /* Get channel key and save it */
1222 tmp = silc_argument_get_arg_type(args, 7, &len);
1224 silc_buffer_set(&keyp, tmp, len);
1225 silc_client_save_channel_key(client, conn, &keyp, channel);
1229 topic = silc_argument_get_arg_type(args, 10, NULL);
1231 silc_free(channel->topic);
1232 channel->topic = silc_memdup(topic, strlen(topic));
1235 /* Get founder key */
1236 tmp = silc_argument_get_arg_type(args, 15, &len);
1238 if (channel->founder_key)
1239 silc_pkcs_public_key_free(channel->founder_key);
1240 channel->founder_key = NULL;
1241 silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1244 /* Get user limit */
1245 tmp = silc_argument_get_arg_type(args, 17, &len);
1246 if (tmp && len == 4)
1247 SILC_GET32_MSB(channel->user_limit, tmp);
1248 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1249 channel->user_limit = 0;
1251 /* Get channel public key list */
1252 tmp = silc_argument_get_arg_type(args, 16, &len);
1254 chpks = silc_argument_list_parse_decoded(tmp, len,
1255 SILC_ARGUMENT_PUBLIC_KEY);
1257 /* Set current channel */
1258 conn->current_channel = channel;
1260 cipher = (channel->internal.channel_key ?
1261 silc_cipher_get_name(channel->internal.channel_key) : NULL);
1262 silc_hash_table_list(channel->user_list, &htl);
1264 /* Notify application */
1265 silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
1266 topic, cipher, hmac, channel->founder_key,
1267 chpks, channel->user_limit);
1270 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
1271 silc_hash_table_list_reset(&htl);
1272 silc_client_unref_channel(client, conn, channel);
1275 silc_fsm_next(fsm, silc_client_command_reply_processed);
1276 return SILC_FSM_CONTINUE;
1279 /********************************** MOTD ************************************/
1281 /* Received reply for MOTD command */
1283 SILC_FSM_STATE(silc_client_command_reply_motd)
1285 SilcClientCommandContext cmd = fsm_context;
1286 SilcClientConnection conn = cmd->conn;
1287 SilcClient client = conn->client;
1288 SilcCommandPayload payload = state_context;
1289 SilcArgumentPayload args = silc_command_get_args(payload);
1291 char *motd = NULL, *cp, line[256];
1294 CHECK_STATUS("Cannot get motd: ");
1297 if (silc_argument_get_arg_num(args) == 3) {
1298 motd = silc_argument_get_arg_type(args, 3, NULL);
1300 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1307 if (cp[i++] == '\n') {
1308 memset(line, 0, sizeof(line));
1309 silc_strncat(line, sizeof(line), cp, i - 1);
1316 SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1325 /* Notify application */
1326 silc_client_command_callback(cmd, motd);
1329 silc_fsm_next(fsm, silc_client_command_reply_processed);
1330 return SILC_FSM_CONTINUE;
1333 /********************************** UMODE ***********************************/
1335 /* Received reply to the UMODE command. Save the current user mode */
1337 SILC_FSM_STATE(silc_client_command_reply_umode)
1339 SilcClientCommandContext cmd = fsm_context;
1340 SilcClientConnection conn = cmd->conn;
1341 SilcCommandPayload payload = state_context;
1342 SilcArgumentPayload args = silc_command_get_args(payload);
1344 SilcUInt32 mode, len;
1347 CHECK_STATUS("Cannot change mode: ");
1350 tmp = silc_argument_get_arg_type(args, 2, &len);
1351 if (!tmp || len != 4) {
1352 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1356 SILC_GET32_MSB(mode, tmp);
1357 conn->local_entry->mode = mode;
1359 /* Notify application */
1360 silc_client_command_callback(cmd, mode);
1363 silc_fsm_next(fsm, silc_client_command_reply_processed);
1364 return SILC_FSM_CONTINUE;
1367 /********************************** CMODE ***********************************/
1369 /* Received reply for CMODE command. */
1371 SILC_FSM_STATE(silc_client_command_reply_cmode)
1373 SilcClientCommandContext cmd = fsm_context;
1374 SilcClientConnection conn = cmd->conn;
1375 SilcClient client = conn->client;
1376 SilcCommandPayload payload = state_context;
1377 SilcArgumentPayload args = silc_command_get_args(payload);
1380 SilcChannelEntry channel;
1382 SilcPublicKey public_key = NULL;
1383 SilcDList channel_pubkeys = NULL;
1387 CHECK_STATUS("Cannot change mode: ");
1390 /* Take Channel ID */
1391 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1392 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1396 /* Get the channel entry */
1397 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1399 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1403 /* Get channel mode */
1404 tmp = silc_argument_get_arg_type(args, 3, &len);
1405 if (!tmp || len != 4) {
1406 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1411 SILC_GET32_MSB(mode, tmp);
1412 channel->mode = mode;
1414 /* Get founder public key */
1415 tmp = silc_argument_get_arg_type(args, 4, &len);
1417 silc_public_key_payload_decode(tmp, len, &public_key);
1419 /* Get user limit */
1420 tmp = silc_argument_get_arg_type(args, 6, &len);
1421 if (tmp && len == 4)
1422 SILC_GET32_MSB(channel->user_limit, tmp);
1423 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1424 channel->user_limit = 0;
1426 /* Get channel public key(s) */
1427 tmp = silc_argument_get_arg_type(args, 5, &len);
1430 silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1432 /* Notify application */
1433 silc_client_command_callback(cmd, channel, mode, public_key,
1434 channel_pubkeys, channel->user_limit);
1436 silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1440 silc_pkcs_public_key_free(public_key);
1441 silc_fsm_next(fsm, silc_client_command_reply_processed);
1442 return SILC_FSM_CONTINUE;
1445 /********************************** CUMODE **********************************/
1447 /* Received reply for CUMODE command */
1449 SILC_FSM_STATE(silc_client_command_reply_cumode)
1451 SilcClientCommandContext cmd = fsm_context;
1452 SilcClientConnection conn = cmd->conn;
1453 SilcClient client = conn->client;
1454 SilcCommandPayload payload = state_context;
1455 SilcArgumentPayload args = silc_command_get_args(payload);
1456 SilcClientEntry client_entry;
1457 SilcChannelEntry channel;
1458 SilcChannelUser chu;
1459 unsigned char *modev;
1460 SilcUInt32 len, mode;
1464 CHECK_STATUS("Cannot change mode: ");
1467 /* Get channel mode */
1468 modev = silc_argument_get_arg_type(args, 2, &len);
1469 if (!modev || len != 4) {
1470 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1473 SILC_GET32_MSB(mode, modev);
1475 /* Take Channel ID */
1476 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1477 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1481 /* Get the channel entry */
1482 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1484 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1489 if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1490 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1494 /* Get client entry */
1495 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1496 if (!client_entry) {
1497 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1502 chu = silc_client_on_channel(channel, client_entry);
1506 /* Notify application */
1507 silc_client_command_callback(cmd, mode, channel, client_entry);
1509 silc_client_unref_client(client, conn, client_entry);
1512 silc_fsm_next(fsm, silc_client_command_reply_processed);
1513 return SILC_FSM_CONTINUE;
1516 /********************************** KICK ************************************/
1518 SILC_FSM_STATE(silc_client_command_reply_kick)
1520 SilcClientCommandContext cmd = fsm_context;
1521 SilcClientConnection conn = cmd->conn;
1522 SilcClient client = conn->client;
1523 SilcCommandPayload payload = state_context;
1524 SilcArgumentPayload args = silc_command_get_args(payload);
1525 SilcClientEntry client_entry;
1526 SilcChannelEntry channel;
1530 CHECK_STATUS("Cannot kick: ");
1533 /* Take Channel ID */
1534 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1535 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1539 /* Get the channel entry */
1540 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1542 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1547 if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1548 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1552 /* Get client entry */
1553 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1554 if (!client_entry) {
1555 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1559 /* Notify application */
1560 silc_client_command_callback(cmd, channel, client_entry);
1562 silc_client_unref_client(client, conn, client_entry);
1565 silc_fsm_next(fsm, silc_client_command_reply_processed);
1566 return SILC_FSM_CONTINUE;
1569 /******************************** SILCOPER **********************************/
1571 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1573 SilcClientCommandContext cmd = fsm_context;
1574 SilcCommandPayload payload = state_context;
1575 SilcArgumentPayload args = silc_command_get_args(payload);
1578 CHECK_STATUS("Cannot change mode: ");
1581 /* Notify application */
1582 silc_client_command_callback(cmd);
1584 silc_fsm_next(fsm, silc_client_command_reply_processed);
1585 return SILC_FSM_CONTINUE;
1588 /********************************** OPER ************************************/
1590 SILC_FSM_STATE(silc_client_command_reply_oper)
1592 SilcClientCommandContext cmd = fsm_context;
1593 SilcCommandPayload payload = state_context;
1594 SilcArgumentPayload args = silc_command_get_args(payload);
1597 CHECK_STATUS("Cannot change mode: ");
1600 /* Notify application */
1601 silc_client_command_callback(cmd);
1603 silc_fsm_next(fsm, silc_client_command_reply_processed);
1604 return SILC_FSM_CONTINUE;
1607 /********************************* DETACH ***********************************/
1609 SILC_FSM_STATE(silc_client_command_reply_detach)
1611 SilcClientCommandContext cmd = fsm_context;
1612 SilcClientConnection conn = cmd->conn;
1613 SilcClient client = conn->client;
1614 SilcCommandPayload payload = state_context;
1615 SilcArgumentPayload args = silc_command_get_args(payload);
1619 CHECK_STATUS("Cannot detach: ");
1622 /* Notify application */
1623 silc_client_command_callback(cmd);
1626 /* Generate the detachment data and deliver it to the client in the
1627 detach client operation */
1628 detach = silc_client_get_detach_data(client, conn);
1630 client->internal->ops->detach(client, conn, silc_buffer_data(detach),
1631 silc_buffer_len(detach));
1632 silc_buffer_free(detach);
1636 silc_fsm_next(fsm, silc_client_command_reply_processed);
1637 return SILC_FSM_CONTINUE;
1640 /********************************** WATCH ***********************************/
1642 SILC_FSM_STATE(silc_client_command_reply_watch)
1644 SilcClientCommandContext cmd = fsm_context;
1645 SilcCommandPayload payload = state_context;
1646 SilcArgumentPayload args = silc_command_get_args(payload);
1649 CHECK_STATUS("Cannot set watch: ");
1652 /* Notify application */
1653 silc_client_command_callback(cmd);
1655 silc_fsm_next(fsm, silc_client_command_reply_processed);
1656 return SILC_FSM_CONTINUE;
1659 /*********************************** BAN ************************************/
1661 SILC_FSM_STATE(silc_client_command_reply_ban)
1663 SilcClientCommandContext cmd = fsm_context;
1664 SilcClientConnection conn = cmd->conn;
1665 SilcClient client = conn->client;
1666 SilcCommandPayload payload = state_context;
1667 SilcArgumentPayload args = silc_command_get_args(payload);
1668 SilcChannelEntry channel;
1671 SilcArgumentPayload invite_args = NULL;
1675 CHECK_STATUS("Cannot set ban: ");
1678 /* Take Channel ID */
1679 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1680 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1684 /* Get the channel entry */
1685 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1687 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1691 /* Get the invite list */
1692 tmp = silc_argument_get_arg_type(args, 3, &len);
1694 invite_args = silc_argument_list_parse(tmp, len);
1696 /* Notify application */
1697 silc_client_command_callback(cmd, channel, invite_args);
1700 silc_argument_payload_free(invite_args);
1703 silc_fsm_next(fsm, silc_client_command_reply_processed);
1704 return SILC_FSM_CONTINUE;
1707 /********************************** LEAVE ***********************************/
1709 /* Reply to LEAVE command. */
1711 SILC_FSM_STATE(silc_client_command_reply_leave)
1713 SilcClientCommandContext cmd = fsm_context;
1714 SilcClientConnection conn = cmd->conn;
1715 SilcClient client = conn->client;
1716 SilcCommandPayload payload = state_context;
1717 SilcArgumentPayload args = silc_command_get_args(payload);
1718 SilcChannelEntry channel;
1722 CHECK_STATUS("Cannot set leave: ");
1725 /* Get Channel ID */
1726 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1727 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1731 /* Get the channel entry */
1732 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1734 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1738 /* Remove us from this channel. */
1739 silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1741 /* Notify application */
1742 silc_client_command_callback(cmd, channel);
1744 /* Now delete the channel. */
1745 silc_client_empty_channel(client, conn, channel);
1746 silc_client_del_channel(client, conn, channel);
1749 silc_fsm_next(fsm, silc_client_command_reply_processed);
1750 return SILC_FSM_CONTINUE;
1753 /********************************* USERS ************************************/
1755 /* Continue USERS command reply processing after resolving unknown users */
1758 silc_client_command_reply_users_resolved(SilcClient client,
1759 SilcClientConnection conn,
1764 SilcClientCommandContext cmd = context;
1765 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1769 /* Continue USERS command after resolving unknown channel */
1772 silc_client_command_reply_users_continue(SilcClient client,
1773 SilcClientConnection conn,
1778 SilcClientCommandContext cmd = context;
1781 SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1782 SilcArgumentPayload args = silc_command_get_args(payload);
1784 cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1785 ERROR_CALLBACK(cmd->status);
1786 silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1789 SILC_FSM_CALL_CONTINUE(&cmd->thread);
1792 /* Reply to USERS command. Received list of client ID's and theirs modes
1793 on the channel we requested. */
1795 SILC_FSM_STATE(silc_client_command_reply_users)
1797 SilcClientCommandContext cmd = fsm_context;
1798 SilcClientConnection conn = cmd->conn;
1799 SilcClient client = conn->client;
1800 SilcCommandPayload payload = state_context;
1801 SilcArgumentPayload args = silc_command_get_args(payload);
1803 SilcUInt32 tmp_len, list_count;
1804 SilcUInt16 idp_len, mode;
1805 SilcHashTableList htl;
1806 SilcBufferStruct client_id_list, client_mode_list;
1807 SilcChannelEntry channel;
1808 SilcClientEntry client_entry;
1813 CHECK_STATUS("Cannot get users: ");
1816 /* Get channel ID */
1817 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1818 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1822 /* Get channel entry */
1823 channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1825 /* Resolve the channel from server */
1826 SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1827 client, conn, &id.u.channel_id,
1828 silc_client_command_reply_users_continue, cmd));
1832 /* Get the list count */
1833 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1834 if (!tmp || tmp_len != 4) {
1835 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1838 SILC_GET32_MSB(list_count, tmp);
1840 /* Get Client ID list */
1841 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1843 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1846 silc_buffer_set(&client_id_list, tmp, tmp_len);
1848 /* Resolve users we do not know about */
1849 if (!cmd->resolved) {
1850 cmd->resolved = TRUE;
1851 SILC_FSM_CALL(silc_client_get_clients_by_list(
1852 client, conn, list_count, &client_id_list,
1853 silc_client_command_reply_users_resolved, cmd));
1857 /* Get client mode list */
1858 tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1860 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1863 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1865 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1867 /* Cache the received Client ID's and modes. */
1868 for (i = 0; i < list_count; i++) {
1869 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1871 if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1875 SILC_GET32_MSB(mode, client_mode_list.data);
1877 /* Save the client on this channel. Unknown clients are ignored as they
1878 clearly do not exist since the resolving didn't find them. */
1879 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1881 silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1882 silc_client_unref_client(client, conn, client_entry);
1884 if (!silc_buffer_pull(&client_id_list, idp_len))
1886 if (!silc_buffer_pull(&client_mode_list, 4))
1890 /* Notify application */
1891 silc_hash_table_list(channel->user_list, &htl);
1892 silc_client_command_callback(cmd, channel, &htl);
1893 silc_hash_table_list_reset(&htl);
1896 silc_fsm_next(fsm, silc_client_command_reply_processed);
1897 return SILC_FSM_CONTINUE;
1900 /********************************** GETKEY **********************************/
1902 /* Received command reply to GETKEY command. WE've received the remote
1903 client's public key. */
1905 SILC_FSM_STATE(silc_client_command_reply_getkey)
1907 SilcClientCommandContext cmd = fsm_context;
1908 SilcClientConnection conn = cmd->conn;
1909 SilcClient client = conn->client;
1910 SilcCommandPayload payload = state_context;
1911 SilcArgumentPayload args = silc_command_get_args(payload);
1912 SilcClientEntry client_entry;
1913 SilcServerEntry server_entry;
1916 SilcPublicKey public_key;
1920 CHECK_STATUS("Cannot get key: ");
1924 if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1925 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1929 /* Get the public key */
1930 tmp = silc_argument_get_arg_type(args, 3, &len);
1932 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1935 if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1936 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1940 if (id.type == SILC_ID_CLIENT) {
1941 /* Received client's public key */
1942 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1943 if (!client_entry) {
1944 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1948 /* Save fingerprint */
1949 if (!client_entry->fingerprint)
1950 silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
1951 client_entry->fingerprint);
1952 if (!client_entry->public_key) {
1953 client_entry->public_key = public_key;
1957 /* Notify application */
1958 silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1959 client_entry->public_key);
1960 silc_client_unref_client(client, conn, client_entry);
1961 } else if (id.type == SILC_ID_SERVER) {
1962 /* Received server's public key */
1963 server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1964 if (!server_entry) {
1965 ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1969 if (!server_entry->public_key) {
1970 server_entry->public_key = public_key;
1974 /* Notify application */
1975 silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1976 server_entry->public_key);
1977 silc_client_unref_server(client, conn, server_entry);
1982 silc_pkcs_public_key_free(public_key);
1983 silc_fsm_next(fsm, silc_client_command_reply_processed);
1984 return SILC_FSM_CONTINUE;
1987 /********************************** SERVICE *********************************/
1989 /* Reply to SERVICE command. */
1990 /* XXX incomplete */
1992 SILC_FSM_STATE(silc_client_command_reply_service)
1994 SilcClientCommandContext cmd = fsm_context;
1995 SilcCommandPayload payload = state_context;
1996 SilcArgumentPayload args = silc_command_get_args(payload);
1998 unsigned char *service_list, *name;
2001 CHECK_STATUS("Cannot get service: ");
2003 /* Get service list */
2004 service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2006 /* Get requested service name */
2007 name = silc_argument_get_arg_type(args, 3, &tmp_len);
2009 /* Notify application */
2010 silc_client_command_callback(cmd, service_list, name);
2012 silc_fsm_next(fsm, silc_client_command_reply_processed);
2013 return SILC_FSM_CONTINUE;
2016 /*********************************** QUIT ***********************************/
2018 /* QUIT command reply stub */
2020 SILC_FSM_STATE(silc_client_command_reply_quit)
2022 silc_fsm_next(fsm, silc_client_command_reply_processed);
2023 return SILC_FSM_CONTINUE;