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