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