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