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