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