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