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