updates.
[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
45 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
46                                       const char *name, int automatic)
47 {
48   SILC_CHANNEL_REC *rec;
49
50   g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
51   g_return_val_if_fail(name != NULL, NULL);
52
53   rec = g_new0(SILC_CHANNEL_REC, 1);
54   rec->chat_type = SILC_PROTOCOL;
55   rec->name = g_strdup(name);
56   rec->server = server;
57
58   channel_init((CHANNEL_REC *) rec, automatic);
59   return rec;
60 }
61
62 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
63 {
64   if (!IS_SILC_CHANNEL(channel))
65     return;
66
67   if (channel->server != NULL && !channel->left && !channel->kicked) {
68     /* destroying channel record without actually
69        having left the channel yet */
70     silc_command_exec(channel->server, "PART", channel->name);
71   }
72 }
73
74 static void silc_channels_join(SILC_SERVER_REC *server,
75                                const char *channels, int automatic)
76 {
77   char **list, **tmp, *channel;
78
79   list = g_strsplit(channels, ",", -1);
80   for (tmp = list; *tmp != NULL; tmp++) {
81     channel = **tmp == '#' ? g_strdup(*tmp) :
82       g_strconcat("#", *tmp, NULL);
83     silc_channel_create(server, channel, FALSE);
84     silc_command_exec(server, "JOIN", channel);
85     g_free(channel);
86   }
87   g_strfreev(list);
88 }
89
90 static void sig_connected(SILC_SERVER_REC *server)
91 {
92   if (IS_SILC_SERVER(server))
93     server->channels_join = (void *) silc_channels_join;
94 }
95
96 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
97                                           SilcChannelEntry entry)
98 {
99   GSList *tmp;
100
101   g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
102
103   for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
104     SILC_CHANNEL_REC *rec = tmp->data;
105
106     if (rec->entry == entry)
107       return rec;
108   }
109
110   return NULL;
111 }
112
113 static void event_join(SILC_SERVER_REC *server, va_list va)
114 {
115   SILC_CHANNEL_REC *chanrec;
116   SILC_NICK_REC *nickrec;
117   SilcClientEntry client;
118   SilcChannelEntry channel;
119
120   client = va_arg(va, SilcClientEntry);
121   channel = va_arg(va, SilcChannelEntry);
122
123   if (client == server->conn->local_entry) {
124     /* you joined to channel */
125     chanrec = silc_channel_find(server, channel->channel_name);
126     if (chanrec != NULL && !chanrec->joined)
127       chanrec->entry = channel;
128   } else {
129     chanrec = silc_channel_find_entry(server, channel);
130     if (chanrec != NULL) {
131       SilcChannelUser user;
132
133       silc_list_start(chanrec->entry->clients);
134       while ((user = silc_list_get(chanrec->entry->clients)) != NULL)
135         if (user->client == client) {
136           nickrec = silc_nicklist_insert(chanrec, user, TRUE);
137           break;
138         }
139     }
140   }
141
142   signal_emit("message join", 4, server, channel->channel_name,
143               client->nickname,
144               client->username == NULL ? "" : client->username);
145 }
146
147 static void event_leave(SILC_SERVER_REC *server, va_list va)
148 {
149   SILC_CHANNEL_REC *chanrec;
150   SILC_NICK_REC *nickrec;
151   SilcClientEntry client;
152   SilcChannelEntry channel;
153
154   client = va_arg(va, SilcClientEntry);
155   channel = va_arg(va, SilcChannelEntry);
156
157   signal_emit("message part", 5, server, channel->channel_name,
158               client->nickname, 
159               client->username == NULL ? "" : client->username, "");
160
161   chanrec = silc_channel_find_entry(server, channel);
162   if (chanrec != NULL) {
163     nickrec = silc_nicklist_find(chanrec, client);
164     if (nickrec != NULL)
165       nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
166   }
167 }
168
169 static void event_signoff(SILC_SERVER_REC *server, va_list va)
170 {
171   SilcClientEntry client;
172   GSList *nicks, *tmp;
173
174   client = va_arg(va, SilcClientEntry);
175
176   signal_emit("message quit", 4, server, client->nickname,
177               client->username == NULL ? "" : client->username, "");
178
179   nicks = nicklist_get_same_unique(SERVER(server), client);
180   for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
181     CHANNEL_REC *channel = tmp->data;
182     NICK_REC *nickrec = tmp->next->data;
183     
184     nicklist_remove(channel, nickrec);
185   }
186 }
187
188 static void event_topic(SILC_SERVER_REC *server, va_list va)
189 {
190   SILC_CHANNEL_REC *chanrec;
191   SilcClientEntry client;
192   SilcChannelEntry channel;
193   char *topic;
194
195   client = va_arg(va, SilcClientEntry);
196   topic = va_arg(va, char *);
197   channel = va_arg(va, SilcChannelEntry);
198
199   chanrec = silc_channel_find_entry(server, channel);
200   if (chanrec != NULL) {
201     g_free_not_null(chanrec->topic);
202     chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
203     signal_emit("channel topic changed", 1, chanrec);
204   }
205
206   signal_emit("message topic", 5, server, channel->channel_name,
207               topic, client->nickname, client->username);
208 }
209
210 static void event_invite(SILC_SERVER_REC *server, va_list va)
211 {
212   SilcClientEntry client;
213   SilcChannelEntry channel;
214   
215   client = va_arg(va, SilcClientEntry);
216   channel = va_arg(va, SilcChannelEntry);
217
218   signal_emit("message invite", 4, server, channel->channel_name,
219               client->nickname, client->username);
220 }
221
222 static void event_nick(SILC_SERVER_REC *server, va_list va)
223 {
224   SilcClientEntry oldclient, newclient;
225
226   oldclient = va_arg(va, SilcClientEntry);
227   newclient = va_arg(va, SilcClientEntry);
228
229   nicklist_rename_unique(SERVER(server),
230                          oldclient, oldclient->nickname,
231                          newclient, newclient->nickname);
232
233   signal_emit("message nick", 4, server, newclient->nickname,
234               oldclient->nickname, newclient->username);
235 }
236
237 static void event_cmode(SILC_SERVER_REC *server, va_list va)
238 {
239   SILC_CHANNEL_REC *chanrec;
240   SilcClientEntry client;
241   SilcChannelEntry channel;
242   char *mode;
243   uint32 modei;
244
245   client = va_arg(va, SilcClientEntry);
246   modei = va_arg(va, uint32);
247   channel = va_arg(va, SilcChannelEntry);
248   mode = silc_client_chmode(modei, channel);
249   
250   chanrec = silc_channel_find_entry(server, channel);
251   if (chanrec != NULL) {
252     g_free_not_null(chanrec->mode);
253     chanrec->mode = g_strdup(mode == NULL ? "" : mode);
254     signal_emit("channel mode changed", 1, chanrec);
255   }
256   
257   /*signal_emit("message mode", 5, server, chanrec->name,
258     client->nickname, client->username, mode);*/
259   printtext(server, channel->channel_name, MSGLEVEL_MODES,
260             "mode/%s [%s] by %s", channel->channel_name, mode,
261             client->nickname);
262   
263   g_free(mode);
264 }
265
266 static void event_cumode(SILC_SERVER_REC *server, va_list va)
267 {
268   SILC_CHANNEL_REC *chanrec;
269   SilcClientEntry client, destclient;
270   SilcChannelEntry channel;
271   int mode;
272   char *modestr;
273   
274   client = va_arg(va, SilcClientEntry);
275   mode = va_arg(va, uint32);
276   destclient = va_arg(va, SilcClientEntry);
277   channel = va_arg(va, SilcChannelEntry);
278   
279   modestr = silc_client_chumode(mode);
280   chanrec = silc_channel_find_entry(server, channel);
281   if (chanrec != NULL) {
282     SILC_NICK_REC *nick;
283     
284     if (destclient == server->conn->local_entry) {
285       chanrec->chanop =
286         (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
287     }
288     
289     nick = silc_nicklist_find(chanrec, client);
290     if (nick != NULL) {
291       nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
292       signal_emit("nick mode changed", 2, chanrec, nick);
293     }
294   }
295   
296   /*signal_emit("message mode", 5, server, chanrec->name,
297     client->nickname, client->username, modestr);*/
298   printtext(server, channel->channel_name, MSGLEVEL_MODES,
299             "mode/%s [%s] by %s", channel->channel_name, modestr,
300             client->nickname);
301   
302   g_free(modestr);
303 }
304
305 static void event_motd(SILC_SERVER_REC *server, va_list va)
306 {
307   char *text = va_arg(va, char *);
308
309   if (!settings_get_bool("skip_motd"))
310     printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
311 }
312
313 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
314 {
315
316 }
317
318 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
319 {
320
321 }
322
323 static void event_kick(SILC_SERVER_REC *server, va_list va)
324 {
325
326 }
327
328 static void event_kill(SILC_SERVER_REC *server, va_list va)
329 {
330
331 }
332
333 static void event_ban(SILC_SERVER_REC *server, va_list va)
334 {
335
336 }
337
338 static void command_part(const char *data, SILC_SERVER_REC *server,
339                          WI_ITEM_REC *item)
340 {
341   SILC_CHANNEL_REC *chanrec;
342   
343   if (!IS_SILC_SERVER(server) || !server->connected)
344     return;
345
346   if (*data == '\0') {
347     if (!IS_SILC_CHANNEL(item))
348       cmd_return_error(CMDERR_NOT_JOINED);
349     data = item->name;
350   }
351
352   chanrec = silc_channel_find(server, data);
353   if (chanrec == NULL) 
354     cmd_return_error(CMDERR_CHAN_NOT_FOUND);
355
356   signal_emit("message part", 5, server, chanrec->name,
357               server->nick, "", "");
358   
359   silc_command_exec(server, "LEAVE", chanrec->name);
360   signal_stop();
361   
362   channel_destroy(CHANNEL(chanrec));
363 }
364
365 void silc_channels_init(void)
366 {
367   signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
368   signal_add("server connected", (SIGNAL_FUNC) sig_connected);
369
370   signal_add("silc event join", (SIGNAL_FUNC) event_join);
371   signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
372   signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
373   signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
374   signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
375   signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
376   signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
377   signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
378   signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
379   signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
380   signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
381   signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
382   signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
383   signal_add("silc event ban", (SIGNAL_FUNC) event_ban);
384   
385   command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
386   
387   silc_nicklist_init();
388 }
389
390 void silc_channels_deinit(void)
391 {
392   signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
393   signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
394
395   signal_remove("silc event join", (SIGNAL_FUNC) event_join);
396   signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
397   signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
398   signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
399   signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
400   signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
401   signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
402   signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
403   signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
404   signal_remove("silc event channel_change", 
405                 (SIGNAL_FUNC) event_channel_change);
406   signal_remove("silc event server_signoff", 
407                 (SIGNAL_FUNC) event_server_signoff);
408   signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
409   signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
410   signal_remove("silc event ban", (SIGNAL_FUNC) event_ban);
411   
412   command_unbind("part", (SIGNAL_FUNC) command_part);
413   
414   silc_nicklist_deinit();
415 }