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