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
2095 SILC_SERVER_CMD_FUNC(invite)
2096 {
2097   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2098   SilcServer server = cmd->server;
2099   SilcSocketConnection sock = cmd->sock, dest_sock;
2100   SilcClientEntry sender, dest;
2101   SilcClientID *dest_id;
2102   SilcChannelEntry channel;
2103   SilcChannelID *channel_id;
2104   SilcBuffer sidp;
2105   unsigned char *tmp;
2106   unsigned int len;
2107
2108   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 2);
2109
2110   /* Get destination ID */
2111   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2112   if (!tmp) {
2113     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2114                                           SILC_STATUS_ERR_NO_CLIENT_ID);
2115     goto out;
2116   }
2117   dest_id = silc_id_payload_parse_id(tmp, len);
2118   if (!dest_id) {
2119     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2120                                           SILC_STATUS_ERR_NO_CLIENT_ID);
2121     goto out;
2122   }
2123
2124   /* Get Channel ID */
2125   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2126   if (!tmp) {
2127     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2128                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2129     goto out;
2130   }
2131   channel_id = silc_id_payload_parse_id(tmp, len);
2132   if (!channel_id) {
2133     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2134                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2135     goto out;
2136   }
2137
2138   /* Check whether the channel exists */
2139   channel = silc_idlist_find_channel_by_id(server->local_list, 
2140                                            channel_id, NULL);
2141   if (!channel) {
2142     channel = silc_idlist_find_channel_by_id(server->global_list, 
2143                                              channel_id, NULL);
2144     if (!channel) {
2145       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2146                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2147       goto out;
2148     }
2149   }
2150
2151   /* Check whether the sender of this command is on the channel. */
2152   sender = (SilcClientEntry)sock->user_data;
2153   if (!silc_server_client_on_channel(sender, channel)) {
2154     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2155                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2156     goto out;
2157   }
2158
2159   /* Check whether the channel is invite-only channel. If yes then the
2160      sender of this command must be at least channel operator. */
2161   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
2162     SilcChannelClientEntry chl;
2163
2164     silc_list_start(channel->user_list);
2165     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2166       if (chl->client == sender) {
2167         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
2168           silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2169                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2170           goto out;
2171         }
2172         break;
2173       }
2174   }
2175
2176   /* Find the connection data for the destination. If it is local we will
2177      send it directly otherwise we will send it to router for routing. */
2178   dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
2179   if (dest)
2180     dest_sock = (SilcSocketConnection)dest->connection;
2181   else
2182     dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
2183
2184   /* Check whether the requested client is already on the channel. */
2185   /* XXX if we are normal server we don't know about global clients on
2186      the channel thus we must request it (USERS command), check from
2187      local cache as well. */
2188   if (silc_server_client_on_channel(dest, channel)) {
2189     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2190                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
2191     goto out;
2192   }
2193
2194   sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
2195
2196   /* Send notify to the client that is invited to the channel */
2197   silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, 
2198                                SILC_ID_CLIENT,
2199                                SILC_NOTIFY_TYPE_INVITE, 2, 
2200                                sidp->data, sidp->len, tmp, len);
2201
2202   /* Send command reply */
2203   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2204                                         SILC_STATUS_OK);
2205
2206   silc_buffer_free(sidp);
2207
2208  out:
2209   silc_server_command_free(cmd);
2210 }
2211
2212 typedef struct {
2213   SilcServer server;
2214   SilcSocketConnection sock;
2215   char *signoff;
2216 } *QuitInternal;
2217
2218 /* Quits connection to client. This gets called if client won't
2219    close the connection even when it has issued QUIT command. */
2220
2221 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
2222 {
2223   QuitInternal q = (QuitInternal)context;
2224
2225   /* Free all client specific data, such as client entry and entires
2226      on channels this client may be on. */
2227   silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
2228                                TRUE, q->signoff);
2229   q->sock->user_data = NULL;
2230
2231   /* Close the connection on our side */
2232   silc_server_close_connection(q->server, q->sock);
2233
2234   silc_free(q->signoff);
2235   silc_free(q);
2236 }
2237
2238 /* Quits SILC session. This is the normal way to disconnect client. */
2239  
2240 SILC_SERVER_CMD_FUNC(quit)
2241 {
2242   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2243   SilcServer server = cmd->server;
2244   SilcSocketConnection sock = cmd->sock;
2245   QuitInternal q;
2246   unsigned char *tmp = NULL;
2247   unsigned int len = 0;
2248
2249   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_QUIT, cmd, 0, 1);
2250
2251   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
2252     goto out;
2253
2254   /* Get destination ID */
2255   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2256   if (len > 128)
2257     tmp = NULL;
2258
2259   q = silc_calloc(1, sizeof(*q));
2260   q->server = server;
2261   q->sock = sock;
2262   q->signoff = tmp ? strdup(tmp) : NULL;
2263
2264   /* We quit the connection with little timeout */
2265   silc_task_register(server->timeout_queue, sock->sock,
2266                      silc_server_command_quit_cb, (void *)q,
2267                      0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
2268
2269  out:
2270   silc_server_command_free(cmd);
2271 }
2272
2273 /* Server side of command KILL. This command is used by router operator
2274    to remove an client from the SILC Network temporarily. */
2275
2276 SILC_SERVER_CMD_FUNC(kill)
2277 {
2278   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2279   SilcServer server = cmd->server;
2280   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2281   SilcClientEntry remote_client;
2282   SilcClientID *client_id;
2283   unsigned char *tmp, *comment;
2284   unsigned int tmp_len, tmp_len2;
2285
2286   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_KILL, cmd, 1, 2);
2287
2288   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
2289     goto out;
2290
2291   /* KILL command works only on router */
2292   if (server->server_type != SILC_ROUTER) {
2293     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2294                                           SILC_STATUS_ERR_NO_ROUTER_PRIV);
2295     goto out;
2296   }
2297
2298   /* Check whether client has the permissions. */
2299   if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
2300     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2301                                           SILC_STATUS_ERR_NO_ROUTER_PRIV);
2302     goto out;
2303   }
2304
2305   /* Get the client ID */
2306   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2307   if (!tmp) {
2308     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2309                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2310     goto out;
2311   }
2312   client_id = silc_id_payload_parse_id(tmp, tmp_len);
2313   if (!client_id) {
2314     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2315                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
2316     goto out;
2317   }
2318
2319   /* Get the client entry */
2320   remote_client = silc_idlist_find_client_by_id(server->local_list, 
2321                                                 client_id, NULL);
2322   if (!remote_client) {
2323     remote_client = silc_idlist_find_client_by_id(server->global_list, 
2324                                                   client_id, NULL);
2325     if (!remote_client) {
2326       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2327                                             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
2328       goto out;
2329     }
2330   }
2331
2332   /* Get comment */
2333   comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
2334   if (tmp_len2 > 128)
2335     comment = NULL;
2336
2337   /* Send reply to the sender */
2338   silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2339                                         SILC_STATUS_OK);
2340
2341   /* Send the KILL notify packets. First send it to the channel, then
2342      to our primary router and then directly to the client who is being
2343      killed right now. */
2344
2345   /* Send KILLED notify to the channels. It is not sent to the client
2346      as it will be sent differently destined directly to the client and not
2347      to the channel. */
2348   silc_server_send_notify_on_channels(server, remote_client, 
2349                                       remote_client, SILC_NOTIFY_TYPE_KILLED,
2350                                       comment ? 2 : 1,
2351                                       tmp, tmp_len,
2352                                       comment, comment ? tmp_len2 : 0);
2353
2354   /* Send KILLED notify to primary route */
2355   if (!server->standalone)
2356     silc_server_send_notify_killed(server, server->router->connection, TRUE,
2357                                    remote_client->id, SILC_ID_CLIENT_LEN,
2358                                    comment);
2359
2360   /* Send KILLED notify to the client directly */
2361   silc_server_send_notify_killed(server, remote_client->connection ? 
2362                                  remote_client->connection : 
2363                                  remote_client->router->connection, FALSE,
2364                                  remote_client->id, SILC_ID_CLIENT_LEN,
2365                                  comment);
2366
2367   /* Remove the client from all channels. This generates new keys to the
2368      channels as well. */
2369   silc_server_remove_from_channels(server, NULL, remote_client, FALSE, 
2370                                    NULL, TRUE);
2371
2372   /* Remove the client entry, If it is locally connected then we will also
2373      disconnect the client here */
2374   if (remote_client->data.registered && remote_client->connection) {
2375     /* Remove locally conneted client */
2376     SilcSocketConnection sock = remote_client->connection;
2377     silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
2378     silc_server_close_connection(server, sock);
2379   } else {
2380     /* Remove remote client */
2381     if (!silc_idlist_del_client(server->global_list, remote_client))
2382       silc_idlist_del_client(server->local_list, remote_client);
2383   }
2384
2385  out:
2386   silc_server_command_free(cmd);
2387 }
2388
2389 /* Server side of command INFO. This sends information about us to 
2390    the client. If client requested specific server we will send the 
2391    command to that server. */
2392
2393 SILC_SERVER_CMD_FUNC(info)
2394 {
2395   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2396   SilcServer server = cmd->server;
2397   SilcBuffer packet, idp;
2398   char *dest_server, *server_info = NULL, *server_name;
2399   unsigned short ident = silc_command_get_ident(cmd->payload);
2400   SilcServerEntry entry = NULL;
2401
2402   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
2403
2404   /* Get server name */
2405   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
2406   if (!dest_server) {
2407     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
2408                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
2409     goto out;
2410   }
2411
2412   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
2413     /* Send our reply */
2414     char info_string[256];
2415
2416     memset(info_string, 0, sizeof(info_string));
2417     snprintf(info_string, sizeof(info_string), 
2418              "location: %s server: %s admin: %s <%s>",
2419              server->config->admin_info->location,
2420              server->config->admin_info->server_type,
2421              server->config->admin_info->admin_name,
2422              server->config->admin_info->admin_email);
2423
2424     server_info = info_string;
2425     entry = server->id_entry;
2426   } else {
2427     /* Check whether we have this server cached */
2428     entry = silc_idlist_find_server_by_name(server->global_list,
2429                                             dest_server, NULL);
2430     if (!entry) {
2431       entry = silc_idlist_find_server_by_name(server->local_list,
2432                                               dest_server, NULL);
2433     }
2434
2435     if (server->server_type == SILC_ROUTER && entry && !entry->server_info) {
2436       /* Send to the server */
2437       SilcBuffer tmpbuf;
2438       unsigned short old_ident;
2439
2440       old_ident = silc_command_get_ident(cmd->payload);
2441       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2442       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2443
2444       silc_server_packet_send(server, entry->connection,
2445                               SILC_PACKET_COMMAND, cmd->packet->flags,
2446                               tmpbuf->data, tmpbuf->len, TRUE);
2447
2448       /* Reprocess this packet after received reply from router */
2449       silc_server_command_pending(server, SILC_COMMAND_INFO, 
2450                                   silc_command_get_ident(cmd->payload),
2451                                   silc_server_command_destructor,
2452                                   silc_server_command_info,
2453                                   silc_server_command_dup(cmd));
2454       cmd->pending = TRUE;
2455       silc_command_set_ident(cmd->payload, old_ident);
2456       silc_buffer_free(tmpbuf);
2457       return;
2458     }
2459
2460     if (!entry && !cmd->pending && !server->standalone) {
2461       /* Send to the primary router */
2462       SilcBuffer tmpbuf;
2463       unsigned short old_ident;
2464
2465       old_ident = silc_command_get_ident(cmd->payload);
2466       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2467       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2468
2469       silc_server_packet_send(server, server->router->connection,
2470                               SILC_PACKET_COMMAND, cmd->packet->flags,
2471                               tmpbuf->data, tmpbuf->len, TRUE);
2472
2473       /* Reprocess this packet after received reply from router */
2474       silc_server_command_pending(server, SILC_COMMAND_INFO, 
2475                                   silc_command_get_ident(cmd->payload),
2476                                   silc_server_command_destructor,
2477                                   silc_server_command_info,
2478                                   silc_server_command_dup(cmd));
2479       cmd->pending = TRUE;
2480       silc_command_set_ident(cmd->payload, old_ident);
2481       silc_buffer_free(tmpbuf);
2482       return;
2483     }
2484   }
2485
2486   if (!entry) {
2487     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
2488                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
2489     goto out;
2490   }
2491
2492   idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
2493   if (!server_info)
2494     server_info = entry->server_info;
2495   server_name = dest_server;
2496
2497   /* Send the reply */
2498   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
2499                                                 SILC_STATUS_OK, ident, 3,
2500                                                 2, idp->data, idp->len,
2501                                                 3, server_name, 
2502                                                 strlen(server_name),
2503                                                 4, server_info, 
2504                                                 strlen(server_info));
2505   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2506                           packet->data, packet->len, FALSE);
2507     
2508   silc_buffer_free(packet);
2509   silc_buffer_free(idp);
2510
2511  out:
2512   silc_server_command_free(cmd);
2513 }
2514
2515 /* Server side of command PING. This just replies to the ping. */
2516
2517 SILC_SERVER_CMD_FUNC(ping)
2518 {
2519   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2520   SilcServer server = cmd->server;
2521   SilcServerID *id;
2522   unsigned int len;
2523   unsigned char *tmp;
2524
2525   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
2526
2527   /* Get Server ID */
2528   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2529   if (!tmp) {
2530     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
2531                                           SILC_STATUS_ERR_NO_SERVER_ID);
2532     goto out;
2533   }
2534   id = silc_id_str2id(tmp, len, SILC_ID_SERVER);
2535   if (!id)
2536     goto out;
2537
2538   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
2539     /* Send our reply */
2540     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
2541                                           SILC_STATUS_OK);
2542   } else {
2543     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
2544                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
2545     goto out;
2546   }
2547
2548   silc_free(id);
2549
2550  out:
2551   silc_server_command_free(cmd);
2552 }
2553
2554 /* Internal routine to join channel. The channel sent to this function
2555    has been either created or resolved from ID lists. This joins the sent
2556    client to the channel. */
2557
2558 static void silc_server_command_join_channel(SilcServer server, 
2559                                              SilcServerCommandContext cmd,
2560                                              SilcChannelEntry channel,
2561                                              SilcClientID *client_id,
2562                                              int created,
2563                                              unsigned int umode)
2564 {
2565   SilcSocketConnection sock = cmd->sock;
2566   unsigned char *tmp;
2567   unsigned int tmp_len, user_count;
2568   unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
2569   SilcClientEntry client;
2570   SilcChannelClientEntry chl;
2571   SilcBuffer reply, chidp, clidp, keyp, user_list, mode_list;
2572   unsigned short ident = silc_command_get_ident(cmd->payload);
2573   char check[512];
2574
2575   SILC_LOG_DEBUG(("Start"));
2576
2577   if (!channel)
2578     return;
2579
2580   /* Get the client entry */
2581   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2582     client = (SilcClientEntry)sock->user_data;
2583   } else {
2584     client = silc_idlist_find_client_by_id(server->local_list, client_id, 
2585                                            NULL);
2586     if (!client)
2587       goto out;
2588   }
2589
2590   /*
2591    * Check channel modes
2592    */
2593
2594   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2595     strncat(check, client->nickname, strlen(client->nickname));
2596     if (!strchr(client->nickname, '@')) {
2597       strncat(check, "@", 1);
2598       strncat(check, server->server_name, strlen(server->server_name));
2599     }
2600     strncat(check, "!", 1);
2601     strncat(check, client->username, strlen(client->username));
2602     if (!strchr(client->username, '@')) {
2603       strncat(check, "@", 1);
2604       strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
2605     }
2606   }
2607
2608   /* Check invite list if channel is invite-only channel */
2609   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
2610       channel->mode & SILC_CHANNEL_MODE_INVITE && channel->invite_list) {
2611     if (!silc_string_match(channel->invite_list, check)) {
2612       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2613                                             SILC_STATUS_ERR_NOT_INVITED);
2614       goto out;
2615     }
2616   }
2617
2618   /* Check ban list if it exists. If the client's nickname, server,
2619      username and/or hostname is in the ban list the access to the
2620      channel is denied. */
2621   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && channel->ban_list) {
2622     if (silc_string_match(channel->ban_list, check)) {
2623       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2624                               SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
2625       goto out;
2626     }
2627   }
2628
2629   /* Get passphrase */
2630   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2631   if (tmp) {
2632     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
2633     memcpy(passphrase, tmp, tmp_len);
2634   }
2635   
2636   /* Check the channel passphrase if set. */
2637   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2638     if (!passphrase || memcmp(channel->passphrase, passphrase,
2639                               strlen(channel->passphrase))) {
2640       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2641                                             SILC_STATUS_ERR_BAD_PASSWORD);
2642       goto out;
2643     }
2644   }
2645
2646   /* Check user count limit if set. */
2647   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
2648     if (silc_list_count(channel->user_list) + 1 > 
2649         channel->user_limit) {
2650       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2651                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
2652       goto out;
2653     }
2654   }
2655
2656   /*
2657    * Client is allowed to join to the channel. Make it happen.
2658    */
2659
2660   /* Check whether the client already is on the channel */
2661   if (silc_server_client_on_channel(client, channel)) {
2662     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2663                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
2664     goto out;
2665   }
2666
2667   /* Generate new channel key as protocol dictates */
2668   if ((!created && silc_list_count(channel->user_list) > 0) || 
2669       !channel->channel_key)
2670     silc_server_create_channel_key(server, channel, 0);
2671
2672   /* Send the channel key. This is broadcasted to the channel but is not
2673      sent to the client who is joining to the channel. */
2674   silc_server_send_channel_key(server, NULL, channel, 
2675                                server->server_type == SILC_ROUTER ? 
2676                                FALSE : !server->standalone);
2677
2678   /* Join the client to the channel by adding it to channel's user list.
2679      Add also the channel to client entry's channels list for fast cross-
2680      referencing. */
2681   chl = silc_calloc(1, sizeof(*chl));
2682   chl->mode = umode;
2683   chl->client = client;
2684   chl->channel = channel;
2685   silc_list_add(channel->user_list, chl);
2686   silc_list_add(client->channels, chl);
2687
2688   /* Get users on the channel */
2689   silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
2690                                    &user_count);
2691
2692   /* Encode Client ID Payload of the original client who wants to join */
2693   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2694
2695   /* Encode command reply packet */
2696   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2697   SILC_PUT32_MSB(channel->mode, mode);
2698   SILC_PUT32_MSB(created, tmp2);
2699   SILC_PUT32_MSB(user_count, tmp3);
2700   tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
2701   keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp, 
2702                                          strlen(channel->channel_key->
2703                                                 cipher->name),
2704                                          channel->channel_key->cipher->name,
2705                                          channel->key_len / 8, channel->key);
2706   silc_free(tmp);
2707   reply = 
2708     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
2709                                          SILC_STATUS_OK, ident, 13,
2710                                          2, channel->channel_name,
2711                                          strlen(channel->channel_name),
2712                                          3, chidp->data, chidp->len,
2713                                          4, clidp->data, clidp->len,
2714                                          5, mode, 4,
2715                                          6, tmp2, 4,
2716                                          7, keyp->data, keyp->len,
2717                                          8, channel->ban_list, 
2718                                          channel->ban_list ?
2719                                          strlen(channel->ban_list) : 0,
2720                                          9, channel->invite_list,
2721                                          channel->invite_list ?
2722                                          strlen(channel->invite_list) : 0,
2723                                          10, channel->topic,
2724                                          channel->topic ?
2725                                          strlen(channel->topic) : 0,
2726                                          11, channel->hmac->hmac->name,
2727                                          strlen(channel->hmac->hmac->name),
2728                                          12, tmp3, 4,
2729                                          13, user_list->data, user_list->len,
2730                                          14, mode_list->data, 
2731                                          mode_list->len);
2732
2733   /* Send command reply */
2734   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
2735                           reply->data, reply->len, FALSE);
2736
2737   if (!cmd->pending) {
2738     /* Send JOIN notify to locally connected clients on the channel */
2739     silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
2740                                        SILC_NOTIFY_TYPE_JOIN, 2,
2741                                        clidp->data, clidp->len,
2742                                        chidp->data, chidp->len);
2743
2744     /* Send JOIN notify packet to our primary router */
2745     if (!server->standalone)
2746       silc_server_send_notify_join(server, server->router->connection,
2747                                    server->server_type == SILC_ROUTER ?
2748                                    TRUE : FALSE, channel, client->id,
2749                                    SILC_ID_CLIENT_LEN);
2750   }
2751
2752   silc_buffer_free(reply);
2753   silc_buffer_free(clidp);
2754   silc_buffer_free(chidp);
2755   silc_buffer_free(keyp);
2756   silc_buffer_free(user_list);
2757   silc_buffer_free(mode_list);
2758
2759  out:
2760   if (passphrase)
2761     silc_free(passphrase);
2762 }
2763
2764 /* Server side of command JOIN. Joins client into requested channel. If 
2765    the channel does not exist it will be created. */
2766
2767 SILC_SERVER_CMD_FUNC(join)
2768 {
2769   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2770   SilcServer server = cmd->server;
2771   int tmp_len;
2772   char *tmp, *channel_name = NULL, *cipher, *hmac;
2773   SilcChannelEntry channel;
2774   unsigned int umode = 0;
2775   int created = FALSE;
2776   SilcClientID *client_id;
2777
2778   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 4);
2779
2780   /* Get channel name */
2781   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2782   if (!tmp) {
2783     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2784                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2785     goto out;
2786   }
2787   channel_name = tmp;
2788
2789   if (strlen(channel_name) > 256)
2790     channel_name[255] = '\0';
2791
2792   if (silc_server_command_bad_chars(channel_name) == TRUE) {
2793     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2794                                           SILC_STATUS_ERR_BAD_CHANNEL);
2795     silc_free(channel_name);
2796     goto out;
2797   }
2798
2799   /* Get Client ID of the client who is joining to the channel */
2800   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2801   if (!tmp) {
2802     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2803                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2804     goto out;
2805   }
2806   client_id = silc_id_payload_parse_id(tmp, tmp_len);
2807   if (!client_id) {
2808     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2809                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2810     goto out;
2811   }
2812
2813   /* Get cipher and hmac name */
2814   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
2815   hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
2816
2817   /* See if the channel exists */
2818   channel = silc_idlist_find_channel_by_name(server->local_list, 
2819                                              channel_name, NULL);
2820
2821   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2822     /* If this is coming from client the Client ID in the command packet must
2823        be same as the client's ID. */
2824     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2825       SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
2826       if (SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
2827         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2828                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2829         goto out;
2830       }
2831     }
2832
2833     if (!channel) {
2834       /* Channel not found */
2835
2836       /* If we are standalone server we don't have a router, we just create 
2837          the channel by ourselves. */
2838       if (server->standalone) {
2839         channel = silc_server_create_new_channel(server, server->id, cipher, 
2840                                                  hmac, channel_name, TRUE);
2841         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2842         created = TRUE;
2843
2844       } else {
2845
2846         /* The channel does not exist on our server. If we are normal server 
2847            we will send JOIN command to our router which will handle the
2848            joining procedure (either creates the channel if it doesn't exist 
2849            or joins the client to it). */
2850         if (server->server_type == SILC_SERVER) {
2851           SilcBuffer tmpbuf;
2852           unsigned short old_ident;
2853           
2854           old_ident = silc_command_get_ident(cmd->payload);
2855           silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2856           tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2857           
2858           /* Send JOIN command to our router */
2859           silc_server_packet_send(server, (SilcSocketConnection)
2860                                   server->router->connection,
2861                                   SILC_PACKET_COMMAND, cmd->packet->flags,
2862                                   tmpbuf->data, tmpbuf->len, TRUE);
2863           
2864           /* Reprocess this packet after received reply from router */
2865           silc_server_command_pending(server, SILC_COMMAND_JOIN, 
2866                                       silc_command_get_ident(cmd->payload),
2867                                       silc_server_command_destructor,
2868                                       silc_server_command_join,
2869                                       silc_server_command_dup(cmd));
2870           cmd->pending = TRUE;
2871           return;
2872         }
2873         
2874         /* We are router and the channel does not seem exist so we will check
2875            our global list as well for the channel. */
2876         channel = silc_idlist_find_channel_by_name(server->global_list, 
2877                                                    channel_name, NULL);
2878         if (!channel) {
2879           /* Channel really does not exist, create it */
2880           channel = silc_server_create_new_channel(server, server->id, cipher, 
2881                                                    hmac, channel_name, TRUE);
2882           umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2883           created = TRUE;
2884         }
2885       }
2886     }
2887   } else {
2888     if (!channel) {
2889       /* Channel not found */
2890
2891       /* If the command came from router and/or we are normal server then
2892          something went wrong with the joining as the channel was not found.
2893          We can't do anything else but ignore this. */
2894       if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
2895           server->server_type == SILC_SERVER)
2896         goto out;
2897       
2898       /* We are router and the channel does not seem exist so we will check
2899          our global list as well for the channel. */
2900       channel = silc_idlist_find_channel_by_name(server->global_list, 
2901                                                  channel_name, NULL);
2902       if (!channel) {
2903         /* Channel really does not exist, create it */
2904         channel = silc_server_create_new_channel(server, server->id, cipher, 
2905                                                  hmac, channel_name, TRUE);
2906         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2907         created = TRUE;
2908       }
2909     }
2910   }
2911
2912   /* If the channel does not have global users and is also empty it means the
2913      channel was created globally (by our router) and the client will be the
2914      channel founder and operator. */
2915   if (!channel->global_users && silc_list_count(channel->user_list) == 0) {
2916     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2917     created = TRUE;             /* Created globally by our router */
2918   }
2919
2920   /* Join to the channel */
2921   silc_server_command_join_channel(server, cmd, channel, client_id,
2922                                    created, umode);
2923
2924   silc_free(client_id);
2925
2926  out:
2927   silc_server_command_free(cmd);
2928 }
2929
2930 /* Server side of command MOTD. Sends server's current "message of the
2931    day" to the client. */
2932
2933 SILC_SERVER_CMD_FUNC(motd)
2934 {
2935   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2936   SilcServer server = cmd->server;
2937   SilcBuffer packet, idp;
2938   char *motd, *dest_server;
2939   int motd_len;
2940   unsigned short ident = silc_command_get_ident(cmd->payload);
2941   
2942   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 1);
2943
2944   /* Get server name */
2945   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
2946   if (!dest_server) {
2947     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
2948                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
2949     goto out;
2950   }
2951
2952   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
2953     /* Send our MOTD */
2954
2955     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
2956
2957     if (server->config && server->config->motd && 
2958         server->config->motd->motd_file) {
2959       /* Send motd */
2960       motd = silc_file_read(server->config->motd->motd_file, &motd_len);
2961       if (!motd)
2962         goto out;
2963       
2964       motd[motd_len] = 0;
2965       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
2966                                                     SILC_STATUS_OK, ident, 2,
2967                                                     2, idp, idp->len,
2968                                                     3, motd, motd_len);
2969       goto out;
2970     } else {
2971       /* No motd */
2972       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
2973                                                     SILC_STATUS_OK, ident, 1,
2974                                                     2, idp, idp->len);
2975     }
2976
2977     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2978                             packet->data, packet->len, FALSE);
2979     silc_buffer_free(packet);
2980     silc_buffer_free(idp);
2981   } else {
2982     SilcServerEntry entry;
2983
2984     /* Check whether we have this server cached */
2985     entry = silc_idlist_find_server_by_name(server->global_list,
2986                                             dest_server, NULL);
2987     if (!entry) {
2988       entry = silc_idlist_find_server_by_name(server->local_list,
2989                                               dest_server, NULL);
2990     }
2991
2992     if (server->server_type == SILC_ROUTER && !cmd->pending && 
2993         entry && !entry->motd) {
2994       /* Send to the server */
2995       SilcBuffer tmpbuf;
2996       unsigned short old_ident;
2997
2998       old_ident = silc_command_get_ident(cmd->payload);
2999       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
3000       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3001
3002       silc_server_packet_send(server, entry->connection,
3003                               SILC_PACKET_COMMAND, cmd->packet->flags,
3004                               tmpbuf->data, tmpbuf->len, TRUE);
3005
3006       /* Reprocess this packet after received reply from router */
3007       silc_server_command_pending(server, SILC_COMMAND_MOTD, 
3008                                   silc_command_get_ident(cmd->payload),
3009                                   silc_server_command_destructor,
3010                                   silc_server_command_motd,
3011                                   silc_server_command_dup(cmd));
3012       cmd->pending = TRUE;
3013       silc_command_set_ident(cmd->payload, old_ident);
3014       silc_buffer_free(tmpbuf);
3015       return;
3016     }
3017
3018     if (!entry && !cmd->pending && !server->standalone) {
3019       /* Send to the primary router */
3020       SilcBuffer tmpbuf;
3021       unsigned short old_ident;
3022
3023       old_ident = silc_command_get_ident(cmd->payload);
3024       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
3025       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3026
3027       silc_server_packet_send(server, server->router->connection,
3028                               SILC_PACKET_COMMAND, cmd->packet->flags,
3029                               tmpbuf->data, tmpbuf->len, TRUE);
3030
3031       /* Reprocess this packet after received reply from router */
3032       silc_server_command_pending(server, SILC_COMMAND_MOTD, 
3033                                   silc_command_get_ident(cmd->payload),
3034                                   silc_server_command_destructor,
3035                                   silc_server_command_motd,
3036                                   silc_server_command_dup(cmd));
3037       cmd->pending = TRUE;
3038       silc_command_set_ident(cmd->payload, old_ident);
3039       silc_buffer_free(tmpbuf);
3040       return;
3041     }
3042
3043     if (!entry) {
3044       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
3045                                             SILC_STATUS_ERR_NO_SUCH_SERVER);
3046       goto out;
3047     }
3048
3049     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
3050
3051     if (entry->motd)
3052       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3053                                                     SILC_STATUS_OK, ident, 2,
3054                                                     2, idp, idp->len,
3055                                                     3, entry->motd,
3056                                                     strlen(entry->motd));
3057     else
3058       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3059                                                     SILC_STATUS_OK, ident, 1,
3060                                                     2, idp, idp->len);
3061
3062     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3063                             packet->data, packet->len, FALSE);
3064     silc_buffer_free(packet);
3065     silc_buffer_free(idp);
3066   }
3067
3068  out:
3069   silc_server_command_free(cmd);
3070 }
3071
3072 /* Server side of command UMODE. Client can use this command to set/unset
3073    user mode. Client actually cannot set itself to be as server/router
3074    operator so this can be used only to unset the modes. */
3075
3076 SILC_SERVER_CMD_FUNC(umode)
3077 {
3078   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3079   SilcServer server = cmd->server;
3080   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3081   SilcBuffer packet;
3082   unsigned char *tmp_mask;
3083   unsigned int mask;
3084   unsigned short ident = silc_command_get_ident(cmd->payload);
3085
3086   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
3087     goto out;
3088
3089   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_UMODE, cmd, 2, 2);
3090
3091   /* Get the client's mode mask */
3092   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
3093   if (!tmp_mask) {
3094     silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3095                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3096     goto out;
3097   }
3098   SILC_GET32_MSB(mask, tmp_mask);
3099
3100   /* 
3101    * Change the mode 
3102    */
3103
3104   if (mask & SILC_UMODE_SERVER_OPERATOR) {
3105     /* Cannot operator mode */
3106     silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3107                                           SILC_STATUS_ERR_PERM_DENIED);
3108     goto out;
3109   } else {
3110     if (client->mode & SILC_UMODE_SERVER_OPERATOR)
3111       /* Remove the server operator rights */
3112       client->mode &= ~SILC_UMODE_SERVER_OPERATOR;
3113   }
3114
3115   if (mask & SILC_UMODE_ROUTER_OPERATOR) {
3116     /* Cannot operator mode */
3117     silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3118                                           SILC_STATUS_ERR_PERM_DENIED);
3119     goto out;
3120   } else {
3121     if (client->mode & SILC_UMODE_ROUTER_OPERATOR)
3122       /* Remove the router operator rights */
3123       client->mode &= ~SILC_UMODE_ROUTER_OPERATOR;
3124   }
3125
3126   /* Send UMODE change to primary router */
3127   if (!server->standalone)
3128     silc_server_send_notify_umode(server, server->router->connection, TRUE,
3129                                   client->id, SILC_ID_CLIENT_LEN,
3130                                   client->mode);
3131
3132   /* Send command reply to sender */
3133   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_UMODE,
3134                                                 SILC_STATUS_OK, ident, 1,
3135                                                 2, tmp_mask, 4);
3136   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3137                           packet->data, packet->len, FALSE);
3138   silc_buffer_free(packet);
3139
3140  out:
3141   silc_server_command_free(cmd);
3142 }
3143
3144 /* Checks that client has rights to add or remove channel modes. If any
3145    of the checks fails FALSE is returned. */
3146
3147 int silc_server_check_cmode_rights(SilcChannelEntry channel,
3148                                    SilcChannelClientEntry client,
3149                                    unsigned int mode)
3150 {
3151   int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
3152   int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
3153
3154   /* Check whether has rights to change anything */
3155   if (!is_op && !is_fo)
3156     return FALSE;
3157
3158   /* Check whether has rights to change everything */
3159   if (is_op && is_fo)
3160     return TRUE;
3161
3162   /* We know that client is channel operator, check that they are not
3163      changing anything that requires channel founder rights. Rest of the
3164      modes are available automatically for channel operator. */
3165
3166   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
3167     if (is_op && !is_fo)
3168       return FALSE;
3169   } else {
3170     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
3171       if (is_op && !is_fo)
3172         return FALSE;
3173     }
3174   }
3175   
3176   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3177     if (is_op && !is_fo)
3178       return FALSE;
3179   } else {
3180     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3181       if (is_op && !is_fo)
3182         return FALSE;
3183     }
3184   }
3185
3186   if (mode & SILC_CHANNEL_MODE_CIPHER) {
3187     if (is_op && !is_fo)
3188       return FALSE;
3189   } else {
3190     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
3191       if (is_op && !is_fo)
3192         return FALSE;
3193     }
3194   }
3195   
3196   return TRUE;
3197 }
3198
3199 /* Server side command of CMODE. Changes channel mode */
3200
3201 SILC_SERVER_CMD_FUNC(cmode)
3202 {
3203   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3204   SilcServer server = cmd->server;
3205   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3206   SilcChannelID *channel_id;
3207   SilcChannelEntry channel;
3208   SilcChannelClientEntry chl;
3209   SilcBuffer packet, cidp;
3210   unsigned char *tmp, *tmp_id, *tmp_mask;
3211   unsigned int argc, mode_mask, tmp_len, tmp_len2;
3212   unsigned short ident = silc_command_get_ident(cmd->payload);
3213
3214   SILC_LOG_DEBUG(("Start"));
3215
3216   argc = silc_argument_get_arg_num(cmd->args);
3217   if (argc < 2) {
3218     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3219                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3220     goto out;
3221   }
3222   if (argc > 8) {
3223     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3224                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
3225     goto out;
3226   }
3227
3228   /* Get Channel ID */
3229   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
3230   if (!tmp_id) {
3231     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3232                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3233     goto out;
3234   }
3235   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
3236   if (!channel_id) {
3237     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3238                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3239     goto out;
3240   }
3241
3242   /* Get the channel mode mask */
3243   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
3244   if (!tmp_mask) {
3245     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3246                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3247     goto out;
3248   }
3249   SILC_GET32_MSB(mode_mask, tmp_mask);
3250
3251   /* Get channel entry */
3252   channel = silc_idlist_find_channel_by_id(server->local_list, 
3253                                            channel_id, NULL);
3254   if (!channel) {
3255     channel = silc_idlist_find_channel_by_id(server->global_list, 
3256                                              channel_id, NULL);
3257     if (!channel) {
3258       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3259                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
3260       goto out;
3261     }
3262   }
3263
3264   /* Check whether this client is on the channel */
3265   if (!silc_server_client_on_channel(client, channel)) {
3266     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3267                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
3268     goto out;
3269   }
3270
3271   /* Get entry to the channel user list */
3272   silc_list_start(channel->user_list);
3273   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
3274     if (chl->client == client)
3275       break;
3276
3277   /* Check that client has rights to change any requested channel modes */
3278   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
3279     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3280                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
3281     goto out;
3282   }
3283
3284   /*
3285    * Check the modes. Modes that requires nothing special operation are
3286    * not checked here.
3287    */
3288
3289   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
3290     /* Channel uses private keys to protect traffic. Client(s) has set the
3291        key locally they want to use, server does not know that key. */
3292     /* Nothing interesting to do here now */
3293   } else {
3294     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
3295       /* The mode is removed and we need to generate and distribute
3296          new channel key. Clients are not using private channel keys
3297          anymore after this. */
3298
3299       /* XXX Duplicated code, make own function for this!! LEAVE uses this
3300          as well */
3301
3302       /* Re-generate channel key */
3303       silc_server_create_channel_key(server, channel, 0);
3304       
3305       /* Encode channel key payload to be distributed on the channel */
3306       packet = 
3307         silc_channel_key_payload_encode(tmp_len2, tmp_id,
3308                                         strlen(channel->channel_key->
3309                                                cipher->name),
3310                                         channel->channel_key->cipher->name,
3311                                         channel->key_len / 8, channel->key);
3312       
3313       /* If we are normal server then we will send it to our router.  If we
3314          are router we will send it to all local servers that has clients on
3315          the channel */
3316       if (server->server_type == SILC_SERVER) {
3317         if (!server->standalone)
3318           silc_server_packet_send(server, 
3319                                   cmd->server->router->connection,
3320                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
3321                                   packet->len, TRUE);
3322       } else {
3323         
3324       }
3325       
3326       /* Send to locally connected clients on the channel */
3327       silc_server_packet_send_local_channel(server, channel, 
3328                                             SILC_PACKET_CHANNEL_KEY, 0,
3329                                             packet->data, packet->len, FALSE);
3330       silc_buffer_free(packet);
3331     }
3332   }
3333   
3334   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
3335     /* User limit is set on channel */
3336     unsigned int user_limit;
3337       
3338     /* Get user limit */
3339     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
3340     if (!tmp) {
3341       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
3342         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3343                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3344         goto out;
3345       }
3346     } else {
3347       SILC_GET32_MSB(user_limit, tmp);
3348       channel->user_limit = user_limit;
3349     }
3350   } else {
3351     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
3352       /* User limit mode is unset. Remove user limit */
3353       channel->user_limit = 0;
3354   }
3355
3356   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
3357     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
3358       /* Passphrase has been set to channel */
3359       
3360       /* Get the passphrase */
3361       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
3362       if (!tmp) {
3363         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3364                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3365         goto out;
3366       }
3367
3368       /* Save the passphrase */
3369       channel->passphrase = strdup(tmp);
3370     }
3371   } else {
3372     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3373       /* Passphrase mode is unset. remove the passphrase */
3374       if (channel->passphrase) {
3375         silc_free(channel->passphrase);
3376         channel->passphrase = NULL;
3377       }
3378     }
3379   }
3380
3381   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
3382     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
3383       /* Cipher to use protect the traffic */
3384       unsigned int key_len;
3385
3386       /* Get cipher */
3387       tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
3388       if (!tmp) {
3389         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3390                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3391         goto out;
3392       }
3393
3394       /* XXX Duplicated code, make own function for this!! */
3395     
3396       /* Delete old cipher and allocate the new one */
3397       silc_cipher_free(channel->channel_key);
3398       if (!silc_cipher_alloc(tmp, &channel->channel_key)) {
3399         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3400                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3401         goto out;
3402       }
3403       key_len = silc_cipher_get_key_len(channel->channel_key) / 8;
3404
3405       /* Re-generate channel key */
3406       silc_server_create_channel_key(server, channel, key_len);
3407     
3408       /* Encode channel key payload to be distributed on the channel */
3409       packet = 
3410         silc_channel_key_payload_encode(tmp_len2, tmp_id,
3411                                         strlen(channel->channel_key->
3412                                                cipher->name),
3413                                         channel->channel_key->cipher->name,
3414                                         channel->key_len / 8, channel->key);
3415     
3416       /* If we are normal server then we will send it to our router.  If we
3417          are router we will send it to all local servers that has clients on
3418          the channel */
3419       if (server->server_type == SILC_SERVER) {
3420         if (!server->standalone)
3421           silc_server_packet_send(server, 
3422                                   cmd->server->router->connection,
3423                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
3424                                   packet->len, TRUE);
3425       } else {
3426         
3427       }
3428     
3429       /* Send to locally connected clients on the channel */
3430       silc_server_packet_send_local_channel(server, channel, 
3431                                             SILC_PACKET_CHANNEL_KEY, 0,
3432                                           packet->data, packet->len, FALSE);
3433       silc_buffer_free(packet);
3434     }
3435   } else {
3436     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
3437       /* Cipher mode is unset. Remove the cipher and revert back to 
3438          default cipher */
3439       char *cipher = channel->channel_key->cipher->name;
3440
3441       /* Generate new cipher and key for the channel */
3442
3443       /* XXX Duplicated code, make own function for this!! */
3444
3445       /* Delete old cipher and allocate default one */
3446       silc_cipher_free(channel->channel_key);
3447       if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
3448         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3449                                    SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3450         goto out;
3451       }
3452
3453       /* Re-generate channel key */
3454       silc_server_create_channel_key(server, channel, 0);
3455       
3456       /* Encode channel key payload to be distributed on the channel */
3457       packet = 
3458         silc_channel_key_payload_encode(tmp_len2, tmp_id,
3459                                         strlen(channel->channel_key->
3460                                                cipher->name),
3461                                         channel->channel_key->cipher->name,
3462                                         channel->key_len / 8, channel->key);
3463       
3464       /* If we are normal server then we will send it to our router.  If we
3465          are router we will send it to all local servers that has clients on
3466          the channel */
3467       if (server->server_type == SILC_SERVER) {
3468         if (!server->standalone)
3469           silc_server_packet_send(server, 
3470                                   cmd->server->router->connection,
3471                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
3472                                   packet->len, TRUE);
3473       } else {
3474         
3475       }
3476       
3477       /* Send to locally connected clients on the channel */
3478       silc_server_packet_send_local_channel(server, channel, 
3479                                             SILC_PACKET_CHANNEL_KEY, 0,
3480                                             packet->data, packet->len, FALSE);
3481       silc_buffer_free(packet);
3482     }
3483   }
3484
3485   /* Finally, set the mode */
3486   channel->mode = mode_mask;
3487
3488   /* Send CMODE_CHANGE notify */
3489   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
3490   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
3491                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
3492                                      cidp->data, cidp->len, 
3493                                      tmp_mask, tmp_len);
3494
3495   /* Set CMODE notify type to network */
3496   if (!server->standalone)
3497     silc_server_send_notify_cmode(server, server->router->connection,
3498                                   server->server_type == SILC_ROUTER ? 
3499                                   TRUE : FALSE, channel,
3500                                   mode_mask, client->id, SILC_ID_CLIENT_LEN);
3501
3502   /* Send command reply to sender */
3503   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
3504                                                 SILC_STATUS_OK, ident, 1,
3505                                                 2, tmp_mask, 4);
3506   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3507                           packet->data, packet->len, FALSE);
3508     
3509   silc_buffer_free(packet);
3510   silc_free(channel_id);
3511   silc_free(cidp);
3512
3513  out:
3514   silc_server_command_free(cmd);
3515 }
3516
3517 /* Server side of CUMODE command. Changes client's mode on a channel. */
3518
3519 SILC_SERVER_CMD_FUNC(cumode)
3520 {
3521   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3522   SilcServer server = cmd->server;
3523   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3524   SilcChannelID *channel_id;
3525   SilcClientID *client_id;
3526   SilcChannelEntry channel;
3527   SilcClientEntry target_client;
3528   SilcChannelClientEntry chl;
3529   SilcBuffer packet, idp;
3530   unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
3531   unsigned int target_mask, sender_mask, tmp_len, tmp_ch_len;
3532   int notify = FALSE;
3533   unsigned short ident = silc_command_get_ident(cmd->payload);
3534
3535   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
3536
3537   /* Get Channel ID */
3538   tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
3539   if (!tmp_ch_id) {
3540     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3541                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3542     goto out;
3543   }
3544   channel_id = silc_id_payload_parse_id(tmp_ch_id, tmp_ch_len);
3545   if (!channel_id) {
3546     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3547                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3548     goto out;
3549   }
3550
3551   /* Get channel entry */
3552   channel = silc_idlist_find_channel_by_id(server->local_list, 
3553                                            channel_id, NULL);
3554   if (!channel) {
3555     channel = silc_idlist_find_channel_by_id(server->global_list, 
3556                                              channel_id, NULL);
3557     if (!channel) {
3558       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3559                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
3560       goto out;
3561     }
3562   }
3563
3564   /* Check whether sender is on the channel */
3565   if (!silc_server_client_on_channel(client, channel)) {
3566     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3567                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
3568     goto out;
3569   }
3570
3571   /* Check that client has rights to change other's rights */
3572   silc_list_start(channel->user_list);
3573   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
3574     if (chl->client == client) {
3575       if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
3576           !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
3577         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3578                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
3579         goto out;
3580       }
3581
3582       sender_mask = chl->mode;
3583       break;
3584     }
3585   }
3586   
3587   /* Get the target client's channel mode mask */
3588   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
3589   if (!tmp_mask) {
3590     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3591                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3592     goto out;
3593   }
3594   SILC_GET32_MSB(target_mask, tmp_mask);
3595
3596   /* Get target Client ID */
3597   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
3598   if (!tmp_id) {
3599     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3600                                           SILC_STATUS_ERR_NO_CLIENT_ID);
3601     goto out;
3602   }
3603   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
3604   if (!client_id) {
3605     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3606                                           SILC_STATUS_ERR_NO_CLIENT_ID);
3607     goto out;
3608   }
3609
3610   /* Get target client's entry */
3611   target_client = silc_idlist_find_client_by_id(server->local_list, 
3612                                                 client_id, NULL);
3613   if (!target_client) {
3614     target_client = silc_idlist_find_client_by_id(server->global_list, 
3615                                                   client_id, NULL);
3616   }
3617
3618   /* Check whether target client is on the channel */
3619   if (!silc_server_client_on_channel(target_client, channel)) {
3620     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3621                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
3622     goto out;
3623   }
3624
3625   /* Get entry to the channel user list */
3626   silc_list_start(channel->user_list);
3627   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
3628     if (chl->client == target_client)
3629       break;
3630
3631   /* 
3632    * Change the mode 
3633    */
3634
3635   /* If the target client is founder, no one else can change their mode
3636      but themselves. */
3637   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
3638     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3639                                           SILC_STATUS_ERR_NOT_YOU);
3640     goto out;
3641   }
3642
3643   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
3644     /* Cannot promote anyone to channel founder */
3645     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3646                                           SILC_STATUS_ERR_NOT_YOU);
3647     goto out;
3648   } else {
3649     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
3650       if (target_client == client) {
3651         /* Remove channel founder rights from itself */
3652         chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
3653         notify = TRUE;
3654       } else {
3655         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3656                                               SILC_STATUS_ERR_NOT_YOU);
3657         goto out;
3658       }
3659     }
3660   }
3661
3662   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
3663     /* Promote to operator */
3664     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
3665       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
3666       notify = TRUE;
3667     }
3668   } else {
3669     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
3670       /* Demote to normal user */
3671       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
3672       notify = TRUE;
3673     }
3674   }
3675
3676   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
3677
3678   /* Send notify to channel, notify only if mode was actually changed. */
3679   if (notify) {
3680     silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
3681                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
3682                                        idp->data, idp->len,
3683                                        tmp_mask, 4, 
3684                                        tmp_id, tmp_len);
3685
3686     /* Set CUMODE notify type to network */
3687     if (!server->standalone)
3688       silc_server_send_notify_cumode(server, server->router->connection,
3689                                      server->server_type == SILC_ROUTER ? 
3690                                      TRUE : FALSE, channel,
3691                                      target_mask, client->id, 
3692                                      SILC_ID_CLIENT_LEN,
3693                                      target_client->id, 
3694                                      SILC_ID_CLIENT_LEN);
3695   }
3696
3697   /* Send command reply to sender */
3698   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
3699                                                 SILC_STATUS_OK, ident, 2,
3700                                                 2, tmp_mask, 4,
3701                                                 3, tmp_id, tmp_len);
3702   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3703                           packet->data, packet->len, FALSE);
3704     
3705   silc_buffer_free(packet);
3706   silc_free(channel_id);
3707   silc_free(client_id);
3708   silc_buffer_free(idp);
3709
3710  out:
3711   silc_server_command_free(cmd);
3712 }
3713
3714 /* Server side of KICK command. Kicks client out of channel. */
3715
3716 SILC_SERVER_CMD_FUNC(kick)
3717 {
3718   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3719   SilcServer server = cmd->server;
3720   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3721   SilcClientEntry target_client;
3722   SilcChannelID *channel_id;
3723   SilcClientID *client_id;
3724   SilcChannelEntry channel;
3725   SilcChannelClientEntry chl;
3726   SilcBuffer idp;
3727   unsigned int tmp_len;
3728   unsigned char *tmp, *comment;
3729
3730   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 3);
3731
3732   /* Get Channel ID */
3733   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3734   if (!tmp) {
3735     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3736                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3737     goto out;
3738   }
3739   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
3740   if (!channel_id) {
3741     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3742                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3743     goto out;
3744   }
3745
3746   /* Get channel entry */
3747   channel = silc_idlist_find_channel_by_id(server->local_list, 
3748                                            channel_id, NULL);
3749   if (!channel) {
3750     channel = silc_idlist_find_channel_by_id(server->local_list, 
3751                                              channel_id, NULL);
3752     if (!channel) {
3753       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3754                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
3755       goto out;
3756     }
3757   }
3758
3759   /* Check whether sender is on the channel */
3760   if (!silc_server_client_on_channel(client, channel)) {
3761     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3762                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
3763     goto out;
3764   }
3765
3766   /* Check that the kicker is channel operator or channel founder */
3767   silc_list_start(channel->user_list);
3768   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
3769     if (chl->client == client) {
3770       if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
3771         silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3772                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
3773         goto out;
3774       }
3775       break;
3776     }
3777   }
3778   
3779   /* Get target Client ID */
3780   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
3781   if (!tmp) {
3782     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3783                                           SILC_STATUS_ERR_NO_CLIENT_ID);
3784     goto out;
3785   }
3786   client_id = silc_id_payload_parse_id(tmp, tmp_len);
3787   if (!client_id) {
3788     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3789                                           SILC_STATUS_ERR_NO_CLIENT_ID);
3790     goto out;
3791   }
3792
3793   /* Get target client's entry */
3794   target_client = silc_idlist_find_client_by_id(server->local_list, 
3795                                                 client_id, NULL);
3796   if (!target_client) {
3797     target_client = silc_idlist_find_client_by_id(server->global_list, 
3798                                                   client_id, NULL);
3799   }
3800
3801   /* Check that the target client is not channel founder. Channel founder
3802      cannot be kicked from the channel. */
3803   silc_list_start(channel->user_list);
3804   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
3805     if (chl->client == target_client) {
3806       if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
3807         silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3808                                   SILC_STATUS_ERR_NO_CHANNEL_FOPRIV);
3809         goto out;
3810       }
3811       break;
3812     }
3813   }
3814   
3815   /* Check whether target client is on the channel */
3816   if (!silc_server_client_on_channel(target_client, channel)) {
3817     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3818                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
3819     goto out;
3820   }
3821
3822   /* Get comment */
3823   tmp_len = 0;
3824   comment = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
3825   if (tmp_len > 128)
3826     comment = NULL;
3827
3828   /* Send command reply to sender */
3829   silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK, 
3830                                         SILC_STATUS_OK);
3831
3832   /* Send KICKED notify to local clients on the channel */
3833   idp = silc_id_payload_encode(target_client->id, SILC_ID_CLIENT);
3834   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
3835                                      SILC_NOTIFY_TYPE_KICKED, 
3836                                      comment ? 2 : 1,
3837                                      idp->data, idp->len,
3838                                      comment, comment ? strlen(comment) : 0);
3839   silc_buffer_free(idp);
3840
3841   /* Remove the client from the channel. If the channel does not exist
3842      after removing the client then the client kicked itself off the channel
3843      and we don't have to send anything after that. */
3844   if (!silc_server_remove_from_one_channel(server, NULL, channel, 
3845                                            target_client, FALSE))
3846     goto out;
3847
3848   /* Send KICKED notify to primary route */
3849   if (!server->standalone)
3850     silc_server_send_notify_kicked(server, server->router->connection,
3851                                    server->server_type == SILC_ROUTER ?
3852                                    TRUE : FALSE, channel,
3853                                    target_client->id, SILC_ID_CLIENT_LEN,
3854                                    comment);
3855
3856   /* Re-generate channel key */
3857   silc_server_create_channel_key(server, channel, 0);
3858
3859   /* Send the channel key to the channel. The key of course is not sent
3860      to the client who was kicked off the channel. */
3861   silc_server_send_channel_key(server, target_client->connection, channel, 
3862                                server->server_type == SILC_ROUTER ? 
3863                                FALSE : !server->standalone);
3864
3865  out:
3866   silc_server_command_free(cmd);
3867 }
3868
3869 /* Server side of OPER command. Client uses this comand to obtain server
3870    operator privileges to this server/router. */
3871
3872 SILC_SERVER_CMD_FUNC(oper)
3873 {
3874   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3875   SilcServer server = cmd->server;
3876   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3877   unsigned char *username, *auth;
3878   unsigned int tmp_len;
3879   SilcServerConfigSectionAdminConnection *admin;
3880   SilcIDListData idata = (SilcIDListData)client;
3881
3882   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_OPER, cmd, 1, 2);
3883
3884   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
3885     goto out;
3886
3887   /* Get the username */
3888   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3889   if (!username) {
3890     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
3891                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3892     goto out;
3893   }
3894
3895   /* Get the admin configuration */
3896   admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
3897                                         username, client->nickname);
3898   if (!admin) {
3899     admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
3900                                           username, client->nickname);
3901     if (!admin) {
3902       silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
3903                                             SILC_STATUS_ERR_AUTH_FAILED);
3904       goto out;
3905     }
3906   }
3907
3908   /* Get the authentication payload */
3909   auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
3910   if (!auth) {
3911     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
3912                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3913     goto out;
3914   }
3915
3916   /* Verify the authentication data */
3917   if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, 
3918                              admin->auth_data, admin->auth_data_len,
3919                              idata->hash, client->id, SILC_ID_CLIENT)) {
3920     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
3921                                           SILC_STATUS_ERR_AUTH_FAILED);
3922     goto out;
3923   }
3924
3925   /* Client is now server operator */
3926   client->mode |= SILC_UMODE_SERVER_OPERATOR;
3927
3928   /* Send UMODE change to primary router */
3929   if (!server->standalone)
3930     silc_server_send_notify_umode(server, server->router->connection, TRUE,
3931                                   client->id, SILC_ID_CLIENT_LEN,
3932                                   client->mode);
3933
3934   /* Send reply to the sender */
3935   silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
3936                                         SILC_STATUS_OK);
3937
3938  out:
3939   silc_server_command_free(cmd);
3940 }
3941
3942 /* Server side of SILCOPER command. Client uses this comand to obtain router
3943    operator privileges to this router. */
3944
3945 SILC_SERVER_CMD_FUNC(silcoper)
3946 {
3947   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3948   SilcServer server = cmd->server;
3949   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3950   unsigned char *username, *auth;
3951   unsigned int tmp_len;
3952   SilcServerConfigSectionAdminConnection *admin;
3953   SilcIDListData idata = (SilcIDListData)client;
3954
3955   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SILCOPER, cmd, 1, 2);
3956
3957   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
3958     goto out;
3959
3960   /* Get the username */
3961   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3962   if (!username) {
3963     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
3964                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3965     goto out;
3966   }
3967
3968   /* Get the admin configuration */
3969   admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
3970                                         username, client->nickname);
3971   if (!admin) {
3972     admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
3973                                           username, client->nickname);
3974     if (!admin) {
3975       silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
3976                                             SILC_STATUS_ERR_AUTH_FAILED);
3977       goto out;
3978     }
3979   }
3980
3981   /* Get the authentication payload */
3982   auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
3983   if (!auth) {
3984     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
3985                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3986     goto out;
3987   }
3988
3989   /* Verify the authentication data */
3990   if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, 
3991                              admin->auth_data, admin->auth_data_len,
3992                              idata->hash, client->id, SILC_ID_CLIENT)) {
3993     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
3994                                           SILC_STATUS_ERR_AUTH_FAILED);
3995     goto out;
3996   }
3997
3998   /* Client is now router operator */
3999   client->mode |= SILC_UMODE_ROUTER_OPERATOR;
4000
4001   /* Send UMODE change to primary router */
4002   if (!server->standalone)
4003     silc_server_send_notify_umode(server, server->router->connection, TRUE,
4004                                   client->id, SILC_ID_CLIENT_LEN,
4005                                   client->mode);
4006
4007   /* Send reply to the sender */
4008   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4009                                         SILC_STATUS_OK);
4010
4011  out:
4012   silc_server_command_free(cmd);
4013 }
4014
4015 /* Server side command of CONNECT. Connects us to the specified remote
4016    server or router. */
4017
4018 SILC_SERVER_CMD_FUNC(connect)
4019 {
4020   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4021   SilcServer server = cmd->server;
4022   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4023   unsigned char *tmp, *host;
4024   unsigned int tmp_len;
4025   unsigned int port = SILC_PORT;
4026
4027   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CONNECT, cmd, 1, 2);
4028
4029   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4030     goto out;
4031
4032   /* Check whether client has the permissions. */
4033   if (client->mode == SILC_UMODE_NONE) {
4034     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4035                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
4036     goto out;
4037   }
4038
4039   if (server->server_type == SILC_ROUTER && 
4040       client->mode & SILC_UMODE_SERVER_OPERATOR) {
4041     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4042                                           SILC_STATUS_ERR_NO_ROUTER_PRIV);
4043     goto out;
4044   }
4045
4046   /* Get the remote server */
4047   host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4048   if (!host) {
4049     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4050                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4051     goto out;
4052   }
4053
4054   /* Get port */
4055   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4056   if (tmp)
4057     SILC_GET32_MSB(port, tmp);
4058
4059   /* Create the connection. It is done with timeout and is async. */
4060   silc_server_create_connection(server, host, port);
4061
4062   /* Send reply to the sender */
4063   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4064                                         SILC_STATUS_OK);
4065
4066  out:
4067   silc_server_command_free(cmd);
4068 }
4069
4070 SILC_SERVER_CMD_FUNC(restart)
4071 {
4072 }
4073
4074 /* Server side command of CLOSE. Closes connection to a specified server. */
4075  
4076 SILC_SERVER_CMD_FUNC(close)
4077 {
4078   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4079   SilcServer server = cmd->server;
4080   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4081   SilcServerEntry server_entry;
4082   SilcSocketConnection sock;
4083   unsigned char *tmp;
4084   unsigned int tmp_len;
4085   unsigned char *name;
4086   unsigned int port = SILC_PORT;
4087
4088   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CLOSE, cmd, 1, 2);
4089
4090   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4091     goto out;
4092
4093   /* Check whether client has the permissions. */
4094   if (client->mode == SILC_UMODE_NONE) {
4095     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4096                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
4097     goto out;
4098   }
4099
4100   /* Get the remote server */
4101   name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4102   if (!name) {
4103     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4104                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4105     goto out;
4106   }
4107
4108   /* Get port */
4109   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4110   if (tmp)
4111     SILC_GET32_MSB(port, tmp);
4112
4113   server_entry = silc_idlist_find_server_by_conn(server->local_list,
4114                                                  name, port, NULL);
4115   if (!server_entry) {
4116     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4117                                           SILC_STATUS_ERR_NO_SERVER_ID);
4118     goto out;
4119   }
4120
4121   /* Send reply to the sender */
4122   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4123                                         SILC_STATUS_OK);
4124
4125   /* Close the connection to the server */
4126   sock = (SilcSocketConnection)server_entry->connection;
4127   silc_server_free_sock_user_data(server, sock);
4128   silc_server_close_connection(server, sock);
4129   
4130  out:
4131   silc_server_command_free(cmd);
4132 }
4133
4134 /* Server side command of SHUTDOWN. Shutdowns the server and closes all
4135    active connections. */
4136  
4137 SILC_SERVER_CMD_FUNC(shutdown)
4138 {
4139   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4140   SilcServer server = cmd->server;
4141   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4142
4143   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SHUTDOWN, cmd, 0, 0);
4144
4145   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4146     goto out;
4147
4148   /* Check whether client has the permission. */
4149   if (client->mode == SILC_UMODE_NONE) {
4150     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
4151                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
4152     goto out;
4153   }
4154
4155   /* Send reply to the sender */
4156   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
4157                                         SILC_STATUS_OK);
4158
4159   /* Then, gracefully, or not, bring the server down. */
4160   silc_server_stop(server);
4161   exit(0);
4162
4163  out:
4164   silc_server_command_free(cmd);
4165 }
4166  
4167 /* Server side command of LEAVE. Removes client from a channel. */
4168
4169 SILC_SERVER_CMD_FUNC(leave)
4170 {
4171   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4172   SilcServer server = cmd->server;
4173   SilcSocketConnection sock = cmd->sock;
4174   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
4175   SilcChannelID *id;
4176   SilcChannelEntry channel;
4177   SilcBuffer packet;
4178   unsigned int i, len;
4179   unsigned char *tmp;
4180
4181   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
4182
4183   /* Get Channel ID */
4184   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
4185   if (!tmp) {
4186     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4187                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4188     goto out;
4189   }
4190   id = silc_id_payload_parse_id(tmp, len);
4191   if (!id) {
4192     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4193                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4194     goto out;
4195   }
4196
4197   /* Get channel entry */
4198   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
4199   if (!channel) {
4200     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
4201     if (!channel) {
4202       silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4203                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
4204       goto out;
4205     }
4206   }
4207
4208   /* Check whether this client is on the channel */
4209   if (!silc_server_client_on_channel(id_entry, channel)) {
4210     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4211                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
4212     goto out;
4213   }
4214
4215   /* Notify routers that they should remove this client from their list
4216      of clients on the channel. Send LEAVE notify type. */
4217   if (!server->standalone)
4218     silc_server_send_notify_leave(server, server->router->connection,
4219                                   server->server_type == SILC_ROUTER ?
4220                                   TRUE : FALSE, channel, id_entry->id,
4221                                   SILC_ID_CLIENT_LEN);
4222
4223   /* Remove client from channel */
4224   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
4225                                           TRUE);
4226   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4227                                         SILC_STATUS_OK);
4228
4229   /* If the channel does not exist anymore we won't send anything */
4230   if (!i)
4231     goto out;
4232
4233   /* Re-generate channel key */
4234   silc_server_create_channel_key(server, channel, 0);
4235
4236   /* Encode channel key payload to be distributed on the channel */
4237   packet = 
4238     silc_channel_key_payload_encode(len, tmp,
4239                                     strlen(channel->channel_key->cipher->name),
4240                                     channel->channel_key->cipher->name,
4241                                     channel->key_len / 8, channel->key);
4242
4243   /* If we are normal server then we will send it to our router.  If we
4244      are router we will send it to all local servers that has clients on
4245      the channel */
4246   if (server->server_type == SILC_SERVER) {
4247     if (!server->standalone)
4248       silc_server_packet_send(server, 
4249                               cmd->server->router->connection,
4250                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
4251                               packet->len, FALSE);
4252   } else {
4253
4254   }
4255
4256   /* Send to locally connected clients on the channel */
4257   silc_server_packet_send_local_channel(server, channel, 
4258                                         SILC_PACKET_CHANNEL_KEY, 0,
4259                                         packet->data, packet->len, FALSE);
4260
4261   silc_buffer_free(packet);
4262   silc_free(id);
4263
4264  out:
4265   silc_server_command_free(cmd);
4266 }
4267
4268 /* Server side of command USERS. Resolves clients and their USERS currently
4269    joined on the requested channel. The list of Client ID's and their modes
4270    on the channel is sent back. */
4271
4272 SILC_SERVER_CMD_FUNC(users)
4273 {
4274   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4275   SilcServer server = cmd->server;
4276   SilcChannelEntry channel;
4277   SilcChannelID *id;
4278   SilcBuffer packet;
4279   unsigned char *channel_id;
4280   unsigned int channel_id_len;
4281   SilcBuffer client_id_list;
4282   SilcBuffer client_mode_list;
4283   unsigned char lc[4];
4284   unsigned int list_count = 0;
4285   unsigned short ident = silc_command_get_ident(cmd->payload);
4286
4287   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
4288
4289   /* Get Channel ID */
4290   channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
4291   if (!channel_id) {
4292     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4293                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4294     goto out;
4295   }
4296   id = silc_id_payload_parse_id(channel_id, channel_id_len);
4297   if (!id) {
4298     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4299                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4300     goto out;
4301   }
4302
4303   /* If we are server and we don't know about this channel we will send
4304      the command to our router. If we know about the channel then we also
4305      have the list of users already. */
4306   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
4307   if (!channel) {
4308     if (server->server_type == SILC_SERVER && !server->standalone &&
4309         !cmd->pending) {
4310       SilcBuffer tmpbuf;
4311       
4312       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
4313       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
4314       
4315       /* Send USERS command */
4316       silc_server_packet_send(server, server->router->connection,
4317                               SILC_PACKET_COMMAND, cmd->packet->flags,
4318                               tmpbuf->data, tmpbuf->len, TRUE);
4319       
4320       /* Reprocess this packet after received reply */
4321       silc_server_command_pending(server, SILC_COMMAND_USERS, 
4322                                   silc_command_get_ident(cmd->payload),
4323                                   silc_server_command_destructor,
4324                                   silc_server_command_users,
4325                                   silc_server_command_dup(cmd));
4326       cmd->pending = TRUE;
4327       silc_command_set_ident(cmd->payload, ident);
4328       
4329       silc_buffer_free(tmpbuf);
4330       silc_free(id);
4331       return;
4332     }
4333
4334     /* We are router and we will check the global list as well. */
4335     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
4336     if (!channel) {
4337       /* Channel really does not exist */
4338       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4339                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
4340       goto out;
4341     }
4342   }
4343
4344   /* Get the users list */
4345   silc_server_get_users_on_channel(server, channel, &client_id_list,
4346                                    &client_mode_list, &list_count);
4347
4348   /* List count */
4349   SILC_PUT32_MSB(list_count, lc);
4350
4351   /* Send reply */
4352   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
4353                                                 SILC_STATUS_OK, ident, 4,
4354                                                 2, channel_id, channel_id_len,
4355                                                 3, lc, 4,
4356                                                 4, client_id_list->data,
4357                                                 client_id_list->len,
4358                                                 5, client_mode_list->data,
4359                                                 client_mode_list->len);
4360   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
4361                           packet->data, packet->len, FALSE);
4362     
4363   silc_buffer_free(packet);
4364   silc_buffer_free(client_id_list);
4365   silc_buffer_free(client_mode_list);
4366   silc_free(id);
4367
4368  out:
4369   silc_server_command_free(cmd);
4370 }
4371
4372 /* Server side of command BAN. This is used to manage the ban list of the
4373    channel. To add clients and remove clients from the ban list. */
4374
4375 SILC_SERVER_CMD_FUNC(ban)
4376 {
4377   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4378   SilcServer server = cmd->server;
4379   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4380   SilcBuffer packet;
4381   SilcChannelEntry channel;
4382   SilcChannelClientEntry chl;
4383   SilcChannelID *channel_id = NULL;
4384   unsigned char *id, *add, *del;
4385   unsigned int id_len, tmp_len;
4386   unsigned short ident = silc_command_get_ident(cmd->payload);
4387
4388   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4389     goto out;
4390
4391   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_BAN, cmd, 0, 3);
4392
4393   /* Get Channel ID */
4394   id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
4395   if (id) {
4396     channel_id = silc_id_payload_parse_id(id, id_len);
4397     if (!channel_id) {
4398       silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4399                                             SILC_STATUS_ERR_NO_CHANNEL_ID);
4400       goto out;
4401     }
4402   }
4403
4404   /* Get channel entry. The server must know about the channel since the
4405      client is expected to be on the channel. */
4406   channel = silc_idlist_find_channel_by_id(server->local_list, 
4407                                            channel_id, NULL);
4408   if (!channel) {
4409     channel = silc_idlist_find_channel_by_id(server->global_list, 
4410                                              channel_id, NULL);
4411     if (!channel) {
4412       silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4413                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
4414       goto out;
4415     }
4416   }
4417
4418   /* Check whether this client is on the channel */
4419   if (!silc_server_client_on_channel(client, channel)) {
4420     silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4421                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
4422     goto out;
4423   }
4424
4425   /* Get entry to the channel user list */
4426   silc_list_start(channel->user_list);
4427   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
4428     if (chl->client == client)
4429       break;
4430
4431   /* The client must be at least channel operator. */
4432   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
4433     silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4434                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
4435     goto out;
4436   }
4437
4438   /* Get the new ban and add it to the ban list */
4439   add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4440   if (add) {
4441     if (!channel->ban_list)
4442       channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list));
4443     else
4444       channel->ban_list = silc_realloc(channel->ban_list, 
4445                                        sizeof(*channel->ban_list) * 
4446                                        (tmp_len + 
4447                                         strlen(channel->ban_list) + 2));
4448     strncat(channel->ban_list, add, tmp_len);
4449     strncat(channel->ban_list, ",", 1);
4450   }
4451
4452   /* Get the ban to be removed and remove it from the list */
4453   del = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
4454   if (del && channel->ban_list) {
4455     char *start, *end, *n;
4456
4457     if (!strncmp(channel->ban_list, del, strlen(channel->ban_list) - 1)) {
4458       silc_free(channel->ban_list);
4459       channel->ban_list = NULL;
4460       goto out0;
4461     }
4462
4463     start = strstr(channel->ban_list, del);
4464     if (start && strlen(start) >= tmp_len) {
4465       end = start + tmp_len;
4466       n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
4467       strncat(n, channel->ban_list, start - channel->ban_list);
4468       strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) - 
4469                            end) - 1);
4470       silc_free(channel->ban_list);
4471       channel->ban_list = n;
4472     }
4473   }
4474
4475  out0:
4476
4477   /* Send the BAN notify type to our primary router. */
4478   if (!server->standalone && (add || del))
4479     silc_server_send_notify_ban(server, server->router->connection,
4480                                 server->server_type == SILC_ROUTER ?
4481                                 TRUE : FALSE, channel, add, del);
4482
4483   /* Send the reply back to the client */
4484   if (channel->ban_list)
4485     packet = 
4486       silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
4487                                            SILC_STATUS_OK, ident, 2,
4488                                            2, id, id_len,
4489                                            3, channel->ban_list, 
4490                                            strlen(channel->ban_list) - 1);
4491   else
4492     packet = 
4493       silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
4494                                            SILC_STATUS_OK, ident, 1,
4495                                            2, id, id_len);
4496
4497   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
4498                           packet->data, packet->len, FALSE);
4499     
4500   silc_buffer_free(packet);
4501
4502  out:
4503   if (channel_id)
4504     silc_free(channel_id);
4505   silc_server_command_free(cmd);
4506 }