Cleaned up WHOIS command.
[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 - 2000 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                                      unsigned int arg_type,
38                                      unsigned char *arg,
39                                      unsigned int arg_len);
40 static void silc_server_command_free(SilcServerCommandContext cmd);
41 void silc_server_command_send_names(SilcServer server,
42                                     SilcSocketConnection sock,
43                                     SilcChannelEntry channel);
44
45 /* Server command list. */
46 SilcServerCommand silc_command_list[] =
47 {
48   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
49   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
50   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
51   SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
52   SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
53   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
54   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
55   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
56   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
57   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
58   SILC_SERVER_CMD(connect, CONNECT, 
59                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
60   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
61   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
62   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
63   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
64   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
65   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
66   SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
67   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
68   SILC_SERVER_CMD(restart, RESTART, 
69                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
70   SILC_SERVER_CMD(close, CLOSE,
71                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
72   SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
73   SILC_SERVER_CMD(silcoper, SILCOPER,
74                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
75   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
76   SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
77
78   { NULL, 0 },
79 };
80
81 #define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max)            \
82 do {                                                                          \
83   unsigned int _argc = silc_argument_get_arg_num(cmd->args);                  \
84                                                                               \
85   SILC_LOG_DEBUG(("Start"));                                                  \
86                                                                               \
87   if (_argc < min) {                                                          \
88     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,            \
89                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
90     silc_server_command_free(cmd);                                            \
91     return;                                                                   \
92   }                                                                           \
93   if (_argc > max) {                                                          \
94     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,            \
95                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);   \
96     silc_server_command_free(cmd);                                            \
97     return;                                                                   \
98   }                                                                           \
99 } while(0)
100
101 /* Returns TRUE if the connection is registered. Unregistered connections
102    usually cannot send commands hence the check. */
103
104 static int silc_server_is_registered(SilcServer server,
105                                      SilcSocketConnection sock,
106                                      SilcServerCommandContext cmd,
107                                      SilcCommand command)
108 {
109   SilcIDListData idata = (SilcIDListData)sock->user_data;
110   if (idata->registered)
111     return TRUE;
112
113   silc_server_command_send_status_reply(cmd, command,
114                                         SILC_STATUS_ERR_NOT_REGISTERED);
115   silc_server_command_free(cmd);
116   return FALSE;
117 }
118
119 /* Processes received command packet. */
120
121 void silc_server_command_process(SilcServer server,
122                                  SilcSocketConnection sock,
123                                  SilcPacketContext *packet)
124 {
125   SilcServerCommandContext ctx;
126   SilcServerCommand *cmd;
127
128 #if 0
129   /* XXX allow commands in but do not execute them more than once per
130      two seconds. */
131
132   /* Check whether it is allowed for this connection to execute any
133      command. */
134   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
135     time_t curtime;
136     SilcClientEntry client = (SilcClientEntry)sock->user_data;
137
138     if (!client)
139       return;
140
141     /* Allow only one command executed in 2 seconds. */
142     curtime = time(NULL);
143     if (client->last_command && (curtime - client->last_command) < 2)
144       return;
145
146     /* Update access time */
147     client->last_command = curtime;
148   }
149 #endif
150   
151   /* Allocate command context. This must be free'd by the
152      command routine receiving it. */
153   ctx = silc_calloc(1, sizeof(*ctx));
154   ctx->server = server;
155   ctx->sock = sock;
156   ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
157   
158   /* Parse the command payload in the packet */
159   ctx->payload = silc_command_payload_parse(packet->buffer);
160   if (!ctx->payload) {
161     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
162     silc_buffer_free(packet->buffer);
163     silc_packet_context_free(packet);
164     silc_free(ctx);
165     return;
166   }
167   ctx->args = silc_command_get_args(ctx->payload);
168   
169   /* Execute command. If this fails the packet is dropped. */
170   for (cmd = silc_command_list; cmd->cb; cmd++)
171     if (cmd->cmd == silc_command_get(ctx->payload)) {
172
173       if (!(cmd->flags & SILC_CF_REG)) {
174         cmd->cb(ctx);
175         break;
176       }
177       
178       if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
179         cmd->cb(ctx);
180         break;
181       }
182     }
183
184   if (cmd == NULL) {
185     SILC_LOG_ERROR(("Unknown command, packet dropped"));
186     silc_server_command_free(ctx);
187     return;
188   }
189 }
190
191 /* Add new pending command to be executed when reply to a command has been
192    received. The `reply_cmd' is the command that will call the `callback'
193    with `context' when reply has been received.  If `ident' is non-zero
194    the `callback' will be executed when received reply with command
195    identifier `ident'. */
196
197 void silc_server_command_pending(SilcServer server,
198                                  SilcCommand reply_cmd,
199                                  unsigned short ident,
200                                  SilcCommandCb callback,
201                                  void *context)
202 {
203   SilcServerCommandPending *reply;
204
205   reply = silc_calloc(1, sizeof(*reply));
206   reply->reply_cmd = reply_cmd;
207   reply->ident = ident;
208   reply->context = context;
209   reply->callback = callback;
210   silc_dlist_add(server->pending_commands, reply);
211 }
212
213 /* Deletes pending command by reply command type. */
214
215 void silc_server_command_pending_del(SilcServer server,
216                                      SilcCommand reply_cmd,
217                                      unsigned short ident)
218 {
219   SilcServerCommandPending *r;
220
221   silc_dlist_start(server->pending_commands);
222   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
223     if (r->reply_cmd == reply_cmd && r->ident == ident) {
224       silc_dlist_del(server->pending_commands, r);
225       break;
226     }
227   }
228 }
229
230 /* Checks for pending commands and marks callbacks to be called from
231    the command reply function. Returns TRUE if there were pending command. */
232
233 int silc_server_command_pending_check(SilcServer server,
234                                       SilcServerCommandReplyContext ctx,
235                                       SilcCommand command, 
236                                       unsigned short ident)
237 {
238   SilcServerCommandPending *r;
239
240   silc_dlist_start(server->pending_commands);
241   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
242     if (r->reply_cmd == command && r->ident == ident) {
243       ctx->context = r->context;
244       ctx->callback = r->callback;
245       ctx->ident = ident;
246       return TRUE;
247     }
248   }
249
250   return FALSE;
251 }
252
253 /* Free's the command context allocated before executing the command */
254
255 static void silc_server_command_free(SilcServerCommandContext cmd)
256 {
257   if (cmd) {
258     if (cmd->payload)
259       silc_command_free_payload(cmd->payload);
260     if (cmd->packet)
261       silc_packet_context_free(cmd->packet);
262     silc_free(cmd);
263   }
264 }
265
266 /* Sends simple status message as command reply packet */
267
268 static void 
269 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
270                                       SilcCommand command,
271                                       SilcCommandStatus status)
272 {
273   SilcBuffer buffer;
274
275   SILC_LOG_DEBUG(("Sending command status %d", status));
276
277   buffer = silc_command_reply_payload_encode_va(command, status, 0, 0);
278   silc_server_packet_send(cmd->server, cmd->sock,
279                           SILC_PACKET_COMMAND_REPLY, 0, 
280                           buffer->data, buffer->len, FALSE);
281   silc_buffer_free(buffer);
282 }
283
284 /* Sends command status reply with one extra argument. The argument
285    type must be sent as argument. */
286
287 static void 
288 silc_server_command_send_status_data(SilcServerCommandContext cmd,
289                                      SilcCommand command,
290                                      SilcCommandStatus status,
291                                      unsigned int arg_type,
292                                      unsigned char *arg,
293                                      unsigned int arg_len)
294 {
295   SilcBuffer buffer;
296
297   SILC_LOG_DEBUG(("Sending command status %d", status));
298
299   buffer = silc_command_reply_payload_encode_va(command, status, 0, 1,
300                                                 arg_type, arg, arg_len);
301   silc_server_packet_send(cmd->server, cmd->sock,
302                           SILC_PACKET_COMMAND_REPLY, 0, 
303                           buffer->data, buffer->len, FALSE);
304   silc_buffer_free(buffer);
305 }
306
307 static int
308 silc_server_command_whois_parse(SilcServerCommandContext cmd,
309                                 SilcClientID **client_id,
310                                 char **nickname,
311                                 char **server_name,
312                                 int *count)
313 {
314   unsigned char *tmp;
315   unsigned int len;
316   unsigned int argc = silc_argument_get_arg_num(cmd->args);
317
318   /* If client ID is in the command it must be used instead of nickname */
319   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
320   if (!tmp) {
321     /* No ID, get the nickname@server string and parse it. */
322     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
323     if (tmp) {
324       if (strchr(tmp, '@')) {
325         len = strcspn(tmp, "@");
326         *nickname = silc_calloc(len + 1, sizeof(char));
327         memcpy(*nickname, tmp, len);
328         *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
329         memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
330       } else {
331         *nickname = strdup(tmp);
332       }
333     } else {
334       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
335                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
336       return FALSE;
337     }
338   } else {
339     /* Command includes ID, use that */
340     *client_id = silc_id_payload_parse_id(tmp, len);
341   }
342
343   /* Get the max count of reply messages allowed */
344   if (argc == 3) {
345     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
346     if (!tmp) {
347       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
348                                             SILC_STATUS_ERR_TOO_MANY_PARAMS);
349       if (*nickname)
350         silc_free(*nickname);
351       if (*server_name)
352         silc_free(*server_name);
353
354       return FALSE;
355     }
356     *count = atoi(tmp);
357   }
358
359   return TRUE;
360 }
361
362 static char
363 silc_server_command_whois_check(SilcServerCommandContext cmd,
364                                 SilcClientEntry *clients,
365                                 unsigned int clients_count)
366 {
367   SilcServer server = cmd->server;
368   int i;
369   SilcClientEntry entry;
370
371   for (i = 0; i < clients_count; i++) {
372     entry = clients[i];
373
374     if (!entry->nickname || !entry->username || !entry->userinfo) {
375       SilcBuffer tmpbuf;
376       
377       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
378       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
379
380       /* Send WHOIS command to fastest route for the client ID */
381       silc_server_packet_send(server,
382                               silc_server_route_get(server, entry->id, 
383                                                     SILC_ID_CLIENT),
384                               SILC_PACKET_COMMAND, cmd->packet->flags,
385                               tmpbuf->data, tmpbuf->len, TRUE);
386       
387       /* Reprocess this packet after received reply */
388       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
389                                   silc_command_get_ident(cmd->payload),
390                                   silc_server_command_whois, (void *)cmd);
391       cmd->pending = TRUE;
392       
393       silc_buffer_free(tmpbuf);
394       return FALSE;
395     }
396   }
397
398   return TRUE;
399 }
400
401 static void
402 silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
403                                      SilcClientEntry *clients,
404                                      unsigned int clients_count)
405 {
406   SilcServer server = cmd->server;
407   char *tmp;
408   int i, count = 0, len;
409   SilcBuffer packet, idp;
410   SilcClientEntry entry;
411   SilcCommandStatus status;
412
413   status = SILC_STATUS_OK;
414   if (clients_count > 1)
415     status = SILC_STATUS_LIST_START;
416
417   for (i = 0; i < clients_count; i++) {
418     entry = clients[i];
419
420     if (count && i - 1 == count)
421       break;
422
423     if (clients_count > 2)
424       status = SILC_STATUS_LIST_ITEM;
425
426     if (clients_count > 1 && i == clients_count - 1)
427       status = SILC_STATUS_LIST_END;
428
429     /* Send WHOIS reply */
430     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
431     tmp = silc_argument_get_first_arg(cmd->args, NULL);
432     
433     /* XXX */
434     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
435       char nh[256], uh[256];
436       unsigned char idle[4];
437       SilcSocketConnection hsock;
438
439       memset(uh, 0, sizeof(uh));
440       memset(nh, 0, sizeof(nh));
441       
442       strncat(nh, entry->nickname, strlen(entry->nickname));
443       strncat(nh, "@", 1);
444       len = entry->router ? strlen(entry->router->server_name) :
445         strlen(server->server_name);
446       strncat(nh, entry->router ? entry->router->server_name :
447               server->server_name, len);
448       
449       strncat(uh, entry->username, strlen(entry->username));
450       strncat(uh, "@", 1);
451       hsock = (SilcSocketConnection)entry->connection;
452       len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
453       strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
454       
455       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
456       
457       /* XXX */
458       if (entry->userinfo)
459         packet = 
460           silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
461                                                status, 0, 5, 
462                                                2, idp->data, idp->len,
463                                                3, nh, strlen(nh),
464                                                4, uh, strlen(uh),
465                                                5, entry->userinfo, 
466                                                strlen(entry->userinfo),
467                                                7, idle, 4);
468       else
469         packet = 
470           silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
471                                                status, 0, 4, 
472                                                2, idp->data, idp->len,
473                                                3, nh, strlen(nh),
474                                                4, uh, strlen(uh),
475                                                7, idle, 4);
476       
477     } else {
478       /* XXX */
479       packet = 
480         silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS, 
481                                              status, 0, 3, 
482                                              2, idp->data, idp->len,
483                                              3, entry->nickname, 
484                                              strlen(entry->nickname),
485                                              4, tmp, strlen(tmp)); /* XXX */
486     }
487     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
488                             0, packet->data, packet->len, FALSE);
489     
490     silc_buffer_free(packet);
491     silc_buffer_free(idp);
492   }
493 }
494
495 static int
496 silc_server_command_whois_from_client(SilcServerCommandContext cmd)
497 {
498   SilcServer server = cmd->server;
499   char *nick = NULL, *server_name = NULL;
500   int count = 0, clients_count;
501   SilcClientID *client_id = NULL;
502   SilcClientEntry *clients = NULL, entry;
503   int ret = 0;
504
505   /* Parse the whois request */
506   if (!silc_server_command_whois_parse(cmd, &client_id, &nick, 
507                                        &server_name, &count))
508     return 0;
509
510   /* Protocol dictates that we must always send the received WHOIS request
511      to our router if we are normal server, so let's do it now unless we
512      are standalone. We will not send any replies to the client until we
513      have received reply from the router. */
514   if (server->server_type == SILC_SERVER && 
515       !cmd->pending && !server->standalone) {
516     SilcBuffer tmpbuf;
517
518     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
519     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
520
521     /* Send WHOIS command to our router */
522     silc_server_packet_send(server, (SilcSocketConnection)
523                             server->router->connection,
524                             SILC_PACKET_COMMAND, cmd->packet->flags,
525                             tmpbuf->data, tmpbuf->len, TRUE);
526
527     /* Reprocess this packet after received reply from router */
528     silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
529                                 silc_command_get_ident(cmd->payload),
530                                 silc_server_command_whois, (void *)cmd);
531     cmd->pending = TRUE;
532
533     silc_buffer_free(tmpbuf);
534     ret = -1;
535     goto out;
536   }
537
538   /* We are ready to process the command request. Let's search for the
539      requested client and send reply to the requesting client. */
540
541   /* Get all clients matching that ID or nickname from local list */
542   if (client_id) {
543     entry = silc_idlist_find_client_by_id(server->local_list, client_id);
544     if (entry) {
545       clients = silc_calloc(1, sizeof(*clients));
546       clients[0] = entry;
547       clients_count = 1;
548     }
549   } else {
550     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
551                                                   nick, server_name,
552                                                   &clients_count);
553   }
554   
555   /* If we are router we will check our global list as well. */
556   if (!clients && server->server_type == SILC_ROUTER) {
557     if (client_id) {
558       entry = silc_idlist_find_client_by_id(server->global_list, client_id);
559       if (entry) {
560         clients = silc_calloc(1, sizeof(*clients));
561         clients[0] = entry;
562         clients_count = 1;
563       }
564     } else {
565       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
566                                                     nick, server_name,
567                                                     &clients_count);
568     }
569   }
570   
571   if (!clients) {
572     /* Such a client really does not exist in the SILC network. */
573     silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
574                                          SILC_STATUS_ERR_NO_SUCH_NICK,
575                                          3, nick, strlen(nick));
576     goto out;
577   }
578
579   /* Router always finds the client entry if it exists in the SILC network.
580      However, it might be incomplete entry and does not include all the
581      mandatory fields that WHOIS command reply requires. Check for these and
582      make query from the server who owns the client if some fields are 
583      missing. */
584   if (server->server_type == SILC_ROUTER &&
585       !silc_server_command_whois_check(cmd, clients, clients_count)) {
586     ret = -1;
587     goto out;
588   }
589
590   /* Send the command reply to the client */
591   silc_server_command_whois_send_reply(cmd, clients, clients_count);
592
593  out:
594   if (clients)
595     silc_free(clients);
596   if (client_id)
597     silc_free(client_id);
598   if (nick)
599     silc_free(nick);
600   if (server_name)
601     silc_free(server_name);
602
603   return ret;
604 }
605
606 static int
607 silc_server_command_whois_from_server(SilcServerCommandContext cmd)
608 {
609   SilcServer server = cmd->server;
610   char *nick = NULL, *server_name = NULL;
611   int count = 0, clients_count;
612   SilcClientID *client_id = NULL;
613   SilcClientEntry *clients = NULL, entry;
614   int ret = 0;
615
616   /* Parse the whois request */
617   if (!silc_server_command_whois_parse(cmd, &client_id, &nick, 
618                                        &server_name, &count))
619     return 0;
620
621   /* Process the command request. Let's search for the requested client and
622      send reply to the requesting server. */
623
624   if (client_id) {
625     entry = silc_idlist_find_client_by_id(server->local_list, client_id);
626     if (entry) {
627       clients = silc_calloc(1, sizeof(*clients));
628       clients[0] = entry;
629       clients_count = 1;
630     }
631   } else {
632     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
633                                                   nick, server_name,
634                                                   &clients_count);
635   }
636   
637   /* If we are router we will check our global list as well. */
638   if (!clients && server->server_type == SILC_ROUTER) {
639     if (client_id) {
640       entry = silc_idlist_find_client_by_id(server->global_list, client_id);
641       if (entry) {
642         clients = silc_calloc(1, sizeof(*clients));
643         clients[0] = entry;
644         clients_count = 1;
645       }
646     } else {
647       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
648                                                     nick, server_name,
649                                                     &clients_count);
650     }
651   }
652
653   if (!clients) {
654     /* Such a client really does not exist in the SILC network. */
655     silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
656                                          SILC_STATUS_ERR_NO_SUCH_NICK,
657                                          3, nick, strlen(nick));
658     goto out;
659   }
660
661   /* Router always finds the client entry if it exists in the SILC network.
662      However, it might be incomplete entry and does not include all the
663      mandatory fields that WHOIS command reply requires. Check for these and
664      make query from the server who owns the client if some fields are 
665      missing. */
666   if (!cmd->pending && server->server_type == SILC_ROUTER &&
667       !silc_server_command_whois_check(cmd, clients, clients_count)) {
668     ret = -1;
669     goto out;
670   }
671
672   /* Send the command reply to the client */
673   silc_server_command_whois_send_reply(cmd, clients, clients_count);
674
675  out:
676   if (clients)
677     silc_free(clients);
678   if (client_id)
679     silc_free(client_id);
680   if (nick)
681     silc_free(nick);
682   if (server_name)
683     silc_free(server_name);
684
685   return ret;
686 }
687
688 /* Server side of command WHOIS. Processes user's query and sends found 
689    results as command replies back to the client. */
690
691 SILC_SERVER_CMD_FUNC(whois)
692 {
693   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
694   int ret;
695
696   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3);
697
698   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
699     ret = silc_server_command_whois_from_client(cmd);
700   else
701     ret = silc_server_command_whois_from_server(cmd);
702
703   if (!ret)
704     silc_server_command_free(cmd);
705 }
706
707 SILC_SERVER_CMD_FUNC(whowas)
708 {
709 }
710
711 SILC_SERVER_CMD_FUNC(identify)
712 {
713   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
714   SilcServer server = cmd->server;
715   char *tmp, *nick = NULL, *server_name = NULL;
716   unsigned int argc, count = 0, len;
717   int use_id = FALSE;
718   SilcClientID *client_id = NULL;
719   SilcClientEntry entry;
720   SilcBuffer packet, idp;
721
722   SILC_LOG_DEBUG(("Start"));
723
724   argc = silc_argument_get_arg_num(cmd->args);
725   if (argc < 1) {
726     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
727                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
728     goto out;
729   }
730   if (argc > 3) {
731     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
732                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
733     goto out;
734   }
735
736   /* If client ID is in the command it must be used instead of nickname */
737   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
738   if (!tmp) {
739
740     /* Get the nickname@server string and parse it. */
741     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
742     if (tmp) {
743       if (strchr(tmp, '@')) {
744         len = strcspn(tmp, "@");
745         nick = silc_calloc(len + 1, sizeof(char));
746         memcpy(nick, tmp, len);
747         server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
748         memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
749       } else {
750         nick = strdup(tmp);
751       }
752     } else {
753       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
754                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
755       goto out;
756     }
757   } else {
758     /* Command includes ID, use that */
759     client_id = silc_id_payload_parse_id(tmp, len);
760     use_id = TRUE;
761   }
762
763   /* Get the max count of reply messages allowed */
764   if (argc == 3) {
765     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
766     if (!tmp) {
767       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
768                                             SILC_STATUS_ERR_TOO_MANY_PARAMS);
769       goto out;
770     }
771     count = atoi(tmp);
772   }
773
774   /* Find client */
775   if (!use_id) {
776     entry = silc_idlist_find_client_by_nickname(server->local_list,
777                                                 nick, NULL);
778     if (!entry)
779       entry = silc_idlist_find_client_by_hash(server->global_list,
780                                               nick, server->md5hash);
781   } else {
782     entry = silc_idlist_find_client_by_id(server->local_list, client_id);
783   }
784
785   /* If client was not found and if we are normal server and are connected
786      to a router we will make global query from the router. */
787   if (!entry && server->server_type == SILC_SERVER && !server->standalone &&
788       !cmd->pending) {
789     SilcBuffer buffer = cmd->packet->buffer;
790     
791     SILC_LOG_DEBUG(("Requesting identify from router"));
792     
793     /* Send IDENTIFY command to our router */
794     silc_buffer_push(buffer, buffer->data - buffer->head);
795     silc_server_packet_forward(server, (SilcSocketConnection)
796                                server->router->connection,
797                                buffer->data, buffer->len, TRUE);
798     return;
799   }
800
801   /* If we are router we have checked our local list by nickname and our
802      global list by hash so far. It is possible that the client is still not
803      found and we'll check it from local list by hash. */
804   if (!entry && server->server_type == SILC_ROUTER)
805     entry = silc_idlist_find_client_by_hash(server->local_list,
806                                             nick, server->md5hash);
807
808   if (!entry) {
809     /* The client definitely does not exist */
810     silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
811                                          SILC_STATUS_ERR_NO_SUCH_NICK,
812                                          3, tmp, strlen(tmp));
813     goto out;
814   }
815
816   /* Send IDENTIFY reply */
817   idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
818   tmp = silc_argument_get_first_arg(cmd->args, NULL);
819   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
820                                                 SILC_STATUS_OK, 0, 2,
821                                                 2, idp->data, idp->len, 
822                                                 3, nick, strlen(nick));
823   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
824     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
825     silc_server_packet_send_dest(server, cmd->sock, 
826                                  SILC_PACKET_COMMAND_REPLY, 0,
827                                  id, cmd->packet->src_id_type,
828                                  packet->data, packet->len, FALSE);
829     silc_free(id);
830   } else {
831     silc_server_packet_send(server, cmd->sock, 
832                             SILC_PACKET_COMMAND_REPLY, 0, 
833                             packet->data, packet->len, FALSE);
834   }
835
836   silc_buffer_free(packet);
837   silc_buffer_free(idp);
838   if (client_id)
839     silc_free(client_id);
840
841  out:
842   if (nick)
843     silc_free(nick);
844   if (server_name)
845     silc_free(server_name);
846   silc_server_command_free(cmd);
847 }
848
849 /* Checks string for bad characters and returns TRUE if they are found. */
850
851 static int silc_server_command_bad_chars(char *nick)
852 {
853   if (strchr(nick, '\\')) return TRUE;
854   if (strchr(nick, '\"')) return TRUE;
855   if (strchr(nick, '´')) return TRUE;
856   if (strchr(nick, '`')) return TRUE;
857   if (strchr(nick, '\'')) return TRUE;
858   if (strchr(nick, '*')) return TRUE;
859   if (strchr(nick, '/')) return TRUE;
860   if (strchr(nick, '@')) return TRUE;
861
862   return FALSE;
863 }
864
865 /* Server side of command NICK. Sets nickname for user. Setting
866    nickname causes generation of a new client ID for the client. The
867    new client ID is sent to the client after changing the nickname. */
868
869 SILC_SERVER_CMD_FUNC(nick)
870 {
871   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
872   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
873   SilcServer server = cmd->server;
874   SilcBuffer packet, nidp, oidp;
875   SilcClientID *new_id;
876   char *nick;
877
878   SILC_LOG_DEBUG(("Start"));
879
880   /* Check number of arguments */
881   if (silc_argument_get_arg_num(cmd->args) < 1) {
882     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
883                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
884     goto out;
885   }
886
887   /* Check nickname */
888   nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
889   if (silc_server_command_bad_chars(nick) == TRUE) {
890     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
891                                           SILC_STATUS_ERR_BAD_NICKNAME);
892     goto out;
893   }
894
895   /* Create new Client ID */
896   silc_id_create_client_id(cmd->server->id, cmd->server->rng, 
897                            cmd->server->md5hash, nick,
898                            &new_id);
899
900   /* Send notify about nickname change to our router. We send the new
901      ID and ask to replace it with the old one. If we are router the
902      packet is broadcasted. */
903   if (!cmd->server->standalone)
904     silc_server_send_replace_id(server, server->router->connection, 
905                                 server->server_type == SILC_SERVER ? 
906                                 FALSE : TRUE, client->id,
907                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
908                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
909
910   /* Remove old cache entry */
911   silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
912                          client->id); 
913
914   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
915
916   /* Free old ID */
917   if (client->id) {
918     memset(client->id, 0, SILC_ID_CLIENT_LEN);
919     silc_free(client->id);
920   }
921
922   /* Save the nickname as this client is our local client */
923   if (client->nickname)
924     silc_free(client->nickname);
925
926   client->nickname = strdup(nick);
927   client->id = new_id;
928
929   /* Update client cache */
930   silc_idcache_add(server->local_list->clients, client->nickname, 
931                    SILC_ID_CLIENT, client->id, (void *)client, TRUE);
932
933   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
934
935   /* Send NICK_CHANGE notify */
936   silc_server_send_notify_on_channels(server, client, 
937                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
938                                       oidp->data, oidp->len, 
939                                       nidp->data, nidp->len);
940
941   /* Send the new Client ID as reply command back to client */
942   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
943                                                 SILC_STATUS_OK, 0, 1, 
944                                                 2, nidp->data, nidp->len);
945   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
946                           0, packet->data, packet->len, FALSE);
947
948   silc_buffer_free(packet);
949   silc_buffer_free(nidp);
950   silc_buffer_free(oidp);
951   
952  out:
953   silc_server_command_free(cmd);
954 }
955
956 SILC_SERVER_CMD_FUNC(list)
957 {
958 }
959
960 /* Server side of TOPIC command. Sets topic for channel and/or returns
961    current topic to client. */
962
963 SILC_SERVER_CMD_FUNC(topic)
964 {
965   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
966   SilcServer server = cmd->server;
967   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
968   SilcChannelID *channel_id;
969   SilcChannelEntry channel;
970   SilcChannelClientEntry chl;
971   SilcBuffer packet, idp;
972   unsigned char *tmp;
973   unsigned int argc, tmp_len;
974
975   /* Check number of arguments */
976   argc = silc_argument_get_arg_num(cmd->args);
977   if (argc < 1) {
978     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
979                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
980     goto out;
981   }
982   if (argc > 2) {
983     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
984                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
985     goto out;
986   }
987
988   /* Get Channel ID */
989   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
990   if (!tmp) {
991     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
992                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
993     goto out;
994   }
995   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
996
997   /* Check whether the channel exists */
998   channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
999   if (!channel) {
1000     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1001                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1002     goto out;
1003   }
1004
1005   if (argc > 1) {
1006     /* Get the topic */
1007     tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1008     if (!tmp) {
1009       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1010                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1011       goto out;
1012     }
1013
1014     if (strlen(tmp) > 256) {
1015       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1016                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1017       goto out;
1018     }
1019
1020     /* See whether has rights to change topic */
1021     silc_list_start(channel->user_list);
1022     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
1023       if (chl->client == client) {
1024         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1025           silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1026                                                 SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1027           goto out;
1028         } else {
1029           break;
1030         }
1031       }
1032     }
1033
1034     /* Set the topic for channel */
1035     if (channel->topic)
1036       silc_free(channel->topic);
1037     channel->topic = strdup(tmp);
1038
1039     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1040
1041     /* Send notify about topic change to all clients on the channel */
1042     silc_server_send_notify_to_channel(server, channel, TRUE,
1043                                        SILC_NOTIFY_TYPE_TOPIC_SET, 2,
1044                                        idp->data, idp->len,
1045                                        channel->topic, strlen(channel->topic));
1046     silc_buffer_free(idp);
1047   }
1048
1049   /* Send the topic to client as reply packet */
1050   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1051   if (channel->topic)
1052     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1053                                                   SILC_STATUS_OK, 0, 2, 
1054                                                   2, idp->data, idp->len,
1055                                                   3, channel->topic, 
1056                                                   strlen(channel->topic));
1057   else
1058     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1059                                                   SILC_STATUS_OK, 0, 1, 
1060                                                   2, idp->data, idp->len);
1061   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1062                           0, packet->data, packet->len, FALSE);
1063
1064   silc_buffer_free(packet);
1065   silc_buffer_free(idp);
1066   silc_free(channel_id);
1067
1068  out:
1069   silc_server_command_free(cmd);
1070 }
1071
1072 /* Server side of INVITE command. Invites some client to join some channel. */
1073
1074 SILC_SERVER_CMD_FUNC(invite)
1075 {
1076   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1077   SilcServer server = cmd->server;
1078   SilcSocketConnection sock = cmd->sock, dest_sock;
1079   SilcClientEntry sender, dest;
1080   SilcClientID *dest_id;
1081   SilcChannelEntry channel;
1082   SilcChannelID *channel_id;
1083   SilcBuffer sidp;
1084   unsigned char *tmp;
1085   unsigned int argc, len;
1086
1087   /* Check number of arguments */
1088   argc = silc_argument_get_arg_num(cmd->args);
1089   if (argc < 1) {
1090     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1091                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1092     goto out;
1093   }
1094   if (argc > 2) {
1095     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1096                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1097     goto out;
1098   }
1099
1100   /* Get destination ID */
1101   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1102   if (!tmp) {
1103     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1104                                           SILC_STATUS_ERR_NO_CLIENT_ID);
1105     goto out;
1106   }
1107   dest_id = silc_id_payload_parse_id(tmp, len);
1108
1109   /* Get Channel ID */
1110   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1111   if (!tmp) {
1112     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1113                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1114     goto out;
1115   }
1116   channel_id = silc_id_payload_parse_id(tmp, len);
1117
1118   /* Check whether the channel exists */
1119   channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
1120   if (!channel) {
1121     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1122                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1123     goto out;
1124   }
1125
1126   /* Check whether the sender of this command is on the channel. */
1127   sender = (SilcClientEntry)sock->user_data;
1128   if (!silc_server_client_on_channel(sender, channel)) {
1129     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1130                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
1131     goto out;
1132   }
1133
1134   /* Check whether the channel is invite-only channel. If yes then the
1135      sender of this command must be at least channel operator. */
1136   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1137     SilcChannelClientEntry chl;
1138
1139     silc_list_start(channel->user_list);
1140     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
1141       if (chl->client == sender) {
1142         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1143           silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1144                                                 SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1145           goto out;
1146         }
1147         break;
1148       }
1149   }
1150
1151   /* Find the connection data for the destination. If it is local we will
1152      send it directly otherwise we will send it to router for routing. */
1153   dest = silc_idlist_find_client_by_id(server->local_list, dest_id);
1154   if (dest)
1155     dest_sock = (SilcSocketConnection)dest->connection;
1156   else
1157     dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
1158
1159   /* Check whether the requested client is already on the channel. */
1160   /* XXX if we are normal server we don't know about global clients on
1161      the channel thus we must request it (NAMES command), check from
1162      local cache as well. */
1163   if (silc_server_client_on_channel(dest, channel)) {
1164     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1165                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1166     goto out;
1167   }
1168
1169   sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
1170
1171   /* Send notify to the client that is invited to the channel */
1172   silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
1173                                SILC_NOTIFY_TYPE_INVITE, 2, 
1174                                sidp->data, sidp->len, tmp, len);
1175
1176   /* Send command reply */
1177   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1178                                         SILC_STATUS_OK);
1179
1180   silc_buffer_free(sidp);
1181
1182  out:
1183   silc_server_command_free(cmd);
1184 }
1185
1186 /* Quits connection to client. This gets called if client won't
1187    close the connection even when it has issued QUIT command. */
1188
1189 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
1190 {
1191   SilcServer server = (SilcServer)context;
1192   SilcSocketConnection sock = server->sockets[fd];
1193
1194   /* Free all client specific data, such as client entry and entires
1195      on channels this client may be on. */
1196   silc_server_free_sock_user_data(server, sock);
1197
1198   /* Close the connection on our side */
1199   silc_server_close_connection(server, sock);
1200 }
1201
1202 /* Quits SILC session. This is the normal way to disconnect client. */
1203  
1204 SILC_SERVER_CMD_FUNC(quit)
1205 {
1206   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1207   SilcServer server = cmd->server;
1208   SilcSocketConnection sock = cmd->sock;
1209
1210   SILC_LOG_DEBUG(("Start"));
1211
1212   /* We quit the connection with little timeout */
1213   silc_task_register(server->timeout_queue, sock->sock,
1214                      silc_server_command_quit_cb, server,
1215                      0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1216
1217   silc_server_command_free(cmd);
1218 }
1219
1220 SILC_SERVER_CMD_FUNC(kill)
1221 {
1222 }
1223
1224 /* Server side of command INFO. This sends information about us to 
1225    the client. If client requested specific server we will send the 
1226    command to that server. */
1227
1228 SILC_SERVER_CMD_FUNC(info)
1229 {
1230   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1231   SilcServer server = cmd->server;
1232   SilcBuffer packet, idp;
1233   unsigned int argc;
1234   char info_string[256], *dest_server;
1235
1236   argc = silc_argument_get_arg_num(cmd->args);
1237   if (argc < 1) {
1238     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1239                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1240     goto out;
1241   }
1242   if (argc > 1) {
1243     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1244                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1245     goto out;
1246   }
1247
1248   /* Get server name */
1249   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
1250   if (!dest_server) {
1251     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1252                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1253     goto out;
1254   }
1255
1256   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
1257     /* Send our reply */
1258     memset(info_string, 0, sizeof(info_string));
1259     snprintf(info_string, sizeof(info_string), 
1260              "location: %s server: %s admin: %s <%s>",
1261              server->config->admin_info->location,
1262              server->config->admin_info->server_type,
1263              server->config->admin_info->admin_name,
1264              server->config->admin_info->admin_email);
1265
1266     idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
1267
1268     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
1269                                                   SILC_STATUS_OK, 0, 2,
1270                                                   2, idp->data, idp->len,
1271                                                   3, info_string, 
1272                                                   strlen(info_string));
1273     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
1274                             packet->data, packet->len, FALSE);
1275     
1276     silc_buffer_free(packet);
1277     silc_buffer_free(idp);
1278   } else {
1279     /* Send this command to the requested server */
1280
1281     if (server->server_type == SILC_SERVER && !server->standalone) {
1282
1283     }
1284
1285     if (server->server_type == SILC_ROUTER) {
1286
1287     }
1288   }
1289   
1290  out:
1291   silc_server_command_free(cmd);
1292 }
1293
1294 SILC_SERVER_CMD_FUNC(connect)
1295 {
1296 }
1297
1298 /* Server side of command PING. This just replies to the ping. */
1299
1300 SILC_SERVER_CMD_FUNC(ping)
1301 {
1302   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1303   SilcServer server = cmd->server;
1304   SilcServerID *id;
1305   unsigned int argc, len;
1306   unsigned char *tmp;
1307
1308   argc = silc_argument_get_arg_num(cmd->args);
1309   if (argc < 1) {
1310     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1311                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1312     goto out;
1313   }
1314   if (argc > 2) {
1315     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1316                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1317     goto out;
1318   }
1319
1320   /* Get Server ID */
1321   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1322   if (!tmp) {
1323     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1324                                           SILC_STATUS_ERR_NO_SERVER_ID);
1325     goto out;
1326   }
1327   id = silc_id_str2id(tmp, SILC_ID_SERVER);
1328   if (!id)
1329     goto out;
1330
1331   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
1332     /* Send our reply */
1333     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1334                                           SILC_STATUS_OK);
1335   } else {
1336     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1337                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1338     goto out;
1339   }
1340
1341   silc_free(id);
1342
1343  out:
1344   silc_server_command_free(cmd);
1345 }
1346
1347 SILC_SERVER_CMD_FUNC(oper)
1348 {
1349 }
1350
1351 typedef struct {
1352   char *channel_name;
1353   char *nickname;
1354   char *username;
1355   char *hostname;
1356   SilcChannelEntry channel;
1357   SilcServer server;
1358   SilcClientEntry client;
1359 } JoinInternalContext;
1360
1361 SILC_TASK_CALLBACK(silc_server_command_join_notify)
1362 {
1363   JoinInternalContext *ctx = (JoinInternalContext *)context;
1364
1365   if (ctx->channel->key && ctx->channel->key_len) {
1366     SilcBuffer clidp;
1367
1368     clidp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT);
1369
1370     silc_server_send_notify_to_channel(ctx->server, ctx->channel, FALSE,
1371                                        SILC_NOTIFY_TYPE_JOIN, 1,
1372                                        clidp->data, clidp->len);
1373 #if 0
1374     /* Send NEW_CHANNEL_USER packet to primary route */
1375     silc_server_send_new_channel_user(server, server->router->connection,
1376                                       server->server_type == SILC_SERVER ?
1377                                       FALSE : TRUE,
1378                                       channel->id, SILC_ID_CHANNEL_LEN,
1379                                       client->id, SILC_ID_CLIENT_LEN);
1380 #endif
1381
1382     /* Send NAMES command reply to the joined channel so the user sees who
1383        is currently on the channel. */
1384     silc_server_command_send_names(ctx->server, ctx->client->connection, 
1385                                    ctx->channel);
1386
1387     silc_buffer_free(clidp);
1388     silc_free(ctx);
1389   } else {
1390     silc_task_register(ctx->server->timeout_queue, fd,
1391                        silc_server_command_join_notify, context,
1392                        0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1393   }
1394 }
1395
1396 /* Assembles NAMES command and executes it. This is called when client
1397    joins to a channel and we wan't to send NAMES command reply to the 
1398    client. */
1399
1400 void silc_server_command_send_names(SilcServer server,
1401                                     SilcSocketConnection sock,
1402                                     SilcChannelEntry channel)
1403 {
1404   SilcServerCommandContext cmd;
1405   SilcBuffer buffer, idp;
1406
1407   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1408   buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1,
1409                                           1, idp->data, idp->len);
1410
1411   cmd = silc_calloc(1, sizeof(*cmd));
1412   cmd->payload = silc_command_payload_parse(buffer);
1413   cmd->args = silc_command_get_args(cmd->payload);
1414   cmd->server = server;
1415   cmd->sock = sock;
1416   cmd->pending = FALSE;
1417
1418   silc_server_command_names((void *)cmd);
1419   silc_free(buffer);
1420   silc_free(idp);
1421 }
1422
1423 /* Internal routine that is called after router has replied to server's
1424    JOIN command it forwarded to the router. The route has joined and possibly
1425    creaetd the channel. This function adds the client to the channel's user
1426    list. */
1427
1428 SILC_SERVER_CMD_FUNC(add_to_channel)
1429 {
1430   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1431   SilcServer server = cmd->server;
1432   SilcClientEntry client;
1433   SilcChannelEntry channel;
1434   SilcChannelClientEntry chl;
1435   char *channel_name;
1436
1437   /* Get channel name */
1438   channel_name = silc_argument_get_arg_type(cmd->args, 1, NULL);
1439
1440   /* Get client entry */
1441   client = (SilcClientEntry)cmd->sock->user_data;
1442
1443   /* Get channel entry */
1444   channel = silc_idlist_find_channel_by_name(server->local_list, channel_name);
1445   if (channel) {
1446     /* Join the client to the channel by adding it to channel's user list.
1447        Add also the channel to client entry's channels list for fast cross-
1448        referencing. */
1449     chl = silc_calloc(1, sizeof(*chl));
1450     //chl->mode = SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO;
1451     chl->client = client;
1452     chl->channel = channel;
1453     silc_list_add(channel->user_list, chl);
1454     silc_list_add(client->channels, chl);
1455   }
1456
1457   silc_server_command_free(cmd);
1458 }
1459
1460 /* Internal routine to join channel. The channel sent to this function
1461    has been either created or resolved from ID lists. This joins the sent
1462    client to the channel. */
1463
1464 static void silc_server_command_join_channel(SilcServer server, 
1465                                              SilcServerCommandContext cmd,
1466                                              SilcChannelEntry channel,
1467                                              int created,
1468                                              unsigned int umode)
1469 {
1470   SilcSocketConnection sock = cmd->sock;
1471   unsigned char *tmp;
1472   unsigned int tmp_len;
1473   unsigned char *passphrase = NULL, mode[4];
1474   SilcClientEntry client;
1475   SilcChannelClientEntry chl;
1476   SilcBuffer reply, chidp, clidp;
1477
1478   if (!channel)
1479     return;
1480
1481   /* Get passphrase */
1482   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1483   if (tmp) {
1484     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1485     memcpy(passphrase, tmp, tmp_len);
1486   }
1487   
1488   /*
1489    * Check channel modes
1490    */
1491
1492   /* Check invite list if channel is invite-only channel */
1493   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1494     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
1495       /* Invite list is specified. Check whether client is invited in the
1496          list. If not, then check whether it has been invited otherwise. */
1497
1498     } else {
1499       /* XXX client must be invited to be able to join the channel */
1500     }
1501   }
1502
1503   /* Check ban list if set */
1504   if (channel->mode & SILC_CHANNEL_MODE_BAN) {
1505
1506   }
1507
1508   /* Check the channel passphrase if set. */
1509   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
1510     if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
1511                               strlen(channel->mode_data.passphrase))) {
1512       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1513                                             SILC_STATUS_ERR_BAD_PASSWORD);
1514       goto out;
1515     }
1516   }
1517
1518   /* Check user count limit if set. */
1519   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
1520     if (silc_list_count(channel->user_list) + 1 > 
1521         channel->mode_data.user_limit) {
1522       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1523                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
1524       goto out;
1525     }
1526   }
1527
1528   /*
1529    * Client is allowed to join to the channel. Make it happen.
1530    */
1531
1532   /* If the JOIN request was forwarded to us we will make a bit slower
1533      query to get the client pointer. Otherwise, we get the client pointer
1534      real easy. */
1535   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1536     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1537     client = silc_idlist_find_client_by_id(server->local_list, id);
1538     if (!client) {
1539       /* XXX */
1540       SILC_LOG_ERROR(("Forwarded join command did not find the client who "
1541                       "wanted to join the channel"));
1542       goto out;
1543     }
1544     silc_free(id);
1545   } else {
1546     client = (SilcClientEntry)sock->user_data;
1547   }
1548
1549   /* Check whether the client already is on the channel */
1550   if (silc_server_client_on_channel(client, channel)) {
1551     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1552                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1553     goto out;
1554   }
1555
1556   /* Generate new channel key as protocol dictates */
1557   if (!created)
1558     silc_server_create_channel_key(server, channel, 0);
1559
1560   /* Join the client to the channel by adding it to channel's user list.
1561      Add also the channel to client entry's channels list for fast cross-
1562      referencing. */
1563   chl = silc_calloc(1, sizeof(*chl));
1564   chl->mode = umode;
1565   chl->client = client;
1566   chl->channel = channel;
1567   silc_list_add(channel->user_list, chl);
1568   silc_list_add(client->channels, chl);
1569
1570   /* Encode Client ID Payload of the original client who wants to join */
1571   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1572
1573   /* Encode command reply packet */
1574   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1575   SILC_PUT32_MSB(channel->mode, mode);
1576   if (!channel->topic) {
1577     reply = 
1578       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1579                                            SILC_STATUS_OK, 0, 3,
1580                                            2, channel->channel_name,
1581                                            strlen(channel->channel_name),
1582                                            3, chidp->data, chidp->len,
1583                                            4, mode, 4);
1584   } else {
1585     reply = 
1586       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1587                                            SILC_STATUS_OK, 0, 4, 
1588                                            2, channel->channel_name, 
1589                                            strlen(channel->channel_name),
1590                                            3, chidp->data, chidp->len,
1591                                            4, mode, 4,
1592                                            5, channel->topic, 
1593                                            strlen(channel->topic));
1594   }
1595     
1596   if (server->server_type == SILC_ROUTER && 
1597       cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1598     /* We are router and server has forwarded this command to us. Send
1599        all replys to the server. */
1600     void *tmpid;
1601
1602     /* Send command reply destined to the original client */
1603     tmpid = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1604     silc_server_packet_send_dest(cmd->server, sock, 
1605                                  SILC_PACKET_COMMAND_REPLY, 0,
1606                                  tmpid, cmd->packet->src_id_type,
1607                                  reply->data, reply->len, FALSE);
1608
1609     /* Distribute new channel key to local cell and local clients. */
1610     silc_server_send_channel_key(server, channel, FALSE);
1611     
1612     /* Distribute JOIN notify into the cell for everbody on the channel */
1613     silc_server_send_notify_to_channel(server, channel, FALSE,
1614                                        SILC_NOTIFY_TYPE_JOIN, 1,
1615                                        clidp->data, clidp->len);
1616
1617     /* Broadcast NEW_CHANNEL_USER packet to primary route */
1618     silc_server_send_new_channel_user(server, server->router->connection,
1619                                       TRUE, channel->id, SILC_ID_CHANNEL_LEN,
1620                                       client->id, SILC_ID_CLIENT_LEN);
1621
1622     silc_free(tmpid);
1623   } else {
1624     /* Client sent the command. Send all replies directly to the client. */
1625
1626     /* Send command reply */
1627     silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
1628                             reply->data, reply->len, FALSE);
1629
1630     /* Send the channel key. Channel key is sent before any other packet
1631        to the channel. */
1632     silc_server_send_channel_key(server, channel, server->standalone ?
1633                                  FALSE : TRUE);
1634     
1635     /* Send JOIN notify to locally connected clients on the channel */
1636     silc_server_send_notify_to_channel(server, channel, FALSE,
1637                                        SILC_NOTIFY_TYPE_JOIN, 1,
1638                                        clidp->data, clidp->len);
1639
1640     /* Send NEW_CHANNEL_USER packet to our primary router */
1641     if (!server->standalone)
1642       silc_server_send_new_channel_user(server, server->router->connection,
1643                                         FALSE, 
1644                                         channel->id, SILC_ID_CHANNEL_LEN,
1645                                         client->id, SILC_ID_CLIENT_LEN);
1646
1647     /* Send NAMES command reply to the joined channel so the user sees who
1648        is currently on the channel. */
1649     silc_server_command_send_names(server, sock, channel);
1650   }
1651
1652   silc_buffer_free(reply);
1653   silc_buffer_free(clidp);
1654   silc_buffer_free(chidp);
1655
1656  out:
1657   if (passphrase)
1658     silc_free(passphrase);
1659 }
1660
1661 /* Server side of command JOIN. Joins client into requested channel. If 
1662    the channel does not exist it will be created. */
1663
1664 SILC_SERVER_CMD_FUNC(join)
1665 {
1666   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1667   SilcServer server = cmd->server;
1668   int argc, tmp_len;
1669   char *tmp, *channel_name = NULL, *cipher = NULL;
1670   SilcChannelEntry channel;
1671   unsigned int umode = 0;
1672   int created = FALSE;
1673
1674   SILC_LOG_DEBUG(("Start"));
1675
1676   /* Check number of parameters */
1677   argc = silc_argument_get_arg_num(cmd->args);
1678   if (argc < 1) {
1679     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1680                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1681     goto out;
1682   }
1683   if (argc > 3) {
1684     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1685                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1686     goto out;
1687   }
1688
1689   /* Get channel name */
1690   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1691   if (!tmp) {
1692     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1693                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1694     goto out;
1695   }
1696   channel_name = tmp;
1697
1698   if (silc_server_command_bad_chars(channel_name) == TRUE) {
1699     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1700                                           SILC_STATUS_ERR_BAD_CHANNEL);
1701     silc_free(channel_name);
1702     goto out;
1703   }
1704
1705   /* Get cipher name */
1706   cipher = silc_argument_get_arg_type(cmd->args, 3, NULL);
1707
1708   /* See if the channel exists */
1709   channel = silc_idlist_find_channel_by_name(server->local_list, channel_name);
1710   if (!channel) {
1711     /* Channel not found */
1712
1713     /* If we are standalone server we don't have a router, we just create 
1714        the channel by ourselves. */
1715     if (server->standalone) {
1716       channel = silc_server_create_new_channel(server, server->id, cipher, 
1717                                                channel_name);
1718       umode |= SILC_CHANNEL_UMODE_CHANOP;
1719       umode |= SILC_CHANNEL_UMODE_CHANFO;
1720       created = TRUE;
1721     } else {
1722
1723       /* The channel does not exist on our server. If we are normal server 
1724          we will send JOIN command to our router which will handle the joining
1725          procedure (either creates the channel if it doesn't exist or joins
1726          the client to it). */
1727       if (server->server_type == SILC_SERVER) {
1728         /* Forward the original JOIN command to the router */
1729         silc_buffer_push(cmd->packet->buffer, 
1730                          cmd->packet->buffer->data - 
1731                          cmd->packet->buffer->head);
1732         silc_server_packet_forward(server, (SilcSocketConnection)
1733                                    server->router->connection,
1734                                    cmd->packet->buffer->data, 
1735                                    cmd->packet->buffer->len, TRUE);
1736
1737         /* Register handler that will be called after the router has replied
1738            to us. We will add the client to the new channel in this callback
1739            function. Will be called from JOIN command reply. */
1740         silc_server_command_pending(server, SILC_COMMAND_JOIN, 
1741                                     ++server->router->data.cmd_ident,
1742                                     silc_server_command_add_to_channel,
1743                                     context);
1744         return;
1745       }
1746       
1747       /* We are router and the channel does not seem exist so we will check
1748          our global list as well for the channel. */
1749       channel = silc_idlist_find_channel_by_name(server->global_list, 
1750                                                  channel_name);
1751       if (!channel) {
1752         /* Channel really does not exist, create it */
1753         channel = silc_server_create_new_channel(server, server->id, cipher, 
1754                                                  channel_name);
1755         umode |= SILC_CHANNEL_UMODE_CHANOP;
1756         umode |= SILC_CHANNEL_UMODE_CHANFO;
1757         created = TRUE;
1758       }
1759     }
1760   }
1761
1762   /* Join to the channel */
1763   silc_server_command_join_channel(server, cmd, channel, created, umode);
1764
1765  out:
1766   silc_server_command_free(cmd);
1767 }
1768
1769 /* Server side of command MOTD. Sends server's current "message of the
1770    day" to the client. */
1771
1772 SILC_SERVER_CMD_FUNC(motd)
1773 {
1774   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1775   SilcServer server = cmd->server;
1776   unsigned int argc;
1777   char *motd;
1778   int motd_len;
1779   
1780   SILC_LOG_DEBUG(("Start"));
1781
1782   argc = silc_argument_get_arg_num(cmd->args);
1783   if (argc < 1) {
1784     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1785                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1786     goto out;
1787   }
1788   if (argc > 2) {
1789     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1790                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1791     goto out;
1792   }
1793
1794   /* XXX show currently only our motd */
1795
1796   if (server->config && server->config->motd && 
1797       server->config->motd->motd_file) {
1798
1799     /* Send motd */
1800     motd = silc_file_read(server->config->motd->motd_file, &motd_len);
1801     if (!motd)
1802       goto out;
1803
1804     motd[motd_len] = 0;
1805     silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
1806                                          SILC_STATUS_OK,
1807                                          2, motd, motd_len);
1808     goto out;
1809   } else {
1810     /* No motd */
1811     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
1812                                           SILC_STATUS_OK);
1813   }
1814
1815  out:
1816   silc_server_command_free(cmd);
1817 }
1818
1819 SILC_SERVER_CMD_FUNC(umode)
1820 {
1821 }
1822
1823 /* Checks that client has rights to add or remove channel modes. If any
1824    of the checks fails FALSE is returned. */
1825
1826 int silc_server_check_cmode_rights(SilcChannelEntry channel,
1827                                    SilcChannelClientEntry client,
1828                                    unsigned int mode)
1829 {
1830   int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
1831   int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
1832
1833   /* Check whether has rights to change anything */
1834   if (!is_op && !is_fo)
1835     return FALSE;
1836
1837   /* Check whether has rights to change everything */
1838   if (is_op && is_fo)
1839     return TRUE;
1840
1841   /* We know that client is channel operator, check that they are not
1842      changing anything that requires channel founder rights. Rest of the
1843      modes are available automatically for channel operator. */
1844
1845   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
1846     if (is_op && !is_fo)
1847       return FALSE;
1848   } else {
1849     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
1850       if (is_op && !is_fo)
1851         return FALSE;
1852     }
1853   }
1854   
1855   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
1856     if (is_op && !is_fo)
1857       return FALSE;
1858   } else {
1859     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
1860       if (is_op && !is_fo)
1861         return FALSE;
1862     }
1863   }
1864
1865   if (mode & SILC_CHANNEL_MODE_CIPHER) {
1866     if (is_op && !is_fo)
1867       return FALSE;
1868   } else {
1869     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
1870       if (is_op && !is_fo)
1871         return FALSE;
1872     }
1873   }
1874   
1875   return TRUE;
1876 }
1877
1878 /* Server side command of CMODE. Changes channel mode */
1879
1880 SILC_SERVER_CMD_FUNC(cmode)
1881 {
1882   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1883   SilcServer server = cmd->server;
1884   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1885   SilcChannelID *channel_id;
1886   SilcChannelEntry channel;
1887   SilcChannelClientEntry chl;
1888   SilcBuffer packet, cidp;
1889   unsigned char *tmp, *tmp_id, *tmp_mask;
1890   unsigned int argc, mode_mask, tmp_len, tmp_len2;
1891
1892   SILC_LOG_DEBUG(("Start"));
1893
1894   argc = silc_argument_get_arg_num(cmd->args);
1895   if (argc < 2) {
1896     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
1897                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1898     goto out;
1899   }
1900   if (argc > 8) {
1901     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
1902                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1903     goto out;
1904   }
1905
1906   /* Get Channel ID */
1907   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
1908   if (!tmp_id) {
1909     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
1910                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1911     goto out;
1912   }
1913   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
1914
1915   /* Get the channel mode mask */
1916   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1917   if (!tmp_mask) {
1918     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
1919                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1920     goto out;
1921   }
1922   SILC_GET32_MSB(mode_mask, tmp_mask);
1923
1924   /* Get channel entry */
1925   channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
1926   if (!channel) {
1927     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
1928                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1929     goto out;
1930   }
1931
1932   /* Check whether this client is on the channel */
1933   if (!silc_server_client_on_channel(client, channel)) {
1934     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
1935                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
1936     goto out;
1937   }
1938
1939   /* Get entry to the channel user list */
1940   silc_list_start(channel->user_list);
1941   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
1942     if (chl->client == client)
1943       break;
1944
1945   /* Check that client has rights to change any requested channel modes */
1946   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
1947     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
1948                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1949     goto out;
1950   }
1951
1952   /*
1953    * Check the modes. Modes that requires nothing special operation are
1954    * not checked here.
1955    */
1956
1957   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
1958     /* Channel uses private keys to protect traffic. Client(s) has set the
1959        key locally they want to use, server does not know that key. */
1960     /* Nothing interesting to do here now */
1961   } else {
1962     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
1963       /* The mode is removed and we need to generate and distribute
1964          new channel key. Clients are not using private channel keys
1965          anymore after this. */
1966
1967       /* XXX Duplicated code, make own function for this!! LEAVE uses this
1968          as well */
1969
1970       /* Re-generate channel key */
1971       silc_server_create_channel_key(server, channel, 0);
1972       
1973       /* Encode channel key payload to be distributed on the channel */
1974       packet = 
1975         silc_channel_key_payload_encode(tmp_len2, tmp_id,
1976                                         strlen(channel->channel_key->
1977                                                cipher->name),
1978                                         channel->channel_key->cipher->name,
1979                                         channel->key_len / 8, channel->key);
1980       
1981       /* If we are normal server then we will send it to our router.  If we
1982          are router we will send it to all local servers that has clients on
1983          the channel */
1984       if (server->server_type == SILC_SERVER) {
1985         if (!server->standalone)
1986           silc_server_packet_send(server, 
1987                                   cmd->server->router->connection,
1988                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1989                                   packet->len, TRUE);
1990       } else {
1991         
1992       }
1993       
1994       /* Send to locally connected clients on the channel */
1995       silc_server_packet_send_local_channel(server, channel, 
1996                                             SILC_PACKET_CHANNEL_KEY, 0,
1997                                             packet->data, packet->len, FALSE);
1998       silc_buffer_free(packet);
1999     }
2000   }
2001   
2002   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
2003     /* User limit is set on channel */
2004     unsigned int user_limit;
2005       
2006     /* Get user limit */
2007     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
2008     if (!tmp) {
2009       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
2010         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2011                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2012         goto out;
2013       }
2014     } else {
2015       SILC_GET32_MSB(user_limit, tmp);
2016       channel->mode_data.user_limit = user_limit;
2017     }
2018   } else {
2019     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
2020       /* User limit mode is unset. Remove user limit */
2021       channel->mode_data.user_limit = 0;
2022   }
2023
2024   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
2025     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
2026       /* Passphrase has been set to channel */
2027       
2028       /* Get the passphrase */
2029       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
2030       if (!tmp) {
2031         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2032                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2033         goto out;
2034       }
2035
2036       /* Save the passphrase */
2037       channel->mode_data.passphrase = strdup(tmp);
2038     }
2039   } else {
2040     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2041       /* Passphrase mode is unset. remove the passphrase */
2042       if (channel->mode_data.passphrase) {
2043         silc_free(channel->mode_data.passphrase);
2044         channel->mode_data.passphrase = NULL;
2045       }
2046     }
2047   }
2048
2049   if (mode_mask & SILC_CHANNEL_MODE_BAN) {
2050     if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
2051       /* Ban list is specified for channel */
2052
2053       /* Get ban list */
2054       tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
2055       if (!tmp) {
2056         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2057                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2058         goto out;
2059       }
2060
2061       /* XXX check that channel founder is not banned */
2062
2063       /* Save the ban list */
2064       channel->mode_data.ban_list = strdup(tmp);
2065     }
2066   } else {
2067     if (channel->mode & SILC_CHANNEL_MODE_BAN) {
2068       /* Ban mode is unset. Remove the entire ban list */
2069       if (channel->mode_data.ban_list) {
2070         silc_free(channel->mode_data.ban_list);
2071         channel->mode_data.ban_list = NULL;
2072       }
2073     }
2074   }
2075
2076   if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
2077     if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
2078       /* Invite list is specified for channel */
2079
2080       /* Get invite list */
2081       tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
2082       if (!tmp) {
2083         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2084                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2085         goto out;
2086       }
2087
2088       /* Save the invite linst */
2089       channel->mode_data.invite_list = strdup(tmp);
2090     }
2091   } else {
2092     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
2093       /* Invite list mode is unset. Remove the entire invite list */
2094       if (channel->mode_data.invite_list) {
2095         silc_free(channel->mode_data.invite_list);
2096         channel->mode_data.invite_list = NULL;
2097       }
2098     }
2099   }
2100
2101   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
2102     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
2103       /* Cipher to use protect the traffic */
2104       unsigned int key_len = 128;
2105       char *cp;
2106
2107       /* Get cipher */
2108       tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
2109       if (!tmp) {
2110         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2111                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2112         goto out;
2113       }
2114
2115       cp = strchr(tmp, ':');
2116       if (cp) {
2117         key_len = atoi(cp);
2118         *cp = '\0';
2119       }
2120
2121       /* XXX Duplicated code, make own function for this!! */
2122     
2123       /* Delete old cipher and allocate the new one */
2124       silc_cipher_free(channel->channel_key);
2125       silc_cipher_alloc(tmp, &channel->channel_key);
2126
2127       key_len /= 8;
2128       if (key_len > 32)
2129         key_len = 32;
2130
2131       /* Re-generate channel key */
2132       silc_server_create_channel_key(server, channel, key_len);
2133     
2134       /* Encode channel key payload to be distributed on the channel */
2135       packet = 
2136         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2137                                         strlen(channel->channel_key->
2138                                                cipher->name),
2139                                         channel->channel_key->cipher->name,
2140                                         channel->key_len / 8, channel->key);
2141     
2142       /* If we are normal server then we will send it to our router.  If we
2143          are router we will send it to all local servers that has clients on
2144          the channel */
2145       if (server->server_type == SILC_SERVER) {
2146         if (!server->standalone)
2147           silc_server_packet_send(server, 
2148                                   cmd->server->router->connection,
2149                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2150                                   packet->len, TRUE);
2151       } else {
2152         
2153       }
2154     
2155       /* Send to locally connected clients on the channel */
2156       silc_server_packet_send_local_channel(server, channel, 
2157                                             SILC_PACKET_CHANNEL_KEY, 0,
2158                                           packet->data, packet->len, FALSE);
2159       silc_buffer_free(packet);
2160     }
2161   } else {
2162     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2163       /* Cipher mode is unset. Remove the cipher and revert back to 
2164          default cipher */
2165
2166       if (channel->mode_data.cipher) {
2167         silc_free(channel->mode_data.cipher);
2168         channel->mode_data.cipher = NULL;
2169         channel->mode_data.key_len = 0;
2170       }
2171
2172       /* Generate new cipher and key for the channel */
2173
2174       /* XXX Duplicated code, make own function for this!! */
2175
2176       /* Delete old cipher and allocate default one */
2177       silc_cipher_free(channel->channel_key);
2178       if (!channel->cipher)
2179         silc_cipher_alloc("twofish", &channel->channel_key);
2180       else
2181         silc_cipher_alloc(channel->cipher, &channel->channel_key);
2182
2183       /* Re-generate channel key */
2184       silc_server_create_channel_key(server, channel, 0);
2185       
2186       /* Encode channel key payload to be distributed on the channel */
2187       packet = 
2188         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2189                                         strlen(channel->channel_key->
2190                                                cipher->name),
2191                                         channel->channel_key->cipher->name,
2192                                         channel->key_len / 8, channel->key);
2193       
2194       /* If we are normal server then we will send it to our router.  If we
2195          are router we will send it to all local servers that has clients on
2196          the channel */
2197       if (server->server_type == SILC_SERVER) {
2198         if (!server->standalone)
2199           silc_server_packet_send(server, 
2200                                   cmd->server->router->connection,
2201                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2202                                   packet->len, TRUE);
2203       } else {
2204         
2205       }
2206       
2207       /* Send to locally connected clients on the channel */
2208       silc_server_packet_send_local_channel(server, channel, 
2209                                             SILC_PACKET_CHANNEL_KEY, 0,
2210                                             packet->data, packet->len, FALSE);
2211       silc_buffer_free(packet);
2212     }
2213   }
2214
2215   /* Finally, set the mode */
2216   channel->mode = mode_mask;
2217
2218   /* Send CMODE_CHANGE notify */
2219   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2220   silc_server_send_notify_to_channel(server, channel, TRUE,
2221                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
2222                                      cidp->data, cidp->len, 
2223                                      tmp_mask, tmp_len);
2224   silc_free(cidp);
2225
2226   /* Send command reply to sender */
2227   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
2228                                                 SILC_STATUS_OK, 0, 1,
2229                                                 2, tmp_mask, 4);
2230   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2231                           packet->data, packet->len, FALSE);
2232     
2233   silc_buffer_free(packet);
2234   silc_free(channel_id);
2235
2236  out:
2237   silc_server_command_free(cmd);
2238 }
2239
2240 /* Server side of CUMODE command. Changes client's mode on a channel. */
2241
2242 SILC_SERVER_CMD_FUNC(cumode)
2243 {
2244   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2245   SilcServer server = cmd->server;
2246   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2247   SilcChannelID *channel_id;
2248   SilcClientID *client_id;
2249   SilcChannelEntry channel;
2250   SilcClientEntry target_client;
2251   SilcChannelClientEntry chl;
2252   SilcBuffer packet, idp;
2253   unsigned char *tmp_id, *tmp_mask;
2254   unsigned int argc, target_mask, sender_mask, tmp_len;
2255   int notify = FALSE;
2256
2257   SILC_LOG_DEBUG(("Start"));
2258
2259   argc = silc_argument_get_arg_num(cmd->args);
2260   if (argc < 3) {
2261     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2262                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2263     goto out;
2264   }
2265   if (argc > 3) {
2266     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2267                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2268     goto out;
2269   }
2270
2271   /* Get Channel ID */
2272   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2273   if (!tmp_id) {
2274     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2275                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2276     goto out;
2277   }
2278   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2279
2280   /* Get channel entry */
2281   channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
2282   if (!channel) {
2283     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2284                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2285     goto out;
2286   }
2287
2288   /* Check whether sender is on the channel */
2289   if (!silc_server_client_on_channel(client, channel)) {
2290     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2291                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2292     goto out;
2293   }
2294
2295   /* Check that client has rights to change other's rights */
2296   silc_list_start(channel->user_list);
2297   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2298     if (chl->client == client) {
2299       if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
2300           !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2301         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2302                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2303         goto out;
2304       }
2305
2306       sender_mask = chl->mode;
2307       break;
2308     }
2309   }
2310   
2311   /* Get the target client's channel mode mask */
2312   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
2313   if (!tmp_mask) {
2314     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2315                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2316     goto out;
2317   }
2318   SILC_GET32_MSB(target_mask, tmp_mask);
2319
2320   /* Get target Client ID */
2321   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2322   if (!tmp_id) {
2323     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2324                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2325     goto out;
2326   }
2327   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2328
2329   /* Get target client's entry */
2330   target_client = silc_idlist_find_client_by_id(server->local_list, client_id);
2331   if (!target_client) {
2332     /* XXX If target client is not one of mine send to primary route */
2333   }
2334
2335   /* Check whether target client is on the channel */
2336   if (!silc_server_client_on_channel(target_client, channel)) {
2337     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2338                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
2339     goto out;
2340   }
2341
2342   /* Get entry to the channel user list */
2343   silc_list_start(channel->user_list);
2344   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2345     if (chl->client == target_client)
2346       break;
2347
2348   /* 
2349    * Change the mode 
2350    */
2351
2352   /* If the target client is founder, no one else can change their mode
2353      but themselves. */
2354   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
2355     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2356                                           SILC_STATUS_ERR_NOT_YOU);
2357     goto out;
2358   }
2359
2360   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
2361     /* Cannot promote anyone to channel founder */
2362     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2363                                           SILC_STATUS_ERR_NOT_YOU);
2364     goto out;
2365   } else {
2366     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
2367       if (target_client == client) {
2368         /* Remove channel founder rights from itself */
2369         chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
2370         notify = TRUE;
2371       } else {
2372         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2373                                               SILC_STATUS_ERR_NOT_YOU);
2374         goto out;
2375       }
2376     }
2377   }
2378
2379   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
2380     /* Promote to operator */
2381     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2382       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
2383       notify = TRUE;
2384     }
2385   } else {
2386     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
2387       /* Demote to normal user */
2388       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
2389       notify = TRUE;
2390     }
2391   }
2392
2393   /* Send notify to channel, notify only if mode was actually changed. */
2394   if (notify) {
2395     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2396     silc_server_send_notify_to_channel(server, channel, TRUE,
2397                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
2398                                        idp->data, idp->len,
2399                                        tmp_mask, 4, tmp_id, tmp_len);
2400     silc_buffer_free(idp);
2401   }
2402
2403   /* Send command reply to sender */
2404   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
2405                                                 SILC_STATUS_OK, 0, 2,
2406                                                 2, tmp_mask, 4,
2407                                                 3, tmp_id, tmp_len);
2408   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2409                           packet->data, packet->len, FALSE);
2410     
2411   silc_buffer_free(packet);
2412   silc_free(channel_id);
2413   silc_free(client_id);
2414
2415  out:
2416   silc_server_command_free(cmd);
2417 }
2418
2419 /* Server side of KICK command. Kicks client out of channel. */
2420
2421 SILC_SERVER_CMD_FUNC(kick)
2422 {
2423 }
2424
2425 SILC_SERVER_CMD_FUNC(restart)
2426 {
2427 }
2428  
2429 SILC_SERVER_CMD_FUNC(close)
2430 {
2431 }
2432  
2433 SILC_SERVER_CMD_FUNC(die)
2434 {
2435 }
2436  
2437 SILC_SERVER_CMD_FUNC(silcoper)
2438 {
2439 }
2440
2441 /* Server side command of LEAVE. Removes client from a channel. */
2442
2443 SILC_SERVER_CMD_FUNC(leave)
2444 {
2445   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2446   SilcServer server = cmd->server;
2447   SilcSocketConnection sock = cmd->sock;
2448   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
2449   SilcChannelID *id;
2450   SilcChannelEntry channel;
2451   SilcBuffer packet;
2452   unsigned int i, argc, len;
2453   unsigned char *tmp;
2454
2455   SILC_LOG_DEBUG(("Start"));
2456
2457   argc = silc_argument_get_arg_num(cmd->args);
2458   if (argc < 1) {
2459     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2460                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2461     goto out;
2462   }
2463   if (argc > 2) {
2464     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2465                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2466     goto out;
2467   }
2468
2469   /* Get Channel ID */
2470   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2471   if (!tmp) {
2472     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2473                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2474     goto out;
2475   }
2476   id = silc_id_payload_parse_id(tmp, len);
2477
2478   /* Get channel entry */
2479   channel = silc_idlist_find_channel_by_id(server->local_list, id);
2480   if (!channel) {
2481     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2482                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2483     goto out;
2484   }
2485
2486   /* Check whether this client is on the channel */
2487   if (!silc_server_client_on_channel(id_entry, channel)) {
2488     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2489                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2490     goto out;
2491   }
2492
2493   /* Notify routers that they should remove this client from their list
2494      of clients on the channel. */
2495   if (!server->standalone)
2496     silc_server_send_remove_channel_user(server, 
2497                                          server->router->connection,
2498                                          server->server_type == SILC_ROUTER ?
2499                                          TRUE : FALSE, id_entry->id, id);
2500
2501   /* Remove client from channel */
2502   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
2503                                           TRUE);
2504   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2505                                         SILC_STATUS_OK);
2506
2507   /* If the channel does not exist anymore we won't send anything */
2508   if (!i)
2509     goto out;
2510
2511   /* Re-generate channel key */
2512   silc_server_create_channel_key(server, channel, 0);
2513
2514   /* Encode channel key payload to be distributed on the channel */
2515   packet = 
2516     silc_channel_key_payload_encode(len, tmp,
2517                                     strlen(channel->channel_key->cipher->name),
2518                                     channel->channel_key->cipher->name,
2519                                     channel->key_len / 8, channel->key);
2520
2521   /* If we are normal server then we will send it to our router.  If we
2522      are router we will send it to all local servers that has clients on
2523      the channel */
2524   if (server->server_type == SILC_SERVER) {
2525     if (!server->standalone)
2526       silc_server_packet_send(server, 
2527                               cmd->server->router->connection,
2528                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2529                               packet->len, TRUE);
2530   } else {
2531
2532   }
2533
2534   /* Send to locally connected clients on the channel */
2535   silc_server_packet_send_local_channel(server, channel, 
2536                                         SILC_PACKET_CHANNEL_KEY, 0,
2537                                         packet->data, packet->len, FALSE);
2538
2539   silc_buffer_free(packet);
2540   silc_free(id);
2541
2542  out:
2543   silc_server_command_free(cmd);
2544 }
2545
2546 /* Server side of command NAMES. Resolves clients and their names currently
2547    joined on the requested channel. The name list is sent back to the
2548    client. */
2549
2550 SILC_SERVER_CMD_FUNC(names)
2551 {
2552   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2553   SilcServer server = cmd->server;
2554   SilcChannelEntry channel;
2555   SilcChannelClientEntry chl;
2556   SilcChannelID *id;
2557   SilcBuffer packet;
2558   unsigned int i, len, len2, tmp_len, argc;
2559   unsigned char *tmp;
2560   char *name_list = NULL, *n;
2561   SilcBuffer client_id_list;
2562   SilcBuffer client_mode_list;
2563
2564   SILC_LOG_DEBUG(("Start"));
2565
2566   argc = silc_argument_get_arg_num(cmd->args);
2567   if (argc < 1) {
2568     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
2569                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2570     goto out;
2571   }
2572   if (argc > 2) {
2573     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
2574                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2575     goto out;
2576   }
2577
2578   /* Get Channel ID */
2579   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2580   if (!tmp) {
2581     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2582                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2583     goto out;
2584   }
2585   id = silc_id_payload_parse_id(tmp, tmp_len);
2586
2587   /* Check whether the channel exists. If we are normal server and the
2588      channel does not exist we will send this same command to our router
2589      which will know if the channel exists. */
2590   channel = silc_idlist_find_channel_by_id(server->local_list, id);
2591   if (!channel) {
2592     if (server->server_type == SILC_SERVER && !server->standalone) {
2593       /* XXX Send names command */
2594
2595       cmd->pending = TRUE;
2596       silc_server_command_pending(server, SILC_COMMAND_NAMES, 0,
2597                                   silc_server_command_names, context);
2598       return;
2599     }
2600
2601     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2602                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2603     goto out;
2604   }
2605
2606   /* Assemble the name list now */
2607   name_list = NULL;
2608   len = 0;
2609   silc_list_start(channel->user_list);
2610   i = 0;
2611   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2612     n = chl->client->nickname;
2613     if (n) {
2614       len2 = strlen(n);
2615       len += len2;
2616       name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
2617       memcpy(name_list + (len - len2), n, len2);
2618       name_list[len] = 0;
2619
2620       if (i == silc_list_count(channel->user_list) - 1)
2621         break;
2622       memcpy(name_list + len, ",", 1);
2623       len++;
2624       i++;
2625     }
2626   }
2627   if (!name_list)
2628     name_list = "";
2629
2630   /* Assemble the Client ID list now */
2631   client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) * 
2632                                      silc_list_count(channel->user_list));
2633   silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
2634   silc_list_start(channel->user_list);
2635   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2636     SilcBuffer idp;
2637
2638     idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
2639     silc_buffer_format(client_id_list,
2640                        SILC_STR_UI_XNSTRING(idp->data, idp->len),
2641                        SILC_STR_END);
2642     silc_buffer_pull(client_id_list, idp->len);
2643     silc_buffer_free(idp);
2644   }
2645   silc_buffer_push(client_id_list, 
2646                    client_id_list->data - client_id_list->head);
2647
2648   /* Assemble mode list */
2649   client_mode_list = silc_buffer_alloc(4 * 
2650                                        silc_list_count(channel->user_list));
2651   silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
2652   silc_list_start(channel->user_list);
2653   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2654     SILC_PUT32_MSB(chl->mode, client_mode_list->data);
2655     silc_buffer_pull(client_mode_list, 4);
2656   }
2657   silc_buffer_push(client_mode_list, 
2658                    client_mode_list->data - client_mode_list->head);
2659
2660   /* Send reply */
2661   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NAMES,
2662                                                 SILC_STATUS_OK, 0, 4,
2663                                                 2, tmp, tmp_len,
2664                                                 3, name_list, 
2665                                                 strlen(name_list),
2666                                                 4, client_id_list->data,
2667                                                 client_id_list->len,
2668                                                 5, client_mode_list->data,
2669                                                 client_mode_list->len);
2670   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2671                           packet->data, packet->len, FALSE);
2672     
2673   silc_buffer_free(packet);
2674   silc_free(name_list);
2675   silc_buffer_free(client_id_list);
2676   silc_buffer_free(client_mode_list);
2677   silc_free(id);
2678
2679  out:
2680   silc_server_command_free(cmd);
2681 }