silcclient: auto-negotiation of private message key using SKE over SILCnet
[silc.git] / lib / silcclient / command_reply.c
1 /*
2
3   command_reply.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2014 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /************************** Types and definitions ***************************/
26
27 /* Calls error command reply callback back to command sender. */
28 #define ERROR_CALLBACK(err)                                     \
29 do {                                                            \
30   void *arg1 = NULL, *arg2 = NULL;                              \
31   if (cmd->status != SILC_STATUS_OK)                            \
32     silc_status_get_args(cmd->status, args, &arg1, &arg2);      \
33   else                                                          \
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);                \
38 } while(0)
39
40 /* Check for error */
41 #define CHECK_STATUS(msg)                                               \
42   SILC_LOG_DEBUG(("%s", silc_get_command_name(cmd->cmd)));              \
43   if (cmd->error != SILC_STATUS_OK) {                                   \
44     if (cmd->verbose)                                                   \
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;                                           \
51   }
52
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;                                   \
60   }
61
62 #define SAY cmd->conn->client->internal->ops->say
63
64 /************************ Static utility functions **************************/
65
66 /* Delivers the command reply back to application */
67
68 static inline void
69 silc_client_command_callback(SilcClientCommandContext cmd, ...)
70 {
71   SilcClientCommandReplyCallback cb;
72   SilcList list;
73   va_list ap, cp;
74
75   va_start(ap, cmd);
76
77   /* Default reply callback */
78   if (cmd->called) {
79     silc_va_copy(cp, ap);
80     cmd->conn->client->internal->ops->command_reply(
81                        cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
82                        cmd->error, cp);
83     va_end(cp);
84   }
85
86   /* Reply callback */
87   list = cmd->reply_callbacks;
88   silc_list_start(list);
89   while ((cb = silc_list_get(list)))
90     if (!cb->do_not_call) {
91       silc_va_copy(cp, ap);
92       cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
93                                    cmd->status, cmd->error, cb->context, cp);
94       va_end(cp);
95     }
96
97   va_end(ap);
98 }
99
100 /* Handles common error status types. */
101
102 static void silc_client_command_process_error(SilcClientCommandContext cmd,
103                                               SilcCommandPayload payload,
104                                               SilcStatus error)
105 {
106   SilcClient client = cmd->conn->client;
107   SilcClientConnection conn = cmd->conn;
108   SilcArgumentPayload args = silc_command_get_args(payload);
109   SilcID id;
110
111   if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
112     SilcClientEntry client_entry;
113
114     /* Remove unknown client entry from cache */
115     if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
116       return;
117
118     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
119     if (client_entry) {
120       silc_client_remove_from_channels(client, conn, client_entry);
121       client_entry->internal.valid = FALSE;
122       silc_client_del_client(client, conn, client_entry);
123       silc_client_unref_client(client, conn, client_entry);
124     }
125     return;
126   }
127
128   if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
129     SilcChannelEntry channel;
130
131     /* Remove unknown channel entry from cache */
132     if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
133       return;
134
135     channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
136     if (channel) {
137       silc_client_empty_channel(client, conn, channel);
138       silc_client_del_channel(client, conn, channel);
139       silc_client_unref_channel(client, conn, channel);
140     }
141     return;
142   }
143
144   if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
145     SilcServerEntry server_entry;
146
147     /* Remove unknown server entry from cache */
148     if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
149       return;
150
151     server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
152     if (server_entry) {
153       silc_client_del_server(client, conn, server_entry);
154       silc_client_unref_server(client, conn, server_entry);
155     }
156     return;
157   }
158 }
159
160 /***************************** Command Reply ********************************/
161
162 /* Process received command reply packet */
163
164 SILC_FSM_STATE(silc_client_command_reply)
165 {
166   SilcClientConnection conn = fsm_context;
167   SilcPacket packet = state_context;
168   SilcClientCommandContext cmd;
169   SilcCommandPayload payload;
170   SilcCommand command;
171   SilcUInt16 cmd_ident;
172
173   /* Get command reply payload from packet */
174   payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
175   silc_packet_free(packet);
176   if (!payload) {
177     SILC_LOG_DEBUG(("Bad command reply packet"));
178     return SILC_FSM_FINISH;
179   }
180
181   cmd_ident = silc_command_get_ident(payload);
182   command = silc_command_get(payload);
183
184   /* Find the command pending reply */
185   silc_mutex_lock(conn->internal->lock);
186   silc_list_start(conn->internal->pending_commands);
187   while ((cmd = silc_list_get(conn->internal->pending_commands))) {
188     if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
189         && cmd->cmd_ident == cmd_ident) {
190       silc_list_del(conn->internal->pending_commands, cmd);
191       break;
192     }
193   }
194   silc_mutex_unlock(conn->internal->lock);
195
196   if (!cmd) {
197     SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
198                     silc_get_command_name(command), cmd_ident));
199     silc_command_payload_free(payload);
200     return SILC_FSM_FINISH;
201   }
202
203   /* Signal command thread that command reply has arrived.  We continue
204      command reply processing synchronously because we save the command
205      payload into state context.  No other reply may arrive to this command
206      while we're processing this reply. */
207   silc_fsm_set_state_context(&cmd->thread, payload);
208   silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
209   silc_fsm_continue_sync(&cmd->thread);
210
211   return SILC_FSM_FINISH;
212 }
213
214 /* Wait here for command reply to arrive from remote host */
215
216 SILC_FSM_STATE(silc_client_command_reply_wait)
217 {
218   SilcClientCommandContext cmd = fsm_context;
219
220   SILC_LOG_DEBUG(("Wait for command reply"));
221
222   /** Wait for command reply */
223   silc_fsm_set_state_context(fsm, NULL);
224   silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
225                       cmd->cmd != SILC_COMMAND_PING ? 40 : 60, 0);
226   return SILC_FSM_WAIT;
227 }
228
229 /* Timeout occurred while waiting command reply */
230
231 SILC_FSM_STATE(silc_client_command_reply_timeout)
232 {
233   SilcClientCommandContext cmd = fsm_context;
234   SilcClientConnection conn = cmd->conn;
235   SilcArgumentPayload args = NULL;
236
237   if (conn->internal->disconnected) {
238     SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
239     silc_list_del(conn->internal->pending_commands, cmd);
240     if (!cmd->called)
241       ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
242     return SILC_FSM_FINISH;
243   }
244
245   SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
246
247   /* Timeout, reply not received in timely fashion */
248   silc_list_del(conn->internal->pending_commands, cmd);
249   ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
250   return SILC_FSM_FINISH;
251 }
252
253 /* Process received command reply payload */
254
255 SILC_FSM_STATE(silc_client_command_reply_process)
256 {
257   SilcClientCommandContext cmd = fsm_context;
258   SilcCommandPayload payload = state_context;
259
260   silc_command_get_status(payload, &cmd->status, &cmd->error);
261
262   switch (cmd->cmd) {
263   case SILC_COMMAND_WHOIS:
264     /** WHOIS */
265     silc_fsm_next(fsm, silc_client_command_reply_whois);
266     break;
267   case SILC_COMMAND_WHOWAS:
268     /** WHOWAS */
269     silc_fsm_next(fsm, silc_client_command_reply_whowas);
270     break;
271   case SILC_COMMAND_IDENTIFY:
272     /** IDENTIFY */
273     silc_fsm_next(fsm, silc_client_command_reply_identify);
274     break;
275   case SILC_COMMAND_NICK:
276     /** NICK */
277     silc_fsm_next(fsm, silc_client_command_reply_nick);
278     break;
279   case SILC_COMMAND_LIST:
280     /** LIST */
281     silc_fsm_next(fsm, silc_client_command_reply_list);
282     break;
283   case SILC_COMMAND_TOPIC:
284     /** TOPIC */
285     silc_fsm_next(fsm, silc_client_command_reply_topic);
286     break;
287   case SILC_COMMAND_INVITE:
288     /** INVITE */
289     silc_fsm_next(fsm, silc_client_command_reply_invite);
290     break;
291   case SILC_COMMAND_QUIT:
292     /** QUIT */
293     silc_fsm_next(fsm, silc_client_command_reply_quit);
294     break;
295   case SILC_COMMAND_KILL:
296     /** KILL */
297     silc_fsm_next(fsm, silc_client_command_reply_kill);
298     break;
299   case SILC_COMMAND_INFO:
300     /** INFO */
301     silc_fsm_next(fsm, silc_client_command_reply_info);
302     break;
303   case SILC_COMMAND_STATS:
304     /** STATS */
305     silc_fsm_next(fsm, silc_client_command_reply_stats);
306     break;
307   case SILC_COMMAND_PING:
308     /** PING */
309     silc_fsm_next(fsm, silc_client_command_reply_ping);
310     break;
311   case SILC_COMMAND_OPER:
312     /** OPER */
313     silc_fsm_next(fsm, silc_client_command_reply_oper);
314     break;
315   case SILC_COMMAND_JOIN:
316     /** JOIN */
317     silc_fsm_next(fsm, silc_client_command_reply_join);
318     break;
319   case SILC_COMMAND_MOTD:
320     /** MOTD */
321     silc_fsm_next(fsm, silc_client_command_reply_motd);
322     break;
323   case SILC_COMMAND_UMODE:
324     /** UMODE */
325     silc_fsm_next(fsm, silc_client_command_reply_umode);
326     break;
327   case SILC_COMMAND_CMODE:
328     /** CMODE */
329     silc_fsm_next(fsm, silc_client_command_reply_cmode);
330     break;
331   case SILC_COMMAND_CUMODE:
332     /** CUMODE */
333     silc_fsm_next(fsm, silc_client_command_reply_cumode);
334     break;
335   case SILC_COMMAND_KICK:
336     /** KICK */
337     silc_fsm_next(fsm, silc_client_command_reply_kick);
338     break;
339   case SILC_COMMAND_BAN:
340     /** BAN */
341     silc_fsm_next(fsm, silc_client_command_reply_ban);
342     break;
343   case SILC_COMMAND_DETACH:
344     /** DETACH */
345     silc_fsm_next(fsm, silc_client_command_reply_detach);
346     break;
347   case SILC_COMMAND_WATCH:
348     /** WATCH */
349     silc_fsm_next(fsm, silc_client_command_reply_watch);
350     break;
351   case SILC_COMMAND_SILCOPER:
352     /** SILCOPER */
353     silc_fsm_next(fsm, silc_client_command_reply_silcoper);
354     break;
355   case SILC_COMMAND_LEAVE:
356     /** LEAVE */
357     silc_fsm_next(fsm, silc_client_command_reply_leave);
358     break;
359   case SILC_COMMAND_USERS:
360     /** USERS */
361     silc_fsm_next(fsm, silc_client_command_reply_users);
362     break;
363   case SILC_COMMAND_GETKEY:
364     /** GETKEY */
365     silc_fsm_next(fsm, silc_client_command_reply_getkey);
366     break;
367   case SILC_COMMAND_SERVICE:
368     /** SERVICE */
369     silc_fsm_next(fsm, silc_client_command_reply_service);
370     break;
371   default:
372     return SILC_FSM_FINISH;
373   }
374
375   return SILC_FSM_CONTINUE;
376 }
377
378 /* Completes command reply processing */
379
380 SILC_FSM_STATE(silc_client_command_reply_processed)
381 {
382   SilcClientCommandContext cmd = fsm_context;
383   SilcClientConnection conn = cmd->conn;
384   SilcCommandPayload payload = state_context;
385
386   silc_command_payload_free(payload);
387
388   if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
389       SILC_STATUS_IS_ERROR(cmd->status))
390     return SILC_FSM_FINISH;
391
392   /* Add back to pending command reply list */
393   silc_mutex_lock(conn->internal->lock);
394   cmd->resolved = FALSE;
395   silc_list_add(conn->internal->pending_commands, cmd);
396   silc_mutex_unlock(conn->internal->lock);
397
398   /** Wait more command payloads */
399   silc_fsm_next(fsm, silc_client_command_reply_wait);
400   return SILC_FSM_CONTINUE;
401 }
402
403 /******************************** WHOIS *************************************/
404
405 /* Received reply for WHOIS command. */
406
407 SILC_FSM_STATE(silc_client_command_reply_whois)
408 {
409   SilcClientCommandContext cmd = fsm_context;
410   SilcClientConnection conn = cmd->conn;
411   SilcClient client = conn->client;
412   SilcCommandPayload payload = state_context;
413   SilcArgumentPayload args = silc_command_get_args(payload);
414   SilcClientEntry client_entry = NULL;
415   SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
416   SilcBufferStruct channels, ch_user_modes;
417   SilcBool has_channels = FALSE;
418   SilcDList channel_list = NULL;
419   SilcID id;
420   char *nickname = NULL, *username = NULL, *realname = NULL;
421   unsigned char *fingerprint, *tmp;
422
423   CHECK_STATUS("WHOIS: ");
424   CHECK_ARGS(5, 11);
425
426   /* Get Client ID */
427   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
428     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
429     goto out;
430   }
431
432   /* Get names */
433   nickname = silc_argument_get_arg_type(args, 3, NULL);
434   username = silc_argument_get_arg_type(args, 4, NULL);
435   realname = silc_argument_get_arg_type(args, 5, NULL);
436   if (!nickname || !username || !realname) {
437     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
438     goto out;
439   }
440
441   /* Get joined channel list */
442   memset(&channels, 0, sizeof(channels));
443   tmp = silc_argument_get_arg_type(args, 6, &len);
444   if (tmp) {
445     has_channels = TRUE;
446     silc_buffer_set(&channels, tmp, len);
447
448     /* Get channel user mode list */
449     tmp = silc_argument_get_arg_type(args, 10, &len);
450     if (!tmp) {
451       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
452       goto out;
453     }
454     silc_buffer_set(&ch_user_modes, tmp, len);
455   }
456
457   /* Get user mode */
458   tmp = silc_argument_get_arg_type(args, 7, &len);
459   if (tmp)
460     SILC_GET32_MSB(mode, tmp);
461
462   /* Get idle time */
463   tmp = silc_argument_get_arg_type(args, 8, &len);
464   if (tmp)
465     SILC_GET32_MSB(idle, tmp);
466
467   /* Get fingerprint */
468   fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
469
470   /* Check if we have this client cached already. */
471   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
472   if (!client_entry) {
473     SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
474     client_entry =
475       silc_client_add_client(client, conn, nickname, username, realname,
476                              &id.u.client_id, mode);
477     if (!client_entry) {
478       ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
479       goto out;
480     }
481     silc_client_ref_client(client, conn, client_entry);
482   } else {
483     silc_client_update_client(client, conn, client_entry,
484                               nickname, username, realname, mode);
485   }
486
487   silc_rwlock_wrlock(client_entry->internal.lock);
488
489   if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
490     memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
491
492   /* Get user attributes */
493   tmp = silc_argument_get_arg_type(args, 11, &len);
494   if (tmp) {
495     if (client_entry->attrs)
496       silc_attribute_payload_list_free(client_entry->attrs);
497     client_entry->attrs = silc_attribute_payload_parse(tmp, len);
498   }
499
500   silc_rwlock_unlock(client_entry->internal.lock);
501
502   /* Parse channel and channel user mode list */
503   if (has_channels) {
504     channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
505                                                    silc_buffer_len(&channels));
506     if (channel_list)
507       silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
508                          &umodes);
509   }
510
511   /* Notify application */
512   silc_client_command_callback(cmd, client_entry, nickname, username,
513                                realname, channel_list, mode, idle, fingerprint,
514                                umodes, client_entry->attrs);
515
516   silc_client_unref_client(client, conn, client_entry);
517   if (has_channels) {
518     silc_channel_payload_list_free(channel_list);
519     silc_free(umodes);
520   }
521
522  out:
523   silc_fsm_next(fsm, silc_client_command_reply_processed);
524   return SILC_FSM_CONTINUE;
525 }
526
527 /******************************** WHOWAS ************************************/
528
529 /* Received reply for WHOWAS command. */
530
531 SILC_FSM_STATE(silc_client_command_reply_whowas)
532 {
533   SilcClientCommandContext cmd = fsm_context;
534   SilcClientConnection conn = cmd->conn;
535   SilcClient client = conn->client;
536   SilcCommandPayload payload = state_context;
537   SilcArgumentPayload args = silc_command_get_args(payload);
538   SilcClientEntry client_entry = NULL;
539   SilcID id;
540   char *nickname, *username;
541   char *realname = NULL;
542
543   CHECK_STATUS("WHOWAS: ");
544   CHECK_ARGS(4, 5);
545
546   /* Get Client ID */
547   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
548     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
549     goto out;
550   }
551
552   /* Get the client entry */
553   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
554
555   /* Get names */
556   nickname = silc_argument_get_arg_type(args, 3, NULL);
557   username = silc_argument_get_arg_type(args, 4, NULL);
558   realname = silc_argument_get_arg_type(args, 5, NULL);
559   if (!nickname || !username) {
560     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
561     goto out;
562   }
563
564   /* Notify application. We don't save any history information to any
565      cache. Just pass the data to the application. */
566   silc_client_command_callback(cmd, client_entry, nickname, username,
567                                realname);
568
569  out:
570   silc_client_unref_client(client, conn, client_entry);
571   silc_fsm_next(fsm, silc_client_command_reply_processed);
572   return SILC_FSM_CONTINUE;
573 }
574
575 /******************************** IDENTIFY **********************************/
576
577 /* Received reply for IDENTIFY command. */
578
579 SILC_FSM_STATE(silc_client_command_reply_identify)
580 {
581   SilcClientCommandContext cmd = fsm_context;
582   SilcClientConnection conn = cmd->conn;
583   SilcClient client = conn->client;
584   SilcCommandPayload payload = state_context;
585   SilcArgumentPayload args = silc_command_get_args(payload);
586   SilcClientEntry client_entry;
587   SilcServerEntry server_entry;
588   SilcChannelEntry channel_entry;
589   SilcUInt32 len;
590   SilcID id;
591   char *name = NULL, *info = NULL;
592
593   CHECK_STATUS("IDENTIFY: ");
594   CHECK_ARGS(2, 4);
595
596   /* Get the ID */
597   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
598     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
599     goto out;
600   }
601
602   /* Get names */
603   name = silc_argument_get_arg_type(args, 3, &len);
604   info = silc_argument_get_arg_type(args, 4, &len);
605
606   switch (id.type) {
607   case SILC_ID_CLIENT:
608     SILC_LOG_DEBUG(("Received client information"));
609
610     /* Check if we have this client cached already. */
611     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
612     if (!client_entry) {
613       SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
614       client_entry =
615         silc_client_add_client(client, conn, name, info, NULL,
616                                &id.u.client_id, 0);
617       if (!client_entry) {
618         ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
619         goto out;
620       }
621       silc_client_ref_client(client, conn, client_entry);
622     } else {
623       silc_client_update_client(client, conn, client_entry,
624                                 name, info, NULL, 0);
625     }
626
627     /* Notify application */
628     silc_client_command_callback(cmd, client_entry, name, info);
629     silc_client_unref_client(client, conn, client_entry);
630     break;
631
632   case SILC_ID_SERVER:
633     SILC_LOG_DEBUG(("Received server information"));
634
635     /* Check if we have this server cached already. */
636     server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
637     if (!server_entry) {
638       SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
639       server_entry = silc_client_add_server(client, conn, name, info,
640                                             &id.u.server_id);
641       if (!server_entry) {
642         ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
643         goto out;
644       }
645       silc_client_ref_server(client, conn, server_entry);
646     } else {
647       silc_client_update_server(client, conn, server_entry, name, info);
648     }
649     server_entry->internal.resolve_cmd_ident = 0;
650
651     /* Notify application */
652     silc_client_command_callback(cmd, server_entry, name, info);
653     silc_client_unref_server(client, conn, server_entry);
654     break;
655
656   case SILC_ID_CHANNEL:
657     SILC_LOG_DEBUG(("Received channel information"));
658
659     /* Check if we have this channel cached already. */
660     channel_entry = silc_client_get_channel_by_id(client, conn,
661                                                   &id.u.channel_id);
662     if (!channel_entry) {
663       SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
664
665       if (!name) {
666         ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
667         goto out;
668       }
669
670       /* Add new channel entry */
671       channel_entry = silc_client_add_channel(client, conn, name, 0,
672                                               &id.u.channel_id);
673       if (!channel_entry) {
674         ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
675         goto out;
676       }
677       silc_client_ref_channel(client, conn, channel_entry);
678     }
679
680     /* Notify application */
681     silc_client_command_callback(cmd, channel_entry,
682                                  channel_entry->channel_name, info);
683     silc_client_unref_channel(client, conn, channel_entry);
684     break;
685   }
686
687  out:
688   silc_fsm_next(fsm, silc_client_command_reply_processed);
689   return SILC_FSM_CONTINUE;
690 }
691
692 /********************************** NICK ************************************/
693
694 /* Received reply for command NICK. */
695
696 SILC_FSM_STATE(silc_client_command_reply_nick)
697 {
698   SilcClientCommandContext cmd = fsm_context;
699   SilcClientConnection conn = cmd->conn;
700   SilcClient client = conn->client;
701   SilcCommandPayload payload = state_context;
702   SilcArgumentPayload args = silc_command_get_args(payload);
703   unsigned char *nick, *idp;
704   SilcUInt32 len, idp_len;
705   SilcClientID old_client_id;
706   SilcID id;
707
708   /* Sanity checks */
709   CHECK_STATUS("Cannot set nickname: ");
710   CHECK_ARGS(2, 3);
711
712   /* Take received Client ID */
713   idp = silc_argument_get_arg_type(args, 2, &idp_len);
714   if (!idp) {
715     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
716     goto out;
717   }
718   if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
719     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
720     goto out;
721   }
722
723   /* Take the new nickname */
724   nick = silc_argument_get_arg_type(args, 3, &len);
725   if (!nick) {
726     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
727     goto out;
728   }
729
730   silc_rwlock_wrlock(conn->local_entry->internal.lock);
731
732   /* Change the nickname */
733   old_client_id = *conn->local_id;
734   if (!silc_client_change_nickname(client, conn, conn->local_entry,
735                                    nick, &id.u.client_id, idp, idp_len)) {
736     ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
737     silc_rwlock_unlock(conn->local_entry->internal.lock);
738     goto out;
739   }
740
741   /* All auto-generated private message keys must be rekeyed because
742      we changed nick and others may not know about it. */
743   conn->internal->ake_generation++;
744   SILC_LOG_DEBUG(("AKE keys will be rekeyed, generation %u",
745                   conn->internal->ake_generation));
746
747   silc_rwlock_unlock(conn->local_entry->internal.lock);
748
749   /* Notify application */
750   silc_client_command_callback(cmd, conn->local_entry,
751                                conn->local_entry->nickname, &old_client_id);
752
753  out:
754   silc_fsm_next(fsm, silc_client_command_reply_processed);
755   return SILC_FSM_CONTINUE;
756 }
757
758 /********************************** LIST ************************************/
759
760 /* Received reply to the LIST command. */
761
762 SILC_FSM_STATE(silc_client_command_reply_list)
763 {
764   SilcClientCommandContext cmd = fsm_context;
765   SilcClientConnection conn = cmd->conn;
766   SilcClient client = conn->client;
767   SilcCommandPayload payload = state_context;
768   SilcArgumentPayload args = silc_command_get_args(payload);
769   unsigned char *tmp, *name, *topic;
770   SilcUInt32 usercount = 0;
771   SilcChannelEntry channel_entry = NULL;
772   SilcID id;
773
774   /* Sanity checks */
775   CHECK_STATUS("Cannot list channels: ");
776
777   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
778     /* There were no channels in the network. */
779     silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
780     silc_fsm_next(fsm, silc_client_command_reply_processed);
781     return SILC_FSM_CONTINUE;
782   }
783
784   CHECK_ARGS(3, 5);
785
786   name = silc_argument_get_arg_type(args, 3, NULL);
787   if (!name) {
788     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
789     goto out;
790   }
791
792   topic = silc_argument_get_arg_type(args, 4, NULL);
793   tmp = silc_argument_get_arg_type(args, 5, NULL);
794   if (tmp)
795     SILC_GET32_MSB(usercount, tmp);
796
797   /* Check whether the channel exists, and add it to cache if it doesn't. */
798   channel_entry = silc_client_get_channel_by_id(client, conn,
799                                                 &id.u.channel_id);
800   if (!channel_entry) {
801     /* Add new channel entry */
802     channel_entry = silc_client_add_channel(client, conn, name, 0,
803                                             &id.u.channel_id);
804     if (!channel_entry) {
805       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
806       goto out;
807     }
808     silc_client_ref_channel(client, conn, channel_entry);
809   }
810
811   /* Notify application */
812   silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name,
813                                topic, usercount);
814
815  out:
816   silc_client_unref_channel(client, conn, channel_entry);
817   silc_fsm_next(fsm, silc_client_command_reply_processed);
818   return SILC_FSM_CONTINUE;
819 }
820
821 /********************************* TOPIC ************************************/
822
823 /* Received reply to topic command. */
824
825 SILC_FSM_STATE(silc_client_command_reply_topic)
826 {
827   SilcClientCommandContext cmd = fsm_context;
828   SilcClientConnection conn = cmd->conn;
829   SilcClient client = conn->client;
830   SilcCommandPayload payload = state_context;
831   SilcArgumentPayload args = silc_command_get_args(payload);
832   SilcChannelEntry channel = NULL;
833   char *topic;
834   SilcUInt32 len;
835   SilcID id;
836
837   /* Sanity checks */
838   CHECK_STATUS("Cannot set topic: ");
839   CHECK_ARGS(2, 3);
840
841   /* Take Channel ID */
842   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
843     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
844     goto out;
845   }
846
847   /* Get the channel entry */
848   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
849   if (!channel) {
850     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
851     goto out;
852   }
853
854   silc_rwlock_wrlock(channel->internal.lock);
855
856   /* Take topic */
857   topic = silc_argument_get_arg_type(args, 3, &len);
858   if (topic) {
859     silc_free(channel->topic);
860     channel->topic = silc_memdup(topic, len);
861   }
862
863   silc_rwlock_unlock(channel->internal.lock);
864
865   /* Notify application */
866   silc_client_command_callback(cmd, channel, channel->topic);
867
868  out:
869   silc_client_unref_channel(client, conn, channel);
870   silc_fsm_next(fsm, silc_client_command_reply_processed);
871   return SILC_FSM_CONTINUE;
872 }
873
874 /********************************* INVITE ***********************************/
875
876 /* Received reply to invite command. */
877
878 SILC_FSM_STATE(silc_client_command_reply_invite)
879 {
880   SilcClientCommandContext cmd = fsm_context;
881   SilcClientConnection conn = cmd->conn;
882   SilcClient client = conn->client;
883   SilcCommandPayload payload = state_context;
884   SilcArgumentPayload args = silc_command_get_args(payload);
885   SilcChannelEntry channel = NULL;
886   unsigned char *tmp;
887   SilcUInt32 len;
888   SilcArgumentPayload invite_args = NULL;
889   SilcID id;
890
891   /* Sanity checks */
892   CHECK_STATUS("Cannot invite: ");
893   CHECK_ARGS(2, 3);
894
895   /* Take Channel ID */
896   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
897     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
898     goto out;
899   }
900
901   /* Get the channel entry */
902   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
903   if (!channel) {
904     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
905     goto out;
906   }
907
908   /* Get the invite list */
909   tmp = silc_argument_get_arg_type(args, 3, &len);
910   if (tmp)
911     invite_args = silc_argument_list_parse(tmp, len);
912
913   /* Notify application */
914   silc_client_command_callback(cmd, channel, invite_args);
915
916   if (invite_args)
917     silc_argument_payload_free(invite_args);
918
919  out:
920   silc_client_unref_channel(client, conn, channel);
921   silc_fsm_next(fsm, silc_client_command_reply_processed);
922   return SILC_FSM_CONTINUE;
923 }
924
925 /********************************** KILL ************************************/
926
927 /* Received reply to the KILL command. */
928
929 SILC_FSM_STATE(silc_client_command_reply_kill)
930 {
931   SilcClientCommandContext cmd = fsm_context;
932   SilcClientConnection conn = cmd->conn;
933   SilcClient client = conn->client;
934   SilcCommandPayload payload = state_context;
935   SilcArgumentPayload args = silc_command_get_args(payload);
936   SilcClientEntry client_entry;
937   SilcID id;
938
939   /* Sanity checks */
940   CHECK_STATUS("Cannot kill: ");
941   CHECK_ARGS(2, 2);
942
943   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
944     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
945     goto out;
946   }
947
948   /* Get the client entry, if exists */
949   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
950
951   /* Notify application */
952   silc_client_command_callback(cmd, client_entry);
953
954   /* Remove the client */
955   if (client_entry) {
956     silc_client_remove_from_channels(client, conn, client_entry);
957     client_entry->internal.valid = FALSE;
958     silc_client_del_client(client, conn, client_entry);
959     silc_client_unref_client(client, conn, client_entry);
960   }
961
962  out:
963   silc_fsm_next(fsm, silc_client_command_reply_processed);
964   return SILC_FSM_CONTINUE;
965 }
966
967 /********************************** INFO ************************************/
968
969 /* Received reply to INFO command. We receive the server ID and some
970    information about the server user requested. */
971
972 SILC_FSM_STATE(silc_client_command_reply_info)
973 {
974   SilcClientCommandContext cmd = fsm_context;
975   SilcClientConnection conn = cmd->conn;
976   SilcClient client = conn->client;
977   SilcCommandPayload payload = state_context;
978   SilcArgumentPayload args = silc_command_get_args(payload);
979   SilcServerEntry server;
980   char *server_name, *server_info;
981   SilcID id;
982
983   /* Sanity checks */
984   CHECK_STATUS("Cannot get info: ");
985   CHECK_ARGS(4, 4);
986
987   /* Get server ID */
988   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
989     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
990     goto out;
991   }
992
993   /* Get server name */
994   server_name = silc_argument_get_arg_type(args, 3, NULL);
995   if (!server_name) {
996     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
997     goto out;
998   }
999
1000   /* Get server info */
1001   server_info = silc_argument_get_arg_type(args, 4, NULL);
1002   if (!server_info) {
1003     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1004     goto out;
1005   }
1006
1007   /* See whether we have this server cached. If not create it. */
1008   server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1009   if (!server) {
1010     SILC_LOG_DEBUG(("Add new server entry (INFO)"));
1011     server = silc_client_add_server(client, conn, server_name,
1012                                     server_info, &id.u.server_id);
1013     if (!server)
1014       goto out;
1015     silc_client_ref_server(client, conn, server);
1016   }
1017
1018   /* Notify application */
1019   silc_client_command_callback(cmd, server, server->server_name,
1020                                server->server_info);
1021   silc_client_unref_server(client, conn, server);
1022
1023  out:
1024   silc_fsm_next(fsm, silc_client_command_reply_processed);
1025   return SILC_FSM_CONTINUE;
1026 }
1027
1028 /********************************** STATS ***********************************/
1029
1030 /* Received reply to STATS command. */
1031
1032 SILC_FSM_STATE(silc_client_command_reply_stats)
1033 {
1034   SilcClientCommandContext cmd = fsm_context;
1035   SilcCommandPayload payload = state_context;
1036   SilcArgumentPayload args = silc_command_get_args(payload);
1037   SilcClientStats stats;
1038   unsigned char *buf = NULL;
1039   SilcUInt32 buf_len = 0;
1040   SilcBufferStruct b;
1041   SilcID id;
1042
1043   /* Sanity checks */
1044   CHECK_STATUS("Cannot get stats: ");
1045   CHECK_ARGS(2, 3);
1046
1047   /* Get server ID */
1048   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1049     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1050     goto out;
1051   }
1052
1053   /* Get statistics structure */
1054   memset(&stats, 0, sizeof(stats));
1055   buf = silc_argument_get_arg_type(args, 3, &buf_len);
1056   if (buf) {
1057     silc_buffer_set(&b, buf, buf_len);
1058     silc_buffer_unformat(&b,
1059                          SILC_STR_UI_INT(&stats.starttime),
1060                          SILC_STR_UI_INT(&stats.uptime),
1061                          SILC_STR_UI_INT(&stats.my_clients),
1062                          SILC_STR_UI_INT(&stats.my_channels),
1063                          SILC_STR_UI_INT(&stats.my_server_ops),
1064                          SILC_STR_UI_INT(&stats.my_router_ops),
1065                          SILC_STR_UI_INT(&stats.cell_clients),
1066                          SILC_STR_UI_INT(&stats.cell_channels),
1067                          SILC_STR_UI_INT(&stats.cell_servers),
1068                          SILC_STR_UI_INT(&stats.clients),
1069                          SILC_STR_UI_INT(&stats.channels),
1070                          SILC_STR_UI_INT(&stats.servers),
1071                          SILC_STR_UI_INT(&stats.routers),
1072                          SILC_STR_UI_INT(&stats.server_ops),
1073                          SILC_STR_UI_INT(&stats.router_ops),
1074                          SILC_STR_END);
1075   }
1076
1077   /* Notify application */
1078   silc_client_command_callback(cmd, &stats);
1079
1080  out:
1081   silc_fsm_next(fsm, silc_client_command_reply_processed);
1082   return SILC_FSM_CONTINUE;
1083 }
1084
1085 /********************************** PING ************************************/
1086
1087 /* Received reply to PING command. */
1088
1089 SILC_FSM_STATE(silc_client_command_reply_ping)
1090 {
1091   SilcClientCommandContext cmd = fsm_context;
1092   SilcClientConnection conn = cmd->conn;
1093   SilcClient client = conn->client;
1094   SilcInt64 diff;
1095
1096   diff = silc_time() - SILC_PTR_TO_64(cmd->context);
1097   if (cmd->verbose)
1098     SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
1099         "Ping reply from %s: %d second%s", conn->remote_host,
1100         (int)diff, diff == 1 ? "" : "s");
1101
1102   /* Notify application */
1103   silc_client_command_callback(cmd);
1104
1105   silc_fsm_next(fsm, silc_client_command_reply_processed);
1106   return SILC_FSM_CONTINUE;
1107 }
1108
1109 /********************************** JOIN ************************************/
1110
1111 /* Continue JOIN command reply processing after resolving unknown users */
1112
1113 static void
1114 silc_client_command_reply_join_resolved(SilcClient client,
1115                                         SilcClientConnection conn,
1116                                         SilcStatus status,
1117                                         SilcDList clients,
1118                                         void *context)
1119 {
1120   SilcClientCommandContext cmd = context;
1121   SilcChannelEntry channel = cmd->context;
1122
1123   channel->internal.resolve_cmd_ident = 0;
1124   silc_client_unref_channel(client, conn, channel);
1125
1126   SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
1127 }
1128
1129
1130 /* Received reply for JOIN command. */
1131
1132 SILC_FSM_STATE(silc_client_command_reply_join)
1133 {
1134   SilcClientCommandContext cmd = fsm_context;
1135   SilcClientConnection conn = cmd->conn;
1136   SilcClient client = conn->client;
1137   SilcCommandPayload payload = state_context;
1138   SilcArgumentPayload args = silc_command_get_args(payload);
1139   SilcChannelEntry channel;
1140   SilcUInt32 mode = 0, len, list_count;
1141   char *topic, *tmp, *channel_name = NULL, *hmac;
1142   const char *cipher;
1143   SilcBufferStruct client_id_list, client_mode_list, keyp;
1144   SilcHashTableList htl;
1145   SilcID id;
1146   int i;
1147
1148   /* Sanity checks */
1149   CHECK_STATUS("Cannot join channel: ");
1150   CHECK_ARGS(9, 17);
1151
1152   /* Get channel name */
1153   channel_name = silc_argument_get_arg_type(args, 2, NULL);
1154   if (!channel_name) {
1155     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1156     goto out;
1157   }
1158
1159   /* Get Channel ID */
1160   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1161     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1162     goto out;
1163   }
1164
1165   /* Check whether we have this channel entry already. */
1166   channel = silc_client_get_channel(client, conn, channel_name);
1167   if (channel) {
1168     if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1169       silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1170   } else {
1171     /* Create new channel entry */
1172     channel = silc_client_add_channel(client, conn, channel_name,
1173                                       mode, &id.u.channel_id);
1174     if (!channel) {
1175       ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1176       goto out;
1177     }
1178     silc_client_ref_channel(client, conn, channel);
1179   }
1180
1181   /* Get hmac */
1182   hmac = silc_argument_get_arg_type(args, 11, NULL);
1183   if (hmac && !silc_hmac_is_supported(hmac)) {
1184     if (cmd->verbose)
1185       SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
1186           "Cannot join channel: Unsupported HMAC `%s'", hmac);
1187     ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1188     silc_rwlock_unlock(channel->internal.lock);
1189     goto out;
1190   }
1191
1192   /* Get the list count */
1193   tmp = silc_argument_get_arg_type(args, 12, &len);
1194   if (!tmp) {
1195     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1196     goto out;
1197   }
1198   SILC_GET32_MSB(list_count, tmp);
1199
1200   /* Get Client ID list */
1201   tmp = silc_argument_get_arg_type(args, 13, &len);
1202   if (!tmp) {
1203     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1204     goto out;
1205   }
1206   silc_buffer_set(&client_id_list, tmp, len);
1207
1208   /* Resolve users we do not know about */
1209   if (!cmd->resolved) {
1210     cmd->resolved = TRUE;
1211     cmd->context = channel;
1212     SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1213                   silc_client_get_clients_by_list(
1214                           client, conn, list_count, &client_id_list,
1215                           silc_client_command_reply_join_resolved, cmd));
1216     /* NOT REACHED */
1217   }
1218
1219   /* Get client mode list */
1220   tmp = silc_argument_get_arg_type(args, 14, &len);
1221   if (!tmp) {
1222     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1223     goto out;
1224   }
1225   silc_buffer_set(&client_mode_list, tmp, len);
1226
1227   silc_rwlock_wrlock(channel->internal.lock);
1228
1229   /* Add clients we received in the reply to the channel */
1230   for (i = 0; i < list_count; i++) {
1231     SilcUInt16 idp_len;
1232     SilcUInt32 mode;
1233     SilcID id;
1234     SilcClientEntry client_entry;
1235
1236     /* Client ID */
1237     SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1238     idp_len += 4;
1239     if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1240       continue;
1241
1242     /* Mode */
1243     SILC_GET32_MSB(mode, client_mode_list.data);
1244
1245     /* Get client entry */
1246     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1247     if (client_entry && client_entry->internal.valid) {
1248       /* Join client to the channel */
1249       silc_rwlock_wrlock(client_entry->internal.lock);
1250       silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1251       silc_rwlock_unlock(client_entry->internal.lock);
1252     }
1253     silc_client_unref_client(client, conn, client_entry);
1254
1255     if (!silc_buffer_pull(&client_id_list, idp_len)) {
1256       silc_rwlock_unlock(channel->internal.lock);
1257       goto out;
1258     }
1259     if (!silc_buffer_pull(&client_mode_list, 4)) {
1260       silc_rwlock_unlock(channel->internal.lock);
1261       goto out;
1262     }
1263   }
1264
1265   /* Get channel mode */
1266   tmp = silc_argument_get_arg_type(args, 5, &len);
1267   if (tmp && len == 4)
1268     SILC_GET32_MSB(mode, tmp);
1269   channel->mode = mode;
1270
1271   /* Get channel key and save it */
1272   tmp = silc_argument_get_arg_type(args, 7, &len);
1273   if (tmp) {
1274     /* If channel key already exists on the channel then while resolving
1275        the user list we have already received new key from server.  Don't
1276        replace it with this old key. */
1277     if (!channel->internal.send_key) {
1278       silc_buffer_set(&keyp, tmp, len);
1279       silc_client_save_channel_key(client, conn, &keyp, channel);
1280     }
1281   }
1282
1283   /* Get topic */
1284   topic = silc_argument_get_arg_type(args, 10, NULL);
1285   if (topic) {
1286     silc_free(channel->topic);
1287     channel->topic = silc_memdup(topic, strlen(topic));
1288   }
1289
1290   /* Get founder key */
1291   tmp = silc_argument_get_arg_type(args, 15, &len);
1292   if (tmp) {
1293     if (channel->founder_key)
1294       silc_pkcs_public_key_free(channel->founder_key);
1295     channel->founder_key = NULL;
1296     silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1297   }
1298
1299   /* Get user limit */
1300   tmp = silc_argument_get_arg_type(args, 17, &len);
1301   if (tmp && len == 4)
1302     SILC_GET32_MSB(channel->user_limit, tmp);
1303   if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1304     channel->user_limit = 0;
1305
1306   /* Get channel public key list */
1307   tmp = silc_argument_get_arg_type(args, 16, &len);
1308   if (tmp)
1309     silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1310
1311   /* Set current channel */
1312   conn->current_channel = channel;
1313
1314   silc_rwlock_unlock(channel->internal.lock);
1315
1316   cipher = (channel->internal.send_key ?
1317             silc_cipher_get_name(channel->internal.send_key) : NULL);
1318   silc_hash_table_list(channel->user_list, &htl);
1319
1320   /* Notify application */
1321   silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
1322                                topic, cipher, hmac, channel->founder_key,
1323                                channel->channel_pubkeys, channel->user_limit);
1324
1325   silc_hash_table_list_reset(&htl);
1326   silc_client_unref_channel(client, conn, channel);
1327
1328  out:
1329   silc_fsm_next(fsm, silc_client_command_reply_processed);
1330   return SILC_FSM_CONTINUE;
1331 }
1332
1333 /********************************** MOTD ************************************/
1334
1335 /* Received reply for MOTD command */
1336
1337 SILC_FSM_STATE(silc_client_command_reply_motd)
1338 {
1339   SilcClientCommandContext cmd = fsm_context;
1340   SilcClientConnection conn = cmd->conn;
1341   SilcClient client = conn->client;
1342   SilcCommandPayload payload = state_context;
1343   SilcArgumentPayload args = silc_command_get_args(payload);
1344   SilcUInt32 i;
1345   char *motd = NULL, *cp, line[256];
1346
1347   /* Sanity checks */
1348   CHECK_STATUS("Cannot get motd: ");
1349   CHECK_ARGS(2, 3);
1350
1351   if (silc_argument_get_arg_num(args) == 3) {
1352     motd = silc_argument_get_arg_type(args, 3, NULL);
1353     if (!motd) {
1354       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1355       goto out;
1356     }
1357
1358     i = 0;
1359     cp = motd;
1360     while(cp[i] != 0) {
1361       if (cp[i++] == '\n') {
1362         memset(line, 0, sizeof(line));
1363         silc_strncat(line, sizeof(line), cp, i - 1);
1364         cp += i;
1365
1366         if (i == 2)
1367           line[0] = ' ';
1368
1369         if (cmd->verbose)
1370           SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1371
1372         if (!strlen(cp))
1373           break;
1374         i = 0;
1375       }
1376     }
1377   }
1378
1379   /* Notify application */
1380   silc_client_command_callback(cmd, motd);
1381
1382  out:
1383   silc_fsm_next(fsm, silc_client_command_reply_processed);
1384   return SILC_FSM_CONTINUE;
1385 }
1386
1387 /********************************** UMODE ***********************************/
1388
1389 /* Received reply to the UMODE command. Save the current user mode */
1390
1391 SILC_FSM_STATE(silc_client_command_reply_umode)
1392 {
1393   SilcClientCommandContext cmd = fsm_context;
1394   SilcClientConnection conn = cmd->conn;
1395   SilcCommandPayload payload = state_context;
1396   SilcArgumentPayload args = silc_command_get_args(payload);
1397   unsigned char *tmp;
1398   SilcUInt32 mode, len;
1399
1400   /* Sanity checks */
1401   CHECK_STATUS("Cannot change mode: ");
1402   CHECK_ARGS(2, 2);
1403
1404   tmp = silc_argument_get_arg_type(args, 2, &len);
1405   if (!tmp || len != 4) {
1406     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1407     goto out;
1408   }
1409
1410   SILC_GET32_MSB(mode, tmp);
1411   silc_rwlock_wrlock(conn->local_entry->internal.lock);
1412   conn->local_entry->mode = mode;
1413   silc_rwlock_unlock(conn->local_entry->internal.lock);
1414
1415   /* Notify application */
1416   silc_client_command_callback(cmd, mode);
1417
1418  out:
1419   silc_fsm_next(fsm, silc_client_command_reply_processed);
1420   return SILC_FSM_CONTINUE;
1421 }
1422
1423 /********************************** CMODE ***********************************/
1424
1425 /* Received reply for CMODE command. */
1426
1427 SILC_FSM_STATE(silc_client_command_reply_cmode)
1428 {
1429   SilcClientCommandContext cmd = fsm_context;
1430   SilcClientConnection conn = cmd->conn;
1431   SilcClient client = conn->client;
1432   SilcCommandPayload payload = state_context;
1433   SilcArgumentPayload args = silc_command_get_args(payload);
1434   unsigned char *tmp;
1435   SilcUInt32 mode;
1436   SilcChannelEntry channel = NULL;
1437   SilcUInt32 len;
1438   SilcPublicKey public_key = NULL;
1439   SilcID id;
1440
1441   /* Sanity checks */
1442   CHECK_STATUS("Cannot change mode: ");
1443   CHECK_ARGS(3, 6);
1444
1445   /* Take Channel ID */
1446   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1447     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1448     goto out;
1449   }
1450
1451   /* Get the channel entry */
1452   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1453   if (!channel) {
1454     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1455     goto out;
1456   }
1457
1458   /* Get founder public key */
1459   tmp = silc_argument_get_arg_type(args, 4, &len);
1460   if (tmp)
1461     silc_public_key_payload_decode(tmp, len, &public_key);
1462
1463   /* Get channel mode */
1464   tmp = silc_argument_get_arg_type(args, 3, &len);
1465   if (!tmp || len != 4) {
1466     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1467     goto out;
1468   }
1469   SILC_GET32_MSB(mode, tmp);
1470
1471   silc_rwlock_wrlock(channel->internal.lock);
1472
1473   /* Get user limit */
1474   tmp = silc_argument_get_arg_type(args, 6, &len);
1475   if (tmp && len == 4)
1476     SILC_GET32_MSB(channel->user_limit, tmp);
1477   if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1478     channel->user_limit = 0;
1479
1480   /* Get channel public key(s) */
1481   tmp = silc_argument_get_arg_type(args, 5, &len);
1482   if (tmp)
1483     silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
1484   else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
1485     silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
1486
1487   /* Save the mode */
1488   channel->mode = mode;
1489
1490   silc_rwlock_unlock(channel->internal.lock);
1491
1492   /* Notify application */
1493   silc_client_command_callback(cmd, channel, mode, public_key,
1494                                channel->channel_pubkeys, channel->user_limit);
1495
1496  out:
1497   silc_client_unref_channel(client, conn, channel);
1498   if (public_key)
1499     silc_pkcs_public_key_free(public_key);
1500   silc_fsm_next(fsm, silc_client_command_reply_processed);
1501   return SILC_FSM_CONTINUE;
1502 }
1503
1504 /********************************** CUMODE **********************************/
1505
1506 /* Received reply for CUMODE command */
1507
1508 SILC_FSM_STATE(silc_client_command_reply_cumode)
1509 {
1510   SilcClientCommandContext cmd = fsm_context;
1511   SilcClientConnection conn = cmd->conn;
1512   SilcClient client = conn->client;
1513   SilcCommandPayload payload = state_context;
1514   SilcArgumentPayload args = silc_command_get_args(payload);
1515   SilcClientEntry client_entry;
1516   SilcChannelEntry channel = NULL;
1517   SilcChannelUser chu;
1518   unsigned char *modev;
1519   SilcUInt32 len, mode;
1520   SilcID id;
1521
1522   /* Sanity checks */
1523   CHECK_STATUS("Cannot change mode: ");
1524   CHECK_ARGS(4, 4);
1525
1526   /* Get channel mode */
1527   modev = silc_argument_get_arg_type(args, 2, &len);
1528   if (!modev || len != 4) {
1529     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1530     goto out;
1531   }
1532   SILC_GET32_MSB(mode, modev);
1533
1534   /* Take Channel ID */
1535   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1536     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1537     goto out;
1538   }
1539
1540   /* Get the channel entry */
1541   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1542   if (!channel) {
1543     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1544     goto out;
1545   }
1546
1547   /* Get Client ID */
1548   if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1549     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1550     goto out;
1551   }
1552
1553   /* Get client entry */
1554   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1555   if (!client_entry) {
1556     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1557     goto out;
1558   }
1559
1560   /* Save the mode */
1561   silc_rwlock_wrlock(channel->internal.lock);
1562   chu = silc_client_on_channel(channel, client_entry);
1563   if (chu)
1564     chu->mode = mode;
1565   silc_rwlock_unlock(channel->internal.lock);
1566
1567   /* Notify application */
1568   silc_client_command_callback(cmd, mode, channel, client_entry);
1569
1570   silc_client_unref_client(client, conn, client_entry);
1571
1572  out:
1573   silc_client_unref_channel(client, conn, channel);
1574   silc_fsm_next(fsm, silc_client_command_reply_processed);
1575   return SILC_FSM_CONTINUE;
1576 }
1577
1578 /********************************** KICK ************************************/
1579
1580 SILC_FSM_STATE(silc_client_command_reply_kick)
1581 {
1582   SilcClientCommandContext cmd = fsm_context;
1583   SilcClientConnection conn = cmd->conn;
1584   SilcClient client = conn->client;
1585   SilcCommandPayload payload = state_context;
1586   SilcArgumentPayload args = silc_command_get_args(payload);
1587   SilcClientEntry client_entry;
1588   SilcChannelEntry channel = NULL;
1589   SilcID id;
1590
1591   /* Sanity checks */
1592   CHECK_STATUS("Cannot kick: ");
1593   CHECK_ARGS(3, 3);
1594
1595   /* Take Channel ID */
1596   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1597     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1598     goto out;
1599   }
1600
1601   /* Get the channel entry */
1602   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1603   if (!channel) {
1604     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1605     goto out;
1606   }
1607
1608   /* Get Client ID */
1609   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1610     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1611     goto out;
1612   }
1613
1614   /* Get client entry */
1615   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1616   if (!client_entry) {
1617     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1618     goto out;
1619   }
1620
1621   /* Notify application */
1622   silc_client_command_callback(cmd, channel, client_entry);
1623
1624   silc_client_unref_client(client, conn, client_entry);
1625
1626  out:
1627   silc_client_unref_channel(client, conn, channel);
1628   silc_fsm_next(fsm, silc_client_command_reply_processed);
1629   return SILC_FSM_CONTINUE;
1630 }
1631
1632 /******************************** SILCOPER **********************************/
1633
1634 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1635 {
1636   SilcClientCommandContext cmd = fsm_context;
1637   SilcCommandPayload payload = state_context;
1638   SilcArgumentPayload args = silc_command_get_args(payload);
1639
1640   /* Sanity checks */
1641   CHECK_STATUS("Cannot change mode: ");
1642   CHECK_ARGS(1, 1);
1643
1644   /* Set user mode */
1645   cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
1646
1647   /* Notify application */
1648   silc_client_command_callback(cmd);
1649
1650   silc_fsm_next(fsm, silc_client_command_reply_processed);
1651   return SILC_FSM_CONTINUE;
1652 }
1653
1654 /********************************** OPER ************************************/
1655
1656 SILC_FSM_STATE(silc_client_command_reply_oper)
1657 {
1658   SilcClientCommandContext cmd = fsm_context;
1659   SilcCommandPayload payload = state_context;
1660   SilcArgumentPayload args = silc_command_get_args(payload);
1661
1662   /* Sanity checks */
1663   CHECK_STATUS("Cannot change mode: ");
1664   CHECK_ARGS(1, 1);
1665
1666   /* Set user mode */
1667   cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
1668
1669   /* Notify application */
1670   silc_client_command_callback(cmd);
1671
1672   silc_fsm_next(fsm, silc_client_command_reply_processed);
1673   return SILC_FSM_CONTINUE;
1674 }
1675
1676 /********************************* DETACH ***********************************/
1677
1678 SILC_FSM_STATE(silc_client_command_reply_detach)
1679 {
1680   SilcClientCommandContext cmd = fsm_context;
1681   SilcClientConnection conn = cmd->conn;
1682   SilcClient client = conn->client;
1683   SilcCommandPayload payload = state_context;
1684   SilcArgumentPayload args = silc_command_get_args(payload);
1685   SilcBuffer detach;
1686
1687   /* Sanity checks */
1688   CHECK_STATUS("Cannot detach: ");
1689   CHECK_ARGS(1, 1);
1690
1691   /* Get detachment data */
1692   detach = silc_client_get_detach_data(client, conn);
1693   if (!detach) {
1694     ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
1695     goto out;
1696   }
1697
1698   /* Notify application */
1699   silc_client_command_callback(cmd, detach);
1700   silc_buffer_free(detach);
1701
1702  out:
1703   silc_fsm_next(fsm, silc_client_command_reply_processed);
1704   return SILC_FSM_CONTINUE;
1705 }
1706
1707 /********************************** WATCH ***********************************/
1708
1709 SILC_FSM_STATE(silc_client_command_reply_watch)
1710 {
1711   SilcClientCommandContext cmd = fsm_context;
1712   SilcCommandPayload payload = state_context;
1713   SilcArgumentPayload args = silc_command_get_args(payload);
1714
1715   /* Sanity checks */
1716   CHECK_STATUS("Cannot set watch: ");
1717   CHECK_ARGS(1, 1);
1718
1719   /* Notify application */
1720   silc_client_command_callback(cmd);
1721
1722   silc_fsm_next(fsm, silc_client_command_reply_processed);
1723   return SILC_FSM_CONTINUE;
1724 }
1725
1726 /*********************************** BAN ************************************/
1727
1728 SILC_FSM_STATE(silc_client_command_reply_ban)
1729 {
1730   SilcClientCommandContext cmd = fsm_context;
1731   SilcClientConnection conn = cmd->conn;
1732   SilcClient client = conn->client;
1733   SilcCommandPayload payload = state_context;
1734   SilcArgumentPayload args = silc_command_get_args(payload);
1735   SilcChannelEntry channel = NULL;
1736   unsigned char *tmp;
1737   SilcUInt32 len;
1738   SilcArgumentPayload invite_args = NULL;
1739   SilcID id;
1740
1741   /* Sanity checks */
1742   CHECK_STATUS("Cannot set ban: ");
1743   CHECK_ARGS(2, 3);
1744
1745   /* Take Channel ID */
1746   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1747     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1748     goto out;
1749   }
1750
1751   /* Get the channel entry */
1752   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1753   if (!channel) {
1754     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1755     goto out;
1756   }
1757
1758   /* Get the invite list */
1759   tmp = silc_argument_get_arg_type(args, 3, &len);
1760   if (tmp)
1761     invite_args = silc_argument_list_parse(tmp, len);
1762
1763   /* Notify application */
1764   silc_client_command_callback(cmd, channel, invite_args);
1765
1766   if (invite_args)
1767     silc_argument_payload_free(invite_args);
1768
1769  out:
1770   silc_client_unref_channel(client, conn, channel);
1771   silc_fsm_next(fsm, silc_client_command_reply_processed);
1772   return SILC_FSM_CONTINUE;
1773 }
1774
1775 /********************************** LEAVE ***********************************/
1776
1777 /* Reply to LEAVE command. */
1778
1779 SILC_FSM_STATE(silc_client_command_reply_leave)
1780 {
1781   SilcClientCommandContext cmd = fsm_context;
1782   SilcClientConnection conn = cmd->conn;
1783   SilcClient client = conn->client;
1784   SilcCommandPayload payload = state_context;
1785   SilcArgumentPayload args = silc_command_get_args(payload);
1786   SilcChannelEntry channel;
1787   SilcCipher key;
1788   SilcHmac hmac;
1789   SilcID id;
1790
1791   /* Sanity checks */
1792   CHECK_STATUS("Cannot set leave: ");
1793   CHECK_ARGS(2, 2);
1794
1795   /* Get Channel ID */
1796   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1797     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1798     goto out;
1799   }
1800
1801   /* Get the channel entry */
1802   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1803   if (!channel) {
1804     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1805     goto out;
1806   }
1807
1808   /* Remove us from this channel. */
1809   silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
1810
1811   /* Notify application */
1812   silc_client_command_callback(cmd, channel);
1813
1814   /* Remove old keys and stuff.  The channel may remain even after leaving
1815      but we want to remove these always. */
1816   if (channel->internal.send_key)
1817     silc_cipher_free(channel->internal.send_key);
1818   channel->internal.send_key = NULL;
1819   if (channel->internal.receive_key)
1820     silc_cipher_free(channel->internal.receive_key);
1821   channel->internal.receive_key = NULL;
1822   if (channel->internal.hmac)
1823     silc_hmac_free(channel->internal.hmac);
1824   channel->internal.hmac = NULL;
1825   if (channel->internal.old_channel_keys) {
1826     silc_dlist_start(channel->internal.old_channel_keys);
1827     while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
1828       silc_cipher_free(key);
1829     silc_dlist_uninit(channel->internal.old_channel_keys);
1830   }
1831   channel->internal.old_channel_keys = NULL;
1832   if (channel->internal.old_hmacs) {
1833     silc_dlist_start(channel->internal.old_hmacs);
1834     while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
1835       silc_hmac_free(hmac);
1836     silc_dlist_uninit(channel->internal.old_hmacs);
1837   }
1838   channel->internal.old_hmacs = NULL;
1839
1840   /* Now delete the channel. */
1841   silc_client_empty_channel(client, conn, channel);
1842   silc_client_del_channel(client, conn, channel);
1843
1844  out:
1845   silc_fsm_next(fsm, silc_client_command_reply_processed);
1846   return SILC_FSM_CONTINUE;
1847 }
1848
1849 /********************************* USERS ************************************/
1850
1851 /* Continue USERS command reply processing after resolving unknown users */
1852
1853 static void
1854 silc_client_command_reply_users_resolved(SilcClient client,
1855                                          SilcClientConnection conn,
1856                                          SilcStatus status,
1857                                          SilcDList clients,
1858                                          void *context)
1859 {
1860   SilcClientCommandContext cmd = context;
1861   SILC_FSM_CALL_CONTINUE(&cmd->thread);
1862 }
1863
1864
1865 /* Continue USERS command after resolving unknown channel */
1866
1867 static void
1868 silc_client_command_reply_users_continue(SilcClient client,
1869                                          SilcClientConnection conn,
1870                                          SilcStatus status,
1871                                          SilcDList channels,
1872                                          void *context)
1873 {
1874   SilcClientCommandContext cmd = context;
1875
1876   if (!channels) {
1877     SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1878     SilcArgumentPayload args = silc_command_get_args(payload);
1879
1880     cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1881     ERROR_CALLBACK(cmd->status);
1882     silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1883   }
1884
1885   SILC_FSM_CALL_CONTINUE(&cmd->thread);
1886 }
1887
1888 /* Reply to USERS command. Received list of client ID's and theirs modes
1889    on the channel we requested. */
1890
1891 SILC_FSM_STATE(silc_client_command_reply_users)
1892 {
1893   SilcClientCommandContext cmd = fsm_context;
1894   SilcClientConnection conn = cmd->conn;
1895   SilcClient client = conn->client;
1896   SilcCommandPayload payload = state_context;
1897   SilcArgumentPayload args = silc_command_get_args(payload);
1898   unsigned char *tmp;
1899   SilcUInt32 tmp_len, list_count, mode;
1900   SilcUInt16 idp_len;
1901   SilcHashTableList htl;
1902   SilcBufferStruct client_id_list, client_mode_list;
1903   SilcChannelEntry channel = NULL;
1904   SilcClientEntry client_entry;
1905   SilcID id;
1906   int i;
1907
1908   /* Sanity checks */
1909   CHECK_STATUS("Cannot get users: ");
1910   CHECK_ARGS(5, 5);
1911
1912   /* Get channel ID */
1913   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1914     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1915     goto out;
1916   }
1917
1918   /* Get channel entry */
1919   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1920   if (!channel) {
1921     /* Resolve the channel from server */
1922     SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1923                         client, conn, &id.u.channel_id,
1924                         silc_client_command_reply_users_continue, cmd));
1925     /* NOT REACHED */
1926   }
1927
1928   /* Get the list count */
1929   tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1930   if (!tmp || tmp_len != 4) {
1931     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1932     goto out;
1933   }
1934   SILC_GET32_MSB(list_count, tmp);
1935
1936   /* Get Client ID list */
1937   tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1938   if (!tmp) {
1939     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1940     goto out;
1941   }
1942   silc_buffer_set(&client_id_list, tmp, tmp_len);
1943
1944   /* Resolve users we do not know about */
1945   if (!cmd->resolved) {
1946     cmd->resolved = TRUE;
1947     silc_client_unref_channel(client, conn, channel);
1948     SILC_FSM_CALL(silc_client_get_clients_by_list(
1949                           client, conn, list_count, &client_id_list,
1950                           silc_client_command_reply_users_resolved, cmd));
1951     /* NOT REACHED */
1952   }
1953
1954   /* Get client mode list */
1955   tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1956   if (!tmp) {
1957     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1958     goto out;
1959   }
1960   silc_buffer_set(&client_mode_list, tmp, tmp_len);
1961
1962   SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1963
1964   silc_rwlock_wrlock(channel->internal.lock);
1965
1966   /* Cache the received Client ID's and modes. */
1967   for (i = 0; i < list_count; i++) {
1968     SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1969     idp_len += 4;
1970     if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1971       goto out;
1972
1973     /* Mode */
1974     SILC_GET32_MSB(mode, client_mode_list.data);
1975
1976     /* Save the client on this channel.  Unknown clients are ignored as they
1977        clearly do not exist since the resolving didn't find them. */
1978     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1979     if (client_entry && client_entry->internal.valid) {
1980       silc_rwlock_wrlock(client_entry->internal.lock);
1981       silc_client_add_to_channel(client, conn, channel, client_entry, mode);
1982       silc_rwlock_unlock(client_entry->internal.lock);
1983     }
1984     silc_client_unref_client(client, conn, client_entry);
1985
1986     if (!silc_buffer_pull(&client_id_list, idp_len)) {
1987       silc_rwlock_unlock(channel->internal.lock);
1988       goto out;
1989     }
1990     if (!silc_buffer_pull(&client_mode_list, 4)) {
1991       silc_rwlock_unlock(channel->internal.lock);
1992       goto out;
1993     }
1994   }
1995
1996   silc_rwlock_unlock(channel->internal.lock);
1997
1998   /* Notify application */
1999   silc_hash_table_list(channel->user_list, &htl);
2000   silc_client_command_callback(cmd, channel, &htl);
2001   silc_hash_table_list_reset(&htl);
2002
2003  out:
2004   silc_client_unref_channel(client, conn, channel);
2005   silc_fsm_next(fsm, silc_client_command_reply_processed);
2006   return SILC_FSM_CONTINUE;
2007 }
2008
2009 /********************************** GETKEY **********************************/
2010
2011 /* Received command reply to GETKEY command. WE've received the remote
2012    client's public key. */
2013
2014 SILC_FSM_STATE(silc_client_command_reply_getkey)
2015 {
2016   SilcClientCommandContext cmd = fsm_context;
2017   SilcClientConnection conn = cmd->conn;
2018   SilcClient client = conn->client;
2019   SilcCommandPayload payload = state_context;
2020   SilcArgumentPayload args = silc_command_get_args(payload);
2021   SilcClientEntry client_entry;
2022   SilcServerEntry server_entry;
2023   unsigned char *tmp;
2024   SilcUInt32 len;
2025   SilcPublicKey public_key = NULL;
2026   SilcID id;
2027
2028   /* Sanity checks */
2029   CHECK_STATUS("Cannot get key: ");
2030   CHECK_ARGS(2, 3);
2031
2032   /* Get the ID */
2033   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
2034     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2035     goto out;
2036   }
2037
2038   /* Get the public key */
2039   tmp = silc_argument_get_arg_type(args, 3, &len);
2040   if (!tmp) {
2041     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2042     goto out;
2043   }
2044   if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
2045     SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
2046         "Cannot decode public key: malformed/unsupported public key");
2047     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2048     goto out;
2049   }
2050
2051   if (id.type == SILC_ID_CLIENT) {
2052     /* Received client's public key */
2053     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
2054     if (!client_entry) {
2055       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2056       goto out;
2057     }
2058
2059     silc_rwlock_wrlock(client_entry->internal.lock);
2060
2061     /* Save fingerprint */
2062     if (!client_entry->fingerprint)
2063       silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
2064                      client_entry->fingerprint);
2065     if (!client_entry->public_key) {
2066       client_entry->public_key = public_key;
2067       public_key = NULL;
2068     }
2069
2070     silc_rwlock_unlock(client_entry->internal.lock);
2071
2072     /* Notify application */
2073     silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
2074                                  client_entry->public_key);
2075     silc_client_unref_client(client, conn, client_entry);
2076   } else if (id.type == SILC_ID_SERVER) {
2077     /* Received server's public key */
2078     server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
2079     if (!server_entry) {
2080       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2081       goto out;
2082     }
2083
2084     silc_rwlock_wrlock(server_entry->internal.lock);
2085
2086     if (!server_entry->public_key) {
2087       server_entry->public_key = public_key;
2088       public_key = NULL;
2089     }
2090
2091     silc_rwlock_unlock(server_entry->internal.lock);
2092
2093     /* Notify application */
2094     silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
2095                                  server_entry->public_key);
2096     silc_client_unref_server(client, conn, server_entry);
2097   }
2098
2099  out:
2100   if (public_key)
2101     silc_pkcs_public_key_free(public_key);
2102   silc_fsm_next(fsm, silc_client_command_reply_processed);
2103   return SILC_FSM_CONTINUE;
2104 }
2105
2106 /********************************** SERVICE *********************************/
2107
2108 /* Reply to SERVICE command. */
2109 /* XXX incomplete */
2110
2111 SILC_FSM_STATE(silc_client_command_reply_service)
2112 {
2113   SilcClientCommandContext cmd = fsm_context;
2114   SilcCommandPayload payload = state_context;
2115   SilcArgumentPayload args = silc_command_get_args(payload);
2116   SilcUInt32 tmp_len;
2117   unsigned char *service_list, *name;
2118
2119   /* Sanity checks */
2120   CHECK_STATUS("Cannot get service: ");
2121
2122   /* Get service list */
2123   service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
2124
2125   /* Get requested service name */
2126   name = silc_argument_get_arg_type(args, 3, &tmp_len);
2127
2128   /* Notify application */
2129   silc_client_command_callback(cmd, service_list, name);
2130
2131   silc_fsm_next(fsm, silc_client_command_reply_processed);
2132   return SILC_FSM_CONTINUE;
2133 }
2134
2135 /*********************************** QUIT ***********************************/
2136
2137 /* QUIT command reply stub */
2138
2139 SILC_FSM_STATE(silc_client_command_reply_quit)
2140 {
2141   silc_fsm_next(fsm, silc_client_command_reply_processed);
2142   return SILC_FSM_CONTINUE;
2143 }