1 /* entities.c - entity tracking
2 * Copyright (C) 2010 Atheme Development Group
3 */
4
5 #include "atheme.h"
6
7 static mowgli_patricia_t *entities;
8 static mowgli_patricia_t *entities_by_id;
9 static char last_entity_uid[IDLEN];
10
init_entities(void)11 void init_entities(void)
12 {
13 entities = mowgli_patricia_create(irccasecanon);
14 entities_by_id = mowgli_patricia_create(noopcanon);
15 memset(last_entity_uid, 'A', sizeof last_entity_uid);
16 }
17
myentity_set_last_uid(const char * last_id)18 void myentity_set_last_uid(const char *last_id)
19 {
20 mowgli_strlcpy(last_entity_uid, last_id, sizeof last_entity_uid);
21 last_entity_uid[IDLEN-1] = '\0';
22 }
23
myentity_get_last_uid(void)24 const char *myentity_get_last_uid(void)
25 {
26 return last_entity_uid;
27 }
28
myentity_alloc_uid(void)29 const char *myentity_alloc_uid(void)
30 {
31 int i;
32
33 for(i = 8; i > 3; i--)
34 {
35 if(last_entity_uid[i] == 'Z')
36 {
37 last_entity_uid[i] = '0';
38 return last_entity_uid;
39 }
40 else if(last_entity_uid[i] != '9')
41 {
42 last_entity_uid[i]++;
43 return last_entity_uid;
44 }
45 else
46 last_entity_uid[i] = 'A';
47 }
48
49 /* if this next if() triggers, we're fucked. */
50 if(last_entity_uid[3] == 'Z')
51 {
52 last_entity_uid[i] = 'A';
53 slog(LG_ERROR, "Out of entity UIDs!");
54 wallops("Out of entity UIDs. This is a Bad Thing.");
55 wallops("You should probably do something about this.");
56 }
57 else
58 last_entity_uid[3]++;
59
60 return last_entity_uid;
61 }
62
myentity_put(myentity_t * mt)63 void myentity_put(myentity_t *mt)
64 {
65 /* If the entity doesn't have an ID yet, allocate one */
66 if (mt->id[0] == '\0')
67 mowgli_strlcpy(mt->id, myentity_alloc_uid(), sizeof mt->id);
68
69 mowgli_patricia_add(entities, mt->name, mt);
70 mowgli_patricia_add(entities_by_id, mt->id, mt);
71 }
72
myentity_del(myentity_t * mt)73 void myentity_del(myentity_t *mt)
74 {
75 mowgli_patricia_delete(entities, mt->name);
76 mowgli_patricia_delete(entities_by_id, mt->id);
77 }
78
myentity_find(const char * name)79 myentity_t *myentity_find(const char *name)
80 {
81 myentity_t *ent;
82 hook_myentity_req_t req;
83
84 return_val_if_fail(name != NULL, NULL);
85
86 if ((ent = mowgli_patricia_retrieve(entities, name)) != NULL)
87 return ent;
88
89 req.name = name;
90 req.entity = NULL;
91 hook_call_myentity_find(&req);
92
93 return req.entity;
94 }
95
myentity_find_uid(const char * uid)96 myentity_t *myentity_find_uid(const char *uid)
97 {
98 return_val_if_fail(uid != NULL, NULL);
99
100 return mowgli_patricia_retrieve(entities_by_id, uid);
101 }
102
myentity_find_ext(const char * name)103 myentity_t *myentity_find_ext(const char *name)
104 {
105 myentity_t *mt;
106
107 return_val_if_fail(name != NULL, NULL);
108
109 mt = entity(myuser_find_ext(name));
110 if (mt != NULL)
111 return mt;
112
113 return myentity_find(name);
114 }
115
myentity_foreach_start(myentity_iteration_state_t * state,myentity_type_t type)116 void myentity_foreach_start(myentity_iteration_state_t *state, myentity_type_t type)
117 {
118 myentity_t *e;
119
120 state->type = type;
121 mowgli_patricia_foreach_start(entities, &state->st);
122
123 e = mowgli_patricia_foreach_cur(entities, &state->st);
124 while (e && state->type != ENT_ANY && state->type != e->type)
125 {
126 mowgli_patricia_foreach_next(entities, &state->st);
127 e = mowgli_patricia_foreach_cur(entities, &state->st);
128 }
129 }
130
myentity_foreach_cur(myentity_iteration_state_t * state)131 myentity_t *myentity_foreach_cur(myentity_iteration_state_t *state)
132 {
133 return mowgli_patricia_foreach_cur(entities, &state->st);
134 }
135
myentity_foreach_next(myentity_iteration_state_t * state)136 void myentity_foreach_next(myentity_iteration_state_t *state)
137 {
138 myentity_t *e;
139 do {
140 mowgli_patricia_foreach_next(entities, &state->st);
141 e = mowgli_patricia_foreach_cur(entities, &state->st);
142 } while (e && state->type != ENT_ANY && state->type != e->type);
143 }
144
myentity_foreach(int (* cb)(myentity_t * mt,void * privdata),void * privdata)145 void myentity_foreach(int (*cb)(myentity_t *mt, void *privdata), void *privdata)
146 {
147 myentity_foreach_t(ENT_ANY, cb, privdata);
148 }
149
myentity_foreach_t(myentity_type_t type,int (* cb)(myentity_t * mt,void * privdata),void * privdata)150 void myentity_foreach_t(myentity_type_t type, int (*cb)(myentity_t *mt, void *privdata), void *privdata)
151 {
152 myentity_iteration_state_t state;
153 myentity_t *mt;
154 MYENTITY_FOREACH_T(mt, &state, type)
155 {
156 if (cb(mt, privdata))
157 return;
158 }
159 }
160
myentity_stats(void (* cb)(const char * line,void * privdata),void * privdata)161 void myentity_stats(void (*cb)(const char *line, void *privdata), void *privdata)
162 {
163 mowgli_patricia_stats(entities, cb, privdata);
164 }
165
166 /* validation */
linear_chanacs_match_entity(chanacs_t * ca,myentity_t * mt)167 static chanacs_t *linear_chanacs_match_entity(chanacs_t *ca, myentity_t *mt)
168 {
169 return ca->entity == mt ? ca : NULL;
170 }
171
linear_can_register_channel(myentity_t * mt)172 static bool linear_can_register_channel(myentity_t *mt)
173 {
174 myuser_t *mu;
175
176 if ((mu = user(mt)) == NULL)
177 return false;
178
179 if (mu->flags & MU_REGNOLIMIT)
180 return true;
181
182 return has_priv_myuser(mu, PRIV_REG_NOLIMIT);
183 }
184
linear_allow_foundership(myentity_t * mt)185 static bool linear_allow_foundership(myentity_t *mt)
186 {
187 myuser_t *mu;
188
189 /* avoid workaround for restricted users where foundership is set on the user after registration. */
190 if ((mu = user(mt)) != NULL)
191 {
192 metadata_t *md;
193
194 md = metadata_find(mu, "private:restrict:setter");
195 if (md != NULL)
196 return false;
197 }
198
199 return true;
200 }
201
202 entity_chanacs_validation_vtable_t linear_chanacs_validate = {
203 .match_entity = linear_chanacs_match_entity,
204 .can_register_channel = linear_can_register_channel,
205 .allow_foundership = linear_allow_foundership,
206 };
207
myentity_get_chanacs_validator(myentity_t * mt)208 entity_chanacs_validation_vtable_t *myentity_get_chanacs_validator(myentity_t *mt)
209 {
210 return mt->chanacs_validate != NULL ? mt->chanacs_validate : &linear_chanacs_validate;
211 }
212
213 /* chanacs */
myentity_count_channels_with_flagset(myentity_t * mt,unsigned int flagset)214 unsigned int myentity_count_channels_with_flagset(myentity_t *mt, unsigned int flagset)
215 {
216 mowgli_node_t *n;
217 chanacs_t *ca;
218 unsigned int count = 0;
219
220 MOWGLI_ITER_FOREACH(n, mt->chanacs.head)
221 {
222 ca = n->data;
223 if (ca->level & flagset)
224 count++;
225 }
226
227 return count;
228 }
229
myentity_can_register_channel(myentity_t * mt)230 bool myentity_can_register_channel(myentity_t *mt)
231 {
232 entity_chanacs_validation_vtable_t *vt;
233
234 return_val_if_fail(mt != NULL, false);
235
236 vt = myentity_get_chanacs_validator(mt);
237 if (vt->can_register_channel(mt))
238 return true;
239
240 return (myentity_count_channels_with_flagset(mt, CA_FOUNDER) < chansvs.maxchans);
241 }
242
myentity_allow_foundership(myentity_t * mt)243 bool myentity_allow_foundership(myentity_t *mt)
244 {
245 entity_chanacs_validation_vtable_t *vt;
246
247 return_val_if_fail(mt != NULL, false);
248
249 vt = myentity_get_chanacs_validator(mt);
250 if (vt->allow_foundership)
251 return vt->allow_foundership(mt);
252
253 return false;
254 }
255