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