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