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