1 /*
2 * Copyright (c) 2005 William Pitcock, et al.
3 * Rights to this code are as documented in doc/LICENSE.
4 *
5 * This file contains code for the CService INFO functions.
6 *
7 */
8
9 #include "atheme.h"
10
11 DECLARE_MODULE_V1
12 (
13 "chanserv/info", false, _modinit, _moddeinit,
14 PACKAGE_STRING,
15 VENDOR_STRING
16 );
17
18 static void cs_cmd_info(sourceinfo_t *si, int parc, char *parv[]);
19
20 command_t cs_info = { "INFO", N_("Displays information on registrations."),
21 AC_NONE, 2, cs_cmd_info, { .path = "cservice/info" } };
22
_modinit(module_t * m)23 void _modinit(module_t *m)
24 {
25 service_named_bind_command("chanserv", &cs_info);
26 }
27
_moddeinit(module_unload_intent_t intent)28 void _moddeinit(module_unload_intent_t intent)
29 {
30 service_named_unbind_command("chanserv", &cs_info);
31 }
32
cs_cmd_info(sourceinfo_t * si,int parc,char * parv[])33 static void cs_cmd_info(sourceinfo_t *si, int parc, char *parv[])
34 {
35 mychan_t *mc;
36 char *name = parv[0];
37 char buf[BUFSIZE], strfbuf[BUFSIZE];
38 struct tm tm;
39 myuser_t *mu;
40 metadata_t *md;
41 mowgli_patricia_iteration_state_t state;
42 hook_channel_req_t req;
43 bool hide_info, hide_acl;
44
45 if (!name)
46 {
47 command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "INFO");
48 command_fail(si, fault_needmoreparams, _("Syntax: INFO <#channel>"));
49 return;
50 }
51
52 if (*name != '#')
53 {
54 command_fail(si, fault_badparams, STR_INVALID_PARAMS, "INFO");
55 command_fail(si, fault_badparams, _("Syntax: INFO <#channel>"));
56 return;
57 }
58
59 if (!(mc = mychan_find(name)))
60 {
61 command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), name);
62 return;
63 }
64
65 if (!has_priv(si, PRIV_CHAN_AUSPEX) && metadata_find(mc, "private:close:closer"))
66 {
67 command_fail(si, fault_noprivs, _("\2%s\2 has been closed down by the %s administration."), mc->name, me.netname);
68 return;
69 }
70
71 hide_info = use_channel_private && mc->flags & MC_PRIVATE &&
72 !chanacs_source_has_flag(mc, si, CA_ACLVIEW) &&
73 !has_priv(si, PRIV_CHAN_AUSPEX);
74 hide_acl = !chanacs_source_has_flag(mc, si, CA_ACLVIEW) &&
75 !has_priv(si, PRIV_CHAN_AUSPEX) &&
76 !(mc->flags & MC_PUBACL);
77
78 tm = *localtime(&mc->registered);
79 strftime(strfbuf, sizeof strfbuf, TIME_FORMAT, &tm);
80
81 command_success_nodata(si, _("Information on \2%s\2:"), mc->name);
82
83 if (!(hide_info && hide_acl))
84 command_success_nodata(si, _("Founder : %s"), mychan_founder_names(mc));
85
86 if (!hide_acl)
87 {
88 mu = mychan_pick_successor(mc);
89 if (mu != NULL)
90 command_success_nodata(si, _("Successor : %s"), entity(mu)->name);
91 else
92 command_success_nodata(si, _("Successor : (none)"));
93 }
94
95 command_success_nodata(si, _("Registered : %s (%s ago)"), strfbuf, time_ago(mc->registered));
96
97 if (CURRTIME - mc->used >= 86400)
98 {
99 if (hide_info)
100 command_success_nodata(si, _("Last used : (about %d weeks ago)"), (int)((CURRTIME - mc->used) / 604800));
101 else
102 {
103 tm = *localtime(&mc->used);
104 strftime(strfbuf, sizeof strfbuf, TIME_FORMAT, &tm);
105 command_success_nodata(si, _("Last used : %s (%s ago)"), strfbuf, time_ago(mc->used));
106 }
107 }
108
109 md = metadata_find(mc, "private:mlockext");
110 if (mc->mlock_on || mc->mlock_off || mc->mlock_limit || mc->mlock_key || md)
111 {
112 if (md != NULL && strlen(md->value) > 450)
113 {
114 /* Be safe */
115 command_success_nodata(si, _("Mode lock is too long, not entirely shown"));
116 md = NULL;
117 }
118
119 command_success_nodata(si, _("Mode lock : %s"), mychan_get_mlock(mc));
120 }
121
122
123 if ((!hide_info || (si->su != NULL && chanuser_find(mc->chan, si->su))) &&
124 (md = metadata_find(mc, "url")))
125 command_success_nodata(si, "URL : %s", md->value);
126
127 if (!hide_info && (md = metadata_find(mc, "email")))
128 command_success_nodata(si, "Email : %s", md->value);
129
130 if ((!hide_info || (si->su != NULL && chanuser_find(mc->chan, si->su))) &&
131 (md = metadata_find(mc, "private:entrymsg")))
132 command_success_nodata(si, "Entrymsg : %s", md->value);
133
134 if (!hide_info)
135 {
136 MOWGLI_PATRICIA_FOREACH(md, &state, object(mc)->metadata)
137 {
138 if (!strncmp(md->name, "private:", 8))
139 continue;
140 /* these are shown separately */
141 if (!strcasecmp(md->name, "email") ||
142 !strcasecmp(md->name, "url") ||
143 !strcasecmp(md->name, "disable_fantasy"))
144 continue;
145 command_success_nodata(si, _("Metadata : %s = %s"),
146 md->name, md->value);
147 }
148 }
149
150 *buf = '\0';
151
152 if (MC_HOLD & mc->flags)
153 strcat(buf, "HOLD");
154
155 if (MC_SECURE & mc->flags)
156 {
157 if (*buf)
158 strcat(buf, " ");
159
160 strcat(buf, "SECURE");
161 }
162
163 if (MC_VERBOSE & mc->flags)
164 {
165 if (*buf)
166 strcat(buf, " ");
167
168 strcat(buf, "VERBOSE");
169 }
170 if (MC_VERBOSE_OPS & mc->flags)
171 {
172 if (*buf)
173 strcat(buf, " ");
174
175 strcat(buf, "VERBOSE_OPS");
176 }
177
178 if (MC_RESTRICTED & mc->flags)
179 {
180 if (*buf)
181 strcat(buf, " ");
182
183 strcat(buf, "RESTRICTED");
184 }
185
186 if (MC_KEEPTOPIC & mc->flags)
187 {
188 if (*buf)
189 strcat(buf, " ");
190
191 strcat(buf, "KEEPTOPIC");
192 }
193
194 if (MC_TOPICLOCK & mc->flags)
195 {
196 if (*buf)
197 strcat(buf, " ");
198
199 strcat(buf, "TOPICLOCK");
200 }
201
202 if (MC_GUARD & mc->flags)
203 {
204 if (*buf)
205 strcat(buf, " ");
206
207 strcat(buf, "GUARD");
208 }
209
210 if (MC_ANTIFLOOD & mc->flags)
211 {
212 if (*buf)
213 strcat(buf, " ");
214
215 strcat(buf, "ANTIFLOOD");
216 }
217
218 if (chansvs.fantasy && !metadata_find(mc, "disable_fantasy"))
219 {
220 if (*buf)
221 strcat(buf, " ");
222
223 strcat(buf, "FANTASY");
224 }
225
226 if (MC_NOSYNC & mc->flags)
227 {
228 if (*buf)
229 strcat(buf, " ");
230
231 strcat(buf, "NOSYNC");
232 }
233
234 if (use_channel_private && MC_PRIVATE & mc->flags)
235 {
236 if (*buf)
237 strcat(buf, " ");
238
239 strcat(buf, "PRIVATE");
240 }
241
242 if (MC_PUBACL & mc->flags)
243 {
244 if (*buf)
245 strcat(buf, " ");
246
247 strcat(buf, "PUBACL");
248 }
249
250 if (use_limitflags && MC_LIMITFLAGS & mc->flags)
251 {
252 if (*buf)
253 strcat(buf, " ");
254
255 strcat(buf, "LIMITFLAGS");
256 }
257
258 if (*buf)
259 command_success_nodata(si, _("Flags : %s"), buf);
260
261 if (chansvs.fantasy && !metadata_find(mc, "disable_fantasy"))
262 {
263 if ((md = metadata_find(mc, "private:prefix")))
264 command_success_nodata(si, _("Prefix : %s"), md->value);
265 else
266 command_success_nodata(si, _("Prefix : %s (default)"), chansvs.trigger);
267 }
268
269 if (has_priv(si, PRIV_CHAN_AUSPEX) && (md = metadata_find(mc, "private:mark:setter")))
270 {
271 const char *setter = md->value;
272 const char *reason;
273 time_t ts;
274
275 md = metadata_find(mc, "private:mark:reason");
276 reason = md != NULL ? md->value : "unknown";
277
278 md = metadata_find(mc, "private:mark:timestamp");
279 ts = md != NULL ? atoi(md->value) : 0;
280
281 tm = *localtime(&ts);
282 strftime(strfbuf, sizeof strfbuf, TIME_FORMAT, &tm);
283
284 command_success_nodata(si, _("%s was \2MARKED\2 by %s on %s (%s)"), mc->name, setter, strfbuf, reason);
285 }
286
287 if (has_priv(si, PRIV_CHAN_AUSPEX) && (MC_INHABIT & mc->flags))
288 command_success_nodata(si, _("%s is temporarily holding this channel."), chansvs.nick);
289
290 if (has_priv(si, PRIV_CHAN_AUSPEX) && (md = metadata_find(mc, "private:close:closer")))
291 {
292 const char *setter = md->value;
293 const char *reason;
294 time_t ts;
295
296 md = metadata_find(mc, "private:close:reason");
297 reason = md != NULL ? md->value : "unknown";
298
299 md = metadata_find(mc, "private:close:timestamp");
300 ts = md != NULL ? atoi(md->value) : 0;
301
302 tm = *localtime(&ts);
303 strftime(strfbuf, sizeof strfbuf, TIME_FORMAT, &tm);
304
305 command_success_nodata(si, _("%s was \2CLOSED\2 by %s on %s (%s)"), mc->name, setter, strfbuf, reason);
306 }
307
308 req.mc = mc;
309 req.si = si;
310 hook_call_channel_info(&req);
311
312 command_success_nodata(si, _("\2*** End of Info ***\2"));
313 logcommand(si, CMDLOG_GET, "INFO: \2%s\2", mc->name);
314 }
315
316 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
317 * vim:ts=8
318 * vim:sw=8
319 * vim:noexpandtab
320 */
321