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