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