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