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
827   id = silc_id_payload_parse_id(id_string, id_len);
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     silc_free(cache->id);
891     entry->id = id;
892     cache->id = entry->id;
893     entry->disabled = FALSE;
894
895     /* Remove the founder auth data if the mode is not set but we have
896        them in the entry */
897     if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
898       silc_pkcs_public_key_free(entry->founder_key);
899       if (entry->founder_passwd) {
900         silc_free(entry->founder_passwd);
901         entry->founder_passwd = NULL;
902       }
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     if (entry->ban_list)
915       silc_free(entry->ban_list);
916     entry->ban_list = silc_calloc(len, sizeof(*entry->ban_list));
917     memcpy(entry->ban_list, tmp, len);
918   }
919
920   /* Get the invite list */
921   tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
922   if (tmp) {
923     if (entry->invite_list)
924       silc_free(entry->invite_list);
925     entry->invite_list = silc_calloc(len, sizeof(*entry->invite_list));
926     memcpy(entry->invite_list, tmp, len);
927   }
928
929   /* Get the topic */
930   tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
931   if (tmp) {
932     if (entry->topic)
933       silc_free(entry->topic);
934     entry->topic = strdup(tmp);
935   }
936
937   /* If channel was not created we know there is global users on the 
938      channel. */
939   entry->global_users = (created == 0 ? TRUE : FALSE);
940
941   /* If channel was just created the mask must be zero */
942   if (!entry->global_users && mode) {
943     SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
944                     "new channel, forcing it to zero", cmd->sock->hostname));
945     mode = 0;
946   }
947
948   /* Save channel mode */
949   entry->mode = mode;
950
951   /* Save channel key */
952   if (keyp) {
953     if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
954       silc_server_save_channel_key(server, keyp, entry);
955     silc_buffer_free(keyp);
956   }
957
958   /* Save the users to the channel */
959   silc_server_save_users_on_channel(server, cmd->sock, entry, 
960                                     client_id, client_id_list,
961                                     client_mode_list, list_count);
962
963  out:
964   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
965   silc_free(client_id);
966   silc_server_command_reply_free(cmd);
967
968   if (client_id_list)
969     silc_buffer_free(client_id_list);
970   if (client_mode_list)
971     silc_buffer_free(client_mode_list);
972 }
973
974 SILC_SERVER_CMD_REPLY_FUNC(users)
975 {
976   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
977   SilcServer server = cmd->server;
978   SilcCommandStatus status;
979   SilcChannelEntry channel;
980   SilcChannelID *channel_id = NULL;
981   SilcBuffer client_id_list;
982   SilcBuffer client_mode_list;
983   unsigned char *tmp;
984   uint32 tmp_len;
985   uint32 list_count;
986
987   COMMAND_CHECK_STATUS;
988
989   /* Get channel ID */
990   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
991   if (!tmp)
992     goto out;
993   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
994   if (!channel_id)
995     goto out;
996
997   /* Get channel entry */
998   channel = silc_idlist_find_channel_by_id(server->local_list, 
999                                            channel_id, NULL);
1000   if (!channel) {
1001     channel = silc_idlist_find_channel_by_id(server->global_list, 
1002                                              channel_id, NULL);
1003     if (!channel) {
1004       SilcBuffer idp;
1005
1006       if (server->server_type != SILC_SERVER)
1007         goto out;
1008
1009       idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1010       silc_server_send_command(server, server->router->connection,
1011                                SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1012                                1, 5, idp->data, idp->len);
1013       silc_buffer_free(idp);
1014
1015       /* Register pending command callback. After we've received the channel
1016          information we will reprocess this command reply by re-calling this
1017          USERS command reply callback. */
1018       silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, 
1019                                   server->cmd_ident,
1020                                   silc_server_command_reply_users, cmd);
1021       return;
1022     }
1023   }
1024
1025   /* Get the list count */
1026   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1027   if (!tmp)
1028     goto out;
1029   SILC_GET32_MSB(list_count, tmp);
1030
1031   /* Get Client ID list */
1032   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1033   if (!tmp)
1034     goto out;
1035
1036   client_id_list = silc_buffer_alloc(tmp_len);
1037   silc_buffer_pull_tail(client_id_list, tmp_len);
1038   silc_buffer_put(client_id_list, tmp, tmp_len);
1039
1040   /* Get client mode list */
1041   tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1042   if (!tmp)
1043     goto out;
1044
1045   client_mode_list = silc_buffer_alloc(tmp_len);
1046   silc_buffer_pull_tail(client_mode_list, tmp_len);
1047   silc_buffer_put(client_mode_list, tmp, tmp_len);
1048
1049   /* Save the users to the channel */
1050   silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1051                                     client_id_list, client_mode_list, 
1052                                     list_count);
1053
1054   silc_buffer_free(client_id_list);
1055   silc_buffer_free(client_mode_list);
1056
1057  out:
1058   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1059   silc_free(channel_id);
1060   silc_server_command_reply_free(cmd);
1061 }
1062
1063 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1064 {
1065   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1066   SilcServer server = cmd->server;
1067   SilcCommandStatus status;
1068   SilcClientEntry client = NULL;
1069   SilcServerEntry server_entry = NULL;
1070   SilcClientID *client_id = NULL;
1071   SilcServerID *server_id = NULL;
1072   SilcSKEPKType type;
1073   unsigned char *tmp, *pk;
1074   uint32 len;
1075   uint16 pk_len;
1076   SilcIDPayload idp = NULL;
1077   SilcIdType id_type;
1078   SilcPublicKey public_key = NULL;
1079
1080   COMMAND_CHECK_STATUS;
1081
1082   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1083   if (!tmp)
1084     goto out;
1085   idp = silc_id_payload_parse(tmp, len);
1086   if (!idp)
1087     goto out;
1088
1089   /* Get the public key payload */
1090   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1091   if (!tmp)
1092     goto out;
1093
1094   /* Decode the public key */
1095
1096   SILC_GET16_MSB(pk_len, tmp);
1097   SILC_GET16_MSB(type, tmp + 2);
1098   pk = tmp + 4;
1099
1100   if (type != SILC_SKE_PK_TYPE_SILC)
1101     goto out;
1102
1103   if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1104     goto out;
1105
1106   id_type = silc_id_payload_get_type(idp);
1107   if (id_type == SILC_ID_CLIENT) {
1108     client_id = silc_id_payload_get_id(idp);
1109
1110     client = silc_idlist_find_client_by_id(server->local_list, client_id,
1111                                            TRUE, NULL);
1112     if (!client) {
1113       client = silc_idlist_find_client_by_id(server->global_list, 
1114                                              client_id, TRUE, NULL);
1115       if (!client)
1116         goto out;
1117     }
1118
1119     client->data.public_key = public_key;
1120   } else if (id_type == SILC_ID_SERVER) {
1121     server_id = silc_id_payload_get_id(idp);
1122
1123     server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1124                                                  TRUE, NULL);
1125     if (!server_entry) {
1126       server_entry = silc_idlist_find_server_by_id(server->global_list, 
1127                                                    server_id, TRUE, NULL);
1128       if (!server_entry)
1129         goto out;
1130     }
1131
1132     server_entry->data.public_key = public_key;
1133   } else {
1134     goto out;
1135   }
1136
1137  out:
1138   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1139   if (idp)
1140     silc_id_payload_free(idp);
1141   silc_free(client_id);
1142   silc_free(server_id);
1143   if (public_key)
1144     silc_pkcs_public_key_free(public_key);
1145   silc_server_command_reply_free(cmd);
1146 }
1147
1148 SILC_SERVER_CMD_REPLY_FUNC(list)
1149 {
1150   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1151   SilcServer server = cmd->server;
1152   SilcCommandStatus status;
1153   SilcChannelID *channel_id = NULL;
1154   SilcChannelEntry channel;
1155   SilcIDCacheEntry cache;
1156   uint32 len;
1157   unsigned char *tmp, *name, *topic;
1158   uint32 usercount = 0;
1159   bool global_list = FALSE;
1160
1161   COMMAND_CHECK_STATUS_LIST;
1162
1163   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1164   channel_id = silc_id_payload_parse_id(tmp, len);
1165   if (!channel_id)
1166     goto out;
1167
1168   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1169   topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1170   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1171   if (tmp)
1172     SILC_GET32_MSB(usercount, tmp);
1173
1174   /* Add the channel entry if we do not have it already */
1175   channel = silc_idlist_find_channel_by_name(server->local_list, 
1176                                              name, &cache);
1177   if (!channel) {
1178     channel = silc_idlist_find_channel_by_name(server->global_list, 
1179                                                name, &cache);
1180     global_list = TRUE;
1181   }
1182   if (!channel) {
1183     /* If router did not find such channel in its lists then this must
1184        be bogus channel or some router in the net is buggy. */
1185     if (server->server_type != SILC_SERVER)
1186       goto out;
1187     
1188     channel = silc_idlist_add_channel(server->global_list, strdup(name),
1189                                       SILC_CHANNEL_MODE_NONE, channel_id, 
1190                                       server->router, NULL, NULL, 
1191                                       time(NULL) + 60);
1192     if (!channel)
1193       goto out;
1194     channel_id = NULL;
1195   } else {
1196     /* Found, update expiry */
1197     if (global_list && server->server_type == SILC_SERVER)
1198       cache->expire = time(NULL) + 60;
1199   }
1200
1201   if (topic) {
1202     silc_free(channel->topic);
1203     channel->topic = strdup(topic);
1204   }
1205
1206   /* Pending callbacks are not executed if this was an list entry */
1207   if (status != SILC_STATUS_OK &&
1208       status != SILC_STATUS_LIST_END) {
1209     silc_server_command_reply_free(cmd);
1210     return;
1211   }
1212
1213   /* Now purge all old entries from the global list, otherwise we'll might
1214      have non-existent entries for long periods of time in the cache. */
1215   silc_idcache_purge(server->global_list->channels);
1216
1217  out:
1218   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1219   silc_free(channel_id);
1220   silc_server_command_reply_free(cmd);
1221 }