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