06bf0c411f78c817fe8d96f5df2c3dc97dec69cd
[crypto.git] / apps / irssi / src / core / channels.c
1 /*
2  channel.c : irssi
3
4     Copyright (C) 1999-2000 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 "misc.h"
24 #include "special-vars.h"
25
26 #include "servers.h"
27 #include "channels.h"
28 #include "channels-setup.h"
29 #include "nicklist.h"
30
31 GSList *channels; /* List of all channels */
32
33 static char *get_join_data(CHANNEL_REC *channel)
34 {
35         return g_strdup(channel->name);
36 }
37
38 void channel_init(CHANNEL_REC *channel, int automatic)
39 {
40         g_return_if_fail(channel != NULL);
41         g_return_if_fail(channel->name != NULL);
42
43         channels = g_slist_append(channels, channel);
44         if (channel->server != NULL) {
45                 channel->server->channels =
46                         g_slist_append(channel->server->channels, channel);
47         }
48
49         MODULE_DATA_INIT(channel);
50         channel->type = module_get_uniq_id_str("WINDOW ITEM TYPE", "CHANNEL");
51         channel->destroy = (void (*) (WI_ITEM_REC *)) channel_destroy;
52         channel->mode = g_strdup("");
53         channel->createtime = time(NULL);
54         channel->get_join_data = get_join_data;
55
56         signal_emit("channel created", 2, channel, GINT_TO_POINTER(automatic));
57 }
58
59 void channel_destroy(CHANNEL_REC *channel)
60 {
61         g_return_if_fail(IS_CHANNEL(channel));
62
63         if (channel->destroying) return;
64         channel->destroying = TRUE;
65
66         channels = g_slist_remove(channels, channel);
67         if (channel->server != NULL)
68                 channel->server->channels = g_slist_remove(channel->server->channels, channel);
69         signal_emit("channel destroyed", 1, channel);
70
71         MODULE_DATA_DEINIT(channel);
72         g_free_not_null(channel->hilight_color);
73         g_free_not_null(channel->topic);
74         g_free_not_null(channel->topic_by);
75         g_free_not_null(channel->key);
76         g_free(channel->mode);
77         g_free(channel->name);
78
79         channel->type = 0;
80         g_free(channel);
81 }
82
83 static CHANNEL_REC *channel_find_server(SERVER_REC *server,
84                                         const char *name)
85 {
86         GSList *tmp;
87
88         g_return_val_if_fail(IS_SERVER(server), NULL);
89
90         if (server->channel_find_func != NULL) {
91                 /* use the server specific channel find function */
92                 return server->channel_find_func(server, name);
93         }
94
95         for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
96                 CHANNEL_REC *rec = tmp->data;
97
98                 if (g_strcasecmp(name, rec->name) == 0)
99                         return rec;
100         }
101
102         return NULL;
103 }
104
105 CHANNEL_REC *channel_find(SERVER_REC *server, const char *name)
106 {
107         g_return_val_if_fail(server == NULL || IS_SERVER(server), NULL);
108         g_return_val_if_fail(name != NULL, NULL);
109
110         if (server != NULL)
111                 return channel_find_server(server, name);
112
113         /* find from any server */
114         return gslist_foreach_find(servers,
115                                    (FOREACH_FIND_FUNC) channel_find_server,
116                                    (void *) name);
117 }
118
119 static CHANNEL_REC *channel_find_servers(GSList *servers, const char *name)
120 {
121         return gslist_foreach_find(servers,
122                                    (FOREACH_FIND_FUNC) channel_find_server,
123                                    (void *) name);
124 }
125
126 static GSList *servers_find_chatnet_except(SERVER_REC *server)
127 {
128         GSList *tmp, *list;
129
130         list = NULL;
131         for (tmp = servers; tmp != NULL; tmp = tmp->next) {
132                 SERVER_REC *rec = tmp->data;
133
134                 if (server != rec && rec->connrec->chatnet != NULL &&
135                     strcmp(server->connrec->chatnet,
136                            rec->connrec->chatnet) == 0) {
137                         /* chatnets match */
138                         list = g_slist_append(list, rec);
139                 }
140         }
141
142         return list;
143 }
144
145 /* connected to server, autojoin to channels. */
146 static void event_connected(SERVER_REC *server)
147 {
148         GString *chans;
149         GSList *tmp, *chatnet_servers;
150
151         g_return_if_fail(SERVER(server));
152
153         if (server->connrec->reconnection ||
154             server->connrec->no_autojoin_channels)
155                 return;
156
157         /* get list of servers in same chat network */
158         chatnet_servers = server->connrec->chatnet == NULL ? NULL:
159                 servers_find_chatnet_except(server);
160
161         /* join to the channels marked with autojoin in setup */
162         chans = g_string_new(NULL);
163         for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) {
164                 CHANNEL_SETUP_REC *rec = tmp->data;
165
166                 if (!rec->autojoin ||
167                     !channel_chatnet_match(rec->chatnet,
168                                            server->connrec->chatnet))
169                         continue;
170
171                 /* check that we haven't already joined this channel in
172                    same chat network connection.. */
173                 if (channel_find_servers(chatnet_servers, rec->name) == NULL)
174                         g_string_sprintfa(chans, "%s,", rec->name);
175         }
176         g_slist_free(chatnet_servers);
177
178         if (chans->len > 0) {
179                 g_string_truncate(chans, chans->len-1);
180                 server->channels_join(server, chans->str, TRUE);
181         }
182
183         g_string_free(chans, TRUE);
184 }
185
186 static int match_nick_flags(SERVER_REC *server, NICK_REC *nick, char flag)
187 {
188         const char *flags = server->get_nick_flags();
189
190         return strchr(flags, flag) == NULL ||
191                 (flag == flags[0] && nick->op) ||
192                 (flag == flags[1] && (nick->voice || nick->halfop ||
193                                       nick->op)) ||
194                 (flag == flags[2] && (nick->halfop || nick->op));
195 }
196
197 /* Send the auto send command to channel */
198 void channel_send_autocommands(CHANNEL_REC *channel)
199 {
200         CHANNEL_SETUP_REC *rec;
201         NICK_REC *nick;
202         char **bots, **bot;
203
204         g_return_if_fail(IS_CHANNEL(channel));
205
206         if (channel->session_rejoin)
207                 return;
208
209         rec = channel_setup_find(channel->name, channel->server->connrec->chatnet);
210         if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd)
211                 return;
212
213         if (rec->botmasks == NULL || !*rec->botmasks) {
214                 /* just send the command. */
215                 eval_special_string(rec->autosendcmd, "", channel->server, channel);
216                 return;
217         }
218
219         /* find first available bot.. */
220         bots = g_strsplit(rec->botmasks, " ", -1);
221         for (bot = bots; *bot != NULL; bot++) {
222                 const char *botnick = *bot;
223
224                 if (*botnick == '\0')
225                         continue;
226
227                 nick = nicklist_find_mask(channel,
228                                           channel->server->isnickflag(*botnick) ?
229                                           botnick+1 : botnick);
230                 if (nick != NULL &&
231                     match_nick_flags(channel->server, nick, *botnick)) {
232                         eval_special_string(rec->autosendcmd, nick->nick,
233                                             channel->server, channel);
234                         break;
235                 }
236         }
237         g_strfreev(bots);
238 }
239
240 void channels_init(void)
241 {
242         channels_setup_init();
243
244         signal_add("event connected", (SIGNAL_FUNC) event_connected);
245 }
246
247 void channels_deinit(void)
248 {
249         channels_setup_deinit();
250
251         signal_remove("event connected", (SIGNAL_FUNC) event_connected);
252 }