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