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