cfcd8b4b6a5513693e63c9776c9acbb9f90a8f3c
[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 - 2003 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       /* entry isn't known so we IDENTIFY it. otherwise the
890        * silc_server_command_motd won't know about it and tell
891        * the client that there is no such server */
892       SilcBuffer buffer;
893       buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
894                                               ++server->cmd_ident, 5,
895                                               1, NULL, 0, 2, NULL, 0,
896                                               3, NULL, 0, 4, NULL, 0,
897                                               5, tmp, tmp_len);
898       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
899                               SILC_PACKET_COMMAND, 0, buffer->data,
900                               buffer->len, TRUE);
901       silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
902                                   server->cmd_ident, 
903                                   silc_server_command_reply_motd,
904                                   cmd);
905       silc_buffer_free(buffer);
906       return;
907     }
908   }
909
910   /* Get the motd */
911   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
912   if (tmp_len > 256)
913     tmp = NULL;
914
915   entry->motd = tmp;
916
917  out:
918   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
919  err:
920   silc_server_command_reply_free(cmd);
921
922   if (entry)
923     entry->motd = NULL;
924 }
925
926 /* Received reply for forwarded JOIN command. Router has created or joined
927    the client to the channel. We save some channel information locally
928    for future use. */
929
930 SILC_SERVER_CMD_REPLY_FUNC(join)
931 {
932   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
933   SilcServer server = cmd->server;
934   SilcIDCacheEntry cache = NULL;
935   SilcStatus status, error;
936   SilcChannelID *id;
937   SilcClientID *client_id = NULL;
938   SilcChannelEntry entry;
939   SilcHmac hmac = NULL;
940   SilcUInt32 id_len, len, list_count;
941   unsigned char *id_string;
942   char *channel_name, *tmp;
943   SilcUInt32 mode, created;
944   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
945   SilcPublicKey founder_key = NULL;
946
947   COMMAND_CHECK_STATUS;
948
949   /* Get channel name */
950   channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
951   if (!channel_name)
952     goto out;
953
954   /* Get channel ID */
955   id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
956   if (!id_string)
957     goto out;
958
959   /* Get client ID */
960   tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
961   if (!tmp)
962     goto out;
963   client_id = silc_id_payload_parse_id(tmp, len, NULL);
964   if (!client_id)
965     goto out;
966
967   /* Get mode mask */
968   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
969   if (!tmp)
970     goto out;
971   SILC_GET32_MSB(mode, tmp);
972
973   /* Get created boolean value */
974   tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
975   if (!tmp)
976     goto out;
977   SILC_GET32_MSB(created, tmp);
978   if (created != 0 && created != 1)
979     goto out;
980
981   /* Get channel key */
982   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
983   if (tmp) {
984     keyp = silc_buffer_alloc(len);
985     silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
986     silc_buffer_put(keyp, tmp, len);
987   }
988
989   /* Parse the Channel ID */
990   id = silc_id_payload_parse_id(id_string, id_len, NULL);
991   if (!id)
992     goto out;
993
994   /* Get hmac */
995   tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
996   if (tmp) {
997     if (!silc_hmac_alloc(tmp, NULL, &hmac))
998       goto out;
999   }
1000
1001   /* Get the list count */
1002   tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1003   if (!tmp)
1004     goto out;
1005   SILC_GET32_MSB(list_count, tmp);
1006
1007   /* Get Client ID list */
1008   tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1009   if (!tmp)
1010     goto out;
1011
1012   client_id_list = silc_buffer_alloc(len);
1013   silc_buffer_pull_tail(client_id_list, len);
1014   silc_buffer_put(client_id_list, tmp, len);
1015
1016   /* Get client mode list */
1017   tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1018   if (!tmp)
1019     goto out;
1020
1021   client_mode_list = silc_buffer_alloc(len);
1022   silc_buffer_pull_tail(client_mode_list, len);
1023   silc_buffer_put(client_mode_list, tmp, len);
1024
1025   /* Get founder key */
1026   tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
1027   if (tmp)
1028     silc_pkcs_public_key_payload_decode(tmp, len, &founder_key);
1029
1030   /* See whether we already have the channel. */
1031   entry = silc_idlist_find_channel_by_name(server->local_list,
1032                                            channel_name, &cache);
1033   if (!entry) {
1034     /* Add new channel */
1035
1036     SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
1037                     (created == 0 ? "existing" : "created"), channel_name,
1038                     silc_id_render(id, SILC_ID_CHANNEL)));
1039
1040     /* If the channel is found from global list we must move it to the
1041        local list. */
1042     entry = silc_idlist_find_channel_by_name(server->global_list,
1043                                              channel_name, &cache);
1044     if (entry)
1045       silc_idlist_del_channel(server->global_list, entry);
1046
1047     /* Add the channel to our local list. */
1048     entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
1049                                     SILC_CHANNEL_MODE_NONE, id,
1050                                     server->router, NULL, hmac, 0);
1051     if (!entry) {
1052       silc_free(id);
1053       goto out;
1054     }
1055     hmac = NULL;
1056     server->stat.my_channels++;
1057     server->stat.channels++;
1058   } else {
1059     /* The entry exists. */
1060
1061     /* If ID has changed, then update it to the cache too. */
1062     if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
1063       silc_idlist_replace_channel_id(server->local_list, entry->id, id);
1064
1065     entry->disabled = FALSE;
1066
1067     /* Remove the founder auth data if the mode is not set but we have
1068        them in the entry */
1069     if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
1070       silc_pkcs_public_key_free(entry->founder_key);
1071       entry->founder_key = NULL;
1072     }
1073   }
1074
1075   if (founder_key) {
1076     if (entry->founder_key)
1077       silc_pkcs_public_key_free(entry->founder_key);
1078     entry->founder_key = founder_key;
1079     founder_key = NULL;
1080   }
1081
1082   if (entry->hmac_name && (hmac || (!hmac && entry->hmac))) {
1083     silc_free(entry->hmac_name);
1084     entry->hmac_name = strdup(silc_hmac_get_name(hmac ? hmac : entry->hmac));
1085   }
1086
1087   /* Get the ban list */
1088   tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
1089   if (tmp && len > 2) {
1090     SilcArgumentPayload iargs;
1091     SilcUInt16 iargc;
1092     SILC_GET16_MSB(iargc, tmp);
1093     iargs = silc_argument_payload_parse(tmp + 2, len - 2, iargc);
1094     if (iargs) {
1095       /* Delete old ban list */
1096       if (entry->ban_list)
1097         silc_hash_table_free(entry->ban_list);
1098       entry->ban_list =
1099         silc_hash_table_alloc(0, silc_hash_ptr,
1100                               NULL, NULL, NULL,
1101                               silc_server_inviteban_destruct, entry, TRUE);
1102
1103       /* Add new ban list */
1104       silc_server_inviteban_process(server, entry->ban_list, 0, iargs);
1105       silc_argument_payload_free(iargs);
1106     }
1107   }
1108
1109   /* Get the invite list */
1110   tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
1111   if (tmp && len > 2) {
1112     SilcArgumentPayload iargs;
1113     SilcUInt16 iargc;
1114     SILC_GET16_MSB(iargc, tmp);
1115     iargs = silc_argument_payload_parse(tmp + 2, len - 2, iargc);
1116     if (iargs) {
1117       /* Delete old invite list */
1118       if (entry->invite_list)
1119         silc_hash_table_free(entry->invite_list);
1120       entry->invite_list =
1121         silc_hash_table_alloc(0, silc_hash_ptr,
1122                               NULL, NULL, NULL,
1123                               silc_server_inviteban_destruct, entry, TRUE);
1124
1125       /* Add new invite list */
1126       silc_server_inviteban_process(server, entry->invite_list, 0, iargs);
1127       silc_argument_payload_free(iargs);
1128     }
1129   }
1130
1131   /* Get the topic */
1132   tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
1133   if (tmp) {
1134     silc_free(entry->topic);
1135     entry->topic = strdup(tmp);
1136   }
1137
1138   /* Get channel public key list */
1139   tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1140   if (tmp && server->server_type == SILC_SERVER)
1141     silc_server_set_channel_pk_list(server, NULL, entry, tmp, len);
1142
1143   /* If channel was not created we know there is global users on the
1144      channel. */
1145   entry->global_users = (created == 0 ? TRUE : FALSE);
1146
1147   /* If channel was just created the mask must be zero */
1148   if (!entry->global_users && mode) {
1149     SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
1150                     "new channel, forcing it to zero", cmd->sock->hostname));
1151     mode = 0;
1152   }
1153
1154   /* Save channel mode */
1155   entry->mode = mode;
1156
1157   /* Save channel key */
1158   if (keyp) {
1159     if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
1160       silc_server_save_channel_key(server, keyp, entry);
1161     silc_buffer_free(keyp);
1162   }
1163
1164   /* Save the users to the channel */
1165   silc_server_save_users_on_channel(server, cmd->sock, entry,
1166                                     client_id, client_id_list,
1167                                     client_mode_list, list_count);
1168   entry->users_resolved = TRUE;
1169
1170  out:
1171   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1172  err:
1173   if (hmac)
1174     silc_hmac_free(hmac);
1175   silc_free(client_id);
1176   silc_server_command_reply_free(cmd);
1177
1178   silc_pkcs_public_key_free(founder_key);
1179   if (client_id_list)
1180     silc_buffer_free(client_id_list);
1181   if (client_mode_list)
1182     silc_buffer_free(client_mode_list);
1183 }
1184
1185 /* Received reply to STATS command.  */
1186
1187 SILC_SERVER_CMD_REPLY_FUNC(stats)
1188 {
1189   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1190   SilcServer server = cmd->server;
1191   SilcStatus status, error;
1192   unsigned char *tmp;
1193   SilcUInt32 tmp_len;
1194   SilcBufferStruct buf;
1195
1196   COMMAND_CHECK_STATUS;
1197
1198   /* Get statistics structure */
1199   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1200   if (server->server_type != SILC_ROUTER && tmp) {
1201     silc_buffer_set(&buf, tmp, tmp_len);
1202     silc_buffer_unformat(&buf,
1203                          SILC_STR_UI_INT(NULL),
1204                          SILC_STR_UI_INT(NULL),
1205                          SILC_STR_UI_INT(NULL),
1206                          SILC_STR_UI_INT(NULL),
1207                          SILC_STR_UI_INT(NULL),
1208                          SILC_STR_UI_INT(NULL),
1209                          SILC_STR_UI_INT(&server->stat.cell_clients),
1210                          SILC_STR_UI_INT(&server->stat.cell_channels),
1211                          SILC_STR_UI_INT(&server->stat.cell_servers),
1212                          SILC_STR_UI_INT(&server->stat.clients),
1213                          SILC_STR_UI_INT(&server->stat.channels),
1214                          SILC_STR_UI_INT(&server->stat.servers),
1215                          SILC_STR_UI_INT(&server->stat.routers),
1216                          SILC_STR_UI_INT(&server->stat.server_ops),
1217                          SILC_STR_UI_INT(&server->stat.router_ops),
1218                          SILC_STR_END);
1219   }
1220
1221  out:
1222   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
1223  err:
1224   silc_server_command_reply_free(cmd);
1225 }
1226
1227 SILC_SERVER_CMD_REPLY_FUNC(users)
1228 {
1229   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1230   SilcServer server = cmd->server;
1231   SilcStatus status, error;
1232   SilcChannelEntry channel;
1233   SilcChannelID *channel_id = NULL;
1234   SilcBuffer client_id_list;
1235   SilcBuffer client_mode_list;
1236   unsigned char *tmp;
1237   SilcUInt32 tmp_len;
1238   SilcUInt32 list_count;
1239
1240   COMMAND_CHECK_STATUS;
1241
1242   /* Get channel ID */
1243   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1244   if (!tmp)
1245     goto out;
1246   channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1247   if (!channel_id)
1248     goto out;
1249
1250   /* Get channel entry */
1251   channel = silc_idlist_find_channel_by_id(server->local_list,
1252                                            channel_id, NULL);
1253   if (!channel) {
1254     channel = silc_idlist_find_channel_by_id(server->global_list,
1255                                              channel_id, NULL);
1256     if (!channel) {
1257       SilcBuffer idp;
1258
1259       if (server->server_type != SILC_SERVER)
1260         goto out;
1261
1262       idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1263       silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
1264                                SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1265                                1, 5, idp->data, idp->len);
1266       silc_buffer_free(idp);
1267
1268       /* Register pending command callback. After we've received the channel
1269          information we will reprocess this command reply by re-calling this
1270          USERS command reply callback. */
1271       silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1272                                   server->cmd_ident,
1273                                   silc_server_command_reply_users, cmd);
1274       return;
1275     }
1276   }
1277
1278   /* Get the list count */
1279   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1280   if (!tmp)
1281     goto out;
1282   SILC_GET32_MSB(list_count, tmp);
1283
1284   /* Get Client ID list */
1285   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1286   if (!tmp)
1287     goto out;
1288
1289   client_id_list = silc_buffer_alloc(tmp_len);
1290   silc_buffer_pull_tail(client_id_list, tmp_len);
1291   silc_buffer_put(client_id_list, tmp, tmp_len);
1292
1293   /* Get client mode list */
1294   tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1295   if (!tmp)
1296     goto out;
1297
1298   client_mode_list = silc_buffer_alloc(tmp_len);
1299   silc_buffer_pull_tail(client_mode_list, tmp_len);
1300   silc_buffer_put(client_mode_list, tmp, tmp_len);
1301
1302   /* Save the users to the channel */
1303   silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1304                                     client_id_list, client_mode_list,
1305                                     list_count);
1306
1307   channel->global_users = silc_server_channel_has_global(channel);
1308   channel->users_resolved = TRUE;
1309
1310   silc_buffer_free(client_id_list);
1311   silc_buffer_free(client_mode_list);
1312
1313  out:
1314   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1315   silc_free(channel_id);
1316  err:
1317   silc_server_command_reply_free(cmd);
1318 }
1319
1320 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1321 {
1322   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1323   SilcServer server = cmd->server;
1324   SilcStatus status, error;
1325   SilcClientEntry client = NULL;
1326   SilcServerEntry server_entry = NULL;
1327   SilcClientID *client_id = NULL;
1328   SilcServerID *server_id = NULL;
1329   unsigned char *tmp;
1330   SilcUInt32 len;
1331   SilcIDPayload idp = NULL;
1332   SilcIdType id_type;
1333   SilcPublicKey public_key = NULL;
1334
1335   COMMAND_CHECK_STATUS;
1336
1337   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1338   if (!tmp)
1339     goto out;
1340   idp = silc_id_payload_parse(tmp, len);
1341   if (!idp)
1342     goto out;
1343
1344   /* Get the public key payload */
1345   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1346   if (!tmp)
1347     goto out;
1348
1349   /* Decode the public key payload */
1350   if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1351     goto out;
1352
1353   id_type = silc_id_payload_get_type(idp);
1354   if (id_type == SILC_ID_CLIENT) {
1355     client_id = silc_id_payload_get_id(idp);
1356
1357     client = silc_idlist_find_client_by_id(server->local_list, client_id,
1358                                            TRUE, NULL);
1359     if (!client) {
1360       client = silc_idlist_find_client_by_id(server->global_list,
1361                                              client_id, TRUE, NULL);
1362       if (!client)
1363         goto out;
1364     }
1365
1366     if (!silc_hash_table_find_by_context(server->pk_hash, public_key,
1367                                          client, NULL))
1368       silc_hash_table_add(server->pk_hash, public_key, client);
1369
1370     client->data.public_key = public_key;
1371     public_key = NULL;
1372   } else if (id_type == SILC_ID_SERVER) {
1373     server_id = silc_id_payload_get_id(idp);
1374
1375     server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1376                                                  TRUE, NULL);
1377     if (!server_entry) {
1378       server_entry = silc_idlist_find_server_by_id(server->global_list,
1379                                                    server_id, TRUE, NULL);
1380       if (!server_entry)
1381         goto out;
1382     }
1383
1384     server_entry->data.public_key = public_key;
1385     public_key = NULL;
1386   } else {
1387     goto out;
1388   }
1389
1390  out:
1391   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1392   if (idp)
1393     silc_id_payload_free(idp);
1394   silc_free(client_id);
1395   silc_free(server_id);
1396   if (public_key)
1397     silc_pkcs_public_key_free(public_key);
1398  err:
1399   silc_server_command_reply_free(cmd);
1400 }
1401
1402 SILC_SERVER_CMD_REPLY_FUNC(list)
1403 {
1404   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1405   SilcServer server = cmd->server;
1406   SilcStatus status, error;
1407   SilcChannelID *channel_id = NULL;
1408   SilcChannelEntry channel;
1409   SilcIDCacheEntry cache;
1410   SilcUInt32 len;
1411   unsigned char *tmp, *name, *topic;
1412   SilcUInt32 usercount = 0;
1413   bool global_list = FALSE;
1414
1415   COMMAND_CHECK_STATUS;
1416
1417   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1418   channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1419   if (!channel_id)
1420     goto out;
1421
1422   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1423   topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1424   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1425   if (tmp)
1426     SILC_GET32_MSB(usercount, tmp);
1427
1428   /* Add the channel entry if we do not have it already */
1429   channel = silc_idlist_find_channel_by_name(server->local_list,
1430                                              name, &cache);
1431   if (!channel) {
1432     channel = silc_idlist_find_channel_by_name(server->global_list,
1433                                                name, &cache);
1434     global_list = TRUE;
1435   }
1436   if (!channel) {
1437     /* If router did not find such channel in its lists then this must
1438        be bogus channel or some router in the net is buggy. */
1439     if (server->server_type != SILC_SERVER)
1440       goto out;
1441
1442     channel = silc_idlist_add_channel(server->global_list, strdup(name),
1443                                       SILC_CHANNEL_MODE_NONE, channel_id,
1444                                       server->router, NULL, NULL,
1445                                       time(NULL) + 60);
1446     if (!channel)
1447       goto out;
1448     channel_id = NULL;
1449   } else {
1450     /* Found, update expiry */
1451     if (global_list && server->server_type == SILC_SERVER)
1452       cache->expire = time(NULL) + 60;
1453   }
1454
1455   channel->user_count = usercount;
1456
1457   if (topic) {
1458     silc_free(channel->topic);
1459     channel->topic = strdup(topic);
1460   }
1461
1462   /* Pending callbacks are not executed if this was an list entry */
1463   if (status != SILC_STATUS_OK &&
1464       status != SILC_STATUS_LIST_END) {
1465     silc_server_command_reply_free(cmd);
1466     return;
1467   }
1468
1469   /* Now purge all old entries from the global list, otherwise we'll might
1470      have non-existent entries for long periods of time in the cache. */
1471   silc_idcache_purge(server->global_list->channels);
1472
1473  out:
1474   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1475   silc_free(channel_id);
1476  err:
1477   silc_server_command_reply_free(cmd);
1478 }
1479
1480 SILC_SERVER_CMD_REPLY_FUNC(watch)
1481 {
1482   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1483   SilcStatus status, error;
1484
1485   COMMAND_CHECK_STATUS;
1486
1487  out:
1488   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1489  err:
1490   silc_server_command_reply_free(cmd);
1491 }
1492
1493 SILC_SERVER_CMD_REPLY_FUNC(ping)
1494 {
1495   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1496   SilcStatus status, error;
1497
1498   COMMAND_CHECK_STATUS;
1499
1500  out:
1501   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_PING);
1502  err:
1503   silc_server_command_reply_free(cmd);
1504 }