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