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