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