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

# User Rev Content
1 michael 3389 /* 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     */