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