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