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