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