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