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