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