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
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   uint32 modei;
233
234   client = va_arg(va, SilcClientEntry);
235   modei = va_arg(va, uint32);
236   channel = va_arg(va, SilcChannelEntry);
237   mode = silc_client_chmode(modei, channel);
238   
239   chanrec = silc_channel_find_entry(server, channel);
240   if (chanrec != NULL) {
241     g_free_not_null(chanrec->mode);
242     chanrec->mode = g_strdup(mode == NULL ? "" : mode);
243     signal_emit("channel mode changed", 1, chanrec);
244   }
245   
246   /*signal_emit("message mode", 5, server, chanrec->name,
247     client->nickname, client->username, mode);*/
248   printtext(server, channel->channel_name, MSGLEVEL_MODES,
249             "mode/%s [%s] by %s", channel->channel_name, mode,
250             client->nickname);
251   
252   g_free(mode);
253 }
254
255 static void event_cumode(SILC_SERVER_REC *server, va_list va)
256 {
257   SILC_CHANNEL_REC *chanrec;
258   SilcClientEntry client, destclient;
259   SilcChannelEntry channel;
260   int mode;
261   char *modestr;
262   
263   client = va_arg(va, SilcClientEntry);
264   mode = va_arg(va, uint32);
265   destclient = va_arg(va, SilcClientEntry);
266   channel = va_arg(va, SilcChannelEntry);
267   
268   modestr = silc_client_chumode(mode);
269   chanrec = silc_channel_find_entry(server, channel);
270   if (chanrec != NULL) {
271     SILC_NICK_REC *nick;
272     
273     if (destclient == server->conn->local_entry) {
274       chanrec->chanop =
275         (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
276     }
277     
278     nick = silc_nicklist_find(chanrec, client);
279     if (nick != NULL) {
280       nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
281       signal_emit("nick mode changed", 2, chanrec, nick);
282     }
283   }
284   
285   /*signal_emit("message mode", 5, server, chanrec->name,
286     client->nickname, client->username, modestr);*/
287   printtext(server, channel->channel_name, MSGLEVEL_MODES,
288             "mode/%s [%s] by %s", channel->channel_name, modestr,
289             client->nickname);
290   
291   g_free(modestr);
292 }
293
294 static void command_part(const char *data, SILC_SERVER_REC *server,
295                          WI_ITEM_REC *item)
296 {
297         SILC_CHANNEL_REC *chanrec;
298
299         if (!IS_SILC_SERVER(server) || !server->connected)
300                 return;
301
302         if (*data == '\0') {
303                 if (!IS_SILC_CHANNEL(item))
304                         cmd_return_error(CMDERR_NOT_JOINED);
305                 data = item->name;
306         }
307
308         chanrec = silc_channel_find(server, data);
309         if (chanrec == NULL) cmd_return_error(CMDERR_CHAN_NOT_FOUND);
310
311         signal_emit("message part", 5, server, chanrec->name,
312                     server->nick, "", "");
313
314         silc_command_exec(server, "LEAVE", chanrec->name);
315         signal_stop();
316
317         channel_destroy(CHANNEL(chanrec));
318 }
319
320 void silc_channels_init(void)
321 {
322         signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
323         signal_add("server connected", (SIGNAL_FUNC) sig_connected);
324
325         signal_add("silc event join", (SIGNAL_FUNC) event_join);
326         signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
327         signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
328         signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
329         signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
330         signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
331         signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
332         signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
333
334         command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
335
336         silc_nicklist_init();
337 }
338
339 void silc_channels_deinit(void)
340 {
341         signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
342         signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
343
344         signal_remove("silc event join", (SIGNAL_FUNC) event_join);
345         signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
346         signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
347         signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
348         signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
349         signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
350         signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
351         signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
352
353         command_unbind("part", (SIGNAL_FUNC) command_part);
354
355         silc_nicklist_deinit();
356 }