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