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