ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/modules/protocol/sjoin.c
Revision: 3389
Committed: Fri Apr 25 14:12:15 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 8660 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

# Content
1 /* SJOIN-related functions.
2 *
3 * IRC Services is copyright (c) 1996-2009 Andrew Church.
4 * E-mail: <achurch@achurch.org>
5 * Parts written by Andrew Kempe and others.
6 * This program is free but copyrighted software; see the file GPL.txt for
7 * details.
8 */
9
10 /* If this file is compiled with UNREAL_HACK defined, the create-channel
11 * callback, do_channel_create(), will be modified to force Unreal to
12 * update channel times properly. Defining BAHAMUT_HACK does the same
13 * thing for Bahamut.
14 */
15
16 #include "services.h"
17 #include "modules.h"
18 #include "modules/chanserv/chanserv.h"
19
20 #include "sjoin.h"
21
22 /*************************************************************************/
23
24 static Module *sjoin_module_chanserv;
25
26 int CSSetChannelTime;
27
28 /*************************************************************************/
29
30 /* Handle an SJOIN command.
31 * Bahamut no-SSJOIN format:
32 * av[0] = TS3 timestamp
33 * av[1] = TS3 timestamp (channel creation time)
34 * av[2] = channel
35 * av[3] = channel modes
36 * av[4] = limit / key (depends on modes in av[3])
37 * av[5] = limit / key (depends on modes in av[3])
38 * av[ac-1] = nickname(s), with modes, joining channel
39 * Bahamut SSJOIN (server source) / Hybrid / PTlink / Unreal SJOIN2/SJ3 format:
40 * av[0] = TS3 timestamp (channel creation time)
41 * av[1] = channel
42 * av[2] = modes (limit/key in av[3]/av[4] as needed)
43 * av[ac-1] = users
44 * (Note that Unreal may omit the modes if there aren't any.
45 * Unreal SJ3 also includes bans and exceptions in av[ac-1]
46 * with prefix characters of & and " respectively.)
47 * Bahamut SSJOIN format (client source):
48 * av[0] = TS3 timestamp (channel creation time)
49 * av[1] = channel
50 */
51
52 static void do_sjoin(const char *source, int ac, char **av)
53 {
54 User *user;
55 char *t, *nick;
56 char *channel;
57 Channel *c = NULL, *ctemp;
58
59 if (isdigit(av[1][0])) {
60 /* Plain SJOIN format, zap join timestamp */
61 memmove(&av[0], &av[1], sizeof(char *) * (ac-1));
62 ac--;
63 }
64
65 channel = av[1];
66 if (ac >= 3) {
67 /* SJOIN from server: nick list in last param */
68 t = av[ac-1];
69 } else {
70 /* SJOIN for a single client: source is nick */
71 /* We assume the nick has no spaces, so we can discard const and
72 * use it in the loop */
73 if (strchr(source, ' '))
74 fatal("sjoin: source nick contains spaces!");
75 t = (char *)source;
76 }
77 while (*(nick=t)) {
78 int32 modes = 0, thismode;
79
80 t = nick + strcspn(nick, " ");
81 if (*t)
82 *t++ = 0;
83 if (*nick == '&' || *nick == '"') {
84 /* Ban (&) or exception (") */
85 char *av[3];
86 av[0] = channel;
87 av[1] = (char *)((*nick=='&') ? "+b" : "+e");
88 av[2] = nick+1;
89 do_cmode(source, 3, av);
90 continue;
91 }
92 do {
93 thismode = cumode_prefix_to_flag(*nick);
94 modes |= thismode;
95 } while (thismode && *nick++); /* increment nick only if thismode!=0 */
96 user = get_user(nick);
97 if (!user) {
98 module_log("sjoin: SJOIN to channel %s for non-existent nick %s"
99 " (%s)", channel, nick, merge_args(ac-1, av));
100 continue;
101 }
102 module_log_debug(1, "%s SJOINs %s", nick, channel);
103 if ((ctemp = join_channel(user, channel, modes)) != NULL)
104 c = ctemp;
105 }
106
107 /* Did anyone actually join the channel? */
108 if (c) {
109 /* Store channel timestamp in channel structure, unless we set it
110 * ourselves. */
111 if (!c->ci)
112 c->creation_time = strtotime(av[0], NULL);
113 /* Set channel modes if there are any. Note how argument list is
114 * conveniently set up for do_cmode(). */
115 if (ac > 3)
116 do_cmode(source, ac-2, av+1);
117 }
118 }
119
120 /*************************************************************************/
121
122 /* Clear out all channel modes using an SJOIN (for CLEAR_USERS). */
123
124 static int sjoin_clear_users(const char *sender, Channel *chan, int what,
125 const void *param)
126 {
127 if (what & CLEAR_USERS) {
128 int i;
129 send_cmd(ServerName, "SJOIN %ld %s + :",
130 (long)(chan->creation_time - 1), chan->name);
131 ARRAY_FOREACH (i, chan->excepts)
132 free(chan->excepts[i]);
133 chan->excepts_count = 0;
134 }
135 return 0;
136 }
137
138 /*************************************************************************/
139 /*************************************************************************/
140
141 /* Callback to set the creation time for a registered channel to the
142 * channel's registration time. This callback is added before the main
143 * ChanServ module is loaded, so c->ci will not yet be set.
144 */
145
146 static typeof(get_channelinfo) *sjoin_p_get_channelinfo = NULL;
147 static typeof(put_channelinfo) *sjoin_p_put_channelinfo = NULL;
148
149 static int sjoin_channel_create(Channel *c, User *u, int32 modes)
150 {
151 if (CSSetChannelTime && sjoin_p_get_channelinfo) {
152 ChannelInfo *ci = sjoin_p_get_channelinfo(c->name);
153 if (ci) {
154 c->creation_time = ci->time_registered;
155 #ifdef UNREAL_HACK
156 /* NOTE: this is a bit of a kludge, since Unreal's SJOIN
157 * doesn't let us set just the channel creation time while
158 * leaving the modes alone. */
159 send_cmd(ServerName, "SJOIN %ld %s %co %s :",
160 (long)c->creation_time, c->name,
161 (modes & CUMODE_o ? '+' : '-'), u->nick);
162 #else
163 send_cmd(ServerName, "SJOIN %ld %s + :%s%s",
164 (long)c->creation_time, c->name,
165 (modes & CUMODE_o ? "@" : ""), u->nick);
166 #endif
167 #ifdef BAHAMUT_HACK
168 if (modes & CUMODE_o) {
169 /* Bahamut ignores users in the user list which aren't on
170 * or behind the server sending the SJOIN, so we need an
171 * extra MODE to explicitly give ops back to the initial
172 * joining user. */
173 send_cmode_cmd(ServerName, c->name, "+o :%s", u->nick);
174 }
175 #endif
176 sjoin_p_put_channelinfo(ci);
177 } /* if (ci) */
178 } /* if (CSSetChannelTime) */
179 return 0;
180 }
181
182 /*************************************************************************/
183
184 /* Callback to watch for modules being loaded. */
185
186 static int sjoin_load_module(Module *mod, const char *name)
187 {
188 if (strcmp(name, "chanserv/main") == 0) {
189 sjoin_module_chanserv = mod;
190 sjoin_p_get_channelinfo = get_module_symbol(NULL, "get_channelinfo");
191 if (!sjoin_p_get_channelinfo)
192 module_log("sjoin: symbol `get_channelinfo' not found, channel"
193 " time setting disabled");
194 sjoin_p_put_channelinfo = get_module_symbol(NULL, "put_channelinfo");
195 if (!sjoin_p_get_channelinfo)
196 module_log("sjoin: symbol `put_channelinfo' not found, channel"
197 " time setting disabled");
198 }
199 return 0;
200 }
201
202 /*************************************************************************/
203
204 /* Callback to watch for modules being unloaded. */
205
206 static int sjoin_unload_module(Module *mod)
207 {
208 if (mod == sjoin_module_chanserv) {
209 sjoin_p_get_channelinfo = NULL;
210 sjoin_module_chanserv = NULL;
211 }
212 return 0;
213 }
214
215 /*************************************************************************/
216
217 /* Initialization. */
218
219 static void exit_sjoin(void);
220
221 static int init_sjoin(void)
222 {
223 sjoin_module_chanserv = NULL;
224 sjoin_p_get_channelinfo = NULL;
225
226 if (!add_callback(NULL, "load module", sjoin_load_module)
227 || !add_callback(NULL, "unload module", sjoin_unload_module)
228 || !add_callback(NULL, "channel create", sjoin_channel_create)
229 || !add_callback(NULL, "clear channel", sjoin_clear_users)
230 ) {
231 module_log("sjoin: Unable to add callbacks");
232 exit_sjoin();
233 return 0;
234 }
235 return 1;
236 }
237
238 /*************************************************************************/
239
240 /* Cleanup. */
241
242 static void exit_sjoin(void)
243 {
244 remove_callback(NULL, "clear channel", sjoin_clear_users);
245 remove_callback(NULL, "channel create", sjoin_channel_create);
246 remove_callback(NULL, "unload module", sjoin_unload_module);
247 remove_callback(NULL, "load module", sjoin_load_module);
248 }
249
250 /*************************************************************************/
251
252 /*
253 * Local variables:
254 * c-file-style: "stroustrup"
255 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
256 * indent-tabs-mode: nil
257 * End:
258 *
259 * vim: expandtab shiftwidth=4:
260 */