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