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