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