Implemented LEAVE command.
[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 - 2000 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 /*
21  * $Id$
22  * $Log$
23  * Revision 1.3  2000/07/03 05:52:22  priikone
24  *      Implemented LEAVE command.
25  *
26  * Revision 1.2  2000/06/28 05:06:38  priikone
27  *      Shorter timeout for channel joining notify.
28  *
29  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
30  *      Importet from internal CVS/Added Log headers.
31  *
32  *
33  */
34
35 #include "serverincludes.h"
36 #include "server_internal.h"
37
38 /* Server command list. */
39 SilcServerCommand silc_command_list[] =
40 {
41   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
42   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
43   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
44   SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
45   SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
46   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
47   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
48   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
49   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
50   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
51   SILC_SERVER_CMD(connect, CONNECT, 
52                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
53   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
54   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
55   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
56   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
57   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
58   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
59   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
60   SILC_SERVER_CMD(restart, RESTART, 
61                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
62   SILC_SERVER_CMD(close, CLOSE,
63                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
64   SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
65   SILC_SERVER_CMD(silcoper, SILCOPER,
66                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
67   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
68   SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
69
70   { NULL, 0 },
71 };
72
73 /* List of pending commands. */
74 SilcServerCommandPending *silc_command_pending = NULL;
75
76 /* Add new pending command to the list of pending commands. Currently
77    pending commands are executed from command replies, thus we can
78    execute any command after receiving some specific command reply.
79
80    The argument `reply_cmd' is the command reply from where the callback
81    function is to be called, thus, it IS NOT the command to be executed. */
82
83 void silc_server_command_pending(SilcCommand reply_cmd,
84                                  SilcCommandCb callback,
85                                  void *context)
86 {
87   SilcServerCommandPending *reply, *r;
88
89   reply = silc_calloc(1, sizeof(*reply));
90   reply->reply_cmd = reply_cmd;
91   reply->context = context;
92   reply->callback = callback;
93
94   if (silc_command_pending == NULL) {
95     silc_command_pending = reply;
96     return;
97   }
98
99   for (r = silc_command_pending; r; r = r->next) {
100     if (r->next == NULL) {
101       r->next = reply;
102       break;
103     }
104   }
105 }
106
107 /* Deletes pending command by reply command type. */
108
109 void silc_server_command_pending_del(SilcCommand reply_cmd)
110 {
111   SilcServerCommandPending *r, *tmp;
112   
113   if (silc_command_pending) {
114     if (silc_command_pending->reply_cmd == reply_cmd) {
115       silc_free(silc_command_pending);
116       silc_command_pending = NULL;
117       return;
118     }
119
120     for (r = silc_command_pending; r; r = r->next) {
121       if (r->next && r->next->reply_cmd == reply_cmd) {
122         tmp = r->next;
123         r->next = r->next->next;
124         silc_free(tmp);
125         break;
126       }
127     }
128   }
129 }
130
131 /* Free's the command context allocated before executing the command */
132
133 static void silc_server_command_free(SilcServerCommandContext cmd)
134 {
135   if (cmd) {
136     silc_command_free_payload(cmd->payload);
137     silc_free(cmd);
138   }
139 }
140
141 /* Sends command status message as command reply packet. */
142
143 static void 
144 silc_server_command_send_status_msg(SilcServerCommandContext cmd,
145                                     SilcCommand command,
146                                     SilcCommandStatus status,
147                                     unsigned char *msg,
148                                     unsigned int msg_len)
149 {
150   SilcBuffer sp_buf, buffer;
151
152   SILC_LOG_DEBUG(("Sending command status %d", status));
153
154   sp_buf = silc_command_encode_status_payload(status, msg, msg_len);
155   buffer = silc_command_encode_payload_va(command, 1, 
156                                           sp_buf->data, sp_buf->len);
157   silc_server_packet_send(cmd->server, cmd->sock,
158                           SILC_PACKET_COMMAND_REPLY, 0, 
159                           buffer->data, buffer->len, FALSE);
160   silc_buffer_free(buffer);
161   silc_buffer_free(sp_buf);
162 }
163
164 /* Sends simple status message as command reply packet */
165
166 static void 
167 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
168                                       SilcCommand command,
169                                       SilcCommandStatus status)
170 {
171   SilcBuffer sp_buf, buffer;
172
173   SILC_LOG_DEBUG(("Sending command status %d", status));
174
175   sp_buf = silc_command_encode_status_payload(status, NULL, 0);
176   buffer = silc_command_encode_payload_va(command, 1, 
177                                           sp_buf->data, sp_buf->len);
178   silc_server_packet_send(cmd->server, cmd->sock,
179                           SILC_PACKET_COMMAND_REPLY, 0, 
180                           buffer->data, buffer->len, FALSE);
181   silc_buffer_free(buffer);
182   silc_buffer_free(sp_buf);
183 }
184
185 /* Server side of command WHOIS. Processes user's query and sends found 
186    results as command replies back to the client. */
187
188 SILC_SERVER_CMD_FUNC(whois)
189 {
190   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
191   char *tmp, *nick = NULL, *server = NULL;
192   unsigned int argc, count = 0, len;
193   SilcClientList *entry;
194   SilcBuffer sp_buf, packet;
195   unsigned char *id_string;
196
197   SILC_LOG_DEBUG(("Start"));
198
199   argc = silc_command_get_arg_num(cmd->payload);
200   if (argc < 1) {
201     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
202                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
203     goto out;
204   }
205   if (argc > 2) {
206     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
207                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
208     goto out;
209   }
210
211   /* Get the nickname@server string and parse it. */
212   tmp = silc_command_get_first_arg(cmd->payload, NULL);
213   if (tmp) {
214     if (strchr(tmp, '@')) {
215       len = strcspn(tmp, "@");
216       nick = silc_calloc(len + 1, sizeof(char));
217       memcpy(nick, tmp, len);
218       server = silc_calloc(strlen(tmp) - len, sizeof(char));
219       memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
220     } else {
221       nick = strdup(tmp);
222     }
223   } else {
224     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
225                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
226     goto out;
227   }
228
229   /* Get the max count of reply messages allowed */
230   if (argc == 2) {
231     tmp = silc_command_get_next_arg(cmd->payload, NULL);
232     if (!tmp) {
233       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
234                                             SILC_STATUS_ERR_TOO_MANY_PARAMS);
235       if (nick)
236         silc_free(nick);
237       if (server)
238         silc_free(server);
239       goto out;
240     }
241     count = atoi(tmp);
242   }
243
244   /* Then, make the query from our local client list */
245   entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
246                                               nick, server);
247   if (!entry) {
248
249     /* If we are normal server and are connected to a router we will
250        make global query from the router. */
251     if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
252
253       goto ok;
254     }
255     
256     /* If we are router then we will check our global list as well. */
257     if (cmd->server->server_type == SILC_ROUTER) {
258       entry =
259         silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
260                                             nick, server);
261       if (!entry) {
262         silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
263                                             SILC_STATUS_ERR_NO_SUCH_NICK,
264                                             tmp, strlen(tmp));
265         goto out;
266       }
267       goto ok;
268     }
269
270     silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
271                                         SILC_STATUS_ERR_NO_SUCH_NICK,
272                                         tmp, strlen(tmp));
273     goto out;
274   }
275
276  ok:
277   /* XXX, works only for local server info */
278
279   /* Send WHOIS reply */
280   id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
281   tmp = silc_command_get_first_arg(cmd->payload, NULL),
282   sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
283
284   /* XXX */
285   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
286     char nh[256], uh[256];
287     SilcSocketConnection hsock;
288
289     memset(uh, 0, sizeof(uh));
290     memset(nh, 0, sizeof(nh));
291
292     strncat(nh, entry->nickname, strlen(entry->nickname));
293     strncat(nh, "@", 1);
294     len = entry->router ? strlen(entry->router->server_name) :
295       strlen(cmd->server->server_name);
296     strncat(nh, entry->router ? entry->router->server_name :
297             cmd->server->server_name, len);
298
299     strncat(uh, entry->username, strlen(entry->username));
300     strncat(uh, "@", 1);
301     hsock = (SilcSocketConnection)entry->connection;
302     len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
303     strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
304
305     /* XXX */
306     if (entry->userinfo)
307       packet = 
308         silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 5, 
309                                        sp_buf->data, sp_buf->len,
310                                        id_string, SILC_ID_CLIENT_LEN,
311                                        nh, strlen(nh),
312                                        uh, strlen(uh),
313                                        entry->userinfo, 
314                                        strlen(entry->userinfo));
315     else
316       packet = 
317         silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
318                                        sp_buf->data, sp_buf->len,
319                                        id_string, SILC_ID_CLIENT_LEN,
320                                        nh, strlen(nh),
321                                        uh, strlen(uh));
322
323   } else {
324     /* XXX */
325     packet = 
326       silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4, 
327                                      sp_buf->data, sp_buf->len,
328                                      id_string, SILC_ID_CLIENT_LEN,
329                                      entry->nickname, strlen(entry->nickname),
330                                      tmp, strlen(tmp)); /* XXX */
331   }
332   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
333                           0, packet->data, packet->len, FALSE);
334
335   silc_free(id_string);
336   silc_buffer_free(packet);
337   silc_free(sp_buf);
338
339  out:
340   silc_server_command_free(cmd);
341 }
342
343 SILC_SERVER_CMD_FUNC(whowas)
344 {
345 }
346
347 SILC_SERVER_CMD_FUNC(identify)
348 {
349   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
350   char *tmp, *nick = NULL, *server = NULL;
351   unsigned int argc, count = 0, len;
352   SilcClientList *entry;
353   SilcBuffer sp_buf, packet;
354   unsigned char *id_string;
355
356   SILC_LOG_DEBUG(("Start"));
357
358   argc = silc_command_get_arg_num(cmd->payload);
359   if (argc < 1) {
360     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
361                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
362     goto out;
363   }
364   if (argc > 2) {
365     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
366                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
367     goto out;
368   }
369
370   /* Get the nickname@server string and parse it. */
371   tmp = silc_command_get_first_arg(cmd->payload, NULL);
372   if (tmp) {
373     if (strchr(tmp, '@')) {
374       len = strcspn(tmp, "@");
375       nick = silc_calloc(len + 1, sizeof(char));
376       memcpy(nick, tmp, len);
377       server = silc_calloc(strlen(tmp) - len, sizeof(char));
378       memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
379     } else {
380       nick = strdup(tmp);
381     }
382   } else {
383     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
384                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
385     goto out;
386   }
387
388   /* Get the max count of reply messages allowed */
389   if (argc == 2) {
390     tmp = silc_command_get_next_arg(cmd->payload, NULL);
391     if (!tmp) {
392       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
393                                             SILC_STATUS_ERR_TOO_MANY_PARAMS);
394       goto out;
395     }
396     count = atoi(tmp);
397   }
398
399   /* Then, make the query from our local client list */
400   entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
401                                           nick, cmd->server->md5hash);
402   if (!entry) {
403
404     /* If we are normal server and are connected to a router we will
405        make global query from the router. */
406     if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
407       SilcBuffer buffer = cmd->packet->buffer;
408
409       /* Send IDENTIFY command to our router */
410       silc_buffer_push(buffer, buffer->data - buffer->head);
411       silc_server_packet_forward(cmd->server, (SilcSocketConnection)
412                                  cmd->server->id_entry->router->connection,
413                                  buffer->data, buffer->len, TRUE);
414       goto out;
415     }
416     
417     /* If we are router then we will check our global list as well. */
418     if (cmd->server->server_type == SILC_ROUTER) {
419       entry = 
420         silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
421                                         nick, cmd->server->md5hash);
422       if (!entry) {
423         silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
424                                             SILC_STATUS_ERR_NO_SUCH_NICK,
425                                             tmp, strlen(tmp));
426         goto out;
427       }
428       goto ok;
429     }
430
431     silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
432                                         SILC_STATUS_ERR_NO_SUCH_NICK,
433                                         tmp, strlen(tmp));
434     goto out;
435   }
436
437  ok:
438   /* Send IDENTIFY reply */
439   id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
440   tmp = silc_command_get_first_arg(cmd->payload, NULL);
441   sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
442   packet = silc_command_encode_payload_va(SILC_COMMAND_IDENTIFY, 3,
443                                           sp_buf->data, sp_buf->len,
444                                           id_string, SILC_ID_CLIENT_LEN,
445                                           nick, strlen(nick));
446 #if 0
447   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
448     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
449     silc_server_packet_send_dest(cmd->server, cmd->sock, 
450                                  SILC_PACKET_COMMAND_REPLY, 0,
451                                  id, cmd->packet->src_id_type,
452                                  packet->data, packet->len, FALSE);
453     silc_free(id);
454   } else
455 #endif
456     silc_server_packet_send(cmd->server, cmd->sock, 
457                             SILC_PACKET_COMMAND_REPLY, 0, 
458                             packet->data, packet->len, FALSE);
459
460   silc_free(id_string);
461   silc_buffer_free(packet);
462   silc_free(sp_buf);
463
464  out:
465   if (nick)
466     silc_free(nick);
467   if (server)
468     silc_free(server);
469   silc_server_command_free(cmd);
470 }
471
472 /* Checks string for bad characters and returns TRUE if they are found. */
473
474 static int silc_server_command_bad_chars(char *nick)
475 {
476   if (strchr(nick, '\\')) return TRUE;
477   if (strchr(nick, '\"')) return TRUE;
478   if (strchr(nick, '´')) return TRUE;
479   if (strchr(nick, '`')) return TRUE;
480   if (strchr(nick, '\'')) return TRUE;
481   if (strchr(nick, '*')) return TRUE;
482   if (strchr(nick, '/')) return TRUE;
483   if (strchr(nick, '@')) return TRUE;
484
485   return FALSE;
486 }
487
488 /* Server side of command NICK. Sets nickname for user. Setting
489    nickname causes generation of a new client ID for the client. The
490    new client ID is sent to the client after changing the nickname. */
491
492 SILC_SERVER_CMD_FUNC(nick)
493 {
494   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
495   SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
496   SilcServer server = cmd->server;
497   SilcBuffer packet, sp_buf;
498   SilcClientID *new_id;
499   char *id_string;
500   char *nick;
501
502   SILC_LOG_DEBUG(("Start"));
503
504 #define LCC(x) server->local_list->client_cache[(x) - 32]
505 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
506
507   /* Check number of arguments */
508   if (silc_command_get_arg_num(cmd->payload) < 1) {
509     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
510                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
511     goto out;
512   }
513
514   /* Check nickname */
515   nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
516   if (silc_server_command_bad_chars(nick) == TRUE) {
517     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
518                                           SILC_STATUS_ERR_BAD_NICKNAME);
519     goto out;
520   }
521
522   /* Create new Client ID */
523   silc_id_create_client_id(cmd->server->id, cmd->server->rng, 
524                            cmd->server->md5hash, nick,
525                            &new_id);
526
527   /* Send notify about nickname change to our router. We send the new
528      ID and ask to replace it with the old one. */
529   if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
530     silc_server_send_replace_id(server, server->id_entry->router->connection, 
531                                 FALSE, id_entry->id,
532                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
533                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
534
535   /* If we are router we have to distribute the new Client ID to all 
536      routers in SILC. */
537   if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
538     silc_server_send_replace_id(server, server->id_entry->router->connection,  
539                                 TRUE, id_entry->id,
540                                 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
541                                 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
542
543   /* Remove old cache entry */
544   silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
545                          LCCC(id_entry->nickname[0]), 
546                          SILC_ID_CLIENT, id_entry->id); 
547   
548   /* Free old ID */
549   if (id_entry->id) {
550     memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
551     silc_free(id_entry->id);
552   }
553
554   /* Save the nickname as this client is our local client */
555   if (id_entry->nickname)
556     silc_free(id_entry->nickname);
557
558   id_entry->nickname = strdup(nick);
559   id_entry->id = new_id;
560
561   /* Update client cache */
562   LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
563                                    id_entry->nickname, SILC_ID_CLIENT, 
564                                    id_entry->id, (void *)id_entry);
565
566   /* Send the new Client ID as reply command back to client */
567   id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
568   sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
569   packet = silc_command_encode_payload_va(SILC_COMMAND_NICK, 2, 
570                                           sp_buf->data, sp_buf->len,
571                                           id_string, SILC_ID_CLIENT_LEN);
572   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
573                           0, packet->data, packet->len, FALSE);
574
575   silc_free(id_string);
576   silc_buffer_free(packet);
577   silc_free(sp_buf);
578
579  out:
580   silc_server_command_free(cmd);
581 #undef LCC
582 #undef LCCC
583 }
584
585 SILC_SERVER_CMD_FUNC(list)
586 {
587 }
588
589 SILC_SERVER_CMD_FUNC(topic)
590 {
591 }
592
593 SILC_SERVER_CMD_FUNC(invite)
594 {
595 }
596
597 /* Quits connection to client. This gets called if client won't
598    close the connection even when it has issued QUIT command. */
599
600 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
601 {
602   SilcServer server = (SilcServer)context;
603   SilcSocketConnection sock = server->sockets[fd];
604
605   /* Free all client specific data, such as client entry and entires
606      on channels this client may be on. */
607   silc_server_free_sock_user_data(server, sock);
608
609   /* Close the connection on our side */
610   silc_server_close_connection(server, sock);
611 }
612
613 /* Quits SILC session. This is the normal way to disconnect client. */
614  
615 SILC_SERVER_CMD_FUNC(quit)
616 {
617   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
618   SilcServer server = cmd->server;
619   SilcSocketConnection sock = cmd->sock;
620
621   SILC_LOG_DEBUG(("Start"));
622
623   /* We quit the connection with little timeout */
624   silc_task_register(server->timeout_queue, sock->sock,
625                      silc_server_command_quit_cb, server,
626                      0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
627
628   silc_server_command_free(cmd);
629 }
630
631 SILC_SERVER_CMD_FUNC(kill)
632 {
633 }
634
635 SILC_SERVER_CMD_FUNC(info)
636 {
637 }
638
639 SILC_SERVER_CMD_FUNC(connect)
640 {
641 }
642
643 SILC_SERVER_CMD_FUNC(ping)
644 {
645 }
646
647 SILC_SERVER_CMD_FUNC(oper)
648 {
649 }
650
651 typedef struct {
652   char *channel_name;
653   char *nickname;
654   char *username;
655   char *hostname;
656   SilcChannelList *channel;
657   SilcServer server;
658 } JoinInternalContext;
659
660 SILC_TASK_CALLBACK(silc_server_command_join_notify)
661 {
662   JoinInternalContext *ctx = (JoinInternalContext *)context;
663
664   if (ctx->channel->key && ctx->channel->key_len) {
665     silc_server_send_notify_to_channel(ctx->server, ctx->channel,
666                                        "%s (%s@%s) has joined channel %s",
667                                        ctx->nickname, ctx->username,
668                                        ctx->hostname, ctx->channel_name);
669     silc_free(ctx);
670   } else {
671     silc_task_register(ctx->server->timeout_queue, fd,
672                        silc_server_command_join_notify, context,
673                        0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
674   }
675 }
676
677 /* Server side of command JOIN. Joins client into requested channel. If 
678    the channel does not exist it will be created. */
679
680 SILC_SERVER_CMD_FUNC(join)
681 {
682   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
683   SilcServer server = cmd->server;
684   SilcSocketConnection sock = cmd->sock;
685   SilcBuffer buffer = cmd->packet->buffer;
686   int argc, i, tmp_len;
687   char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
688   unsigned char *passphrase, mode[4];
689   SilcChannelList *channel;
690   SilcServerID *router_id;
691   SilcIDCache *id_cache;
692   SilcBuffer packet, sp_buf;
693   SilcClientList *client;
694
695   SILC_LOG_DEBUG(("Start"));
696
697 #define LCC(x) server->local_list->channel_cache[(x) - 32]
698 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
699
700   /* Check number of parameters */
701   argc = silc_command_get_arg_num(cmd->payload);
702   if (argc < 1) {
703     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
704                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
705     goto out;
706   }
707   if (argc > 3) {
708     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
709                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
710     goto out;
711   }
712
713   /* Get channel name */
714   tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
715   channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
716   memcpy(channel_name, tmp, tmp_len);
717   if (silc_server_command_bad_chars(tmp) == TRUE) {
718     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
719                                           SILC_STATUS_ERR_BAD_CHANNEL);
720     silc_free(channel_name);
721     goto out;
722   }
723
724   /* Get passphrase */
725   tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
726   if (tmp) {
727     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
728     memcpy(passphrase, tmp, tmp_len);
729   }
730   
731   /* Get cipher name */
732   cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
733
734   /* See if the channel exists */
735   if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]), 
736                                 channel_name, &id_cache) == FALSE) {
737     /* Channel not found */
738     id_cache = NULL;
739
740     /* If we are standalone server we don't have a router, we just create 
741        the channel by  ourselves. */
742     if (server->standalone) {
743       router_id = server->id;
744       channel = silc_server_new_channel(server, router_id, 
745                                         cipher, channel_name);
746       goto join_channel;
747     }
748
749     /* No channel ID found, the channel does not exist on our server.
750        We send JOIN command to our router which will handle the joining
751        procedure (either creates the channel if it doesn't exist or
752        joins the client to it) - if we are normal server. */
753     if (server->server_type == SILC_SERVER) {
754
755       /* Forward the original JOIN command to the router */
756       silc_buffer_push(buffer, buffer->data - buffer->head);
757       silc_server_packet_forward(server, (SilcSocketConnection)
758                                  server->id_entry->router->connection,
759                                  buffer->data, buffer->len, TRUE);
760       
761       /* Add the command to be pending. It will be re-executed after
762          router has replied back to us. */
763       cmd->pending = TRUE;
764       silc_server_command_pending(SILC_COMMAND_JOIN, 
765                                   silc_server_command_join, context);
766       return;
767     }
768   }
769
770   /* If we are router and the channel does not exist we will check our
771      global list for the channel. */
772   if (!id_cache && server->server_type == SILC_ROUTER) {
773
774     /* Notify all routers about the new channel in SILC network. */
775     if (!server->standalone) {
776 #if 0
777       silc_server_send_new_id(server, server->id_entry->router->connection, 
778                               TRUE,
779                               xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
780 #endif
781     }
782
783   }
784
785   channel = (SilcChannelList *)id_cache->context;
786
787  join_channel:
788
789   /* XXX must check whether the client already is on the channel */
790
791   /* Join the client to the channel */
792   i = channel->user_list_count;
793   channel->user_list = silc_realloc(channel->user_list, 
794                                     sizeof(*channel->user_list) * (i + 1));
795   channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
796
797   /* If the JOIN request was forwarded to us we will make a bit slower
798      query to get the client pointer. Otherwise, we get the client pointer
799      real easy. */
800   if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
801     client = (SilcClientList *)sock->user_data;
802     channel->user_list[i].client = client;
803   } else {
804     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
805     client = silc_idlist_find_client_by_id(server->local_list->clients, id);
806     channel->user_list[i].client = client;
807     silc_free(id);
808   }
809   channel->user_list_count++;
810
811   i = client->channel_count;
812   client->channel = silc_realloc(client->channel, 
813                                  sizeof(*client->channel) * (i + 1));
814   client->channel[i] = channel;
815   client->channel_count++;
816
817   /* Notify router about new user on channel. If we are normal server
818      we send it to our router, if we are router we send it to our
819      primary route. */
820   if (!server->standalone) {
821
822   }
823
824   /* Send command reply to the client. Client receives the Channe ID,
825      channel mode and possibly other information in this reply packet. */
826   if (!cmd->pending) {
827     id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
828     sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
829     SILC_PUT32_MSB(channel->mode, mode);
830
831     if (!channel->topic)
832       packet = 
833         silc_command_encode_payload_va(SILC_COMMAND_JOIN, 4,
834                                        sp_buf->data, sp_buf->len,
835                                        channel_name, strlen(channel_name),
836                                        id_string, SILC_ID_CHANNEL_LEN,
837                                        mode, 4);
838     else
839       packet = 
840         silc_command_encode_payload_va(SILC_COMMAND_JOIN, 5,
841                                        sp_buf->data, sp_buf->len,
842                                        channel_name, strlen(channel_name),
843                                        id_string, SILC_ID_CHANNEL_LEN,
844                                        mode, 4,
845                                        channel->topic, strlen(channel->topic));
846
847     if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
848       void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
849       silc_server_packet_send_dest(cmd->server, cmd->sock, 
850                                    SILC_PACKET_COMMAND_REPLY, 0,
851                                    id, cmd->packet->src_id_type,
852                                    packet->data, packet->len, FALSE);
853       silc_free(id);
854     } else
855       silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
856                               packet->data, packet->len, FALSE);
857     
858     silc_buffer_free(packet);
859     silc_free(sp_buf);
860   }
861
862   /* Send channel key to the client. Client cannot start transmitting
863      to the channel until we have sent the key. */
864   if (!cmd->pending) {
865     tmp_len = strlen(channel->channel_key->cipher->name);
866     packet = 
867       silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, 
868                                       id_string, tmp_len, 
869                                       channel->channel_key->cipher->name,
870                                       channel->key_len / 8, channel->key);
871     
872     silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
873                             packet->data, packet->len, FALSE);
874     silc_buffer_free(packet);
875   }
876
877   if (id_string)
878     silc_free(id_string);
879
880   /* Finally, send notify message to all clients on the channel about
881      new user on the channel. */
882   if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
883     if (!cmd->pending) {
884       silc_server_send_notify_to_channel(server, channel,
885                                          "%s (%s@%s) has joined channel %s",
886                                          client->nickname, client->username,
887                                          sock->hostname ? sock->hostname :
888                                          sock->ip, channel_name);
889     } else {
890       /* This is pending command request. Send the notify after we have
891          received the key for the channel from the router. */
892       JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
893       ctx->channel_name = channel_name;
894       ctx->nickname = client->nickname;
895       ctx->username = client->username;
896       ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
897       ctx->channel = channel;
898       ctx->server = server;
899       silc_task_register(server->timeout_queue, sock->sock,
900                          silc_server_command_join_notify, ctx,
901                          0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
902     }
903   }
904
905  out:
906   silc_server_command_free(cmd);
907 #undef LCC
908 #undef LCCC
909 }
910
911 /* Server side of command MOTD. Sends servers current "message of the
912    day" to the client. */
913
914 SILC_SERVER_CMD_FUNC(motd)
915 {
916
917   SILC_LOG_DEBUG(("Start"));
918
919 }
920
921 SILC_SERVER_CMD_FUNC(umode)
922 {
923 }
924
925 SILC_SERVER_CMD_FUNC(cmode)
926 {
927 }
928
929 SILC_SERVER_CMD_FUNC(kick)
930 {
931 }
932
933 SILC_SERVER_CMD_FUNC(restart)
934 {
935 }
936  
937 SILC_SERVER_CMD_FUNC(close)
938 {
939 }
940  
941 SILC_SERVER_CMD_FUNC(die)
942 {
943 }
944  
945 SILC_SERVER_CMD_FUNC(silcoper)
946 {
947 }
948
949 /* Server side command of LEAVE. Removes client from a channel. */
950
951 SILC_SERVER_CMD_FUNC(leave)
952 {
953   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
954   SilcSocketConnection sock = cmd->sock;
955   SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
956   SilcServer server = cmd->server;
957   SilcChannelID *id;
958   SilcChannelList *channel;
959   SilcBuffer packet;
960   unsigned int i, argc, key_len;
961   unsigned char *tmp, channel_key[32];
962
963   SILC_LOG_DEBUG(("Start"));
964
965   argc = silc_command_get_arg_num(cmd->payload);
966   if (argc < 1) {
967     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
968                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
969     goto out;
970   }
971   if (argc > 2) {
972     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
973                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
974     goto out;
975   }
976
977   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
978   if (!tmp) {
979     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
980                                           SILC_STATUS_ERR_BAD_CHANNEL_ID);
981     goto out;
982   }
983
984   /* Get Channel ID */
985   id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
986
987   /* Get channel entry */
988   channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
989
990   /* Remove client from channel */
991   i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
992   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
993                                         SILC_STATUS_OK);
994
995   /* If the channel does not exist anymore we won't send anything */
996   if (!i)
997     goto out;
998
999   /* Re-generate channel key */
1000   key_len = channel->key_len / 8;
1001   for (i = 0; i < key_len; i++)
1002     channel_key[i] = silc_rng_get_byte(server->rng);
1003   channel->channel_key->cipher->set_key(channel->channel_key->context, 
1004                                         channel_key, key_len);
1005   memset(channel->key, 0, key_len);
1006   silc_free(channel->key);
1007   channel->key = silc_calloc(key_len, sizeof(*channel->key));
1008   memcpy(channel->key, channel_key, key_len);
1009   memset(channel_key, 0, sizeof(channel_key));
1010
1011   /* Encode channel key payload to be distributed on the channel */
1012   packet = 
1013     silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1014                                     strlen(channel->channel_key->cipher->name),
1015                                     channel->channel_key->cipher->name,
1016                                     key_len, channel->key);
1017
1018   /* If we are normal server then we will send it to our router.  If we
1019      are router we will send it to all local servers that has clients on
1020      the channel */
1021   if (server->server_type == SILC_SERVER) {
1022     if (!server->standalone)
1023       silc_server_packet_send(server, 
1024                               cmd->server->id_entry->router->connection,
1025                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1026                               packet->len, TRUE);
1027   } else {
1028
1029   }
1030
1031   /* Send to locally connected clients on the channel */
1032   silc_server_packet_send_local_channel(server, channel, 
1033                                         SILC_PACKET_CHANNEL_KEY, 0,
1034                                         packet->data, packet->len, FALSE);
1035
1036   silc_buffer_free(packet);
1037   silc_free(id);
1038
1039  out:
1040   silc_server_command_free(cmd);
1041 }
1042
1043 SILC_SERVER_CMD_FUNC(names)
1044 {
1045 }