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