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