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