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