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