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 > 1) {
396       for (k = 1, i = 1; i < argc; i++) {
397         tmp = silc_argument_get_arg_type(cmd->args, i + 3, &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                                                       status, 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                                                       status, 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   if (strlen(nick) > 128)
1285     nick[127] = '\0';
1286
1287   /* Create new Client ID */
1288   silc_id_create_client_id(cmd->server->id, cmd->server->rng, 
1289                            cmd->server->md5hash, nick,
1290                            &new_id);
1291
1292   /* Send notify about nickname change to our router. We send the new
1293      ID and ask to replace it with the old one. If we are router the
1294      packet is broadcasted. Send NICK_CHANGE notify. */
1295   if (!server->standalone)
1296     silc_server_send_notify_nick_change(server, server->router->connection, 
1297                                         server->server_type == SILC_SERVER ? 
1298                                         FALSE : TRUE, client->id,
1299                                         new_id, SILC_ID_CLIENT_LEN);
1300
1301   /* Remove old cache entry */
1302   silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
1303                          client->id); 
1304
1305   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1306
1307   /* Free old ID */
1308   if (client->id) {
1309     memset(client->id, 0, SILC_ID_CLIENT_LEN);
1310     silc_free(client->id);
1311   }
1312
1313   /* Save the nickname as this client is our local client */
1314   if (client->nickname)
1315     silc_free(client->nickname);
1316
1317   client->nickname = strdup(nick);
1318   client->id = new_id;
1319
1320   /* Update client cache */
1321   silc_idcache_add(server->local_list->clients, client->nickname, 
1322                    SILC_ID_CLIENT, client->id, (void *)client, TRUE);
1323
1324   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1325
1326   /* Send NICK_CHANGE notify to the client's channels */
1327   silc_server_send_notify_on_channels(server, client, 
1328                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
1329                                       oidp->data, oidp->len, 
1330                                       nidp->data, nidp->len);
1331
1332   /* Send the new Client ID as reply command back to client */
1333   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
1334                                                 SILC_STATUS_OK, 0, 1, 
1335                                                 2, nidp->data, nidp->len);
1336   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1337                           0, packet->data, packet->len, FALSE);
1338
1339   silc_buffer_free(packet);
1340   silc_buffer_free(nidp);
1341   silc_buffer_free(oidp);
1342   
1343  out:
1344   silc_server_command_free(cmd);
1345 }
1346
1347 SILC_SERVER_CMD_FUNC(list)
1348 {
1349 }
1350
1351 /* Server side of TOPIC command. Sets topic for channel and/or returns
1352    current topic to client. */
1353
1354 SILC_SERVER_CMD_FUNC(topic)
1355 {
1356   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1357   SilcServer server = cmd->server;
1358   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1359   SilcChannelID *channel_id;
1360   SilcChannelEntry channel;
1361   SilcChannelClientEntry chl;
1362   SilcBuffer packet, idp;
1363   unsigned char *tmp;
1364   unsigned int argc, tmp_len;
1365
1366   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
1367
1368   argc = silc_argument_get_arg_num(cmd->args);
1369
1370   /* Get Channel ID */
1371   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1372   if (!tmp) {
1373     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1374                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1375     goto out;
1376   }
1377   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1378   if (!channel_id) {
1379     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1380                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1381     goto out;
1382   }
1383
1384   /* Check whether the channel exists */
1385   channel = silc_idlist_find_channel_by_id(server->local_list, 
1386                                            channel_id, NULL);
1387   if (!channel) {
1388     channel = silc_idlist_find_channel_by_id(server->global_list, 
1389                                              channel_id, NULL);
1390     if (!channel) {
1391       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1392                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1393       goto out;
1394     }
1395   }
1396
1397   if (argc > 1) {
1398     /* Get the topic */
1399     tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1400     if (!tmp) {
1401       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1402                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1403       goto out;
1404     }
1405
1406     if (strlen(tmp) > 256) {
1407       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1408                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1409       goto out;
1410     }
1411
1412     /* See whether has rights to change topic */
1413     silc_list_start(channel->user_list);
1414     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
1415       if (chl->client == client)
1416         break;
1417
1418     if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1419       if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
1420         silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1421                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1422         goto out;
1423       }
1424     }
1425
1426     /* Set the topic for channel */
1427     if (channel->topic)
1428       silc_free(channel->topic);
1429     channel->topic = strdup(tmp);
1430
1431     /* Send TOPIC_SET notify type to the network */
1432     if (!server->standalone)
1433       silc_server_send_notify_topic_set(server, server->router->connection,
1434                                         server->server_type == SILC_ROUTER ?
1435                                         TRUE : FALSE, channel, client->id,
1436                                         SILC_ID_CLIENT_LEN, channel->topic);
1437
1438     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1439
1440     /* Send notify about topic change to all clients on the channel */
1441     silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
1442                                        SILC_NOTIFY_TYPE_TOPIC_SET, 2,
1443                                        idp->data, idp->len,
1444                                        channel->topic, strlen(channel->topic));
1445     silc_buffer_free(idp);
1446   }
1447
1448   /* Send the topic to client as reply packet */
1449   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1450   if (channel->topic)
1451     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1452                                                   SILC_STATUS_OK, 0, 2, 
1453                                                   2, idp->data, idp->len,
1454                                                   3, channel->topic, 
1455                                                   strlen(channel->topic));
1456   else
1457     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1458                                                   SILC_STATUS_OK, 0, 1, 
1459                                                   2, idp->data, idp->len);
1460   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1461                           0, packet->data, packet->len, FALSE);
1462
1463   silc_buffer_free(packet);
1464   silc_buffer_free(idp);
1465   silc_free(channel_id);
1466
1467  out:
1468   silc_server_command_free(cmd);
1469 }
1470
1471 /* Server side of INVITE command. Invites some client to join some channel. */
1472
1473 SILC_SERVER_CMD_FUNC(invite)
1474 {
1475   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1476   SilcServer server = cmd->server;
1477   SilcSocketConnection sock = cmd->sock, dest_sock;
1478   SilcClientEntry sender, dest;
1479   SilcClientID *dest_id;
1480   SilcChannelEntry channel;
1481   SilcChannelID *channel_id;
1482   SilcBuffer sidp;
1483   unsigned char *tmp;
1484   unsigned int len;
1485
1486   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 2);
1487
1488   /* Get destination ID */
1489   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1490   if (!tmp) {
1491     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1492                                           SILC_STATUS_ERR_NO_CLIENT_ID);
1493     goto out;
1494   }
1495   dest_id = silc_id_payload_parse_id(tmp, len);
1496   if (!dest_id) {
1497     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1498                                           SILC_STATUS_ERR_NO_CLIENT_ID);
1499     goto out;
1500   }
1501
1502   /* Get Channel ID */
1503   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1504   if (!tmp) {
1505     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1506                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1507     goto out;
1508   }
1509   channel_id = silc_id_payload_parse_id(tmp, len);
1510   if (!channel_id) {
1511     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1512                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1513     goto out;
1514   }
1515
1516   /* Check whether the channel exists */
1517   channel = silc_idlist_find_channel_by_id(server->local_list, 
1518                                            channel_id, NULL);
1519   if (!channel) {
1520     channel = silc_idlist_find_channel_by_id(server->global_list, 
1521                                              channel_id, NULL);
1522     if (!channel) {
1523       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1524                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1525       goto out;
1526     }
1527   }
1528
1529   /* Check whether the sender of this command is on the channel. */
1530   sender = (SilcClientEntry)sock->user_data;
1531   if (!silc_server_client_on_channel(sender, channel)) {
1532     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1533                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
1534     goto out;
1535   }
1536
1537   /* Check whether the channel is invite-only channel. If yes then the
1538      sender of this command must be at least channel operator. */
1539   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1540     SilcChannelClientEntry chl;
1541
1542     silc_list_start(channel->user_list);
1543     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
1544       if (chl->client == sender) {
1545         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1546           silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1547                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1548           goto out;
1549         }
1550         break;
1551       }
1552   }
1553
1554   /* Find the connection data for the destination. If it is local we will
1555      send it directly otherwise we will send it to router for routing. */
1556   dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
1557   if (dest)
1558     dest_sock = (SilcSocketConnection)dest->connection;
1559   else
1560     dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
1561
1562   /* Check whether the requested client is already on the channel. */
1563   /* XXX if we are normal server we don't know about global clients on
1564      the channel thus we must request it (USERS command), check from
1565      local cache as well. */
1566   if (silc_server_client_on_channel(dest, channel)) {
1567     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1568                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1569     goto out;
1570   }
1571
1572   sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
1573
1574   /* Send notify to the client that is invited to the channel */
1575   silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, 
1576                                SILC_ID_CLIENT,
1577                                SILC_NOTIFY_TYPE_INVITE, 2, 
1578                                sidp->data, sidp->len, tmp, len);
1579
1580   /* Send command reply */
1581   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1582                                         SILC_STATUS_OK);
1583
1584   silc_buffer_free(sidp);
1585
1586  out:
1587   silc_server_command_free(cmd);
1588 }
1589
1590 typedef struct {
1591   SilcServer server;
1592   SilcSocketConnection sock;
1593   char *signoff;
1594 } *QuitInternal;
1595
1596 /* Quits connection to client. This gets called if client won't
1597    close the connection even when it has issued QUIT command. */
1598
1599 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
1600 {
1601   QuitInternal q = (QuitInternal)context;
1602
1603   /* Free all client specific data, such as client entry and entires
1604      on channels this client may be on. */
1605   silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
1606                                q->signoff);
1607   q->sock->user_data = NULL;
1608
1609   /* Close the connection on our side */
1610   silc_server_close_connection(q->server, q->sock);
1611
1612   silc_free(q->signoff);
1613   silc_free(q);
1614 }
1615
1616 /* Quits SILC session. This is the normal way to disconnect client. */
1617  
1618 SILC_SERVER_CMD_FUNC(quit)
1619 {
1620   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1621   SilcServer server = cmd->server;
1622   SilcSocketConnection sock = cmd->sock;
1623   QuitInternal q;
1624   unsigned char *tmp = NULL;
1625   unsigned int len = 0;
1626
1627   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_QUIT, cmd, 0, 1);
1628
1629   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
1630     goto out;
1631
1632   /* Get destination ID */
1633   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1634   if (len > 128)
1635     tmp = NULL;
1636
1637   q = silc_calloc(1, sizeof(*q));
1638   q->server = server;
1639   q->sock = sock;
1640   q->signoff = tmp ? strdup(tmp) : NULL;
1641
1642   /* We quit the connection with little timeout */
1643   silc_task_register(server->timeout_queue, sock->sock,
1644                      silc_server_command_quit_cb, (void *)q,
1645                      0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1646
1647  out:
1648   silc_server_command_free(cmd);
1649 }
1650
1651 SILC_SERVER_CMD_FUNC(kill)
1652 {
1653 }
1654
1655 /* Server side of command INFO. This sends information about us to 
1656    the client. If client requested specific server we will send the 
1657    command to that server. */
1658
1659 SILC_SERVER_CMD_FUNC(info)
1660 {
1661   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1662   SilcServer server = cmd->server;
1663   SilcBuffer packet, idp;
1664   char info_string[256], *dest_server;
1665
1666   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
1667
1668   /* Get server name */
1669   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
1670   if (!dest_server) {
1671     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1672                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1673     goto out;
1674   }
1675
1676   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
1677     /* Send our reply */
1678     memset(info_string, 0, sizeof(info_string));
1679     snprintf(info_string, sizeof(info_string), 
1680              "location: %s server: %s admin: %s <%s>",
1681              server->config->admin_info->location,
1682              server->config->admin_info->server_type,
1683              server->config->admin_info->admin_name,
1684              server->config->admin_info->admin_email);
1685
1686     idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
1687
1688     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
1689                                                   SILC_STATUS_OK, 0, 2,
1690                                                   2, idp->data, idp->len,
1691                                                   3, info_string, 
1692                                                   strlen(info_string));
1693     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
1694                             packet->data, packet->len, FALSE);
1695     
1696     silc_buffer_free(packet);
1697     silc_buffer_free(idp);
1698   } else {
1699     /* Send this command to the requested server */
1700
1701     if (server->server_type == SILC_SERVER && !server->standalone) {
1702
1703     }
1704
1705     if (server->server_type == SILC_ROUTER) {
1706
1707     }
1708   }
1709   
1710  out:
1711   silc_server_command_free(cmd);
1712 }
1713
1714 /* Server side of command PING. This just replies to the ping. */
1715
1716 SILC_SERVER_CMD_FUNC(ping)
1717 {
1718   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1719   SilcServer server = cmd->server;
1720   SilcServerID *id;
1721   unsigned int len;
1722   unsigned char *tmp;
1723
1724   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
1725
1726   /* Get Server ID */
1727   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1728   if (!tmp) {
1729     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1730                                           SILC_STATUS_ERR_NO_SERVER_ID);
1731     goto out;
1732   }
1733   id = silc_id_str2id(tmp, len, SILC_ID_SERVER);
1734   if (!id)
1735     goto out;
1736
1737   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
1738     /* Send our reply */
1739     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1740                                           SILC_STATUS_OK);
1741   } else {
1742     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1743                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1744     goto out;
1745   }
1746
1747   silc_free(id);
1748
1749  out:
1750   silc_server_command_free(cmd);
1751 }
1752
1753 /* Internal routine to join channel. The channel sent to this function
1754    has been either created or resolved from ID lists. This joins the sent
1755    client to the channel. */
1756
1757 static void silc_server_command_join_channel(SilcServer server, 
1758                                              SilcServerCommandContext cmd,
1759                                              SilcChannelEntry channel,
1760                                              SilcClientID *client_id,
1761                                              int created,
1762                                              unsigned int umode)
1763 {
1764   SilcSocketConnection sock = cmd->sock;
1765   unsigned char *tmp;
1766   unsigned int tmp_len, user_count;
1767   unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
1768   SilcClientEntry client;
1769   SilcChannelClientEntry chl;
1770   SilcBuffer reply, chidp, clidp, keyp, user_list, mode_list;
1771   unsigned short ident = silc_command_get_ident(cmd->payload);
1772
1773   SILC_LOG_DEBUG(("Start"));
1774
1775   if (!channel)
1776     return;
1777
1778   /* Get passphrase */
1779   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1780   if (tmp) {
1781     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1782     memcpy(passphrase, tmp, tmp_len);
1783   }
1784   
1785   /*
1786    * Check channel modes
1787    */
1788
1789   /* Check invite list if channel is invite-only channel */
1790   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1791     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
1792       /* Invite list is specified. Check whether client is invited in the
1793          list. If not, then check whether it has been invited otherwise. */
1794
1795     } else {
1796       /* XXX client must be invited to be able to join the channel */
1797     }
1798   }
1799
1800   /* Check ban list if set */
1801   if (channel->mode & SILC_CHANNEL_MODE_BAN) {
1802
1803   }
1804
1805   /* Check the channel passphrase if set. */
1806   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
1807     if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
1808                               strlen(channel->mode_data.passphrase))) {
1809       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1810                                             SILC_STATUS_ERR_BAD_PASSWORD);
1811       goto out;
1812     }
1813   }
1814
1815   /* Check user count limit if set. */
1816   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
1817     if (silc_list_count(channel->user_list) + 1 > 
1818         channel->mode_data.user_limit) {
1819       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1820                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
1821       goto out;
1822     }
1823   }
1824
1825   /*
1826    * Client is allowed to join to the channel. Make it happen.
1827    */
1828
1829   /* Get the client entry */
1830   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
1831     client = (SilcClientEntry)sock->user_data;
1832   } else {
1833     client = silc_idlist_find_client_by_id(server->local_list, client_id, 
1834                                            NULL);
1835     if (!client) {
1836       /* XXX actually this is useless since router finds always cell's
1837          local clients from its local lists. */
1838       client = silc_idlist_find_client_by_id(server->global_list, client_id, 
1839                                              NULL);
1840       if (!client)
1841         goto out;
1842     }
1843   }
1844
1845   /* Check whether the client already is on the channel */
1846   if (silc_server_client_on_channel(client, channel)) {
1847     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1848                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1849     goto out;
1850   }
1851
1852   /* Generate new channel key as protocol dictates */
1853   if ((!created && silc_list_count(channel->user_list) > 0) || 
1854       !channel->channel_key)
1855     silc_server_create_channel_key(server, channel, 0);
1856
1857   /* Send the channel key. This is broadcasted to the channel but is not
1858      sent to the client who is joining to the channel. */
1859   silc_server_send_channel_key(server, NULL, channel, 
1860                                server->server_type == SILC_ROUTER ? 
1861                                FALSE : !server->standalone);
1862
1863   /* Join the client to the channel by adding it to channel's user list.
1864      Add also the channel to client entry's channels list for fast cross-
1865      referencing. */
1866   chl = silc_calloc(1, sizeof(*chl));
1867   chl->mode = umode;
1868   chl->client = client;
1869   chl->channel = channel;
1870   silc_list_add(channel->user_list, chl);
1871   silc_list_add(client->channels, chl);
1872
1873   /* Get users on the channel */
1874   silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
1875                                    &user_count);
1876
1877   /* Encode Client ID Payload of the original client who wants to join */
1878   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1879
1880   /* Encode command reply packet */
1881   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1882   SILC_PUT32_MSB(channel->mode, mode);
1883   SILC_PUT32_MSB(created, tmp2);
1884   SILC_PUT32_MSB(user_count, tmp3);
1885   tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1886   keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp, 
1887                                          strlen(channel->channel_key->
1888                                                 cipher->name),
1889                                          channel->channel_key->cipher->name,
1890                                          channel->key_len / 8, channel->key);
1891   silc_free(tmp);
1892   if (!channel->topic) {
1893     reply = 
1894       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1895                                            SILC_STATUS_OK, ident, 9,
1896                                            2, channel->channel_name,
1897                                            strlen(channel->channel_name),
1898                                            3, chidp->data, chidp->len,
1899                                            4, clidp->data, clidp->len,
1900                                            5, mode, 4,
1901                                            6, tmp2, 4,
1902                                            7, keyp->data, keyp->len,
1903                                            12, tmp3, 4,
1904                                            13, user_list->data, user_list->len,
1905                                            14, mode_list->data, 
1906                                            mode_list->len);
1907   } else {
1908     reply = 
1909       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1910                                            SILC_STATUS_OK, ident, 10, 
1911                                            2, channel->channel_name, 
1912                                            strlen(channel->channel_name),
1913                                            3, chidp->data, chidp->len,
1914                                            4, clidp->data, clidp->len,
1915                                            5, mode, 4,
1916                                            6, tmp2, 4,
1917                                            7, keyp->data, keyp->len,
1918                                            10, channel->topic, 
1919                                            strlen(channel->topic),
1920                                            12, tmp3, 4,
1921                                            13, user_list->data, user_list->len,
1922                                            14, mode_list->data, 
1923                                            mode_list->len);
1924   }
1925
1926   /* Send command reply */
1927   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
1928                           reply->data, reply->len, FALSE);
1929
1930   if (!cmd->pending) {
1931     /* Send JOIN notify to locally connected clients on the channel */
1932     silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
1933                                        SILC_NOTIFY_TYPE_JOIN, 2,
1934                                        clidp->data, clidp->len,
1935                                        chidp->data, chidp->len);
1936
1937     /* Send JOIN notify packet to our primary router */
1938     if (!server->standalone)
1939       silc_server_send_notify_join(server, server->router->connection,
1940                                    server->server_type == SILC_ROUTER ?
1941                                    TRUE : FALSE, channel, client->id,
1942                                    SILC_ID_CLIENT_LEN);
1943   }
1944
1945   silc_buffer_free(reply);
1946   silc_buffer_free(clidp);
1947   silc_buffer_free(chidp);
1948   silc_buffer_free(keyp);
1949   silc_buffer_free(user_list);
1950   silc_buffer_free(mode_list);
1951
1952  out:
1953   if (passphrase)
1954     silc_free(passphrase);
1955 }
1956
1957 /* Server side of command JOIN. Joins client into requested channel. If 
1958    the channel does not exist it will be created. */
1959
1960 SILC_SERVER_CMD_FUNC(join)
1961 {
1962   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1963   SilcServer server = cmd->server;
1964   int tmp_len;
1965   char *tmp, *channel_name = NULL, *cipher, *hmac;
1966   SilcChannelEntry channel;
1967   unsigned int umode = 0;
1968   int created = FALSE;
1969   SilcClientID *client_id;
1970
1971   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 4);
1972
1973   /* Get channel name */
1974   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1975   if (!tmp) {
1976     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1977                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1978     goto out;
1979   }
1980   channel_name = tmp;
1981
1982   if (strlen(channel_name) > 256)
1983     channel_name[255] = '\0';
1984
1985   if (silc_server_command_bad_chars(channel_name) == TRUE) {
1986     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1987                                           SILC_STATUS_ERR_BAD_CHANNEL);
1988     silc_free(channel_name);
1989     goto out;
1990   }
1991
1992   /* Get Client ID of the client who is joining to the channel */
1993   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1994   if (!tmp) {
1995     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1996                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1997     goto out;
1998   }
1999   client_id = silc_id_payload_parse_id(tmp, tmp_len);
2000   if (!client_id) {
2001     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2002                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2003     goto out;
2004   }
2005
2006   /* Get cipher and hmac name */
2007   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
2008   hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
2009
2010   /* See if the channel exists */
2011   channel = silc_idlist_find_channel_by_name(server->local_list, 
2012                                              channel_name, NULL);
2013
2014   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2015     /* If this is coming from client the Client ID in the command packet must
2016        be same as the client's ID. */
2017     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2018       SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
2019       if (SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
2020         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2021                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2022         goto out;
2023       }
2024     }
2025
2026     if (!channel) {
2027       /* Channel not found */
2028
2029       /* If we are standalone server we don't have a router, we just create 
2030          the channel by ourselves. */
2031       if (server->standalone) {
2032         channel = silc_server_create_new_channel(server, server->id, cipher, 
2033                                                  hmac, channel_name, TRUE);
2034         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2035         created = TRUE;
2036
2037       } else {
2038
2039         /* The channel does not exist on our server. If we are normal server 
2040            we will send JOIN command to our router which will handle the
2041            joining procedure (either creates the channel if it doesn't exist 
2042            or joins the client to it). */
2043         if (server->server_type == SILC_SERVER) {
2044           SilcBuffer tmpbuf;
2045           unsigned short old_ident;
2046           
2047           old_ident = silc_command_get_ident(cmd->payload);
2048           silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2049           tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2050           
2051           /* Send JOIN command to our router */
2052           silc_server_packet_send(server, (SilcSocketConnection)
2053                                   server->router->connection,
2054                                   SILC_PACKET_COMMAND, cmd->packet->flags,
2055                                   tmpbuf->data, tmpbuf->len, TRUE);
2056           
2057           /* Reprocess this packet after received reply from router */
2058           silc_server_command_pending(server, SILC_COMMAND_JOIN, 
2059                                       silc_command_get_ident(cmd->payload),
2060                                       silc_server_command_destructor,
2061                                       silc_server_command_join,
2062                                       silc_server_command_dup(cmd));
2063           cmd->pending = TRUE;
2064           return;
2065         }
2066         
2067         /* We are router and the channel does not seem exist so we will check
2068            our global list as well for the channel. */
2069         channel = silc_idlist_find_channel_by_name(server->global_list, 
2070                                                    channel_name, NULL);
2071         if (!channel) {
2072           /* Channel really does not exist, create it */
2073           channel = silc_server_create_new_channel(server, server->id, cipher, 
2074                                                    hmac, channel_name, TRUE);
2075           umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2076           created = TRUE;
2077         }
2078       }
2079     }
2080   } else {
2081     if (!channel) {
2082       /* Channel not found */
2083
2084       /* If the command came from router and/or we are normal server then
2085          something went wrong with the joining as the channel was not found.
2086          We can't do anything else but ignore this. */
2087       if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
2088           server->server_type == SILC_SERVER)
2089         goto out;
2090       
2091       /* We are router and the channel does not seem exist so we will check
2092          our global list as well for the channel. */
2093       channel = silc_idlist_find_channel_by_name(server->global_list, 
2094                                                  channel_name, NULL);
2095       if (!channel) {
2096         /* Channel really does not exist, create it */
2097         channel = silc_server_create_new_channel(server, server->id, cipher, 
2098                                                  hmac, channel_name, TRUE);
2099         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2100         created = TRUE;
2101       }
2102     }
2103   }
2104
2105   /* If the channel does not have global users and is also empty it means the
2106      channel was created globally (by our router) and the client will be the
2107      channel founder and operator. */
2108   if (!channel->global_users && silc_list_count(channel->user_list) == 0) {
2109     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2110     created = TRUE;             /* Created globally by our router */
2111   }
2112
2113   /* Join to the channel */
2114   silc_server_command_join_channel(server, cmd, channel, client_id,
2115                                    created, umode);
2116
2117   silc_free(client_id);
2118
2119  out:
2120   silc_server_command_free(cmd);
2121 }
2122
2123 /* Server side of command MOTD. Sends server's current "message of the
2124    day" to the client. */
2125
2126 SILC_SERVER_CMD_FUNC(motd)
2127 {
2128   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2129   SilcServer server = cmd->server;
2130   char *motd;
2131   int motd_len;
2132   
2133   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 2);
2134
2135   /* XXX show currently only our motd */
2136
2137   if (server->config && server->config->motd && 
2138       server->config->motd->motd_file) {
2139
2140     /* Send motd */
2141     motd = silc_file_read(server->config->motd->motd_file, &motd_len);
2142     if (!motd)
2143       goto out;
2144
2145     motd[motd_len] = 0;
2146     silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
2147                                          SILC_STATUS_OK,
2148                                          2, motd, motd_len);
2149     goto out;
2150   } else {
2151     /* No motd */
2152     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
2153                                           SILC_STATUS_OK);
2154   }
2155
2156  out:
2157   silc_server_command_free(cmd);
2158 }
2159
2160 SILC_SERVER_CMD_FUNC(umode)
2161 {
2162 }
2163
2164 /* Checks that client has rights to add or remove channel modes. If any
2165    of the checks fails FALSE is returned. */
2166
2167 int silc_server_check_cmode_rights(SilcChannelEntry channel,
2168                                    SilcChannelClientEntry client,
2169                                    unsigned int mode)
2170 {
2171   int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
2172   int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
2173
2174   /* Check whether has rights to change anything */
2175   if (!is_op && !is_fo)
2176     return FALSE;
2177
2178   /* Check whether has rights to change everything */
2179   if (is_op && is_fo)
2180     return TRUE;
2181
2182   /* We know that client is channel operator, check that they are not
2183      changing anything that requires channel founder rights. Rest of the
2184      modes are available automatically for channel operator. */
2185
2186   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
2187     if (is_op && !is_fo)
2188       return FALSE;
2189   } else {
2190     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2191       if (is_op && !is_fo)
2192         return FALSE;
2193     }
2194   }
2195   
2196   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2197     if (is_op && !is_fo)
2198       return FALSE;
2199   } else {
2200     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2201       if (is_op && !is_fo)
2202         return FALSE;
2203     }
2204   }
2205
2206   if (mode & SILC_CHANNEL_MODE_CIPHER) {
2207     if (is_op && !is_fo)
2208       return FALSE;
2209   } else {
2210     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2211       if (is_op && !is_fo)
2212         return FALSE;
2213     }
2214   }
2215   
2216   return TRUE;
2217 }
2218
2219 /* Server side command of CMODE. Changes channel mode */
2220
2221 SILC_SERVER_CMD_FUNC(cmode)
2222 {
2223   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2224   SilcServer server = cmd->server;
2225   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2226   SilcChannelID *channel_id;
2227   SilcChannelEntry channel;
2228   SilcChannelClientEntry chl;
2229   SilcBuffer packet, cidp;
2230   unsigned char *tmp, *tmp_id, *tmp_mask;
2231   unsigned int argc, mode_mask, tmp_len, tmp_len2;
2232
2233   SILC_LOG_DEBUG(("Start"));
2234
2235   argc = silc_argument_get_arg_num(cmd->args);
2236   if (argc < 2) {
2237     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2238                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2239     goto out;
2240   }
2241   if (argc > 8) {
2242     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2243                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2244     goto out;
2245   }
2246
2247   /* Get Channel ID */
2248   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
2249   if (!tmp_id) {
2250     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2251                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2252     goto out;
2253   }
2254   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
2255   if (!channel_id) {
2256     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2257                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2258     goto out;
2259   }
2260
2261   /* Get the channel mode mask */
2262   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2263   if (!tmp_mask) {
2264     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2265                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2266     goto out;
2267   }
2268   SILC_GET32_MSB(mode_mask, tmp_mask);
2269
2270   /* Get channel entry */
2271   channel = silc_idlist_find_channel_by_id(server->local_list, 
2272                                            channel_id, NULL);
2273   if (!channel) {
2274     channel = silc_idlist_find_channel_by_id(server->global_list, 
2275                                              channel_id, NULL);
2276     if (!channel) {
2277       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2278                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2279       goto out;
2280     }
2281   }
2282
2283   /* Check whether this client is on the channel */
2284   if (!silc_server_client_on_channel(client, channel)) {
2285     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2286                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2287     goto out;
2288   }
2289
2290   /* Get entry to the channel user list */
2291   silc_list_start(channel->user_list);
2292   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2293     if (chl->client == client)
2294       break;
2295
2296   /* Check that client has rights to change any requested channel modes */
2297   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
2298     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2299                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2300     goto out;
2301   }
2302
2303   /*
2304    * Check the modes. Modes that requires nothing special operation are
2305    * not checked here.
2306    */
2307
2308   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
2309     /* Channel uses private keys to protect traffic. Client(s) has set the
2310        key locally they want to use, server does not know that key. */
2311     /* Nothing interesting to do here now */
2312   } else {
2313     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2314       /* The mode is removed and we need to generate and distribute
2315          new channel key. Clients are not using private channel keys
2316          anymore after this. */
2317
2318       /* XXX Duplicated code, make own function for this!! LEAVE uses this
2319          as well */
2320
2321       /* Re-generate channel key */
2322       silc_server_create_channel_key(server, channel, 0);
2323       
2324       /* Encode channel key payload to be distributed on the channel */
2325       packet = 
2326         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2327                                         strlen(channel->channel_key->
2328                                                cipher->name),
2329                                         channel->channel_key->cipher->name,
2330                                         channel->key_len / 8, channel->key);
2331       
2332       /* If we are normal server then we will send it to our router.  If we
2333          are router we will send it to all local servers that has clients on
2334          the channel */
2335       if (server->server_type == SILC_SERVER) {
2336         if (!server->standalone)
2337           silc_server_packet_send(server, 
2338                                   cmd->server->router->connection,
2339                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2340                                   packet->len, TRUE);
2341       } else {
2342         
2343       }
2344       
2345       /* Send to locally connected clients on the channel */
2346       silc_server_packet_send_local_channel(server, channel, 
2347                                             SILC_PACKET_CHANNEL_KEY, 0,
2348                                             packet->data, packet->len, FALSE);
2349       silc_buffer_free(packet);
2350     }
2351   }
2352   
2353   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
2354     /* User limit is set on channel */
2355     unsigned int user_limit;
2356       
2357     /* Get user limit */
2358     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
2359     if (!tmp) {
2360       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
2361         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2362                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2363         goto out;
2364       }
2365     } else {
2366       SILC_GET32_MSB(user_limit, tmp);
2367       channel->mode_data.user_limit = user_limit;
2368     }
2369   } else {
2370     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
2371       /* User limit mode is unset. Remove user limit */
2372       channel->mode_data.user_limit = 0;
2373   }
2374
2375   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
2376     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
2377       /* Passphrase has been set to channel */
2378       
2379       /* Get the passphrase */
2380       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
2381       if (!tmp) {
2382         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2383                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2384         goto out;
2385       }
2386
2387       /* Save the passphrase */
2388       channel->mode_data.passphrase = strdup(tmp);
2389     }
2390   } else {
2391     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2392       /* Passphrase mode is unset. remove the passphrase */
2393       if (channel->mode_data.passphrase) {
2394         silc_free(channel->mode_data.passphrase);
2395         channel->mode_data.passphrase = NULL;
2396       }
2397     }
2398   }
2399
2400   if (mode_mask & SILC_CHANNEL_MODE_BAN) {
2401     if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
2402       /* Ban list is specified for channel */
2403
2404       /* Get ban list */
2405       tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
2406       if (!tmp) {
2407         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2408                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2409         goto out;
2410       }
2411
2412       /* XXX check that channel founder is not banned */
2413
2414       /* Save the ban list */
2415       channel->mode_data.ban_list = strdup(tmp);
2416     }
2417   } else {
2418     if (channel->mode & SILC_CHANNEL_MODE_BAN) {
2419       /* Ban mode is unset. Remove the entire ban list */
2420       if (channel->mode_data.ban_list) {
2421         silc_free(channel->mode_data.ban_list);
2422         channel->mode_data.ban_list = NULL;
2423       }
2424     }
2425   }
2426
2427   if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
2428     if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
2429       /* Invite list is specified for channel */
2430
2431       /* Get invite list */
2432       tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
2433       if (!tmp) {
2434         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2435                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2436         goto out;
2437       }
2438
2439       /* Save the invite linst */
2440       channel->mode_data.invite_list = strdup(tmp);
2441     }
2442   } else {
2443     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
2444       /* Invite list mode is unset. Remove the entire invite list */
2445       if (channel->mode_data.invite_list) {
2446         silc_free(channel->mode_data.invite_list);
2447         channel->mode_data.invite_list = NULL;
2448       }
2449     }
2450   }
2451
2452   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
2453     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
2454       /* Cipher to use protect the traffic */
2455       unsigned int key_len;
2456
2457       /* Get cipher */
2458       tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
2459       if (!tmp) {
2460         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2461                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2462         goto out;
2463       }
2464
2465       /* XXX Duplicated code, make own function for this!! */
2466     
2467       /* Delete old cipher and allocate the new one */
2468       silc_cipher_free(channel->channel_key);
2469       if (!silc_cipher_alloc(tmp, &channel->channel_key)) {
2470         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2471                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
2472         goto out;
2473       }
2474       key_len = silc_cipher_get_key_len(channel->channel_key) / 8;
2475
2476       /* Re-generate channel key */
2477       silc_server_create_channel_key(server, channel, key_len);
2478     
2479       /* Encode channel key payload to be distributed on the channel */
2480       packet = 
2481         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2482                                         strlen(channel->channel_key->
2483                                                cipher->name),
2484                                         channel->channel_key->cipher->name,
2485                                         channel->key_len / 8, channel->key);
2486     
2487       /* If we are normal server then we will send it to our router.  If we
2488          are router we will send it to all local servers that has clients on
2489          the channel */
2490       if (server->server_type == SILC_SERVER) {
2491         if (!server->standalone)
2492           silc_server_packet_send(server, 
2493                                   cmd->server->router->connection,
2494                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2495                                   packet->len, TRUE);
2496       } else {
2497         
2498       }
2499     
2500       /* Send to locally connected clients on the channel */
2501       silc_server_packet_send_local_channel(server, channel, 
2502                                             SILC_PACKET_CHANNEL_KEY, 0,
2503                                           packet->data, packet->len, FALSE);
2504       silc_buffer_free(packet);
2505     }
2506   } else {
2507     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2508       /* Cipher mode is unset. Remove the cipher and revert back to 
2509          default cipher */
2510
2511       if (channel->mode_data.cipher) {
2512         silc_free(channel->mode_data.cipher);
2513         channel->mode_data.cipher = NULL;
2514         channel->mode_data.key_len = 0;
2515       }
2516
2517       /* Generate new cipher and key for the channel */
2518
2519       /* XXX Duplicated code, make own function for this!! */
2520
2521       /* Delete old cipher and allocate default one */
2522       silc_cipher_free(channel->channel_key);
2523       if (!channel->cipher)
2524         silc_cipher_alloc("aes-256-cbc", &channel->channel_key);
2525       else {
2526         if (!silc_cipher_alloc(channel->cipher, &channel->channel_key)) {
2527           silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2528                                   SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
2529           goto out;
2530         }
2531       }
2532
2533       /* Re-generate channel key */
2534       silc_server_create_channel_key(server, channel, 0);
2535       
2536       /* Encode channel key payload to be distributed on the channel */
2537       packet = 
2538         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2539                                         strlen(channel->channel_key->
2540                                                cipher->name),
2541                                         channel->channel_key->cipher->name,
2542                                         channel->key_len / 8, channel->key);
2543       
2544       /* If we are normal server then we will send it to our router.  If we
2545          are router we will send it to all local servers that has clients on
2546          the channel */
2547       if (server->server_type == SILC_SERVER) {
2548         if (!server->standalone)
2549           silc_server_packet_send(server, 
2550                                   cmd->server->router->connection,
2551                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2552                                   packet->len, TRUE);
2553       } else {
2554         
2555       }
2556       
2557       /* Send to locally connected clients on the channel */
2558       silc_server_packet_send_local_channel(server, channel, 
2559                                             SILC_PACKET_CHANNEL_KEY, 0,
2560                                             packet->data, packet->len, FALSE);
2561       silc_buffer_free(packet);
2562     }
2563   }
2564
2565   /* Finally, set the mode */
2566   channel->mode = mode_mask;
2567
2568   /* Send CMODE_CHANGE notify */
2569   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2570   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
2571                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
2572                                      cidp->data, cidp->len, 
2573                                      tmp_mask, tmp_len);
2574
2575   /* Set CMODE notify type to network */
2576   if (!server->standalone)
2577     silc_server_send_notify_cmode(server, server->router->connection,
2578                                   server->server_type == SILC_ROUTER ? 
2579                                   TRUE : FALSE, channel,
2580                                   mode_mask, client->id, SILC_ID_CLIENT_LEN);
2581
2582   /* Send command reply to sender */
2583   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
2584                                                 SILC_STATUS_OK, 0, 1,
2585                                                 2, tmp_mask, 4);
2586   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2587                           packet->data, packet->len, FALSE);
2588     
2589   silc_buffer_free(packet);
2590   silc_free(channel_id);
2591   silc_free(cidp);
2592
2593  out:
2594   silc_server_command_free(cmd);
2595 }
2596
2597 /* Server side of CUMODE command. Changes client's mode on a channel. */
2598
2599 SILC_SERVER_CMD_FUNC(cumode)
2600 {
2601   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2602   SilcServer server = cmd->server;
2603   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2604   SilcChannelID *channel_id;
2605   SilcClientID *client_id;
2606   SilcChannelEntry channel;
2607   SilcClientEntry target_client;
2608   SilcChannelClientEntry chl;
2609   SilcBuffer packet, idp;
2610   unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
2611   unsigned int target_mask, sender_mask, tmp_len, tmp_ch_len;
2612   int notify = FALSE;
2613
2614   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
2615
2616   /* Get Channel ID */
2617   tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
2618   if (!tmp_ch_id) {
2619     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2620                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2621     goto out;
2622   }
2623   channel_id = silc_id_payload_parse_id(tmp_ch_id, tmp_ch_len);
2624   if (!channel_id) {
2625     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2626                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2627     goto out;
2628   }
2629
2630   /* Get channel entry */
2631   channel = silc_idlist_find_channel_by_id(server->local_list, 
2632                                            channel_id, NULL);
2633   if (!channel) {
2634     channel = silc_idlist_find_channel_by_id(server->global_list, 
2635                                              channel_id, NULL);
2636     if (!channel) {
2637       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2638                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2639       goto out;
2640     }
2641   }
2642
2643   /* Check whether sender is on the channel */
2644   if (!silc_server_client_on_channel(client, channel)) {
2645     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2646                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2647     goto out;
2648   }
2649
2650   /* Check that client has rights to change other's rights */
2651   silc_list_start(channel->user_list);
2652   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2653     if (chl->client == client) {
2654       if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
2655           !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2656         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2657                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2658         goto out;
2659       }
2660
2661       sender_mask = chl->mode;
2662       break;
2663     }
2664   }
2665   
2666   /* Get the target client's channel mode mask */
2667   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
2668   if (!tmp_mask) {
2669     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2670                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2671     goto out;
2672   }
2673   SILC_GET32_MSB(target_mask, tmp_mask);
2674
2675   /* Get target Client ID */
2676   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2677   if (!tmp_id) {
2678     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2679                                           SILC_STATUS_ERR_NO_CLIENT_ID);
2680     goto out;
2681   }
2682   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2683   if (!client_id) {
2684     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2685                                           SILC_STATUS_ERR_NO_CLIENT_ID);
2686     goto out;
2687   }
2688
2689   /* Get target client's entry */
2690   target_client = silc_idlist_find_client_by_id(server->local_list, 
2691                                                 client_id, NULL);
2692   if (!target_client) {
2693     target_client = silc_idlist_find_client_by_id(server->global_list, 
2694                                                   client_id, NULL);
2695   }
2696
2697   /* Check whether target client is on the channel */
2698   if (!silc_server_client_on_channel(target_client, channel)) {
2699     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2700                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
2701     goto out;
2702   }
2703
2704   /* Get entry to the channel user list */
2705   silc_list_start(channel->user_list);
2706   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2707     if (chl->client == target_client)
2708       break;
2709
2710   /* 
2711    * Change the mode 
2712    */
2713
2714   /* If the target client is founder, no one else can change their mode
2715      but themselves. */
2716   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
2717     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2718                                           SILC_STATUS_ERR_NOT_YOU);
2719     goto out;
2720   }
2721
2722   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
2723     /* Cannot promote anyone to channel founder */
2724     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2725                                           SILC_STATUS_ERR_NOT_YOU);
2726     goto out;
2727   } else {
2728     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
2729       if (target_client == client) {
2730         /* Remove channel founder rights from itself */
2731         chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
2732         notify = TRUE;
2733       } else {
2734         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2735                                               SILC_STATUS_ERR_NOT_YOU);
2736         goto out;
2737       }
2738     }
2739   }
2740
2741   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
2742     /* Promote to operator */
2743     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2744       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
2745       notify = TRUE;
2746     }
2747   } else {
2748     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
2749       /* Demote to normal user */
2750       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
2751       notify = TRUE;
2752     }
2753   }
2754
2755   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2756
2757   /* Send notify to channel, notify only if mode was actually changed. */
2758   if (notify) {
2759     silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
2760                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
2761                                        idp->data, idp->len,
2762                                        tmp_mask, 4, 
2763                                        tmp_id, tmp_len);
2764
2765     /* Set CUMODE notify type to network */
2766     if (!server->standalone)
2767       silc_server_send_notify_cumode(server, server->router->connection,
2768                                      server->server_type == SILC_ROUTER ? 
2769                                      TRUE : FALSE, channel,
2770                                      target_mask, client->id, 
2771                                      SILC_ID_CLIENT_LEN,
2772                                      target_client->id, 
2773                                      SILC_ID_CLIENT_LEN);
2774   }
2775
2776   /* Send command reply to sender */
2777   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
2778                                                 SILC_STATUS_OK, 0, 2,
2779                                                 2, tmp_mask, 4,
2780                                                 3, tmp_id, tmp_len);
2781   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2782                           packet->data, packet->len, FALSE);
2783     
2784   silc_buffer_free(packet);
2785   silc_free(channel_id);
2786   silc_free(client_id);
2787   silc_buffer_free(idp);
2788
2789  out:
2790   silc_server_command_free(cmd);
2791 }
2792
2793 /* Server side of KICK command. Kicks client out of channel. */
2794
2795 SILC_SERVER_CMD_FUNC(kick)
2796 {
2797   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2798   SilcServer server = cmd->server;
2799   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2800   SilcClientEntry target_client;
2801   SilcChannelID *channel_id;
2802   SilcClientID *client_id;
2803   SilcChannelEntry channel;
2804   SilcChannelClientEntry chl;
2805   SilcBuffer idp;
2806   unsigned int tmp_len;
2807   unsigned char *tmp, *comment;
2808
2809   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 3);
2810
2811   /* Get Channel ID */
2812   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2813   if (!tmp) {
2814     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
2815                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2816     goto out;
2817   }
2818   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
2819   if (!channel_id) {
2820     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
2821                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2822     goto out;
2823   }
2824
2825   /* Get channel entry */
2826   channel = silc_idlist_find_channel_by_id(server->local_list, 
2827                                            channel_id, NULL);
2828   if (!channel) {
2829     channel = silc_idlist_find_channel_by_id(server->local_list, 
2830                                              channel_id, NULL);
2831     if (!channel) {
2832       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
2833                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2834       goto out;
2835     }
2836   }
2837
2838   /* Check whether sender is on the channel */
2839   if (!silc_server_client_on_channel(client, channel)) {
2840     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
2841                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2842     goto out;
2843   }
2844
2845   /* Check that the kicker is channel operator or channel founder */
2846   silc_list_start(channel->user_list);
2847   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2848     if (chl->client == client) {
2849       if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
2850         silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
2851                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2852         goto out;
2853       }
2854       break;
2855     }
2856   }
2857   
2858   /* Get target Client ID */
2859   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2860   if (!tmp) {
2861     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
2862                                           SILC_STATUS_ERR_NO_CLIENT_ID);
2863     goto out;
2864   }
2865   client_id = silc_id_payload_parse_id(tmp, tmp_len);
2866   if (!client_id) {
2867     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
2868                                           SILC_STATUS_ERR_NO_CLIENT_ID);
2869     goto out;
2870   }
2871
2872   /* Get target client's entry */
2873   target_client = silc_idlist_find_client_by_id(server->local_list, 
2874                                                 client_id, NULL);
2875   if (!target_client) {
2876     target_client = silc_idlist_find_client_by_id(server->global_list, 
2877                                                   client_id, NULL);
2878   }
2879
2880   /* Check that the target client is not channel founder. Channel founder
2881      cannot be kicked from the channel. */
2882   silc_list_start(channel->user_list);
2883   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2884     if (chl->client == target_client) {
2885       if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
2886         silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
2887                                   SILC_STATUS_ERR_NO_CHANNEL_FOPRIV);
2888         goto out;
2889       }
2890       break;
2891     }
2892   }
2893   
2894   /* Check whether target client is on the channel */
2895   if (!silc_server_client_on_channel(target_client, channel)) {
2896     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
2897                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
2898     goto out;
2899   }
2900
2901   /* Get comment */
2902   tmp_len = 0;
2903   comment = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2904   if (tmp_len > 128)
2905     comment = NULL;
2906
2907   /* Send command reply to sender */
2908   silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK, 
2909                                         SILC_STATUS_OK);
2910
2911   /* Send KICKED notify to local clients on the channel */
2912   idp = silc_id_payload_encode(target_client->id, SILC_ID_CLIENT);
2913   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
2914                                      SILC_NOTIFY_TYPE_KICKED, 
2915                                      comment ? 2 : 1,
2916                                      idp->data, idp->len,
2917                                      comment, comment ? strlen(comment) : 0);
2918   silc_buffer_free(idp);
2919
2920   /* Remove the client from the channel. If the channel does not exist
2921      after removing the client then the client kicked itself of the channel
2922      and we don't have to send anything after that. */
2923   if (!silc_server_remove_from_one_channel(server, NULL, channel, 
2924                                            target_client, FALSE))
2925     goto out;
2926
2927   /* Send KICKED notify to primary route */
2928   if (!server->standalone)
2929     silc_server_send_notify_kicked(server, server->router->connection,
2930                                    server->server_type == SILC_ROUTER ?
2931                                    TRUE : FALSE, channel,
2932                                    target_client->id, SILC_ID_CLIENT_LEN,
2933                                    comment);
2934
2935   /* Re-generate channel key */
2936   silc_server_create_channel_key(server, channel, 0);
2937
2938   /* Send the channel key to the channel. The key of course is not sent
2939      to the client who joined the channel. */
2940   silc_server_send_channel_key(server, target_client->connection, channel, 
2941                                server->server_type == SILC_ROUTER ? 
2942                                FALSE : !server->standalone);
2943
2944  out:
2945   silc_server_command_free(cmd);
2946 }
2947
2948 SILC_SERVER_CMD_FUNC(oper)
2949 {
2950 }
2951
2952 SILC_SERVER_CMD_FUNC(silcoper)
2953 {
2954 }
2955
2956 /* Server side command of CONNECT. Connects us to the specified remote
2957    server or router. */
2958
2959 SILC_SERVER_CMD_FUNC(connect)
2960 {
2961   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2962   SilcServer server = cmd->server;
2963   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2964   unsigned char *tmp;
2965   unsigned int tmp_len;
2966   unsigned int port = SILC_PORT;
2967
2968   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CONNECT, cmd, 1, 2);
2969
2970   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
2971     goto out;
2972
2973   /* Check whether client has the permissions. */
2974   if (client->mode == SILC_UMODE_NONE) {
2975     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
2976                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
2977     goto out;
2978   }
2979
2980   if (server->server_type == SILC_ROUTER && 
2981       client->mode & SILC_UMODE_SERVER_OPERATOR) {
2982     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
2983                                           SILC_STATUS_ERR_NO_ROUTER_PRIV);
2984     goto out;
2985   }
2986
2987   /* Get the remote server */
2988   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2989   if (!tmp) {
2990     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
2991                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2992     goto out;
2993   }
2994
2995   /* Get port */
2996   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2997   if (tmp)
2998     SILC_GET32_MSB(port, tmp);
2999
3000   /* Create the connection. It is done with timeout and is async. */
3001   silc_server_create_connection(server, tmp, port);
3002
3003   /* Send reply to the sender */
3004   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
3005                                         SILC_STATUS_OK);
3006
3007  out:
3008   silc_server_command_free(cmd);
3009 }
3010
3011 SILC_SERVER_CMD_FUNC(restart)
3012 {
3013 }
3014
3015 /* Server side command of CLOSE. Closes connection to a specified server. */
3016  
3017 SILC_SERVER_CMD_FUNC(close)
3018 {
3019   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3020   SilcServer server = cmd->server;
3021   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3022   SilcServerEntry server_entry;
3023   unsigned char *tmp;
3024   unsigned int tmp_len;
3025   unsigned char *name;
3026   unsigned int port = SILC_PORT;
3027
3028   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CLOSE, cmd, 1, 2);
3029
3030   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
3031     goto out;
3032
3033   /* Check whether client has the permissions. */
3034   if (client->mode == SILC_UMODE_NONE) {
3035     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
3036                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
3037     goto out;
3038   }
3039
3040   /* Get the remote server */
3041   name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3042   if (!name) {
3043     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
3044                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3045     goto out;
3046   }
3047
3048   /* Get port */
3049   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
3050   if (tmp)
3051     SILC_GET32_MSB(port, tmp);
3052
3053   server_entry = silc_idlist_find_server_by_conn(server->local_list,
3054                                                  name, port, NULL);
3055   if (!server_entry) {
3056     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
3057                                           SILC_STATUS_ERR_NO_SERVER_ID);
3058     goto out;
3059   }
3060
3061   /* Close the connection to the server */
3062   silc_server_free_sock_user_data(server, server_entry->connection);
3063   silc_server_disconnect_remote(server, server_entry->connection,
3064                                 "Server closed connection: "
3065                                 "Closed by operator");
3066   
3067   /* Send reply to the sender */
3068   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
3069                                         SILC_STATUS_OK);
3070
3071  out:
3072   silc_server_command_free(cmd);
3073 }
3074
3075 /* Server side command of SHUTDOWN. Shutdowns the server and closes all
3076    active connections. */
3077  
3078 SILC_SERVER_CMD_FUNC(shutdown)
3079 {
3080   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3081   SilcServer server = cmd->server;
3082   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3083
3084   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SHUTDOWN, cmd, 0, 0);
3085
3086   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
3087     goto out;
3088
3089   /* Check whether client has the permission. */
3090   if (client->mode == SILC_UMODE_NONE) {
3091     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
3092                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
3093     goto out;
3094   }
3095
3096   /* Then, gracefully, or not, bring the server down. */
3097   silc_server_stop(server);
3098
3099   /* Send reply to the sender */
3100   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
3101                                         SILC_STATUS_OK);
3102
3103  out:
3104   silc_server_command_free(cmd);
3105 }
3106  
3107 /* Server side command of LEAVE. Removes client from a channel. */
3108
3109 SILC_SERVER_CMD_FUNC(leave)
3110 {
3111   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3112   SilcServer server = cmd->server;
3113   SilcSocketConnection sock = cmd->sock;
3114   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
3115   SilcChannelID *id;
3116   SilcChannelEntry channel;
3117   SilcBuffer packet;
3118   unsigned int i, len;
3119   unsigned char *tmp;
3120
3121   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
3122
3123   /* Get Channel ID */
3124   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
3125   if (!tmp) {
3126     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
3127                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3128     goto out;
3129   }
3130   id = silc_id_payload_parse_id(tmp, len);
3131   if (!id) {
3132     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
3133                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3134     goto out;
3135   }
3136
3137   /* Get channel entry */
3138   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
3139   if (!channel) {
3140     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
3141     if (!channel) {
3142       silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
3143                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
3144       goto out;
3145     }
3146   }
3147
3148   /* Check whether this client is on the channel */
3149   if (!silc_server_client_on_channel(id_entry, channel)) {
3150     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
3151                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
3152     goto out;
3153   }
3154
3155   /* Notify routers that they should remove this client from their list
3156      of clients on the channel. Send LEAVE notify type. */
3157   if (!server->standalone)
3158     silc_server_send_notify_leave(server, server->router->connection,
3159                                   server->server_type == SILC_ROUTER ?
3160                                   TRUE : FALSE, channel, id_entry->id,
3161                                   SILC_ID_CLIENT_LEN);
3162
3163   /* Remove client from channel */
3164   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
3165                                           TRUE);
3166   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
3167                                         SILC_STATUS_OK);
3168
3169   /* If the channel does not exist anymore we won't send anything */
3170   if (!i)
3171     goto out;
3172
3173   /* Re-generate channel key */
3174   silc_server_create_channel_key(server, channel, 0);
3175
3176   /* Encode channel key payload to be distributed on the channel */
3177   packet = 
3178     silc_channel_key_payload_encode(len, tmp,
3179                                     strlen(channel->channel_key->cipher->name),
3180                                     channel->channel_key->cipher->name,
3181                                     channel->key_len / 8, channel->key);
3182
3183   /* If we are normal server then we will send it to our router.  If we
3184      are router we will send it to all local servers that has clients on
3185      the channel */
3186   if (server->server_type == SILC_SERVER) {
3187     if (!server->standalone)
3188       silc_server_packet_send(server, 
3189                               cmd->server->router->connection,
3190                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
3191                               packet->len, FALSE);
3192   } else {
3193
3194   }
3195
3196   /* Send to locally connected clients on the channel */
3197   silc_server_packet_send_local_channel(server, channel, 
3198                                         SILC_PACKET_CHANNEL_KEY, 0,
3199                                         packet->data, packet->len, FALSE);
3200
3201   silc_buffer_free(packet);
3202   silc_free(id);
3203
3204  out:
3205   silc_server_command_free(cmd);
3206 }
3207
3208 /* Server side of command USERS. Resolves clients and their USERS currently
3209    joined on the requested channel. The list of Client ID's and their modes
3210    on the channel is sent back. */
3211
3212 SILC_SERVER_CMD_FUNC(users)
3213 {
3214   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3215   SilcServer server = cmd->server;
3216   SilcChannelEntry channel;
3217   SilcChannelID *id;
3218   SilcBuffer packet;
3219   unsigned char *channel_id;
3220   unsigned int channel_id_len;
3221   SilcBuffer client_id_list;
3222   SilcBuffer client_mode_list;
3223   unsigned char lc[4];
3224   unsigned int list_count = 0;
3225   unsigned short ident = silc_command_get_ident(cmd->payload);
3226
3227   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
3228
3229   /* Get Channel ID */
3230   channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
3231   if (!channel_id) {
3232     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
3233                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3234     goto out;
3235   }
3236   id = silc_id_payload_parse_id(channel_id, channel_id_len);
3237   if (!id) {
3238     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
3239                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3240     goto out;
3241   }
3242
3243   /* If we are server and we don't know about this channel we will send
3244      the command to our router. If we know about the channel then we also
3245      have the list of users already. */
3246   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
3247   if (!channel) {
3248     if (server->server_type == SILC_SERVER && !server->standalone &&
3249         !cmd->pending) {
3250       SilcBuffer tmpbuf;
3251       
3252       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
3253       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3254       
3255       /* Send USERS command */
3256       silc_server_packet_send(server, server->router->connection,
3257                               SILC_PACKET_COMMAND, cmd->packet->flags,
3258                               tmpbuf->data, tmpbuf->len, TRUE);
3259       
3260       /* Reprocess this packet after received reply */
3261       silc_server_command_pending(server, SILC_COMMAND_USERS, 
3262                                   silc_command_get_ident(cmd->payload),
3263                                   silc_server_command_destructor,
3264                                   silc_server_command_users,
3265                                   silc_server_command_dup(cmd));
3266       cmd->pending = TRUE;
3267       silc_command_set_ident(cmd->payload, ident);
3268       
3269       silc_buffer_free(tmpbuf);
3270       silc_free(id);
3271       return;
3272     }
3273
3274     /* We are router and we will check the global list as well. */
3275     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
3276     if (!channel) {
3277       /* Channel really does not exist */
3278       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
3279                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
3280       goto out;
3281     }
3282   }
3283
3284   /* Get the users list */
3285   silc_server_get_users_on_channel(server, channel, &client_id_list,
3286                                    &client_mode_list, &list_count);
3287
3288   /* List count */
3289   SILC_PUT32_MSB(list_count, lc);
3290
3291   /* Send reply */
3292   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
3293                                                 SILC_STATUS_OK, 0, 4,
3294                                                 2, channel_id, channel_id_len,
3295                                                 3, lc, 4,
3296                                                 4, client_id_list->data,
3297                                                 client_id_list->len,
3298                                                 5, client_mode_list->data,
3299                                                 client_mode_list->len);
3300   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3301                           packet->data, packet->len, FALSE);
3302     
3303   silc_buffer_free(packet);
3304   silc_buffer_free(client_id_list);
3305   silc_buffer_free(client_mode_list);
3306   silc_free(id);
3307
3308  out:
3309   silc_server_command_free(cmd);
3310 }