updates.
[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 - 2002 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  * Command reply functions are "the otherside" of the command functions.
22  * Reply to a command sent by server is handled by these functions.
23  *
24  * The arguments received from server are also passed to the calling
25  * application through command_reply client operation.  The arguments are
26  * exactly same and in same order as the server sent it.  However, ID's are
27  * not sent to the application.  Instead, corresponding ID entry is sent
28  * to the application.  For example, instead of sending Client ID the 
29  * corresponding SilcClientEntry is sent to the application.  The case is
30  * same with for example Channel ID's.  This way application has all the
31  * necessary data already in hand without redundant searching.  If ID is
32  * received but ID entry does not exist, NULL is sent.
33  */
34
35 #include "clientlibincludes.h"
36 #include "client_internal.h"
37
38 const SilcCommandStatusMessage silc_command_status_messages[] = {
39
40   { STAT(NO_SUCH_NICK),      "There was no such nickname" },
41   { STAT(NO_SUCH_CHANNEL),   "There was no such channel" },
42   { STAT(NO_SUCH_SERVER),    "There was no such server" },
43   { STAT(TOO_MANY_TARGETS),  "Duplicate recipients. No message delivered" },
44   { STAT(NO_RECIPIENT),      "No recipient given" },
45   { STAT(UNKNOWN_COMMAND),   "Unknown command" },
46   { STAT(WILDCARDS),         "Unknown command" },
47   { STAT(NO_CLIENT_ID),      "No Client ID given" },
48   { STAT(NO_CHANNEL_ID),     "No Channel ID given" },
49   { STAT(NO_SERVER_ID),      "No Server ID given" },
50   { STAT(BAD_CLIENT_ID),     "Bad Client ID" },
51   { STAT(BAD_CHANNEL_ID),    "Bad Channel ID" },
52   { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
53   { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
54   { STAT(NICKNAME_IN_USE),   "Nickname already exists" },
55   { STAT(NOT_ON_CHANNEL),    "You are not on that channel" },
56   { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
57   { STAT(USER_ON_CHANNEL),   "User already on the channel" },
58   { STAT(NOT_REGISTERED),    "You have not registered" },
59   { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
60   { STAT(TOO_MANY_PARAMS),   "Too many parameters" },
61   { STAT(PERM_DENIED),       "Permission denied" },
62   { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
63   { STAT(BAD_PASSWORD),      "Cannot join channel. Incorrect password" },
64   { STAT(CHANNEL_IS_FULL),   "Cannot join channel. Channel is full" },
65   { STAT(NOT_INVITED),     "Cannot join channel. You have not been invited" },
66   { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
67   { STAT(UNKNOWN_MODE),    "Unknown mode" },
68   { STAT(NOT_YOU),         "Cannot change mode for other users" },
69   { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
70   { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
71   { STAT(NO_SERVER_PRIV),  "Permission denied. You are not server operator" },
72   { STAT(NO_ROUTER_PRIV),  "Permission denied. You are not SILC operator" },
73   { STAT(BAD_NICKNAME),    "Bad nickname" },
74   { STAT(BAD_CHANNEL),     "Bad channel name" },
75   { STAT(AUTH_FAILED),     "Authentication failed" },
76   { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
77   { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
78
79   { 0, NULL }
80 };
81 /* Command reply operation that is called at the end of all command replys. 
82    Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
83 #define COMMAND_REPLY(args) cmd->client->internal->ops->command_reply args
84 #define ARGS cmd->client, cmd->sock->user_data,                         \
85              cmd->payload, TRUE, silc_command_get(cmd->payload), status
86
87 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
88 #define COMMAND_REPLY_ERROR cmd->client->internal->ops->                \
89   command_reply(cmd->client, cmd->sock->user_data, cmd->payload,        \
90   FALSE, silc_command_get(cmd->payload), status)
91
92 #define SAY cmd->client->internal->ops->say
93
94 /* All functions that call the COMMAND_CHECK_STATUS or the
95    COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
96
97 #define COMMAND_CHECK_STATUS                                              \
98 do {                                                                      \
99   SILC_LOG_DEBUG(("Start"));                                              \
100   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
101   if (status != SILC_STATUS_OK)  {                                        \
102     COMMAND_REPLY_ERROR;                                                  \
103     goto out;                                                             \
104   }                                                                       \
105 } while(0)
106
107 #define COMMAND_CHECK_STATUS_LIST                                         \
108 do {                                                                      \
109   SILC_LOG_DEBUG(("Start"));                                              \
110   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
111   if (status != SILC_STATUS_OK &&                                         \
112       status != SILC_STATUS_LIST_START &&                                 \
113       status != SILC_STATUS_LIST_ITEM &&                                  \
114       status != SILC_STATUS_LIST_END) {                                   \
115     COMMAND_REPLY_ERROR;                                                  \
116     goto out;                                                             \
117   }                                                                       \
118 } while(0)
119
120 /* Process received command reply. */
121
122 void silc_client_command_reply_process(SilcClient client,
123                                        SilcSocketConnection sock,
124                                        SilcPacketContext *packet)
125 {
126   SilcBuffer buffer = packet->buffer;
127   SilcClientCommand cmd;
128   SilcClientCommandReplyContext ctx;
129   SilcCommandPayload payload;
130   SilcCommand command;
131   SilcCommandCb reply = NULL;
132   
133   /* Get command reply payload from packet */
134   payload = silc_command_payload_parse(buffer->data, buffer->len);
135   if (!payload) {
136     /* Silently ignore bad reply packet */
137     SILC_LOG_DEBUG(("Bad command reply packet"));
138     return;
139   }
140   
141   /* Allocate command reply context. This must be free'd by the
142      command reply routine receiving it. */
143   ctx = silc_calloc(1, sizeof(*ctx));
144   ctx->client = client;
145   ctx->sock = sock;
146   ctx->payload = payload;
147   ctx->args = silc_command_get_args(ctx->payload);
148   ctx->packet = packet;
149   ctx->ident = silc_command_get_ident(ctx->payload);
150
151   /* Check for pending commands and mark to be exeucted */
152   silc_client_command_pending_check(sock->user_data, ctx, 
153                                     silc_command_get(ctx->payload), 
154                                     ctx->ident);
155
156   /* Execute command reply */
157
158   command = silc_command_get(ctx->payload);
159
160   /* Try to find matching the command identifier */
161   silc_list_start(client->internal->commands);
162   while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
163     if (cmd->cmd == command && !cmd->ident)
164       reply = cmd->reply;
165     if (cmd->cmd == command && cmd->ident == ctx->ident) {
166       (*cmd->reply)((void *)ctx, NULL);
167       break;
168     }
169   }
170
171   if (cmd == SILC_LIST_END) {
172     if (reply)
173       /* No specific identifier for command reply, call first one found */
174       (*reply)(ctx, NULL);
175     else
176       silc_free(ctx);
177   }
178 }
179
180 /* Returns status message string */
181
182 char *silc_client_command_status_message(SilcCommandStatus status)
183 {
184   int i;
185
186   for (i = 0; silc_command_status_messages[i].message; i++) {
187     if (silc_command_status_messages[i].status == status)
188       break;
189   }
190
191   if (silc_command_status_messages[i].message == NULL)
192     return NULL;
193
194   return silc_command_status_messages[i].message;
195 }
196
197 /* Free command reply context and its internals. */
198
199 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
200 {
201   if (cmd) {
202     silc_command_payload_free(cmd->payload);
203     silc_free(cmd);
204   }
205 }
206
207 static void 
208 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
209                                      SilcCommandStatus status,
210                                      bool notify)
211 {
212   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
213   SilcClientID *client_id;
214   SilcClientEntry client_entry = NULL;
215   int argc;
216   uint32 len;
217   unsigned char *id_data, *tmp;
218   char *nickname = NULL, *username = NULL;
219   char *realname = NULL;
220   uint32 idle = 0, mode = 0;
221   SilcBuffer channels = NULL;
222   unsigned char *fingerprint;
223   uint32 fingerprint_len;
224   
225   argc = silc_argument_get_arg_num(cmd->args);
226
227   id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
228   if (!id_data) {
229     if (notify)
230       COMMAND_REPLY_ERROR;
231     return;
232   }
233   
234   client_id = silc_id_payload_parse_id(id_data, len);
235   if (!client_id) {
236     if (notify)
237       COMMAND_REPLY_ERROR;
238     return;
239   }
240   
241   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
242   username = silc_argument_get_arg_type(cmd->args, 4, &len);
243   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
244   if (!nickname || !username || !realname) {
245     if (notify)
246       COMMAND_REPLY_ERROR;
247     return;
248   }
249
250   tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
251   if (tmp) {
252     channels = silc_buffer_alloc(len);
253     silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
254     silc_buffer_put(channels, tmp, len);
255   }
256
257   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
258   if (tmp)
259     SILC_GET32_MSB(mode, tmp);
260
261   tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
262   if (tmp)
263     SILC_GET32_MSB(idle, tmp);
264
265   fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
266
267   /* Check if we have this client cached already. */
268   client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
269   if (!client_entry) {
270     SILC_LOG_DEBUG(("Adding new client entry"));
271     client_entry = 
272       silc_client_add_client(cmd->client, conn, nickname, username, realname,
273                              client_id, mode);
274   } else {
275     silc_client_update_client(cmd->client, conn, client_entry, 
276                               nickname, username, realname, mode);
277     silc_free(client_id);
278   }
279
280   if (fingerprint && !client_entry->fingerprint) {
281     client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
282     client_entry->fingerprint_len = fingerprint_len;
283   }
284
285   if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
286     client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
287
288   /* Notify application */
289   if (!cmd->callback && notify)
290     COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, 
291                    channels, mode, idle, fingerprint));
292
293   if (channels)
294     silc_buffer_free(channels);
295 }
296
297 /* Received reply for WHOIS command. This maybe called several times
298    for one WHOIS command as server may reply with list of results. */
299
300 SILC_CLIENT_CMD_REPLY_FUNC(whois)
301 {
302   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
303   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
304   SilcCommandStatus status;
305
306   COMMAND_CHECK_STATUS_LIST;
307
308   /* Save WHOIS info */
309   silc_client_command_reply_whois_save(cmd, status, TRUE);
310
311   /* Pending callbacks are not executed if this was an list entry */
312   if (status != SILC_STATUS_OK &&
313       status != SILC_STATUS_LIST_END) {
314     silc_client_command_reply_free(cmd);
315     return;
316   }
317
318  out:
319   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
320
321   /* If we received notify for invalid ID we'll remove the ID if we
322      have it cached. */
323   if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
324     SilcClientEntry client_entry;
325     uint32 tmp_len;
326     unsigned char *tmp =
327       silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
328                                  2, &tmp_len);
329     if (tmp) {
330       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
331       if (client_id) {
332         client_entry = silc_client_get_client_by_id(cmd->client, conn,
333                                                     client_id);
334         if (client_entry)
335           silc_client_del_client(cmd->client, conn, client_entry);
336         silc_free(client_id);
337       }
338     }
339   }
340
341   silc_client_command_reply_free(cmd);
342 }
343
344 /* Received reply for WHOWAS command. */
345
346 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
347 {
348   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
349   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
350   SilcCommandStatus status;
351   SilcClientID *client_id;
352   SilcClientEntry client_entry = NULL;
353   uint32 len;
354   unsigned char *id_data;
355   char *nickname, *username;
356   char *realname = NULL;
357
358   COMMAND_CHECK_STATUS_LIST;
359
360   id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
361   if (!id_data) {
362     COMMAND_REPLY_ERROR;
363     goto out;
364   }
365   
366   client_id = silc_id_payload_parse_id(id_data, len);
367   if (!client_id) {
368     COMMAND_REPLY_ERROR;
369     goto out;
370   }
371
372   /* Get the client entry, if exists */
373   client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
374   silc_free(client_id);
375
376   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
377   username = silc_argument_get_arg_type(cmd->args, 4, &len);
378   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
379   if (!nickname || !username) {
380     COMMAND_REPLY_ERROR;
381     goto out;
382   }
383
384   /* Notify application. We don't save any history information to any
385      cache. Just pass the data to the application for displaying on 
386      the screen. */
387   COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
388
389   /* Pending callbacks are not executed if this was an list entry */
390   if (status != SILC_STATUS_OK &&
391       status != SILC_STATUS_LIST_END) {
392     silc_client_command_reply_free(cmd);
393     return;
394   }
395
396  out:
397   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
398   silc_client_command_reply_free(cmd);
399 }
400
401 static void 
402 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
403                                         SilcCommandStatus status,
404                                         bool notify)
405 {
406   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
407   SilcClient client = cmd->client;
408   SilcClientID *client_id = NULL;
409   SilcServerID *server_id = NULL;
410   SilcChannelID *channel_id = NULL;
411   SilcIDCacheEntry id_cache = NULL;
412   SilcClientEntry client_entry;
413   SilcServerEntry server_entry;
414   SilcChannelEntry channel_entry;
415   int argc;
416   uint32 len;
417   unsigned char *id_data;
418   char *name = NULL, *info = NULL;
419   SilcIDPayload idp = NULL;
420   SilcIdType id_type;
421   
422   argc = silc_argument_get_arg_num(cmd->args);
423
424   id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
425   if (!id_data) {
426     if (notify)
427       COMMAND_REPLY_ERROR;
428     return;
429   }
430   idp = silc_id_payload_parse(id_data, len);
431   if (!idp) {
432     if (notify)
433       COMMAND_REPLY_ERROR;
434     return;
435   }
436
437   name = silc_argument_get_arg_type(cmd->args, 3, &len);
438   info = silc_argument_get_arg_type(cmd->args, 4, &len);
439
440   id_type = silc_id_payload_get_type(idp);
441
442   switch (id_type) {
443   case SILC_ID_CLIENT:
444     client_id = silc_id_payload_get_id(idp);
445
446     SILC_LOG_DEBUG(("Received client information"));
447
448     /* Check if we have this client cached already. */
449     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
450     if (!client_entry) {
451       SILC_LOG_DEBUG(("Adding new client entry"));
452       client_entry = 
453         silc_client_add_client(cmd->client, conn, name, info, NULL,
454                                silc_id_dup(client_id, id_type), 0);
455     } else {
456       silc_client_update_client(cmd->client, conn, client_entry, 
457                                 name, info, NULL, 0);
458     }
459
460     if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
461       client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
462
463     /* Notify application */
464     if (notify)
465       COMMAND_REPLY((ARGS, client_entry, name, info));
466     break;
467
468   case SILC_ID_SERVER:
469     server_id = silc_id_payload_get_id(idp);
470
471     SILC_LOG_DEBUG(("Received server information"));
472
473     /* Check if we have this server cached already. */
474     if (!silc_idcache_find_by_id_one(conn->server_cache, 
475                                      (void *)server_id, &id_cache)) {
476       SILC_LOG_DEBUG(("Adding new server entry"));
477       
478       server_entry = silc_calloc(1, sizeof(*server_entry));
479       server_entry->server_id = silc_id_dup(server_id, id_type);
480       if (name)
481         server_entry->server_name = strdup(name);
482       if (info)
483         server_entry->server_info = strdup(info);
484       
485       /* Add server to cache */
486       silc_idcache_add(conn->server_cache, server_entry->server_name,
487                        server_entry->server_id, (void *)server_entry, 
488                        0, NULL);
489     } else {
490       server_entry = (SilcServerEntry)id_cache->context;
491     }
492
493     /* Notify application */
494     if (notify)
495       COMMAND_REPLY((ARGS, server_entry, name, info));
496     break;
497
498   case SILC_ID_CHANNEL:
499     channel_id = silc_id_payload_get_id(idp);
500
501     SILC_LOG_DEBUG(("Received channel information"));
502
503     /* Check if we have this channel cached already. */
504     channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
505     if (!channel_entry) {
506       if (!name)
507         break;
508
509       /* Add new channel entry */
510       channel_entry = silc_client_add_channel(client, conn, name, 0,
511                                               channel_id);
512       channel_id = NULL;
513     }
514
515     /* Notify application */
516     if (notify)
517       COMMAND_REPLY((ARGS, channel_entry, name, info));
518     break;
519   }
520
521   silc_id_payload_free(idp);
522   silc_free(client_id);
523   silc_free(server_id);
524   silc_free(channel_id);
525 }
526
527 /* Received reply for IDENTIFY command. This maybe called several times
528    for one IDENTIFY command as server may reply with list of results. 
529    This is totally silent and does not print anything on screen. */
530
531 SILC_CLIENT_CMD_REPLY_FUNC(identify)
532 {
533   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
534   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
535   SilcCommandStatus status;
536
537   COMMAND_CHECK_STATUS_LIST;
538
539   /* Save IDENTIFY info */
540   silc_client_command_reply_identify_save(cmd, status, TRUE);
541
542   /* Pending callbacks are not executed if this was an list entry */
543   if (status != SILC_STATUS_OK &&
544       status != SILC_STATUS_LIST_END) {
545     silc_client_command_reply_free(cmd);
546     return;
547   }
548
549  out:
550   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
551
552   /* If we received notify for invalid ID we'll remove the ID if we
553      have it cached. */
554   if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
555     SilcClientEntry client_entry;
556     uint32 tmp_len;
557     unsigned char *tmp =
558       silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
559                                  2, &tmp_len);
560     if (tmp) {
561       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
562       if (client_id) {
563         client_entry = silc_client_get_client_by_id(cmd->client, conn,
564                                                     client_id);
565         if (client_entry)
566           silc_client_del_client(cmd->client, conn, client_entry);
567         silc_free(client_id);
568       }
569     }
570   }
571
572   silc_client_command_reply_free(cmd);
573 }
574
575 /* Received reply for command NICK. If everything went without errors
576    we just received our new Client ID. */
577
578 SILC_CLIENT_CMD_REPLY_FUNC(nick)
579 {
580   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
581   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
582   SilcCommandStatus status;
583   SilcIDPayload idp;
584   unsigned char *tmp;
585   uint32 argc, len;
586
587   SILC_LOG_DEBUG(("Start"));
588
589   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
590   if (status != SILC_STATUS_OK) {
591     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
592         "Cannot set nickname: %s", silc_client_command_status_message(status));
593     COMMAND_REPLY_ERROR;
594     goto out;
595   }
596
597   argc = silc_argument_get_arg_num(cmd->args);
598   if (argc < 2 || argc > 2) {
599     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
600         "Cannot set nickname: bad reply to command");
601     COMMAND_REPLY_ERROR;
602     goto out;
603   }
604
605   /* Take received Client ID */
606   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
607   idp = silc_id_payload_parse(tmp, len);
608   if (!idp) {
609     COMMAND_REPLY_ERROR;
610     goto out;
611   }
612   silc_client_receive_new_id(cmd->client, cmd->sock, idp);
613     
614   /* Notify application */
615   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
616   COMMAND_REPLY((ARGS, conn->local_entry));
617   silc_client_command_reply_free(cmd);
618   return;
619
620  out:
621   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
622   silc_client_command_reply_free(cmd);
623 }
624
625 /* Received reply to the LIST command. */
626
627 SILC_CLIENT_CMD_REPLY_FUNC(list)
628 {
629   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
630   SilcCommandStatus status;
631   unsigned char *tmp, *name, *topic;
632   uint32 usercount = 0;
633
634   COMMAND_CHECK_STATUS_LIST;
635
636   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
637   topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
638   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
639   if (tmp)
640     SILC_GET32_MSB(usercount, tmp);
641
642   /* Notify application */
643   COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
644
645   /* Pending callbacks are not executed if this was an list entry */
646   if (status != SILC_STATUS_OK &&
647       status != SILC_STATUS_LIST_END) {
648     silc_client_command_reply_free(cmd);
649     return;
650   }
651
652  out:
653   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
654   silc_client_command_reply_free(cmd);
655 }
656
657 /* Received reply to topic command. */
658
659 SILC_CLIENT_CMD_REPLY_FUNC(topic)
660 {
661   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
662   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
663   SilcCommandStatus status;
664   SilcChannelEntry channel;
665   SilcChannelID *channel_id = NULL;
666   unsigned char *tmp;
667   char *topic;
668   uint32 argc, len;
669
670   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
671   if (status != SILC_STATUS_OK) {
672     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
673         "%s", silc_client_command_status_message(status));
674     COMMAND_REPLY_ERROR;
675     goto out;
676   }
677
678   argc = silc_argument_get_arg_num(cmd->args);
679   if (argc < 1 || argc > 3) {
680     COMMAND_REPLY_ERROR;
681     goto out;
682   }
683
684   /* Take Channel ID */
685   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
686   if (!tmp)
687     goto out;
688
689   /* Take topic */
690   topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
691   if (!topic)
692     goto out;
693
694   channel_id = silc_id_payload_parse_id(tmp, len);
695   if (!channel_id)
696     goto out;
697
698   /* Get the channel entry */
699   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
700   if (!channel) {
701     silc_free(channel_id);
702     COMMAND_REPLY_ERROR;
703     goto out;
704   }
705   
706   /* Notify application */
707   COMMAND_REPLY((ARGS, channel, topic));
708
709  out:
710   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
711   silc_client_command_reply_free(cmd);
712 }
713
714 /* Received reply to invite command. */
715
716 SILC_CLIENT_CMD_REPLY_FUNC(invite)
717 {
718   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
719   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
720   SilcCommandStatus status;
721   SilcChannelEntry channel;
722   SilcChannelID *channel_id;
723   unsigned char *tmp;
724   uint32 len;
725
726   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
727   SILC_GET16_MSB(status, tmp);
728   if (status != SILC_STATUS_OK) {
729     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
730         "%s", silc_client_command_status_message(status));
731     COMMAND_REPLY_ERROR;
732     goto out;
733   }
734
735   /* Take Channel ID */
736   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
737   if (!tmp)
738     goto out;
739
740   channel_id = silc_id_payload_parse_id(tmp, len);
741   if (!channel_id)
742     goto out;
743
744   /* Get the channel entry */
745   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
746   if (!channel) {
747     silc_free(channel_id);
748     COMMAND_REPLY_ERROR;
749     goto out;
750   }
751
752   /* Get the invite list */
753   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
754
755   /* Notify application */
756   COMMAND_REPLY((ARGS, channel, tmp));
757
758  out:
759   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
760   silc_client_command_reply_free(cmd);
761 }
762
763 /* Received reply to the KILL command. */
764  
765 SILC_CLIENT_CMD_REPLY_FUNC(kill)
766 {
767   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
768   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
769   SilcCommandStatus status;
770
771   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
772   if (status != SILC_STATUS_OK) {
773     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
774         "%s", silc_client_command_status_message(status));
775     COMMAND_REPLY_ERROR;
776     goto out;
777   }
778
779   /* Notify application */
780   COMMAND_REPLY((ARGS));
781
782  out:
783   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
784   silc_client_command_reply_free(cmd);
785 }
786
787 /* Received reply to INFO command. We receive the server ID and some
788    information about the server user requested. */
789
790 SILC_CLIENT_CMD_REPLY_FUNC(info)
791 {
792   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
793   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
794   SilcCommandStatus status;
795   unsigned char *tmp;
796   SilcIDCacheEntry id_cache;
797   SilcServerEntry server;
798   SilcServerID *server_id = NULL;
799   char *server_name, *server_info;
800   uint32 len;
801
802   SILC_LOG_DEBUG(("Start"));
803
804   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
805   SILC_GET16_MSB(status, tmp);
806   if (status != SILC_STATUS_OK) {
807     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", 
808         silc_client_command_status_message(status));
809     COMMAND_REPLY_ERROR;
810     goto out;
811   }
812
813   /* Get server ID */
814   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
815   if (!tmp)
816     goto out;
817
818   server_id = silc_id_payload_parse_id(tmp, len);
819   if (!server_id)
820     goto out;
821
822   /* Get server name */
823   server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
824   if (!server_name)
825     goto out;
826
827   /* Get server info */
828   server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
829   if (!server_info)
830     goto out;
831
832   /* See whether we have this server cached. If not create it. */
833   if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
834                                    &id_cache)) {
835     SILC_LOG_DEBUG(("New server entry"));
836
837     server = silc_calloc(1, sizeof(*server));
838     server->server_name = strdup(server_name);
839     server->server_info = strdup(server_info);
840     server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
841
842     /* Add it to the cache */
843     silc_idcache_add(conn->server_cache, server->server_name,
844                      server->server_id, (void *)server, 0, NULL);
845   } else {
846     server = (SilcServerEntry)id_cache->context;
847   }
848   
849   /* Notify application */
850   COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
851
852  out:
853   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
854   silc_free(server_id);
855   silc_client_command_reply_free(cmd);
856 }
857
858 /* Received reply to PING command. The reply time is shown to user. */
859
860 SILC_CLIENT_CMD_REPLY_FUNC(ping)
861 {
862   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
863   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
864   SilcCommandStatus status;
865   void *id;
866   int i;
867   time_t diff, curtime;
868
869   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
870   if (status != SILC_STATUS_OK) {
871     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
872         "%s", silc_client_command_status_message(status));
873     COMMAND_REPLY_ERROR;
874     goto out;
875   }
876
877   curtime = time(NULL);
878   id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
879                       cmd->packet->src_id_type);
880   if (!id || !conn->ping) {
881     COMMAND_REPLY_ERROR;
882     goto out;
883   }
884
885   for (i = 0; i < conn->ping_count; i++) {
886     if (!conn->ping[i].dest_id)
887       continue;
888     if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
889       diff = curtime - conn->ping[i].start_time;
890       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
891           "Ping reply from %s: %d second%s", 
892           conn->ping[i].dest_name, diff, 
893           diff == 1 ? "" : "s");
894       
895       conn->ping[i].start_time = 0;
896       silc_free(conn->ping[i].dest_id);
897       conn->ping[i].dest_id = NULL;
898       silc_free(conn->ping[i].dest_name);
899       conn->ping[i].dest_name = NULL;
900       break;
901     }
902   }
903
904   silc_free(id);
905
906   /* Notify application */
907   COMMAND_REPLY((ARGS));
908
909  out:
910   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
911   silc_client_command_reply_free(cmd);
912 }
913
914 /* Received reply for JOIN command. */
915
916 SILC_CLIENT_CMD_REPLY_FUNC(join)
917 {
918   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
919   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
920   SilcCommandStatus status;
921   SilcChannelEntry channel;
922   SilcChannelUser chu;
923   SilcChannelID *channel_id;
924   uint32 argc, mode = 0, len, list_count;
925   char *topic, *tmp, *channel_name = NULL, *hmac;
926   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
927   int i;
928
929   SILC_LOG_DEBUG(("Start"));
930
931   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
932   if (status != SILC_STATUS_OK) {
933     if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
934       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
935           "%s", silc_client_command_status_message(status));
936     COMMAND_REPLY_ERROR;
937     goto out;
938   }
939
940   argc = silc_argument_get_arg_num(cmd->args);
941   if (argc < 7 || argc > 14) {
942     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
943         "Cannot join channel: Bad reply packet");
944     COMMAND_REPLY_ERROR;
945     goto out;
946   }
947
948   /* Get channel name */
949   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
950   if (!tmp) {
951     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
952         "Cannot join channel: Bad reply packet");
953     COMMAND_REPLY_ERROR;
954     goto out;
955   }
956   channel_name = tmp;
957
958   /* Get Channel ID */
959   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
960   if (!tmp) {
961     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
962         "Cannot join channel: Bad reply packet");
963     COMMAND_REPLY_ERROR;
964     goto out;
965   }
966   channel_id = silc_id_payload_parse_id(tmp, len);
967   if (!channel_id) {
968     COMMAND_REPLY_ERROR;
969     goto out;
970   }
971
972   /* Get channel mode */
973   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
974   if (tmp)
975     SILC_GET32_MSB(mode, tmp);
976
977   /* Get channel key */
978   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
979   if (tmp) {
980     keyp = silc_buffer_alloc(len);
981     silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
982     silc_buffer_put(keyp, tmp, len);
983   }
984
985   /* Get topic */
986   topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
987
988   /* Check whether we have this channel entry already. */
989   channel = silc_client_get_channel(cmd->client, conn, channel_name);
990   if (channel) {
991     if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
992       silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
993   } else {
994     /* Create new channel entry */
995     channel = silc_client_add_channel(cmd->client, conn, channel_name, 
996                                       mode, channel_id);
997   }
998
999   conn->current_channel = channel;
1000
1001   /* Get hmac */
1002   hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1003   if (hmac) {
1004     if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1005       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, 
1006           "Cannot join channel: Unsupported HMAC `%s'", hmac);
1007       COMMAND_REPLY_ERROR;
1008       goto out;
1009     }
1010   }
1011
1012   /* Get the list count */
1013   tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1014   if (!tmp)
1015     goto out;
1016   SILC_GET32_MSB(list_count, tmp);
1017
1018   /* Get Client ID list */
1019   tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1020   if (!tmp)
1021     goto out;
1022
1023   client_id_list = silc_buffer_alloc(len);
1024   silc_buffer_pull_tail(client_id_list, len);
1025   silc_buffer_put(client_id_list, tmp, len);
1026
1027   /* Get client mode list */
1028   tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1029   if (!tmp)
1030     goto out;
1031
1032   client_mode_list = silc_buffer_alloc(len);
1033   silc_buffer_pull_tail(client_mode_list, len);
1034   silc_buffer_put(client_mode_list, tmp, len);
1035
1036   /* Add clients we received in the reply to the channel */
1037   for (i = 0; i < list_count; i++) {
1038     uint16 idp_len;
1039     uint32 mode;
1040     SilcClientID *client_id;
1041     SilcClientEntry client_entry;
1042
1043     /* Client ID */
1044     SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1045     idp_len += 4;
1046     client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1047     if (!client_id)
1048       continue;
1049
1050     /* Mode */
1051     SILC_GET32_MSB(mode, client_mode_list->data);
1052
1053     /* Check if we have this client cached already. */
1054     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1055     if (!client_entry) {
1056       /* No, we don't have it, add entry for it. */
1057       client_entry = 
1058         silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1059                                silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1060     }
1061
1062     /* Join client to the channel */
1063     chu = silc_calloc(1, sizeof(*chu));
1064     chu->client = client_entry;
1065     chu->channel = channel;
1066     chu->mode = mode;
1067     silc_hash_table_add(channel->user_list, client_entry, chu);
1068     silc_hash_table_add(client_entry->channels, channel, chu);
1069
1070     silc_free(client_id);
1071     silc_buffer_pull(client_id_list, idp_len);
1072     silc_buffer_pull(client_mode_list, 4);
1073   }
1074   silc_buffer_push(client_id_list, client_id_list->data - 
1075                    client_id_list->head);
1076   silc_buffer_push(client_mode_list, client_mode_list->data - 
1077                    client_mode_list->head);
1078
1079   /* Save channel key */
1080   if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1081     silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1082
1083   /* Notify application */
1084   COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, 
1085                  keyp ? keyp->head : NULL, NULL,
1086                  NULL, topic, hmac, list_count, client_id_list, 
1087                  client_mode_list));
1088
1089  out:
1090   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1091   silc_client_command_reply_free(cmd);
1092
1093   if (keyp)
1094     silc_buffer_free(keyp);
1095   if (client_id_list)
1096     silc_buffer_free(client_id_list);
1097   if (client_mode_list)
1098     silc_buffer_free(client_mode_list);
1099 }
1100
1101 /* Received reply for MOTD command */
1102
1103 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1104 {
1105   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1106   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1107   SilcCommandStatus status;
1108   uint32 argc, i;
1109   unsigned char *tmp;
1110   char *motd = NULL, *cp, line[256];
1111
1112   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1113   SILC_GET16_MSB(status, tmp);
1114   if (status != SILC_STATUS_OK) {
1115     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1116         "%s", silc_client_command_status_message(status));
1117     COMMAND_REPLY_ERROR;
1118     return;
1119   }
1120
1121   argc = silc_argument_get_arg_num(cmd->args);
1122   if (argc > 3) {
1123     COMMAND_REPLY_ERROR;
1124     goto out;
1125   }
1126
1127   if (argc == 3) {
1128     motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1129     if (!motd) {
1130       COMMAND_REPLY_ERROR;
1131       goto out;
1132     }
1133
1134     i = 0;
1135     cp = motd;
1136     while(cp[i] != 0) {
1137       if (cp[i++] == '\n') {
1138         memset(line, 0, sizeof(line));
1139         strncat(line, cp, i - 1);
1140         cp += i;
1141         
1142         if (i == 2)
1143           line[0] = ' ';
1144         
1145         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1146         
1147         if (!strlen(cp))
1148           break;
1149         i = 0;
1150       }
1151     }
1152   }
1153
1154   /* Notify application */
1155   COMMAND_REPLY((ARGS, motd));
1156
1157  out:
1158   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1159   silc_client_command_reply_free(cmd);
1160 }
1161
1162 /* Received reply tot he UMODE command. Save the current user mode */
1163
1164 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1165 {
1166   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1167   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1168   SilcCommandStatus status;
1169   unsigned char *tmp;
1170   uint32 mode;
1171
1172   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1173   SILC_GET16_MSB(status, tmp);
1174   if (status != SILC_STATUS_OK) {
1175     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1176         "%s", silc_client_command_status_message(status));
1177     COMMAND_REPLY_ERROR;
1178     goto out;
1179   }
1180
1181   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1182   if (!tmp) {
1183     COMMAND_REPLY_ERROR;
1184     goto out;
1185   }
1186
1187   SILC_GET32_MSB(mode, tmp);
1188   conn->local_entry->mode = mode;
1189
1190   /* Notify application */
1191   COMMAND_REPLY((ARGS, mode));
1192
1193  out:
1194   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1195   silc_client_command_reply_free(cmd);
1196 }
1197
1198 /* Received reply for CMODE command. */
1199
1200 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1201 {
1202   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1203   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1204   SilcCommandStatus status;
1205   unsigned char *tmp;
1206   uint32 mode;
1207   SilcChannelID *channel_id;
1208   SilcChannelEntry channel;
1209   uint32 len;
1210
1211   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1212   if (status != SILC_STATUS_OK) {
1213     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1214         "%s", silc_client_command_status_message(status));
1215     COMMAND_REPLY_ERROR;
1216     goto out;
1217   }
1218
1219   /* Take Channel ID */
1220   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1221   if (!tmp)
1222     goto out;
1223   channel_id = silc_id_payload_parse_id(tmp, len);
1224   if (!channel_id)
1225     goto out;
1226
1227   /* Get the channel entry */
1228   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1229   if (!channel) {
1230     silc_free(channel_id);
1231     COMMAND_REPLY_ERROR;
1232     goto out;
1233   }
1234   
1235   /* Get channel mode */
1236   tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1237   if (!tmp) {
1238     silc_free(channel_id);
1239     COMMAND_REPLY_ERROR;
1240     goto out;
1241   }
1242
1243   /* Save the mode */
1244   SILC_GET32_MSB(mode, tmp);
1245   channel->mode = mode;
1246
1247   /* Notify application */
1248   COMMAND_REPLY((ARGS, channel, mode));
1249
1250   silc_free(channel_id);
1251
1252  out:
1253   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1254   silc_client_command_reply_free(cmd);
1255 }
1256
1257 /* Received reply for CUMODE command */
1258
1259 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1260 {
1261   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1262   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1263   SilcCommandStatus status;
1264   SilcClientID *client_id;
1265   SilcChannelID *channel_id;
1266   SilcClientEntry client_entry;
1267   SilcChannelEntry channel;
1268   SilcChannelUser chu;
1269   unsigned char *modev, *tmp, *id;
1270   uint32 len, mode;
1271   
1272   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1273   if (status != SILC_STATUS_OK) {
1274     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1275         "%s", silc_client_command_status_message(status));
1276     COMMAND_REPLY_ERROR;
1277     goto out;
1278   }
1279   
1280   /* Get channel mode */
1281   modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1282   if (!modev) {
1283     COMMAND_REPLY_ERROR;
1284     goto out;
1285   }
1286
1287   /* Take Channel ID */
1288   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1289   if (!tmp)
1290     goto out;
1291   channel_id = silc_id_payload_parse_id(tmp, len);
1292   if (!channel_id)
1293     goto out;
1294
1295   /* Get the channel entry */
1296   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1297   if (!channel) {
1298     silc_free(channel_id);
1299     COMMAND_REPLY_ERROR;
1300     goto out;
1301   }
1302   
1303   /* Get Client ID */
1304   id = silc_argument_get_arg_type(cmd->args, 4, &len);
1305   if (!id) {
1306     silc_free(channel_id);
1307     COMMAND_REPLY_ERROR;
1308     goto out;
1309   }
1310   client_id = silc_id_payload_parse_id(id, len);
1311   if (!client_id) {
1312     silc_free(channel_id);
1313     COMMAND_REPLY_ERROR;
1314     goto out;
1315   }
1316   
1317   /* Get client entry */
1318   client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1319   if (!client_entry) {
1320     silc_free(channel_id);
1321     silc_free(client_id);
1322     COMMAND_REPLY_ERROR;
1323     goto out;
1324   }
1325
1326   /* Save the mode */
1327   SILC_GET32_MSB(mode, modev);
1328   chu = silc_client_on_channel(channel, client_entry);
1329   if (chu)
1330     chu->mode = mode;
1331
1332   /* Notify application */
1333   COMMAND_REPLY((ARGS, mode, channel, client_entry));
1334   silc_free(client_id);
1335   silc_free(channel_id);
1336   
1337  out:
1338   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1339   silc_client_command_reply_free(cmd);
1340 }
1341
1342 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1343 {
1344   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1345   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1346   SilcCommandStatus status;
1347   unsigned char *tmp;
1348
1349   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1350   SILC_GET16_MSB(status, tmp);
1351   if (status != SILC_STATUS_OK) {
1352     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1353         "%s", silc_client_command_status_message(status));
1354     COMMAND_REPLY_ERROR;
1355     goto out;
1356   }
1357
1358   /* Notify application */
1359   COMMAND_REPLY((ARGS));
1360
1361  out:
1362   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1363   silc_client_command_reply_free(cmd);
1364 }
1365
1366 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1367 {
1368   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1369   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1370   SilcCommandStatus status;
1371   unsigned char *tmp;
1372
1373   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1374   SILC_GET16_MSB(status, tmp);
1375   if (status != SILC_STATUS_OK) {
1376     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1377         "%s", silc_client_command_status_message(status));
1378     COMMAND_REPLY_ERROR;
1379     goto out;
1380   }
1381
1382   /* Notify application */
1383   COMMAND_REPLY((ARGS));
1384
1385  out:
1386   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1387   silc_client_command_reply_free(cmd);
1388 }
1389
1390 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1391 {
1392   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1393   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1394   SilcCommandStatus status;
1395   unsigned char *tmp;
1396
1397   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1398   SILC_GET16_MSB(status, tmp);
1399   if (status != SILC_STATUS_OK) {
1400     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1401         "%s", silc_client_command_status_message(status));
1402     COMMAND_REPLY_ERROR;
1403     goto out;
1404   }
1405
1406   /* Notify application */
1407   COMMAND_REPLY((ARGS));
1408
1409  out:
1410   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1411   silc_client_command_reply_free(cmd);
1412 }
1413
1414 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1415 {
1416   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1417   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1418   SilcCommandStatus status;
1419   unsigned char *tmp;
1420
1421   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1422   SILC_GET16_MSB(status, tmp);
1423   if (status != SILC_STATUS_OK) {
1424     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1425         "%s", silc_client_command_status_message(status));
1426     COMMAND_REPLY_ERROR;
1427     goto out;
1428   }
1429
1430   /* Notify application */
1431   COMMAND_REPLY((ARGS));
1432
1433  out:
1434   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1435   silc_client_command_reply_free(cmd);
1436 }
1437
1438 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1439 {
1440   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1441   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1442   SilcCommandStatus status;
1443   SilcChannelEntry channel;
1444   SilcChannelID *channel_id;
1445   unsigned char *tmp;
1446   uint32 len;
1447
1448   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1449   SILC_GET16_MSB(status, tmp);
1450   if (status != SILC_STATUS_OK) {
1451     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1452         "%s", silc_client_command_status_message(status));
1453     COMMAND_REPLY_ERROR;
1454     goto out;
1455   }
1456
1457   /* Take Channel ID */
1458   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1459   if (!tmp)
1460     goto out;
1461
1462   channel_id = silc_id_payload_parse_id(tmp, len);
1463   if (!channel_id)
1464     goto out;
1465
1466   /* Get the channel entry */
1467   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1468   if (!channel) {
1469     silc_free(channel_id);
1470     COMMAND_REPLY_ERROR;
1471     goto out;
1472   }
1473   
1474   /* Get the ban list */
1475   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1476
1477   /* Notify application */
1478   COMMAND_REPLY((ARGS, channel, tmp));
1479
1480  out:
1481   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1482   silc_client_command_reply_free(cmd);
1483 }
1484
1485 SILC_CLIENT_CMD_REPLY_FUNC(close)
1486 {
1487   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1488   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1489   SilcCommandStatus status;
1490   unsigned char *tmp;
1491
1492   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1493   SILC_GET16_MSB(status, tmp);
1494   if (status != SILC_STATUS_OK) {
1495     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1496         "%s", silc_client_command_status_message(status));
1497     COMMAND_REPLY_ERROR;
1498     goto out;
1499   }
1500
1501   /* Notify application */
1502   COMMAND_REPLY((ARGS));
1503
1504  out:
1505   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1506   silc_client_command_reply_free(cmd);
1507 }
1508  
1509 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1510 {
1511   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1512   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1513   SilcCommandStatus status;
1514   unsigned char *tmp;
1515
1516   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1517   SILC_GET16_MSB(status, tmp);
1518   if (status != SILC_STATUS_OK) {
1519     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1520         "%s", silc_client_command_status_message(status));
1521     COMMAND_REPLY_ERROR;
1522     goto out;
1523   }
1524
1525   /* Notify application */
1526   COMMAND_REPLY((ARGS));
1527
1528  out:
1529   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1530   silc_client_command_reply_free(cmd);
1531 }
1532  
1533 /* Reply to LEAVE command. */
1534
1535 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1536 {
1537   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1538   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1539   SilcCommandStatus status;
1540   unsigned char *tmp;
1541
1542   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1543   SILC_GET16_MSB(status, tmp);
1544   if (status != SILC_STATUS_OK) {
1545     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1546         "%s", silc_client_command_status_message(status));
1547     COMMAND_REPLY_ERROR;
1548     goto out;
1549   }
1550
1551   /* Notify application */
1552   COMMAND_REPLY((ARGS));
1553
1554  out:
1555   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1556   silc_client_command_reply_free(cmd);
1557 }
1558
1559 /* Channel resolving callback for USERS command reply. */
1560
1561 static void silc_client_command_reply_users_cb(SilcClient client,
1562                                                SilcClientConnection conn,
1563                                                SilcChannelEntry *channels,
1564                                                uint32 channels_count,
1565                                                void *context)
1566 {
1567   if (!channels_count) {
1568     SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1569     SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1570     SilcCommandStatus status = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1571
1572     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1573         "%s", silc_client_command_status_message(status));
1574     COMMAND_REPLY_ERROR;
1575     SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1576     silc_client_command_reply_free(cmd);
1577     return;
1578   }
1579
1580   silc_client_command_reply_users(context, NULL);
1581 }
1582
1583 /* Reply to USERS command. Received list of client ID's and theirs modes
1584    on the channel we requested. */
1585
1586 SILC_CLIENT_CMD_REPLY_FUNC(users)
1587 {
1588   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1589   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1590   SilcCommandStatus status;
1591   SilcChannelEntry channel;
1592   SilcClientEntry client_entry;
1593   SilcChannelUser chu;
1594   SilcChannelID *channel_id = NULL;
1595   SilcBuffer client_id_list = NULL;
1596   SilcBuffer client_mode_list = NULL;
1597   unsigned char *tmp;
1598   uint32 tmp_len, list_count;
1599   int i;
1600   unsigned char **res_argv = NULL;
1601   uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1602
1603   SILC_LOG_DEBUG(("Start"));
1604
1605   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1606   SILC_GET16_MSB(status, tmp);
1607   if (status != SILC_STATUS_OK) {
1608     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1609         "%s", silc_client_command_status_message(status));
1610     COMMAND_REPLY_ERROR;
1611     goto out;
1612   }
1613
1614   /* Get channel ID */
1615   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1616   if (!tmp) {
1617     COMMAND_REPLY_ERROR;
1618     goto out;
1619   }
1620   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1621   if (!channel_id) {
1622     COMMAND_REPLY_ERROR;
1623     goto out;
1624   }
1625   
1626   /* Get the list count */
1627   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1628   if (!tmp) {
1629     COMMAND_REPLY_ERROR;
1630     goto out;
1631   }
1632   SILC_GET32_MSB(list_count, tmp);
1633
1634   /* Get Client ID list */
1635   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1636   if (!tmp) {
1637     COMMAND_REPLY_ERROR;
1638     goto out;
1639   }
1640
1641   client_id_list = silc_buffer_alloc(tmp_len);
1642   silc_buffer_pull_tail(client_id_list, tmp_len);
1643   silc_buffer_put(client_id_list, tmp, tmp_len);
1644
1645   /* Get client mode list */
1646   tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1647   if (!tmp) {
1648     COMMAND_REPLY_ERROR;
1649     goto out;
1650   }
1651
1652   client_mode_list = silc_buffer_alloc(tmp_len);
1653   silc_buffer_pull_tail(client_mode_list, tmp_len);
1654   silc_buffer_put(client_mode_list, tmp, tmp_len);
1655
1656   /* Get channel entry */
1657   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1658   if (!channel) {
1659     /* Resolve the channel from server */
1660     silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1661                                           silc_client_command_reply_users_cb,
1662                                           cmd);
1663     silc_free(channel_id);
1664     if (client_id_list)
1665       silc_buffer_free(client_id_list);
1666     if (client_mode_list)
1667       silc_buffer_free(client_mode_list);
1668     return;
1669   }
1670
1671   /* Cache the received Client ID's and modes. */
1672   for (i = 0; i < list_count; i++) {
1673     uint16 idp_len;
1674     uint32 mode;
1675     SilcClientID *client_id;
1676
1677     /* Client ID */
1678     SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1679     idp_len += 4;
1680     client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1681     if (!client_id)
1682       continue;
1683
1684     /* Mode */
1685     SILC_GET32_MSB(mode, client_mode_list->data);
1686
1687     /* Check if we have this client cached already. */
1688     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1689     if (!client_entry || !client_entry->username || !client_entry->realname) {
1690       if (client_entry) {
1691         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1692           silc_buffer_pull(client_id_list, idp_len);
1693           silc_buffer_pull(client_mode_list, 4);
1694           continue;
1695         }
1696         client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1697       }
1698
1699       /* No we don't have it (or it is incomplete in information), query
1700          it from the server. Assemble argument table that will be sent
1701          for the WHOIS command later. */
1702       res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1703                               (res_argc + 1));
1704       res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1705                                    (res_argc + 1));
1706       res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1707                                     (res_argc + 1));
1708       res_argv[res_argc] = client_id_list->data;
1709       res_argv_lens[res_argc] = idp_len;
1710       res_argv_types[res_argc] = res_argc + 3;
1711       res_argc++;
1712     } else {
1713       if (!silc_client_on_channel(channel, client_entry)) {
1714         chu = silc_calloc(1, sizeof(*chu));
1715         chu->client = client_entry;
1716         chu->channel = channel;
1717         silc_hash_table_add(channel->user_list, client_entry, chu);
1718         silc_hash_table_add(client_entry->channels, channel, chu);
1719       }
1720     }
1721
1722     silc_free(client_id);
1723     silc_buffer_pull(client_id_list, idp_len);
1724     silc_buffer_pull(client_mode_list, 4);
1725   }
1726
1727   /* Query the client information from server if the list included clients
1728      that we don't know about. */
1729   if (res_argc) {
1730     SilcBuffer res_cmd;
1731
1732     /* Send the WHOIS command to server */
1733     silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1734                                  silc_client_command_reply_whois_i, 0,
1735                                  ++conn->cmd_ident);
1736     res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1737                                           res_argc, res_argv, res_argv_lens,
1738                                           res_argv_types, conn->cmd_ident);
1739     silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, 
1740                             NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1741                             TRUE);
1742
1743     /* Register pending command callback. After we've received the WHOIS
1744        command reply we will reprocess this command reply by re-calling this
1745        USERS command reply callback. */
1746     silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1747                                 silc_client_command_reply_users, cmd);
1748
1749     silc_buffer_free(res_cmd);
1750     silc_free(channel_id);
1751     silc_free(res_argv);
1752     silc_free(res_argv_lens);
1753     silc_free(res_argv_types);
1754     if (client_id_list)
1755       silc_buffer_free(client_id_list);
1756     if (client_mode_list)
1757       silc_buffer_free(client_mode_list);
1758     return;
1759   }
1760   
1761   silc_buffer_push(client_id_list, (client_id_list->data - 
1762                                     client_id_list->head));
1763   silc_buffer_push(client_mode_list, (client_mode_list->data - 
1764                                       client_mode_list->head));
1765
1766   /* Notify application */
1767   COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1768
1769  out:
1770   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1771   silc_client_command_reply_free(cmd);
1772   silc_free(channel_id);
1773   if (client_id_list)
1774     silc_buffer_free(client_id_list);
1775   if (client_mode_list)
1776     silc_buffer_free(client_mode_list);
1777 }
1778
1779 /* Received command reply to GETKEY command. WE've received the remote
1780    client's public key. */
1781
1782 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1783 {
1784   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1785   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1786   SilcCommandStatus status;
1787   SilcIDCacheEntry id_cache;
1788   SilcIDPayload idp = NULL;
1789   SilcClientID *client_id = NULL;
1790   SilcClientEntry client_entry;
1791   SilcServerID *server_id = NULL;
1792   SilcServerEntry server_entry;
1793   SilcSKEPKType type;
1794   unsigned char *tmp, *pk;
1795   uint32 len;
1796   uint16 pk_len;
1797   SilcIdType id_type;
1798   SilcPublicKey public_key = NULL;
1799
1800   SILC_LOG_DEBUG(("Start"));
1801
1802   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1803   SILC_GET16_MSB(status, tmp);
1804   if (status != SILC_STATUS_OK) {
1805     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1806         "%s", silc_client_command_status_message(status));
1807     COMMAND_REPLY_ERROR;
1808     goto out;
1809   }
1810
1811   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1812   if (!tmp) {
1813     COMMAND_REPLY_ERROR;
1814     goto out;
1815   }
1816   idp = silc_id_payload_parse(tmp, len);
1817   if (!idp) {
1818     COMMAND_REPLY_ERROR;
1819     goto out;
1820   }
1821
1822   /* Get the public key payload */
1823   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1824   if (tmp) {
1825     /* Decode the public key */
1826     SILC_GET16_MSB(pk_len, tmp);
1827     SILC_GET16_MSB(type, tmp + 2);
1828     pk = tmp + 4;
1829     
1830     if (type == SILC_SKE_PK_TYPE_SILC)
1831       if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1832         public_key = NULL;
1833   } 
1834    
1835   id_type = silc_id_payload_get_type(idp);
1836   if (id_type == SILC_ID_CLIENT) {
1837     /* Received client's public key */
1838     client_id = silc_id_payload_get_id(idp);
1839     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1840     if (!client_entry) {
1841       COMMAND_REPLY_ERROR;
1842       goto out;
1843     }
1844
1845     /* Notify application */
1846     COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1847   } else if (id_type == SILC_ID_SERVER) {
1848     /* Received server's public key */
1849     server_id = silc_id_payload_get_id(idp);
1850     if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1851                                      &id_cache)) {
1852       COMMAND_REPLY_ERROR;
1853       goto out;
1854     }
1855
1856     server_entry = (SilcServerEntry)id_cache->context;
1857
1858     /* Notify application */
1859     COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1860   }
1861
1862  out:
1863   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1864   if (idp)
1865     silc_id_payload_free(idp);
1866   if (public_key)
1867     silc_pkcs_public_key_free(public_key);
1868   silc_free(client_id);
1869   silc_free(server_id);
1870   silc_client_command_reply_free(cmd);
1871 }
1872
1873 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1874 {
1875   silc_client_command_reply_free(context);
1876 }
1877
1878
1879 /******************************************************************************
1880
1881                       Internal command reply functions
1882
1883 ******************************************************************************/
1884
1885 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1886 {
1887   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1888   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1889   SilcCommandStatus status;
1890
1891   SILC_LOG_DEBUG(("Start"));
1892
1893   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1894   if (status != SILC_STATUS_OK &&
1895       status != SILC_STATUS_LIST_START &&
1896       status != SILC_STATUS_LIST_ITEM &&
1897       status != SILC_STATUS_LIST_END)
1898     goto out;
1899
1900   /* Save WHOIS info */
1901   silc_client_command_reply_whois_save(cmd, status, FALSE);
1902
1903   /* Pending callbacks are not executed if this was an list entry */
1904   if (status != SILC_STATUS_OK &&
1905       status != SILC_STATUS_LIST_END) {
1906     silc_client_command_reply_free(cmd);
1907     return;
1908   }
1909
1910  out:
1911   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1912
1913   /* If we received notify for invalid ID we'll remove the ID if we
1914      have it cached. */
1915   if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1916     SilcClientEntry client_entry;
1917     uint32 tmp_len;
1918     unsigned char *tmp =
1919       silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1920                                  2, &tmp_len);
1921     if (tmp) {
1922       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1923       if (client_id) {
1924         client_entry = silc_client_get_client_by_id(cmd->client, conn,
1925                                                     client_id);
1926         if (client_entry)
1927           silc_client_del_client(cmd->client, conn, client_entry);
1928         silc_free(client_id);
1929       }
1930     }
1931   }
1932
1933   /* Unregister this command reply */
1934   silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1935                                  NULL, silc_client_command_reply_whois_i,
1936                                  cmd->ident);
1937
1938   silc_client_command_reply_free(cmd);
1939 }
1940
1941 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1942 {
1943   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1944   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1945   SilcCommandStatus status;
1946
1947   SILC_LOG_DEBUG(("Start"));
1948
1949   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1950   if (status != SILC_STATUS_OK &&
1951       status != SILC_STATUS_LIST_START &&
1952       status != SILC_STATUS_LIST_ITEM &&
1953       status != SILC_STATUS_LIST_END)
1954     goto out;
1955
1956   /* Save IDENTIFY info */
1957   silc_client_command_reply_identify_save(cmd, status, FALSE);
1958
1959   /* Pending callbacks are not executed if this was an list entry */
1960   if (status != SILC_STATUS_OK &&
1961       status != SILC_STATUS_LIST_END) {
1962     silc_client_command_reply_free(cmd);
1963     return;
1964   }
1965
1966  out:
1967   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1968
1969   /* If we received notify for invalid ID we'll remove the ID if we
1970      have it cached. */
1971   if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1972     SilcClientEntry client_entry;
1973     uint32 tmp_len;
1974     unsigned char *tmp =
1975       silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1976                                  2, &tmp_len);
1977     if (tmp) {
1978       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1979       if (client_id) {
1980         client_entry = silc_client_get_client_by_id(cmd->client, conn,
1981                                                     client_id);
1982         if (client_entry)
1983           silc_client_del_client(cmd->client, conn, client_entry);
1984         silc_free(client_id);
1985       }
1986     }
1987   }
1988
1989   /* Unregister this command reply */
1990   silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1991                                  NULL, silc_client_command_reply_identify_i,
1992                                  cmd->ident);
1993
1994   silc_client_command_reply_free(cmd);
1995 }
1996
1997 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1998 {
1999   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2000   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2001   SilcCommandStatus status;
2002   unsigned char *tmp;
2003   SilcIDCacheEntry id_cache;
2004   SilcServerEntry server;
2005   SilcServerID *server_id = NULL;
2006   char *server_name, *server_info;
2007   uint32 len;
2008
2009   SILC_LOG_DEBUG(("Start"));
2010
2011   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2012   SILC_GET16_MSB(status, tmp);
2013   if (status != SILC_STATUS_OK)
2014     goto out;
2015
2016   /* Get server ID */
2017   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2018   if (!tmp)
2019     goto out;
2020
2021   server_id = silc_id_payload_parse_id(tmp, len);
2022   if (!server_id)
2023     goto out;
2024
2025   /* Get server name */
2026   server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2027   if (!server_name)
2028     goto out;
2029
2030   /* Get server info */
2031   server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2032   if (!server_info)
2033     goto out;
2034
2035   /* See whether we have this server cached. If not create it. */
2036   if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2037                                    &id_cache)) {
2038     SILC_LOG_DEBUG(("New server entry"));
2039     server = silc_calloc(1, sizeof(*server));
2040     server->server_name = strdup(server_name);
2041     server->server_info = strdup(server_info);
2042     server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2043
2044     /* Add it to the cache */
2045     silc_idcache_add(conn->server_cache, server->server_name,
2046                      server->server_id, (void *)server, 0, NULL);
2047   }
2048   
2049  out:
2050   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2051   silc_free(server_id);
2052   silc_client_command_reply_free(cmd);
2053 }