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