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