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], TRUE, NULL);
773       if (!entry && check_global)
774         entry = silc_idlist_find_client_by_id(server->global_list, 
775                                               client_id[i], TRUE, 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, TRUE, NULL);
1254       if (!entry && check_global)
1255         entry = silc_idlist_find_server_by_name(server->local_list,
1256                                                 tmp, TRUE, 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, TRUE, NULL);
1327         if (!entry && check_global)
1328           entry = (void *)silc_idlist_find_client_by_id(server->global_list, 
1329                                                         id, TRUE, 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, TRUE, NULL);
1346         if (!entry && check_global)
1347           entry = (void *)silc_idlist_find_server_by_id(server->global_list, 
1348                                                         id, TRUE, 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   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1811
1812   /* Remove old cache entry */
1813   silc_idcache_del_by_context(server->local_list->clients, client);
1814
1815   /* Free old ID */
1816   silc_free(client->id);
1817
1818   /* Save the nickname as this client is our local client */
1819   silc_free(client->nickname);
1820
1821   client->nickname = strdup(nick);
1822   client->id = new_id;
1823
1824   /* Update client cache */
1825   silc_idcache_add(server->local_list->clients, client->nickname, 
1826                    client->id, (void *)client, FALSE);
1827
1828   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1829
1830   /* Send NICK_CHANGE notify to the client's channels */
1831   silc_server_send_notify_on_channels(server, NULL, client, 
1832                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
1833                                       oidp->data, oidp->len, 
1834                                       nidp->data, nidp->len);
1835
1836   /* Send the new Client ID as reply command back to client */
1837   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
1838                                                 SILC_STATUS_OK, ident, 1, 
1839                                                 2, nidp->data, nidp->len);
1840   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1841                           0, packet->data, packet->len, FALSE);
1842
1843   silc_buffer_free(packet);
1844   silc_buffer_free(nidp);
1845   silc_buffer_free(oidp);
1846   
1847  out:
1848   silc_server_command_free(cmd);
1849 }
1850
1851 /* Sends the LIST command reply */
1852
1853 static void
1854 silc_server_command_list_send_reply(SilcServerCommandContext cmd,
1855                                     SilcChannelEntry *lch, 
1856                                     uint32 lch_count,
1857                                     SilcChannelEntry *gch,
1858                                     uint32 gch_count)
1859 {
1860   int i;
1861   SilcBuffer packet, idp;
1862   SilcChannelEntry entry;
1863   SilcCommandStatus status;
1864   uint16 ident = silc_command_get_ident(cmd->payload);
1865   char *topic;
1866   unsigned char usercount[4];
1867   uint32 users;
1868
1869   for (i = 0; i < lch_count; i++)
1870     if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
1871       lch[i] = NULL;
1872   for (i = 0; i < gch_count; i++)
1873     if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
1874       gch[i] = NULL;
1875
1876   status = SILC_STATUS_OK;
1877   if ((lch_count + gch_count) > 1)
1878     status = SILC_STATUS_LIST_START;
1879
1880   /* Local list */
1881   for (i = 0; i < lch_count; i++) {
1882     entry = lch[i];
1883
1884     if (!entry)
1885       continue;
1886
1887     if (i >= 1)
1888       status = SILC_STATUS_LIST_ITEM;
1889
1890     if (i == lch_count - 1 && gch_count)
1891       break;
1892     if (lch_count > 1 && i == lch_count - 1)
1893       status = SILC_STATUS_LIST_END;
1894
1895     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1896
1897     if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
1898       topic = "*private*";
1899       memset(usercount, 0, sizeof(usercount));
1900     } else {
1901       topic = entry->topic;
1902       users = silc_hash_table_count(entry->user_list);
1903       SILC_PUT32_MSB(users, usercount);
1904     }
1905
1906     /* Send the reply */
1907     if (topic)
1908       packet = 
1909         silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
1910                                              status, ident, 4, 
1911                                              2, idp->data, idp->len,
1912                                              3, entry->channel_name, 
1913                                              strlen(entry->channel_name),
1914                                              4, topic, strlen(topic),
1915                                              5, usercount, 4);
1916     else
1917       packet = 
1918         silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
1919                                              status, ident, 3, 
1920                                              2, idp->data, idp->len,
1921                                              3, entry->channel_name, 
1922                                              strlen(entry->channel_name),
1923                                              5, usercount, 4);
1924     silc_server_packet_send(cmd->server, cmd->sock, 
1925                             SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
1926                             packet->len, FALSE);
1927     silc_buffer_free(packet);
1928     silc_buffer_free(idp);
1929   }
1930
1931   status = i ? SILC_STATUS_LIST_ITEM : SILC_STATUS_OK;
1932
1933   /* Global list */
1934   for (i = 0; i < gch_count; i++) {
1935     entry = gch[i];
1936
1937     if (!entry)
1938       continue;
1939
1940     if (i >= 1)
1941       status = SILC_STATUS_LIST_ITEM;
1942
1943     if (gch_count > 1 && i == lch_count - 1)
1944       status = SILC_STATUS_LIST_END;
1945
1946     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1947
1948     if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
1949       topic = "*private*";
1950       memset(usercount, 0, sizeof(usercount));
1951     } else {
1952       topic = entry->topic;
1953       users = silc_hash_table_count(entry->user_list);
1954       SILC_PUT32_MSB(users, usercount);
1955     }
1956
1957     /* Send the reply */
1958     if (topic)
1959       packet = 
1960         silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
1961                                              status, ident, 4, 
1962                                              2, idp->data, idp->len,
1963                                              3, entry->channel_name, 
1964                                              strlen(entry->channel_name),
1965                                              4, topic, strlen(topic),
1966                                              5, usercount, 4);
1967     else
1968       packet = 
1969         silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
1970                                              status, ident, 3, 
1971                                              2, idp->data, idp->len,
1972                                              3, entry->channel_name, 
1973                                              strlen(entry->channel_name),
1974                                              5, usercount, 4);
1975     silc_server_packet_send(cmd->server, cmd->sock, 
1976                             SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
1977                             packet->len, FALSE);
1978     silc_buffer_free(packet);
1979     silc_buffer_free(idp);
1980   }
1981 }
1982
1983 /* Server side of LIST command. This lists the channel of the requested
1984    server. Secret channels are not listed. */
1985
1986 SILC_SERVER_CMD_FUNC(list)
1987 {
1988   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1989   SilcServer server = cmd->server;
1990   SilcChannelID *channel_id = NULL;
1991   unsigned char *tmp;
1992   uint32 tmp_len;
1993   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
1994   uint32 lch_count = 0, gch_count = 0;
1995
1996   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 2);
1997
1998   /* Get Channel ID */
1999   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2000   if (tmp) {
2001     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
2002     if (!channel_id) {
2003       silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
2004                                             SILC_STATUS_ERR_NO_CHANNEL_ID);
2005       goto out;
2006     }
2007   }
2008
2009   /* Get the channels from local list */
2010   lchannels = silc_idlist_get_channels(server->local_list, channel_id,
2011                                        &lch_count);
2012   
2013   /* Get the channels from global list if we are router */
2014   if (server->server_type == SILC_ROUTER) 
2015     gchannels = silc_idlist_get_channels(server->global_list, channel_id,
2016                                          &gch_count);
2017
2018   /* Send the reply */
2019   silc_server_command_list_send_reply(cmd, lchannels, lch_count, 
2020                                       gchannels, gch_count);
2021
2022  out:
2023   silc_server_command_free(cmd);
2024 }
2025
2026 /* Server side of TOPIC command. Sets topic for channel and/or returns
2027    current topic to client. */
2028
2029 SILC_SERVER_CMD_FUNC(topic)
2030 {
2031   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2032   SilcServer server = cmd->server;
2033   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2034   SilcChannelID *channel_id;
2035   SilcChannelEntry channel;
2036   SilcChannelClientEntry chl;
2037   SilcBuffer packet, idp;
2038   unsigned char *tmp;
2039   uint32 argc, tmp_len;
2040   uint16 ident = silc_command_get_ident(cmd->payload);
2041
2042   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_TOPIC, cmd, 1, 2);
2043
2044   argc = silc_argument_get_arg_num(cmd->args);
2045
2046   /* Get Channel ID */
2047   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2048   if (!tmp) {
2049     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2050                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2051     goto out;
2052   }
2053   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
2054   if (!channel_id) {
2055     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2056                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2057     goto out;
2058   }
2059
2060   /* Check whether the channel exists */
2061   channel = silc_idlist_find_channel_by_id(server->local_list, 
2062                                            channel_id, NULL);
2063   if (!channel) {
2064     channel = silc_idlist_find_channel_by_id(server->global_list, 
2065                                              channel_id, NULL);
2066     if (!channel) {
2067       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2068                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2069       goto out;
2070     }
2071   }
2072
2073   if (argc > 1) {
2074     /* Get the topic */
2075     tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
2076     if (!tmp) {
2077       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2078                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2079       goto out;
2080     }
2081
2082     if (strlen(tmp) > 256) {
2083       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2084                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2085       goto out;
2086     }
2087
2088     /* See whether the client is on channel and has rights to change topic */
2089     if (!silc_hash_table_find(channel->user_list, client, NULL, 
2090                               (void *)&chl)) {
2091       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2092                                             SILC_STATUS_ERR_NOT_ON_CHANNEL);
2093       goto out;
2094     }
2095
2096     if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
2097       if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
2098         silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2099                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2100         goto out;
2101       }
2102     }
2103
2104     /* Set the topic for channel */
2105     if (channel->topic)
2106       silc_free(channel->topic);
2107     channel->topic = strdup(tmp);
2108
2109     /* Send TOPIC_SET notify type to the network */
2110     if (!server->standalone)
2111       silc_server_send_notify_topic_set(server, server->router->connection,
2112                                         server->server_type == SILC_ROUTER ?
2113                                         TRUE : FALSE, channel, client->id,
2114                                         channel->topic);
2115
2116     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2117
2118     /* Send notify about topic change to all clients on the channel */
2119     silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
2120                                        SILC_NOTIFY_TYPE_TOPIC_SET, 2,
2121                                        idp->data, idp->len,
2122                                        channel->topic, strlen(channel->topic));
2123     silc_buffer_free(idp);
2124   }
2125
2126   /* Send the topic to client as reply packet */
2127   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
2128   if (channel->topic)
2129     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
2130                                                   SILC_STATUS_OK, ident, 2, 
2131                                                   2, idp->data, idp->len,
2132                                                   3, channel->topic, 
2133                                                   strlen(channel->topic));
2134   else
2135     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
2136                                                   SILC_STATUS_OK, ident, 1, 
2137                                                   2, idp->data, idp->len);
2138   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
2139                           0, packet->data, packet->len, FALSE);
2140
2141   silc_buffer_free(packet);
2142   silc_buffer_free(idp);
2143   silc_free(channel_id);
2144
2145  out:
2146   silc_server_command_free(cmd);
2147 }
2148
2149 /* Server side of INVITE command. Invites some client to join some channel. 
2150    This command is also used to manage the invite list of the channel. */
2151
2152 SILC_SERVER_CMD_FUNC(invite)
2153 {
2154   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2155   SilcServer server = cmd->server;
2156   SilcSocketConnection sock = cmd->sock, dest_sock;
2157   SilcChannelClientEntry chl;
2158   SilcClientEntry sender, dest;
2159   SilcClientID *dest_id = NULL;
2160   SilcChannelEntry channel;
2161   SilcChannelID *channel_id = NULL;
2162   SilcIDListData idata;
2163   SilcBuffer idp, idp2, packet;
2164   unsigned char *tmp, *add, *del;
2165   uint32 len;
2166   uint16 ident = silc_command_get_ident(cmd->payload);
2167
2168   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
2169
2170   /* Get Channel ID */
2171   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2172   if (!tmp) {
2173     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2174                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2175     goto out;
2176   }
2177   channel_id = silc_id_payload_parse_id(tmp, len);
2178   if (!channel_id) {
2179     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2180                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2181     goto out;
2182   }
2183
2184   /* Get the channel entry */
2185   channel = silc_idlist_find_channel_by_id(server->local_list, 
2186                                            channel_id, NULL);
2187   if (!channel) {
2188     channel = silc_idlist_find_channel_by_id(server->global_list, 
2189                                              channel_id, NULL);
2190     if (!channel) {
2191       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2192                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2193       goto out;
2194     }
2195   }
2196
2197   /* Check whether the sender of this command is on the channel. */
2198   sender = (SilcClientEntry)sock->user_data;
2199   if (!silc_server_client_on_channel(sender, channel)) {
2200     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2201                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2202     goto out;
2203   }
2204
2205   /* Check whether the channel is invite-only channel. If yes then the
2206      sender of this command must be at least channel operator. */
2207   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
2208     silc_hash_table_find(channel->user_list, sender, NULL, (void *)&chl);
2209     if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
2210       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2211                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2212       goto out;
2213     }
2214   }
2215
2216   /* Get destination client ID */
2217   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2218   if (tmp) {
2219     char invite[512];
2220
2221     dest_id = silc_id_payload_parse_id(tmp, len);
2222     if (!dest_id) {
2223       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2224                                             SILC_STATUS_ERR_NO_CLIENT_ID);
2225       goto out;
2226     }
2227
2228     /* Get the client entry */
2229     dest = silc_server_get_client_resolve(server, dest_id);
2230     if (!dest) {
2231       if (server->server_type == SILC_ROUTER) {
2232         silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2233                                      SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
2234         goto out;
2235       }
2236       
2237       /* The client info is being resolved. Reprocess this packet after
2238          receiving the reply to the query. */
2239       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
2240                                   server->cmd_ident,
2241                                   silc_server_command_destructor,
2242                                   silc_server_command_invite, 
2243                                   silc_server_command_dup(cmd));
2244       cmd->pending = TRUE;
2245       silc_free(channel_id);
2246       silc_free(dest_id);
2247       return;
2248     }
2249
2250     /* Check whether the requested client is already on the channel. */
2251     if (silc_server_client_on_channel(dest, channel)) {
2252       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2253                                             SILC_STATUS_ERR_USER_ON_CHANNEL);
2254       goto out;
2255     }
2256     
2257     /* Get route to the client */
2258     dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, &idata);
2259     if (!dest_sock) {
2260       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2261                                             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
2262       goto out;
2263     }
2264
2265     memset(invite, 0, sizeof(invite));
2266     strncat(invite, dest->nickname, strlen(dest->nickname));
2267     strncat(invite, "!", 1);
2268     strncat(invite, dest->username, strlen(dest->username));
2269     if (!strchr(dest->username, '@')) {
2270       strncat(invite, "@", 1);
2271       strncat(invite, cmd->sock->hostname, strlen(cmd->sock->hostname));
2272     }
2273
2274     len = strlen(invite);
2275     if (!channel->invite_list)
2276       channel->invite_list = silc_calloc(len + 2, 
2277                                          sizeof(*channel->invite_list));
2278     else
2279       channel->invite_list = silc_realloc(channel->invite_list, 
2280                                           sizeof(*channel->invite_list) * 
2281                                           (len + 
2282                                            strlen(channel->invite_list) + 2));
2283     strncat(channel->invite_list, invite, len);
2284     strncat(channel->invite_list, ",", 1);
2285
2286     /* Send notify to the client that is invited to the channel */
2287     idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
2288     idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
2289     silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, 
2290                                  SILC_ID_CLIENT,
2291                                  SILC_NOTIFY_TYPE_INVITE, 3, 
2292                                  idp->data, idp->len, 
2293                                  channel->channel_name, 
2294                                  strlen(channel->channel_name),
2295                                  idp2->data, idp2->len);
2296     silc_buffer_free(idp);
2297     silc_buffer_free(idp2);
2298   }
2299
2300   /* Add the client to the invite list of the channel */
2301   add = silc_argument_get_arg_type(cmd->args, 3, &len);
2302   if (add) {
2303     if (!channel->invite_list)
2304       channel->invite_list = silc_calloc(len + 2, 
2305                                          sizeof(*channel->invite_list));
2306     else
2307       channel->invite_list = silc_realloc(channel->invite_list, 
2308                                           sizeof(*channel->invite_list) * 
2309                                           (len + 
2310                                            strlen(channel->invite_list) + 2));
2311     if (add[len - 1] == ',')
2312       add[len - 1] = '\0';
2313     
2314     strncat(channel->invite_list, add, len);
2315     strncat(channel->invite_list, ",", 1);
2316   }
2317
2318   /* Get the invite to be removed and remove it from the list */
2319   del = silc_argument_get_arg_type(cmd->args, 4, &len);
2320   if (del && channel->invite_list) {
2321     char *start, *end, *n;
2322
2323     if (!strncmp(channel->invite_list, del, 
2324                  strlen(channel->invite_list) - 1)) {
2325       silc_free(channel->invite_list);
2326       channel->invite_list = NULL;
2327     } else {
2328       start = strstr(channel->invite_list, del);
2329       if (start && strlen(start) >= len) {
2330         end = start + len;
2331         n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n));
2332         strncat(n, channel->invite_list, start - channel->invite_list);
2333         strncat(n, end + 1, ((channel->invite_list + 
2334                               strlen(channel->invite_list)) - end) - 1);
2335         silc_free(channel->invite_list);
2336         channel->invite_list = n;
2337       }
2338     }
2339   }
2340
2341   /* Send notify to the primary router */
2342   if (!server->standalone)
2343     silc_server_send_notify_invite(server, server->router->connection,
2344                                    server->server_type == SILC_ROUTER ?
2345                                    TRUE : FALSE, channel,
2346                                    sender->id, add, del);
2347
2348   /* Send command reply */
2349   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2350
2351   if (add || del)
2352     packet = 
2353       silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
2354                                            SILC_STATUS_OK, ident, 2,
2355                                            2, tmp, len,
2356                                            3, channel->invite_list,
2357                                            channel->invite_list ?
2358                                            strlen(channel->invite_list) : 0);
2359   else
2360     packet = 
2361       silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
2362                                            SILC_STATUS_OK, ident, 1,
2363                                            2, tmp, len);
2364   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2365                           packet->data, packet->len, FALSE);
2366   silc_buffer_free(packet);
2367
2368  out:
2369   if (dest_id)
2370     silc_free(dest_id);
2371   if (channel_id)
2372     silc_free(channel_id);
2373   silc_server_command_free(cmd);
2374 }
2375
2376 typedef struct {
2377   SilcServer server;
2378   SilcSocketConnection sock;
2379   char *signoff;
2380 } *QuitInternal;
2381
2382 /* Quits connection to client. This gets called if client won't
2383    close the connection even when it has issued QUIT command. */
2384
2385 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
2386 {
2387   QuitInternal q = (QuitInternal)context;
2388
2389   /* Free all client specific data, such as client entry and entires
2390      on channels this client may be on. */
2391   silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
2392                                TRUE, q->signoff);
2393   q->sock->user_data = NULL;
2394
2395   /* Close the connection on our side */
2396   silc_server_close_connection(q->server, q->sock);
2397
2398   silc_free(q->signoff);
2399   silc_free(q);
2400 }
2401
2402 /* Quits SILC session. This is the normal way to disconnect client. */
2403  
2404 SILC_SERVER_CMD_FUNC(quit)
2405 {
2406   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2407   SilcServer server = cmd->server;
2408   SilcSocketConnection sock = cmd->sock;
2409   QuitInternal q;
2410   unsigned char *tmp = NULL;
2411   uint32 len = 0;
2412
2413   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_QUIT, cmd, 0, 1);
2414
2415   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
2416     goto out;
2417
2418   /* Get destination ID */
2419   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2420   if (len > 128)
2421     tmp = NULL;
2422
2423   q = silc_calloc(1, sizeof(*q));
2424   q->server = server;
2425   q->sock = sock;
2426   q->signoff = tmp ? strdup(tmp) : NULL;
2427
2428   /* We quit the connection with little timeout */
2429   silc_schedule_task_add(server->schedule, sock->sock,
2430                      silc_server_command_quit_cb, (void *)q,
2431                      0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
2432
2433  out:
2434   silc_server_command_free(cmd);
2435 }
2436
2437 /* Server side of command KILL. This command is used by router operator
2438    to remove an client from the SILC Network temporarily. */
2439
2440 SILC_SERVER_CMD_FUNC(kill)
2441 {
2442   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2443   SilcServer server = cmd->server;
2444   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2445   SilcClientEntry remote_client;
2446   SilcClientID *client_id;
2447   unsigned char *tmp, *comment;
2448   uint32 tmp_len, tmp_len2;
2449
2450   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
2451
2452   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
2453     goto out;
2454
2455   /* KILL command works only on router */
2456   if (server->server_type != SILC_ROUTER) {
2457     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2458                                           SILC_STATUS_ERR_NO_ROUTER_PRIV);
2459     goto out;
2460   }
2461
2462   /* Check whether client has the permissions. */
2463   if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
2464     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2465                                           SILC_STATUS_ERR_NO_ROUTER_PRIV);
2466     goto out;
2467   }
2468
2469   /* Get the client ID */
2470   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2471   if (!tmp) {
2472     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2473                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2474     goto out;
2475   }
2476   client_id = silc_id_payload_parse_id(tmp, tmp_len);
2477   if (!client_id) {
2478     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2479                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
2480     goto out;
2481   }
2482
2483   /* Get the client entry */
2484   remote_client = silc_idlist_find_client_by_id(server->local_list, 
2485                                                 client_id, TRUE, NULL);
2486   if (!remote_client) {
2487     remote_client = silc_idlist_find_client_by_id(server->global_list, 
2488                                                   client_id, TRUE, NULL);
2489     if (!remote_client) {
2490       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2491                                             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
2492       goto out;
2493     }
2494   }
2495
2496   /* Get comment */
2497   comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
2498   if (tmp_len2 > 128)
2499     comment = NULL;
2500
2501   /* Send reply to the sender */
2502   silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2503                                         SILC_STATUS_OK);
2504
2505   /* Send the KILL notify packets. First send it to the channel, then
2506      to our primary router and then directly to the client who is being
2507      killed right now. */
2508
2509   /* Send KILLED notify to the channels. It is not sent to the client
2510      as it will be sent differently destined directly to the client and not
2511      to the channel. */
2512   silc_server_send_notify_on_channels(server, remote_client, 
2513                                       remote_client, SILC_NOTIFY_TYPE_KILLED,
2514                                       comment ? 2 : 1,
2515                                       tmp, tmp_len,
2516                                       comment, comment ? tmp_len2 : 0);
2517
2518   /* Send KILLED notify to primary route */
2519   if (!server->standalone)
2520     silc_server_send_notify_killed(server, server->router->connection, TRUE,
2521                                    remote_client->id, comment);
2522
2523   /* Send KILLED notify to the client directly */
2524   silc_server_send_notify_killed(server, remote_client->connection ? 
2525                                  remote_client->connection : 
2526                                  remote_client->router->connection, FALSE,
2527                                  remote_client->id, comment);
2528
2529   /* Remove the client from all channels. This generates new keys to the
2530      channels as well. */
2531   silc_server_remove_from_channels(server, NULL, remote_client, FALSE, 
2532                                    NULL, TRUE);
2533
2534   /* Remove the client entry, If it is locally connected then we will also
2535      disconnect the client here */
2536   if (remote_client->connection) {
2537     /* Remove locally conneted client */
2538     SilcSocketConnection sock = remote_client->connection;
2539     silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
2540     silc_server_close_connection(server, sock);
2541   } else {
2542     /* Remove remote client */
2543     if (!silc_idlist_del_client(server->global_list, remote_client))
2544       silc_idlist_del_client(server->local_list, remote_client);
2545   }
2546
2547  out:
2548   silc_server_command_free(cmd);
2549 }
2550
2551 /* Server side of command INFO. This sends information about us to 
2552    the client. If client requested specific server we will send the 
2553    command to that server. */
2554
2555 SILC_SERVER_CMD_FUNC(info)
2556 {
2557   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2558   SilcServer server = cmd->server;
2559   SilcBuffer packet, idp;
2560   unsigned char *tmp;
2561   uint32 tmp_len;
2562   char *dest_server, *server_info = NULL, *server_name;
2563   uint16 ident = silc_command_get_ident(cmd->payload);
2564   SilcServerEntry entry = NULL;
2565   SilcServerID *server_id = NULL;
2566
2567   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 0, 2);
2568
2569   /* Get server name */
2570   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
2571
2572   /* Get Server ID */
2573   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2574   if (tmp) {
2575     server_id = silc_id_payload_parse_id(tmp, tmp_len);
2576     if (!server_id) {
2577       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
2578                                             SILC_STATUS_ERR_NO_SERVER_ID);
2579       goto out;
2580     }
2581   }
2582
2583   if (server_id) {
2584     /* Check whether we have this server cached */
2585     entry = silc_idlist_find_server_by_id(server->local_list,
2586                                           server_id, TRUE, NULL);
2587     if (!entry) {
2588       entry = silc_idlist_find_server_by_id(server->global_list,
2589                                             server_id, TRUE, NULL);
2590       if (!entry && server->server_type == SILC_ROUTER) {
2591         silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
2592                                               SILC_STATUS_ERR_NO_SUCH_SERVER);
2593         goto out;
2594       }
2595     }
2596   }
2597
2598   /* Some buggy servers has sent request to router about themselves. */
2599   if (server->server_type == SILC_ROUTER && cmd->sock->user_data == entry)
2600     goto out;
2601
2602   if ((!dest_server && !server_id && !entry) || (entry && 
2603                                                  entry == server->id_entry) ||
2604       (dest_server && !cmd->pending && 
2605        !strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
2606     /* Send our reply */
2607     char info_string[256];
2608
2609     memset(info_string, 0, sizeof(info_string));
2610     snprintf(info_string, sizeof(info_string), 
2611              "location: %s server: %s admin: %s <%s>",
2612              server->config->admin_info->location,
2613              server->config->admin_info->server_type,
2614              server->config->admin_info->admin_name,
2615              server->config->admin_info->admin_email);
2616
2617     server_info = info_string;
2618     entry = server->id_entry;
2619   } else {
2620     /* Check whether we have this server cached */
2621     if (!entry && dest_server) {
2622       entry = silc_idlist_find_server_by_name(server->global_list,
2623                                               dest_server, TRUE, NULL);
2624       if (!entry) {
2625         entry = silc_idlist_find_server_by_name(server->local_list,
2626                                                 dest_server, TRUE, NULL);
2627       }
2628     }
2629
2630     if (!cmd->pending &&
2631         server->server_type == SILC_ROUTER && entry && !entry->server_info) {
2632       /* Send to the server */
2633       SilcBuffer tmpbuf;
2634       uint16 old_ident;
2635
2636       old_ident = silc_command_get_ident(cmd->payload);
2637       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2638       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2639
2640       silc_server_packet_send(server, entry->connection,
2641                               SILC_PACKET_COMMAND, cmd->packet->flags,
2642                               tmpbuf->data, tmpbuf->len, TRUE);
2643
2644       /* Reprocess this packet after received reply from router */
2645       silc_server_command_pending(server, SILC_COMMAND_INFO, 
2646                                   silc_command_get_ident(cmd->payload),
2647                                   silc_server_command_destructor,
2648                                   silc_server_command_info,
2649                                   silc_server_command_dup(cmd));
2650       cmd->pending = TRUE;
2651       silc_command_set_ident(cmd->payload, old_ident);
2652       silc_buffer_free(tmpbuf);
2653       return;
2654     }
2655
2656     if (!entry && !cmd->pending && !server->standalone) {
2657       /* Send to the primary router */
2658       SilcBuffer tmpbuf;
2659       uint16 old_ident;
2660
2661       old_ident = silc_command_get_ident(cmd->payload);
2662       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2663       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2664
2665       silc_server_packet_send(server, server->router->connection,
2666                               SILC_PACKET_COMMAND, cmd->packet->flags,
2667                               tmpbuf->data, tmpbuf->len, TRUE);
2668
2669       /* Reprocess this packet after received reply from router */
2670       silc_server_command_pending(server, SILC_COMMAND_INFO, 
2671                                   silc_command_get_ident(cmd->payload),
2672                                   silc_server_command_destructor,
2673                                   silc_server_command_info,
2674                                   silc_server_command_dup(cmd));
2675       cmd->pending = TRUE;
2676       silc_command_set_ident(cmd->payload, old_ident);
2677       silc_buffer_free(tmpbuf);
2678       return;
2679     }
2680   }
2681
2682   if (server_id)
2683     silc_free(server_id);
2684
2685   if (!entry) {
2686     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
2687                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
2688     goto out;
2689   }
2690
2691   idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
2692   if (!server_info)
2693     server_info = entry->server_info;
2694   server_name = entry->server_name;
2695
2696   /* Send the reply */
2697   if (server_info)
2698     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
2699                                                   SILC_STATUS_OK, ident, 3,
2700                                                   2, idp->data, idp->len,
2701                                                   3, server_name, 
2702                                                   strlen(server_name),
2703                                                   4, server_info, 
2704                                                   strlen(server_info));
2705   else
2706     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
2707                                                   SILC_STATUS_OK, ident, 2,
2708                                                   2, idp->data, idp->len,
2709                                                   3, server_name, 
2710                                                   strlen(server_name));
2711   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2712                           packet->data, packet->len, FALSE);
2713     
2714   silc_buffer_free(packet);
2715   silc_buffer_free(idp);
2716
2717  out:
2718   silc_server_command_free(cmd);
2719 }
2720
2721 /* Server side of command PING. This just replies to the ping. */
2722
2723 SILC_SERVER_CMD_FUNC(ping)
2724 {
2725   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2726   SilcServer server = cmd->server;
2727   SilcServerID *id;
2728   uint32 len;
2729   unsigned char *tmp;
2730
2731   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 1, 2);
2732
2733   /* Get Server ID */
2734   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2735   if (!tmp) {
2736     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
2737                                           SILC_STATUS_ERR_NO_SERVER_ID);
2738     goto out;
2739   }
2740   id = silc_id_str2id(tmp, len, SILC_ID_SERVER);
2741   if (!id)
2742     goto out;
2743
2744   if (SILC_ID_SERVER_COMPARE(id, server->id)) {
2745     /* Send our reply */
2746     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
2747                                           SILC_STATUS_OK);
2748   } else {
2749     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
2750                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
2751     goto out;
2752   }
2753
2754   silc_free(id);
2755
2756  out:
2757   silc_server_command_free(cmd);
2758 }
2759
2760 /* Internal routine to join channel. The channel sent to this function
2761    has been either created or resolved from ID lists. This joins the sent
2762    client to the channel. */
2763
2764 static void silc_server_command_join_channel(SilcServer server, 
2765                                              SilcServerCommandContext cmd,
2766                                              SilcChannelEntry channel,
2767                                              SilcClientID *client_id,
2768                                              int created,
2769                                              uint32 umode)
2770 {
2771   SilcSocketConnection sock = cmd->sock;
2772   unsigned char *tmp;
2773   uint32 tmp_len, user_count;
2774   unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
2775   SilcClientEntry client;
2776   SilcChannelClientEntry chl;
2777   SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
2778   uint16 ident = silc_command_get_ident(cmd->payload);
2779   char check[512], check2[512];
2780
2781   SILC_LOG_DEBUG(("Start"));
2782
2783   if (!channel)
2784     return;
2785
2786   /* Get the client entry */
2787   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2788     client = (SilcClientEntry)sock->user_data;
2789   } else {
2790     client = silc_server_get_client_resolve(server, client_id);
2791     if (!client) {
2792       if (cmd->pending)
2793         goto out;
2794
2795       /* The client info is being resolved. Reprocess this packet after
2796          receiving the reply to the query. */
2797       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
2798                                   server->cmd_ident, NULL,
2799                                   silc_server_command_join, 
2800                                   silc_server_command_dup(cmd));
2801       cmd->pending = TRUE;
2802       return;
2803     }
2804
2805     cmd->pending = FALSE;
2806   }
2807
2808   /*
2809    * Check channel modes
2810    */
2811
2812   memset(check, 0, sizeof(check));
2813   memset(check2, 0, sizeof(check2));
2814   strncat(check, client->nickname, strlen(client->nickname));
2815   strncat(check, "!", 1);
2816   strncat(check, client->username, strlen(client->username));
2817   if (!strchr(client->username, '@')) {
2818     strncat(check, "@", 1);
2819     strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
2820   }
2821
2822   strncat(check2, client->nickname, strlen(client->nickname));
2823   if (!strchr(client->nickname, '@')) {
2824     strncat(check2, "@", 1);
2825     strncat(check2, server->server_name, strlen(server->server_name));
2826   }
2827   strncat(check2, "!", 1);
2828   strncat(check2, client->username, strlen(client->username));
2829   if (!strchr(client->username, '@')) {
2830     strncat(check2, "@", 1);
2831     strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
2832   }
2833
2834   /* Check invite list if channel is invite-only channel */
2835   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
2836     if (!channel->invite_list ||
2837         (!silc_string_match(channel->invite_list, check) &&
2838          !silc_string_match(channel->invite_list, check2))) {
2839       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2840                                             SILC_STATUS_ERR_NOT_INVITED);
2841       goto out;
2842     }
2843   }
2844
2845   /* Check ban list if it exists. If the client's nickname, server,
2846      username and/or hostname is in the ban list the access to the
2847      channel is denied. */
2848   if (channel->ban_list) {
2849     if (silc_string_match(channel->ban_list, check) ||
2850         silc_string_match(channel->ban_list, check2)) {
2851       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2852                               SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
2853       goto out;
2854     }
2855   }
2856
2857   /* Get passphrase */
2858   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2859   if (tmp) {
2860     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
2861     memcpy(passphrase, tmp, tmp_len);
2862   }
2863   
2864   /* Check the channel passphrase if set. */
2865   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2866     if (!passphrase || memcmp(channel->passphrase, passphrase,
2867                               strlen(channel->passphrase))) {
2868       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2869                                             SILC_STATUS_ERR_BAD_PASSWORD);
2870       goto out;
2871     }
2872   }
2873
2874   /* Check user count limit if set. */
2875   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
2876     if (silc_hash_table_count(channel->user_list) + 1 > 
2877         channel->user_limit) {
2878       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2879                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
2880       goto out;
2881     }
2882   }
2883
2884   /*
2885    * Client is allowed to join to the channel. Make it happen.
2886    */
2887
2888   /* Check whether the client already is on the channel */
2889   if (silc_server_client_on_channel(client, channel)) {
2890     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2891                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
2892     goto out;
2893   }
2894
2895   /* Generate new channel key as protocol dictates */
2896   if ((!created && silc_hash_table_count(channel->user_list) > 0) || 
2897       !channel->channel_key)
2898     if (!silc_server_create_channel_key(server, channel, 0))
2899       goto out;
2900
2901   /* Send the channel key. This is broadcasted to the channel but is not
2902      sent to the client who is joining to the channel. */
2903   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
2904     silc_server_send_channel_key(server, NULL, channel, 
2905                                  server->server_type == SILC_ROUTER ? 
2906                                  FALSE : !server->standalone);
2907
2908   /* Join the client to the channel by adding it to channel's user list.
2909      Add also the channel to client entry's channels list for fast cross-
2910      referencing. */
2911   chl = silc_calloc(1, sizeof(*chl));
2912   chl->mode = umode;
2913   chl->client = client;
2914   chl->channel = channel;
2915   silc_hash_table_add(channel->user_list, client, chl);
2916   silc_hash_table_add(client->channels, channel, chl);
2917
2918   /* Get users on the channel */
2919   silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
2920                                    &user_count);
2921
2922   /* Encode Client ID Payload of the original client who wants to join */
2923   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2924
2925   /* Encode command reply packet */
2926   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2927   SILC_PUT32_MSB(channel->mode, mode);
2928   SILC_PUT32_MSB(created, tmp2);
2929   SILC_PUT32_MSB(user_count, tmp3);
2930
2931   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
2932     tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
2933     keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp, 
2934                                            strlen(channel->channel_key->
2935                                                   cipher->name),
2936                                            channel->channel_key->cipher->name,
2937                                            channel->key_len / 8, channel->key);
2938     silc_free(tmp);
2939   }
2940
2941   reply = 
2942     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
2943                                          SILC_STATUS_OK, ident, 13,
2944                                          2, channel->channel_name,
2945                                          strlen(channel->channel_name),
2946                                          3, chidp->data, chidp->len,
2947                                          4, clidp->data, clidp->len,
2948                                          5, mode, 4,
2949                                          6, tmp2, 4,
2950                                          7, keyp ? keyp->data : NULL, 
2951                                          keyp ? keyp->len : 0,
2952                                          8, channel->ban_list, 
2953                                          channel->ban_list ?
2954                                          strlen(channel->ban_list) : 0,
2955                                          9, channel->invite_list,
2956                                          channel->invite_list ?
2957                                          strlen(channel->invite_list) : 0,
2958                                          10, channel->topic,
2959                                          channel->topic ?
2960                                          strlen(channel->topic) : 0,
2961                                          11, channel->hmac->hmac->name,
2962                                          strlen(channel->hmac->hmac->name),
2963                                          12, tmp3, 4,
2964                                          13, user_list->data, user_list->len,
2965                                          14, mode_list->data, 
2966                                          mode_list->len);
2967
2968   /* Send command reply */
2969   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
2970                           reply->data, reply->len, FALSE);
2971
2972   if (!cmd->pending) {
2973     /* Send JOIN notify to locally connected clients on the channel */
2974     silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
2975                                        SILC_NOTIFY_TYPE_JOIN, 2,
2976                                        clidp->data, clidp->len,
2977                                        chidp->data, chidp->len);
2978
2979     /* Send JOIN notify packet to our primary router */
2980     if (!server->standalone)
2981       silc_server_send_notify_join(server, server->router->connection,
2982                                    server->server_type == SILC_ROUTER ?
2983                                    TRUE : FALSE, channel, client->id);
2984   }
2985
2986   silc_buffer_free(reply);
2987   silc_buffer_free(clidp);
2988   silc_buffer_free(chidp);
2989   silc_buffer_free(keyp);
2990   silc_buffer_free(user_list);
2991   silc_buffer_free(mode_list);
2992
2993  out:
2994   if (passphrase)
2995     silc_free(passphrase);
2996 }
2997
2998 /* Server side of command JOIN. Joins client into requested channel. If 
2999    the channel does not exist it will be created. */
3000
3001 SILC_SERVER_CMD_FUNC(join)
3002 {
3003   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3004   SilcServer server = cmd->server;
3005   uint32 tmp_len;
3006   char *tmp, *channel_name = NULL, *cipher, *hmac;
3007   SilcChannelEntry channel;
3008   uint32 umode = 0;
3009   int created = FALSE;
3010   SilcClientID *client_id;
3011
3012   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 1, 4);
3013
3014   /* Get channel name */
3015   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3016   if (!tmp) {
3017     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3018                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3019     goto out;
3020   }
3021   channel_name = tmp;
3022
3023   if (strlen(channel_name) > 256)
3024     channel_name[255] = '\0';
3025
3026   if (silc_server_command_bad_chars(channel_name) == TRUE) {
3027     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3028                                           SILC_STATUS_ERR_BAD_CHANNEL);
3029     goto out;
3030   }
3031
3032   /* Get Client ID of the client who is joining to the channel */
3033   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
3034   if (!tmp) {
3035     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3036                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3037     goto out;
3038   }
3039   client_id = silc_id_payload_parse_id(tmp, tmp_len);
3040   if (!client_id) {
3041     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3042                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3043     goto out;
3044   }
3045
3046   /* Get cipher and hmac name */
3047   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
3048   hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
3049
3050   /* See if the channel exists */
3051   channel = silc_idlist_find_channel_by_name(server->local_list, 
3052                                              channel_name, NULL);
3053
3054   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
3055     /* If this is coming from client the Client ID in the command packet must
3056        be same as the client's ID. */
3057     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
3058       SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
3059       if (!SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
3060         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3061                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3062         goto out;
3063       }
3064     }
3065
3066     if (!channel || !channel->id) {
3067       /* Channel not found */
3068
3069       /* If we are standalone server we don't have a router, we just create 
3070          the channel by ourselves. */
3071       if (server->standalone) {
3072         channel = silc_server_create_new_channel(server, server->id, cipher, 
3073                                                  hmac, channel_name, TRUE);
3074         if (!channel) {
3075           silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3076                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3077           goto out;
3078         }
3079
3080         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3081         created = TRUE;
3082
3083       } else {
3084
3085         /* The channel does not exist on our server. If we are normal server 
3086            we will send JOIN command to our router which will handle the
3087            joining procedure (either creates the channel if it doesn't exist 
3088            or joins the client to it). */
3089         if (server->server_type == SILC_SERVER) {
3090           SilcBuffer tmpbuf;
3091           uint16 old_ident;
3092
3093           /* If this is pending command callback then we've resolved
3094              it and it didn't work, return since we've notified the
3095              client already in the command reply callback. */
3096           if (cmd->pending)
3097             goto out;
3098           
3099           old_ident = silc_command_get_ident(cmd->payload);
3100           silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
3101           tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3102           
3103           /* Send JOIN command to our router */
3104           silc_server_packet_send(server, (SilcSocketConnection)
3105                                   server->router->connection,
3106                                   SILC_PACKET_COMMAND, cmd->packet->flags,
3107                                   tmpbuf->data, tmpbuf->len, TRUE);
3108           
3109           /* Reprocess this packet after received reply from router */
3110           silc_server_command_pending(server, SILC_COMMAND_JOIN, 
3111                                       silc_command_get_ident(cmd->payload),
3112                                       silc_server_command_destructor,
3113                                       silc_server_command_join,
3114                                       silc_server_command_dup(cmd));
3115           cmd->pending = TRUE;
3116           return;
3117         }
3118         
3119         /* We are router and the channel does not seem exist so we will check
3120            our global list as well for the channel. */
3121         channel = silc_idlist_find_channel_by_name(server->global_list, 
3122                                                    channel_name, NULL);
3123         if (!channel) {
3124           /* Channel really does not exist, create it */
3125           channel = silc_server_create_new_channel(server, server->id, cipher, 
3126                                                    hmac, channel_name, TRUE);
3127           if (!channel) {
3128             silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3129                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3130             goto out;
3131           }
3132
3133           umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3134           created = TRUE;
3135         }
3136       }
3137     }
3138   } else {
3139     if (!channel) {
3140       /* Channel not found */
3141
3142       /* If the command came from router and/or we are normal server then
3143          something went wrong with the joining as the channel was not found.
3144          We can't do anything else but ignore this. */
3145       if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
3146           server->server_type == SILC_SERVER)
3147         goto out;
3148       
3149       /* We are router and the channel does not seem exist so we will check
3150          our global list as well for the channel. */
3151       channel = silc_idlist_find_channel_by_name(server->global_list, 
3152                                                  channel_name, NULL);
3153       if (!channel) {
3154         /* Channel really does not exist, create it */
3155         channel = silc_server_create_new_channel(server, server->id, cipher, 
3156                                                  hmac, channel_name, TRUE);
3157         if (!channel) {
3158           silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3159                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3160           goto out;
3161         }
3162
3163         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3164         created = TRUE;
3165       }
3166     }
3167   }
3168
3169   /* If the channel does not have global users and is also empty it means the
3170      channel was created globally (by our router) and the client will be the
3171      channel founder and operator. */
3172   if (!channel->global_users && !silc_hash_table_count(channel->user_list)) {
3173     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3174     created = TRUE;             /* Created globally by our router */
3175   }
3176
3177   /* Join to the channel */
3178   silc_server_command_join_channel(server, cmd, channel, client_id,
3179                                    created, umode);
3180
3181   silc_free(client_id);
3182
3183  out:
3184   silc_server_command_free(cmd);
3185 }
3186
3187 /* Server side of command MOTD. Sends server's current "message of the
3188    day" to the client. */
3189
3190 SILC_SERVER_CMD_FUNC(motd)
3191 {
3192   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3193   SilcServer server = cmd->server;
3194   SilcBuffer packet, idp;
3195   char *motd, *dest_server;
3196   uint32 motd_len;
3197   uint16 ident = silc_command_get_ident(cmd->payload);
3198   
3199   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_MOTD, cmd, 1, 1);
3200
3201   /* Get server name */
3202   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
3203   if (!dest_server) {
3204     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
3205                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
3206     goto out;
3207   }
3208
3209   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
3210     /* Send our MOTD */
3211
3212     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
3213
3214     if (server->config && server->config->motd && 
3215         server->config->motd->motd_file) {
3216       /* Send motd */
3217       motd = silc_file_read(server->config->motd->motd_file, &motd_len);
3218       if (!motd)
3219         goto out;
3220       
3221       motd[motd_len] = 0;
3222       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3223                                                     SILC_STATUS_OK, ident, 2,
3224                                                     2, idp, idp->len,
3225                                                     3, motd, motd_len);
3226       goto out;
3227     } else {
3228       /* No motd */
3229       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3230                                                     SILC_STATUS_OK, ident, 1,
3231                                                     2, idp, idp->len);
3232     }
3233
3234     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3235                             packet->data, packet->len, FALSE);
3236     silc_buffer_free(packet);
3237     silc_buffer_free(idp);
3238   } else {
3239     SilcServerEntry entry;
3240
3241     /* Check whether we have this server cached */
3242     entry = silc_idlist_find_server_by_name(server->global_list,
3243                                             dest_server, TRUE, NULL);
3244     if (!entry) {
3245       entry = silc_idlist_find_server_by_name(server->local_list,
3246                                               dest_server, TRUE, NULL);
3247     }
3248
3249     if (server->server_type == SILC_ROUTER && !cmd->pending && 
3250         entry && !entry->motd) {
3251       /* Send to the server */
3252       SilcBuffer tmpbuf;
3253       uint16 old_ident;
3254
3255       old_ident = silc_command_get_ident(cmd->payload);
3256       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
3257       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3258
3259       silc_server_packet_send(server, entry->connection,
3260                               SILC_PACKET_COMMAND, cmd->packet->flags,
3261                               tmpbuf->data, tmpbuf->len, TRUE);
3262
3263       /* Reprocess this packet after received reply from router */
3264       silc_server_command_pending(server, SILC_COMMAND_MOTD, 
3265                                   silc_command_get_ident(cmd->payload),
3266                                   silc_server_command_destructor,
3267                                   silc_server_command_motd,
3268                                   silc_server_command_dup(cmd));
3269       cmd->pending = TRUE;
3270       silc_command_set_ident(cmd->payload, old_ident);
3271       silc_buffer_free(tmpbuf);
3272       return;
3273     }
3274
3275     if (!entry && !cmd->pending && !server->standalone) {
3276       /* Send to the primary router */
3277       SilcBuffer tmpbuf;
3278       uint16 old_ident;
3279
3280       old_ident = silc_command_get_ident(cmd->payload);
3281       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
3282       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3283
3284       silc_server_packet_send(server, server->router->connection,
3285                               SILC_PACKET_COMMAND, cmd->packet->flags,
3286                               tmpbuf->data, tmpbuf->len, TRUE);
3287
3288       /* Reprocess this packet after received reply from router */
3289       silc_server_command_pending(server, SILC_COMMAND_MOTD, 
3290                                   silc_command_get_ident(cmd->payload),
3291                                   silc_server_command_destructor,
3292                                   silc_server_command_motd,
3293                                   silc_server_command_dup(cmd));
3294       cmd->pending = TRUE;
3295       silc_command_set_ident(cmd->payload, old_ident);
3296       silc_buffer_free(tmpbuf);
3297       return;
3298     }
3299
3300     if (!entry) {
3301       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
3302                                             SILC_STATUS_ERR_NO_SUCH_SERVER);
3303       goto out;
3304     }
3305
3306     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
3307
3308     if (entry->motd)
3309       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3310                                                     SILC_STATUS_OK, ident, 2,
3311                                                     2, idp, idp->len,
3312                                                     3, entry->motd,
3313                                                     strlen(entry->motd));
3314     else
3315       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3316                                                     SILC_STATUS_OK, ident, 1,
3317                                                     2, idp, idp->len);
3318
3319     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3320                             packet->data, packet->len, FALSE);
3321     silc_buffer_free(packet);
3322     silc_buffer_free(idp);
3323   }
3324
3325  out:
3326   silc_server_command_free(cmd);
3327 }
3328
3329 /* Server side of command UMODE. Client can use this command to set/unset
3330    user mode. Client actually cannot set itself to be as server/router
3331    operator so this can be used only to unset the modes. */
3332
3333 SILC_SERVER_CMD_FUNC(umode)
3334 {
3335   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3336   SilcServer server = cmd->server;
3337   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3338   SilcBuffer packet;
3339   unsigned char *tmp_mask;
3340   uint32 mask;
3341   uint16 ident = silc_command_get_ident(cmd->payload);
3342
3343   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
3344     goto out;
3345
3346   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_UMODE, cmd, 2, 2);
3347
3348   /* Get the client's mode mask */
3349   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
3350   if (!tmp_mask) {
3351     silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3352                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3353     goto out;
3354   }
3355   SILC_GET32_MSB(mask, tmp_mask);
3356
3357   /* 
3358    * Change the mode 
3359    */
3360
3361   if (mask & SILC_UMODE_SERVER_OPERATOR) {
3362     if (!(client->mode & SILC_UMODE_SERVER_OPERATOR)) {
3363       /* Cannot operator mode */
3364       silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3365                                             SILC_STATUS_ERR_PERM_DENIED);
3366       goto out;
3367     }
3368   } else {
3369     if (client->mode & SILC_UMODE_SERVER_OPERATOR)
3370       /* Remove the server operator rights */
3371       client->mode &= ~SILC_UMODE_SERVER_OPERATOR;
3372   }
3373
3374   if (mask & SILC_UMODE_ROUTER_OPERATOR) {
3375     if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
3376       /* Cannot operator mode */
3377       silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3378                                             SILC_STATUS_ERR_PERM_DENIED);
3379       goto out;
3380     }
3381   } else {
3382     if (client->mode & SILC_UMODE_ROUTER_OPERATOR)
3383       /* Remove the router operator rights */
3384       client->mode &= ~SILC_UMODE_ROUTER_OPERATOR;
3385   }
3386
3387   if (mask & SILC_UMODE_GONE) {
3388     client->mode |= SILC_UMODE_GONE;
3389   } else {
3390     if (client->mode & SILC_UMODE_GONE)
3391       /* Remove the gone status */
3392       client->mode &= ~SILC_UMODE_GONE;
3393   }
3394
3395   /* Send UMODE change to primary router */
3396   if (!server->standalone)
3397     silc_server_send_notify_umode(server, server->router->connection, TRUE,
3398                                   client->id, client->mode);
3399
3400   /* Send command reply to sender */
3401   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_UMODE,
3402                                                 SILC_STATUS_OK, ident, 1,
3403                                                 2, tmp_mask, 4);
3404   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3405                           packet->data, packet->len, FALSE);
3406   silc_buffer_free(packet);
3407
3408  out:
3409   silc_server_command_free(cmd);
3410 }
3411
3412 /* Checks that client has rights to add or remove channel modes. If any
3413    of the checks fails FALSE is returned. */
3414
3415 int silc_server_check_cmode_rights(SilcChannelEntry channel,
3416                                    SilcChannelClientEntry client,
3417                                    uint32 mode)
3418 {
3419   int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
3420   int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
3421
3422   /* Check whether has rights to change anything */
3423   if (!is_op && !is_fo)
3424     return FALSE;
3425
3426   /* Check whether has rights to change everything */
3427   if (is_op && is_fo)
3428     return TRUE;
3429
3430   /* We know that client is channel operator, check that they are not
3431      changing anything that requires channel founder rights. Rest of the
3432      modes are available automatically for channel operator. */
3433
3434   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
3435     if (is_op && !is_fo)
3436       return FALSE;
3437   } else {
3438     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
3439       if (is_op && !is_fo)
3440         return FALSE;
3441     }
3442   }
3443   
3444   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3445     if (is_op && !is_fo)
3446       return FALSE;
3447   } else {
3448     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3449       if (is_op && !is_fo)
3450         return FALSE;
3451     }
3452   }
3453
3454   if (mode & SILC_CHANNEL_MODE_CIPHER) {
3455     if (is_op && !is_fo)
3456       return FALSE;
3457   } else {
3458     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
3459       if (is_op && !is_fo)
3460         return FALSE;
3461     }
3462   }
3463   
3464   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
3465     if (is_op && !is_fo)
3466       return FALSE;
3467   } else {
3468     if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
3469       if (is_op && !is_fo)
3470         return FALSE;
3471     }
3472   }
3473   
3474   return TRUE;
3475 }
3476
3477 /* Server side command of CMODE. Changes channel mode */
3478
3479 SILC_SERVER_CMD_FUNC(cmode)
3480 {
3481   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3482   SilcServer server = cmd->server;
3483   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3484   SilcIDListData idata = (SilcIDListData)client;
3485   SilcChannelID *channel_id;
3486   SilcChannelEntry channel;
3487   SilcChannelClientEntry chl;
3488   SilcBuffer packet, cidp;
3489   unsigned char *tmp, *tmp_id, *tmp_mask;
3490   char *cipher = NULL, *hmac = NULL;
3491   uint32 mode_mask, tmp_len, tmp_len2;
3492   uint16 ident = silc_command_get_ident(cmd->payload);
3493
3494   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 2, 7);
3495
3496   /* Get Channel ID */
3497   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
3498   if (!tmp_id) {
3499     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3500                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3501     goto out;
3502   }
3503   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
3504   if (!channel_id) {
3505     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3506                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3507     goto out;
3508   }
3509
3510   /* Get the channel mode mask */
3511   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
3512   if (!tmp_mask) {
3513     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3514                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3515     goto out;
3516   }
3517   SILC_GET32_MSB(mode_mask, tmp_mask);
3518
3519   /* Get channel entry */
3520   channel = silc_idlist_find_channel_by_id(server->local_list, 
3521                                            channel_id, NULL);
3522   if (!channel) {
3523     channel = silc_idlist_find_channel_by_id(server->global_list, 
3524                                              channel_id, NULL);
3525     if (!channel) {
3526       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3527                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
3528       goto out;
3529     }
3530   }
3531
3532   /* Check whether this client is on the channel */
3533   if (!silc_server_client_on_channel(client, channel)) {
3534     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3535                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
3536     goto out;
3537   }
3538
3539   /* Get entry to the channel user list */
3540   silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
3541
3542   /* Check that client has rights to change any requested channel modes */
3543   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
3544     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3545                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
3546     goto out;
3547   }
3548
3549   /*
3550    * Check the modes. Modes that requires nothing special operation are
3551    * not checked here.
3552    */
3553
3554   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
3555     /* Channel uses private keys to protect traffic. Client(s) has set the
3556        key locally they want to use, server does not know that key. */
3557     /* Nothing interesting to do here */
3558   } else {
3559     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
3560       /* The mode is removed and we need to generate and distribute
3561          new channel key. Clients are not using private channel keys
3562          anymore after this. */
3563
3564       /* Re-generate channel key */
3565       if (!silc_server_create_channel_key(server, channel, 0))
3566         goto out;
3567       
3568       /* Send the channel key. This sends it to our local clients and if
3569          we are normal server to our router as well. */
3570       silc_server_send_channel_key(server, NULL, channel, 
3571                                    server->server_type == SILC_ROUTER ? 
3572                                    FALSE : !server->standalone);
3573
3574       cipher = channel->channel_key->cipher->name;
3575       hmac = channel->hmac->hmac->name;
3576     }
3577   }
3578   
3579   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
3580     /* User limit is set on channel */
3581     uint32 user_limit;
3582       
3583     /* Get user limit */
3584     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
3585     if (!tmp) {
3586       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
3587         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3588                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3589         goto out;
3590       }
3591     } else {
3592       SILC_GET32_MSB(user_limit, tmp);
3593       channel->user_limit = user_limit;
3594     }
3595   } else {
3596     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
3597       /* User limit mode is unset. Remove user limit */
3598       channel->user_limit = 0;
3599   }
3600
3601   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
3602     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
3603       /* Passphrase has been set to channel */
3604       
3605       /* Get the passphrase */
3606       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
3607       if (!tmp) {
3608         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3609                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3610         goto out;
3611       }
3612
3613       /* Save the passphrase */
3614       channel->passphrase = strdup(tmp);
3615     }
3616   } else {
3617     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3618       /* Passphrase mode is unset. remove the passphrase */
3619       if (channel->passphrase) {
3620         silc_free(channel->passphrase);
3621         channel->passphrase = NULL;
3622       }
3623     }
3624   }
3625
3626   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
3627     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
3628       /* Cipher to use protect the traffic */
3629
3630       /* Get cipher */
3631       cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
3632       if (!cipher) {
3633         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3634                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3635         goto out;
3636       }
3637
3638       /* Delete old cipher and allocate the new one */
3639       silc_cipher_free(channel->channel_key);
3640       if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
3641         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3642                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3643         goto out;
3644       }
3645
3646       /* Re-generate channel key */
3647       if (!silc_server_create_channel_key(server, channel, 0))
3648         goto out;
3649     
3650       /* Send the channel key. This sends it to our local clients and if
3651          we are normal server to our router as well. */
3652       silc_server_send_channel_key(server, NULL, channel, 
3653                                    server->server_type == SILC_ROUTER ? 
3654                                    FALSE : !server->standalone);
3655     }
3656   } else {
3657     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
3658       /* Cipher mode is unset. Remove the cipher and revert back to 
3659          default cipher */
3660       cipher = channel->cipher;
3661
3662       /* Delete old cipher and allocate default one */
3663       silc_cipher_free(channel->channel_key);
3664       if (!silc_cipher_alloc(cipher ? cipher : "aes-256-cbc", 
3665                              &channel->channel_key)) {
3666         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3667                                    SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3668         goto out;
3669       }
3670
3671       /* Re-generate channel key */
3672       if (!silc_server_create_channel_key(server, channel, 0))
3673         goto out;
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, TRUE, NULL);
3919   if (!target_client) {
3920     target_client = silc_idlist_find_client_by_id(server->global_list, 
3921                                                   client_id, TRUE, 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, TRUE, NULL);
4156   if (!target_client) {
4157     target_client = silc_idlist_find_client_by_id(server->global_list, 
4158                                                   client_id, TRUE, 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     if (!silc_server_create_channel_key(server, channel, 0))
4213       goto out;
4214     
4215     /* Send the channel key to the channel. The key of course is not sent
4216        to the client who was kicked off the channel. */
4217     silc_server_send_channel_key(server, target_client->connection, channel, 
4218                                  server->server_type == SILC_ROUTER ? 
4219                                  FALSE : !server->standalone);
4220   }
4221
4222  out:
4223   silc_server_command_free(cmd);
4224 }
4225
4226 /* Server side of OPER command. Client uses this comand to obtain server
4227    operator privileges to this server/router. */
4228
4229 SILC_SERVER_CMD_FUNC(oper)
4230 {
4231   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4232   SilcServer server = cmd->server;
4233   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4234   unsigned char *username, *auth;
4235   uint32 tmp_len;
4236   SilcServerConfigSectionAdminConnection *admin;
4237   SilcIDListData idata = (SilcIDListData)client;
4238
4239   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
4240
4241   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4242     goto out;
4243
4244   /* Get the username */
4245   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4246   if (!username) {
4247     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4248                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4249     goto out;
4250   }
4251
4252   /* Get the admin configuration */
4253   admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
4254                                         username, client->nickname);
4255   if (!admin) {
4256     admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
4257                                           username, client->nickname);
4258     if (!admin) {
4259       silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4260                                             SILC_STATUS_ERR_AUTH_FAILED);
4261       goto out;
4262     }
4263   }
4264
4265   /* Get the authentication payload */
4266   auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4267   if (!auth) {
4268     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4269                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4270     goto out;
4271   }
4272
4273   /* Verify the authentication data */
4274   if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, 
4275                              admin->auth_data, admin->auth_data_len,
4276                              idata->hash, client->id, SILC_ID_CLIENT)) {
4277     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4278                                           SILC_STATUS_ERR_AUTH_FAILED);
4279     goto out;
4280   }
4281
4282   /* Client is now server operator */
4283   client->mode |= SILC_UMODE_SERVER_OPERATOR;
4284
4285   /* Send UMODE change to primary router */
4286   if (!server->standalone)
4287     silc_server_send_notify_umode(server, server->router->connection, TRUE,
4288                                   client->id, client->mode);
4289
4290   /* Send reply to the sender */
4291   silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4292                                         SILC_STATUS_OK);
4293
4294  out:
4295   silc_server_command_free(cmd);
4296 }
4297
4298 /* Server side of SILCOPER command. Client uses this comand to obtain router
4299    operator privileges to this router. */
4300
4301 SILC_SERVER_CMD_FUNC(silcoper)
4302 {
4303   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4304   SilcServer server = cmd->server;
4305   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4306   unsigned char *username, *auth;
4307   uint32 tmp_len;
4308   SilcServerConfigSectionAdminConnection *admin;
4309   SilcIDListData idata = (SilcIDListData)client;
4310
4311   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
4312
4313   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4314     goto out;
4315
4316   if (server->server_type == SILC_SERVER) {
4317     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4318                                           SILC_STATUS_ERR_AUTH_FAILED);
4319     goto out;
4320   }
4321
4322   /* Get the username */
4323   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4324   if (!username) {
4325     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4326                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4327     goto out;
4328   }
4329
4330   /* Get the admin configuration */
4331   admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
4332                                         username, client->nickname);
4333   if (!admin) {
4334     admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
4335                                           username, client->nickname);
4336     if (!admin) {
4337       silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4338                                             SILC_STATUS_ERR_AUTH_FAILED);
4339       goto out;
4340     }
4341   }
4342
4343   /* Get the authentication payload */
4344   auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4345   if (!auth) {
4346     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4347                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4348     goto out;
4349   }
4350
4351   /* Verify the authentication data */
4352   if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, 
4353                              admin->auth_data, admin->auth_data_len,
4354                              idata->hash, client->id, SILC_ID_CLIENT)) {
4355     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4356                                           SILC_STATUS_ERR_AUTH_FAILED);
4357     goto out;
4358   }
4359
4360   /* Client is now router operator */
4361   client->mode |= SILC_UMODE_ROUTER_OPERATOR;
4362
4363   /* Send UMODE change to primary router */
4364   if (!server->standalone)
4365     silc_server_send_notify_umode(server, server->router->connection, TRUE,
4366                                   client->id, client->mode);
4367
4368   /* Send reply to the sender */
4369   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4370                                         SILC_STATUS_OK);
4371
4372  out:
4373   silc_server_command_free(cmd);
4374 }
4375
4376 /* Server side command of CONNECT. Connects us to the specified remote
4377    server or router. */
4378
4379 SILC_SERVER_CMD_FUNC(connect)
4380 {
4381   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4382   SilcServer server = cmd->server;
4383   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4384   unsigned char *tmp, *host;
4385   uint32 tmp_len;
4386   uint32 port = SILC_PORT;
4387
4388   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CONNECT, cmd, 1, 2);
4389
4390   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4391     goto out;
4392
4393   /* Check whether client has the permissions. */
4394   if (client->mode == SILC_UMODE_NONE) {
4395     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4396                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
4397     goto out;
4398   }
4399
4400   if (server->server_type == SILC_ROUTER && 
4401       client->mode & SILC_UMODE_SERVER_OPERATOR) {
4402     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4403                                           SILC_STATUS_ERR_NO_ROUTER_PRIV);
4404     goto out;
4405   }
4406
4407   /* Get the remote server */
4408   host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4409   if (!host) {
4410     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4411                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4412     goto out;
4413   }
4414
4415   /* Get port */
4416   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4417   if (tmp)
4418     SILC_GET32_MSB(port, tmp);
4419
4420   /* Create the connection. It is done with timeout and is async. */
4421   silc_server_create_connection(server, host, port);
4422
4423   /* Send reply to the sender */
4424   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4425                                         SILC_STATUS_OK);
4426
4427  out:
4428   silc_server_command_free(cmd);
4429 }
4430
4431 /* Server side of command BAN. This is used to manage the ban list of the
4432    channel. To add clients and remove clients from the ban list. */
4433
4434 SILC_SERVER_CMD_FUNC(ban)
4435 {
4436   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4437   SilcServer server = cmd->server;
4438   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4439   SilcBuffer packet;
4440   SilcChannelEntry channel;
4441   SilcChannelClientEntry chl;
4442   SilcChannelID *channel_id = NULL;
4443   unsigned char *id, *add, *del;
4444   uint32 id_len, tmp_len;
4445   uint16 ident = silc_command_get_ident(cmd->payload);
4446
4447   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4448     goto out;
4449
4450   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_BAN, cmd, 0, 3);
4451
4452   /* Get Channel ID */
4453   id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
4454   if (id) {
4455     channel_id = silc_id_payload_parse_id(id, id_len);
4456     if (!channel_id) {
4457       silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4458                                             SILC_STATUS_ERR_NO_CHANNEL_ID);
4459       goto out;
4460     }
4461   }
4462
4463   /* Get channel entry. The server must know about the channel since the
4464      client is expected to be on the channel. */
4465   channel = silc_idlist_find_channel_by_id(server->local_list, 
4466                                            channel_id, NULL);
4467   if (!channel) {
4468     channel = silc_idlist_find_channel_by_id(server->global_list, 
4469                                              channel_id, NULL);
4470     if (!channel) {
4471       silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4472                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
4473       goto out;
4474     }
4475   }
4476
4477   /* Check whether this client is on the channel */
4478   if (!silc_server_client_on_channel(client, channel)) {
4479     silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4480                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
4481     goto out;
4482   }
4483
4484   /* Get entry to the channel user list */
4485   silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
4486
4487   /* The client must be at least channel operator. */
4488   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
4489     silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4490                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
4491     goto out;
4492   }
4493
4494   /* Get the new ban and add it to the ban list */
4495   add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4496   if (add) {
4497     if (!channel->ban_list)
4498       channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list));
4499     else
4500       channel->ban_list = silc_realloc(channel->ban_list, 
4501                                        sizeof(*channel->ban_list) * 
4502                                        (tmp_len + 
4503                                         strlen(channel->ban_list) + 2));
4504     if (add[tmp_len - 1] == ',')
4505       add[tmp_len - 1] = '\0';
4506
4507     strncat(channel->ban_list, add, tmp_len);
4508     strncat(channel->ban_list, ",", 1);
4509   }
4510
4511   /* Get the ban to be removed and remove it from the list */
4512   del = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
4513   if (del && channel->ban_list) {
4514     char *start, *end, *n;
4515
4516     if (!strncmp(channel->ban_list, del, strlen(channel->ban_list) - 1)) {
4517       silc_free(channel->ban_list);
4518       channel->ban_list = NULL;
4519     } else {
4520       start = strstr(channel->ban_list, del);
4521       if (start && strlen(start) >= tmp_len) {
4522         end = start + tmp_len;
4523         n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
4524         strncat(n, channel->ban_list, start - channel->ban_list);
4525         strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) - 
4526                              end) - 1);
4527         silc_free(channel->ban_list);
4528         channel->ban_list = n;
4529       }
4530     }
4531   }
4532
4533   /* Send the BAN notify type to our primary router. */
4534   if (!server->standalone && (add || del))
4535     silc_server_send_notify_ban(server, server->router->connection,
4536                                 server->server_type == SILC_ROUTER ?
4537                                 TRUE : FALSE, channel, add, del);
4538
4539   /* Send the reply back to the client */
4540   if (channel->ban_list)
4541     packet = 
4542       silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
4543                                            SILC_STATUS_OK, ident, 2,
4544                                            2, id, id_len,
4545                                            3, channel->ban_list, 
4546                                            strlen(channel->ban_list) - 1);
4547   else
4548     packet = 
4549       silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
4550                                            SILC_STATUS_OK, ident, 1,
4551                                            2, id, id_len);
4552
4553   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
4554                           packet->data, packet->len, FALSE);
4555     
4556   silc_buffer_free(packet);
4557
4558  out:
4559   if (channel_id)
4560     silc_free(channel_id);
4561   silc_server_command_free(cmd);
4562 }
4563
4564 /* Server side command of CLOSE. Closes connection to a specified server. */
4565  
4566 SILC_SERVER_CMD_FUNC(close)
4567 {
4568   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4569   SilcServer server = cmd->server;
4570   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4571   SilcServerEntry server_entry;
4572   SilcSocketConnection sock;
4573   unsigned char *tmp;
4574   uint32 tmp_len;
4575   unsigned char *name;
4576   uint32 port = SILC_PORT;
4577
4578   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CLOSE, cmd, 1, 2);
4579
4580   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4581     goto out;
4582
4583   /* Check whether client has the permissions. */
4584   if (client->mode == SILC_UMODE_NONE) {
4585     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4586                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
4587     goto out;
4588   }
4589
4590   /* Get the remote server */
4591   name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4592   if (!name) {
4593     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4594                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4595     goto out;
4596   }
4597
4598   /* Get port */
4599   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4600   if (tmp)
4601     SILC_GET32_MSB(port, tmp);
4602
4603   server_entry = silc_idlist_find_server_by_conn(server->local_list,
4604                                                  name, port, FALSE, NULL);
4605   if (!server_entry) {
4606     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4607                                           SILC_STATUS_ERR_NO_SERVER_ID);
4608     goto out;
4609   }
4610
4611   /* Send reply to the sender */
4612   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4613                                         SILC_STATUS_OK);
4614
4615   /* Close the connection to the server */
4616   sock = (SilcSocketConnection)server_entry->connection;
4617   silc_server_free_sock_user_data(server, sock);
4618   silc_server_close_connection(server, sock);
4619   
4620  out:
4621   silc_server_command_free(cmd);
4622 }
4623
4624 /* Server side command of SHUTDOWN. Shutdowns the server and closes all
4625    active connections. */
4626  
4627 SILC_SERVER_CMD_FUNC(shutdown)
4628 {
4629   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4630   SilcServer server = cmd->server;
4631   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4632
4633   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SHUTDOWN, cmd, 0, 0);
4634
4635   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4636     goto out;
4637
4638   /* Check whether client has the permission. */
4639   if (client->mode == SILC_UMODE_NONE) {
4640     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
4641                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
4642     goto out;
4643   }
4644
4645   /* Send reply to the sender */
4646   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
4647                                         SILC_STATUS_OK);
4648
4649   /* Then, gracefully, or not, bring the server down. */
4650   silc_server_stop(server);
4651   exit(0);
4652
4653  out:
4654   silc_server_command_free(cmd);
4655 }
4656  
4657 /* Server side command of LEAVE. Removes client from a channel. */
4658
4659 SILC_SERVER_CMD_FUNC(leave)
4660 {
4661   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4662   SilcServer server = cmd->server;
4663   SilcSocketConnection sock = cmd->sock;
4664   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
4665   SilcChannelID *id = NULL;
4666   SilcChannelEntry channel;
4667   uint32 len;
4668   unsigned char *tmp;
4669
4670   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 2);
4671
4672   /* Get Channel ID */
4673   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
4674   if (!tmp) {
4675     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4676                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4677     goto out;
4678   }
4679   id = silc_id_payload_parse_id(tmp, len);
4680   if (!id) {
4681     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4682                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4683     goto out;
4684   }
4685
4686   /* Get channel entry */
4687   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
4688   if (!channel) {
4689     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
4690     if (!channel) {
4691       silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4692                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
4693       goto out;
4694     }
4695   }
4696
4697   /* Check whether this client is on the channel */
4698   if (!silc_server_client_on_channel(id_entry, channel)) {
4699     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4700                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
4701     goto out;
4702   }
4703
4704   /* Notify routers that they should remove this client from their list
4705      of clients on the channel. Send LEAVE notify type. */
4706   if (!server->standalone)
4707     silc_server_send_notify_leave(server, server->router->connection,
4708                                   server->server_type == SILC_ROUTER ?
4709                                   TRUE : FALSE, channel, id_entry->id);
4710
4711   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4712                                         SILC_STATUS_OK);
4713
4714   /* Remove client from channel */
4715   if (!silc_server_remove_from_one_channel(server, sock, channel, id_entry,
4716                                            TRUE))
4717     /* If the channel does not exist anymore we won't send anything */
4718     goto out;
4719
4720   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
4721     /* Re-generate channel key */
4722     if (!silc_server_create_channel_key(server, channel, 0))
4723       goto out;
4724
4725     /* Send the channel key */
4726     silc_server_send_channel_key(server, NULL, channel, 
4727                                  server->server_type == SILC_ROUTER ? 
4728                                  FALSE : !server->standalone);
4729   }
4730
4731  out:
4732   if (id)
4733     silc_free(id);
4734   silc_server_command_free(cmd);
4735 }
4736
4737 /* Server side of command USERS. Resolves clients and their USERS currently
4738    joined on the requested channel. The list of Client ID's and their modes
4739    on the channel is sent back. */
4740
4741 SILC_SERVER_CMD_FUNC(users)
4742 {
4743   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4744   SilcServer server = cmd->server;
4745   SilcChannelEntry channel;
4746   SilcChannelID *id = NULL;
4747   SilcBuffer packet, idp;
4748   unsigned char *channel_id;
4749   uint32 channel_id_len;
4750   SilcBuffer client_id_list;
4751   SilcBuffer client_mode_list;
4752   unsigned char lc[4];
4753   uint32 list_count = 0;
4754   uint16 ident = silc_command_get_ident(cmd->payload);
4755   char *channel_name;
4756
4757   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_USERS, cmd, 1, 2);
4758
4759   /* Get Channel ID */
4760   channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
4761
4762   /* Get channel name */
4763   channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
4764
4765   if (!channel_id && !channel_name) {
4766     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4767                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4768     goto out;
4769   }
4770
4771   if (channel_id) {
4772     id = silc_id_payload_parse_id(channel_id, channel_id_len);
4773     if (!id) {
4774       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4775                                             SILC_STATUS_ERR_NO_CHANNEL_ID);
4776       goto out;
4777     }
4778   }
4779
4780   /* If we are server and we don't know about this channel we will send
4781      the command to our router. If we know about the channel then we also
4782      have the list of users already. */
4783   if (id)
4784     channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
4785   else
4786     channel = silc_idlist_find_channel_by_name(server->local_list, 
4787                                                channel_name, NULL);
4788
4789   if (!channel) {
4790     if (server->server_type == SILC_SERVER && !server->standalone &&
4791         !cmd->pending) {
4792       SilcBuffer tmpbuf;
4793       
4794       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
4795       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
4796       
4797       /* Send USERS command */
4798       silc_server_packet_send(server, server->router->connection,
4799                               SILC_PACKET_COMMAND, cmd->packet->flags,
4800                               tmpbuf->data, tmpbuf->len, TRUE);
4801       
4802       /* Reprocess this packet after received reply */
4803       silc_server_command_pending(server, SILC_COMMAND_USERS, 
4804                                   silc_command_get_ident(cmd->payload),
4805                                   silc_server_command_destructor,
4806                                   silc_server_command_users,
4807                                   silc_server_command_dup(cmd));
4808       cmd->pending = TRUE;
4809       silc_command_set_ident(cmd->payload, ident);
4810       
4811       silc_buffer_free(tmpbuf);
4812       silc_free(id);
4813       return;
4814     }
4815
4816     /* Check the global list as well. */
4817     if (id)
4818       channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
4819     else
4820       channel = silc_idlist_find_channel_by_name(server->global_list, 
4821                                                  channel_name, NULL);
4822     if (!channel) {
4823       /* Channel really does not exist */
4824       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4825                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
4826       goto out;
4827     }
4828   }
4829
4830   /* If the channel is private or secret do not send anything */
4831   if (channel->mode & (SILC_CHANNEL_MODE_PRIVATE | SILC_CHANNEL_MODE_SECRET)) {
4832     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4833                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
4834     goto out;
4835   }
4836
4837   /* Get the users list */
4838   silc_server_get_users_on_channel(server, channel, &client_id_list,
4839                                    &client_mode_list, &list_count);
4840
4841   /* List count */
4842   SILC_PUT32_MSB(list_count, lc);
4843
4844   /* Send reply */
4845   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
4846   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
4847                                                 SILC_STATUS_OK, ident, 4,
4848                                                 2, idp->data, idp->len,
4849                                                 3, lc, 4,
4850                                                 4, client_id_list->data,
4851                                                 client_id_list->len,
4852                                                 5, client_mode_list->data,
4853                                                 client_mode_list->len);
4854   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
4855                           packet->data, packet->len, FALSE);
4856     
4857   silc_buffer_free(idp);
4858   silc_buffer_free(packet);
4859   silc_buffer_free(client_id_list);
4860   silc_buffer_free(client_mode_list);
4861   if (id)
4862     silc_free(id);
4863
4864  out:
4865   silc_server_command_free(cmd);
4866 }
4867
4868 /* Server side of command GETKEY. This fetches the client's public key
4869    from the server where to the client is connected. */
4870
4871 SILC_SERVER_CMD_FUNC(getkey)
4872 {
4873   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4874   SilcServer server = cmd->server;
4875   SilcBuffer packet;
4876   SilcClientEntry client;
4877   SilcServerEntry server_entry;
4878   SilcClientID *client_id = NULL;
4879   SilcServerID *server_id = NULL;
4880   SilcIDPayload idp = NULL;
4881   uint16 ident = silc_command_get_ident(cmd->payload);
4882   unsigned char *tmp;
4883   uint32 tmp_len;
4884   SilcBuffer pk;
4885   SilcIdType id_type;
4886
4887   SILC_LOG_DEBUG(("Start"));
4888
4889   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4890   if (!tmp) {
4891     silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
4892                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4893     goto out;
4894   }
4895   idp = silc_id_payload_parse_data(tmp, tmp_len);
4896   if (!idp) {
4897     silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
4898                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4899     goto out;
4900   }
4901
4902   id_type = silc_id_payload_get_type(idp);
4903   if (id_type == SILC_ID_CLIENT) {
4904     client_id = silc_id_payload_get_id(idp);
4905
4906     /* If the client is not found from local list there is no chance it
4907        would be locally connected client so send the command further. */
4908     client = silc_idlist_find_client_by_id(server->local_list, 
4909                                            client_id, TRUE, NULL);
4910     if (!client)
4911       client = silc_idlist_find_client_by_id(server->global_list, 
4912                                              client_id, TRUE, NULL);
4913     
4914     if ((!client && !cmd->pending && !server->standalone) ||
4915         (client && !client->connection && !cmd->pending && 
4916          !server->standalone) ||
4917         (client && !client->data.public_key && !cmd->pending &&
4918          !server->standalone)) {
4919       SilcBuffer tmpbuf;
4920       uint16 old_ident;
4921       SilcSocketConnection dest_sock;
4922       
4923       dest_sock = silc_server_get_client_route(server, NULL, 0, 
4924                                                client_id, NULL);
4925       if (!dest_sock)
4926         goto out;
4927       
4928       old_ident = silc_command_get_ident(cmd->payload);
4929       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
4930       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
4931       
4932       silc_server_packet_send(server, dest_sock,
4933                               SILC_PACKET_COMMAND, cmd->packet->flags,
4934                               tmpbuf->data, tmpbuf->len, TRUE);
4935       
4936       /* Reprocess this packet after received reply from router */
4937       silc_server_command_pending(server, SILC_COMMAND_GETKEY, 
4938                                   silc_command_get_ident(cmd->payload),
4939                                   silc_server_command_destructor,
4940                                   silc_server_command_getkey,
4941                                   silc_server_command_dup(cmd));
4942       cmd->pending = TRUE;
4943       
4944       silc_command_set_ident(cmd->payload, old_ident);
4945       silc_buffer_free(tmpbuf);
4946       return;
4947     }
4948
4949     if (!client && cmd->pending) {
4950       silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
4951                                             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
4952       goto out;
4953     }
4954
4955     /* The client is locally connected, just get the public key and
4956        send it back. */
4957     tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
4958     pk = silc_buffer_alloc(4 + tmp_len);
4959     silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
4960     silc_buffer_format(pk,
4961                        SILC_STR_UI_SHORT(tmp_len),
4962                        SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
4963                        SILC_STR_UI_XNSTRING(tmp, tmp_len),
4964                        SILC_STR_END);
4965     silc_free(tmp);
4966
4967   } else if (id_type == SILC_ID_SERVER) {
4968     server_id = silc_id_payload_get_id(idp);
4969
4970     /* If the server is not found from local list there is no chance it
4971        would be locally connected server so send the command further. */
4972     server_entry = silc_idlist_find_server_by_id(server->local_list, 
4973                                                  server_id, TRUE, NULL);
4974     if (!server_entry)
4975       server_entry = silc_idlist_find_server_by_id(server->global_list, 
4976                                                    server_id, TRUE, NULL);
4977     
4978     if ((!server_entry && !cmd->pending && !server->standalone) ||
4979         (server_entry && !server_entry->connection && !cmd->pending &&
4980          !server->standalone) ||
4981         (server_entry && !server_entry->data.public_key && !cmd->pending &&
4982          !server->standalone)) {
4983       SilcBuffer tmpbuf;
4984       uint16 old_ident;
4985       
4986       old_ident = silc_command_get_ident(cmd->payload);
4987       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
4988       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
4989       
4990       silc_server_packet_send(server, server->router->connection,
4991                               SILC_PACKET_COMMAND, cmd->packet->flags,
4992                               tmpbuf->data, tmpbuf->len, TRUE);
4993       
4994       /* Reprocess this packet after received reply from router */
4995       silc_server_command_pending(server, SILC_COMMAND_GETKEY, 
4996                                   silc_command_get_ident(cmd->payload),
4997                                   silc_server_command_destructor,
4998                                   silc_server_command_getkey,
4999                                   silc_server_command_dup(cmd));
5000       cmd->pending = TRUE;
5001       
5002       silc_command_set_ident(cmd->payload, old_ident);
5003       silc_buffer_free(tmpbuf);
5004       return;
5005     }
5006
5007     if (!server_entry && cmd->pending) {
5008       silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
5009                                             SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
5010       goto out;
5011     }
5012
5013     /* The client is locally connected, just get the public key and
5014        send it back. */
5015     tmp = silc_pkcs_public_key_encode(server_entry->data.public_key, &tmp_len);
5016     pk = silc_buffer_alloc(4 + tmp_len);
5017     silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
5018     silc_buffer_format(pk,
5019                        SILC_STR_UI_SHORT(tmp_len),
5020                        SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
5021                        SILC_STR_UI_XNSTRING(tmp, tmp_len),
5022                        SILC_STR_END);
5023     silc_free(tmp);
5024   } else {
5025     goto out;
5026   }
5027
5028   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5029   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY,
5030                                                 SILC_STATUS_OK, ident, 2,
5031                                                 2, tmp, tmp_len,
5032                                                 3, pk->data, pk->len);
5033   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
5034                           packet->data, packet->len, FALSE);
5035   silc_buffer_free(packet);
5036   silc_buffer_free(pk);
5037
5038  out:
5039   if (idp)
5040     silc_id_payload_free(idp);
5041   silc_free(client_id);
5042   silc_free(server_id);
5043   silc_server_command_free(cmd);
5044 }