]> jfr.im git - solanum.git/blob - src/capability.c
edbf1d7320ca274a32ad57cb1de79ba0f9893fff
[solanum.git] / src / capability.c
1 /*
2 * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice is present in all copies.
7 *
8 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
12 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
17 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
18 * POSSIBILITY OF SUCH DAMAGE.
19 */
20
21 #include "stdinc.h"
22 #include "capability.h"
23 #include "irc_dictionary.h"
24
25 static rb_dlink_list capability_indexes = { NULL, NULL, 0 };
26
27 struct CapabilityIndex {
28 char *name;
29 struct Dictionary *cap_dict;
30 unsigned int highest_bit;
31 rb_dlink_node node;
32 };
33
34 #define CAP_ORPHANED 0x1
35 #define CAP_REQUIRED 0x2
36
37 struct CapabilityEntry {
38 char *cap;
39 unsigned int value;
40 unsigned int flags;
41 };
42
43 unsigned int
44 capability_get(struct CapabilityIndex *idx, const char *cap)
45 {
46 struct CapabilityEntry *entry;
47
48 s_assert(idx != NULL);
49
50 entry = irc_dictionary_retrieve(idx->cap_dict, cap);
51 if (entry != NULL && !(entry->flags & CAP_ORPHANED))
52 return (1 << entry->value);
53
54 return 0;
55 }
56
57 unsigned int
58 capability_put(struct CapabilityIndex *idx, const char *cap)
59 {
60 struct CapabilityEntry *entry;
61
62 s_assert(idx != NULL);
63 if (!idx->highest_bit)
64 return 0xFFFFFFFF;
65
66 if ((entry = irc_dictionary_retrieve(idx->cap_dict, cap)) != NULL)
67 {
68 entry->flags &= ~CAP_ORPHANED;
69 return (1 << entry->value);
70 }
71
72 entry = rb_malloc(sizeof(struct CapabilityEntry));
73 entry->cap = rb_strdup(cap);
74 entry->flags = 0;
75 entry->value = idx->highest_bit;
76
77 irc_dictionary_add(idx->cap_dict, entry->cap, entry);
78
79 idx->highest_bit++;
80 if (idx->highest_bit % (sizeof(unsigned int) * 8) == 0)
81 idx->highest_bit = 0;
82
83 return (1 << entry->value);
84 }
85
86 unsigned int
87 capability_put_anonymous(struct CapabilityIndex *idx)
88 {
89 unsigned int value;
90
91 s_assert(idx != NULL);
92 if (!idx->highest_bit)
93 return 0xFFFFFFFF;
94 value = 1 << idx->highest_bit;
95 idx->highest_bit++;
96 if (idx->highest_bit % (sizeof(unsigned int) * 8) == 0)
97 idx->highest_bit = 0;
98 return value;
99 }
100
101 void
102 capability_orphan(struct CapabilityIndex *idx, const char *cap)
103 {
104 struct CapabilityEntry *entry;
105
106 s_assert(idx != NULL);
107
108 entry = irc_dictionary_retrieve(idx->cap_dict, cap);
109 if (entry != NULL)
110 {
111 entry->flags &= ~CAP_REQUIRED;
112 entry->flags |= CAP_ORPHANED;
113 }
114 }
115
116 void
117 capability_require(struct CapabilityIndex *idx, const char *cap)
118 {
119 struct CapabilityEntry *entry;
120
121 s_assert(idx != NULL);
122
123 entry = irc_dictionary_retrieve(idx->cap_dict, cap);
124 if (entry != NULL)
125 entry->flags |= CAP_REQUIRED;
126 }
127
128 static void
129 capability_destroy(struct DictionaryElement *delem, void *privdata)
130 {
131 s_assert(delem != NULL);
132
133 rb_free(delem->data);
134 }
135
136 struct CapabilityIndex *
137 capability_index_create(const char *name)
138 {
139 struct CapabilityIndex *idx;
140
141 idx = rb_malloc(sizeof(struct CapabilityIndex));
142 idx->name = rb_strdup(name);
143 idx->cap_dict = irc_dictionary_create(strcasecmp);
144 idx->highest_bit = 1;
145
146 rb_dlinkAdd(idx, &idx->node, &capability_indexes);
147
148 return idx;
149 }
150
151 void
152 capability_index_destroy(struct CapabilityIndex *idx)
153 {
154 s_assert(idx != NULL);
155
156 rb_dlinkDelete(&idx->node, &capability_indexes);
157
158 irc_dictionary_destroy(idx->cap_dict, capability_destroy, NULL);
159 rb_free(idx);
160 }
161
162 const char *
163 capability_index_list(struct CapabilityIndex *idx, unsigned int cap_mask)
164 {
165 struct DictionaryIter iter;
166 struct CapabilityEntry *entry;
167 static char buf[BUFSIZE];
168 char *t = buf;
169 int tl;
170
171 s_assert(idx != NULL);
172
173 *t = '\0';
174
175 DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
176 {
177 if ((1 << entry->value) & cap_mask)
178 {
179 tl = rb_sprintf(t, "%s ", entry->cap);
180 t += tl;
181 }
182 }
183
184 t--;
185 *t = '\0';
186
187 return buf;
188 }
189
190 unsigned int
191 capability_index_mask(struct CapabilityIndex *idx)
192 {
193 struct DictionaryIter iter;
194 struct CapabilityEntry *entry;
195 unsigned int mask = 0;
196
197 s_assert(idx != NULL);
198
199 DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
200 {
201 if (!(entry->flags & CAP_ORPHANED))
202 mask |= (1 << entry->value);
203 }
204
205 return mask;
206 }
207
208 unsigned int
209 capability_index_get_required(struct CapabilityIndex *idx)
210 {
211 struct DictionaryIter iter;
212 struct CapabilityEntry *entry;
213 unsigned int mask = 0;
214
215 s_assert(idx != NULL);
216
217 DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
218 {
219 if (!(entry->flags & CAP_ORPHANED) && (entry->flags & CAP_REQUIRED))
220 mask |= (1 << entry->value);
221 }
222
223 return mask;
224 }
225
226 void
227 capability_index_stats(void (*cb)(const char *line, void *privdata), void *privdata)
228 {
229 rb_dlink_node *node;
230 char buf[BUFSIZE];
231
232 RB_DLINK_FOREACH(node, capability_indexes.head)
233 {
234 struct CapabilityIndex *idx = node->data;
235 struct DictionaryIter iter;
236 struct CapabilityEntry *entry;
237
238 rb_snprintf(buf, sizeof buf, "'%s': allocated bits - %d", idx->name, (idx->highest_bit - 1));
239 cb(buf, privdata);
240
241 DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
242 {
243 rb_snprintf(buf, sizeof buf, "bit %d: '%s'", entry->value, entry->cap);
244 cb(buf, privdata);
245 }
246
247 rb_snprintf(buf, sizeof buf, "'%s': remaining bits - %ld", idx->name,
248 (sizeof(unsigned int) * 8) - (idx->highest_bit - 1));
249 cb(buf, privdata);
250 }
251
252 rb_snprintf(buf, sizeof buf, "%ld capability indexes", rb_dlink_list_length(&capability_indexes));
253 cb(buf, privdata);
254 }