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