WHOIS command works on router environment.
[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 void silc_server_command_send_names(SilcServer server,
42                                     SilcSocketConnection sock,
43                                     SilcChannelEntry channel);
44
45 /* Server command list. */
46 SilcServerCommand silc_command_list[] =
47 {
48   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
49   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
50   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
51   SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
52   SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
53   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
54   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
55   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
56   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
57   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
58   SILC_SERVER_CMD(connect, CONNECT, 
59                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
60   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
61   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
62   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
63   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
64   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
65   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
66   SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
67   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
68   SILC_SERVER_CMD(restart, RESTART, 
69                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
70   SILC_SERVER_CMD(close, CLOSE,
71                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
72   SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
73   SILC_SERVER_CMD(silcoper, SILCOPER,
74                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
75   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
76   SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
77
78   { NULL, 0 },
79 };
80
81 #define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max)            \
82 do {                                                                          \
83   unsigned int _argc = silc_argument_get_arg_num(cmd->args);                  \
84                                                                               \
85   SILC_LOG_DEBUG(("Start"));                                                  \
86                                                                               \
87   if (_argc < min) {                                                          \
88     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,            \
89                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
90     silc_server_command_free(cmd);                                            \
91     return;                                                                   \
92   }                                                                           \
93   if (_argc > max) {                                                          \
94     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,            \
95                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);   \
96     silc_server_command_free(cmd);                                            \
97     return;                                                                   \
98   }                                                                           \
99 } while(0)
100
101 /* Returns TRUE if the connection is registered. Unregistered connections
102    usually cannot send commands hence the check. */
103
104 static int silc_server_is_registered(SilcServer server,
105                                      SilcSocketConnection sock,
106                                      SilcServerCommandContext cmd,
107                                      SilcCommand command)
108 {
109   SilcIDListData idata = (SilcIDListData)sock->user_data;
110   if (idata->registered)
111     return TRUE;
112
113   silc_server_command_send_status_reply(cmd, command,
114                                         SILC_STATUS_ERR_NOT_REGISTERED);
115   silc_server_command_free(cmd);
116   return FALSE;
117 }
118
119 /* Processes received command packet. */
120
121 void silc_server_command_process(SilcServer server,
122                                  SilcSocketConnection sock,
123                                  SilcPacketContext *packet)
124 {
125   SilcServerCommandContext ctx;
126   SilcServerCommand *cmd;
127
128 #if 0
129   /* XXX allow commands in but do not execute them more than once per
130      two seconds. */
131
132   /* Check whether it is allowed for this connection to execute any
133      command. */
134   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
135     time_t curtime;
136     SilcClientEntry client = (SilcClientEntry)sock->user_data;
137
138     if (!client)
139       return;
140
141     /* Allow only one command executed in 2 seconds. */
142     curtime = time(NULL);
143     if (client->last_command && (curtime - client->last_command) < 2)
144       return;
145
146     /* Update access time */
147     client->last_command = curtime;
148   }
149 #endif
150   
151   /* Allocate command context. This must be free'd by the
152      command routine receiving it. */
153   ctx = silc_calloc(1, sizeof(*ctx));
154   ctx->server = server;
155   ctx->sock = sock;
156   ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
157   
158   /* Parse the command payload in the packet */
159   ctx->payload = silc_command_payload_parse(packet->buffer);
160   if (!ctx->payload) {
161     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
162     silc_buffer_free(packet->buffer);
163     silc_packet_context_free(packet);
164     silc_free(ctx);
165     return;
166   }
167   ctx->args = silc_command_get_args(ctx->payload);
168   
169   /* Execute command. If this fails the packet is dropped. */
170   for (cmd = silc_command_list; cmd->cb; cmd++)
171     if (cmd->cmd == silc_command_get(ctx->payload)) {
172
173       if (!(cmd->flags & SILC_CF_REG)) {
174         cmd->cb(ctx);
175         break;
176       }
177       
178       if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
179         cmd->cb(ctx);
180         break;
181       }
182     }
183
184   if (cmd == NULL) {
185     SILC_LOG_ERROR(("Unknown command, packet dropped"));
186     silc_server_command_free(ctx);
187     return;
188   }
189 }
190
191 /* Add new pending command to be executed when reply to a command has been
192    received. The `reply_cmd' is the command that will call the `callback'
193    with `context' when reply has been received.  If `ident' is non-zero
194    the `callback' will be executed when received reply with command
195    identifier `ident'. */
196
197 void silc_server_command_pending(SilcServer server,
198                                  SilcCommand reply_cmd,
199                                  unsigned short ident,
200                                  SilcCommandCb callback,
201                                  void *context)
202 {
203   SilcServerCommandPending *reply;
204
205   reply = silc_calloc(1, sizeof(*reply));
206   reply->reply_cmd = reply_cmd;
207   reply->ident = ident;
208   reply->context = context;
209   reply->callback = callback;
210   silc_dlist_add(server->pending_commands, reply);
211 }
212
213 /* Deletes pending command by reply command type. */
214
215 void silc_server_command_pending_del(SilcServer server,
216                                      SilcCommand reply_cmd,
217                                      unsigned short ident)
218 {
219   SilcServerCommandPending *r;
220
221   silc_dlist_start(server->pending_commands);
222   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
223     if (r->reply_cmd == reply_cmd && r->ident == ident) {
224       silc_dlist_del(server->pending_commands, r);
225       break;
226     }
227   }
228 }
229
230 /* Checks for pending commands and marks callbacks to be called from
231    the command reply function. Returns TRUE if there were pending command. */
232
233 int silc_server_command_pending_check(SilcServer server,
234                                       SilcServerCommandReplyContext ctx,
235                                       SilcCommand command, 
236                                       unsigned short ident)
237 {
238   SilcServerCommandPending *r;
239
240   silc_dlist_start(server->pending_commands);
241   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
242     if (r->reply_cmd == command && r->ident == ident) {
243       ctx->context = r->context;
244       ctx->callback = r->callback;
245       ctx->ident = ident;
246       return TRUE;
247     }
248   }
249
250   return FALSE;
251 }
252
253 /* Free's the command context allocated before executing the command */
254
255 static void silc_server_command_free(SilcServerCommandContext cmd)
256 {
257   if (cmd) {
258     if (cmd->payload)
259       silc_command_free_payload(cmd->payload);
260     if (cmd->packet)
261       silc_packet_context_free(cmd->packet);
262     silc_free(cmd);
263   }
264 }
265
266 /* Sends simple status message as command reply packet */
267
268 static void 
269 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
270                                       SilcCommand command,
271                                       SilcCommandStatus status)
272 {
273   SilcBuffer buffer;
274
275   SILC_LOG_DEBUG(("Sending command status %d", status));
276
277   buffer = silc_command_reply_payload_encode_va(command, status, 0, 0);
278   silc_server_packet_send(cmd->server, cmd->sock,
279                           SILC_PACKET_COMMAND_REPLY, 0, 
280                           buffer->data, buffer->len, FALSE);
281   silc_buffer_free(buffer);
282 }
283
284 /* Sends command status reply with one extra argument. The argument
285    type must be sent as argument. */
286
287 static void 
288 silc_server_command_send_status_data(SilcServerCommandContext cmd,
289                                      SilcCommand command,
290                                      SilcCommandStatus status,
291                                      unsigned int arg_type,
292                                      unsigned char *arg,
293                                      unsigned int arg_len)
294 {
295   SilcBuffer buffer;
296
297   SILC_LOG_DEBUG(("Sending command status %d", status));
298
299   buffer = silc_command_reply_payload_encode_va(command, status, 0, 1,
300                                                 arg_type, arg, arg_len);
301   silc_server_packet_send(cmd->server, cmd->sock,
302                           SILC_PACKET_COMMAND_REPLY, 0, 
303                           buffer->data, buffer->len, FALSE);
304   silc_buffer_free(buffer);
305 }
306
307 /******************************************************************************
308
309                               WHOIS Functions
310
311 ******************************************************************************/
312
313 static int
314 silc_server_command_whois_parse(SilcServerCommandContext cmd,
315                                 SilcClientID **client_id,
316                                 char **nickname,
317                                 char **server_name,
318                                 int *count)
319 {
320   unsigned char *tmp;
321   unsigned int len;
322   unsigned int argc = silc_argument_get_arg_num(cmd->args);
323
324   /* If client ID is in the command it must be used instead of nickname */
325   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
326   if (!tmp) {
327     /* No ID, get the nickname@server string and parse it. */
328     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
329     if (tmp) {
330       if (strchr(tmp, '@')) {
331         len = strcspn(tmp, "@");
332         *nickname = silc_calloc(len + 1, sizeof(char));
333         memcpy(*nickname, tmp, len);
334         *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
335         memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
336       } else {
337         *nickname = strdup(tmp);
338       }
339     } else {
340       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
341                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
342       return FALSE;
343     }
344   } else {
345     /* Command includes ID, use that */
346     *client_id = silc_id_payload_parse_id(tmp, len);
347   }
348
349   /* Get the max count of reply messages allowed */
350   if (argc == 3) {
351     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
352     if (!tmp) {
353       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
354                                             SILC_STATUS_ERR_TOO_MANY_PARAMS);
355       if (*nickname)
356         silc_free(*nickname);
357       if (*server_name)
358         silc_free(*server_name);
359
360       return FALSE;
361     }
362     *count = atoi(tmp);
363   }
364
365   return TRUE;
366 }
367
368 static char
369 silc_server_command_whois_check(SilcServerCommandContext cmd,
370                                 SilcClientEntry *clients,
371                                 unsigned int clients_count)
372 {
373   SilcServer server = cmd->server;
374   int i;
375   SilcClientEntry entry;
376
377   for (i = 0; i < clients_count; i++) {
378     entry = clients[i];
379
380     if (!entry->nickname || !entry->username || !entry->userinfo) {
381       SilcBuffer tmpbuf;
382       unsigned short old_ident;
383       
384       old_ident = silc_command_get_ident(cmd->payload);
385       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
386       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
387
388       /* Send WHOIS command */
389       silc_server_packet_send(server, entry->router->connection,
390                               SILC_PACKET_COMMAND, cmd->packet->flags,
391                               tmpbuf->data, tmpbuf->len, TRUE);
392       
393       /* Reprocess this packet after received reply */
394       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
395                                   silc_command_get_ident(cmd->payload),
396                                   silc_server_command_whois, (void *)cmd);
397       cmd->pending = TRUE;
398       
399       silc_command_set_ident(cmd->payload, old_ident);
400
401       silc_buffer_free(tmpbuf);
402       return FALSE;
403     }
404   }
405
406   return TRUE;
407 }
408
409 static void
410 silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
411                                      SilcClientEntry *clients,
412                                      unsigned int clients_count)
413 {
414   SilcServer server = cmd->server;
415   char *tmp;
416   int i, count = 0, len;
417   SilcBuffer packet, idp;
418   SilcClientEntry entry;
419   SilcCommandStatus status;
420   unsigned short ident = silc_command_get_ident(cmd->payload);
421
422   status = SILC_STATUS_OK;
423   if (clients_count > 1)
424     status = SILC_STATUS_LIST_START;
425
426   for (i = 0; i < clients_count; i++) {
427     entry = clients[i];
428
429     if (count && i - 1 == count)
430       break;
431
432     if (clients_count > 2)
433       status = SILC_STATUS_LIST_ITEM;
434
435     if (clients_count > 1 && i == clients_count - 1)
436       status = SILC_STATUS_LIST_END;
437
438     /* Send WHOIS reply */
439     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
440     tmp = silc_argument_get_first_arg(cmd->args, NULL);
441     
442     /* XXX */
443     {
444       char nh[256], uh[256];
445       unsigned char idle[4];
446       SilcSocketConnection hsock;
447
448       memset(uh, 0, sizeof(uh));
449       memset(nh, 0, sizeof(nh));
450       
451       strncat(nh, entry->nickname, strlen(entry->nickname));
452       if (!strchr(entry->nickname, '@')) {
453         strncat(nh, "@", 1);
454         len = entry->router ? strlen(entry->router->server_name) :
455           strlen(server->server_name);
456         strncat(nh, entry->router ? entry->router->server_name :
457                 server->server_name, len);
458       }
459       
460       strncat(uh, entry->username, strlen(entry->username));
461       if (!strchr(entry->username, '@')) {
462         strncat(uh, "@", 1);
463         hsock = (SilcSocketConnection)entry->connection;
464         len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
465         strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
466       }
467       
468       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
469       
470       /* XXX */
471       if (entry->userinfo)
472         packet = 
473           silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
474                                                status, ident, 5, 
475                                                2, idp->data, idp->len,
476                                                3, nh, strlen(nh),
477                                                4, uh, strlen(uh),
478                                                5, entry->userinfo, 
479                                                strlen(entry->userinfo),
480                                                7, idle, 4);
481       else
482         packet = 
483           silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
484                                                status, ident, 4, 
485                                                2, idp->data, idp->len,
486                                                3, nh, strlen(nh),
487                                                4, uh, strlen(uh),
488                                                7, idle, 4);
489     }
490     
491     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
492                             0, packet->data, packet->len, FALSE);
493     
494     silc_buffer_free(packet);
495     silc_buffer_free(idp);
496   }
497 }
498
499 static int
500 silc_server_command_whois_from_client(SilcServerCommandContext cmd)
501 {
502   SilcServer server = cmd->server;
503   char *nick = NULL, *server_name = NULL;
504   int count = 0, clients_count;
505   SilcClientID *client_id = NULL;
506   SilcClientEntry *clients = NULL, entry;
507   int ret = 0;
508
509   /* Parse the whois request */
510   if (!silc_server_command_whois_parse(cmd, &client_id, &nick, 
511                                        &server_name, &count))
512     return 0;
513
514   /* Protocol dictates that we must always send the received WHOIS request
515      to our router if we are normal server, so let's do it now unless we
516      are standalone. We will not send any replies to the client until we
517      have received reply from the router. */
518   if (server->server_type == SILC_SERVER && 
519       !cmd->pending && !server->standalone) {
520     SilcBuffer tmpbuf;
521     unsigned short old_ident;
522
523     old_ident = silc_command_get_ident(cmd->payload);
524     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
525     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
526
527     /* Send WHOIS command to our router */
528     silc_server_packet_send(server, (SilcSocketConnection)
529                             server->router->connection,
530                             SILC_PACKET_COMMAND, cmd->packet->flags,
531                             tmpbuf->data, tmpbuf->len, TRUE);
532
533     /* Reprocess this packet after received reply from router */
534     silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
535                                 silc_command_get_ident(cmd->payload),
536                                 silc_server_command_whois, (void *)cmd);
537     cmd->pending = TRUE;
538
539     silc_command_set_ident(cmd->payload, old_ident);
540
541     silc_buffer_free(tmpbuf);
542     ret = -1;
543     goto out;
544   }
545
546   /* We are ready to process the command request. Let's search for the
547      requested client and send reply to the requesting client. */
548
549   /* Get all clients matching that ID or nickname from local list */
550   if (client_id) {
551     entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
552     if (entry) {
553       clients = silc_calloc(1, sizeof(*clients));
554       clients[0] = entry;
555       clients_count = 1;
556     }
557   } else {
558     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
559                                                   nick, server_name,
560                                                   &clients_count);
561   }
562   
563   /* Check global list as well */
564   if (!clients) {
565     if (client_id) {
566       entry = silc_idlist_find_client_by_id(server->global_list, 
567                                             client_id, NULL);
568       if (entry) {
569         clients = silc_calloc(1, sizeof(*clients));
570         clients[0] = entry;
571         clients_count = 1;
572       }
573     } else {
574       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
575                                                     nick, server_name,
576                                                     &clients_count);
577     }
578   }
579   
580   if (!clients) {
581     /* Such a client really does not exist in the SILC network. */
582     silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
583                                          SILC_STATUS_ERR_NO_SUCH_NICK,
584                                          3, nick, strlen(nick));
585     goto out;
586   }
587
588   /* Router always finds the client entry if it exists in the SILC network.
589      However, it might be incomplete entry and does not include all the
590      mandatory fields that WHOIS command reply requires. Check for these and
591      make query from the server who owns the client if some fields are 
592      missing. */
593   if (server->server_type == SILC_ROUTER &&
594       !silc_server_command_whois_check(cmd, clients, clients_count)) {
595     ret = -1;
596     goto out;
597   }
598
599   /* Send the command reply to the client */
600   silc_server_command_whois_send_reply(cmd, clients, clients_count);
601
602  out:
603   if (clients)
604     silc_free(clients);
605   if (client_id)
606     silc_free(client_id);
607   if (nick)
608     silc_free(nick);
609   if (server_name)
610     silc_free(server_name);
611
612   return ret;
613 }
614
615 static int
616 silc_server_command_whois_from_server(SilcServerCommandContext cmd)
617 {
618   SilcServer server = cmd->server;
619   char *nick = NULL, *server_name = NULL;
620   int count = 0, clients_count;
621   SilcClientID *client_id = NULL;
622   SilcClientEntry *clients = NULL, entry;
623   int ret = 0;
624
625   /* Parse the whois request */
626   if (!silc_server_command_whois_parse(cmd, &client_id, &nick, 
627                                        &server_name, &count))
628     return 0;
629
630   /* Process the command request. Let's search for the requested client and
631      send reply to the requesting server. */
632
633   if (client_id) {
634     entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
635     if (entry) {
636       clients = silc_calloc(1, sizeof(*clients));
637       clients[0] = entry;
638       clients_count = 1;
639     }
640   } else {
641     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
642                                                   nick, server_name,
643                                                   &clients_count);
644     if (!clients)
645       clients = silc_idlist_get_clients_by_hash(server->local_list, 
646                                                 nick, server->md5hash,
647                                                 &clients_count);
648   }
649   
650   /* If we are router we will check our global list as well. */
651   if (!clients && server->server_type == SILC_ROUTER) {
652     if (client_id) {
653       entry = silc_idlist_find_client_by_id(server->global_list, 
654                                             client_id, NULL);
655       if (entry) {
656         clients = silc_calloc(1, sizeof(*clients));
657         clients[0] = entry;
658         clients_count = 1;
659       }
660     } else {
661       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
662                                                     nick, server_name,
663                                                     &clients_count);
664       if (!clients)
665         clients = silc_idlist_get_clients_by_hash(server->global_list, 
666                                                   nick, server->md5hash,
667                                                   &clients_count);
668     }
669   }
670
671   if (!clients) {
672     /* Such a client really does not exist in the SILC network. */
673     silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
674                                          SILC_STATUS_ERR_NO_SUCH_NICK,
675                                          3, nick, strlen(nick));
676     goto out;
677   }
678
679   /* Router always finds the client entry if it exists in the SILC network.
680      However, it might be incomplete entry and does not include all the
681      mandatory fields that WHOIS command reply requires. Check for these and
682      make query from the server who owns the client if some fields are 
683      missing. */
684   if (!cmd->pending && server->server_type == SILC_ROUTER &&
685       !silc_server_command_whois_check(cmd, clients, clients_count)) {
686     ret = -1;
687     goto out;
688   }
689
690   /* Send the command reply to the client */
691   silc_server_command_whois_send_reply(cmd, clients, clients_count);
692
693  out:
694   if (clients)
695     silc_free(clients);
696   if (client_id)
697     silc_free(client_id);
698   if (nick)
699     silc_free(nick);
700   if (server_name)
701     silc_free(server_name);
702
703   return ret;
704 }
705
706 /* Server side of command WHOIS. Processes user's query and sends found 
707    results as command replies back to the client. */
708
709 SILC_SERVER_CMD_FUNC(whois)
710 {
711   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
712   int ret;
713
714   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3);
715
716   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
717     ret = silc_server_command_whois_from_client(cmd);
718   else
719     ret = silc_server_command_whois_from_server(cmd);
720
721   if (!ret)
722     silc_server_command_free(cmd);
723 }
724
725 SILC_SERVER_CMD_FUNC(whowas)
726 {
727 }
728
729 /******************************************************************************
730
731                               IDENTIFY Functions
732
733 ******************************************************************************/
734
735 static int
736 silc_server_command_identify_parse(SilcServerCommandContext cmd,
737                                    SilcClientID **client_id,
738                                    char **nickname,
739                                    char **server_name,
740                                    int *count)
741 {
742   unsigned char *tmp;
743   unsigned int len;
744   unsigned int argc = silc_argument_get_arg_num(cmd->args);
745
746   /* If client ID is in the command it must be used instead of nickname */
747   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
748   if (!tmp) {
749     /* No ID, get the nickname@server string and parse it. */
750     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
751     if (tmp) {
752       if (strchr(tmp, '@')) {
753         len = strcspn(tmp, "@");
754         *nickname = silc_calloc(len + 1, sizeof(char));
755         memcpy(*nickname, tmp, len);
756         *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
757         memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
758       } else {
759         *nickname = strdup(tmp);
760       }
761     } else {
762       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
763                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
764       return FALSE;
765     }
766   } else {
767     /* Command includes ID, use that */
768     *client_id = silc_id_payload_parse_id(tmp, len);
769   }
770
771   /* Get the max count of reply messages allowed */
772   if (argc == 3) {
773     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
774     if (!tmp) {
775       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
776                                             SILC_STATUS_ERR_TOO_MANY_PARAMS);
777       if (*nickname)
778         silc_free(*nickname);
779       if (*server_name)
780         silc_free(*server_name);
781
782       return FALSE;
783     }
784     *count = atoi(tmp);
785   }
786
787   return TRUE;
788 }
789
790 static void
791 silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
792                                         SilcClientEntry *clients,
793                                         unsigned int clients_count)
794 {
795   SilcServer server = cmd->server;
796   char *tmp;
797   int i, count = 0, len;
798   SilcBuffer packet, idp;
799   SilcClientEntry entry;
800   SilcCommandStatus status;
801   unsigned short ident = silc_command_get_ident(cmd->payload);
802
803   status = SILC_STATUS_OK;
804   if (clients_count > 1)
805     status = SILC_STATUS_LIST_START;
806
807   for (i = 0; i < clients_count; i++) {
808     entry = clients[i];
809
810     if (count && i - 1 == count)
811       break;
812
813     if (clients_count > 2)
814       status = SILC_STATUS_LIST_ITEM;
815
816     if (clients_count > 1 && i == clients_count - 1)
817       status = SILC_STATUS_LIST_END;
818
819     /* Send IDENTIFY reply */
820     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
821     tmp = silc_argument_get_first_arg(cmd->args, NULL);
822     
823     /* XXX */
824     {
825       char nh[256], uh[256];
826       SilcSocketConnection hsock;
827
828       memset(uh, 0, sizeof(uh));
829       memset(nh, 0, sizeof(nh));
830       
831       strncat(nh, entry->nickname, strlen(entry->nickname));
832       if (!strchr(entry->nickname, '@')) {
833         strncat(nh, "@", 1);
834         len = entry->router ? strlen(entry->router->server_name) :
835           strlen(server->server_name);
836         strncat(nh, entry->router ? entry->router->server_name :
837                 server->server_name, len);
838       }
839       
840       if (!entry->username) {
841         packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
842                                                       SILC_STATUS_OK, ident, 2,
843                                                       2, idp->data, idp->len, 
844                                                       3, nh, strlen(nh));
845       } else {
846         strncat(uh, entry->username, strlen(entry->username));
847         if (!strchr(entry->username, '@')) {
848           strncat(uh, "@", 1);
849           hsock = (SilcSocketConnection)entry->connection;
850           len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
851           strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
852         }
853       
854         packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
855                                                       SILC_STATUS_OK, ident, 3,
856                                                       2, idp->data, idp->len, 
857                                                       3, nh, strlen(nh),
858                                                       4, uh, strlen(uh));
859       }
860       
861       silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
862                               0, packet->data, packet->len, FALSE);
863       
864       silc_buffer_free(packet);
865       silc_buffer_free(idp);
866     }
867   }
868 }
869
870 static int
871 silc_server_command_identify_from_client(SilcServerCommandContext cmd)
872 {
873   SilcServer server = cmd->server;
874   char *nick = NULL, *server_name = NULL;
875   int count = 0, clients_count;
876   SilcClientID *client_id = NULL;
877   SilcClientEntry *clients = NULL, entry;
878   int ret = 0;
879
880   /* Parse the IDENTIFY request */
881   if (!silc_server_command_identify_parse(cmd, &client_id, &nick, 
882                                           &server_name, &count))
883     return 0;
884
885   /* Protocol dictates that we must always send the received IDENTIFY request
886      to our router if we are normal server, so let's do it now unless we
887      are standalone. We will not send any replies to the client until we
888      have received reply from the router. */
889   if (server->server_type == SILC_SERVER && 
890       !cmd->pending && !server->standalone) {
891     SilcBuffer tmpbuf;
892     unsigned short old_ident;
893
894     old_ident = silc_command_get_ident(cmd->payload);
895     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
896     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
897
898     /* Send IDENTIFY command to our router */
899     silc_server_packet_send(server, (SilcSocketConnection)
900                             server->router->connection,
901                             SILC_PACKET_COMMAND, cmd->packet->flags,
902                             tmpbuf->data, tmpbuf->len, TRUE);
903
904     /* Reprocess this packet after received reply from router */
905     silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, 
906                                 silc_command_get_ident(cmd->payload),
907                                 silc_server_command_identify, (void *)cmd);
908     cmd->pending = TRUE;
909
910     silc_command_set_ident(cmd->payload, old_ident);
911
912     silc_buffer_free(tmpbuf);
913     ret = -1;
914     goto out;
915   }
916
917   /* We are ready to process the command request. Let's search for the
918      requested client and send reply to the requesting client. */
919
920   /* Get all clients matching that ID or nickname from local list */
921   if (client_id) {
922     entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
923     if (entry) {
924       clients = silc_calloc(1, sizeof(*clients));
925       clients[0] = entry;
926       clients_count = 1;
927     }
928   } else {
929     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
930                                                   nick, server_name,
931                                                   &clients_count);
932   }
933   
934   /* Check global list as well */
935   if (!clients) {
936     if (client_id) {
937       entry = silc_idlist_find_client_by_id(server->global_list, 
938                                             client_id, NULL);
939       if (entry) {
940         clients = silc_calloc(1, sizeof(*clients));
941         clients[0] = entry;
942         clients_count = 1;
943       }
944     } else {
945       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
946                                                     nick, server_name,
947                                                     &clients_count);
948     }
949   }
950   
951   if (!clients) {
952     /* Such a client really does not exist in the SILC network. */
953     silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
954                                          SILC_STATUS_ERR_NO_SUCH_NICK,
955                                          3, nick, strlen(nick));
956     goto out;
957   }
958
959   /* Send the command reply to the client */
960   silc_server_command_identify_send_reply(cmd, clients, clients_count);
961
962  out:
963   if (clients)
964     silc_free(clients);
965   if (client_id)
966     silc_free(client_id);
967   if (nick)
968     silc_free(nick);
969   if (server_name)
970     silc_free(server_name);
971
972   return ret;
973 }
974
975 static int
976 silc_server_command_identify_from_server(SilcServerCommandContext cmd)
977 {
978   SilcServer server = cmd->server;
979   char *nick = NULL, *server_name = NULL;
980   int count = 0, clients_count;
981   SilcClientID *client_id = NULL;
982   SilcClientEntry *clients = NULL, entry;
983   int ret = 0;
984
985   /* Parse the IDENTIFY request */
986   if (!silc_server_command_identify_parse(cmd, &client_id, &nick, 
987                                           &server_name, &count))
988     return 0;
989
990   /* Process the command request. Let's search for the requested client and
991      send reply to the requesting server. */
992
993   if (client_id) {
994     entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
995     if (entry) {
996       clients = silc_calloc(1, sizeof(*clients));
997       clients[0] = entry;
998       clients_count = 1;
999     }
1000   } else {
1001     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
1002                                                   nick, server_name,
1003                                                   &clients_count);
1004     if (!clients)
1005       clients = silc_idlist_get_clients_by_hash(server->local_list, 
1006                                                 nick, server->md5hash,
1007                                                 &clients_count);
1008   }
1009   
1010   /* If we are router we will check our global list as well. */
1011   if (!clients && server->server_type == SILC_ROUTER) {
1012     if (client_id) {
1013       entry = silc_idlist_find_client_by_id(server->global_list, 
1014                                             client_id, NULL);
1015       if (entry) {
1016         clients = silc_calloc(1, sizeof(*clients));
1017         clients[0] = entry;
1018         clients_count = 1;
1019       }
1020     } else {
1021       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
1022                                                     nick, server_name,
1023                                                     &clients_count);
1024       if (!clients)
1025         clients = silc_idlist_get_clients_by_hash(server->global_list, 
1026                                                   nick, server->md5hash,
1027                                                   &clients_count);
1028     }
1029   }
1030
1031   if (!clients) {
1032     /* Such a client really does not exist in the SILC network. */
1033     silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1034                                          SILC_STATUS_ERR_NO_SUCH_NICK,
1035                                          3, nick, strlen(nick));
1036     goto out;
1037   }
1038
1039   /* Send the command reply to the client */
1040   silc_server_command_identify_send_reply(cmd, clients, clients_count);
1041
1042  out:
1043   if (clients)
1044     silc_free(clients);
1045   if (client_id)
1046     silc_free(client_id);
1047   if (nick)
1048     silc_free(nick);
1049   if (server_name)
1050     silc_free(server_name);
1051
1052   return ret;
1053 }
1054
1055 SILC_SERVER_CMD_FUNC(identify)
1056 {
1057   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1058   int ret;
1059
1060   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3);
1061
1062   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1063     ret = silc_server_command_identify_from_client(cmd);
1064   else
1065     ret = silc_server_command_identify_from_server(cmd);
1066
1067   if (!ret)
1068     silc_server_command_free(cmd);
1069 }
1070
1071 /* Checks string for bad characters and returns TRUE if they are found. */
1072
1073 static int silc_server_command_bad_chars(char *nick)
1074 {
1075   if (strchr(nick, '\\')) return TRUE;
1076   if (strchr(nick, '\"')) return TRUE;
1077   if (strchr(nick, '´')) return TRUE;
1078   if (strchr(nick, '`')) return TRUE;
1079   if (strchr(nick, '\'')) return TRUE;
1080   if (strchr(nick, '*')) return TRUE;
1081   if (strchr(nick, '/')) return TRUE;
1082   if (strchr(nick, '@')) return TRUE;
1083
1084   return FALSE;
1085 }
1086
1087 /* Server side of command NICK. Sets nickname for user. Setting
1088    nickname causes generation of a new client ID for the client. The
1089    new client ID is sent to the client after changing the nickname. */
1090
1091 SILC_SERVER_CMD_FUNC(nick)
1092 {
1093   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1094   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1095   SilcServer server = cmd->server;
1096   SilcBuffer packet, nidp, oidp;
1097   SilcClientID *new_id;
1098   char *nick;
1099
1100   SILC_LOG_DEBUG(("Start"));
1101
1102   /* Check number of arguments */
1103   if (silc_argument_get_arg_num(cmd->args) < 1) {
1104     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
1105                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1106     goto out;
1107   }
1108
1109   /* Check nickname */
1110   nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
1111   if (silc_server_command_bad_chars(nick) == TRUE) {
1112     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
1113                                           SILC_STATUS_ERR_BAD_NICKNAME);
1114     goto out;
1115   }
1116
1117   /* Create new Client ID */
1118   silc_id_create_client_id(cmd->server->id, cmd->server->rng, 
1119                            cmd->server->md5hash, nick,
1120                            &new_id);
1121
1122   /* Send notify about nickname change to our router. We send the new
1123      ID and ask to replace it with the old one. If we are router the
1124      packet is broadcasted. */
1125   if (!cmd->server->standalone)
1126     silc_server_send_replace_id(server, server->router->connection, 
1127                                 server->server_type == SILC_SERVER ? 
1128                                 FALSE : TRUE, client->id,
1129                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
1130                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
1131
1132   /* Remove old cache entry */
1133   silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
1134                          client->id); 
1135
1136   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1137
1138   /* Free old ID */
1139   if (client->id) {
1140     memset(client->id, 0, SILC_ID_CLIENT_LEN);
1141     silc_free(client->id);
1142   }
1143
1144   /* Save the nickname as this client is our local client */
1145   if (client->nickname)
1146     silc_free(client->nickname);
1147
1148   client->nickname = strdup(nick);
1149   client->id = new_id;
1150
1151   /* Update client cache */
1152   silc_idcache_add(server->local_list->clients, client->nickname, 
1153                    SILC_ID_CLIENT, client->id, (void *)client, TRUE);
1154
1155   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1156
1157   /* Send NICK_CHANGE notify */
1158   silc_server_send_notify_on_channels(server, client, 
1159                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
1160                                       oidp->data, oidp->len, 
1161                                       nidp->data, nidp->len);
1162
1163   /* Send the new Client ID as reply command back to client */
1164   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
1165                                                 SILC_STATUS_OK, 0, 1, 
1166                                                 2, nidp->data, nidp->len);
1167   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1168                           0, packet->data, packet->len, FALSE);
1169
1170   silc_buffer_free(packet);
1171   silc_buffer_free(nidp);
1172   silc_buffer_free(oidp);
1173   
1174  out:
1175   silc_server_command_free(cmd);
1176 }
1177
1178 SILC_SERVER_CMD_FUNC(list)
1179 {
1180 }
1181
1182 /* Server side of TOPIC command. Sets topic for channel and/or returns
1183    current topic to client. */
1184
1185 SILC_SERVER_CMD_FUNC(topic)
1186 {
1187   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1188   SilcServer server = cmd->server;
1189   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1190   SilcChannelID *channel_id;
1191   SilcChannelEntry channel;
1192   SilcChannelClientEntry chl;
1193   SilcBuffer packet, idp;
1194   unsigned char *tmp;
1195   unsigned int argc, tmp_len;
1196
1197   /* Check number of arguments */
1198   argc = silc_argument_get_arg_num(cmd->args);
1199   if (argc < 1) {
1200     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1201                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1202     goto out;
1203   }
1204   if (argc > 2) {
1205     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1206                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1207     goto out;
1208   }
1209
1210   /* Get Channel ID */
1211   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1212   if (!tmp) {
1213     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1214                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1215     goto out;
1216   }
1217   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1218
1219   /* Check whether the channel exists */
1220   channel = silc_idlist_find_channel_by_id(server->local_list, 
1221                                            channel_id, NULL);
1222   if (!channel) {
1223     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1224                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1225     goto out;
1226   }
1227
1228   if (argc > 1) {
1229     /* Get the topic */
1230     tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1231     if (!tmp) {
1232       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1233                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1234       goto out;
1235     }
1236
1237     if (strlen(tmp) > 256) {
1238       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1239                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1240       goto out;
1241     }
1242
1243     /* See whether has rights to change topic */
1244     silc_list_start(channel->user_list);
1245     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
1246       if (chl->client == client) {
1247         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1248           silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1249                                                 SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1250           goto out;
1251         } else {
1252           break;
1253         }
1254       }
1255     }
1256
1257     /* Set the topic for channel */
1258     if (channel->topic)
1259       silc_free(channel->topic);
1260     channel->topic = strdup(tmp);
1261
1262     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1263
1264     /* Send notify about topic change to all clients on the channel */
1265     silc_server_send_notify_to_channel(server, channel, TRUE,
1266                                        SILC_NOTIFY_TYPE_TOPIC_SET, 2,
1267                                        idp->data, idp->len,
1268                                        channel->topic, strlen(channel->topic));
1269     silc_buffer_free(idp);
1270   }
1271
1272   /* Send the topic to client as reply packet */
1273   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1274   if (channel->topic)
1275     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1276                                                   SILC_STATUS_OK, 0, 2, 
1277                                                   2, idp->data, idp->len,
1278                                                   3, channel->topic, 
1279                                                   strlen(channel->topic));
1280   else
1281     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1282                                                   SILC_STATUS_OK, 0, 1, 
1283                                                   2, idp->data, idp->len);
1284   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1285                           0, packet->data, packet->len, FALSE);
1286
1287   silc_buffer_free(packet);
1288   silc_buffer_free(idp);
1289   silc_free(channel_id);
1290
1291  out:
1292   silc_server_command_free(cmd);
1293 }
1294
1295 /* Server side of INVITE command. Invites some client to join some channel. */
1296
1297 SILC_SERVER_CMD_FUNC(invite)
1298 {
1299   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1300   SilcServer server = cmd->server;
1301   SilcSocketConnection sock = cmd->sock, dest_sock;
1302   SilcClientEntry sender, dest;
1303   SilcClientID *dest_id;
1304   SilcChannelEntry channel;
1305   SilcChannelID *channel_id;
1306   SilcBuffer sidp;
1307   unsigned char *tmp;
1308   unsigned int argc, len;
1309
1310   /* Check number of arguments */
1311   argc = silc_argument_get_arg_num(cmd->args);
1312   if (argc < 1) {
1313     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1314                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1315     goto out;
1316   }
1317   if (argc > 2) {
1318     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1319                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1320     goto out;
1321   }
1322
1323   /* Get destination ID */
1324   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1325   if (!tmp) {
1326     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1327                                           SILC_STATUS_ERR_NO_CLIENT_ID);
1328     goto out;
1329   }
1330   dest_id = silc_id_payload_parse_id(tmp, len);
1331
1332   /* Get Channel ID */
1333   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1334   if (!tmp) {
1335     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1336                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1337     goto out;
1338   }
1339   channel_id = silc_id_payload_parse_id(tmp, len);
1340
1341   /* Check whether the channel exists */
1342   channel = silc_idlist_find_channel_by_id(server->local_list, 
1343                                            channel_id, NULL);
1344   if (!channel) {
1345     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1346                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1347     goto out;
1348   }
1349
1350   /* Check whether the sender of this command is on the channel. */
1351   sender = (SilcClientEntry)sock->user_data;
1352   if (!silc_server_client_on_channel(sender, channel)) {
1353     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1354                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
1355     goto out;
1356   }
1357
1358   /* Check whether the channel is invite-only channel. If yes then the
1359      sender of this command must be at least channel operator. */
1360   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1361     SilcChannelClientEntry chl;
1362
1363     silc_list_start(channel->user_list);
1364     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
1365       if (chl->client == sender) {
1366         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1367           silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1368                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1369           goto out;
1370         }
1371         break;
1372       }
1373   }
1374
1375   /* Find the connection data for the destination. If it is local we will
1376      send it directly otherwise we will send it to router for routing. */
1377   dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
1378   if (dest)
1379     dest_sock = (SilcSocketConnection)dest->connection;
1380   else
1381     dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
1382
1383   /* Check whether the requested client is already on the channel. */
1384   /* XXX if we are normal server we don't know about global clients on
1385      the channel thus we must request it (NAMES command), check from
1386      local cache as well. */
1387   if (silc_server_client_on_channel(dest, channel)) {
1388     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1389                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1390     goto out;
1391   }
1392
1393   sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
1394
1395   /* Send notify to the client that is invited to the channel */
1396   silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
1397                                SILC_NOTIFY_TYPE_INVITE, 2, 
1398                                sidp->data, sidp->len, tmp, len);
1399
1400   /* Send command reply */
1401   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1402                                         SILC_STATUS_OK);
1403
1404   silc_buffer_free(sidp);
1405
1406  out:
1407   silc_server_command_free(cmd);
1408 }
1409
1410 /* Quits connection to client. This gets called if client won't
1411    close the connection even when it has issued QUIT command. */
1412
1413 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
1414 {
1415   SilcServer server = (SilcServer)context;
1416   SilcSocketConnection sock = server->sockets[fd];
1417
1418   /* Free all client specific data, such as client entry and entires
1419      on channels this client may be on. */
1420   silc_server_free_sock_user_data(server, sock);
1421
1422   /* Close the connection on our side */
1423   silc_server_close_connection(server, sock);
1424 }
1425
1426 /* Quits SILC session. This is the normal way to disconnect client. */
1427  
1428 SILC_SERVER_CMD_FUNC(quit)
1429 {
1430   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1431   SilcServer server = cmd->server;
1432   SilcSocketConnection sock = cmd->sock;
1433
1434   SILC_LOG_DEBUG(("Start"));
1435
1436   /* We quit the connection with little timeout */
1437   silc_task_register(server->timeout_queue, sock->sock,
1438                      silc_server_command_quit_cb, server,
1439                      0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1440
1441   silc_server_command_free(cmd);
1442 }
1443
1444 SILC_SERVER_CMD_FUNC(kill)
1445 {
1446 }
1447
1448 /* Server side of command INFO. This sends information about us to 
1449    the client. If client requested specific server we will send the 
1450    command to that server. */
1451
1452 SILC_SERVER_CMD_FUNC(info)
1453 {
1454   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1455   SilcServer server = cmd->server;
1456   SilcBuffer packet, idp;
1457   unsigned int argc;
1458   char info_string[256], *dest_server;
1459
1460   argc = silc_argument_get_arg_num(cmd->args);
1461   if (argc < 1) {
1462     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1463                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1464     goto out;
1465   }
1466   if (argc > 1) {
1467     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1468                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1469     goto out;
1470   }
1471
1472   /* Get server name */
1473   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
1474   if (!dest_server) {
1475     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1476                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1477     goto out;
1478   }
1479
1480   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
1481     /* Send our reply */
1482     memset(info_string, 0, sizeof(info_string));
1483     snprintf(info_string, sizeof(info_string), 
1484              "location: %s server: %s admin: %s <%s>",
1485              server->config->admin_info->location,
1486              server->config->admin_info->server_type,
1487              server->config->admin_info->admin_name,
1488              server->config->admin_info->admin_email);
1489
1490     idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
1491
1492     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
1493                                                   SILC_STATUS_OK, 0, 2,
1494                                                   2, idp->data, idp->len,
1495                                                   3, info_string, 
1496                                                   strlen(info_string));
1497     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
1498                             packet->data, packet->len, FALSE);
1499     
1500     silc_buffer_free(packet);
1501     silc_buffer_free(idp);
1502   } else {
1503     /* Send this command to the requested server */
1504
1505     if (server->server_type == SILC_SERVER && !server->standalone) {
1506
1507     }
1508
1509     if (server->server_type == SILC_ROUTER) {
1510
1511     }
1512   }
1513   
1514  out:
1515   silc_server_command_free(cmd);
1516 }
1517
1518 SILC_SERVER_CMD_FUNC(connect)
1519 {
1520 }
1521
1522 /* Server side of command PING. This just replies to the ping. */
1523
1524 SILC_SERVER_CMD_FUNC(ping)
1525 {
1526   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1527   SilcServer server = cmd->server;
1528   SilcServerID *id;
1529   unsigned int argc, len;
1530   unsigned char *tmp;
1531
1532   argc = silc_argument_get_arg_num(cmd->args);
1533   if (argc < 1) {
1534     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1535                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1536     goto out;
1537   }
1538   if (argc > 2) {
1539     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1540                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1541     goto out;
1542   }
1543
1544   /* Get Server ID */
1545   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1546   if (!tmp) {
1547     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1548                                           SILC_STATUS_ERR_NO_SERVER_ID);
1549     goto out;
1550   }
1551   id = silc_id_str2id(tmp, SILC_ID_SERVER);
1552   if (!id)
1553     goto out;
1554
1555   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
1556     /* Send our reply */
1557     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1558                                           SILC_STATUS_OK);
1559   } else {
1560     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1561                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1562     goto out;
1563   }
1564
1565   silc_free(id);
1566
1567  out:
1568   silc_server_command_free(cmd);
1569 }
1570
1571 SILC_SERVER_CMD_FUNC(oper)
1572 {
1573 }
1574
1575 typedef struct {
1576   char *channel_name;
1577   char *nickname;
1578   char *username;
1579   char *hostname;
1580   SilcChannelEntry channel;
1581   SilcServer server;
1582   SilcClientEntry client;
1583 } JoinInternalContext;
1584
1585 SILC_TASK_CALLBACK(silc_server_command_join_notify)
1586 {
1587   JoinInternalContext *ctx = (JoinInternalContext *)context;
1588
1589   if (ctx->channel->key && ctx->channel->key_len) {
1590     SilcBuffer clidp;
1591
1592     clidp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT);
1593
1594     silc_server_send_notify_to_channel(ctx->server, ctx->channel, FALSE,
1595                                        SILC_NOTIFY_TYPE_JOIN, 1,
1596                                        clidp->data, clidp->len);
1597 #if 0
1598     /* Send NEW_CHANNEL_USER packet to primary route */
1599     silc_server_send_new_channel_user(server, server->router->connection,
1600                                       server->server_type == SILC_SERVER ?
1601                                       FALSE : TRUE,
1602                                       channel->id, SILC_ID_CHANNEL_LEN,
1603                                       client->id, SILC_ID_CLIENT_LEN);
1604 #endif
1605
1606     /* Send NAMES command reply to the joined channel so the user sees who
1607        is currently on the channel. */
1608     silc_server_command_send_names(ctx->server, ctx->client->connection, 
1609                                    ctx->channel);
1610
1611     silc_buffer_free(clidp);
1612     silc_free(ctx);
1613   } else {
1614     silc_task_register(ctx->server->timeout_queue, fd,
1615                        silc_server_command_join_notify, context,
1616                        0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1617   }
1618 }
1619
1620 /* Assembles NAMES command and executes it. This is called when client
1621    joins to a channel and we wan't to send NAMES command reply to the 
1622    client. */
1623
1624 void silc_server_command_send_names(SilcServer server,
1625                                     SilcSocketConnection sock,
1626                                     SilcChannelEntry channel)
1627 {
1628   SilcServerCommandContext cmd;
1629   SilcBuffer buffer, idp;
1630
1631   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1632   buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1,
1633                                           1, idp->data, idp->len);
1634
1635   cmd = silc_calloc(1, sizeof(*cmd));
1636   cmd->payload = silc_command_payload_parse(buffer);
1637   cmd->args = silc_command_get_args(cmd->payload);
1638   cmd->server = server;
1639   cmd->sock = sock;
1640   cmd->pending = FALSE;
1641
1642   silc_server_command_names((void *)cmd);
1643   silc_free(buffer);
1644   silc_free(idp);
1645 }
1646
1647 /* Internal routine that is called after router has replied to server's
1648    JOIN command it forwarded to the router. The route has joined and possibly
1649    creaetd the channel. This function adds the client to the channel's user
1650    list. */
1651
1652 SILC_SERVER_CMD_FUNC(add_to_channel)
1653 {
1654   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1655   SilcServer server = cmd->server;
1656   SilcClientEntry client;
1657   SilcChannelEntry channel;
1658   SilcChannelClientEntry chl;
1659   char *channel_name;
1660
1661   /* Get channel name */
1662   channel_name = silc_argument_get_arg_type(cmd->args, 1, NULL);
1663
1664   /* Get client entry */
1665   client = (SilcClientEntry)cmd->sock->user_data;
1666
1667   /* Get channel entry */
1668   channel = silc_idlist_find_channel_by_name(server->local_list, 
1669                                              channel_name, NULL);
1670   if (channel) {
1671     /* Join the client to the channel by adding it to channel's user list.
1672        Add also the channel to client entry's channels list for fast cross-
1673        referencing. */
1674     chl = silc_calloc(1, sizeof(*chl));
1675     //chl->mode = SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO;
1676     chl->client = client;
1677     chl->channel = channel;
1678     silc_list_add(channel->user_list, chl);
1679     silc_list_add(client->channels, chl);
1680   }
1681
1682   silc_server_command_free(cmd);
1683 }
1684
1685 /* Internal routine to join channel. The channel sent to this function
1686    has been either created or resolved from ID lists. This joins the sent
1687    client to the channel. */
1688
1689 static void silc_server_command_join_channel(SilcServer server, 
1690                                              SilcServerCommandContext cmd,
1691                                              SilcChannelEntry channel,
1692                                              int created,
1693                                              unsigned int umode)
1694 {
1695   SilcSocketConnection sock = cmd->sock;
1696   unsigned char *tmp;
1697   unsigned int tmp_len;
1698   unsigned char *passphrase = NULL, mode[4];
1699   SilcClientEntry client;
1700   SilcChannelClientEntry chl;
1701   SilcBuffer reply, chidp, clidp;
1702
1703   if (!channel)
1704     return;
1705
1706   /* Get passphrase */
1707   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1708   if (tmp) {
1709     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1710     memcpy(passphrase, tmp, tmp_len);
1711   }
1712   
1713   /*
1714    * Check channel modes
1715    */
1716
1717   /* Check invite list if channel is invite-only channel */
1718   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1719     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
1720       /* Invite list is specified. Check whether client is invited in the
1721          list. If not, then check whether it has been invited otherwise. */
1722
1723     } else {
1724       /* XXX client must be invited to be able to join the channel */
1725     }
1726   }
1727
1728   /* Check ban list if set */
1729   if (channel->mode & SILC_CHANNEL_MODE_BAN) {
1730
1731   }
1732
1733   /* Check the channel passphrase if set. */
1734   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
1735     if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
1736                               strlen(channel->mode_data.passphrase))) {
1737       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1738                                             SILC_STATUS_ERR_BAD_PASSWORD);
1739       goto out;
1740     }
1741   }
1742
1743   /* Check user count limit if set. */
1744   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
1745     if (silc_list_count(channel->user_list) + 1 > 
1746         channel->mode_data.user_limit) {
1747       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1748                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
1749       goto out;
1750     }
1751   }
1752
1753   /*
1754    * Client is allowed to join to the channel. Make it happen.
1755    */
1756
1757   /* If the JOIN request was forwarded to us we will make a bit slower
1758      query to get the client pointer. Otherwise, we get the client pointer
1759      real easy. */
1760   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1761     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1762     client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
1763     if (!client) {
1764       /* XXX */
1765       SILC_LOG_ERROR(("Forwarded join command did not find the client who "
1766                       "wanted to join the channel"));
1767       goto out;
1768     }
1769     silc_free(id);
1770   } else {
1771     client = (SilcClientEntry)sock->user_data;
1772   }
1773
1774   /* Check whether the client already is on the channel */
1775   if (silc_server_client_on_channel(client, channel)) {
1776     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1777                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1778     goto out;
1779   }
1780
1781   /* Generate new channel key as protocol dictates */
1782   if (!created)
1783     silc_server_create_channel_key(server, channel, 0);
1784
1785   /* Join the client to the channel by adding it to channel's user list.
1786      Add also the channel to client entry's channels list for fast cross-
1787      referencing. */
1788   chl = silc_calloc(1, sizeof(*chl));
1789   chl->mode = umode;
1790   chl->client = client;
1791   chl->channel = channel;
1792   silc_list_add(channel->user_list, chl);
1793   silc_list_add(client->channels, chl);
1794
1795   /* Encode Client ID Payload of the original client who wants to join */
1796   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1797
1798   /* Encode command reply packet */
1799   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1800   SILC_PUT32_MSB(channel->mode, mode);
1801   if (!channel->topic) {
1802     reply = 
1803       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1804                                            SILC_STATUS_OK, 0, 3,
1805                                            2, channel->channel_name,
1806                                            strlen(channel->channel_name),
1807                                            3, chidp->data, chidp->len,
1808                                            4, mode, 4);
1809   } else {
1810     reply = 
1811       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1812                                            SILC_STATUS_OK, 0, 4, 
1813                                            2, channel->channel_name, 
1814                                            strlen(channel->channel_name),
1815                                            3, chidp->data, chidp->len,
1816                                            4, mode, 4,
1817                                            5, channel->topic, 
1818                                            strlen(channel->topic));
1819   }
1820     
1821   if (server->server_type == SILC_ROUTER && 
1822       cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1823     /* We are router and server has forwarded this command to us. Send
1824        all replys to the server. */
1825     void *tmpid;
1826
1827     /* Send command reply destined to the original client */
1828     tmpid = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1829     silc_server_packet_send_dest(cmd->server, sock, 
1830                                  SILC_PACKET_COMMAND_REPLY, 0,
1831                                  tmpid, cmd->packet->src_id_type,
1832                                  reply->data, reply->len, FALSE);
1833
1834     /* Distribute new channel key to local cell and local clients. */
1835     silc_server_send_channel_key(server, channel, FALSE);
1836     
1837     /* Distribute JOIN notify into the cell for everbody on the channel */
1838     silc_server_send_notify_to_channel(server, channel, FALSE,
1839                                        SILC_NOTIFY_TYPE_JOIN, 1,
1840                                        clidp->data, clidp->len);
1841
1842     /* Broadcast NEW_CHANNEL_USER packet to primary route */
1843     silc_server_send_new_channel_user(server, server->router->connection,
1844                                       TRUE, channel->id, SILC_ID_CHANNEL_LEN,
1845                                       client->id, SILC_ID_CLIENT_LEN);
1846
1847     silc_free(tmpid);
1848   } else {
1849     /* Client sent the command. Send all replies directly to the client. */
1850
1851     /* Send command reply */
1852     silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
1853                             reply->data, reply->len, FALSE);
1854
1855     /* Send the channel key. Channel key is sent before any other packet
1856        to the channel. */
1857     silc_server_send_channel_key(server, channel, server->standalone ?
1858                                  FALSE : TRUE);
1859     
1860     /* Send JOIN notify to locally connected clients on the channel */
1861     silc_server_send_notify_to_channel(server, channel, FALSE,
1862                                        SILC_NOTIFY_TYPE_JOIN, 1,
1863                                        clidp->data, clidp->len);
1864
1865     /* Send NEW_CHANNEL_USER packet to our primary router */
1866     if (!server->standalone)
1867       silc_server_send_new_channel_user(server, server->router->connection,
1868                                         FALSE, 
1869                                         channel->id, SILC_ID_CHANNEL_LEN,
1870                                         client->id, SILC_ID_CLIENT_LEN);
1871
1872     /* Send NAMES command reply to the joined channel so the user sees who
1873        is currently on the channel. */
1874     silc_server_command_send_names(server, sock, channel);
1875   }
1876
1877   silc_buffer_free(reply);
1878   silc_buffer_free(clidp);
1879   silc_buffer_free(chidp);
1880
1881  out:
1882   if (passphrase)
1883     silc_free(passphrase);
1884 }
1885
1886 /* Server side of command JOIN. Joins client into requested channel. If 
1887    the channel does not exist it will be created. */
1888
1889 SILC_SERVER_CMD_FUNC(join)
1890 {
1891   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1892   SilcServer server = cmd->server;
1893   int argc, tmp_len;
1894   char *tmp, *channel_name = NULL, *cipher = NULL;
1895   SilcChannelEntry channel;
1896   unsigned int umode = 0;
1897   int created = FALSE;
1898
1899   SILC_LOG_DEBUG(("Start"));
1900
1901   /* Check number of parameters */
1902   argc = silc_argument_get_arg_num(cmd->args);
1903   if (argc < 1) {
1904     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1905                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1906     goto out;
1907   }
1908   if (argc > 3) {
1909     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1910                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
1911     goto out;
1912   }
1913
1914   /* Get channel name */
1915   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1916   if (!tmp) {
1917     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1918                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1919     goto out;
1920   }
1921   channel_name = tmp;
1922
1923   if (silc_server_command_bad_chars(channel_name) == TRUE) {
1924     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1925                                           SILC_STATUS_ERR_BAD_CHANNEL);
1926     silc_free(channel_name);
1927     goto out;
1928   }
1929
1930   /* Get cipher name */
1931   cipher = silc_argument_get_arg_type(cmd->args, 3, NULL);
1932
1933   /* See if the channel exists */
1934   channel = silc_idlist_find_channel_by_name(server->local_list, 
1935                                              channel_name, NULL);
1936   if (!channel) {
1937     /* Channel not found */
1938
1939     /* If we are standalone server we don't have a router, we just create 
1940        the channel by ourselves. */
1941     if (server->standalone) {
1942       channel = silc_server_create_new_channel(server, server->id, cipher, 
1943                                                channel_name);
1944       umode |= SILC_CHANNEL_UMODE_CHANOP;
1945       umode |= SILC_CHANNEL_UMODE_CHANFO;
1946       created = TRUE;
1947     } else {
1948
1949       /* The channel does not exist on our server. If we are normal server 
1950          we will send JOIN command to our router which will handle the joining
1951          procedure (either creates the channel if it doesn't exist or joins
1952          the client to it). */
1953       if (server->server_type == SILC_SERVER) {
1954         /* Forward the original JOIN command to the router */
1955         silc_buffer_push(cmd->packet->buffer, 
1956                          cmd->packet->buffer->data - 
1957                          cmd->packet->buffer->head);
1958         silc_server_packet_forward(server, (SilcSocketConnection)
1959                                    server->router->connection,
1960                                    cmd->packet->buffer->data, 
1961                                    cmd->packet->buffer->len, TRUE);
1962
1963         /* Register handler that will be called after the router has replied
1964            to us. We will add the client to the new channel in this callback
1965            function. Will be called from JOIN command reply. */
1966         silc_server_command_pending(server, SILC_COMMAND_JOIN, 
1967                                     ++server->router->data.cmd_ident,
1968                                     silc_server_command_add_to_channel,
1969                                     context);
1970         return;
1971       }
1972       
1973       /* We are router and the channel does not seem exist so we will check
1974          our global list as well for the channel. */
1975       channel = silc_idlist_find_channel_by_name(server->global_list, 
1976                                                  channel_name, NULL);
1977       if (!channel) {
1978         /* Channel really does not exist, create it */
1979         channel = silc_server_create_new_channel(server, server->id, cipher, 
1980                                                  channel_name);
1981         umode |= SILC_CHANNEL_UMODE_CHANOP;
1982         umode |= SILC_CHANNEL_UMODE_CHANFO;
1983         created = TRUE;
1984       }
1985     }
1986   }
1987
1988   /* Join to the channel */
1989   silc_server_command_join_channel(server, cmd, channel, created, umode);
1990
1991  out:
1992   silc_server_command_free(cmd);
1993 }
1994
1995 /* Server side of command MOTD. Sends server's current "message of the
1996    day" to the client. */
1997
1998 SILC_SERVER_CMD_FUNC(motd)
1999 {
2000   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2001   SilcServer server = cmd->server;
2002   unsigned int argc;
2003   char *motd;
2004   int motd_len;
2005   
2006   SILC_LOG_DEBUG(("Start"));
2007
2008   argc = silc_argument_get_arg_num(cmd->args);
2009   if (argc < 1) {
2010     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2011                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2012     goto out;
2013   }
2014   if (argc > 2) {
2015     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2016                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2017     goto out;
2018   }
2019
2020   /* XXX show currently only our motd */
2021
2022   if (server->config && server->config->motd && 
2023       server->config->motd->motd_file) {
2024
2025     /* Send motd */
2026     motd = silc_file_read(server->config->motd->motd_file, &motd_len);
2027     if (!motd)
2028       goto out;
2029
2030     motd[motd_len] = 0;
2031     silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
2032                                          SILC_STATUS_OK,
2033                                          2, motd, motd_len);
2034     goto out;
2035   } else {
2036     /* No motd */
2037     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
2038                                           SILC_STATUS_OK);
2039   }
2040
2041  out:
2042   silc_server_command_free(cmd);
2043 }
2044
2045 SILC_SERVER_CMD_FUNC(umode)
2046 {
2047 }
2048
2049 /* Checks that client has rights to add or remove channel modes. If any
2050    of the checks fails FALSE is returned. */
2051
2052 int silc_server_check_cmode_rights(SilcChannelEntry channel,
2053                                    SilcChannelClientEntry client,
2054                                    unsigned int mode)
2055 {
2056   int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
2057   int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
2058
2059   /* Check whether has rights to change anything */
2060   if (!is_op && !is_fo)
2061     return FALSE;
2062
2063   /* Check whether has rights to change everything */
2064   if (is_op && is_fo)
2065     return TRUE;
2066
2067   /* We know that client is channel operator, check that they are not
2068      changing anything that requires channel founder rights. Rest of the
2069      modes are available automatically for channel operator. */
2070
2071   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
2072     if (is_op && !is_fo)
2073       return FALSE;
2074   } else {
2075     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2076       if (is_op && !is_fo)
2077         return FALSE;
2078     }
2079   }
2080   
2081   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2082     if (is_op && !is_fo)
2083       return FALSE;
2084   } else {
2085     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2086       if (is_op && !is_fo)
2087         return FALSE;
2088     }
2089   }
2090
2091   if (mode & SILC_CHANNEL_MODE_CIPHER) {
2092     if (is_op && !is_fo)
2093       return FALSE;
2094   } else {
2095     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2096       if (is_op && !is_fo)
2097         return FALSE;
2098     }
2099   }
2100   
2101   return TRUE;
2102 }
2103
2104 /* Server side command of CMODE. Changes channel mode */
2105
2106 SILC_SERVER_CMD_FUNC(cmode)
2107 {
2108   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2109   SilcServer server = cmd->server;
2110   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2111   SilcChannelID *channel_id;
2112   SilcChannelEntry channel;
2113   SilcChannelClientEntry chl;
2114   SilcBuffer packet, cidp;
2115   unsigned char *tmp, *tmp_id, *tmp_mask;
2116   unsigned int argc, mode_mask, tmp_len, tmp_len2;
2117
2118   SILC_LOG_DEBUG(("Start"));
2119
2120   argc = silc_argument_get_arg_num(cmd->args);
2121   if (argc < 2) {
2122     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2123                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2124     goto out;
2125   }
2126   if (argc > 8) {
2127     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2128                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2129     goto out;
2130   }
2131
2132   /* Get Channel ID */
2133   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
2134   if (!tmp_id) {
2135     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2136                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2137     goto out;
2138   }
2139   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
2140
2141   /* Get the channel mode mask */
2142   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2143   if (!tmp_mask) {
2144     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2145                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2146     goto out;
2147   }
2148   SILC_GET32_MSB(mode_mask, tmp_mask);
2149
2150   /* Get channel entry */
2151   channel = silc_idlist_find_channel_by_id(server->local_list, 
2152                                            channel_id, NULL);
2153   if (!channel) {
2154     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2155                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2156     goto out;
2157   }
2158
2159   /* Check whether this client is on the channel */
2160   if (!silc_server_client_on_channel(client, channel)) {
2161     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2162                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2163     goto out;
2164   }
2165
2166   /* Get entry to the channel user list */
2167   silc_list_start(channel->user_list);
2168   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2169     if (chl->client == client)
2170       break;
2171
2172   /* Check that client has rights to change any requested channel modes */
2173   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
2174     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2175                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2176     goto out;
2177   }
2178
2179   /*
2180    * Check the modes. Modes that requires nothing special operation are
2181    * not checked here.
2182    */
2183
2184   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
2185     /* Channel uses private keys to protect traffic. Client(s) has set the
2186        key locally they want to use, server does not know that key. */
2187     /* Nothing interesting to do here now */
2188   } else {
2189     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2190       /* The mode is removed and we need to generate and distribute
2191          new channel key. Clients are not using private channel keys
2192          anymore after this. */
2193
2194       /* XXX Duplicated code, make own function for this!! LEAVE uses this
2195          as well */
2196
2197       /* Re-generate channel key */
2198       silc_server_create_channel_key(server, channel, 0);
2199       
2200       /* Encode channel key payload to be distributed on the channel */
2201       packet = 
2202         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2203                                         strlen(channel->channel_key->
2204                                                cipher->name),
2205                                         channel->channel_key->cipher->name,
2206                                         channel->key_len / 8, channel->key);
2207       
2208       /* If we are normal server then we will send it to our router.  If we
2209          are router we will send it to all local servers that has clients on
2210          the channel */
2211       if (server->server_type == SILC_SERVER) {
2212         if (!server->standalone)
2213           silc_server_packet_send(server, 
2214                                   cmd->server->router->connection,
2215                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2216                                   packet->len, TRUE);
2217       } else {
2218         
2219       }
2220       
2221       /* Send to locally connected clients on the channel */
2222       silc_server_packet_send_local_channel(server, channel, 
2223                                             SILC_PACKET_CHANNEL_KEY, 0,
2224                                             packet->data, packet->len, FALSE);
2225       silc_buffer_free(packet);
2226     }
2227   }
2228   
2229   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
2230     /* User limit is set on channel */
2231     unsigned int user_limit;
2232       
2233     /* Get user limit */
2234     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
2235     if (!tmp) {
2236       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
2237         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2238                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2239         goto out;
2240       }
2241     } else {
2242       SILC_GET32_MSB(user_limit, tmp);
2243       channel->mode_data.user_limit = user_limit;
2244     }
2245   } else {
2246     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
2247       /* User limit mode is unset. Remove user limit */
2248       channel->mode_data.user_limit = 0;
2249   }
2250
2251   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
2252     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
2253       /* Passphrase has been set to channel */
2254       
2255       /* Get the passphrase */
2256       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
2257       if (!tmp) {
2258         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2259                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2260         goto out;
2261       }
2262
2263       /* Save the passphrase */
2264       channel->mode_data.passphrase = strdup(tmp);
2265     }
2266   } else {
2267     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2268       /* Passphrase mode is unset. remove the passphrase */
2269       if (channel->mode_data.passphrase) {
2270         silc_free(channel->mode_data.passphrase);
2271         channel->mode_data.passphrase = NULL;
2272       }
2273     }
2274   }
2275
2276   if (mode_mask & SILC_CHANNEL_MODE_BAN) {
2277     if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
2278       /* Ban list is specified for channel */
2279
2280       /* Get ban list */
2281       tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
2282       if (!tmp) {
2283         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2284                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2285         goto out;
2286       }
2287
2288       /* XXX check that channel founder is not banned */
2289
2290       /* Save the ban list */
2291       channel->mode_data.ban_list = strdup(tmp);
2292     }
2293   } else {
2294     if (channel->mode & SILC_CHANNEL_MODE_BAN) {
2295       /* Ban mode is unset. Remove the entire ban list */
2296       if (channel->mode_data.ban_list) {
2297         silc_free(channel->mode_data.ban_list);
2298         channel->mode_data.ban_list = NULL;
2299       }
2300     }
2301   }
2302
2303   if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
2304     if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
2305       /* Invite list is specified for channel */
2306
2307       /* Get invite list */
2308       tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
2309       if (!tmp) {
2310         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2311                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2312         goto out;
2313       }
2314
2315       /* Save the invite linst */
2316       channel->mode_data.invite_list = strdup(tmp);
2317     }
2318   } else {
2319     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
2320       /* Invite list mode is unset. Remove the entire invite list */
2321       if (channel->mode_data.invite_list) {
2322         silc_free(channel->mode_data.invite_list);
2323         channel->mode_data.invite_list = NULL;
2324       }
2325     }
2326   }
2327
2328   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
2329     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
2330       /* Cipher to use protect the traffic */
2331       unsigned int key_len = 128;
2332       char *cp;
2333
2334       /* Get cipher */
2335       tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
2336       if (!tmp) {
2337         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2338                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2339         goto out;
2340       }
2341
2342       cp = strchr(tmp, ':');
2343       if (cp) {
2344         key_len = atoi(cp);
2345         *cp = '\0';
2346       }
2347
2348       /* XXX Duplicated code, make own function for this!! */
2349     
2350       /* Delete old cipher and allocate the new one */
2351       silc_cipher_free(channel->channel_key);
2352       silc_cipher_alloc(tmp, &channel->channel_key);
2353
2354       key_len /= 8;
2355       if (key_len > 32)
2356         key_len = 32;
2357
2358       /* Re-generate channel key */
2359       silc_server_create_channel_key(server, channel, key_len);
2360     
2361       /* Encode channel key payload to be distributed on the channel */
2362       packet = 
2363         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2364                                         strlen(channel->channel_key->
2365                                                cipher->name),
2366                                         channel->channel_key->cipher->name,
2367                                         channel->key_len / 8, channel->key);
2368     
2369       /* If we are normal server then we will send it to our router.  If we
2370          are router we will send it to all local servers that has clients on
2371          the channel */
2372       if (server->server_type == SILC_SERVER) {
2373         if (!server->standalone)
2374           silc_server_packet_send(server, 
2375                                   cmd->server->router->connection,
2376                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2377                                   packet->len, TRUE);
2378       } else {
2379         
2380       }
2381     
2382       /* Send to locally connected clients on the channel */
2383       silc_server_packet_send_local_channel(server, channel, 
2384                                             SILC_PACKET_CHANNEL_KEY, 0,
2385                                           packet->data, packet->len, FALSE);
2386       silc_buffer_free(packet);
2387     }
2388   } else {
2389     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2390       /* Cipher mode is unset. Remove the cipher and revert back to 
2391          default cipher */
2392
2393       if (channel->mode_data.cipher) {
2394         silc_free(channel->mode_data.cipher);
2395         channel->mode_data.cipher = NULL;
2396         channel->mode_data.key_len = 0;
2397       }
2398
2399       /* Generate new cipher and key for the channel */
2400
2401       /* XXX Duplicated code, make own function for this!! */
2402
2403       /* Delete old cipher and allocate default one */
2404       silc_cipher_free(channel->channel_key);
2405       if (!channel->cipher)
2406         silc_cipher_alloc("twofish", &channel->channel_key);
2407       else
2408         silc_cipher_alloc(channel->cipher, &channel->channel_key);
2409
2410       /* Re-generate channel key */
2411       silc_server_create_channel_key(server, channel, 0);
2412       
2413       /* Encode channel key payload to be distributed on the channel */
2414       packet = 
2415         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2416                                         strlen(channel->channel_key->
2417                                                cipher->name),
2418                                         channel->channel_key->cipher->name,
2419                                         channel->key_len / 8, channel->key);
2420       
2421       /* If we are normal server then we will send it to our router.  If we
2422          are router we will send it to all local servers that has clients on
2423          the channel */
2424       if (server->server_type == SILC_SERVER) {
2425         if (!server->standalone)
2426           silc_server_packet_send(server, 
2427                                   cmd->server->router->connection,
2428                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2429                                   packet->len, TRUE);
2430       } else {
2431         
2432       }
2433       
2434       /* Send to locally connected clients on the channel */
2435       silc_server_packet_send_local_channel(server, channel, 
2436                                             SILC_PACKET_CHANNEL_KEY, 0,
2437                                             packet->data, packet->len, FALSE);
2438       silc_buffer_free(packet);
2439     }
2440   }
2441
2442   /* Finally, set the mode */
2443   channel->mode = mode_mask;
2444
2445   /* Send CMODE_CHANGE notify */
2446   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2447   silc_server_send_notify_to_channel(server, channel, TRUE,
2448                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
2449                                      cidp->data, cidp->len, 
2450                                      tmp_mask, tmp_len);
2451   silc_free(cidp);
2452
2453   /* Send command reply to sender */
2454   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
2455                                                 SILC_STATUS_OK, 0, 1,
2456                                                 2, tmp_mask, 4);
2457   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2458                           packet->data, packet->len, FALSE);
2459     
2460   silc_buffer_free(packet);
2461   silc_free(channel_id);
2462
2463  out:
2464   silc_server_command_free(cmd);
2465 }
2466
2467 /* Server side of CUMODE command. Changes client's mode on a channel. */
2468
2469 SILC_SERVER_CMD_FUNC(cumode)
2470 {
2471   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2472   SilcServer server = cmd->server;
2473   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2474   SilcChannelID *channel_id;
2475   SilcClientID *client_id;
2476   SilcChannelEntry channel;
2477   SilcClientEntry target_client;
2478   SilcChannelClientEntry chl;
2479   SilcBuffer packet, idp;
2480   unsigned char *tmp_id, *tmp_mask;
2481   unsigned int argc, target_mask, sender_mask, tmp_len;
2482   int notify = FALSE;
2483
2484   SILC_LOG_DEBUG(("Start"));
2485
2486   argc = silc_argument_get_arg_num(cmd->args);
2487   if (argc < 3) {
2488     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2489                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2490     goto out;
2491   }
2492   if (argc > 3) {
2493     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2494                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2495     goto out;
2496   }
2497
2498   /* Get Channel ID */
2499   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2500   if (!tmp_id) {
2501     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2502                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2503     goto out;
2504   }
2505   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2506
2507   /* Get channel entry */
2508   channel = silc_idlist_find_channel_by_id(server->local_list, 
2509                                            channel_id, NULL);
2510   if (!channel) {
2511     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2512                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2513     goto out;
2514   }
2515
2516   /* Check whether sender is on the channel */
2517   if (!silc_server_client_on_channel(client, channel)) {
2518     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2519                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2520     goto out;
2521   }
2522
2523   /* Check that client has rights to change other's rights */
2524   silc_list_start(channel->user_list);
2525   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2526     if (chl->client == client) {
2527       if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
2528           !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2529         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2530                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2531         goto out;
2532       }
2533
2534       sender_mask = chl->mode;
2535       break;
2536     }
2537   }
2538   
2539   /* Get the target client's channel mode mask */
2540   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
2541   if (!tmp_mask) {
2542     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2543                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2544     goto out;
2545   }
2546   SILC_GET32_MSB(target_mask, tmp_mask);
2547
2548   /* Get target Client ID */
2549   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2550   if (!tmp_id) {
2551     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2552                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2553     goto out;
2554   }
2555   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2556
2557   /* Get target client's entry */
2558   target_client = silc_idlist_find_client_by_id(server->local_list, 
2559                                                 client_id, NULL);
2560   if (!target_client) {
2561     /* XXX If target client is not one of mine send to primary route */
2562   }
2563
2564   /* Check whether target client is on the channel */
2565   if (!silc_server_client_on_channel(target_client, channel)) {
2566     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2567                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
2568     goto out;
2569   }
2570
2571   /* Get entry to the channel user list */
2572   silc_list_start(channel->user_list);
2573   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2574     if (chl->client == target_client)
2575       break;
2576
2577   /* 
2578    * Change the mode 
2579    */
2580
2581   /* If the target client is founder, no one else can change their mode
2582      but themselves. */
2583   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
2584     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2585                                           SILC_STATUS_ERR_NOT_YOU);
2586     goto out;
2587   }
2588
2589   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
2590     /* Cannot promote anyone to channel founder */
2591     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2592                                           SILC_STATUS_ERR_NOT_YOU);
2593     goto out;
2594   } else {
2595     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
2596       if (target_client == client) {
2597         /* Remove channel founder rights from itself */
2598         chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
2599         notify = TRUE;
2600       } else {
2601         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2602                                               SILC_STATUS_ERR_NOT_YOU);
2603         goto out;
2604       }
2605     }
2606   }
2607
2608   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
2609     /* Promote to operator */
2610     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2611       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
2612       notify = TRUE;
2613     }
2614   } else {
2615     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
2616       /* Demote to normal user */
2617       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
2618       notify = TRUE;
2619     }
2620   }
2621
2622   /* Send notify to channel, notify only if mode was actually changed. */
2623   if (notify) {
2624     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2625     silc_server_send_notify_to_channel(server, channel, TRUE,
2626                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
2627                                        idp->data, idp->len,
2628                                        tmp_mask, 4, tmp_id, tmp_len);
2629     silc_buffer_free(idp);
2630   }
2631
2632   /* Send command reply to sender */
2633   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
2634                                                 SILC_STATUS_OK, 0, 2,
2635                                                 2, tmp_mask, 4,
2636                                                 3, tmp_id, tmp_len);
2637   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2638                           packet->data, packet->len, FALSE);
2639     
2640   silc_buffer_free(packet);
2641   silc_free(channel_id);
2642   silc_free(client_id);
2643
2644  out:
2645   silc_server_command_free(cmd);
2646 }
2647
2648 /* Server side of KICK command. Kicks client out of channel. */
2649
2650 SILC_SERVER_CMD_FUNC(kick)
2651 {
2652 }
2653
2654 SILC_SERVER_CMD_FUNC(restart)
2655 {
2656 }
2657  
2658 SILC_SERVER_CMD_FUNC(close)
2659 {
2660 }
2661  
2662 SILC_SERVER_CMD_FUNC(die)
2663 {
2664 }
2665  
2666 SILC_SERVER_CMD_FUNC(silcoper)
2667 {
2668 }
2669
2670 /* Server side command of LEAVE. Removes client from a channel. */
2671
2672 SILC_SERVER_CMD_FUNC(leave)
2673 {
2674   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2675   SilcServer server = cmd->server;
2676   SilcSocketConnection sock = cmd->sock;
2677   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
2678   SilcChannelID *id;
2679   SilcChannelEntry channel;
2680   SilcBuffer packet;
2681   unsigned int i, argc, len;
2682   unsigned char *tmp;
2683
2684   SILC_LOG_DEBUG(("Start"));
2685
2686   argc = silc_argument_get_arg_num(cmd->args);
2687   if (argc < 1) {
2688     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2689                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2690     goto out;
2691   }
2692   if (argc > 2) {
2693     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2694                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2695     goto out;
2696   }
2697
2698   /* Get Channel ID */
2699   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2700   if (!tmp) {
2701     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2702                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2703     goto out;
2704   }
2705   id = silc_id_payload_parse_id(tmp, len);
2706
2707   /* Get channel entry */
2708   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
2709   if (!channel) {
2710     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2711                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2712     goto out;
2713   }
2714
2715   /* Check whether this client is on the channel */
2716   if (!silc_server_client_on_channel(id_entry, channel)) {
2717     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2718                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2719     goto out;
2720   }
2721
2722   /* Notify routers that they should remove this client from their list
2723      of clients on the channel. */
2724   if (!server->standalone)
2725     silc_server_send_remove_channel_user(server, 
2726                                          server->router->connection,
2727                                          server->server_type == SILC_ROUTER ?
2728                                          TRUE : FALSE, id_entry->id, id);
2729
2730   /* Remove client from channel */
2731   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
2732                                           TRUE);
2733   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2734                                         SILC_STATUS_OK);
2735
2736   /* If the channel does not exist anymore we won't send anything */
2737   if (!i)
2738     goto out;
2739
2740   /* Re-generate channel key */
2741   silc_server_create_channel_key(server, channel, 0);
2742
2743   /* Encode channel key payload to be distributed on the channel */
2744   packet = 
2745     silc_channel_key_payload_encode(len, tmp,
2746                                     strlen(channel->channel_key->cipher->name),
2747                                     channel->channel_key->cipher->name,
2748                                     channel->key_len / 8, channel->key);
2749
2750   /* If we are normal server then we will send it to our router.  If we
2751      are router we will send it to all local servers that has clients on
2752      the channel */
2753   if (server->server_type == SILC_SERVER) {
2754     if (!server->standalone)
2755       silc_server_packet_send(server, 
2756                               cmd->server->router->connection,
2757                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2758                               packet->len, TRUE);
2759   } else {
2760
2761   }
2762
2763   /* Send to locally connected clients on the channel */
2764   silc_server_packet_send_local_channel(server, channel, 
2765                                         SILC_PACKET_CHANNEL_KEY, 0,
2766                                         packet->data, packet->len, FALSE);
2767
2768   silc_buffer_free(packet);
2769   silc_free(id);
2770
2771  out:
2772   silc_server_command_free(cmd);
2773 }
2774
2775 /* Server side of command NAMES. Resolves clients and their names currently
2776    joined on the requested channel. The name list is sent back to the
2777    client. */
2778
2779 SILC_SERVER_CMD_FUNC(names)
2780 {
2781   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2782   SilcServer server = cmd->server;
2783   SilcChannelEntry channel;
2784   SilcChannelClientEntry chl;
2785   SilcChannelID *id;
2786   SilcBuffer packet;
2787   unsigned int i, len, len2, tmp_len, argc;
2788   unsigned char *tmp;
2789   char *name_list = NULL, *n;
2790   SilcBuffer client_id_list;
2791   SilcBuffer client_mode_list;
2792
2793   SILC_LOG_DEBUG(("Start"));
2794
2795   argc = silc_argument_get_arg_num(cmd->args);
2796   if (argc < 1) {
2797     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
2798                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2799     goto out;
2800   }
2801   if (argc > 2) {
2802     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
2803                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2804     goto out;
2805   }
2806
2807   /* Get Channel ID */
2808   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2809   if (!tmp) {
2810     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2811                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2812     goto out;
2813   }
2814   id = silc_id_payload_parse_id(tmp, tmp_len);
2815
2816   /* Check whether the channel exists. If we are normal server and the
2817      channel does not exist we will send this same command to our router
2818      which will know if the channel exists. */
2819   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
2820   if (!channel) {
2821     if (server->server_type == SILC_SERVER && !server->standalone) {
2822       /* XXX Send names command */
2823
2824       cmd->pending = TRUE;
2825       silc_server_command_pending(server, SILC_COMMAND_NAMES, 0,
2826                                   silc_server_command_names, context);
2827       return;
2828     }
2829
2830     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2831                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2832     goto out;
2833   }
2834
2835   /* Assemble the name list now */
2836   name_list = NULL;
2837   len = 0;
2838   silc_list_start(channel->user_list);
2839   i = 0;
2840   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2841     n = chl->client->nickname;
2842     if (n) {
2843       len2 = strlen(n);
2844       len += len2;
2845       name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
2846       memcpy(name_list + (len - len2), n, len2);
2847       name_list[len] = 0;
2848
2849       if (i == silc_list_count(channel->user_list) - 1)
2850         break;
2851       memcpy(name_list + len, ",", 1);
2852       len++;
2853       i++;
2854     }
2855   }
2856   if (!name_list)
2857     name_list = "";
2858
2859   /* Assemble the Client ID list now */
2860   client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) * 
2861                                      silc_list_count(channel->user_list));
2862   silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
2863   silc_list_start(channel->user_list);
2864   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2865     SilcBuffer idp;
2866
2867     idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
2868     silc_buffer_format(client_id_list,
2869                        SILC_STR_UI_XNSTRING(idp->data, idp->len),
2870                        SILC_STR_END);
2871     silc_buffer_pull(client_id_list, idp->len);
2872     silc_buffer_free(idp);
2873   }
2874   silc_buffer_push(client_id_list, 
2875                    client_id_list->data - client_id_list->head);
2876
2877   /* Assemble mode list */
2878   client_mode_list = silc_buffer_alloc(4 * 
2879                                        silc_list_count(channel->user_list));
2880   silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
2881   silc_list_start(channel->user_list);
2882   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2883     SILC_PUT32_MSB(chl->mode, client_mode_list->data);
2884     silc_buffer_pull(client_mode_list, 4);
2885   }
2886   silc_buffer_push(client_mode_list, 
2887                    client_mode_list->data - client_mode_list->head);
2888
2889   /* Send reply */
2890   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NAMES,
2891                                                 SILC_STATUS_OK, 0, 4,
2892                                                 2, tmp, tmp_len,
2893                                                 3, name_list, 
2894                                                 strlen(name_list),
2895                                                 4, client_id_list->data,
2896                                                 client_id_list->len,
2897                                                 5, client_mode_list->data,
2898                                                 client_mode_list->len);
2899   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2900                           packet->data, packet->len, FALSE);
2901     
2902   silc_buffer_free(packet);
2903   silc_free(name_list);
2904   silc_buffer_free(client_id_list);
2905   silc_buffer_free(client_mode_list);
2906   silc_free(id);
2907
2908  out:
2909   silc_server_command_free(cmd);
2910 }