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