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