Fixed the USERS & JOIN command replys, added silc-expandos.c to
[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), 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), 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   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
102   if (status != SILC_STATUS_OK)  {                                        \
103     COMMAND_REPLY_ERROR;                                                  \
104     goto out;                                                             \
105   }                                                                       \
106 } while(0)
107
108 #define COMMAND_CHECK_STATUS_LIST                                         \
109 do {                                                                      \
110   SILC_LOG_DEBUG(("Start"));                                              \
111   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
112   if (status != SILC_STATUS_OK &&                                         \
113       status != SILC_STATUS_LIST_START &&                                 \
114       status != SILC_STATUS_LIST_ITEM &&                                  \
115       status != SILC_STATUS_LIST_END) {                                   \
116     COMMAND_REPLY_ERROR;                                                  \
117     goto out;                                                             \
118   }                                                                       \
119 } while(0)
120
121 /* Process received command reply. */
122
123 void silc_client_command_reply_process(SilcClient client,
124                                        SilcSocketConnection sock,
125                                        SilcPacketContext *packet)
126 {
127   SilcBuffer buffer = packet->buffer;
128   SilcClientCommand cmd;
129   SilcClientCommandReplyContext ctx;
130   SilcCommandPayload payload;
131   SilcCommand command;
132   SilcCommandCb reply = NULL;
133   
134   /* Get command reply payload from packet */
135   payload = silc_command_payload_parse(buffer->data, buffer->len);
136   if (!payload) {
137     /* Silently ignore bad reply packet */
138     SILC_LOG_DEBUG(("Bad command reply packet"));
139     return;
140   }
141   
142   /* Allocate command reply context. This must be free'd by the
143      command reply routine receiving it. */
144   ctx = silc_calloc(1, sizeof(*ctx));
145   ctx->client = client;
146   ctx->sock = sock;
147   ctx->payload = payload;
148   ctx->args = silc_command_get_args(ctx->payload);
149   ctx->packet = packet;
150   ctx->ident = silc_command_get_ident(ctx->payload);
151
152   /* Check for pending commands and mark to be exeucted */
153   silc_client_command_pending_check(sock->user_data, ctx, 
154                                     silc_command_get(ctx->payload), 
155                                     ctx->ident);
156
157   /* Execute command reply */
158
159   command = silc_command_get(ctx->payload);
160
161   /* Try to find matching the command identifier */
162   silc_list_start(client->internal->commands);
163   while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
164     if (cmd->cmd == command && !cmd->ident)
165       reply = cmd->reply;
166     if (cmd->cmd == command && cmd->ident == ctx->ident) {
167       (*cmd->reply)((void *)ctx, NULL);
168       break;
169     }
170   }
171
172   if (cmd == SILC_LIST_END) {
173     if (reply)
174       /* No specific identifier for command reply, call first one found */
175       (*reply)(ctx, NULL);
176     else
177       silc_free(ctx);
178   }
179 }
180
181 /* Returns status message string */
182
183 char *silc_client_command_status_message(SilcCommandStatus status)
184 {
185   int i;
186
187   for (i = 0; silc_command_status_messages[i].message; i++) {
188     if (silc_command_status_messages[i].status == status)
189       break;
190   }
191
192   if (silc_command_status_messages[i].message == NULL)
193     return NULL;
194
195   return silc_command_status_messages[i].message;
196 }
197
198 /* Free command reply context and its internals. */
199
200 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
201 {
202   if (cmd) {
203     silc_command_payload_free(cmd->payload);
204     silc_free(cmd);
205   }
206 }
207
208 static void 
209 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
210                                      SilcCommandStatus status,
211                                      bool notify)
212 {
213   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
214   SilcClientID *client_id;
215   SilcClientEntry client_entry = NULL;
216   int argc;
217   SilcUInt32 len;
218   unsigned char *id_data, *tmp;
219   char *nickname = NULL, *username = NULL;
220   char *realname = NULL;
221   SilcUInt32 idle = 0, mode = 0;
222   SilcBuffer channels = NULL;
223   unsigned char *fingerprint;
224   SilcUInt32 fingerprint_len;
225   
226   argc = silc_argument_get_arg_num(cmd->args);
227
228   id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
229   if (!id_data) {
230     if (notify)
231       COMMAND_REPLY_ERROR;
232     return;
233   }
234   
235   client_id = silc_id_payload_parse_id(id_data, len);
236   if (!client_id) {
237     if (notify)
238       COMMAND_REPLY_ERROR;
239     return;
240   }
241   
242   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
243   username = silc_argument_get_arg_type(cmd->args, 4, &len);
244   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
245   if (!nickname || !username || !realname) {
246     if (notify)
247       COMMAND_REPLY_ERROR;
248     return;
249   }
250
251   tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
252   if (tmp) {
253     channels = silc_buffer_alloc(len);
254     silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
255     silc_buffer_put(channels, tmp, len);
256   }
257
258   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
259   if (tmp)
260     SILC_GET32_MSB(mode, tmp);
261
262   tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
263   if (tmp)
264     SILC_GET32_MSB(idle, tmp);
265
266   fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
267
268   /* Check if we have this client cached already. */
269   client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
270   if (!client_entry) {
271     SILC_LOG_DEBUG(("Adding new client entry"));
272     client_entry = 
273       silc_client_add_client(cmd->client, conn, nickname, username, realname,
274                              client_id, mode);
275   } else {
276     silc_client_update_client(cmd->client, conn, client_entry, 
277                               nickname, username, realname, mode);
278     silc_free(client_id);
279   }
280
281   if (fingerprint && !client_entry->fingerprint) {
282     client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
283     client_entry->fingerprint_len = fingerprint_len;
284   }
285
286   if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
287     client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
288
289   /* Notify application */
290   if (!cmd->callback && notify)
291     COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, 
292                    channels, mode, idle, fingerprint));
293
294   if (channels)
295     silc_buffer_free(channels);
296 }
297
298 /* Received reply for WHOIS command. This maybe called several times
299    for one WHOIS command as server may reply with list of results. */
300
301 SILC_CLIENT_CMD_REPLY_FUNC(whois)
302 {
303   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
304   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
305   SilcCommandStatus status;
306
307   COMMAND_CHECK_STATUS_LIST;
308
309   /* Save WHOIS info */
310   silc_client_command_reply_whois_save(cmd, status, TRUE);
311
312   /* Pending callbacks are not executed if this was an list entry */
313   if (status != SILC_STATUS_OK &&
314       status != SILC_STATUS_LIST_END) {
315     silc_client_command_reply_free(cmd);
316     return;
317   }
318
319  out:
320   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
321
322   /* If we received notify for invalid ID we'll remove the ID if we
323      have it cached. */
324   if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
325     SilcClientEntry client_entry;
326     SilcUInt32 tmp_len;
327     unsigned char *tmp =
328       silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
329                                  2, &tmp_len);
330     if (tmp) {
331       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
332       if (client_id) {
333         client_entry = silc_client_get_client_by_id(cmd->client, conn,
334                                                     client_id);
335         if (client_entry)
336           silc_client_del_client(cmd->client, conn, client_entry);
337         silc_free(client_id);
338       }
339     }
340   }
341
342   silc_client_command_reply_free(cmd);
343 }
344
345 /* Received reply for WHOWAS command. */
346
347 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
348 {
349   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
350   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
351   SilcCommandStatus status;
352   SilcClientID *client_id;
353   SilcClientEntry client_entry = NULL;
354   SilcUInt32 len;
355   unsigned char *id_data;
356   char *nickname, *username;
357   char *realname = NULL;
358
359   COMMAND_CHECK_STATUS_LIST;
360
361   id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
362   if (!id_data) {
363     COMMAND_REPLY_ERROR;
364     goto out;
365   }
366   
367   client_id = silc_id_payload_parse_id(id_data, len);
368   if (!client_id) {
369     COMMAND_REPLY_ERROR;
370     goto out;
371   }
372
373   /* Get the client entry, if exists */
374   client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
375   silc_free(client_id);
376
377   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
378   username = silc_argument_get_arg_type(cmd->args, 4, &len);
379   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
380   if (!nickname || !username) {
381     COMMAND_REPLY_ERROR;
382     goto out;
383   }
384
385   /* Notify application. We don't save any history information to any
386      cache. Just pass the data to the application for displaying on 
387      the screen. */
388   COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
389
390   /* Pending callbacks are not executed if this was an list entry */
391   if (status != SILC_STATUS_OK &&
392       status != SILC_STATUS_LIST_END) {
393     silc_client_command_reply_free(cmd);
394     return;
395   }
396
397  out:
398   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
399   silc_client_command_reply_free(cmd);
400 }
401
402 static void 
403 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
404                                         SilcCommandStatus status,
405                                         bool notify)
406 {
407   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
408   SilcClient client = cmd->client;
409   SilcClientID *client_id = NULL;
410   SilcServerID *server_id = NULL;
411   SilcChannelID *channel_id = NULL;
412   SilcIDCacheEntry id_cache = NULL;
413   SilcClientEntry client_entry;
414   SilcServerEntry server_entry;
415   SilcChannelEntry channel_entry;
416   int argc;
417   SilcUInt32 len;
418   unsigned char *id_data;
419   char *name = NULL, *info = NULL;
420   SilcIDPayload idp = NULL;
421   SilcIdType id_type;
422   
423   argc = silc_argument_get_arg_num(cmd->args);
424
425   id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
426   if (!id_data) {
427     if (notify)
428       COMMAND_REPLY_ERROR;
429     return;
430   }
431   idp = silc_id_payload_parse(id_data, len);
432   if (!idp) {
433     if (notify)
434       COMMAND_REPLY_ERROR;
435     return;
436   }
437
438   name = silc_argument_get_arg_type(cmd->args, 3, &len);
439   info = silc_argument_get_arg_type(cmd->args, 4, &len);
440
441   id_type = silc_id_payload_get_type(idp);
442
443   switch (id_type) {
444   case SILC_ID_CLIENT:
445     client_id = silc_id_payload_get_id(idp);
446
447     SILC_LOG_DEBUG(("Received client information"));
448
449     /* Check if we have this client cached already. */
450     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
451     if (!client_entry) {
452       SILC_LOG_DEBUG(("Adding new client entry"));
453       client_entry = 
454         silc_client_add_client(cmd->client, conn, name, info, NULL,
455                                silc_id_dup(client_id, id_type), 0);
456     } else {
457       silc_client_update_client(cmd->client, conn, client_entry, 
458                                 name, info, NULL, 0);
459     }
460
461     if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
462       client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
463
464     /* Notify application */
465     if (notify)
466       COMMAND_REPLY((ARGS, client_entry, name, info));
467     break;
468
469   case SILC_ID_SERVER:
470     server_id = silc_id_payload_get_id(idp);
471
472     SILC_LOG_DEBUG(("Received server information"));
473
474     /* Check if we have this server cached already. */
475     if (!silc_idcache_find_by_id_one(conn->server_cache, 
476                                      (void *)server_id, &id_cache)) {
477       SILC_LOG_DEBUG(("Adding new server entry"));
478       
479       server_entry = silc_calloc(1, sizeof(*server_entry));
480       server_entry->server_id = silc_id_dup(server_id, id_type);
481       if (name)
482         server_entry->server_name = strdup(name);
483       if (info)
484         server_entry->server_info = strdup(info);
485       
486       /* Add server to cache */
487       silc_idcache_add(conn->server_cache, server_entry->server_name,
488                        server_entry->server_id, (void *)server_entry, 
489                        0, NULL);
490     } else {
491       server_entry = (SilcServerEntry)id_cache->context;
492     }
493
494     /* Notify application */
495     if (notify)
496       COMMAND_REPLY((ARGS, server_entry, name, info));
497     break;
498
499   case SILC_ID_CHANNEL:
500     channel_id = silc_id_payload_get_id(idp);
501
502     SILC_LOG_DEBUG(("Received channel information"));
503
504     /* Check if we have this channel cached already. */
505     channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
506     if (!channel_entry) {
507       if (!name)
508         break;
509
510       /* Add new channel entry */
511       channel_entry = silc_client_add_channel(client, conn, name, 0,
512                                               channel_id);
513       channel_id = NULL;
514     }
515
516     /* Notify application */
517     if (notify)
518       COMMAND_REPLY((ARGS, channel_entry, name, info));
519     break;
520   }
521
522   silc_id_payload_free(idp);
523   silc_free(client_id);
524   silc_free(server_id);
525   silc_free(channel_id);
526 }
527
528 /* Received reply for IDENTIFY command. This maybe called several times
529    for one IDENTIFY command as server may reply with list of results. 
530    This is totally silent and does not print anything on screen. */
531
532 SILC_CLIENT_CMD_REPLY_FUNC(identify)
533 {
534   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
535   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
536   SilcCommandStatus status;
537
538   COMMAND_CHECK_STATUS_LIST;
539
540   /* Save IDENTIFY info */
541   silc_client_command_reply_identify_save(cmd, status, TRUE);
542
543   /* Pending callbacks are not executed if this was an list entry */
544   if (status != SILC_STATUS_OK &&
545       status != SILC_STATUS_LIST_END) {
546     silc_client_command_reply_free(cmd);
547     return;
548   }
549
550  out:
551   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
552
553   /* If we received notify for invalid ID we'll remove the ID if we
554      have it cached. */
555   if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
556     SilcClientEntry client_entry;
557     SilcUInt32 tmp_len;
558     unsigned char *tmp =
559       silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
560                                  2, &tmp_len);
561     if (tmp) {
562       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
563       if (client_id) {
564         client_entry = silc_client_get_client_by_id(cmd->client, conn,
565                                                     client_id);
566         if (client_entry)
567           silc_client_del_client(cmd->client, conn, client_entry);
568         silc_free(client_id);
569       }
570     }
571   }
572
573   silc_client_command_reply_free(cmd);
574 }
575
576 /* Received reply for command NICK. If everything went without errors
577    we just received our new Client ID. */
578
579 SILC_CLIENT_CMD_REPLY_FUNC(nick)
580 {
581   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
582   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
583   SilcCommandStatus status;
584   SilcIDPayload idp;
585   unsigned char *tmp;
586   SilcUInt32 argc, len;
587
588   SILC_LOG_DEBUG(("Start"));
589
590   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
591   if (status != SILC_STATUS_OK) {
592     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
593         "Cannot set nickname: %s", silc_client_command_status_message(status));
594     COMMAND_REPLY_ERROR;
595     goto out;
596   }
597
598   argc = silc_argument_get_arg_num(cmd->args);
599   if (argc < 2 || argc > 2) {
600     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
601         "Cannot set nickname: bad reply to command");
602     COMMAND_REPLY_ERROR;
603     goto out;
604   }
605
606   /* Take received Client ID */
607   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
608   idp = silc_id_payload_parse(tmp, len);
609   if (!idp) {
610     COMMAND_REPLY_ERROR;
611     goto out;
612   }
613   silc_client_receive_new_id(cmd->client, cmd->sock, idp);
614     
615   /* Notify application */
616   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
617   COMMAND_REPLY((ARGS, conn->local_entry));
618   silc_client_command_reply_free(cmd);
619   return;
620
621  out:
622   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
623   silc_client_command_reply_free(cmd);
624 }
625
626 /* Received reply to the LIST command. */
627
628 SILC_CLIENT_CMD_REPLY_FUNC(list)
629 {
630   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
631   SilcCommandStatus status;
632   unsigned char *tmp, *name, *topic;
633   SilcUInt32 usercount = 0;
634
635   COMMAND_CHECK_STATUS_LIST;
636
637   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
638   topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
639   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
640   if (tmp)
641     SILC_GET32_MSB(usercount, tmp);
642
643   /* Notify application */
644   COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
645
646   /* Pending callbacks are not executed if this was an list entry */
647   if (status != SILC_STATUS_OK &&
648       status != SILC_STATUS_LIST_END) {
649     silc_client_command_reply_free(cmd);
650     return;
651   }
652
653  out:
654   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
655   silc_client_command_reply_free(cmd);
656 }
657
658 /* Received reply to topic command. */
659
660 SILC_CLIENT_CMD_REPLY_FUNC(topic)
661 {
662   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
663   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
664   SilcCommandStatus status;
665   SilcChannelEntry channel;
666   SilcChannelID *channel_id = NULL;
667   unsigned char *tmp;
668   char *topic;
669   SilcUInt32 argc, len;
670
671   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
672   if (status != SILC_STATUS_OK) {
673     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
674         "%s", silc_client_command_status_message(status));
675     COMMAND_REPLY_ERROR;
676     goto out;
677   }
678
679   argc = silc_argument_get_arg_num(cmd->args);
680   if (argc < 1 || argc > 3) {
681     COMMAND_REPLY_ERROR;
682     goto out;
683   }
684
685   /* Take Channel ID */
686   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
687   if (!tmp)
688     goto out;
689
690   /* Take topic */
691   topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
692   if (!topic)
693     goto out;
694
695   channel_id = silc_id_payload_parse_id(tmp, len);
696   if (!channel_id)
697     goto out;
698
699   /* Get the channel entry */
700   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
701   if (!channel) {
702     silc_free(channel_id);
703     COMMAND_REPLY_ERROR;
704     goto out;
705   }
706   
707   /* Notify application */
708   COMMAND_REPLY((ARGS, channel, topic));
709
710  out:
711   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
712   silc_client_command_reply_free(cmd);
713 }
714
715 /* Received reply to invite command. */
716
717 SILC_CLIENT_CMD_REPLY_FUNC(invite)
718 {
719   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
720   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
721   SilcCommandStatus status;
722   SilcChannelEntry channel;
723   SilcChannelID *channel_id;
724   unsigned char *tmp;
725   SilcUInt32 len;
726
727   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
728   SILC_GET16_MSB(status, tmp);
729   if (status != SILC_STATUS_OK) {
730     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
731         "%s", silc_client_command_status_message(status));
732     COMMAND_REPLY_ERROR;
733     goto out;
734   }
735
736   /* Take Channel ID */
737   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
738   if (!tmp)
739     goto out;
740
741   channel_id = silc_id_payload_parse_id(tmp, len);
742   if (!channel_id)
743     goto out;
744
745   /* Get the channel entry */
746   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
747   if (!channel) {
748     silc_free(channel_id);
749     COMMAND_REPLY_ERROR;
750     goto out;
751   }
752
753   /* Get the invite list */
754   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
755
756   /* Notify application */
757   COMMAND_REPLY((ARGS, channel, tmp));
758
759  out:
760   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
761   silc_client_command_reply_free(cmd);
762 }
763
764 /* Received reply to the KILL command. */
765  
766 SILC_CLIENT_CMD_REPLY_FUNC(kill)
767 {
768   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
769   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
770   SilcCommandStatus status;
771
772   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
773   if (status != SILC_STATUS_OK) {
774     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
775         "%s", silc_client_command_status_message(status));
776     COMMAND_REPLY_ERROR;
777     goto out;
778   }
779
780   /* Notify application */
781   COMMAND_REPLY((ARGS));
782
783  out:
784   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
785   silc_client_command_reply_free(cmd);
786 }
787
788 /* Received reply to INFO command. We receive the server ID and some
789    information about the server user requested. */
790
791 SILC_CLIENT_CMD_REPLY_FUNC(info)
792 {
793   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
794   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
795   SilcCommandStatus status;
796   unsigned char *tmp;
797   SilcIDCacheEntry id_cache;
798   SilcServerEntry server;
799   SilcServerID *server_id = NULL;
800   char *server_name, *server_info;
801   SilcUInt32 len;
802
803   SILC_LOG_DEBUG(("Start"));
804
805   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
806   SILC_GET16_MSB(status, tmp);
807   if (status != SILC_STATUS_OK) {
808     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", 
809         silc_client_command_status_message(status));
810     COMMAND_REPLY_ERROR;
811     goto out;
812   }
813
814   /* Get server ID */
815   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
816   if (!tmp)
817     goto out;
818
819   server_id = silc_id_payload_parse_id(tmp, len);
820   if (!server_id)
821     goto out;
822
823   /* Get server name */
824   server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
825   if (!server_name)
826     goto out;
827
828   /* Get server info */
829   server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
830   if (!server_info)
831     goto out;
832
833   /* See whether we have this server cached. If not create it. */
834   if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
835                                    &id_cache)) {
836     SILC_LOG_DEBUG(("New server entry"));
837
838     server = silc_calloc(1, sizeof(*server));
839     server->server_name = strdup(server_name);
840     server->server_info = strdup(server_info);
841     server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
842
843     /* Add it to the cache */
844     silc_idcache_add(conn->server_cache, server->server_name,
845                      server->server_id, (void *)server, 0, NULL);
846   } else {
847     server = (SilcServerEntry)id_cache->context;
848   }
849   
850   /* Notify application */
851   COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
852
853  out:
854   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
855   silc_free(server_id);
856   silc_client_command_reply_free(cmd);
857 }
858
859 /* Received reply to PING command. The reply time is shown to user. */
860
861 SILC_CLIENT_CMD_REPLY_FUNC(ping)
862 {
863   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
864   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
865   SilcCommandStatus status;
866   void *id;
867   int i;
868   time_t diff, curtime;
869
870   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
871   if (status != SILC_STATUS_OK) {
872     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
873         "%s", silc_client_command_status_message(status));
874     COMMAND_REPLY_ERROR;
875     goto out;
876   }
877
878   curtime = time(NULL);
879   id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
880                       cmd->packet->src_id_type);
881   if (!id || !conn->ping) {
882     COMMAND_REPLY_ERROR;
883     goto out;
884   }
885
886   for (i = 0; i < conn->ping_count; i++) {
887     if (!conn->ping[i].dest_id)
888       continue;
889     if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
890       diff = curtime - conn->ping[i].start_time;
891       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
892           "Ping reply from %s: %d second%s", 
893           conn->ping[i].dest_name, diff, 
894           diff == 1 ? "" : "s");
895       
896       conn->ping[i].start_time = 0;
897       silc_free(conn->ping[i].dest_id);
898       conn->ping[i].dest_id = NULL;
899       silc_free(conn->ping[i].dest_name);
900       conn->ping[i].dest_name = NULL;
901       break;
902     }
903   }
904
905   silc_free(id);
906
907   /* Notify application */
908   COMMAND_REPLY((ARGS));
909
910  out:
911   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
912   silc_client_command_reply_free(cmd);
913 }
914
915 /* Received reply for JOIN command. */
916
917 SILC_CLIENT_CMD_REPLY_FUNC(join)
918 {
919   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
920   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
921   SilcCommandStatus status;
922   SilcChannelEntry channel;
923   SilcChannelUser chu;
924   SilcChannelID *channel_id;
925   SilcUInt32 argc, mode = 0, len, list_count;
926   char *topic, *tmp, *channel_name = NULL, *hmac;
927   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
928   int i;
929
930   SILC_LOG_DEBUG(("Start"));
931
932   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
933   if (status != SILC_STATUS_OK) {
934     if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
935       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
936           "%s", silc_client_command_status_message(status));
937     COMMAND_REPLY_ERROR;
938     goto out;
939   }
940
941   argc = silc_argument_get_arg_num(cmd->args);
942   if (argc < 7 || argc > 14) {
943     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
944         "Cannot join channel: Bad reply packet");
945     COMMAND_REPLY_ERROR;
946     goto out;
947   }
948
949   /* Get channel name */
950   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
951   if (!tmp) {
952     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
953         "Cannot join channel: Bad reply packet");
954     COMMAND_REPLY_ERROR;
955     goto out;
956   }
957   channel_name = tmp;
958
959   /* Get Channel ID */
960   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
961   if (!tmp) {
962     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
963         "Cannot join channel: Bad reply packet");
964     COMMAND_REPLY_ERROR;
965     goto out;
966   }
967   channel_id = silc_id_payload_parse_id(tmp, len);
968   if (!channel_id) {
969     COMMAND_REPLY_ERROR;
970     goto out;
971   }
972
973   /* Get channel mode */
974   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
975   if (tmp)
976     SILC_GET32_MSB(mode, tmp);
977
978   /* Get channel key */
979   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
980   if (tmp) {
981     keyp = silc_buffer_alloc(len);
982     silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
983     silc_buffer_put(keyp, tmp, len);
984   }
985
986   /* Get topic */
987   topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
988
989   /* Check whether we have this channel entry already. */
990   channel = silc_client_get_channel(cmd->client, conn, channel_name);
991   if (channel) {
992     if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
993       silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
994   } else {
995     /* Create new channel entry */
996     channel = silc_client_add_channel(cmd->client, conn, channel_name, 
997                                       mode, channel_id);
998   }
999
1000   conn->current_channel = channel;
1001
1002   /* Get hmac */
1003   hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1004   if (hmac) {
1005     if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1006       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, 
1007           "Cannot join channel: Unsupported HMAC `%s'", hmac);
1008       COMMAND_REPLY_ERROR;
1009       goto out;
1010     }
1011   }
1012
1013   /* Get the list count */
1014   tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1015   if (!tmp)
1016     goto out;
1017   SILC_GET32_MSB(list_count, tmp);
1018
1019   /* Get Client ID list */
1020   tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1021   if (!tmp)
1022     goto out;
1023
1024   client_id_list = silc_buffer_alloc(len);
1025   silc_buffer_pull_tail(client_id_list, len);
1026   silc_buffer_put(client_id_list, tmp, len);
1027
1028   /* Get client mode list */
1029   tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1030   if (!tmp)
1031     goto out;
1032
1033   client_mode_list = silc_buffer_alloc(len);
1034   silc_buffer_pull_tail(client_mode_list, len);
1035   silc_buffer_put(client_mode_list, tmp, len);
1036
1037   /* Add clients we received in the reply to the channel */
1038   for (i = 0; i < list_count; i++) {
1039     SilcUInt16 idp_len;
1040     SilcUInt32 mode;
1041     SilcClientID *client_id;
1042     SilcClientEntry client_entry;
1043
1044     /* Client ID */
1045     SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1046     idp_len += 4;
1047     client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1048     if (!client_id)
1049       continue;
1050
1051     /* Mode */
1052     SILC_GET32_MSB(mode, client_mode_list->data);
1053
1054     /* Check if we have this client cached already. */
1055     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1056     if (!client_entry) {
1057       /* No, we don't have it, add entry for it. */
1058       client_entry = 
1059         silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1060                                silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1061     }
1062
1063     /* Join client to the channel */
1064     if (!silc_client_on_channel(channel, client_entry)) {
1065       chu = silc_calloc(1, sizeof(*chu));
1066       chu->client = client_entry;
1067       chu->channel = channel;
1068       chu->mode = mode;
1069       silc_hash_table_add(channel->user_list, client_entry, chu);
1070       silc_hash_table_add(client_entry->channels, channel, chu);
1071     }
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   SilcUInt32 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   SilcUInt32 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   SilcUInt32 mode;
1210   SilcChannelID *channel_id;
1211   SilcChannelEntry channel;
1212   SilcUInt32 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   SilcUInt32 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   SilcUInt32 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                                                SilcUInt32 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   SilcUInt32 tmp_len, list_count;
1602   int i;
1603   unsigned char **res_argv = NULL;
1604   SilcUInt32 *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     SilcUInt16 idp_len;
1677     SilcUInt32 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->mode = mode;
1720         chu->channel = channel;
1721         silc_hash_table_add(channel->user_list, client_entry, chu);
1722         silc_hash_table_add(client_entry->channels, channel, chu);
1723       }
1724     }
1725
1726     silc_free(client_id);
1727     silc_buffer_pull(client_id_list, idp_len);
1728     silc_buffer_pull(client_mode_list, 4);
1729   }
1730
1731   /* Query the client information from server if the list included clients
1732      that we don't know about. */
1733   if (res_argc) {
1734     SilcBuffer res_cmd;
1735
1736     /* Send the WHOIS command to server */
1737     silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1738                                  silc_client_command_reply_whois_i, 0,
1739                                  ++conn->cmd_ident);
1740     res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1741                                           res_argc, res_argv, res_argv_lens,
1742                                           res_argv_types, conn->cmd_ident);
1743     silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, 
1744                             NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1745                             TRUE);
1746
1747     /* Register pending command callback. After we've received the WHOIS
1748        command reply we will reprocess this command reply by re-calling this
1749        USERS command reply callback. */
1750     silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1751                                 silc_client_command_reply_users, cmd);
1752
1753     silc_buffer_free(res_cmd);
1754     silc_free(channel_id);
1755     silc_free(res_argv);
1756     silc_free(res_argv_lens);
1757     silc_free(res_argv_types);
1758     if (client_id_list)
1759       silc_buffer_free(client_id_list);
1760     if (client_mode_list)
1761       silc_buffer_free(client_mode_list);
1762     return;
1763   }
1764   
1765   silc_buffer_push(client_id_list, (client_id_list->data - 
1766                                     client_id_list->head));
1767   silc_buffer_push(client_mode_list, (client_mode_list->data - 
1768                                       client_mode_list->head));
1769
1770   /* Notify application */
1771   COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1772
1773  out:
1774   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1775   silc_client_command_reply_free(cmd);
1776   silc_free(channel_id);
1777   if (client_id_list)
1778     silc_buffer_free(client_id_list);
1779   if (client_mode_list)
1780     silc_buffer_free(client_mode_list);
1781 }
1782
1783 /* Received command reply to GETKEY command. WE've received the remote
1784    client's public key. */
1785
1786 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1787 {
1788   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1789   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1790   SilcCommandStatus status;
1791   SilcIDCacheEntry id_cache;
1792   SilcIDPayload idp = NULL;
1793   SilcClientID *client_id = NULL;
1794   SilcClientEntry client_entry;
1795   SilcServerID *server_id = NULL;
1796   SilcServerEntry server_entry;
1797   SilcSKEPKType type;
1798   unsigned char *tmp, *pk;
1799   SilcUInt32 len;
1800   SilcUInt16 pk_len;
1801   SilcIdType id_type;
1802   SilcPublicKey public_key = NULL;
1803
1804   SILC_LOG_DEBUG(("Start"));
1805
1806   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1807   SILC_GET16_MSB(status, tmp);
1808   if (status != SILC_STATUS_OK) {
1809     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1810         "%s", silc_client_command_status_message(status));
1811     COMMAND_REPLY_ERROR;
1812     goto out;
1813   }
1814
1815   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1816   if (!tmp) {
1817     COMMAND_REPLY_ERROR;
1818     goto out;
1819   }
1820   idp = silc_id_payload_parse(tmp, len);
1821   if (!idp) {
1822     COMMAND_REPLY_ERROR;
1823     goto out;
1824   }
1825
1826   /* Get the public key payload */
1827   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1828   if (tmp) {
1829     /* Decode the public key */
1830     SILC_GET16_MSB(pk_len, tmp);
1831     SILC_GET16_MSB(type, tmp + 2);
1832     pk = tmp + 4;
1833     
1834     if (type == SILC_SKE_PK_TYPE_SILC)
1835       if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1836         public_key = NULL;
1837   } 
1838    
1839   id_type = silc_id_payload_get_type(idp);
1840   if (id_type == SILC_ID_CLIENT) {
1841     /* Received client's public key */
1842     client_id = silc_id_payload_get_id(idp);
1843     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1844     if (!client_entry) {
1845       COMMAND_REPLY_ERROR;
1846       goto out;
1847     }
1848
1849     /* Notify application */
1850     COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1851   } else if (id_type == SILC_ID_SERVER) {
1852     /* Received server's public key */
1853     server_id = silc_id_payload_get_id(idp);
1854     if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1855                                      &id_cache)) {
1856       COMMAND_REPLY_ERROR;
1857       goto out;
1858     }
1859
1860     server_entry = (SilcServerEntry)id_cache->context;
1861
1862     /* Notify application */
1863     COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1864   }
1865
1866  out:
1867   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1868   if (idp)
1869     silc_id_payload_free(idp);
1870   if (public_key)
1871     silc_pkcs_public_key_free(public_key);
1872   silc_free(client_id);
1873   silc_free(server_id);
1874   silc_client_command_reply_free(cmd);
1875 }
1876
1877 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1878 {
1879   silc_client_command_reply_free(context);
1880 }
1881
1882
1883 /******************************************************************************
1884
1885                       Internal command reply functions
1886
1887 ******************************************************************************/
1888
1889 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1890 {
1891   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1892   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1893   SilcCommandStatus status;
1894
1895   SILC_LOG_DEBUG(("Start"));
1896
1897   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1898   if (status != SILC_STATUS_OK &&
1899       status != SILC_STATUS_LIST_START &&
1900       status != SILC_STATUS_LIST_ITEM &&
1901       status != SILC_STATUS_LIST_END)
1902     goto out;
1903
1904   /* Save WHOIS info */
1905   silc_client_command_reply_whois_save(cmd, status, FALSE);
1906
1907   /* Pending callbacks are not executed if this was an list entry */
1908   if (status != SILC_STATUS_OK &&
1909       status != SILC_STATUS_LIST_END) {
1910     silc_client_command_reply_free(cmd);
1911     return;
1912   }
1913
1914  out:
1915   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1916
1917   /* If we received notify for invalid ID we'll remove the ID if we
1918      have it cached. */
1919   if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1920     SilcClientEntry client_entry;
1921     SilcUInt32 tmp_len;
1922     unsigned char *tmp =
1923       silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1924                                  2, &tmp_len);
1925     if (tmp) {
1926       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1927       if (client_id) {
1928         client_entry = silc_client_get_client_by_id(cmd->client, conn,
1929                                                     client_id);
1930         if (client_entry)
1931           silc_client_del_client(cmd->client, conn, client_entry);
1932         silc_free(client_id);
1933       }
1934     }
1935   }
1936
1937   /* Unregister this command reply */
1938   silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1939                                  NULL, silc_client_command_reply_whois_i,
1940                                  cmd->ident);
1941
1942   silc_client_command_reply_free(cmd);
1943 }
1944
1945 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1946 {
1947   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1948   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1949   SilcCommandStatus status;
1950
1951   SILC_LOG_DEBUG(("Start"));
1952
1953   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1954   if (status != SILC_STATUS_OK &&
1955       status != SILC_STATUS_LIST_START &&
1956       status != SILC_STATUS_LIST_ITEM &&
1957       status != SILC_STATUS_LIST_END)
1958     goto out;
1959
1960   /* Save IDENTIFY info */
1961   silc_client_command_reply_identify_save(cmd, status, FALSE);
1962
1963   /* Pending callbacks are not executed if this was an list entry */
1964   if (status != SILC_STATUS_OK &&
1965       status != SILC_STATUS_LIST_END) {
1966     silc_client_command_reply_free(cmd);
1967     return;
1968   }
1969
1970  out:
1971   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1972
1973   /* If we received notify for invalid ID we'll remove the ID if we
1974      have it cached. */
1975   if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1976     SilcClientEntry client_entry;
1977     SilcUInt32 tmp_len;
1978     unsigned char *tmp =
1979       silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1980                                  2, &tmp_len);
1981     if (tmp) {
1982       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1983       if (client_id) {
1984         client_entry = silc_client_get_client_by_id(cmd->client, conn,
1985                                                     client_id);
1986         if (client_entry)
1987           silc_client_del_client(cmd->client, conn, client_entry);
1988         silc_free(client_id);
1989       }
1990     }
1991   }
1992
1993   /* Unregister this command reply */
1994   silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1995                                  NULL, silc_client_command_reply_identify_i,
1996                                  cmd->ident);
1997
1998   silc_client_command_reply_free(cmd);
1999 }
2000
2001 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2002 {
2003   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2004   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2005   SilcCommandStatus status;
2006   unsigned char *tmp;
2007   SilcIDCacheEntry id_cache;
2008   SilcServerEntry server;
2009   SilcServerID *server_id = NULL;
2010   char *server_name, *server_info;
2011   SilcUInt32 len;
2012
2013   SILC_LOG_DEBUG(("Start"));
2014
2015   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2016   SILC_GET16_MSB(status, tmp);
2017   if (status != SILC_STATUS_OK)
2018     goto out;
2019
2020   /* Get server ID */
2021   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2022   if (!tmp)
2023     goto out;
2024
2025   server_id = silc_id_payload_parse_id(tmp, len);
2026   if (!server_id)
2027     goto out;
2028
2029   /* Get server name */
2030   server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2031   if (!server_name)
2032     goto out;
2033
2034   /* Get server info */
2035   server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2036   if (!server_info)
2037     goto out;
2038
2039   /* See whether we have this server cached. If not create it. */
2040   if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2041                                    &id_cache)) {
2042     SILC_LOG_DEBUG(("New server entry"));
2043     server = silc_calloc(1, sizeof(*server));
2044     server->server_name = strdup(server_name);
2045     server->server_info = strdup(server_info);
2046     server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2047
2048     /* Add it to the cache */
2049     silc_idcache_add(conn->server_cache, server->server_name,
2050                      server->server_id, (void *)server, 0, NULL);
2051   }
2052   
2053  out:
2054   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2055   silc_free(server_id);
2056   silc_client_command_reply_free(cmd);
2057 }