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