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 - 2000 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 static void silc_server_command_free(SilcServerCommandContext cmd);
41 void silc_server_command_send_users(SilcServer server,
42                                     SilcSocketConnection sock,
43                                     SilcChannelEntry channel,
44                                     int pending);
45
46 /* Server command list. */
47 SilcServerCommand silc_command_list[] =
48 {
49   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
50   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
51   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
52   SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
53   SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
54   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
55   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
56   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
57   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
58   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
59   SILC_SERVER_CMD(connect, CONNECT, 
60                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
61   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
62   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
63   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
64   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
65   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
66   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
67   SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
68   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
69   SILC_SERVER_CMD(restart, RESTART, 
70                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
71   SILC_SERVER_CMD(close, CLOSE,
72                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
73   SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
74   SILC_SERVER_CMD(silcoper, SILCOPER,
75                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
76   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
77   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
78
79   { NULL, 0 },
80 };
81
82 #define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max)            \
83 do {                                                                          \
84   unsigned int _argc = silc_argument_get_arg_num(cmd->args);                  \
85                                                                               \
86   SILC_LOG_DEBUG(("Start"));                                                  \
87                                                                               \
88   if (_argc < min) {                                                          \
89     silc_server_command_send_status_reply(cmd, command,                       \
90                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
91     silc_server_command_free(cmd);                                            \
92     return;                                                                   \
93   }                                                                           \
94   if (_argc > max) {                                                          \
95     silc_server_command_send_status_reply(cmd, command,                       \
96                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);   \
97     silc_server_command_free(cmd);                                            \
98     return;                                                                   \
99   }                                                                           \
100 } while(0)
101
102 /* Returns TRUE if the connection is registered. Unregistered connections
103    usually cannot send commands hence the check. */
104
105 static int silc_server_is_registered(SilcServer server,
106                                      SilcSocketConnection sock,
107                                      SilcServerCommandContext cmd,
108                                      SilcCommand command)
109 {
110   SilcIDListData idata = (SilcIDListData)sock->user_data;
111   if (idata->registered)
112     return TRUE;
113
114   silc_server_command_send_status_reply(cmd, command,
115                                         SILC_STATUS_ERR_NOT_REGISTERED);
116   silc_server_command_free(cmd);
117   return FALSE;
118 }
119
120 /* Processes received command packet. */
121
122 void silc_server_command_process(SilcServer server,
123                                  SilcSocketConnection sock,
124                                  SilcPacketContext *packet)
125 {
126   SilcServerCommandContext ctx;
127   SilcServerCommand *cmd;
128
129 #if 0
130   /* XXX allow commands in but do not execute them more than once per
131      two seconds. */
132
133   /* Check whether it is allowed for this connection to execute any
134      command. */
135   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
136     time_t curtime;
137     SilcClientEntry client = (SilcClientEntry)sock->user_data;
138
139     if (!client)
140       return;
141
142     /* Allow only one command executed in 2 seconds. */
143     curtime = time(NULL);
144     if (client->last_command && (curtime - client->last_command) < 2)
145       return;
146
147     /* Update access time */
148     client->last_command = curtime;
149   }
150 #endif
151   
152   /* Allocate command context. This must be free'd by the
153      command routine receiving it. */
154   ctx = silc_calloc(1, sizeof(*ctx));
155   ctx->server = server;
156   ctx->sock = sock;
157   ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
158   
159   /* Parse the command payload in the packet */
160   ctx->payload = silc_command_payload_parse(packet->buffer);
161   if (!ctx->payload) {
162     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
163     silc_buffer_free(packet->buffer);
164     silc_packet_context_free(packet);
165     silc_free(ctx);
166     return;
167   }
168   ctx->args = silc_command_get_args(ctx->payload);
169   
170   /* Execute command. If this fails the packet is dropped. */
171   for (cmd = silc_command_list; cmd->cb; cmd++)
172     if (cmd->cmd == silc_command_get(ctx->payload)) {
173
174       if (!(cmd->flags & SILC_CF_REG)) {
175         cmd->cb(ctx);
176         break;
177       }
178       
179       if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
180         cmd->cb(ctx);
181         break;
182       }
183     }
184
185   if (cmd == NULL) {
186     SILC_LOG_ERROR(("Unknown command, packet dropped"));
187     silc_server_command_free(ctx);
188     return;
189   }
190 }
191
192 /* Add new pending command to be executed when reply to a command has been
193    received. The `reply_cmd' is the command that will call the `callback'
194    with `context' when reply has been received.  If `ident' is non-zero
195    the `callback' will be executed when received reply with command
196    identifier `ident'. */
197
198 void silc_server_command_pending(SilcServer server,
199                                  SilcCommand reply_cmd,
200                                  unsigned short ident,
201                                  SilcCommandCb callback,
202                                  void *context)
203 {
204   SilcServerCommandPending *reply;
205
206   reply = silc_calloc(1, sizeof(*reply));
207   reply->reply_cmd = reply_cmd;
208   reply->ident = ident;
209   reply->context = context;
210   reply->callback = callback;
211   silc_dlist_add(server->pending_commands, reply);
212 }
213
214 /* Deletes pending command by reply command type. */
215
216 void silc_server_command_pending_del(SilcServer server,
217                                      SilcCommand reply_cmd,
218                                      unsigned short ident)
219 {
220   SilcServerCommandPending *r;
221
222   silc_dlist_start(server->pending_commands);
223   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
224     if (r->reply_cmd == reply_cmd && r->ident == ident) {
225       silc_dlist_del(server->pending_commands, r);
226       break;
227     }
228   }
229 }
230
231 /* Checks for pending commands and marks callbacks to be called from
232    the command reply function. Returns TRUE if there were pending command. */
233
234 int silc_server_command_pending_check(SilcServer server,
235                                       SilcServerCommandReplyContext ctx,
236                                       SilcCommand command, 
237                                       unsigned short ident)
238 {
239   SilcServerCommandPending *r;
240
241   silc_dlist_start(server->pending_commands);
242   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
243     if (r->reply_cmd == command && r->ident == ident) {
244       ctx->context = r->context;
245       ctx->callback = r->callback;
246       ctx->ident = ident;
247       return TRUE;
248     }
249   }
250
251   return FALSE;
252 }
253
254 /* Free's the command context allocated before executing the command */
255
256 static void silc_server_command_free(SilcServerCommandContext cmd)
257 {
258   if (cmd) {
259     if (cmd->payload)
260       silc_command_free_payload(cmd->payload);
261     if (cmd->packet)
262       silc_packet_context_free(cmd->packet);
263     silc_free(cmd);
264   }
265 }
266
267 /* Sends simple status message as command reply packet */
268
269 static void 
270 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
271                                       SilcCommand command,
272                                       SilcCommandStatus status)
273 {
274   SilcBuffer buffer;
275
276   SILC_LOG_DEBUG(("Sending command status %d", status));
277
278   buffer = silc_command_reply_payload_encode_va(command, status, 0, 0);
279   silc_server_packet_send(cmd->server, cmd->sock,
280                           SILC_PACKET_COMMAND_REPLY, 0, 
281                           buffer->data, buffer->len, FALSE);
282   silc_buffer_free(buffer);
283 }
284
285 /* Sends command status reply with one extra argument. The argument
286    type must be sent as argument. */
287
288 static void 
289 silc_server_command_send_status_data(SilcServerCommandContext cmd,
290                                      SilcCommand command,
291                                      SilcCommandStatus status,
292                                      unsigned int arg_type,
293                                      unsigned char *arg,
294                                      unsigned int arg_len)
295 {
296   SilcBuffer buffer;
297
298   SILC_LOG_DEBUG(("Sending command status %d", status));
299
300   buffer = silc_command_reply_payload_encode_va(command, status, 0, 1,
301                                                 arg_type, arg, arg_len);
302   silc_server_packet_send(cmd->server, cmd->sock,
303                           SILC_PACKET_COMMAND_REPLY, 0, 
304                           buffer->data, buffer->len, FALSE);
305   silc_buffer_free(buffer);
306 }
307
308 /******************************************************************************
309
310                               WHOIS Functions
311
312 ******************************************************************************/
313
314 static int
315 silc_server_command_whois_parse(SilcServerCommandContext cmd,
316                                 SilcClientID ***client_id,
317                                 unsigned int *client_id_count,
318                                 char **nickname,
319                                 char **server_name,
320                                 int *count,
321                                 SilcCommand command)
322 {
323   unsigned char *tmp;
324   unsigned int len;
325   unsigned int argc = silc_argument_get_arg_num(cmd->args);
326   int i, k;
327
328   /* If client ID is in the command it must be used instead of nickname */
329   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
330   if (!tmp) {
331     /* No ID, get the nickname@server string and parse it. */
332     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
333     if (tmp) {
334       if (strchr(tmp, '@')) {
335         len = strcspn(tmp, "@");
336         *nickname = silc_calloc(len + 1, sizeof(char));
337         memcpy(*nickname, tmp, len);
338         *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
339         memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
340       } else {
341         *nickname = strdup(tmp);
342       }
343     } else {
344       silc_server_command_send_status_reply(cmd, command,
345                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
346       return FALSE;
347     }
348   } else {
349     /* Command includes ID, we must use that.  Also check whether the command
350        has more than one ID set - take them all. */
351
352     *client_id = silc_calloc(1, sizeof(**client_id));
353     (*client_id)[0] = silc_id_payload_parse_id(tmp, len);
354     *client_id_count = 1;
355
356     /* Take all ID's from the command packet */
357     if (argc > 3) {
358       for (k = 1, i = 4; i < argc; i++) {
359         tmp = silc_argument_get_arg_type(cmd->args, i, &len);
360         if (tmp) {
361           *client_id = silc_realloc(*client_id, sizeof(**client_id) *
362                                     (*client_id_count + 1));
363           (*client_id)[k++] = silc_id_payload_parse_id(tmp, len);
364           (*client_id_count)++;
365         }
366       }
367     }
368
369     /* Command includes ID, use that */
370   }
371
372   /* Get the max count of reply messages allowed */
373   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
374   if (tmp)
375     *count = atoi(tmp);
376   else
377     *count = 0;
378
379   return TRUE;
380 }
381
382 static char
383 silc_server_command_whois_check(SilcServerCommandContext cmd,
384                                 SilcClientEntry *clients,
385                                 unsigned int clients_count)
386 {
387   SilcServer server = cmd->server;
388   int i;
389   SilcClientEntry entry;
390
391   for (i = 0; i < clients_count; i++) {
392     entry = clients[i];
393
394     if (!entry->nickname || !entry->username || !entry->userinfo) {
395       SilcBuffer tmpbuf;
396       unsigned short old_ident;
397
398       if (!entry->router)
399         continue;
400       
401       old_ident = silc_command_get_ident(cmd->payload);
402       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
403       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
404
405       /* Send WHOIS command */
406       silc_server_packet_send(server, entry->router->connection,
407                               SILC_PACKET_COMMAND, cmd->packet->flags,
408                               tmpbuf->data, tmpbuf->len, TRUE);
409       
410       /* Reprocess this packet after received reply */
411       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
412                                   silc_command_get_ident(cmd->payload),
413                                   silc_server_command_whois, (void *)cmd);
414       cmd->pending = TRUE;
415       
416       silc_command_set_ident(cmd->payload, old_ident);
417
418       silc_buffer_free(tmpbuf);
419       return FALSE;
420     }
421   }
422
423   return TRUE;
424 }
425
426 static void
427 silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
428                                      SilcClientEntry *clients,
429                                      unsigned int clients_count)
430 {
431   SilcServer server = cmd->server;
432   char *tmp;
433   int i, count = 0, len;
434   SilcBuffer packet, idp;
435   SilcClientEntry entry;
436   SilcCommandStatus status;
437   unsigned short ident = silc_command_get_ident(cmd->payload);
438
439   status = SILC_STATUS_OK;
440   if (clients_count > 1)
441     status = SILC_STATUS_LIST_START;
442
443   for (i = 0; i < clients_count; i++) {
444     entry = clients[i];
445
446     if (count && i - 1 == count)
447       break;
448
449     if (clients_count > 2)
450       status = SILC_STATUS_LIST_ITEM;
451
452     if (clients_count > 1 && i == clients_count - 1)
453       status = SILC_STATUS_LIST_END;
454
455     /* Send WHOIS reply */
456     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
457     tmp = silc_argument_get_first_arg(cmd->args, NULL);
458     
459     /* XXX */
460     {
461       char nh[256], uh[256];
462       unsigned char idle[4];
463       SilcSocketConnection hsock;
464
465       memset(uh, 0, sizeof(uh));
466       memset(nh, 0, sizeof(nh));
467       
468       strncat(nh, entry->nickname, strlen(entry->nickname));
469       if (!strchr(entry->nickname, '@')) {
470         strncat(nh, "@", 1);
471         len = entry->router ? strlen(entry->router->server_name) :
472           strlen(server->server_name);
473         strncat(nh, entry->router ? entry->router->server_name :
474                 server->server_name, len);
475       }
476       
477       strncat(uh, entry->username, strlen(entry->username));
478       if (!strchr(entry->username, '@')) {
479         strncat(uh, "@", 1);
480         hsock = (SilcSocketConnection)entry->connection;
481         len = strlen(hsock->hostname);
482         strncat(uh, hsock->hostname, len);
483       }
484       
485       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
486       
487       /* XXX */
488       if (entry->userinfo)
489         packet = 
490           silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
491                                                status, ident, 5, 
492                                                2, idp->data, idp->len,
493                                                3, nh, strlen(nh),
494                                                4, uh, strlen(uh),
495                                                5, entry->userinfo, 
496                                                strlen(entry->userinfo),
497                                                7, idle, 4);
498       else
499         packet = 
500           silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
501                                                status, ident, 4, 
502                                                2, idp->data, idp->len,
503                                                3, nh, strlen(nh),
504                                                4, uh, strlen(uh),
505                                                7, idle, 4);
506     }
507     
508     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
509                             0, packet->data, packet->len, FALSE);
510     
511     silc_buffer_free(packet);
512     silc_buffer_free(idp);
513   }
514 }
515
516 static int
517 silc_server_command_whois_from_client(SilcServerCommandContext cmd)
518 {
519   SilcServer server = cmd->server;
520   char *nick = NULL, *server_name = NULL;
521   int count = 0, clients_count = 0;
522   SilcClientEntry *clients = NULL, entry;
523   SilcClientID **client_id = NULL;
524   unsigned int client_id_count = 0;
525   int i, ret = 0;
526
527   /* Protocol dictates that we must always send the received WHOIS request
528      to our router if we are normal server, so let's do it now unless we
529      are standalone. We will not send any replies to the client until we
530      have received reply from the router. */
531   if (server->server_type == SILC_SERVER && 
532       !cmd->pending && !server->standalone) {
533     SilcBuffer tmpbuf;
534     unsigned short old_ident;
535
536     old_ident = silc_command_get_ident(cmd->payload);
537     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
538     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
539
540     /* Send WHOIS command to our router */
541     silc_server_packet_send(server, (SilcSocketConnection)
542                             server->router->connection,
543                             SILC_PACKET_COMMAND, cmd->packet->flags,
544                             tmpbuf->data, tmpbuf->len, TRUE);
545
546     /* Reprocess this packet after received reply from router */
547     silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
548                                 silc_command_get_ident(cmd->payload),
549                                 silc_server_command_whois, (void *)cmd);
550     cmd->pending = TRUE;
551
552     silc_command_set_ident(cmd->payload, old_ident);
553
554     silc_buffer_free(tmpbuf);
555     ret = -1;
556     goto out;
557   }
558
559   /* We are ready to process the command request. Let's search for the
560      requested client and send reply to the requesting client. */
561
562   /* Parse the whois request */
563   if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
564                                        &nick, &server_name, &count,
565                                        SILC_COMMAND_WHOIS))
566     return 0;
567
568   /* Get all clients matching that ID or nickname from local list */
569   if (client_id_count) {
570     /* Check all Client ID's received in the command packet */
571     for (i = 0; i < client_id_count; i++) {
572       entry = silc_idlist_find_client_by_id(server->local_list, 
573                                             client_id[i], NULL);
574       if (entry) {
575         clients = silc_realloc(clients, sizeof(*clients) * 
576                                (clients_count + 1));
577         clients[clients_count++] = entry;
578       }
579     }
580   } else {
581     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
582                                                   nick, server_name,
583                                                   &clients_count);
584   }
585   
586   /* Check global list as well */
587   if (!clients) {
588     if (client_id_count) {
589       /* Check all Client ID's received in the command packet */
590       for (i = 0; i < client_id_count; i++) {
591         entry = silc_idlist_find_client_by_id(server->global_list, 
592                                               client_id[i], NULL);
593         if (entry) {
594           clients = silc_realloc(clients, sizeof(*clients) * 
595                                  (clients_count + 1));
596           clients[clients_count++] = entry;
597         }
598       }
599     } else {
600       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
601                                                     nick, server_name,
602                                                     &clients_count);
603     }
604   }
605   
606   if (!clients) {
607     /* Such client(s) really does not exist in the SILC network. */
608     if (!client_id_count) {
609       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
610                                            SILC_STATUS_ERR_NO_SUCH_NICK,
611                                            3, nick, strlen(nick));
612     } else {
613       SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
614       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
615                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
616                                            2, idp->data, idp->len);
617       silc_buffer_free(idp);
618     }
619     goto out;
620   }
621
622   /* Router always finds the client entry if it exists in the SILC network.
623      However, it might be incomplete entry and does not include all the
624      mandatory fields that WHOIS command reply requires. Check for these and
625      make query from the server who owns the client if some fields are 
626      missing. */
627   if (server->server_type == SILC_ROUTER &&
628       !silc_server_command_whois_check(cmd, clients, clients_count)) {
629     ret = -1;
630     goto out;
631   }
632
633   /* Send the command reply to the client */
634   silc_server_command_whois_send_reply(cmd, clients, clients_count);
635
636  out:
637   if (client_id_count) {
638     for (i = 0; i < client_id_count; i++)
639       silc_free(client_id[i]);
640     silc_free(client_id);
641   }
642   if (clients)
643     silc_free(clients);
644   if (nick)
645     silc_free(nick);
646   if (server_name)
647     silc_free(server_name);
648
649   return ret;
650 }
651
652 static int
653 silc_server_command_whois_from_server(SilcServerCommandContext cmd)
654 {
655   SilcServer server = cmd->server;
656   char *nick = NULL, *server_name = NULL;
657   int count = 0, clients_count = 0;
658   SilcClientEntry *clients = NULL, entry;
659   SilcClientID **client_id = NULL;
660   unsigned int client_id_count = 0;
661   int i, ret = 0;
662
663   /* Parse the whois request */
664   if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
665                                        &nick, &server_name, &count,
666                                        SILC_COMMAND_WHOIS))
667     return 0;
668
669   /* Process the command request. Let's search for the requested client and
670      send reply to the requesting server. */
671
672   if (client_id_count) {
673     /* Check all Client ID's received in the command packet */
674     for (i = 0; i < client_id_count; i++) {
675       entry = silc_idlist_find_client_by_id(server->local_list, 
676                                             client_id[i], NULL);
677       if (entry) {
678         clients = silc_realloc(clients, sizeof(*clients) * 
679                                (clients_count + 1));
680         clients[clients_count++] = entry;
681       }
682     }
683   } else {
684     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
685                                                   nick, server_name,
686                                                   &clients_count);
687     if (!clients)
688       clients = silc_idlist_get_clients_by_hash(server->local_list, 
689                                                 nick, server->md5hash,
690                                                 &clients_count);
691   }
692   
693   /* If we are router we will check our global list as well. */
694   if (!clients && server->server_type == SILC_ROUTER) {
695     if (client_id_count) {
696       /* Check all Client ID's received in the command packet */
697       for (i = 0; i < client_id_count; i++) {
698         entry = silc_idlist_find_client_by_id(server->global_list, 
699                                               client_id[i], NULL);
700         if (entry) {
701           clients = silc_realloc(clients, sizeof(*clients) * 
702                                  (clients_count + 1));
703           clients[clients_count++] = entry;
704         }
705       }
706     } else {
707       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
708                                                     nick, server_name,
709                                                     &clients_count);
710       if (!clients)
711         clients = silc_idlist_get_clients_by_hash(server->global_list, 
712                                                   nick, server->md5hash,
713                                                   &clients_count);
714     }
715   }
716
717   if (!clients) {
718     /* Such a client really does not exist in the SILC network. */
719     if (!client_id_count) {
720       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
721                                            SILC_STATUS_ERR_NO_SUCH_NICK,
722                                            3, nick, strlen(nick));
723     } else {
724       SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
725       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
726                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
727                                            2, idp->data, idp->len);
728       silc_buffer_free(idp);
729     }
730     goto out;
731   }
732
733   /* Router always finds the client entry if it exists in the SILC network.
734      However, it might be incomplete entry and does not include all the
735      mandatory fields that WHOIS command reply requires. Check for these and
736      make query from the server who owns the client if some fields are 
737      missing. */
738   if (server->server_type == SILC_ROUTER &&
739       !silc_server_command_whois_check(cmd, clients, clients_count)) {
740     ret = -1;
741     goto out;
742   }
743
744   /* Send the command reply to the client */
745   silc_server_command_whois_send_reply(cmd, clients, clients_count);
746
747  out:
748   if (client_id_count) {
749     for (i = 0; i < client_id_count; i++)
750       silc_free(client_id[i]);
751     silc_free(client_id);
752   }
753   if (clients)
754     silc_free(clients);
755   if (nick)
756     silc_free(nick);
757   if (server_name)
758     silc_free(server_name);
759
760   return ret;
761 }
762
763 /* Server side of command WHOIS. Processes user's query and sends found 
764    results as command replies back to the client. */
765
766 SILC_SERVER_CMD_FUNC(whois)
767 {
768   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
769   int ret;
770
771   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3328);
772
773   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
774     ret = silc_server_command_whois_from_client(cmd);
775   else
776     ret = silc_server_command_whois_from_server(cmd);
777
778   if (!ret)
779     silc_server_command_free(cmd);
780 }
781
782 SILC_SERVER_CMD_FUNC(whowas)
783 {
784 }
785
786 /******************************************************************************
787
788                               IDENTIFY Functions
789
790 ******************************************************************************/
791
792 /* Checks that all mandatory fields are present. If not then send WHOIS 
793    request to the server who owns the client. We use WHOIS because we want
794    to get as much information as possible at once. */
795
796 static char
797 silc_server_command_identify_check(SilcServerCommandContext cmd,
798                                    SilcClientEntry *clients,
799                                    unsigned int clients_count)
800 {
801   SilcServer server = cmd->server;
802   int i;
803   SilcClientEntry entry;
804
805   for (i = 0; i < clients_count; i++) {
806     entry = clients[i];
807
808     if (!entry->nickname) {
809       SilcBuffer tmpbuf;
810       unsigned short old_ident;
811       
812       if (!entry->router)
813         continue;
814       
815       old_ident = silc_command_get_ident(cmd->payload);
816       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
817       silc_command_set_command(cmd->payload, SILC_COMMAND_WHOIS);
818       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
819       
820       /* Send WHOIS request. We send WHOIS since we're doing the requesting
821          now anyway so make it a good one. */
822       silc_server_packet_send(server, entry->router->connection,
823                               SILC_PACKET_COMMAND, cmd->packet->flags,
824                               tmpbuf->data, tmpbuf->len, TRUE);
825       
826       /* Reprocess this packet after received reply */
827       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
828                                   silc_command_get_ident(cmd->payload),
829                                   silc_server_command_identify, (void *)cmd);
830       cmd->pending = TRUE;
831       
832       /* Put old data back to the Command Payload we just changed */
833       silc_command_set_ident(cmd->payload, old_ident);
834       silc_command_set_command(cmd->payload, SILC_COMMAND_IDENTIFY);
835
836       silc_buffer_free(tmpbuf);
837       return FALSE;
838     }
839   }
840
841   return TRUE;
842 }
843
844 static void
845 silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
846                                         SilcClientEntry *clients,
847                                         unsigned int clients_count)
848 {
849   SilcServer server = cmd->server;
850   char *tmp;
851   int i, count = 0, len;
852   SilcBuffer packet, idp;
853   SilcClientEntry entry;
854   SilcCommandStatus status;
855   unsigned short ident = silc_command_get_ident(cmd->payload);
856
857   status = SILC_STATUS_OK;
858   if (clients_count > 1)
859     status = SILC_STATUS_LIST_START;
860
861   for (i = 0; i < clients_count; i++) {
862     entry = clients[i];
863
864     if (count && i - 1 == count)
865       break;
866
867     if (clients_count > 2)
868       status = SILC_STATUS_LIST_ITEM;
869
870     if (clients_count > 1 && i == clients_count - 1)
871       status = SILC_STATUS_LIST_END;
872
873     /* Send IDENTIFY reply */
874     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
875     tmp = silc_argument_get_first_arg(cmd->args, NULL);
876     
877     /* XXX */
878     {
879       char nh[256], uh[256];
880       SilcSocketConnection hsock;
881
882       memset(uh, 0, sizeof(uh));
883       memset(nh, 0, sizeof(nh));
884       
885       strncat(nh, entry->nickname, strlen(entry->nickname));
886       if (!strchr(entry->nickname, '@')) {
887         strncat(nh, "@", 1);
888         len = entry->router ? strlen(entry->router->server_name) :
889           strlen(server->server_name);
890         strncat(nh, entry->router ? entry->router->server_name :
891                 server->server_name, len);
892       }
893       
894       if (!entry->username) {
895         packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
896                                                       SILC_STATUS_OK, ident, 2,
897                                                       2, idp->data, idp->len, 
898                                                       3, nh, strlen(nh));
899       } else {
900         strncat(uh, entry->username, strlen(entry->username));
901         if (!strchr(entry->username, '@')) {
902           strncat(uh, "@", 1);
903           hsock = (SilcSocketConnection)entry->connection;
904           len = strlen(hsock->hostname);
905           strncat(uh, hsock->hostname, len);
906         }
907       
908         packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
909                                                       SILC_STATUS_OK, ident, 3,
910                                                       2, idp->data, idp->len, 
911                                                       3, nh, strlen(nh),
912                                                       4, uh, strlen(uh));
913       }
914       
915       silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
916                               0, packet->data, packet->len, FALSE);
917       
918       silc_buffer_free(packet);
919       silc_buffer_free(idp);
920     }
921   }
922 }
923
924 static int
925 silc_server_command_identify_from_client(SilcServerCommandContext cmd)
926 {
927   SilcServer server = cmd->server;
928   char *nick = NULL, *server_name = NULL;
929   int count = 0, clients_count = 0; 
930   SilcClientEntry *clients = NULL, entry;
931   SilcClientID **client_id = NULL;
932   unsigned int client_id_count = 0;
933   int i, ret = 0;
934
935   /* Protocol dictates that we must always send the received IDENTIFY request
936      to our router if we are normal server, so let's do it now unless we
937      are standalone. We will not send any replies to the client until we
938      have received reply from the router. */
939   if (server->server_type == SILC_SERVER && 
940       !cmd->pending && !server->standalone) {
941     SilcBuffer tmpbuf;
942     unsigned short old_ident;
943
944     old_ident = silc_command_get_ident(cmd->payload);
945     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
946     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
947
948     /* Send IDENTIFY command to our router */
949     silc_server_packet_send(server, (SilcSocketConnection)
950                             server->router->connection,
951                             SILC_PACKET_COMMAND, cmd->packet->flags,
952                             tmpbuf->data, tmpbuf->len, TRUE);
953
954     /* Reprocess this packet after received reply from router */
955     silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, 
956                                 silc_command_get_ident(cmd->payload),
957                                 silc_server_command_identify, (void *)cmd);
958     cmd->pending = TRUE;
959
960     silc_command_set_ident(cmd->payload, old_ident);
961
962     silc_buffer_free(tmpbuf);
963     ret = -1;
964     goto out;
965   }
966
967   /* We are ready to process the command request. Let's search for the
968      requested client and send reply to the requesting client. */
969
970   /* Parse the IDENTIFY request */
971   if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
972                                        &nick, &server_name, &count,
973                                        SILC_COMMAND_IDENTIFY))
974     return 0;
975
976   /* Get all clients matching that ID or nickname from local list */
977   if (client_id_count) { 
978     /* Check all Client ID's received in the command packet */
979     for (i = 0; i < client_id_count; i++) {
980       entry = silc_idlist_find_client_by_id(server->local_list, 
981                                             client_id[i], NULL);
982       if (entry) {
983         clients = silc_realloc(clients, sizeof(*clients) * 
984                                (clients_count + 1));
985         clients[clients_count++] = entry;
986       }
987     }
988   } else {
989     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
990                                                   nick, server_name,
991                                                   &clients_count);
992   }
993   
994   /* Check global list as well */
995   if (!clients) {
996     if (client_id_count) {
997       /* Check all Client ID's received in the command packet */
998       for (i = 0; i < client_id_count; i++) {
999         entry = silc_idlist_find_client_by_id(server->global_list, 
1000                                               client_id[i], NULL);
1001         if (entry) {
1002           clients = silc_realloc(clients, sizeof(*clients) * 
1003                                  (clients_count + 1));
1004           clients[clients_count++] = entry;
1005         }
1006       }
1007     } else {
1008       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
1009                                                     nick, server_name,
1010                                                     &clients_count);
1011     }
1012   }
1013   
1014   if (!clients) {
1015     /* Such a client really does not exist in the SILC network. */
1016     if (!client_id_count) {
1017       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1018                                            SILC_STATUS_ERR_NO_SUCH_NICK,
1019                                            3, nick, strlen(nick));
1020     } else {
1021       SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
1022       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1023                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
1024                                            2, idp->data, idp->len);
1025       silc_buffer_free(idp);
1026     }
1027     goto out;
1028   }
1029
1030   /* Check that all mandatory fields are present and request those data
1031      from the server who owns the client if necessary. */
1032   if (!cmd->pending && server->server_type == SILC_ROUTER &&
1033       !silc_server_command_identify_check(cmd, clients, clients_count)) {
1034     ret = -1;
1035     goto out;
1036   }
1037
1038   /* Send the command reply to the client */
1039   silc_server_command_identify_send_reply(cmd, clients, clients_count);
1040
1041  out:
1042   if (client_id_count) {
1043     for (i = 0; i < client_id_count; i++)
1044       silc_free(client_id[i]);
1045     silc_free(client_id);
1046   }
1047   if (clients)
1048     silc_free(clients);
1049   if (nick)
1050     silc_free(nick);
1051   if (server_name)
1052     silc_free(server_name);
1053
1054   return ret;
1055 }
1056
1057 static int
1058 silc_server_command_identify_from_server(SilcServerCommandContext cmd)
1059 {
1060   SilcServer server = cmd->server;
1061   char *nick = NULL, *server_name = NULL;
1062   int count = 0, clients_count = 0;
1063   SilcClientEntry *clients = NULL, entry;
1064   SilcClientID **client_id = NULL;
1065   unsigned int client_id_count = 0;
1066   int i, ret = 0;
1067
1068   /* Parse the IDENTIFY request */
1069   if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
1070                                        &nick, &server_name, &count,
1071                                        SILC_COMMAND_IDENTIFY))
1072     return 0;
1073
1074   /* Process the command request. Let's search for the requested client and
1075      send reply to the requesting server. */
1076
1077   if (client_id_count) {
1078     /* Check all Client ID's received in the command packet */
1079     for (i = 0; i < client_id_count; i++) {
1080       entry = silc_idlist_find_client_by_id(server->local_list, 
1081                                             client_id[i], NULL);
1082       if (entry) {
1083         clients = silc_realloc(clients, sizeof(*clients) * 
1084                                (clients_count + 1));
1085         clients[clients_count++] = entry;
1086       }
1087     }
1088   } else {
1089     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
1090                                                   nick, server_name,
1091                                                   &clients_count);
1092     if (!clients)
1093       clients = silc_idlist_get_clients_by_hash(server->local_list, 
1094                                                 nick, server->md5hash,
1095                                                 &clients_count);
1096   }
1097   
1098   /* If we are router we will check our global list as well. */
1099   if (!clients && server->server_type == SILC_ROUTER) {
1100     if (client_id_count) {
1101       /* Check all Client ID's received in the command packet */
1102       for (i = 0; i < client_id_count; i++) {
1103         entry = silc_idlist_find_client_by_id(server->global_list, 
1104                                               client_id[i], NULL);
1105         if (entry) {
1106           clients = silc_realloc(clients, sizeof(*clients) * 
1107                                  (clients_count + 1));
1108           clients[clients_count++] = entry;
1109         }
1110       }
1111     } else {
1112       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
1113                                                     nick, server_name,
1114                                                     &clients_count);
1115       if (!clients)
1116         clients = silc_idlist_get_clients_by_hash(server->global_list, 
1117                                                   nick, server->md5hash,
1118                                                   &clients_count);
1119     }
1120   }
1121
1122   if (!clients) {
1123     /* Such a client really does not exist in the SILC network. */
1124     if (!client_id_count) {
1125       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1126                                            SILC_STATUS_ERR_NO_SUCH_NICK,
1127                                            3, nick, strlen(nick));
1128     } else {
1129       SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
1130       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1131                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
1132                                            2, idp->data, idp->len);
1133       silc_buffer_free(idp);
1134     }
1135     goto out;
1136   }
1137
1138   /* Check that all mandatory fields are present and request those data
1139      from the server who owns the client if necessary. */
1140   if (!cmd->pending && server->server_type == SILC_ROUTER &&
1141       !silc_server_command_identify_check(cmd, clients, clients_count)) {
1142     ret = -1;
1143     goto out;
1144   }
1145
1146   /* Send the command reply */
1147   silc_server_command_identify_send_reply(cmd, clients, clients_count);
1148
1149  out:
1150   if (client_id_count) {
1151     for (i = 0; i < client_id_count; i++)
1152       silc_free(client_id[i]);
1153     silc_free(client_id);
1154   }
1155   if (clients)
1156     silc_free(clients);
1157   if (nick)
1158     silc_free(nick);
1159   if (server_name)
1160     silc_free(server_name);
1161
1162   return ret;
1163 }
1164
1165 SILC_SERVER_CMD_FUNC(identify)
1166 {
1167   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1168   int ret;
1169
1170   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
1171
1172   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1173     ret = silc_server_command_identify_from_client(cmd);
1174   else
1175     ret = silc_server_command_identify_from_server(cmd);
1176
1177   if (!ret)
1178     silc_server_command_free(cmd);
1179 }
1180
1181 /* Checks string for bad characters and returns TRUE if they are found. */
1182
1183 static int silc_server_command_bad_chars(char *nick)
1184 {
1185   if (strchr(nick, '\\')) return TRUE;
1186   if (strchr(nick, '\"')) return TRUE;
1187   if (strchr(nick, '´')) return TRUE;
1188   if (strchr(nick, '`')) return TRUE;
1189   if (strchr(nick, '\'')) return TRUE;
1190   if (strchr(nick, '*')) return TRUE;
1191   if (strchr(nick, '/')) return TRUE;
1192   if (strchr(nick, '@')) return TRUE;
1193
1194   return FALSE;
1195 }
1196
1197 /* Server side of command NICK. Sets nickname for user. Setting
1198    nickname causes generation of a new client ID for the client. The
1199    new client ID is sent to the client after changing the nickname. */
1200
1201 SILC_SERVER_CMD_FUNC(nick)
1202 {
1203   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1204   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1205   SilcServer server = cmd->server;
1206   SilcBuffer packet, nidp, oidp;
1207   SilcClientID *new_id;
1208   char *nick;
1209
1210   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NICK, cmd, 1, 1);
1211
1212   /* Check nickname */
1213   nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
1214   if (silc_server_command_bad_chars(nick) == TRUE) {
1215     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
1216                                           SILC_STATUS_ERR_BAD_NICKNAME);
1217     goto out;
1218   }
1219
1220   /* Create new Client ID */
1221   silc_id_create_client_id(cmd->server->id, cmd->server->rng, 
1222                            cmd->server->md5hash, nick,
1223                            &new_id);
1224
1225   /* Send notify about nickname change to our router. We send the new
1226      ID and ask to replace it with the old one. If we are router the
1227      packet is broadcasted. */
1228   if (!server->standalone)
1229     silc_server_send_replace_id(server, server->router->connection, 
1230                                 server->server_type == SILC_SERVER ? 
1231                                 FALSE : TRUE, client->id,
1232                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
1233                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
1234
1235   /* Remove old cache entry */
1236   silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
1237                          client->id); 
1238
1239   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1240
1241   /* Free old ID */
1242   if (client->id) {
1243     memset(client->id, 0, SILC_ID_CLIENT_LEN);
1244     silc_free(client->id);
1245   }
1246
1247   /* Save the nickname as this client is our local client */
1248   if (client->nickname)
1249     silc_free(client->nickname);
1250
1251   client->nickname = strdup(nick);
1252   client->id = new_id;
1253
1254   /* Update client cache */
1255   silc_idcache_add(server->local_list->clients, client->nickname, 
1256                    SILC_ID_CLIENT, client->id, (void *)client, TRUE);
1257
1258   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1259
1260   /* Send NICK_CHANGE notify */
1261   silc_server_send_notify_on_channels(server, client, 
1262                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
1263                                       oidp->data, oidp->len, 
1264                                       nidp->data, nidp->len);
1265
1266   /* Send the new Client ID as reply command back to client */
1267   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
1268                                                 SILC_STATUS_OK, 0, 1, 
1269                                                 2, nidp->data, nidp->len);
1270   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1271                           0, packet->data, packet->len, FALSE);
1272
1273   silc_buffer_free(packet);
1274   silc_buffer_free(nidp);
1275   silc_buffer_free(oidp);
1276   
1277  out:
1278   silc_server_command_free(cmd);
1279 }
1280
1281 SILC_SERVER_CMD_FUNC(list)
1282 {
1283 }
1284
1285 /* Server side of TOPIC command. Sets topic for channel and/or returns
1286    current topic to client. */
1287
1288 SILC_SERVER_CMD_FUNC(topic)
1289 {
1290   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1291   SilcServer server = cmd->server;
1292   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1293   SilcChannelID *channel_id;
1294   SilcChannelEntry channel;
1295   SilcChannelClientEntry chl;
1296   SilcBuffer packet, idp;
1297   unsigned char *tmp;
1298   unsigned int argc, tmp_len;
1299
1300   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
1301
1302   argc = silc_argument_get_arg_num(cmd->args);
1303
1304   /* Get Channel ID */
1305   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1306   if (!tmp) {
1307     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1308                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1309     goto out;
1310   }
1311   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1312
1313   /* Check whether the channel exists */
1314   channel = silc_idlist_find_channel_by_id(server->local_list, 
1315                                            channel_id, NULL);
1316   if (!channel) {
1317     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1318                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1319     goto out;
1320   }
1321
1322   if (argc > 1) {
1323     /* Get the topic */
1324     tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1325     if (!tmp) {
1326       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1327                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1328       goto out;
1329     }
1330
1331     if (strlen(tmp) > 256) {
1332       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1333                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1334       goto out;
1335     }
1336
1337     /* See whether has rights to change topic */
1338     silc_list_start(channel->user_list);
1339     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
1340       if (chl->client == client) {
1341         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1342           silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1343                                                 SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1344           goto out;
1345         } else {
1346           break;
1347         }
1348       }
1349     }
1350
1351     /* Set the topic for channel */
1352     if (channel->topic)
1353       silc_free(channel->topic);
1354     channel->topic = strdup(tmp);
1355
1356     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1357
1358     /* Send notify about topic change to all clients on the channel */
1359     silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
1360                                        SILC_NOTIFY_TYPE_TOPIC_SET, 2,
1361                                        idp->data, idp->len,
1362                                        channel->topic, strlen(channel->topic));
1363     silc_buffer_free(idp);
1364   }
1365
1366   /* Send the topic to client as reply packet */
1367   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1368   if (channel->topic)
1369     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1370                                                   SILC_STATUS_OK, 0, 2, 
1371                                                   2, idp->data, idp->len,
1372                                                   3, channel->topic, 
1373                                                   strlen(channel->topic));
1374   else
1375     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1376                                                   SILC_STATUS_OK, 0, 1, 
1377                                                   2, idp->data, idp->len);
1378   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1379                           0, packet->data, packet->len, FALSE);
1380
1381   silc_buffer_free(packet);
1382   silc_buffer_free(idp);
1383   silc_free(channel_id);
1384
1385  out:
1386   silc_server_command_free(cmd);
1387 }
1388
1389 /* Server side of INVITE command. Invites some client to join some channel. */
1390
1391 SILC_SERVER_CMD_FUNC(invite)
1392 {
1393   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1394   SilcServer server = cmd->server;
1395   SilcSocketConnection sock = cmd->sock, dest_sock;
1396   SilcClientEntry sender, dest;
1397   SilcClientID *dest_id;
1398   SilcChannelEntry channel;
1399   SilcChannelID *channel_id;
1400   SilcBuffer sidp;
1401   unsigned char *tmp;
1402   unsigned int len;
1403
1404   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 2);
1405
1406   /* Get destination ID */
1407   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1408   if (!tmp) {
1409     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1410                                           SILC_STATUS_ERR_NO_CLIENT_ID);
1411     goto out;
1412   }
1413   dest_id = silc_id_payload_parse_id(tmp, len);
1414
1415   /* Get Channel ID */
1416   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1417   if (!tmp) {
1418     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1419                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1420     goto out;
1421   }
1422   channel_id = silc_id_payload_parse_id(tmp, len);
1423
1424   /* Check whether the channel exists */
1425   channel = silc_idlist_find_channel_by_id(server->local_list, 
1426                                            channel_id, NULL);
1427   if (!channel) {
1428     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1429                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1430     goto out;
1431   }
1432
1433   /* Check whether the sender of this command is on the channel. */
1434   sender = (SilcClientEntry)sock->user_data;
1435   if (!silc_server_client_on_channel(sender, channel)) {
1436     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1437                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
1438     goto out;
1439   }
1440
1441   /* Check whether the channel is invite-only channel. If yes then the
1442      sender of this command must be at least channel operator. */
1443   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1444     SilcChannelClientEntry chl;
1445
1446     silc_list_start(channel->user_list);
1447     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
1448       if (chl->client == sender) {
1449         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1450           silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1451                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1452           goto out;
1453         }
1454         break;
1455       }
1456   }
1457
1458   /* Find the connection data for the destination. If it is local we will
1459      send it directly otherwise we will send it to router for routing. */
1460   dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
1461   if (dest)
1462     dest_sock = (SilcSocketConnection)dest->connection;
1463   else
1464     dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
1465
1466   /* Check whether the requested client is already on the channel. */
1467   /* XXX if we are normal server we don't know about global clients on
1468      the channel thus we must request it (USERS command), check from
1469      local cache as well. */
1470   if (silc_server_client_on_channel(dest, channel)) {
1471     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1472                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1473     goto out;
1474   }
1475
1476   sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
1477
1478   /* Send notify to the client that is invited to the channel */
1479   silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
1480                                SILC_NOTIFY_TYPE_INVITE, 2, 
1481                                sidp->data, sidp->len, tmp, len);
1482
1483   /* Send command reply */
1484   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1485                                         SILC_STATUS_OK);
1486
1487   silc_buffer_free(sidp);
1488
1489  out:
1490   silc_server_command_free(cmd);
1491 }
1492
1493 /* Quits connection to client. This gets called if client won't
1494    close the connection even when it has issued QUIT command. */
1495
1496 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
1497 {
1498   SilcServer server = (SilcServer)context;
1499   SilcSocketConnection sock = server->sockets[fd];
1500
1501   /* Free all client specific data, such as client entry and entires
1502      on channels this client may be on. */
1503   silc_server_free_sock_user_data(server, sock);
1504
1505   /* Close the connection on our side */
1506   silc_server_close_connection(server, sock);
1507 }
1508
1509 /* Quits SILC session. This is the normal way to disconnect client. */
1510  
1511 SILC_SERVER_CMD_FUNC(quit)
1512 {
1513   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1514   SilcServer server = cmd->server;
1515   SilcSocketConnection sock = cmd->sock;
1516
1517   SILC_LOG_DEBUG(("Start"));
1518
1519   /* We quit the connection with little timeout */
1520   silc_task_register(server->timeout_queue, sock->sock,
1521                      silc_server_command_quit_cb, server,
1522                      0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1523
1524   silc_server_command_free(cmd);
1525 }
1526
1527 SILC_SERVER_CMD_FUNC(kill)
1528 {
1529 }
1530
1531 /* Server side of command INFO. This sends information about us to 
1532    the client. If client requested specific server we will send the 
1533    command to that server. */
1534
1535 SILC_SERVER_CMD_FUNC(info)
1536 {
1537   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1538   SilcServer server = cmd->server;
1539   SilcBuffer packet, idp;
1540   char info_string[256], *dest_server;
1541
1542   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
1543
1544   /* Get server name */
1545   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
1546   if (!dest_server) {
1547     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1548                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1549     goto out;
1550   }
1551
1552   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
1553     /* Send our reply */
1554     memset(info_string, 0, sizeof(info_string));
1555     snprintf(info_string, sizeof(info_string), 
1556              "location: %s server: %s admin: %s <%s>",
1557              server->config->admin_info->location,
1558              server->config->admin_info->server_type,
1559              server->config->admin_info->admin_name,
1560              server->config->admin_info->admin_email);
1561
1562     idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
1563
1564     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
1565                                                   SILC_STATUS_OK, 0, 2,
1566                                                   2, idp->data, idp->len,
1567                                                   3, info_string, 
1568                                                   strlen(info_string));
1569     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
1570                             packet->data, packet->len, FALSE);
1571     
1572     silc_buffer_free(packet);
1573     silc_buffer_free(idp);
1574   } else {
1575     /* Send this command to the requested server */
1576
1577     if (server->server_type == SILC_SERVER && !server->standalone) {
1578
1579     }
1580
1581     if (server->server_type == SILC_ROUTER) {
1582
1583     }
1584   }
1585   
1586  out:
1587   silc_server_command_free(cmd);
1588 }
1589
1590 SILC_SERVER_CMD_FUNC(connect)
1591 {
1592 }
1593
1594 /* Server side of command PING. This just replies to the ping. */
1595
1596 SILC_SERVER_CMD_FUNC(ping)
1597 {
1598   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1599   SilcServer server = cmd->server;
1600   SilcServerID *id;
1601   unsigned int len;
1602   unsigned char *tmp;
1603
1604   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
1605
1606   /* Get Server ID */
1607   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1608   if (!tmp) {
1609     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1610                                           SILC_STATUS_ERR_NO_SERVER_ID);
1611     goto out;
1612   }
1613   id = silc_id_str2id(tmp, SILC_ID_SERVER);
1614   if (!id)
1615     goto out;
1616
1617   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
1618     /* Send our reply */
1619     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1620                                           SILC_STATUS_OK);
1621   } else {
1622     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1623                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1624     goto out;
1625   }
1626
1627   silc_free(id);
1628
1629  out:
1630   silc_server_command_free(cmd);
1631 }
1632
1633 SILC_SERVER_CMD_FUNC(oper)
1634 {
1635 }
1636
1637 /* Assembles USERS command and executes it. This is called when client
1638    joins to a channel and we wan't to send USERS command reply to the 
1639    client. */
1640
1641 void silc_server_command_send_users(SilcServer server,
1642                                     SilcSocketConnection sock,
1643                                     SilcChannelEntry channel,
1644                                     int pending)
1645 {
1646   SilcServerCommandContext cmd;
1647   SilcBuffer buffer, idp;
1648   SilcPacketContext *packet = silc_packet_context_alloc();
1649
1650   SILC_LOG_DEBUG(("Start"));
1651
1652   /* Create USERS command packet and process it. */
1653   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1654   buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 0, 1,
1655                                           1, idp->data, idp->len);
1656
1657   packet->buffer = silc_buffer_copy(buffer);
1658   packet->sock = sock;
1659   packet->type = SILC_PACKET_COMMAND;
1660
1661   cmd = silc_calloc(1, sizeof(*cmd));
1662   cmd->payload = silc_command_payload_parse(buffer);
1663   cmd->args = silc_command_get_args(cmd->payload);
1664   cmd->server = server;
1665   cmd->sock = sock;
1666   cmd->packet = silc_packet_context_dup(packet);
1667   cmd->pending = FALSE;
1668
1669   if (pending) {
1670     /* If this function was called from pending command then instead of
1671        processing the command now, register a pending command callback which
1672        will process it after we've received the automatic USERS command 
1673        reply. */
1674     silc_server_command_pending(server, SILC_COMMAND_USERS, 0,
1675                                 silc_server_command_users, (void *)cmd);
1676     cmd->pending = TRUE;
1677     silc_free(buffer);
1678     silc_free(idp);
1679     return;
1680   }
1681
1682   /* Process USERS command. */
1683   silc_server_command_users((void *)cmd);
1684  
1685   silc_free(buffer);
1686   silc_free(idp);
1687   silc_packet_context_free(packet);
1688 }
1689
1690 /* Internal routine to join channel. The channel sent to this function
1691    has been either created or resolved from ID lists. This joins the sent
1692    client to the channel. */
1693
1694 static void silc_server_command_join_channel(SilcServer server, 
1695                                              SilcServerCommandContext cmd,
1696                                              SilcChannelEntry channel,
1697                                              SilcClientID *client_id,
1698                                              int created,
1699                                              unsigned int umode)
1700 {
1701   SilcSocketConnection sock = cmd->sock;
1702   unsigned char *tmp;
1703   unsigned int tmp_len;
1704   unsigned char *passphrase = NULL, mode[4], tmp2[4];
1705   SilcClientEntry client;
1706   SilcChannelClientEntry chl;
1707   SilcBuffer reply, chidp, clidp, keyp;
1708   unsigned short ident = silc_command_get_ident(cmd->payload);
1709
1710   SILC_LOG_DEBUG(("Start"));
1711
1712   if (!channel)
1713     return;
1714
1715   /* Get passphrase */
1716   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1717   if (tmp) {
1718     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1719     memcpy(passphrase, tmp, tmp_len);
1720   }
1721   
1722   /*
1723    * Check channel modes
1724    */
1725
1726   /* Check invite list if channel is invite-only channel */
1727   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1728     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
1729       /* Invite list is specified. Check whether client is invited in the
1730          list. If not, then check whether it has been invited otherwise. */
1731
1732     } else {
1733       /* XXX client must be invited to be able to join the channel */
1734     }
1735   }
1736
1737   /* Check ban list if set */
1738   if (channel->mode & SILC_CHANNEL_MODE_BAN) {
1739
1740   }
1741
1742   /* Check the channel passphrase if set. */
1743   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
1744     if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
1745                               strlen(channel->mode_data.passphrase))) {
1746       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1747                                             SILC_STATUS_ERR_BAD_PASSWORD);
1748       goto out;
1749     }
1750   }
1751
1752   /* Check user count limit if set. */
1753   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
1754     if (silc_list_count(channel->user_list) + 1 > 
1755         channel->mode_data.user_limit) {
1756       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1757                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
1758       goto out;
1759     }
1760   }
1761
1762   /*
1763    * Client is allowed to join to the channel. Make it happen.
1764    */
1765
1766   /* Get the client entry */
1767   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
1768     client = (SilcClientEntry)sock->user_data;
1769   } else {
1770     client = silc_idlist_find_client_by_id(server->local_list, client_id, 
1771                                            NULL);
1772     if (!client) {
1773       /* XXX actually this is useless since router finds always cell's
1774          local clients from its local lists. */
1775       client = silc_idlist_find_client_by_id(server->global_list, client_id, 
1776                                              NULL);
1777       if (!client)
1778         goto out;
1779     }
1780   }
1781
1782   /* Check whether the client already is on the channel */
1783   if (silc_server_client_on_channel(client, channel)) {
1784     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1785                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1786     goto out;
1787   }
1788
1789   /* Generate new channel key as protocol dictates */
1790   if (!created || !channel->channel_key)
1791     silc_server_create_channel_key(server, channel, 0);
1792
1793   /* Send the channel key. This is broadcasted to the channel but is not
1794      sent to the client who is joining to the channel. */
1795   silc_server_send_channel_key(server, NULL, channel, 
1796                                server->server_type == SILC_ROUTER ? 
1797                                FALSE : server->standalone);
1798
1799   /* Join the client to the channel by adding it to channel's user list.
1800      Add also the channel to client entry's channels list for fast cross-
1801      referencing. */
1802   chl = silc_calloc(1, sizeof(*chl));
1803   chl->mode = umode;
1804   chl->client = client;
1805   chl->channel = channel;
1806   silc_list_add(channel->user_list, chl);
1807   silc_list_add(client->channels, chl);
1808
1809   /* Encode Client ID Payload of the original client who wants to join */
1810   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1811
1812   /* Encode command reply packet */
1813   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1814   SILC_PUT32_MSB(channel->mode, mode);
1815   SILC_PUT32_MSB(created, tmp2);
1816   tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1817   keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp, 
1818                                          SILC_ID_CHANNEL_LEN,
1819                                          channel->channel_key->cipher->name,
1820                                          channel->key_len / 8, channel->key);
1821   silc_free(tmp);
1822   if (!channel->topic) {
1823     reply = 
1824       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1825                                            SILC_STATUS_OK, ident, 5,
1826                                            2, channel->channel_name,
1827                                            strlen(channel->channel_name),
1828                                            3, chidp->data, chidp->len,
1829                                            4, mode, 4,
1830                                            5, tmp2, 4,
1831                                            6, keyp->data, keyp->len);
1832   } else {
1833     reply = 
1834       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1835                                            SILC_STATUS_OK, ident, 6, 
1836                                            2, channel->channel_name, 
1837                                            strlen(channel->channel_name),
1838                                            3, chidp->data, chidp->len,
1839                                            4, mode, 4,
1840                                            5, tmp2, 4,
1841                                            6, keyp->data, keyp->len,
1842                                            8, channel->topic, 
1843                                            strlen(channel->topic));
1844   }
1845
1846   /* Send command reply */
1847   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
1848                           reply->data, reply->len, FALSE);
1849
1850   if (!cmd->pending) {
1851     /* Send JOIN notify to locally connected clients on the channel */
1852     silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
1853                                        SILC_NOTIFY_TYPE_JOIN, 1,
1854                                        clidp->data, clidp->len);
1855
1856     /* Send NEW_CHANNEL_USER packet to our primary router */
1857     if (!server->standalone)
1858       silc_server_send_new_channel_user(server, server->router->connection,
1859                                         server->server_type == SILC_SERVER ?
1860                                         FALSE : TRUE,
1861                                         channel->id, SILC_ID_CHANNEL_LEN,
1862                                         client->id, SILC_ID_CLIENT_LEN);
1863   }
1864
1865   /* Send USERS command reply to the joined channel so the user sees who
1866      is currently on the channel. */
1867   silc_server_command_send_users(server, sock, channel, cmd->pending);
1868
1869   silc_buffer_free(reply);
1870   silc_buffer_free(clidp);
1871   silc_buffer_free(chidp);
1872   silc_buffer_free(keyp);
1873
1874  out:
1875   if (passphrase)
1876     silc_free(passphrase);
1877 }
1878
1879 /* Server side of command JOIN. Joins client into requested channel. If 
1880    the channel does not exist it will be created. */
1881
1882 SILC_SERVER_CMD_FUNC(join)
1883 {
1884   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1885   SilcServer server = cmd->server;
1886   int tmp_len;
1887   char *tmp, *channel_name = NULL, *cipher = NULL;
1888   SilcChannelEntry channel;
1889   unsigned int umode = 0;
1890   int created = FALSE;
1891   SilcClientID *client_id;
1892
1893   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 4);
1894
1895   /* Get channel name */
1896   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1897   if (!tmp) {
1898     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1899                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1900     goto out;
1901   }
1902   channel_name = tmp;
1903
1904   if (silc_server_command_bad_chars(channel_name) == TRUE) {
1905     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1906                                           SILC_STATUS_ERR_BAD_CHANNEL);
1907     silc_free(channel_name);
1908     goto out;
1909   }
1910
1911   /* Get Client ID of the client who is joining to the channel */
1912   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1913   if (!tmp) {
1914     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1915                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1916     goto out;
1917   }
1918   client_id = silc_id_payload_parse_id(tmp, tmp_len);
1919   if (!client_id)
1920     goto out;
1921
1922   /* Get cipher name */
1923   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
1924
1925   /* See if the channel exists */
1926   channel = silc_idlist_find_channel_by_name(server->local_list, 
1927                                              channel_name, NULL);
1928
1929   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
1930     /* If this is coming from client the Client ID in the command packet must
1931        be same as the client's ID. */
1932     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
1933       SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
1934       if (SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
1935         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1936                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1937         goto out;
1938       }
1939     }
1940
1941     if (!channel) {
1942       /* Channel not found */
1943
1944       /* If we are standalone server we don't have a router, we just create 
1945          the channel by ourselves. */
1946       if (server->standalone) {
1947         channel = silc_server_create_new_channel(server, server->id, cipher, 
1948                                                  channel_name);
1949         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
1950         created = TRUE;
1951
1952       } else {
1953
1954         /* The channel does not exist on our server. If we are normal server 
1955            we will send JOIN command to our router which will handle the
1956            joining procedure (either creates the channel if it doesn't exist 
1957            or joins the client to it). */
1958         if (server->server_type == SILC_SERVER) {
1959           SilcBuffer tmpbuf;
1960           unsigned short old_ident;
1961           
1962           old_ident = silc_command_get_ident(cmd->payload);
1963           silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
1964           tmpbuf = silc_command_payload_encode_payload(cmd->payload);
1965           
1966           /* Send JOIN command to our router */
1967           silc_server_packet_send(server, (SilcSocketConnection)
1968                                   server->router->connection,
1969                                   SILC_PACKET_COMMAND, cmd->packet->flags,
1970                                   tmpbuf->data, tmpbuf->len, TRUE);
1971           
1972           /* Reprocess this packet after received reply from router */
1973           silc_server_command_pending(server, SILC_COMMAND_JOIN, 
1974                                       silc_command_get_ident(cmd->payload),
1975                                       silc_server_command_join, context);
1976           cmd->pending = TRUE;
1977           return;
1978         }
1979         
1980         /* We are router and the channel does not seem exist so we will check
1981            our global list as well for the channel. */
1982         channel = silc_idlist_find_channel_by_name(server->global_list, 
1983                                                    channel_name, NULL);
1984         if (!channel) {
1985           /* Channel really does not exist, create it */
1986           channel = silc_server_create_new_channel(server, server->id, cipher, 
1987                                                    channel_name);
1988           umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
1989           created = TRUE;
1990         }
1991       }
1992     }
1993   } else {
1994     if (!channel) {
1995       /* Channel not found */
1996
1997       /* If the command came from router and/or we are normal server then
1998          something went wrong with the joining as the channel was not found.
1999          We can't do anything else but ignore this. */
2000       if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
2001           server->server_type == SILC_SERVER)
2002         goto out;
2003       
2004       /* We are router and the channel does not seem exist so we will check
2005          our global list as well for the channel. */
2006       channel = silc_idlist_find_channel_by_name(server->global_list, 
2007                                                  channel_name, NULL);
2008       if (!channel) {
2009         /* Channel really does not exist, create it */
2010         channel = silc_server_create_new_channel(server, server->id, cipher, 
2011                                                  channel_name);
2012         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2013         created = TRUE;
2014       }
2015     }
2016   }
2017
2018   /* If the channel does not have global users and is also empty it means the
2019      channel was created globally (by our router) and the client will be the
2020      channel founder and operator. */
2021   if (!channel->global_users && silc_list_count(channel->user_list) == 0) {
2022     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2023     created = TRUE;             /* Created globally by our router */
2024   }
2025
2026   /* Join to the channel */
2027   silc_server_command_join_channel(server, cmd, channel, client_id,
2028                                    created, umode);
2029
2030   silc_free(client_id);
2031
2032  out:
2033   silc_server_command_free(cmd);
2034 }
2035
2036 /* Server side of command MOTD. Sends server's current "message of the
2037    day" to the client. */
2038
2039 SILC_SERVER_CMD_FUNC(motd)
2040 {
2041   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2042   SilcServer server = cmd->server;
2043   char *motd;
2044   int motd_len;
2045   
2046   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 2);
2047
2048   /* XXX show currently only our motd */
2049
2050   if (server->config && server->config->motd && 
2051       server->config->motd->motd_file) {
2052
2053     /* Send motd */
2054     motd = silc_file_read(server->config->motd->motd_file, &motd_len);
2055     if (!motd)
2056       goto out;
2057
2058     motd[motd_len] = 0;
2059     silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
2060                                          SILC_STATUS_OK,
2061                                          2, motd, motd_len);
2062     goto out;
2063   } else {
2064     /* No motd */
2065     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
2066                                           SILC_STATUS_OK);
2067   }
2068
2069  out:
2070   silc_server_command_free(cmd);
2071 }
2072
2073 SILC_SERVER_CMD_FUNC(umode)
2074 {
2075 }
2076
2077 /* Checks that client has rights to add or remove channel modes. If any
2078    of the checks fails FALSE is returned. */
2079
2080 int silc_server_check_cmode_rights(SilcChannelEntry channel,
2081                                    SilcChannelClientEntry client,
2082                                    unsigned int mode)
2083 {
2084   int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
2085   int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
2086
2087   /* Check whether has rights to change anything */
2088   if (!is_op && !is_fo)
2089     return FALSE;
2090
2091   /* Check whether has rights to change everything */
2092   if (is_op && is_fo)
2093     return TRUE;
2094
2095   /* We know that client is channel operator, check that they are not
2096      changing anything that requires channel founder rights. Rest of the
2097      modes are available automatically for channel operator. */
2098
2099   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
2100     if (is_op && !is_fo)
2101       return FALSE;
2102   } else {
2103     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2104       if (is_op && !is_fo)
2105         return FALSE;
2106     }
2107   }
2108   
2109   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2110     if (is_op && !is_fo)
2111       return FALSE;
2112   } else {
2113     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2114       if (is_op && !is_fo)
2115         return FALSE;
2116     }
2117   }
2118
2119   if (mode & SILC_CHANNEL_MODE_CIPHER) {
2120     if (is_op && !is_fo)
2121       return FALSE;
2122   } else {
2123     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2124       if (is_op && !is_fo)
2125         return FALSE;
2126     }
2127   }
2128   
2129   return TRUE;
2130 }
2131
2132 /* Server side command of CMODE. Changes channel mode */
2133
2134 SILC_SERVER_CMD_FUNC(cmode)
2135 {
2136   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2137   SilcServer server = cmd->server;
2138   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2139   SilcChannelID *channel_id;
2140   SilcChannelEntry channel;
2141   SilcChannelClientEntry chl;
2142   SilcBuffer packet, cidp;
2143   unsigned char *tmp, *tmp_id, *tmp_mask;
2144   unsigned int argc, mode_mask, tmp_len, tmp_len2;
2145
2146   SILC_LOG_DEBUG(("Start"));
2147
2148   argc = silc_argument_get_arg_num(cmd->args);
2149   if (argc < 2) {
2150     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2151                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2152     goto out;
2153   }
2154   if (argc > 8) {
2155     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2156                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2157     goto out;
2158   }
2159
2160   /* Get Channel ID */
2161   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
2162   if (!tmp_id) {
2163     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2164                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2165     goto out;
2166   }
2167   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
2168
2169   /* Get the channel mode mask */
2170   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2171   if (!tmp_mask) {
2172     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2173                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2174     goto out;
2175   }
2176   SILC_GET32_MSB(mode_mask, tmp_mask);
2177
2178   /* Get channel entry */
2179   channel = silc_idlist_find_channel_by_id(server->local_list, 
2180                                            channel_id, NULL);
2181   if (!channel) {
2182     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2183                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2184     goto out;
2185   }
2186
2187   /* Check whether this client is on the channel */
2188   if (!silc_server_client_on_channel(client, channel)) {
2189     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2190                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2191     goto out;
2192   }
2193
2194   /* Get entry to the channel user list */
2195   silc_list_start(channel->user_list);
2196   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2197     if (chl->client == client)
2198       break;
2199
2200   /* Check that client has rights to change any requested channel modes */
2201   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
2202     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2203                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2204     goto out;
2205   }
2206
2207   /*
2208    * Check the modes. Modes that requires nothing special operation are
2209    * not checked here.
2210    */
2211
2212   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
2213     /* Channel uses private keys to protect traffic. Client(s) has set the
2214        key locally they want to use, server does not know that key. */
2215     /* Nothing interesting to do here now */
2216   } else {
2217     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2218       /* The mode is removed and we need to generate and distribute
2219          new channel key. Clients are not using private channel keys
2220          anymore after this. */
2221
2222       /* XXX Duplicated code, make own function for this!! LEAVE uses this
2223          as well */
2224
2225       /* Re-generate channel key */
2226       silc_server_create_channel_key(server, channel, 0);
2227       
2228       /* Encode channel key payload to be distributed on the channel */
2229       packet = 
2230         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2231                                         strlen(channel->channel_key->
2232                                                cipher->name),
2233                                         channel->channel_key->cipher->name,
2234                                         channel->key_len / 8, channel->key);
2235       
2236       /* If we are normal server then we will send it to our router.  If we
2237          are router we will send it to all local servers that has clients on
2238          the channel */
2239       if (server->server_type == SILC_SERVER) {
2240         if (!server->standalone)
2241           silc_server_packet_send(server, 
2242                                   cmd->server->router->connection,
2243                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2244                                   packet->len, TRUE);
2245       } else {
2246         
2247       }
2248       
2249       /* Send to locally connected clients on the channel */
2250       silc_server_packet_send_local_channel(server, channel, 
2251                                             SILC_PACKET_CHANNEL_KEY, 0,
2252                                             packet->data, packet->len, FALSE);
2253       silc_buffer_free(packet);
2254     }
2255   }
2256   
2257   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
2258     /* User limit is set on channel */
2259     unsigned int user_limit;
2260       
2261     /* Get user limit */
2262     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
2263     if (!tmp) {
2264       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
2265         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2266                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2267         goto out;
2268       }
2269     } else {
2270       SILC_GET32_MSB(user_limit, tmp);
2271       channel->mode_data.user_limit = user_limit;
2272     }
2273   } else {
2274     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
2275       /* User limit mode is unset. Remove user limit */
2276       channel->mode_data.user_limit = 0;
2277   }
2278
2279   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
2280     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
2281       /* Passphrase has been set to channel */
2282       
2283       /* Get the passphrase */
2284       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
2285       if (!tmp) {
2286         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2287                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2288         goto out;
2289       }
2290
2291       /* Save the passphrase */
2292       channel->mode_data.passphrase = strdup(tmp);
2293     }
2294   } else {
2295     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2296       /* Passphrase mode is unset. remove the passphrase */
2297       if (channel->mode_data.passphrase) {
2298         silc_free(channel->mode_data.passphrase);
2299         channel->mode_data.passphrase = NULL;
2300       }
2301     }
2302   }
2303
2304   if (mode_mask & SILC_CHANNEL_MODE_BAN) {
2305     if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
2306       /* Ban list is specified for channel */
2307
2308       /* Get ban list */
2309       tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
2310       if (!tmp) {
2311         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2312                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2313         goto out;
2314       }
2315
2316       /* XXX check that channel founder is not banned */
2317
2318       /* Save the ban list */
2319       channel->mode_data.ban_list = strdup(tmp);
2320     }
2321   } else {
2322     if (channel->mode & SILC_CHANNEL_MODE_BAN) {
2323       /* Ban mode is unset. Remove the entire ban list */
2324       if (channel->mode_data.ban_list) {
2325         silc_free(channel->mode_data.ban_list);
2326         channel->mode_data.ban_list = NULL;
2327       }
2328     }
2329   }
2330
2331   if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
2332     if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
2333       /* Invite list is specified for channel */
2334
2335       /* Get invite list */
2336       tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
2337       if (!tmp) {
2338         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2339                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2340         goto out;
2341       }
2342
2343       /* Save the invite linst */
2344       channel->mode_data.invite_list = strdup(tmp);
2345     }
2346   } else {
2347     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
2348       /* Invite list mode is unset. Remove the entire invite list */
2349       if (channel->mode_data.invite_list) {
2350         silc_free(channel->mode_data.invite_list);
2351         channel->mode_data.invite_list = NULL;
2352       }
2353     }
2354   }
2355
2356   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
2357     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
2358       /* Cipher to use protect the traffic */
2359       unsigned int key_len = 128;
2360       char *cp;
2361
2362       /* Get cipher */
2363       tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
2364       if (!tmp) {
2365         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2366                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2367         goto out;
2368       }
2369
2370       cp = strchr(tmp, ':');
2371       if (cp) {
2372         key_len = atoi(cp);
2373         *cp = '\0';
2374       }
2375
2376       /* XXX Duplicated code, make own function for this!! */
2377     
2378       /* Delete old cipher and allocate the new one */
2379       silc_cipher_free(channel->channel_key);
2380       silc_cipher_alloc(tmp, &channel->channel_key);
2381
2382       key_len /= 8;
2383       if (key_len > 32)
2384         key_len = 32;
2385
2386       /* Re-generate channel key */
2387       silc_server_create_channel_key(server, channel, key_len);
2388     
2389       /* Encode channel key payload to be distributed on the channel */
2390       packet = 
2391         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2392                                         strlen(channel->channel_key->
2393                                                cipher->name),
2394                                         channel->channel_key->cipher->name,
2395                                         channel->key_len / 8, channel->key);
2396     
2397       /* If we are normal server then we will send it to our router.  If we
2398          are router we will send it to all local servers that has clients on
2399          the channel */
2400       if (server->server_type == SILC_SERVER) {
2401         if (!server->standalone)
2402           silc_server_packet_send(server, 
2403                                   cmd->server->router->connection,
2404                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2405                                   packet->len, TRUE);
2406       } else {
2407         
2408       }
2409     
2410       /* Send to locally connected clients on the channel */
2411       silc_server_packet_send_local_channel(server, channel, 
2412                                             SILC_PACKET_CHANNEL_KEY, 0,
2413                                           packet->data, packet->len, FALSE);
2414       silc_buffer_free(packet);
2415     }
2416   } else {
2417     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2418       /* Cipher mode is unset. Remove the cipher and revert back to 
2419          default cipher */
2420
2421       if (channel->mode_data.cipher) {
2422         silc_free(channel->mode_data.cipher);
2423         channel->mode_data.cipher = NULL;
2424         channel->mode_data.key_len = 0;
2425       }
2426
2427       /* Generate new cipher and key for the channel */
2428
2429       /* XXX Duplicated code, make own function for this!! */
2430
2431       /* Delete old cipher and allocate default one */
2432       silc_cipher_free(channel->channel_key);
2433       if (!channel->cipher)
2434         silc_cipher_alloc("twofish", &channel->channel_key);
2435       else
2436         silc_cipher_alloc(channel->cipher, &channel->channel_key);
2437
2438       /* Re-generate channel key */
2439       silc_server_create_channel_key(server, channel, 0);
2440       
2441       /* Encode channel key payload to be distributed on the channel */
2442       packet = 
2443         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2444                                         strlen(channel->channel_key->
2445                                                cipher->name),
2446                                         channel->channel_key->cipher->name,
2447                                         channel->key_len / 8, channel->key);
2448       
2449       /* If we are normal server then we will send it to our router.  If we
2450          are router we will send it to all local servers that has clients on
2451          the channel */
2452       if (server->server_type == SILC_SERVER) {
2453         if (!server->standalone)
2454           silc_server_packet_send(server, 
2455                                   cmd->server->router->connection,
2456                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2457                                   packet->len, TRUE);
2458       } else {
2459         
2460       }
2461       
2462       /* Send to locally connected clients on the channel */
2463       silc_server_packet_send_local_channel(server, channel, 
2464                                             SILC_PACKET_CHANNEL_KEY, 0,
2465                                             packet->data, packet->len, FALSE);
2466       silc_buffer_free(packet);
2467     }
2468   }
2469
2470   /* Finally, set the mode */
2471   channel->mode = mode_mask;
2472
2473   /* Send CMODE_CHANGE notify */
2474   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2475   silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
2476                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
2477                                      cidp->data, cidp->len, 
2478                                      tmp_mask, tmp_len);
2479   silc_free(cidp);
2480
2481   /* Send command reply to sender */
2482   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
2483                                                 SILC_STATUS_OK, 0, 1,
2484                                                 2, tmp_mask, 4);
2485   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2486                           packet->data, packet->len, FALSE);
2487     
2488   silc_buffer_free(packet);
2489   silc_free(channel_id);
2490
2491  out:
2492   silc_server_command_free(cmd);
2493 }
2494
2495 /* Server side of CUMODE command. Changes client's mode on a channel. */
2496
2497 SILC_SERVER_CMD_FUNC(cumode)
2498 {
2499   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2500   SilcServer server = cmd->server;
2501   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2502   SilcChannelID *channel_id;
2503   SilcClientID *client_id;
2504   SilcChannelEntry channel;
2505   SilcClientEntry target_client;
2506   SilcChannelClientEntry chl;
2507   SilcBuffer packet, idp;
2508   unsigned char *tmp_id, *tmp_mask;
2509   unsigned int target_mask, sender_mask, tmp_len;
2510   int notify = FALSE;
2511
2512   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
2513
2514   /* Get Channel ID */
2515   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2516   if (!tmp_id) {
2517     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2518                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2519     goto out;
2520   }
2521   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2522
2523   /* Get channel entry */
2524   channel = silc_idlist_find_channel_by_id(server->local_list, 
2525                                            channel_id, NULL);
2526   if (!channel) {
2527     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2528                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2529     goto out;
2530   }
2531
2532   /* Check whether sender is on the channel */
2533   if (!silc_server_client_on_channel(client, channel)) {
2534     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2535                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2536     goto out;
2537   }
2538
2539   /* Check that client has rights to change other's rights */
2540   silc_list_start(channel->user_list);
2541   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2542     if (chl->client == client) {
2543       if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
2544           !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2545         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2546                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2547         goto out;
2548       }
2549
2550       sender_mask = chl->mode;
2551       break;
2552     }
2553   }
2554   
2555   /* Get the target client's channel mode mask */
2556   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
2557   if (!tmp_mask) {
2558     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2559                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2560     goto out;
2561   }
2562   SILC_GET32_MSB(target_mask, tmp_mask);
2563
2564   /* Get target Client ID */
2565   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2566   if (!tmp_id) {
2567     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2568                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2569     goto out;
2570   }
2571   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2572
2573   /* Get target client's entry */
2574   target_client = silc_idlist_find_client_by_id(server->local_list, 
2575                                                 client_id, NULL);
2576   if (!target_client) {
2577     /* XXX If target client is not one of mine send to primary route */
2578   }
2579
2580   /* Check whether target client is on the channel */
2581   if (!silc_server_client_on_channel(target_client, channel)) {
2582     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2583                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
2584     goto out;
2585   }
2586
2587   /* Get entry to the channel user list */
2588   silc_list_start(channel->user_list);
2589   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2590     if (chl->client == target_client)
2591       break;
2592
2593   /* 
2594    * Change the mode 
2595    */
2596
2597   /* If the target client is founder, no one else can change their mode
2598      but themselves. */
2599   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
2600     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2601                                           SILC_STATUS_ERR_NOT_YOU);
2602     goto out;
2603   }
2604
2605   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
2606     /* Cannot promote anyone to channel founder */
2607     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2608                                           SILC_STATUS_ERR_NOT_YOU);
2609     goto out;
2610   } else {
2611     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
2612       if (target_client == client) {
2613         /* Remove channel founder rights from itself */
2614         chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
2615         notify = TRUE;
2616       } else {
2617         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2618                                               SILC_STATUS_ERR_NOT_YOU);
2619         goto out;
2620       }
2621     }
2622   }
2623
2624   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
2625     /* Promote to operator */
2626     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2627       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
2628       notify = TRUE;
2629     }
2630   } else {
2631     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
2632       /* Demote to normal user */
2633       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
2634       notify = TRUE;
2635     }
2636   }
2637
2638   /* Send notify to channel, notify only if mode was actually changed. */
2639   if (notify) {
2640     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2641     silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
2642                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
2643                                        idp->data, idp->len,
2644                                        tmp_mask, 4, tmp_id, tmp_len);
2645     silc_buffer_free(idp);
2646   }
2647
2648   /* Send command reply to sender */
2649   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
2650                                                 SILC_STATUS_OK, 0, 2,
2651                                                 2, tmp_mask, 4,
2652                                                 3, tmp_id, tmp_len);
2653   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2654                           packet->data, packet->len, FALSE);
2655     
2656   silc_buffer_free(packet);
2657   silc_free(channel_id);
2658   silc_free(client_id);
2659
2660  out:
2661   silc_server_command_free(cmd);
2662 }
2663
2664 /* Server side of KICK command. Kicks client out of channel. */
2665
2666 SILC_SERVER_CMD_FUNC(kick)
2667 {
2668 }
2669
2670 SILC_SERVER_CMD_FUNC(restart)
2671 {
2672 }
2673  
2674 SILC_SERVER_CMD_FUNC(close)
2675 {
2676 }
2677  
2678 SILC_SERVER_CMD_FUNC(die)
2679 {
2680 }
2681  
2682 SILC_SERVER_CMD_FUNC(silcoper)
2683 {
2684 }
2685
2686 /* Server side command of LEAVE. Removes client from a channel. */
2687
2688 SILC_SERVER_CMD_FUNC(leave)
2689 {
2690   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2691   SilcServer server = cmd->server;
2692   SilcSocketConnection sock = cmd->sock;
2693   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
2694   SilcChannelID *id;
2695   SilcChannelEntry channel;
2696   SilcBuffer packet;
2697   unsigned int i, len;
2698   unsigned char *tmp;
2699
2700   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
2701
2702   /* Get Channel ID */
2703   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2704   if (!tmp) {
2705     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2706                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2707     goto out;
2708   }
2709   id = silc_id_payload_parse_id(tmp, len);
2710
2711   /* Get channel entry */
2712   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
2713   if (!channel) {
2714     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2715                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2716     goto out;
2717   }
2718
2719   /* Check whether this client is on the channel */
2720   if (!silc_server_client_on_channel(id_entry, channel)) {
2721     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2722                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2723     goto out;
2724   }
2725
2726   /* Notify routers that they should remove this client from their list
2727      of clients on the channel. */
2728   if (!server->standalone)
2729     silc_server_send_remove_channel_user(server, 
2730                                          server->router->connection,
2731                                          server->server_type == SILC_ROUTER ?
2732                                          TRUE : FALSE, id_entry->id, id);
2733
2734   /* Remove client from channel */
2735   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
2736                                           TRUE);
2737   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2738                                         SILC_STATUS_OK);
2739
2740   /* If the channel does not exist anymore we won't send anything */
2741   if (!i)
2742     goto out;
2743
2744   /* Re-generate channel key */
2745   silc_server_create_channel_key(server, channel, 0);
2746
2747   /* Encode channel key payload to be distributed on the channel */
2748   packet = 
2749     silc_channel_key_payload_encode(len, tmp,
2750                                     strlen(channel->channel_key->cipher->name),
2751                                     channel->channel_key->cipher->name,
2752                                     channel->key_len / 8, channel->key);
2753
2754   /* If we are normal server then we will send it to our router.  If we
2755      are router we will send it to all local servers that has clients on
2756      the channel */
2757   if (server->server_type == SILC_SERVER) {
2758     if (!server->standalone)
2759       silc_server_packet_send(server, 
2760                               cmd->server->router->connection,
2761                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2762                               packet->len, TRUE);
2763   } else {
2764
2765   }
2766
2767   /* Send to locally connected clients on the channel */
2768   silc_server_packet_send_local_channel(server, channel, 
2769                                         SILC_PACKET_CHANNEL_KEY, 0,
2770                                         packet->data, packet->len, FALSE);
2771
2772   silc_buffer_free(packet);
2773   silc_free(id);
2774
2775  out:
2776   silc_server_command_free(cmd);
2777 }
2778
2779 /* Server side of command USERS. Resolves clients and their USERS currently
2780    joined on the requested channel. The list of Client ID's and their modes
2781    on the channel is sent back. */
2782
2783 SILC_SERVER_CMD_FUNC(users)
2784 {
2785   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2786   SilcServer server = cmd->server;
2787   SilcChannelEntry channel;
2788   SilcChannelClientEntry chl;
2789   SilcChannelID *id;
2790   SilcBuffer packet;
2791   unsigned char *channel_id;
2792   unsigned int channel_id_len;
2793   SilcBuffer client_id_list;
2794   SilcBuffer client_mode_list;
2795   SilcBuffer idp;
2796   unsigned char lc[4];
2797   unsigned int list_count = 0;
2798   unsigned short ident = silc_command_get_ident(cmd->payload);
2799
2800   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
2801
2802   /* Get Channel ID */
2803   channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
2804   if (!channel_id) {
2805     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
2806                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2807     goto out;
2808   }
2809   id = silc_id_payload_parse_id(channel_id, channel_id_len);
2810
2811   /* If we are server and we don't know about this channel we will send
2812      the command to our router. If we know about the channel then we also
2813      have the list of users already. */
2814   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
2815   if (!channel) {
2816     if (server->server_type == SILC_SERVER && !server->standalone &&
2817         !cmd->pending) {
2818       SilcBuffer tmpbuf;
2819       
2820       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2821       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2822       
2823       /* Send USERS command */
2824       silc_server_packet_send(server, server->router->connection,
2825                               SILC_PACKET_COMMAND, cmd->packet->flags,
2826                               tmpbuf->data, tmpbuf->len, TRUE);
2827       
2828       /* Reprocess this packet after received reply */
2829       silc_server_command_pending(server, SILC_COMMAND_USERS, 
2830                                   silc_command_get_ident(cmd->payload),
2831                                   silc_server_command_users, (void *)cmd);
2832       cmd->pending = TRUE;
2833       silc_command_set_ident(cmd->payload, ident);
2834       
2835       silc_buffer_free(tmpbuf);
2836       silc_free(id);
2837       return;
2838     }
2839
2840     /* We are router and we will check the global list as well. */
2841     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
2842     if (!channel) {
2843       /* Channel really does not exist */
2844       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
2845                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2846       goto out;
2847     }
2848   }
2849
2850   /* Assemble the lists now */
2851
2852   client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) * 
2853                                      silc_list_count(channel->user_list));
2854   silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
2855   client_mode_list = 
2856     silc_buffer_alloc(4 * silc_list_count(channel->user_list));
2857   silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
2858
2859   silc_list_start(channel->user_list);
2860   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2861     /* Client ID */
2862     idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
2863     silc_buffer_put(client_id_list, idp->data, idp->len);
2864     silc_buffer_pull(client_id_list, idp->len);
2865     silc_buffer_free(idp);
2866
2867     /* Client's mode on channel */
2868     SILC_PUT32_MSB(chl->mode, client_mode_list->data);
2869     silc_buffer_pull(client_mode_list, 4);
2870
2871     list_count++;
2872   }
2873   silc_buffer_push(client_id_list, 
2874                    client_id_list->data - client_id_list->head);
2875   silc_buffer_push(client_mode_list, 
2876                    client_mode_list->data - client_mode_list->head);
2877
2878   /* List count */
2879   SILC_PUT32_MSB(list_count, lc);
2880
2881   /* Send reply */
2882   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
2883                                                 SILC_STATUS_OK, 0, 4,
2884                                                 2, channel_id, channel_id_len,
2885                                                 3, lc, 4,
2886                                                 4, client_id_list->data,
2887                                                 client_id_list->len,
2888                                                 5, client_mode_list->data,
2889                                                 client_mode_list->len);
2890   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2891                           packet->data, packet->len, FALSE);
2892     
2893   silc_buffer_free(packet);
2894   silc_buffer_free(client_id_list);
2895   silc_buffer_free(client_mode_list);
2896   silc_free(id);
2897
2898  out:
2899   silc_server_command_free(cmd);
2900 }