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