Removed command packet processing from server.c and added it to
[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 /*
21  * $Id$
22  * $Log$
23  * Revision 1.8  2000/07/10 05:42:59  priikone
24  *      Removed command packet processing from server.c and added it to
25  *      command.c.
26  *      Implemented INFO command. Added support for testing that
27  *      connections are registered before executing commands.
28  *
29  * Revision 1.7  2000/07/07 06:55:24  priikone
30  *      Do not allow client to join twice on same channel.
31  *
32  * Revision 1.6  2000/07/06 10:20:59  priikone
33  *      Cipher name in joining is not mandatory, removed check.
34  *
35  * Revision 1.5  2000/07/06 07:16:43  priikone
36  *      Fixed a wrong way of sending command replies. The fixed way
37  *      does comply with the protocol.
38  *
39  * Revision 1.4  2000/07/05 06:13:38  priikone
40  *      Added PING, INVITE and NAMES command.
41  *
42  * Revision 1.3  2000/07/03 05:52:22  priikone
43  *      Implemented LEAVE command.
44  *
45  * Revision 1.2  2000/06/28 05:06:38  priikone
46  *      Shorter timeout for channel joining notify.
47  *
48  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
49  *      Imported from internal CVS/Added Log headers.
50  *
51  *
52  */
53
54 #include "serverincludes.h"
55 #include "server_internal.h"
56
57 static int silc_server_is_registered(SilcServer server,
58                                      SilcSocketConnection sock,
59                                      SilcServerCommandContext cmd,
60                                      SilcCommand command);
61 static void 
62 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
63                                       SilcCommand command,
64                                       SilcCommandStatus status);
65 static void 
66 silc_server_command_send_status_data(SilcServerCommandContext cmd,
67                                      SilcCommand command,
68                                      SilcCommandStatus status,
69                                      unsigned int arg_type,
70                                      unsigned char *arg,
71                                      unsigned int arg_len);
72 static void silc_server_command_free(SilcServerCommandContext cmd);
73
74 /* Server command list. */
75 SilcServerCommand silc_command_list[] =
76 {
77   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
78   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
79   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
80   SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
81   SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
82   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
83   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
84   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
85   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
86   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
87   SILC_SERVER_CMD(connect, CONNECT, 
88                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
89   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
90   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
91   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
92   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
93   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
94   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
95   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
96   SILC_SERVER_CMD(restart, RESTART, 
97                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
98   SILC_SERVER_CMD(close, CLOSE,
99                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
100   SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
101   SILC_SERVER_CMD(silcoper, SILCOPER,
102                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
103   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
104   SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
105
106   { NULL, 0 },
107 };
108
109 /* List of pending commands. */
110 SilcServerCommandPending *silc_command_pending = NULL;
111
112 /* Returns TRUE if the connection is registered. Unregistered connections
113    usually cannot send commands hence the check. */
114
115 static int silc_server_is_registered(SilcServer server,
116                                      SilcSocketConnection sock,
117                                      SilcServerCommandContext cmd,
118                                      SilcCommand command)
119 {
120   switch(sock->type) {
121   case SILC_SOCKET_TYPE_CLIENT:
122     {
123       SilcClientList *client = (SilcClientList *)sock->user_data;
124       if (client->registered)
125         return TRUE;
126       break;
127     }
128   case SILC_SOCKET_TYPE_SERVER:
129   case SILC_SOCKET_TYPE_ROUTER:
130     {
131       SilcServerList *serv = (SilcServerList *)sock->user_data;
132       if (serv->registered)
133         return TRUE;
134       break;
135     }
136   default:
137     break;
138   }
139
140   silc_server_command_send_status_reply(cmd, command,
141                                         SILC_STATUS_ERR_NOT_REGISTERED);
142   silc_server_command_free(cmd);
143   return FALSE;
144 }
145
146 /* Processes received command packet. */
147
148 void silc_server_command_process(SilcServer server,
149                                  SilcSocketConnection sock,
150                                  SilcPacketContext *packet)
151 {
152   SilcServerCommandContext ctx;
153   SilcServerCommand *cmd;
154   
155   /* Allocate command context. This must be free'd by the
156      command routine receiving it. */
157   ctx = silc_calloc(1, sizeof(*ctx));
158   ctx->server = server;
159   ctx->sock = sock;
160   ctx->packet = packet; /* Save original packet */
161   
162   /* Parse the command payload in the packet */
163   ctx->payload = silc_command_parse_payload(packet->buffer);
164   if (!ctx->payload) {
165     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
166     silc_buffer_free(packet->buffer);
167     silc_free(ctx);
168     return;
169   }
170   
171   /* Execute command. If this fails the packet is dropped. */
172   for (cmd = silc_command_list; cmd->cb; cmd++)
173     if (cmd->cmd == silc_command_get(ctx->payload)) {
174
175       if (!(cmd->flags & SILC_CF_REG)) {
176         cmd->cb(ctx);
177         break;
178       }
179       
180       if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
181         cmd->cb(ctx);
182         break;
183       }
184     }
185
186   if (cmd == NULL) {
187     SILC_LOG_ERROR(("Unknown command, packet dropped"));
188     silc_free(ctx);
189     return;
190   }
191
192   silc_buffer_free(packet->buffer);
193 }
194
195 /* Add new pending command to the list of pending commands. Currently
196    pending commands are executed from command replies, thus we can
197    execute any command after receiving some specific command reply.
198
199    The argument `reply_cmd' is the command reply from where the callback
200    function is to be called, thus, it IS NOT the command to be executed. */
201
202 void silc_server_command_pending(SilcCommand reply_cmd,
203                                  SilcCommandCb callback,
204                                  void *context)
205 {
206   SilcServerCommandPending *reply, *r;
207
208   reply = silc_calloc(1, sizeof(*reply));
209   reply->reply_cmd = reply_cmd;
210   reply->context = context;
211   reply->callback = callback;
212
213   if (silc_command_pending == NULL) {
214     silc_command_pending = reply;
215     return;
216   }
217
218   for (r = silc_command_pending; r; r = r->next) {
219     if (r->next == NULL) {
220       r->next = reply;
221       break;
222     }
223   }
224 }
225
226 /* Deletes pending command by reply command type. */
227
228 void silc_server_command_pending_del(SilcCommand reply_cmd)
229 {
230   SilcServerCommandPending *r, *tmp;
231   
232   if (silc_command_pending) {
233     if (silc_command_pending->reply_cmd == reply_cmd) {
234       silc_free(silc_command_pending);
235       silc_command_pending = NULL;
236       return;
237     }
238
239     for (r = silc_command_pending; r; r = r->next) {
240       if (r->next && r->next->reply_cmd == reply_cmd) {
241         tmp = r->next;
242         r->next = r->next->next;
243         silc_free(tmp);
244         break;
245       }
246     }
247   }
248 }
249
250 /* Free's the command context allocated before executing the command */
251
252 static void silc_server_command_free(SilcServerCommandContext cmd)
253 {
254   if (cmd) {
255     silc_command_free_payload(cmd->payload);
256     silc_free(cmd);
257   }
258 }
259
260 #define SILC_COMMAND_STATUS_DATA(x) \
261   (
262
263 /* Sends simple status message as command reply packet */
264
265 static void 
266 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
267                                       SilcCommand command,
268                                       SilcCommandStatus status)
269 {
270   SilcBuffer buffer;
271
272   SILC_LOG_DEBUG(("Sending command status %d", status));
273
274   buffer = silc_command_encode_reply_payload_va(command, status, 0);
275   silc_server_packet_send(cmd->server, cmd->sock,
276                           SILC_PACKET_COMMAND_REPLY, 0, 
277                           buffer->data, buffer->len, FALSE);
278   silc_buffer_free(buffer);
279 }
280
281 /* Sends command status reply with one extra argument. The argument
282    type must be sent as argument. */
283
284 static void 
285 silc_server_command_send_status_data(SilcServerCommandContext cmd,
286                                      SilcCommand command,
287                                      SilcCommandStatus status,
288                                      unsigned int arg_type,
289                                      unsigned char *arg,
290                                      unsigned int arg_len)
291 {
292   SilcBuffer buffer;
293
294   SILC_LOG_DEBUG(("Sending command status %d", status));
295
296   buffer = silc_command_encode_reply_payload_va(command, status, 1,
297                                                 arg_type, arg, arg_len);
298   silc_server_packet_send(cmd->server, cmd->sock,
299                           SILC_PACKET_COMMAND_REPLY, 0, 
300                           buffer->data, buffer->len, FALSE);
301   silc_buffer_free(buffer);
302 }
303
304 /* Server side of command WHOIS. Processes user's query and sends found 
305    results as command replies back to the client. */
306
307 SILC_SERVER_CMD_FUNC(whois)
308 {
309   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
310   char *tmp, *nick = NULL, *server = NULL;
311   unsigned int argc, count = 0, len;
312   SilcClientList *entry;
313   SilcBuffer packet;
314   unsigned char *id_string;
315
316   SILC_LOG_DEBUG(("Start"));
317
318   argc = silc_command_get_arg_num(cmd->payload);
319   if (argc < 1) {
320     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
321                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
322     goto out;
323   }
324   if (argc > 2) {
325     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
326                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
327     goto out;
328   }
329
330   /* Get the nickname@server string and parse it. */
331   tmp = silc_command_get_first_arg(cmd->payload, NULL);
332   if (tmp) {
333     if (strchr(tmp, '@')) {
334       len = strcspn(tmp, "@");
335       nick = silc_calloc(len + 1, sizeof(char));
336       memcpy(nick, tmp, len);
337       server = silc_calloc(strlen(tmp) - len, sizeof(char));
338       memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
339     } else {
340       nick = strdup(tmp);
341     }
342   } else {
343     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
344                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
345     goto out;
346   }
347
348   /* Get the max count of reply messages allowed */
349   if (argc == 2) {
350     tmp = silc_command_get_next_arg(cmd->payload, NULL);
351     if (!tmp) {
352       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
353                                             SILC_STATUS_ERR_TOO_MANY_PARAMS);
354       if (nick)
355         silc_free(nick);
356       if (server)
357         silc_free(server);
358       goto out;
359     }
360     count = atoi(tmp);
361   }
362
363   /* Then, make the query from our local client list */
364   entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
365                                               nick, server);
366   if (!entry) {
367
368     /* If we are normal server and are connected to a router we will
369        make global query from the router. */
370     if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
371
372       goto ok;
373     }
374     
375     /* If we are router then we will check our global list as well. */
376     if (cmd->server->server_type == SILC_ROUTER) {
377       entry =
378         silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
379                                             nick, server);
380       if (!entry) {
381         silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
382                                              SILC_STATUS_ERR_NO_SUCH_NICK,
383                                              3, tmp, strlen(tmp));
384         goto out;
385       }
386       goto ok;
387     }
388
389     silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
390                                          SILC_STATUS_ERR_NO_SUCH_NICK,
391                                          3, tmp, strlen(tmp));
392     goto out;
393   }
394
395  ok:
396   /* XXX, works only for local server info */
397
398   /* Send WHOIS reply */
399   id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
400   tmp = silc_command_get_first_arg(cmd->payload, NULL);
401
402   /* XXX */
403   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
404     char nh[256], uh[256];
405     SilcSocketConnection hsock;
406
407     memset(uh, 0, sizeof(uh));
408     memset(nh, 0, sizeof(nh));
409
410     strncat(nh, entry->nickname, strlen(entry->nickname));
411     strncat(nh, "@", 1);
412     len = entry->router ? strlen(entry->router->server_name) :
413       strlen(cmd->server->server_name);
414     strncat(nh, entry->router ? entry->router->server_name :
415             cmd->server->server_name, len);
416
417     strncat(uh, entry->username, strlen(entry->username));
418     strncat(uh, "@", 1);
419     hsock = (SilcSocketConnection)entry->connection;
420     len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
421     strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
422
423     /* XXX */
424     if (entry->userinfo)
425       packet = 
426         silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
427                                              SILC_STATUS_OK, 4, 
428                                              2, id_string, SILC_ID_CLIENT_LEN,
429                                              3, nh, strlen(nh),
430                                              4, uh, strlen(uh),
431                                              5, entry->userinfo, 
432                                              strlen(entry->userinfo));
433     else
434       packet = 
435         silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
436                                              SILC_STATUS_OK, 3, 
437                                              2, id_string, SILC_ID_CLIENT_LEN,
438                                              3, nh, strlen(nh),
439                                              4, uh, strlen(uh));
440
441   } else {
442     /* XXX */
443     packet = 
444       silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS, 
445                                            SILC_STATUS_OK, 3, 
446                                            2, id_string, SILC_ID_CLIENT_LEN,
447                                            3, entry->nickname, 
448                                            strlen(entry->nickname),
449                                            4, tmp, strlen(tmp)); /* XXX */
450   }
451   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
452                           0, packet->data, packet->len, FALSE);
453
454   silc_free(id_string);
455   silc_buffer_free(packet);
456
457  out:
458   silc_server_command_free(cmd);
459 }
460
461 SILC_SERVER_CMD_FUNC(whowas)
462 {
463 }
464
465 SILC_SERVER_CMD_FUNC(identify)
466 {
467   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
468   char *tmp, *nick = NULL, *server = NULL;
469   unsigned int argc, count = 0, len;
470   SilcClientList *entry;  SilcBuffer packet;
471   unsigned char *id_string;
472
473   SILC_LOG_DEBUG(("Start"));
474
475   argc = silc_command_get_arg_num(cmd->payload);
476   if (argc < 1) {
477     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
478                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
479     goto out;
480   }
481   if (argc > 2) {
482     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
483                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
484     goto out;
485   }
486
487   /* Get the nickname@server string and parse it. */
488   tmp = silc_command_get_first_arg(cmd->payload, NULL);
489   if (tmp) {
490     if (strchr(tmp, '@')) {
491       len = strcspn(tmp, "@");
492       nick = silc_calloc(len + 1, sizeof(char));
493       memcpy(nick, tmp, len);
494       server = silc_calloc(strlen(tmp) - len, sizeof(char));
495       memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
496     } else {
497       nick = strdup(tmp);
498     }
499   } else {
500     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
501                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
502     goto out;
503   }
504
505   /* Get the max count of reply messages allowed */
506   if (argc == 2) {
507     tmp = silc_command_get_next_arg(cmd->payload, NULL);
508     if (!tmp) {
509       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
510                                             SILC_STATUS_ERR_TOO_MANY_PARAMS);
511       goto out;
512     }
513     count = atoi(tmp);
514   }
515
516   /* Then, make the query from our local client list */
517   entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
518                                           nick, cmd->server->md5hash);
519   if (!entry) {
520
521     /* If we are normal server and are connected to a router we will
522        make global query from the router. */
523     if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
524       SilcBuffer buffer = cmd->packet->buffer;
525
526       /* Send IDENTIFY command to our router */
527       silc_buffer_push(buffer, buffer->data - buffer->head);
528       silc_server_packet_forward(cmd->server, (SilcSocketConnection)
529                                  cmd->server->id_entry->router->connection,
530                                  buffer->data, buffer->len, TRUE);
531       goto out;
532     }
533     
534     /* If we are router then we will check our global list as well. */
535     if (cmd->server->server_type == SILC_ROUTER) {
536       entry = 
537         silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
538                                         nick, cmd->server->md5hash);
539       if (!entry) {
540         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
541                                              SILC_STATUS_ERR_NO_SUCH_NICK,
542                                              3, tmp, strlen(tmp));
543         goto out;
544       }
545       goto ok;
546     }
547
548     silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
549                                          SILC_STATUS_ERR_NO_SUCH_NICK,
550                                          3, tmp, strlen(tmp));
551     goto out;
552   }
553
554  ok:
555   /* Send IDENTIFY reply */
556   id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
557   tmp = silc_command_get_first_arg(cmd->payload, NULL);
558   packet = silc_command_encode_reply_payload_va(SILC_COMMAND_IDENTIFY,
559                                                 SILC_STATUS_OK, 2,
560                                                 2, id_string, 
561                                                 SILC_ID_CLIENT_LEN,
562                                                 3, nick, strlen(nick));
563 #if 0
564   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
565     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
566     silc_server_packet_send_dest(cmd->server, cmd->sock, 
567                                  SILC_PACKET_COMMAND_REPLY, 0,
568                                  id, cmd->packet->src_id_type,
569                                  packet->data, packet->len, FALSE);
570     silc_free(id);
571   } else
572 #endif
573     silc_server_packet_send(cmd->server, cmd->sock, 
574                             SILC_PACKET_COMMAND_REPLY, 0, 
575                             packet->data, packet->len, FALSE);
576
577   silc_free(id_string);
578   silc_buffer_free(packet);
579
580  out:
581   if (nick)
582     silc_free(nick);
583   if (server)
584     silc_free(server);
585   silc_server_command_free(cmd);
586 }
587
588 /* Checks string for bad characters and returns TRUE if they are found. */
589
590 static int silc_server_command_bad_chars(char *nick)
591 {
592   if (strchr(nick, '\\')) return TRUE;
593   if (strchr(nick, '\"')) return TRUE;
594   if (strchr(nick, '´')) return TRUE;
595   if (strchr(nick, '`')) return TRUE;
596   if (strchr(nick, '\'')) return TRUE;
597   if (strchr(nick, '*')) return TRUE;
598   if (strchr(nick, '/')) return TRUE;
599   if (strchr(nick, '@')) return TRUE;
600
601   return FALSE;
602 }
603
604 /* Server side of command NICK. Sets nickname for user. Setting
605    nickname causes generation of a new client ID for the client. The
606    new client ID is sent to the client after changing the nickname. */
607
608 SILC_SERVER_CMD_FUNC(nick)
609 {
610   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
611   SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
612   SilcServer server = cmd->server;
613   SilcBuffer packet;
614   SilcClientID *new_id;
615   char *id_string;
616   char *nick;
617
618   SILC_LOG_DEBUG(("Start"));
619
620 #define LCC(x) server->local_list->client_cache[(x) - 32]
621 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
622
623   /* Check number of arguments */
624   if (silc_command_get_arg_num(cmd->payload) < 1) {
625     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
626                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
627     goto out;
628   }
629
630   /* Check nickname */
631   nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
632   if (silc_server_command_bad_chars(nick) == TRUE) {
633     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
634                                           SILC_STATUS_ERR_BAD_NICKNAME);
635     goto out;
636   }
637
638   /* Create new Client ID */
639   silc_id_create_client_id(cmd->server->id, cmd->server->rng, 
640                            cmd->server->md5hash, nick,
641                            &new_id);
642
643   /* Send notify about nickname change to our router. We send the new
644      ID and ask to replace it with the old one. */
645   if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
646     silc_server_send_replace_id(server, server->id_entry->router->connection, 
647                                 FALSE, id_entry->id,
648                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
649                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
650
651   /* If we are router we have to distribute the new Client ID to all 
652      routers in SILC. */
653   if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
654     silc_server_send_replace_id(server, server->id_entry->router->connection,  
655                                 TRUE, id_entry->id,
656                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
657                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
658
659   /* Remove old cache entry */
660   silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
661                          LCCC(id_entry->nickname[0]), 
662                          SILC_ID_CLIENT, id_entry->id); 
663   
664   /* Free old ID */
665   if (id_entry->id) {
666     memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
667     silc_free(id_entry->id);
668   }
669
670   /* Save the nickname as this client is our local client */
671   if (id_entry->nickname)
672     silc_free(id_entry->nickname);
673
674   id_entry->nickname = strdup(nick);
675   id_entry->id = new_id;
676
677   /* Update client cache */
678   LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
679                                    id_entry->nickname, SILC_ID_CLIENT, 
680                                    id_entry->id, (void *)id_entry);
681
682   /* Send the new Client ID as reply command back to client */
683   id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
684   packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NICK, 
685                                                 SILC_STATUS_OK, 1, 
686                                                 2, id_string, 
687                                                 SILC_ID_CLIENT_LEN);
688   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
689                           0, packet->data, packet->len, FALSE);
690
691   silc_free(id_string);
692   silc_buffer_free(packet);
693
694  out:
695   silc_server_command_free(cmd);
696 #undef LCC
697 #undef LCCC
698 }
699
700 SILC_SERVER_CMD_FUNC(list)
701 {
702 }
703
704 SILC_SERVER_CMD_FUNC(topic)
705 {
706 }
707
708 /* Server side of INVITE command. Invites some client to join some channel. */
709
710 SILC_SERVER_CMD_FUNC(invite)
711 {
712   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
713   SilcServer server = cmd->server;
714   SilcSocketConnection sock = cmd->sock, dest_sock;
715   SilcClientList *sender, *dest;
716   SilcClientID *dest_id;
717   SilcChannelList *channel;
718   SilcChannelID *channel_id;
719   unsigned int argc, len;
720   unsigned char *id_string;
721
722   /* Check number of arguments */
723   argc = silc_command_get_arg_num(cmd->payload);
724   if (argc < 1) {
725     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
726                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
727     goto out;
728   }
729   if (argc > 2) {
730     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
731                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
732     goto out;
733   }
734
735   /* Get destination ID */
736   id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
737   if (!id_string) {
738     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
739                                           SILC_STATUS_ERR_NO_CLIENT_ID);
740     goto out;
741   }
742   dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
743
744   /* Get Channel ID */
745   id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
746   if (!id_string) {
747     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
748                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
749     goto out;
750   }
751   channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
752
753   /* Check whether the channel exists */
754   channel = silc_idlist_find_channel_by_id(server->local_list->channels, 
755                                            channel_id);
756   if (!channel) {
757     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
758                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
759     goto out;
760   }
761
762   /* Check whether the sender of this command is on the channel. */
763   sender = (SilcClientList *)sock->user_data;
764   if (!silc_server_client_on_channel(sender, channel)) {
765     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
766                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
767     goto out;
768   }
769
770   /* Check whether the channel is invite-only channel. If yes then the
771      sender of this command must be at least channel operator. */
772   /* XXX */
773
774   /* Find the connection data for the destination. If it is local we will
775      send it directly otherwise we will send it to router for routing. */
776   dest = silc_idlist_find_client_by_id(server->local_list->clients, dest_id);
777   if (dest)
778     dest_sock = (SilcSocketConnection)dest->connection;
779   else
780     dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
781
782   /* Check whether the requested client is already on the channel. */
783   /* XXX if we are normal server we don't know about global clients on
784      the channel thus we must request it (NAMES command), check from
785      local cache as well. */
786   if (silc_server_client_on_channel(dest, channel)) {
787     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
788                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
789     goto out;
790   }
791
792   /* Send notify to the client that is invited to the channel */
793   silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
794                                "%s invites you to channel %s",
795                                sender->nickname, channel->channel_name);
796
797   /* Send command reply */
798   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
799                                         SILC_STATUS_OK);
800
801  out:
802   silc_server_command_free(cmd);
803 }
804
805 /* Quits connection to client. This gets called if client won't
806    close the connection even when it has issued QUIT command. */
807
808 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
809 {
810   SilcServer server = (SilcServer)context;
811   SilcSocketConnection sock = server->sockets[fd];
812
813   /* Free all client specific data, such as client entry and entires
814      on channels this client may be on. */
815   silc_server_free_sock_user_data(server, sock);
816
817   /* Close the connection on our side */
818   silc_server_close_connection(server, sock);
819 }
820
821 /* Quits SILC session. This is the normal way to disconnect client. */
822  
823 SILC_SERVER_CMD_FUNC(quit)
824 {
825   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
826   SilcServer server = cmd->server;
827   SilcSocketConnection sock = cmd->sock;
828
829   SILC_LOG_DEBUG(("Start"));
830
831   /* We quit the connection with little timeout */
832   silc_task_register(server->timeout_queue, sock->sock,
833                      silc_server_command_quit_cb, server,
834                      0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
835
836   silc_server_command_free(cmd);
837 }
838
839 SILC_SERVER_CMD_FUNC(kill)
840 {
841 }
842
843 /* Server side of command INFO. This sends information about us to 
844    the client. If client requested specific server we will send the 
845    command to that server. */
846
847 SILC_SERVER_CMD_FUNC(info)
848 {
849   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
850   SilcServer server = cmd->server;
851   SilcBuffer packet;
852   unsigned int argc;
853   unsigned char *id_string;
854   char info_string[256], *dest_server;
855
856   argc = silc_command_get_arg_num(cmd->payload);
857   if (argc < 1) {
858     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
859                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
860     goto out;
861   }
862   if (argc > 1) {
863     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
864                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
865     goto out;
866   }
867
868   /* Get server name */
869   dest_server = silc_command_get_arg_type(cmd->payload, 1, NULL);
870   if (!dest_server) {
871     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
872                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
873     goto out;
874   }
875
876   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
877     /* Send our reply */
878     memset(info_string, 0, sizeof(info_string));
879     snprintf(info_string, sizeof(info_string), "%s %s %s <%s>",
880              server->config->admin_info->location,
881              server->config->admin_info->server_type,
882              server->config->admin_info->admin_name,
883              server->config->admin_info->admin_email);
884
885     id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
886
887     packet = 
888       silc_command_encode_reply_payload_va(SILC_COMMAND_INFO,
889                                            SILC_STATUS_OK, 2,
890                                            2, id_string, SILC_ID_SERVER_LEN,
891                                            3, info_string, 
892                                            strlen(info_string));
893     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
894                             packet->data, packet->len, FALSE);
895     
896     silc_free(id_string);
897     silc_buffer_free(packet);
898   } else {
899     /* Send this command to the requested server */
900
901     if (server->server_type == SILC_SERVER && !server->standalone) {
902
903     }
904
905     if (server->server_type == SILC_ROUTER) {
906
907     }
908   }
909   
910  out:
911   silc_server_command_free(cmd);
912 }
913
914 SILC_SERVER_CMD_FUNC(connect)
915 {
916 }
917
918 /* Server side of command PING. This just replies to the ping. */
919
920 SILC_SERVER_CMD_FUNC(ping)
921 {
922   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
923   SilcServer server = cmd->server;
924   SilcServerID *id;
925   unsigned int argc;
926   unsigned char *id_string;
927
928   argc = silc_command_get_arg_num(cmd->payload);
929   if (argc < 1) {
930     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
931                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
932     goto out;
933   }
934   if (argc > 2) {
935     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
936                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
937     goto out;
938   }
939
940   /* Get Server ID */
941   id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
942   if (!id_string) {
943     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
944                                           SILC_STATUS_ERR_NO_SERVER_ID);
945     goto out;
946   }
947   id = silc_id_str2id(id_string, SILC_ID_SERVER);
948
949   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
950     /* Send our reply */
951     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
952                                           SILC_STATUS_OK);
953   } else {
954     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
955                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
956     goto out;
957   }
958
959   silc_free(id);
960
961  out:
962   silc_server_command_free(cmd);
963 }
964
965 SILC_SERVER_CMD_FUNC(oper)
966 {
967 }
968
969 typedef struct {
970   char *channel_name;
971   char *nickname;
972   char *username;
973   char *hostname;
974   SilcChannelList *channel;
975   SilcServer server;
976 } JoinInternalContext;
977
978 SILC_TASK_CALLBACK(silc_server_command_join_notify)
979 {
980   JoinInternalContext *ctx = (JoinInternalContext *)context;
981
982   if (ctx->channel->key && ctx->channel->key_len) {
983     silc_server_send_notify_to_channel(ctx->server, ctx->channel,
984                                        "%s (%s@%s) has joined channel %s",
985                                        ctx->nickname, ctx->username,
986                                        ctx->hostname, ctx->channel_name);
987     silc_free(ctx);
988   } else {
989     silc_task_register(ctx->server->timeout_queue, fd,
990                        silc_server_command_join_notify, context,
991                        0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
992   }
993 }
994
995 /* Assembles NAMES command and executes it. This is called when client
996    joins to a channel and we wan't to send NAMES command reply to the 
997    client. */
998
999 void silc_server_command_send_names(SilcServer server,
1000                                     SilcSocketConnection sock,
1001                                     SilcChannelList *channel)
1002 {
1003   SilcServerCommandContext cmd;
1004   SilcBuffer buffer;
1005   unsigned char *id_string;
1006
1007   id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1008   buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
1009                                           1, id_string, SILC_ID_CHANNEL_LEN);
1010
1011   cmd = silc_calloc(1, sizeof(*cmd));
1012   cmd->payload = silc_command_parse_payload(buffer);
1013   cmd->server = server;
1014   cmd->sock = sock;
1015   cmd->pending = FALSE;
1016
1017   silc_server_command_names((void *)cmd);
1018   silc_free(id_string);
1019   silc_free(buffer);
1020 }
1021
1022 /* Server side of command JOIN. Joins client into requested channel. If 
1023    the channel does not exist it will be created. */
1024
1025 SILC_SERVER_CMD_FUNC(join)
1026 {
1027   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1028   SilcServer server = cmd->server;
1029   SilcSocketConnection sock = cmd->sock;
1030   SilcBuffer buffer = cmd->packet->buffer;
1031   int argc, i, tmp_len;
1032   char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
1033   unsigned char *passphrase, mode[4];
1034   SilcChannelList *channel;
1035   SilcServerID *router_id;
1036   SilcIDCache *id_cache;
1037   SilcBuffer packet;
1038   SilcClientList *client;
1039
1040   SILC_LOG_DEBUG(("Start"));
1041
1042 #define LCC(x) server->local_list->channel_cache[(x) - 32]
1043 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
1044
1045   /* Check number of parameters */
1046   argc = silc_command_get_arg_num(cmd->payload);
1047   if (argc < 1) {
1048     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1049                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1050     goto out;
1051   }
1052   if (argc > 3) {
1053     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1054                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1055     goto out;
1056   }
1057
1058   /* Get channel name */
1059   tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
1060   channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
1061   memcpy(channel_name, tmp, tmp_len);
1062   if (silc_server_command_bad_chars(tmp) == TRUE) {
1063     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1064                                           SILC_STATUS_ERR_BAD_CHANNEL);
1065     silc_free(channel_name);
1066     goto out;
1067   }
1068
1069   /* Get passphrase */
1070   tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
1071   if (tmp) {
1072     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1073     memcpy(passphrase, tmp, tmp_len);
1074   }
1075   
1076   /* Get cipher name */
1077   cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
1078
1079   /* See if the channel exists */
1080   if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]), 
1081                                 channel_name, &id_cache) == FALSE) {
1082     /* Channel not found */
1083     id_cache = NULL;
1084
1085     /* If we are standalone server we don't have a router, we just create 
1086        the channel by  ourselves. */
1087     if (server->standalone) {
1088       router_id = server->id;
1089       channel = silc_server_new_channel(server, router_id, 
1090                                         cipher, channel_name);
1091       goto join_channel;
1092     }
1093
1094     /* No channel ID found, the channel does not exist on our server.
1095        We send JOIN command to our router which will handle the joining
1096        procedure (either creates the channel if it doesn't exist or
1097        joins the client to it) - if we are normal server. */
1098     if (server->server_type == SILC_SERVER) {
1099
1100       /* Forward the original JOIN command to the router */
1101       silc_buffer_push(buffer, buffer->data - buffer->head);
1102       silc_server_packet_forward(server, (SilcSocketConnection)
1103                                  server->id_entry->router->connection,
1104                                  buffer->data, buffer->len, TRUE);
1105       
1106       /* Add the command to be pending. It will be re-executed after
1107          router has replied back to us. */
1108       cmd->pending = TRUE;
1109       silc_server_command_pending(SILC_COMMAND_JOIN, 
1110                                   silc_server_command_join, context);
1111       return;
1112     }
1113   }
1114
1115   /* If we are router and the channel does not exist we will check our
1116      global list for the channel. */
1117   if (!id_cache && server->server_type == SILC_ROUTER) {
1118
1119     /* Notify all routers about the new channel in SILC network. */
1120     if (!server->standalone) {
1121 #if 0
1122       silc_server_send_new_id(server, server->id_entry->router->connection, 
1123                               TRUE,
1124                               xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
1125 #endif
1126     }
1127
1128   }
1129
1130   channel = (SilcChannelList *)id_cache->context;
1131
1132  join_channel:
1133
1134   /* If the JOIN request was forwarded to us we will make a bit slower
1135      query to get the client pointer. Otherwise, we get the client pointer
1136      real easy. */
1137   if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1138     client = (SilcClientList *)sock->user_data;
1139   } else {
1140     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1141     client = silc_idlist_find_client_by_id(server->local_list->clients, id);
1142     if (!client) {
1143       /* XXX */
1144       goto out;
1145     }
1146     silc_free(id);
1147   }
1148
1149   /* Check whether the client already is on the channel */
1150   if (silc_server_client_on_channel(client, channel)) {
1151     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1152                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1153     silc_free(channel_name);
1154     goto out;
1155   }
1156
1157   /* Join the client to the channel */
1158   i = channel->user_list_count;
1159   channel->user_list = silc_realloc(channel->user_list, 
1160                                     sizeof(*channel->user_list) * (i + 1));
1161   channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
1162   channel->user_list[i].client = client;
1163   channel->user_list_count++;
1164
1165   /* Add the channel to client's channel list */
1166   i = client->channel_count;
1167   client->channel = silc_realloc(client->channel, 
1168                                  sizeof(*client->channel) * (i + 1));
1169   client->channel[i] = channel;
1170   client->channel_count++;
1171
1172   /* Notify router about new user on channel. If we are normal server
1173      we send it to our router, if we are router we send it to our
1174      primary route. */
1175   if (!server->standalone) {
1176
1177   }
1178
1179   /* Send command reply to the client. Client receives the Channe ID,
1180      channel mode and possibly other information in this reply packet. */
1181   if (!cmd->pending) {
1182     id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1183     SILC_PUT32_MSB(channel->mode, mode);
1184
1185     if (!channel->topic)
1186       packet = 
1187         silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1188                                              SILC_STATUS_OK, 3,
1189                                              2, channel_name, 
1190                                              strlen(channel_name),
1191                                              3, id_string, SILC_ID_CHANNEL_LEN,
1192                                              4, mode, 4);
1193     else
1194       packet = 
1195         silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1196                                              SILC_STATUS_OK, 4, 
1197                                              2, channel_name, 
1198                                              strlen(channel_name),
1199                                              3, id_string, SILC_ID_CHANNEL_LEN,
1200                                              4, mode, 4,
1201                                              5, channel->topic, 
1202                                              strlen(channel->topic));
1203
1204     if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1205       void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1206       silc_server_packet_send_dest(cmd->server, cmd->sock, 
1207                                    SILC_PACKET_COMMAND_REPLY, 0,
1208                                    id, cmd->packet->src_id_type,
1209                                    packet->data, packet->len, FALSE);
1210       silc_free(id);
1211     } else
1212       silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
1213                               packet->data, packet->len, FALSE);
1214     
1215     silc_buffer_free(packet);
1216   }
1217
1218   /* Send channel key to the client. Client cannot start transmitting
1219      to the channel until we have sent the key. */
1220   if (!cmd->pending) {
1221     tmp_len = strlen(channel->channel_key->cipher->name);
1222     packet = 
1223       silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, 
1224                                       id_string, tmp_len, 
1225                                       channel->channel_key->cipher->name,
1226                                       channel->key_len / 8, channel->key);
1227     
1228     silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
1229                             packet->data, packet->len, FALSE);
1230     silc_buffer_free(packet);
1231   }
1232
1233   if (id_string)
1234     silc_free(id_string);
1235
1236   /* Finally, send notify message to all clients on the channel about
1237      new user on the channel. */
1238   if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1239     if (!cmd->pending) {
1240       silc_server_send_notify_to_channel(server, channel,
1241                                          "%s (%s@%s) has joined channel %s",
1242                                          client->nickname, client->username,
1243                                          sock->hostname ? sock->hostname :
1244                                          sock->ip, channel_name);
1245     } else {
1246       /* This is pending command request. Send the notify after we have
1247          received the key for the channel from the router. */
1248       JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1249       ctx->channel_name = channel_name;
1250       ctx->nickname = client->nickname;
1251       ctx->username = client->username;
1252       ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1253       ctx->channel = channel;
1254       ctx->server = server;
1255       silc_task_register(server->timeout_queue, sock->sock,
1256                          silc_server_command_join_notify, ctx,
1257                          0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1258     }
1259   }
1260
1261   /* Send NAMES command reply to the joined channel so the user sees who
1262      is currently on the channel. */
1263   silc_server_command_send_names(server, sock, channel);
1264
1265  out:
1266   silc_server_command_free(cmd);
1267 #undef LCC
1268 #undef LCCC
1269 }
1270
1271 /* Server side of command MOTD. Sends servers current "message of the
1272    day" to the client. */
1273
1274 SILC_SERVER_CMD_FUNC(motd)
1275 {
1276
1277   SILC_LOG_DEBUG(("Start"));
1278
1279 }
1280
1281 SILC_SERVER_CMD_FUNC(umode)
1282 {
1283 }
1284
1285 SILC_SERVER_CMD_FUNC(cmode)
1286 {
1287 }
1288
1289 SILC_SERVER_CMD_FUNC(kick)
1290 {
1291 }
1292
1293 SILC_SERVER_CMD_FUNC(restart)
1294 {
1295 }
1296  
1297 SILC_SERVER_CMD_FUNC(close)
1298 {
1299 }
1300  
1301 SILC_SERVER_CMD_FUNC(die)
1302 {
1303 }
1304  
1305 SILC_SERVER_CMD_FUNC(silcoper)
1306 {
1307 }
1308
1309 /* Server side command of LEAVE. Removes client from a channel. */
1310
1311 SILC_SERVER_CMD_FUNC(leave)
1312 {
1313   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1314   SilcServer server = cmd->server;
1315   SilcSocketConnection sock = cmd->sock;
1316   SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
1317   SilcChannelID *id;
1318   SilcChannelList *channel;
1319   SilcBuffer packet;
1320   unsigned int i, argc, key_len;
1321   unsigned char *tmp, channel_key[32];
1322
1323   SILC_LOG_DEBUG(("Start"));
1324
1325   argc = silc_command_get_arg_num(cmd->payload);
1326   if (argc < 1) {
1327     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1328                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1329     goto out;
1330   }
1331   if (argc > 2) {
1332     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1333                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1334     goto out;
1335   }
1336
1337   /* Get Channel ID */
1338   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1339   if (!tmp) {
1340     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1341                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1342     goto out;
1343   }
1344   id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1345
1346   /* Get channel entry */
1347   channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1348   if (!channel) {
1349     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1350                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1351     goto out;
1352   }
1353
1354   /* Check whether this client is on the channel */
1355   if (!silc_server_client_on_channel(id_entry, channel)) {
1356     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1357                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
1358     goto out;
1359   }
1360
1361   /* Remove client from channel */
1362   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
1363   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1364                                         SILC_STATUS_OK);
1365
1366   /* If the channel does not exist anymore we won't send anything */
1367   if (!i)
1368     goto out;
1369
1370   /* Re-generate channel key */
1371   key_len = channel->key_len / 8;
1372   for (i = 0; i < key_len; i++)
1373     channel_key[i] = silc_rng_get_byte(server->rng);
1374   channel->channel_key->cipher->set_key(channel->channel_key->context, 
1375                                         channel_key, key_len);
1376   memset(channel->key, 0, key_len);
1377   silc_free(channel->key);
1378   channel->key = silc_calloc(key_len, sizeof(*channel->key));
1379   memcpy(channel->key, channel_key, key_len);
1380   memset(channel_key, 0, sizeof(channel_key));
1381
1382   /* Encode channel key payload to be distributed on the channel */
1383   packet = 
1384     silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1385                                     strlen(channel->channel_key->cipher->name),
1386                                     channel->channel_key->cipher->name,
1387                                     key_len, channel->key);
1388
1389   /* If we are normal server then we will send it to our router.  If we
1390      are router we will send it to all local servers that has clients on
1391      the channel */
1392   if (server->server_type == SILC_SERVER) {
1393     if (!server->standalone)
1394       silc_server_packet_send(server, 
1395                               cmd->server->id_entry->router->connection,
1396                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1397                               packet->len, TRUE);
1398   } else {
1399
1400   }
1401
1402   /* Send to locally connected clients on the channel */
1403   silc_server_packet_send_local_channel(server, channel, 
1404                                         SILC_PACKET_CHANNEL_KEY, 0,
1405                                         packet->data, packet->len, FALSE);
1406
1407   silc_buffer_free(packet);
1408   silc_free(id);
1409
1410  out:
1411   silc_server_command_free(cmd);
1412 }
1413
1414 /* Server side of command NAMES. Resolves clients and their names currently
1415    joined on the requested channel. The name list is sent back to the
1416    client. */
1417
1418 SILC_SERVER_CMD_FUNC(names)
1419 {
1420   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1421   SilcServer server = cmd->server;
1422   SilcChannelList *channel;
1423   SilcChannelID *id;
1424   SilcBuffer packet;
1425   unsigned int i, len, len2, argc;
1426   unsigned char *tmp;
1427   char *name_list = NULL, *n;
1428   SilcBuffer client_id_list;
1429
1430   SILC_LOG_DEBUG(("Start"));
1431
1432   argc = silc_command_get_arg_num(cmd->payload);
1433   if (argc < 1) {
1434     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1435                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1436     goto out;
1437   }
1438   if (argc > 2) {
1439     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1440                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1441     goto out;
1442   }
1443
1444   /* Get Channel ID */
1445   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1446   if (!tmp) {
1447     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1448                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1449     goto out;
1450   }
1451   id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1452
1453   /* Check whether the channel exists. If we are normal server and the
1454      channel does not exist we will send this same command to our router
1455      which will know if the channel exists. */
1456   channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1457   if (!channel) {
1458     if (server->server_type == SILC_SERVER && !server->standalone) {
1459       /* XXX Send names command */
1460
1461       cmd->pending = TRUE;
1462       silc_server_command_pending(SILC_COMMAND_NAMES, 
1463                                   silc_server_command_names, context);
1464       return;
1465     }
1466
1467     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1468                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1469     goto out;
1470   }
1471
1472   /* Assemble the name list now */
1473   name_list = NULL;
1474   len = 0;
1475   for (i = 0; i < channel->user_list_count; i++) {
1476     if (!channel->user_list[i].client)
1477       continue;
1478
1479     n = channel->user_list[i].client->nickname;
1480     if (n) {
1481       len2 = strlen(n);
1482       len += len2;
1483       name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1484       memcpy(name_list + (len - len2), n, len2);
1485       name_list[len] = 0;
1486
1487       if (i == channel->user_list_count - 1)
1488         break;
1489       memcpy(name_list + len, ",", 1);
1490       len++;
1491     }
1492   }
1493
1494   /* Assemble the Client ID list now */
1495   client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN * 
1496                                      channel->user_list_count);
1497   silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
1498                                          channel->user_list_count));
1499   for (i = 0; i < channel->user_list_count; i++) {
1500     unsigned char *id_string;
1501
1502     if (!channel->user_list[i].client)
1503       continue;
1504
1505     id_string = silc_id_id2str(channel->user_list[i].client->id,
1506                                SILC_ID_CLIENT);
1507     silc_buffer_format(client_id_list,
1508                        SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
1509                        SILC_STR_END);
1510     silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
1511     silc_free(id_string);
1512   }
1513   silc_buffer_push(client_id_list, 
1514                    client_id_list->data - client_id_list->head);
1515
1516   /* Send reply */
1517   packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NAMES,
1518                                                 SILC_STATUS_OK, 3,
1519                                                 2, tmp, SILC_ID_CHANNEL_LEN,
1520                                                 3, name_list, 
1521                                                 strlen(name_list),
1522                                                 4, client_id_list->data,
1523                                                 client_id_list->len);
1524   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
1525                           packet->data, packet->len, FALSE);
1526     
1527   silc_buffer_free(packet);
1528   silc_free(name_list);
1529   silc_buffer_free(client_id_list);
1530   silc_free(id);
1531
1532  out:
1533   silc_server_command_free(cmd);
1534 }