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