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