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