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