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