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