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