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