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 SILC_TASK_CALLBACK(silc_server_command_process_timeout);
41
42 /* Server command list. */
43 SilcServerCommand silc_command_list[] =
44 {
45   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
46   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
47   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
48   SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
49   SILC_SERVER_CMD(list, LIST, SILC_CF_LAG_STRICT | SILC_CF_REG),
50   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
51   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
52   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
53   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG_STRICT | SILC_CF_REG | SILC_CF_OPER),
54   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
55   SILC_SERVER_CMD(connect, CONNECT, 
56                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
57   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
58   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
59   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG_STRICT | SILC_CF_REG),
60   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
61   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
62   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG_STRICT | SILC_CF_REG),
63   SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
64   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
65   SILC_SERVER_CMD(restart, RESTART, 
66                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
67   SILC_SERVER_CMD(close, CLOSE,
68                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
69   SILC_SERVER_CMD(shutdown, SHUTDOWN, SILC_CF_LAG | SILC_CF_REG | 
70                   SILC_CF_OPER),
71   SILC_SERVER_CMD(silcoper, SILCOPER,
72                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
73   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
74   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
75   SILC_SERVER_CMD(ban, BAN, SILC_CF_LAG_STRICT | SILC_CF_REG),
76
77   { NULL, 0 },
78 };
79
80 #define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max)            \
81 do {                                                                          \
82   unsigned int _argc = silc_argument_get_arg_num(cmd->args);                  \
83                                                                               \
84   SILC_LOG_DEBUG(("Start"));                                                  \
85                                                                               \
86   if (_argc < min) {                                                          \
87     silc_server_command_send_status_reply(cmd, command,                       \
88                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
89     silc_server_command_free(cmd);                                            \
90     return;                                                                   \
91   }                                                                           \
92   if (_argc > max) {                                                          \
93     silc_server_command_send_status_reply(cmd, command,                       \
94                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);   \
95     silc_server_command_free(cmd);                                            \
96     return;                                                                   \
97   }                                                                           \
98 } while(0)
99
100 /* Returns TRUE if the connection is registered. Unregistered connections
101    usually cannot send commands hence the check. */
102
103 static int silc_server_is_registered(SilcServer server,
104                                      SilcSocketConnection sock,
105                                      SilcServerCommandContext cmd,
106                                      SilcCommand command)
107 {
108   SilcIDListData idata = (SilcIDListData)sock->user_data;
109   if (idata->registered)
110     return TRUE;
111
112   silc_server_command_send_status_reply(cmd, command,
113                                         SILC_STATUS_ERR_NOT_REGISTERED);
114   silc_server_command_free(cmd);
115   return FALSE;
116 }
117
118 /* Internal context to hold data when executed command with timeout. */
119 typedef struct {
120   SilcServerCommandContext ctx;
121   SilcServerCommand *cmd;
122 } *SilcServerCommandTimeout;
123
124 /* Timeout callback to process commands with timeout for client. Client's
125    commands are always executed with timeout. */
126
127 SILC_TASK_CALLBACK(silc_server_command_process_timeout)
128 {
129   SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
130   SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
131
132   /* Update access time */
133   client->last_command = time(NULL);
134
135   if (!(timeout->cmd->flags & SILC_CF_REG))
136     timeout->cmd->cb(timeout->ctx);
137   else if (silc_server_is_registered(timeout->ctx->server, 
138                                      timeout->ctx->sock, 
139                                      timeout->ctx, 
140                                      timeout->cmd->cmd))
141     timeout->cmd->cb(timeout->ctx);
142
143   silc_free(timeout);
144 }
145
146 /* Processes received command packet. */
147
148 void silc_server_command_process(SilcServer server,
149                                  SilcSocketConnection sock,
150                                  SilcPacketContext *packet)
151 {
152   SilcServerCommandContext ctx;
153   SilcServerCommand *cmd;
154   SilcCommand command;
155
156   /* Allocate command context. This must be free'd by the
157      command routine receiving it. */
158   ctx = silc_server_command_alloc();
159   ctx->server = server;
160   ctx->sock = silc_socket_dup(sock);
161   ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
162   
163   /* Parse the command payload in the packet */
164   ctx->payload = silc_command_payload_parse(packet->buffer);
165   if (!ctx->payload) {
166     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
167     silc_buffer_free(packet->buffer);
168     silc_packet_context_free(packet);
169     silc_socket_free(ctx->sock);
170     silc_free(ctx);
171     return;
172   }
173   ctx->args = silc_command_get_args(ctx->payload);
174
175   /* Get the command */
176   command = silc_command_get(ctx->payload);
177   for (cmd = silc_command_list; cmd->cb; cmd++)
178     if (cmd->cmd == command)
179       break;
180
181   if (cmd == NULL) {
182     silc_server_command_send_status_reply(ctx, command,
183                                           SILC_STATUS_ERR_UNKNOWN_COMMAND);
184     silc_server_command_free(ctx);
185     return;
186   }
187
188   /* Execute client's commands always with timeout.  Normally they are
189      executed with zero (0) timeout but if client is sending command more
190      frequently than once in 2 seconds, then the timeout may be 0 to 2
191      seconds. */
192   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
193     SilcClientEntry client = (SilcClientEntry)sock->user_data;
194     SilcServerCommandTimeout timeout = silc_calloc(1, sizeof(*timeout));
195     int fast;
196
197     timeout->ctx = ctx;
198     timeout->cmd = cmd;
199
200     if (client->last_command && (time(NULL) - client->last_command) < 2) {
201       client->fast_command++;
202       fast = FALSE;
203     } else {
204       client->fast_command = ((client->fast_command - 1) <= 0 ? 0 : 
205                               client->fast_command--);
206       fast = TRUE;
207     }
208
209     if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
210                   (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
211       silc_task_register(server->timeout_queue, sock->sock, 
212                          silc_server_command_process_timeout,
213                          (void *)timeout, 
214                          2 - (time(NULL) - client->last_command), 0,
215                          SILC_TASK_TIMEOUT,
216                          SILC_TASK_PRI_NORMAL);
217     else
218       silc_task_register(server->timeout_queue, sock->sock, 
219                          silc_server_command_process_timeout,
220                          (void *)timeout, 
221                          0, 1,
222                          SILC_TASK_TIMEOUT,
223                          SILC_TASK_PRI_NORMAL);
224     return;
225   }
226
227   /* Execute for server */
228
229   if (!(cmd->flags & SILC_CF_REG))
230     cmd->cb(ctx);
231   else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
232     cmd->cb(ctx);
233 }
234
235 /* Allocate Command Context */
236
237 SilcServerCommandContext silc_server_command_alloc()
238 {
239   SilcServerCommandContext ctx = silc_calloc(1, sizeof(*ctx));
240   ctx->users++;
241   return ctx;
242 }
243
244 /* Free's the command context allocated before executing the command */
245
246 void silc_server_command_free(SilcServerCommandContext ctx)
247 {
248   ctx->users--;
249   SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
250                   ctx->users));
251   if (ctx->users < 1) {
252     if (ctx->payload)
253       silc_command_free_payload(ctx->payload);
254     if (ctx->packet)
255       silc_packet_context_free(ctx->packet);
256     if (ctx->sock)
257       silc_socket_free(ctx->sock); /* Decrease reference counter */
258     silc_free(ctx);
259   }
260 }
261
262 /* Duplicate Command Context by adding reference counter. The context won't
263    be free'd untill it hits zero. */
264
265 SilcServerCommandContext 
266 silc_server_command_dup(SilcServerCommandContext ctx)
267 {
268   ctx->users++;
269   SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
270                   ctx->users));
271   return ctx;
272 }
273
274 /* Add new pending command to be executed when reply to a command has been
275    received. The `reply_cmd' is the command that will call the `callback'
276    with `context' when reply has been received.  If `ident' is non-zero
277    the `callback' will be executed when received reply with command
278    identifier `ident'. */
279
280 void silc_server_command_pending(SilcServer server,
281                                  SilcCommand reply_cmd,
282                                  unsigned short ident,
283                                  SilcServerPendingDestructor destructor,
284                                  SilcCommandCb callback,
285                                  void *context)
286 {
287   SilcServerCommandPending *reply;
288
289   reply = silc_calloc(1, sizeof(*reply));
290   reply->reply_cmd = reply_cmd;
291   reply->ident = ident;
292   reply->context = context;
293   reply->callback = callback;
294   reply->destructor = destructor;
295   silc_dlist_add(server->pending_commands, reply);
296 }
297
298 /* Deletes pending command by reply command type. */
299
300 void silc_server_command_pending_del(SilcServer server,
301                                      SilcCommand reply_cmd,
302                                      unsigned short ident)
303 {
304   SilcServerCommandPending *r;
305
306   silc_dlist_start(server->pending_commands);
307   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
308     if (r->reply_cmd == reply_cmd && r->ident == ident) {
309       silc_dlist_del(server->pending_commands, r);
310       break;
311     }
312   }
313 }
314
315 /* Checks for pending commands and marks callbacks to be called from
316    the command reply function. Returns TRUE if there were pending command. */
317
318 int silc_server_command_pending_check(SilcServer server,
319                                       SilcServerCommandReplyContext ctx,
320                                       SilcCommand command, 
321                                       unsigned short ident)
322 {
323   SilcServerCommandPending *r;
324
325   silc_dlist_start(server->pending_commands);
326   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
327     if (r->reply_cmd == command && r->ident == ident) {
328       ctx->context = r->context;
329       ctx->callback = r->callback;
330       ctx->destructor = r->destructor;
331       ctx->ident = ident;
332       return TRUE;
333     }
334   }
335
336   return FALSE;
337 }
338
339 /* Destructor function for pending callbacks. This is called when using
340    pending commands to free the context given for the pending command. */
341
342 static void silc_server_command_destructor(void *context)
343 {
344   silc_server_command_free((SilcServerCommandContext)context);
345 }
346
347 /* Sends simple status message as command reply packet */
348
349 static void 
350 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
351                                       SilcCommand command,
352                                       SilcCommandStatus status)
353 {
354   SilcBuffer buffer;
355
356   SILC_LOG_DEBUG(("Sending command status %d", status));
357
358   buffer = 
359     silc_command_reply_payload_encode_va(command, status, 
360                                          silc_command_get_ident(cmd->payload),
361                                          0);
362   silc_server_packet_send(cmd->server, cmd->sock,
363                           SILC_PACKET_COMMAND_REPLY, 0, 
364                           buffer->data, buffer->len, FALSE);
365   silc_buffer_free(buffer);
366 }
367
368 /* Sends command status reply with one extra argument. The argument
369    type must be sent as argument. */
370
371 static void 
372 silc_server_command_send_status_data(SilcServerCommandContext cmd,
373                                      SilcCommand command,
374                                      SilcCommandStatus status,
375                                      unsigned int arg_type,
376                                      unsigned char *arg,
377                                      unsigned int arg_len)
378 {
379   SilcBuffer buffer;
380
381   SILC_LOG_DEBUG(("Sending command status %d", status));
382
383   buffer = 
384     silc_command_reply_payload_encode_va(command, status, 
385                                          silc_command_get_ident(cmd->payload),
386                                          1, arg_type, arg, arg_len);
387   silc_server_packet_send(cmd->server, cmd->sock,
388                           SILC_PACKET_COMMAND_REPLY, 0, 
389                           buffer->data, buffer->len, FALSE);
390   silc_buffer_free(buffer);
391 }
392
393 /******************************************************************************
394
395                               WHOIS Functions
396
397 ******************************************************************************/
398
399 static int
400 silc_server_command_whois_parse(SilcServerCommandContext cmd,
401                                 SilcClientID ***client_id,
402                                 unsigned int *client_id_count,
403                                 char **nickname,
404                                 char **server_name,
405                                 int *count,
406                                 SilcCommand command)
407 {
408   unsigned char *tmp;
409   unsigned int len;
410   unsigned int argc = silc_argument_get_arg_num(cmd->args);
411   int i, k;
412
413   /* If client ID is in the command it must be used instead of nickname */
414   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
415   if (!tmp) {
416     /* No ID, get the nickname@server string and parse it. */
417     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
418     if (tmp) {
419       if (strchr(tmp, '@')) {
420         len = strcspn(tmp, "@");
421         *nickname = silc_calloc(len + 1, sizeof(char));
422         memcpy(*nickname, tmp, len);
423         *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
424         memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
425       } else {
426         *nickname = strdup(tmp);
427       }
428     } else {
429       silc_server_command_send_status_reply(cmd, command,
430                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
431       return FALSE;
432     }
433   } else {
434     /* Command includes ID, we must use that.  Also check whether the command
435        has more than one ID set - take them all. */
436
437     *client_id = silc_calloc(1, sizeof(**client_id));
438     (*client_id)[0] = silc_id_payload_parse_id(tmp, len);
439     if ((*client_id)[0] == NULL) {
440       silc_free(*client_id);
441       return FALSE;
442     }
443     *client_id_count = 1;
444
445     /* Take all ID's from the command packet */
446     if (argc > 1) {
447       for (k = 1, i = 1; i < argc; i++) {
448         tmp = silc_argument_get_arg_type(cmd->args, i + 3, &len);
449         if (tmp) {
450           *client_id = silc_realloc(*client_id, sizeof(**client_id) *
451                                     (*client_id_count + 1));
452           (*client_id)[k] = silc_id_payload_parse_id(tmp, len);
453           if ((*client_id)[k] == NULL) {
454             /* Cleanup all and fail */
455             for (i = 0; i < *client_id_count; i++)
456               silc_free((*client_id)[i]);
457             silc_free(*client_id);
458             return FALSE;
459           }
460           (*client_id_count)++;
461           k++;
462         }
463       }
464     }
465
466     /* Command includes ID, use that */
467   }
468
469   /* Get the max count of reply messages allowed */
470   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
471   if (tmp)
472     *count = atoi(tmp);
473   else
474     *count = 0;
475
476   return TRUE;
477 }
478
479 static char
480 silc_server_command_whois_check(SilcServerCommandContext cmd,
481                                 SilcClientEntry *clients,
482                                 unsigned int clients_count)
483 {
484   SilcServer server = cmd->server;
485   int i;
486   SilcClientEntry entry;
487
488   for (i = 0; i < clients_count; i++) {
489     entry = clients[i];
490
491     if (entry->data.registered == FALSE)
492       continue;
493
494     if (!entry->nickname || !entry->username || !entry->userinfo) {
495       SilcBuffer tmpbuf;
496       unsigned short old_ident;
497
498       if (!entry->router)
499         continue;
500       
501       old_ident = silc_command_get_ident(cmd->payload);
502       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
503       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
504
505       /* Send WHOIS command */
506       silc_server_packet_send(server, entry->router->connection,
507                               SILC_PACKET_COMMAND, cmd->packet->flags,
508                               tmpbuf->data, tmpbuf->len, TRUE);
509       
510       /* Reprocess this packet after received reply */
511       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
512                                   silc_command_get_ident(cmd->payload),
513                                   silc_server_command_destructor,
514                                   silc_server_command_whois, 
515                                   silc_server_command_dup(cmd));
516       cmd->pending = TRUE;
517       
518       silc_command_set_ident(cmd->payload, old_ident);
519
520       silc_buffer_free(tmpbuf);
521       return FALSE;
522     }
523   }
524
525   return TRUE;
526 }
527
528 static void
529 silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
530                                      SilcClientEntry *clients,
531                                      unsigned int clients_count,
532                                      int count)
533 {
534   SilcServer server = cmd->server;
535   char *tmp;
536   int i, k, len;
537   SilcBuffer packet, idp, channels;
538   SilcClientEntry entry;
539   SilcCommandStatus status;
540   unsigned short ident = silc_command_get_ident(cmd->payload);
541   char nh[128], uh[128];
542   unsigned char idle[4], mode[4];
543   SilcSocketConnection hsock;
544
545   len = 0;
546   for (i = 0; i < clients_count; i++)
547     if (clients[i]->data.registered)
548       len++;
549
550   status = SILC_STATUS_OK;
551   if (len > 1)
552     status = SILC_STATUS_LIST_START;
553
554   for (i = 0, k = 0; i < clients_count; i++) {
555     entry = clients[i];
556
557     if (entry->data.registered == FALSE) {
558       if (clients_count == 1) {
559         SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
560         silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
561                                              SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
562                                              2, idp->data, idp->len);
563         silc_buffer_free(idp);
564       }
565       continue;
566     }
567
568     if (k >= 1)
569       status = SILC_STATUS_LIST_ITEM;
570
571     if (clients_count > 1 && k == clients_count - 1)
572       status = SILC_STATUS_LIST_END;
573
574     if (count && k - 1 == count)
575       status = SILC_STATUS_LIST_END;
576
577     if (count && k - 1 > count)
578       break;
579
580     /* Sanity check, however these should never fail. However, as
581        this sanity check has been added here they have failed. */
582     if (!entry->nickname || !entry->username || !entry->userinfo)
583       continue;
584       
585     /* Send WHOIS reply */
586     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
587     tmp = silc_argument_get_first_arg(cmd->args, NULL);
588     
589     memset(uh, 0, sizeof(uh));
590     memset(nh, 0, sizeof(nh));
591     memset(idle, 0, sizeof(idle));
592     
593     strncat(nh, entry->nickname, strlen(entry->nickname));
594     if (!strchr(entry->nickname, '@')) {
595       strncat(nh, "@", 1);
596       len = entry->router ? strlen(entry->router->server_name) :
597         strlen(server->server_name);
598       strncat(nh, entry->router ? entry->router->server_name :
599               server->server_name, len);
600     }
601       
602     strncat(uh, entry->username, strlen(entry->username));
603     if (!strchr(entry->username, '@')) {
604       strncat(uh, "@", 1);
605       hsock = (SilcSocketConnection)entry->connection;
606       len = strlen(hsock->hostname);
607       strncat(uh, hsock->hostname, len);
608     }
609
610     channels = silc_server_get_client_channel_list(server, entry);
611       
612     SILC_PUT32_MSB(entry->mode, mode);
613
614     if (entry->connection) {
615       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
616     }
617
618     if (channels)
619       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
620                                                     status, ident, 7, 
621                                                     2, idp->data, idp->len,
622                                                     3, nh, strlen(nh),
623                                                     4, uh, strlen(uh),
624                                                     5, entry->userinfo, 
625                                                     strlen(entry->userinfo),
626                                                     6, channels->data,
627                                                     channels->len,
628                                                     7, mode, 4,
629                                                     8, idle, 4);
630     else
631       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
632                                                     status, ident, 6, 
633                                                     2, idp->data, idp->len,
634                                                     3, nh, strlen(nh),
635                                                     4, uh, strlen(uh),
636                                                     5, entry->userinfo, 
637                                                     strlen(entry->userinfo),
638                                                     7, mode, 4,
639                                                     8, idle, 4);
640     
641     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
642                             0, packet->data, packet->len, FALSE);
643     
644     silc_buffer_free(packet);
645     silc_buffer_free(idp);
646     if (channels)
647       silc_buffer_free(channels);
648
649     k++;
650   }
651 }
652
653 static int
654 silc_server_command_whois_from_client(SilcServerCommandContext cmd)
655 {
656   SilcServer server = cmd->server;
657   char *nick = NULL, *server_name = NULL;
658   int count = 0, clients_count = 0;
659   SilcClientEntry *clients = NULL, entry;
660   SilcClientID **client_id = NULL;
661   unsigned int client_id_count = 0;
662   int i, ret = 0;
663
664   /* Protocol dictates that we must always send the received WHOIS request
665      to our router if we are normal server, so let's do it now unless we
666      are standalone. We will not send any replies to the client until we
667      have received reply from the router. */
668   if (server->server_type == SILC_SERVER && !cmd->pending && 
669       !server->standalone) {
670     SilcBuffer tmpbuf;
671     unsigned short old_ident;
672
673     old_ident = silc_command_get_ident(cmd->payload);
674     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
675     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
676
677     /* Send WHOIS command to our router */
678     silc_server_packet_send(server, (SilcSocketConnection)
679                             server->router->connection,
680                             SILC_PACKET_COMMAND, cmd->packet->flags,
681                             tmpbuf->data, tmpbuf->len, TRUE);
682
683     /* Reprocess this packet after received reply from router */
684     silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
685                                 silc_command_get_ident(cmd->payload),
686                                 silc_server_command_destructor,
687                                 silc_server_command_whois,
688                                 silc_server_command_dup(cmd));
689     cmd->pending = TRUE;
690
691     silc_command_set_ident(cmd->payload, old_ident);
692
693     silc_buffer_free(tmpbuf);
694     ret = -1;
695     goto out;
696   }
697
698   /* We are ready to process the command request. Let's search for the
699      requested client and send reply to the requesting client. */
700
701   /* Parse the whois request */
702   if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
703                                        &nick, &server_name, &count,
704                                        SILC_COMMAND_WHOIS))
705     return 0;
706
707   /* Get all clients matching that ID or nickname from local list */
708   if (client_id_count) {
709     /* Check all Client ID's received in the command packet */
710     for (i = 0; i < client_id_count; i++) {
711       entry = silc_idlist_find_client_by_id(server->local_list, 
712                                             client_id[i], NULL);
713       if (entry) {
714         clients = silc_realloc(clients, sizeof(*clients) * 
715                                (clients_count + 1));
716         clients[clients_count++] = entry;
717       }
718     }
719   } else {
720     clients = silc_idlist_get_clients_by_hash(server->local_list, 
721                                               nick, server->md5hash,
722                                               &clients_count);
723     if (!clients)
724       clients = silc_idlist_get_clients_by_nickname(server->local_list, 
725                                                     nick, server_name,
726                                                     &clients_count);
727   }
728   
729   /* Check global list as well */
730   if (!clients) {
731     if (client_id_count) {
732       /* Check all Client ID's received in the command packet */
733       for (i = 0; i < client_id_count; i++) {
734         entry = silc_idlist_find_client_by_id(server->global_list, 
735                                               client_id[i], NULL);
736         if (entry) {
737           clients = silc_realloc(clients, sizeof(*clients) * 
738                                  (clients_count + 1));
739           clients[clients_count++] = entry;
740         }
741       }
742     } else {
743       clients = silc_idlist_get_clients_by_hash(server->global_list, 
744                                                 nick, server->md5hash,
745                                                 &clients_count);
746       if (!clients)
747         clients = silc_idlist_get_clients_by_nickname(server->global_list, 
748                                                       nick, server_name,
749                                                       &clients_count);
750     }
751   }
752   
753   if (!clients) {
754     /* Such client(s) really does not exist in the SILC network. */
755     if (!client_id_count) {
756       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
757                                            SILC_STATUS_ERR_NO_SUCH_NICK,
758                                            3, nick, strlen(nick));
759     } else {
760       SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
761       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
762                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
763                                            2, idp->data, idp->len);
764       silc_buffer_free(idp);
765     }
766     goto out;
767   }
768
769   /* Router always finds the client entry if it exists in the SILC network.
770      However, it might be incomplete entry and does not include all the
771      mandatory fields that WHOIS command reply requires. Check for these and
772      make query from the server who owns the client if some fields are 
773      missing. */
774   if (!silc_server_command_whois_check(cmd, clients, clients_count)) {
775     ret = -1;
776     goto out;
777   }
778
779   /* Send the command reply to the client */
780   silc_server_command_whois_send_reply(cmd, clients, clients_count,
781                                        count);
782
783  out:
784   if (client_id_count) {
785     for (i = 0; i < client_id_count; i++)
786       silc_free(client_id[i]);
787     silc_free(client_id);
788   }
789   if (clients)
790     silc_free(clients);
791   if (nick)
792     silc_free(nick);
793   if (server_name)
794     silc_free(server_name);
795
796   return ret;
797 }
798
799 static int
800 silc_server_command_whois_from_server(SilcServerCommandContext cmd)
801 {
802   SilcServer server = cmd->server;
803   char *nick = NULL, *server_name = NULL;
804   int count = 0, clients_count = 0;
805   SilcClientEntry *clients = NULL, entry;
806   SilcClientID **client_id = NULL;
807   unsigned int client_id_count = 0;
808   int i, ret = 0;
809
810   /* Parse the whois request */
811   if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
812                                        &nick, &server_name, &count,
813                                        SILC_COMMAND_WHOIS))
814     return 0;
815
816   /* Process the command request. Let's search for the requested client and
817      send reply to the requesting server. */
818
819   if (client_id_count) {
820     /* Check all Client ID's received in the command packet */
821     for (i = 0; i < client_id_count; i++) {
822       entry = silc_idlist_find_client_by_id(server->local_list, 
823                                             client_id[i], NULL);
824       if (entry) {
825         clients = silc_realloc(clients, sizeof(*clients) * 
826                                (clients_count + 1));
827         clients[clients_count++] = entry;
828       }
829     }
830   } else {
831     clients = silc_idlist_get_clients_by_hash(server->local_list, 
832                                               nick, server->md5hash,
833                                               &clients_count);
834     if (!clients)
835       clients = silc_idlist_get_clients_by_nickname(server->local_list, 
836                                                     nick, server_name,
837                                                     &clients_count);
838   }
839   
840   /* If we are router we will check our global list as well. */
841   if (!clients && server->server_type == SILC_ROUTER) {
842     if (client_id_count) {
843       /* Check all Client ID's received in the command packet */
844       for (i = 0; i < client_id_count; i++) {
845         entry = silc_idlist_find_client_by_id(server->global_list, 
846                                               client_id[i], NULL);
847         if (entry) {
848           clients = silc_realloc(clients, sizeof(*clients) * 
849                                  (clients_count + 1));
850           clients[clients_count++] = entry;
851         }
852       }
853     } else {
854       clients = silc_idlist_get_clients_by_hash(server->global_list, 
855                                                 nick, server->md5hash,
856                                                 &clients_count);
857       if (!clients)
858         clients = silc_idlist_get_clients_by_nickname(server->global_list, 
859                                                       nick, server_name,
860                                                       &clients_count);
861     }
862   }
863
864   if (!clients) {
865     /* Such a client really does not exist in the SILC network. */
866     if (!client_id_count) {
867       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
868                                            SILC_STATUS_ERR_NO_SUCH_NICK,
869                                            3, nick, strlen(nick));
870     } else {
871       SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
872       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
873                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
874                                            2, idp->data, idp->len);
875       silc_buffer_free(idp);
876     }
877     goto out;
878   }
879
880   /* Router always finds the client entry if it exists in the SILC network.
881      However, it might be incomplete entry and does not include all the
882      mandatory fields that WHOIS command reply requires. Check for these and
883      make query from the server who owns the client if some fields are 
884      missing. */
885   if (!silc_server_command_whois_check(cmd, clients, clients_count)) {
886     ret = -1;
887     goto out;
888   }
889
890   /* Send the command reply to the client */
891   silc_server_command_whois_send_reply(cmd, clients, clients_count,
892                                        count);
893
894  out:
895   if (client_id_count) {
896     for (i = 0; i < client_id_count; i++)
897       silc_free(client_id[i]);
898     silc_free(client_id);
899   }
900   if (clients)
901     silc_free(clients);
902   if (nick)
903     silc_free(nick);
904   if (server_name)
905     silc_free(server_name);
906
907   return ret;
908 }
909
910 /* Server side of command WHOIS. Processes user's query and sends found 
911    results as command replies back to the client. */
912
913 SILC_SERVER_CMD_FUNC(whois)
914 {
915   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
916   int ret = 0;
917
918   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3328);
919
920   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
921     ret = silc_server_command_whois_from_client(cmd);
922   else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) ||
923            (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
924     ret = silc_server_command_whois_from_server(cmd);
925
926   if (!ret)
927     silc_server_command_free(cmd);
928 }
929
930 /******************************************************************************
931
932                               WHOWAS Functions
933
934 ******************************************************************************/
935
936 static int
937 silc_server_command_whowas_parse(SilcServerCommandContext cmd,
938                                  char **nickname,
939                                  char **server_name,
940                                  int *count)
941 {
942   unsigned char *tmp;
943   unsigned int len;
944
945   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
946   if (!tmp) {
947     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOWAS,
948                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
949     return FALSE;
950   }
951
952   /* Get the nickname@server string and parse it. */
953   if (strchr(tmp, '@')) {
954     len = strcspn(tmp, "@");
955     *nickname = silc_calloc(len + 1, sizeof(char));
956     memcpy(*nickname, tmp, len);
957     *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
958     memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
959   } else {
960     *nickname = strdup(tmp);
961   }
962   /* Get the max count of reply messages allowed */
963   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
964   if (tmp)
965     *count = atoi(tmp);
966   else
967     *count = 0;
968
969   return TRUE;
970 }
971
972 static char
973 silc_server_command_whowas_check(SilcServerCommandContext cmd,
974                                  SilcClientEntry *clients,
975                                  unsigned int clients_count)
976 {
977   SilcServer server = cmd->server;
978   int i;
979   SilcClientEntry entry;
980
981   for (i = 0; i < clients_count; i++) {
982     entry = clients[i];
983
984     if (!entry->nickname || !entry->username) {
985       SilcBuffer tmpbuf;
986       unsigned short old_ident;
987
988       if (!entry->router)
989         continue;
990       
991       old_ident = silc_command_get_ident(cmd->payload);
992       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
993       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
994
995       /* Send WHOWAS command */
996       silc_server_packet_send(server, entry->router->connection,
997                               SILC_PACKET_COMMAND, cmd->packet->flags,
998                               tmpbuf->data, tmpbuf->len, TRUE);
999       
1000       /* Reprocess this packet after received reply */
1001       silc_server_command_pending(server, SILC_COMMAND_WHOWAS, 
1002                                   silc_command_get_ident(cmd->payload),
1003                                   silc_server_command_destructor,
1004                                   silc_server_command_whowas, 
1005                                   silc_server_command_dup(cmd));
1006       cmd->pending = TRUE;
1007       
1008       silc_command_set_ident(cmd->payload, old_ident);
1009
1010       silc_buffer_free(tmpbuf);
1011       return FALSE;
1012     }
1013   }
1014
1015   return TRUE;
1016 }
1017
1018 static void
1019 silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
1020                                       SilcClientEntry *clients,
1021                                       unsigned int clients_count)
1022 {
1023   SilcServer server = cmd->server;
1024   char *tmp;
1025   int i, count = 0, len;
1026   SilcBuffer packet, idp;
1027   SilcClientEntry entry = NULL;
1028   SilcCommandStatus status;
1029   unsigned short ident = silc_command_get_ident(cmd->payload);
1030   char found = FALSE;
1031   char nh[256], uh[256];
1032
1033   status = SILC_STATUS_OK;
1034   if (clients_count > 1)
1035     status = SILC_STATUS_LIST_START;
1036
1037   for (i = 0; i < clients_count; i++) {
1038     entry = clients[i];
1039
1040     /* We will take only clients that are not valid anymore. They are the
1041        ones that are not registered anymore but still have a ID. They
1042        have disconnected us, and thus valid for WHOWAS. */
1043     if (entry->data.registered == TRUE)
1044       continue;
1045     if (entry->id == NULL)
1046       continue;
1047
1048     if (count && i - 1 == count)
1049       break;
1050
1051     found = TRUE;
1052
1053     if (clients_count > 2)
1054       status = SILC_STATUS_LIST_ITEM;
1055
1056     if (clients_count > 1 && i == clients_count - 1)
1057       status = SILC_STATUS_LIST_END;
1058
1059     /* Sanity check, however these should never fail. However, as
1060        this sanity check has been added here they have failed. */
1061     if (!entry->nickname || !entry->username)
1062       continue;
1063       
1064     /* Send WHOWAS reply */
1065     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1066     tmp = silc_argument_get_first_arg(cmd->args, NULL);
1067     
1068     memset(uh, 0, sizeof(uh));
1069     memset(nh, 0, sizeof(nh));
1070
1071     strncat(nh, entry->nickname, strlen(entry->nickname));
1072     if (!strchr(entry->nickname, '@')) {
1073       strncat(nh, "@", 1);
1074       len = entry->router ? strlen(entry->router->server_name) :
1075         strlen(server->server_name);
1076       strncat(nh, entry->router ? entry->router->server_name :
1077               server->server_name, len);
1078     }
1079       
1080     strncat(uh, entry->username, strlen(entry->username));
1081     if (!strchr(entry->username, '@')) {
1082       strncat(uh, "@", 1);
1083       strcat(uh, "*private*");
1084     }
1085       
1086     if (entry->userinfo)
1087       packet = 
1088         silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
1089                                              status, ident, 4, 
1090                                              2, idp->data, idp->len,
1091                                              3, nh, strlen(nh),
1092                                              4, uh, strlen(uh),
1093                                              5, entry->userinfo, 
1094                                              strlen(entry->userinfo));
1095     else
1096       packet = 
1097         silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
1098                                              status, ident, 3, 
1099                                              2, idp->data, idp->len,
1100                                              3, nh, strlen(nh),
1101                                              4, uh, strlen(uh));
1102
1103     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1104                             0, packet->data, packet->len, FALSE);
1105     
1106     silc_buffer_free(packet);
1107     silc_buffer_free(idp);
1108   }
1109
1110   if (found == FALSE && entry)
1111     silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
1112                                          SILC_STATUS_ERR_NO_SUCH_NICK,
1113                                          3, entry->nickname, 
1114                                          strlen(entry->nickname));
1115 }
1116
1117 static int
1118 silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
1119 {
1120   SilcServer server = cmd->server;
1121   char *nick = NULL, *server_name = NULL;
1122   int count = 0, clients_count = 0;
1123   SilcClientEntry *clients = NULL;
1124   int ret = 0;
1125
1126   /* Protocol dictates that we must always send the received WHOWAS request
1127      to our router if we are normal server, so let's do it now unless we
1128      are standalone. We will not send any replies to the client until we
1129      have received reply from the router. */
1130   if (server->server_type == SILC_SERVER && 
1131       !cmd->pending && !server->standalone) {
1132     SilcBuffer tmpbuf;
1133     unsigned short old_ident;
1134
1135     old_ident = silc_command_get_ident(cmd->payload);
1136     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
1137     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
1138
1139     /* Send WHOWAS command to our router */
1140     silc_server_packet_send(server, (SilcSocketConnection)
1141                             server->router->connection,
1142                             SILC_PACKET_COMMAND, cmd->packet->flags,
1143                             tmpbuf->data, tmpbuf->len, TRUE);
1144
1145     /* Reprocess this packet after received reply from router */
1146     silc_server_command_pending(server, SILC_COMMAND_WHOWAS, 
1147                                 silc_command_get_ident(cmd->payload),
1148                                 silc_server_command_destructor,
1149                                 silc_server_command_whowas,
1150                                 silc_server_command_dup(cmd));
1151     cmd->pending = TRUE;
1152
1153     silc_command_set_ident(cmd->payload, old_ident);
1154
1155     silc_buffer_free(tmpbuf);
1156     ret = -1;
1157     goto out;
1158   }
1159
1160   /* We are ready to process the command request. Let's search for the
1161      requested client and send reply to the requesting client. */
1162
1163   /* Parse the whowas request */
1164   if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
1165     return 0;
1166
1167   /* Get all clients matching that nickname from local list */
1168   clients = silc_idlist_get_clients_by_nickname(server->local_list, 
1169                                                 nick, server_name,
1170                                                 &clients_count);
1171   if (!clients)
1172     clients = silc_idlist_get_clients_by_hash(server->local_list, 
1173                                               nick, server->md5hash,
1174                                               &clients_count);
1175   
1176   /* Check global list as well */
1177   if (!clients) {
1178     clients = silc_idlist_get_clients_by_nickname(server->global_list, 
1179                                                   nick, server_name,
1180                                                   &clients_count);
1181     if (!clients)
1182       clients = silc_idlist_get_clients_by_hash(server->global_list, 
1183                                                 nick, server->md5hash,
1184                                                 &clients_count);
1185   }
1186   
1187   if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
1188     ret = -1;
1189     goto out;
1190   }
1191
1192   /* Send the command reply to the client */
1193   silc_server_command_whowas_send_reply(cmd, clients, clients_count);
1194
1195  out:
1196   if (clients)
1197     silc_free(clients);
1198   if (nick)
1199     silc_free(nick);
1200   if (server_name)
1201     silc_free(server_name);
1202
1203   return ret;
1204 }
1205
1206 static int
1207 silc_server_command_whowas_from_server(SilcServerCommandContext cmd)
1208 {
1209   SilcServer server = cmd->server;
1210   char *nick = NULL, *server_name = NULL;
1211   int count = 0, clients_count = 0;
1212   SilcClientEntry *clients = NULL;
1213   int ret = 0;
1214
1215   /* Parse the whowas request */
1216   if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
1217     return 0;
1218
1219   /* Process the command request. Let's search for the requested client and
1220      send reply to the requesting server. */
1221
1222   clients = silc_idlist_get_clients_by_nickname(server->local_list, 
1223                                                 nick, server_name,
1224                                                 &clients_count);
1225   if (!clients)
1226     clients = silc_idlist_get_clients_by_hash(server->local_list, 
1227                                               nick, server->md5hash,
1228                                               &clients_count);
1229   
1230   /* If we are router we will check our global list as well. */
1231   if (!clients && server->server_type == SILC_ROUTER) {
1232     clients = silc_idlist_get_clients_by_nickname(server->global_list, 
1233                                                   nick, server_name,
1234                                                   &clients_count);
1235     if (!clients)
1236       clients = silc_idlist_get_clients_by_hash(server->global_list, 
1237                                                 nick, server->md5hash,
1238                                                 &clients_count);
1239   }
1240
1241   if (!clients) {
1242     /* Such a client really does not exist in the SILC network. */
1243     silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
1244                                          SILC_STATUS_ERR_NO_SUCH_NICK,
1245                                          3, nick, strlen(nick));
1246     goto out;
1247   }
1248
1249   /* Send the command reply to the client */
1250   silc_server_command_whowas_send_reply(cmd, clients, clients_count);
1251
1252  out:
1253   if (clients)
1254     silc_free(clients);
1255   if (nick)
1256     silc_free(nick);
1257   if (server_name)
1258     silc_free(server_name);
1259
1260   return ret;
1261 }
1262
1263 /* Server side of command WHOWAS. */
1264
1265 SILC_SERVER_CMD_FUNC(whowas)
1266 {
1267   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1268   int ret = 0;
1269
1270   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOWAS, cmd, 1, 2);
1271
1272   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1273     ret = silc_server_command_whowas_from_client(cmd);
1274   else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) ||
1275            (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
1276     ret = silc_server_command_whowas_from_server(cmd);
1277
1278   if (!ret)
1279     silc_server_command_free(cmd);
1280 }
1281
1282 /******************************************************************************
1283
1284                               IDENTIFY Functions
1285
1286 ******************************************************************************/
1287
1288 /* Checks that all mandatory fields are present. If not then send WHOIS 
1289    request to the server who owns the client. We use WHOIS because we want
1290    to get as much information as possible at once. */
1291
1292 static char
1293 silc_server_command_identify_check(SilcServerCommandContext cmd,
1294                                    SilcClientEntry *clients,
1295                                    unsigned int clients_count)
1296 {
1297   SilcServer server = cmd->server;
1298   int i;
1299   SilcClientEntry entry;
1300
1301   for (i = 0; i < clients_count; i++) {
1302     entry = clients[i];
1303
1304     if (entry->data.registered == FALSE)
1305       continue;
1306
1307     if (!entry->nickname) {
1308       SilcBuffer tmpbuf;
1309       unsigned short old_ident;
1310       
1311       if (!entry->router)
1312         continue;
1313       
1314       old_ident = silc_command_get_ident(cmd->payload);
1315       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
1316       silc_command_set_command(cmd->payload, SILC_COMMAND_WHOIS);
1317       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
1318       
1319       /* Send WHOIS request. We send WHOIS since we're doing the requesting
1320          now anyway so make it a good one. */
1321       silc_server_packet_send(server, entry->router->connection,
1322                               SILC_PACKET_COMMAND, cmd->packet->flags,
1323                               tmpbuf->data, tmpbuf->len, TRUE);
1324       
1325       /* Reprocess this packet after received reply */
1326       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
1327                                   silc_command_get_ident(cmd->payload),
1328                                   silc_server_command_destructor,
1329                                   silc_server_command_identify,
1330                                   silc_server_command_dup(cmd));
1331
1332       cmd->pending = TRUE;
1333       
1334       /* Put old data back to the Command Payload we just changed */
1335       silc_command_set_ident(cmd->payload, old_ident);
1336       silc_command_set_command(cmd->payload, SILC_COMMAND_IDENTIFY);
1337
1338       silc_buffer_free(tmpbuf);
1339       return FALSE;
1340     }
1341   }
1342
1343   return TRUE;
1344 }
1345
1346 static void
1347 silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
1348                                         SilcClientEntry *clients,
1349                                         unsigned int clients_count,
1350                                         int count)
1351 {
1352   SilcServer server = cmd->server;
1353   char *tmp;
1354   int i, k, len;
1355   SilcBuffer packet, idp;
1356   SilcClientEntry entry;
1357   SilcCommandStatus status;
1358   unsigned short ident = silc_command_get_ident(cmd->payload);
1359   char nh[256], uh[256];
1360   SilcSocketConnection hsock;
1361
1362   len = 0;
1363   for (i = 0; i < clients_count; i++)
1364     if (clients[i]->data.registered)
1365       len++;
1366
1367   status = SILC_STATUS_OK;
1368   if (len > 1)
1369     status = SILC_STATUS_LIST_START;
1370
1371   for (i = 0, k = 0; i < clients_count; i++) {
1372     entry = clients[i];
1373
1374     if (entry->data.registered == FALSE) {
1375       if (clients_count == 1) {
1376         SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1377         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1378                                              SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
1379                                              2, idp->data, idp->len);
1380         silc_buffer_free(idp);
1381       }
1382       continue;
1383     }
1384
1385     if (k >= 1)
1386       status = SILC_STATUS_LIST_ITEM;
1387
1388     if (clients_count > 1 && k == clients_count - 1)
1389       status = SILC_STATUS_LIST_END;
1390
1391     if (count && k - 1 == count)
1392       status = SILC_STATUS_LIST_END;
1393
1394     if (count && k - 1 > count)
1395       break;
1396
1397     /* Send IDENTIFY reply */
1398     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1399     tmp = silc_argument_get_first_arg(cmd->args, NULL);
1400     
1401     memset(uh, 0, sizeof(uh));
1402     memset(nh, 0, sizeof(nh));
1403       
1404     strncat(nh, entry->nickname, strlen(entry->nickname));
1405     if (!strchr(entry->nickname, '@')) {
1406       strncat(nh, "@", 1);
1407       len = entry->router ? strlen(entry->router->server_name) :
1408         strlen(server->server_name);
1409       strncat(nh, entry->router ? entry->router->server_name :
1410               server->server_name, len);
1411     }
1412       
1413     if (!entry->username) {
1414       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
1415                                                     status, ident, 2,
1416                                                     2, idp->data, idp->len, 
1417                                                     3, nh, strlen(nh));
1418     } else {
1419       strncat(uh, entry->username, strlen(entry->username));
1420       if (!strchr(entry->username, '@')) {
1421         strncat(uh, "@", 1);
1422         hsock = (SilcSocketConnection)entry->connection;
1423         len = strlen(hsock->hostname);
1424         strncat(uh, hsock->hostname, len);
1425       }
1426       
1427       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
1428                                                     status, ident, 3,
1429                                                     2, idp->data, idp->len, 
1430                                                     3, nh, strlen(nh),
1431                                                     4, uh, strlen(uh));
1432     }
1433       
1434     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1435                             0, packet->data, packet->len, FALSE);
1436     
1437     silc_buffer_free(packet);
1438     silc_buffer_free(idp);
1439
1440     k++;
1441   }
1442 }
1443
1444 static int
1445 silc_server_command_identify_from_client(SilcServerCommandContext cmd)
1446 {
1447   SilcServer server = cmd->server;
1448   char *nick = NULL, *server_name = NULL;
1449   int count = 0, clients_count = 0; 
1450   SilcClientEntry *clients = NULL, entry;
1451   SilcClientID **client_id = NULL;
1452   unsigned int client_id_count = 0;
1453   int i, ret = 0;
1454
1455   /* Protocol dictates that we must always send the received IDENTIFY request
1456      to our router if we are normal server, so let's do it now unless we
1457      are standalone. We will not send any replies to the client until we
1458      have received reply from the router. */
1459   if (server->server_type == SILC_SERVER && 
1460       !cmd->pending && !server->standalone) {
1461     SilcBuffer tmpbuf;
1462     unsigned short old_ident;
1463
1464     old_ident = silc_command_get_ident(cmd->payload);
1465     silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
1466     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
1467
1468     /* Send IDENTIFY command to our router */
1469     silc_server_packet_send(server, (SilcSocketConnection)
1470                             server->router->connection,
1471                             SILC_PACKET_COMMAND, cmd->packet->flags,
1472                             tmpbuf->data, tmpbuf->len, TRUE);
1473
1474     /* Reprocess this packet after received reply from router */
1475     silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, 
1476                                 silc_command_get_ident(cmd->payload),
1477                                 silc_server_command_destructor,
1478                                 silc_server_command_identify,
1479                                 silc_server_command_dup(cmd));
1480     cmd->pending = TRUE;
1481
1482     silc_command_set_ident(cmd->payload, old_ident);
1483
1484     silc_buffer_free(tmpbuf);
1485     ret = -1;
1486     goto out;
1487   }
1488
1489   /* We are ready to process the command request. Let's search for the
1490      requested client and send reply to the requesting client. */
1491
1492   /* Parse the IDENTIFY request */
1493   if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
1494                                        &nick, &server_name, &count,
1495                                        SILC_COMMAND_IDENTIFY))
1496     return 0;
1497
1498   /* Get all clients matching that ID or nickname from local list */
1499   if (client_id_count) { 
1500     /* Check all Client ID's received in the command packet */
1501     for (i = 0; i < client_id_count; i++) {
1502       entry = silc_idlist_find_client_by_id(server->local_list, 
1503                                             client_id[i], NULL);
1504       if (entry) {
1505         clients = silc_realloc(clients, sizeof(*clients) * 
1506                                (clients_count + 1));
1507         clients[clients_count++] = entry;
1508       }
1509     }
1510   } else {
1511     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
1512                                                   nick, server_name,
1513                                                   &clients_count);
1514     if (!clients)
1515       clients = silc_idlist_get_clients_by_hash(server->local_list, 
1516                                                 nick, server->md5hash,
1517                                                 &clients_count);
1518   }
1519   
1520   /* Check global list as well */
1521   if (!clients) {
1522     if (client_id_count) {
1523       /* Check all Client ID's received in the command packet */
1524       for (i = 0; i < client_id_count; i++) {
1525         entry = silc_idlist_find_client_by_id(server->global_list, 
1526                                               client_id[i], NULL);
1527         if (entry) {
1528           clients = silc_realloc(clients, sizeof(*clients) * 
1529                                  (clients_count + 1));
1530           clients[clients_count++] = entry;
1531         }
1532       }
1533     } else {
1534       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
1535                                                     nick, server_name,
1536                                                     &clients_count);
1537       if (!clients)
1538         clients = silc_idlist_get_clients_by_hash(server->global_list, 
1539                                                   nick, server->md5hash,
1540                                                   &clients_count);
1541     }
1542   }
1543   
1544   if (!clients) {
1545     /* Such a client really does not exist in the SILC network. */
1546     if (!client_id_count) {
1547       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1548                                            SILC_STATUS_ERR_NO_SUCH_NICK,
1549                                            3, nick, strlen(nick));
1550     } else {
1551       SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
1552       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1553                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
1554                                            2, idp->data, idp->len);
1555       silc_buffer_free(idp);
1556     }
1557     goto out;
1558   }
1559
1560   /* Check that all mandatory fields are present and request those data
1561      from the server who owns the client if necessary. */
1562   if (!silc_server_command_identify_check(cmd, clients, clients_count)) {
1563     ret = -1;
1564     goto out;
1565   }
1566
1567   /* Send the command reply to the client */
1568   silc_server_command_identify_send_reply(cmd, clients, clients_count,
1569                                           count);
1570
1571  out:
1572   if (client_id_count) {
1573     for (i = 0; i < client_id_count; i++)
1574       silc_free(client_id[i]);
1575     silc_free(client_id);
1576   }
1577   if (clients)
1578     silc_free(clients);
1579   if (nick)
1580     silc_free(nick);
1581   if (server_name)
1582     silc_free(server_name);
1583
1584   return ret;
1585 }
1586
1587 static int
1588 silc_server_command_identify_from_server(SilcServerCommandContext cmd)
1589 {
1590   SilcServer server = cmd->server;
1591   char *nick = NULL, *server_name = NULL;
1592   int count = 0, clients_count = 0;
1593   SilcClientEntry *clients = NULL, entry;
1594   SilcClientID **client_id = NULL;
1595   unsigned int client_id_count = 0;
1596   int i, ret = 0;
1597
1598   /* Parse the IDENTIFY request */
1599   if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
1600                                        &nick, &server_name, &count,
1601                                        SILC_COMMAND_IDENTIFY))
1602     return 0;
1603
1604   /* Process the command request. Let's search for the requested client and
1605      send reply to the requesting server. */
1606
1607   if (client_id_count) {
1608     /* Check all Client ID's received in the command packet */
1609     for (i = 0; i < client_id_count; i++) {
1610       entry = silc_idlist_find_client_by_id(server->local_list, 
1611                                             client_id[i], NULL);
1612       if (entry) {
1613         clients = silc_realloc(clients, sizeof(*clients) * 
1614                                (clients_count + 1));
1615         clients[clients_count++] = entry;
1616       }
1617     }
1618   } else {
1619     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
1620                                                   nick, server_name,
1621                                                   &clients_count);
1622     if (!clients)
1623       clients = silc_idlist_get_clients_by_hash(server->local_list, 
1624                                                 nick, server->md5hash,
1625                                                 &clients_count);
1626   }
1627   
1628   /* If we are router we will check our global list as well. */
1629   if (!clients && server->server_type == SILC_ROUTER) {
1630     if (client_id_count) {
1631       /* Check all Client ID's received in the command packet */
1632       for (i = 0; i < client_id_count; i++) {
1633         entry = silc_idlist_find_client_by_id(server->global_list, 
1634                                               client_id[i], NULL);
1635         if (entry) {
1636           clients = silc_realloc(clients, sizeof(*clients) * 
1637                                  (clients_count + 1));
1638           clients[clients_count++] = entry;
1639         }
1640       }
1641     } else {
1642       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
1643                                                     nick, server_name,
1644                                                     &clients_count);
1645       if (!clients)
1646         clients = silc_idlist_get_clients_by_hash(server->global_list, 
1647                                                   nick, server->md5hash,
1648                                                   &clients_count);
1649     }
1650   }
1651
1652   if (!clients) {
1653     /* Such a client really does not exist in the SILC network. */
1654     if (!client_id_count) {
1655       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1656                                            SILC_STATUS_ERR_NO_SUCH_NICK,
1657                                            3, nick, strlen(nick));
1658     } else {
1659       SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
1660       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1661                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
1662                                            2, idp->data, idp->len);
1663       silc_buffer_free(idp);
1664     }
1665     goto out;
1666   }
1667
1668   /* Check that all mandatory fields are present and request those data
1669      from the server who owns the client if necessary. */
1670   if (!silc_server_command_identify_check(cmd, clients, clients_count)) {
1671     ret = -1;
1672     goto out;
1673   }
1674
1675   /* Send the command reply */
1676   silc_server_command_identify_send_reply(cmd, clients, clients_count, count);
1677
1678  out:
1679   if (client_id_count) {
1680     for (i = 0; i < client_id_count; i++)
1681       silc_free(client_id[i]);
1682     silc_free(client_id);
1683   }
1684   if (clients)
1685     silc_free(clients);
1686   if (nick)
1687     silc_free(nick);
1688   if (server_name)
1689     silc_free(server_name);
1690
1691   return ret;
1692 }
1693
1694 SILC_SERVER_CMD_FUNC(identify)
1695 {
1696   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1697   int ret = 0;
1698
1699   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
1700
1701   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1702     ret = silc_server_command_identify_from_client(cmd);
1703   else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) |
1704            (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
1705     ret = silc_server_command_identify_from_server(cmd);
1706
1707   if (!ret)
1708     silc_server_command_free(cmd);
1709 }
1710
1711 /* Checks string for bad characters and returns TRUE if they are found. */
1712
1713 static int silc_server_command_bad_chars(char *nick)
1714 {
1715   if (strchr(nick, '\\')) return TRUE;
1716   if (strchr(nick, '\"')) return TRUE;
1717   if (strchr(nick, '´')) return TRUE;
1718   if (strchr(nick, '`')) return TRUE;
1719   if (strchr(nick, '\'')) return TRUE;
1720   if (strchr(nick, '*')) return TRUE;
1721   if (strchr(nick, '/')) return TRUE;
1722   if (strchr(nick, '@')) return TRUE;
1723
1724   return FALSE;
1725 }
1726
1727 /* Server side of command NICK. Sets nickname for user. Setting
1728    nickname causes generation of a new client ID for the client. The
1729    new client ID is sent to the client after changing the nickname. */
1730
1731 SILC_SERVER_CMD_FUNC(nick)
1732 {
1733   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1734   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1735   SilcServer server = cmd->server;
1736   SilcBuffer packet, nidp, oidp;
1737   SilcClientID *new_id;
1738   char *nick;
1739   unsigned short ident = silc_command_get_ident(cmd->payload);
1740
1741   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
1742     goto out;
1743
1744   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NICK, cmd, 1, 1);
1745
1746   /* Check nickname */
1747   nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
1748   if (silc_server_command_bad_chars(nick) == TRUE) {
1749     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
1750                                           SILC_STATUS_ERR_BAD_NICKNAME);
1751     goto out;
1752   }
1753
1754   if (strlen(nick) > 128)
1755     nick[127] = '\0';
1756
1757   /* Create new Client ID */
1758   silc_id_create_client_id(cmd->server->id, cmd->server->rng, 
1759                            cmd->server->md5hash, nick,
1760                            &new_id);
1761
1762   /* Send notify about nickname change to our router. We send the new
1763      ID and ask to replace it with the old one. If we are router the
1764      packet is broadcasted. Send NICK_CHANGE notify. */
1765   if (!server->standalone)
1766     silc_server_send_notify_nick_change(server, server->router->connection, 
1767                                         server->server_type == SILC_SERVER ? 
1768                                         FALSE : TRUE, client->id,
1769                                         new_id, SILC_ID_CLIENT_LEN);
1770
1771   /* Remove old cache entry */
1772   silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
1773                          client->id); 
1774
1775   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1776
1777   /* Free old ID */
1778   if (client->id) {
1779     memset(client->id, 0, SILC_ID_CLIENT_LEN);
1780     silc_free(client->id);
1781   }
1782
1783   /* Save the nickname as this client is our local client */
1784   if (client->nickname)
1785     silc_free(client->nickname);
1786
1787   client->nickname = strdup(nick);
1788   client->id = new_id;
1789
1790   /* Update client cache */
1791   silc_idcache_add(server->local_list->clients, client->nickname, 
1792                    strlen(client->nickname), SILC_ID_CLIENT, client->id, 
1793                    (void *)client, TRUE, FALSE);
1794
1795   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1796
1797   /* Send NICK_CHANGE notify to the client's channels */
1798   silc_server_send_notify_on_channels(server, NULL, client, 
1799                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
1800                                       oidp->data, oidp->len, 
1801                                       nidp->data, nidp->len);
1802
1803   /* Send the new Client ID as reply command back to client */
1804   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
1805                                                 SILC_STATUS_OK, ident, 1, 
1806                                                 2, nidp->data, nidp->len);
1807   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1808                           0, packet->data, packet->len, FALSE);
1809
1810   silc_buffer_free(packet);
1811   silc_buffer_free(nidp);
1812   silc_buffer_free(oidp);
1813   
1814  out:
1815   silc_server_command_free(cmd);
1816 }
1817
1818 /* Sends the LIST command reply */
1819
1820 static void
1821 silc_server_command_list_send_reply(SilcServerCommandContext cmd,
1822                                     SilcChannelEntry *lch, 
1823                                     unsigned int lch_count,
1824                                     SilcChannelEntry *gch,
1825                                     unsigned int gch_count)
1826 {
1827   int i;
1828   SilcBuffer packet, idp;
1829   SilcChannelEntry entry;
1830   SilcCommandStatus status;
1831   unsigned short ident = silc_command_get_ident(cmd->payload);
1832   char *topic;
1833   unsigned char usercount[4];
1834   unsigned int users;
1835
1836   for (i = 0; i < lch_count; i++)
1837     if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
1838       lch[i] = NULL;
1839   for (i = 0; i < gch_count; i++)
1840     if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
1841       gch[i] = NULL;
1842
1843   status = SILC_STATUS_OK;
1844   if ((lch_count + gch_count) > 1)
1845     status = SILC_STATUS_LIST_START;
1846
1847   /* Local list */
1848   for (i = 0; i < lch_count; i++) {
1849     entry = lch[i];
1850
1851     if (!entry)
1852       continue;
1853
1854     if (i >= 1)
1855       status = SILC_STATUS_LIST_ITEM;
1856
1857     if (i == lch_count - 1 && gch_count)
1858       break;
1859     if (lch_count > 1 && i == lch_count - 1)
1860       status = SILC_STATUS_LIST_END;
1861
1862     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1863
1864     if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
1865       topic = "*private*";
1866       memset(usercount, 0, sizeof(usercount));
1867     } else {
1868       topic = entry->topic;
1869       users = silc_list_count(entry->user_list);
1870       SILC_PUT32_MSB(users, usercount);
1871     }
1872
1873     /* Send the reply */
1874     if (topic)
1875       packet = 
1876         silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
1877                                              status, ident, 4, 
1878                                              2, idp->data, idp->len,
1879                                              3, entry->channel_name, 
1880                                              strlen(entry->channel_name),
1881                                              4, topic, strlen(topic),
1882                                              5, usercount, 4);
1883     else
1884       packet = 
1885         silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
1886                                              status, ident, 3, 
1887                                              2, idp->data, idp->len,
1888                                              3, entry->channel_name, 
1889                                              strlen(entry->channel_name),
1890                                              5, usercount, 4);
1891     silc_server_packet_send(cmd->server, cmd->sock, 
1892                             SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
1893                             packet->len, FALSE);
1894     silc_buffer_free(packet);
1895     silc_buffer_free(idp);
1896   }
1897
1898   status = i ? SILC_STATUS_LIST_ITEM : SILC_STATUS_OK;
1899
1900   /* Global list */
1901   for (i = 0; i < gch_count; i++) {
1902     entry = gch[i];
1903
1904     if (!entry)
1905       continue;
1906
1907     if (i >= 1)
1908       status = SILC_STATUS_LIST_ITEM;
1909
1910     if (gch_count > 1 && i == lch_count - 1)
1911       status = SILC_STATUS_LIST_END;
1912
1913     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1914
1915     if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
1916       topic = "*private*";
1917       memset(usercount, 0, sizeof(usercount));
1918     } else {
1919       topic = entry->topic;
1920       users = silc_list_count(entry->user_list);
1921       SILC_PUT32_MSB(users, usercount);
1922     }
1923
1924     /* Send the reply */
1925     if (topic)
1926       packet = 
1927         silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
1928                                              status, ident, 4, 
1929                                              2, idp->data, idp->len,
1930                                              3, entry->channel_name, 
1931                                              strlen(entry->channel_name),
1932                                              4, topic, strlen(topic),
1933                                              5, usercount, 4);
1934     else
1935       packet = 
1936         silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
1937                                              status, ident, 3, 
1938                                              2, idp->data, idp->len,
1939                                              3, entry->channel_name, 
1940                                              strlen(entry->channel_name),
1941                                              5, usercount, 4);
1942     silc_server_packet_send(cmd->server, cmd->sock, 
1943                             SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
1944                             packet->len, FALSE);
1945     silc_buffer_free(packet);
1946     silc_buffer_free(idp);
1947   }
1948 }
1949
1950 /* Server side of LIST command. This lists the channel of the requested
1951    server. Secret channels are not listed. */
1952
1953 SILC_SERVER_CMD_FUNC(list)
1954 {
1955   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1956   SilcServer server = cmd->server;
1957   SilcChannelID *channel_id = NULL;
1958   unsigned char *tmp;
1959   unsigned int tmp_len;
1960   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
1961   unsigned int lch_count = 0, gch_count = 0;
1962
1963   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LIST, cmd, 0, 2);
1964
1965   /* Get Channel ID */
1966   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1967   if (tmp) {
1968     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1969     if (!channel_id) {
1970       silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
1971                                             SILC_STATUS_ERR_NO_CHANNEL_ID);
1972       goto out;
1973     }
1974   }
1975
1976   /* Get the channels from local list */
1977   lchannels = silc_idlist_get_channels(server->local_list, channel_id,
1978                                        &lch_count);
1979   
1980   /* Get the channels from global list if we are router */
1981   if (server->server_type == SILC_ROUTER) 
1982     gchannels = silc_idlist_get_channels(server->global_list, channel_id,
1983                                          &gch_count);
1984
1985   /* Send the reply */
1986   silc_server_command_list_send_reply(cmd, lchannels, lch_count, 
1987                                       gchannels, gch_count);
1988
1989  out:
1990   silc_server_command_free(cmd);
1991 }
1992
1993 /* Server side of TOPIC command. Sets topic for channel and/or returns
1994    current topic to client. */
1995
1996 SILC_SERVER_CMD_FUNC(topic)
1997 {
1998   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1999   SilcServer server = cmd->server;
2000   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2001   SilcChannelID *channel_id;
2002   SilcChannelEntry channel;
2003   SilcChannelClientEntry chl;
2004   SilcBuffer packet, idp;
2005   unsigned char *tmp;
2006   unsigned int argc, tmp_len;
2007   unsigned short ident = silc_command_get_ident(cmd->payload);
2008
2009   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
2010
2011   argc = silc_argument_get_arg_num(cmd->args);
2012
2013   /* Get Channel ID */
2014   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2015   if (!tmp) {
2016     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2017                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2018     goto out;
2019   }
2020   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
2021   if (!channel_id) {
2022     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2023                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2024     goto out;
2025   }
2026
2027   /* Check whether the channel exists */
2028   channel = silc_idlist_find_channel_by_id(server->local_list, 
2029                                            channel_id, NULL);
2030   if (!channel) {
2031     channel = silc_idlist_find_channel_by_id(server->global_list, 
2032                                              channel_id, NULL);
2033     if (!channel) {
2034       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2035                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2036       goto out;
2037     }
2038   }
2039
2040   if (argc > 1) {
2041     /* Get the topic */
2042     tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
2043     if (!tmp) {
2044       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2045                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2046       goto out;
2047     }
2048
2049     if (strlen(tmp) > 256) {
2050       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2051                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2052       goto out;
2053     }
2054
2055     /* See whether has rights to change topic */
2056     silc_list_start(channel->user_list);
2057     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2058       if (chl->client == client)
2059         break;
2060
2061     if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
2062       if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
2063         silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
2064                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2065         goto out;
2066       }
2067     }
2068
2069     /* Set the topic for channel */
2070     if (channel->topic)
2071       silc_free(channel->topic);
2072     channel->topic = strdup(tmp);
2073
2074     /* Send TOPIC_SET notify type to the network */
2075     if (!server->standalone)
2076       silc_server_send_notify_topic_set(server, server->router->connection,
2077                                         server->server_type == SILC_ROUTER ?
2078                                         TRUE : FALSE, channel, client->id,
2079                                         SILC_ID_CLIENT_LEN, channel->topic);
2080
2081     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2082
2083     /* Send notify about topic change to all clients on the channel */
2084     silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
2085                                        SILC_NOTIFY_TYPE_TOPIC_SET, 2,
2086                                        idp->data, idp->len,
2087                                        channel->topic, strlen(channel->topic));
2088     silc_buffer_free(idp);
2089   }
2090
2091   /* Send the topic to client as reply packet */
2092   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
2093   if (channel->topic)
2094     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
2095                                                   SILC_STATUS_OK, ident, 2, 
2096                                                   2, idp->data, idp->len,
2097                                                   3, channel->topic, 
2098                                                   strlen(channel->topic));
2099   else
2100     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
2101                                                   SILC_STATUS_OK, ident, 1, 
2102                                                   2, idp->data, idp->len);
2103   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
2104                           0, packet->data, packet->len, FALSE);
2105
2106   silc_buffer_free(packet);
2107   silc_buffer_free(idp);
2108   silc_free(channel_id);
2109
2110  out:
2111   silc_server_command_free(cmd);
2112 }
2113
2114 /* Server side of INVITE command. Invites some client to join some channel. 
2115    This command is also used to manage the invite list of the channel. */
2116
2117 SILC_SERVER_CMD_FUNC(invite)
2118 {
2119   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2120   SilcServer server = cmd->server;
2121   SilcSocketConnection sock = cmd->sock, dest_sock;
2122   SilcChannelClientEntry chl;
2123   SilcClientEntry sender, dest;
2124   SilcClientID *dest_id = NULL;
2125   SilcChannelEntry channel;
2126   SilcChannelID *channel_id = NULL;
2127   SilcIDListData idata;
2128   SilcBuffer idp, idp2, packet;
2129   unsigned char *tmp, *add, *del;
2130   unsigned int len;
2131   unsigned short ident = silc_command_get_ident(cmd->payload);
2132
2133   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 4);
2134
2135   /* Get Channel ID */
2136   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2137   if (!tmp) {
2138     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2139                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2140     goto out;
2141   }
2142   channel_id = silc_id_payload_parse_id(tmp, len);
2143   if (!channel_id) {
2144     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2145                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
2146     goto out;
2147   }
2148
2149   /* Get the channel entry */
2150   channel = silc_idlist_find_channel_by_id(server->local_list, 
2151                                            channel_id, NULL);
2152   if (!channel) {
2153     channel = silc_idlist_find_channel_by_id(server->global_list, 
2154                                              channel_id, NULL);
2155     if (!channel) {
2156       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2157                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2158       goto out;
2159     }
2160   }
2161
2162   /* Check whether the sender of this command is on the channel. */
2163   sender = (SilcClientEntry)sock->user_data;
2164   if (!silc_server_client_on_channel(sender, channel)) {
2165     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2166                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
2167     goto out;
2168   }
2169
2170   /* Check whether the channel is invite-only channel. If yes then the
2171      sender of this command must be at least channel operator. */
2172   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
2173     silc_list_start(channel->user_list);
2174     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2175       if (chl->client == sender) {
2176         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
2177           silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2178                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2179           goto out;
2180         }
2181         break;
2182       }
2183   }
2184
2185   /* Get destination client ID */
2186   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2187   if (tmp) {
2188     char invite[512];
2189
2190     dest_id = silc_id_payload_parse_id(tmp, len);
2191     if (!dest_id) {
2192       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2193                                             SILC_STATUS_ERR_NO_CLIENT_ID);
2194       goto out;
2195     }
2196
2197     /* Get the client entry */
2198     dest = silc_server_get_client_resolve(server, dest_id);
2199     if (!dest) {
2200       if (server->server_type == SILC_ROUTER) {
2201         silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2202                                      SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
2203         goto out;
2204       }
2205       
2206       /* The client info is being resolved. Reprocess this packet after
2207          receiving the reply to the query. */
2208       silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
2209                                   server->cmd_ident,
2210                                   silc_server_command_destructor,
2211                                   silc_server_command_invite, 
2212                                   silc_server_command_dup(cmd));
2213       cmd->pending = TRUE;
2214       silc_free(channel_id);
2215       silc_free(dest_id);
2216       return;
2217     }
2218
2219     /* Check whether the requested client is already on the channel. */
2220     if (silc_server_client_on_channel(dest, channel)) {
2221       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2222                                             SILC_STATUS_ERR_USER_ON_CHANNEL);
2223       goto out;
2224     }
2225     
2226     /* Get route to the client */
2227     dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, &idata);
2228
2229     memset(invite, 0, sizeof(invite));
2230     strncat(invite, dest->nickname, strlen(dest->nickname));
2231     strncat(invite, "!", 1);
2232     strncat(invite, dest->username, strlen(dest->username));
2233     if (!strchr(dest->username, '@')) {
2234       strncat(invite, "@", 1);
2235       strncat(invite, cmd->sock->hostname, strlen(cmd->sock->hostname));
2236     }
2237
2238     len = strlen(invite);
2239     if (!channel->invite_list)
2240       channel->invite_list = silc_calloc(len + 2, 
2241                                          sizeof(*channel->invite_list));
2242     else
2243       channel->invite_list = silc_realloc(channel->invite_list, 
2244                                           sizeof(*channel->invite_list) * 
2245                                           (len + 
2246                                            strlen(channel->invite_list) + 2));
2247     strncat(channel->invite_list, invite, len);
2248     strncat(channel->invite_list, ",", 1);
2249
2250     /* Send notify to the client that is invited to the channel */
2251     idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
2252     idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
2253     silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, 
2254                                  SILC_ID_CLIENT,
2255                                  SILC_NOTIFY_TYPE_INVITE, 3, 
2256                                  idp->data, idp->len, 
2257                                  channel->channel_name, 
2258                                  strlen(channel->channel_name),
2259                                  idp2->data, idp2->len);
2260     silc_buffer_free(idp);
2261     silc_buffer_free(idp2);
2262   }
2263
2264   /* Add the client to the invite list of the channel */
2265   add = silc_argument_get_arg_type(cmd->args, 3, &len);
2266   if (add) {
2267     if (!channel->invite_list)
2268       channel->invite_list = silc_calloc(len + 2, 
2269                                          sizeof(*channel->invite_list));
2270     else
2271       channel->invite_list = silc_realloc(channel->invite_list, 
2272                                           sizeof(*channel->invite_list) * 
2273                                           (len + 
2274                                            strlen(channel->invite_list) + 2));
2275     if (add[len - 1] == ',')
2276       add[len - 1] = '\0';
2277     
2278     strncat(channel->invite_list, add, len);
2279     strncat(channel->invite_list, ",", 1);
2280   }
2281
2282   /* Get the invite to be removed and remove it from the list */
2283   del = silc_argument_get_arg_type(cmd->args, 4, &len);
2284   if (del && channel->invite_list) {
2285     char *start, *end, *n;
2286
2287     if (!strncmp(channel->invite_list, del, 
2288                  strlen(channel->invite_list) - 1)) {
2289       silc_free(channel->invite_list);
2290       channel->invite_list = NULL;
2291     } else {
2292       start = strstr(channel->invite_list, del);
2293       if (start && strlen(start) >= len) {
2294         end = start + len;
2295         n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n));
2296         strncat(n, channel->invite_list, start - channel->invite_list);
2297         strncat(n, end + 1, ((channel->invite_list + 
2298                               strlen(channel->invite_list)) - end) - 1);
2299         silc_free(channel->invite_list);
2300         channel->invite_list = n;
2301       }
2302     }
2303   }
2304
2305   /* Send notify to the primary router */
2306   if (!server->standalone)
2307     silc_server_send_notify_invite(server, server->router->connection,
2308                                    server->server_type == SILC_ROUTER ?
2309                                    TRUE : FALSE, channel,
2310                                    sender->id, SILC_ID_CLIENT_LEN,
2311                                    add, del);
2312
2313   /* Send command reply */
2314   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2315   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
2316                                                 SILC_STATUS_OK, ident, 2,
2317                                                 2, tmp, len,
2318                                                 3, channel->invite_list,
2319                                                 channel->invite_list ?
2320                                                 strlen(channel->invite_list) :
2321                                                 0);
2322   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2323                           packet->data, packet->len, FALSE);
2324   silc_buffer_free(packet);
2325
2326  out:
2327   if (dest_id)
2328     silc_free(dest_id);
2329   if (channel_id)
2330     silc_free(channel_id);
2331   silc_server_command_free(cmd);
2332 }
2333
2334 typedef struct {
2335   SilcServer server;
2336   SilcSocketConnection sock;
2337   char *signoff;
2338 } *QuitInternal;
2339
2340 /* Quits connection to client. This gets called if client won't
2341    close the connection even when it has issued QUIT command. */
2342
2343 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
2344 {
2345   QuitInternal q = (QuitInternal)context;
2346
2347   /* Free all client specific data, such as client entry and entires
2348      on channels this client may be on. */
2349   silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
2350                                TRUE, q->signoff);
2351   q->sock->user_data = NULL;
2352
2353   /* Close the connection on our side */
2354   silc_server_close_connection(q->server, q->sock);
2355
2356   silc_free(q->signoff);
2357   silc_free(q);
2358 }
2359
2360 /* Quits SILC session. This is the normal way to disconnect client. */
2361  
2362 SILC_SERVER_CMD_FUNC(quit)
2363 {
2364   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2365   SilcServer server = cmd->server;
2366   SilcSocketConnection sock = cmd->sock;
2367   QuitInternal q;
2368   unsigned char *tmp = NULL;
2369   unsigned int len = 0;
2370
2371   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_QUIT, cmd, 0, 1);
2372
2373   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
2374     goto out;
2375
2376   /* Get destination ID */
2377   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2378   if (len > 128)
2379     tmp = NULL;
2380
2381   q = silc_calloc(1, sizeof(*q));
2382   q->server = server;
2383   q->sock = sock;
2384   q->signoff = tmp ? strdup(tmp) : NULL;
2385
2386   /* We quit the connection with little timeout */
2387   silc_task_register(server->timeout_queue, sock->sock,
2388                      silc_server_command_quit_cb, (void *)q,
2389                      0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
2390
2391  out:
2392   silc_server_command_free(cmd);
2393 }
2394
2395 /* Server side of command KILL. This command is used by router operator
2396    to remove an client from the SILC Network temporarily. */
2397
2398 SILC_SERVER_CMD_FUNC(kill)
2399 {
2400   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2401   SilcServer server = cmd->server;
2402   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2403   SilcClientEntry remote_client;
2404   SilcClientID *client_id;
2405   unsigned char *tmp, *comment;
2406   unsigned int tmp_len, tmp_len2;
2407
2408   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_KILL, cmd, 1, 2);
2409
2410   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
2411     goto out;
2412
2413   /* KILL command works only on router */
2414   if (server->server_type != SILC_ROUTER) {
2415     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2416                                           SILC_STATUS_ERR_NO_ROUTER_PRIV);
2417     goto out;
2418   }
2419
2420   /* Check whether client has the permissions. */
2421   if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
2422     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2423                                           SILC_STATUS_ERR_NO_ROUTER_PRIV);
2424     goto out;
2425   }
2426
2427   /* Get the client ID */
2428   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2429   if (!tmp) {
2430     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2431                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2432     goto out;
2433   }
2434   client_id = silc_id_payload_parse_id(tmp, tmp_len);
2435   if (!client_id) {
2436     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2437                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
2438     goto out;
2439   }
2440
2441   /* Get the client entry */
2442   remote_client = silc_idlist_find_client_by_id(server->local_list, 
2443                                                 client_id, NULL);
2444   if (!remote_client) {
2445     remote_client = silc_idlist_find_client_by_id(server->global_list, 
2446                                                   client_id, NULL);
2447     if (!remote_client) {
2448       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2449                                             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
2450       goto out;
2451     }
2452   }
2453
2454   /* Get comment */
2455   comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
2456   if (tmp_len2 > 128)
2457     comment = NULL;
2458
2459   /* Send reply to the sender */
2460   silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
2461                                         SILC_STATUS_OK);
2462
2463   /* Send the KILL notify packets. First send it to the channel, then
2464      to our primary router and then directly to the client who is being
2465      killed right now. */
2466
2467   /* Send KILLED notify to the channels. It is not sent to the client
2468      as it will be sent differently destined directly to the client and not
2469      to the channel. */
2470   silc_server_send_notify_on_channels(server, remote_client, 
2471                                       remote_client, SILC_NOTIFY_TYPE_KILLED,
2472                                       comment ? 2 : 1,
2473                                       tmp, tmp_len,
2474                                       comment, comment ? tmp_len2 : 0);
2475
2476   /* Send KILLED notify to primary route */
2477   if (!server->standalone)
2478     silc_server_send_notify_killed(server, server->router->connection, TRUE,
2479                                    remote_client->id, SILC_ID_CLIENT_LEN,
2480                                    comment);
2481
2482   /* Send KILLED notify to the client directly */
2483   silc_server_send_notify_killed(server, remote_client->connection ? 
2484                                  remote_client->connection : 
2485                                  remote_client->router->connection, FALSE,
2486                                  remote_client->id, SILC_ID_CLIENT_LEN,
2487                                  comment);
2488
2489   /* Remove the client from all channels. This generates new keys to the
2490      channels as well. */
2491   silc_server_remove_from_channels(server, NULL, remote_client, FALSE, 
2492                                    NULL, TRUE);
2493
2494   /* Remove the client entry, If it is locally connected then we will also
2495      disconnect the client here */
2496   if (remote_client->data.registered && remote_client->connection) {
2497     /* Remove locally conneted client */
2498     SilcSocketConnection sock = remote_client->connection;
2499     silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
2500     silc_server_close_connection(server, sock);
2501   } else {
2502     /* Remove remote client */
2503     if (!silc_idlist_del_client(server->global_list, remote_client))
2504       silc_idlist_del_client(server->local_list, remote_client);
2505   }
2506
2507  out:
2508   silc_server_command_free(cmd);
2509 }
2510
2511 /* Server side of command INFO. This sends information about us to 
2512    the client. If client requested specific server we will send the 
2513    command to that server. */
2514
2515 SILC_SERVER_CMD_FUNC(info)
2516 {
2517   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2518   SilcServer server = cmd->server;
2519   SilcBuffer packet, idp;
2520   char *dest_server, *server_info = NULL, *server_name;
2521   unsigned short ident = silc_command_get_ident(cmd->payload);
2522   SilcServerEntry entry = NULL;
2523
2524   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
2525
2526   /* Get server name */
2527   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
2528   if (!dest_server) {
2529     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
2530                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
2531     goto out;
2532   }
2533
2534   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
2535     /* Send our reply */
2536     char info_string[256];
2537
2538     memset(info_string, 0, sizeof(info_string));
2539     snprintf(info_string, sizeof(info_string), 
2540              "location: %s server: %s admin: %s <%s>",
2541              server->config->admin_info->location,
2542              server->config->admin_info->server_type,
2543              server->config->admin_info->admin_name,
2544              server->config->admin_info->admin_email);
2545
2546     server_info = info_string;
2547     entry = server->id_entry;
2548   } else {
2549     /* Check whether we have this server cached */
2550     entry = silc_idlist_find_server_by_name(server->global_list,
2551                                             dest_server, NULL);
2552     if (!entry) {
2553       entry = silc_idlist_find_server_by_name(server->local_list,
2554                                               dest_server, NULL);
2555     }
2556
2557     if (server->server_type == SILC_ROUTER && entry && !entry->server_info) {
2558       /* Send to the server */
2559       SilcBuffer tmpbuf;
2560       unsigned short old_ident;
2561
2562       old_ident = silc_command_get_ident(cmd->payload);
2563       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2564       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2565
2566       silc_server_packet_send(server, entry->connection,
2567                               SILC_PACKET_COMMAND, cmd->packet->flags,
2568                               tmpbuf->data, tmpbuf->len, TRUE);
2569
2570       /* Reprocess this packet after received reply from router */
2571       silc_server_command_pending(server, SILC_COMMAND_INFO, 
2572                                   silc_command_get_ident(cmd->payload),
2573                                   silc_server_command_destructor,
2574                                   silc_server_command_info,
2575                                   silc_server_command_dup(cmd));
2576       cmd->pending = TRUE;
2577       silc_command_set_ident(cmd->payload, old_ident);
2578       silc_buffer_free(tmpbuf);
2579       return;
2580     }
2581
2582     if (!entry && !cmd->pending && !server->standalone) {
2583       /* Send to the primary router */
2584       SilcBuffer tmpbuf;
2585       unsigned short old_ident;
2586
2587       old_ident = silc_command_get_ident(cmd->payload);
2588       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2589       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2590
2591       silc_server_packet_send(server, server->router->connection,
2592                               SILC_PACKET_COMMAND, cmd->packet->flags,
2593                               tmpbuf->data, tmpbuf->len, TRUE);
2594
2595       /* Reprocess this packet after received reply from router */
2596       silc_server_command_pending(server, SILC_COMMAND_INFO, 
2597                                   silc_command_get_ident(cmd->payload),
2598                                   silc_server_command_destructor,
2599                                   silc_server_command_info,
2600                                   silc_server_command_dup(cmd));
2601       cmd->pending = TRUE;
2602       silc_command_set_ident(cmd->payload, old_ident);
2603       silc_buffer_free(tmpbuf);
2604       return;
2605     }
2606   }
2607
2608   if (!entry) {
2609     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
2610                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
2611     goto out;
2612   }
2613
2614   idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
2615   if (!server_info)
2616     server_info = entry->server_info;
2617   server_name = dest_server;
2618
2619   /* Send the reply */
2620   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
2621                                                 SILC_STATUS_OK, ident, 3,
2622                                                 2, idp->data, idp->len,
2623                                                 3, server_name, 
2624                                                 strlen(server_name),
2625                                                 4, server_info, 
2626                                                 strlen(server_info));
2627   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
2628                           packet->data, packet->len, FALSE);
2629     
2630   silc_buffer_free(packet);
2631   silc_buffer_free(idp);
2632
2633  out:
2634   silc_server_command_free(cmd);
2635 }
2636
2637 /* Server side of command PING. This just replies to the ping. */
2638
2639 SILC_SERVER_CMD_FUNC(ping)
2640 {
2641   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2642   SilcServer server = cmd->server;
2643   SilcServerID *id;
2644   unsigned int len;
2645   unsigned char *tmp;
2646
2647   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
2648
2649   /* Get Server ID */
2650   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2651   if (!tmp) {
2652     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
2653                                           SILC_STATUS_ERR_NO_SERVER_ID);
2654     goto out;
2655   }
2656   id = silc_id_str2id(tmp, len, SILC_ID_SERVER);
2657   if (!id)
2658     goto out;
2659
2660   if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
2661     /* Send our reply */
2662     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
2663                                           SILC_STATUS_OK);
2664   } else {
2665     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
2666                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
2667     goto out;
2668   }
2669
2670   silc_free(id);
2671
2672  out:
2673   silc_server_command_free(cmd);
2674 }
2675
2676 /* Internal routine to join channel. The channel sent to this function
2677    has been either created or resolved from ID lists. This joins the sent
2678    client to the channel. */
2679
2680 static void silc_server_command_join_channel(SilcServer server, 
2681                                              SilcServerCommandContext cmd,
2682                                              SilcChannelEntry channel,
2683                                              SilcClientID *client_id,
2684                                              int created,
2685                                              unsigned int umode)
2686 {
2687   SilcSocketConnection sock = cmd->sock;
2688   unsigned char *tmp;
2689   unsigned int tmp_len, user_count;
2690   unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
2691   SilcClientEntry client;
2692   SilcChannelClientEntry chl;
2693   SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
2694   unsigned short ident = silc_command_get_ident(cmd->payload);
2695   char check[512];
2696
2697   SILC_LOG_DEBUG(("Start"));
2698
2699   if (!channel)
2700     return;
2701
2702   /* Get the client entry */
2703   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2704     client = (SilcClientEntry)sock->user_data;
2705   } else {
2706     client = silc_idlist_find_client_by_id(server->local_list, client_id, 
2707                                            NULL);
2708     if (!client)
2709       goto out;
2710   }
2711
2712   /*
2713    * Check channel modes
2714    */
2715
2716   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2717     strncat(check, client->nickname, strlen(client->nickname));
2718     if (!strchr(client->nickname, '@')) {
2719       strncat(check, "@", 1);
2720       strncat(check, server->server_name, strlen(server->server_name));
2721     }
2722     strncat(check, "!", 1);
2723     strncat(check, client->username, strlen(client->username));
2724     if (!strchr(client->username, '@')) {
2725       strncat(check, "@", 1);
2726       strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
2727     }
2728   }
2729
2730   /* Check invite list if channel is invite-only channel */
2731   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
2732       channel->mode & SILC_CHANNEL_MODE_INVITE) {
2733     if (!channel->invite_list) {
2734       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2735                                             SILC_STATUS_ERR_NOT_INVITED);
2736       goto out;
2737     }
2738
2739     if (!silc_string_match(channel->invite_list, check)) {
2740       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2741                                             SILC_STATUS_ERR_NOT_INVITED);
2742       goto out;
2743     }
2744   }
2745
2746   /* Check ban list if it exists. If the client's nickname, server,
2747      username and/or hostname is in the ban list the access to the
2748      channel is denied. */
2749   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && channel->ban_list) {
2750     if (silc_string_match(channel->ban_list, check)) {
2751       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2752                               SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
2753       goto out;
2754     }
2755   }
2756
2757   /* Get passphrase */
2758   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2759   if (tmp) {
2760     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
2761     memcpy(passphrase, tmp, tmp_len);
2762   }
2763   
2764   /* Check the channel passphrase if set. */
2765   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2766     if (!passphrase || memcmp(channel->passphrase, passphrase,
2767                               strlen(channel->passphrase))) {
2768       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2769                                             SILC_STATUS_ERR_BAD_PASSWORD);
2770       goto out;
2771     }
2772   }
2773
2774   /* Check user count limit if set. */
2775   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
2776     if (silc_list_count(channel->user_list) + 1 > 
2777         channel->user_limit) {
2778       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2779                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
2780       goto out;
2781     }
2782   }
2783
2784   /*
2785    * Client is allowed to join to the channel. Make it happen.
2786    */
2787
2788   /* Check whether the client already is on the channel */
2789   if (silc_server_client_on_channel(client, channel)) {
2790     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2791                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
2792     goto out;
2793   }
2794
2795   /* Generate new channel key as protocol dictates */
2796   if ((!created && silc_list_count(channel->user_list) > 0) || 
2797       !channel->channel_key)
2798     silc_server_create_channel_key(server, channel, 0);
2799
2800   /* Send the channel key. This is broadcasted to the channel but is not
2801      sent to the client who is joining to the channel. */
2802   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
2803     silc_server_send_channel_key(server, NULL, channel, 
2804                                  server->server_type == SILC_ROUTER ? 
2805                                  FALSE : !server->standalone);
2806
2807   /* Join the client to the channel by adding it to channel's user list.
2808      Add also the channel to client entry's channels list for fast cross-
2809      referencing. */
2810   chl = silc_calloc(1, sizeof(*chl));
2811   chl->mode = umode;
2812   chl->client = client;
2813   chl->channel = channel;
2814   silc_list_add(channel->user_list, chl);
2815   silc_list_add(client->channels, chl);
2816
2817   /* Get users on the channel */
2818   silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
2819                                    &user_count);
2820
2821   /* Encode Client ID Payload of the original client who wants to join */
2822   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2823
2824   /* Encode command reply packet */
2825   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2826   SILC_PUT32_MSB(channel->mode, mode);
2827   SILC_PUT32_MSB(created, tmp2);
2828   SILC_PUT32_MSB(user_count, tmp3);
2829
2830   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
2831     tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
2832     keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp, 
2833                                            strlen(channel->channel_key->
2834                                                   cipher->name),
2835                                            channel->channel_key->cipher->name,
2836                                            channel->key_len / 8, channel->key);
2837     silc_free(tmp);
2838   }
2839
2840   reply = 
2841     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
2842                                          SILC_STATUS_OK, ident, 13,
2843                                          2, channel->channel_name,
2844                                          strlen(channel->channel_name),
2845                                          3, chidp->data, chidp->len,
2846                                          4, clidp->data, clidp->len,
2847                                          5, mode, 4,
2848                                          6, tmp2, 4,
2849                                          7, keyp ? keyp->data : NULL, 
2850                                          keyp ? keyp->len : 0,
2851                                          8, channel->ban_list, 
2852                                          channel->ban_list ?
2853                                          strlen(channel->ban_list) : 0,
2854                                          9, channel->invite_list,
2855                                          channel->invite_list ?
2856                                          strlen(channel->invite_list) : 0,
2857                                          10, channel->topic,
2858                                          channel->topic ?
2859                                          strlen(channel->topic) : 0,
2860                                          11, channel->hmac->hmac->name,
2861                                          strlen(channel->hmac->hmac->name),
2862                                          12, tmp3, 4,
2863                                          13, user_list->data, user_list->len,
2864                                          14, mode_list->data, 
2865                                          mode_list->len);
2866
2867   /* Send command reply */
2868   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
2869                           reply->data, reply->len, FALSE);
2870
2871   if (!cmd->pending) {
2872     /* Send JOIN notify to locally connected clients on the channel */
2873     silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
2874                                        SILC_NOTIFY_TYPE_JOIN, 2,
2875                                        clidp->data, clidp->len,
2876                                        chidp->data, chidp->len);
2877
2878     /* Send JOIN notify packet to our primary router */
2879     if (!server->standalone)
2880       silc_server_send_notify_join(server, server->router->connection,
2881                                    server->server_type == SILC_ROUTER ?
2882                                    TRUE : FALSE, channel, client->id,
2883                                    SILC_ID_CLIENT_LEN);
2884   }
2885
2886   silc_buffer_free(reply);
2887   silc_buffer_free(clidp);
2888   silc_buffer_free(chidp);
2889   silc_buffer_free(keyp);
2890   silc_buffer_free(user_list);
2891   silc_buffer_free(mode_list);
2892
2893  out:
2894   if (passphrase)
2895     silc_free(passphrase);
2896 }
2897
2898 /* Server side of command JOIN. Joins client into requested channel. If 
2899    the channel does not exist it will be created. */
2900
2901 SILC_SERVER_CMD_FUNC(join)
2902 {
2903   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2904   SilcServer server = cmd->server;
2905   int tmp_len;
2906   char *tmp, *channel_name = NULL, *cipher, *hmac;
2907   SilcChannelEntry channel;
2908   unsigned int umode = 0;
2909   int created = FALSE;
2910   SilcClientID *client_id;
2911
2912   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 4);
2913
2914   /* Get channel name */
2915   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2916   if (!tmp) {
2917     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2918                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2919     goto out;
2920   }
2921   channel_name = tmp;
2922
2923   if (strlen(channel_name) > 256)
2924     channel_name[255] = '\0';
2925
2926   if (silc_server_command_bad_chars(channel_name) == TRUE) {
2927     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2928                                           SILC_STATUS_ERR_BAD_CHANNEL);
2929     silc_free(channel_name);
2930     goto out;
2931   }
2932
2933   /* Get Client ID of the client who is joining to the channel */
2934   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2935   if (!tmp) {
2936     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2937                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2938     goto out;
2939   }
2940   client_id = silc_id_payload_parse_id(tmp, tmp_len);
2941   if (!client_id) {
2942     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2943                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2944     goto out;
2945   }
2946
2947   /* Get cipher and hmac name */
2948   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
2949   hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
2950
2951   /* See if the channel exists */
2952   channel = silc_idlist_find_channel_by_name(server->local_list, 
2953                                              channel_name, NULL);
2954
2955   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2956     /* If this is coming from client the Client ID in the command packet must
2957        be same as the client's ID. */
2958     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
2959       SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
2960       if (SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
2961         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2962                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2963         goto out;
2964       }
2965     }
2966
2967     if (!channel) {
2968       /* Channel not found */
2969
2970       /* If we are standalone server we don't have a router, we just create 
2971          the channel by ourselves. */
2972       if (server->standalone) {
2973         channel = silc_server_create_new_channel(server, server->id, cipher, 
2974                                                  hmac, channel_name, TRUE);
2975         if (!channel) {
2976           silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2977                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
2978           goto out;
2979         }
2980
2981         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2982         created = TRUE;
2983
2984       } else {
2985
2986         /* The channel does not exist on our server. If we are normal server 
2987            we will send JOIN command to our router which will handle the
2988            joining procedure (either creates the channel if it doesn't exist 
2989            or joins the client to it). */
2990         if (server->server_type == SILC_SERVER) {
2991           SilcBuffer tmpbuf;
2992           unsigned short old_ident;
2993           
2994           old_ident = silc_command_get_ident(cmd->payload);
2995           silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
2996           tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2997           
2998           /* Send JOIN command to our router */
2999           silc_server_packet_send(server, (SilcSocketConnection)
3000                                   server->router->connection,
3001                                   SILC_PACKET_COMMAND, cmd->packet->flags,
3002                                   tmpbuf->data, tmpbuf->len, TRUE);
3003           
3004           /* Reprocess this packet after received reply from router */
3005           silc_server_command_pending(server, SILC_COMMAND_JOIN, 
3006                                       silc_command_get_ident(cmd->payload),
3007                                       silc_server_command_destructor,
3008                                       silc_server_command_join,
3009                                       silc_server_command_dup(cmd));
3010           cmd->pending = TRUE;
3011           return;
3012         }
3013         
3014         /* We are router and the channel does not seem exist so we will check
3015            our global list as well for the channel. */
3016         channel = silc_idlist_find_channel_by_name(server->global_list, 
3017                                                    channel_name, NULL);
3018         if (!channel) {
3019           /* Channel really does not exist, create it */
3020           channel = silc_server_create_new_channel(server, server->id, cipher, 
3021                                                    hmac, channel_name, TRUE);
3022           if (!channel) {
3023             silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3024                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3025             goto out;
3026           }
3027
3028           umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3029           created = TRUE;
3030         }
3031       }
3032     }
3033   } else {
3034     if (!channel) {
3035       /* Channel not found */
3036
3037       /* If the command came from router and/or we are normal server then
3038          something went wrong with the joining as the channel was not found.
3039          We can't do anything else but ignore this. */
3040       if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
3041           server->server_type == SILC_SERVER)
3042         goto out;
3043       
3044       /* We are router and the channel does not seem exist so we will check
3045          our global list as well for the channel. */
3046       channel = silc_idlist_find_channel_by_name(server->global_list, 
3047                                                  channel_name, NULL);
3048       if (!channel) {
3049         /* Channel really does not exist, create it */
3050         channel = silc_server_create_new_channel(server, server->id, cipher, 
3051                                                  hmac, channel_name, TRUE);
3052         if (!channel) {
3053           silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
3054                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3055           goto out;
3056         }
3057
3058         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3059         created = TRUE;
3060       }
3061     }
3062   }
3063
3064   /* If the channel does not have global users and is also empty it means the
3065      channel was created globally (by our router) and the client will be the
3066      channel founder and operator. */
3067   if (!channel->global_users && silc_list_count(channel->user_list) == 0) {
3068     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
3069     created = TRUE;             /* Created globally by our router */
3070   }
3071
3072   /* Join to the channel */
3073   silc_server_command_join_channel(server, cmd, channel, client_id,
3074                                    created, umode);
3075
3076   silc_free(client_id);
3077
3078  out:
3079   silc_server_command_free(cmd);
3080 }
3081
3082 /* Server side of command MOTD. Sends server's current "message of the
3083    day" to the client. */
3084
3085 SILC_SERVER_CMD_FUNC(motd)
3086 {
3087   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3088   SilcServer server = cmd->server;
3089   SilcBuffer packet, idp;
3090   char *motd, *dest_server;
3091   int motd_len;
3092   unsigned short ident = silc_command_get_ident(cmd->payload);
3093   
3094   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 1);
3095
3096   /* Get server name */
3097   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
3098   if (!dest_server) {
3099     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
3100                                           SILC_STATUS_ERR_NO_SUCH_SERVER);
3101     goto out;
3102   }
3103
3104   if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
3105     /* Send our MOTD */
3106
3107     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
3108
3109     if (server->config && server->config->motd && 
3110         server->config->motd->motd_file) {
3111       /* Send motd */
3112       motd = silc_file_read(server->config->motd->motd_file, &motd_len);
3113       if (!motd)
3114         goto out;
3115       
3116       motd[motd_len] = 0;
3117       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3118                                                     SILC_STATUS_OK, ident, 2,
3119                                                     2, idp, idp->len,
3120                                                     3, motd, motd_len);
3121       goto out;
3122     } else {
3123       /* No motd */
3124       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3125                                                     SILC_STATUS_OK, ident, 1,
3126                                                     2, idp, idp->len);
3127     }
3128
3129     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3130                             packet->data, packet->len, FALSE);
3131     silc_buffer_free(packet);
3132     silc_buffer_free(idp);
3133   } else {
3134     SilcServerEntry entry;
3135
3136     /* Check whether we have this server cached */
3137     entry = silc_idlist_find_server_by_name(server->global_list,
3138                                             dest_server, NULL);
3139     if (!entry) {
3140       entry = silc_idlist_find_server_by_name(server->local_list,
3141                                               dest_server, NULL);
3142     }
3143
3144     if (server->server_type == SILC_ROUTER && !cmd->pending && 
3145         entry && !entry->motd) {
3146       /* Send to the server */
3147       SilcBuffer tmpbuf;
3148       unsigned short old_ident;
3149
3150       old_ident = silc_command_get_ident(cmd->payload);
3151       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
3152       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3153
3154       silc_server_packet_send(server, entry->connection,
3155                               SILC_PACKET_COMMAND, cmd->packet->flags,
3156                               tmpbuf->data, tmpbuf->len, TRUE);
3157
3158       /* Reprocess this packet after received reply from router */
3159       silc_server_command_pending(server, SILC_COMMAND_MOTD, 
3160                                   silc_command_get_ident(cmd->payload),
3161                                   silc_server_command_destructor,
3162                                   silc_server_command_motd,
3163                                   silc_server_command_dup(cmd));
3164       cmd->pending = TRUE;
3165       silc_command_set_ident(cmd->payload, old_ident);
3166       silc_buffer_free(tmpbuf);
3167       return;
3168     }
3169
3170     if (!entry && !cmd->pending && !server->standalone) {
3171       /* Send to the primary router */
3172       SilcBuffer tmpbuf;
3173       unsigned short old_ident;
3174
3175       old_ident = silc_command_get_ident(cmd->payload);
3176       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
3177       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
3178
3179       silc_server_packet_send(server, server->router->connection,
3180                               SILC_PACKET_COMMAND, cmd->packet->flags,
3181                               tmpbuf->data, tmpbuf->len, TRUE);
3182
3183       /* Reprocess this packet after received reply from router */
3184       silc_server_command_pending(server, SILC_COMMAND_MOTD, 
3185                                   silc_command_get_ident(cmd->payload),
3186                                   silc_server_command_destructor,
3187                                   silc_server_command_motd,
3188                                   silc_server_command_dup(cmd));
3189       cmd->pending = TRUE;
3190       silc_command_set_ident(cmd->payload, old_ident);
3191       silc_buffer_free(tmpbuf);
3192       return;
3193     }
3194
3195     if (!entry) {
3196       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
3197                                             SILC_STATUS_ERR_NO_SUCH_SERVER);
3198       goto out;
3199     }
3200
3201     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
3202
3203     if (entry->motd)
3204       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3205                                                     SILC_STATUS_OK, ident, 2,
3206                                                     2, idp, idp->len,
3207                                                     3, entry->motd,
3208                                                     strlen(entry->motd));
3209     else
3210       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
3211                                                     SILC_STATUS_OK, ident, 1,
3212                                                     2, idp, idp->len);
3213
3214     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3215                             packet->data, packet->len, FALSE);
3216     silc_buffer_free(packet);
3217     silc_buffer_free(idp);
3218   }
3219
3220  out:
3221   silc_server_command_free(cmd);
3222 }
3223
3224 /* Server side of command UMODE. Client can use this command to set/unset
3225    user mode. Client actually cannot set itself to be as server/router
3226    operator so this can be used only to unset the modes. */
3227
3228 SILC_SERVER_CMD_FUNC(umode)
3229 {
3230   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3231   SilcServer server = cmd->server;
3232   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3233   SilcBuffer packet;
3234   unsigned char *tmp_mask;
3235   unsigned int mask;
3236   unsigned short ident = silc_command_get_ident(cmd->payload);
3237
3238   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
3239     goto out;
3240
3241   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_UMODE, cmd, 2, 2);
3242
3243   /* Get the client's mode mask */
3244   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
3245   if (!tmp_mask) {
3246     silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3247                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3248     goto out;
3249   }
3250   SILC_GET32_MSB(mask, tmp_mask);
3251
3252   /* 
3253    * Change the mode 
3254    */
3255
3256   if (mask & SILC_UMODE_SERVER_OPERATOR) {
3257     /* Cannot operator mode */
3258     silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3259                                           SILC_STATUS_ERR_PERM_DENIED);
3260     goto out;
3261   } else {
3262     if (client->mode & SILC_UMODE_SERVER_OPERATOR)
3263       /* Remove the server operator rights */
3264       client->mode &= ~SILC_UMODE_SERVER_OPERATOR;
3265   }
3266
3267   if (mask & SILC_UMODE_ROUTER_OPERATOR) {
3268     /* Cannot operator mode */
3269     silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
3270                                           SILC_STATUS_ERR_PERM_DENIED);
3271     goto out;
3272   } else {
3273     if (client->mode & SILC_UMODE_ROUTER_OPERATOR)
3274       /* Remove the router operator rights */
3275       client->mode &= ~SILC_UMODE_ROUTER_OPERATOR;
3276   }
3277
3278   /* Send UMODE change to primary router */
3279   if (!server->standalone)
3280     silc_server_send_notify_umode(server, server->router->connection, TRUE,
3281                                   client->id, SILC_ID_CLIENT_LEN,
3282                                   client->mode);
3283
3284   /* Send command reply to sender */
3285   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_UMODE,
3286                                                 SILC_STATUS_OK, ident, 1,
3287                                                 2, tmp_mask, 4);
3288   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3289                           packet->data, packet->len, FALSE);
3290   silc_buffer_free(packet);
3291
3292  out:
3293   silc_server_command_free(cmd);
3294 }
3295
3296 /* Checks that client has rights to add or remove channel modes. If any
3297    of the checks fails FALSE is returned. */
3298
3299 int silc_server_check_cmode_rights(SilcChannelEntry channel,
3300                                    SilcChannelClientEntry client,
3301                                    unsigned int mode)
3302 {
3303   int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
3304   int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
3305
3306   /* Check whether has rights to change anything */
3307   if (!is_op && !is_fo)
3308     return FALSE;
3309
3310   /* Check whether has rights to change everything */
3311   if (is_op && is_fo)
3312     return TRUE;
3313
3314   /* We know that client is channel operator, check that they are not
3315      changing anything that requires channel founder rights. Rest of the
3316      modes are available automatically for channel operator. */
3317
3318   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
3319     if (is_op && !is_fo)
3320       return FALSE;
3321   } else {
3322     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
3323       if (is_op && !is_fo)
3324         return FALSE;
3325     }
3326   }
3327   
3328   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3329     if (is_op && !is_fo)
3330       return FALSE;
3331   } else {
3332     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3333       if (is_op && !is_fo)
3334         return FALSE;
3335     }
3336   }
3337
3338   if (mode & SILC_CHANNEL_MODE_CIPHER) {
3339     if (is_op && !is_fo)
3340       return FALSE;
3341   } else {
3342     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
3343       if (is_op && !is_fo)
3344         return FALSE;
3345     }
3346   }
3347   
3348   return TRUE;
3349 }
3350
3351 /* Server side command of CMODE. Changes channel mode */
3352
3353 SILC_SERVER_CMD_FUNC(cmode)
3354 {
3355   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3356   SilcServer server = cmd->server;
3357   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3358   SilcChannelID *channel_id;
3359   SilcChannelEntry channel;
3360   SilcChannelClientEntry chl;
3361   SilcBuffer packet, cidp;
3362   unsigned char *tmp, *tmp_id, *tmp_mask;
3363   char *cipher = NULL, *hmac = NULL;
3364   unsigned int argc, mode_mask, tmp_len, tmp_len2;
3365   unsigned short ident = silc_command_get_ident(cmd->payload);
3366
3367   SILC_LOG_DEBUG(("Start"));
3368
3369   argc = silc_argument_get_arg_num(cmd->args);
3370   if (argc < 2) {
3371     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3372                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3373     goto out;
3374   }
3375   if (argc > 8) {
3376     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3377                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
3378     goto out;
3379   }
3380
3381   /* Get Channel ID */
3382   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
3383   if (!tmp_id) {
3384     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3385                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3386     goto out;
3387   }
3388   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
3389   if (!channel_id) {
3390     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3391                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3392     goto out;
3393   }
3394
3395   /* Get the channel mode mask */
3396   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
3397   if (!tmp_mask) {
3398     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3399                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3400     goto out;
3401   }
3402   SILC_GET32_MSB(mode_mask, tmp_mask);
3403
3404   /* Get channel entry */
3405   channel = silc_idlist_find_channel_by_id(server->local_list, 
3406                                            channel_id, NULL);
3407   if (!channel) {
3408     channel = silc_idlist_find_channel_by_id(server->global_list, 
3409                                              channel_id, NULL);
3410     if (!channel) {
3411       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3412                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
3413       goto out;
3414     }
3415   }
3416
3417   /* Check whether this client is on the channel */
3418   if (!silc_server_client_on_channel(client, channel)) {
3419     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3420                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
3421     goto out;
3422   }
3423
3424   /* Get entry to the channel user list */
3425   silc_list_start(channel->user_list);
3426   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
3427     if (chl->client == client)
3428       break;
3429
3430   /* Check that client has rights to change any requested channel modes */
3431   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
3432     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3433                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
3434     goto out;
3435   }
3436
3437   /*
3438    * Check the modes. Modes that requires nothing special operation are
3439    * not checked here.
3440    */
3441
3442   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
3443     /* Channel uses private keys to protect traffic. Client(s) has set the
3444        key locally they want to use, server does not know that key. */
3445     /* Nothing interesting to do here */
3446   } else {
3447     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
3448       /* The mode is removed and we need to generate and distribute
3449          new channel key. Clients are not using private channel keys
3450          anymore after this. */
3451
3452       /* Re-generate channel key */
3453       silc_server_create_channel_key(server, channel, 0);
3454       
3455       /* Send the channel key. This sends it to our local clients and if
3456          we are normal server to our router as well. */
3457       silc_server_send_channel_key(server, NULL, channel, 
3458                                    server->server_type == SILC_ROUTER ? 
3459                                    FALSE : !server->standalone);
3460
3461       cipher = channel->channel_key->cipher->name;
3462       hmac = channel->hmac->hmac->name;
3463     }
3464   }
3465   
3466   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
3467     /* User limit is set on channel */
3468     unsigned int user_limit;
3469       
3470     /* Get user limit */
3471     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
3472     if (!tmp) {
3473       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
3474         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3475                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3476         goto out;
3477       }
3478     } else {
3479       SILC_GET32_MSB(user_limit, tmp);
3480       channel->user_limit = user_limit;
3481     }
3482   } else {
3483     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
3484       /* User limit mode is unset. Remove user limit */
3485       channel->user_limit = 0;
3486   }
3487
3488   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
3489     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
3490       /* Passphrase has been set to channel */
3491       
3492       /* Get the passphrase */
3493       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
3494       if (!tmp) {
3495         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3496                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3497         goto out;
3498       }
3499
3500       /* Save the passphrase */
3501       channel->passphrase = strdup(tmp);
3502     }
3503   } else {
3504     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3505       /* Passphrase mode is unset. remove the passphrase */
3506       if (channel->passphrase) {
3507         silc_free(channel->passphrase);
3508         channel->passphrase = NULL;
3509       }
3510     }
3511   }
3512
3513   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
3514     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
3515       /* Cipher to use protect the traffic */
3516
3517       /* Get cipher */
3518       cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
3519       if (!cipher) {
3520         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3521                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3522         goto out;
3523       }
3524
3525       /* Delete old cipher and allocate the new one */
3526       silc_cipher_free(channel->channel_key);
3527       if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
3528         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3529                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3530         goto out;
3531       }
3532
3533       /* Re-generate channel key */
3534       silc_server_create_channel_key(server, channel, 0);
3535     
3536       /* Send the channel key. This sends it to our local clients and if
3537          we are normal server to our router as well. */
3538       silc_server_send_channel_key(server, NULL, channel, 
3539                                    server->server_type == SILC_ROUTER ? 
3540                                    FALSE : !server->standalone);
3541     }
3542   } else {
3543     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
3544       /* Cipher mode is unset. Remove the cipher and revert back to 
3545          default cipher */
3546       cipher = channel->cipher;
3547
3548       /* Delete old cipher and allocate default one */
3549       silc_cipher_free(channel->channel_key);
3550       if (!silc_cipher_alloc(cipher ? cipher : "aes-256-cbc", 
3551                              &channel->channel_key)) {
3552         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3553                                    SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3554         goto out;
3555       }
3556
3557       /* Re-generate channel key */
3558       silc_server_create_channel_key(server, channel, 0);
3559       
3560       /* Send the channel key. This sends it to our local clients and if
3561          we are normal server to our router as well. */
3562       silc_server_send_channel_key(server, NULL, channel, 
3563                                    server->server_type == SILC_ROUTER ? 
3564                                    FALSE : !server->standalone);
3565     }
3566   }
3567
3568   if (mode_mask & SILC_CHANNEL_MODE_HMAC) {
3569     if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) {
3570       /* HMAC to use protect the traffic */
3571       unsigned char hash[32];
3572
3573       /* Get hmac */
3574       hmac = silc_argument_get_arg_type(cmd->args, 6, NULL);
3575       if (!hmac) {
3576         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3577                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3578         goto out;
3579       }
3580
3581       /* Delete old hmac and allocate the new one */
3582       silc_hmac_free(channel->hmac);
3583       if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
3584         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3585                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3586         goto out;
3587       }
3588
3589       /* Set the HMAC key out of current channel key. The client must do
3590          this locally. */
3591       silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
3592                      hash);
3593       silc_hmac_set_key(channel->hmac, hash, 
3594                         silc_hash_len(channel->hmac->hash));
3595       memset(hash, 0, sizeof(hash));
3596     }
3597   } else {
3598     if (channel->mode & SILC_CHANNEL_MODE_HMAC) {
3599       /* Hmac mode is unset. Remove the hmac and revert back to 
3600          default hmac */
3601       unsigned char hash[32];
3602       hmac = channel->hmac_name;
3603
3604       /* Delete old hmac and allocate default one */
3605       silc_hmac_free(channel->hmac);
3606       if (!silc_hmac_alloc(hmac ? hmac : "hmac-sha1-96", NULL, 
3607                            &channel->hmac)) {
3608         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3609                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
3610         goto out;
3611       }
3612
3613       /* Set the HMAC key out of current channel key. The client must do
3614          this locally. */
3615       silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
3616                      hash);
3617       silc_hmac_set_key(channel->hmac, hash, 
3618                         silc_hash_len(channel->hmac->hash));
3619       memset(hash, 0, sizeof(hash));
3620     }
3621   }
3622
3623   /* Finally, set the mode */
3624   channel->mode = mode_mask;
3625
3626   /* Send CMODE_CHANGE notify */
3627   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
3628   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
3629                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 4,
3630                                      cidp->data, cidp->len, 
3631                                      tmp_mask, tmp_len,
3632                                      cipher, cipher ? strlen(cipher) : 0,
3633                                      hmac, hmac ? strlen(hmac) : 0);
3634
3635   /* Set CMODE notify type to network */
3636   if (!server->standalone)
3637     silc_server_send_notify_cmode(server, server->router->connection,
3638                                   server->server_type == SILC_ROUTER ? 
3639                                   TRUE : FALSE, channel,
3640                                   mode_mask, client->id, SILC_ID_CLIENT_LEN,
3641                                   cipher, hmac);
3642
3643   /* Send command reply to sender */
3644   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
3645                                                 SILC_STATUS_OK, ident, 1,
3646                                                 2, tmp_mask, 4);
3647   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3648                           packet->data, packet->len, FALSE);
3649     
3650   silc_buffer_free(packet);
3651   silc_free(channel_id);
3652   silc_free(cidp);
3653
3654  out:
3655   silc_server_command_free(cmd);
3656 }
3657
3658 /* Server side of CUMODE command. Changes client's mode on a channel. */
3659
3660 SILC_SERVER_CMD_FUNC(cumode)
3661 {
3662   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3663   SilcServer server = cmd->server;
3664   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3665   SilcChannelID *channel_id;
3666   SilcClientID *client_id;
3667   SilcChannelEntry channel;
3668   SilcClientEntry target_client;
3669   SilcChannelClientEntry chl;
3670   SilcBuffer packet, idp;
3671   unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
3672   unsigned int target_mask, sender_mask, tmp_len, tmp_ch_len;
3673   int notify = FALSE;
3674   unsigned short ident = silc_command_get_ident(cmd->payload);
3675
3676   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
3677
3678   /* Get Channel ID */
3679   tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
3680   if (!tmp_ch_id) {
3681     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3682                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3683     goto out;
3684   }
3685   channel_id = silc_id_payload_parse_id(tmp_ch_id, tmp_ch_len);
3686   if (!channel_id) {
3687     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3688                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3689     goto out;
3690   }
3691
3692   /* Get channel entry */
3693   channel = silc_idlist_find_channel_by_id(server->local_list, 
3694                                            channel_id, NULL);
3695   if (!channel) {
3696     channel = silc_idlist_find_channel_by_id(server->global_list, 
3697                                              channel_id, NULL);
3698     if (!channel) {
3699       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3700                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
3701       goto out;
3702     }
3703   }
3704
3705   /* Check whether sender is on the channel */
3706   if (!silc_server_client_on_channel(client, channel)) {
3707     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3708                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
3709     goto out;
3710   }
3711
3712   /* Check that client has rights to change other's rights */
3713   silc_list_start(channel->user_list);
3714   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
3715     if (chl->client == client) {
3716       if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
3717           !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
3718         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3719                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
3720         goto out;
3721       }
3722
3723       sender_mask = chl->mode;
3724       break;
3725     }
3726   }
3727   
3728   /* Get the target client's channel mode mask */
3729   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
3730   if (!tmp_mask) {
3731     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3732                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
3733     goto out;
3734   }
3735   SILC_GET32_MSB(target_mask, tmp_mask);
3736
3737   /* Get target Client ID */
3738   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
3739   if (!tmp_id) {
3740     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3741                                           SILC_STATUS_ERR_NO_CLIENT_ID);
3742     goto out;
3743   }
3744   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
3745   if (!client_id) {
3746     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3747                                           SILC_STATUS_ERR_NO_CLIENT_ID);
3748     goto out;
3749   }
3750
3751   /* Get target client's entry */
3752   target_client = silc_idlist_find_client_by_id(server->local_list, 
3753                                                 client_id, NULL);
3754   if (!target_client) {
3755     target_client = silc_idlist_find_client_by_id(server->global_list, 
3756                                                   client_id, NULL);
3757   }
3758
3759   /* Check whether target client is on the channel */
3760   if (!silc_server_client_on_channel(target_client, channel)) {
3761     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3762                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
3763     goto out;
3764   }
3765
3766   /* Get entry to the channel user list */
3767   silc_list_start(channel->user_list);
3768   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
3769     if (chl->client == target_client)
3770       break;
3771
3772   /* 
3773    * Change the mode 
3774    */
3775
3776   /* If the target client is founder, no one else can change their mode
3777      but themselves. */
3778   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
3779     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3780                                           SILC_STATUS_ERR_NOT_YOU);
3781     goto out;
3782   }
3783
3784   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
3785     /* Cannot promote anyone to channel founder */
3786     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3787                                           SILC_STATUS_ERR_NOT_YOU);
3788     goto out;
3789   } else {
3790     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
3791       if (target_client == client) {
3792         /* Remove channel founder rights from itself */
3793         chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
3794         notify = TRUE;
3795       } else {
3796         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3797                                               SILC_STATUS_ERR_NOT_YOU);
3798         goto out;
3799       }
3800     }
3801   }
3802
3803   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
3804     /* Promote to operator */
3805     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
3806       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
3807       notify = TRUE;
3808     }
3809   } else {
3810     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
3811       /* Demote to normal user */
3812       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
3813       notify = TRUE;
3814     }
3815   }
3816
3817   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
3818
3819   /* Send notify to channel, notify only if mode was actually changed. */
3820   if (notify) {
3821     silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
3822                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
3823                                        idp->data, idp->len,
3824                                        tmp_mask, 4, 
3825                                        tmp_id, tmp_len);
3826
3827     /* Set CUMODE notify type to network */
3828     if (!server->standalone)
3829       silc_server_send_notify_cumode(server, server->router->connection,
3830                                      server->server_type == SILC_ROUTER ? 
3831                                      TRUE : FALSE, channel,
3832                                      target_mask, client->id, 
3833                                      SILC_ID_CLIENT_LEN,
3834                                      target_client->id, 
3835                                      SILC_ID_CLIENT_LEN);
3836   }
3837
3838   /* Send command reply to sender */
3839   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
3840                                                 SILC_STATUS_OK, ident, 2,
3841                                                 2, tmp_mask, 4,
3842                                                 3, tmp_id, tmp_len);
3843   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
3844                           packet->data, packet->len, FALSE);
3845     
3846   silc_buffer_free(packet);
3847   silc_free(channel_id);
3848   silc_free(client_id);
3849   silc_buffer_free(idp);
3850
3851  out:
3852   silc_server_command_free(cmd);
3853 }
3854
3855 /* Server side of KICK command. Kicks client out of channel. */
3856
3857 SILC_SERVER_CMD_FUNC(kick)
3858 {
3859   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3860   SilcServer server = cmd->server;
3861   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
3862   SilcClientEntry target_client;
3863   SilcChannelID *channel_id;
3864   SilcClientID *client_id;
3865   SilcChannelEntry channel;
3866   SilcChannelClientEntry chl;
3867   SilcBuffer idp;
3868   unsigned int tmp_len;
3869   unsigned char *tmp, *comment;
3870
3871   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 3);
3872
3873   /* Get Channel ID */
3874   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3875   if (!tmp) {
3876     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3877                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3878     goto out;
3879   }
3880   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
3881   if (!channel_id) {
3882     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3883                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
3884     goto out;
3885   }
3886
3887   /* Get channel entry */
3888   channel = silc_idlist_find_channel_by_id(server->local_list, 
3889                                            channel_id, NULL);
3890   if (!channel) {
3891     channel = silc_idlist_find_channel_by_id(server->local_list, 
3892                                              channel_id, NULL);
3893     if (!channel) {
3894       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3895                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
3896       goto out;
3897     }
3898   }
3899
3900   /* Check whether sender is on the channel */
3901   if (!silc_server_client_on_channel(client, channel)) {
3902     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3903                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
3904     goto out;
3905   }
3906
3907   /* Check that the kicker is channel operator or channel founder */
3908   silc_list_start(channel->user_list);
3909   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
3910     if (chl->client == client) {
3911       if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
3912         silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3913                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
3914         goto out;
3915       }
3916       break;
3917     }
3918   }
3919   
3920   /* Get target Client ID */
3921   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
3922   if (!tmp) {
3923     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3924                                           SILC_STATUS_ERR_NO_CLIENT_ID);
3925     goto out;
3926   }
3927   client_id = silc_id_payload_parse_id(tmp, tmp_len);
3928   if (!client_id) {
3929     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3930                                           SILC_STATUS_ERR_NO_CLIENT_ID);
3931     goto out;
3932   }
3933
3934   /* Get target client's entry */
3935   target_client = silc_idlist_find_client_by_id(server->local_list, 
3936                                                 client_id, NULL);
3937   if (!target_client) {
3938     target_client = silc_idlist_find_client_by_id(server->global_list, 
3939                                                   client_id, NULL);
3940   }
3941
3942   /* Check that the target client is not channel founder. Channel founder
3943      cannot be kicked from the channel. */
3944   silc_list_start(channel->user_list);
3945   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
3946     if (chl->client == target_client) {
3947       if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
3948         silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3949                                   SILC_STATUS_ERR_NO_CHANNEL_FOPRIV);
3950         goto out;
3951       }
3952       break;
3953     }
3954   }
3955   
3956   /* Check whether target client is on the channel */
3957   if (!silc_server_client_on_channel(target_client, channel)) {
3958     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3959                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
3960     goto out;
3961   }
3962
3963   /* Get comment */
3964   tmp_len = 0;
3965   comment = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
3966   if (tmp_len > 128)
3967     comment = NULL;
3968
3969   /* Send command reply to sender */
3970   silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK, 
3971                                         SILC_STATUS_OK);
3972
3973   /* Send KICKED notify to local clients on the channel */
3974   idp = silc_id_payload_encode(target_client->id, SILC_ID_CLIENT);
3975   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
3976                                      SILC_NOTIFY_TYPE_KICKED, 
3977                                      comment ? 2 : 1,
3978                                      idp->data, idp->len,
3979                                      comment, comment ? strlen(comment) : 0);
3980   silc_buffer_free(idp);
3981
3982   /* Remove the client from the channel. If the channel does not exist
3983      after removing the client then the client kicked itself off the channel
3984      and we don't have to send anything after that. */
3985   if (!silc_server_remove_from_one_channel(server, NULL, channel, 
3986                                            target_client, FALSE))
3987     goto out;
3988
3989   /* Send KICKED notify to primary route */
3990   if (!server->standalone)
3991     silc_server_send_notify_kicked(server, server->router->connection,
3992                                    server->server_type == SILC_ROUTER ?
3993                                    TRUE : FALSE, channel,
3994                                    target_client->id, SILC_ID_CLIENT_LEN,
3995                                    comment);
3996
3997   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
3998     /* Re-generate channel key */
3999     silc_server_create_channel_key(server, channel, 0);
4000     
4001     /* Send the channel key to the channel. The key of course is not sent
4002        to the client who was kicked off the channel. */
4003     silc_server_send_channel_key(server, target_client->connection, channel, 
4004                                  server->server_type == SILC_ROUTER ? 
4005                                  FALSE : !server->standalone);
4006   }
4007
4008  out:
4009   silc_server_command_free(cmd);
4010 }
4011
4012 /* Server side of OPER command. Client uses this comand to obtain server
4013    operator privileges to this server/router. */
4014
4015 SILC_SERVER_CMD_FUNC(oper)
4016 {
4017   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4018   SilcServer server = cmd->server;
4019   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4020   unsigned char *username, *auth;
4021   unsigned int tmp_len;
4022   SilcServerConfigSectionAdminConnection *admin;
4023   SilcIDListData idata = (SilcIDListData)client;
4024
4025   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_OPER, cmd, 1, 2);
4026
4027   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4028     goto out;
4029
4030   /* Get the username */
4031   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4032   if (!username) {
4033     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4034                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4035     goto out;
4036   }
4037
4038   /* Get the admin configuration */
4039   admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
4040                                         username, client->nickname);
4041   if (!admin) {
4042     admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
4043                                           username, client->nickname);
4044     if (!admin) {
4045       silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4046                                             SILC_STATUS_ERR_AUTH_FAILED);
4047       goto out;
4048     }
4049   }
4050
4051   /* Get the authentication payload */
4052   auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4053   if (!auth) {
4054     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4055                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4056     goto out;
4057   }
4058
4059   /* Verify the authentication data */
4060   if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, 
4061                              admin->auth_data, admin->auth_data_len,
4062                              idata->hash, client->id, SILC_ID_CLIENT)) {
4063     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4064                                           SILC_STATUS_ERR_AUTH_FAILED);
4065     goto out;
4066   }
4067
4068   /* Client is now server operator */
4069   client->mode |= SILC_UMODE_SERVER_OPERATOR;
4070
4071   /* Send UMODE change to primary router */
4072   if (!server->standalone)
4073     silc_server_send_notify_umode(server, server->router->connection, TRUE,
4074                                   client->id, SILC_ID_CLIENT_LEN,
4075                                   client->mode);
4076
4077   /* Send reply to the sender */
4078   silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4079                                         SILC_STATUS_OK);
4080
4081  out:
4082   silc_server_command_free(cmd);
4083 }
4084
4085 /* Server side of SILCOPER command. Client uses this comand to obtain router
4086    operator privileges to this router. */
4087
4088 SILC_SERVER_CMD_FUNC(silcoper)
4089 {
4090   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4091   SilcServer server = cmd->server;
4092   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4093   unsigned char *username, *auth;
4094   unsigned int tmp_len;
4095   SilcServerConfigSectionAdminConnection *admin;
4096   SilcIDListData idata = (SilcIDListData)client;
4097
4098   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SILCOPER, cmd, 1, 2);
4099
4100   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4101     goto out;
4102
4103   /* Get the username */
4104   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4105   if (!username) {
4106     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4107                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4108     goto out;
4109   }
4110
4111   /* Get the admin configuration */
4112   admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
4113                                         username, client->nickname);
4114   if (!admin) {
4115     admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
4116                                           username, client->nickname);
4117     if (!admin) {
4118       silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4119                                             SILC_STATUS_ERR_AUTH_FAILED);
4120       goto out;
4121     }
4122   }
4123
4124   /* Get the authentication payload */
4125   auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4126   if (!auth) {
4127     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4128                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4129     goto out;
4130   }
4131
4132   /* Verify the authentication data */
4133   if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, 
4134                              admin->auth_data, admin->auth_data_len,
4135                              idata->hash, client->id, SILC_ID_CLIENT)) {
4136     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4137                                           SILC_STATUS_ERR_AUTH_FAILED);
4138     goto out;
4139   }
4140
4141   /* Client is now router operator */
4142   client->mode |= SILC_UMODE_ROUTER_OPERATOR;
4143
4144   /* Send UMODE change to primary router */
4145   if (!server->standalone)
4146     silc_server_send_notify_umode(server, server->router->connection, TRUE,
4147                                   client->id, SILC_ID_CLIENT_LEN,
4148                                   client->mode);
4149
4150   /* Send reply to the sender */
4151   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4152                                         SILC_STATUS_OK);
4153
4154  out:
4155   silc_server_command_free(cmd);
4156 }
4157
4158 /* Server side command of CONNECT. Connects us to the specified remote
4159    server or router. */
4160
4161 SILC_SERVER_CMD_FUNC(connect)
4162 {
4163   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4164   SilcServer server = cmd->server;
4165   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4166   unsigned char *tmp, *host;
4167   unsigned int tmp_len;
4168   unsigned int port = SILC_PORT;
4169
4170   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CONNECT, cmd, 1, 2);
4171
4172   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4173     goto out;
4174
4175   /* Check whether client has the permissions. */
4176   if (client->mode == SILC_UMODE_NONE) {
4177     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4178                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
4179     goto out;
4180   }
4181
4182   if (server->server_type == SILC_ROUTER && 
4183       client->mode & SILC_UMODE_SERVER_OPERATOR) {
4184     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4185                                           SILC_STATUS_ERR_NO_ROUTER_PRIV);
4186     goto out;
4187   }
4188
4189   /* Get the remote server */
4190   host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4191   if (!host) {
4192     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4193                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4194     goto out;
4195   }
4196
4197   /* Get port */
4198   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4199   if (tmp)
4200     SILC_GET32_MSB(port, tmp);
4201
4202   /* Create the connection. It is done with timeout and is async. */
4203   silc_server_create_connection(server, host, port);
4204
4205   /* Send reply to the sender */
4206   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
4207                                         SILC_STATUS_OK);
4208
4209  out:
4210   silc_server_command_free(cmd);
4211 }
4212
4213 SILC_SERVER_CMD_FUNC(restart)
4214 {
4215   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4216
4217   silc_server_command_free(cmd);
4218 }
4219
4220 /* Server side command of CLOSE. Closes connection to a specified server. */
4221  
4222 SILC_SERVER_CMD_FUNC(close)
4223 {
4224   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4225   SilcServer server = cmd->server;
4226   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4227   SilcServerEntry server_entry;
4228   SilcSocketConnection sock;
4229   unsigned char *tmp;
4230   unsigned int tmp_len;
4231   unsigned char *name;
4232   unsigned int port = SILC_PORT;
4233
4234   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CLOSE, cmd, 1, 2);
4235
4236   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4237     goto out;
4238
4239   /* Check whether client has the permissions. */
4240   if (client->mode == SILC_UMODE_NONE) {
4241     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4242                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
4243     goto out;
4244   }
4245
4246   /* Get the remote server */
4247   name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4248   if (!name) {
4249     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4250                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
4251     goto out;
4252   }
4253
4254   /* Get port */
4255   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4256   if (tmp)
4257     SILC_GET32_MSB(port, tmp);
4258
4259   server_entry = silc_idlist_find_server_by_conn(server->local_list,
4260                                                  name, port, NULL);
4261   if (!server_entry) {
4262     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4263                                           SILC_STATUS_ERR_NO_SERVER_ID);
4264     goto out;
4265   }
4266
4267   /* Send reply to the sender */
4268   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
4269                                         SILC_STATUS_OK);
4270
4271   /* Close the connection to the server */
4272   sock = (SilcSocketConnection)server_entry->connection;
4273   silc_server_free_sock_user_data(server, sock);
4274   silc_server_close_connection(server, sock);
4275   
4276  out:
4277   silc_server_command_free(cmd);
4278 }
4279
4280 /* Server side command of SHUTDOWN. Shutdowns the server and closes all
4281    active connections. */
4282  
4283 SILC_SERVER_CMD_FUNC(shutdown)
4284 {
4285   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4286   SilcServer server = cmd->server;
4287   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4288
4289   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SHUTDOWN, cmd, 0, 0);
4290
4291   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4292     goto out;
4293
4294   /* Check whether client has the permission. */
4295   if (client->mode == SILC_UMODE_NONE) {
4296     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
4297                                           SILC_STATUS_ERR_NO_SERVER_PRIV);
4298     goto out;
4299   }
4300
4301   /* Send reply to the sender */
4302   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
4303                                         SILC_STATUS_OK);
4304
4305   /* Then, gracefully, or not, bring the server down. */
4306   silc_server_stop(server);
4307   exit(0);
4308
4309  out:
4310   silc_server_command_free(cmd);
4311 }
4312  
4313 /* Server side command of LEAVE. Removes client from a channel. */
4314
4315 SILC_SERVER_CMD_FUNC(leave)
4316 {
4317   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4318   SilcServer server = cmd->server;
4319   SilcSocketConnection sock = cmd->sock;
4320   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
4321   SilcChannelID *id;
4322   SilcChannelEntry channel;
4323   unsigned int len;
4324   unsigned char *tmp;
4325
4326   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
4327
4328   /* Get Channel ID */
4329   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
4330   if (!tmp) {
4331     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4332                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4333     goto out;
4334   }
4335   id = silc_id_payload_parse_id(tmp, len);
4336   if (!id) {
4337     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4338                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4339     goto out;
4340   }
4341
4342   /* Get channel entry */
4343   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
4344   if (!channel) {
4345     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
4346     if (!channel) {
4347       silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4348                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
4349       goto out;
4350     }
4351   }
4352
4353   /* Check whether this client is on the channel */
4354   if (!silc_server_client_on_channel(id_entry, channel)) {
4355     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4356                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
4357     goto out;
4358   }
4359
4360   /* Notify routers that they should remove this client from their list
4361      of clients on the channel. Send LEAVE notify type. */
4362   if (!server->standalone)
4363     silc_server_send_notify_leave(server, server->router->connection,
4364                                   server->server_type == SILC_ROUTER ?
4365                                   TRUE : FALSE, channel, id_entry->id,
4366                                   SILC_ID_CLIENT_LEN);
4367
4368   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4369                                         SILC_STATUS_OK);
4370
4371   /* Remove client from channel */
4372   if (!silc_server_remove_from_one_channel(server, sock, channel, id_entry,
4373                                            TRUE))
4374     /* If the channel does not exist anymore we won't send anything */
4375     goto out;
4376
4377   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
4378     /* Re-generate channel key */
4379     silc_server_create_channel_key(server, channel, 0);
4380
4381     /* Send the channel key */
4382     silc_server_send_channel_key(server, NULL, channel, 
4383                                  server->server_type == SILC_ROUTER ? 
4384                                  FALSE : !server->standalone);
4385   }
4386
4387   silc_free(id);
4388
4389  out:
4390   silc_server_command_free(cmd);
4391 }
4392
4393 /* Server side of command USERS. Resolves clients and their USERS currently
4394    joined on the requested channel. The list of Client ID's and their modes
4395    on the channel is sent back. */
4396
4397 SILC_SERVER_CMD_FUNC(users)
4398 {
4399   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4400   SilcServer server = cmd->server;
4401   SilcChannelEntry channel;
4402   SilcChannelID *id;
4403   SilcBuffer packet;
4404   unsigned char *channel_id;
4405   unsigned int channel_id_len;
4406   SilcBuffer client_id_list;
4407   SilcBuffer client_mode_list;
4408   unsigned char lc[4];
4409   unsigned int list_count = 0;
4410   unsigned short ident = silc_command_get_ident(cmd->payload);
4411
4412   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
4413
4414   /* Get Channel ID */
4415   channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
4416   if (!channel_id) {
4417     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4418                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4419     goto out;
4420   }
4421   id = silc_id_payload_parse_id(channel_id, channel_id_len);
4422   if (!id) {
4423     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4424                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
4425     goto out;
4426   }
4427
4428   /* If we are server and we don't know about this channel we will send
4429      the command to our router. If we know about the channel then we also
4430      have the list of users already. */
4431   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
4432   if (!channel) {
4433     if (server->server_type == SILC_SERVER && !server->standalone &&
4434         !cmd->pending) {
4435       SilcBuffer tmpbuf;
4436       
4437       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
4438       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
4439       
4440       /* Send USERS command */
4441       silc_server_packet_send(server, server->router->connection,
4442                               SILC_PACKET_COMMAND, cmd->packet->flags,
4443                               tmpbuf->data, tmpbuf->len, TRUE);
4444       
4445       /* Reprocess this packet after received reply */
4446       silc_server_command_pending(server, SILC_COMMAND_USERS, 
4447                                   silc_command_get_ident(cmd->payload),
4448                                   silc_server_command_destructor,
4449                                   silc_server_command_users,
4450                                   silc_server_command_dup(cmd));
4451       cmd->pending = TRUE;
4452       silc_command_set_ident(cmd->payload, ident);
4453       
4454       silc_buffer_free(tmpbuf);
4455       silc_free(id);
4456       return;
4457     }
4458
4459     /* We are router and we will check the global list as well. */
4460     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
4461     if (!channel) {
4462       /* Channel really does not exist */
4463       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4464                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
4465       goto out;
4466     }
4467   }
4468
4469   /* Get the users list */
4470   silc_server_get_users_on_channel(server, channel, &client_id_list,
4471                                    &client_mode_list, &list_count);
4472
4473   /* List count */
4474   SILC_PUT32_MSB(list_count, lc);
4475
4476   /* Send reply */
4477   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
4478                                                 SILC_STATUS_OK, ident, 4,
4479                                                 2, channel_id, channel_id_len,
4480                                                 3, lc, 4,
4481                                                 4, client_id_list->data,
4482                                                 client_id_list->len,
4483                                                 5, client_mode_list->data,
4484                                                 client_mode_list->len);
4485   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
4486                           packet->data, packet->len, FALSE);
4487     
4488   silc_buffer_free(packet);
4489   silc_buffer_free(client_id_list);
4490   silc_buffer_free(client_mode_list);
4491   silc_free(id);
4492
4493  out:
4494   silc_server_command_free(cmd);
4495 }
4496
4497 /* Server side of command BAN. This is used to manage the ban list of the
4498    channel. To add clients and remove clients from the ban list. */
4499
4500 SILC_SERVER_CMD_FUNC(ban)
4501 {
4502   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4503   SilcServer server = cmd->server;
4504   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
4505   SilcBuffer packet;
4506   SilcChannelEntry channel;
4507   SilcChannelClientEntry chl;
4508   SilcChannelID *channel_id = NULL;
4509   unsigned char *id, *add, *del;
4510   unsigned int id_len, tmp_len;
4511   unsigned short ident = silc_command_get_ident(cmd->payload);
4512
4513   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
4514     goto out;
4515
4516   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_BAN, cmd, 0, 3);
4517
4518   /* Get Channel ID */
4519   id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
4520   if (id) {
4521     channel_id = silc_id_payload_parse_id(id, id_len);
4522     if (!channel_id) {
4523       silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4524                                             SILC_STATUS_ERR_NO_CHANNEL_ID);
4525       goto out;
4526     }
4527   }
4528
4529   /* Get channel entry. The server must know about the channel since the
4530      client is expected to be on the channel. */
4531   channel = silc_idlist_find_channel_by_id(server->local_list, 
4532                                            channel_id, NULL);
4533   if (!channel) {
4534     channel = silc_idlist_find_channel_by_id(server->global_list, 
4535                                              channel_id, NULL);
4536     if (!channel) {
4537       silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4538                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL);
4539       goto out;
4540     }
4541   }
4542
4543   /* Check whether this client is on the channel */
4544   if (!silc_server_client_on_channel(client, channel)) {
4545     silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4546                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
4547     goto out;
4548   }
4549
4550   /* Get entry to the channel user list */
4551   silc_list_start(channel->user_list);
4552   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
4553     if (chl->client == client)
4554       break;
4555
4556   /* The client must be at least channel operator. */
4557   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
4558     silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4559                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
4560     goto out;
4561   }
4562
4563   /* Get the new ban and add it to the ban list */
4564   add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4565   if (add) {
4566     if (!channel->ban_list)
4567       channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list));
4568     else
4569       channel->ban_list = silc_realloc(channel->ban_list, 
4570                                        sizeof(*channel->ban_list) * 
4571                                        (tmp_len + 
4572                                         strlen(channel->ban_list) + 2));
4573     if (add[tmp_len - 1] == ',')
4574       add[tmp_len - 1] = '\0';
4575
4576     strncat(channel->ban_list, add, tmp_len);
4577     strncat(channel->ban_list, ",", 1);
4578   }
4579
4580   /* Get the ban to be removed and remove it from the list */
4581   del = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
4582   if (del && channel->ban_list) {
4583     char *start, *end, *n;
4584
4585     if (!strncmp(channel->ban_list, del, strlen(channel->ban_list) - 1)) {
4586       silc_free(channel->ban_list);
4587       channel->ban_list = NULL;
4588     } else {
4589       start = strstr(channel->ban_list, del);
4590       if (start && strlen(start) >= tmp_len) {
4591         end = start + tmp_len;
4592         n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
4593         strncat(n, channel->ban_list, start - channel->ban_list);
4594         strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) - 
4595                              end) - 1);
4596         silc_free(channel->ban_list);
4597         channel->ban_list = n;
4598       }
4599     }
4600   }
4601
4602   /* Send the BAN notify type to our primary router. */
4603   if (!server->standalone && (add || del))
4604     silc_server_send_notify_ban(server, server->router->connection,
4605                                 server->server_type == SILC_ROUTER ?
4606                                 TRUE : FALSE, channel, add, del);
4607
4608   /* Send the reply back to the client */
4609   if (channel->ban_list)
4610     packet = 
4611       silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
4612                                            SILC_STATUS_OK, ident, 2,
4613                                            2, id, id_len,
4614                                            3, channel->ban_list, 
4615                                            strlen(channel->ban_list) - 1);
4616   else
4617     packet = 
4618       silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
4619                                            SILC_STATUS_OK, ident, 1,
4620                                            2, id, id_len);
4621
4622   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
4623                           packet->data, packet->len, FALSE);
4624     
4625   silc_buffer_free(packet);
4626
4627  out:
4628   if (channel_id)
4629     silc_free(channel_id);
4630   silc_server_command_free(cmd);
4631 }