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