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