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