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