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