'#' isn't needed as channel prefix anymore
[silc.git] / apps / irssi / src / silc / core / silc-channels.c
1 /*
2   silc-channels.c : irssi
3
4   Copyright (C) 2000 - 2001 Timo Sirainen
5                             Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11   
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16   
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22 #include "module.h"
23
24 #include "net-nonblock.h"
25 #include "net-sendbuffer.h"
26 #include "signals.h"
27 #include "servers.h"
28 #include "commands.h"
29 #include "levels.h"
30 #include "modules.h"
31 #include "rawlog.h"
32 #include "misc.h"
33 #include "settings.h"
34
35 #include "channels-setup.h"
36
37 #include "silc-servers.h"
38 #include "silc-channels.h"
39 #include "silc-queries.h"
40 #include "silc-nicklist.h"
41 #include "window-item-def.h"
42
43 #include "fe-common/core/printtext.h"
44 #include "fe-common/silc/module-formats.h"
45
46 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
47                                       const char *name, int automatic)
48 {
49   SILC_CHANNEL_REC *rec;
50
51   g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
52   g_return_val_if_fail(name != NULL, NULL);
53
54   rec = g_new0(SILC_CHANNEL_REC, 1);
55   rec->chat_type = SILC_PROTOCOL;
56   rec->name = g_strdup(name);
57   rec->server = server;
58
59   channel_init((CHANNEL_REC *) rec, automatic);
60   return rec;
61 }
62
63 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
64 {
65   if (!IS_SILC_CHANNEL(channel))
66     return;
67
68   if (channel->server != NULL && !channel->left && !channel->kicked) {
69     /* destroying channel record without actually
70        having left the channel yet */
71     silc_command_exec(channel->server, "PART", channel->name);
72   }
73 }
74
75 static void silc_channels_join(SILC_SERVER_REC *server,
76                                const char *channels, int automatic)
77 {
78   char **list, **tmp;
79   SILC_CHANNEL_REC *chanrec;
80
81   list = g_strsplit(channels, ",", -1);
82   for (tmp = list; *tmp != NULL; tmp++) {
83     chanrec = silc_channel_find(server, *tmp);
84     if (chanrec)
85       continue;
86
87     silc_command_exec(server, "JOIN", *tmp);
88   }
89
90   g_strfreev(list);
91 }
92
93 static void sig_connected(SILC_SERVER_REC *server)
94 {
95   if (IS_SILC_SERVER(server))
96     server->channels_join = (void *) silc_channels_join;
97 }
98
99 /* "server quit" signal from the core to indicate that QUIT command
100    was called. */
101
102 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
103 {
104   if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
105     silc_command_exec(server, "QUIT", msg);
106 }
107
108 /*
109  * "event join". Joined to a channel.
110  */
111
112 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
113                                           SilcChannelEntry entry)
114 {
115   GSList *tmp;
116
117   g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
118
119   for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
120     SILC_CHANNEL_REC *rec = tmp->data;
121
122     if (rec->entry == entry)
123       return rec;
124   }
125
126   return NULL;
127 }
128
129 static void event_join(SILC_SERVER_REC *server, va_list va)
130 {
131   SILC_CHANNEL_REC *chanrec;
132   SILC_NICK_REC *nickrec;
133   SilcClientEntry client;
134   SilcChannelEntry channel;
135   char userhost[256];
136
137   client = va_arg(va, SilcClientEntry);
138   channel = va_arg(va, SilcChannelEntry);
139
140   if (client == server->conn->local_entry) {
141     /* You joined to channel */
142     chanrec = silc_channel_find(server, channel->channel_name);
143     if (chanrec != NULL && !chanrec->joined)
144       chanrec->entry = channel;
145   } else {
146     chanrec = silc_channel_find_entry(server, channel);
147     if (chanrec != NULL) {
148       SilcChannelUser chu = silc_client_on_channel(channel, client);
149       if (chu)
150         nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
151     }
152   }
153
154   memset(userhost, 0, sizeof(userhost));
155   if (client->username)
156     snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
157              client->username, client->hostname);
158   signal_emit("message join", 4, server, channel->channel_name,
159               client->nickname,
160               client->username == NULL ? "" : userhost);
161 }
162
163 /*
164  * "event leave". Left a channel.
165  */
166
167 static void event_leave(SILC_SERVER_REC *server, va_list va)
168 {
169   SILC_CHANNEL_REC *chanrec;
170   SILC_NICK_REC *nickrec;
171   SilcClientEntry client;
172   SilcChannelEntry channel;
173   char userhost[256];
174
175   client = va_arg(va, SilcClientEntry);
176   channel = va_arg(va, SilcChannelEntry);
177
178   memset(userhost, 0, sizeof(userhost));
179   if (client->username)
180     snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
181              client->username, client->hostname);
182   signal_emit("message part", 5, server, channel->channel_name,
183               client->nickname,  client->username ?  userhost : "", 
184               client->nickname);
185
186   chanrec = silc_channel_find_entry(server, channel);
187   if (chanrec != NULL) {
188     nickrec = silc_nicklist_find(chanrec, client);
189     if (nickrec != NULL)
190       nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
191   }
192 }
193
194 /*
195  * "event signoff". Left the network.
196  */
197
198 static void event_signoff(SILC_SERVER_REC *server, va_list va)
199 {
200   SilcClientEntry client;
201   GSList *nicks, *tmp;
202   char *message;
203   char userhost[256];
204
205   client = va_arg(va, SilcClientEntry);
206   message = va_arg(va, char *);
207
208   silc_server_free_ftp(server, client);
209
210   memset(userhost, 0, sizeof(userhost));
211   if (client->username)
212     snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
213              client->username, client->hostname);
214   signal_emit("message quit", 4, server, client->nickname,
215               client->username ? userhost : "", 
216               message ? message : "");
217
218   nicks = nicklist_get_same_unique(SERVER(server), client);
219   for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
220     CHANNEL_REC *channel = tmp->data;
221     NICK_REC *nickrec = tmp->next->data;
222     
223     nicklist_remove(channel, nickrec);
224   }
225 }
226
227 /*
228  * "event topic". Changed topic.
229  */
230
231 static void event_topic(SILC_SERVER_REC *server, va_list va)
232 {
233   SILC_CHANNEL_REC *chanrec;
234   void *entry;
235   SilcClientEntry client;
236   SilcServerEntry server_entry;
237   SilcChannelEntry channel;
238   char *topic;
239   char userhost[256];
240   SilcIdType idtype;
241
242   idtype = va_arg(va, int);
243   entry = va_arg(va, void *);
244   topic = va_arg(va, char *);
245   channel = va_arg(va, SilcChannelEntry);
246
247   chanrec = silc_channel_find_entry(server, channel);
248   if (chanrec != NULL) {
249     g_free_not_null(chanrec->topic);
250     chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
251     signal_emit("channel topic changed", 1, chanrec);
252   }
253
254   if (idtype == SILC_ID_CLIENT) {
255     client = (SilcClientEntry)entry;
256     memset(userhost, 0, sizeof(userhost));
257     snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
258              client->username, client->hostname);
259     signal_emit("message topic", 5, server, channel->channel_name,
260                 topic, client->nickname, userhost);
261   } else if (idtype == SILC_ID_SERVER) {
262     server_entry = (SilcServerEntry)entry;
263     signal_emit("message topic", 5, server, channel->channel_name,
264                 topic, server_entry->server_name, 
265                 server_entry->server_name);
266   } else {
267     channel = (SilcChannelEntry)entry;
268     signal_emit("message topic", 5, server, channel->channel_name,
269                 topic, channel->channel_name, channel->channel_name);
270   }
271 }
272
273 /*
274  * "event invite". Invited or modified invite list.
275  */
276
277 static void event_invite(SILC_SERVER_REC *server, va_list va)
278 {
279   SilcClientEntry client;
280   SilcChannelEntry channel;
281   char *channel_name;
282   char userhost[256];
283   
284   channel = va_arg(va, SilcChannelEntry);
285   channel_name = va_arg(va, char *);
286   client = va_arg(va, SilcClientEntry);
287
288   memset(userhost, 0, sizeof(userhost));
289   snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
290            client->username, client->hostname);
291   signal_emit("message invite", 4, server, channel ? channel->channel_name :
292               channel_name, client->nickname, userhost);
293 }
294
295 /*
296  * "event nick". Changed nickname.
297  */
298
299 static void event_nick(SILC_SERVER_REC *server, va_list va)
300 {
301   SilcClientEntry oldclient, newclient;
302   char userhost[256];
303
304   oldclient = va_arg(va, SilcClientEntry);
305   newclient = va_arg(va, SilcClientEntry);
306
307   nicklist_rename_unique(SERVER(server),
308                          oldclient, oldclient->nickname,
309                          newclient, newclient->nickname);
310
311   memset(userhost, 0, sizeof(userhost));
312   snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
313            newclient->username, newclient->hostname);
314   signal_emit("message nick", 4, server, newclient->nickname, 
315               oldclient->nickname, userhost);
316 }
317
318 /*
319  * "event cmode". Changed channel mode.
320  */
321
322 static void event_cmode(SILC_SERVER_REC *server, va_list va)
323 {
324   SILC_CHANNEL_REC *chanrec;
325   void *entry;
326   SilcClientEntry client;
327   SilcServerEntry server_entry;
328   SilcChannelEntry channel;
329   char *mode;
330   uint32 modei;
331   SilcIdType idtype;
332
333   idtype = va_arg(va, int);
334   entry = va_arg(va, void *);
335   modei = va_arg(va, uint32);
336   (void)va_arg(va, char *);
337   (void)va_arg(va, char *);
338   channel = va_arg(va, SilcChannelEntry);
339
340   mode = silc_client_chmode(modei, 
341                             channel->channel_key ? 
342                             channel->channel_key->cipher->name : "",
343                             channel->hmac ? 
344                             silc_hmac_get_name(channel->hmac) : "");
345
346   chanrec = silc_channel_find_entry(server, channel);
347   if (chanrec != NULL) {
348     g_free_not_null(chanrec->mode);
349     chanrec->mode = g_strdup(mode == NULL ? "" : mode);
350     signal_emit("channel mode changed", 1, chanrec);
351   }
352   
353   if (idtype == SILC_ID_CLIENT) {
354     client = (SilcClientEntry)entry;
355     printformat_module("fe-common/silc", server, channel->channel_name,
356                        MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
357                        channel->channel_name, mode ? mode : "removed all",
358                        client->nickname);
359   } else {
360     server_entry = (SilcServerEntry)entry;
361     printformat_module("fe-common/silc", server, channel->channel_name,
362                        MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
363                        channel->channel_name, mode ? mode : "removed all",
364                        server_entry->server_name);
365   }
366   
367   g_free(mode);
368 }
369
370 /*
371  * "event cumode". Changed user's mode on channel.
372  */
373
374 static void event_cumode(SILC_SERVER_REC *server, va_list va)
375 {
376   SILC_CHANNEL_REC *chanrec;
377   SilcClientEntry client, destclient;
378   SilcChannelEntry channel;
379   int mode;
380   char *modestr;
381   
382   client = va_arg(va, SilcClientEntry);
383   mode = va_arg(va, uint32);
384   destclient = va_arg(va, SilcClientEntry);
385   channel = va_arg(va, SilcChannelEntry);
386   
387   modestr = silc_client_chumode(mode);
388   chanrec = silc_channel_find_entry(server, channel);
389   if (chanrec != NULL) {
390     SILC_NICK_REC *nick;
391     
392     if (destclient == server->conn->local_entry) {
393       chanrec->chanop =
394         (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
395     }
396
397     nick = silc_nicklist_find(chanrec, destclient);
398     if (nick != NULL) {
399       nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
400       nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
401       signal_emit("nick mode changed", 2, chanrec, nick);
402     }
403   }
404   
405   printformat_module("fe-common/silc", server, channel->channel_name,
406                      MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
407                      channel->channel_name, destclient->nickname, 
408                      modestr ? modestr : "removed all",
409                      client->nickname);
410
411   if (mode & SILC_CHANNEL_UMODE_CHANFO)
412     printformat_module("fe-common/silc", 
413                        server, channel->channel_name, MSGLEVEL_CRAP,
414                        SILCTXT_CHANNEL_FOUNDER,
415                        channel->channel_name, destclient->nickname);
416
417   g_free(modestr);
418 }
419
420 /*
421  * "event motd". Received MOTD.
422  */
423
424 static void event_motd(SILC_SERVER_REC *server, va_list va)
425 {
426   char *text = va_arg(va, char *);
427
428   if (!settings_get_bool("skip_motd"))
429     printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
430 }
431
432 /*
433  * "event channel_change". Channel ID has changed.
434  */
435
436 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
437 {
438   /* Nothing interesting to do */
439 }
440
441 /*
442  * "event server_signoff". Server has quit the network.
443  */
444
445 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
446 {
447   SilcClientEntry *clients;
448   uint32 clients_count;
449   int i;
450   char userhost[256];
451   
452   (void)va_arg(va, void *);
453   clients = va_arg(va, SilcClientEntry *);
454   clients_count = va_arg(va, uint32);
455   
456   for (i = 0; i < clients_count; i++) {
457     GSList *nicks, *tmp;
458
459     memset(userhost, 0, sizeof(userhost));
460     if (clients[i]->username)
461       snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
462                clients[i]->username, clients[i]->hostname);
463     signal_emit("message quit", 4, server, clients[i]->nickname,
464                 clients[i]->username ? userhost : "", 
465                 "server signoff");
466
467     silc_server_free_ftp(server, clients[i]);
468
469     nicks = nicklist_get_same_unique(SERVER(server), clients[i]);
470     for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
471       CHANNEL_REC *channel = tmp->data;
472       NICK_REC *nickrec = tmp->next->data;
473       nicklist_remove(channel, nickrec);
474     }
475   }
476 }
477
478 /*
479  * "event kick". Someone was kicked from channel.
480  */
481
482 static void event_kick(SILC_SERVER_REC *server, va_list va)
483 {
484   SilcClientConnection conn = server->conn;
485   SilcClientEntry client_entry, kicker;
486   SilcChannelEntry channel_entry;
487   char *tmp;
488   SILC_CHANNEL_REC *chanrec;
489
490   client_entry = va_arg(va, SilcClientEntry);
491   tmp = va_arg(va, char *);
492   kicker = va_arg(va, SilcClientEntry);
493   channel_entry = va_arg(va, SilcChannelEntry);
494
495   chanrec = silc_channel_find_entry(server, channel_entry);
496   
497   if (client_entry == conn->local_entry) {
498     printformat_module("fe-common/silc", server, channel_entry->channel_name,
499                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU, 
500                        kicker->nickname,
501                        channel_entry->channel_name, tmp ? tmp : "");
502     if (chanrec) {
503       chanrec->kicked = TRUE;
504       channel_destroy((CHANNEL_REC *)chanrec);
505     }
506   } else {
507     printformat_module("fe-common/silc", server, channel_entry->channel_name,
508                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED, 
509                        client_entry->nickname,
510                        kicker->nickname,
511                        channel_entry->channel_name, tmp ? tmp : "");
512
513     if (chanrec) {
514       SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
515       if (nickrec != NULL)
516         nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
517     }
518   }
519 }
520
521 /*
522  * "event kill". Someone was killed from the network.
523  */
524
525 static void event_kill(SILC_SERVER_REC *server, va_list va)
526 {
527   SilcClientConnection conn = server->conn;
528   SilcClientEntry client_entry;
529   char *tmp;
530
531   client_entry = va_arg(va, SilcClientEntry);
532   tmp = va_arg(va, char *);
533   
534   if (client_entry == conn->local_entry) {
535     printformat_module("fe-common/silc", server, NULL,
536                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU, 
537                        tmp ? tmp : "");
538   } else {
539     GSList *nicks, *tmpn;
540     nicks = nicklist_get_same_unique(SERVER(server), client_entry);
541     for (tmpn = nicks; tmpn != NULL; tmpn = tmpn->next->next) {
542       CHANNEL_REC *channel = tmpn->data;
543       NICK_REC *nickrec = tmpn->next->data;
544       nicklist_remove(channel, nickrec);
545     }
546
547     printformat_module("fe-common/silc", server, NULL,
548                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED, 
549                        client_entry->nickname,
550                        tmp ? tmp : "");
551   }
552 }
553
554 /* PART (LEAVE) command. */
555
556 static void command_part(const char *data, SILC_SERVER_REC *server,
557                          WI_ITEM_REC *item)
558 {
559   SILC_CHANNEL_REC *chanrec;
560   char userhost[256];
561   
562   if (!IS_SILC_SERVER(server) || !server->connected)
563     cmd_return_error(CMDERR_NOT_CONNECTED);
564
565   if (!strcmp(data, "*") || *data == '\0') {
566     if (!IS_SILC_CHANNEL(item))
567       cmd_return_error(CMDERR_NOT_JOINED);
568     data = item->name;
569   }
570
571   chanrec = silc_channel_find(server, data);
572   if (chanrec == NULL) 
573     cmd_return_error(CMDERR_CHAN_NOT_FOUND);
574
575   memset(userhost, 0, sizeof(userhost));
576   snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
577            server->conn->local_entry->username, 
578            server->conn->local_entry->hostname);
579   signal_emit("message part", 5, server, chanrec->name,
580               server->nick, userhost, "");
581   
582   silc_command_exec(server, "LEAVE", chanrec->name);
583   signal_stop();
584   
585   channel_destroy(CHANNEL(chanrec));
586 }
587
588 /* ME local command. */
589
590 static void command_me(const char *data, SILC_SERVER_REC *server,
591                        WI_ITEM_REC *item)
592 {
593   SILC_CHANNEL_REC *chanrec;
594   char *tmpcmd = "ME", *tmp;
595   uint32 argc = 0;
596   unsigned char **argv;
597   uint32 *argv_lens, *argv_types;
598   int i;
599  
600   if (!IS_SILC_SERVER(server) || !server->connected)
601     cmd_return_error(CMDERR_NOT_CONNECTED);
602
603   if (!IS_SILC_CHANNEL(item))
604     cmd_return_error(CMDERR_NOT_JOINED);
605
606   /* Now parse all arguments */
607   tmp = g_strconcat(tmpcmd, " ", data, NULL);
608   silc_parse_command_line(tmp, &argv, &argv_lens,
609                           &argv_types, &argc, 2);
610   g_free(tmp);
611
612   if (argc < 2)
613     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
614
615   chanrec = silc_channel_find(server, item->name);
616   if (chanrec == NULL) 
617     cmd_return_error(CMDERR_CHAN_NOT_FOUND);
618
619   /* Send the action message */
620   silc_client_send_channel_message(silc_client, server->conn, 
621                                    chanrec->entry, NULL,
622                                    SILC_MESSAGE_FLAG_ACTION, 
623                                    argv[1], argv_lens[1], TRUE);
624
625   printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
626                      MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION, 
627                      server->conn->local_entry->nickname, argv[1]);
628
629   for (i = 0; i < argc; i++)
630     silc_free(argv[i]);
631   silc_free(argv_lens);
632   silc_free(argv_types);
633 }
634
635 /* ACTION local command. Same as ME but takes the channel as mandatory
636    argument. */
637
638 static void command_action(const char *data, SILC_SERVER_REC *server,
639                            WI_ITEM_REC *item)
640 {
641   SILC_CHANNEL_REC *chanrec;
642   char *tmpcmd = "ME", *tmp;
643   uint32 argc = 0;
644   unsigned char **argv;
645   uint32 *argv_lens, *argv_types;
646   int i;
647  
648   if (!IS_SILC_SERVER(server) || !server->connected)
649     cmd_return_error(CMDERR_NOT_CONNECTED);
650
651   if (!IS_SILC_CHANNEL(item))
652     cmd_return_error(CMDERR_NOT_JOINED);
653
654   /* Now parse all arguments */
655   tmp = g_strconcat(tmpcmd, " ", data, NULL);
656   silc_parse_command_line(tmp, &argv, &argv_lens,
657                           &argv_types, &argc, 3);
658   g_free(tmp);
659
660   if (argc < 3)
661     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
662
663   chanrec = silc_channel_find(server, argv[1]);
664   if (chanrec == NULL) 
665     cmd_return_error(CMDERR_CHAN_NOT_FOUND);
666
667   /* Send the action message */
668   silc_client_send_channel_message(silc_client, server->conn, 
669                                    chanrec->entry, NULL,
670                                    SILC_MESSAGE_FLAG_ACTION, 
671                                    argv[2], argv_lens[2], TRUE);
672
673   printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
674                      MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION, 
675                      server->conn->local_entry->nickname, argv[2]);
676
677   for (i = 0; i < argc; i++)
678     silc_free(argv[i]);
679   silc_free(argv_lens);
680   silc_free(argv_types);
681 }
682
683 /* NOTICE local command. */
684
685 static void command_notice(const char *data, SILC_SERVER_REC *server,
686                            WI_ITEM_REC *item)
687 {
688   SILC_CHANNEL_REC *chanrec;
689   char *tmpcmd = "ME", *tmp;
690   uint32 argc = 0;
691   unsigned char **argv;
692   uint32 *argv_lens, *argv_types;
693   int i;
694  
695   if (!IS_SILC_SERVER(server) || !server->connected)
696     cmd_return_error(CMDERR_NOT_CONNECTED);
697
698   if (!IS_SILC_CHANNEL(item))
699     cmd_return_error(CMDERR_NOT_JOINED);
700
701   /* Now parse all arguments */
702   tmp = g_strconcat(tmpcmd, " ", data, NULL);
703   silc_parse_command_line(tmp, &argv, &argv_lens,
704                           &argv_types, &argc, 2);
705   g_free(tmp);
706
707   if (argc < 2)
708     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
709
710   chanrec = silc_channel_find(server, item->name);
711   if (chanrec == NULL) 
712     cmd_return_error(CMDERR_CHAN_NOT_FOUND);
713
714   /* Send the action message */
715   silc_client_send_channel_message(silc_client, server->conn, 
716                                    chanrec->entry, NULL,
717                                    SILC_MESSAGE_FLAG_NOTICE, 
718                                    argv[1], argv_lens[1], TRUE);
719
720   printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
721                      MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE, 
722                      server->conn->local_entry->nickname, argv[1]);
723
724   for (i = 0; i < argc; i++)
725     silc_free(argv[i]);
726   silc_free(argv_lens);
727   silc_free(argv_types);
728 }
729
730 /* AWAY local command.  Sends UMODE command that sets the SILC_UMODE_GONE
731    flag. */
732
733 static void command_away(const char *data, SILC_SERVER_REC *server,
734                          WI_ITEM_REC *item)
735 {
736   bool set;
737
738   if (!IS_SILC_SERVER(server) || !server->connected)
739     cmd_return_error(CMDERR_NOT_CONNECTED);
740
741   if (*data == '\0') {
742     /* Remove any possible away message */
743     silc_client_set_away_message(silc_client, server->conn, NULL);
744     set = FALSE;
745
746     printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, 
747                        SILCTXT_UNSET_AWAY);
748   } else {
749     /* Set the away message */
750     silc_client_set_away_message(silc_client, server->conn, (char *)data);
751     set = TRUE;
752
753     printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, 
754                        SILCTXT_SET_AWAY, data);
755   }
756
757   signal_emit("away mode changed", 1, server);
758
759   silc_command_exec(server, "UMODE", set ? "+g" : "-g");
760 }
761
762 typedef struct {
763   int type;                     /* 1 = msg, 2 = channel */
764   bool responder;
765   SILC_SERVER_REC *server;
766 } *KeyInternal;
767
768 /* Key agreement callback that is called after the key agreement protocol
769    has been performed. This is called also if error occured during the
770    key agreement protocol. The `key' is the allocated key material and
771    the caller is responsible of freeing it. The `key' is NULL if error
772    has occured. The application can freely use the `key' to whatever
773    purpose it needs. See lib/silcske/silcske.h for the definition of
774    the SilcSKEKeyMaterial structure. */
775
776 static void keyagr_completion(SilcClient client,
777                               SilcClientConnection conn,
778                               SilcClientEntry client_entry,
779                               SilcKeyAgreementStatus status,
780                               SilcSKEKeyMaterial *key,
781                               void *context)
782 {
783   KeyInternal i = (KeyInternal)context;
784
785   switch(status) {
786   case SILC_KEY_AGREEMENT_OK:
787     printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
788                        SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
789
790     if (i->type == 1) {
791       /* Set the private key for this client */
792       silc_client_del_private_message_key(client, conn, client_entry);
793       silc_client_add_private_message_key_ske(client, conn, client_entry,
794                                               NULL, key, i->responder);
795       printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
796                          SILCTXT_KEY_AGREEMENT_PRIVMSG, 
797                          client_entry->nickname);
798       silc_ske_free_key_material(key);
799     }
800     
801     break;
802     
803   case SILC_KEY_AGREEMENT_ERROR:
804     printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
805                        SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
806     break;
807     
808   case SILC_KEY_AGREEMENT_FAILURE:
809     printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
810                        SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
811     break;
812     
813   case SILC_KEY_AGREEMENT_TIMEOUT:
814     printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
815                        SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
816     break;
817     
818   case SILC_KEY_AGREEMENT_ABORTED:
819     printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
820                        SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
821     break;
822     
823   default:
824     break;
825   } 
826
827   if (i)
828     silc_free(i);
829 }
830
831 /* Local command KEY. This command is used to set and unset private
832    keys for channels, set and unset private keys for private messages
833    with remote clients and to send key agreement requests and
834    negotiate the key agreement protocol with remote client.  The
835    key agreement is supported only to negotiate private message keys,
836    it currently cannot be used to negotiate private keys for channels,
837    as it is not convenient for that purpose. */
838
839 typedef struct {
840   SILC_SERVER_REC *server;
841   char *data;
842   char *nick;
843   WI_ITEM_REC *item;
844 } *KeyGetClients;
845
846 /* Callback to be called after client information is resolved from the
847    server. */
848
849 static void silc_client_command_key_get_clients(SilcClient client,
850                                                 SilcClientConnection conn,
851                                                 SilcClientEntry *clients,
852                                                 uint32 clients_count,
853                                                 void *context)
854 {
855   KeyGetClients internal = (KeyGetClients)context;
856
857   if (!clients) {
858     printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s", 
859               internal->nick);
860     silc_free(internal->data);
861     silc_free(internal->nick);
862     silc_free(internal);
863     return;
864   }
865
866   signal_emit("command key", 3, internal->data, internal->server,
867               internal->item);
868
869   silc_free(internal->data);
870   silc_free(internal->nick);
871   silc_free(internal);
872 }
873
874 static void command_key(const char *data, SILC_SERVER_REC *server,
875                         WI_ITEM_REC *item)
876 {
877   SilcClientConnection conn;
878   SilcClientEntry *entrys, client_entry = NULL;
879   uint32 entry_count;
880   SilcChannelEntry channel_entry = NULL;
881   char *nickname = NULL, *tmp;
882   int command = 0, port = 0, type = 0;
883   char *hostname = NULL;
884   KeyInternal internal = NULL;
885   uint32 argc = 0;
886   unsigned char **argv;
887   uint32 *argv_lens, *argv_types;
888   char *bindhost = NULL;
889  
890   if (!server || !IS_SILC_SERVER(server) || !server->connected)
891     cmd_return_error(CMDERR_NOT_CONNECTED);
892
893   conn = server->conn;
894
895   /* Now parse all arguments */
896   tmp = g_strconcat("KEY", " ", data, NULL);
897   silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
898   g_free(tmp);
899
900   if (argc < 4)
901     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
902
903   /* Get type */
904   if (!strcasecmp(argv[1], "msg"))
905     type = 1;
906   if (!strcasecmp(argv[1], "channel"))
907     type = 2;
908
909   if (type == 0)
910     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
911
912   if (type == 1) {
913     if (argv[2][0] == '*') {
914       nickname = strdup("*");
915     } else {
916       /* Parse the typed nickname. */
917       if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
918         printformat_module("fe-common/silc", server, NULL,
919                            MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
920         return;
921       }
922       
923       /* Find client entry */
924       entrys = silc_client_get_clients_local(silc_client, conn, nickname,
925                                              argv[2], &entry_count);
926       if (!entrys) {
927         KeyGetClients inter = silc_calloc(1, sizeof(*inter));
928         inter->server = server;
929         inter->data = strdup(data);
930         inter->nick = strdup(nickname);
931         inter->item = item;
932         silc_client_get_clients(silc_client, conn, nickname, argv[2],
933                                 silc_client_command_key_get_clients, inter);
934         goto out;
935       }
936       client_entry = entrys[0];
937       silc_free(entrys);
938     }
939   }
940
941   if (type == 2) {
942     /* Get channel entry */
943     char *name;
944
945     if (argv[2][0] == '*') {
946       if (!conn->current_channel) {
947         silc_free(nickname);
948         cmd_return_error(CMDERR_NOT_JOINED);
949       }
950       name = conn->current_channel->channel_name;
951     } else {
952       name = argv[2];
953     }
954
955     channel_entry = silc_client_get_channel(silc_client, conn, name);
956     if (!channel_entry) {
957       silc_free(nickname);
958       cmd_return_error(CMDERR_NOT_JOINED);
959     }
960   }
961
962   /* Set command */
963   if (!strcasecmp(argv[3], "set")) {
964     command = 1;
965
966     if (argc >= 5) {
967       if (type == 1 && client_entry) {
968         /* Set private message key */
969         
970         silc_client_del_private_message_key(silc_client, conn, client_entry);
971
972         if (argc >= 6)
973           silc_client_add_private_message_key(silc_client, conn, client_entry,
974                                               argv[5], argv[4],
975                                               argv_lens[4],
976                                               (argv[4][0] == '*' ?
977                                                TRUE : FALSE), FALSE);
978         else
979           silc_client_add_private_message_key(silc_client, conn, client_entry,
980                                               NULL, argv[4],
981                                               argv_lens[4],
982                                               (argv[4][0] == '*' ?
983                                                TRUE : FALSE), FALSE);
984
985         /* Send the key to the remote client so that it starts using it
986            too. */
987         silc_client_send_private_message_key(silc_client, conn, 
988                                              client_entry, TRUE);
989       } else if (type == 2) {
990         /* Set private channel key */
991         char *cipher = NULL, *hmac = NULL;
992
993         if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
994           printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
995                              SILCTXT_CH_PRIVATE_KEY_NOMODE, 
996                              channel_entry->channel_name);
997           goto out;
998         }
999
1000         if (argc >= 6)
1001           cipher = argv[5];
1002         if (argc >= 7)
1003           hmac = argv[6];
1004
1005         if (!silc_client_add_channel_private_key(silc_client, conn, 
1006                                                  channel_entry,
1007                                                  cipher, hmac,
1008                                                  argv[4],
1009                                                  argv_lens[4])) {
1010           printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1011                              SILCTXT_CH_PRIVATE_KEY_ERROR, 
1012                              channel_entry->channel_name);
1013           goto out;
1014         }
1015
1016         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1017                            SILCTXT_CH_PRIVATE_KEY_ADD, 
1018                            channel_entry->channel_name);
1019       }
1020     }
1021
1022     goto out;
1023   }
1024   
1025   /* Unset command */
1026   if (!strcasecmp(argv[3], "unset")) {
1027     command = 2;
1028
1029     if (type == 1 && client_entry) {
1030       /* Unset private message key */
1031       silc_client_del_private_message_key(silc_client, conn, client_entry);
1032     } else if (type == 2) {
1033       /* Unset channel key(s) */
1034       SilcChannelPrivateKey *keys;
1035       uint32 keys_count;
1036       int number;
1037
1038       if (argc == 4)
1039         silc_client_del_channel_private_keys(silc_client, conn, 
1040                                              channel_entry);
1041
1042       if (argc > 4) {
1043         number = atoi(argv[4]);
1044         keys = silc_client_list_channel_private_keys(silc_client, conn, 
1045                                                      channel_entry,
1046                                                      &keys_count);
1047         if (!keys)
1048           goto out;
1049
1050         if (!number || number > keys_count) {
1051           silc_client_free_channel_private_keys(keys, keys_count);
1052           goto out;
1053         }
1054
1055         silc_client_del_channel_private_key(silc_client, conn, channel_entry,
1056                                             keys[number - 1]);
1057         silc_client_free_channel_private_keys(keys, keys_count);
1058       }
1059
1060       goto out;
1061     }
1062   }
1063
1064   /* List command */
1065   if (!strcasecmp(argv[3], "list")) {
1066     command = 3;
1067
1068     if (type == 1) {
1069       SilcPrivateMessageKeys keys;
1070       uint32 keys_count;
1071       int k, i, len;
1072       char buf[1024];
1073
1074       keys = silc_client_list_private_message_keys(silc_client, conn, 
1075                                                    &keys_count);
1076       if (!keys)
1077         goto out;
1078
1079       /* list the private message key(s) */
1080       if (nickname[0] == '*') {
1081         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1082                            SILCTXT_PRIVATE_KEY_LIST);
1083         for (k = 0; k < keys_count; k++) {
1084           memset(buf, 0, sizeof(buf));
1085           strncat(buf, "  ", 2);
1086           len = strlen(keys[k].client_entry->nickname);
1087           strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1088           if (len < 30)
1089             for (i = 0; i < 30 - len; i++)
1090               strcat(buf, " ");
1091           strcat(buf, " ");
1092           
1093           len = strlen(keys[k].cipher);
1094           strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1095           if (len < 14)
1096             for (i = 0; i < 14 - len; i++)
1097               strcat(buf, " ");
1098           strcat(buf, " ");
1099
1100           if (keys[k].key)
1101             strcat(buf, "<hidden>");
1102           else
1103             strcat(buf, "*generated*");
1104
1105           silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1106         }
1107       } else {
1108         printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1109                            SILCTXT_PRIVATE_KEY_LIST_NICK,
1110                            client_entry->nickname);
1111         for (k = 0; k < keys_count; k++) {
1112           if (keys[k].client_entry != client_entry)
1113             continue;
1114
1115           memset(buf, 0, sizeof(buf));
1116           strncat(buf, "  ", 2);
1117           len = strlen(keys[k].client_entry->nickname);
1118           strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
1119           if (len < 30)
1120             for (i = 0; i < 30 - len; i++)
1121               strcat(buf, " ");
1122           strcat(buf, " ");
1123           
1124           len = strlen(keys[k].cipher);
1125           strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
1126           if (len < 14)
1127             for (i = 0; i < 14 - len; i++)
1128               strcat(buf, " ");
1129           strcat(buf, " ");
1130
1131           if (keys[k].key)
1132             strcat(buf, "<hidden>");
1133           else
1134             strcat(buf, "*generated*");
1135
1136           silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1137         }
1138       }
1139
1140       silc_client_free_private_message_keys(keys, keys_count);
1141
1142     } else if (type == 2) {
1143       SilcChannelPrivateKey *keys;
1144       uint32 keys_count;
1145       int k, i, len;
1146       char buf[1024];
1147
1148       keys = silc_client_list_channel_private_keys(silc_client, conn, 
1149                                                    channel_entry,
1150                                                    &keys_count);
1151
1152       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1153                          SILCTXT_CH_PRIVATE_KEY_LIST,
1154                          channel_entry->channel_name);
1155
1156       if (!keys)
1157         goto out;
1158       
1159       for (k = 0; k < keys_count; k++) {
1160         memset(buf, 0, sizeof(buf));
1161         strncat(buf, "  ", 2);
1162
1163         len = strlen(keys[k]->cipher->cipher->name);
1164         strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
1165         if (len < 16)
1166           for (i = 0; i < 16 - len; i++)
1167             strcat(buf, " ");
1168         strcat(buf, " ");
1169         
1170         len = strlen(silc_hmac_get_name(keys[k]->hmac));
1171         strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
1172         if (len < 16)
1173           for (i = 0; i < 16 - len; i++)
1174             strcat(buf, " ");
1175         strcat(buf, " ");
1176         
1177         strcat(buf, "<hidden>");
1178
1179         silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
1180       }
1181       
1182       silc_client_free_channel_private_keys(keys, keys_count);
1183     }
1184
1185     goto out;
1186   }
1187
1188   /* Send command is used to send key agreement */
1189   if (!strcasecmp(argv[3], "agreement")) {
1190     command = 4;
1191
1192     if (argc >= 5)
1193       hostname = argv[4];
1194     if (argc >= 6)
1195       port = atoi(argv[5]);
1196
1197     internal = silc_calloc(1, sizeof(*internal));
1198     internal->type = type;
1199     internal->server = server;
1200     
1201     if (!hostname) {
1202       if (settings_get_bool("use_auto_addr")) {
1203        
1204         hostname = (char *)settings_get_str("auto_public_ip");
1205
1206 /* If the hostname isn't set, treat this case as if auto_public_ip wasn't
1207  * set.
1208  */
1209         if ((hostname) && (*hostname == '\0')) {
1210            hostname = NULL;
1211         }
1212         else {
1213           bindhost = (char *)settings_get_str("auto_bind_ip");
1214             
1215 /* if the bind_ip isn't set, but the public_ip IS, then assume then
1216  * public_ip is the same value as the bind_ip.
1217  */
1218           if ((bindhost) && (*bindhost == '\0')) {
1219             bindhost = hostname;
1220           }
1221            port = settings_get_int("auto_bind_port");
1222         }
1223       }  /* if use_auto_addr */
1224     }
1225   }
1226
1227   /* Start command is used to start key agreement (after receiving the
1228      key_agreement client operation). */
1229   if (!strcasecmp(argv[3], "negotiate")) {
1230     command = 5;
1231
1232     if (argc >= 5)
1233       hostname = argv[4];
1234     if (argc >= 6)
1235       port = atoi(argv[5]);
1236
1237     internal = silc_calloc(1, sizeof(*internal));
1238     internal->type = type;
1239     internal->server = server;
1240   }
1241
1242   if (command == 0) {
1243     silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1244              "Usage: /KEY msg|channel <nickname|channel> "
1245              "set|unset|agreement|negotiate [<arguments>]");
1246     goto out;
1247   }
1248
1249   if (command == 4 && client_entry) {
1250     printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1251                        SILCTXT_KEY_AGREEMENT, argv[2]);
1252     internal->responder = TRUE;
1253     silc_client_send_key_agreement(silc_client, conn, client_entry, hostname, 
1254                                    bindhost, port, 120, keyagr_completion, 
1255                                    internal);
1256     if (!hostname)
1257       silc_free(internal);
1258     goto out;
1259   }
1260
1261   if (command == 5 && client_entry && hostname) {
1262     printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1263                        SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1264     internal->responder = FALSE;
1265     silc_client_perform_key_agreement(silc_client, conn, client_entry, 
1266                                       hostname, port, keyagr_completion, 
1267                                       internal);
1268     goto out;
1269   }
1270
1271  out:
1272   silc_free(nickname);
1273 }
1274
1275 /* Lists locally saved client and server public keys. */
1276
1277 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1278                              WI_ITEM_REC *item)
1279 {
1280
1281 }
1282
1283 void silc_channels_init(void)
1284 {
1285   signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1286   signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1287   signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1288
1289   signal_add("silc event join", (SIGNAL_FUNC) event_join);
1290   signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
1291   signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
1292   signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
1293   signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
1294   signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
1295   signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
1296   signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
1297   signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
1298   signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
1299   signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
1300   signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
1301   signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
1302   
1303   command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1304   command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1305   command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1306   command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1307   command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1308   command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1309   command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1310
1311   silc_nicklist_init();
1312 }
1313
1314 void silc_channels_deinit(void)
1315 {
1316   signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1317   signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1318   signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1319
1320   signal_remove("silc event join", (SIGNAL_FUNC) event_join);
1321   signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
1322   signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
1323   signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
1324   signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
1325   signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
1326   signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
1327   signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
1328   signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
1329   signal_remove("silc event channel_change", 
1330                 (SIGNAL_FUNC) event_channel_change);
1331   signal_remove("silc event server_signoff", 
1332                 (SIGNAL_FUNC) event_server_signoff);
1333   signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
1334   signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
1335   
1336   command_unbind("part", (SIGNAL_FUNC) command_part);
1337   command_unbind("me", (SIGNAL_FUNC) command_me);
1338   command_unbind("action", (SIGNAL_FUNC) command_action);
1339   command_unbind("notice", (SIGNAL_FUNC) command_notice);
1340   command_unbind("away", (SIGNAL_FUNC) command_away);
1341   command_unbind("key", (SIGNAL_FUNC) command_key);
1342   command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1343
1344   silc_nicklist_deinit();
1345 }