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