Delete and add correct public keys and client entrys to pk_hash.
[silc.git] / apps / silcd / command_reply.c
1 /*
2
3   command_reply.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2004 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 #include "serverincludes.h"
22 #include "server_internal.h"
23 #include "command_reply.h"
24
25 /* All functions that call the COMMAND_CHECK_STATUS macros must have
26    out: and err: goto labels. */
27
28 #define COMMAND_CHECK_STATUS                                            \
29 do {                                                                    \
30   SILC_LOG_DEBUG(("Start"));                                            \
31   if (!silc_command_get_status(cmd->payload, &status, &error)) {        \
32     if (SILC_STATUS_IS_ERROR(status))                                   \
33       goto out;                                                         \
34     if (status == SILC_STATUS_LIST_END)                                 \
35       goto out;                                                         \
36     goto err;                                                           \
37   }                                                                     \
38 } while(0)
39
40 /* Server command reply list. Not all commands have reply function as
41    they are never sent by server. More maybe added later if need appears. */
42 SilcServerCommandReply silc_command_reply_list[] =
43 {
44   SILC_SERVER_CMD_REPLY(whois, WHOIS),
45   SILC_SERVER_CMD_REPLY(whowas, WHOWAS),
46   SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
47   SILC_SERVER_CMD_REPLY(info, INFO),
48   SILC_SERVER_CMD_REPLY(motd, MOTD),
49   SILC_SERVER_CMD_REPLY(join, JOIN),
50   SILC_SERVER_CMD_REPLY(stats, STATS),
51   SILC_SERVER_CMD_REPLY(users, USERS),
52   SILC_SERVER_CMD_REPLY(getkey, GETKEY),
53   SILC_SERVER_CMD_REPLY(list, LIST),
54   SILC_SERVER_CMD_REPLY(watch, WATCH),
55   SILC_SERVER_CMD_REPLY(ping, PING),
56
57   { NULL, 0 },
58 };
59
60 /* Process received command reply. */
61
62 void silc_server_command_reply_process(SilcServer server,
63                                        SilcSocketConnection sock,
64                                        SilcBuffer buffer)
65 {
66   SilcServerCommandReply *cmd;
67   SilcServerCommandReplyContext ctx;
68   SilcCommandPayload payload;
69   SilcCommand command;
70
71   SILC_LOG_DEBUG(("Start"));
72
73   /* Get command reply payload from packet */
74   payload = silc_command_payload_parse(buffer->data, buffer->len);
75   if (!payload) {
76     /* Silently ignore bad reply packet */
77     SILC_LOG_DEBUG(("Bad command reply packet"));
78     return;
79   }
80
81   /* Allocate command reply context. This must be free'd by the
82      command reply routine receiving it. */
83   ctx = silc_calloc(1, sizeof(*ctx));
84   ctx->server = server;
85   ctx->sock = silc_socket_dup(sock);
86   ctx->payload = payload;
87   ctx->args = silc_command_get_args(ctx->payload);
88   ctx->ident = silc_command_get_ident(ctx->payload);
89   command = silc_command_get(ctx->payload);
90
91   /* Client is not allowed to send reply to all commands */
92   if (sock->type == SILC_SOCKET_TYPE_CLIENT &&
93       command != SILC_COMMAND_WHOIS) {
94     silc_server_command_reply_free(ctx);
95     return;
96   }
97
98   /* Check for pending commands and mark to be exeucted */
99   ctx->callbacks =
100     silc_server_command_pending_check(server, command,
101                                       ctx->ident, &ctx->callbacks_count);
102
103   /* Execute command reply */
104   for (cmd = silc_command_reply_list; cmd->cb; cmd++)
105     if (cmd->cmd == command)
106       break;
107
108   if (cmd == NULL || !cmd->cb) {
109     silc_server_command_reply_free(ctx);
110     return;
111   }
112
113   cmd->cb(ctx, NULL);
114 }
115
116 /* Free command reply context and its internals. */
117
118 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
119 {
120   if (cmd) {
121     silc_command_payload_free(cmd->payload);
122     if (cmd->sock)
123       silc_socket_free(cmd->sock); /* Decrease the reference counter */
124     silc_free(cmd->callbacks);
125     silc_free(cmd);
126   }
127 }
128
129 static void
130 silc_server_command_process_error(SilcServerCommandReplyContext cmd,
131                                   SilcStatus error)
132 {
133   SilcServer server = cmd->server;
134
135   /* If we received notify for invalid ID we'll remove the ID if we
136      have it cached. */
137   if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
138       cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
139     SilcClientEntry client;
140     SilcUInt32 tmp_len;
141     unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
142     if (tmp) {
143       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
144       if (client_id) {
145         SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
146                         "the entry from cache"));
147         client = silc_idlist_find_client_by_id(server->global_list,
148                                                client_id, FALSE, NULL);
149         if (client) {
150
151           if (client->data.public_key)
152             silc_hash_table_del_by_context(server->pk_hash,
153                                            client->data.public_key,
154                                            client);
155
156           silc_server_remove_from_channels(server, NULL, client, TRUE,
157                                            NULL, TRUE, FALSE);
158           silc_idlist_del_data(client);
159           silc_idlist_del_client(server->global_list, client);
160         }
161         silc_free(client_id);
162       }
163     }
164   }
165 }
166
167 /* Caches the received WHOIS information. */
168
169 static char
170 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
171 {
172   SilcServer server = cmd->server;
173   unsigned char *tmp, *id_data, *umodes;
174   char *nickname, *username, *realname, *servername = NULL;
175   unsigned char *fingerprint;
176   SilcClientID *client_id;
177   SilcClientEntry client;
178   SilcIDCacheEntry cache = NULL;
179   char global = FALSE;
180   char *nick;
181   SilcUInt32 mode = 0, len, len2, id_len, flen;
182
183   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
184   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
185   username = silc_argument_get_arg_type(cmd->args, 4, &len);
186   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
187   if (!id_data || !nickname || !username || !realname)
188     return FALSE;
189
190   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
191   if (tmp)
192     SILC_GET32_MSB(mode, tmp);
193
194   client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
195   if (!client_id)
196     return FALSE;
197
198   fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
199
200   /* Check if we have this client cached already. */
201
202   client = silc_idlist_find_client_by_id(server->local_list, client_id,
203                                          FALSE, NULL);
204   if (!client) {
205     client = silc_idlist_find_client_by_id(server->global_list, client_id,
206                                            FALSE, NULL);
207     global = TRUE;
208   }
209
210   if (!client) {
211     /* If router did not find such Client ID in its lists then this must
212        be bogus client or some router in the net is buggy. */
213     if (server->server_type != SILC_SERVER)
214       return FALSE;
215
216     /* Take hostname out of nick string if it includes it. */
217     silc_parse_userfqdn(nickname, &nick, &servername);
218
219     /* We don't have that client anywhere, add it. The client is added
220        to global list since server didn't have it in the lists so it must be
221        global. */
222     client = silc_idlist_add_client(server->global_list, nick,
223                                     strdup(username),
224                                     strdup(realname), client_id,
225                                     cmd->sock->user_data, NULL, 0);
226     if (!client) {
227       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
228       return FALSE;
229     }
230
231     client->data.status |=
232       (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
233     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
234     client->mode = mode;
235     client->servername = servername;
236   } else {
237     /* We have the client already, update the data */
238
239     SILC_LOG_DEBUG(("Updating client data"));
240
241     /* Take hostname out of nick string if it includes it. */
242     silc_parse_userfqdn(nickname, &nick, &servername);
243
244     /* Remove the old cache entry  */
245     silc_idcache_del_by_context(global ? server->global_list->clients :
246                                 server->local_list->clients, client);
247
248     silc_free(client->nickname);
249     silc_free(client->username);
250     silc_free(client->userinfo);
251     silc_free(client->servername);
252
253     client->nickname = nick;
254     client->username = strdup(username);
255     client->userinfo = strdup(realname);
256     client->servername = servername;
257     client->mode = mode;
258     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
259     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
260
261     /* Create new cache entry */
262     silc_idcache_add(global ? server->global_list->clients :
263                      server->local_list->clients, nick, client->id,
264                      client, 0, NULL);
265     silc_free(client_id);
266   }
267
268   /* Save channel list if it was sent to us */
269   if (server->server_type == SILC_SERVER) {
270     tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
271     umodes = silc_argument_get_arg_type(cmd->args, 10, &len2);
272     if (tmp && umodes) {
273       SilcBufferStruct channels_buf, umodes_buf;
274       silc_buffer_set(&channels_buf, tmp, len);
275       silc_buffer_set(&umodes_buf, umodes, len2);
276       silc_server_save_user_channels(server, cmd->sock, client, &channels_buf,
277                                      &umodes_buf);
278     } else {
279       silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
280     }
281
282     /* If client is global and is not on any channel then add that we'll
283        expire the entry after a while. */
284     if (global) {
285       silc_idlist_find_client_by_id(server->global_list, client->id,
286                                     FALSE, &cache);
287       if (!silc_hash_table_count(client->channels))
288         cache->expire = time(NULL) + 300;
289       else
290         cache->expire = 0;
291     }
292   }
293
294   if (fingerprint && flen == sizeof(client->data.fingerprint))
295     memcpy(client->data.fingerprint, fingerprint, flen);
296
297   /* Take Requested Attributes if set. */
298   tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
299   if (tmp) {
300     silc_free(client->attrs);
301     client->attrs = silc_memdup(tmp, len);
302     client->attrs_len = len;
303
304     /* Try to take public key from attributes if present and we don't have
305        the key already.  Do this only on normal server.  Routers do GETKEY
306        for all clients anyway. */
307     if (server->server_type != SILC_ROUTER && !client->data.public_key) {
308       SilcAttributePayload attr;
309       SilcAttributeObjPk pk;
310       unsigned char f[20];
311       SilcDList attrs = silc_attribute_payload_parse(tmp, len);
312
313       SILC_LOG_DEBUG(("Take client public key from attributes"));
314
315       if (attrs) {
316         silc_dlist_start(attrs);
317         while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
318           if (silc_attribute_get_attribute(attr) ==
319               SILC_ATTRIBUTE_USER_PUBLIC_KEY) {
320
321             if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
322               continue;
323
324             /* Take only SILC public keys */
325             if (strcmp(pk.type, "silc-rsa")) {
326               silc_free(pk.type);
327               silc_free(pk.data);
328               continue;
329             }
330
331             /* Verify that the server provided fingerprint matches the key */
332             silc_hash_make(server->sha1hash, pk.data, pk.data_len, f);
333             if (memcmp(f, client->data.fingerprint, sizeof(f))) {
334               silc_free(pk.type);
335               silc_free(pk.data);
336               continue;
337             }
338
339             /* Save the public key. */
340             if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
341                                              &client->data.public_key)) {
342               silc_free(pk.type);
343               silc_free(pk.data);
344               continue;
345             }
346
347             SILC_LOG_DEBUG(("Saved client public key from attributes"));
348
349             /* Add to public key hash table */
350             if (!silc_hash_table_find_by_context(server->pk_hash,
351                                                  client->data.public_key,
352                                                  client, NULL))
353               silc_hash_table_add(server->pk_hash,
354                                   client->data.public_key, client);
355
356             silc_free(pk.type);
357             silc_free(pk.data);
358             break;
359           }
360         }
361
362         silc_attribute_payload_list_free(attrs);
363       }
364     }
365   }
366
367   return TRUE;
368 }
369
370 /* Handle requested attributes reply in WHOIS from client */
371
372 static char
373 silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd)
374 {
375   unsigned char *tmp;
376   SilcUInt32 len;
377   SilcClientEntry client = cmd->sock->user_data;
378
379   /* Take Requested Attributes if set. */
380   tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
381   if (tmp && client) {
382     silc_free(client->attrs);
383     client->attrs = silc_memdup(tmp, len);
384     client->attrs_len = len;
385   }
386
387   client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
388
389   return TRUE;
390 }
391
392 /* Reiceved reply for WHOIS command. We sent the whois request to our
393    primary router, if we are normal server, and thus has now received reply
394    to the command. We will figure out what client originally sent us the
395    command and will send the reply to it.  If we are router we will figure
396    out who server sent us the command and send reply to that one. */
397
398 SILC_SERVER_CMD_REPLY_FUNC(whois)
399 {
400   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
401   SilcStatus status, error;
402
403   COMMAND_CHECK_STATUS;
404
405   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) {
406     if (!silc_server_command_reply_whois_save(cmd))
407       goto out;
408   } else {
409     if (!silc_server_command_reply_whois_save_client(cmd))
410       goto out;
411   }
412
413   /* Pending callbacks are not executed if this was an list entry */
414   if (status != SILC_STATUS_OK &&
415       status != SILC_STATUS_LIST_END) {
416     silc_server_command_reply_free(cmd);
417     return;
418   }
419
420  out:
421   silc_server_command_process_error(cmd, error);
422   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
423   silc_server_command_reply_free(cmd);
424   return;
425
426  err:
427   silc_server_command_process_error(cmd, error);
428   silc_server_command_reply_free(cmd);
429 }
430
431 /* Caches the received WHOWAS information for a short period of time. */
432
433 static char
434 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
435 {
436   SilcServer server = cmd->server;
437   SilcUInt32 len, id_len;
438   unsigned char *id_data;
439   char *nickname, *username, *realname, *servername = NULL;
440   SilcClientID *client_id;
441   SilcClientEntry client;
442   SilcIDCacheEntry cache = NULL;
443   char *nick;
444   int global = FALSE;
445
446   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
447   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
448   username = silc_argument_get_arg_type(cmd->args, 4, &len);
449   if (!id_data || !nickname || !username)
450     return FALSE;
451
452   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
453
454   client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
455   if (!client_id)
456     return FALSE;
457
458   /* Check if we have this client cached already. */
459
460   client = silc_idlist_find_client_by_id(server->local_list, client_id,
461                                          FALSE, &cache);
462   if (!client) {
463     client = silc_idlist_find_client_by_id(server->global_list,
464                                            client_id, FALSE, &cache);
465     global = TRUE;
466   }
467
468   if (!client) {
469     /* If router did not find such Client ID in its lists then this must
470        be bogus client or some router in the net is buggy. */
471     if (server->server_type != SILC_SERVER)
472       return FALSE;
473
474     /* Take hostname out of nick string if it includes it. */
475     silc_parse_userfqdn(nickname, &nick, &servername);
476
477     /* We don't have that client anywhere, add it. The client is added
478        to global list since server didn't have it in the lists so it must be
479        global. */
480     client = silc_idlist_add_client(server->global_list, nick,
481                                     strdup(username), strdup(realname),
482                                     silc_id_dup(client_id, SILC_ID_CLIENT),
483                                     cmd->sock->user_data, NULL,
484                                     SILC_ID_CACHE_EXPIRE_DEF);
485     if (!client) {
486       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
487       return FALSE;
488     }
489
490     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
491     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
492     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
493     client->servername = servername;
494   } else {
495     /* We have the client already, update the data */
496
497     /* Take hostname out of nick string if it includes it. */
498     silc_parse_userfqdn(nickname, &nick, &servername);
499
500     silc_free(client->nickname);
501     silc_free(client->username);
502     silc_free(client->servername);
503
504     client->nickname = nick;
505     client->username = strdup(username);
506     client->servername = servername;
507     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
508     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
509
510     /* Remove the old cache entry and create a new one */
511     silc_idcache_del_by_context(global ? server->global_list->clients :
512                                 server->local_list->clients, client);
513     silc_idcache_add(global ? server->global_list->clients :
514                      server->local_list->clients, nick, client->id,
515                      client, 0, NULL);
516   }
517
518   /* If client is global and is not on any channel then add that we'll
519      expire the entry after a while. */
520   if (global) {
521     silc_idlist_find_client_by_id(server->global_list, client->id,
522                                   FALSE, &cache);
523     if (!silc_hash_table_count(client->channels))
524       cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
525     else
526       cache->expire = 0;
527   }
528
529   silc_free(client_id);
530
531   return TRUE;
532 }
533
534 /* Received reply for WHOWAS command. Cache the client information only for
535    a short period of time. */
536
537 SILC_SERVER_CMD_REPLY_FUNC(whowas)
538 {
539   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
540   SilcStatus status, error;
541
542   COMMAND_CHECK_STATUS;
543
544   if (!silc_server_command_reply_whowas_save(cmd))
545     goto out;
546
547   /* Pending callbacks are not executed if this was an list entry */
548   if (status != SILC_STATUS_OK &&
549       status != SILC_STATUS_LIST_END) {
550     silc_server_command_reply_free(cmd);
551     return;
552   }
553
554  out:
555   silc_server_command_process_error(cmd, error);
556   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
557   silc_server_command_reply_free(cmd);
558   return;
559
560  err:
561   silc_server_command_process_error(cmd, error);
562   silc_server_command_reply_free(cmd);
563 }
564
565 /* Caches the received IDENTIFY information. */
566
567 static char
568 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
569 {
570   SilcServer server = cmd->server;
571   SilcUInt32 len, id_len;
572   unsigned char *id_data;
573   char *name, *info;
574   SilcClientID *client_id = NULL;
575   SilcServerID *server_id = NULL;
576   SilcChannelID *channel_id = NULL;
577   SilcClientEntry client;
578   SilcServerEntry server_entry;
579   SilcChannelEntry channel;
580   char global = FALSE;
581   char *nick = NULL;
582   SilcIDPayload idp = NULL;
583   SilcIdType id_type;
584   int expire = 0;
585
586   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
587   if (!id_data)
588     return FALSE;
589   idp = silc_id_payload_parse(id_data, id_len);
590   if (!idp)
591     return FALSE;
592
593   name = silc_argument_get_arg_type(cmd->args, 3, &len);
594   info = silc_argument_get_arg_type(cmd->args, 4, &len);
595
596   id_type = silc_id_payload_get_type(idp);
597
598   switch (id_type) {
599   case SILC_ID_CLIENT:
600     client_id = silc_id_payload_get_id(idp);
601     if (!client_id)
602       goto error;
603
604     SILC_LOG_DEBUG(("Received client information"));
605
606     client = silc_idlist_find_client_by_id(server->local_list,
607                                            client_id, FALSE, NULL);
608     if (!client) {
609       client = silc_idlist_find_client_by_id(server->global_list, client_id,
610                                              FALSE, NULL);
611       global = TRUE;
612     }
613     if (!client) {
614       /* If router did not find such Client ID in its lists then this must
615          be bogus client or some router in the net is buggy. */
616       if (server->server_type != SILC_SERVER)
617         goto error;
618
619       /* Take nickname */
620       if (name)
621         silc_parse_userfqdn(name, &nick, NULL);
622
623       /* We don't have that client anywhere, add it. The client is added
624          to global list since server didn't have it in the lists so it must be
625          global. */
626       client = silc_idlist_add_client(server->global_list, nick,
627                                       info ? strdup(info) : NULL, NULL,
628                                       client_id, cmd->sock->user_data,
629                                       NULL, time(NULL) + 300);
630       if (!client) {
631         SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
632         goto error;
633       }
634       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
635       client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
636       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
637     } else {
638       /* We have the client already, update the data */
639
640       SILC_LOG_DEBUG(("Updating client data"));
641
642       /* Take nickname */
643       if (name) {
644         silc_parse_userfqdn(name, &nick, NULL);
645
646         /* Remove the old cache entry */
647         silc_idcache_del_by_context(global ? server->global_list->clients :
648                                     server->local_list->clients, client);
649
650         silc_free(client->nickname);
651         client->nickname = nick;
652       }
653
654       if (info) {
655         silc_free(client->username);
656         client->username = strdup(info);
657       }
658
659       client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
660       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
661
662       if (name) {
663         /* Add new cache entry */
664         silc_idcache_add(global ? server->global_list->clients :
665                          server->local_list->clients, nick, client->id,
666                          client, expire, NULL);
667       }
668
669       /* If client is global and is not on any channel then add that we'll
670          expire the entry after a while. */
671       if (global && server->server_type == SILC_SERVER) {
672         SilcIDCacheEntry cache = NULL;
673         silc_idlist_find_client_by_id(server->global_list, client->id,
674                                       FALSE, &cache);
675         if (!silc_hash_table_count(client->channels))
676           cache->expire = time(NULL) + 300;
677         else
678           cache->expire = 0;
679       }
680
681       silc_free(client_id);
682     }
683
684     break;
685
686   case SILC_ID_SERVER:
687     if (!name)
688       goto error;
689
690     server_id = silc_id_payload_get_id(idp);
691     if (!server_id)
692       goto error;
693
694     SILC_LOG_DEBUG(("Received server information"));
695
696     server_entry = silc_idlist_find_server_by_id(server->local_list,
697                                                  server_id, FALSE, NULL);
698     if (!server_entry)
699       server_entry = silc_idlist_find_server_by_id(server->global_list,
700                                                    server_id, FALSE, NULL);
701     if (!server_entry) {
702       /* If router did not find such Server ID in its lists then this must
703          be bogus server or some router in the net is buggy. */
704       if (server->server_type != SILC_SERVER)
705         goto error;
706
707       /* We don't have that server anywhere, add it. */
708       server_entry = silc_idlist_add_server(server->global_list,
709                                             strdup(name), 0,
710                                             server_id, server->router,
711                                             SILC_PRIMARY_ROUTE(server));
712       if (!server_entry) {
713         silc_free(server_id);
714         goto error;
715       }
716       server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
717       server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
718       server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
719       server_id = NULL;
720     }
721
722     silc_free(server_id);
723     break;
724
725   case SILC_ID_CHANNEL:
726     if (!name)
727       goto error;
728
729     channel_id = silc_id_payload_get_id(idp);
730     if (!channel_id)
731       goto error;
732
733     SILC_LOG_DEBUG(("Received channel information"));
734
735     channel = silc_idlist_find_channel_by_name(server->local_list,
736                                                name, NULL);
737     if (!channel)
738       channel = silc_idlist_find_channel_by_name(server->global_list,
739                                                  name, NULL);
740     if (!channel) {
741       /* If router did not find such Channel ID in its lists then this must
742          be bogus channel or some router in the net is buggy. */
743       if (server->server_type != SILC_SERVER)
744         goto error;
745
746       /* We don't have that channel anywhere, add it. */
747       channel = silc_idlist_add_channel(server->global_list, strdup(name),
748                                         SILC_CHANNEL_MODE_NONE, channel_id,
749                                         server->router, NULL, NULL, 0);
750       if (!channel) {
751         silc_free(channel_id);
752         goto error;
753       }
754       channel_id = NULL;
755     }
756
757     silc_free(channel_id);
758     break;
759   }
760
761   silc_id_payload_free(idp);
762   return TRUE;
763
764  error:
765   silc_id_payload_free(idp);
766   return FALSE;
767 }
768
769 /* Received reply for forwarded IDENTIFY command. We have received the
770    requested identify information now and we will cache it. After this we
771    will call the pending command so that the requestee gets the information
772    after all. */
773
774 SILC_SERVER_CMD_REPLY_FUNC(identify)
775 {
776   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
777   SilcStatus status, error;
778
779   COMMAND_CHECK_STATUS;
780
781   if (!silc_server_command_reply_identify_save(cmd))
782     goto out;
783
784   /* Pending callbacks are not executed if this was an list entry */
785   if (status != SILC_STATUS_OK &&
786       status != SILC_STATUS_LIST_END) {
787     silc_server_command_reply_free(cmd);
788     return;
789   }
790
791  out:
792   silc_server_command_process_error(cmd, error);
793   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
794   silc_server_command_reply_free(cmd);
795   return;
796
797  err:
798   silc_server_command_process_error(cmd, error);
799   silc_server_command_reply_free(cmd);
800 }
801
802 /* Received reply fro INFO command. Cache the server and its information */
803
804 SILC_SERVER_CMD_REPLY_FUNC(info)
805 {
806   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
807   SilcServer server = cmd->server;
808   SilcStatus status, error;
809   SilcServerEntry entry;
810   SilcServerID *server_id;
811   SilcUInt32 tmp_len;
812   unsigned char *tmp, *name;
813
814   COMMAND_CHECK_STATUS;
815
816   /* Get Server ID */
817   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
818   if (!tmp)
819     goto out;
820   server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
821   if (!server_id)
822     goto out;
823
824   /* Get the name */
825   name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
826   if (tmp_len > 256)
827     goto out;
828
829   entry = silc_idlist_find_server_by_id(server->local_list, server_id,
830                                         FALSE, NULL);
831   if (!entry) {
832     entry = silc_idlist_find_server_by_id(server->global_list, server_id,
833                                           FALSE, NULL);
834     if (!entry) {
835       /* Add the server to global list */
836       server_id = silc_id_dup(server_id, SILC_ID_SERVER);
837       entry = silc_idlist_add_server(server->global_list, name, 0,
838                                      server_id, cmd->sock->user_data,
839                                      cmd->sock);
840       if (!entry) {
841         silc_free(server_id);
842         goto out;
843       }
844       entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
845     }
846   }
847
848   /* Get the info string */
849   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
850   if (tmp_len > 256)
851     tmp = NULL;
852
853   entry->server_info = tmp ? strdup(tmp) : NULL;
854
855  out:
856   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
857  err:
858   silc_server_command_reply_free(cmd);
859 }
860
861 /* Received reply fro MOTD command. */
862
863 SILC_SERVER_CMD_REPLY_FUNC(motd)
864 {
865   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
866   SilcServer server = cmd->server;
867   SilcStatus status, error;
868   SilcServerEntry entry = NULL;
869   SilcServerID *server_id;
870   SilcUInt32 tmp_len;
871   unsigned char *tmp;
872
873   COMMAND_CHECK_STATUS;
874
875   /* Get Server ID */
876   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
877   if (!tmp)
878     goto out;
879   server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
880   if (!server_id)
881     goto out;
882
883   entry = silc_idlist_find_server_by_id(server->local_list, server_id,
884                                         TRUE, NULL);
885   if (!entry) {
886     entry = silc_idlist_find_server_by_id(server->global_list, server_id,
887                                           TRUE, NULL);
888     if (!entry) {
889       SilcBuffer buffer;
890
891       /* If router did not find such Server ID in its lists then this must
892          be bogus client or some router in the net is buggy. */
893       if (server->server_type != SILC_SERVER)
894         goto out;
895
896       /* entry isn't known so we IDENTIFY it. otherwise the
897          silc_server_command_motd won't know about it and tell
898          the client that there is no such server */
899       buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
900                                               ++server->cmd_ident, 5,
901                                               1, NULL, 0, 2, NULL, 0,
902                                               3, NULL, 0, 4, NULL, 0,
903                                               5, tmp, tmp_len);
904       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
905                               SILC_PACKET_COMMAND, 0, buffer->data,
906                               buffer->len, TRUE);
907       silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
908                                   server->cmd_ident,
909                                   silc_server_command_reply_motd,
910                                   cmd);
911       silc_buffer_free(buffer);
912       return;
913     }
914   }
915
916   /* Get the motd */
917   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
918   if (tmp_len > 256)
919     tmp = NULL;
920
921   entry->motd = tmp;
922
923  out:
924   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
925  err:
926   silc_server_command_reply_free(cmd);
927
928   if (entry)
929     entry->motd = NULL;
930 }
931
932 /* Received reply for forwarded JOIN command. Router has created or joined
933    the client to the channel. We save some channel information locally
934    for future use. */
935
936 SILC_SERVER_CMD_REPLY_FUNC(join)
937 {
938   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
939   SilcServer server = cmd->server;
940   SilcIDCacheEntry cache = NULL;
941   SilcStatus status, error;
942   SilcChannelID *id;
943   SilcClientID *client_id = NULL;
944   SilcChannelEntry entry;
945   SilcHmac hmac = NULL;
946   SilcUInt32 id_len, len, list_count;
947   unsigned char *id_string;
948   char *channel_name, *tmp;
949   SilcUInt32 mode, created;
950   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
951   SilcPublicKey founder_key = NULL;
952
953   COMMAND_CHECK_STATUS;
954
955   /* Get channel name */
956   channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
957   if (!channel_name)
958     goto out;
959
960   /* Get channel ID */
961   id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
962   if (!id_string)
963     goto out;
964
965   /* Get client ID */
966   tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
967   if (!tmp)
968     goto out;
969   client_id = silc_id_payload_parse_id(tmp, len, NULL);
970   if (!client_id)
971     goto out;
972
973   /* Get mode mask */
974   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
975   if (!tmp)
976     goto out;
977   SILC_GET32_MSB(mode, tmp);
978
979   /* Get created boolean value */
980   tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
981   if (!tmp)
982     goto out;
983   SILC_GET32_MSB(created, tmp);
984   if (created != 0 && created != 1)
985     goto out;
986
987   /* Get channel key */
988   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
989   if (tmp) {
990     keyp = silc_buffer_alloc(len);
991     silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
992     silc_buffer_put(keyp, tmp, len);
993   }
994
995   /* Parse the Channel ID */
996   id = silc_id_payload_parse_id(id_string, id_len, NULL);
997   if (!id)
998     goto out;
999
1000   /* Get hmac */
1001   tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
1002   if (tmp) {
1003     if (!silc_hmac_alloc(tmp, NULL, &hmac))
1004       goto out;
1005   }
1006
1007   /* Get the list count */
1008   tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1009   if (!tmp)
1010     goto out;
1011   SILC_GET32_MSB(list_count, tmp);
1012
1013   /* Get Client ID list */
1014   tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1015   if (!tmp)
1016     goto out;
1017
1018   client_id_list = silc_buffer_alloc(len);
1019   silc_buffer_pull_tail(client_id_list, len);
1020   silc_buffer_put(client_id_list, tmp, len);
1021
1022   /* Get client mode list */
1023   tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1024   if (!tmp)
1025     goto out;
1026
1027   client_mode_list = silc_buffer_alloc(len);
1028   silc_buffer_pull_tail(client_mode_list, len);
1029   silc_buffer_put(client_mode_list, tmp, len);
1030
1031   /* Get founder key */
1032   tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
1033   if (tmp)
1034     silc_pkcs_public_key_payload_decode(tmp, len, &founder_key);
1035
1036   /* See whether we already have the channel. */
1037   entry = silc_idlist_find_channel_by_name(server->local_list,
1038                                            channel_name, &cache);
1039   if (!entry) {
1040     /* Add new channel */
1041
1042     SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
1043                     (created == 0 ? "existing" : "created"), channel_name,
1044                     silc_id_render(id, SILC_ID_CHANNEL)));
1045
1046     /* If the channel is found from global list we must move it to the
1047        local list. */
1048     entry = silc_idlist_find_channel_by_name(server->global_list,
1049                                              channel_name, &cache);
1050     if (entry)
1051       silc_idlist_del_channel(server->global_list, entry);
1052
1053     /* Add the channel to our local list. */
1054     entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
1055                                     SILC_CHANNEL_MODE_NONE, id,
1056                                     server->router, NULL, hmac, 0);
1057     if (!entry) {
1058       silc_free(id);
1059       goto out;
1060     }
1061     hmac = NULL;
1062     server->stat.my_channels++;
1063     server->stat.channels++;
1064   } else {
1065     /* The entry exists. */
1066
1067     /* If ID has changed, then update it to the cache too. */
1068     if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
1069       silc_idlist_replace_channel_id(server->local_list, entry->id, id);
1070
1071     entry->disabled = FALSE;
1072
1073     /* Remove the founder auth data if the mode is not set but we have
1074        them in the entry */
1075     if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
1076       silc_pkcs_public_key_free(entry->founder_key);
1077       entry->founder_key = NULL;
1078     }
1079   }
1080
1081   if (founder_key) {
1082     if (entry->founder_key)
1083       silc_pkcs_public_key_free(entry->founder_key);
1084     entry->founder_key = founder_key;
1085     founder_key = NULL;
1086   }
1087
1088   if (entry->hmac_name && (hmac || (!hmac && entry->hmac))) {
1089     silc_free(entry->hmac_name);
1090     entry->hmac_name = strdup(silc_hmac_get_name(hmac ? hmac : entry->hmac));
1091   }
1092
1093   /* Get the ban list */
1094   tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
1095   if (tmp && len > 2) {
1096     SilcArgumentPayload iargs;
1097     SilcUInt16 iargc;
1098     SILC_GET16_MSB(iargc, tmp);
1099     iargs = silc_argument_payload_parse(tmp + 2, len - 2, iargc);
1100     if (iargs) {
1101       /* Delete old ban list */
1102       if (entry->ban_list)
1103         silc_hash_table_free(entry->ban_list);
1104       entry->ban_list =
1105         silc_hash_table_alloc(0, silc_hash_ptr,
1106                               NULL, NULL, NULL,
1107                               silc_server_inviteban_destruct, entry, TRUE);
1108
1109       /* Add new ban list */
1110       silc_server_inviteban_process(server, entry->ban_list, 0, iargs);
1111       silc_argument_payload_free(iargs);
1112     }
1113   }
1114
1115   /* Get the invite list */
1116   tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
1117   if (tmp && len > 2) {
1118     SilcArgumentPayload iargs;
1119     SilcUInt16 iargc;
1120     SILC_GET16_MSB(iargc, tmp);
1121     iargs = silc_argument_payload_parse(tmp + 2, len - 2, iargc);
1122     if (iargs) {
1123       /* Delete old invite list */
1124       if (entry->invite_list)
1125         silc_hash_table_free(entry->invite_list);
1126       entry->invite_list =
1127         silc_hash_table_alloc(0, silc_hash_ptr,
1128                               NULL, NULL, NULL,
1129                               silc_server_inviteban_destruct, entry, TRUE);
1130
1131       /* Add new invite list */
1132       silc_server_inviteban_process(server, entry->invite_list, 0, iargs);
1133       silc_argument_payload_free(iargs);
1134     }
1135   }
1136
1137   /* Get the topic */
1138   tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
1139   if (tmp) {
1140     silc_free(entry->topic);
1141     entry->topic = strdup(tmp);
1142   }
1143
1144   /* Get channel public key list */
1145   tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1146   if (tmp && server->server_type == SILC_SERVER)
1147     silc_server_set_channel_pk_list(server, NULL, entry, tmp, len);
1148
1149   /* If channel was not created we know there is global users on the
1150      channel. */
1151   entry->global_users = (created == 0 ? TRUE : FALSE);
1152
1153   /* If channel was just created the mask must be zero */
1154   if (!entry->global_users && mode) {
1155     SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
1156                     "new channel, forcing it to zero", cmd->sock->hostname));
1157     mode = 0;
1158   }
1159
1160   /* Save channel mode */
1161   entry->mode = mode;
1162
1163   /* Save channel key */
1164   if (keyp) {
1165     if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
1166       silc_server_save_channel_key(server, keyp, entry);
1167     silc_buffer_free(keyp);
1168   }
1169
1170   /* Save the users to the channel */
1171   silc_server_save_users_on_channel(server, cmd->sock, entry,
1172                                     client_id, client_id_list,
1173                                     client_mode_list, list_count);
1174   entry->users_resolved = TRUE;
1175
1176  out:
1177   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1178  err:
1179   if (hmac)
1180     silc_hmac_free(hmac);
1181   silc_free(client_id);
1182   silc_server_command_reply_free(cmd);
1183
1184   silc_pkcs_public_key_free(founder_key);
1185   if (client_id_list)
1186     silc_buffer_free(client_id_list);
1187   if (client_mode_list)
1188     silc_buffer_free(client_mode_list);
1189 }
1190
1191 /* Received reply to STATS command.  */
1192
1193 SILC_SERVER_CMD_REPLY_FUNC(stats)
1194 {
1195   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1196   SilcServer server = cmd->server;
1197   SilcStatus status, error;
1198   unsigned char *tmp;
1199   SilcUInt32 tmp_len;
1200   SilcBufferStruct buf;
1201
1202   COMMAND_CHECK_STATUS;
1203
1204   /* Get statistics structure */
1205   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1206   if (server->server_type != SILC_ROUTER && tmp) {
1207     silc_buffer_set(&buf, tmp, tmp_len);
1208     silc_buffer_unformat(&buf,
1209                          SILC_STR_UI_INT(NULL),
1210                          SILC_STR_UI_INT(NULL),
1211                          SILC_STR_UI_INT(NULL),
1212                          SILC_STR_UI_INT(NULL),
1213                          SILC_STR_UI_INT(NULL),
1214                          SILC_STR_UI_INT(NULL),
1215                          SILC_STR_UI_INT(&server->stat.cell_clients),
1216                          SILC_STR_UI_INT(&server->stat.cell_channels),
1217                          SILC_STR_UI_INT(&server->stat.cell_servers),
1218                          SILC_STR_UI_INT(&server->stat.clients),
1219                          SILC_STR_UI_INT(&server->stat.channels),
1220                          SILC_STR_UI_INT(&server->stat.servers),
1221                          SILC_STR_UI_INT(&server->stat.routers),
1222                          SILC_STR_UI_INT(&server->stat.server_ops),
1223                          SILC_STR_UI_INT(&server->stat.router_ops),
1224                          SILC_STR_END);
1225   }
1226
1227  out:
1228   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
1229  err:
1230   silc_server_command_reply_free(cmd);
1231 }
1232
1233 SILC_SERVER_CMD_REPLY_FUNC(users)
1234 {
1235   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1236   SilcServer server = cmd->server;
1237   SilcStatus status, error;
1238   SilcChannelEntry channel;
1239   SilcChannelID *channel_id = NULL;
1240   SilcBuffer client_id_list;
1241   SilcBuffer client_mode_list;
1242   unsigned char *tmp;
1243   SilcUInt32 tmp_len;
1244   SilcUInt32 list_count;
1245
1246   COMMAND_CHECK_STATUS;
1247
1248   /* Get channel ID */
1249   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1250   if (!tmp)
1251     goto out;
1252   channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1253   if (!channel_id)
1254     goto out;
1255
1256   /* Get channel entry */
1257   channel = silc_idlist_find_channel_by_id(server->local_list,
1258                                            channel_id, NULL);
1259   if (!channel) {
1260     channel = silc_idlist_find_channel_by_id(server->global_list,
1261                                              channel_id, NULL);
1262     if (!channel) {
1263       SilcBuffer idp;
1264
1265       if (server->server_type != SILC_SERVER)
1266         goto out;
1267
1268       idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1269       silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
1270                                SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1271                                1, 5, idp->data, idp->len);
1272       silc_buffer_free(idp);
1273
1274       /* Register pending command callback. After we've received the channel
1275          information we will reprocess this command reply by re-calling this
1276          USERS command reply callback. */
1277       silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1278                                   server->cmd_ident,
1279                                   silc_server_command_reply_users, cmd);
1280       return;
1281     }
1282   }
1283
1284   /* Get the list count */
1285   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1286   if (!tmp)
1287     goto out;
1288   SILC_GET32_MSB(list_count, tmp);
1289
1290   /* Get Client ID list */
1291   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1292   if (!tmp)
1293     goto out;
1294
1295   client_id_list = silc_buffer_alloc(tmp_len);
1296   silc_buffer_pull_tail(client_id_list, tmp_len);
1297   silc_buffer_put(client_id_list, tmp, tmp_len);
1298
1299   /* Get client mode list */
1300   tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1301   if (!tmp)
1302     goto out;
1303
1304   client_mode_list = silc_buffer_alloc(tmp_len);
1305   silc_buffer_pull_tail(client_mode_list, tmp_len);
1306   silc_buffer_put(client_mode_list, tmp, tmp_len);
1307
1308   /* Save the users to the channel */
1309   silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1310                                     client_id_list, client_mode_list,
1311                                     list_count);
1312
1313   channel->global_users = silc_server_channel_has_global(channel);
1314   channel->users_resolved = TRUE;
1315
1316   silc_buffer_free(client_id_list);
1317   silc_buffer_free(client_mode_list);
1318
1319  out:
1320   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1321   silc_free(channel_id);
1322  err:
1323   silc_server_command_reply_free(cmd);
1324 }
1325
1326 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1327 {
1328   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1329   SilcServer server = cmd->server;
1330   SilcStatus status, error;
1331   SilcClientEntry client = NULL;
1332   SilcServerEntry server_entry = NULL;
1333   SilcClientID *client_id = NULL;
1334   SilcServerID *server_id = NULL;
1335   unsigned char *tmp;
1336   SilcUInt32 len;
1337   SilcIDPayload idp = NULL;
1338   SilcIdType id_type;
1339   SilcPublicKey public_key = NULL;
1340
1341   COMMAND_CHECK_STATUS;
1342
1343   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1344   if (!tmp)
1345     goto out;
1346   idp = silc_id_payload_parse(tmp, len);
1347   if (!idp)
1348     goto out;
1349
1350   /* Get the public key payload */
1351   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1352   if (!tmp)
1353     goto out;
1354
1355   /* Decode the public key payload */
1356   if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1357     goto out;
1358
1359   id_type = silc_id_payload_get_type(idp);
1360   if (id_type == SILC_ID_CLIENT) {
1361     client_id = silc_id_payload_get_id(idp);
1362
1363     client = silc_idlist_find_client_by_id(server->local_list, client_id,
1364                                            TRUE, NULL);
1365     if (!client) {
1366       client = silc_idlist_find_client_by_id(server->global_list,
1367                                              client_id, TRUE, NULL);
1368       if (!client)
1369         goto out;
1370     }
1371
1372     if (!client->data.public_key) {
1373       if (!silc_hash_table_find_by_context(server->pk_hash, public_key,
1374                                            client, NULL))
1375         silc_hash_table_add(server->pk_hash, public_key, client);
1376
1377       client->data.public_key = public_key;
1378       public_key = NULL;
1379     }
1380   } else if (id_type == SILC_ID_SERVER) {
1381     server_id = silc_id_payload_get_id(idp);
1382
1383     server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1384                                                  TRUE, NULL);
1385     if (!server_entry) {
1386       server_entry = silc_idlist_find_server_by_id(server->global_list,
1387                                                    server_id, TRUE, NULL);
1388       if (!server_entry)
1389         goto out;
1390     }
1391
1392     server_entry->data.public_key = public_key;
1393     public_key = NULL;
1394   } else {
1395     goto out;
1396   }
1397
1398  out:
1399   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1400   if (idp)
1401     silc_id_payload_free(idp);
1402   silc_free(client_id);
1403   silc_free(server_id);
1404   if (public_key)
1405     silc_pkcs_public_key_free(public_key);
1406  err:
1407   silc_server_command_reply_free(cmd);
1408 }
1409
1410 SILC_SERVER_CMD_REPLY_FUNC(list)
1411 {
1412   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1413   SilcServer server = cmd->server;
1414   SilcStatus status, error;
1415   SilcChannelID *channel_id = NULL;
1416   SilcChannelEntry channel;
1417   SilcIDCacheEntry cache;
1418   SilcUInt32 len;
1419   unsigned char *tmp, *name, *topic;
1420   SilcUInt32 usercount = 0;
1421   bool global_list = FALSE;
1422
1423   COMMAND_CHECK_STATUS;
1424
1425   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1426   channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1427   if (!channel_id)
1428     goto out;
1429
1430   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1431   topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1432   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1433   if (tmp)
1434     SILC_GET32_MSB(usercount, tmp);
1435
1436   /* Add the channel entry if we do not have it already */
1437   channel = silc_idlist_find_channel_by_name(server->local_list,
1438                                              name, &cache);
1439   if (!channel) {
1440     channel = silc_idlist_find_channel_by_name(server->global_list,
1441                                                name, &cache);
1442     global_list = TRUE;
1443   }
1444   if (!channel) {
1445     /* If router did not find such channel in its lists then this must
1446        be bogus channel or some router in the net is buggy. */
1447     if (server->server_type != SILC_SERVER)
1448       goto out;
1449
1450     channel = silc_idlist_add_channel(server->global_list, strdup(name),
1451                                       SILC_CHANNEL_MODE_NONE, channel_id,
1452                                       server->router, NULL, NULL,
1453                                       time(NULL) + 60);
1454     if (!channel)
1455       goto out;
1456     channel_id = NULL;
1457   } else {
1458     /* Found, update expiry */
1459     if (global_list && server->server_type == SILC_SERVER)
1460       cache->expire = time(NULL) + 60;
1461   }
1462
1463   channel->user_count = usercount;
1464
1465   if (topic) {
1466     silc_free(channel->topic);
1467     channel->topic = strdup(topic);
1468   }
1469
1470   /* Pending callbacks are not executed if this was an list entry */
1471   if (status != SILC_STATUS_OK &&
1472       status != SILC_STATUS_LIST_END) {
1473     silc_server_command_reply_free(cmd);
1474     return;
1475   }
1476
1477   /* Now purge all old entries from the global list, otherwise we'll might
1478      have non-existent entries for long periods of time in the cache. */
1479   silc_idcache_purge(server->global_list->channels);
1480
1481  out:
1482   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1483   silc_free(channel_id);
1484  err:
1485   silc_server_command_reply_free(cmd);
1486 }
1487
1488 SILC_SERVER_CMD_REPLY_FUNC(watch)
1489 {
1490   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1491   SilcStatus status, error;
1492
1493   COMMAND_CHECK_STATUS;
1494
1495  out:
1496   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1497  err:
1498   silc_server_command_reply_free(cmd);
1499 }
1500
1501 SILC_SERVER_CMD_REPLY_FUNC(ping)
1502 {
1503   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1504   SilcStatus status, error;
1505
1506   COMMAND_CHECK_STATUS;
1507
1508  out:
1509   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_PING);
1510  err:
1511   silc_server_command_reply_free(cmd);
1512 }