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