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