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