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