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