Client library rewrites.
[silc.git] / lib / silcclient / command_reply.c
1 /*
2
3   command_reply.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2006 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /************************** Types and definitions ***************************/
26
27 /* Calls error command reply callback back to command sender. */
28 #define ERROR_CALLBACK(error)                                   \
29 do {                                                            \
30   void *arg1 = NULL, *arg2 = NULL;                              \
31   if (cmd->status != SILC_STATUS_OK)                            \
32     silc_status_get_args(cmd->status, args, &arg1, &arg2);      \
33   else                                                          \
34     cmd->status = error;                                        \
35    silc_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     SILC_LOG_DEBUG(("Bad command reply packet"));
139     return SILC_FSM_FINISH;
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 == SILC_COMMAND_NONE)
150         && cmd->cmd_ident == cmd_ident)
151       break;
152   silc_mutex_unlock(conn->internal->lock);
153
154   if (!cmd) {
155     SILC_LOG_DEBUG(("Unknown command reply"));
156     silc_command_payload_free(payload);
157     return SILC_FSM_FINISH;
158   }
159
160   /* Signal command thread that command reply has arrived */
161   silc_fsm_set_state_context(&cmd->thread, payload);
162   silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
163   silc_fsm_continue_sync(&cmd->thread);
164
165   return SILC_FSM_FINISH;
166 }
167
168 /* Wait here for command reply to arrive from remote host */
169
170 SILC_FSM_STATE(silc_client_command_reply_wait)
171 {
172   SILC_LOG_DEBUG(("Wait for command reply"));
173
174   /** Wait for command reply */
175   silc_fsm_set_state_context(fsm, NULL);
176   silc_fsm_next_later(fsm, silc_client_command_reply_timeout, 20, 0);
177   return SILC_FSM_WAIT;
178 }
179
180 /* Timeout occurred while waiting command reply */
181
182 SILC_FSM_STATE(silc_client_command_reply_timeout)
183 {
184   SilcClientCommandContext cmd = fsm_context;
185   SilcArgumentPayload args = NULL;
186
187   /* Timeout, reply not received in timely fashion */
188   ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
189   return SILC_FSM_FINISH;
190 }
191
192 /* Process received command reply payload */
193
194 SILC_FSM_STATE(silc_client_command_reply_process)
195 {
196   SilcClientCommandContext cmd = fsm_context;
197   SilcCommandPayload payload = state_context;
198
199   silc_command_get_status(payload, &cmd->status, &cmd->error);
200
201   switch (cmd->cmd) {
202   case SILC_COMMAND_WHOIS:
203     /** WHOIS */
204     silc_fsm_next(fsm, silc_client_command_reply_whois);
205     break;
206   case SILC_COMMAND_WHOWAS:
207     /** WHOWAS */
208     silc_fsm_next(fsm, silc_client_command_reply_whowas);
209     break;
210   case SILC_COMMAND_IDENTIFY:
211     /** IDENTIFY */
212     silc_fsm_next(fsm, silc_client_command_reply_identify);
213     break;
214   case SILC_COMMAND_NICK:
215     /** NICK */
216     silc_fsm_next(fsm, silc_client_command_reply_nick);
217     break;
218   case SILC_COMMAND_LIST:
219     /** LIST */
220     silc_fsm_next(fsm, silc_client_command_reply_list);
221     break;
222   case SILC_COMMAND_TOPIC:
223     /** TOPIC */
224     silc_fsm_next(fsm, silc_client_command_reply_topic);
225     break;
226   case SILC_COMMAND_INVITE:
227     /** INVITE */
228     silc_fsm_next(fsm, silc_client_command_reply_invite);
229     break;
230   case SILC_COMMAND_QUIT:
231     /** QUIT */
232     silc_fsm_next(fsm, silc_client_command_reply_quit);
233     break;
234   case SILC_COMMAND_KILL:
235     /** KILL */
236     silc_fsm_next(fsm, silc_client_command_reply_kill);
237     break;
238   case SILC_COMMAND_INFO:
239     /** INFO */
240     silc_fsm_next(fsm, silc_client_command_reply_info);
241     break;
242   case SILC_COMMAND_STATS:
243     /** STATS */
244     silc_fsm_next(fsm, silc_client_command_reply_stats);
245     break;
246   case SILC_COMMAND_PING:
247     /** PING */
248     silc_fsm_next(fsm, silc_client_command_reply_ping);
249     break;
250   case SILC_COMMAND_OPER:
251     /** OPER */
252     silc_fsm_next(fsm, silc_client_command_reply_oper);
253     break;
254   case SILC_COMMAND_JOIN:
255     /** JOIN */
256     silc_fsm_next(fsm, silc_client_command_reply_join);
257     break;
258   case SILC_COMMAND_MOTD:
259     /** MOTD */
260     silc_fsm_next(fsm, silc_client_command_reply_motd);
261     break;
262   case SILC_COMMAND_UMODE:
263     /** UMODE */
264     silc_fsm_next(fsm, silc_client_command_reply_umode);
265     break;
266   case SILC_COMMAND_CMODE:
267     /** CMODE */
268     silc_fsm_next(fsm, silc_client_command_reply_cmode);
269     break;
270   case SILC_COMMAND_CUMODE:
271     /** CUMODE */
272     silc_fsm_next(fsm, silc_client_command_reply_cumode);
273     break;
274   case SILC_COMMAND_KICK:
275     /** KICK */
276     silc_fsm_next(fsm, silc_client_command_reply_kick);
277     break;
278   case SILC_COMMAND_BAN:
279     /** BAN */
280     silc_fsm_next(fsm, silc_client_command_reply_ban);
281     break;
282   case SILC_COMMAND_DETACH:
283     /** DETACH */
284     silc_fsm_next(fsm, silc_client_command_reply_detach);
285     break;
286   case SILC_COMMAND_WATCH:
287     /** WATCH */
288     silc_fsm_next(fsm, silc_client_command_reply_watch);
289     break;
290   case SILC_COMMAND_SILCOPER:
291     /** SILCOPER */
292     silc_fsm_next(fsm, silc_client_command_reply_silcoper);
293     break;
294   case SILC_COMMAND_LEAVE:
295     /** LEAVE */
296     silc_fsm_next(fsm, silc_client_command_reply_leave);
297     break;
298   case SILC_COMMAND_USERS:
299     /** USERS */
300     silc_fsm_next(fsm, silc_client_command_reply_users);
301     break;
302   case SILC_COMMAND_GETKEY:
303     /** GETKEY */
304     silc_fsm_next(fsm, silc_client_command_reply_getkey);
305     break;
306   case SILC_COMMAND_SERVICE:
307     /** SERVICE */
308     silc_fsm_next(fsm, silc_client_command_reply_service);
309     break;
310   default:
311     return SILC_FSM_FINISH;
312   }
313
314   return SILC_FSM_CONTINUE;
315 }
316
317 /* Completes command reply processing */
318
319 SILC_FSM_STATE(silc_client_command_reply_processed)
320 {
321   SilcClientCommandContext cmd = fsm_context;
322   SilcCommandPayload payload = state_context;
323
324   silc_command_payload_free(payload);
325
326   if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
327       SILC_STATUS_IS_ERROR(cmd->status))
328     return SILC_FSM_FINISH;
329
330   /** Wait more command payloads */
331   silc_fsm_next(fsm, silc_client_command_reply_wait);
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_processed);
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_processed);
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->internal.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_processed);
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_processed);
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_processed);
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_processed);
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_processed);
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_processed);
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_processed);
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_processed);
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_processed);
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_processed);
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   SilcUInt32 mode = 0, len, list_count;
1033   char *topic, *tmp, *channel_name = NULL, *hmac;
1034   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
1035   SilcBufferStruct chpklist;
1036   SilcID id;
1037   int i;
1038
1039   /* Sanity checks */
1040   CHECK_STATUS("Cannot join channel: ");
1041   CHECK_ARGS(9, 17);
1042
1043   /* Get channel name */
1044   channel_name = silc_argument_get_arg_type(args, 2, NULL);
1045   if (!channel_name) {
1046     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1047     goto out;
1048   }
1049
1050   /* Get Channel ID */
1051   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1052     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1053     goto out;
1054   }
1055
1056   /* Get channel mode */
1057   tmp = silc_argument_get_arg_type(args, 5, NULL);
1058   if (tmp)
1059     SILC_GET32_MSB(mode, tmp);
1060
1061   /* Get channel key */
1062   tmp = silc_argument_get_arg_type(args, 7, &len);
1063   if (tmp) {
1064     keyp = silc_buffer_alloc_size(len);
1065     if (keyp)
1066       silc_buffer_put(keyp, tmp, len);
1067   }
1068
1069   /* Get topic */
1070   topic = silc_argument_get_arg_type(args, 10, NULL);
1071
1072   /* Check whether we have this channel entry already. */
1073   channel = silc_client_get_channel(client, conn, channel_name);
1074   if (channel) {
1075     if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
1076       silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
1077   } else {
1078     /* Create new channel entry */
1079     channel = silc_client_add_channel(client, conn, channel_name,
1080                                       mode, &id.u.channel_id);
1081     if (!channel) {
1082       ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
1083       goto out;
1084     }
1085   }
1086
1087   conn->current_channel = channel;
1088   channel->mode = mode;
1089
1090   /* Get hmac */
1091   hmac = silc_argument_get_arg_type(args, 11, NULL);
1092   if (hmac) {
1093     if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
1094       if (cmd->verbose)
1095         SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
1096             "Cannot join channel: Unsupported HMAC `%s'", hmac);
1097       ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
1098       goto out;
1099     }
1100   }
1101
1102   /* Get the list count */
1103   tmp = silc_argument_get_arg_type(args, 12, &len);
1104   if (!tmp) {
1105     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1106     goto out;
1107   }
1108   SILC_GET32_MSB(list_count, tmp);
1109
1110   /* Get Client ID list */
1111   tmp = silc_argument_get_arg_type(args, 13, &len);
1112   if (!tmp) {
1113     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1114     goto out;
1115   }
1116
1117   client_id_list = silc_buffer_alloc_size(len);
1118   if (client_id_list)
1119     silc_buffer_put(client_id_list, tmp, len);
1120
1121   /* Get client mode list */
1122   tmp = silc_argument_get_arg_type(args, 14, &len);
1123   if (!tmp) {
1124     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1125     goto out;
1126   }
1127
1128   client_mode_list = silc_buffer_alloc_size(len);
1129   if (client_mode_list)
1130     silc_buffer_put(client_mode_list, tmp, len);
1131
1132   /* Add clients we received in the reply to the channel */
1133   for (i = 0; i < list_count; i++) {
1134     SilcUInt16 idp_len;
1135     SilcUInt32 mode;
1136     SilcID id;
1137     SilcClientEntry client_entry;
1138
1139     /* Client ID */
1140     SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1141     idp_len += 4;
1142     if (!silc_id_payload_parse_id(client_id_list->data, idp_len, &id))
1143       goto out;
1144
1145     /* Mode */
1146     SILC_GET32_MSB(mode, client_mode_list->data);
1147
1148     /* Check if we have this client cached already. */
1149     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1150     if (!client_entry) {
1151       /* No, we don't have it, add entry for it. */
1152       client_entry =
1153         silc_client_add_client(client, conn, NULL, NULL, NULL,
1154                                &id.u.client_id, 0);
1155       if (!client_entry)
1156         goto out;
1157     }
1158
1159     /* Join client to the channel */
1160     if (!silc_client_add_to_channel(channel, client_entry, mode)) {
1161       silc_client_unref_client(client, conn, client_entry);
1162       goto out;
1163     }
1164     silc_client_unref_client(client, conn, client_entry);
1165
1166     if (!silc_buffer_pull(client_id_list, idp_len))
1167       goto out;
1168     if (!silc_buffer_pull(client_mode_list, 4))
1169       goto out;
1170   }
1171   silc_buffer_start(client_id_list);
1172   silc_buffer_start(client_mode_list);
1173
1174   /* Save channel key */
1175 #if 0
1176   if (keyp)
1177     silc_client_save_channel_key(client, conn, keyp, channel);
1178 #endif /* 0 */
1179
1180   /* Get founder key */
1181   tmp = silc_argument_get_arg_type(args, 15, &len);
1182   if (tmp) {
1183     if (channel->founder_key)
1184       silc_pkcs_public_key_free(channel->founder_key);
1185     channel->founder_key = NULL;
1186     silc_public_key_payload_decode(tmp, len, &channel->founder_key);
1187   }
1188
1189   /* Get user limit */
1190   tmp = silc_argument_get_arg_type(args, 17, &len);
1191   if (tmp && len == 4)
1192     SILC_GET32_MSB(channel->user_limit, tmp);
1193   if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1194     channel->user_limit = 0;
1195
1196   /* Get channel public key list */
1197   tmp = silc_argument_get_arg_type(args, 16, &len);
1198   if (tmp)
1199     silc_buffer_set(&chpklist, tmp, len);
1200
1201   if (topic) {
1202     silc_free(channel->topic);
1203     channel->topic = silc_memdup(topic, strlen(topic));
1204   }
1205
1206   /* Notify application */
1207   silc_client_command_callback(cmd, channel_name, channel, mode, 0,
1208                                keyp ? keyp->head : NULL, NULL,
1209                                NULL, topic, hmac, list_count, client_id_list,
1210                                client_mode_list, channel->founder_key,
1211                                tmp ? &chpklist : NULL, channel->user_limit);
1212
1213  out:
1214   silc_buffer_free(keyp);
1215   silc_buffer_free(client_id_list);
1216   silc_buffer_free(client_mode_list);
1217   silc_fsm_next(fsm, silc_client_command_reply_processed);
1218   return SILC_FSM_CONTINUE;
1219 }
1220
1221 /********************************** MOTD ************************************/
1222
1223 /* Received reply for MOTD command */
1224
1225 SILC_FSM_STATE(silc_client_command_reply_motd)
1226 {
1227   SilcClientCommandContext cmd = fsm_context;
1228   SilcClientConnection conn = cmd->conn;
1229   SilcClient client = conn->client;
1230   SilcCommandPayload payload = state_context;
1231   SilcArgumentPayload args = silc_command_get_args(payload);
1232   SilcUInt32 i;
1233   char *motd = NULL, *cp, line[256];
1234
1235   /* Sanity checks */
1236   CHECK_STATUS("Cannot get motd: ");
1237   CHECK_ARGS(2, 3);
1238
1239   if (silc_argument_get_arg_num(args) == 3) {
1240     motd = silc_argument_get_arg_type(args, 3, NULL);
1241     if (!motd) {
1242       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1243       goto out;
1244     }
1245
1246     i = 0;
1247     cp = motd;
1248     while(cp[i] != 0) {
1249       if (cp[i++] == '\n') {
1250         memset(line, 0, sizeof(line));
1251         silc_strncat(line, sizeof(line), cp, i - 1);
1252         cp += i;
1253
1254         if (i == 2)
1255           line[0] = ' ';
1256
1257         if (cmd->verbose)
1258           SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1259
1260         if (!strlen(cp))
1261           break;
1262         i = 0;
1263       }
1264     }
1265   }
1266
1267   /* Notify application */
1268   silc_client_command_callback(cmd, motd);
1269
1270  out:
1271   silc_fsm_next(fsm, silc_client_command_reply_processed);
1272   return SILC_FSM_CONTINUE;
1273 }
1274
1275 /********************************** UMODE ***********************************/
1276
1277 /* Received reply to the UMODE command. Save the current user mode */
1278
1279 SILC_FSM_STATE(silc_client_command_reply_umode)
1280 {
1281   SilcClientCommandContext cmd = fsm_context;
1282   SilcClientConnection conn = cmd->conn;
1283   SilcCommandPayload payload = state_context;
1284   SilcArgumentPayload args = silc_command_get_args(payload);
1285   unsigned char *tmp;
1286   SilcUInt32 mode, len;
1287
1288   /* Sanity checks */
1289   CHECK_STATUS("Cannot change mode: ");
1290   CHECK_ARGS(2, 2);
1291
1292   tmp = silc_argument_get_arg_type(args, 2, &len);
1293   if (!tmp || len != 4) {
1294     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1295     goto out;
1296   }
1297
1298   SILC_GET32_MSB(mode, tmp);
1299   conn->local_entry->mode = mode;
1300
1301   /* Notify application */
1302   silc_client_command_callback(cmd, mode);
1303
1304  out:
1305   silc_fsm_next(fsm, silc_client_command_reply_processed);
1306   return SILC_FSM_CONTINUE;
1307 }
1308
1309 /********************************** CMODE ***********************************/
1310
1311 /* Received reply for CMODE command. */
1312
1313 SILC_FSM_STATE(silc_client_command_reply_cmode)
1314 {
1315   SilcClientCommandContext cmd = fsm_context;
1316   SilcClientConnection conn = cmd->conn;
1317   SilcClient client = conn->client;
1318   SilcCommandPayload payload = state_context;
1319   SilcArgumentPayload args = silc_command_get_args(payload);
1320   unsigned char *tmp;
1321   SilcUInt32 mode;
1322   SilcChannelEntry channel;
1323   SilcUInt32 len;
1324   SilcPublicKey public_key = NULL;
1325   SilcDList channel_pubkeys = NULL;
1326   SilcID id;
1327
1328   /* Sanity checks */
1329   CHECK_STATUS("Cannot change mode: ");
1330   CHECK_ARGS(3, 6);
1331
1332   /* Take Channel ID */
1333   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1334     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1335     goto out;
1336   }
1337
1338   /* Get the channel entry */
1339   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1340   if (!channel) {
1341     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1342     goto out;
1343   }
1344
1345   /* Get channel mode */
1346   tmp = silc_argument_get_arg_type(args, 3, &len);
1347   if (!tmp || len != 4) {
1348     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1349     goto out;
1350   }
1351
1352   /* Save the mode */
1353   SILC_GET32_MSB(mode, tmp);
1354   channel->mode = mode;
1355
1356   /* Get founder public key */
1357   tmp = silc_argument_get_arg_type(args, 4, &len);
1358   if (tmp)
1359     silc_public_key_payload_decode(tmp, len, &public_key);
1360
1361   /* Get user limit */
1362   tmp = silc_argument_get_arg_type(args, 6, &len);
1363   if (tmp && len == 4)
1364     SILC_GET32_MSB(channel->user_limit, tmp);
1365   if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1366     channel->user_limit = 0;
1367
1368   /* Get channel public key(s) */
1369   tmp = silc_argument_get_arg_type(args, 5, &len);
1370   if (tmp)
1371     channel_pubkeys =
1372       silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
1373
1374   /* Notify application */
1375   silc_client_command_callback(cmd, channel, mode, public_key,
1376                                channel_pubkeys, channel->user_limit);
1377
1378   silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
1379
1380  out:
1381   if (public_key)
1382     silc_pkcs_public_key_free(public_key);
1383   silc_fsm_next(fsm, silc_client_command_reply_processed);
1384   return SILC_FSM_CONTINUE;
1385 }
1386
1387 /********************************** CUMODE **********************************/
1388
1389 /* Received reply for CUMODE command */
1390
1391 SILC_FSM_STATE(silc_client_command_reply_cumode)
1392 {
1393   SilcClientCommandContext cmd = fsm_context;
1394   SilcClientConnection conn = cmd->conn;
1395   SilcClient client = conn->client;
1396   SilcCommandPayload payload = state_context;
1397   SilcArgumentPayload args = silc_command_get_args(payload);
1398   SilcClientEntry client_entry;
1399   SilcChannelEntry channel;
1400   SilcChannelUser chu;
1401   unsigned char *modev;
1402   SilcUInt32 len, mode;
1403   SilcID id;
1404
1405   /* Sanity checks */
1406   CHECK_STATUS("Cannot change mode: ");
1407   CHECK_ARGS(4, 4);
1408
1409   /* Get channel mode */
1410   modev = silc_argument_get_arg_type(args, 2, &len);
1411   if (!modev || len != 4) {
1412     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1413     goto out;
1414   }
1415   SILC_GET32_MSB(mode, modev);
1416
1417   /* Take Channel ID */
1418   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1419     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1420     goto out;
1421   }
1422
1423   /* Get the channel entry */
1424   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1425   if (!channel) {
1426     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1427     goto out;
1428   }
1429
1430   /* Get Client ID */
1431   if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
1432     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1433     goto out;
1434   }
1435
1436   /* Get client entry */
1437   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1438   if (!client_entry) {
1439     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1440     goto out;
1441   }
1442
1443   /* Save the mode */
1444   chu = silc_client_on_channel(channel, client_entry);
1445   if (chu)
1446     chu->mode = mode;
1447
1448   /* Notify application */
1449   silc_client_command_callback(cmd, mode, channel, client_entry);
1450
1451   silc_client_unref_client(client, conn, client_entry);
1452
1453  out:
1454   silc_fsm_next(fsm, silc_client_command_reply_processed);
1455   return SILC_FSM_CONTINUE;
1456 }
1457
1458 /********************************** KICK ************************************/
1459
1460 SILC_FSM_STATE(silc_client_command_reply_kick)
1461 {
1462   SilcClientCommandContext cmd = fsm_context;
1463   SilcClientConnection conn = cmd->conn;
1464   SilcClient client = conn->client;
1465   SilcCommandPayload payload = state_context;
1466   SilcArgumentPayload args = silc_command_get_args(payload);
1467   SilcClientEntry client_entry;
1468   SilcChannelEntry channel;
1469   SilcID id;
1470
1471   /* Sanity checks */
1472   CHECK_STATUS("Cannot kick: ");
1473   CHECK_ARGS(3, 3);
1474
1475   /* Take Channel ID */
1476   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1477     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1478     goto out;
1479   }
1480
1481   /* Get the channel entry */
1482   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1483   if (!channel) {
1484     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1485     goto out;
1486   }
1487
1488   /* Get Client ID */
1489   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
1490     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1491     goto out;
1492   }
1493
1494   /* Get client entry */
1495   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1496   if (!client_entry) {
1497     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1498     goto out;
1499   }
1500
1501   /* Notify application */
1502   silc_client_command_callback(cmd, channel, client_entry);
1503
1504   silc_client_unref_client(client, conn, client_entry);
1505
1506  out:
1507   silc_fsm_next(fsm, silc_client_command_reply_processed);
1508   return SILC_FSM_CONTINUE;
1509 }
1510
1511 /******************************** SILCOPER **********************************/
1512
1513 SILC_FSM_STATE(silc_client_command_reply_silcoper)
1514 {
1515   SilcClientCommandContext cmd = fsm_context;
1516   SilcCommandPayload payload = state_context;
1517   SilcArgumentPayload args = silc_command_get_args(payload);
1518
1519   /* Sanity checks */
1520   CHECK_STATUS("Cannot change mode: ");
1521   CHECK_ARGS(1, 1);
1522
1523   /* Notify application */
1524   silc_client_command_callback(cmd);
1525
1526   silc_fsm_next(fsm, silc_client_command_reply_processed);
1527   return SILC_FSM_CONTINUE;
1528 }
1529
1530 /********************************** OPER ************************************/
1531
1532 SILC_FSM_STATE(silc_client_command_reply_oper)
1533 {
1534   SilcClientCommandContext cmd = fsm_context;
1535   SilcCommandPayload payload = state_context;
1536   SilcArgumentPayload args = silc_command_get_args(payload);
1537
1538   /* Sanity checks */
1539   CHECK_STATUS("Cannot change mode: ");
1540   CHECK_ARGS(1, 1);
1541
1542   /* Notify application */
1543   silc_client_command_callback(cmd);
1544
1545   silc_fsm_next(fsm, silc_client_command_reply_processed);
1546   return SILC_FSM_CONTINUE;
1547 }
1548
1549 /********************************* DETACH ***********************************/
1550
1551 SILC_FSM_STATE(silc_client_command_reply_detach)
1552 {
1553   SilcClientCommandContext cmd = fsm_context;
1554   SilcClientConnection conn = cmd->conn;
1555   SilcClient client = conn->client;
1556   SilcCommandPayload payload = state_context;
1557   SilcArgumentPayload args = silc_command_get_args(payload);
1558   SilcBuffer detach;
1559
1560   /* Sanity checks */
1561   CHECK_STATUS("Cannot detach: ");
1562   CHECK_ARGS(1, 1);
1563
1564   /* Notify application */
1565   silc_client_command_callback(cmd);
1566
1567 #if 0
1568   /* Generate the detachment data and deliver it to the client in the
1569      detach client operation */
1570   detach = silc_client_get_detach_data(client, conn);
1571   if (detach) {
1572     client->internal->ops->detach(client, conn, silc_buffer_data(detach),
1573                                   silc_buffer_len(detach));
1574     silc_buffer_free(detach);
1575   }
1576 #endif /* 0 */
1577
1578   silc_fsm_next(fsm, silc_client_command_reply_processed);
1579   return SILC_FSM_CONTINUE;
1580 }
1581
1582 /********************************** WATCH ***********************************/
1583
1584 SILC_FSM_STATE(silc_client_command_reply_watch)
1585 {
1586   SilcClientCommandContext cmd = fsm_context;
1587   SilcCommandPayload payload = state_context;
1588   SilcArgumentPayload args = silc_command_get_args(payload);
1589
1590   /* Sanity checks */
1591   CHECK_STATUS("Cannot set watch: ");
1592   CHECK_ARGS(1, 1);
1593
1594   /* Notify application */
1595   silc_client_command_callback(cmd);
1596
1597   silc_fsm_next(fsm, silc_client_command_reply_processed);
1598   return SILC_FSM_CONTINUE;
1599 }
1600
1601 /*********************************** BAN ************************************/
1602
1603 SILC_FSM_STATE(silc_client_command_reply_ban)
1604 {
1605   SilcClientCommandContext cmd = fsm_context;
1606   SilcClientConnection conn = cmd->conn;
1607   SilcClient client = conn->client;
1608   SilcCommandPayload payload = state_context;
1609   SilcArgumentPayload args = silc_command_get_args(payload);
1610   SilcChannelEntry channel;
1611   unsigned char *tmp;
1612   SilcUInt32 len;
1613   SilcBufferStruct buf;
1614   SilcID id;
1615
1616   /* Sanity checks */
1617   CHECK_STATUS("Cannot set ban: ");
1618   CHECK_ARGS(2, 3);
1619
1620   /* Take Channel ID */
1621   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1622     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1623     goto out;
1624   }
1625
1626   /* Get the channel entry */
1627   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1628   if (!channel) {
1629     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1630     goto out;
1631   }
1632
1633   /* Get the ban list */
1634   tmp = silc_argument_get_arg_type(args, 3, &len);
1635   if (tmp)
1636     silc_buffer_set(&buf, tmp, len);
1637
1638   /* Notify application */
1639   silc_client_command_callback(cmd, channel, tmp ? &buf : NULL);
1640
1641  out:
1642   silc_fsm_next(fsm, silc_client_command_reply_processed);
1643   return SILC_FSM_CONTINUE;
1644 }
1645
1646 /********************************** LEAVE ***********************************/
1647
1648 /* Reply to LEAVE command. */
1649
1650 SILC_FSM_STATE(silc_client_command_reply_leave)
1651 {
1652   SilcClientCommandContext cmd = fsm_context;
1653   SilcClientConnection conn = cmd->conn;
1654   SilcClient client = conn->client;
1655   SilcCommandPayload payload = state_context;
1656   SilcArgumentPayload args = silc_command_get_args(payload);
1657   SilcChannelEntry channel;
1658   SilcID id;
1659
1660   /* Sanity checks */
1661   CHECK_STATUS("Cannot set leave: ");
1662   CHECK_ARGS(2, 2);
1663
1664   /* Get Channel ID */
1665   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1666     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1667     goto out;
1668   }
1669
1670   /* Get the channel entry */
1671   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1672   if (!channel) {
1673     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1674     goto out;
1675   }
1676
1677   /* Remove us from this channel. */
1678   silc_client_remove_from_channel(channel, conn->local_entry);
1679
1680   /* Notify application */
1681   silc_client_command_callback(cmd, channel);
1682
1683   /* Now delete the channel. */
1684   silc_client_del_channel(client, conn, channel);
1685
1686  out:
1687   silc_fsm_next(fsm, silc_client_command_reply_processed);
1688   return SILC_FSM_CONTINUE;
1689 }
1690
1691 /********************************* USERS ************************************/
1692
1693 /* Continue USERS command after resolving unknown users */
1694
1695 static void
1696 silc_client_command_reply_users_resolved(SilcClient client,
1697                                          SilcClientConnection conn,
1698                                          SilcStatus status,
1699                                          SilcDList clients,
1700                                          void *context)
1701 {
1702   SilcClientCommandContext cmd = context;
1703   SILC_FSM_CALL_CONTINUE(&cmd->thread);
1704 }
1705
1706 /* Continue USERS command after resolving unknown channel */
1707
1708 static void
1709 silc_client_command_reply_users_continue(SilcClient client,
1710                                          SilcClientConnection conn,
1711                                          SilcStatus status,
1712                                          SilcDList channels,
1713                                          void *context)
1714 {
1715   SilcClientCommandContext cmd = context;
1716
1717   if (!channels) {
1718     SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
1719     SilcArgumentPayload args = silc_command_get_args(payload);
1720
1721     cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
1722     ERROR_CALLBACK(cmd->status);
1723     silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
1724   }
1725
1726   SILC_FSM_CALL_CONTINUE(&cmd->thread);
1727 }
1728
1729 /* Reply to USERS command. Received list of client ID's and theirs modes
1730    on the channel we requested. */
1731
1732 SILC_FSM_STATE(silc_client_command_reply_users)
1733 {
1734   SilcClientCommandContext cmd = fsm_context;
1735   SilcClientConnection conn = cmd->conn;
1736   SilcClient client = conn->client;
1737   SilcCommandPayload payload = state_context;
1738   SilcArgumentPayload args = silc_command_get_args(payload);
1739   unsigned char *tmp;
1740   SilcUInt32 tmp_len, list_count;
1741   SilcUInt16 idp_len, mode;
1742   SilcHashTableList htl;
1743   SilcBufferStruct client_id_list, client_mode_list;
1744   SilcChannelEntry channel;
1745   SilcClientEntry client_entry;
1746   SilcID id;
1747   int i;
1748
1749   /* Sanity checks */
1750   CHECK_STATUS("Cannot get users: ");
1751   CHECK_ARGS(5, 5);
1752
1753   /* Get channel ID */
1754   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1755     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1756     goto out;
1757   }
1758
1759   /* Get channel entry */
1760   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1761   if (!channel) {
1762     /* Resolve the channel from server */
1763     SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1764                         client, conn, &id.u.channel_id,
1765                         silc_client_command_reply_users_continue, cmd));
1766     /* NOT REACHED */
1767   }
1768
1769   /* Get the list count */
1770   tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1771   if (!tmp || tmp_len != 4) {
1772     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1773     goto out;
1774   }
1775   SILC_GET32_MSB(list_count, tmp);
1776
1777   /* Get Client ID list */
1778   tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1779   if (!tmp) {
1780     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1781     goto out;
1782   }
1783   silc_buffer_set(&client_id_list, tmp, tmp_len);
1784
1785   /* Resolve users we do not know about */
1786   if (!cmd->resolved) {
1787     cmd->resolved = TRUE;
1788     SILC_FSM_CALL(silc_client_get_clients_by_list(
1789                           client, conn, list_count, &client_id_list,
1790                           silc_client_command_reply_users_resolved, cmd));
1791     /* NOT REACHED */
1792   }
1793
1794   /* Get client mode list */
1795   tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
1796   if (!tmp) {
1797     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1798     goto out;
1799   }
1800   silc_buffer_set(&client_mode_list, tmp, tmp_len);
1801
1802   SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1803
1804   /* Cache the received Client ID's and modes. */
1805   for (i = 0; i < list_count; i++) {
1806     SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1807     idp_len += 4;
1808     if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
1809       goto out;
1810
1811     /* Mode */
1812     SILC_GET32_MSB(mode, client_mode_list.data);
1813
1814     /* Save the client on this channel.  Unknown clients are ignored as they
1815        clearly do not exist since the resolving didn't find them. */
1816     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1817     if (client_entry)
1818       silc_client_add_to_channel(channel, client_entry, mode);
1819     silc_client_unref_client(client, conn, client_entry);
1820
1821     if (!silc_buffer_pull(&client_id_list, idp_len))
1822       goto out;
1823     if (!silc_buffer_pull(&client_mode_list, 4))
1824       goto out;
1825   }
1826
1827   /* Notify application */
1828   silc_hash_table_list(channel->user_list, &htl);
1829   silc_client_command_callback(cmd, channel, &htl);
1830   silc_hash_table_list_reset(&htl);
1831
1832  out:
1833   silc_fsm_next(fsm, silc_client_command_reply_processed);
1834   return SILC_FSM_CONTINUE;
1835 }
1836
1837 /********************************** GETKEY **********************************/
1838
1839 /* Received command reply to GETKEY command. WE've received the remote
1840    client's public key. */
1841
1842 SILC_FSM_STATE(silc_client_command_reply_getkey)
1843 {
1844   SilcClientCommandContext cmd = fsm_context;
1845   SilcClientConnection conn = cmd->conn;
1846   SilcClient client = conn->client;
1847   SilcCommandPayload payload = state_context;
1848   SilcArgumentPayload args = silc_command_get_args(payload);
1849   SilcClientEntry client_entry;
1850   SilcServerEntry server_entry;
1851   unsigned char *tmp;
1852   SilcUInt32 len;
1853   SilcPublicKey public_key;
1854   SilcID id;
1855
1856   /* Sanity checks */
1857   CHECK_STATUS("Cannot get key: ");
1858   CHECK_ARGS(2, 3);
1859
1860   /* Get the ID */
1861   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1862     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1863     goto out;
1864   }
1865
1866   /* Get the public key */
1867   tmp = silc_argument_get_arg_type(args, 3, &len);
1868   if (!tmp) {
1869     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1870     goto out;
1871   }
1872   if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
1873     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1874     goto out;
1875   }
1876
1877   if (id.type == SILC_ID_CLIENT) {
1878     /* Received client's public key */
1879     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1880     if (!client_entry) {
1881       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1882       goto out;
1883     }
1884
1885     /* Save fingerprint */
1886     if (!client_entry->fingerprint)
1887       silc_hash_make(client->sha1hash, tmp + 4, len - 4,
1888                      client_entry->fingerprint);
1889     if (!client_entry->public_key) {
1890       client_entry->public_key = public_key;
1891       public_key = NULL;
1892     }
1893
1894     /* Notify application */
1895     silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
1896                                  client_entry->public_key);
1897     silc_client_unref_client(client, conn, client_entry);
1898   } else if (id.type == SILC_ID_SERVER) {
1899     /* Received server's public key */
1900     server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1901     if (!server_entry) {
1902       ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1903       goto out;
1904     }
1905
1906     if (!server_entry->public_key) {
1907       server_entry->public_key = public_key;
1908       public_key = NULL;
1909     }
1910
1911     /* Notify application */
1912     silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
1913                                  server_entry->public_key);
1914   }
1915
1916  out:
1917   if (public_key)
1918     silc_pkcs_public_key_free(public_key);
1919   silc_fsm_next(fsm, silc_client_command_reply_processed);
1920   return SILC_FSM_CONTINUE;
1921 }
1922
1923 /********************************** SERVICE *********************************/
1924
1925 /* Reply to SERVICE command. */
1926 /* XXX incomplete */
1927
1928 SILC_FSM_STATE(silc_client_command_reply_service)
1929 {
1930   SilcClientCommandContext cmd = fsm_context;
1931   SilcCommandPayload payload = state_context;
1932   SilcArgumentPayload args = silc_command_get_args(payload);
1933   SilcUInt32 tmp_len;
1934   unsigned char *service_list, *name;
1935
1936   /* Sanity checks */
1937   CHECK_STATUS("Cannot get service: ");
1938
1939   /* Get service list */
1940   service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
1941
1942   /* Get requested service name */
1943   name = silc_argument_get_arg_type(args, 3, &tmp_len);
1944
1945   /* Notify application */
1946   silc_client_command_callback(cmd, service_list, name);
1947
1948   silc_fsm_next(fsm, silc_client_command_reply_processed);
1949   return SILC_FSM_CONTINUE;
1950 }
1951
1952 /*********************************** QUIT ***********************************/
1953
1954 /* QUIT command reply stub */
1955
1956 SILC_FSM_STATE(silc_client_command_reply_quit)
1957 {
1958   silc_fsm_next(fsm, silc_client_command_reply_processed);
1959   return SILC_FSM_CONTINUE;
1960 }