imported.
[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
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "module.h"
22 #include "signals.h"
23 #include "commands.h"
24 #include "levels.h"
25 #include "misc.h"
26 #include "channels-setup.h"
27 #include "levels.h"
28
29 #include "silc-channels.h"
30 #include "silc-nicklist.h"
31
32 #include "fe-common/core/printtext.h"
33
34 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
35                                       const char *name, int automatic)
36 {
37         SILC_CHANNEL_REC *rec;
38
39         g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
40         g_return_val_if_fail(name != NULL, NULL);
41
42         rec = g_new0(SILC_CHANNEL_REC, 1);
43         rec->chat_type = SILC_PROTOCOL;
44         rec->name = g_strdup(name);
45         rec->server = server;
46
47         channel_init((CHANNEL_REC *) rec, automatic);
48         return rec;
49 }
50
51 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
52 {
53         if (!IS_SILC_CHANNEL(channel))
54                 return;
55
56         if (channel->server != NULL && !channel->left && !channel->kicked) {
57                 /* destroying channel record without actually
58                    having left the channel yet */
59                 silc_command_exec(channel->server, "PART", channel->name);
60         }
61 }
62
63 static void silc_channels_join(SILC_SERVER_REC *server,
64                                const char *channels, int automatic)
65 {
66         char **list, **tmp, *channel;
67
68         list = g_strsplit(channels, ",", -1);
69         for (tmp = list; *tmp != NULL; tmp++) {
70                 channel = **tmp == '#' ? g_strdup(*tmp) :
71                         g_strconcat("#", *tmp, NULL);
72                 silc_channel_create(server, channel, FALSE);
73                 silc_command_exec(server, "JOIN", channel);
74                 g_free(channel);
75         }
76         g_strfreev(list);
77 }
78
79 static void sig_connected(SILC_SERVER_REC *server)
80 {
81         if (IS_SILC_SERVER(server))
82                 server->channels_join = (void *) silc_channels_join;
83 }
84
85 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
86                                           SilcChannelEntry entry)
87 {
88         GSList *tmp;
89
90         g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
91
92         for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
93                 SILC_CHANNEL_REC *rec = tmp->data;
94
95                 if (rec->entry == entry)
96                         return rec;
97         }
98
99         return NULL;
100 }
101
102 static void event_join(SILC_SERVER_REC *server, va_list va)
103 {
104         SILC_CHANNEL_REC *chanrec;
105         SILC_NICK_REC *nickrec;
106         SilcClientEntry client;
107         SilcChannelEntry channel;
108
109         client = va_arg(va, SilcClientEntry);
110         channel = va_arg(va, SilcChannelEntry);
111
112         if (client == server->conn->local_entry) {
113                 /* you joined to channel */
114                 chanrec = silc_channel_find(server, channel->channel_name);
115                 if (chanrec != NULL && !chanrec->joined)
116                         chanrec->entry = channel;
117         } else {
118                 chanrec = silc_channel_find_entry(server, channel);
119                 if (chanrec != NULL) {
120                         SilcChannelUser user;
121
122                         silc_list_start(chanrec->entry->clients);
123                         while ((user = silc_list_get(chanrec->entry->clients)) != NULL)
124                                 if (user->client == client) {
125                                         nickrec = silc_nicklist_insert(chanrec, user, TRUE);
126                                         break;
127                                 }
128                 }
129         }
130
131         signal_emit("message join", 4, server, channel->channel_name,
132                     client->nickname,
133                     client->username == NULL ? "" : client->username);
134 }
135
136 static void event_leave(SILC_SERVER_REC *server, va_list va)
137 {
138         SILC_CHANNEL_REC *chanrec;
139         SILC_NICK_REC *nickrec;
140         SilcClientEntry client;
141         SilcChannelEntry channel;
142
143         client = va_arg(va, SilcClientEntry);
144         channel = va_arg(va, SilcChannelEntry);
145
146         signal_emit("message part", 5, server, channel->channel_name,
147                     client->nickname, 
148                     client->username == NULL ? "" : client->username, "");
149
150         chanrec = silc_channel_find_entry(server, channel);
151         if (chanrec != NULL) {
152                 nickrec = silc_nicklist_find(chanrec, client);
153                 if (nickrec != NULL)
154                         nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
155         }
156 }
157
158 static void event_signoff(SILC_SERVER_REC *server, va_list va)
159 {
160         SilcClientEntry client;
161         GSList *nicks, *tmp;
162
163         client = va_arg(va, SilcClientEntry);
164
165         signal_emit("message quit", 4, server, client->nickname,
166                     client->username == NULL ? "" : client->username, "");
167
168         nicks = nicklist_get_same_unique(SERVER(server), client);
169         for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
170                 CHANNEL_REC *channel = tmp->data;
171                 NICK_REC *nickrec = tmp->next->data;
172
173                 nicklist_remove(channel, nickrec);
174         }
175 }
176
177 static void event_topic(SILC_SERVER_REC *server, va_list va)
178 {
179         SILC_CHANNEL_REC *chanrec;
180         SilcClientEntry client;
181         SilcChannelEntry channel;
182         char *topic;
183
184         client = va_arg(va, SilcClientEntry);
185         topic = va_arg(va, char *);
186         channel = va_arg(va, SilcChannelEntry);
187
188         chanrec = silc_channel_find_entry(server, channel);
189         if (chanrec != NULL) {
190                 g_free_not_null(chanrec->topic);
191                 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
192                 signal_emit("channel topic changed", 1, chanrec);
193         }
194
195         signal_emit("message topic", 5, server, channel->channel_name,
196                     topic, client->nickname, client->username);
197 }
198
199 static void event_invite(SILC_SERVER_REC *server, va_list va)
200 {
201         SilcClientEntry client;
202         SilcChannelEntry channel;
203
204         client = va_arg(va, SilcClientEntry);
205         channel = va_arg(va, SilcChannelEntry);
206
207         signal_emit("message invite", 4, server, channel->channel_name,
208                     client->nickname, client->username);
209 }
210
211 static void event_nick(SILC_SERVER_REC *server, va_list va)
212 {
213         SilcClientEntry oldclient, newclient;
214
215         oldclient = va_arg(va, SilcClientEntry);
216         newclient = va_arg(va, SilcClientEntry);
217
218         nicklist_rename_unique(SERVER(server),
219                                oldclient, oldclient->nickname,
220                                newclient, newclient->nickname);
221
222         signal_emit("message nick", 4, server, newclient->nickname,
223                     oldclient->nickname, newclient->username);
224 }
225
226 static void event_cmode(SILC_SERVER_REC *server, va_list va)
227 {
228         SILC_CHANNEL_REC *chanrec;
229         SilcClientEntry client;
230         SilcChannelEntry channel;
231         char *mode;
232
233         client = va_arg(va, SilcClientEntry);
234         mode = silc_client_chmode(va_arg(va, unsigned int));
235         channel = va_arg(va, SilcChannelEntry);
236
237         chanrec = silc_channel_find_entry(server, channel);
238         if (chanrec != NULL) {
239                 g_free_not_null(chanrec->mode);
240                 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
241                 signal_emit("channel mode changed", 1, chanrec);
242         }
243
244         /*signal_emit("message mode", 5, server, chanrec->name,
245                     client->nickname, client->username, mode);*/
246         printtext(server, channel->channel_name, MSGLEVEL_MODES,
247                   "mode/%s [%s] by %s", channel->channel_name, mode,
248                   client->nickname);
249
250         g_free(mode);
251 }
252
253 static void event_cumode(SILC_SERVER_REC *server, va_list va)
254 {
255         SILC_CHANNEL_REC *chanrec;
256         SilcClientEntry client, destclient;
257         SilcChannelEntry channel;
258         int mode;
259         char *modestr;
260
261         client = va_arg(va, SilcClientEntry);
262         mode = va_arg(va, unsigned int);
263         destclient = va_arg(va, SilcClientEntry);
264         channel = va_arg(va, SilcChannelEntry);
265
266         modestr = silc_client_chumode(mode);
267         chanrec = silc_channel_find_entry(server, channel);
268         if (chanrec != NULL) {
269                 SILC_NICK_REC *nick;
270
271                 if (destclient == server->conn->local_entry) {
272                         chanrec->chanop =
273                                 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
274                 }
275
276                 nick = silc_nicklist_find(chanrec, client);
277                 if (nick != NULL) {
278                         nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
279                         signal_emit("nick mode changed", 2, chanrec, nick);
280                 }
281         }
282
283         /*signal_emit("message mode", 5, server, chanrec->name,
284                     client->nickname, client->username, modestr);*/
285         printtext(server, channel->channel_name, MSGLEVEL_MODES,
286                   "mode/%s [%s] by %s", channel->channel_name, modestr,
287                   client->nickname);
288
289         g_free(modestr);
290 }
291
292 static void command_part(const char *data, SILC_SERVER_REC *server,
293                          WI_ITEM_REC *item)
294 {
295         SILC_CHANNEL_REC *chanrec;
296
297         if (!IS_SILC_SERVER(server) || !server->connected)
298                 return;
299
300         if (*data == '\0') {
301                 if (!IS_SILC_CHANNEL(item))
302                         cmd_return_error(CMDERR_NOT_JOINED);
303                 data = item->name;
304         }
305
306         chanrec = silc_channel_find(server, data);
307         if (chanrec == NULL) cmd_return_error(CMDERR_CHAN_NOT_FOUND);
308
309         signal_emit("message part", 5, server, chanrec->name,
310                     server->nick, "", "");
311
312         silc_command_exec(server, "LEAVE", chanrec->name);
313         signal_stop();
314
315         channel_destroy(CHANNEL(chanrec));
316 }
317
318 void silc_channels_init(void)
319 {
320         signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
321         signal_add("server connected", (SIGNAL_FUNC) sig_connected);
322
323         signal_add("silc event join", (SIGNAL_FUNC) event_join);
324         signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
325         signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
326         signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
327         signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
328         signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
329         signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
330         signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
331
332         command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
333
334         silc_nicklist_init();
335 }
336
337 void silc_channels_deinit(void)
338 {
339         signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
340         signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
341
342         signal_remove("silc event join", (SIGNAL_FUNC) event_join);
343         signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
344         signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
345         signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
346         signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
347         signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
348         signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
349         signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
350
351         command_unbind("part", (SIGNAL_FUNC) command_part);
352
353         silc_nicklist_deinit();
354 }