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