Cannot close itself.
[silc.git] / apps / silcd / command.c
1 /*
2
3   command.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
25 static int silc_server_is_registered(SilcServer server,
26                                      SilcSocketConnection sock,
27                                      SilcServerCommandContext cmd,
28                                      SilcCommand command);
29 static void 
30 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
31                                       SilcCommand command,
32                                       SilcStatus status,
33                                       SilcStatus error);
34 static void 
35 silc_server_command_send_status_data(SilcServerCommandContext cmd,
36                                      SilcCommand command,
37                                      SilcStatus status,
38                                      SilcStatus error,
39                                      SilcUInt32 arg_type,
40                                      const unsigned char *arg,
41                                      SilcUInt32 arg_len);
42 static bool
43 silc_server_command_pending_error_check(SilcServerCommandContext cmd,
44                                         SilcServerCommandReplyContext cmdr,
45                                         SilcCommand command);
46 SILC_TASK_CALLBACK(silc_server_command_process_timeout);
47
48 /* Server command list. */
49 SilcServerCommand silc_command_list[] =
50 {
51   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
52   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
53   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
54   SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
55   SILC_SERVER_CMD(list, LIST, SILC_CF_LAG_STRICT | SILC_CF_REG),
56   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
57   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
58   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
59   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG_STRICT | SILC_CF_REG | SILC_CF_OPER),
60   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
61   SILC_SERVER_CMD(stats, STATS, SILC_CF_LAG | SILC_CF_REG),
62   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
63   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
64   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG_STRICT | SILC_CF_REG),
65   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
66   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
67   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG_STRICT | SILC_CF_REG),
68   SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
69   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
70   SILC_SERVER_CMD(ban, BAN, SILC_CF_LAG_STRICT | SILC_CF_REG),
71   SILC_SERVER_CMD(detach, DETACH, SILC_CF_LAG_STRICT | SILC_CF_REG),
72   SILC_SERVER_CMD(watch, WATCH, SILC_CF_LAG | SILC_CF_REG),
73   SILC_SERVER_CMD(silcoper, SILCOPER,
74                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
75   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
76   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
77   SILC_SERVER_CMD(getkey, GETKEY, SILC_CF_LAG | SILC_CF_REG),
78
79   SILC_SERVER_CMD(connect, PRIV_CONNECT, 
80                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
81   SILC_SERVER_CMD(close, PRIV_CLOSE,
82                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
83   SILC_SERVER_CMD(shutdown, PRIV_SHUTDOWN, SILC_CF_LAG | SILC_CF_REG | 
84                   SILC_CF_OPER),
85
86   { NULL, 0 },
87 };
88
89 /* Performs several checks to the command. It first checks whether this
90    command was called as pending command callback. If it was then it checks
91    whether error occurred in the command reply where the pending command
92    callback was called. 
93
94    It also checks that the requested command includes correct amount
95    of arguments. */
96 #define SILC_SERVER_COMMAND_CHECK(command, context, min, max)                \
97 do {                                                                         \
98   SilcUInt32 _argc;                                                          \
99                                                                              \
100   if (silc_server_command_pending_error_check(cmd, context2, command)) {     \
101     SILC_LOG_DEBUG(("Error occurred in command reply, command not called")); \
102     silc_server_command_free(cmd);                                           \
103     return;                                                                  \
104   }                                                                          \
105                                                                              \
106   _argc = silc_argument_get_arg_num(cmd->args);                              \
107   if (_argc < min) {                                                         \
108     SILC_LOG_DEBUG(("Not enough parameters in command"));                    \
109     silc_server_command_send_status_reply(cmd, command,                      \
110                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, \
111                                           0);                                \
112     silc_server_command_free(cmd);                                           \
113     return;                                                                  \
114   }                                                                          \
115   if (_argc > max) {                                                         \
116     SILC_LOG_DEBUG(("Too many parameters in command"));                      \
117     silc_server_command_send_status_reply(cmd, command,                      \
118                                           SILC_STATUS_ERR_TOO_MANY_PARAMS,   \
119                                           0);                                \
120     silc_server_command_free(cmd);                                           \
121     return;                                                                  \
122   }                                                                          \
123 } while(0)
124
125 /* Returns TRUE if the connection is registered. Unregistered connections
126    usually cannot send commands hence the check. */
127
128 static int silc_server_is_registered(SilcServer server,
129                                      SilcSocketConnection sock,
130                                      SilcServerCommandContext cmd,
131                                      SilcCommand command)
132 {
133   SilcIDListData idata = (SilcIDListData)sock->user_data;
134
135   if (!idata)
136     return FALSE;
137
138   if (idata->status & SILC_IDLIST_STATUS_REGISTERED)
139     return TRUE;
140
141   silc_server_command_send_status_reply(cmd, command,
142                                         SILC_STATUS_ERR_NOT_REGISTERED, 0);
143   return FALSE;
144 }
145
146 /* Internal context to hold data when executed command with timeout. */
147 typedef struct {
148   SilcServerCommandContext ctx;
149   SilcServerCommand *cmd;
150 } *SilcServerCommandTimeout;
151
152 /* Timeout callback to process commands with timeout for client. Client's
153    commands are always executed with timeout. */
154
155 SILC_TASK_CALLBACK(silc_server_command_process_timeout)
156 {
157   SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
158   SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
159
160   if (!client) {
161     SILC_LOG_DEBUG(("Client entry is invalid"));
162     silc_server_command_free(timeout->ctx);
163     silc_free(timeout);
164   }
165
166   /* Update access time */
167   client->last_command = time(NULL);
168
169   if (!(timeout->cmd->flags & SILC_CF_REG)) {
170     SILC_LOG_DEBUG(("Calling %s command",
171                     silc_get_command_name(timeout->cmd->cmd)));
172     timeout->cmd->cb(timeout->ctx, NULL);
173   } else if (silc_server_is_registered(timeout->ctx->server, 
174                                        timeout->ctx->sock, 
175                                        timeout->ctx, 
176                                        timeout->cmd->cmd)) {
177     SILC_LOG_DEBUG(("Calling %s command",
178                     silc_get_command_name(timeout->cmd->cmd)));
179     timeout->cmd->cb(timeout->ctx, NULL);
180   } else {
181     SILC_LOG_DEBUG(("Client is not registered"));
182     silc_server_command_free(timeout->ctx);
183   }
184
185   silc_free(timeout);
186 }
187
188 /* Processes received command packet. */
189
190 void silc_server_command_process(SilcServer server,
191                                  SilcSocketConnection sock,
192                                  SilcPacketContext *packet)
193 {
194   SilcServerCommandContext ctx;
195   SilcServerCommand *cmd;
196   SilcCommand command;
197
198   /* Allocate command context. This must be free'd by the
199      command routine receiving it. */
200   ctx = silc_server_command_alloc();
201   ctx->server = server;
202   ctx->sock = silc_socket_dup(sock);
203   ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
204   
205   /* Parse the command payload in the packet */
206   ctx->payload = silc_command_payload_parse(packet->buffer->data,
207                                             packet->buffer->len);
208   if (!ctx->payload) {
209     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
210     silc_packet_context_free(packet);
211     silc_socket_free(ctx->sock);
212     silc_free(ctx);
213     return;
214   }
215   ctx->args = silc_command_get_args(ctx->payload);
216
217   /* Get the command */
218   command = silc_command_get(ctx->payload);
219   for (cmd = silc_command_list; cmd->cb; cmd++)
220     if (cmd->cmd == command)
221       break;
222
223   if (!cmd || !cmd->cb) {
224     SILC_LOG_DEBUG(("Unknown command %d", command));
225     silc_server_command_send_status_reply(ctx, command,
226                                           SILC_STATUS_ERR_UNKNOWN_COMMAND, 0);
227     silc_server_command_free(ctx);
228     return;
229   }
230
231   /* Execute client's commands always with timeout.  Normally they are
232      executed with zero (0) timeout but if client is sending command more
233      frequently than once in 2 seconds, then the timeout may be 0 to 2
234      seconds. */
235   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
236     SilcClientEntry client = (SilcClientEntry)sock->user_data;
237     SilcServerCommandTimeout timeout;
238     int fast;
239
240     if (!client) {
241       SILC_LOG_DEBUG(("Client entry is invalid"));
242       silc_server_command_free(ctx);
243     }
244
245     timeout = silc_calloc(1, sizeof(*timeout));
246     timeout->ctx = ctx;
247     timeout->cmd = cmd;
248
249     if (client->last_command && (time(NULL) - client->last_command) < 2) {
250       client->fast_command++;
251       fast = FALSE;
252     } else {
253       if (client->fast_command - 2 <= 0)
254         client->fast_command = 0;
255       else
256         client->fast_command -= 2;
257       fast = TRUE;
258     }
259
260     if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
261                   (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
262       silc_schedule_task_add(server->schedule, sock->sock, 
263                              silc_server_command_process_timeout, timeout,
264                              (client->fast_command < 3 ? 0 :
265                               2 - (time(NULL) - client->last_command)),
266                              (client->fast_command < 3 ? 200000 : 0),
267                              SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
268     else
269       silc_schedule_task_add(server->schedule, sock->sock, 
270                              silc_server_command_process_timeout, timeout,
271                              0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
272     return;
273   }
274
275   /* Execute for server */
276
277   if (!(cmd->flags & SILC_CF_REG)) {
278     SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
279     cmd->cb(ctx, NULL);
280   } else if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
281     SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
282     cmd->cb(ctx, NULL);
283   } else {
284     SILC_LOG_DEBUG(("Server is not registered"));
285     silc_server_command_free(ctx);
286   }
287 }
288
289 /* Allocate Command Context */
290
291 SilcServerCommandContext silc_server_command_alloc()
292 {
293   SilcServerCommandContext ctx = silc_calloc(1, sizeof(*ctx));
294   ctx->users++;
295   return ctx;
296 }
297
298 /* Free's the command context allocated before executing the command */
299
300 void silc_server_command_free(SilcServerCommandContext ctx)
301 {
302   ctx->users--;
303   SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
304                   ctx->users));
305   if (ctx->users < 1) {
306     if (ctx->payload)
307       silc_command_payload_free(ctx->payload);
308     if (ctx->packet)
309       silc_packet_context_free(ctx->packet);
310     if (ctx->sock)
311       silc_socket_free(ctx->sock); /* Decrease reference counter */
312     silc_free(ctx);
313   }
314 }
315
316 /* Duplicate Command Context by adding reference counter. The context won't
317    be free'd untill it hits zero. */
318
319 SilcServerCommandContext 
320 silc_server_command_dup(SilcServerCommandContext ctx)
321 {
322   ctx->users++;
323   SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
324                   ctx->users));
325   return ctx;
326 }
327
328 /* Add new pending command to be executed when reply to a command has been
329    received. The `reply_cmd' is the command that will call the `callback'
330    with `context' when reply has been received.  It can be SILC_COMMAND_NONE
331    to match any command with the `ident'.  If `ident' is non-zero
332    the `callback' will be executed when received reply with command
333    identifier `ident'. If there already exists pending command for the
334    specified command, ident, callback and context this function has no
335    effect. */
336
337 bool silc_server_command_pending(SilcServer server,
338                                  SilcCommand reply_cmd,
339                                  SilcUInt16 ident,
340                                  SilcCommandCb callback,
341                                  void *context)
342 {
343   SilcServerCommandPending *reply;
344
345   /* Check whether identical pending already exists for same command,
346      ident, callback and callback context. If it does then it would be
347      error to register it again. */
348   silc_dlist_start(server->pending_commands);
349   while ((reply = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
350     if (reply->reply_cmd == reply_cmd && reply->ident == ident &&
351         reply->callback == callback && reply->context == context)
352       return FALSE;
353   }
354
355   reply = silc_calloc(1, sizeof(*reply));
356   reply->reply_cmd = reply_cmd;
357   reply->ident = ident;
358   reply->context = context;
359   reply->callback = callback;
360   silc_dlist_add(server->pending_commands, reply);
361
362   return TRUE;
363 }
364
365 /* Deletes pending command by reply command type. */
366
367 void silc_server_command_pending_del(SilcServer server,
368                                      SilcCommand reply_cmd,
369                                      SilcUInt16 ident)
370 {
371   SilcServerCommandPending *r;
372
373   silc_dlist_start(server->pending_commands);
374   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
375     if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
376                                        r->reply_check))
377         && r->ident == ident) {
378       silc_dlist_del(server->pending_commands, r);
379       silc_free(r);
380     }
381   }
382 }
383
384 /* Checks for pending commands and marks callbacks to be called from
385    the command reply function. Returns TRUE if there were pending command. */
386
387 SilcServerCommandPendingCallbacks
388 silc_server_command_pending_check(SilcServer server,
389                                   SilcServerCommandReplyContext ctx,
390                                   SilcCommand command, 
391                                   SilcUInt16 ident,
392                                   SilcUInt32 *callbacks_count)
393 {
394   SilcServerCommandPending *r;
395   SilcServerCommandPendingCallbacks callbacks = NULL;
396   int i = 0;
397
398   silc_dlist_start(server->pending_commands);
399   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
400     if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
401         && r->ident == ident) {
402       callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
403       callbacks[i].context = r->context;
404       callbacks[i].callback = r->callback;
405       r->reply_check = TRUE;
406       ctx->ident = ident;
407       i++;
408     }
409   }
410
411   *callbacks_count = i;
412   return callbacks;
413 }
414
415 /* Sends simple status message as command reply packet */
416
417 static void 
418 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
419                                       SilcCommand command,
420                                       SilcStatus status,
421                                       SilcStatus error)
422 {
423   SilcBuffer buffer;
424
425   SILC_LOG_DEBUG(("Sending command status %d", status));
426
427   buffer = 
428     silc_command_reply_payload_encode_va(command, status, error,
429                                          silc_command_get_ident(cmd->payload),
430                                          0);
431   silc_server_packet_send(cmd->server, cmd->sock,
432                           SILC_PACKET_COMMAND_REPLY, 0, 
433                           buffer->data, buffer->len, FALSE);
434   silc_buffer_free(buffer);
435 }
436
437 /* Sends command status reply with one extra argument. The argument
438    type must be sent as argument. */
439
440 static void 
441 silc_server_command_send_status_data(SilcServerCommandContext cmd,
442                                      SilcCommand command,
443                                      SilcStatus status,
444                                      SilcStatus error,
445                                      SilcUInt32 arg_type,
446                                      const unsigned char *arg,
447                                      SilcUInt32 arg_len)
448 {
449   SilcBuffer buffer;
450
451   SILC_LOG_DEBUG(("Sending command status %d", status));
452
453   buffer = 
454     silc_command_reply_payload_encode_va(command, status, 0,
455                                          silc_command_get_ident(cmd->payload),
456                                          1, arg_type, arg, arg_len);
457   silc_server_packet_send(cmd->server, cmd->sock,
458                           SILC_PACKET_COMMAND_REPLY, 0, 
459                           buffer->data, buffer->len, FALSE);
460   silc_buffer_free(buffer);
461 }
462
463 /* This function can be called to check whether in the command reply
464    an error occurred. This function has no effect if this is called
465    when the command function was not called as pending command callback. 
466    This returns TRUE if error had occurred. */
467
468 static bool
469 silc_server_command_pending_error_check(SilcServerCommandContext cmd,
470                                         SilcServerCommandReplyContext cmdr,
471                                         SilcCommand command)
472 {
473   if (!cmd->pending || !cmdr)
474     return FALSE;
475
476   if (!silc_command_get_status(cmdr->payload, NULL, NULL)) {
477     SilcBuffer buffer;
478
479     /* Send the same command reply payload */
480     silc_command_set_ident(cmdr->payload, 
481                            silc_command_get_ident(cmd->payload));
482     buffer = silc_command_payload_encode_payload(cmdr->payload);
483     silc_server_packet_send(cmd->server, cmd->sock,
484                             SILC_PACKET_COMMAND_REPLY, 0, 
485                             buffer->data, buffer->len, FALSE);
486     silc_buffer_free(buffer);
487     return TRUE;
488   }
489
490   return FALSE;
491 }
492
493 /******************************************************************************
494
495                               WHOIS Functions
496
497 ******************************************************************************/
498
499 typedef struct {
500   void *id;
501   SilcIdType id_type;
502   SilcUInt32 index;
503   SilcStatus error;
504 } *ResolveError;
505
506 #define ADD_ERROR(errptr, errptr_count, _id, _id_type, _index, _status) \
507 do {                                                                    \
508   errptr = silc_realloc(errptr, sizeof(*errptr) * (errptr_count + 1));  \
509   if (!errptr)                                                          \
510     return FALSE;                                                       \
511   errptr[errptr_count].id = _id;                                        \
512   errptr[errptr_count].id_type = _id_type;                              \
513   errptr[errptr_count].index = _index;                                  \
514   errptr[errptr_count].error = _status;                                 \
515   errptr_count++;                                                       \
516 } while(0)
517
518 static int
519 silc_server_command_whois_parse(SilcServerCommandContext cmd,
520                                 SilcClientID ***client_id,
521                                 SilcUInt32 *client_id_count,
522                                 char **nickname,
523                                 char **server_name,
524                                 int *count,
525                                 ResolveError *error_client,
526                                 SilcUInt32 *error_client_count)
527 {
528   unsigned char *tmp;
529   SilcUInt32 len;
530   SilcUInt32 argc = silc_argument_get_arg_num(cmd->args);
531   void *id;
532   int i, k;
533
534   /* If client ID is in the command it must be used instead of nickname */
535   tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
536   if (!tmp) {
537     /* No ID, get the nickname@server string and parse it. */
538     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
539     if (tmp) {
540       silc_parse_userfqdn(tmp, nickname, server_name);
541     } else {
542       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
543                                             SILC_STATUS_ERR_BAD_NICKNAME, 0);
544       return FALSE;
545     }
546   } else {
547     /* Command includes ID, we must use that.  Take all ID's from the 
548        command packet */
549     for (k = 0, i = 0; i < argc; i++) {
550       tmp = silc_argument_get_arg_type(cmd->args, i + 4, &len);
551       if (!tmp)
552         continue;
553       id = silc_id_payload_parse_id(tmp, len, NULL);
554       if (id) {
555         *client_id = silc_realloc(*client_id, sizeof(**client_id) *
556                                   (*client_id_count + 1));
557         (*client_id)[k] = id;
558         (*client_id_count)++;
559         k++;
560       } else {
561         ADD_ERROR((*error_client), (*error_client_count), NULL, 0, i + 4,
562                   SILC_STATUS_ERR_BAD_CLIENT_ID);
563       }
564     }
565   }
566
567   /* Get the max count of reply messages allowed */
568   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
569   if (tmp)
570     SILC_GET32_MSB(*count, tmp);
571   else
572     *count = 0;
573
574   return TRUE;
575 }
576
577 /* Resolve context used by both WHOIS and IDENTIFY commands */
578 typedef struct {
579   SilcServerEntry router;
580   SilcUInt16 ident;
581   unsigned char **res_argv;
582   SilcUInt32 *res_argv_lens;
583   SilcUInt32 *res_argv_types;
584   SilcUInt32 res_argc;
585 } *SilcServerResolveContext;
586
587 static bool
588 silc_server_command_whois_check(SilcServerCommandContext cmd,
589                                 SilcClientEntry *clients,
590                                 SilcUInt32 clients_count)
591 {
592   SilcServer server = cmd->server;
593   SilcClientEntry entry;
594   SilcServerResolveContext resolve = NULL, r = NULL;
595   SilcUInt32 resolve_count = 0;
596   int i, k;
597   bool no_res = TRUE;
598
599   SILC_LOG_DEBUG(("Start"));
600
601   for (i = 0; i < clients_count; i++) {
602     entry = clients[i];
603     if (!entry)
604       continue;
605
606     if ((entry->nickname && entry->username && entry->userinfo) ||
607         !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
608       if (!entry->router)
609         continue;
610
611       /* If we are normal server, and we've not resolved this client from
612          router and it is global client, we'll check whether it is on some
613          channel.  If not then we cannot be sure about its validity, and
614          we'll resolve it from router. */
615       if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
616           entry->connection || silc_hash_table_count(entry->channels))
617         continue;
618     }
619
620     /* We need to resolve this entry since it is not complete */
621
622     if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
623       /* The entry is being resolved (and we are not the resolver) so attach
624          to the command reply and we're done with this one. */
625       silc_server_command_pending(server, SILC_COMMAND_NONE, 
626                                   entry->resolve_cmd_ident,
627                                   silc_server_command_whois,
628                                   silc_server_command_dup(cmd));
629       no_res = FALSE;
630     } else {
631       if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
632         /* We've resolved this and it still is not ready.  We'll return
633            and are that this will be handled again after it is resolved. */
634         for (i = 0; i < resolve_count; i++) {
635           for (k = 0; k < r->res_argc; k++)
636             silc_free(r->res_argv[k]);
637           silc_free(r->res_argv);
638           silc_free(r->res_argv_lens);
639           silc_free(r->res_argv_types);
640         }
641         silc_free(resolve);
642         return FALSE;
643       } else {
644         /* We'll resolve this client */
645         SilcBuffer idp;
646
647         r = NULL;
648         for (k = 0; k < resolve_count; k++) {
649           if (resolve[k].router == entry->router) {
650             r = &resolve[k];
651             break;
652           }
653         }
654
655         if (!r) {
656           resolve = silc_realloc(resolve, sizeof(*resolve) * 
657                                  (resolve_count + 1));
658           r = &resolve[resolve_count];
659           memset(r, 0, sizeof(*r));
660           r->router = entry->router;
661           r->ident = ++server->cmd_ident;
662           resolve_count++;
663         }
664
665         r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
666                                    (r->res_argc + 1));
667         r->res_argv_lens = silc_realloc(r->res_argv_lens, 
668                                         sizeof(*r->res_argv_lens) *
669                                         (r->res_argc + 1));
670         r->res_argv_types = silc_realloc(r->res_argv_types, 
671                                          sizeof(*r->res_argv_types) *
672                                          (r->res_argc + 1));
673         idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
674         r->res_argv[r->res_argc] = silc_calloc(idp->len, 
675                                                sizeof(**r->res_argv));
676         memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
677         r->res_argv_lens[r->res_argc] = idp->len;
678         r->res_argv_types[r->res_argc] = r->res_argc + 4;
679         r->res_argc++;
680         silc_buffer_free(idp);
681
682         entry->resolve_cmd_ident = r->ident;
683         entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
684         entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
685       }
686     }
687   }
688
689   /* Do the resolving */
690   for (i = 0; i < resolve_count; i++) {
691     SilcBuffer res_cmd;
692
693     r = &resolve[i];
694
695     /* Send WHOIS request. We send WHOIS since we're doing the requesting
696        now anyway so make it a good one. */
697     res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
698                                           r->res_argc, r->res_argv, 
699                                           r->res_argv_lens,
700                                           r->res_argv_types, 
701                                           r->ident);
702     silc_server_packet_send(server, r->router->connection,
703                             SILC_PACKET_COMMAND, cmd->packet->flags,
704                             res_cmd->data, res_cmd->len, FALSE);
705
706     /* Reprocess this packet after received reply */
707     silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
708                                 r->ident,
709                                 silc_server_command_whois,
710                                 silc_server_command_dup(cmd));
711     cmd->pending = TRUE;
712
713     silc_buffer_free(res_cmd);
714     for (k = 0; k < r->res_argc; k++)
715       silc_free(r->res_argv[k]);
716     silc_free(r->res_argv);
717     silc_free(r->res_argv_lens);
718     silc_free(r->res_argv_types);
719     no_res = FALSE;
720   }
721   silc_free(resolve);
722
723   return no_res;
724 }
725
726 static void
727 silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
728                                      SilcClientEntry *clients,
729                                      SilcUInt32 clients_count, 
730                                      ResolveError errors,
731                                      SilcUInt32 errors_count,
732                                      int count, const char *nickname,
733                                      SilcClientID **client_ids)
734 {
735   SilcServer server = cmd->server;
736   char *tmp;
737   int i, k, valid_count = clients_count;
738   SilcUInt32 len;
739   SilcBuffer packet, idp, channels, umode_list = NULL;
740   SilcClientEntry entry;
741   SilcStatus status;
742   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
743   char nh[256], uh[256];
744   unsigned char idle[4], mode[4];
745   unsigned char *fingerprint, fempty[20];
746   SilcSocketConnection hsock;
747
748   if (nickname) {
749     /* Process only valid clients and ignore those that are not registered. 
750        This is checked with nickname only because when resolved client IDs
751        we check that they are registered earlier. */
752     valid_count = 0;
753     for (i = 0; i < clients_count; i++)
754       if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
755         valid_count++;
756       else
757         clients[i] = NULL;
758
759     if (!valid_count) {
760       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
761                                            SILC_STATUS_ERR_NO_SUCH_NICK, 0,
762                                            3, nickname, strlen(nickname));
763       return;
764     }
765   }
766
767   memset(fempty, 0, sizeof(fempty));
768
769   /* Start processing found clients. */
770   status = SILC_STATUS_OK;
771   if (valid_count > 1)
772     status = SILC_STATUS_LIST_START;
773
774   for (i = 0, k = 0; i < clients_count; i++) {
775     entry = clients[i];
776     if (!entry)
777       continue;
778
779     if (k >= 1)
780       status = SILC_STATUS_LIST_ITEM;
781     if (valid_count > 1 && k == valid_count - 1 && !errors_count)
782       status = SILC_STATUS_LIST_END;
783     if (count && k - 1 == count)
784       status = SILC_STATUS_LIST_END;
785
786     /* Send WHOIS reply */
787     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
788     tmp = silc_argument_get_first_arg(cmd->args, NULL);
789     
790     memset(uh, 0, sizeof(uh));
791     memset(nh, 0, sizeof(nh));
792     memset(idle, 0, sizeof(idle));
793     
794     strncat(nh, entry->nickname, strlen(entry->nickname));
795     if (!strchr(entry->nickname, '@')) {
796       strncat(nh, "@", 1);
797       if (entry->servername) {
798         strncat(nh, entry->servername, strlen(entry->servername));
799       } else {
800         len = entry->router ? strlen(entry->router->server_name) :
801           strlen(server->server_name);
802         strncat(nh, entry->router ? entry->router->server_name :
803                 server->server_name, len);
804       }
805     }
806       
807     strncat(uh, entry->username, strlen(entry->username));
808     if (!strchr(entry->username, '@') && entry->connection) {
809       strncat(uh, "@", 1);
810       hsock = (SilcSocketConnection)entry->connection;
811       len = strlen(hsock->hostname);
812       strncat(uh, hsock->hostname, len);
813     }
814
815     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
816       channels = silc_server_get_client_channel_list(server, entry, FALSE, 
817                                                      FALSE, &umode_list);
818     else
819       channels = silc_server_get_client_channel_list(server, entry, TRUE, 
820                                                      TRUE, &umode_list);
821
822     if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
823       fingerprint = entry->data.fingerprint;
824     else
825       fingerprint = NULL;
826       
827     SILC_PUT32_MSB(entry->mode, mode);
828     if (entry->connection)
829       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
830
831     packet = 
832       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
833                                            status, 0, ident, 9, 
834                                            2, idp->data, idp->len,
835                                            3, nh, strlen(nh),
836                                            4, uh, strlen(uh),
837                                            5, entry->userinfo, 
838                                            strlen(entry->userinfo),
839                                            6, channels ? channels->data : NULL,
840                                            channels ? channels->len : 0,
841                                            7, mode, 4,
842                                            8, idle, 4,
843                                            9, fingerprint,
844                                            fingerprint ? 20 : 0,
845                                            10, umode_list ? umode_list->data :
846                                            NULL, umode_list ? umode_list->len :
847                                            0);
848
849     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
850                             0, packet->data, packet->len, FALSE);
851     
852     silc_buffer_free(packet);
853     silc_buffer_free(idp);
854     if (channels)
855       silc_buffer_free(channels);
856     if (umode_list) {
857       silc_buffer_free(umode_list);
858       umode_list = NULL;
859     }
860
861     if (status == SILC_STATUS_LIST_END)
862       break;
863     k++;
864   }
865
866   /* Send error replies */
867   if (status == SILC_STATUS_OK && errors_count > 1)
868     status = SILC_STATUS_LIST_START;
869
870   idp = NULL;
871   for (i = 0, k = 0; i < errors_count; i++) {
872     if (errors[i].id) {
873       idp = silc_id_payload_encode(errors[i].id, SILC_ID_CLIENT);
874       tmp = idp->data;
875       len = idp->len;
876     } else {
877       tmp = silc_argument_get_arg_type(cmd->args, errors[i].index, &len);
878     }
879       
880     if (k >= 1)
881       status = SILC_STATUS_LIST_ITEM;
882     if (errors_count > 1 && k == errors_count - 1)
883       status = SILC_STATUS_LIST_END;
884     if (count && k - 1 == count)
885       status = SILC_STATUS_LIST_END;
886       
887     /* Send error */
888     silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
889                                          (status == SILC_STATUS_OK ?
890                                           errors[i].error : status),
891                                          (status == SILC_STATUS_OK ?
892                                           0 : errors[i].error),
893                                          2, tmp, len);
894     silc_buffer_free(idp);
895     idp = NULL;
896       
897     if (status == SILC_STATUS_LIST_END)
898       break;
899     k++;
900   }
901 }
902
903 static void 
904 silc_server_command_whois_send_router(SilcServerCommandContext cmd)
905 {
906   SilcServer server = cmd->server;
907   SilcBuffer tmpbuf;
908   SilcUInt16 old_ident;
909
910   old_ident = silc_command_get_ident(cmd->payload);
911   silc_command_set_ident(cmd->payload, ++server->cmd_ident);
912   tmpbuf = silc_command_payload_encode_payload(cmd->payload);
913
914   /* Send WHOIS command to our router */
915   silc_server_packet_send(server, (SilcSocketConnection)
916                           SILC_PRIMARY_ROUTE(server),
917                           SILC_PACKET_COMMAND, cmd->packet->flags,
918                           tmpbuf->data, tmpbuf->len, TRUE);
919
920   /* Reprocess this packet after received reply from router */
921   silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
922                               silc_command_get_ident(cmd->payload),
923                               silc_server_command_whois,
924                               silc_server_command_dup(cmd));
925   cmd->pending = TRUE;
926   silc_command_set_ident(cmd->payload, old_ident);
927   silc_buffer_free(tmpbuf);
928 }
929
930 static int
931 silc_server_command_whois_process(SilcServerCommandContext cmd)
932 {
933   SilcServer server = cmd->server;
934   char *nick = NULL, *server_name = NULL;
935   int count = 0;
936   SilcClientEntry *clients = NULL, entry;
937   SilcClientID **client_id = NULL;
938   SilcUInt32 client_id_count = 0, clients_count = 0, error_client_count = 0;
939   ResolveError error_client = NULL;
940   int i, ret = 0;
941   bool check_global = FALSE;
942
943   /* Parse the whois request */
944   if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
945                                        &nick, &server_name, &count,
946                                        &error_client, &error_client_count))
947     return 0;
948
949   /* Send the WHOIS request to the router only if it included nickname.
950      Since nicknames can be expanded into many clients we need to send it
951      to router.  If the WHOIS included only client ID's we will check them
952      first locally since we just might have them. */
953   if (nick && !client_id_count && cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
954       server->server_type == SILC_SERVER && !cmd->pending &&
955       !server->standalone) {
956     silc_server_command_whois_send_router(cmd);
957     ret = -1;
958     goto out;
959   }
960
961   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
962     check_global = TRUE;
963   else if (server->server_type != SILC_SERVER)
964     check_global = TRUE;
965
966   /* Get all clients matching that ID or nickname from local list */
967   if (client_id_count) {
968     /* Check all Client ID's received in the command packet */
969     for (i = 0; i < client_id_count; i++) {
970       entry = silc_idlist_find_client_by_id(server->local_list, 
971                                             client_id[i], TRUE, NULL);
972       if (!entry && check_global)
973         entry = silc_idlist_find_client_by_id(server->global_list, 
974                                               client_id[i], TRUE, NULL);
975       if (entry) {
976         clients = silc_realloc(clients, sizeof(*clients) * 
977                                (clients_count + 1));
978         clients[clients_count++] = entry;
979       } else {
980         /* If we are normal server and did not send the request first to router
981            do it now, since we do not have the Client ID information. */
982         if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
983             server->server_type == SILC_SERVER && !cmd->pending && 
984             !server->standalone) {
985           silc_server_command_whois_send_router(cmd);
986           ret = -1;
987           goto out;
988         }
989
990         ADD_ERROR(error_client, error_client_count, client_id[i], 
991                   SILC_ID_CLIENT, 0, SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
992       }
993     }
994   } else if (nick) {
995     /* Find by nickname */
996     if (!silc_idlist_get_clients_by_hash(server->local_list, 
997                                          nick, server->md5hash,
998                                          &clients, &clients_count))
999       silc_idlist_get_clients_by_nickname(server->local_list, 
1000                                           nick, server_name,
1001                                           &clients, &clients_count);
1002     if (check_global) {
1003       if (!silc_idlist_get_clients_by_hash(server->global_list, 
1004                                            nick, server->md5hash,
1005                                            &clients, &clients_count))
1006         silc_idlist_get_clients_by_nickname(server->global_list, 
1007                                             nick, server_name,
1008                                             &clients, &clients_count);
1009     }
1010   }
1011   
1012   if (!clients && (client_id_count || nick)) {
1013     /* If we are normal server and did not send the request first to router
1014        do it now, since we do not have the information. */
1015     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
1016         server->server_type == SILC_SERVER && !cmd->pending && 
1017         !server->standalone) {
1018       silc_server_command_whois_send_router(cmd);
1019       ret = -1;
1020       goto out;
1021     }
1022
1023     /* Such client(s) really does not exist in the SILC network. */
1024     if (!client_id_count)
1025       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
1026                                            SILC_STATUS_ERR_NO_SUCH_NICK, 0,
1027                                            3, nick, strlen(nick));
1028     else
1029       silc_server_command_whois_send_reply(cmd, NULL, 0,
1030                                            error_client, error_client_count,
1031                                            0, NULL, NULL);
1032     goto out;
1033   }
1034
1035   /* Router always finds the client entry if it exists in the SILC network.
1036      However, it might be incomplete entry and does not include all the
1037      mandatory fields that WHOIS command reply requires. Check for these and
1038      make query from the server who owns the client if some fields are 
1039      missing. */
1040   if (!silc_server_command_whois_check(cmd, clients, clients_count)) {
1041     ret = -1;
1042     goto out;
1043   }
1044
1045   /* Send the command reply */
1046   silc_server_command_whois_send_reply(cmd, clients, clients_count,
1047                                        error_client, error_client_count,
1048                                        count, nick, client_id);
1049
1050  out:
1051   if (client_id_count) {
1052     for (i = 0; i < client_id_count; i++)
1053       silc_free(client_id[i]);
1054     silc_free(client_id);
1055   }
1056   silc_free(clients);
1057   silc_free(error_client);
1058   silc_free(nick);
1059   silc_free(server_name);
1060
1061   return ret;
1062 }
1063
1064 /* Server side of command WHOIS. Processes user's query and sends found 
1065    results as command replies back to the client. */
1066
1067 SILC_SERVER_CMD_FUNC(whois)
1068 {
1069   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1070   int ret = 0;
1071
1072   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 3328);
1073
1074   ret = silc_server_command_whois_process(cmd);
1075   silc_server_command_free(cmd);
1076 }
1077
1078 /******************************************************************************
1079
1080                               WHOWAS Functions
1081
1082 ******************************************************************************/
1083
1084 static int
1085 silc_server_command_whowas_parse(SilcServerCommandContext cmd,
1086                                  char **nickname,
1087                                  char **server_name,
1088                                  int *count)
1089 {
1090   unsigned char *tmp;
1091   SilcUInt32 len;
1092
1093   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1094   if (!tmp) {
1095     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOWAS,
1096                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 
1097                                           0);
1098     return FALSE;
1099   }
1100
1101   /* Get the nickname@server string and parse it. */
1102   silc_parse_userfqdn(tmp, nickname, server_name);
1103
1104   /* Get the max count of reply messages allowed */
1105   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1106   if (tmp)
1107     SILC_GET32_MSB(*count, tmp);
1108   else
1109     *count = 0;
1110
1111   return TRUE;
1112 }
1113
1114 static char
1115 silc_server_command_whowas_check(SilcServerCommandContext cmd,
1116                                  SilcClientEntry *clients,
1117                                  SilcUInt32 clients_count)
1118 {
1119   SilcServer server = cmd->server;
1120   int i;
1121   SilcClientEntry entry;
1122
1123   for (i = 0; i < clients_count; i++) {
1124     entry = clients[i];
1125
1126     if (!entry->nickname || !entry->username) {
1127       SilcBuffer tmpbuf;
1128       SilcUInt16 old_ident;
1129
1130       if (!entry->router)
1131         continue;
1132       
1133       old_ident = silc_command_get_ident(cmd->payload);
1134       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
1135       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
1136
1137       /* Send WHOWAS command */
1138       silc_server_packet_send(server, entry->router->connection,
1139                               SILC_PACKET_COMMAND, cmd->packet->flags,
1140                               tmpbuf->data, tmpbuf->len, TRUE);
1141       
1142       /* Reprocess this packet after received reply */
1143       silc_server_command_pending(server, SILC_COMMAND_WHOWAS, 
1144                                   silc_command_get_ident(cmd->payload),
1145                                   silc_server_command_whowas, 
1146                                   silc_server_command_dup(cmd));
1147       cmd->pending = TRUE;
1148       silc_command_set_ident(cmd->payload, old_ident);
1149
1150       silc_buffer_free(tmpbuf);
1151       return FALSE;
1152     }
1153   }
1154
1155   return TRUE;
1156 }
1157
1158 static void
1159 silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
1160                                       SilcClientEntry *clients,
1161                                       SilcUInt32 clients_count)
1162 {
1163   SilcServer server = cmd->server;
1164   char *tmp;
1165   int i, k, count = 0, len;
1166   SilcBuffer packet, idp;
1167   SilcClientEntry entry = NULL;
1168   SilcStatus status;
1169   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1170   char nh[256], uh[256];
1171   int valid_count;
1172
1173   status = SILC_STATUS_OK;
1174
1175   /* Process only entries that are not registered anymore. */
1176   valid_count = 0;
1177   for (i = 0; i < clients_count; i++) {
1178     if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
1179       clients[i] = NULL;
1180     else
1181       valid_count++;
1182   }
1183
1184   if (!valid_count) {
1185     /* No valid entries found at all, just send error */
1186     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1187     silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
1188                                          SILC_STATUS_ERR_NO_SUCH_NICK, 0,
1189                                          3, tmp, tmp ? strlen(tmp) : 0);
1190     return;
1191   }
1192
1193   if (valid_count > 1)
1194     status = SILC_STATUS_LIST_START;
1195
1196   for (i = 0, k = 0; i < clients_count; i++) {
1197     entry = clients[i];
1198     if (!entry)
1199       continue;
1200
1201     if (k >= 1)
1202       status = SILC_STATUS_LIST_ITEM;
1203     if (valid_count > 1 && k == valid_count - 1)
1204       status = SILC_STATUS_LIST_END;
1205     if (count && k - 1 == count)
1206       status = SILC_STATUS_LIST_END;
1207
1208     /* Send WHOWAS reply */
1209     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1210     tmp = silc_argument_get_first_arg(cmd->args, NULL);
1211     memset(uh, 0, sizeof(uh));
1212     memset(nh, 0, sizeof(nh));
1213
1214     strncat(nh, entry->nickname, strlen(entry->nickname));
1215     if (!strchr(entry->nickname, '@')) {
1216       strncat(nh, "@", 1);
1217       if (entry->servername) {
1218         strncat(nh, entry->servername, strlen(entry->servername));
1219       } else {
1220         len = entry->router ? strlen(entry->router->server_name) :
1221           strlen(server->server_name);
1222         strncat(nh, entry->router ? entry->router->server_name :
1223                 server->server_name, len);
1224       }
1225     }
1226       
1227     strncat(uh, entry->username, strlen(entry->username));
1228     if (!strchr(entry->username, '@')) {
1229       strncat(uh, "@", 1);
1230       strcat(uh, "*private*");
1231     }
1232       
1233     packet = 
1234       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
1235                                            status, 0, ident, 4, 
1236                                            2, idp->data, idp->len,
1237                                            3, nh, strlen(nh),
1238                                            4, uh, strlen(uh),
1239                                            5, entry->userinfo, 
1240                                            entry->userinfo ? 
1241                                            strlen(entry->userinfo) : 0);
1242     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1243                             0, packet->data, packet->len, FALSE);
1244     
1245     silc_buffer_free(packet);
1246     silc_buffer_free(idp);
1247
1248     if (status == SILC_STATUS_LIST_END)
1249       break;
1250     k++;
1251   }
1252 }
1253
1254 static int
1255 silc_server_command_whowas_process(SilcServerCommandContext cmd)
1256 {
1257   SilcServer server = cmd->server;
1258   char *nick = NULL, *server_name = NULL;
1259   int count = 0;
1260   SilcClientEntry *clients = NULL;
1261   SilcUInt32 clients_count = 0;
1262   int ret = 0;
1263   bool check_global = FALSE;
1264
1265   /* Protocol dictates that we must always send the received WHOWAS request
1266      to our router if we are normal server, so let's do it now unless we
1267      are standalone. We will not send any replies to the client until we
1268      have received reply from the router. */
1269   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
1270       server->server_type == SILC_SERVER && !cmd->pending && 
1271       !server->standalone) {
1272     SilcBuffer tmpbuf;
1273     SilcUInt16 old_ident;
1274
1275     old_ident = silc_command_get_ident(cmd->payload);
1276     silc_command_set_ident(cmd->payload, ++server->cmd_ident);
1277     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
1278
1279     /* Send WHOWAS command to our router */
1280     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
1281                             SILC_PACKET_COMMAND, cmd->packet->flags,
1282                             tmpbuf->data, tmpbuf->len, TRUE);
1283
1284     /* Reprocess this packet after received reply from router */
1285     silc_server_command_pending(server, SILC_COMMAND_WHOWAS, 
1286                                 silc_command_get_ident(cmd->payload),
1287                                 silc_server_command_whowas,
1288                                 silc_server_command_dup(cmd));
1289     cmd->pending = TRUE;
1290     silc_command_set_ident(cmd->payload, old_ident);
1291
1292     silc_buffer_free(tmpbuf);
1293     ret = -1;
1294     goto out;
1295   }
1296
1297   /* We are ready to process the command request. Let's search for the
1298      requested client and send reply to the requesting client. */
1299
1300   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1301     check_global = TRUE;
1302   else if (server->server_type != SILC_SERVER)
1303     check_global = TRUE;
1304
1305   /* Parse the whowas request */
1306   if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
1307     return 0;
1308
1309   /* Get all clients matching that nickname from local list */
1310   if (!silc_idlist_get_clients_by_nickname(server->local_list, 
1311                                            nick, server_name,
1312                                            &clients, &clients_count))
1313     silc_idlist_get_clients_by_hash(server->local_list, 
1314                                     nick, server->md5hash,
1315                                     &clients, &clients_count);
1316   
1317   /* Check global list as well */
1318   if (check_global) {
1319     if (!silc_idlist_get_clients_by_nickname(server->global_list, 
1320                                              nick, server_name,
1321                                              &clients, &clients_count))
1322       silc_idlist_get_clients_by_hash(server->global_list, 
1323                                       nick, server->md5hash,
1324                                       &clients, &clients_count);
1325   }
1326   
1327   if (!clients) {
1328     /* Such a client really does not exist in the SILC network. */
1329     silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
1330                                          SILC_STATUS_ERR_NO_SUCH_NICK, 0,
1331                                          3, nick, strlen(nick));
1332     goto out;
1333   }
1334
1335   if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
1336     ret = -1;
1337     goto out;
1338   }
1339
1340   /* Send the command reply to the client */
1341   silc_server_command_whowas_send_reply(cmd, clients, clients_count);
1342
1343  out:
1344   silc_free(clients);
1345   silc_free(nick);
1346   silc_free(server_name);
1347   return ret;
1348 }
1349
1350 /* Server side of command WHOWAS. */
1351
1352 SILC_SERVER_CMD_FUNC(whowas)
1353 {
1354   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1355   int ret = 0;
1356
1357   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
1358
1359   ret = silc_server_command_whowas_process(cmd);
1360   silc_server_command_free(cmd);
1361 }
1362
1363 /******************************************************************************
1364
1365                               IDENTIFY Functions
1366
1367 ******************************************************************************/
1368
1369 static void 
1370 silc_server_command_identify_send_router(SilcServerCommandContext cmd)
1371 {
1372   SilcServer server = cmd->server;
1373   SilcBuffer tmpbuf;
1374   SilcUInt16 old_ident;
1375
1376   old_ident = silc_command_get_ident(cmd->payload);
1377   silc_command_set_ident(cmd->payload, ++server->cmd_ident);
1378   tmpbuf = silc_command_payload_encode_payload(cmd->payload);
1379
1380   /* Send IDENTIFY command to our router */
1381   silc_server_packet_send(server, (SilcSocketConnection)
1382                           SILC_PRIMARY_ROUTE(server),
1383                           SILC_PACKET_COMMAND, cmd->packet->flags,
1384                           tmpbuf->data, tmpbuf->len, TRUE);
1385
1386   /* Reprocess this packet after received reply from router */
1387   silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, 
1388                               silc_command_get_ident(cmd->payload),
1389                               silc_server_command_identify,
1390                               silc_server_command_dup(cmd));
1391   cmd->pending = TRUE;
1392   silc_command_set_ident(cmd->payload, old_ident);
1393   silc_buffer_free(tmpbuf);
1394 }
1395
1396 static int
1397 silc_server_command_identify_parse(SilcServerCommandContext cmd,
1398                                    SilcClientEntry **clients,
1399                                    SilcUInt32 *clients_count,
1400                                    SilcServerEntry **servers,
1401                                    SilcUInt32 *servers_count,
1402                                    SilcChannelEntry **channels,
1403                                    SilcUInt32 *channels_count,
1404                                    SilcUInt32 *count,
1405                                    ResolveError *error_id,
1406                                    SilcUInt32 *error_id_count)
1407 {
1408   SilcServer server = cmd->server;
1409   unsigned char *tmp;
1410   SilcUInt32 len;
1411   SilcUInt32 argc = silc_argument_get_arg_num(cmd->args);
1412   SilcIDPayload idp;
1413   bool check_global = FALSE;
1414   void *entry;
1415   int i;
1416
1417   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1418     check_global = TRUE;
1419   else if (server->server_type != SILC_SERVER)
1420     check_global = TRUE;
1421
1422   /* If ID Payload is in the command it must be used instead of names */
1423   tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
1424   if (!tmp) {
1425     /* No ID, get the names. */
1426
1427     /* If we are normal server and have not resolved information from
1428        router yet, do so now. */
1429     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
1430         server->server_type == SILC_SERVER && !cmd->pending && 
1431         !server->standalone) {
1432       silc_server_command_identify_send_router(cmd);
1433       return -1;
1434     }
1435
1436     /* Try to get nickname@server. */
1437     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1438     if (tmp) {
1439       char *nick = NULL;
1440       char *nick_server = NULL;
1441
1442       silc_parse_userfqdn(tmp, &nick, &nick_server);
1443
1444       if (!silc_idlist_get_clients_by_hash(server->local_list, 
1445                                            nick, server->md5hash,
1446                                            clients, clients_count))
1447         silc_idlist_get_clients_by_nickname(server->local_list, 
1448                                             nick, nick_server,
1449                                             clients, clients_count);
1450       if (check_global) {
1451         if (!silc_idlist_get_clients_by_hash(server->global_list, 
1452                                              nick, server->md5hash,
1453                                              clients, clients_count))
1454           silc_idlist_get_clients_by_nickname(server->global_list, 
1455                                               nick, nick_server,
1456                                               clients, clients_count);
1457       }
1458
1459       silc_free(nick);
1460       silc_free(nick_server);
1461
1462       if (!(*clients)) {
1463         /* the nickname does not exist, send error reply */
1464         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1465                                              SILC_STATUS_ERR_NO_SUCH_NICK, 0,
1466                                              3, tmp, strlen(tmp));
1467         return 0;
1468       }
1469     }
1470
1471     /* Try to get server name */
1472     tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1473     if (tmp) {
1474       entry = silc_idlist_find_server_by_name(server->local_list,
1475                                               tmp, TRUE, NULL);
1476       if (!entry && check_global)
1477         entry = silc_idlist_find_server_by_name(server->global_list,
1478                                                 tmp, TRUE, NULL);
1479       if (entry) {
1480         *servers = silc_realloc(*servers, sizeof(**servers) * 
1481                                 (*servers_count + 1));
1482         (*servers)[(*servers_count)++] = entry;
1483       }
1484
1485       if (!(*servers)) {
1486         /* the server does not exist, send error reply */
1487         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1488                                              SILC_STATUS_ERR_NO_SUCH_SERVER,
1489                                              0, 3, tmp, strlen(tmp));
1490         return 0;
1491       }
1492     }
1493
1494     /* Try to get channel name */
1495     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1496     if (tmp) {
1497       entry = silc_idlist_find_channel_by_name(server->local_list,
1498                                                tmp, NULL);
1499       if (!entry && check_global)
1500         entry = silc_idlist_find_channel_by_name(server->global_list,
1501                                                  tmp, NULL);
1502       if (entry) {
1503         *channels = silc_realloc(*channels, sizeof(**channels) * 
1504                                  (*channels_count + 1));
1505         (*channels)[(*channels_count)++] = entry;
1506       }
1507
1508       if (!(*channels)) {
1509         /* The channel does not exist, send error reply */
1510         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1511                                              SILC_STATUS_ERR_NO_SUCH_CHANNEL,
1512                                              0, 3, tmp, strlen(tmp));
1513         return 0;
1514       }
1515     }
1516
1517     if (!(*clients) && !(*servers) && !(*channels)) {
1518       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
1519                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
1520                                             0);
1521       return 0;
1522     }
1523   } else {
1524     /* Command includes ID, we must use that.  Also check whether the command
1525        has more than one ID set - take them all. */
1526
1527     /* Take all ID's from the command packet */
1528     for (i = 0; i < argc; i++) {
1529       void *id;
1530
1531       tmp = silc_argument_get_arg_type(cmd->args, i + 5, &len);
1532       if (!tmp)
1533         continue;
1534       
1535       idp = silc_id_payload_parse(tmp, len);
1536       if (!idp)
1537         ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
1538                   SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1539
1540       id = silc_id_payload_get_id(idp);
1541       switch (silc_id_payload_get_type(idp)) {
1542         
1543       case SILC_ID_CLIENT:
1544         entry = silc_idlist_find_client_by_id(server->local_list, 
1545                                               id, TRUE, NULL);
1546         if (!entry && check_global)
1547           entry = silc_idlist_find_client_by_id(server->global_list, 
1548                                                 id, TRUE, NULL);
1549         if (entry) {
1550           *clients = silc_realloc(*clients, sizeof(**clients) * 
1551                                   (*clients_count + 1));
1552           (*clients)[(*clients_count)++] = (SilcClientEntry)entry;
1553         } else {
1554           /* If we are normal server and have not resolved information from
1555              router yet, do so now. */
1556           if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
1557               server->server_type == SILC_SERVER && !cmd->pending && 
1558               !server->standalone) {
1559             silc_server_command_identify_send_router(cmd);
1560             silc_free(*clients);
1561             silc_free(*servers);
1562             silc_free(*channels);
1563             silc_free(*error_id);
1564             return -1;
1565           }
1566
1567           ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
1568                     SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
1569         }
1570
1571         break;
1572         
1573       case SILC_ID_SERVER:
1574         entry = silc_idlist_find_server_by_id(server->local_list, 
1575                                               id, TRUE, NULL);
1576         if (!entry && check_global)
1577           entry = silc_idlist_find_server_by_id(server->global_list, 
1578                                                 id, TRUE, NULL);
1579         if (entry) {
1580           *servers = silc_realloc(*servers, sizeof(**servers) * 
1581                                   (*servers_count + 1));
1582           (*servers)[(*servers_count)++] = (SilcServerEntry)entry;
1583         } else {
1584           /* If we are normal server and have not resolved information from
1585              router yet, do so now. */
1586           if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
1587               server->server_type == SILC_SERVER && !cmd->pending && 
1588               !server->standalone) {
1589             silc_server_command_identify_send_router(cmd);
1590             silc_free(*clients);
1591             silc_free(*servers);
1592             silc_free(*channels);
1593             silc_free(*error_id);
1594             return -1;
1595           }
1596
1597           ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
1598                     SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
1599         }
1600         break;
1601         
1602       case SILC_ID_CHANNEL:
1603         entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
1604         if (!entry && check_global)
1605           entry = silc_idlist_find_channel_by_id(server->global_list, id,
1606                                                  NULL);
1607         if (entry) {
1608           *channels = silc_realloc(*channels, sizeof(**channels) * 
1609                                    (*channels_count + 1));
1610           (*channels)[(*channels_count)++] = (SilcChannelEntry)entry;
1611         } else {
1612           /* If we are normal server and have not resolved information from
1613              router yet, do so now. */
1614           if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
1615               server->server_type == SILC_SERVER && !cmd->pending && 
1616               !server->standalone) {
1617             silc_server_command_identify_send_router(cmd);
1618             silc_free(*clients);
1619             silc_free(*servers);
1620             silc_free(*channels);
1621             silc_free(*error_id);
1622             return -1;
1623           }
1624
1625           ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
1626                     SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
1627         }
1628         break;
1629       }
1630
1631       silc_id_payload_free(idp);
1632       silc_free(id);
1633     }
1634   }
1635
1636   /* Get the max count of reply messages allowed */
1637   tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
1638   if (tmp)
1639     SILC_GET32_MSB(*count, tmp);
1640   else
1641     *count = 0;
1642
1643   return 1;
1644 }
1645
1646 /* Checks that all mandatory fields in client entry are present. If not
1647    then send WHOIS request to the server who owns the client. We use
1648    WHOIS because we want to get as much information as possible at once. */
1649
1650 static bool
1651 silc_server_command_identify_check_client(SilcServerCommandContext cmd,
1652                                           SilcClientEntry *clients,
1653                                           SilcUInt32 clients_count)
1654 {
1655   SilcServer server = cmd->server;
1656   SilcClientEntry entry;
1657   SilcServerResolveContext resolve = NULL, r = NULL;
1658   SilcUInt32 resolve_count = 0;
1659   int i, k;
1660   bool no_res = TRUE;
1661
1662   for (i = 0; i < clients_count; i++) {
1663     entry = clients[i];
1664     if (!entry)
1665       continue;
1666
1667     if (entry->nickname || 
1668         !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1669       if (!entry->router)
1670         continue;
1671
1672       /* If we are normal server, and we've not resolved this client from
1673          router and it is global client, we'll check whether it is on some
1674          channel.  If not then we cannot be sure about its validity, and
1675          we'll resolve it from router. */
1676       if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
1677           entry->connection || silc_hash_table_count(entry->channels))
1678         continue;
1679     }
1680
1681     /* We need to resolve this entry since it is not complete */
1682
1683     if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1684       /* The entry is being resolved (and we are not the resolver) so attach
1685          to the command reply and we're done with this one. */
1686       silc_server_command_pending(server, SILC_COMMAND_NONE, 
1687                                   entry->resolve_cmd_ident,
1688                                   silc_server_command_identify,
1689                                   silc_server_command_dup(cmd));
1690       no_res = FALSE;
1691     } else {
1692       if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1693         /* We've resolved this and it still is not ready.  We'll return
1694            and are that this will be handled again after it is resolved. */
1695         for (i = 0; i < resolve_count; i++) {
1696           for (k = 0; k < r->res_argc; k++)
1697             silc_free(r->res_argv[k]);
1698           silc_free(r->res_argv);
1699           silc_free(r->res_argv_lens);
1700           silc_free(r->res_argv_types);
1701         }
1702         silc_free(resolve);
1703         return FALSE;
1704       } else {
1705         /* We'll resolve this client */
1706         SilcBuffer idp;
1707
1708         r = NULL;
1709         for (k = 0; k < resolve_count; k++) {
1710           if (resolve[k].router == entry->router) {
1711             r = &resolve[k];
1712             break;
1713           }
1714         }
1715
1716         if (!r) {
1717           resolve = silc_realloc(resolve, sizeof(*resolve) * 
1718                                  (resolve_count + 1));
1719           r = &resolve[resolve_count];
1720           memset(r, 0, sizeof(*r));
1721           r->router = entry->router;
1722           r->ident = ++server->cmd_ident;
1723           resolve_count++;
1724         }
1725
1726         r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
1727                                    (r->res_argc + 1));
1728         r->res_argv_lens = silc_realloc(r->res_argv_lens, 
1729                                         sizeof(*r->res_argv_lens) *
1730                                         (r->res_argc + 1));
1731         r->res_argv_types = silc_realloc(r->res_argv_types, 
1732                                          sizeof(*r->res_argv_types) *
1733                                          (r->res_argc + 1));
1734         idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1735         r->res_argv[r->res_argc] = silc_calloc(idp->len, 
1736                                                sizeof(**r->res_argv));
1737         memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
1738         r->res_argv_lens[r->res_argc] = idp->len;
1739         r->res_argv_types[r->res_argc] = r->res_argc + 4;
1740         r->res_argc++;
1741         silc_buffer_free(idp);
1742
1743         entry->resolve_cmd_ident = r->ident;
1744         entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1745         entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1746       }
1747     }
1748   }
1749
1750   /* Do the resolving */
1751   for (i = 0; i < resolve_count; i++) {
1752     SilcBuffer res_cmd;
1753
1754     r = &resolve[i];
1755
1756     /* Send WHOIS request. We send WHOIS since we're doing the requesting
1757        now anyway so make it a good one. */
1758     res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1759                                           r->res_argc, r->res_argv, 
1760                                           r->res_argv_lens,
1761                                           r->res_argv_types, 
1762                                           r->ident);
1763     silc_server_packet_send(server, r->router->connection,
1764                             SILC_PACKET_COMMAND, cmd->packet->flags,
1765                             res_cmd->data, res_cmd->len, FALSE);
1766
1767     /* Reprocess this packet after received reply */
1768     silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
1769                                 r->ident,
1770                                 silc_server_command_identify,
1771                                 silc_server_command_dup(cmd));
1772     cmd->pending = TRUE;
1773
1774     silc_buffer_free(res_cmd);
1775     for (k = 0; k < r->res_argc; k++)
1776       silc_free(r->res_argv[k]);
1777     silc_free(r->res_argv);
1778     silc_free(r->res_argv_lens);
1779     silc_free(r->res_argv_types);
1780     no_res = FALSE;
1781   }
1782   silc_free(resolve);
1783
1784   return no_res;
1785 }
1786
1787 static void
1788 silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
1789                                         SilcClientEntry *clients,
1790                                         SilcUInt32 clients_count,
1791                                         SilcServerEntry *servers,
1792                                         SilcUInt32 servers_count,
1793                                         SilcChannelEntry *channels,
1794                                         SilcUInt32 channels_count,
1795                                         ResolveError errors,
1796                                         SilcUInt32 errors_count,
1797                                         int count)
1798 {
1799   SilcServer server = cmd->server;
1800   int i, k, valid_count;
1801   SilcUInt32 len;
1802   SilcBuffer packet, idp;
1803   SilcStatus status;
1804   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1805   char nh[256], uh[256];
1806   SilcSocketConnection hsock;
1807   unsigned char *tmp;
1808
1809   status = SILC_STATUS_OK;
1810
1811   if (clients) {
1812     SilcClientEntry entry;
1813     valid_count = clients_count;
1814
1815     if (silc_argument_get_arg_type(cmd->args, 1, NULL)) {
1816       /* Process only valid clients and ignore those that are not registered. 
1817          This is checked with nickname only because when resolved client IDs
1818          we check that they are registered earlier. */
1819       valid_count = 0;
1820       for (i = 0; i < clients_count; i++) {
1821         if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
1822           valid_count++;
1823         else
1824           clients[i] = NULL;
1825       }
1826
1827       if (!valid_count) {
1828         /* No valid entries found at all, just send error */
1829         tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1830         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1831                                              SILC_STATUS_ERR_NO_SUCH_NICK, 0,
1832                                              3, tmp, tmp ? strlen(tmp) : 0);
1833         return;
1834       }
1835     }
1836
1837     /* Process all valid client entries and send command replies */
1838
1839     if (valid_count > 1)
1840       status = SILC_STATUS_LIST_START;
1841
1842     for (i = 0, k = 0; i < clients_count; i++) {
1843       entry = clients[i];
1844       if (!entry)
1845         continue;
1846
1847       if (k >= 1)
1848         status = SILC_STATUS_LIST_ITEM;
1849       if (valid_count > 1 && k == valid_count - 1 
1850           && !servers_count && !channels_count && !errors_count)
1851         status = SILC_STATUS_LIST_END;
1852       if (count && k - 1 == count)
1853         status = SILC_STATUS_LIST_END;
1854
1855       /* Send IDENTIFY reply */
1856
1857       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1858       memset(uh, 0, sizeof(uh));
1859       memset(nh, 0, sizeof(nh));
1860       strncat(nh, entry->nickname, strlen(entry->nickname));
1861       if (!strchr(entry->nickname, '@')) {
1862         strncat(nh, "@", 1);
1863         if (entry->servername) {
1864           strncat(nh, entry->servername, strlen(entry->servername));
1865         } else {
1866           len = entry->router ? strlen(entry->router->server_name) :
1867             strlen(server->server_name);
1868           strncat(nh, entry->router ? entry->router->server_name :
1869                   server->server_name, len);
1870         }
1871       }
1872
1873       if (!entry->username) {
1874         packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
1875                                                       status, 0, ident, 2,
1876                                                       2, idp->data, idp->len, 
1877                                                       3, nh, strlen(nh));
1878       } else {
1879         strncat(uh, entry->username, strlen(entry->username));
1880         if (!strchr(entry->username, '@') && entry->connection) {
1881           strncat(uh, "@", 1);
1882           hsock = (SilcSocketConnection)entry->connection;
1883           len = strlen(hsock->hostname);
1884           strncat(uh, hsock->hostname, len);
1885         }
1886         
1887         packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
1888                                                       status, 0, ident, 3,
1889                                                       2, idp->data, idp->len, 
1890                                                       3, nh, strlen(nh),
1891                                                       4, uh, strlen(uh));
1892       }
1893       
1894       silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1895                               0, packet->data, packet->len, FALSE);
1896       
1897       silc_buffer_free(packet);
1898       silc_buffer_free(idp);
1899       
1900       if (status == SILC_STATUS_LIST_END)
1901         break;
1902       k++;
1903     }
1904   }
1905
1906   if (servers) {
1907     SilcServerEntry entry;
1908
1909     if (status == SILC_STATUS_OK && servers_count > 1)
1910       status = SILC_STATUS_LIST_START;
1911
1912     for (i = 0, k = 0; i < servers_count; i++) {
1913       entry = servers[i];
1914       
1915       if (k >= 1)
1916         status = SILC_STATUS_LIST_ITEM;
1917       if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1918           !errors_count)
1919         status = SILC_STATUS_LIST_END;
1920       if (count && k - 1 == count)
1921         status = SILC_STATUS_LIST_END;
1922       
1923       /* Send IDENTIFY reply */
1924       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1925       packet = 
1926         silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
1927                                              status, 0, ident, 2,
1928                                              2, idp->data, idp->len, 
1929                                              3, entry->server_name, 
1930                                              entry->server_name ? 
1931                                              strlen(entry->server_name) : 0);
1932       silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1933                               0, packet->data, packet->len, FALSE);
1934       
1935       silc_buffer_free(packet);
1936       silc_buffer_free(idp);
1937       
1938       if (status == SILC_STATUS_LIST_END)
1939         break;
1940       k++;
1941     }
1942   }
1943
1944   if (channels) {
1945     SilcChannelEntry entry;
1946
1947     if (status == SILC_STATUS_OK && channels_count > 1)
1948       status = SILC_STATUS_LIST_START;
1949
1950     for (i = 0, k = 0; i < channels_count; i++) {
1951       entry = channels[i];
1952       
1953       if (k >= 1)
1954         status = SILC_STATUS_LIST_ITEM;
1955       if (channels_count > 1 && k == channels_count - 1 && !errors_count)
1956         status = SILC_STATUS_LIST_END;
1957       if (count && k - 1 == count)
1958         status = SILC_STATUS_LIST_END;
1959       
1960       /* Send IDENTIFY reply */
1961       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1962       packet = 
1963         silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
1964                                              status, 0, ident, 2,
1965                                              2, idp->data, idp->len, 
1966                                              3, entry->channel_name, 
1967                                              entry->channel_name ? 
1968                                              strlen(entry->channel_name): 0);
1969       silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1970                               0, packet->data, packet->len, FALSE);
1971       
1972       silc_buffer_free(packet);
1973       silc_buffer_free(idp);
1974       
1975       if (status == SILC_STATUS_LIST_END)
1976         break;
1977       k++;
1978     }
1979   }
1980
1981   /* Send error replies */
1982   if (errors) {
1983     if (status == SILC_STATUS_OK && errors_count > 1)
1984       status = SILC_STATUS_LIST_START;
1985
1986     idp = NULL;
1987     for (i = 0, k = 0; i < errors_count; i++) {
1988       if (errors[i].id) {
1989         idp = silc_id_payload_encode(errors[i].id, SILC_ID_CLIENT);
1990         tmp = idp->data;
1991         len = idp->len;
1992       } else {
1993         tmp = silc_argument_get_arg_type(cmd->args, errors[i].index, &len);
1994       }
1995       
1996       if (k >= 1)
1997         status = SILC_STATUS_LIST_ITEM;
1998       if (errors_count > 1 && k == errors_count - 1)
1999         status = SILC_STATUS_LIST_END;
2000       if (count && k - 1 == count)
2001         status = SILC_STATUS_LIST_END;
2002       
2003       /* Send error */
2004       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
2005                                            (status == SILC_STATUS_OK ?
2006                                             errors[i].error : status),
2007                                            (status == SILC_STATUS_OK ?
2008                                             0 : errors[i].error),
2009                                            2, tmp, len);
2010       silc_buffer_free(idp);
2011       idp = NULL;
2012       
2013       if (status == SILC_STATUS_LIST_END)
2014         break;
2015       k++;
2016     }
2017   }
2018 }
2019
2020 static int
2021 silc_server_command_identify_process(SilcServerCommandContext cmd)
2022 {
2023   SilcUInt32 count = 0;
2024   int ret = 0;
2025   SilcClientEntry *clients = NULL;
2026   SilcServerEntry *servers = NULL;
2027   SilcChannelEntry *channels = NULL;
2028   SilcUInt32 clients_count = 0, servers_count = 0, channels_count = 0;
2029   SilcUInt32 errors_count = 0;
2030   ResolveError errors = NULL;
2031
2032   /* Parse the IDENTIFY request */
2033   ret = silc_server_command_identify_parse(cmd,
2034                                            &clients, &clients_count,
2035                                            &servers, &servers_count,
2036                                            &channels, &channels_count,
2037                                            &count, &errors, &errors_count);
2038   if (ret < 1)
2039     return ret;
2040   ret = 0;
2041
2042   /* Check that all mandatory fields are present and request those data
2043      from the server who owns the client if necessary. */
2044   if (!silc_server_command_identify_check_client(cmd, clients, 
2045                                                  clients_count)) {
2046     ret = -1;
2047     goto out;
2048   }
2049
2050   /* Send the command reply to the client */
2051   silc_server_command_identify_send_reply(cmd, 
2052                                           clients, clients_count,
2053                                           servers, servers_count,
2054                                           channels, channels_count, 
2055                                           errors, errors_count,
2056                                           count);
2057
2058  out:
2059   silc_free(clients);
2060   silc_free(servers);
2061   silc_free(channels);
2062   silc_free(errors);
2063   return ret;
2064 }
2065
2066 SILC_SERVER_CMD_FUNC(identify)
2067 {
2068   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2069   int ret = 0;
2070
2071   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
2072
2073   ret = silc_server_command_identify_process(cmd);
2074   silc_server_command_free(cmd);
2075 }
2076
2077 /* Server side of command NICK. Sets nickname for user. Setting
2078    nickname causes generation of a new client ID for the client. The
2079    new client ID is sent to the client after changing the nickname. */
2080
2081 SILC_SERVER_CMD_FUNC(nick)
2082 {
2083   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2084   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2085   SilcServer server = cmd->server;
2086   SilcBuffer packet, nidp, oidp = NULL;
2087   SilcClientID *new_id;
2088   SilcUInt32 nick_len;
2089   char *nick;
2090   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
2091   int nickfail = 0;
2092
2093   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
2094     goto out;
2095
2096   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
2097
2098   /* Check nickname */
2099   nick = silc_argument_get_arg_type(cmd->args, 1, &nick_len);
2100   if (nick_len > 128)
2101     nick[128] = '\0';
2102   if (silc_server_name_bad_chars(nick, nick_len) == TRUE) {
2103     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
2104                                           SILC_STATUS_ERR_BAD_NICKNAME, 0);
2105     goto out;
2106   }
2107
2108   /* Check for same nickname */
2109   if (!strcmp(client->nickname, nick)) {
2110     nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2111     goto send_reply;
2112   }
2113
2114   /* Create new Client ID */
2115   while (!silc_id_create_client_id(cmd->server, cmd->server->id, 
2116                                    cmd->server->rng, 
2117                                    cmd->server->md5hash, nick,
2118                                    &new_id)) {
2119     nickfail++;
2120     if (nickfail > 9) {
2121       silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
2122                                             SILC_STATUS_ERR_BAD_NICKNAME, 0);
2123       goto out;
2124     }
2125     snprintf(&nick[strlen(nick) - 1], 1, "%d", nickfail);
2126   }
2127
2128   /* Send notify about nickname change to our router. We send the new
2129      ID and ask to replace it with the old one. If we are router the
2130      packet is broadcasted. Send NICK_CHANGE notify. */
2131   silc_server_send_notify_nick_change(server, SILC_PRIMARY_ROUTE(server),
2132                                       SILC_BROADCAST(server), client->id,
2133                                       new_id, nick);
2134
2135   /* Check if anyone is watching the old nickname */
2136   if (server->server_type == SILC_ROUTER)
2137     silc_server_check_watcher_list(server, client, nick,
2138                                    SILC_NOTIFY_TYPE_NICK_CHANGE);
2139
2140   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2141
2142   /* Remove old cache entry */
2143   silc_idcache_del_by_context(server->local_list->clients, client);
2144
2145   silc_free(client->id);
2146   client->id = new_id;
2147
2148   silc_free(client->nickname);
2149   client->nickname = strdup(nick);
2150
2151   /* Update client cache */
2152   silc_idcache_add(server->local_list->clients, client->nickname, 
2153                    client->id, (void *)client, 0, NULL);
2154
2155   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2156
2157   /* Send NICK_CHANGE notify to the client's channels */
2158   silc_server_send_notify_on_channels(server, NULL, client, 
2159                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
2160                                       oidp->data, oidp->len, 
2161                                       nidp->data, nidp->len,
2162                                       client->nickname, 
2163                                       strlen(client->nickname));
2164
2165   /* Check if anyone is watching the new nickname */
2166   if (server->server_type == SILC_ROUTER)
2167     silc_server_check_watcher_list(server, client, NULL,
2168                                    SILC_NOTIFY_TYPE_NICK_CHANGE);
2169
2170  send_reply:
2171   /* Send the new Client ID as reply command back to client */
2172   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
2173                                                 SILC_STATUS_OK, 0, ident, 2,
2174                                                 2, nidp->data, nidp->len,
2175                                                 3, nick, strlen(nick));
2176   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
2177                           0, packet->data, packet->len, FALSE);
2178
2179   silc_buffer_free(packet);
2180   silc_buffer_free(nidp);
2181   if (oidp)
2182     silc_buffer_free(oidp);
2183   
2184  out:
2185   silc_server_command_free(cmd);
2186 }
2187
2188 /* Sends the LIST command reply */
2189
2190 static void
2191 silc_server_command_list_send_reply(SilcServerCommandContext cmd,
2192                                     SilcChannelEntry *lch, 
2193                                     SilcUInt32 lch_count,
2194                                     SilcChannelEntry *gch,
2195                                     SilcUInt32 gch_count)
2196 {
2197   int i, k;
2198   SilcBuffer packet, idp;
2199   SilcChannelEntry entry;
2200   SilcStatus status;
2201   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
2202   char *topic;
2203   unsigned char usercount[4];
2204   SilcUInt32 users;
2205   int valid_lcount = 0, valid_rcount = 0;
2206
2207   for (i = 0; i < lch_count; i++) {
2208     if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
2209       lch[i] = NULL;
2210     else
2211       valid_lcount++;
2212   }
2213   for (i = 0; i < gch_count; i++) {
2214     if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
2215       gch[i] = NULL;
2216     else
2217       valid_rcount++;
2218   }
2219
2220   status = SILC_STATUS_OK;
2221   if ((lch_count + gch_count) > 1)
2222     status = SILC_STATUS_LIST_START;
2223
2224   /* Local list */
2225   for (i = 0, k = 0; i < lch_count; i++) {
2226     entry = lch[i];
2227     if (!entry)
2228       continue;
2229
2230     if (k >= 1)
2231       status = SILC_STATUS_LIST_ITEM;
2232     if (valid_lcount > 1 && k == valid_lcount - 1 && !valid_rcount)
2233       status = SILC_STATUS_LIST_END;
2234
2235     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
2236
2237     if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
2238       topic = "*private*";
2239       memset(usercount, 0, sizeof(usercount));
2240     } else {
2241       topic = entry->topic;
2242       users = silc_hash_table_count(entry->user_list);
2243       SILC_PUT32_MSB(users, usercount);
2244     }
2245
2246     /* Send the reply */
2247     packet = 
2248       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
2249                                            status, 0, ident, 4,
2250                                            2, idp->data, idp->len,
2251                                            3, entry->channel_name, 
2252                                            strlen(entry->channel_name),
2253                                            4, topic, topic ? strlen(topic) : 0,
2254                                            5, usercount, 4);
2255     silc_server_packet_send(cmd->server, cmd->sock, 
2256                             SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
2257                             packet->len, FALSE);
2258     silc_buffer_free(packet);
2259     silc_buffer_free(idp);
2260     k++;
2261   }
2262
2263   /* Global list */
2264   for (i = 0, k = 0; i < gch_count; i++) {
2265     entry = gch[i];
2266     if (!entry)
2267       continue;
2268
2269     if (k >= 1)
2270       status = SILC_STATUS_LIST_ITEM;
2271     if (valid_rcount > 1 && k == valid_rcount - 1)
2272       status = SILC_STATUS_LIST_END;
2273
2274     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
2275
2276     if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
2277       topic = "*private*";
2278       memset(usercount, 0, sizeof(usercount));
2279     } else {
2280       topic = entry->topic;
2281       users = entry->user_count;
2282       SILC_PUT32_MSB(users, usercount);
2283     }
2284
2285     /* Send the reply */
2286     packet = 
2287       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
2288                                            status, 0, ident, 4,
2289                                            2, idp->data, idp->len,
2290                                            3, entry->channel_name, 
2291                                            strlen(entry->channel_name),
2292                                            4, topic, topic ? strlen(topic) : 0,
2293                                            5, usercount, 4);
2294     silc_server_packet_send(cmd->server, cmd->sock, 
2295                             SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
2296                             packet->len, FALSE);
2297     silc_buffer_free(packet);
2298     silc_buffer_free(idp);
2299     k++;
2300   }
2301 }
2302
2303 /* Server side of LIST command. This lists the channel of the requested
2304    server. Secret channels are not listed. */
2305
2306 SILC_SERVER_CMD_FUNC(list)
2307 {
2308   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2309   SilcServer server = cmd->server;
2310   SilcChannelID *channel_id = NULL;
2311   unsigned char *tmp;
2312   SilcUInt32 tmp_len;
2313   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
2314   SilcUInt32 lch_count = 0, gch_count = 0;
2315
2316   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 1);
2317
2318   /* If we are normal server, send the command to router, since we
2319      want to know all channels in the network. */
2320   if (!cmd->pending && server->server_type == SILC_SERVER && 
2321       !server->standalone) {
2322     SilcBuffer tmpbuf;
2323     SilcUInt16 old_ident;
2324     
2325     old_ident = silc_command_get_ident(cmd->payload);
2326     silc_command_set_ident(cmd->payload, ++server->cmd_ident);
2327     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2328     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
2329                             SILC_PACKET_COMMAND, cmd->packet->flags,
2330                             tmpbuf->data, tmpbuf->len, TRUE);
2331
2332     /* Reprocess this packet after received reply from router */
2333     silc_server_command_pending(server, SILC_COMMAND_LIST, 
2334                                 silc_command_get_ident(cmd->payload),
2335                                 silc_server_command_list, 
2336                                 silc_server_command_dup(cmd));
2337     cmd->pending = TRUE;
2338     silc_command_set_ident(cmd->payload, old_ident);
2339     silc_buffer_free(tmpbuf);
2340     goto out;
2341   }
2342
2343   /* Get Channel ID */
2344   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2345   if (tmp) {
2346     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2347     if (!channel_id) {
2348       silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
2349                                             SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
2350       goto out;
2351     }
2352   }
2353
2354   /* Get the channels from local list */
2355   lchannels = silc_idlist_get_channels(server->local_list, channel_id,
2356                                        &lch_count);
2357   
2358   /* Get the channels from global list */
2359   gchannels = silc_idlist_get_channels(server->global_list, channel_id,
2360                                        &gch_count);
2361
2362   /* Send the reply */
2363   silc_server_command_list_send_reply(cmd, lchannels, lch_count, 
2364                                       gchannels, gch_count);
2365
2366   silc_free(lchannels);
2367   silc_free(gchannels);
2368
2369  out:
2370   silc_server_command_free(cmd);
2371 }
2372
2373 /* Server side of TOPIC command. Sets topic for channel and/or returns
2374    current topic to client. */
2375
2376 SILC_SERVER_CMD_FUNC(topic)
2377 {
2378   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2379   SilcServer server = cmd->server;
2380   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2381   SilcChannelID *channel_id;
2382   SilcChannelEntry channel;
2383   SilcChannelClientEntry chl;
2384   SilcBuffer packet, idp;
2385   unsigned char *tmp;
2386   SilcUInt32 argc, tmp_len;
2387   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
2388
2389   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
2390     goto out;
2391
2392   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_TOPIC, cmd, 1, 2);
2393
2394   argc = silc_argument_get_arg_num(cmd->args);
2395
2396   /* Get Channel ID */
2397   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2398   if (!tmp) {
2399     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2400                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
2401     goto out;
2402   }
2403   channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2404   if (!channel_id) {
2405     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2406                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
2407     goto out;
2408   }
2409
2410   /* Check whether the channel exists */
2411   channel = silc_idlist_find_channel_by_id(server->local_list, 
2412                                            channel_id, NULL);
2413   if (!channel) {
2414     channel = silc_idlist_find_channel_by_id(server->global_list, 
2415                                              channel_id, NULL);
2416     if (!channel) {
2417       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2418                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL,
2419                                             0);
2420       goto out;
2421     }
2422   }
2423
2424   if (argc > 1) {
2425     /* Get the topic */
2426     tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
2427     if (!tmp) {
2428       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2429                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
2430                                             0);
2431       goto out;
2432     }
2433
2434     if (strlen(tmp) > 256) {
2435       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2436                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
2437                                             0);
2438       goto out;
2439     }
2440
2441     /* See whether the client is on channel and has rights to change topic */
2442     if (!silc_server_client_on_channel(client, channel, &chl)) {
2443       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2444                                             SILC_STATUS_ERR_NOT_ON_CHANNEL,
2445                                             0);
2446       goto out;
2447     }
2448
2449     if (channel->mode & SILC_CHANNEL_MODE_TOPIC &&
2450         !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
2451         !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
2452       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2453                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV,
2454                                             0);
2455       goto out;
2456     }
2457
2458     if (!channel->topic || strcmp(channel->topic, tmp)) {
2459       /* Set the topic for channel */
2460       silc_free(channel->topic);
2461       channel->topic = strdup(tmp);
2462
2463       /* Send TOPIC_SET notify type to the network */
2464       silc_server_send_notify_topic_set(server, SILC_PRIMARY_ROUTE(server),
2465                                         SILC_BROADCAST(server), channel,
2466                                         client->id, SILC_ID_CLIENT,
2467                                         channel->topic);
2468
2469       /* Send notify about topic change to all clients on the channel */
2470       idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2471       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
2472                                          SILC_NOTIFY_TYPE_TOPIC_SET, 2,
2473                                          idp->data, idp->len,
2474                                          channel->topic,
2475                                          strlen(channel->topic));
2476       silc_buffer_free(idp);
2477     }
2478   }
2479
2480   /* Send the topic to client as reply packet */
2481   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
2482   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
2483                                                 SILC_STATUS_OK, 0, ident, 2, 
2484                                                 2, idp->data, idp->len,
2485                                                 3, channel->topic, 
2486                                                 channel->topic ? 
2487                                                 strlen(channel->topic) : 0);
2488   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
2489                           0, packet->data, packet->len, FALSE);
2490
2491   silc_buffer_free(packet);
2492   silc_buffer_free(idp);
2493   silc_free(channel_id);
2494
2495  out:
2496   silc_server_command_free(cmd);
2497 }
2498
2499 /* Server side of INVITE command. Invites some client to join some channel. 
2500    This command is also used to manage the invite list of the channel. */
2501
2502 SILC_SERVER_CMD_FUNC(invite)
2503 {
2504   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2505   SilcServer server = cmd->server;
2506   SilcSocketConnection sock = cmd->sock, dest_sock;
2507   SilcChannelClientEntry chl;
2508   SilcClientEntry sender, dest;
2509   SilcClientID *dest_id = NULL;
2510   SilcChannelEntry channel;
2511   SilcChannelID *channel_id = NULL;
2512   SilcIDListData idata;
2513   SilcBuffer idp, idp2, packet;
2514   unsigned char *tmp, *add, *del;
2515   SilcUInt32 len;
2516   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
2517
2518   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
2519
2520   /* Get Channel ID */
2521   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2522   if (!tmp) {
2523     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2524                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
2525     goto out;
2526   }
2527   channel_id = silc_id_payload_parse_id(tmp, len, NULL);
2528   if (!channel_id) {
2529     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2530                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
2531     goto out;
2532   }
2533
2534   /* Get the channel entry */
2535   channel = silc_idlist_find_channel_by_id(server->local_list, 
2536                                            channel_id, NULL);
2537   if (!channel) {
2538     channel = silc_idlist_find_channel_by_id(server->global_list, 
2539                                              channel_id, NULL);
2540     if (!channel) {
2541       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2542                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL,
2543                                             0);
2544       goto out;
2545     }
2546   }
2547
2548   /* Check whether the sender of this command is on the channel. */
2549   sender = (SilcClientEntry)sock->user_data;
2550   if (!sender || !silc_server_client_on_channel(sender, channel, &chl)) {
2551     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2552                                           SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
2553     goto out;
2554   }
2555
2556   /* Check whether the channel is invite-only channel. If yes then the
2557      sender of this command must be at least channel operator. */
2558   if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
2559       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
2560       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
2561     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2562                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV,
2563                                           0);
2564     goto out;
2565   }
2566
2567   /* Get destination client ID */
2568   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2569   if (tmp) {
2570     char invite[512];
2571     bool resolve;
2572
2573     dest_id = silc_id_payload_parse_id(tmp, len, NULL);
2574     if (!dest_id) {
2575       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2576                                             SILC_STATUS_ERR_NO_CLIENT_ID, 0);
2577       goto out;
2578     }
2579
2580     /* Get the client entry */
2581     dest = silc_server_get_client_resolve(server, dest_id, FALSE, &resolve);
2582     if (!dest) {
2583       if (server->server_type != SILC_SERVER || !resolve) {
2584         silc_server_command_send_status_reply(
2585                                         cmd, SILC_COMMAND_INVITE,
2586                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0);
2587         goto out;
2588       }
2589       
2590       /* The client info is being resolved. Reprocess this packet after
2591          receiving the reply to the query. */
2592       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
2593                                   server->cmd_ident,
2594                                   silc_server_command_invite, 
2595                                   silc_server_command_dup(cmd));
2596       cmd->pending = TRUE;
2597       silc_free(channel_id);
2598       silc_free(dest_id);
2599       goto out;
2600     }
2601
2602     /* Check whether the requested client is already on the channel. */
2603     if (silc_server_client_on_channel(dest, channel, NULL)) {
2604       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2605                                             SILC_STATUS_ERR_USER_ON_CHANNEL,
2606                                             0);
2607       goto out;
2608     }
2609     
2610     /* Get route to the client */
2611     dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, 
2612                                              &idata, NULL);
2613     if (!dest_sock) {
2614       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2615                                             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
2616                                             0);
2617       goto out;
2618     }
2619
2620     memset(invite, 0, sizeof(invite));
2621     strncat(invite, dest->nickname, strlen(dest->nickname));
2622     strncat(invite, "!", 1);
2623     strncat(invite, dest->username, strlen(dest->username));
2624     if (!strchr(dest->username, '@')) {
2625       strncat(invite, "@", 1);
2626       strncat(invite, cmd->sock->hostname, strlen(cmd->sock->hostname));
2627     }
2628
2629     len = strlen(invite);
2630     if (!channel->invite_list)
2631       channel->invite_list = silc_calloc(len + 2, 
2632                                          sizeof(*channel->invite_list));
2633     else
2634       channel->invite_list = silc_realloc(channel->invite_list, 
2635                                           sizeof(*channel->invite_list) * 
2636                                           (len + 
2637                                            strlen(channel->invite_list) + 2));
2638     strncat(channel->invite_list, invite, len);
2639     strncat(channel->invite_list, ",", 1);
2640
2641     if (!(dest->mode & SILC_UMODE_BLOCK_INVITE)) {
2642       /* Send notify to the client that is invited to the channel */
2643       idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
2644       idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
2645       silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, 
2646                                    SILC_ID_CLIENT,
2647                                    SILC_NOTIFY_TYPE_INVITE, 3, 
2648                                    idp->data, idp->len, 
2649                                    channel->channel_name, 
2650                                    strlen(channel->channel_name),
2651                                    idp2->data, idp2->len);
2652       silc_buffer_free(idp);
2653       silc_buffer_free(idp2);
2654     }
2655   }
2656
2657   /* Add the client to the invite list of the channel */
2658   add = silc_argument_get_arg_type(cmd->args, 3, &len);
2659   if (add) {
2660     if (!channel->invite_list)
2661       channel->invite_list = silc_calloc(len + 2, 
2662                                          sizeof(*channel->invite_list));
2663     else
2664       channel->invite_list = silc_realloc(channel->invite_list, 
2665                                           sizeof(*channel->invite_list) * 
2666                                           (len + 
2667                                            strlen(channel->invite_list) + 2));
2668     if (add[len - 1] == ',')
2669       add[len - 1] = '\0';
2670     
2671     strncat(channel->invite_list, add, len);
2672     strncat(channel->invite_list, ",", 1);
2673   }
2674
2675   /* Get the invite to be removed and remove it from the list */
2676   del = silc_argument_get_arg_type(cmd->args, 4, &len);
2677   if (del && channel->invite_list) {
2678     char *start, *end, *n;
2679
2680     if (!strncmp(channel->invite_list, del, 
2681                  strlen(channel->invite_list) - 1)) {
2682       silc_free(channel->invite_list);
2683       channel->invite_list = NULL;
2684     } else {
2685       start = strstr(channel->invite_list, del);
2686       if (start && strlen(start) >= len) {
2687         end = start + len;
2688         n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n));
2689         strncat(n, channel->invite_list, start - channel->invite_list);
2690         strncat(n, end + 1, ((channel->invite_list + 
2691                               strlen(channel->invite_list)) - end) - 1);
2692         silc_free(channel->invite_list);
2693         channel->invite_list = n;
2694       }
2695     }
2696   }
2697
2698   /* Send notify to the primary router */
2699   silc_server_send_notify_invite(server, SILC_PRIMARY_ROUTE(server),
2700                                  SILC_BROADCAST(server), channel,
2701                                  sender->id, add, del);
2702
2703   /* Send command reply */
2704   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2705
2706   if (add || del)
2707     packet = 
2708       silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
2709                                            SILC_STATUS_OK, 0, ident, 2,
2710                                            2, tmp, len,
2711                                            3, channel->invite_list,
2712                                            channel->invite_list ?
2713                                            strlen(channel->invite_list) : 0);
2714   else
2715     packet = 
2716       silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
2717                                            SILC_STATUS_OK, 0, ident, 1,
2718                                            2, tmp, len);
2719   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2720                           packet->data, packet->len, FALSE);
2721   silc_buffer_free(packet);
2722
2723  out:
2724   silc_free(dest_id);
2725   silc_free(channel_id);
2726   silc_server_command_free(cmd);
2727 }
2728
2729 typedef struct {
2730   SilcServer server;
2731   SilcSocketConnection sock;
2732   char *signoff;
2733 } *QuitInternal;
2734
2735 /* Quits connection to client. This gets called if client won't
2736    close the connection even when it has issued QUIT command. */
2737
2738 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
2739 {
2740   QuitInternal q = (QuitInternal)context;
2741
2742   /* Free all client specific data, such as client entry and entires
2743      on channels this client may be on. */
2744   silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
2745                                TRUE, q->signoff);
2746   q->sock->user_data = NULL;
2747
2748   /* Close the connection on our side */
2749   silc_server_close_connection(q->server, q->sock);
2750
2751   silc_free(q->signoff);
2752   silc_free(q);
2753 }
2754
2755 /* Quits SILC session. This is the normal way to disconnect client. */
2756  
2757 SILC_SERVER_CMD_FUNC(quit)
2758 {
2759   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2760   SilcServer server = cmd->server;
2761   SilcSocketConnection sock = cmd->sock;
2762   QuitInternal q;
2763   unsigned char *tmp = NULL;
2764   SilcUInt32 len = 0;
2765
2766   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_QUIT, cmd, 0, 1);
2767
2768   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
2769     goto out;
2770
2771   /* Get message */
2772   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2773   if (len > 128)
2774     tmp = NULL;
2775
2776   q = silc_calloc(1, sizeof(*q));
2777   q->server = server;
2778   q->sock = sock;
2779   q->signoff = tmp ? strdup(tmp) : NULL;
2780
2781   /* We quit the connection with little timeout */
2782   silc_schedule_task_add(server->schedule, sock->sock,
2783                          silc_server_command_quit_cb, (void *)q,
2784                          0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
2785
2786  out:
2787   silc_server_command_free(cmd);
2788 }
2789
2790 /* Server side of command KILL. This command is used by router operator
2791    to remove an client from the SILC Network temporarily. */
2792
2793 SILC_SERVER_CMD_FUNC(kill)
2794 {
2795   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2796   SilcServer server = cmd->server;
2797   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2798   SilcClientEntry remote_client;
2799   SilcClientID *client_id;
2800   unsigned char *tmp, *comment;
2801   SilcUInt32 tmp_len, tmp_len2;
2802   bool local;
2803
2804   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
2805
2806   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
2807     goto out;
2808
2809   /* KILL command works only on router */
2810   if (server->server_type != SILC_ROUTER) {
2811     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2812                                           SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
2813     goto out;
2814   }
2815
2816   /* Check whether client has the permissions. */
2817   if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
2818     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2819                                           SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
2820     goto out;
2821   }
2822
2823   /* Get the client ID */
2824   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2825   if (!tmp) {
2826     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2827                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
2828                                           0);
2829     goto out;
2830   }
2831   client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2832   if (!client_id) {
2833     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2834                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
2835                                           0);
2836     goto out;
2837   }
2838
2839   /* Get the client entry */
2840   remote_client = silc_idlist_find_client_by_id(server->local_list, 
2841                                                 client_id, TRUE, NULL);
2842   local = TRUE;
2843   if (!remote_client) {
2844     remote_client = silc_idlist_find_client_by_id(server->global_list, 
2845                                                   client_id, TRUE, NULL);
2846     local = FALSE;
2847     if (!remote_client) {
2848       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2849                                             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
2850                                             0);
2851       goto out;
2852     }
2853   }
2854
2855   /* Get comment */
2856   comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
2857   if (tmp_len2 > 128)
2858     tmp_len2 = 128;
2859
2860   /* Send reply to the sender */
2861   silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2862                                         SILC_STATUS_OK, 0);
2863
2864   /* Check if anyone is watching this nickname */
2865   if (server->server_type == SILC_ROUTER)
2866     silc_server_check_watcher_list(server, client, NULL,
2867                                    SILC_NOTIFY_TYPE_KILLED);
2868
2869   /* Now do the killing */
2870   silc_server_kill_client(server, remote_client, comment, client->id,
2871                           SILC_ID_CLIENT);
2872
2873  out:
2874   silc_server_command_free(cmd);
2875 }
2876
2877 /* Server side of command INFO. This sends information about us to 
2878    the client. If client requested specific server we will send the 
2879    command to that server. */
2880
2881 SILC_SERVER_CMD_FUNC(info)
2882 {
2883   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2884   SilcServer server = cmd->server;
2885   SilcBuffer packet, idp;
2886   unsigned char *tmp;
2887   SilcUInt32 tmp_len;
2888   char *dest_server, *server_info = NULL, *server_name;
2889   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
2890   SilcServerEntry entry = NULL;
2891   SilcServerID *server_id = NULL;
2892
2893   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 0, 2);
2894
2895   /* Get server name */
2896   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
2897
2898   /* Get Server ID */
2899   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2900   if (tmp) {
2901     server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2902     if (!server_id) {
2903       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
2904                                             SILC_STATUS_ERR_NO_SERVER_ID, 0);
2905       goto out;
2906     }
2907   }
2908
2909   if (server_id) {
2910     /* Check whether we have this server cached */
2911     entry = silc_idlist_find_server_by_id(server->local_list,
2912                                           server_id, TRUE, NULL);
2913     if (!entry) {
2914       entry = silc_idlist_find_server_by_id(server->global_list,
2915                                             server_id, TRUE, NULL);
2916       if (!entry && server->server_type != SILC_SERVER) {
2917         silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
2918                                               SILC_STATUS_ERR_NO_SUCH_SERVER,
2919                                               0);
2920         goto out;
2921       }
2922     }
2923   }
2924
2925   /* Some buggy servers has sent request to router about themselves. */
2926   if (server->server_type != SILC_SERVER && cmd->sock->user_data == entry)
2927     goto out;
2928
2929   if ((!dest_server && !server_id && !entry) || (entry && 
2930                                                  entry == server->id_entry) ||
2931       (dest_server && !cmd->pending && 
2932        !strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
2933     /* Send our reply */
2934     char info_string[256];
2935
2936     memset(info_string, 0, sizeof(info_string));
2937     snprintf(info_string, sizeof(info_string), 
2938              "location: %s server: %s admin: %s <%s>",
2939              server->config->server_info->location,
2940              server->config->server_info->server_type,
2941              server->config->server_info->admin,
2942              server->config->server_info->email);
2943
2944     server_info = info_string;
2945     entry = server->id_entry;
2946   } else {
2947     /* Check whether we have this server cached */
2948     if (!entry && dest_server) {
2949       entry = silc_idlist_find_server_by_name(server->global_list,
2950                                               dest_server, TRUE, NULL);
2951       if (!entry) {
2952         entry = silc_idlist_find_server_by_name(server->local_list,
2953                                                 dest_server, TRUE, NULL);
2954       }
2955     }
2956
2957     if (!cmd->pending &&
2958         server->server_type != SILC_SERVER && entry && !entry->server_info) {
2959       /* Send to the server */
2960       SilcBuffer tmpbuf;
2961       SilcUInt16 old_ident;
2962
2963       old_ident = silc_command_get_ident(cmd->payload);
2964       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
2965       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2966
2967       silc_server_packet_send(server, entry->connection,
2968                               SILC_PACKET_COMMAND, cmd->packet->flags,
2969                               tmpbuf->data, tmpbuf->len, TRUE);
2970
2971       /* Reprocess this packet after received reply from router */
2972       silc_server_command_pending(server, SILC_COMMAND_INFO, 
2973                                   silc_command_get_ident(cmd->payload),
2974                                   silc_server_command_info,
2975                                   silc_server_command_dup(cmd));
2976       cmd->pending = TRUE;
2977       silc_command_set_ident(cmd->payload, old_ident);
2978       silc_buffer_free(tmpbuf);
2979       goto out;
2980     }
2981
2982     if (!entry && !cmd->pending && !server->standalone) {
2983       /* Send to the primary router */
2984       SilcBuffer tmpbuf;
2985       SilcUInt16 old_ident;
2986
2987       old_ident = silc_command_get_ident(cmd->payload);
2988       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
2989       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2990
2991       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
2992                               SILC_PACKET_COMMAND, cmd->packet->flags,
2993                               tmpbuf->data, tmpbuf->len, TRUE);
2994
2995       /* Reprocess this packet after received reply from router */
2996       silc_server_command_pending(server, SILC_COMMAND_INFO, 
2997                                   silc_command_get_ident(cmd->payload),
2998                                   silc_server_command_info,
2999                                   silc_server_command_dup(cmd));
3000       cmd->pending = TRUE;
3001       silc_command_set_ident(cmd->payload, old_ident);
3002       silc_buffer_free(tmpbuf);
3003       goto out;
3004     }
3005   }
3006
3007   silc_free(server_id);
3008
3009   if (!entry) {
3010     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
3011                                           SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
3012     goto out;
3013   }
3014
3015   idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
3016   if (!server_info)
3017     server_info = entry->server_info;
3018   server_name = entry->server_name;
3019
3020   /* Send the reply */
3021   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
3022                                                 SILC_STATUS_OK, 0, ident, 3,
3023                                                 2, idp->data, idp->len,
3024                                                 3, server_name, 
3025                                                 strlen(server_name),
3026                                                 4, server_info, 
3027                                                 server_info ? 
3028                                                 strlen(server_info) : 0);
3029   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3030                           packet->data, packet->len, FALSE);
3031     
3032   silc_buffer_free(packet);
3033   silc_buffer_free(idp);
3034
3035  out:
3036   silc_server_command_free(cmd);
3037 }
3038
3039 /* Server side of command PING. This just replies to the ping. */
3040
3041 SILC_SERVER_CMD_FUNC(ping)
3042 {
3043   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3044   SilcServer server = cmd->server;
3045   SilcServerID *id;
3046   SilcUInt32 len;
3047   unsigned char *tmp;
3048
3049   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 1, 2);
3050
3051   /* Get Server ID */
3052   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
3053   if (!tmp) {
3054     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
3055                                           SILC_STATUS_ERR_NO_SERVER_ID, 0);
3056     goto out;
3057   }
3058   id = silc_id_str2id(tmp, len, SILC_ID_SERVER);
3059   if (!id)
3060     goto out;
3061
3062   if (SILC_ID_SERVER_COMPARE(id, server->id)) {
3063     /* Send our reply */
3064     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
3065                                           SILC_STATUS_OK, 0);
3066   } else {
3067     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
3068                                           SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
3069     goto out;
3070   }
3071
3072   silc_free(id);
3073
3074  out:
3075   silc_server_command_free(cmd);
3076 }
3077
3078 /* Server side of command STATS. */
3079
3080 SILC_SERVER_CMD_FUNC(stats)
3081 {
3082   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3083   SilcServer server = cmd->server;
3084   SilcServerID *server_id;
3085   unsigned char *tmp;
3086   SilcUInt32 tmp_len;
3087   SilcBuffer packet, stats;
3088   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
3089   SilcUInt32 uptime;
3090
3091   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_STATS, cmd, 1, 1);
3092
3093   /* Get Server ID */
3094   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3095   if (!tmp) {
3096     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
3097                                           SILC_STATUS_ERR_NO_SERVER_ID, 0);
3098     goto out;
3099   }
3100   server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
3101   if (!server_id)
3102     goto out;
3103
3104   /* The ID must be ours */
3105   if (!SILC_ID_SERVER_COMPARE(server->id, server_id)) {
3106     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
3107                                           SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
3108     silc_free(server_id);
3109     goto out;
3110   }
3111   silc_free(server_id);
3112
3113   /* If we are router then just send everything we got. If we are normal
3114      server then we'll send this to our router to get all the latest
3115      statistical information. */
3116   if (!cmd->pending && server->server_type != SILC_ROUTER && 
3117       !server->standalone) {
3118     /* Send request to our router */
3119     SilcBuffer idp = silc_id_payload_encode(server->router->id, 
3120                                             SILC_ID_SERVER);
3121     packet = silc_command_payload_encode_va(SILC_COMMAND_STATS, 
3122                                             ++server->cmd_ident, 1,
3123                                             1, idp->data, idp->len);
3124     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
3125                             SILC_PACKET_COMMAND, 0, packet->data,
3126                             packet->len, FALSE);
3127
3128     /* Reprocess this packet after received reply from router */
3129     silc_server_command_pending(server, SILC_COMMAND_STATS, 
3130                                 server->cmd_ident,
3131                                 silc_server_command_stats,
3132                                 silc_server_command_dup(cmd));
3133     cmd->pending = TRUE;
3134     silc_buffer_free(packet);
3135     silc_buffer_free(idp);
3136     goto out;
3137   }
3138
3139   /* Send our reply to sender */
3140   uptime = time(NULL) - server->starttime;
3141
3142   stats = silc_buffer_alloc_size(60);
3143   silc_buffer_format(stats,
3144                      SILC_STR_UI_INT(server->starttime),
3145                      SILC_STR_UI_INT(uptime),
3146                      SILC_STR_UI_INT(server->stat.my_clients),
3147                      SILC_STR_UI_INT(server->stat.my_channels),
3148                      SILC_STR_UI_INT(server->stat.my_server_ops),
3149                      SILC_STR_UI_INT(server->stat.my_router_ops),
3150                      SILC_STR_UI_INT(server->stat.cell_clients),
3151                      SILC_STR_UI_INT(server->stat.cell_channels),
3152                      SILC_STR_UI_INT(server->stat.cell_servers),
3153                      SILC_STR_UI_INT(server->stat.clients),
3154                      SILC_STR_UI_INT(server->stat.channels),
3155                      SILC_STR_UI_INT(server->stat.servers),
3156                      SILC_STR_UI_INT(server->stat.routers),
3157                      SILC_STR_UI_INT(server->stat.server_ops),
3158                      SILC_STR_UI_INT(server->stat.router_ops),
3159                      SILC_STR_END);
3160
3161   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_STATS, 
3162                                                 SILC_STATUS_OK, 0, ident, 2,
3163                                                 2, tmp, tmp_len,
3164                                                 3, stats->data, stats->len);
3165   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
3166                           0, packet->data, packet->len, FALSE);
3167   silc_buffer_free(packet);
3168   silc_buffer_free(stats);
3169
3170  out:
3171   silc_server_command_free(cmd);
3172 }
3173
3174 /* Internal routine to join channel. The channel sent to this function
3175    has been either created or resolved from ID lists. This joins the sent
3176    client to the channel. */
3177
3178 static void silc_server_command_join_channel(SilcServer server, 
3179                                              SilcServerCommandContext cmd,
3180                                              SilcChannelEntry channel,
3181                                              SilcClientID *client_id,
3182                                              bool created,
3183                                              bool create_key,
3184                                              SilcUInt32 umode,
3185                                              const unsigned char *auth,
3186                                              SilcUInt32 auth_len)
3187 {
3188   SilcSocketConnection sock = cmd->sock;
3189   unsigned char *tmp;
3190   SilcUInt32 tmp_len, user_count;
3191   unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
3192   SilcClientEntry client;
3193   SilcChannelClientEntry chl;
3194   SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
3195   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
3196   char check[512], check2[512];
3197   bool founder = FALSE;
3198   bool resolve;
3199   unsigned char *fkey = NULL;
3200   SilcUInt32 fkey_len = 0;
3201
3202   SILC_LOG_DEBUG(("Joining client to channel"));
3203
3204   if (!channel)
3205     return;
3206
3207   /* Get the client entry */
3208   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
3209     client = (SilcClientEntry)sock->user_data;
3210     if (!client)
3211       return;
3212   } else {
3213     client = silc_server_get_client_resolve(server, client_id, FALSE, 
3214                                             &resolve);
3215     if (!client) {
3216       if (cmd->pending)
3217         goto out;
3218
3219       if (!resolve) {
3220         silc_server_command_send_status_reply(
3221                                          cmd, SILC_COMMAND_JOIN,
3222                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
3223         goto out;
3224       }
3225
3226       /* The client info is being resolved. Reprocess this packet after
3227          receiving the reply to the query. */
3228       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
3229                                   server->cmd_ident,
3230                                   silc_server_command_join, 
3231                                   silc_server_command_dup(cmd));
3232       cmd->pending = TRUE;
3233       goto out;
3234     }
3235
3236     cmd->pending = FALSE;
3237   }
3238
3239   /*
3240    * Check founder auth payload if provided.  If client can gain founder
3241    * privileges it can override various conditions on joining the channel,
3242    * and can have directly the founder mode set on the channel.
3243    */
3244   if (auth && auth_len && channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
3245     SilcIDListData idata = (SilcIDListData)client;
3246     SilcChannelClientEntry chl2;
3247     SilcHashTableList htl;
3248
3249     if (channel->founder_key && idata->public_key &&
3250         silc_pkcs_public_key_compare(channel->founder_key, 
3251                                      idata->public_key)) {
3252       /* Check whether the client is to become founder */
3253       if (silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
3254                                 channel->founder_key, 0, server->sha1hash,
3255                                 client->id, SILC_ID_CLIENT)) {
3256
3257         /* There cannot be anyone else as founder on the channel now.  This
3258            client is definitely the founder due to this authentication */
3259         silc_hash_table_list(channel->user_list, &htl);
3260         while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
3261           if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
3262             chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
3263             silc_server_force_cumode_change(server, NULL, channel, chl2,
3264                                             chl2->mode);
3265             break;
3266           }
3267         silc_hash_table_list_reset(&htl);
3268
3269         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3270         founder = TRUE;
3271       }
3272     }
3273   }
3274
3275   /*
3276    * Check channel modes
3277    */
3278
3279   if (!umode) {
3280     memset(check, 0, sizeof(check));
3281     memset(check2, 0, sizeof(check2));
3282     strncat(check, client->nickname, strlen(client->nickname));
3283     strncat(check, "!", 1);
3284     strncat(check, client->username, strlen(client->username));
3285     if (!strchr(client->username, '@')) {
3286       strncat(check, "@", 1);
3287       strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
3288     }
3289
3290     strncat(check2, client->nickname, strlen(client->nickname));
3291     if (!strchr(client->nickname, '@')) {
3292       strncat(check2, "@", 1);
3293       strncat(check2, server->server_name, strlen(server->server_name));
3294     }
3295     strncat(check2, "!", 1);
3296     strncat(check2, client->username, strlen(client->username));
3297     if (!strchr(client->username, '@')) {
3298       strncat(check2, "@", 1);
3299       strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
3300     }
3301     
3302     /* Check invite list if channel is invite-only channel */
3303     if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
3304       if (!channel->invite_list ||
3305           (!silc_string_match(channel->invite_list, check) &&
3306            !silc_string_match(channel->invite_list, check2))) {
3307         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3308                                               SILC_STATUS_ERR_NOT_INVITED, 0);
3309         goto out;
3310       }
3311     }
3312
3313     /* Check ban list if it exists. If the client's nickname, server,
3314        username and/or hostname is in the ban list the access to the
3315        channel is denied. */
3316     if (channel->ban_list) {
3317       if (silc_string_match(channel->ban_list, check) ||
3318           silc_string_match(channel->ban_list, check2)) {
3319         silc_server_command_send_status_reply(
3320                                       cmd, SILC_COMMAND_JOIN,
3321                                       SILC_STATUS_ERR_BANNED_FROM_CHANNEL, 0);
3322         goto out;
3323       }
3324     }
3325     
3326     /* Check user count limit if set. */
3327     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
3328       if (silc_hash_table_count(channel->user_list) + 1 > 
3329           channel->user_limit) {
3330         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3331                                               SILC_STATUS_ERR_CHANNEL_IS_FULL,
3332                                               0);
3333         goto out;
3334       }
3335     }
3336   }
3337
3338   /* Check the channel passphrase if set. */
3339   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3340     /* Get passphrase */
3341     tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
3342     if (tmp)
3343       passphrase = silc_memdup(tmp, tmp_len);
3344   
3345     if (!passphrase || !channel->passphrase ||
3346         memcmp(passphrase, channel->passphrase, strlen(channel->passphrase))) {
3347       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3348                                             SILC_STATUS_ERR_BAD_PASSWORD, 0);
3349       goto out;
3350     }
3351   }
3352
3353   /*
3354    * Client is allowed to join to the channel. Make it happen.
3355    */
3356
3357   /* Check whether the client already is on the channel */
3358   if (silc_server_client_on_channel(client, channel, NULL)) {
3359     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3360                                           SILC_STATUS_ERR_USER_ON_CHANNEL, 0);
3361     goto out;
3362   }
3363
3364   /* Generate new channel key as protocol dictates */
3365   if (create_key) {
3366     if (!silc_server_create_channel_key(server, channel, 0))
3367       goto out;
3368
3369     /* Send the channel key. This is broadcasted to the channel but is not
3370        sent to the client who is joining to the channel. */
3371     if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
3372       silc_server_send_channel_key(server, NULL, channel, 
3373                                    server->server_type == SILC_ROUTER ? 
3374                                    FALSE : !server->standalone);
3375   }
3376
3377   /* Join the client to the channel by adding it to channel's user list.
3378      Add also the channel to client entry's channels list for fast cross-
3379      referencing. */
3380   chl = silc_calloc(1, sizeof(*chl));
3381   chl->mode = umode;
3382   chl->client = client;
3383   chl->channel = channel;
3384   silc_hash_table_add(channel->user_list, client, chl);
3385   silc_hash_table_add(client->channels, channel, chl);
3386   channel->user_count++;
3387   channel->disabled = FALSE;
3388
3389   /* Get users on the channel */
3390   silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
3391                                    &user_count);
3392
3393   /* Encode Client ID Payload of the original client who wants to join */
3394   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
3395
3396   /* Encode command reply packet */
3397   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
3398   SILC_PUT32_MSB(channel->mode, mode);
3399   SILC_PUT32_MSB(created, tmp2);
3400   SILC_PUT32_MSB(user_count, tmp3);
3401
3402   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
3403     tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
3404     keyp = silc_channel_key_payload_encode(silc_id_get_len(channel->id,
3405                                                            SILC_ID_CHANNEL), 
3406                                            tmp,
3407                                            strlen(channel->channel_key->
3408                                                   cipher->name),
3409                                            channel->channel_key->cipher->name,
3410                                            channel->key_len / 8, channel->key);
3411     silc_free(tmp);
3412   }
3413
3414   if (channel->founder_key)
3415     fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
3416
3417   reply = 
3418     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
3419                                          SILC_STATUS_OK, 0, ident, 14,
3420                                          2, channel->channel_name,
3421                                          strlen(channel->channel_name),
3422                                          3, chidp->data, chidp->len,
3423                                          4, clidp->data, clidp->len,
3424                                          5, mode, 4,
3425                                          6, tmp2, 4,
3426                                          7, keyp ? keyp->data : NULL, 
3427                                          keyp ? keyp->len : 0,
3428                                          8, channel->ban_list, 
3429                                          channel->ban_list ?
3430                                          strlen(channel->ban_list) : 0,
3431                                          9, channel->invite_list,
3432                                          channel->invite_list ?
3433                                          strlen(channel->invite_list) : 0,
3434                                          10, channel->topic,
3435                                          channel->topic ?
3436                                          strlen(channel->topic) : 0,
3437                                          11, silc_hmac_get_name(channel->hmac),
3438                                          strlen(silc_hmac_get_name(channel->
3439                                                                    hmac)),
3440                                          12, tmp3, 4,
3441                                          13, user_list->data, user_list->len,
3442                                          14, mode_list->data, 
3443                                          mode_list->len,
3444                                          15, fkey, fkey_len);
3445
3446   /* Send command reply */
3447   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
3448                           reply->data, reply->len, FALSE);
3449
3450   /* Send JOIN notify to locally connected clients on the channel. If
3451      we are normal server then router will send or have sent JOIN notify
3452      already. However since we've added the client already to our channel
3453      we'll ignore it (in packet_receive.c) so we must send it here. If
3454      we are router then this will send it to local clients and local
3455      servers. */
3456   SILC_LOG_DEBUG(("Send JOIN notify to channel"));
3457   silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
3458                                      SILC_NOTIFY_TYPE_JOIN, 2,
3459                                      clidp->data, clidp->len,
3460                                      chidp->data, chidp->len);
3461
3462   /* Update statistics */
3463   server->stat.my_chanclients++;
3464   if (server->server_type == SILC_ROUTER) {
3465     server->stat.cell_chanclients++;
3466     server->stat.chanclients++;
3467   }
3468
3469   if (!cmd->pending) {
3470     /* Send JOIN notify packet to our primary router */
3471     silc_server_send_notify_join(server, SILC_PRIMARY_ROUTE(server),
3472                                  SILC_BROADCAST(server), channel, client->id);
3473
3474     if (keyp)
3475       /* Distribute the channel key to all backup routers. */
3476       silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
3477                               keyp->data, keyp->len, FALSE, TRUE);
3478
3479     /* If client became founder by providing correct founder auth data
3480        notify the mode change to the channel. */
3481     if (founder) {
3482       SILC_PUT32_MSB(chl->mode, mode);
3483       SILC_LOG_DEBUG(("Send CUMODE_CHANGE notify to channel"));
3484       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
3485                                          SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
3486                                          clidp->data, clidp->len,
3487                                          mode, 4, clidp->data, clidp->len,
3488                                          fkey, fkey_len);
3489     }
3490   }
3491
3492   /* Set CUMODE notify type to network */
3493   if (founder)
3494     silc_server_send_notify_cumode(server, SILC_PRIMARY_ROUTE(server),
3495                                    SILC_BROADCAST(server), channel,
3496                                    chl->mode, client->id, SILC_ID_CLIENT,
3497                                    client->id, channel->founder_key);
3498
3499   silc_buffer_free(reply);
3500   silc_buffer_free(clidp);
3501   silc_buffer_free(chidp);
3502   silc_buffer_free(keyp);
3503   silc_buffer_free(user_list);
3504   silc_buffer_free(mode_list);
3505   silc_free(fkey);
3506
3507  out:
3508   silc_free(passphrase);
3509 }
3510
3511 /* Server side of command JOIN. Joins client into requested channel. If 
3512    the channel does not exist it will be created. */
3513
3514 SILC_SERVER_CMD_FUNC(join)
3515 {
3516   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3517   SilcServer server = cmd->server;
3518   unsigned char *auth;
3519   SilcUInt32 tmp_len, auth_len;
3520   char *tmp, *channel_name = NULL, *cipher, *hmac;
3521   SilcChannelEntry channel;
3522   SilcUInt32 umode = 0;
3523   bool created = FALSE, create_key = TRUE;
3524   SilcClientID *client_id;
3525
3526   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 6);
3527
3528   /* Get channel name */
3529   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3530   if (!tmp) {
3531     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3532                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
3533                                           0);
3534     goto out;
3535   }
3536   channel_name = tmp;
3537
3538   if (tmp_len > 256)
3539     channel_name[255] = '\0';
3540
3541   if (silc_server_name_bad_chars(channel_name, tmp_len) == TRUE) {
3542     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3543                                           SILC_STATUS_ERR_BAD_CHANNEL, 0);
3544     goto out;
3545   }
3546
3547   /* Get Client ID of the client who is joining to the channel */
3548   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
3549   if (!tmp) {
3550     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3551                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
3552                                           0);
3553     goto out;
3554   }
3555   client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
3556   if (!client_id) {
3557     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3558                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
3559                                           0);
3560     goto out;
3561   }
3562
3563   /* Get cipher, hmac name and auth payload */
3564   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
3565   hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
3566   auth = silc_argument_get_arg_type(cmd->args, 6, &auth_len);
3567
3568   /* See if the channel exists */
3569   channel = silc_idlist_find_channel_by_name(server->local_list, 
3570                                              channel_name, NULL);
3571
3572   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
3573     SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
3574     if (!entry) {
3575       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3576                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
3577                                             0);
3578       goto out;
3579     }
3580
3581     silc_free(client_id);
3582     client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
3583
3584     if (!channel || 
3585         (channel->disabled && server->server_type != SILC_ROUTER)) {
3586       /* Channel not found */
3587
3588       /* If we are standalone server we don't have a router, we just create 
3589          the channel by ourselves. */
3590       if (server->standalone) {
3591         channel = silc_server_create_new_channel(server, server->id, cipher, 
3592                                                  hmac, channel_name, TRUE);
3593         if (!channel) {
3594           silc_server_command_send_status_reply(
3595                                          cmd, SILC_COMMAND_JOIN,
3596                                          SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
3597                                          0);
3598           silc_free(client_id);
3599           goto out;
3600         }
3601         
3602         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3603         created = TRUE;
3604         create_key = FALSE;
3605         
3606       } else {
3607
3608         /* The channel does not exist on our server. If we are normal server 
3609            we will send JOIN command to our router which will handle the
3610            joining procedure (either creates the channel if it doesn't exist 
3611            or joins the client to it). */
3612         if (server->server_type != SILC_ROUTER) {
3613           SilcBuffer tmpbuf;
3614           SilcUInt16 old_ident;
3615
3616           /* If this is pending command callback then we've resolved
3617              it and it didn't work, return since we've notified the
3618              client already in the command reply callback. */
3619           if (cmd->pending) {
3620             silc_free(client_id);
3621             goto out;
3622           }
3623           
3624           old_ident = silc_command_get_ident(cmd->payload);
3625           silc_command_set_ident(cmd->payload, ++server->cmd_ident);
3626           tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3627           
3628           /* Send JOIN command to our router */
3629           silc_server_packet_send(server, (SilcSocketConnection)
3630                                   SILC_PRIMARY_ROUTE(server),
3631                                   SILC_PACKET_COMMAND, cmd->packet->flags,
3632                                   tmpbuf->data, tmpbuf->len, TRUE);
3633           
3634           /* Reprocess this packet after received reply from router */
3635           silc_server_command_pending(server, SILC_COMMAND_JOIN, 
3636                                       silc_command_get_ident(cmd->payload),
3637                                       silc_server_command_join,
3638                                       silc_server_command_dup(cmd));
3639           cmd->pending = TRUE;
3640           silc_command_set_ident(cmd->payload, old_ident);
3641           silc_buffer_free(tmpbuf);
3642           silc_free(client_id);
3643           goto out;
3644         }
3645         
3646         /* We are router and the channel does not seem exist so we will check
3647            our global list as well for the channel. */
3648         channel = silc_idlist_find_channel_by_name(server->global_list, 
3649                                                    channel_name, NULL);
3650         if (!channel) {
3651           /* Channel really does not exist, create it */
3652           channel = silc_server_create_new_channel(server, server->id, cipher, 
3653                                                    hmac, channel_name, TRUE);
3654           if (!channel) {
3655             silc_server_command_send_status_reply(
3656                                        cmd, SILC_COMMAND_JOIN,
3657                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
3658             silc_free(client_id);
3659             goto out;
3660           }
3661
3662           umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3663           created = TRUE;
3664           create_key = FALSE;
3665         }
3666       }
3667     }
3668   } else {
3669     if (!channel) {
3670       /* Channel not found */
3671
3672       /* If the command came from router and we are normal server then
3673          something went wrong with the joining as the channel was not found.
3674          We can't do anything else but ignore this. */
3675       if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
3676           server->server_type != SILC_ROUTER) {
3677         silc_free(client_id);
3678         goto out;
3679       }
3680       
3681       /* We are router and the channel does not seem exist so we will check
3682          our global list as well for the channel. */
3683       channel = silc_idlist_find_channel_by_name(server->global_list, 
3684                                                  channel_name, NULL);
3685       if (!channel) {
3686         /* Channel really does not exist, create it */
3687         channel = silc_server_create_new_channel(server, server->id, cipher, 
3688                                                  hmac, channel_name, TRUE);
3689         if (!channel) {
3690           silc_server_command_send_status_reply(
3691                                        cmd, SILC_COMMAND_JOIN,
3692                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
3693           silc_free(client_id);
3694           goto out;
3695         }
3696
3697         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3698         created = TRUE;
3699         create_key = FALSE;
3700       }
3701     }
3702   }
3703
3704   /* Check whether the channel was created by our router */
3705   if (cmd->pending && context2) {
3706     SilcServerCommandReplyContext reply = context2;
3707
3708     if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) {
3709       tmp = silc_argument_get_arg_type(reply->args, 6, NULL);
3710       SILC_GET32_MSB(created, tmp);
3711       if (silc_argument_get_arg_type(reply->args, 7, NULL))
3712         create_key = FALSE;     /* Router returned the key already */
3713
3714       if (silc_command_get_status(reply->payload, NULL, NULL) &&
3715           channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3716         /* Save channel passphrase, if user provided it successfully */
3717         unsigned char *pa;
3718         SilcUInt32 pa_len;
3719         pa = silc_argument_get_arg_type(cmd->args, 3, &pa_len);
3720         if (pa) {
3721           silc_free(channel->passphrase);
3722           channel->passphrase = silc_memdup(pa, pa_len);
3723         }
3724       }
3725     }
3726
3727     if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS &&
3728         !channel->disabled && !silc_hash_table_count(channel->user_list))
3729       created = TRUE;
3730   }
3731
3732   /* If the channel does not have global users and is also empty the client
3733      will be the channel founder and operator. */
3734   if (!channel->disabled &&
3735       !channel->global_users && !silc_hash_table_count(channel->user_list))
3736     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3737
3738   /* Join to the channel */
3739   silc_server_command_join_channel(server, cmd, channel, client_id,
3740                                    created, create_key, umode,
3741                                    auth, auth_len);
3742
3743   silc_free(client_id);
3744
3745  out:
3746   silc_server_command_free(cmd);
3747 }
3748
3749 /* Server side of command MOTD. Sends server's current "message of the
3750    day" to the client. */
3751
3752 SILC_SERVER_CMD_FUNC(motd)
3753 {
3754   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3755   SilcServer server = cmd->server;
3756   SilcBuffer packet, idp;
3757   char *motd, *dest_server;
3758   SilcUInt32 motd_len;
3759   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
3760   
3761   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_MOTD, cmd, 1, 1);
3762
3763   /* Get server name */
3764   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
3765   if (!dest_server) {
3766     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
3767                                           SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
3768     goto out;
3769   }
3770
3771   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
3772     /* Send our MOTD */
3773
3774     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
3775
3776     if (server->config && server->config->server_info &&
3777         server->config->server_info->motd_file) {
3778       /* Send motd */
3779       motd = silc_file_readfile(server->config->server_info->motd_file,
3780                                 &motd_len);
3781       if (!motd)
3782         goto out;
3783       
3784       motd[motd_len] = 0;
3785       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3786                                                     SILC_STATUS_OK, 0, 
3787                                                     ident, 2,
3788                                                     2, idp, idp->len,
3789                                                     3, motd, motd_len);
3790     } else {
3791       /* No motd */
3792       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3793                                                     SILC_STATUS_OK, 0, 
3794                                                     ident, 1,
3795                                                     2, idp, idp->len);
3796     }
3797
3798     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3799                             packet->data, packet->len, FALSE);
3800     silc_buffer_free(packet);
3801     silc_buffer_free(idp);
3802   } else {
3803     SilcServerEntry entry;
3804
3805     /* Check whether we have this server cached */
3806     entry = silc_idlist_find_server_by_name(server->global_list,
3807                                             dest_server, TRUE, NULL);
3808     if (!entry) {
3809       entry = silc_idlist_find_server_by_name(server->local_list,
3810                                               dest_server, TRUE, NULL);
3811     }
3812
3813     if (server->server_type != SILC_SERVER && !cmd->pending && 
3814         entry && !entry->motd) {
3815       /* Send to the server */
3816       SilcBuffer tmpbuf;
3817       SilcUInt16 old_ident;
3818
3819       old_ident = silc_command_get_ident(cmd->payload);
3820       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
3821       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3822
3823       silc_server_packet_send(server, entry->connection,
3824                               SILC_PACKET_COMMAND, cmd->packet->flags,
3825                               tmpbuf->data, tmpbuf->len, TRUE);
3826
3827       /* Reprocess this packet after received reply from router */
3828       silc_server_command_pending(server, SILC_COMMAND_MOTD, 
3829                                   silc_command_get_ident(cmd->payload),
3830                                   silc_server_command_motd,
3831                                   silc_server_command_dup(cmd));
3832       cmd->pending = TRUE;
3833       silc_command_set_ident(cmd->payload, old_ident);
3834       silc_buffer_free(tmpbuf);
3835       goto out;
3836     }
3837
3838     if (!entry && !cmd->pending && !server->standalone) {
3839       /* Send to the primary router */
3840       SilcBuffer tmpbuf;
3841       SilcUInt16 old_ident;
3842
3843       old_ident = silc_command_get_ident(cmd->payload);
3844       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
3845       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3846
3847       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
3848                               SILC_PACKET_COMMAND, cmd->packet->flags,
3849                               tmpbuf->data, tmpbuf->len, TRUE);
3850
3851       /* Reprocess this packet after received reply from router */
3852       silc_server_command_pending(server, SILC_COMMAND_MOTD, 
3853                                   silc_command_get_ident(cmd->payload),
3854                                   silc_server_command_motd,
3855                                   silc_server_command_dup(cmd));
3856       cmd->pending = TRUE;
3857       silc_command_set_ident(cmd->payload, old_ident);
3858       silc_buffer_free(tmpbuf);
3859       goto out;
3860     }
3861
3862     if (!entry) {
3863       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
3864                                             SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
3865       goto out;
3866     }
3867
3868     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
3869     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3870                                                   SILC_STATUS_OK, 0, ident, 2,
3871                                                   2, idp, idp->len,
3872                                                   3, entry->motd,
3873                                                   entry->motd ? 
3874                                                   strlen(entry->motd) : 0);
3875     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3876                             packet->data, packet->len, FALSE);
3877     silc_buffer_free(packet);
3878     silc_buffer_free(idp);
3879   }
3880
3881  out:
3882   silc_server_command_free(cmd);
3883 }
3884
3885 /* Server side of command UMODE. Client can use this command to set/unset
3886    user mode. Client actually cannot set itself to be as server/router
3887    operator so this can be used only to unset the modes. */
3888
3889 SILC_SERVER_CMD_FUNC(umode)
3890 {
3891   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3892   SilcServer server = cmd->server;
3893   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3894   SilcBuffer packet;
3895   unsigned char *tmp_mask, m[4];
3896   SilcUInt32 mask = 0;
3897   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
3898   bool set_mask = FALSE;
3899
3900   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
3901     goto out;
3902
3903   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_UMODE, cmd, 1, 2);
3904
3905   /* Get the client's mode mask */
3906   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
3907   if (tmp_mask) {
3908     SILC_GET32_MSB(mask, tmp_mask);
3909     set_mask = TRUE;
3910   }
3911
3912   if (set_mask) {
3913     /* Check that mode changing is allowed. */
3914     if (!silc_server_check_umode_rights(server, client, mask)) {
3915       silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3916                                             SILC_STATUS_ERR_PERM_DENIED, 0);
3917       goto out;
3918     }
3919
3920     /* Anonymous mode cannot be set by client */
3921     if (mask & SILC_UMODE_ANONYMOUS) {
3922       if (!(client->mode & SILC_UMODE_ANONYMOUS)) {
3923         silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3924                                               SILC_STATUS_ERR_PERM_DENIED, 0);
3925         goto out;
3926       }
3927     } else {
3928       if (client->mode & SILC_UMODE_ANONYMOUS) {
3929         silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3930                                               SILC_STATUS_ERR_PERM_DENIED, 0);
3931         goto out;
3932       }
3933     }
3934
3935     /* Update statistics */
3936     if (mask & SILC_UMODE_GONE) {
3937       if (!(client->mode & SILC_UMODE_GONE))
3938         server->stat.my_aways++;
3939     } else {
3940       if (client->mode & SILC_UMODE_GONE)
3941         server->stat.my_aways--;
3942     }
3943
3944     /* Change the mode */
3945     client->mode = mask;
3946
3947     /* Send UMODE change to primary router */
3948     silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
3949                                   SILC_BROADCAST(server), client->id,
3950                                   client->mode);
3951
3952     /* Check if anyone is watching this nickname */
3953     if (server->server_type == SILC_ROUTER)
3954       silc_server_check_watcher_list(server, client, NULL,
3955                                      SILC_NOTIFY_TYPE_UMODE_CHANGE);
3956   }
3957
3958   /* Send command reply to sender */
3959   SILC_PUT32_MSB(client->mode, m);
3960   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_UMODE,
3961                                                 SILC_STATUS_OK, 0, ident, 1,
3962                                                 2, m, sizeof(m));
3963   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3964                           packet->data, packet->len, FALSE);
3965   silc_buffer_free(packet);
3966
3967  out:
3968   silc_server_command_free(cmd);
3969 }
3970
3971 /* Server side command of CMODE. Changes channel mode */
3972
3973 SILC_SERVER_CMD_FUNC(cmode)
3974 {
3975   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3976   SilcServer server = cmd->server;
3977   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3978   SilcIDListData idata = (SilcIDListData)client;
3979   SilcChannelID *channel_id = NULL;
3980   SilcChannelEntry channel;
3981   SilcChannelClientEntry chl;
3982   SilcBuffer packet, cidp;
3983   unsigned char *tmp, *tmp_id, *tmp_mask;
3984   char *cipher = NULL, *hmac = NULL, *passphrase = NULL;
3985   SilcUInt32 mode_mask = 0, old_mask = 0, tmp_len, tmp_len2;
3986   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
3987   bool set_mask = FALSE;
3988   SilcPublicKey founder_key = NULL;
3989   unsigned char *fkey = NULL;
3990   SilcUInt32 fkey_len = 0;
3991
3992   if (!client) {
3993     silc_server_command_free(cmd);
3994     return;
3995   }
3996
3997   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 7);
3998
3999   /* Get Channel ID */
4000   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
4001   if (!tmp_id) {
4002     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4003                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
4004     silc_server_command_free(cmd);
4005     return;
4006   }
4007   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2, NULL);
4008   if (!channel_id) {
4009     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4010                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
4011     silc_server_command_free(cmd);
4012     return;
4013   }
4014
4015   /* Get channel entry */
4016   channel = silc_idlist_find_channel_by_id(server->local_list, 
4017                                            channel_id, NULL);
4018   if (!channel) {
4019     channel = silc_idlist_find_channel_by_id(server->global_list, 
4020                                              channel_id, NULL);
4021     if (!channel) {
4022       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4023                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL,
4024                                             0);
4025       silc_free(channel_id);
4026       silc_server_command_free(cmd);
4027       return;
4028     }
4029   }
4030   old_mask = channel->mode;
4031
4032   /* Get the channel mode mask */
4033   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4034   if (tmp_mask) {
4035     SILC_GET32_MSB(mode_mask, tmp_mask);
4036     set_mask = TRUE;
4037   }
4038
4039   /* Check whether this client is on the channel */
4040   if (!silc_server_client_on_channel(client, channel, &chl)) {
4041     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4042                                           SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
4043     goto out;
4044   }
4045
4046   /* Check that client has rights to change any requested channel modes */
4047   if (set_mask && !silc_server_check_cmode_rights(server, channel, chl, 
4048                                                   mode_mask)) {
4049     SILC_LOG_DEBUG(("Client does not have rights to change mode"));
4050     silc_server_command_send_status_reply(
4051                              cmd, SILC_COMMAND_CMODE,
4052                              (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) ? 
4053                               SILC_STATUS_ERR_NO_CHANNEL_PRIV :
4054                               SILC_STATUS_ERR_NO_CHANNEL_FOPRIV), 0);
4055     goto out;
4056   }
4057
4058   /* If mode mask was not sent as argument then merely return the current
4059      mode mask to the sender. */
4060   if (!set_mask) {
4061     unsigned char m[4];
4062     SILC_PUT32_MSB(channel->mode, m);
4063     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
4064                                                   SILC_STATUS_OK, 0, ident, 2,
4065                                                   2, tmp_id, tmp_len2,
4066                                                   3, m, sizeof(m));
4067     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
4068                             packet->data, packet->len, FALSE);
4069     silc_buffer_free(packet);
4070     goto out;
4071   }
4072
4073   /*
4074    * Check the modes. Modes that requires nothing special operation are
4075    * not checked here.
4076    */
4077
4078   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
4079     /* Channel uses private keys to protect traffic. Client(s) has set the
4080        key locally they want to use, server does not know that key. */
4081     /* Nothing interesting to do here */
4082   } else {
4083     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
4084       /* The mode is removed and we need to generate and distribute
4085          new channel key. Clients are not using private channel keys
4086          anymore after this. */
4087       
4088       /* Re-generate channel key */
4089       if (!silc_server_create_channel_key(server, channel, 0))
4090         goto out;
4091         
4092       /* Send the channel key. This sends it to our local clients and if
4093          we are normal server to our router as well. */
4094       silc_server_send_channel_key(server, NULL, channel, 
4095                                    server->server_type == SILC_ROUTER ? 
4096                                    FALSE : !server->standalone);
4097         
4098       cipher = channel->channel_key->cipher->name;
4099       hmac = (char *)silc_hmac_get_name(channel->hmac);
4100     }
4101   }
4102
4103   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
4104     /* User limit is set on channel */
4105     SilcUInt32 user_limit;
4106       
4107     /* Get user limit */
4108     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
4109     if (!tmp) {
4110       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
4111         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4112                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
4113         goto out;
4114       }
4115     } else {
4116       SILC_GET32_MSB(user_limit, tmp);
4117       channel->user_limit = user_limit;
4118     }
4119   } else {
4120     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
4121       /* User limit mode is unset. Remove user limit */
4122       channel->user_limit = 0;
4123   }
4124
4125   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
4126     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
4127       /* Passphrase has been set to channel */
4128       
4129       /* Get the passphrase */
4130       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
4131       if (!tmp) {
4132         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4133                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
4134         goto out;
4135       }
4136
4137       /* Save the passphrase */
4138       passphrase = channel->passphrase = silc_memdup(tmp, strlen(tmp));
4139     }
4140   } else {
4141     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
4142       /* Passphrase mode is unset. remove the passphrase */
4143       silc_free(channel->passphrase);
4144       channel->passphrase = NULL;
4145     }
4146   }
4147
4148   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
4149     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
4150       /* Cipher to use protect the traffic */
4151       SilcCipher newkey, oldkey;
4152
4153       /* Get cipher */
4154       cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
4155       if (!cipher) {
4156         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4157                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
4158         goto out;
4159       }
4160
4161       /* Delete old cipher and allocate the new one */
4162       if (!silc_cipher_alloc(cipher, &newkey)) {
4163         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4164                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
4165         goto out;
4166       }
4167
4168       oldkey = channel->channel_key;
4169       channel->channel_key = newkey;
4170
4171       /* Re-generate channel key */
4172       if (!silc_server_create_channel_key(server, channel, 0)) {
4173         /* We don't have new key, revert to old one */
4174         channel->channel_key = oldkey;
4175         goto out;
4176       }
4177
4178       /* Remove old channel key for good */
4179       silc_cipher_free(oldkey);
4180
4181       /* Send the channel key. This sends it to our local clients and if
4182          we are normal server to our router as well. */
4183       silc_server_send_channel_key(server, NULL, channel, 
4184                                    server->server_type == SILC_ROUTER ? 
4185                                    FALSE : !server->standalone);
4186     }
4187   } else {
4188     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
4189       /* Cipher mode is unset. Remove the cipher and revert back to 
4190          default cipher */
4191       SilcCipher newkey, oldkey;
4192       cipher = channel->cipher;
4193
4194       /* Delete old cipher and allocate default one */
4195       if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER, &newkey)) {
4196         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4197                                    SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
4198         goto out;
4199       }
4200
4201       oldkey = channel->channel_key;
4202       channel->channel_key = newkey;
4203
4204       /* Re-generate channel key */
4205       if (!silc_server_create_channel_key(server, channel, 0)) {
4206         /* We don't have new key, revert to old one */
4207         channel->channel_key = oldkey;
4208         goto out;
4209       }
4210       
4211       /* Remove old channel key for good */
4212       silc_cipher_free(oldkey);
4213
4214       /* Send the channel key. This sends it to our local clients and if
4215          we are normal server to our router as well. */
4216       silc_server_send_channel_key(server, NULL, channel, 
4217                                    server->server_type == SILC_ROUTER ? 
4218                                    FALSE : !server->standalone);
4219     }
4220   }
4221
4222   if (mode_mask & SILC_CHANNEL_MODE_HMAC) {
4223     if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) {
4224       /* HMAC to use protect the traffic */
4225       unsigned char hash[32];
4226       SilcHmac newhmac;
4227
4228       /* Get hmac */
4229       hmac = silc_argument_get_arg_type(cmd->args, 6, NULL);
4230       if (!hmac) {
4231         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4232                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
4233         goto out;
4234       }
4235
4236       /* Delete old hmac and allocate the new one */
4237       if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
4238         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4239                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
4240         goto out;
4241       }
4242
4243       silc_hmac_free(channel->hmac);
4244       channel->hmac = newhmac;
4245
4246       /* Set the HMAC key out of current channel key. The client must do
4247          this locally. */
4248       silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
4249                      channel->key_len / 8, hash);
4250       silc_hmac_set_key(channel->hmac, hash, 
4251                         silc_hash_len(silc_hmac_get_hash(channel->hmac)));
4252       memset(hash, 0, sizeof(hash));
4253     }
4254   } else {
4255     if (channel->mode & SILC_CHANNEL_MODE_HMAC) {
4256       /* Hmac mode is unset. Remove the hmac and revert back to 
4257          default hmac */
4258       SilcHmac newhmac;
4259       unsigned char hash[32];
4260       hmac = channel->hmac_name;
4261
4262       /* Delete old hmac and allocate default one */
4263       silc_hmac_free(channel->hmac);
4264       if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL, &newhmac)) {
4265         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4266                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
4267         goto out;
4268       }
4269
4270       silc_hmac_free(channel->hmac);
4271       channel->hmac = newhmac;
4272
4273       /* Set the HMAC key out of current channel key. The client must do
4274          this locally. */
4275       silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
4276                      channel->key_len / 8, 
4277                      hash);
4278       silc_hmac_set_key(channel->hmac, hash, 
4279                         silc_hash_len(silc_hmac_get_hash(channel->hmac)));
4280       memset(hash, 0, sizeof(hash));
4281     }
4282   }
4283
4284   if (mode_mask & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
4285     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
4286       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
4287         /* Set the founder authentication */
4288         tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len);
4289         if (!tmp) {
4290           silc_server_command_send_status_reply(
4291                                      cmd, SILC_COMMAND_CMODE,
4292                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
4293           goto out;
4294         }
4295
4296         /* Verify the payload before setting the mode */
4297         if (!silc_auth_verify_data(tmp, tmp_len, SILC_AUTH_PUBLIC_KEY, 
4298                                    idata->public_key, 0, server->sha1hash,
4299                                    client->id, SILC_ID_CLIENT)) {
4300           silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4301                                                 SILC_STATUS_ERR_AUTH_FAILED,
4302                                                 0);
4303           goto out;
4304         }
4305
4306         /* Save the public key */
4307         channel->founder_key = silc_pkcs_public_key_copy(idata->public_key);
4308         if (!channel->founder_key) {
4309           silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4310                                                 SILC_STATUS_ERR_AUTH_FAILED,
4311                                                 0);
4312           goto out;
4313         }
4314
4315         founder_key = channel->founder_key;
4316         fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
4317         if (!fkey) {
4318           silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
4319                                                 SILC_STATUS_ERR_AUTH_FAILED,
4320                                                 0);
4321           silc_pkcs_public_key_free(channel->founder_key);
4322           channel->founder_key = NULL;
4323           goto out;
4324         }
4325       }
4326     }
4327   } else {
4328     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
4329       if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
4330         if (channel->founder_key)
4331           silc_pkcs_public_key_free(channel->founder_key);
4332         channel->founder_key = NULL;
4333       }
4334     }
4335   }
4336
4337   /* Finally, set the mode */
4338   old_mask = channel->mode = mode_mask;
4339
4340   /* Send CMODE_CHANGE notify. */
4341   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
4342   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
4343                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 6,
4344                                      cidp->data, cidp->len, 
4345                                      tmp_mask, 4,
4346                                      cipher, cipher ? strlen(cipher) : 0,
4347                                      hmac, hmac ? strlen(hmac) : 0,
4348                                      passphrase, passphrase ? 
4349                                      strlen(passphrase) : 0,
4350                                      fkey, fkey_len);
4351
4352   /* Set CMODE notify type to network */
4353   silc_server_send_notify_cmode(server, SILC_PRIMARY_ROUTE(server),
4354                                 SILC_BROADCAST(server), channel,
4355                                 mode_mask, client->id, SILC_ID_CLIENT,
4356                                 cipher, hmac, passphrase, founder_key);
4357
4358   /* Send command reply to sender */
4359   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
4360                                                 SILC_STATUS_OK, 0, ident, 2,
4361                                                 2, tmp_id, tmp_len2,
4362                                                 3, tmp_mask, 4);
4363   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
4364                           packet->data, packet->len, FALSE);
4365
4366   silc_buffer_free(packet);
4367   silc_buffer_free(cidp);
4368
4369  out:
4370   channel->mode = old_mask;
4371   silc_free(fkey);
4372   silc_free(channel_id);
4373   silc_server_command_free(cmd);
4374 }
4375
4376 /* Server side of CUMODE command. Changes client's mode on a channel. */
4377
4378 SILC_SERVER_CMD_FUNC(cumode)
4379 {
4380   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4381   SilcServer server = cmd->server;
4382   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4383   SilcIDListData idata = (SilcIDListData)client;
4384   SilcChannelID *channel_id;
4385   SilcClientID *client_id;
4386   SilcChannelEntry channel;
4387   SilcClientEntry target_client;
4388   SilcChannelClientEntry chl;
4389   SilcBuffer packet, idp;
4390   unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
4391   SilcUInt32 target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
4392   int notify = FALSE;
4393   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
4394   SilcPublicKey founder_key = NULL;
4395   unsigned char *fkey = NULL;
4396   SilcUInt32 fkey_len = 0;
4397
4398   if (!client)
4399     goto out;
4400
4401   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
4402
4403   /* Get Channel ID */
4404   tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
4405   if (!tmp_ch_id) {
4406     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4407                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
4408     goto out;
4409   }
4410   channel_id = silc_id_payload_parse_id(tmp_ch_id, tmp_ch_len, NULL);
4411   if (!channel_id) {
4412     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4413                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
4414     goto out;
4415   }
4416
4417   /* Get channel entry */
4418   channel = silc_idlist_find_channel_by_id(server->local_list, 
4419                                            channel_id, NULL);
4420   if (!channel) {
4421     channel = silc_idlist_find_channel_by_id(server->global_list, 
4422                                              channel_id, NULL);
4423     if (!channel) {
4424       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4425                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL,
4426                                             0);
4427       goto out;
4428     }
4429   }
4430
4431   /* Check whether sender is on the channel */
4432   if (!silc_server_client_on_channel(client, channel, &chl)) {
4433     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4434                                           SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
4435     goto out;
4436   }
4437   sender_mask = chl->mode;
4438   
4439   /* Get the target client's channel mode mask */
4440   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
4441   if (!tmp_mask) {
4442     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4443                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4444                                           0);
4445     goto out;
4446   }
4447   SILC_GET32_MSB(target_mask, tmp_mask);
4448
4449   /* Get target Client ID */
4450   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
4451   if (!tmp_id) {
4452     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4453                                           SILC_STATUS_ERR_NO_CLIENT_ID, 0);
4454     goto out;
4455   }
4456   client_id = silc_id_payload_parse_id(tmp_id, tmp_len, NULL);
4457   if (!client_id) {
4458     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4459                                           SILC_STATUS_ERR_NO_CLIENT_ID, 0);
4460     goto out;
4461   }
4462
4463   /* Get target client's entry */
4464   target_client = silc_idlist_find_client_by_id(server->local_list, 
4465                                                 client_id, TRUE, NULL);
4466   if (!target_client) {
4467     target_client = silc_idlist_find_client_by_id(server->global_list, 
4468                                                   client_id, TRUE, NULL);
4469   }
4470
4471   if (target_client != client &&
4472       !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
4473       !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
4474     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4475                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0);
4476     goto out;
4477   }
4478
4479   /* Check whether target client is on the channel */
4480   if (target_client != client) {
4481     if (!silc_server_client_on_channel(target_client, channel, &chl)) {
4482       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4483                                  SILC_STATUS_ERR_USER_NOT_ON_CHANNEL, 0);
4484       goto out;
4485     }
4486   }
4487
4488   /* 
4489    * Change the mode 
4490    */
4491
4492   /* If the target client is founder, no one else can change their mode
4493      but themselves. */
4494   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && client != target_client) {
4495     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4496                                           SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
4497                                           0);
4498     goto out;
4499   }
4500
4501   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
4502     if (target_client != client) {
4503       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4504                                             SILC_STATUS_ERR_NOT_YOU, 0);
4505       goto out;
4506     }
4507
4508     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
4509       /* The client tries to claim the founder rights. */
4510       unsigned char *tmp_auth;
4511       SilcUInt32 tmp_auth_len;
4512       SilcChannelClientEntry chl2;
4513       SilcHashTableList htl;
4514
4515       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
4516           !channel->founder_key || !idata->public_key ||
4517           !silc_pkcs_public_key_compare(channel->founder_key, 
4518                                         idata->public_key)) {
4519         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4520                                               SILC_STATUS_ERR_AUTH_FAILED, 0);
4521         goto out;
4522       }
4523
4524       tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
4525       if (!tmp_auth) {
4526         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4527                                               SILC_STATUS_ERR_AUTH_FAILED, 0);
4528         goto out;
4529       }
4530
4531       /* Verify the authentication payload */
4532       if (!silc_auth_verify_data(tmp_auth, tmp_auth_len, SILC_AUTH_PUBLIC_KEY,
4533                                  channel->founder_key, 0, server->sha1hash,
4534                                  client->id, SILC_ID_CLIENT)) {
4535         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4536                                               SILC_STATUS_ERR_AUTH_FAILED, 0);
4537         goto out;
4538       }
4539
4540       notify = TRUE;
4541       founder_key = channel->founder_key;
4542       fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
4543       if (!fkey) {
4544         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4545                                               SILC_STATUS_ERR_AUTH_FAILED, 0);
4546         goto out;
4547       }
4548
4549       /* There cannot be anyone else as founder on the channel now.  This
4550          client is definitely the founder due to this authentication */
4551       silc_hash_table_list(channel->user_list, &htl);
4552       while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
4553         if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
4554           chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
4555           silc_server_force_cumode_change(server, NULL, channel, chl2,
4556                                           chl2->mode);
4557           break;
4558         }
4559       silc_hash_table_list_reset(&htl);
4560
4561       sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
4562     }
4563   } else {
4564     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
4565       if (target_client == client) {
4566         /* Remove channel founder rights from itself */
4567         chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
4568         notify = TRUE;
4569       } else {
4570         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4571                                               SILC_STATUS_ERR_NOT_YOU, 0);
4572         goto out;
4573       }
4574     }
4575   }
4576
4577   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
4578     /* Promote to operator */
4579     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
4580       if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) && 
4581           !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
4582         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4583                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV,
4584                                               0);
4585         goto out;
4586       }
4587
4588       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
4589       notify = TRUE;
4590     }
4591   } else {
4592     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
4593       if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
4594           !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
4595         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,   
4596                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV,
4597                                               0);
4598         goto out;
4599       }
4600       
4601       /* Demote to normal user */
4602       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
4603       notify = TRUE;
4604     }
4605   }
4606
4607   if (target_mask & SILC_CHANNEL_UMODE_BLOCK_MESSAGES) {
4608     if (target_client != client) {
4609       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4610                                             SILC_STATUS_ERR_NOT_YOU, 0);
4611       goto out;
4612     }
4613
4614     if (!(chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)) {
4615       chl->mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
4616       notify = TRUE;
4617     }
4618   } else {
4619     if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES) {
4620       if (target_client != client) {
4621         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4622                                               SILC_STATUS_ERR_NOT_YOU, 0);
4623         goto out;
4624       }
4625
4626       chl->mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
4627       notify = TRUE;
4628     }
4629   }
4630
4631   if (target_mask & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS) {
4632     if (target_client != client) {
4633       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4634                                             SILC_STATUS_ERR_NOT_YOU, 0);
4635       goto out;
4636     }
4637
4638     if (!(chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)) {
4639       chl->mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
4640       notify = TRUE;
4641     }
4642   } else {
4643     if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS) {
4644       if (target_client != client) {
4645         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4646                                               SILC_STATUS_ERR_NOT_YOU, 0);
4647         goto out;
4648       }
4649
4650       chl->mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
4651       notify = TRUE;
4652     }
4653   }
4654
4655   if (target_mask & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS) {
4656     if (target_client != client) {
4657       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4658                                             SILC_STATUS_ERR_NOT_YOU, 0);
4659       goto out;
4660     }
4661
4662     if (!(chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)) {
4663       chl->mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
4664       notify = TRUE;
4665     }
4666   } else {
4667     if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS) {
4668       if (target_client != client) {
4669         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4670                                               SILC_STATUS_ERR_NOT_YOU, 0);
4671         goto out;
4672       }
4673
4674       chl->mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
4675       notify = TRUE;
4676     }
4677   }
4678
4679   if (target_mask & SILC_CHANNEL_UMODE_QUIET) {
4680     if (!(chl->mode & SILC_CHANNEL_UMODE_QUIET)) {
4681       if (client == target_client) {
4682         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4683                                               SILC_STATUS_ERR_PERM_DENIED, 0);
4684         goto out;
4685       }
4686       chl->mode |= SILC_CHANNEL_UMODE_QUIET;
4687       notify = TRUE;
4688     }
4689   } else {
4690     if (chl->mode & SILC_CHANNEL_UMODE_QUIET) {
4691       if (client == target_client) {
4692         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
4693                                               SILC_STATUS_ERR_PERM_DENIED, 0);
4694         goto out;
4695       }
4696       chl->mode &= ~SILC_CHANNEL_UMODE_QUIET;
4697       notify = TRUE;
4698     }
4699   }
4700
4701   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
4702   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
4703
4704   /* Send notify to channel, notify only if mode was actually changed. */
4705   if (notify) {
4706     silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
4707                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
4708                                        idp->data, idp->len,
4709                                        tmp_mask, 4, 
4710                                        tmp_id, tmp_len,
4711                                        fkey, fkey_len);
4712
4713     /* Set CUMODE notify type to network */
4714     silc_server_send_notify_cumode(server, SILC_PRIMARY_ROUTE(server),
4715                                    SILC_BROADCAST(server), channel,
4716                                    target_mask, client->id, SILC_ID_CLIENT,
4717                                    target_client->id, founder_key);
4718   }
4719
4720   /* Send command reply to sender */
4721   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
4722                                                 SILC_STATUS_OK, 0, ident, 3,
4723                                                 2, tmp_mask, 4,
4724                                                 3, tmp_ch_id, tmp_ch_len,
4725                                                 4, tmp_id, tmp_len);
4726   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
4727                           packet->data, packet->len, FALSE);
4728     
4729   silc_buffer_free(packet);
4730   silc_free(channel_id);
4731   silc_free(client_id);
4732   silc_buffer_free(idp);
4733
4734  out:
4735   silc_free(fkey);
4736   silc_server_command_free(cmd);
4737 }
4738
4739 /* Server side of KICK command. Kicks client out of channel. */
4740
4741 SILC_SERVER_CMD_FUNC(kick)
4742 {
4743   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4744   SilcServer server = cmd->server;
4745   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4746   SilcClientEntry target_client;
4747   SilcChannelID *channel_id;
4748   SilcClientID *client_id;
4749   SilcChannelEntry channel;
4750   SilcChannelClientEntry chl;
4751   SilcBuffer idp;
4752   SilcUInt32 tmp_len, target_idp_len;
4753   unsigned char *tmp, *comment, *target_idp;
4754
4755   if (!client)
4756     goto out;
4757
4758   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
4759
4760   /* Get Channel ID */
4761   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4762   if (!tmp) {
4763     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
4764                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
4765     goto out;
4766   }
4767   channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
4768   if (!channel_id) {
4769     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
4770                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
4771     goto out;
4772   }
4773
4774   /* Get channel entry */
4775   channel = silc_idlist_find_channel_by_id(server->local_list, 
4776                                            channel_id, NULL);
4777   if (!channel) {
4778     channel = silc_idlist_find_channel_by_id(server->local_list, 
4779                                              channel_id, NULL);
4780     if (!channel) {
4781       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
4782                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL,
4783                                             0);
4784       goto out;
4785     }
4786   }
4787
4788   /* Check whether sender is on the channel */
4789   if (!silc_server_client_on_channel(client, channel, &chl)) {
4790     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
4791                                           SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
4792     goto out;
4793   }
4794
4795   /* Check that the kicker is channel operator or channel founder */
4796   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
4797       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
4798     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
4799                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0);
4800     goto out;
4801   }
4802   
4803   /* Get target Client ID */
4804   target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
4805   if (!target_idp) {
4806     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
4807                                           SILC_STATUS_ERR_NO_CLIENT_ID, 0);
4808     goto out;
4809   }
4810   client_id = silc_id_payload_parse_id(target_idp, target_idp_len, NULL);
4811   if (!client_id) {
4812     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
4813                                           SILC_STATUS_ERR_NO_CLIENT_ID, 0);
4814     goto out;
4815   }
4816
4817   /* Get target client's entry */
4818   target_client = silc_idlist_find_client_by_id(server->local_list, 
4819                                                 client_id, TRUE, NULL);
4820   if (!target_client) {
4821     target_client = silc_idlist_find_client_by_id(server->global_list, 
4822                                                   client_id, TRUE, NULL);
4823   }
4824
4825   /* Check whether target client is on the channel */
4826   if (!silc_server_client_on_channel(target_client, channel, &chl)) {
4827     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
4828                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL,
4829                                           0);
4830     goto out;
4831   }
4832
4833   /* Check that the target client is not channel founder. Channel founder
4834      cannot be kicked from the channel. */
4835   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
4836     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
4837                                           SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
4838                                           0);
4839     goto out;
4840   }
4841   
4842   /* Get comment */
4843   tmp_len = 0;
4844   comment = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
4845   if (tmp_len > 128)
4846     comment = NULL;
4847
4848   /* Send command reply to sender */
4849   silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK, 
4850                                         SILC_STATUS_OK, 0);
4851
4852   /* Send KICKED notify to local clients on the channel */
4853   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
4854   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
4855                                      SILC_NOTIFY_TYPE_KICKED, 3,
4856                                      target_idp, target_idp_len,
4857                                      comment, comment ? strlen(comment) : 0,
4858                                      idp->data, idp->len);
4859   silc_buffer_free(idp);
4860
4861   /* Send KICKED notify to primary route */
4862   silc_server_send_notify_kicked(server, SILC_PRIMARY_ROUTE(server),
4863                                  SILC_BROADCAST(server), channel,
4864                                  target_client->id, client->id, comment);
4865
4866   /* Remove the client from the channel. If the channel does not exist
4867      after removing the client then the client kicked itself off the channel
4868      and we don't have to send anything after that. */
4869   if (!silc_server_remove_from_one_channel(server, NULL, channel, 
4870                                            target_client, FALSE))
4871     goto out;
4872
4873   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
4874     /* Re-generate channel key */
4875     if (!silc_server_create_channel_key(server, channel, 0))
4876       goto out;
4877     
4878     /* Send the channel key to the channel. The key of course is not sent
4879        to the client who was kicked off the channel. */
4880     silc_server_send_channel_key(server, target_client->connection, channel, 
4881                                  server->server_type == SILC_ROUTER ? 
4882                                  FALSE : !server->standalone);
4883   }
4884
4885  out:
4886   silc_server_command_free(cmd);
4887 }
4888
4889 /* Server side of OPER command. Client uses this comand to obtain server
4890    operator privileges to this server/router. */
4891
4892 SILC_SERVER_CMD_FUNC(oper)
4893 {
4894   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4895   SilcServer server = cmd->server;
4896   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4897   unsigned char *username, *auth;
4898   SilcUInt32 tmp_len;
4899   SilcServerConfigAdmin *admin;
4900   SilcIDListData idata = (SilcIDListData)client;
4901   bool result = FALSE;
4902   SilcPublicKey cached_key;
4903
4904   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
4905     goto out;
4906
4907   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
4908
4909   /* Get the username */
4910   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4911   if (!username) {
4912     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4913                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4914                                           0);
4915     goto out;
4916   }
4917
4918   /* Get the admin configuration */
4919   admin = silc_server_config_find_admin(server, cmd->sock->ip,
4920                                         username, client->nickname);
4921   if (!admin) {
4922     admin = silc_server_config_find_admin(server, cmd->sock->hostname,
4923                                           username, client->nickname);
4924     if (!admin) {
4925       silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4926                                             SILC_STATUS_ERR_AUTH_FAILED,
4927                                             0);
4928       goto out;
4929     }
4930   }
4931
4932   /* Get the authentication payload */
4933   auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4934   if (!auth) {
4935     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4936                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4937                                           0);
4938     goto out;
4939   }
4940
4941   /* Verify the authentication data. If both passphrase and public key
4942      is set then try both of them. */
4943   if (admin->passphrase)
4944     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PASSWORD,
4945                                    admin->passphrase, admin->passphrase_len,
4946                                    idata->hash, client->id, SILC_ID_CLIENT);
4947   if (!result && admin->publickeys) {
4948     cached_key = silc_server_get_public_key(server, admin->publickeys);
4949     if (!cached_key)
4950       goto out;
4951     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
4952                                    cached_key, 0, idata->hash, 
4953                                    client->id, SILC_ID_CLIENT);
4954   }
4955   if (!result) {
4956     /* Authentication failed */
4957     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4958                                           SILC_STATUS_ERR_AUTH_FAILED,
4959                                           0);
4960     goto out;
4961   }
4962
4963   /* Client is now server operator */
4964   client->mode |= SILC_UMODE_SERVER_OPERATOR;
4965
4966   /* Update statistics */
4967   if (SILC_IS_LOCAL(client))
4968     server->stat.my_server_ops++;
4969   if (server->server_type == SILC_ROUTER)
4970     server->stat.server_ops++;
4971
4972   /* Send UMODE change to primary router */
4973   silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
4974                                 SILC_BROADCAST(server), client->id,
4975                                 client->mode);
4976
4977   /* Check if anyone is watching this nickname */
4978   if (server->server_type == SILC_ROUTER)
4979     silc_server_check_watcher_list(server, client, NULL,
4980                                    SILC_NOTIFY_TYPE_UMODE_CHANGE);
4981
4982   /* Send reply to the sender */
4983   silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4984                                         SILC_STATUS_OK, 0);
4985
4986  out:
4987   silc_server_command_free(cmd);
4988 }
4989
4990 SILC_TASK_CALLBACK(silc_server_command_detach_cb)
4991 {
4992   QuitInternal q = (QuitInternal)context;
4993   SilcClientID *client_id = (SilcClientID *)q->sock;
4994   SilcClientEntry client;
4995   SilcSocketConnection sock;
4996
4997   client = silc_idlist_find_client_by_id(q->server->local_list, client_id,
4998                                          TRUE, NULL);
4999   if (client && client->connection) {
5000     sock = client->connection;
5001
5002     /* If there is pending outgoing data for the client then purge it
5003        to the network before closing connection. */
5004     silc_server_packet_queue_purge(q->server, sock);
5005
5006     /* Close the connection on our side */
5007     client->router = NULL;
5008     client->connection = NULL;
5009     sock->user_data = NULL;
5010     silc_server_close_connection(q->server, sock);
5011   }
5012
5013   silc_free(client_id);
5014   silc_free(q);
5015 }
5016
5017 SILC_TASK_CALLBACK(silc_server_command_detach_timeout)
5018 {
5019   QuitInternal q = (QuitInternal)context;
5020   SilcClientID *client_id = (SilcClientID *)q->sock;
5021   SilcClientEntry client;
5022
5023   client = silc_idlist_find_client_by_id(q->server->local_list, client_id,
5024                                          TRUE, NULL);
5025   if (client && client->mode & SILC_UMODE_DETACHED) {
5026     SILC_LOG_DEBUG(("Detach timeout"));
5027     silc_server_free_client_data(q->server, NULL, client, TRUE,
5028                                  "Detach timeout");
5029   }
5030
5031   silc_free(client_id);
5032   silc_free(q);
5033 }
5034
5035 /* Server side of DETACH command.  Detached the client from the network
5036    by closing the connection but preserving the session. */
5037
5038 SILC_SERVER_CMD_FUNC(detach)
5039 {
5040   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5041   SilcServer server = cmd->server;
5042   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
5043   QuitInternal q;
5044
5045   if (server->config->detach_disabled) {
5046     silc_server_command_send_status_reply(cmd, SILC_COMMAND_DETACH,
5047                                           SILC_STATUS_ERR_UNKNOWN_COMMAND, 0);
5048     goto out;
5049   }
5050
5051   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
5052     goto out;
5053
5054   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_DETACH, cmd, 0, 0);
5055
5056   /* Remove operator privileges, since the client may resume in some
5057      other server which to it does not have operator privileges. */
5058   SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
5059   SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
5060
5061   /* Send the user mode notify to notify that client is detached */
5062   client->mode |= SILC_UMODE_DETACHED;
5063   client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
5064   client->last_command = 0;
5065   client->fast_command = 0;
5066   silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
5067                                 SILC_BROADCAST(server), client->id,
5068                                 client->mode);
5069   server->stat.my_detached++;
5070
5071   /* Check if anyone is watching this nickname */
5072   if (server->server_type == SILC_ROUTER)
5073     silc_server_check_watcher_list(server, client, NULL,
5074                                    SILC_NOTIFY_TYPE_UMODE_CHANGE);
5075
5076   q = silc_calloc(1, sizeof(*q));
5077   q->server = server;
5078   q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
5079   silc_schedule_task_add(server->schedule, 0, silc_server_command_detach_cb,
5080                          q, 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
5081
5082   if (server->config->detach_timeout) {
5083     q = silc_calloc(1, sizeof(*q));
5084     q->server = server;
5085     q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
5086     silc_schedule_task_add(server->schedule, 0, 
5087                            silc_server_command_detach_timeout,
5088                            q, server->config->detach_timeout * 60,
5089                            0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
5090   }
5091
5092   /* Send reply to the sender */
5093   silc_server_command_send_status_reply(cmd, SILC_COMMAND_DETACH,
5094                                         SILC_STATUS_OK, 0);
5095
5096  out:
5097   silc_server_command_free(cmd);
5098 }
5099
5100 /* Server side of WATCH command. */
5101
5102 SILC_SERVER_CMD_FUNC(watch)
5103 {
5104   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5105   SilcServer server = cmd->server;
5106   char *add_nick, *del_nick;
5107   SilcUInt32 add_nick_len, del_nick_len, tmp_len;
5108   char nick[128 + 1];
5109   unsigned char hash[16], *tmp;
5110   SilcClientEntry client;
5111   SilcClientID *client_id = NULL;
5112
5113   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WATCH, cmd, 1, 3);
5114
5115   if (server->server_type == SILC_SERVER && !server->standalone) {
5116     if (!cmd->pending) {
5117       /* Send the command to router */
5118       SilcBuffer tmpbuf;
5119       SilcUInt16 old_ident;
5120
5121       old_ident = silc_command_get_ident(cmd->payload);
5122       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
5123       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
5124
5125       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
5126                               SILC_PACKET_COMMAND, cmd->packet->flags,
5127                               tmpbuf->data, tmpbuf->len, TRUE);
5128
5129       /* Reprocess this packet after received reply from router */
5130       silc_server_command_pending(server, SILC_COMMAND_WATCH,
5131                                   silc_command_get_ident(cmd->payload),
5132                                   silc_server_command_watch,
5133                                   silc_server_command_dup(cmd));
5134       cmd->pending = TRUE;
5135       silc_command_set_ident(cmd->payload, old_ident);
5136       silc_buffer_free(tmpbuf);
5137     } else if (context2) {
5138       /* Received reply from router, just send same data to the client. */
5139       SilcServerCommandReplyContext reply = context2;
5140       SilcStatus status;
5141       silc_command_get_status(reply->payload, &status, NULL);
5142       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, status,
5143                                             0);
5144     }
5145
5146     goto out;
5147   }
5148
5149   /* We are router and keep the watch list for local cell */
5150
5151   /* Get the client ID */
5152   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5153   if (!tmp) {
5154     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
5155                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5156                                           0);
5157     goto out;
5158   }
5159   client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
5160   if (!client_id) {
5161     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
5162                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
5163                                           0);
5164     goto out;
5165   }
5166
5167   /* Get the client entry which must be in local list */
5168   client = silc_idlist_find_client_by_id(server->local_list, 
5169                                          client_id, TRUE, NULL);
5170   if (!client) {
5171     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
5172                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
5173                                           0);
5174     goto out;
5175   }
5176
5177   /* Take nickname */
5178   add_nick = silc_argument_get_arg_type(cmd->args, 2, &add_nick_len);
5179   del_nick = silc_argument_get_arg_type(cmd->args, 3, &del_nick_len);
5180   if (!add_nick && !del_nick) {
5181     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
5182                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5183                                           0);
5184     goto out;
5185   }
5186
5187   if (add_nick && add_nick_len > 128)
5188     add_nick[128] = '\0';
5189   if (del_nick && del_nick_len > 128)
5190     del_nick[128] = '\0';
5191
5192   memset(nick, 0, sizeof(nick));
5193
5194   /* Add new nickname to be watched in our cell */
5195   if (add_nick) {
5196     if (silc_server_name_bad_chars(add_nick, strlen(add_nick)) == TRUE) {
5197       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
5198                                             SILC_STATUS_ERR_BAD_NICKNAME, 0);
5199       goto out;
5200     }
5201
5202     /* Hash the nick, we have the hash saved, not nicks because we can
5203        do one to one mapping to the nick from Client ID hash this way. */
5204     silc_to_lower(add_nick, nick, sizeof(nick) - 1);
5205     silc_hash_make(server->md5hash, nick, strlen(nick), hash);
5206
5207     /* Check whether this client is already watching this nickname */
5208     if (silc_hash_table_find_by_context(server->watcher_list, hash, 
5209                                         client, NULL)) {
5210       /* Nickname is alredy being watched for this client */
5211       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
5212                                             SILC_STATUS_ERR_NICKNAME_IN_USE,
5213                                             0);
5214       goto out;
5215     }
5216
5217     /* Get the nickname from the watcher list and use the same key in
5218        new entries as well.  If key doesn't exist then create it. */
5219     if (!silc_hash_table_find(server->watcher_list, hash, (void **)&tmp, NULL))
5220       tmp = silc_memdup(hash, CLIENTID_HASH_LEN);
5221
5222     /* Add the client to the watcher list with the specified nickname hash. */
5223     silc_hash_table_add(server->watcher_list, tmp, client);
5224   }
5225
5226   /* Delete nickname from watch list */
5227   if (del_nick) {
5228     if (silc_server_name_bad_chars(del_nick, strlen(del_nick)) == TRUE) {
5229       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
5230                                             SILC_STATUS_ERR_BAD_NICKNAME, 0);
5231       goto out;
5232     }
5233
5234     /* Hash the nick, we have the hash saved, not nicks because we can
5235        do one to one mapping to the nick from Client ID hash this way. */
5236     silc_to_lower(del_nick, nick, sizeof(nick) - 1);
5237     silc_hash_make(server->md5hash, nick, strlen(nick), hash);
5238
5239     /* Check that this client is watching for this nickname */
5240     if (!silc_hash_table_find_by_context(server->watcher_list, hash, 
5241                                          client, (void **)&tmp)) {
5242       /* Nickname is alredy being watched for this client */
5243       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
5244                                             SILC_STATUS_ERR_NO_SUCH_NICK, 0);
5245       goto out;
5246     }
5247
5248     /* Delete the nickname from the watcher list. */
5249     silc_hash_table_del_by_context(server->watcher_list, hash, client);
5250
5251     /* Now check whether there still exists entries with this key, if not
5252        then free the key to not leak memory. */
5253     if (!silc_hash_table_find(server->watcher_list, hash, NULL, NULL))
5254       silc_free(tmp);
5255   }
5256
5257   /* Distribute the watch list to backup routers too */
5258   if (server->backup) {
5259     SilcBuffer tmpbuf;
5260     silc_command_set_ident(cmd->payload, ++server->cmd_ident);
5261     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
5262     silc_server_backup_send(server, NULL, SILC_PACKET_COMMAND,
5263                             cmd->packet->flags, tmpbuf->data, tmpbuf->len,
5264                             FALSE, TRUE);
5265     silc_buffer_free(tmpbuf);
5266   }
5267
5268   silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
5269                                         SILC_STATUS_OK, 0);
5270
5271  out:
5272   silc_free(client_id);
5273   silc_server_command_free(cmd);
5274 }
5275
5276 /* Server side of SILCOPER command. Client uses this comand to obtain router
5277    operator privileges to this router. */
5278
5279 SILC_SERVER_CMD_FUNC(silcoper)
5280 {
5281   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5282   SilcServer server = cmd->server;
5283   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
5284   unsigned char *username, *auth;
5285   SilcUInt32 tmp_len;
5286   SilcServerConfigAdmin *admin;
5287   SilcIDListData idata = (SilcIDListData)client;
5288   bool result = FALSE;
5289   SilcPublicKey cached_key;
5290
5291   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
5292     goto out;
5293
5294   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
5295
5296   if (server->server_type != SILC_ROUTER) {
5297     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
5298                                           SILC_STATUS_ERR_AUTH_FAILED, 0);
5299     goto out;
5300   }
5301
5302   /* Get the username */
5303   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5304   if (!username) {
5305     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
5306                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5307                                           0);
5308     goto out;
5309   }
5310
5311   /* Get the admin configuration */
5312   admin = silc_server_config_find_admin(server, cmd->sock->ip,
5313                                         username, client->nickname);
5314   if (!admin) {
5315     admin = silc_server_config_find_admin(server, cmd->sock->hostname,
5316                                           username, client->nickname);
5317     if (!admin) {
5318       silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
5319                                             SILC_STATUS_ERR_AUTH_FAILED, 0);
5320       goto out;
5321     }
5322   }
5323
5324   /* Get the authentication payload */
5325   auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
5326   if (!auth) {
5327     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
5328                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5329                                           0);
5330     goto out;
5331   }
5332
5333   /* Verify the authentication data. If both passphrase and public key
5334      is set then try both of them. */
5335   if (admin->passphrase)
5336     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PASSWORD,
5337                                    admin->passphrase, admin->passphrase_len,
5338                                    idata->hash, client->id, SILC_ID_CLIENT);
5339   if (!result && admin->publickeys) {
5340     cached_key = silc_server_get_public_key(server, admin->publickeys);
5341     if (!cached_key)
5342       goto out;
5343     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
5344                                    cached_key, 0, idata->hash, 
5345                                    client->id, SILC_ID_CLIENT);
5346   }
5347   if (!result) {
5348     /* Authentication failed */
5349     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
5350                                           SILC_STATUS_ERR_AUTH_FAILED, 0);
5351     goto out;
5352   }
5353
5354   /* Client is now router operator */
5355   client->mode |= SILC_UMODE_ROUTER_OPERATOR;
5356
5357   /* Update statistics */
5358   if (SILC_IS_LOCAL(client))
5359     server->stat.my_router_ops++;
5360   if (server->server_type == SILC_ROUTER)
5361     server->stat.router_ops++;
5362
5363   /* Send UMODE change to primary router */
5364   silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
5365                                 SILC_BROADCAST(server), client->id,
5366                                 client->mode);
5367
5368   /* Check if anyone is watching this nickname */
5369   if (server->server_type == SILC_ROUTER)
5370     silc_server_check_watcher_list(server, client, NULL,
5371                                    SILC_NOTIFY_TYPE_UMODE_CHANGE);
5372
5373   /* Send reply to the sender */
5374   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
5375                                         SILC_STATUS_OK, 0);
5376
5377  out:
5378   silc_server_command_free(cmd);
5379 }
5380
5381 /* Server side of command BAN. This is used to manage the ban list of the
5382    channel. To add clients and remove clients from the ban list. */
5383
5384 SILC_SERVER_CMD_FUNC(ban)
5385 {
5386   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5387   SilcServer server = cmd->server;
5388   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
5389   SilcBuffer packet;
5390   SilcChannelEntry channel;
5391   SilcChannelClientEntry chl;
5392   SilcChannelID *channel_id = NULL;
5393   unsigned char *id, *add, *del;
5394   SilcUInt32 id_len, tmp_len;
5395   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
5396
5397   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
5398     goto out;
5399
5400   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_BAN, cmd, 0, 3);
5401
5402   /* Get Channel ID */
5403   id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
5404   if (id) {
5405     channel_id = silc_id_payload_parse_id(id, id_len, NULL);
5406     if (!channel_id) {
5407       silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
5408                                             SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
5409       goto out;
5410     }
5411   }
5412
5413   /* Get channel entry. The server must know about the channel since the
5414      client is expected to be on the channel. */
5415   channel = silc_idlist_find_channel_by_id(server->local_list, 
5416                                            channel_id, NULL);
5417   if (!channel) {
5418     channel = silc_idlist_find_channel_by_id(server->global_list, 
5419                                              channel_id, NULL);
5420     if (!channel) {
5421       silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
5422                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL,
5423                                             0);
5424       goto out;
5425     }
5426   }
5427
5428   /* Check whether this client is on the channel */
5429   if (!silc_server_client_on_channel(client, channel, &chl)) {
5430     silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
5431                                           SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
5432     goto out;
5433   }
5434
5435   /* The client must be at least channel operator. */
5436   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
5437     silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
5438                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0);
5439     goto out;
5440   }
5441
5442   /* Get the new ban and add it to the ban list */
5443   add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
5444   if (add) {
5445     if (!channel->ban_list)
5446       channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list));
5447     else
5448       channel->ban_list = silc_realloc(channel->ban_list, 
5449                                        sizeof(*channel->ban_list) * 
5450                                        (tmp_len + 
5451                                         strlen(channel->ban_list) + 2));
5452     if (add[tmp_len - 1] == ',')
5453       add[tmp_len - 1] = '\0';
5454
5455     strncat(channel->ban_list, add, tmp_len);
5456     strncat(channel->ban_list, ",", 1);
5457   }
5458
5459   /* Get the ban to be removed and remove it from the list */
5460   del = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
5461   if (del && channel->ban_list) {
5462     char *start, *end, *n;
5463
5464     if (!strncmp(channel->ban_list, del, strlen(channel->ban_list) - 1)) {
5465       silc_free(channel->ban_list);
5466       channel->ban_list = NULL;
5467     } else {
5468       start = strstr(channel->ban_list, del);
5469       if (start && strlen(start) >= tmp_len) {
5470         end = start + tmp_len;
5471         n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
5472         strncat(n, channel->ban_list, start - channel->ban_list);
5473         strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) - 
5474                              end) - 1);
5475         silc_free(channel->ban_list);
5476         channel->ban_list = n;
5477       }
5478     }
5479   }
5480
5481   /* Send the BAN notify type to our primary router. */
5482   if (add || del)
5483     silc_server_send_notify_ban(server, SILC_PRIMARY_ROUTE(server),
5484                                 SILC_BROADCAST(server), channel, add, del);
5485
5486   /* Send the reply back to the client */
5487   packet = 
5488     silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
5489                                          SILC_STATUS_OK, 0, ident, 2,
5490                                          2, id, id_len,
5491                                          3, channel->ban_list, 
5492                                          channel->ban_list ? 
5493                                          strlen(channel->ban_list) -1 : 0);
5494   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
5495                           packet->data, packet->len, FALSE);
5496     
5497   silc_buffer_free(packet);
5498
5499  out:
5500   silc_free(channel_id);
5501   silc_server_command_free(cmd);
5502 }
5503
5504 /* Server side command of LEAVE. Removes client from a channel. */
5505
5506 SILC_SERVER_CMD_FUNC(leave)
5507 {
5508   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5509   SilcServer server = cmd->server;
5510   SilcSocketConnection sock = cmd->sock;
5511   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
5512   SilcChannelID *id = NULL;
5513   SilcChannelEntry channel;
5514   SilcUInt32 len;
5515   unsigned char *tmp;
5516
5517   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !id_entry)
5518     goto out;
5519
5520   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 2);
5521
5522   /* Get Channel ID */
5523   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
5524   if (!tmp) {
5525     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
5526                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
5527     goto out;
5528   }
5529   id = silc_id_payload_parse_id(tmp, len, NULL);
5530   if (!id) {
5531     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
5532                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
5533     goto out;
5534   }
5535
5536   /* Get channel entry */
5537   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
5538   if (!channel) {
5539     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
5540     if (!channel) {
5541       silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
5542                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL,
5543                                             0);
5544       goto out;
5545     }
5546   }
5547
5548   /* Check whether this client is on the channel */
5549   if (!silc_server_client_on_channel(id_entry, channel, NULL)) {
5550     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
5551                                           SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
5552     goto out;
5553   }
5554
5555   /* Notify routers that they should remove this client from their list
5556      of clients on the channel. Send LEAVE notify type. */
5557   silc_server_send_notify_leave(server, SILC_PRIMARY_ROUTE(server),
5558                                 SILC_BROADCAST(server), channel, id_entry->id);
5559
5560   silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
5561                                        SILC_STATUS_OK, 0, 2, tmp, len);
5562
5563   /* Remove client from channel */
5564   if (!silc_server_remove_from_one_channel(server, sock, channel, id_entry,
5565                                            TRUE))
5566     /* If the channel does not exist anymore we won't send anything */
5567     goto out;
5568
5569   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
5570     /* Re-generate channel key */
5571     if (!silc_server_create_channel_key(server, channel, 0))
5572       goto out;
5573
5574     /* Send the channel key */
5575     silc_server_send_channel_key(server, NULL, channel, 
5576                                  server->server_type == SILC_ROUTER ? 
5577                                  FALSE : !server->standalone);
5578   }
5579
5580  out:
5581   silc_free(id);
5582   silc_server_command_free(cmd);
5583 }
5584
5585 /* Server side of command USERS. Resolves clients and their USERS currently
5586    joined on the requested channel. The list of Client ID's and their modes
5587    on the channel is sent back. */
5588
5589 SILC_SERVER_CMD_FUNC(users)
5590 {
5591   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5592   SilcServer server = cmd->server;
5593   SilcChannelEntry channel;
5594   SilcChannelID *id = NULL;
5595   SilcBuffer packet, idp;
5596   unsigned char *channel_id;
5597   SilcUInt32 channel_id_len;
5598   SilcBuffer client_id_list;
5599   SilcBuffer client_mode_list;
5600   unsigned char lc[4];
5601   SilcUInt32 list_count = 0;
5602   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
5603   char *channel_name;
5604
5605   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_USERS, cmd, 1, 2);
5606
5607   /* Get Channel ID */
5608   channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
5609
5610   /* Get channel name */
5611   channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
5612
5613   if (!channel_id && !channel_name) {
5614     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
5615                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
5616     goto out;
5617   }
5618
5619   if (channel_id) {
5620     id = silc_id_payload_parse_id(channel_id, channel_id_len, NULL);
5621     if (!id) {
5622       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
5623                                             SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
5624       goto out;
5625     }
5626   }
5627
5628   /* If we are server and we don't know about this channel we will send
5629      the command to our router. If we know about the channel then we also
5630      have the list of users already. */
5631   if (id)
5632     channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
5633   else
5634     channel = silc_idlist_find_channel_by_name(server->local_list, 
5635                                                channel_name, NULL);
5636
5637   if (!channel || (!server->standalone && (channel->disabled || 
5638                     !channel->users_resolved))) {
5639     if (server->server_type != SILC_ROUTER && !server->standalone &&
5640         !cmd->pending) {
5641       SilcBuffer tmpbuf;
5642       
5643       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
5644       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
5645       
5646       /* Send USERS command */
5647       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
5648                               SILC_PACKET_COMMAND, cmd->packet->flags,
5649                               tmpbuf->data, tmpbuf->len, TRUE);
5650       
5651       /* Reprocess this packet after received reply */
5652       silc_server_command_pending(server, SILC_COMMAND_USERS, 
5653                                   silc_command_get_ident(cmd->payload),
5654                                   silc_server_command_users,
5655                                   silc_server_command_dup(cmd));
5656       cmd->pending = TRUE;
5657       silc_command_set_ident(cmd->payload, ident);
5658       silc_buffer_free(tmpbuf);
5659       silc_free(id);
5660       goto out;
5661     }
5662
5663     /* Check the global list as well. */
5664     if (id)
5665       channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
5666     else
5667       channel = silc_idlist_find_channel_by_name(server->global_list, 
5668                                                  channel_name, NULL);
5669     if (!channel) {
5670       /* Channel really does not exist */
5671       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
5672                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL,
5673                                             0);
5674       goto out;
5675     }
5676   }
5677
5678   /* If the channel is private or secret do not send anything, unless the
5679      user requesting this command is on the channel or is server */
5680   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
5681     if (channel->mode & (SILC_CHANNEL_MODE_PRIVATE | SILC_CHANNEL_MODE_SECRET)
5682         && !silc_server_client_on_channel(cmd->sock->user_data, channel, 
5683                                           NULL)) {
5684       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
5685                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL,
5686                                             0);
5687       goto out;
5688     }
5689   }
5690
5691   /* Get the users list */
5692   if (!silc_server_get_users_on_channel(server, channel, &client_id_list,
5693                                         &client_mode_list, &list_count)) {
5694     list_count = 0;
5695     client_id_list = NULL;
5696     client_mode_list = NULL;
5697   }
5698
5699   /* List count */
5700   SILC_PUT32_MSB(list_count, lc);
5701
5702   /* Send reply */
5703   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
5704   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
5705                                                 SILC_STATUS_OK, 0, ident, 4,
5706                                                 2, idp->data, idp->len,
5707                                                 3, lc, 4,
5708                                                 4, client_id_list ? 
5709                                                 client_id_list->data : NULL,
5710                                                 client_id_list ?
5711                                                 client_id_list->len : 0,
5712                                                 5, client_mode_list ?
5713                                                 client_mode_list->data : NULL,
5714                                                 client_mode_list ?
5715                                                 client_mode_list->len : 0);
5716   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
5717                           packet->data, packet->len, FALSE);
5718     
5719   silc_buffer_free(idp);
5720   silc_buffer_free(packet);
5721   if (client_id_list)
5722     silc_buffer_free(client_id_list);
5723   if (client_mode_list)
5724     silc_buffer_free(client_mode_list);
5725   silc_free(id);
5726
5727  out:
5728   silc_server_command_free(cmd);
5729 }
5730
5731 /* Server side of command GETKEY. This fetches the client's public key
5732    from the server where to the client is connected. */
5733
5734 SILC_SERVER_CMD_FUNC(getkey)
5735 {
5736   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5737   SilcServer server = cmd->server;
5738   SilcBuffer packet;
5739   SilcClientEntry client;
5740   SilcServerEntry server_entry;
5741   SilcClientID *client_id = NULL;
5742   SilcServerID *server_id = NULL;
5743   SilcIDPayload idp = NULL;
5744   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
5745   unsigned char *tmp, *pkdata;
5746   SilcUInt32 tmp_len, pklen;
5747   SilcBuffer pk = NULL;
5748   SilcIdType id_type;
5749   SilcPublicKey public_key;
5750
5751   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5752   if (!tmp) {
5753     silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
5754                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5755                                           0);
5756     goto out;
5757   }
5758   idp = silc_id_payload_parse(tmp, tmp_len);
5759   if (!idp) {
5760     silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
5761                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5762                                           0);
5763     goto out;
5764   }
5765
5766   id_type = silc_id_payload_get_type(idp);
5767   if (id_type == SILC_ID_CLIENT) {
5768     client_id = silc_id_payload_get_id(idp);
5769
5770     /* If the client is not found from local list there is no chance it
5771        would be locally connected client so send the command further. */
5772     client = silc_idlist_find_client_by_id(server->local_list, 
5773                                            client_id, TRUE, NULL);
5774     if (!client)
5775       client = silc_idlist_find_client_by_id(server->global_list, 
5776                                              client_id, TRUE, NULL);
5777     
5778     if ((!client && !cmd->pending && !server->standalone) ||
5779         (client && !client->connection && !cmd->pending &&
5780          !(client->mode & SILC_UMODE_DETACHED)) ||
5781         (client && !client->data.public_key && !cmd->pending)) {
5782       SilcBuffer tmpbuf;
5783       SilcUInt16 old_ident;
5784       SilcSocketConnection dest_sock;
5785       
5786       dest_sock = silc_server_get_client_route(server, NULL, 0, 
5787                                                client_id, NULL, NULL);
5788       if (!dest_sock)
5789         goto out;
5790       
5791       old_ident = silc_command_get_ident(cmd->payload);
5792       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
5793       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
5794       
5795       silc_server_packet_send(server, dest_sock,
5796                               SILC_PACKET_COMMAND, cmd->packet->flags,
5797                               tmpbuf->data, tmpbuf->len, TRUE);
5798       
5799       /* Reprocess this packet after received reply from router */
5800       silc_server_command_pending(server, SILC_COMMAND_GETKEY, 
5801                                   silc_command_get_ident(cmd->payload),
5802                                   silc_server_command_getkey,
5803                                   silc_server_command_dup(cmd));
5804       cmd->pending = TRUE;
5805       silc_command_set_ident(cmd->payload, old_ident);
5806       silc_buffer_free(tmpbuf);
5807       goto out;
5808     }
5809
5810     if (!client) {
5811       silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
5812                                             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
5813                                             0);
5814       goto out;
5815     }
5816
5817     /* The client is locally connected, just get the public key and
5818        send it back. If they key does not exist then do not send it, 
5819        send just OK reply */
5820     public_key = client->data.public_key;
5821     if (!public_key) {
5822       pkdata = NULL;
5823       pklen = 0;
5824     } else {
5825       tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
5826       pk = silc_buffer_alloc(4 + tmp_len);
5827       silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
5828       silc_buffer_format(pk,
5829                          SILC_STR_UI_SHORT(tmp_len),
5830                          SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
5831                          SILC_STR_UI_XNSTRING(tmp, tmp_len),
5832                          SILC_STR_END);
5833       silc_free(tmp);
5834       pkdata = pk->data;
5835       pklen = pk->len;
5836     }
5837   } else if (id_type == SILC_ID_SERVER) {
5838     server_id = silc_id_payload_get_id(idp);
5839
5840     /* If the server is not found from local list there is no chance it
5841        would be locally connected server so send the command further. */
5842     server_entry = silc_idlist_find_server_by_id(server->local_list, 
5843                                                  server_id, TRUE, NULL);
5844     if (!server_entry)
5845       server_entry = silc_idlist_find_server_by_id(server->global_list, 
5846                                                    server_id, TRUE, NULL);
5847     
5848     if (server_entry != server->id_entry &&
5849         ((!server_entry && !cmd->pending && !server->standalone) ||
5850          (server_entry && !server_entry->connection && !cmd->pending &&
5851           !server->standalone) ||
5852          (server_entry && !server_entry->data.public_key && !cmd->pending &&
5853           !server->standalone))) {
5854       SilcBuffer tmpbuf;
5855       SilcUInt16 old_ident;
5856       
5857       old_ident = silc_command_get_ident(cmd->payload);
5858       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
5859       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
5860       
5861       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
5862                               SILC_PACKET_COMMAND, cmd->packet->flags,
5863                               tmpbuf->data, tmpbuf->len, TRUE);
5864       
5865       /* Reprocess this packet after received reply from router */
5866       silc_server_command_pending(server, SILC_COMMAND_GETKEY, 
5867                                   silc_command_get_ident(cmd->payload),
5868                                   silc_server_command_getkey,
5869                                   silc_server_command_dup(cmd));
5870       cmd->pending = TRUE;
5871       silc_command_set_ident(cmd->payload, old_ident);
5872       silc_buffer_free(tmpbuf);
5873       goto out;
5874     }
5875
5876     if (!server_entry) {
5877       silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
5878                                             SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
5879                                             0);
5880       goto out;
5881     }
5882
5883     /* If they key does not exist then do not send it, send just OK reply */
5884     public_key = (!server_entry->data.public_key ? 
5885                   (server_entry == server->id_entry ? server->public_key :
5886                    NULL) : server_entry->data.public_key);
5887     if (!public_key) {
5888       pkdata = NULL;
5889       pklen = 0;
5890     } else {
5891       tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
5892       pk = silc_buffer_alloc(4 + tmp_len);
5893       silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
5894       silc_buffer_format(pk,
5895                          SILC_STR_UI_SHORT(tmp_len),
5896                          SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
5897                          SILC_STR_UI_XNSTRING(tmp, tmp_len),
5898                          SILC_STR_END);
5899       silc_free(tmp);
5900       pkdata = pk->data;
5901       pklen = pk->len;
5902     }
5903   } else {
5904     goto out;
5905   }
5906
5907   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5908   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY,
5909                                                 SILC_STATUS_OK, 0, ident, 
5910                                                 pkdata ? 2 : 1,
5911                                                 2, tmp, tmp_len,
5912                                                 3, pkdata, pklen);
5913   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
5914                           packet->data, packet->len, FALSE);
5915   silc_buffer_free(packet);
5916
5917   if (pk)
5918     silc_buffer_free(pk);
5919
5920  out:
5921   if (idp)
5922     silc_id_payload_free(idp);
5923   silc_free(client_id);
5924   silc_free(server_id);
5925   silc_server_command_free(cmd);
5926 }
5927
5928
5929 /* Private range commands, specific to this implementation */
5930
5931 /* Server side command of CONNECT. Connects us to the specified remote
5932    server or router. */
5933
5934 SILC_SERVER_CMD_FUNC(connect)
5935 {
5936   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5937   SilcServer server = cmd->server;
5938   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
5939   unsigned char *tmp, *host;
5940   SilcUInt32 tmp_len;
5941   SilcUInt32 port = SILC_PORT;
5942
5943   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
5944     goto out;
5945
5946   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CONNECT, cmd, 1, 2);
5947
5948   /* Check whether client has the permissions. */
5949   if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
5950       !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
5951     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
5952                                           SILC_STATUS_ERR_NO_SERVER_PRIV, 0);
5953     goto out;
5954   }
5955
5956   if (server->server_type == SILC_ROUTER && 
5957       client->mode & SILC_UMODE_SERVER_OPERATOR) {
5958     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
5959                                           SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
5960     goto out;
5961   }
5962
5963   /* Get the remote server */
5964   host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5965   if (!host) {
5966     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
5967                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5968                                           0);
5969     goto out;
5970   }
5971
5972   /* Get port */
5973   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
5974   if (tmp)
5975     SILC_GET32_MSB(port, tmp);
5976
5977   /* Create the connection. It is done with timeout and is async. */
5978   silc_server_create_connection(server, host, port);
5979
5980   /* Send reply to the sender */
5981   silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
5982                                         SILC_STATUS_OK, 0);
5983
5984  out:
5985   silc_server_command_free(cmd);
5986 }
5987
5988 /* Server side command of CLOSE. Closes connection to a specified server. */
5989  
5990 SILC_SERVER_CMD_FUNC(close)
5991 {
5992   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5993   SilcServer server = cmd->server;
5994   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
5995   SilcServerEntry server_entry;
5996   SilcSocketConnection sock;
5997   unsigned char *tmp;
5998   SilcUInt32 tmp_len;
5999   unsigned char *name;
6000   SilcUInt32 port = SILC_PORT;
6001
6002   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
6003     goto out;
6004
6005   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CLOSE, cmd, 1, 2);
6006
6007   /* Check whether client has the permissions. */
6008   if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
6009       !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
6010     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
6011                                           SILC_STATUS_ERR_NO_SERVER_PRIV,
6012                                           0);
6013     goto out;
6014   }
6015
6016   /* Get the remote server */
6017   name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
6018   if (!name) {
6019     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
6020                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
6021                                           0);
6022     goto out;
6023   }
6024
6025   /* Get port */
6026   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
6027   if (tmp)
6028     SILC_GET32_MSB(port, tmp);
6029
6030   server_entry = silc_idlist_find_server_by_conn(server->local_list,
6031                                                  name, port, FALSE, NULL);
6032   if (!server_entry)
6033     server_entry = silc_idlist_find_server_by_conn(server->global_list,
6034                                                    name, port, FALSE, NULL);
6035   if (!server_entry) {
6036     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
6037                                           SILC_STATUS_ERR_NO_SERVER_ID, 0);
6038     goto out;
6039   }
6040
6041   if (server_entry == server->id_entry) {
6042     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
6043                                           SILC_STATUS_ERR_NO_SERVER_ID, 0);
6044     goto out;
6045   }
6046
6047   /* Send reply to the sender */
6048   silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
6049                                         SILC_STATUS_OK, 0);
6050
6051   /* Close the connection to the server */
6052   sock = (SilcSocketConnection)server_entry->connection;
6053
6054   /* If we shutdown primary router connection manually then don't trigger
6055      any reconnect or backup router connections, by setting the router
6056      to NULL here. */
6057   if (server->router == server_entry) {
6058     server->id_entry->router = NULL;
6059     server->router = NULL;
6060     server->standalone = TRUE;
6061   }
6062   silc_server_free_sock_user_data(server, sock, NULL);
6063   silc_server_close_connection(server, sock);
6064   
6065  out:
6066   silc_server_command_free(cmd);
6067 }
6068
6069 /* Server side command of SHUTDOWN. Shutdowns the server and closes all
6070    active connections. */
6071  
6072 SILC_SERVER_CMD_FUNC(shutdown)
6073 {
6074   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
6075   SilcServer server = cmd->server;
6076   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
6077
6078   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
6079     goto out;
6080
6081   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_SHUTDOWN, cmd, 0, 0);
6082
6083   /* Check whether client has the permission. */
6084   if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
6085       !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
6086     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_SHUTDOWN,
6087                                           SILC_STATUS_ERR_NO_SERVER_PRIV,
6088                                           0);
6089     goto out;
6090   }
6091
6092   /* Send reply to the sender */
6093   silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_SHUTDOWN,
6094                                         SILC_STATUS_OK, 0);
6095
6096   /* Then, gracefully, or not, bring the server down. */
6097   silc_server_stop(server);
6098   exit(0);
6099
6100  out:
6101   silc_server_command_free(cmd);
6102 }