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