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