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