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. */
1289   if (!server->standalone)
1290     silc_server_send_replace_id(server, server->router->connection, 
1291                                 server->server_type == SILC_SERVER ? 
1292                                 FALSE : TRUE, client->id,
1293                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
1294                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
1295
1296   /* Remove old cache entry */
1297   silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
1298                          client->id); 
1299
1300   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1301
1302   /* Free old ID */
1303   if (client->id) {
1304     memset(client->id, 0, SILC_ID_CLIENT_LEN);
1305     silc_free(client->id);
1306   }
1307
1308   /* Save the nickname as this client is our local client */
1309   if (client->nickname)
1310     silc_free(client->nickname);
1311
1312   client->nickname = strdup(nick);
1313   client->id = new_id;
1314
1315   /* Update client cache */
1316   silc_idcache_add(server->local_list->clients, client->nickname, 
1317                    SILC_ID_CLIENT, client->id, (void *)client, TRUE);
1318
1319   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1320
1321   /* Send NICK_CHANGE notify */
1322   silc_server_send_notify_on_channels(server, client, 
1323                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
1324                                       oidp->data, oidp->len, 
1325                                       nidp->data, nidp->len);
1326
1327   /* Send the new Client ID as reply command back to client */
1328   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
1329                                                 SILC_STATUS_OK, 0, 1, 
1330                                                 2, nidp->data, nidp->len);
1331   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1332                           0, packet->data, packet->len, FALSE);
1333
1334   silc_buffer_free(packet);
1335   silc_buffer_free(nidp);
1336   silc_buffer_free(oidp);
1337   
1338  out:
1339   silc_server_command_free(cmd);
1340 }
1341
1342 SILC_SERVER_CMD_FUNC(list)
1343 {
1344 }
1345
1346 /* Server side of TOPIC command. Sets topic for channel and/or returns
1347    current topic to client. */
1348
1349 SILC_SERVER_CMD_FUNC(topic)
1350 {
1351   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1352   SilcServer server = cmd->server;
1353   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1354   SilcChannelID *channel_id;
1355   SilcChannelEntry channel;
1356   SilcChannelClientEntry chl;
1357   SilcBuffer packet, idp;
1358   unsigned char *tmp;
1359   unsigned int argc, tmp_len;
1360
1361   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
1362
1363   argc = silc_argument_get_arg_num(cmd->args);
1364
1365   /* Get Channel ID */
1366   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1367   if (!tmp) {
1368     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1369                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1370     goto out;
1371   }
1372   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1373   if (!channel_id) {
1374     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1375                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1376     goto out;
1377   }
1378
1379   /* Check whether the channel exists */
1380   channel = silc_idlist_find_channel_by_id(server->local_list, 
1381                                            channel_id, NULL);
1382   if (!channel) {
1383     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1384                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1385     goto out;
1386   }
1387
1388   if (argc > 1) {
1389     /* Get the topic */
1390     tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1391     if (!tmp) {
1392       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1393                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1394       goto out;
1395     }
1396
1397     if (strlen(tmp) > 256) {
1398       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1399                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1400       goto out;
1401     }
1402
1403     /* See whether has rights to change topic */
1404     silc_list_start(channel->user_list);
1405     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
1406       if (chl->client == client)
1407         break;
1408
1409     if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1410       if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
1411         silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1412                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1413         goto out;
1414       }
1415     }
1416
1417     /* Set the topic for channel */
1418     if (channel->topic)
1419       silc_free(channel->topic);
1420     channel->topic = strdup(tmp);
1421
1422     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1423
1424     /* Send notify about topic change to all clients on the channel */
1425     silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
1426                                        SILC_NOTIFY_TYPE_TOPIC_SET, 2,
1427                                        idp->data, idp->len,
1428                                        channel->topic, strlen(channel->topic));
1429     silc_buffer_free(idp);
1430   }
1431
1432   /* Send the topic to client as reply packet */
1433   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1434   if (channel->topic)
1435     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1436                                                   SILC_STATUS_OK, 0, 2, 
1437                                                   2, idp->data, idp->len,
1438                                                   3, channel->topic, 
1439                                                   strlen(channel->topic));
1440   else
1441     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
1442                                                   SILC_STATUS_OK, 0, 1, 
1443                                                   2, idp->data, idp->len);
1444   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1445                           0, packet->data, packet->len, FALSE);
1446
1447   silc_buffer_free(packet);
1448   silc_buffer_free(idp);
1449   silc_free(channel_id);
1450
1451  out:
1452   silc_server_command_free(cmd);
1453 }
1454
1455 /* Server side of INVITE command. Invites some client to join some channel. */
1456
1457 SILC_SERVER_CMD_FUNC(invite)
1458 {
1459   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1460   SilcServer server = cmd->server;
1461   SilcSocketConnection sock = cmd->sock, dest_sock;
1462   SilcClientEntry sender, dest;
1463   SilcClientID *dest_id;
1464   SilcChannelEntry channel;
1465   SilcChannelID *channel_id;
1466   SilcBuffer sidp;
1467   unsigned char *tmp;
1468   unsigned int len;
1469
1470   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 2);
1471
1472   /* Get destination ID */
1473   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1474   if (!tmp) {
1475     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1476                                           SILC_STATUS_ERR_NO_CLIENT_ID);
1477     goto out;
1478   }
1479   dest_id = silc_id_payload_parse_id(tmp, len);
1480   if (!dest_id) {
1481     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1482                                           SILC_STATUS_ERR_NO_CLIENT_ID);
1483     goto out;
1484   }
1485
1486   /* Get Channel ID */
1487   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1488   if (!tmp) {
1489     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1490                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1491     goto out;
1492   }
1493   channel_id = silc_id_payload_parse_id(tmp, len);
1494   if (!channel_id) {
1495     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1496                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
1497     goto out;
1498   }
1499
1500   /* Check whether the channel exists */
1501   channel = silc_idlist_find_channel_by_id(server->local_list, 
1502                                            channel_id, NULL);
1503   if (!channel) {
1504     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1505                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1506     goto out;
1507   }
1508
1509   /* Check whether the sender of this command is on the channel. */
1510   sender = (SilcClientEntry)sock->user_data;
1511   if (!silc_server_client_on_channel(sender, channel)) {
1512     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1513                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
1514     goto out;
1515   }
1516
1517   /* Check whether the channel is invite-only channel. If yes then the
1518      sender of this command must be at least channel operator. */
1519   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1520     SilcChannelClientEntry chl;
1521
1522     silc_list_start(channel->user_list);
1523     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
1524       if (chl->client == sender) {
1525         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1526           silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1527                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1528           goto out;
1529         }
1530         break;
1531       }
1532   }
1533
1534   /* Find the connection data for the destination. If it is local we will
1535      send it directly otherwise we will send it to router for routing. */
1536   dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
1537   if (dest)
1538     dest_sock = (SilcSocketConnection)dest->connection;
1539   else
1540     dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
1541
1542   /* Check whether the requested client is already on the channel. */
1543   /* XXX if we are normal server we don't know about global clients on
1544      the channel thus we must request it (USERS command), check from
1545      local cache as well. */
1546   if (silc_server_client_on_channel(dest, channel)) {
1547     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1548                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1549     goto out;
1550   }
1551
1552   sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
1553
1554   /* Send notify to the client that is invited to the channel */
1555   silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
1556                                SILC_NOTIFY_TYPE_INVITE, 2, 
1557                                sidp->data, sidp->len, tmp, len);
1558
1559   /* Send command reply */
1560   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1561                                         SILC_STATUS_OK);
1562
1563   silc_buffer_free(sidp);
1564
1565  out:
1566   silc_server_command_free(cmd);
1567 }
1568
1569 /* Quits connection to client. This gets called if client won't
1570    close the connection even when it has issued QUIT command. */
1571
1572 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
1573 {
1574   SilcServer server = (SilcServer)context;
1575   SilcSocketConnection sock = server->sockets[fd];
1576
1577   /* Free all client specific data, such as client entry and entires
1578      on channels this client may be on. */
1579   silc_server_free_sock_user_data(server, sock);
1580
1581   /* Close the connection on our side */
1582   silc_server_close_connection(server, sock);
1583 }
1584
1585 /* Quits SILC session. This is the normal way to disconnect client. */
1586  
1587 SILC_SERVER_CMD_FUNC(quit)
1588 {
1589   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1590   SilcServer server = cmd->server;
1591   SilcSocketConnection sock = cmd->sock;
1592
1593   SILC_LOG_DEBUG(("Start"));
1594
1595   /* We quit the connection with little timeout */
1596   silc_task_register(server->timeout_queue, sock->sock,
1597                      silc_server_command_quit_cb, server,
1598                      0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1599
1600   silc_server_command_free(cmd);
1601 }
1602
1603 SILC_SERVER_CMD_FUNC(kill)
1604 {
1605 }
1606
1607 /* Server side of command INFO. This sends information about us to 
1608    the client. If client requested specific server we will send the 
1609    command to that server. */
1610
1611 SILC_SERVER_CMD_FUNC(info)
1612 {
1613   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1614   SilcServer server = cmd->server;
1615   SilcBuffer packet, idp;
1616   char info_string[256], *dest_server;
1617
1618   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
1619
1620   /* Get server name */
1621   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
1622   if (!dest_server) {
1623     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1624                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1625     goto out;
1626   }
1627
1628   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
1629     /* Send our reply */
1630     memset(info_string, 0, sizeof(info_string));
1631     snprintf(info_string, sizeof(info_string), 
1632              "location: %s server: %s admin: %s <%s>",
1633              server->config->admin_info->location,
1634              server->config->admin_info->server_type,
1635              server->config->admin_info->admin_name,
1636              server->config->admin_info->admin_email);
1637
1638     idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
1639
1640     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
1641                                                   SILC_STATUS_OK, 0, 2,
1642                                                   2, idp->data, idp->len,
1643                                                   3, info_string, 
1644                                                   strlen(info_string));
1645     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
1646                             packet->data, packet->len, FALSE);
1647     
1648     silc_buffer_free(packet);
1649     silc_buffer_free(idp);
1650   } else {
1651     /* Send this command to the requested server */
1652
1653     if (server->server_type == SILC_SERVER && !server->standalone) {
1654
1655     }
1656
1657     if (server->server_type == SILC_ROUTER) {
1658
1659     }
1660   }
1661   
1662  out:
1663   silc_server_command_free(cmd);
1664 }
1665
1666 SILC_SERVER_CMD_FUNC(connect)
1667 {
1668 }
1669
1670 /* Server side of command PING. This just replies to the ping. */
1671
1672 SILC_SERVER_CMD_FUNC(ping)
1673 {
1674   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1675   SilcServer server = cmd->server;
1676   SilcServerID *id;
1677   unsigned int len;
1678   unsigned char *tmp;
1679
1680   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
1681
1682   /* Get Server ID */
1683   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1684   if (!tmp) {
1685     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1686                                           SILC_STATUS_ERR_NO_SERVER_ID);
1687     goto out;
1688   }
1689   id = silc_id_str2id(tmp, len, SILC_ID_SERVER);
1690   if (!id)
1691     goto out;
1692
1693   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
1694     /* Send our reply */
1695     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1696                                           SILC_STATUS_OK);
1697   } else {
1698     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1699                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
1700     goto out;
1701   }
1702
1703   silc_free(id);
1704
1705  out:
1706   silc_server_command_free(cmd);
1707 }
1708
1709 SILC_SERVER_CMD_FUNC(oper)
1710 {
1711 }
1712
1713 /* Assembles USERS command and executes it. This is called when client
1714    joins to a channel and we wan't to send USERS command reply to the 
1715    client. */
1716
1717 void silc_server_command_send_users(SilcServer server,
1718                                     SilcSocketConnection sock,
1719                                     SilcChannelEntry channel,
1720                                     int pending)
1721 {
1722   SilcServerCommandContext cmd;
1723   SilcBuffer buffer, idp;
1724   SilcPacketContext *packet = silc_packet_context_alloc();
1725
1726   SILC_LOG_DEBUG(("Start"));
1727
1728   /* Create USERS command packet and process it. */
1729   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1730   buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 0, 1,
1731                                           1, idp->data, idp->len);
1732
1733   packet->buffer = silc_buffer_copy(buffer);
1734   packet->sock = sock;
1735   packet->type = SILC_PACKET_COMMAND;
1736
1737   cmd = silc_server_command_alloc();
1738   cmd->payload = silc_command_payload_parse(buffer);
1739   if (!cmd->payload) {
1740     silc_free(cmd);
1741     silc_buffer_free(buffer);
1742     silc_buffer_free(idp);
1743     silc_packet_context_free(packet);
1744     return;
1745   }
1746   cmd->args = silc_command_get_args(cmd->payload);
1747   cmd->server = server;
1748   cmd->sock = silc_socket_dup(sock);
1749   cmd->packet = silc_packet_context_dup(packet);
1750   cmd->pending = FALSE;
1751
1752   if (pending) {
1753     /* If this function was called from pending command then instead of
1754        processing the command now, register a pending command callback which
1755        will process it after we've received the automatic USERS command 
1756        reply which server will send in JOIN. */
1757     silc_server_command_pending(server, SILC_COMMAND_USERS, 0, NULL,
1758                                 silc_server_command_users, cmd);
1759     cmd->pending = TRUE;
1760     silc_buffer_free(buffer);
1761     silc_buffer_free(idp);
1762     return;
1763   }
1764
1765   /* Process USERS command. */
1766   silc_server_command_users((void *)cmd);
1767
1768   silc_buffer_free(buffer);
1769   silc_buffer_free(idp);
1770   silc_packet_context_free(packet);
1771 }
1772
1773 /* Internal routine to join channel. The channel sent to this function
1774    has been either created or resolved from ID lists. This joins the sent
1775    client to the channel. */
1776
1777 static void silc_server_command_join_channel(SilcServer server, 
1778                                              SilcServerCommandContext cmd,
1779                                              SilcChannelEntry channel,
1780                                              SilcClientID *client_id,
1781                                              int created,
1782                                              unsigned int umode)
1783 {
1784   SilcSocketConnection sock = cmd->sock;
1785   unsigned char *tmp;
1786   unsigned int tmp_len;
1787   unsigned char *passphrase = NULL, mode[4], tmp2[4];
1788   SilcClientEntry client;
1789   SilcChannelClientEntry chl;
1790   SilcBuffer reply, chidp, clidp, keyp;
1791   unsigned short ident = silc_command_get_ident(cmd->payload);
1792
1793   SILC_LOG_DEBUG(("Start"));
1794
1795   if (!channel)
1796     return;
1797
1798   /* Get passphrase */
1799   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1800   if (tmp) {
1801     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1802     memcpy(passphrase, tmp, tmp_len);
1803   }
1804   
1805   /*
1806    * Check channel modes
1807    */
1808
1809   /* Check invite list if channel is invite-only channel */
1810   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1811     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
1812       /* Invite list is specified. Check whether client is invited in the
1813          list. If not, then check whether it has been invited otherwise. */
1814
1815     } else {
1816       /* XXX client must be invited to be able to join the channel */
1817     }
1818   }
1819
1820   /* Check ban list if set */
1821   if (channel->mode & SILC_CHANNEL_MODE_BAN) {
1822
1823   }
1824
1825   /* Check the channel passphrase if set. */
1826   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
1827     if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
1828                               strlen(channel->mode_data.passphrase))) {
1829       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1830                                             SILC_STATUS_ERR_BAD_PASSWORD);
1831       goto out;
1832     }
1833   }
1834
1835   /* Check user count limit if set. */
1836   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
1837     if (silc_list_count(channel->user_list) + 1 > 
1838         channel->mode_data.user_limit) {
1839       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1840                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
1841       goto out;
1842     }
1843   }
1844
1845   /*
1846    * Client is allowed to join to the channel. Make it happen.
1847    */
1848
1849   /* Get the client entry */
1850   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
1851     client = (SilcClientEntry)sock->user_data;
1852   } else {
1853     client = silc_idlist_find_client_by_id(server->local_list, client_id, 
1854                                            NULL);
1855     if (!client) {
1856       /* XXX actually this is useless since router finds always cell's
1857          local clients from its local lists. */
1858       client = silc_idlist_find_client_by_id(server->global_list, client_id, 
1859                                              NULL);
1860       if (!client)
1861         goto out;
1862     }
1863   }
1864
1865   /* Check whether the client already is on the channel */
1866   if (silc_server_client_on_channel(client, channel)) {
1867     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1868                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
1869     goto out;
1870   }
1871
1872   /* Generate new channel key as protocol dictates */
1873   if (!created || !channel->channel_key)
1874     silc_server_create_channel_key(server, channel, 0);
1875
1876   /* Send the channel key. This is broadcasted to the channel but is not
1877      sent to the client who is joining to the channel. */
1878   silc_server_send_channel_key(server, NULL, channel, 
1879                                server->server_type == SILC_ROUTER ? 
1880                                FALSE : server->standalone);
1881
1882   /* Join the client to the channel by adding it to channel's user list.
1883      Add also the channel to client entry's channels list for fast cross-
1884      referencing. */
1885   chl = silc_calloc(1, sizeof(*chl));
1886   chl->mode = umode;
1887   chl->client = client;
1888   chl->channel = channel;
1889   silc_list_add(channel->user_list, chl);
1890   silc_list_add(client->channels, chl);
1891
1892   /* Encode Client ID Payload of the original client who wants to join */
1893   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1894
1895   /* Encode command reply packet */
1896   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1897   SILC_PUT32_MSB(channel->mode, mode);
1898   SILC_PUT32_MSB(created, tmp2);
1899   tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1900   keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp, 
1901                                          SILC_ID_CHANNEL_LEN,
1902                                          channel->channel_key->cipher->name,
1903                                          channel->key_len / 8, channel->key);
1904   silc_free(tmp);
1905   if (!channel->topic) {
1906     reply = 
1907       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1908                                            SILC_STATUS_OK, ident, 5,
1909                                            2, channel->channel_name,
1910                                            strlen(channel->channel_name),
1911                                            3, chidp->data, chidp->len,
1912                                            4, mode, 4,
1913                                            5, tmp2, 4,
1914                                            6, keyp->data, keyp->len);
1915   } else {
1916     reply = 
1917       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1918                                            SILC_STATUS_OK, ident, 6, 
1919                                            2, channel->channel_name, 
1920                                            strlen(channel->channel_name),
1921                                            3, chidp->data, chidp->len,
1922                                            4, mode, 4,
1923                                            5, tmp2, 4,
1924                                            6, keyp->data, keyp->len,
1925                                            8, channel->topic, 
1926                                            strlen(channel->topic));
1927   }
1928
1929   /* Send command reply */
1930   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
1931                           reply->data, reply->len, FALSE);
1932
1933   if (!cmd->pending) {
1934     /* Send JOIN notify to locally connected clients on the channel */
1935     silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
1936                                        SILC_NOTIFY_TYPE_JOIN, 1,
1937                                        clidp->data, clidp->len);
1938
1939     /* Send NEW_CHANNEL_USER packet to our primary router */
1940     if (!server->standalone)
1941       silc_server_send_new_channel_user(server, server->router->connection,
1942                                         server->server_type == SILC_SERVER ?
1943                                         FALSE : TRUE,
1944                                         channel->id, SILC_ID_CHANNEL_LEN,
1945                                         client->id, SILC_ID_CLIENT_LEN);
1946   }
1947
1948   /* Send USERS command reply to the joined channel so the user sees who
1949      is currently on the channel. */
1950   silc_server_command_send_users(server, sock, channel, cmd->pending);
1951
1952   silc_buffer_free(reply);
1953   silc_buffer_free(clidp);
1954   silc_buffer_free(chidp);
1955   silc_buffer_free(keyp);
1956
1957  out:
1958   if (passphrase)
1959     silc_free(passphrase);
1960 }
1961
1962 /* Server side of command JOIN. Joins client into requested channel. If 
1963    the channel does not exist it will be created. */
1964
1965 SILC_SERVER_CMD_FUNC(join)
1966 {
1967   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1968   SilcServer server = cmd->server;
1969   int tmp_len;
1970   char *tmp, *channel_name = NULL, *cipher = NULL;
1971   SilcChannelEntry channel;
1972   unsigned int umode = 0;
1973   int created = FALSE;
1974   SilcClientID *client_id;
1975
1976   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 4);
1977
1978   /* Get channel name */
1979   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1980   if (!tmp) {
1981     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1982                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1983     goto out;
1984   }
1985   channel_name = tmp;
1986
1987   if (silc_server_command_bad_chars(channel_name) == TRUE) {
1988     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1989                                           SILC_STATUS_ERR_BAD_CHANNEL);
1990     silc_free(channel_name);
1991     goto out;
1992   }
1993
1994   /* Get Client ID of the client who is joining to the channel */
1995   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1996   if (!tmp) {
1997     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1998                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1999     goto out;
2000   }
2001   client_id = silc_id_payload_parse_id(tmp, tmp_len);
2002   if (!client_id) {
2003     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2004                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2005     goto out;
2006   }
2007
2008   /* Get cipher name */
2009   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
2010
2011   /* See if the channel exists */
2012   channel = silc_idlist_find_channel_by_name(server->local_list, 
2013                                              channel_name, NULL);
2014
2015   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2016     /* If this is coming from client the Client ID in the command packet must
2017        be same as the client's ID. */
2018     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2019       SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
2020       if (SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
2021         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2022                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2023         goto out;
2024       }
2025     }
2026
2027     if (!channel) {
2028       /* Channel not found */
2029
2030       /* If we are standalone server we don't have a router, we just create 
2031          the channel by ourselves. */
2032       if (server->standalone) {
2033         channel = silc_server_create_new_channel(server, server->id, cipher, 
2034                                                  channel_name, TRUE);
2035         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2036         created = TRUE;
2037
2038       } else {
2039
2040         /* The channel does not exist on our server. If we are normal server 
2041            we will send JOIN command to our router which will handle the
2042            joining procedure (either creates the channel if it doesn't exist 
2043            or joins the client to it). */
2044         if (server->server_type == SILC_SERVER) {
2045           SilcBuffer tmpbuf;
2046           unsigned short old_ident;
2047           
2048           old_ident = silc_command_get_ident(cmd->payload);
2049           silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2050           tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2051           
2052           /* Send JOIN command to our router */
2053           silc_server_packet_send(server, (SilcSocketConnection)
2054                                   server->router->connection,
2055                                   SILC_PACKET_COMMAND, cmd->packet->flags,
2056                                   tmpbuf->data, tmpbuf->len, TRUE);
2057           
2058           /* Reprocess this packet after received reply from router */
2059           silc_server_command_pending(server, SILC_COMMAND_JOIN, 
2060                                       silc_command_get_ident(cmd->payload),
2061                                       silc_server_command_destructor,
2062                                       silc_server_command_join,
2063                                       silc_server_command_dup(cmd));
2064           cmd->pending = TRUE;
2065           return;
2066         }
2067         
2068         /* We are router and the channel does not seem exist so we will check
2069            our global list as well for the channel. */
2070         channel = silc_idlist_find_channel_by_name(server->global_list, 
2071                                                    channel_name, NULL);
2072         if (!channel) {
2073           /* Channel really does not exist, create it */
2074           channel = silc_server_create_new_channel(server, server->id, cipher, 
2075                                                    channel_name, TRUE);
2076           umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2077           created = TRUE;
2078         }
2079       }
2080     }
2081   } else {
2082     if (!channel) {
2083       /* Channel not found */
2084
2085       /* If the command came from router and/or we are normal server then
2086          something went wrong with the joining as the channel was not found.
2087          We can't do anything else but ignore this. */
2088       if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
2089           server->server_type == SILC_SERVER)
2090         goto out;
2091       
2092       /* We are router and the channel does not seem exist so we will check
2093          our global list as well for the channel. */
2094       channel = silc_idlist_find_channel_by_name(server->global_list, 
2095                                                  channel_name, NULL);
2096       if (!channel) {
2097         /* Channel really does not exist, create it */
2098         channel = silc_server_create_new_channel(server, server->id, cipher, 
2099                                                  channel_name, TRUE);
2100         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2101         created = TRUE;
2102       }
2103     }
2104   }
2105
2106   /* If the channel does not have global users and is also empty it means the
2107      channel was created globally (by our router) and the client will be the
2108      channel founder and operator. */
2109   if (!channel->global_users && silc_list_count(channel->user_list) == 0) {
2110     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2111     created = TRUE;             /* Created globally by our router */
2112   }
2113
2114   /* Join to the channel */
2115   silc_server_command_join_channel(server, cmd, channel, client_id,
2116                                    created, umode);
2117
2118   silc_free(client_id);
2119
2120  out:
2121   silc_server_command_free(cmd);
2122 }
2123
2124 /* Server side of command MOTD. Sends server's current "message of the
2125    day" to the client. */
2126
2127 SILC_SERVER_CMD_FUNC(motd)
2128 {
2129   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2130   SilcServer server = cmd->server;
2131   char *motd;
2132   int motd_len;
2133   
2134   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 2);
2135
2136   /* XXX show currently only our motd */
2137
2138   if (server->config && server->config->motd && 
2139       server->config->motd->motd_file) {
2140
2141     /* Send motd */
2142     motd = silc_file_read(server->config->motd->motd_file, &motd_len);
2143     if (!motd)
2144       goto out;
2145
2146     motd[motd_len] = 0;
2147     silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
2148                                          SILC_STATUS_OK,
2149                                          2, motd, motd_len);
2150     goto out;
2151   } else {
2152     /* No motd */
2153     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
2154                                           SILC_STATUS_OK);
2155   }
2156
2157  out:
2158   silc_server_command_free(cmd);
2159 }
2160
2161 SILC_SERVER_CMD_FUNC(umode)
2162 {
2163 }
2164
2165 /* Checks that client has rights to add or remove channel modes. If any
2166    of the checks fails FALSE is returned. */
2167
2168 int silc_server_check_cmode_rights(SilcChannelEntry channel,
2169                                    SilcChannelClientEntry client,
2170                                    unsigned int mode)
2171 {
2172   int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
2173   int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
2174
2175   /* Check whether has rights to change anything */
2176   if (!is_op && !is_fo)
2177     return FALSE;
2178
2179   /* Check whether has rights to change everything */
2180   if (is_op && is_fo)
2181     return TRUE;
2182
2183   /* We know that client is channel operator, check that they are not
2184      changing anything that requires channel founder rights. Rest of the
2185      modes are available automatically for channel operator. */
2186
2187   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
2188     if (is_op && !is_fo)
2189       return FALSE;
2190   } else {
2191     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2192       if (is_op && !is_fo)
2193         return FALSE;
2194     }
2195   }
2196   
2197   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2198     if (is_op && !is_fo)
2199       return FALSE;
2200   } else {
2201     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2202       if (is_op && !is_fo)
2203         return FALSE;
2204     }
2205   }
2206
2207   if (mode & SILC_CHANNEL_MODE_CIPHER) {
2208     if (is_op && !is_fo)
2209       return FALSE;
2210   } else {
2211     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2212       if (is_op && !is_fo)
2213         return FALSE;
2214     }
2215   }
2216   
2217   return TRUE;
2218 }
2219
2220 /* Server side command of CMODE. Changes channel mode */
2221
2222 SILC_SERVER_CMD_FUNC(cmode)
2223 {
2224   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2225   SilcServer server = cmd->server;
2226   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2227   SilcChannelID *channel_id;
2228   SilcChannelEntry channel;
2229   SilcChannelClientEntry chl;
2230   SilcBuffer packet, cidp;
2231   unsigned char *tmp, *tmp_id, *tmp_mask;
2232   unsigned int argc, mode_mask, tmp_len, tmp_len2;
2233
2234   SILC_LOG_DEBUG(("Start"));
2235
2236   argc = silc_argument_get_arg_num(cmd->args);
2237   if (argc < 2) {
2238     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2239                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2240     goto out;
2241   }
2242   if (argc > 8) {
2243     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2244                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
2245     goto out;
2246   }
2247
2248   /* Get Channel ID */
2249   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
2250   if (!tmp_id) {
2251     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2252                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2253     goto out;
2254   }
2255   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
2256   if (!channel_id) {
2257     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2258                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2259     goto out;
2260   }
2261
2262   /* Get the channel mode mask */
2263   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2264   if (!tmp_mask) {
2265     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2266                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2267     goto out;
2268   }
2269   SILC_GET32_MSB(mode_mask, tmp_mask);
2270
2271   /* Get channel entry */
2272   channel = silc_idlist_find_channel_by_id(server->local_list, 
2273                                            channel_id, NULL);
2274   if (!channel) {
2275     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2276                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2277     goto out;
2278   }
2279
2280   /* Check whether this client is on the channel */
2281   if (!silc_server_client_on_channel(client, channel)) {
2282     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2283                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2284     goto out;
2285   }
2286
2287   /* Get entry to the channel user list */
2288   silc_list_start(channel->user_list);
2289   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2290     if (chl->client == client)
2291       break;
2292
2293   /* Check that client has rights to change any requested channel modes */
2294   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
2295     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2296                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2297     goto out;
2298   }
2299
2300   /*
2301    * Check the modes. Modes that requires nothing special operation are
2302    * not checked here.
2303    */
2304
2305   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
2306     /* Channel uses private keys to protect traffic. Client(s) has set the
2307        key locally they want to use, server does not know that key. */
2308     /* Nothing interesting to do here now */
2309   } else {
2310     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2311       /* The mode is removed and we need to generate and distribute
2312          new channel key. Clients are not using private channel keys
2313          anymore after this. */
2314
2315       /* XXX Duplicated code, make own function for this!! LEAVE uses this
2316          as well */
2317
2318       /* Re-generate channel key */
2319       silc_server_create_channel_key(server, channel, 0);
2320       
2321       /* Encode channel key payload to be distributed on the channel */
2322       packet = 
2323         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2324                                         strlen(channel->channel_key->
2325                                                cipher->name),
2326                                         channel->channel_key->cipher->name,
2327                                         channel->key_len / 8, channel->key);
2328       
2329       /* If we are normal server then we will send it to our router.  If we
2330          are router we will send it to all local servers that has clients on
2331          the channel */
2332       if (server->server_type == SILC_SERVER) {
2333         if (!server->standalone)
2334           silc_server_packet_send(server, 
2335                                   cmd->server->router->connection,
2336                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2337                                   packet->len, TRUE);
2338       } else {
2339         
2340       }
2341       
2342       /* Send to locally connected clients on the channel */
2343       silc_server_packet_send_local_channel(server, channel, 
2344                                             SILC_PACKET_CHANNEL_KEY, 0,
2345                                             packet->data, packet->len, FALSE);
2346       silc_buffer_free(packet);
2347     }
2348   }
2349   
2350   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
2351     /* User limit is set on channel */
2352     unsigned int user_limit;
2353       
2354     /* Get user limit */
2355     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
2356     if (!tmp) {
2357       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
2358         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2359                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2360         goto out;
2361       }
2362     } else {
2363       SILC_GET32_MSB(user_limit, tmp);
2364       channel->mode_data.user_limit = user_limit;
2365     }
2366   } else {
2367     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
2368       /* User limit mode is unset. Remove user limit */
2369       channel->mode_data.user_limit = 0;
2370   }
2371
2372   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
2373     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
2374       /* Passphrase has been set to channel */
2375       
2376       /* Get the passphrase */
2377       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
2378       if (!tmp) {
2379         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2380                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2381         goto out;
2382       }
2383
2384       /* Save the passphrase */
2385       channel->mode_data.passphrase = strdup(tmp);
2386     }
2387   } else {
2388     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2389       /* Passphrase mode is unset. remove the passphrase */
2390       if (channel->mode_data.passphrase) {
2391         silc_free(channel->mode_data.passphrase);
2392         channel->mode_data.passphrase = NULL;
2393       }
2394     }
2395   }
2396
2397   if (mode_mask & SILC_CHANNEL_MODE_BAN) {
2398     if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
2399       /* Ban list is specified for channel */
2400
2401       /* Get ban list */
2402       tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
2403       if (!tmp) {
2404         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2405                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2406         goto out;
2407       }
2408
2409       /* XXX check that channel founder is not banned */
2410
2411       /* Save the ban list */
2412       channel->mode_data.ban_list = strdup(tmp);
2413     }
2414   } else {
2415     if (channel->mode & SILC_CHANNEL_MODE_BAN) {
2416       /* Ban mode is unset. Remove the entire ban list */
2417       if (channel->mode_data.ban_list) {
2418         silc_free(channel->mode_data.ban_list);
2419         channel->mode_data.ban_list = NULL;
2420       }
2421     }
2422   }
2423
2424   if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
2425     if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
2426       /* Invite list is specified for channel */
2427
2428       /* Get invite list */
2429       tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
2430       if (!tmp) {
2431         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2432                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2433         goto out;
2434       }
2435
2436       /* Save the invite linst */
2437       channel->mode_data.invite_list = strdup(tmp);
2438     }
2439   } else {
2440     if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
2441       /* Invite list mode is unset. Remove the entire invite list */
2442       if (channel->mode_data.invite_list) {
2443         silc_free(channel->mode_data.invite_list);
2444         channel->mode_data.invite_list = NULL;
2445       }
2446     }
2447   }
2448
2449   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
2450     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
2451       /* Cipher to use protect the traffic */
2452       unsigned int key_len = 128;
2453       char *cp;
2454
2455       /* Get cipher */
2456       tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
2457       if (!tmp) {
2458         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2459                                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2460         goto out;
2461       }
2462
2463       cp = strchr(tmp, ':');
2464       if (cp) {
2465         key_len = atoi(cp);
2466         *cp = '\0';
2467       }
2468
2469       /* XXX Duplicated code, make own function for this!! */
2470     
2471       /* Delete old cipher and allocate the new one */
2472       silc_cipher_free(channel->channel_key);
2473       silc_cipher_alloc(tmp, &channel->channel_key);
2474
2475       key_len /= 8;
2476       if (key_len > 32)
2477         key_len = 32;
2478
2479       /* Re-generate channel key */
2480       silc_server_create_channel_key(server, channel, key_len);
2481     
2482       /* Encode channel key payload to be distributed on the channel */
2483       packet = 
2484         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2485                                         strlen(channel->channel_key->
2486                                                cipher->name),
2487                                         channel->channel_key->cipher->name,
2488                                         channel->key_len / 8, channel->key);
2489     
2490       /* If we are normal server then we will send it to our router.  If we
2491          are router we will send it to all local servers that has clients on
2492          the channel */
2493       if (server->server_type == SILC_SERVER) {
2494         if (!server->standalone)
2495           silc_server_packet_send(server, 
2496                                   cmd->server->router->connection,
2497                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2498                                   packet->len, TRUE);
2499       } else {
2500         
2501       }
2502     
2503       /* Send to locally connected clients on the channel */
2504       silc_server_packet_send_local_channel(server, channel, 
2505                                             SILC_PACKET_CHANNEL_KEY, 0,
2506                                           packet->data, packet->len, FALSE);
2507       silc_buffer_free(packet);
2508     }
2509   } else {
2510     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2511       /* Cipher mode is unset. Remove the cipher and revert back to 
2512          default cipher */
2513
2514       if (channel->mode_data.cipher) {
2515         silc_free(channel->mode_data.cipher);
2516         channel->mode_data.cipher = NULL;
2517         channel->mode_data.key_len = 0;
2518       }
2519
2520       /* Generate new cipher and key for the channel */
2521
2522       /* XXX Duplicated code, make own function for this!! */
2523
2524       /* Delete old cipher and allocate default one */
2525       silc_cipher_free(channel->channel_key);
2526       if (!channel->cipher)
2527         silc_cipher_alloc("twofish", &channel->channel_key);
2528       else
2529         silc_cipher_alloc(channel->cipher, &channel->channel_key);
2530
2531       /* Re-generate channel key */
2532       silc_server_create_channel_key(server, channel, 0);
2533       
2534       /* Encode channel key payload to be distributed on the channel */
2535       packet = 
2536         silc_channel_key_payload_encode(tmp_len2, tmp_id,
2537                                         strlen(channel->channel_key->
2538                                                cipher->name),
2539                                         channel->channel_key->cipher->name,
2540                                         channel->key_len / 8, channel->key);
2541       
2542       /* If we are normal server then we will send it to our router.  If we
2543          are router we will send it to all local servers that has clients on
2544          the channel */
2545       if (server->server_type == SILC_SERVER) {
2546         if (!server->standalone)
2547           silc_server_packet_send(server, 
2548                                   cmd->server->router->connection,
2549                                   SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2550                                   packet->len, TRUE);
2551       } else {
2552         
2553       }
2554       
2555       /* Send to locally connected clients on the channel */
2556       silc_server_packet_send_local_channel(server, channel, 
2557                                             SILC_PACKET_CHANNEL_KEY, 0,
2558                                             packet->data, packet->len, FALSE);
2559       silc_buffer_free(packet);
2560     }
2561   }
2562
2563   /* Finally, set the mode */
2564   channel->mode = mode_mask;
2565
2566   /* Send CMODE_CHANGE notify */
2567   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2568   silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
2569                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
2570                                      cidp->data, cidp->len, 
2571                                      tmp_mask, tmp_len);
2572
2573   /* Set SET_MODE packet to network */
2574   if (!server->standalone)
2575     silc_server_send_set_mode(server, server->router->connection,
2576                               server->server_type == SILC_ROUTER ? 
2577                               TRUE : FALSE, SILC_MODE_TYPE_CHANNEL,
2578                               mode_mask, 2,
2579                               tmp_id, tmp_len2,
2580                               cidp->data, cidp->len);
2581
2582   /* Send command reply to sender */
2583   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
2584                                                 SILC_STATUS_OK, 0, 1,
2585                                                 2, tmp_mask, 4);
2586   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2587                           packet->data, packet->len, FALSE);
2588     
2589   silc_buffer_free(packet);
2590   silc_free(channel_id);
2591   silc_free(cidp);
2592
2593  out:
2594   silc_server_command_free(cmd);
2595 }
2596
2597 /* Server side of CUMODE command. Changes client's mode on a channel. */
2598
2599 SILC_SERVER_CMD_FUNC(cumode)
2600 {
2601   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2602   SilcServer server = cmd->server;
2603   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2604   SilcChannelID *channel_id;
2605   SilcClientID *client_id;
2606   SilcChannelEntry channel;
2607   SilcClientEntry target_client;
2608   SilcChannelClientEntry chl;
2609   SilcBuffer packet, idp;
2610   unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
2611   unsigned int target_mask, sender_mask, tmp_len, tmp_ch_len;
2612   int notify = FALSE;
2613
2614   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
2615
2616   /* Get Channel ID */
2617   tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
2618   if (!tmp_ch_id) {
2619     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2620                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2621     goto out;
2622   }
2623   channel_id = silc_id_payload_parse_id(tmp_ch_id, tmp_ch_len);
2624   if (!channel_id) {
2625     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2626                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2627     goto out;
2628   }
2629
2630   /* Get channel entry */
2631   channel = silc_idlist_find_channel_by_id(server->local_list, 
2632                                            channel_id, NULL);
2633   if (!channel) {
2634     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2635                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2636     goto out;
2637   }
2638
2639   /* Check whether sender is on the channel */
2640   if (!silc_server_client_on_channel(client, channel)) {
2641     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2642                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2643     goto out;
2644   }
2645
2646   /* Check that client has rights to change other's rights */
2647   silc_list_start(channel->user_list);
2648   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2649     if (chl->client == client) {
2650       if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
2651           !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2652         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2653                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2654         goto out;
2655       }
2656
2657       sender_mask = chl->mode;
2658       break;
2659     }
2660   }
2661   
2662   /* Get the target client's channel mode mask */
2663   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
2664   if (!tmp_mask) {
2665     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2666                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2667     goto out;
2668   }
2669   SILC_GET32_MSB(target_mask, tmp_mask);
2670
2671   /* Get target Client ID */
2672   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2673   if (!tmp_id) {
2674     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2675                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2676     goto out;
2677   }
2678   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2679   if (!client_id) {
2680     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2681                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2682     goto out;
2683   }
2684
2685   /* Get target client's entry */
2686   target_client = silc_idlist_find_client_by_id(server->local_list, 
2687                                                 client_id, NULL);
2688   if (!target_client) {
2689     target_client = silc_idlist_find_client_by_id(server->global_list, 
2690                                                   client_id, NULL);
2691   }
2692
2693   /* Check whether target client is on the channel */
2694   if (!silc_server_client_on_channel(target_client, channel)) {
2695     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2696                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
2697     goto out;
2698   }
2699
2700   /* Get entry to the channel user list */
2701   silc_list_start(channel->user_list);
2702   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2703     if (chl->client == target_client)
2704       break;
2705
2706   /* 
2707    * Change the mode 
2708    */
2709
2710   /* If the target client is founder, no one else can change their mode
2711      but themselves. */
2712   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
2713     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2714                                           SILC_STATUS_ERR_NOT_YOU);
2715     goto out;
2716   }
2717
2718   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
2719     /* Cannot promote anyone to channel founder */
2720     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2721                                           SILC_STATUS_ERR_NOT_YOU);
2722     goto out;
2723   } else {
2724     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
2725       if (target_client == client) {
2726         /* Remove channel founder rights from itself */
2727         chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
2728         notify = TRUE;
2729       } else {
2730         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2731                                               SILC_STATUS_ERR_NOT_YOU);
2732         goto out;
2733       }
2734     }
2735   }
2736
2737   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
2738     /* Promote to operator */
2739     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2740       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
2741       notify = TRUE;
2742     }
2743   } else {
2744     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
2745       /* Demote to normal user */
2746       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
2747       notify = TRUE;
2748     }
2749   }
2750
2751   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2752
2753   /* Send notify to channel, notify only if mode was actually changed. */
2754   if (notify) {
2755     silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
2756                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
2757                                        idp->data, idp->len,
2758                                        tmp_mask, 4, 
2759                                        tmp_id, tmp_len);
2760   }
2761
2762   /* Set SET_MODE packet to network */
2763   if (!server->standalone)
2764     silc_server_send_set_mode(server, server->router->connection,
2765                               server->server_type == SILC_ROUTER ? 
2766                               TRUE : FALSE, SILC_MODE_TYPE_UCHANNEL,
2767                               target_mask, 3,
2768                               tmp_ch_id, tmp_ch_len,
2769                               idp->data, idp->len,
2770                               tmp_id, tmp_len);
2771
2772   /* Send command reply to sender */
2773   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
2774                                                 SILC_STATUS_OK, 0, 2,
2775                                                 2, tmp_mask, 4,
2776                                                 3, tmp_id, tmp_len);
2777   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2778                           packet->data, packet->len, FALSE);
2779     
2780   silc_buffer_free(packet);
2781   silc_free(channel_id);
2782   silc_free(client_id);
2783   silc_buffer_free(idp);
2784
2785  out:
2786   silc_server_command_free(cmd);
2787 }
2788
2789 /* Server side of KICK command. Kicks client out of channel. */
2790
2791 SILC_SERVER_CMD_FUNC(kick)
2792 {
2793 }
2794
2795 SILC_SERVER_CMD_FUNC(restart)
2796 {
2797 }
2798  
2799 SILC_SERVER_CMD_FUNC(close)
2800 {
2801 }
2802  
2803 SILC_SERVER_CMD_FUNC(die)
2804 {
2805 }
2806  
2807 SILC_SERVER_CMD_FUNC(silcoper)
2808 {
2809 }
2810
2811 /* Server side command of LEAVE. Removes client from a channel. */
2812
2813 SILC_SERVER_CMD_FUNC(leave)
2814 {
2815   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2816   SilcServer server = cmd->server;
2817   SilcSocketConnection sock = cmd->sock;
2818   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
2819   SilcChannelID *id;
2820   SilcChannelEntry channel;
2821   SilcBuffer packet;
2822   unsigned int i, len;
2823   unsigned char *tmp;
2824
2825   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
2826
2827   /* Get Channel ID */
2828   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2829   if (!tmp) {
2830     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2831                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2832     goto out;
2833   }
2834   id = silc_id_payload_parse_id(tmp, len);
2835   if (!id) {
2836     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2837                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2838     goto out;
2839   }
2840
2841   /* Get channel entry */
2842   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
2843   if (!channel) {
2844     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2845                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2846     goto out;
2847   }
2848
2849   /* Check whether this client is on the channel */
2850   if (!silc_server_client_on_channel(id_entry, channel)) {
2851     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2852                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2853     goto out;
2854   }
2855
2856   /* Notify routers that they should remove this client from their list
2857      of clients on the channel. */
2858   if (!server->standalone)
2859     silc_server_send_remove_channel_user(server, 
2860                                          server->router->connection,
2861                                          server->server_type == SILC_ROUTER ?
2862                                          TRUE : FALSE, id_entry->id, id);
2863
2864   /* Remove client from channel */
2865   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
2866                                           TRUE);
2867   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2868                                         SILC_STATUS_OK);
2869
2870   /* If the channel does not exist anymore we won't send anything */
2871   if (!i)
2872     goto out;
2873
2874   /* Re-generate channel key */
2875   silc_server_create_channel_key(server, channel, 0);
2876
2877   /* Encode channel key payload to be distributed on the channel */
2878   packet = 
2879     silc_channel_key_payload_encode(len, tmp,
2880                                     strlen(channel->channel_key->cipher->name),
2881                                     channel->channel_key->cipher->name,
2882                                     channel->key_len / 8, channel->key);
2883
2884   /* If we are normal server then we will send it to our router.  If we
2885      are router we will send it to all local servers that has clients on
2886      the channel */
2887   if (server->server_type == SILC_SERVER) {
2888     if (!server->standalone)
2889       silc_server_packet_send(server, 
2890                               cmd->server->router->connection,
2891                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2892                               packet->len, FALSE);
2893   } else {
2894
2895   }
2896
2897   /* Send to locally connected clients on the channel */
2898   silc_server_packet_send_local_channel(server, channel, 
2899                                         SILC_PACKET_CHANNEL_KEY, 0,
2900                                         packet->data, packet->len, FALSE);
2901
2902   silc_buffer_free(packet);
2903   silc_free(id);
2904
2905  out:
2906   silc_server_command_free(cmd);
2907 }
2908
2909 /* Server side of command USERS. Resolves clients and their USERS currently
2910    joined on the requested channel. The list of Client ID's and their modes
2911    on the channel is sent back. */
2912
2913 SILC_SERVER_CMD_FUNC(users)
2914 {
2915   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2916   SilcServer server = cmd->server;
2917   SilcChannelEntry channel;
2918   SilcChannelClientEntry chl;
2919   SilcChannelID *id;
2920   SilcBuffer packet;
2921   unsigned char *channel_id;
2922   unsigned int channel_id_len;
2923   SilcBuffer client_id_list;
2924   SilcBuffer client_mode_list;
2925   SilcBuffer idp;
2926   unsigned char lc[4];
2927   unsigned int list_count = 0;
2928   unsigned short ident = silc_command_get_ident(cmd->payload);
2929
2930   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
2931
2932   /* Get Channel ID */
2933   channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
2934   if (!channel_id) {
2935     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
2936                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2937     goto out;
2938   }
2939   id = silc_id_payload_parse_id(channel_id, channel_id_len);
2940   if (!id) {
2941     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
2942                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2943     goto out;
2944   }
2945
2946   /* If we are server and we don't know about this channel we will send
2947      the command to our router. If we know about the channel then we also
2948      have the list of users already. */
2949   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
2950   if (!channel) {
2951     if (server->server_type == SILC_SERVER && !server->standalone &&
2952         !cmd->pending) {
2953       SilcBuffer tmpbuf;
2954       
2955       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2956       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2957       
2958       /* Send USERS command */
2959       silc_server_packet_send(server, server->router->connection,
2960                               SILC_PACKET_COMMAND, cmd->packet->flags,
2961                               tmpbuf->data, tmpbuf->len, TRUE);
2962       
2963       /* Reprocess this packet after received reply */
2964       silc_server_command_pending(server, SILC_COMMAND_USERS, 
2965                                   silc_command_get_ident(cmd->payload),
2966                                   silc_server_command_destructor,
2967                                   silc_server_command_users,
2968                                   silc_server_command_dup(cmd));
2969       cmd->pending = TRUE;
2970       silc_command_set_ident(cmd->payload, ident);
2971       
2972       silc_buffer_free(tmpbuf);
2973       silc_free(id);
2974       return;
2975     }
2976
2977     /* We are router and we will check the global list as well. */
2978     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
2979     if (!channel) {
2980       /* Channel really does not exist */
2981       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
2982                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2983       goto out;
2984     }
2985   }
2986
2987   /* Assemble the lists now */
2988
2989   client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) * 
2990                                      silc_list_count(channel->user_list));
2991   silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
2992   client_mode_list = 
2993     silc_buffer_alloc(4 * silc_list_count(channel->user_list));
2994   silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
2995
2996   silc_list_start(channel->user_list);
2997   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2998     /* Client ID */
2999     idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
3000     silc_buffer_put(client_id_list, idp->data, idp->len);
3001     silc_buffer_pull(client_id_list, idp->len);
3002     silc_buffer_free(idp);
3003
3004     /* Client's mode on channel */
3005     SILC_PUT32_MSB(chl->mode, client_mode_list->data);
3006     silc_buffer_pull(client_mode_list, 4);
3007
3008     list_count++;
3009   }
3010   silc_buffer_push(client_id_list, 
3011                    client_id_list->data - client_id_list->head);
3012   silc_buffer_push(client_mode_list, 
3013                    client_mode_list->data - client_mode_list->head);
3014
3015   /* List count */
3016   SILC_PUT32_MSB(list_count, lc);
3017
3018   /* Send reply */
3019   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
3020                                                 SILC_STATUS_OK, 0, 4,
3021                                                 2, channel_id, channel_id_len,
3022                                                 3, lc, 4,
3023                                                 4, client_id_list->data,
3024                                                 client_id_list->len,
3025                                                 5, client_mode_list->data,
3026                                                 client_mode_list->len);
3027   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3028                           packet->data, packet->len, FALSE);
3029     
3030   silc_buffer_free(packet);
3031   silc_buffer_free(client_id_list);
3032   silc_buffer_free(client_mode_list);
3033   silc_free(id);
3034
3035  out:
3036   silc_server_command_free(cmd);
3037 }