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