Added PING, INVITE and NAMES command.
[silc.git] / apps / silcd / command.c
1 /*
2
3   command.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /*
21  * $Id$
22  * $Log$
23  * Revision 1.4  2000/07/05 06:13:38  priikone
24  *      Added PING, INVITE and NAMES command.
25  *
26  * Revision 1.3  2000/07/03 05:52:22  priikone
27  *      Implemented LEAVE command.
28  *
29  * Revision 1.2  2000/06/28 05:06:38  priikone
30  *      Shorter timeout for channel joining notify.
31  *
32  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
33  *      Imported from internal CVS/Added Log headers.
34  *
35  *
36  */
37
38 #include "serverincludes.h"
39 #include "server_internal.h"
40
41 /* Server command list. */
42 SilcServerCommand silc_command_list[] =
43 {
44   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
45   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
46   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
47   SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
48   SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
49   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
50   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
51   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
52   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
53   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
54   SILC_SERVER_CMD(connect, CONNECT, 
55                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
56   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
57   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
58   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
59   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
60   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
61   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
62   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
63   SILC_SERVER_CMD(restart, RESTART, 
64                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
65   SILC_SERVER_CMD(close, CLOSE,
66                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
67   SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
68   SILC_SERVER_CMD(silcoper, SILCOPER,
69                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
70   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
71   SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
72
73   { NULL, 0 },
74 };
75
76 /* List of pending commands. */
77 SilcServerCommandPending *silc_command_pending = NULL;
78
79 /* Add new pending command to the list of pending commands. Currently
80    pending commands are executed from command replies, thus we can
81    execute any command after receiving some specific command reply.
82
83    The argument `reply_cmd' is the command reply from where the callback
84    function is to be called, thus, it IS NOT the command to be executed. */
85
86 void silc_server_command_pending(SilcCommand reply_cmd,
87                                  SilcCommandCb callback,
88                                  void *context)
89 {
90   SilcServerCommandPending *reply, *r;
91
92   reply = silc_calloc(1, sizeof(*reply));
93   reply->reply_cmd = reply_cmd;
94   reply->context = context;
95   reply->callback = callback;
96
97   if (silc_command_pending == NULL) {
98     silc_command_pending = reply;
99     return;
100   }
101
102   for (r = silc_command_pending; r; r = r->next) {
103     if (r->next == NULL) {
104       r->next = reply;
105       break;
106     }
107   }
108 }
109
110 /* Deletes pending command by reply command type. */
111
112 void silc_server_command_pending_del(SilcCommand reply_cmd)
113 {
114   SilcServerCommandPending *r, *tmp;
115   
116   if (silc_command_pending) {
117     if (silc_command_pending->reply_cmd == reply_cmd) {
118       silc_free(silc_command_pending);
119       silc_command_pending = NULL;
120       return;
121     }
122
123     for (r = silc_command_pending; r; r = r->next) {
124       if (r->next && r->next->reply_cmd == reply_cmd) {
125         tmp = r->next;
126         r->next = r->next->next;
127         silc_free(tmp);
128         break;
129       }
130     }
131   }
132 }
133
134 /* Free's the command context allocated before executing the command */
135
136 static void silc_server_command_free(SilcServerCommandContext cmd)
137 {
138   if (cmd) {
139     silc_command_free_payload(cmd->payload);
140     silc_free(cmd);
141   }
142 }
143
144 /* Sends command status message as command reply packet. */
145
146 static void 
147 silc_server_command_send_status_msg(SilcServerCommandContext cmd,
148                                     SilcCommand command,
149                                     SilcCommandStatus status,
150                                     unsigned char *msg,
151                                     unsigned int msg_len)
152 {
153   SilcBuffer sp_buf, buffer;
154
155   SILC_LOG_DEBUG(("Sending command status %d", status));
156
157   sp_buf = silc_command_encode_status_payload(status, msg, msg_len);
158   buffer = silc_command_encode_payload_va(command, 1, 
159                                           sp_buf->data, sp_buf->len);
160   silc_server_packet_send(cmd->server, cmd->sock,
161                           SILC_PACKET_COMMAND_REPLY, 0, 
162                           buffer->data, buffer->len, FALSE);
163   silc_buffer_free(buffer);
164   silc_buffer_free(sp_buf);
165 }
166
167 /* Sends simple status message as command reply packet */
168
169 static void 
170 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
171                                       SilcCommand command,
172                                       SilcCommandStatus status)
173 {
174   SilcBuffer sp_buf, buffer;
175
176   SILC_LOG_DEBUG(("Sending command status %d", status));
177
178   sp_buf = silc_command_encode_status_payload(status, NULL, 0);
179   buffer = silc_command_encode_payload_va(command, 1, 
180                                           sp_buf->data, sp_buf->len);
181   silc_server_packet_send(cmd->server, cmd->sock,
182                           SILC_PACKET_COMMAND_REPLY, 0, 
183                           buffer->data, buffer->len, FALSE);
184   silc_buffer_free(buffer);
185   silc_buffer_free(sp_buf);
186 }
187
188 /* Server side of command WHOIS. Processes user's query and sends found 
189    results as command replies back to the client. */
190
191 SILC_SERVER_CMD_FUNC(whois)
192 {
193   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
194   char *tmp, *nick = NULL, *server = NULL;
195   unsigned int argc, count = 0, len;
196   SilcClientList *entry;
197   SilcBuffer sp_buf, packet;
198   unsigned char *id_string;
199
200   SILC_LOG_DEBUG(("Start"));
201
202   argc = silc_command_get_arg_num(cmd->payload);
203   if (argc < 1) {
204     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
205                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
206     goto out;
207   }
208   if (argc > 2) {
209     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
210                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
211     goto out;
212   }
213
214   /* Get the nickname@server string and parse it. */
215   tmp = silc_command_get_first_arg(cmd->payload, NULL);
216   if (tmp) {
217     if (strchr(tmp, '@')) {
218       len = strcspn(tmp, "@");
219       nick = silc_calloc(len + 1, sizeof(char));
220       memcpy(nick, tmp, len);
221       server = silc_calloc(strlen(tmp) - len, sizeof(char));
222       memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
223     } else {
224       nick = strdup(tmp);
225     }
226   } else {
227     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
228                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
229     goto out;
230   }
231
232   /* Get the max count of reply messages allowed */
233   if (argc == 2) {
234     tmp = silc_command_get_next_arg(cmd->payload, NULL);
235     if (!tmp) {
236       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
237                                             SILC_STATUS_ERR_TOO_MANY_PARAMS);
238       if (nick)
239         silc_free(nick);
240       if (server)
241         silc_free(server);
242       goto out;
243     }
244     count = atoi(tmp);
245   }
246
247   /* Then, make the query from our local client list */
248   entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
249                                               nick, server);
250   if (!entry) {
251
252     /* If we are normal server and are connected to a router we will
253        make global query from the router. */
254     if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
255
256       goto ok;
257     }
258     
259     /* If we are router then we will check our global list as well. */
260     if (cmd->server->server_type == SILC_ROUTER) {
261       entry =
262         silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
263                                             nick, server);
264       if (!entry) {
265         silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
266                                             SILC_STATUS_ERR_NO_SUCH_NICK,
267                                             tmp, strlen(tmp));
268         goto out;
269       }
270       goto ok;
271     }
272
273     silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
274                                         SILC_STATUS_ERR_NO_SUCH_NICK,
275                                         tmp, strlen(tmp));
276     goto out;
277   }
278
279  ok:
280   /* XXX, works only for local server info */
281
282   /* Send WHOIS reply */
283   id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
284   tmp = silc_command_get_first_arg(cmd->payload, NULL),
285   sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
286
287   /* XXX */
288   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
289     char nh[256], uh[256];
290     SilcSocketConnection hsock;
291
292     memset(uh, 0, sizeof(uh));
293     memset(nh, 0, sizeof(nh));
294
295     strncat(nh, entry->nickname, strlen(entry->nickname));
296     strncat(nh, "@", 1);
297     len = entry->router ? strlen(entry->router->server_name) :
298       strlen(cmd->server->server_name);
299     strncat(nh, entry->router ? entry->router->server_name :
300             cmd->server->server_name, len);
301
302     strncat(uh, entry->username, strlen(entry->username));
303     strncat(uh, "@", 1);
304     hsock = (SilcSocketConnection)entry->connection;
305     len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
306     strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
307
308     /* XXX */
309     if (entry->userinfo)
310       packet = 
311         silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 5, 
312                                        sp_buf->data, sp_buf->len,
313                                        id_string, SILC_ID_CLIENT_LEN,
314                                        nh, strlen(nh),
315                                        uh, strlen(uh),
316                                        entry->userinfo, 
317                                        strlen(entry->userinfo));
318     else
319       packet = 
320         silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
321                                        sp_buf->data, sp_buf->len,
322                                        id_string, SILC_ID_CLIENT_LEN,
323                                        nh, strlen(nh),
324                                        uh, strlen(uh));
325
326   } else {
327     /* XXX */
328     packet = 
329       silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4, 
330                                      sp_buf->data, sp_buf->len,
331                                      id_string, SILC_ID_CLIENT_LEN,
332                                      entry->nickname, strlen(entry->nickname),
333                                      tmp, strlen(tmp)); /* XXX */
334   }
335   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
336                           0, packet->data, packet->len, FALSE);
337
338   silc_free(id_string);
339   silc_buffer_free(packet);
340   silc_free(sp_buf);
341
342  out:
343   silc_server_command_free(cmd);
344 }
345
346 SILC_SERVER_CMD_FUNC(whowas)
347 {
348 }
349
350 SILC_SERVER_CMD_FUNC(identify)
351 {
352   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
353   char *tmp, *nick = NULL, *server = NULL;
354   unsigned int argc, count = 0, len;
355   SilcClientList *entry;  SilcBuffer sp_buf, 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_IDENTIFY,
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_IDENTIFY,
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 = silc_calloc(strlen(tmp) - len, sizeof(char));
380       memcpy(server, 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_IDENTIFY,
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_IDENTIFY,
395                                             SILC_STATUS_ERR_TOO_MANY_PARAMS);
396       goto out;
397     }
398     count = atoi(tmp);
399   }
400
401   /* Then, make the query from our local client list */
402   entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
403                                           nick, cmd->server->md5hash);
404   if (!entry) {
405
406     /* If we are normal server and are connected to a router we will
407        make global query from the router. */
408     if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
409       SilcBuffer buffer = cmd->packet->buffer;
410
411       /* Send IDENTIFY command to our router */
412       silc_buffer_push(buffer, buffer->data - buffer->head);
413       silc_server_packet_forward(cmd->server, (SilcSocketConnection)
414                                  cmd->server->id_entry->router->connection,
415                                  buffer->data, buffer->len, TRUE);
416       goto out;
417     }
418     
419     /* If we are router then we will check our global list as well. */
420     if (cmd->server->server_type == SILC_ROUTER) {
421       entry = 
422         silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
423                                         nick, cmd->server->md5hash);
424       if (!entry) {
425         silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
426                                             SILC_STATUS_ERR_NO_SUCH_NICK,
427                                             tmp, strlen(tmp));
428         goto out;
429       }
430       goto ok;
431     }
432
433     silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
434                                         SILC_STATUS_ERR_NO_SUCH_NICK,
435                                         tmp, strlen(tmp));
436     goto out;
437   }
438
439  ok:
440   /* Send IDENTIFY reply */
441   id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
442   tmp = silc_command_get_first_arg(cmd->payload, NULL);
443   sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
444   packet = silc_command_encode_payload_va(SILC_COMMAND_IDENTIFY, 3,
445                                           sp_buf->data, sp_buf->len,
446                                           id_string, SILC_ID_CLIENT_LEN,
447                                           nick, strlen(nick));
448 #if 0
449   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
450     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
451     silc_server_packet_send_dest(cmd->server, cmd->sock, 
452                                  SILC_PACKET_COMMAND_REPLY, 0,
453                                  id, cmd->packet->src_id_type,
454                                  packet->data, packet->len, FALSE);
455     silc_free(id);
456   } else
457 #endif
458     silc_server_packet_send(cmd->server, cmd->sock, 
459                             SILC_PACKET_COMMAND_REPLY, 0, 
460                             packet->data, packet->len, FALSE);
461
462   silc_free(id_string);
463   silc_buffer_free(packet);
464   silc_free(sp_buf);
465
466  out:
467   if (nick)
468     silc_free(nick);
469   if (server)
470     silc_free(server);
471   silc_server_command_free(cmd);
472 }
473
474 /* Checks string for bad characters and returns TRUE if they are found. */
475
476 static int silc_server_command_bad_chars(char *nick)
477 {
478   if (strchr(nick, '\\')) return TRUE;
479   if (strchr(nick, '\"')) return TRUE;
480   if (strchr(nick, '´')) return TRUE;
481   if (strchr(nick, '`')) return TRUE;
482   if (strchr(nick, '\'')) return TRUE;
483   if (strchr(nick, '*')) return TRUE;
484   if (strchr(nick, '/')) return TRUE;
485   if (strchr(nick, '@')) return TRUE;
486
487   return FALSE;
488 }
489
490 /* Server side of command NICK. Sets nickname for user. Setting
491    nickname causes generation of a new client ID for the client. The
492    new client ID is sent to the client after changing the nickname. */
493
494 SILC_SERVER_CMD_FUNC(nick)
495 {
496   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
497   SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
498   SilcServer server = cmd->server;
499   SilcBuffer packet, sp_buf;
500   SilcClientID *new_id;
501   char *id_string;
502   char *nick;
503
504   SILC_LOG_DEBUG(("Start"));
505
506 #define LCC(x) server->local_list->client_cache[(x) - 32]
507 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
508
509   /* Check number of arguments */
510   if (silc_command_get_arg_num(cmd->payload) < 1) {
511     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
512                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
513     goto out;
514   }
515
516   /* Check nickname */
517   nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
518   if (silc_server_command_bad_chars(nick) == TRUE) {
519     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
520                                           SILC_STATUS_ERR_BAD_NICKNAME);
521     goto out;
522   }
523
524   /* Create new Client ID */
525   silc_id_create_client_id(cmd->server->id, cmd->server->rng, 
526                            cmd->server->md5hash, nick,
527                            &new_id);
528
529   /* Send notify about nickname change to our router. We send the new
530      ID and ask to replace it with the old one. */
531   if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
532     silc_server_send_replace_id(server, server->id_entry->router->connection, 
533                                 FALSE, id_entry->id,
534                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
535                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
536
537   /* If we are router we have to distribute the new Client ID to all 
538      routers in SILC. */
539   if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
540     silc_server_send_replace_id(server, server->id_entry->router->connection,  
541                                 TRUE, id_entry->id,
542                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
543                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
544
545   /* Remove old cache entry */
546   silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
547                          LCCC(id_entry->nickname[0]), 
548                          SILC_ID_CLIENT, id_entry->id); 
549   
550   /* Free old ID */
551   if (id_entry->id) {
552     memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
553     silc_free(id_entry->id);
554   }
555
556   /* Save the nickname as this client is our local client */
557   if (id_entry->nickname)
558     silc_free(id_entry->nickname);
559
560   id_entry->nickname = strdup(nick);
561   id_entry->id = new_id;
562
563   /* Update client cache */
564   LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
565                                    id_entry->nickname, SILC_ID_CLIENT, 
566                                    id_entry->id, (void *)id_entry);
567
568   /* Send the new Client ID as reply command back to client */
569   id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
570   sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
571   packet = silc_command_encode_payload_va(SILC_COMMAND_NICK, 2, 
572                                           sp_buf->data, sp_buf->len,
573                                           id_string, SILC_ID_CLIENT_LEN);
574   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
575                           0, packet->data, packet->len, FALSE);
576
577   silc_free(id_string);
578   silc_buffer_free(packet);
579   silc_free(sp_buf);
580
581  out:
582   silc_server_command_free(cmd);
583 #undef LCC
584 #undef LCCC
585 }
586
587 SILC_SERVER_CMD_FUNC(list)
588 {
589 }
590
591 SILC_SERVER_CMD_FUNC(topic)
592 {
593 }
594
595 /* Server side of INVITE command. Invites some client to join some channel. */
596
597 SILC_SERVER_CMD_FUNC(invite)
598 {
599   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
600   SilcServer server = cmd->server;
601   SilcSocketConnection sock = cmd->sock, dest_sock;
602   SilcClientList *sender, *dest;
603   SilcClientID *dest_id;
604   SilcChannelList *channel;
605   SilcChannelID *channel_id;
606   unsigned int argc, len;
607   unsigned char *id_string;
608
609   /* Check number of arguments */
610   argc = silc_command_get_arg_num(cmd->payload);
611   if (argc < 1) {
612     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
613                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
614     goto out;
615   }
616   if (argc > 2) {
617     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
618                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
619     goto out;
620   }
621
622   /* Get destination ID */
623   id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
624   if (!id_string) {
625     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
626                                           SILC_STATUS_ERR_NO_CLIENT_ID);
627     goto out;
628   }
629   dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
630
631   /* Get Channel ID */
632   id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
633   if (!id_string) {
634     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
635                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
636     goto out;
637   }
638   channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
639
640   /* Check whether the channel exists */
641   channel = silc_idlist_find_channel_by_id(server->local_list->channels, 
642                                            channel_id);
643   if (!channel) {
644     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
645                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
646     goto out;
647   }
648
649   /* Check whether the sender of this command is on the channel. */
650   sender = (SilcClientList *)sock->user_data;
651   if (!silc_server_client_on_channel(sender, channel)) {
652     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
653                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
654     goto out;
655   }
656
657   /* Check whether the channel is invite-only channel. If yes then the
658      sender of this command must be at least channel operator. */
659   /* XXX */
660
661   /* Check whether the requested client is already on the channel. */
662   /* XXX if we are normal server we don't know about global clients on
663      the channel thus we must request it (NAMES command), check from
664      local cache as well. */
665
666   /* Find the connection data for the destination. If it is local we will
667      send it directly otherwise we will send it to router for routing. */
668   dest = silc_idlist_find_client_by_id(server->local_list->clients, dest_id);
669   if (dest)
670     dest_sock = (SilcSocketConnection)dest->connection;
671   else
672     dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
673
674   /* Send notify to the client that is invited to the channel */
675   silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
676                                "%s invites you to channel %s",
677                                sender->nickname, channel->channel_name);
678
679   /* Send command reply */
680   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
681                                         SILC_STATUS_OK);
682
683  out:
684   silc_server_command_free(cmd);
685 }
686
687 /* Quits connection to client. This gets called if client won't
688    close the connection even when it has issued QUIT command. */
689
690 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
691 {
692   SilcServer server = (SilcServer)context;
693   SilcSocketConnection sock = server->sockets[fd];
694
695   /* Free all client specific data, such as client entry and entires
696      on channels this client may be on. */
697   silc_server_free_sock_user_data(server, sock);
698
699   /* Close the connection on our side */
700   silc_server_close_connection(server, sock);
701 }
702
703 /* Quits SILC session. This is the normal way to disconnect client. */
704  
705 SILC_SERVER_CMD_FUNC(quit)
706 {
707   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
708   SilcServer server = cmd->server;
709   SilcSocketConnection sock = cmd->sock;
710
711   SILC_LOG_DEBUG(("Start"));
712
713   /* We quit the connection with little timeout */
714   silc_task_register(server->timeout_queue, sock->sock,
715                      silc_server_command_quit_cb, server,
716                      0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
717
718   silc_server_command_free(cmd);
719 }
720
721 SILC_SERVER_CMD_FUNC(kill)
722 {
723 }
724
725 SILC_SERVER_CMD_FUNC(info)
726 {
727 }
728
729 SILC_SERVER_CMD_FUNC(connect)
730 {
731 }
732
733 /* Server side of command PING. This just replies to the ping. */
734
735 SILC_SERVER_CMD_FUNC(ping)
736 {
737   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
738   SilcServer server = cmd->server;
739   SilcServerID *id;
740   unsigned int argc;
741   unsigned char *id_string;
742
743   argc = silc_command_get_arg_num(cmd->payload);
744   if (argc < 1) {
745     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
746                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
747     goto out;
748   }
749   if (argc > 2) {
750     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
751                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
752     goto out;
753   }
754
755   /* Get Server ID */
756   id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
757   if (!id_string) {
758     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
759                                           SILC_STATUS_ERR_NO_SERVER_ID);
760     goto out;
761   }
762   id = silc_id_str2id(id_string, SILC_ID_SERVER);
763
764   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
765     /* Send our reply */
766     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
767                                           SILC_STATUS_OK);
768   } else {
769     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
770                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
771     goto out;
772   }
773
774   silc_free(id);
775
776  out:
777   silc_server_command_free(cmd);
778 }
779
780 SILC_SERVER_CMD_FUNC(oper)
781 {
782 }
783
784 typedef struct {
785   char *channel_name;
786   char *nickname;
787   char *username;
788   char *hostname;
789   SilcChannelList *channel;
790   SilcServer server;
791 } JoinInternalContext;
792
793 SILC_TASK_CALLBACK(silc_server_command_join_notify)
794 {
795   JoinInternalContext *ctx = (JoinInternalContext *)context;
796
797   if (ctx->channel->key && ctx->channel->key_len) {
798     silc_server_send_notify_to_channel(ctx->server, ctx->channel,
799                                        "%s (%s@%s) has joined channel %s",
800                                        ctx->nickname, ctx->username,
801                                        ctx->hostname, ctx->channel_name);
802     silc_free(ctx);
803   } else {
804     silc_task_register(ctx->server->timeout_queue, fd,
805                        silc_server_command_join_notify, context,
806                        0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
807   }
808 }
809
810 /* Assembles NAMES command and executes it. This is called when client
811    joins to a channel and we wan't to send NAMES command reply to the 
812    client. */
813
814 void silc_server_command_send_names(SilcServer server,
815                                     SilcSocketConnection sock,
816                                     SilcChannelList *channel)
817 {
818   SilcServerCommandContext cmd;
819   SilcBuffer buffer;
820   unsigned char *id_string;
821
822   id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
823   buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
824                                           id_string, SILC_ID_CHANNEL_LEN);
825
826   cmd = silc_calloc(1, sizeof(*cmd));
827   cmd->payload = silc_command_parse_payload(buffer);
828   cmd->server = server;
829   cmd->sock = sock;
830   cmd->pending = FALSE;
831
832   silc_server_command_names((void *)cmd);
833   silc_free(id_string);
834   silc_free(buffer);
835 }
836
837 /* Server side of command JOIN. Joins client into requested channel. If 
838    the channel does not exist it will be created. */
839
840 SILC_SERVER_CMD_FUNC(join)
841 {
842   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
843   SilcServer server = cmd->server;
844   SilcSocketConnection sock = cmd->sock;
845   SilcBuffer buffer = cmd->packet->buffer;
846   int argc, i, tmp_len;
847   char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
848   unsigned char *passphrase, mode[4];
849   SilcChannelList *channel;
850   SilcServerID *router_id;
851   SilcIDCache *id_cache;
852   SilcBuffer packet, sp_buf;
853   SilcClientList *client;
854
855   SILC_LOG_DEBUG(("Start"));
856
857 #define LCC(x) server->local_list->channel_cache[(x) - 32]
858 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
859
860   /* Check number of parameters */
861   argc = silc_command_get_arg_num(cmd->payload);
862   if (argc < 1) {
863     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
864                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
865     goto out;
866   }
867   if (argc > 3) {
868     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
869                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
870     goto out;
871   }
872
873   /* Get channel name */
874   tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
875   channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
876   memcpy(channel_name, tmp, tmp_len);
877   if (silc_server_command_bad_chars(tmp) == TRUE) {
878     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
879                                           SILC_STATUS_ERR_BAD_CHANNEL);
880     silc_free(channel_name);
881     goto out;
882   }
883
884   /* Get passphrase */
885   tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
886   if (tmp) {
887     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
888     memcpy(passphrase, tmp, tmp_len);
889   }
890   
891   /* Get cipher name */
892   cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
893
894   /* See if the channel exists */
895   if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]), 
896                                 channel_name, &id_cache) == FALSE) {
897     /* Channel not found */
898     id_cache = NULL;
899
900     /* If we are standalone server we don't have a router, we just create 
901        the channel by  ourselves. */
902     if (server->standalone) {
903       router_id = server->id;
904       channel = silc_server_new_channel(server, router_id, 
905                                         cipher, channel_name);
906       goto join_channel;
907     }
908
909     /* No channel ID found, the channel does not exist on our server.
910        We send JOIN command to our router which will handle the joining
911        procedure (either creates the channel if it doesn't exist or
912        joins the client to it) - if we are normal server. */
913     if (server->server_type == SILC_SERVER) {
914
915       /* Forward the original JOIN command to the router */
916       silc_buffer_push(buffer, buffer->data - buffer->head);
917       silc_server_packet_forward(server, (SilcSocketConnection)
918                                  server->id_entry->router->connection,
919                                  buffer->data, buffer->len, TRUE);
920       
921       /* Add the command to be pending. It will be re-executed after
922          router has replied back to us. */
923       cmd->pending = TRUE;
924       silc_server_command_pending(SILC_COMMAND_JOIN, 
925                                   silc_server_command_join, context);
926       return;
927     }
928   }
929
930   /* If we are router and the channel does not exist we will check our
931      global list for the channel. */
932   if (!id_cache && server->server_type == SILC_ROUTER) {
933
934     /* Notify all routers about the new channel in SILC network. */
935     if (!server->standalone) {
936 #if 0
937       silc_server_send_new_id(server, server->id_entry->router->connection, 
938                               TRUE,
939                               xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
940 #endif
941     }
942
943   }
944
945   channel = (SilcChannelList *)id_cache->context;
946
947  join_channel:
948
949   /* XXX must check whether the client already is on the channel */
950
951   /* Join the client to the channel */
952   i = channel->user_list_count;
953   channel->user_list = silc_realloc(channel->user_list, 
954                                     sizeof(*channel->user_list) * (i + 1));
955   channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
956
957   /* If the JOIN request was forwarded to us we will make a bit slower
958      query to get the client pointer. Otherwise, we get the client pointer
959      real easy. */
960   if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
961     client = (SilcClientList *)sock->user_data;
962     channel->user_list[i].client = client;
963   } else {
964     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
965     client = silc_idlist_find_client_by_id(server->local_list->clients, id);
966     channel->user_list[i].client = client;
967     silc_free(id);
968   }
969   channel->user_list_count++;
970
971   i = client->channel_count;
972   client->channel = silc_realloc(client->channel, 
973                                  sizeof(*client->channel) * (i + 1));
974   client->channel[i] = channel;
975   client->channel_count++;
976
977   /* Notify router about new user on channel. If we are normal server
978      we send it to our router, if we are router we send it to our
979      primary route. */
980   if (!server->standalone) {
981
982   }
983
984   /* Send command reply to the client. Client receives the Channe ID,
985      channel mode and possibly other information in this reply packet. */
986   if (!cmd->pending) {
987     id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
988     sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
989     SILC_PUT32_MSB(channel->mode, mode);
990
991     if (!channel->topic)
992       packet = 
993         silc_command_encode_payload_va(SILC_COMMAND_JOIN, 4,
994                                        sp_buf->data, sp_buf->len,
995                                        channel_name, strlen(channel_name),
996                                        id_string, SILC_ID_CHANNEL_LEN,
997                                        mode, 4);
998     else
999       packet = 
1000         silc_command_encode_payload_va(SILC_COMMAND_JOIN, 5,
1001                                        sp_buf->data, sp_buf->len,
1002                                        channel_name, strlen(channel_name),
1003                                        id_string, SILC_ID_CHANNEL_LEN,
1004                                        mode, 4,
1005                                        channel->topic, strlen(channel->topic));
1006
1007     if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1008       void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1009       silc_server_packet_send_dest(cmd->server, cmd->sock, 
1010                                    SILC_PACKET_COMMAND_REPLY, 0,
1011                                    id, cmd->packet->src_id_type,
1012                                    packet->data, packet->len, FALSE);
1013       silc_free(id);
1014     } else
1015       silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
1016                               packet->data, packet->len, FALSE);
1017     
1018     silc_buffer_free(packet);
1019     silc_free(sp_buf);
1020   }
1021
1022   /* Send channel key to the client. Client cannot start transmitting
1023      to the channel until we have sent the key. */
1024   if (!cmd->pending) {
1025     tmp_len = strlen(channel->channel_key->cipher->name);
1026     packet = 
1027       silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, 
1028                                       id_string, tmp_len, 
1029                                       channel->channel_key->cipher->name,
1030                                       channel->key_len / 8, channel->key);
1031     
1032     silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
1033                             packet->data, packet->len, FALSE);
1034     silc_buffer_free(packet);
1035   }
1036
1037   if (id_string)
1038     silc_free(id_string);
1039
1040   /* Finally, send notify message to all clients on the channel about
1041      new user on the channel. */
1042   if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1043     if (!cmd->pending) {
1044       silc_server_send_notify_to_channel(server, channel,
1045                                          "%s (%s@%s) has joined channel %s",
1046                                          client->nickname, client->username,
1047                                          sock->hostname ? sock->hostname :
1048                                          sock->ip, channel_name);
1049     } else {
1050       /* This is pending command request. Send the notify after we have
1051          received the key for the channel from the router. */
1052       JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1053       ctx->channel_name = channel_name;
1054       ctx->nickname = client->nickname;
1055       ctx->username = client->username;
1056       ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1057       ctx->channel = channel;
1058       ctx->server = server;
1059       silc_task_register(server->timeout_queue, sock->sock,
1060                          silc_server_command_join_notify, ctx,
1061                          0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1062     }
1063   }
1064
1065   /* Send NAMES command reply to the joined channel so the user sees who
1066      is currently on the channel. */
1067   silc_server_command_send_names(server, sock, channel);
1068
1069  out:
1070   silc_server_command_free(cmd);
1071 #undef LCC
1072 #undef LCCC
1073 }
1074
1075 /* Server side of command MOTD. Sends servers current "message of the
1076    day" to the client. */
1077
1078 SILC_SERVER_CMD_FUNC(motd)
1079 {
1080
1081   SILC_LOG_DEBUG(("Start"));
1082
1083 }
1084
1085 SILC_SERVER_CMD_FUNC(umode)
1086 {
1087 }
1088
1089 SILC_SERVER_CMD_FUNC(cmode)
1090 {
1091 }
1092
1093 SILC_SERVER_CMD_FUNC(kick)
1094 {
1095 }
1096
1097 SILC_SERVER_CMD_FUNC(restart)
1098 {
1099 }
1100  
1101 SILC_SERVER_CMD_FUNC(close)
1102 {
1103 }
1104  
1105 SILC_SERVER_CMD_FUNC(die)
1106 {
1107 }
1108  
1109 SILC_SERVER_CMD_FUNC(silcoper)
1110 {
1111 }
1112
1113 /* Server side command of LEAVE. Removes client from a channel. */
1114
1115 SILC_SERVER_CMD_FUNC(leave)
1116 {
1117   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1118   SilcServer server = cmd->server;
1119   SilcSocketConnection sock = cmd->sock;
1120   SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
1121   SilcChannelID *id;
1122   SilcChannelList *channel;
1123   SilcBuffer packet;
1124   unsigned int i, argc, key_len;
1125   unsigned char *tmp, channel_key[32];
1126
1127   SILC_LOG_DEBUG(("Start"));
1128
1129   argc = silc_command_get_arg_num(cmd->payload);
1130   if (argc < 1) {
1131     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1132                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1133     goto out;
1134   }
1135   if (argc > 2) {
1136     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1137                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1138     goto out;
1139   }
1140
1141   /* Get Channel ID */
1142   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1143   if (!tmp) {
1144     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1145                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1146     goto out;
1147   }
1148   id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1149
1150   /* Get channel entry */
1151   channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1152   if (!channel) {
1153     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1154                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1155     goto out;
1156   }
1157
1158   /* Check whether this client is on the channel */
1159   if (!silc_server_client_on_channel(id_entry, channel)) {
1160     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1161                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
1162     goto out;
1163   }
1164
1165   /* Remove client from channel */
1166   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
1167   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1168                                         SILC_STATUS_OK);
1169
1170   /* If the channel does not exist anymore we won't send anything */
1171   if (!i)
1172     goto out;
1173
1174   /* Re-generate channel key */
1175   key_len = channel->key_len / 8;
1176   for (i = 0; i < key_len; i++)
1177     channel_key[i] = silc_rng_get_byte(server->rng);
1178   channel->channel_key->cipher->set_key(channel->channel_key->context, 
1179                                         channel_key, key_len);
1180   memset(channel->key, 0, key_len);
1181   silc_free(channel->key);
1182   channel->key = silc_calloc(key_len, sizeof(*channel->key));
1183   memcpy(channel->key, channel_key, key_len);
1184   memset(channel_key, 0, sizeof(channel_key));
1185
1186   /* Encode channel key payload to be distributed on the channel */
1187   packet = 
1188     silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1189                                     strlen(channel->channel_key->cipher->name),
1190                                     channel->channel_key->cipher->name,
1191                                     key_len, channel->key);
1192
1193   /* If we are normal server then we will send it to our router.  If we
1194      are router we will send it to all local servers that has clients on
1195      the channel */
1196   if (server->server_type == SILC_SERVER) {
1197     if (!server->standalone)
1198       silc_server_packet_send(server, 
1199                               cmd->server->id_entry->router->connection,
1200                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1201                               packet->len, TRUE);
1202   } else {
1203
1204   }
1205
1206   /* Send to locally connected clients on the channel */
1207   silc_server_packet_send_local_channel(server, channel, 
1208                                         SILC_PACKET_CHANNEL_KEY, 0,
1209                                         packet->data, packet->len, FALSE);
1210
1211   silc_buffer_free(packet);
1212   silc_free(id);
1213
1214  out:
1215   silc_server_command_free(cmd);
1216 }
1217
1218 /* Server side of command NAMES. Resolves clients and their names currently
1219    joined on the requested channel. The name list is sent back to the
1220    client. */
1221
1222 SILC_SERVER_CMD_FUNC(names)
1223 {
1224   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1225   SilcServer server = cmd->server;
1226   SilcChannelList *channel;
1227   SilcChannelID *id;
1228   unsigned int i, len, len2, argc;
1229   unsigned char *tmp;
1230   char *name_list = NULL, *n;
1231
1232   SILC_LOG_DEBUG(("Start"));
1233
1234   argc = silc_command_get_arg_num(cmd->payload);
1235   if (argc < 1) {
1236     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1237                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1238     goto out;
1239   }
1240   if (argc > 2) {
1241     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1242                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1243     goto out;
1244   }
1245
1246   /* Get Channel ID */
1247   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1248   if (!tmp) {
1249     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1250                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1251     goto out;
1252   }
1253   id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1254
1255   /* Check whether the channel exists. If we are normal server and the
1256      channel does not exist we will send this same command to our router
1257      which will know if the channel exists. */
1258   channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1259   if (!channel) {
1260     if (server->server_type == SILC_SERVER && !server->standalone) {
1261       /* XXX Send names command */
1262
1263       cmd->pending = TRUE;
1264       silc_server_command_pending(SILC_COMMAND_NAMES, 
1265                                   silc_server_command_names, context);
1266       return;
1267     }
1268
1269     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1270                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1271     goto out;
1272   }
1273
1274   /* Assemble the name list now */
1275   name_list = NULL;
1276   len = 0;
1277   for (i = 0; i < channel->user_list_count; i++) {
1278     n = channel->user_list[i].client->nickname;
1279     if (n) {
1280       len2 = strlen(n);
1281       len += len2;
1282       name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1283       memcpy(name_list + (len - len2), n, len2);
1284       name_list[len] = 0;
1285
1286       if (i == channel->user_list_count - 1)
1287         break;
1288       memcpy(name_list + len, ",", 1);
1289       len++;
1290     }
1291   }
1292
1293   /* Send the reply */
1294   silc_server_command_send_status_msg(cmd, SILC_COMMAND_NAMES, SILC_STATUS_OK,
1295                                       name_list, strlen(name_list));
1296
1297   silc_free(name_list);
1298   silc_free(id);
1299
1300  out:
1301   silc_server_command_free(cmd);
1302 }