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