Integer type name change.
[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     chu = silc_calloc(1, sizeof(*chu));
1065     chu->client = client_entry;
1066     chu->channel = channel;
1067     chu->mode = mode;
1068     silc_hash_table_add(channel->user_list, client_entry, chu);
1069     silc_hash_table_add(client_entry->channels, channel, chu);
1070
1071     silc_free(client_id);
1072     silc_buffer_pull(client_id_list, idp_len);
1073     silc_buffer_pull(client_mode_list, 4);
1074   }
1075   silc_buffer_push(client_id_list, client_id_list->data - 
1076                    client_id_list->head);
1077   silc_buffer_push(client_mode_list, client_mode_list->data - 
1078                    client_mode_list->head);
1079
1080   /* Save channel key */
1081   if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1082     silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1083
1084   /* Notify application */
1085   COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, 
1086                  keyp ? keyp->head : NULL, NULL,
1087                  NULL, topic, hmac, list_count, client_id_list, 
1088                  client_mode_list));
1089
1090  out:
1091   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1092   silc_client_command_reply_free(cmd);
1093
1094   if (keyp)
1095     silc_buffer_free(keyp);
1096   if (client_id_list)
1097     silc_buffer_free(client_id_list);
1098   if (client_mode_list)
1099     silc_buffer_free(client_mode_list);
1100 }
1101
1102 /* Received reply for MOTD command */
1103
1104 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1105 {
1106   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1107   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1108   SilcCommandStatus status;
1109   SilcUInt32 argc, i;
1110   unsigned char *tmp;
1111   char *motd = NULL, *cp, line[256];
1112
1113   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1114   SILC_GET16_MSB(status, tmp);
1115   if (status != SILC_STATUS_OK) {
1116     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1117         "%s", silc_client_command_status_message(status));
1118     COMMAND_REPLY_ERROR;
1119     return;
1120   }
1121
1122   argc = silc_argument_get_arg_num(cmd->args);
1123   if (argc > 3) {
1124     COMMAND_REPLY_ERROR;
1125     goto out;
1126   }
1127
1128   if (argc == 3) {
1129     motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1130     if (!motd) {
1131       COMMAND_REPLY_ERROR;
1132       goto out;
1133     }
1134
1135     i = 0;
1136     cp = motd;
1137     while(cp[i] != 0) {
1138       if (cp[i++] == '\n') {
1139         memset(line, 0, sizeof(line));
1140         strncat(line, cp, i - 1);
1141         cp += i;
1142         
1143         if (i == 2)
1144           line[0] = ' ';
1145         
1146         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1147         
1148         if (!strlen(cp))
1149           break;
1150         i = 0;
1151       }
1152     }
1153   }
1154
1155   /* Notify application */
1156   COMMAND_REPLY((ARGS, motd));
1157
1158  out:
1159   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1160   silc_client_command_reply_free(cmd);
1161 }
1162
1163 /* Received reply tot he UMODE command. Save the current user mode */
1164
1165 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1166 {
1167   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1168   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1169   SilcCommandStatus status;
1170   unsigned char *tmp;
1171   SilcUInt32 mode;
1172
1173   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1174   SILC_GET16_MSB(status, tmp);
1175   if (status != SILC_STATUS_OK) {
1176     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1177         "%s", silc_client_command_status_message(status));
1178     COMMAND_REPLY_ERROR;
1179     goto out;
1180   }
1181
1182   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1183   if (!tmp) {
1184     COMMAND_REPLY_ERROR;
1185     goto out;
1186   }
1187
1188   SILC_GET32_MSB(mode, tmp);
1189   conn->local_entry->mode = mode;
1190
1191   /* Notify application */
1192   COMMAND_REPLY((ARGS, mode));
1193
1194  out:
1195   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1196   silc_client_command_reply_free(cmd);
1197 }
1198
1199 /* Received reply for CMODE command. */
1200
1201 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1202 {
1203   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1204   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1205   SilcCommandStatus status;
1206   unsigned char *tmp;
1207   SilcUInt32 mode;
1208   SilcChannelID *channel_id;
1209   SilcChannelEntry channel;
1210   SilcUInt32 len;
1211
1212   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1213   if (status != SILC_STATUS_OK) {
1214     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1215         "%s", silc_client_command_status_message(status));
1216     COMMAND_REPLY_ERROR;
1217     goto out;
1218   }
1219
1220   /* Take Channel ID */
1221   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1222   if (!tmp)
1223     goto out;
1224   channel_id = silc_id_payload_parse_id(tmp, len);
1225   if (!channel_id)
1226     goto out;
1227
1228   /* Get the channel entry */
1229   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1230   if (!channel) {
1231     silc_free(channel_id);
1232     COMMAND_REPLY_ERROR;
1233     goto out;
1234   }
1235   
1236   /* Get channel mode */
1237   tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1238   if (!tmp) {
1239     silc_free(channel_id);
1240     COMMAND_REPLY_ERROR;
1241     goto out;
1242   }
1243
1244   /* Save the mode */
1245   SILC_GET32_MSB(mode, tmp);
1246   channel->mode = mode;
1247
1248   /* Notify application */
1249   COMMAND_REPLY((ARGS, channel, mode));
1250
1251   silc_free(channel_id);
1252
1253  out:
1254   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1255   silc_client_command_reply_free(cmd);
1256 }
1257
1258 /* Received reply for CUMODE command */
1259
1260 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1261 {
1262   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1263   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1264   SilcCommandStatus status;
1265   SilcClientID *client_id;
1266   SilcChannelID *channel_id;
1267   SilcClientEntry client_entry;
1268   SilcChannelEntry channel;
1269   SilcChannelUser chu;
1270   unsigned char *modev, *tmp, *id;
1271   SilcUInt32 len, mode;
1272   
1273   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1274   if (status != SILC_STATUS_OK) {
1275     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1276         "%s", silc_client_command_status_message(status));
1277     COMMAND_REPLY_ERROR;
1278     goto out;
1279   }
1280   
1281   /* Get channel mode */
1282   modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1283   if (!modev) {
1284     COMMAND_REPLY_ERROR;
1285     goto out;
1286   }
1287
1288   /* Take Channel ID */
1289   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1290   if (!tmp)
1291     goto out;
1292   channel_id = silc_id_payload_parse_id(tmp, len);
1293   if (!channel_id)
1294     goto out;
1295
1296   /* Get the channel entry */
1297   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1298   if (!channel) {
1299     silc_free(channel_id);
1300     COMMAND_REPLY_ERROR;
1301     goto out;
1302   }
1303   
1304   /* Get Client ID */
1305   id = silc_argument_get_arg_type(cmd->args, 4, &len);
1306   if (!id) {
1307     silc_free(channel_id);
1308     COMMAND_REPLY_ERROR;
1309     goto out;
1310   }
1311   client_id = silc_id_payload_parse_id(id, len);
1312   if (!client_id) {
1313     silc_free(channel_id);
1314     COMMAND_REPLY_ERROR;
1315     goto out;
1316   }
1317   
1318   /* Get client entry */
1319   client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1320   if (!client_entry) {
1321     silc_free(channel_id);
1322     silc_free(client_id);
1323     COMMAND_REPLY_ERROR;
1324     goto out;
1325   }
1326
1327   /* Save the mode */
1328   SILC_GET32_MSB(mode, modev);
1329   chu = silc_client_on_channel(channel, client_entry);
1330   if (chu)
1331     chu->mode = mode;
1332
1333   /* Notify application */
1334   COMMAND_REPLY((ARGS, mode, channel, client_entry));
1335   silc_free(client_id);
1336   silc_free(channel_id);
1337   
1338  out:
1339   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1340   silc_client_command_reply_free(cmd);
1341 }
1342
1343 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1344 {
1345   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1346   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1347   SilcCommandStatus status;
1348   unsigned char *tmp;
1349
1350   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1351   SILC_GET16_MSB(status, tmp);
1352   if (status != SILC_STATUS_OK) {
1353     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1354         "%s", silc_client_command_status_message(status));
1355     COMMAND_REPLY_ERROR;
1356     goto out;
1357   }
1358
1359   /* Notify application */
1360   COMMAND_REPLY((ARGS));
1361
1362  out:
1363   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1364   silc_client_command_reply_free(cmd);
1365 }
1366
1367 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1368 {
1369   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1370   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1371   SilcCommandStatus status;
1372   unsigned char *tmp;
1373
1374   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1375   SILC_GET16_MSB(status, tmp);
1376   if (status != SILC_STATUS_OK) {
1377     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1378         "%s", silc_client_command_status_message(status));
1379     COMMAND_REPLY_ERROR;
1380     goto out;
1381   }
1382
1383   /* Notify application */
1384   COMMAND_REPLY((ARGS));
1385
1386  out:
1387   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1388   silc_client_command_reply_free(cmd);
1389 }
1390
1391 SILC_CLIENT_CMD_REPLY_FUNC(oper)
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_OPER);
1412   silc_client_command_reply_free(cmd);
1413 }
1414
1415 SILC_CLIENT_CMD_REPLY_FUNC(connect)
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_CONNECT);
1436   silc_client_command_reply_free(cmd);
1437 }
1438
1439 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1440 {
1441   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1442   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1443   SilcCommandStatus status;
1444   SilcChannelEntry channel;
1445   SilcChannelID *channel_id;
1446   unsigned char *tmp;
1447   SilcUInt32 len;
1448
1449   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1450   SILC_GET16_MSB(status, tmp);
1451   if (status != SILC_STATUS_OK) {
1452     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1453         "%s", silc_client_command_status_message(status));
1454     COMMAND_REPLY_ERROR;
1455     goto out;
1456   }
1457
1458   /* Take Channel ID */
1459   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1460   if (!tmp)
1461     goto out;
1462
1463   channel_id = silc_id_payload_parse_id(tmp, len);
1464   if (!channel_id)
1465     goto out;
1466
1467   /* Get the channel entry */
1468   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1469   if (!channel) {
1470     silc_free(channel_id);
1471     COMMAND_REPLY_ERROR;
1472     goto out;
1473   }
1474   
1475   /* Get the ban list */
1476   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1477
1478   /* Notify application */
1479   COMMAND_REPLY((ARGS, channel, tmp));
1480
1481  out:
1482   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1483   silc_client_command_reply_free(cmd);
1484 }
1485
1486 SILC_CLIENT_CMD_REPLY_FUNC(close)
1487 {
1488   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1489   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1490   SilcCommandStatus status;
1491   unsigned char *tmp;
1492
1493   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1494   SILC_GET16_MSB(status, tmp);
1495   if (status != SILC_STATUS_OK) {
1496     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1497         "%s", silc_client_command_status_message(status));
1498     COMMAND_REPLY_ERROR;
1499     goto out;
1500   }
1501
1502   /* Notify application */
1503   COMMAND_REPLY((ARGS));
1504
1505  out:
1506   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1507   silc_client_command_reply_free(cmd);
1508 }
1509  
1510 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1511 {
1512   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1513   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1514   SilcCommandStatus status;
1515   unsigned char *tmp;
1516
1517   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1518   SILC_GET16_MSB(status, tmp);
1519   if (status != SILC_STATUS_OK) {
1520     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1521         "%s", silc_client_command_status_message(status));
1522     COMMAND_REPLY_ERROR;
1523     goto out;
1524   }
1525
1526   /* Notify application */
1527   COMMAND_REPLY((ARGS));
1528
1529  out:
1530   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1531   silc_client_command_reply_free(cmd);
1532 }
1533  
1534 /* Reply to LEAVE command. */
1535
1536 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1537 {
1538   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1539   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1540   SilcCommandStatus status;
1541   unsigned char *tmp;
1542
1543   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1544   SILC_GET16_MSB(status, tmp);
1545   if (status != SILC_STATUS_OK) {
1546     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1547         "%s", silc_client_command_status_message(status));
1548     COMMAND_REPLY_ERROR;
1549     goto out;
1550   }
1551
1552   /* Notify application */
1553   COMMAND_REPLY((ARGS));
1554
1555  out:
1556   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1557   silc_client_command_reply_free(cmd);
1558 }
1559
1560 /* Channel resolving callback for USERS command reply. */
1561
1562 static void silc_client_command_reply_users_cb(SilcClient client,
1563                                                SilcClientConnection conn,
1564                                                SilcChannelEntry *channels,
1565                                                SilcUInt32 channels_count,
1566                                                void *context)
1567 {
1568   if (!channels_count) {
1569     SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1570     SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1571     SilcCommandStatus status = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1572
1573     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1574         "%s", silc_client_command_status_message(status));
1575     COMMAND_REPLY_ERROR;
1576     SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1577     silc_client_command_reply_free(cmd);
1578     return;
1579   }
1580
1581   silc_client_command_reply_users(context, NULL);
1582 }
1583
1584 /* Reply to USERS command. Received list of client ID's and theirs modes
1585    on the channel we requested. */
1586
1587 SILC_CLIENT_CMD_REPLY_FUNC(users)
1588 {
1589   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1590   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1591   SilcCommandStatus status;
1592   SilcChannelEntry channel;
1593   SilcClientEntry client_entry;
1594   SilcChannelUser chu;
1595   SilcChannelID *channel_id = NULL;
1596   SilcBuffer client_id_list = NULL;
1597   SilcBuffer client_mode_list = NULL;
1598   unsigned char *tmp;
1599   SilcUInt32 tmp_len, list_count;
1600   int i;
1601   unsigned char **res_argv = NULL;
1602   SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1603
1604   SILC_LOG_DEBUG(("Start"));
1605
1606   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1607   SILC_GET16_MSB(status, tmp);
1608   if (status != SILC_STATUS_OK) {
1609     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1610         "%s", silc_client_command_status_message(status));
1611     COMMAND_REPLY_ERROR;
1612     goto out;
1613   }
1614
1615   /* Get channel ID */
1616   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1617   if (!tmp) {
1618     COMMAND_REPLY_ERROR;
1619     goto out;
1620   }
1621   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1622   if (!channel_id) {
1623     COMMAND_REPLY_ERROR;
1624     goto out;
1625   }
1626   
1627   /* Get the list count */
1628   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1629   if (!tmp) {
1630     COMMAND_REPLY_ERROR;
1631     goto out;
1632   }
1633   SILC_GET32_MSB(list_count, tmp);
1634
1635   /* Get Client ID list */
1636   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1637   if (!tmp) {
1638     COMMAND_REPLY_ERROR;
1639     goto out;
1640   }
1641
1642   client_id_list = silc_buffer_alloc(tmp_len);
1643   silc_buffer_pull_tail(client_id_list, tmp_len);
1644   silc_buffer_put(client_id_list, tmp, tmp_len);
1645
1646   /* Get client mode list */
1647   tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1648   if (!tmp) {
1649     COMMAND_REPLY_ERROR;
1650     goto out;
1651   }
1652
1653   client_mode_list = silc_buffer_alloc(tmp_len);
1654   silc_buffer_pull_tail(client_mode_list, tmp_len);
1655   silc_buffer_put(client_mode_list, tmp, tmp_len);
1656
1657   /* Get channel entry */
1658   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1659   if (!channel) {
1660     /* Resolve the channel from server */
1661     silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1662                                           silc_client_command_reply_users_cb,
1663                                           cmd);
1664     silc_free(channel_id);
1665     if (client_id_list)
1666       silc_buffer_free(client_id_list);
1667     if (client_mode_list)
1668       silc_buffer_free(client_mode_list);
1669     return;
1670   }
1671
1672   /* Cache the received Client ID's and modes. */
1673   for (i = 0; i < list_count; i++) {
1674     SilcUInt16 idp_len;
1675     SilcUInt32 mode;
1676     SilcClientID *client_id;
1677
1678     /* Client ID */
1679     SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1680     idp_len += 4;
1681     client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1682     if (!client_id)
1683       continue;
1684
1685     /* Mode */
1686     SILC_GET32_MSB(mode, client_mode_list->data);
1687
1688     /* Check if we have this client cached already. */
1689     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1690     if (!client_entry || !client_entry->username || !client_entry->realname) {
1691       if (client_entry) {
1692         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1693           silc_buffer_pull(client_id_list, idp_len);
1694           silc_buffer_pull(client_mode_list, 4);
1695           continue;
1696         }
1697         client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1698       }
1699
1700       /* No we don't have it (or it is incomplete in information), query
1701          it from the server. Assemble argument table that will be sent
1702          for the WHOIS command later. */
1703       res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1704                               (res_argc + 1));
1705       res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1706                                    (res_argc + 1));
1707       res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1708                                     (res_argc + 1));
1709       res_argv[res_argc] = client_id_list->data;
1710       res_argv_lens[res_argc] = idp_len;
1711       res_argv_types[res_argc] = res_argc + 3;
1712       res_argc++;
1713     } else {
1714       if (!silc_client_on_channel(channel, client_entry)) {
1715         chu = silc_calloc(1, sizeof(*chu));
1716         chu->client = client_entry;
1717         chu->channel = channel;
1718         silc_hash_table_add(channel->user_list, client_entry, chu);
1719         silc_hash_table_add(client_entry->channels, channel, chu);
1720       }
1721     }
1722
1723     silc_free(client_id);
1724     silc_buffer_pull(client_id_list, idp_len);
1725     silc_buffer_pull(client_mode_list, 4);
1726   }
1727
1728   /* Query the client information from server if the list included clients
1729      that we don't know about. */
1730   if (res_argc) {
1731     SilcBuffer res_cmd;
1732
1733     /* Send the WHOIS command to server */
1734     silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1735                                  silc_client_command_reply_whois_i, 0,
1736                                  ++conn->cmd_ident);
1737     res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1738                                           res_argc, res_argv, res_argv_lens,
1739                                           res_argv_types, conn->cmd_ident);
1740     silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, 
1741                             NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1742                             TRUE);
1743
1744     /* Register pending command callback. After we've received the WHOIS
1745        command reply we will reprocess this command reply by re-calling this
1746        USERS command reply callback. */
1747     silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1748                                 silc_client_command_reply_users, cmd);
1749
1750     silc_buffer_free(res_cmd);
1751     silc_free(channel_id);
1752     silc_free(res_argv);
1753     silc_free(res_argv_lens);
1754     silc_free(res_argv_types);
1755     if (client_id_list)
1756       silc_buffer_free(client_id_list);
1757     if (client_mode_list)
1758       silc_buffer_free(client_mode_list);
1759     return;
1760   }
1761   
1762   silc_buffer_push(client_id_list, (client_id_list->data - 
1763                                     client_id_list->head));
1764   silc_buffer_push(client_mode_list, (client_mode_list->data - 
1765                                       client_mode_list->head));
1766
1767   /* Notify application */
1768   COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1769
1770  out:
1771   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1772   silc_client_command_reply_free(cmd);
1773   silc_free(channel_id);
1774   if (client_id_list)
1775     silc_buffer_free(client_id_list);
1776   if (client_mode_list)
1777     silc_buffer_free(client_mode_list);
1778 }
1779
1780 /* Received command reply to GETKEY command. WE've received the remote
1781    client's public key. */
1782
1783 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1784 {
1785   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1786   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1787   SilcCommandStatus status;
1788   SilcIDCacheEntry id_cache;
1789   SilcIDPayload idp = NULL;
1790   SilcClientID *client_id = NULL;
1791   SilcClientEntry client_entry;
1792   SilcServerID *server_id = NULL;
1793   SilcServerEntry server_entry;
1794   SilcSKEPKType type;
1795   unsigned char *tmp, *pk;
1796   SilcUInt32 len;
1797   SilcUInt16 pk_len;
1798   SilcIdType id_type;
1799   SilcPublicKey public_key = NULL;
1800
1801   SILC_LOG_DEBUG(("Start"));
1802
1803   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1804   SILC_GET16_MSB(status, tmp);
1805   if (status != SILC_STATUS_OK) {
1806     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1807         "%s", silc_client_command_status_message(status));
1808     COMMAND_REPLY_ERROR;
1809     goto out;
1810   }
1811
1812   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1813   if (!tmp) {
1814     COMMAND_REPLY_ERROR;
1815     goto out;
1816   }
1817   idp = silc_id_payload_parse(tmp, len);
1818   if (!idp) {
1819     COMMAND_REPLY_ERROR;
1820     goto out;
1821   }
1822
1823   /* Get the public key payload */
1824   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1825   if (tmp) {
1826     /* Decode the public key */
1827     SILC_GET16_MSB(pk_len, tmp);
1828     SILC_GET16_MSB(type, tmp + 2);
1829     pk = tmp + 4;
1830     
1831     if (type == SILC_SKE_PK_TYPE_SILC)
1832       if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1833         public_key = NULL;
1834   } 
1835    
1836   id_type = silc_id_payload_get_type(idp);
1837   if (id_type == SILC_ID_CLIENT) {
1838     /* Received client's public key */
1839     client_id = silc_id_payload_get_id(idp);
1840     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1841     if (!client_entry) {
1842       COMMAND_REPLY_ERROR;
1843       goto out;
1844     }
1845
1846     /* Notify application */
1847     COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1848   } else if (id_type == SILC_ID_SERVER) {
1849     /* Received server's public key */
1850     server_id = silc_id_payload_get_id(idp);
1851     if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1852                                      &id_cache)) {
1853       COMMAND_REPLY_ERROR;
1854       goto out;
1855     }
1856
1857     server_entry = (SilcServerEntry)id_cache->context;
1858
1859     /* Notify application */
1860     COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1861   }
1862
1863  out:
1864   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1865   if (idp)
1866     silc_id_payload_free(idp);
1867   if (public_key)
1868     silc_pkcs_public_key_free(public_key);
1869   silc_free(client_id);
1870   silc_free(server_id);
1871   silc_client_command_reply_free(cmd);
1872 }
1873
1874 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1875 {
1876   silc_client_command_reply_free(context);
1877 }
1878
1879
1880 /******************************************************************************
1881
1882                       Internal command reply functions
1883
1884 ******************************************************************************/
1885
1886 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1887 {
1888   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1889   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1890   SilcCommandStatus status;
1891
1892   SILC_LOG_DEBUG(("Start"));
1893
1894   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1895   if (status != SILC_STATUS_OK &&
1896       status != SILC_STATUS_LIST_START &&
1897       status != SILC_STATUS_LIST_ITEM &&
1898       status != SILC_STATUS_LIST_END)
1899     goto out;
1900
1901   /* Save WHOIS info */
1902   silc_client_command_reply_whois_save(cmd, status, FALSE);
1903
1904   /* Pending callbacks are not executed if this was an list entry */
1905   if (status != SILC_STATUS_OK &&
1906       status != SILC_STATUS_LIST_END) {
1907     silc_client_command_reply_free(cmd);
1908     return;
1909   }
1910
1911  out:
1912   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1913
1914   /* If we received notify for invalid ID we'll remove the ID if we
1915      have it cached. */
1916   if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1917     SilcClientEntry client_entry;
1918     SilcUInt32 tmp_len;
1919     unsigned char *tmp =
1920       silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1921                                  2, &tmp_len);
1922     if (tmp) {
1923       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1924       if (client_id) {
1925         client_entry = silc_client_get_client_by_id(cmd->client, conn,
1926                                                     client_id);
1927         if (client_entry)
1928           silc_client_del_client(cmd->client, conn, client_entry);
1929         silc_free(client_id);
1930       }
1931     }
1932   }
1933
1934   /* Unregister this command reply */
1935   silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1936                                  NULL, silc_client_command_reply_whois_i,
1937                                  cmd->ident);
1938
1939   silc_client_command_reply_free(cmd);
1940 }
1941
1942 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1943 {
1944   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1945   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1946   SilcCommandStatus status;
1947
1948   SILC_LOG_DEBUG(("Start"));
1949
1950   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1951   if (status != SILC_STATUS_OK &&
1952       status != SILC_STATUS_LIST_START &&
1953       status != SILC_STATUS_LIST_ITEM &&
1954       status != SILC_STATUS_LIST_END)
1955     goto out;
1956
1957   /* Save IDENTIFY info */
1958   silc_client_command_reply_identify_save(cmd, status, FALSE);
1959
1960   /* Pending callbacks are not executed if this was an list entry */
1961   if (status != SILC_STATUS_OK &&
1962       status != SILC_STATUS_LIST_END) {
1963     silc_client_command_reply_free(cmd);
1964     return;
1965   }
1966
1967  out:
1968   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1969
1970   /* If we received notify for invalid ID we'll remove the ID if we
1971      have it cached. */
1972   if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1973     SilcClientEntry client_entry;
1974     SilcUInt32 tmp_len;
1975     unsigned char *tmp =
1976       silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1977                                  2, &tmp_len);
1978     if (tmp) {
1979       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1980       if (client_id) {
1981         client_entry = silc_client_get_client_by_id(cmd->client, conn,
1982                                                     client_id);
1983         if (client_entry)
1984           silc_client_del_client(cmd->client, conn, client_entry);
1985         silc_free(client_id);
1986       }
1987     }
1988   }
1989
1990   /* Unregister this command reply */
1991   silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1992                                  NULL, silc_client_command_reply_identify_i,
1993                                  cmd->ident);
1994
1995   silc_client_command_reply_free(cmd);
1996 }
1997
1998 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1999 {
2000   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2001   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2002   SilcCommandStatus status;
2003   unsigned char *tmp;
2004   SilcIDCacheEntry id_cache;
2005   SilcServerEntry server;
2006   SilcServerID *server_id = NULL;
2007   char *server_name, *server_info;
2008   SilcUInt32 len;
2009
2010   SILC_LOG_DEBUG(("Start"));
2011
2012   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2013   SILC_GET16_MSB(status, tmp);
2014   if (status != SILC_STATUS_OK)
2015     goto out;
2016
2017   /* Get server ID */
2018   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2019   if (!tmp)
2020     goto out;
2021
2022   server_id = silc_id_payload_parse_id(tmp, len);
2023   if (!server_id)
2024     goto out;
2025
2026   /* Get server name */
2027   server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2028   if (!server_name)
2029     goto out;
2030
2031   /* Get server info */
2032   server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2033   if (!server_info)
2034     goto out;
2035
2036   /* See whether we have this server cached. If not create it. */
2037   if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2038                                    &id_cache)) {
2039     SILC_LOG_DEBUG(("New server entry"));
2040     server = silc_calloc(1, sizeof(*server));
2041     server->server_name = strdup(server_name);
2042     server->server_info = strdup(server_info);
2043     server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2044
2045     /* Add it to the cache */
2046     silc_idcache_add(conn->server_cache, server->server_name,
2047                      server->server_id, (void *)server, 0, NULL);
2048   }
2049   
2050  out:
2051   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2052   silc_free(server_id);
2053   silc_client_command_reply_free(cmd);
2054 }