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