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