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