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