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