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