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