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