More checks for not having purge timeout for global clients that
[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   /* If client is global and is not on any channel then add that we'll
405      expire the entry after a while. */
406   if (global) {
407     silc_idlist_find_client_by_id(server->global_list, client->id,
408                                   FALSE, &cache);
409     if (!silc_hash_table_count(client->channels))
410       cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
411     else
412       cache->expire = 0;
413   }
414
415   silc_free(client_id);
416
417   return TRUE;
418 }
419
420 /* Received reply for WHOWAS command. Cache the client information only for
421    a short period of time. */
422
423 SILC_SERVER_CMD_REPLY_FUNC(whowas)
424 {
425   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
426   SilcStatus status, error;
427
428   COMMAND_CHECK_STATUS;
429
430   if (!silc_server_command_reply_whowas_save(cmd))
431     goto out;
432
433   /* Pending callbacks are not executed if this was an list entry */
434   if (status != SILC_STATUS_OK &&
435       status != SILC_STATUS_LIST_END) {
436     silc_server_command_reply_free(cmd);
437     return;
438   }
439
440  out:
441   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
442  err:
443   silc_server_command_reply_free(cmd);
444 }
445
446 /* Caches the received IDENTIFY information. */
447
448 static char
449 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
450 {
451   SilcServer server = cmd->server;
452   SilcUInt32 len, id_len;
453   unsigned char *id_data;
454   char *name, *info;
455   SilcClientID *client_id = NULL;
456   SilcServerID *server_id = NULL;
457   SilcChannelID *channel_id = NULL;
458   SilcClientEntry client;
459   SilcServerEntry server_entry;
460   SilcChannelEntry channel;
461   char global = FALSE;
462   char *nick = NULL;
463   SilcIDPayload idp = NULL;
464   SilcIdType id_type;
465   int expire = 0;
466
467   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
468   if (!id_data)
469     return FALSE;
470   idp = silc_id_payload_parse(id_data, id_len);
471   if (!idp)
472     return FALSE;
473
474   name = silc_argument_get_arg_type(cmd->args, 3, &len);
475   info = silc_argument_get_arg_type(cmd->args, 4, &len);
476
477   id_type = silc_id_payload_get_type(idp);
478
479   switch (id_type) {
480   case SILC_ID_CLIENT:
481     client_id = silc_id_payload_get_id(idp);
482     if (!client_id)
483       goto error;
484
485     SILC_LOG_DEBUG(("Received client information"));
486
487     client = silc_idlist_find_client_by_id(server->local_list, 
488                                            client_id, FALSE, NULL);
489     if (!client) {
490       client = silc_idlist_find_client_by_id(server->global_list, client_id,
491                                              FALSE, NULL);
492       global = TRUE;
493     }
494     if (!client) {
495       /* If router did not find such Client ID in its lists then this must
496          be bogus client or some router in the net is buggy. */
497       if (server->server_type != SILC_SERVER)
498         goto error;
499
500       /* Take nickname */
501       if (name)
502         silc_parse_userfqdn(name, &nick, NULL);
503
504       /* We don't have that client anywhere, add it. The client is added
505          to global list since server didn't have it in the lists so it must be 
506          global. */
507       client = silc_idlist_add_client(server->global_list, nick, 
508                                       info ? strdup(info) : NULL, NULL,
509                                       client_id, cmd->sock->user_data,
510                                       NULL, time(NULL) + 300);
511       if (!client) {
512         SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
513         goto error;
514       }
515       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
516       client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
517       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
518     } else {
519       /* We have the client already, update the data */
520       
521       SILC_LOG_DEBUG(("Updating client data"));
522       
523       /* Take nickname */
524       if (name) {
525         silc_parse_userfqdn(name, &nick, NULL);
526
527         /* Remove the old cache entry */
528         silc_idcache_del_by_context(global ? server->global_list->clients :
529                                     server->local_list->clients, client);
530
531         silc_free(client->nickname);
532         client->nickname = nick;
533       }
534       
535       if (info) {
536         silc_free(client->username);
537         client->username = strdup(info);
538       }
539
540       client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
541       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
542       
543       if (name) {
544         /* Add new cache entry */
545         silc_idcache_add(global ? server->global_list->clients :
546                          server->local_list->clients, nick, client->id, 
547                          client, expire, NULL);
548       }
549
550       /* If client is global and is not on any channel then add that we'll
551          expire the entry after a while. */
552       if (global && server->server_type == SILC_SERVER) {
553         SilcIDCacheEntry cache = NULL;
554         silc_idlist_find_client_by_id(server->global_list, client->id,
555                                       FALSE, &cache);
556         if (!silc_hash_table_count(client->channels))
557           cache->expire = time(NULL) + 300;
558         else
559           cache->expire = 0;
560       }
561
562       silc_free(client_id);
563     }
564
565     break;
566
567   case SILC_ID_SERVER:
568     if (!name)
569       goto error;
570
571     server_id = silc_id_payload_get_id(idp);
572     if (!server_id)
573       goto error;
574
575     SILC_LOG_DEBUG(("Received server information"));
576
577     server_entry = silc_idlist_find_server_by_id(server->local_list, 
578                                                  server_id, FALSE, NULL);
579     if (!server_entry)
580       server_entry = silc_idlist_find_server_by_id(server->global_list, 
581                                                    server_id, FALSE, NULL);
582     if (!server_entry) {
583       /* If router did not find such Server ID in its lists then this must
584          be bogus server or some router in the net is buggy. */
585       if (server->server_type != SILC_SERVER)
586         goto error;
587       
588       /* We don't have that server anywhere, add it. */
589       server_entry = silc_idlist_add_server(server->global_list, 
590                                             strdup(name), 0,
591                                             server_id, server->router,
592                                             SILC_PRIMARY_ROUTE(server));
593       if (!server_entry) {
594         silc_free(server_id);
595         goto error;
596       }
597       server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
598       server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
599       server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
600       server_id = NULL;
601     }
602
603     silc_free(server_id);
604     break;
605
606   case SILC_ID_CHANNEL:
607     if (!name)
608       goto error;
609
610     channel_id = silc_id_payload_get_id(idp);
611     if (!channel_id)
612       goto error;
613
614     SILC_LOG_DEBUG(("Received channel information"));
615
616     channel = silc_idlist_find_channel_by_name(server->local_list, 
617                                                name, NULL);
618     if (!channel)
619       channel = silc_idlist_find_channel_by_name(server->global_list, 
620                                                  name, NULL);
621     if (!channel) {
622       /* If router did not find such Channel ID in its lists then this must
623          be bogus channel or some router in the net is buggy. */
624       if (server->server_type != SILC_SERVER)
625         goto error;
626       
627       /* We don't have that channel anywhere, add it. */
628       channel = silc_idlist_add_channel(server->global_list, strdup(name),
629                                         SILC_CHANNEL_MODE_NONE, channel_id, 
630                                         server->router, NULL, NULL, 0);
631       if (!channel) {
632         silc_free(channel_id);
633         goto error;
634       }
635       channel_id = NULL;
636     }
637
638     silc_free(channel_id);
639     break;
640   }
641
642   silc_id_payload_free(idp);
643   return TRUE;
644
645  error:
646   silc_id_payload_free(idp);
647   return FALSE;
648 }
649
650 /* Received reply for forwarded IDENTIFY command. We have received the
651    requested identify information now and we will cache it. After this we
652    will call the pending command so that the requestee gets the information
653    after all. */
654
655 SILC_SERVER_CMD_REPLY_FUNC(identify)
656 {
657   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
658   SilcStatus status, error;
659
660   COMMAND_CHECK_STATUS;
661
662   if (!silc_server_command_reply_identify_save(cmd))
663     goto out;
664
665   /* Pending callbacks are not executed if this was an list entry */
666   if (status != SILC_STATUS_OK &&
667       status != SILC_STATUS_LIST_END) {
668     silc_server_command_reply_free(cmd);
669     return;
670   }
671
672  out:
673   silc_server_command_process_error(cmd, error);
674   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
675   silc_server_command_reply_free(cmd);
676   return;
677
678  err:
679   silc_server_command_process_error(cmd, error);
680   silc_server_command_reply_free(cmd);
681 }
682
683 /* Received reply fro INFO command. Cache the server and its information */
684
685 SILC_SERVER_CMD_REPLY_FUNC(info)
686 {
687   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
688   SilcServer server = cmd->server;
689   SilcStatus status, error;
690   SilcServerEntry entry;
691   SilcServerID *server_id;
692   SilcUInt32 tmp_len;
693   unsigned char *tmp, *name;
694
695   COMMAND_CHECK_STATUS;
696
697   /* Get Server ID */
698   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
699   if (!tmp)
700     goto out;
701   server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
702   if (!server_id)
703     goto out;
704
705   /* Get the name */
706   name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
707   if (tmp_len > 256)
708     goto out;
709
710   entry = silc_idlist_find_server_by_id(server->local_list, server_id, 
711                                         FALSE, NULL);
712   if (!entry) {
713     entry = silc_idlist_find_server_by_id(server->global_list, server_id, 
714                                           FALSE, NULL);
715     if (!entry) {
716       /* Add the server to global list */
717       server_id = silc_id_dup(server_id, SILC_ID_SERVER);
718       entry = silc_idlist_add_server(server->global_list, name, 0,
719                                      server_id, cmd->sock->user_data,
720                                      cmd->sock);
721       if (!entry) {
722         silc_free(server_id);
723         goto out;
724       }
725       entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
726     }
727   }
728
729   /* Get the info string */
730   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
731   if (tmp_len > 256)
732     tmp = NULL;
733
734   entry->server_info = tmp ? strdup(tmp) : NULL;
735
736  out:
737   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
738  err:
739   silc_server_command_reply_free(cmd);
740 }
741
742 /* Received reply fro MOTD command. */
743
744 SILC_SERVER_CMD_REPLY_FUNC(motd)
745 {
746   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
747   SilcServer server = cmd->server;
748   SilcStatus status, error;
749   SilcServerEntry entry = NULL;
750   SilcServerID *server_id;
751   SilcUInt32 tmp_len;
752   unsigned char *tmp;
753
754   COMMAND_CHECK_STATUS;
755
756   /* Get Server ID */
757   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
758   if (!tmp)
759     goto out;
760   server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
761   if (!server_id)
762     goto out;
763
764   entry = silc_idlist_find_server_by_id(server->local_list, server_id, 
765                                         TRUE, NULL);
766   if (!entry) {
767     entry = silc_idlist_find_server_by_id(server->global_list, server_id, 
768                                           TRUE, NULL);
769     if (!entry)
770       goto out;
771   }
772
773   /* Get the motd */
774   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
775   if (tmp_len > 256)
776     tmp = NULL;
777
778   entry->motd = tmp;
779
780  out:
781   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
782  err:
783   silc_server_command_reply_free(cmd);
784
785   if (entry)
786     entry->motd = NULL;
787 }
788
789 /* Received reply for forwarded JOIN command. Router has created or joined
790    the client to the channel. We save some channel information locally
791    for future use. */
792
793 SILC_SERVER_CMD_REPLY_FUNC(join)
794 {
795   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
796   SilcServer server = cmd->server;
797   SilcIDCacheEntry cache = NULL;
798   SilcStatus status, error;
799   SilcChannelID *id;
800   SilcClientID *client_id = NULL;
801   SilcChannelEntry entry;
802   SilcHmac hmac = NULL;
803   SilcUInt32 id_len, len, list_count;
804   unsigned char *id_string;
805   char *channel_name, *tmp;
806   SilcUInt32 mode, created;
807   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
808   SilcPublicKey founder_key = NULL;
809
810   COMMAND_CHECK_STATUS;
811
812   /* Get channel name */
813   channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
814   if (!channel_name)
815     goto out;
816
817   /* Get channel ID */
818   id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
819   if (!id_string)
820     goto out;
821
822   /* Get client ID */
823   tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
824   if (!tmp)
825     goto out;
826   client_id = silc_id_payload_parse_id(tmp, len, NULL);
827   if (!client_id)
828     goto out;
829
830   /* Get mode mask */
831   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
832   if (!tmp)
833     goto out;
834   SILC_GET32_MSB(mode, tmp);
835
836   /* Get created boolean value */
837   tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
838   if (!tmp)
839     goto out;
840   SILC_GET32_MSB(created, tmp);
841   if (created != 0 && created != 1)
842     goto out;
843
844   /* Get channel key */
845   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
846   if (tmp) {
847     keyp = silc_buffer_alloc(len);
848     silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
849     silc_buffer_put(keyp, tmp, len);
850   }
851
852   /* Parse the Channel ID */
853   id = silc_id_payload_parse_id(id_string, id_len, NULL);
854   if (!id)
855     goto out;
856
857   /* Get hmac */
858   tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
859   if (tmp) {
860     if (!silc_hmac_alloc(tmp, NULL, &hmac))
861       goto out;
862   }
863
864   /* Get the list count */
865   tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
866   if (!tmp)
867     goto out;
868   SILC_GET32_MSB(list_count, tmp);
869
870   /* Get Client ID list */
871   tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
872   if (!tmp)
873     goto out;
874
875   client_id_list = silc_buffer_alloc(len);
876   silc_buffer_pull_tail(client_id_list, len);
877   silc_buffer_put(client_id_list, tmp, len);
878
879   /* Get client mode list */
880   tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
881   if (!tmp)
882     goto out;
883
884   client_mode_list = silc_buffer_alloc(len);
885   silc_buffer_pull_tail(client_mode_list, len);
886   silc_buffer_put(client_mode_list, tmp, len);
887
888   /* Get founder key */
889   tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
890   if (tmp)
891     silc_pkcs_public_key_decode(tmp, len, &founder_key);
892
893   /* See whether we already have the channel. */
894   entry = silc_idlist_find_channel_by_name(server->local_list, 
895                                            channel_name, &cache);
896   if (!entry) {
897     /* Add new channel */
898
899     SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)", 
900                     (created == 0 ? "existing" : "created"), channel_name,
901                     silc_id_render(id, SILC_ID_CHANNEL)));
902
903     /* If the channel is found from global list we must move it to the
904        local list. */
905     entry = silc_idlist_find_channel_by_name(server->global_list,
906                                              channel_name, &cache);
907     if (entry)
908       silc_idlist_del_channel(server->global_list, entry);
909
910     /* Add the channel to our local list. */
911     entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
912                                     SILC_CHANNEL_MODE_NONE, id,
913                                     server->router, NULL, hmac, 0);
914     if (!entry) {
915       silc_free(id);
916       goto out;
917     }
918     server->stat.my_channels++;
919     server->stat.channels++;
920   } else {
921     /* The entry exists. */
922
923     /* If ID has changed, then update it to the cache too. */
924     if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
925       silc_idlist_replace_channel_id(server->local_list, entry->id, id);
926
927     entry->disabled = FALSE;
928
929     /* Remove the founder auth data if the mode is not set but we have
930        them in the entry */
931     if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
932       silc_pkcs_public_key_free(entry->founder_key);
933       entry->founder_key = NULL;
934     }
935   }
936
937   if (founder_key) {
938     if (entry->founder_key)
939       silc_pkcs_public_key_free(entry->founder_key);
940     entry->founder_key = founder_key;
941     founder_key = NULL;
942   }
943
944   if (entry->hmac_name && hmac) {
945     silc_free(entry->hmac_name);
946     entry->hmac_name = strdup(silc_hmac_get_name(hmac));
947   }
948
949   /* Get the ban list */
950   tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
951   if (tmp) {
952     silc_free(entry->ban_list);
953     entry->ban_list = silc_memdup(tmp, len);
954   }
955
956   /* Get the invite list */
957   tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
958   if (tmp) {
959     silc_free(entry->invite_list);
960     entry->invite_list = silc_memdup(tmp, len);
961   }
962
963   /* Get the topic */
964   tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
965   if (tmp) {
966     silc_free(entry->topic);
967     entry->topic = strdup(tmp);
968   }
969
970   /* If channel was not created we know there is global users on the 
971      channel. */
972   entry->global_users = (created == 0 ? TRUE : FALSE);
973
974   /* If channel was just created the mask must be zero */
975   if (!entry->global_users && mode) {
976     SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
977                     "new channel, forcing it to zero", cmd->sock->hostname));
978     mode = 0;
979   }
980
981   /* Save channel mode */
982   entry->mode = mode;
983
984   /* Save channel key */
985   if (keyp) {
986     if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
987       silc_server_save_channel_key(server, keyp, entry);
988     silc_buffer_free(keyp);
989   }
990
991   /* Save the users to the channel */
992   silc_server_save_users_on_channel(server, cmd->sock, entry, 
993                                     client_id, client_id_list,
994                                     client_mode_list, list_count);
995   entry->users_resolved = TRUE;
996
997  out:
998   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
999  err:
1000   silc_free(client_id);
1001   silc_server_command_reply_free(cmd);
1002
1003   silc_pkcs_public_key_free(founder_key);
1004   if (client_id_list)
1005     silc_buffer_free(client_id_list);
1006   if (client_mode_list)
1007     silc_buffer_free(client_mode_list);
1008 }
1009
1010 /* Received reply to STATS command.  */
1011
1012 SILC_SERVER_CMD_REPLY_FUNC(stats)
1013 {
1014   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1015   SilcServer server = cmd->server;
1016   SilcStatus status, error;
1017   unsigned char *tmp;
1018   SilcUInt32 tmp_len;
1019   SilcBufferStruct buf;
1020
1021   COMMAND_CHECK_STATUS;
1022
1023   /* Get statistics structure */
1024   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1025   if (server->server_type == SILC_SERVER && tmp) {
1026     silc_buffer_set(&buf, tmp, tmp_len);
1027     silc_buffer_unformat(&buf,
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(NULL),
1033                          SILC_STR_UI_INT(NULL),
1034                          SILC_STR_UI_INT(&server->stat.cell_clients),
1035                          SILC_STR_UI_INT(&server->stat.cell_channels),
1036                          SILC_STR_UI_INT(&server->stat.cell_servers),
1037                          SILC_STR_UI_INT(&server->stat.clients),
1038                          SILC_STR_UI_INT(&server->stat.channels),
1039                          SILC_STR_UI_INT(&server->stat.servers),
1040                          SILC_STR_UI_INT(&server->stat.routers),
1041                          SILC_STR_UI_INT(&server->stat.server_ops),
1042                          SILC_STR_UI_INT(&server->stat.router_ops),
1043                          SILC_STR_END);
1044   }
1045
1046  out:
1047   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
1048  err:
1049   silc_server_command_reply_free(cmd);
1050 }
1051
1052 SILC_SERVER_CMD_REPLY_FUNC(users)
1053 {
1054   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1055   SilcServer server = cmd->server;
1056   SilcStatus status, error;
1057   SilcChannelEntry channel;
1058   SilcChannelID *channel_id = NULL;
1059   SilcBuffer client_id_list;
1060   SilcBuffer client_mode_list;
1061   unsigned char *tmp;
1062   SilcUInt32 tmp_len;
1063   SilcUInt32 list_count;
1064
1065   COMMAND_CHECK_STATUS;
1066
1067   /* Get channel ID */
1068   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1069   if (!tmp)
1070     goto out;
1071   channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1072   if (!channel_id)
1073     goto out;
1074
1075   /* Get channel entry */
1076   channel = silc_idlist_find_channel_by_id(server->local_list, 
1077                                            channel_id, NULL);
1078   if (!channel) {
1079     channel = silc_idlist_find_channel_by_id(server->global_list, 
1080                                              channel_id, NULL);
1081     if (!channel) {
1082       SilcBuffer idp;
1083
1084       if (server->server_type != SILC_SERVER)
1085         goto out;
1086
1087       idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1088       silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
1089                                SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1090                                1, 5, idp->data, idp->len);
1091       silc_buffer_free(idp);
1092
1093       /* Register pending command callback. After we've received the channel
1094          information we will reprocess this command reply by re-calling this
1095          USERS command reply callback. */
1096       silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, 
1097                                   server->cmd_ident,
1098                                   silc_server_command_reply_users, cmd);
1099       return;
1100     }
1101   }
1102
1103   /* Get the list count */
1104   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1105   if (!tmp)
1106     goto out;
1107   SILC_GET32_MSB(list_count, tmp);
1108
1109   /* Get Client ID list */
1110   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1111   if (!tmp)
1112     goto out;
1113
1114   client_id_list = silc_buffer_alloc(tmp_len);
1115   silc_buffer_pull_tail(client_id_list, tmp_len);
1116   silc_buffer_put(client_id_list, tmp, tmp_len);
1117
1118   /* Get client mode list */
1119   tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1120   if (!tmp)
1121     goto out;
1122
1123   client_mode_list = silc_buffer_alloc(tmp_len);
1124   silc_buffer_pull_tail(client_mode_list, tmp_len);
1125   silc_buffer_put(client_mode_list, tmp, tmp_len);
1126
1127   /* Save the users to the channel */
1128   silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1129                                     client_id_list, client_mode_list, 
1130                                     list_count);
1131
1132   channel->global_users = silc_server_channel_has_global(channel);
1133   channel->users_resolved = TRUE;
1134
1135   silc_buffer_free(client_id_list);
1136   silc_buffer_free(client_mode_list);
1137
1138  out:
1139   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1140   silc_free(channel_id);
1141  err:
1142   silc_server_command_reply_free(cmd);
1143 }
1144
1145 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1146 {
1147   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1148   SilcServer server = cmd->server;
1149   SilcStatus status, error;
1150   SilcClientEntry client = NULL;
1151   SilcServerEntry server_entry = NULL;
1152   SilcClientID *client_id = NULL;
1153   SilcServerID *server_id = NULL;
1154   SilcSKEPKType type;
1155   unsigned char *tmp, *pk;
1156   SilcUInt32 len;
1157   SilcUInt16 pk_len;
1158   SilcIDPayload idp = NULL;
1159   SilcIdType id_type;
1160   SilcPublicKey public_key = NULL;
1161
1162   COMMAND_CHECK_STATUS;
1163
1164   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1165   if (!tmp)
1166     goto out;
1167   idp = silc_id_payload_parse(tmp, len);
1168   if (!idp)
1169     goto out;
1170
1171   /* Get the public key payload */
1172   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1173   if (!tmp)
1174     goto out;
1175
1176   /* Decode the public key */
1177
1178   SILC_GET16_MSB(pk_len, tmp);
1179   SILC_GET16_MSB(type, tmp + 2);
1180   pk = tmp + 4;
1181
1182   if (type != SILC_SKE_PK_TYPE_SILC)
1183     goto out;
1184
1185   if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1186     goto out;
1187
1188   id_type = silc_id_payload_get_type(idp);
1189   if (id_type == SILC_ID_CLIENT) {
1190     client_id = silc_id_payload_get_id(idp);
1191
1192     client = silc_idlist_find_client_by_id(server->local_list, client_id,
1193                                            TRUE, NULL);
1194     if (!client) {
1195       client = silc_idlist_find_client_by_id(server->global_list, 
1196                                              client_id, TRUE, NULL);
1197       if (!client)
1198         goto out;
1199     }
1200
1201     client->data.public_key = public_key;
1202     public_key = NULL;
1203   } else if (id_type == SILC_ID_SERVER) {
1204     server_id = silc_id_payload_get_id(idp);
1205
1206     server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1207                                                  TRUE, NULL);
1208     if (!server_entry) {
1209       server_entry = silc_idlist_find_server_by_id(server->global_list, 
1210                                                    server_id, TRUE, NULL);
1211       if (!server_entry)
1212         goto out;
1213     }
1214
1215     server_entry->data.public_key = public_key;
1216     public_key = NULL;
1217   } else {
1218     goto out;
1219   }
1220
1221  out:
1222   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1223   if (idp)
1224     silc_id_payload_free(idp);
1225   silc_free(client_id);
1226   silc_free(server_id);
1227   if (public_key)
1228     silc_pkcs_public_key_free(public_key);
1229  err:
1230   silc_server_command_reply_free(cmd);
1231 }
1232
1233 SILC_SERVER_CMD_REPLY_FUNC(list)
1234 {
1235   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1236   SilcServer server = cmd->server;
1237   SilcStatus status, error;
1238   SilcChannelID *channel_id = NULL;
1239   SilcChannelEntry channel;
1240   SilcIDCacheEntry cache;
1241   SilcUInt32 len;
1242   unsigned char *tmp, *name, *topic;
1243   SilcUInt32 usercount = 0;
1244   bool global_list = FALSE;
1245
1246   COMMAND_CHECK_STATUS;
1247
1248   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1249   channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1250   if (!channel_id)
1251     goto out;
1252
1253   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1254   topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1255   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1256   if (tmp)
1257     SILC_GET32_MSB(usercount, tmp);
1258
1259   /* Add the channel entry if we do not have it already */
1260   channel = silc_idlist_find_channel_by_name(server->local_list, 
1261                                              name, &cache);
1262   if (!channel) {
1263     channel = silc_idlist_find_channel_by_name(server->global_list, 
1264                                                name, &cache);
1265     global_list = TRUE;
1266   }
1267   if (!channel) {
1268     /* If router did not find such channel in its lists then this must
1269        be bogus channel or some router in the net is buggy. */
1270     if (server->server_type != SILC_SERVER)
1271       goto out;
1272     
1273     channel = silc_idlist_add_channel(server->global_list, strdup(name),
1274                                       SILC_CHANNEL_MODE_NONE, channel_id, 
1275                                       server->router, NULL, NULL, 
1276                                       time(NULL) + 60);
1277     if (!channel)
1278       goto out;
1279     channel_id = NULL;
1280   } else {
1281     /* Found, update expiry */
1282     if (global_list && server->server_type == SILC_SERVER)
1283       cache->expire = time(NULL) + 60;
1284   }
1285
1286   channel->user_count = usercount;
1287
1288   if (topic) {
1289     silc_free(channel->topic);
1290     channel->topic = strdup(topic);
1291   }
1292
1293   /* Pending callbacks are not executed if this was an list entry */
1294   if (status != SILC_STATUS_OK &&
1295       status != SILC_STATUS_LIST_END) {
1296     silc_server_command_reply_free(cmd);
1297     return;
1298   }
1299
1300   /* Now purge all old entries from the global list, otherwise we'll might
1301      have non-existent entries for long periods of time in the cache. */
1302   silc_idcache_purge(server->global_list->channels);
1303
1304  out:
1305   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1306   silc_free(channel_id);
1307  err:
1308   silc_server_command_reply_free(cmd);
1309 }
1310
1311 SILC_SERVER_CMD_REPLY_FUNC(watch)
1312 {
1313   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1314   SilcStatus status, error;
1315
1316   COMMAND_CHECK_STATUS;
1317
1318  out:
1319   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1320  err:
1321   silc_server_command_reply_free(cmd);
1322 }