Diffstat (limited to 'libical/src/libicalss/icalgauge.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libical/src/libicalss/icalgauge.c | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/libical/src/libicalss/icalgauge.c b/libical/src/libicalss/icalgauge.c new file mode 100644 index 0000000..b958ecf --- a/dev/null +++ b/libical/src/libicalss/icalgauge.c | |||
@@ -0,0 +1,447 @@ | |||
1 | /* -*- Mode: C -*- */ | ||
2 | /*====================================================================== | ||
3 | FILE: icalgauge.c | ||
4 | CREATOR: eric 23 December 1999 | ||
5 | |||
6 | |||
7 | $Id$ | ||
8 | $Locker$ | ||
9 | |||
10 | (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org | ||
11 | |||
12 | This program is free software; you can redistribute it and/or modify | ||
13 | it under the terms of either: | ||
14 | |||
15 | The LGPL as published by the Free Software Foundation, version | ||
16 | 2.1, available at: http://www.fsf.org/copyleft/lesser.html | ||
17 | |||
18 | Or: | ||
19 | |||
20 | The Mozilla Public License Version 1.0. You may obtain a copy of | ||
21 | the License at http://www.mozilla.org/MPL/ | ||
22 | |||
23 | The Original Code is eric. The Initial Developer of the Original | ||
24 | Code is Eric Busboom | ||
25 | |||
26 | |||
27 | ======================================================================*/ | ||
28 | |||
29 | #include "ical.h" | ||
30 | #include "icalgauge.h" | ||
31 | #include "icalgaugeimpl.h" | ||
32 | #include <stdlib.h> | ||
33 | |||
34 | extern char* input_buffer; | ||
35 | extern char* input_buffer_p; | ||
36 | int ssparse(void); | ||
37 | |||
38 | struct icalgauge_impl *icalss_yy_gauge; | ||
39 | |||
40 | icalgauge* icalgauge_new_from_sql(char* sql) | ||
41 | { | ||
42 | struct icalgauge_impl *impl; | ||
43 | |||
44 | int r; | ||
45 | |||
46 | if ( ( impl = (struct icalgauge_impl*) | ||
47 | malloc(sizeof(struct icalgauge_impl))) == 0) { | ||
48 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | impl->select = pvl_newlist(); | ||
53 | impl->from = pvl_newlist(); | ||
54 | impl->where = pvl_newlist(); | ||
55 | |||
56 | icalss_yy_gauge = impl; | ||
57 | |||
58 | input_buffer_p = input_buffer = sql; | ||
59 | r = ssparse(); | ||
60 | |||
61 | return impl; | ||
62 | } | ||
63 | |||
64 | |||
65 | void icalgauge_free(icalgauge* gauge) | ||
66 | { | ||
67 | struct icalgauge_impl *impl = (struct icalgauge_impl*)gauge; | ||
68 | struct icalgauge_where *w; | ||
69 | |||
70 | assert(impl->select != 0); | ||
71 | assert(impl->where != 0); | ||
72 | assert(impl->from != 0); | ||
73 | |||
74 | if(impl->select){ | ||
75 | while( (w=pvl_pop(impl->select)) != 0){ | ||
76 | if(w->value != 0){ | ||
77 | free(w->value); | ||
78 | } | ||
79 | free(w); | ||
80 | } | ||
81 | pvl_free(impl->select); | ||
82 | } | ||
83 | |||
84 | if(impl->where){ | ||
85 | while( (w=pvl_pop(impl->where)) != 0){ | ||
86 | |||
87 | if(w->value != 0){ | ||
88 | free(w->value); | ||
89 | } | ||
90 | free(w); | ||
91 | } | ||
92 | pvl_free(impl->where); | ||
93 | } | ||
94 | |||
95 | if(impl->from){ | ||
96 | pvl_free(impl->from); | ||
97 | } | ||
98 | |||
99 | } | ||
100 | |||
101 | /* Convert a VQUERY component into a gauge */ | ||
102 | icalcomponent* icalgauge_make_gauge(icalcomponent* query); | ||
103 | |||
104 | /* icaldirset_test compares a component against a gauge, and returns | ||
105 | true if the component passes the test | ||
106 | |||
107 | The gauge is a VCALENDAR component that specifies how to test the | ||
108 | target components. The guage holds a collection of VEVENT, VTODO or | ||
109 | VJOURNAL sub-components. Each of the sub-components has a | ||
110 | collection of properties that are compared to corresponding | ||
111 | properties in the target component, according to the | ||
112 | X-LIC-COMPARETYPE parameters to the gauge's properties. | ||
113 | |||
114 | When a gauge has several sub-components, the results of testing the | ||
115 | target against each of them is ORed together - the target | ||
116 | component will pass if it matches any of the sub-components in the | ||
117 | gauge. However, the results of matching the properties in a | ||
118 | sub-component are ANDed -- the target must match every property in | ||
119 | a gauge sub-component to match the sub-component. | ||
120 | |||
121 | Here is an example: | ||
122 | |||
123 | BEGIN:XROOT | ||
124 | DTSTART;X-LIC-COMPARETYPE=LESS:19981025T020000 | ||
125 | ORGANIZER;X-LIC-COMPARETYPE=EQUAL:mrbig@host.com | ||
126 | END:XROOT | ||
127 | BEGIN:XROOT | ||
128 | LOCATION;X-LIC-COMPARETYPE=EQUAL:McNary's Pub | ||
129 | END:XROOT | ||
130 | |||
131 | This gauge has two sub-components; one which will match a VEVENT | ||
132 | based on start time, and organizer, and another that matches based | ||
133 | on LOCATION. A target component will pass the test if it matched | ||
134 | either of the sub-components. | ||
135 | |||
136 | */ | ||
137 | |||
138 | |||
139 | int icalgauge_compare_recurse(icalcomponent* comp, icalcomponent* gauge) | ||
140 | { | ||
141 | int pass = 1,localpass = 0; | ||
142 | icalproperty *p; | ||
143 | icalcomponent *child,*subgauge; | ||
144 | icalcomponent_kind gaugekind, compkind; | ||
145 | |||
146 | icalerror_check_arg_rz( (comp!=0), "comp"); | ||
147 | icalerror_check_arg_rz( (gauge!=0), "gauge"); | ||
148 | |||
149 | gaugekind = icalcomponent_isa(gauge); | ||
150 | compkind = icalcomponent_isa(comp); | ||
151 | |||
152 | if( ! (gaugekind == compkind || gaugekind == ICAL_ANY_COMPONENT) ){ | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /* Test properties. For each property in the gauge, search through | ||
157 | the component for a similar property. If one is found, compare | ||
158 | the two properties value with the comparison specified in the | ||
159 | gauge with the X-LIC-COMPARETYPE parameter */ | ||
160 | |||
161 | for(p = icalcomponent_get_first_property(gauge,ICAL_ANY_PROPERTY); | ||
162 | p != 0; | ||
163 | p = icalcomponent_get_next_property(gauge,ICAL_ANY_PROPERTY)){ | ||
164 | |||
165 | icalproperty* targetprop; | ||
166 | icalparameter* compareparam; | ||
167 | icalparameter_xliccomparetype compare; | ||
168 | int rel; /* The relationship between the gauge and target values.*/ | ||
169 | |||
170 | /* Extract the comparison type from the gauge. If there is no | ||
171 | comparison type, assume that it is "EQUAL" */ | ||
172 | |||
173 | compareparam = icalproperty_get_first_parameter( | ||
174 | p, | ||
175 | ICAL_XLICCOMPARETYPE_PARAMETER); | ||
176 | |||
177 | if (compareparam!=0){ | ||
178 | compare = icalparameter_get_xliccomparetype(compareparam); | ||
179 | } else { | ||
180 | compare = ICAL_XLICCOMPARETYPE_EQUAL; | ||
181 | } | ||
182 | |||
183 | /* Find a property in the component that has the same type | ||
184 | as the gauge property. HACK -- multiples of a single | ||
185 | property type in the gauge will match only the first | ||
186 | instance in the component */ | ||
187 | |||
188 | targetprop = icalcomponent_get_first_property(comp, | ||
189 | icalproperty_isa(p)); | ||
190 | |||
191 | if(targetprop != 0){ | ||
192 | |||
193 | /* Compare the values of the gauge property and the target | ||
194 | property */ | ||
195 | |||
196 | rel = icalvalue_compare(icalproperty_get_value(p), | ||
197 | icalproperty_get_value(targetprop)); | ||
198 | |||
199 | /* Now see if the comparison is equavalent to the comparison | ||
200 | specified in the gauge */ | ||
201 | |||
202 | if (rel == compare){ | ||
203 | localpass++; | ||
204 | } else if (compare == ICAL_XLICCOMPARETYPE_LESSEQUAL && | ||
205 | ( rel == ICAL_XLICCOMPARETYPE_LESS || | ||
206 | rel == ICAL_XLICCOMPARETYPE_EQUAL)) { | ||
207 | localpass++; | ||
208 | } else if (compare == ICAL_XLICCOMPARETYPE_GREATEREQUAL && | ||
209 | ( rel == ICAL_XLICCOMPARETYPE_GREATER || | ||
210 | rel == ICAL_XLICCOMPARETYPE_EQUAL)) { | ||
211 | localpass++; | ||
212 | } else if (compare == ICAL_XLICCOMPARETYPE_NOTEQUAL && | ||
213 | ( rel == ICAL_XLICCOMPARETYPE_GREATER || | ||
214 | rel == ICAL_XLICCOMPARETYPE_LESS)) { | ||
215 | localpass++; | ||
216 | } else { | ||
217 | localpass = 0; | ||
218 | } | ||
219 | |||
220 | pass = pass && (localpass>0); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | /* Test subcomponents. Look for a child component that has a | ||
225 | counterpart in the gauge. If one is found, recursively call | ||
226 | icaldirset_test */ | ||
227 | |||
228 | for(subgauge = icalcomponent_get_first_component(gauge,ICAL_ANY_COMPONENT); | ||
229 | subgauge != 0; | ||
230 | subgauge = icalcomponent_get_next_component(gauge,ICAL_ANY_COMPONENT)){ | ||
231 | |||
232 | gaugekind = icalcomponent_isa(subgauge); | ||
233 | |||
234 | if (gaugekind == ICAL_ANY_COMPONENT){ | ||
235 | child = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT); | ||
236 | } else { | ||
237 | child = icalcomponent_get_first_component(comp,gaugekind); | ||
238 | } | ||
239 | |||
240 | if(child !=0){ | ||
241 | localpass = icalgauge_compare_recurse(child,subgauge); | ||
242 | pass = pass && localpass; | ||
243 | } else { | ||
244 | pass = 0; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | return pass; | ||
249 | } | ||
250 | |||
251 | |||
252 | int icalgauge_compare(icalgauge* gauge,icalcomponent* comp) | ||
253 | { | ||
254 | |||
255 | struct icalgauge_impl *impl = (struct icalgauge_impl*)gauge; | ||
256 | icalcomponent *inner; | ||
257 | int local_pass = 0; | ||
258 | int last_clause = 1, this_clause = 1; | ||
259 | pvl_elem e; | ||
260 | |||
261 | icalerror_check_arg_rz( (comp!=0), "comp"); | ||
262 | icalerror_check_arg_rz( (gauge!=0), "gauge"); | ||
263 | |||
264 | inner = icalcomponent_get_first_real_component(comp); | ||
265 | |||
266 | if(inner == 0){ | ||
267 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | |||
272 | /* Check that this component is one of the FROM types */ | ||
273 | local_pass = 0; | ||
274 | for(e = pvl_head(impl->from);e!=0;e=pvl_next(e)){ | ||
275 | icalcomponent_kind k = (icalcomponent_kind)pvl_data(e); | ||
276 | |||
277 | if(k == icalcomponent_isa(inner)){ | ||
278 | local_pass=1; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | if(local_pass == 0){ | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | |||
287 | /* Check each where clause against the component */ | ||
288 | for(e = pvl_head(impl->where);e!=0;e=pvl_next(e)){ | ||
289 | struct icalgauge_where *w = pvl_data(e); | ||
290 | icalcomponent *sub_comp; | ||
291 | icalvalue *v; | ||
292 | icalproperty *prop; | ||
293 | icalvalue_kind vk; | ||
294 | |||
295 | if(w->prop == ICAL_NO_PROPERTY || w->value == 0){ | ||
296 | icalerror_set_errno(ICAL_INTERNAL_ERROR); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | /* First, create a value from the gauge */ | ||
301 | vk = icalenum_property_kind_to_value_kind(w->prop); | ||
302 | |||
303 | if(vk == ICAL_NO_VALUE){ | ||
304 | icalerror_set_errno(ICAL_INTERNAL_ERROR); | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | v = icalvalue_new_from_string(vk,w->value); | ||
309 | |||
310 | if (v == 0){ | ||
311 | /* Keep error set by icalvalue_from-string*/ | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | /* Now find the corresponding property in the component, | ||
316 | descending into a sub-component if necessary */ | ||
317 | |||
318 | if(w->comp == ICAL_NO_COMPONENT){ | ||
319 | sub_comp = inner; | ||
320 | } else { | ||
321 | sub_comp = icalcomponent_get_first_component(inner,w->comp); | ||
322 | if(sub_comp == 0){ | ||
323 | return 0; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | this_clause = 0; | ||
328 | local_pass = 0; | ||
329 | for(prop = icalcomponent_get_first_property(sub_comp,w->prop); | ||
330 | prop != 0; | ||
331 | prop = icalcomponent_get_next_property(sub_comp,w->prop)){ | ||
332 | icalvalue* prop_value; | ||
333 | icalgaugecompare relation; | ||
334 | |||
335 | prop_value = icalproperty_get_value(prop); | ||
336 | |||
337 | relation = (icalgaugecompare)icalvalue_compare(prop_value,v); | ||
338 | |||
339 | if (relation == w->compare){ | ||
340 | local_pass++; | ||
341 | } else if (w->compare == ICALGAUGECOMPARE_LESSEQUAL && | ||
342 | ( relation == ICALGAUGECOMPARE_LESS || | ||
343 | relation == ICALGAUGECOMPARE_EQUAL)) { | ||
344 | local_pass++; | ||
345 | } else if (w->compare == ICALGAUGECOMPARE_GREATEREQUAL && | ||
346 | ( relation == ICALGAUGECOMPARE_GREATER || | ||
347 | relation == ICALGAUGECOMPARE_EQUAL)) { | ||
348 | local_pass++; | ||
349 | } else if (w->compare == ICALGAUGECOMPARE_NOTEQUAL && | ||
350 | ( relation == ICALGAUGECOMPARE_GREATER || | ||
351 | relation == ICALGAUGECOMPARE_LESS)) { | ||
352 | local_pass++; | ||
353 | } else { | ||
354 | local_pass = 0; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | this_clause = local_pass > 0 ? 1 : 0; | ||
359 | |||
360 | /* Now look at the logic operator for this clause to see how | ||
361 | the value should be merge with the previous clause */ | ||
362 | |||
363 | if(w->logic == ICALGAUGELOGIC_AND){ | ||
364 | last_clause = this_clause && last_clause; | ||
365 | } else if(w->logic == ICALGAUGELOGIC_AND) { | ||
366 | last_clause = this_clause || last_clause; | ||
367 | } else { | ||
368 | last_clause = this_clause; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | return last_clause; | ||
373 | |||
374 | } | ||
375 | |||
376 | |||
377 | void icalgauge_dump(icalcomponent* gauge) | ||
378 | { | ||
379 | |||
380 | pvl_elem *p; | ||
381 | struct icalgauge_impl *impl = (struct icalgauge_impl*)gauge; | ||
382 | |||
383 | |||
384 | printf("--- Select ---\n"); | ||
385 | for(p = pvl_head(impl->select);p!=0;p=pvl_next(p)){ | ||
386 | struct icalgauge_where *w = pvl_data(p); | ||
387 | |||
388 | if(w->comp != ICAL_NO_COMPONENT){ | ||
389 | printf("%s ",icalenum_component_kind_to_string(w->comp)); | ||
390 | } | ||
391 | |||
392 | if(w->prop != ICAL_NO_PROPERTY){ | ||
393 | printf("%s ",icalenum_property_kind_to_string(w->prop)); | ||
394 | } | ||
395 | |||
396 | if (w->compare != ICALGAUGECOMPARE_NONE){ | ||
397 | printf("%d ",w->compare); | ||
398 | } | ||
399 | |||
400 | |||
401 | if (w->value!=0){ | ||
402 | printf("%s",w->value); | ||
403 | } | ||
404 | |||
405 | |||
406 | printf("\n"); | ||
407 | } | ||
408 | |||
409 | printf("--- From ---\n"); | ||
410 | for(p = pvl_head(impl->from);p!=0;p=pvl_next(p)){ | ||
411 | icalcomponent_kind k = (icalcomponent_kind)pvl_data(p); | ||
412 | |||
413 | printf("%s\n",icalenum_component_kind_to_string(k)); | ||
414 | } | ||
415 | |||
416 | printf("--- Where ---\n"); | ||
417 | for(p = pvl_head(impl->where);p!=0;p=pvl_next(p)){ | ||
418 | struct icalgauge_where *w = pvl_data(p); | ||
419 | |||
420 | if(w->logic != ICALGAUGELOGIC_NONE){ | ||
421 | printf("%d ",w->logic); | ||
422 | } | ||
423 | |||
424 | if(w->comp != ICAL_NO_COMPONENT){ | ||
425 | printf("%s ",icalenum_component_kind_to_string(w->comp)); | ||
426 | } | ||
427 | |||
428 | if(w->prop != ICAL_NO_PROPERTY){ | ||
429 | printf("%s ",icalenum_property_kind_to_string(w->prop)); | ||
430 | } | ||
431 | |||
432 | if (w->compare != ICALGAUGECOMPARE_NONE){ | ||
433 | printf("%d ",w->compare); | ||
434 | } | ||
435 | |||
436 | |||
437 | if (w->value!=0){ | ||
438 | printf("%s",w->value); | ||
439 | } | ||
440 | |||
441 | |||
442 | printf("\n"); | ||
443 | } | ||
444 | |||
445 | |||
446 | } | ||
447 | |||