updates
[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, command,                       \
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, command,                       \
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 = strlen(hsock->hostname);
465         strncat(uh, hsock->hostname, 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 (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 /* Checks that all mandatory fields are present. If not then send WHOIS 
791    request to the server who owns the client. We use WHOIS because we want
792    to get as much information as possible at once. */
793
794 static char
795 silc_server_command_identify_check(SilcServerCommandContext cmd,
796                                    SilcClientEntry *clients,
797                                    unsigned int clients_count)
798 {
799   SilcServer server = cmd->server;
800   int i;
801   SilcClientEntry entry;
802
803   for (i = 0; i < clients_count; i++) {
804     entry = clients[i];
805
806     if (!entry->nickname) {
807       SilcBuffer tmpbuf;
808       unsigned short old_ident;
809       
810       old_ident = silc_command_get_ident(cmd->payload);
811       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
812       silc_command_set_command(cmd->payload, SILC_COMMAND_WHOIS);
813       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
814       
815       /* Send WHOIS request. We send WHOIS since we're doing the requesting
816          now anyway so make it a good one. */
817       silc_server_packet_send(server, entry->router->connection,
818                               SILC_PACKET_COMMAND, cmd->packet->flags,
819                               tmpbuf->data, tmpbuf->len, TRUE);
820       
821       /* Reprocess this packet after received reply */
822       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
823                                   silc_command_get_ident(cmd->payload),
824                                   silc_server_command_identify, (void *)cmd);
825       cmd->pending = TRUE;
826       
827       /* Put old data back to the Command Payload we just changed */
828       silc_command_set_ident(cmd->payload, old_ident);
829       silc_command_set_command(cmd->payload, SILC_COMMAND_IDENTIFY);
830
831       silc_buffer_free(tmpbuf);
832       return FALSE;
833     }
834   }
835
836   return TRUE;
837 }
838
839 static void
840 silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
841                                         SilcClientEntry *clients,
842                                         unsigned int clients_count)
843 {
844   SilcServer server = cmd->server;
845   char *tmp;
846   int i, count = 0, len;
847   SilcBuffer packet, idp;
848   SilcClientEntry entry;
849   SilcCommandStatus status;
850   unsigned short ident = silc_command_get_ident(cmd->payload);
851
852   status = SILC_STATUS_OK;
853   if (clients_count > 1)
854     status = SILC_STATUS_LIST_START;
855
856   for (i = 0; i < clients_count; i++) {
857     entry = clients[i];
858
859     if (count && i - 1 == count)
860       break;
861
862     if (clients_count > 2)
863       status = SILC_STATUS_LIST_ITEM;
864
865     if (clients_count > 1 && i == clients_count - 1)
866       status = SILC_STATUS_LIST_END;
867
868     /* Send IDENTIFY reply */
869     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
870     tmp = silc_argument_get_first_arg(cmd->args, NULL);
871     
872     /* XXX */
873     {
874       char nh[256], uh[256];
875       SilcSocketConnection hsock;
876
877       memset(uh, 0, sizeof(uh));
878       memset(nh, 0, sizeof(nh));
879       
880       strncat(nh, entry->nickname, strlen(entry->nickname));
881       if (!strchr(entry->nickname, '@')) {
882         strncat(nh, "@", 1);
883         len = entry->router ? strlen(entry->router->server_name) :
884           strlen(server->server_name);
885         strncat(nh, entry->router ? entry->router->server_name :
886                 server->server_name, len);
887       }
888       
889       if (!entry->username) {
890         packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
891                                                       SILC_STATUS_OK, ident, 2,
892                                                       2, idp->data, idp->len, 
893                                                       3, nh, strlen(nh));
894       } else {
895         strncat(uh, entry->username, strlen(entry->username));
896         if (!strchr(entry->username, '@')) {
897           strncat(uh, "@", 1);
898           hsock = (SilcSocketConnection)entry->connection;
899           len = strlen(hsock->hostname);
900           strncat(uh, hsock->hostname, len);
901         }
902       
903         packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
904                                                       SILC_STATUS_OK, ident, 3,
905                                                       2, idp->data, idp->len, 
906                                                       3, nh, strlen(nh),
907                                                       4, uh, strlen(uh));
908       }
909       
910       silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
911                               0, packet->data, packet->len, FALSE);
912       
913       silc_buffer_free(packet);
914       silc_buffer_free(idp);
915     }
916   }
917 }
918
919 static int
920 silc_server_command_identify_from_client(SilcServerCommandContext cmd)
921 {
922   SilcServer server = cmd->server;
923   char *nick = NULL, *server_name = NULL;
924   int count = 0, clients_count;
925   SilcClientID *client_id = NULL;
926   SilcClientEntry *clients = NULL, entry;
927   int ret = 0;
928
929   /* Parse the IDENTIFY request */
930   if (!silc_server_command_identify_parse(cmd, &client_id, &nick, 
931                                           &server_name, &count))
932     return 0;
933
934   /* Protocol dictates that we must always send the received IDENTIFY request
935      to our router if we are normal server, so let's do it now unless we
936      are standalone. We will not send any replies to the client until we
937      have received reply from the router. */
938   if (server->server_type == SILC_SERVER && 
939       !cmd->pending && !server->standalone) {
940     SilcBuffer tmpbuf;
941     unsigned short old_ident;
942
943     old_ident = silc_command_get_ident(cmd->payload);
944     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
945     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
946
947     /* Send IDENTIFY command to our router */
948     silc_server_packet_send(server, (SilcSocketConnection)
949                             server->router->connection,
950                             SILC_PACKET_COMMAND, cmd->packet->flags,
951                             tmpbuf->data, tmpbuf->len, TRUE);
952
953     /* Reprocess this packet after received reply from router */
954     silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, 
955                                 silc_command_get_ident(cmd->payload),
956                                 silc_server_command_identify, (void *)cmd);
957     cmd->pending = TRUE;
958
959     silc_command_set_ident(cmd->payload, old_ident);
960
961     silc_buffer_free(tmpbuf);
962     ret = -1;
963     goto out;
964   }
965
966   /* We are ready to process the command request. Let's search for the
967      requested client and send reply to the requesting client. */
968
969   /* Get all clients matching that ID or nickname from local list */
970   if (client_id) {
971     entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
972     if (entry) {
973       clients = silc_calloc(1, sizeof(*clients));
974       clients[0] = entry;
975       clients_count = 1;
976     }
977   } else {
978     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
979                                                   nick, server_name,
980                                                   &clients_count);
981   }
982   
983   /* Check global list as well */
984   if (!clients) {
985     if (client_id) {
986       entry = silc_idlist_find_client_by_id(server->global_list, 
987                                             client_id, NULL);
988       if (entry) {
989         clients = silc_calloc(1, sizeof(*clients));
990         clients[0] = entry;
991         clients_count = 1;
992       }
993     } else {
994       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
995                                                     nick, server_name,
996                                                     &clients_count);
997     }
998   }
999   
1000   if (!clients) {
1001     /* Such a client really does not exist in the SILC network. */
1002     silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1003                                          SILC_STATUS_ERR_NO_SUCH_NICK,
1004                                          3, nick, strlen(nick));
1005     goto out;
1006   }
1007
1008   /* Check that all mandatory fields are present and request those data
1009      from the server who owns the client if necessary. */
1010   if (!cmd->pending && server->server_type == SILC_ROUTER &&
1011       !silc_server_command_identify_check(cmd, clients, clients_count)) {
1012     ret = -1;
1013     goto out;
1014   }
1015
1016   /* Send the command reply to the client */
1017   silc_server_command_identify_send_reply(cmd, clients, clients_count);
1018
1019  out:
1020   if (clients)
1021     silc_free(clients);
1022   if (client_id)
1023     silc_free(client_id);
1024   if (nick)
1025     silc_free(nick);
1026   if (server_name)
1027     silc_free(server_name);
1028
1029   return ret;
1030 }
1031
1032 static int
1033 silc_server_command_identify_from_server(SilcServerCommandContext cmd)
1034 {
1035   SilcServer server = cmd->server;
1036   char *nick = NULL, *server_name = NULL;
1037   int count = 0, clients_count;
1038   SilcClientID *client_id = NULL;
1039   SilcClientEntry *clients = NULL, entry;
1040   int ret = 0;
1041
1042   /* Parse the IDENTIFY request */
1043   if (!silc_server_command_identify_parse(cmd, &client_id, &nick, 
1044                                           &server_name, &count))
1045     return 0;
1046
1047   /* Process the command request. Let's search for the requested client and
1048      send reply to the requesting server. */
1049
1050   if (client_id) {
1051     entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
1052     if (entry) {
1053       clients = silc_calloc(1, sizeof(*clients));
1054       clients[0] = entry;
1055       clients_count = 1;
1056     }
1057   } else {
1058     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
1059                                                   nick, server_name,
1060                                                   &clients_count);
1061     if (!clients)
1062       clients = silc_idlist_get_clients_by_hash(server->local_list, 
1063                                                 nick, server->md5hash,
1064                                                 &clients_count);
1065   }
1066   
1067   /* If we are router we will check our global list as well. */
1068   if (!clients && server->server_type == SILC_ROUTER) {
1069     if (client_id) {
1070       entry = silc_idlist_find_client_by_id(server->global_list, 
1071                                             client_id, NULL);
1072       if (entry) {
1073         clients = silc_calloc(1, sizeof(*clients));
1074         clients[0] = entry;
1075         clients_count = 1;
1076       }
1077     } else {
1078       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
1079                                                     nick, server_name,
1080                                                     &clients_count);
1081       if (!clients)
1082         clients = silc_idlist_get_clients_by_hash(server->global_list, 
1083                                                   nick, server->md5hash,
1084                                                   &clients_count);
1085     }
1086   }
1087
1088   if (!clients) {
1089     /* Such a client really does not exist in the SILC network. */
1090     silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1091                                          SILC_STATUS_ERR_NO_SUCH_NICK,
1092                                          3, nick, strlen(nick));
1093     goto out;
1094   }
1095
1096   /* Check that all mandatory fields are present and request those data
1097      from the server who owns the client if necessary. */
1098   if (!cmd->pending && server->server_type == SILC_ROUTER &&
1099       !silc_server_command_identify_check(cmd, clients, clients_count)) {
1100     ret = -1;
1101     goto out;
1102   }
1103
1104   /* Send the command reply */
1105   silc_server_command_identify_send_reply(cmd, clients, clients_count);
1106
1107  out:
1108   if (clients)
1109     silc_free(clients);
1110   if (client_id)
1111     silc_free(client_id);
1112   if (nick)
1113     silc_free(nick);
1114   if (server_name)
1115     silc_free(server_name);
1116
1117   return ret;
1118 }
1119
1120 SILC_SERVER_CMD_FUNC(identify)
1121 {
1122   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1123   int ret;
1124
1125   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3);
1126
1127   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1128     ret = silc_server_command_identify_from_client(cmd);
1129   else
1130     ret = silc_server_command_identify_from_server(cmd);
1131
1132   if (!ret)
1133     silc_server_command_free(cmd);
1134 }
1135
1136 /* Checks string for bad characters and returns TRUE if they are found. */
1137
1138 static int silc_server_command_bad_chars(char *nick)
1139 {
1140   if (strchr(nick, '\\')) return TRUE;
1141   if (strchr(nick, '\"')) return TRUE;
1142   if (strchr(nick, '´')) return TRUE;
1143   if (strchr(nick, '`')) return TRUE;
1144   if (strchr(nick, '\'')) return TRUE;
1145   if (strchr(nick, '*')) return TRUE;
1146   if (strchr(nick, '/')) return TRUE;
1147   if (strchr(nick, '@')) return TRUE;
1148
1149   return FALSE;
1150 }
1151
1152 /* Server side of command NICK. Sets nickname for user. Setting
1153    nickname causes generation of a new client ID for the client. The
1154    new client ID is sent to the client after changing the nickname. */
1155
1156 SILC_SERVER_CMD_FUNC(nick)
1157 {
1158   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1159   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1160   SilcServer server = cmd->server;
1161   SilcBuffer packet, nidp, oidp;
1162   SilcClientID *new_id;
1163   char *nick;
1164
1165   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NICK, cmd, 1, 1);
1166
1167   /* Check nickname */
1168   nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
1169   if (silc_server_command_bad_chars(nick) == TRUE) {
1170     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
1171                                           SILC_STATUS_ERR_BAD_NICKNAME);
1172     goto out;
1173   }
1174
1175   /* Create new Client ID */
1176   silc_id_create_client_id(cmd->server->id, cmd->server->rng, 
1177                            cmd->server->md5hash, nick,
1178                            &new_id);
1179
1180   /* Send notify about nickname change to our router. We send the new
1181      ID and ask to replace it with the old one. If we are router the
1182      packet is broadcasted. */
1183   if (!cmd->server->standalone)
1184     silc_server_send_replace_id(server, server->router->connection, 
1185                                 server->server_type == SILC_SERVER ? 
1186                                 FALSE : TRUE, client->id,
1187                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
1188                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
1189
1190   /* Remove old cache entry */
1191   silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
1192                          client->id); 
1193
1194   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1195
1196   /* Free old ID */
1197   if (client->id) {
1198     memset(client->id, 0, SILC_ID_CLIENT_LEN);
1199     silc_free(client->id);
1200   }
1201
1202   /* Save the nickname as this client is our local client */
1203   if (client->nickname)
1204     silc_free(client->nickname);
1205
1206   client->nickname = strdup(nick);
1207   client->id = new_id;
1208
1209   /* Update client cache */
1210   silc_idcache_add(server->local_list->clients, client->nickname, 
1211                    SILC_ID_CLIENT, client->id, (void *)client, TRUE);
1212
1213   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1214
1215   /* Send NICK_CHANGE notify */
1216   silc_server_send_notify_on_channels(server, client, 
1217                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
1218                                       oidp->data, oidp->len, 
1219                                       nidp->data, nidp->len);
1220
1221   /* Send the new Client ID as reply command back to client */
1222   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
1223                                                 SILC_STATUS_OK, 0, 1, 
1224                                                 2, nidp->data, nidp->len);
1225   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1226                           0, packet->data, packet->len, FALSE);
1227
1228   silc_buffer_free(packet);
1229   silc_buffer_free(nidp);
1230   silc_buffer_free(oidp);
1231   
1232  out:
1233   silc_server_command_free(cmd);
1234 }
1235
1236 SILC_SERVER_CMD_FUNC(list)
1237 {
1238 }
1239
1240 /* Server side of TOPIC command. Sets topic for channel and/or returns
1241    current topic to client. */
1242
1243 SILC_SERVER_CMD_FUNC(topic)
1244 {
1245   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1246   SilcServer server = cmd->server;
1247   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1248   SilcChannelID *channel_id;
1249   SilcChannelEntry channel;
1250   SilcChannelClientEntry chl;
1251   SilcBuffer packet, idp;
1252   unsigned char *tmp;
1253   unsigned int argc, tmp_len;
1254
1255   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
1256
1257   argc = silc_argument_get_arg_num(cmd->args);
1258
1259   /* Get Channel ID */
1260   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1261   if (!tmp) {
1262     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1263                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1264     goto out;
1265   }
1266   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1267
1268   /* Check whether the channel exists */
1269   channel = silc_idlist_find_channel_by_id(server->local_list, 
1270                                            channel_id, NULL);
1271   if (!channel) {
1272     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1273                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1274     goto out;
1275   }
1276
1277   if (argc > 1) {
1278     /* Get the topic */
1279     tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1280     if (!tmp) {
1281       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1282                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1283       goto out;
1284     }
1285
1286     if (strlen(tmp) > 256) {
1287       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1288                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1289       goto out;
1290     }
1291
1292     /* See whether has rights to change topic */
1293     silc_list_start(channel->user_list);
1294     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
1295       if (chl->client == client) {
1296         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1297           silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1298                                                 SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1299           goto out;
1300         } else {
1301           break;
1302         }
1303       }
1304     }
1305
1306     /* Set the topic for channel */
1307     if (channel->topic)
1308       silc_free(channel->topic);
1309     channel->topic = strdup(tmp);
1310
1311     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1312
1313     /* Send notify about topic change to all clients on the channel */
1314     silc_server_send_notify_to_channel(server, channel, TRUE,
1315                                        SILC_NOTIFY_TYPE_TOPIC_SET, 2,
1316                                        idp->data, idp->len,
1317                                        channel->topic, strlen(channel->topic));
1318     silc_buffer_free(idp);
1319   }
1320
1321   /* Send the topic to client as reply packet */
1322   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1323   if (channel->topic)
1324     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1325                                                   SILC_STATUS_OK, 0, 2, 
1326                                                   2, idp->data, idp->len,
1327                                                   3, channel->topic, 
1328                                                   strlen(channel->topic));
1329   else
1330     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1331                                                   SILC_STATUS_OK, 0, 1, 
1332                                                   2, idp->data, idp->len);
1333   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1334                           0, packet->data, packet->len, FALSE);
1335
1336   silc_buffer_free(packet);
1337   silc_buffer_free(idp);
1338   silc_free(channel_id);
1339
1340  out:
1341   silc_server_command_free(cmd);
1342 }
1343
1344 /* Server side of INVITE command. Invites some client to join some channel. */
1345
1346 SILC_SERVER_CMD_FUNC(invite)
1347 {
1348   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1349   SilcServer server = cmd->server;
1350   SilcSocketConnection sock = cmd->sock, dest_sock;
1351   SilcClientEntry sender, dest;
1352   SilcClientID *dest_id;
1353   SilcChannelEntry channel;
1354   SilcChannelID *channel_id;
1355   SilcBuffer sidp;
1356   unsigned char *tmp;
1357   unsigned int len;
1358
1359   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 2);
1360
1361   /* Get destination ID */
1362   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1363   if (!tmp) {
1364     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1365                                           SILC_STATUS_ERR_NO_CLIENT_ID);
1366     goto out;
1367   }
1368   dest_id = silc_id_payload_parse_id(tmp, len);
1369
1370   /* Get Channel ID */
1371   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1372   if (!tmp) {
1373     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1374                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1375     goto out;
1376   }
1377   channel_id = silc_id_payload_parse_id(tmp, len);
1378
1379   /* Check whether the channel exists */
1380   channel = silc_idlist_find_channel_by_id(server->local_list, 
1381                                            channel_id, NULL);
1382   if (!channel) {
1383     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1384                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1385     goto out;
1386   }
1387
1388   /* Check whether the sender of this command is on the channel. */
1389   sender = (SilcClientEntry)sock->user_data;
1390   if (!silc_server_client_on_channel(sender, channel)) {
1391     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1392                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
1393     goto out;
1394   }
1395
1396   /* Check whether the channel is invite-only channel. If yes then the
1397      sender of this command must be at least channel operator. */
1398   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1399     SilcChannelClientEntry chl;
1400
1401     silc_list_start(channel->user_list);
1402     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
1403       if (chl->client == sender) {
1404         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1405           silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1406                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1407           goto out;
1408         }
1409         break;
1410       }
1411   }
1412
1413   /* Find the connection data for the destination. If it is local we will
1414      send it directly otherwise we will send it to router for routing. */
1415   dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
1416   if (dest)
1417     dest_sock = (SilcSocketConnection)dest->connection;
1418   else
1419     dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
1420
1421   /* Check whether the requested client is already on the channel. */
1422   /* XXX if we are normal server we don't know about global clients on
1423      the channel thus we must request it (NAMES command), check from
1424      local cache as well. */
1425   if (silc_server_client_on_channel(dest, channel)) {
1426     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1427                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1428     goto out;
1429   }
1430
1431   sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
1432
1433   /* Send notify to the client that is invited to the channel */
1434   silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
1435                                SILC_NOTIFY_TYPE_INVITE, 2, 
1436                                sidp->data, sidp->len, tmp, len);
1437
1438   /* Send command reply */
1439   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1440                                         SILC_STATUS_OK);
1441
1442   silc_buffer_free(sidp);
1443
1444  out:
1445   silc_server_command_free(cmd);
1446 }
1447
1448 /* Quits connection to client. This gets called if client won't
1449    close the connection even when it has issued QUIT command. */
1450
1451 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
1452 {
1453   SilcServer server = (SilcServer)context;
1454   SilcSocketConnection sock = server->sockets[fd];
1455
1456   /* Free all client specific data, such as client entry and entires
1457      on channels this client may be on. */
1458   silc_server_free_sock_user_data(server, sock);
1459
1460   /* Close the connection on our side */
1461   silc_server_close_connection(server, sock);
1462 }
1463
1464 /* Quits SILC session. This is the normal way to disconnect client. */
1465  
1466 SILC_SERVER_CMD_FUNC(quit)
1467 {
1468   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1469   SilcServer server = cmd->server;
1470   SilcSocketConnection sock = cmd->sock;
1471
1472   SILC_LOG_DEBUG(("Start"));
1473
1474   /* We quit the connection with little timeout */
1475   silc_task_register(server->timeout_queue, sock->sock,
1476                      silc_server_command_quit_cb, server,
1477                      0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1478
1479   silc_server_command_free(cmd);
1480 }
1481
1482 SILC_SERVER_CMD_FUNC(kill)
1483 {
1484 }
1485
1486 /* Server side of command INFO. This sends information about us to 
1487    the client. If client requested specific server we will send the 
1488    command to that server. */
1489
1490 SILC_SERVER_CMD_FUNC(info)
1491 {
1492   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1493   SilcServer server = cmd->server;
1494   SilcBuffer packet, idp;
1495   char info_string[256], *dest_server;
1496
1497   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
1498
1499   /* Get server name */
1500   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
1501   if (!dest_server) {
1502     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1503                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1504     goto out;
1505   }
1506
1507   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
1508     /* Send our reply */
1509     memset(info_string, 0, sizeof(info_string));
1510     snprintf(info_string, sizeof(info_string), 
1511              "location: %s server: %s admin: %s <%s>",
1512              server->config->admin_info->location,
1513              server->config->admin_info->server_type,
1514              server->config->admin_info->admin_name,
1515              server->config->admin_info->admin_email);
1516
1517     idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
1518
1519     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
1520                                                   SILC_STATUS_OK, 0, 2,
1521                                                   2, idp->data, idp->len,
1522                                                   3, info_string, 
1523                                                   strlen(info_string));
1524     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
1525                             packet->data, packet->len, FALSE);
1526     
1527     silc_buffer_free(packet);
1528     silc_buffer_free(idp);
1529   } else {
1530     /* Send this command to the requested server */
1531
1532     if (server->server_type == SILC_SERVER && !server->standalone) {
1533
1534     }
1535
1536     if (server->server_type == SILC_ROUTER) {
1537
1538     }
1539   }
1540   
1541  out:
1542   silc_server_command_free(cmd);
1543 }
1544
1545 SILC_SERVER_CMD_FUNC(connect)
1546 {
1547 }
1548
1549 /* Server side of command PING. This just replies to the ping. */
1550
1551 SILC_SERVER_CMD_FUNC(ping)
1552 {
1553   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1554   SilcServer server = cmd->server;
1555   SilcServerID *id;
1556   unsigned int len;
1557   unsigned char *tmp;
1558
1559   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
1560
1561   /* Get Server ID */
1562   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1563   if (!tmp) {
1564     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1565                                           SILC_STATUS_ERR_NO_SERVER_ID);
1566     goto out;
1567   }
1568   id = silc_id_str2id(tmp, SILC_ID_SERVER);
1569   if (!id)
1570     goto out;
1571
1572   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
1573     /* Send our reply */
1574     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1575                                           SILC_STATUS_OK);
1576   } else {
1577     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1578                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1579     goto out;
1580   }
1581
1582   silc_free(id);
1583
1584  out:
1585   silc_server_command_free(cmd);
1586 }
1587
1588 SILC_SERVER_CMD_FUNC(oper)
1589 {
1590 }
1591
1592 typedef struct {
1593   char *channel_name;
1594   char *nickname;
1595   char *username;
1596   char *hostname;
1597   SilcChannelEntry channel;
1598   SilcServer server;
1599   SilcClientEntry client;
1600 } JoinInternalContext;
1601
1602 SILC_TASK_CALLBACK(silc_server_command_join_notify)
1603 {
1604   JoinInternalContext *ctx = (JoinInternalContext *)context;
1605
1606   if (ctx->channel->key && ctx->channel->key_len) {
1607     SilcBuffer clidp;
1608
1609     clidp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT);
1610
1611     silc_server_send_notify_to_channel(ctx->server, ctx->channel, FALSE,
1612                                        SILC_NOTIFY_TYPE_JOIN, 1,
1613                                        clidp->data, clidp->len);
1614 #if 0
1615     /* Send NEW_CHANNEL_USER packet to primary route */
1616     silc_server_send_new_channel_user(server, server->router->connection,
1617                                       server->server_type == SILC_SERVER ?
1618                                       FALSE : TRUE,
1619                                       channel->id, SILC_ID_CHANNEL_LEN,
1620                                       client->id, SILC_ID_CLIENT_LEN);
1621 #endif
1622
1623     /* Send NAMES command reply to the joined channel so the user sees who
1624        is currently on the channel. */
1625     silc_server_command_send_names(ctx->server, ctx->client->connection, 
1626                                    ctx->channel);
1627
1628     silc_buffer_free(clidp);
1629     silc_free(ctx);
1630   } else {
1631     silc_task_register(ctx->server->timeout_queue, fd,
1632                        silc_server_command_join_notify, context,
1633                        0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1634   }
1635 }
1636
1637 /* Assembles NAMES command and executes it. This is called when client
1638    joins to a channel and we wan't to send NAMES command reply to the 
1639    client. */
1640
1641 void silc_server_command_send_names(SilcServer server,
1642                                     SilcSocketConnection sock,
1643                                     SilcChannelEntry channel)
1644 {
1645   SilcServerCommandContext cmd;
1646   SilcBuffer buffer, idp;
1647
1648   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1649   buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1,
1650                                           1, idp->data, idp->len);
1651
1652   cmd = silc_calloc(1, sizeof(*cmd));
1653   cmd->payload = silc_command_payload_parse(buffer);
1654   cmd->args = silc_command_get_args(cmd->payload);
1655   cmd->server = server;
1656   cmd->sock = sock;
1657   cmd->pending = FALSE;
1658
1659   silc_server_command_names((void *)cmd);
1660   silc_free(buffer);
1661   silc_free(idp);
1662 }
1663
1664 /* Internal routine that is called after router has replied to server's
1665    JOIN command it forwarded to the router. The route has joined and possibly
1666    creaetd the channel. This function adds the client to the channel's user
1667    list. */
1668
1669 SILC_SERVER_CMD_FUNC(add_to_channel)
1670 {
1671   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1672   SilcServer server = cmd->server;
1673   SilcClientEntry client;
1674   SilcChannelEntry channel;
1675   SilcChannelClientEntry chl;
1676   char *channel_name;
1677
1678   /* Get channel name */
1679   channel_name = silc_argument_get_arg_type(cmd->args, 1, NULL);
1680
1681   /* Get client entry */
1682   client = (SilcClientEntry)cmd->sock->user_data;
1683
1684   /* Get channel entry */
1685   channel = silc_idlist_find_channel_by_name(server->local_list, 
1686                                              channel_name, NULL);
1687   if (channel) {
1688     /* Join the client to the channel by adding it to channel's user list.
1689        Add also the channel to client entry's channels list for fast cross-
1690        referencing. */
1691     chl = silc_calloc(1, sizeof(*chl));
1692     //chl->mode = SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO;
1693     chl->client = client;
1694     chl->channel = channel;
1695     silc_list_add(channel->user_list, chl);
1696     silc_list_add(client->channels, chl);
1697   }
1698
1699   silc_server_command_free(cmd);
1700 }
1701
1702 /* Internal routine to join channel. The channel sent to this function
1703    has been either created or resolved from ID lists. This joins the sent
1704    client to the channel. */
1705
1706 static void silc_server_command_join_channel(SilcServer server, 
1707                                              SilcServerCommandContext cmd,
1708                                              SilcChannelEntry channel,
1709                                              int created,
1710                                              unsigned int umode)
1711 {
1712   SilcSocketConnection sock = cmd->sock;
1713   unsigned char *tmp;
1714   unsigned int tmp_len;
1715   unsigned char *passphrase = NULL, mode[4];
1716   SilcClientEntry client;
1717   SilcChannelClientEntry chl;
1718   SilcBuffer reply, chidp, clidp;
1719
1720   SILC_LOG_DEBUG(("Start"));
1721
1722   if (!channel)
1723     return;
1724
1725   /* Get passphrase */
1726   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1727   if (tmp) {
1728     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1729     memcpy(passphrase, tmp, tmp_len);
1730   }
1731   
1732   /*
1733    * Check channel modes
1734    */
1735
1736   /* Check invite list if channel is invite-only channel */
1737   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1738     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
1739       /* Invite list is specified. Check whether client is invited in the
1740          list. If not, then check whether it has been invited otherwise. */
1741
1742     } else {
1743       /* XXX client must be invited to be able to join the channel */
1744     }
1745   }
1746
1747   /* Check ban list if set */
1748   if (channel->mode & SILC_CHANNEL_MODE_BAN) {
1749
1750   }
1751
1752   /* Check the channel passphrase if set. */
1753   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
1754     if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
1755                               strlen(channel->mode_data.passphrase))) {
1756       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1757                                             SILC_STATUS_ERR_BAD_PASSWORD);
1758       goto out;
1759     }
1760   }
1761
1762   /* Check user count limit if set. */
1763   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
1764     if (silc_list_count(channel->user_list) + 1 > 
1765         channel->mode_data.user_limit) {
1766       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1767                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
1768       goto out;
1769     }
1770   }
1771
1772   /*
1773    * Client is allowed to join to the channel. Make it happen.
1774    */
1775
1776   /* If the JOIN request was forwarded to us we will make a bit slower
1777      query to get the client pointer. Otherwise, we get the client pointer
1778      real easy. */
1779   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1780     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1781     client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
1782     if (!client) {
1783       /* XXX */
1784       SILC_LOG_ERROR(("Forwarded join command did not find the client who "
1785                       "wanted to join the channel"));
1786       goto out;
1787     }
1788     silc_free(id);
1789   } else {
1790     client = (SilcClientEntry)sock->user_data;
1791   }
1792
1793   /* Check whether the client already is on the channel */
1794   if (silc_server_client_on_channel(client, channel)) {
1795     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1796                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1797     goto out;
1798   }
1799
1800   /* Generate new channel key as protocol dictates */
1801   if (!created)
1802     silc_server_create_channel_key(server, channel, 0);
1803
1804   /* Join the client to the channel by adding it to channel's user list.
1805      Add also the channel to client entry's channels list for fast cross-
1806      referencing. */
1807   chl = silc_calloc(1, sizeof(*chl));
1808   chl->mode = umode;
1809   chl->client = client;
1810   chl->channel = channel;
1811   silc_list_add(channel->user_list, chl);
1812   silc_list_add(client->channels, chl);
1813
1814   /* Encode Client ID Payload of the original client who wants to join */
1815   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1816
1817   /* Encode command reply packet */
1818   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1819   SILC_PUT32_MSB(channel->mode, mode);
1820   if (!channel->topic) {
1821     reply = 
1822       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1823                                            SILC_STATUS_OK, 0, 3,
1824                                            2, channel->channel_name,
1825                                            strlen(channel->channel_name),
1826                                            3, chidp->data, chidp->len,
1827                                            4, mode, 4);
1828   } else {
1829     reply = 
1830       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1831                                            SILC_STATUS_OK, 0, 4, 
1832                                            2, channel->channel_name, 
1833                                            strlen(channel->channel_name),
1834                                            3, chidp->data, chidp->len,
1835                                            4, mode, 4,
1836                                            5, channel->topic, 
1837                                            strlen(channel->topic));
1838   }
1839     
1840   if (server->server_type == SILC_ROUTER && 
1841       cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1842     /* We are router and server has forwarded this command to us. Send
1843        all replys to the server. */
1844     void *tmpid;
1845
1846     /* Send command reply destined to the original client */
1847     tmpid = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1848     silc_server_packet_send_dest(cmd->server, sock, 
1849                                  SILC_PACKET_COMMAND_REPLY, 0,
1850                                  tmpid, cmd->packet->src_id_type,
1851                                  reply->data, reply->len, FALSE);
1852
1853     /* Distribute new channel key to local cell and local clients. */
1854     silc_server_send_channel_key(server, channel, FALSE);
1855     
1856     /* Distribute JOIN notify into the cell for everbody on the channel */
1857     silc_server_send_notify_to_channel(server, channel, FALSE,
1858                                        SILC_NOTIFY_TYPE_JOIN, 1,
1859                                        clidp->data, clidp->len);
1860
1861     /* Broadcast NEW_CHANNEL_USER packet to primary route */
1862     silc_server_send_new_channel_user(server, server->router->connection,
1863                                       TRUE, channel->id, SILC_ID_CHANNEL_LEN,
1864                                       client->id, SILC_ID_CLIENT_LEN);
1865
1866     silc_free(tmpid);
1867   } else {
1868     /* Client sent the command. Send all replies directly to the client. */
1869
1870     /* Send command reply */
1871     silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
1872                             reply->data, reply->len, FALSE);
1873
1874     /* Send the channel key. Channel key is sent before any other packet
1875        to the channel. */
1876     silc_server_send_channel_key(server, channel, server->standalone ?
1877                                  FALSE : TRUE);
1878     
1879     /* Send JOIN notify to locally connected clients on the channel */
1880     silc_server_send_notify_to_channel(server, channel, FALSE,
1881                                        SILC_NOTIFY_TYPE_JOIN, 1,
1882                                        clidp->data, clidp->len);
1883
1884     /* Send NEW_CHANNEL_USER packet to our primary router */
1885     if (!server->standalone)
1886       silc_server_send_new_channel_user(server, server->router->connection,
1887                                         FALSE, 
1888                                         channel->id, SILC_ID_CHANNEL_LEN,
1889                                         client->id, SILC_ID_CLIENT_LEN);
1890
1891     /* Send NAMES command reply to the joined channel so the user sees who
1892        is currently on the channel. */
1893     silc_server_command_send_names(server, sock, channel);
1894   }
1895
1896   silc_buffer_free(reply);
1897   silc_buffer_free(clidp);
1898   silc_buffer_free(chidp);
1899
1900  out:
1901   if (passphrase)
1902     silc_free(passphrase);
1903 }
1904
1905 /* Server side of command JOIN. Joins client into requested channel. If 
1906    the channel does not exist it will be created. */
1907
1908 SILC_SERVER_CMD_FUNC(join)
1909 {
1910   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1911   SilcServer server = cmd->server;
1912   int tmp_len;
1913   char *tmp, *channel_name = NULL, *cipher = NULL;
1914   SilcChannelEntry channel;
1915   unsigned int umode = 0;
1916   int created = FALSE;
1917
1918   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 3);
1919
1920   /* Get channel name */
1921   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1922   if (!tmp) {
1923     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1924                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1925     goto out;
1926   }
1927   channel_name = tmp;
1928
1929   if (silc_server_command_bad_chars(channel_name) == TRUE) {
1930     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1931                                           SILC_STATUS_ERR_BAD_CHANNEL);
1932     silc_free(channel_name);
1933     goto out;
1934   }
1935
1936   /* Get cipher name */
1937   cipher = silc_argument_get_arg_type(cmd->args, 3, NULL);
1938
1939   /* See if the channel exists */
1940   channel = silc_idlist_find_channel_by_name(server->local_list, 
1941                                              channel_name, NULL);
1942   if (!channel) {
1943     /* Channel not found */
1944
1945     /* If we are standalone server we don't have a router, we just create 
1946        the channel by ourselves. */
1947     if (server->standalone) {
1948       channel = silc_server_create_new_channel(server, server->id, cipher, 
1949                                                channel_name);
1950       umode |= SILC_CHANNEL_UMODE_CHANOP;
1951       umode |= SILC_CHANNEL_UMODE_CHANFO;
1952       created = TRUE;
1953     } else {
1954
1955       /* The channel does not exist on our server. If we are normal server 
1956          we will send JOIN command to our router which will handle the joining
1957          procedure (either creates the channel if it doesn't exist or joins
1958          the client to it). */
1959       if (server->server_type == SILC_SERVER) {
1960         /* Forward the original JOIN command to the router */
1961         silc_buffer_push(cmd->packet->buffer, 
1962                          cmd->packet->buffer->data - 
1963                          cmd->packet->buffer->head);
1964         silc_server_packet_forward(server, (SilcSocketConnection)
1965                                    server->router->connection,
1966                                    cmd->packet->buffer->data, 
1967                                    cmd->packet->buffer->len, TRUE);
1968
1969         /* Register handler that will be called after the router has replied
1970            to us. We will add the client to the new channel in this callback
1971            function. Will be called from JOIN command reply. */
1972         silc_server_command_pending(server, SILC_COMMAND_JOIN, 
1973                                     ++server->router->data.cmd_ident,
1974                                     silc_server_command_add_to_channel,
1975                                     context);
1976         return;
1977       }
1978       
1979       /* We are router and the channel does not seem exist so we will check
1980          our global list as well for the channel. */
1981       channel = silc_idlist_find_channel_by_name(server->global_list, 
1982                                                  channel_name, NULL);
1983       if (!channel) {
1984         /* Channel really does not exist, create it */
1985         channel = silc_server_create_new_channel(server, server->id, cipher, 
1986                                                  channel_name);
1987         umode |= SILC_CHANNEL_UMODE_CHANOP;
1988         umode |= SILC_CHANNEL_UMODE_CHANFO;
1989         created = TRUE;
1990       }
1991     }
1992   }
1993
1994   /* Join to the channel */
1995   silc_server_command_join_channel(server, cmd, channel, created, umode);
1996
1997  out:
1998   silc_server_command_free(cmd);
1999 }
2000
2001 /* Server side of command MOTD. Sends server's current "message of the
2002    day" to the client. */
2003
2004 SILC_SERVER_CMD_FUNC(motd)
2005 {
2006   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2007   SilcServer server = cmd->server;
2008   char *motd;
2009   int motd_len;
2010   
2011   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 2);
2012
2013   /* XXX show currently only our motd */
2014
2015   if (server->config && server->config->motd && 
2016       server->config->motd->motd_file) {
2017
2018     /* Send motd */
2019     motd = silc_file_read(server->config->motd->motd_file, &motd_len);
2020     if (!motd)
2021       goto out;
2022
2023     motd[motd_len] = 0;
2024     silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
2025                                          SILC_STATUS_OK,
2026                                          2, motd, motd_len);
2027     goto out;
2028   } else {
2029     /* No motd */
2030     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
2031                                           SILC_STATUS_OK);
2032   }
2033
2034  out:
2035   silc_server_command_free(cmd);
2036 }
2037
2038 SILC_SERVER_CMD_FUNC(umode)
2039 {
2040 }
2041
2042 /* Checks that client has rights to add or remove channel modes. If any
2043    of the checks fails FALSE is returned. */
2044
2045 int silc_server_check_cmode_rights(SilcChannelEntry channel,
2046                                    SilcChannelClientEntry client,
2047                                    unsigned int mode)
2048 {
2049   int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
2050   int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
2051
2052   /* Check whether has rights to change anything */
2053   if (!is_op && !is_fo)
2054     return FALSE;
2055
2056   /* Check whether has rights to change everything */
2057   if (is_op && is_fo)
2058     return TRUE;
2059
2060   /* We know that client is channel operator, check that they are not
2061      changing anything that requires channel founder rights. Rest of the
2062      modes are available automatically for channel operator. */
2063
2064   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
2065     if (is_op && !is_fo)
2066       return FALSE;
2067   } else {
2068     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2069       if (is_op && !is_fo)
2070         return FALSE;
2071     }
2072   }
2073   
2074   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2075     if (is_op && !is_fo)
2076       return FALSE;
2077   } else {
2078     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2079       if (is_op && !is_fo)
2080         return FALSE;
2081     }
2082   }
2083
2084   if (mode & SILC_CHANNEL_MODE_CIPHER) {
2085     if (is_op && !is_fo)
2086       return FALSE;
2087   } else {
2088     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2089       if (is_op && !is_fo)
2090         return FALSE;
2091     }
2092   }
2093   
2094   return TRUE;
2095 }
2096
2097 /* Server side command of CMODE. Changes channel mode */
2098
2099 SILC_SERVER_CMD_FUNC(cmode)
2100 {
2101   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2102   SilcServer server = cmd->server;
2103   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2104   SilcChannelID *channel_id;
2105   SilcChannelEntry channel;
2106   SilcChannelClientEntry chl;
2107   SilcBuffer packet, cidp;
2108   unsigned char *tmp, *tmp_id, *tmp_mask;
2109   unsigned int argc, mode_mask, tmp_len, tmp_len2;
2110
2111   SILC_LOG_DEBUG(("Start"));
2112
2113   argc = silc_argument_get_arg_num(cmd->args);
2114   if (argc < 2) {
2115     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2116                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2117     goto out;
2118   }
2119   if (argc > 8) {
2120     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2121                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2122     goto out;
2123   }
2124
2125   /* Get Channel ID */
2126   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
2127   if (!tmp_id) {
2128     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2129                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2130     goto out;
2131   }
2132   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
2133
2134   /* Get the channel mode mask */
2135   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2136   if (!tmp_mask) {
2137     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2138                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2139     goto out;
2140   }
2141   SILC_GET32_MSB(mode_mask, tmp_mask);
2142
2143   /* Get channel entry */
2144   channel = silc_idlist_find_channel_by_id(server->local_list, 
2145                                            channel_id, NULL);
2146   if (!channel) {
2147     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2148                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2149     goto out;
2150   }
2151
2152   /* Check whether this client is on the channel */
2153   if (!silc_server_client_on_channel(client, channel)) {
2154     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2155                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2156     goto out;
2157   }
2158
2159   /* Get entry to the channel user list */
2160   silc_list_start(channel->user_list);
2161   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2162     if (chl->client == client)
2163       break;
2164
2165   /* Check that client has rights to change any requested channel modes */
2166   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
2167     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2168                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2169     goto out;
2170   }
2171
2172   /*
2173    * Check the modes. Modes that requires nothing special operation are
2174    * not checked here.
2175    */
2176
2177   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
2178     /* Channel uses private keys to protect traffic. Client(s) has set the
2179        key locally they want to use, server does not know that key. */
2180     /* Nothing interesting to do here now */
2181   } else {
2182     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2183       /* The mode is removed and we need to generate and distribute
2184          new channel key. Clients are not using private channel keys
2185          anymore after this. */
2186
2187       /* XXX Duplicated code, make own function for this!! LEAVE uses this
2188          as well */
2189
2190       /* Re-generate channel key */
2191       silc_server_create_channel_key(server, channel, 0);
2192       
2193       /* Encode channel key payload to be distributed on the channel */
2194       packet = 
2195         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2196                                         strlen(channel->channel_key->
2197                                                cipher->name),
2198                                         channel->channel_key->cipher->name,
2199                                         channel->key_len / 8, channel->key);
2200       
2201       /* If we are normal server then we will send it to our router.  If we
2202          are router we will send it to all local servers that has clients on
2203          the channel */
2204       if (server->server_type == SILC_SERVER) {
2205         if (!server->standalone)
2206           silc_server_packet_send(server, 
2207                                   cmd->server->router->connection,
2208                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2209                                   packet->len, TRUE);
2210       } else {
2211         
2212       }
2213       
2214       /* Send to locally connected clients on the channel */
2215       silc_server_packet_send_local_channel(server, channel, 
2216                                             SILC_PACKET_CHANNEL_KEY, 0,
2217                                             packet->data, packet->len, FALSE);
2218       silc_buffer_free(packet);
2219     }
2220   }
2221   
2222   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
2223     /* User limit is set on channel */
2224     unsigned int user_limit;
2225       
2226     /* Get user limit */
2227     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
2228     if (!tmp) {
2229       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
2230         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2231                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2232         goto out;
2233       }
2234     } else {
2235       SILC_GET32_MSB(user_limit, tmp);
2236       channel->mode_data.user_limit = user_limit;
2237     }
2238   } else {
2239     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
2240       /* User limit mode is unset. Remove user limit */
2241       channel->mode_data.user_limit = 0;
2242   }
2243
2244   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
2245     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
2246       /* Passphrase has been set to channel */
2247       
2248       /* Get the passphrase */
2249       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
2250       if (!tmp) {
2251         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2252                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2253         goto out;
2254       }
2255
2256       /* Save the passphrase */
2257       channel->mode_data.passphrase = strdup(tmp);
2258     }
2259   } else {
2260     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2261       /* Passphrase mode is unset. remove the passphrase */
2262       if (channel->mode_data.passphrase) {
2263         silc_free(channel->mode_data.passphrase);
2264         channel->mode_data.passphrase = NULL;
2265       }
2266     }
2267   }
2268
2269   if (mode_mask & SILC_CHANNEL_MODE_BAN) {
2270     if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
2271       /* Ban list is specified for channel */
2272
2273       /* Get ban list */
2274       tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
2275       if (!tmp) {
2276         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2277                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2278         goto out;
2279       }
2280
2281       /* XXX check that channel founder is not banned */
2282
2283       /* Save the ban list */
2284       channel->mode_data.ban_list = strdup(tmp);
2285     }
2286   } else {
2287     if (channel->mode & SILC_CHANNEL_MODE_BAN) {
2288       /* Ban mode is unset. Remove the entire ban list */
2289       if (channel->mode_data.ban_list) {
2290         silc_free(channel->mode_data.ban_list);
2291         channel->mode_data.ban_list = NULL;
2292       }
2293     }
2294   }
2295
2296   if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
2297     if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
2298       /* Invite list is specified for channel */
2299
2300       /* Get invite list */
2301       tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
2302       if (!tmp) {
2303         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2304                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2305         goto out;
2306       }
2307
2308       /* Save the invite linst */
2309       channel->mode_data.invite_list = strdup(tmp);
2310     }
2311   } else {
2312     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
2313       /* Invite list mode is unset. Remove the entire invite list */
2314       if (channel->mode_data.invite_list) {
2315         silc_free(channel->mode_data.invite_list);
2316         channel->mode_data.invite_list = NULL;
2317       }
2318     }
2319   }
2320
2321   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
2322     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
2323       /* Cipher to use protect the traffic */
2324       unsigned int key_len = 128;
2325       char *cp;
2326
2327       /* Get cipher */
2328       tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
2329       if (!tmp) {
2330         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2331                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2332         goto out;
2333       }
2334
2335       cp = strchr(tmp, ':');
2336       if (cp) {
2337         key_len = atoi(cp);
2338         *cp = '\0';
2339       }
2340
2341       /* XXX Duplicated code, make own function for this!! */
2342     
2343       /* Delete old cipher and allocate the new one */
2344       silc_cipher_free(channel->channel_key);
2345       silc_cipher_alloc(tmp, &channel->channel_key);
2346
2347       key_len /= 8;
2348       if (key_len > 32)
2349         key_len = 32;
2350
2351       /* Re-generate channel key */
2352       silc_server_create_channel_key(server, channel, key_len);
2353     
2354       /* Encode channel key payload to be distributed on the channel */
2355       packet = 
2356         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2357                                         strlen(channel->channel_key->
2358                                                cipher->name),
2359                                         channel->channel_key->cipher->name,
2360                                         channel->key_len / 8, channel->key);
2361     
2362       /* If we are normal server then we will send it to our router.  If we
2363          are router we will send it to all local servers that has clients on
2364          the channel */
2365       if (server->server_type == SILC_SERVER) {
2366         if (!server->standalone)
2367           silc_server_packet_send(server, 
2368                                   cmd->server->router->connection,
2369                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2370                                   packet->len, TRUE);
2371       } else {
2372         
2373       }
2374     
2375       /* Send to locally connected clients on the channel */
2376       silc_server_packet_send_local_channel(server, channel, 
2377                                             SILC_PACKET_CHANNEL_KEY, 0,
2378                                           packet->data, packet->len, FALSE);
2379       silc_buffer_free(packet);
2380     }
2381   } else {
2382     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2383       /* Cipher mode is unset. Remove the cipher and revert back to 
2384          default cipher */
2385
2386       if (channel->mode_data.cipher) {
2387         silc_free(channel->mode_data.cipher);
2388         channel->mode_data.cipher = NULL;
2389         channel->mode_data.key_len = 0;
2390       }
2391
2392       /* Generate new cipher and key for the channel */
2393
2394       /* XXX Duplicated code, make own function for this!! */
2395
2396       /* Delete old cipher and allocate default one */
2397       silc_cipher_free(channel->channel_key);
2398       if (!channel->cipher)
2399         silc_cipher_alloc("twofish", &channel->channel_key);
2400       else
2401         silc_cipher_alloc(channel->cipher, &channel->channel_key);
2402
2403       /* Re-generate channel key */
2404       silc_server_create_channel_key(server, channel, 0);
2405       
2406       /* Encode channel key payload to be distributed on the channel */
2407       packet = 
2408         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2409                                         strlen(channel->channel_key->
2410                                                cipher->name),
2411                                         channel->channel_key->cipher->name,
2412                                         channel->key_len / 8, channel->key);
2413       
2414       /* If we are normal server then we will send it to our router.  If we
2415          are router we will send it to all local servers that has clients on
2416          the channel */
2417       if (server->server_type == SILC_SERVER) {
2418         if (!server->standalone)
2419           silc_server_packet_send(server, 
2420                                   cmd->server->router->connection,
2421                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2422                                   packet->len, TRUE);
2423       } else {
2424         
2425       }
2426       
2427       /* Send to locally connected clients on the channel */
2428       silc_server_packet_send_local_channel(server, channel, 
2429                                             SILC_PACKET_CHANNEL_KEY, 0,
2430                                             packet->data, packet->len, FALSE);
2431       silc_buffer_free(packet);
2432     }
2433   }
2434
2435   /* Finally, set the mode */
2436   channel->mode = mode_mask;
2437
2438   /* Send CMODE_CHANGE notify */
2439   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2440   silc_server_send_notify_to_channel(server, channel, TRUE,
2441                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
2442                                      cidp->data, cidp->len, 
2443                                      tmp_mask, tmp_len);
2444   silc_free(cidp);
2445
2446   /* Send command reply to sender */
2447   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
2448                                                 SILC_STATUS_OK, 0, 1,
2449                                                 2, tmp_mask, 4);
2450   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2451                           packet->data, packet->len, FALSE);
2452     
2453   silc_buffer_free(packet);
2454   silc_free(channel_id);
2455
2456  out:
2457   silc_server_command_free(cmd);
2458 }
2459
2460 /* Server side of CUMODE command. Changes client's mode on a channel. */
2461
2462 SILC_SERVER_CMD_FUNC(cumode)
2463 {
2464   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2465   SilcServer server = cmd->server;
2466   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2467   SilcChannelID *channel_id;
2468   SilcClientID *client_id;
2469   SilcChannelEntry channel;
2470   SilcClientEntry target_client;
2471   SilcChannelClientEntry chl;
2472   SilcBuffer packet, idp;
2473   unsigned char *tmp_id, *tmp_mask;
2474   unsigned int target_mask, sender_mask, tmp_len;
2475   int notify = FALSE;
2476
2477   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
2478
2479   /* Get Channel ID */
2480   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2481   if (!tmp_id) {
2482     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2483                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2484     goto out;
2485   }
2486   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2487
2488   /* Get channel entry */
2489   channel = silc_idlist_find_channel_by_id(server->local_list, 
2490                                            channel_id, NULL);
2491   if (!channel) {
2492     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2493                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2494     goto out;
2495   }
2496
2497   /* Check whether sender is on the channel */
2498   if (!silc_server_client_on_channel(client, channel)) {
2499     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2500                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2501     goto out;
2502   }
2503
2504   /* Check that client has rights to change other's rights */
2505   silc_list_start(channel->user_list);
2506   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2507     if (chl->client == client) {
2508       if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
2509           !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2510         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2511                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2512         goto out;
2513       }
2514
2515       sender_mask = chl->mode;
2516       break;
2517     }
2518   }
2519   
2520   /* Get the target client's channel mode mask */
2521   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
2522   if (!tmp_mask) {
2523     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2524                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2525     goto out;
2526   }
2527   SILC_GET32_MSB(target_mask, tmp_mask);
2528
2529   /* Get target Client ID */
2530   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2531   if (!tmp_id) {
2532     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2533                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2534     goto out;
2535   }
2536   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2537
2538   /* Get target client's entry */
2539   target_client = silc_idlist_find_client_by_id(server->local_list, 
2540                                                 client_id, NULL);
2541   if (!target_client) {
2542     /* XXX If target client is not one of mine send to primary route */
2543   }
2544
2545   /* Check whether target client is on the channel */
2546   if (!silc_server_client_on_channel(target_client, channel)) {
2547     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2548                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
2549     goto out;
2550   }
2551
2552   /* Get entry to the channel user list */
2553   silc_list_start(channel->user_list);
2554   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2555     if (chl->client == target_client)
2556       break;
2557
2558   /* 
2559    * Change the mode 
2560    */
2561
2562   /* If the target client is founder, no one else can change their mode
2563      but themselves. */
2564   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
2565     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2566                                           SILC_STATUS_ERR_NOT_YOU);
2567     goto out;
2568   }
2569
2570   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
2571     /* Cannot promote anyone to channel founder */
2572     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2573                                           SILC_STATUS_ERR_NOT_YOU);
2574     goto out;
2575   } else {
2576     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
2577       if (target_client == client) {
2578         /* Remove channel founder rights from itself */
2579         chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
2580         notify = TRUE;
2581       } else {
2582         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2583                                               SILC_STATUS_ERR_NOT_YOU);
2584         goto out;
2585       }
2586     }
2587   }
2588
2589   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
2590     /* Promote to operator */
2591     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2592       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
2593       notify = TRUE;
2594     }
2595   } else {
2596     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
2597       /* Demote to normal user */
2598       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
2599       notify = TRUE;
2600     }
2601   }
2602
2603   /* Send notify to channel, notify only if mode was actually changed. */
2604   if (notify) {
2605     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2606     silc_server_send_notify_to_channel(server, channel, TRUE,
2607                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
2608                                        idp->data, idp->len,
2609                                        tmp_mask, 4, tmp_id, tmp_len);
2610     silc_buffer_free(idp);
2611   }
2612
2613   /* Send command reply to sender */
2614   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
2615                                                 SILC_STATUS_OK, 0, 2,
2616                                                 2, tmp_mask, 4,
2617                                                 3, tmp_id, tmp_len);
2618   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2619                           packet->data, packet->len, FALSE);
2620     
2621   silc_buffer_free(packet);
2622   silc_free(channel_id);
2623   silc_free(client_id);
2624
2625  out:
2626   silc_server_command_free(cmd);
2627 }
2628
2629 /* Server side of KICK command. Kicks client out of channel. */
2630
2631 SILC_SERVER_CMD_FUNC(kick)
2632 {
2633 }
2634
2635 SILC_SERVER_CMD_FUNC(restart)
2636 {
2637 }
2638  
2639 SILC_SERVER_CMD_FUNC(close)
2640 {
2641 }
2642  
2643 SILC_SERVER_CMD_FUNC(die)
2644 {
2645 }
2646  
2647 SILC_SERVER_CMD_FUNC(silcoper)
2648 {
2649 }
2650
2651 /* Server side command of LEAVE. Removes client from a channel. */
2652
2653 SILC_SERVER_CMD_FUNC(leave)
2654 {
2655   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2656   SilcServer server = cmd->server;
2657   SilcSocketConnection sock = cmd->sock;
2658   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
2659   SilcChannelID *id;
2660   SilcChannelEntry channel;
2661   SilcBuffer packet;
2662   unsigned int i, len;
2663   unsigned char *tmp;
2664
2665   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
2666
2667   /* Get Channel ID */
2668   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2669   if (!tmp) {
2670     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2671                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2672     goto out;
2673   }
2674   id = silc_id_payload_parse_id(tmp, len);
2675
2676   /* Get channel entry */
2677   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
2678   if (!channel) {
2679     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2680                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2681     goto out;
2682   }
2683
2684   /* Check whether this client is on the channel */
2685   if (!silc_server_client_on_channel(id_entry, channel)) {
2686     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2687                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2688     goto out;
2689   }
2690
2691   /* Notify routers that they should remove this client from their list
2692      of clients on the channel. */
2693   if (!server->standalone)
2694     silc_server_send_remove_channel_user(server, 
2695                                          server->router->connection,
2696                                          server->server_type == SILC_ROUTER ?
2697                                          TRUE : FALSE, id_entry->id, id);
2698
2699   /* Remove client from channel */
2700   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
2701                                           TRUE);
2702   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2703                                         SILC_STATUS_OK);
2704
2705   /* If the channel does not exist anymore we won't send anything */
2706   if (!i)
2707     goto out;
2708
2709   /* Re-generate channel key */
2710   silc_server_create_channel_key(server, channel, 0);
2711
2712   /* Encode channel key payload to be distributed on the channel */
2713   packet = 
2714     silc_channel_key_payload_encode(len, tmp,
2715                                     strlen(channel->channel_key->cipher->name),
2716                                     channel->channel_key->cipher->name,
2717                                     channel->key_len / 8, channel->key);
2718
2719   /* If we are normal server then we will send it to our router.  If we
2720      are router we will send it to all local servers that has clients on
2721      the channel */
2722   if (server->server_type == SILC_SERVER) {
2723     if (!server->standalone)
2724       silc_server_packet_send(server, 
2725                               cmd->server->router->connection,
2726                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2727                               packet->len, TRUE);
2728   } else {
2729
2730   }
2731
2732   /* Send to locally connected clients on the channel */
2733   silc_server_packet_send_local_channel(server, channel, 
2734                                         SILC_PACKET_CHANNEL_KEY, 0,
2735                                         packet->data, packet->len, FALSE);
2736
2737   silc_buffer_free(packet);
2738   silc_free(id);
2739
2740  out:
2741   silc_server_command_free(cmd);
2742 }
2743
2744 /* Server side of command NAMES. Resolves clients and their names currently
2745    joined on the requested channel. The name list is sent back to the
2746    client. */
2747
2748 SILC_SERVER_CMD_FUNC(names)
2749 {
2750   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2751   SilcServer server = cmd->server;
2752   SilcChannelEntry channel;
2753   SilcChannelClientEntry chl;
2754   SilcChannelID *id;
2755   SilcBuffer packet;
2756   unsigned int i, len, len2, tmp_len;
2757   unsigned char *tmp;
2758   char *name_list = NULL, *n;
2759   SilcBuffer client_id_list;
2760   SilcBuffer client_mode_list;
2761
2762   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NAMES, cmd, 1, 2);
2763
2764   /* Get Channel ID */
2765   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2766   if (!tmp) {
2767     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2768                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2769     goto out;
2770   }
2771   id = silc_id_payload_parse_id(tmp, tmp_len);
2772
2773   /* Check whether the channel exists. If we are normal server and the
2774      channel does not exist we will send this same command to our router
2775      which will know if the channel exists. */
2776   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
2777   if (!channel) {
2778     if (server->server_type == SILC_SERVER && !server->standalone) {
2779       /* XXX Send names command */
2780
2781       cmd->pending = TRUE;
2782       silc_server_command_pending(server, SILC_COMMAND_NAMES, 0,
2783                                   silc_server_command_names, context);
2784       return;
2785     }
2786
2787     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2788                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2789     goto out;
2790   }
2791
2792   /* Assemble the name list now */
2793   name_list = NULL;
2794   len = 0;
2795   silc_list_start(channel->user_list);
2796   i = 0;
2797   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2798     n = chl->client->nickname;
2799     if (n) {
2800       len2 = strlen(n);
2801       len += len2;
2802       name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
2803       memcpy(name_list + (len - len2), n, len2);
2804       name_list[len] = 0;
2805
2806       if (i == silc_list_count(channel->user_list) - 1)
2807         break;
2808       memcpy(name_list + len, ",", 1);
2809       len++;
2810       i++;
2811     }
2812   }
2813   if (!name_list)
2814     name_list = "";
2815
2816   /* Assemble the Client ID list now */
2817   client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) * 
2818                                      silc_list_count(channel->user_list));
2819   silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
2820   silc_list_start(channel->user_list);
2821   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2822     SilcBuffer idp;
2823
2824     idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
2825     silc_buffer_format(client_id_list,
2826                        SILC_STR_UI_XNSTRING(idp->data, idp->len),
2827                        SILC_STR_END);
2828     silc_buffer_pull(client_id_list, idp->len);
2829     silc_buffer_free(idp);
2830   }
2831   silc_buffer_push(client_id_list, 
2832                    client_id_list->data - client_id_list->head);
2833
2834   /* Assemble mode list */
2835   client_mode_list = silc_buffer_alloc(4 * 
2836                                        silc_list_count(channel->user_list));
2837   silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
2838   silc_list_start(channel->user_list);
2839   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2840     SILC_PUT32_MSB(chl->mode, client_mode_list->data);
2841     silc_buffer_pull(client_mode_list, 4);
2842   }
2843   silc_buffer_push(client_mode_list, 
2844                    client_mode_list->data - client_mode_list->head);
2845
2846   /* Send reply */
2847   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NAMES,
2848                                                 SILC_STATUS_OK, 0, 4,
2849                                                 2, tmp, tmp_len,
2850                                                 3, name_list, 
2851                                                 strlen(name_list),
2852                                                 4, client_id_list->data,
2853                                                 client_id_list->len,
2854                                                 5, client_mode_list->data,
2855                                                 client_mode_list->len);
2856   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2857                           packet->data, packet->len, FALSE);
2858     
2859   silc_buffer_free(packet);
2860   silc_free(name_list);
2861   silc_buffer_free(client_id_list);
2862   silc_buffer_free(client_mode_list);
2863   silc_free(id);
2864
2865  out:
2866   silc_server_command_free(cmd);
2867 }