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