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