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