2 /*======================================================================
4 CREATOR: eric 23 December 1999
7 $Id: icalgauge.c,v 1.15 2008-01-02 20:07:40 dothebart Exp $
10 (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of either:
15 The LGPL as published by the Free Software Foundation, version
16 2.1, available at: http://www.fsf.org/copyleft/lesser.html
20 The Mozilla Public License Version 1.0. You may obtain a copy of
21 the License at http://www.mozilla.org/MPL/
23 The Original Code is eric. The Initial Developer of the Original
27 ======================================================================*/
29 #include <libical/ical.h>
30 #include "icalgauge.h"
31 #include "icalgaugeimpl.h"
34 #include "icalssyacc.h"
38 extern char *input_buffer;
39 extern char *input_buffer_p;
41 struct icalgauge_impl *icalss_yy_gauge;
43 icalgauge* icalgauge_new_from_sql(char* sql, int expand)
45 struct icalgauge_impl *impl;
48 if ( ( impl = (struct icalgauge_impl*)
49 malloc(sizeof(struct icalgauge_impl))) == 0) {
50 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
54 impl->select = pvl_newlist();
55 impl->from = pvl_newlist();
56 impl->where = pvl_newlist();
57 impl->expand = expand;
59 icalss_yy_gauge = impl;
60 input_buffer = input_buffer_p = sql;
73 int icalgauge_get_expand(icalgauge* gauge)
75 return (gauge->expand);
79 void icalgauge_free(icalgauge* gauge)
81 struct icalgauge_where *w;
83 assert(gauge->select != 0);
84 assert(gauge->where != 0);
85 assert(gauge->from != 0);
88 while( (w=pvl_pop(gauge->select)) != 0){
94 pvl_free(gauge->select);
99 while( (w=pvl_pop(gauge->where)) != 0){
106 pvl_free(gauge->where);
111 pvl_free(gauge->from);
120 /** Convert a VQUERY component into a gauge */
121 icalcomponent* icalgauge_make_gauge(icalcomponent* query);
124 icaldirset_test compares a component against a gauge, and returns
125 true if the component passes the test
127 The gauge is a VCALENDAR component that specifies how to test the
128 target components. The gauge holds a collection of VEVENT, VTODO or
129 VJOURNAL sub-components. Each of the sub-components has a
130 collection of properties that are compared to corresponding
131 properties in the target component, according to the
132 X-LIC-COMPARETYPE parameters to the gauge's properties.
134 When a gauge has several sub-components, the results of testing the
135 target against each of them is ORed together - the target
136 component will pass if it matches any of the sub-components in the
137 gauge. However, the results of matching the properties in a
138 sub-component are ANDed -- the target must match every property in
139 a gauge sub-component to match the sub-component.
144 DTSTART;X-LIC-COMPARETYPE=LESS:19981025T020000
145 ORGANIZER;X-LIC-COMPARETYPE=EQUAL:mrbig@host.com
148 LOCATION;X-LIC-COMPARETYPE=EQUAL:McNary's Pub
151 This gauge has two sub-components; one which will match a VEVENT
152 based on start time, and organizer, and another that matches based
153 on LOCATION. A target component will pass the test if it matched
154 either of the sub-components.
159 int icalgauge_compare_recurse(icalcomponent* comp, icalcomponent* gauge)
161 int pass = 1,localpass = 0;
163 icalcomponent *child,*subgauge;
164 icalcomponent_kind gaugekind, compkind;
166 icalerror_check_arg_rz( (comp!=0), "comp");
167 icalerror_check_arg_rz( (gauge!=0), "gauge");
169 gaugekind = icalcomponent_isa(gauge);
170 compkind = icalcomponent_isa(comp);
172 if( ! (gaugekind == compkind || gaugekind == ICAL_ANY_COMPONENT) ){
176 /* Test properties. For each property in the gauge, search through
177 the component for a similar property. If one is found, compare
178 the two properties value with the comparison specified in the
179 gauge with the X-LIC-COMPARETYPE parameter */
181 for(p = icalcomponent_get_first_property(gauge,ICAL_ANY_PROPERTY);
183 p = icalcomponent_get_next_property(gauge,ICAL_ANY_PROPERTY)){
185 icalproperty* targetprop;
186 icalparameter* compareparam;
187 icalparameter_xliccomparetype compare;
188 int rel; /* The relationship between the gauge and target values.*/
190 /* Extract the comparison type from the gauge. If there is no
191 comparison type, assume that it is "EQUAL" */
193 compareparam = icalproperty_get_first_parameter(
195 ICAL_XLICCOMPARETYPE_PARAMETER);
197 if (compareparam!=0){
198 compare = icalparameter_get_xliccomparetype(compareparam);
200 compare = ICAL_XLICCOMPARETYPE_EQUAL;
203 /* Find a property in the component that has the same type
204 as the gauge property. HACK -- multiples of a single
205 property type in the gauge will match only the first
206 instance in the component */
208 targetprop = icalcomponent_get_first_property(comp,
209 icalproperty_isa(p));
213 /* Compare the values of the gauge property and the target
216 rel = icalvalue_compare(icalproperty_get_value(p),
217 icalproperty_get_value(targetprop));
219 /* Now see if the comparison is equavalent to the comparison
220 specified in the gauge */
224 } else if (compare == ICAL_XLICCOMPARETYPE_LESSEQUAL &&
225 ( rel == ICAL_XLICCOMPARETYPE_LESS ||
226 rel == ICAL_XLICCOMPARETYPE_EQUAL)) {
228 } else if (compare == ICAL_XLICCOMPARETYPE_GREATEREQUAL &&
229 ( rel == ICAL_XLICCOMPARETYPE_GREATER ||
230 rel == ICAL_XLICCOMPARETYPE_EQUAL)) {
232 } else if (compare == ICAL_XLICCOMPARETYPE_NOTEQUAL &&
233 ( rel == ICAL_XLICCOMPARETYPE_GREATER ||
234 rel == ICAL_XLICCOMPARETYPE_LESS)) {
240 pass = pass && (localpass>0);
244 /* Test subcomponents. Look for a child component that has a
245 counterpart in the gauge. If one is found, recursively call
248 for(subgauge = icalcomponent_get_first_component(gauge,ICAL_ANY_COMPONENT);
250 subgauge = icalcomponent_get_next_component(gauge,ICAL_ANY_COMPONENT)){
252 gaugekind = icalcomponent_isa(subgauge);
254 if (gaugekind == ICAL_ANY_COMPONENT){
255 child = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT);
257 child = icalcomponent_get_first_component(comp,gaugekind);
261 localpass = icalgauge_compare_recurse(child,subgauge);
262 pass = pass && localpass;
272 int icalgauge_compare(icalgauge* gauge,icalcomponent* comp)
275 icalcomponent *inner;
277 int last_clause = 1, this_clause = 1;
279 icalcomponent_kind kind;
281 int compare_recur = 0;
284 icalerror_check_arg_rz( (comp!=0), "comp");
285 icalerror_check_arg_rz( (gauge!=0), "gauge");
287 inner = icalcomponent_get_first_real_component(comp);
290 /* Wally Yau: our component is not always wrapped with
291 * a <VCALENDAR>. It's not an error.
292 * icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
294 kind = icalcomponent_isa(comp);
295 if(kind == ICAL_VEVENT_COMPONENT ||
296 kind == ICAL_VTODO_COMPONENT ||
297 kind == ICAL_VJOURNAL_COMPONENT ||
298 kind == ICAL_VQUERY_COMPONENT ||
299 kind == ICAL_VAGENDA_COMPONENT){
303 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
309 /* Check that this component is one of the FROM types */
311 for(e = pvl_head(gauge->from);e!=0;e=pvl_next(e)){
312 icalcomponent_kind k = (icalcomponent_kind)pvl_data(e);
314 if(k == icalcomponent_isa(inner)){
324 /**** Check each where clause against the component ****/
325 for(e = pvl_head(gauge->where);e!=0;e=pvl_next(e)){
326 struct icalgauge_where *w = pvl_data(e);
327 icalcomponent *sub_comp;
332 if(w->prop == ICAL_NO_PROPERTY || w->value == 0){
333 icalerror_set_errno(ICAL_INTERNAL_ERROR);
337 /* First, create a value from the gauge */
338 vk = icalenum_property_kind_to_value_kind(w->prop);
340 if(vk == ICAL_NO_VALUE){
341 icalerror_set_errno(ICAL_INTERNAL_ERROR);
345 if (w->compare == ICALGAUGECOMPARE_ISNULL || w->compare == ICALGAUGECOMPARE_ISNOTNULL)
346 v = icalvalue_new(vk);
348 v = icalvalue_new_from_string(vk,w->value);
351 /* Keep error set by icalvalue_from-string*/
355 /* Now find the corresponding property in the component,
356 descending into a sub-component if necessary */
358 if(w->comp == ICAL_NO_COMPONENT){
361 sub_comp = icalcomponent_get_first_component(inner,w->comp);
368 /* check if it is a recurring */
369 rrule = icalcomponent_get_first_property(sub_comp,ICAL_RRULE_PROPERTY);
374 if (w->prop == ICAL_DTSTART_PROPERTY ||
375 w->prop == ICAL_DTEND_PROPERTY ||
376 w->prop == ICAL_DUE_PROPERTY){
377 /** needs to use recurrence-id to do comparison */
385 local_pass = (w->compare == ICALGAUGECOMPARE_ISNULL) ? 1 : 0;
387 for(prop = icalcomponent_get_first_property(sub_comp,w->prop);
389 prop = icalcomponent_get_next_property(sub_comp,w->prop)){
390 icalvalue* prop_value;
391 icalgaugecompare relation;
393 if (w->compare == ICALGAUGECOMPARE_ISNULL) {
398 if (w->compare == ICALGAUGECOMPARE_ISNOTNULL) {
404 icalproperty *p = icalcomponent_get_first_property(sub_comp, ICAL_RECURRENCEID_PROPERTY);
405 prop_value = icalproperty_get_value(p);
407 else /* prop value from this component */
408 prop_value = icalproperty_get_value(prop);
410 relation = (icalgaugecompare)icalvalue_compare(prop_value,v);
412 if (relation == w->compare){
414 } else if (w->compare == ICALGAUGECOMPARE_LESSEQUAL &&
415 ( relation == ICALGAUGECOMPARE_LESS ||
416 relation == ICALGAUGECOMPARE_EQUAL)) {
418 } else if (w->compare == ICALGAUGECOMPARE_GREATEREQUAL &&
419 ( relation == ICALGAUGECOMPARE_GREATER ||
420 relation == ICALGAUGECOMPARE_EQUAL)) {
422 } else if (w->compare == ICALGAUGECOMPARE_NOTEQUAL &&
423 ( relation == ICALGAUGECOMPARE_GREATER ||
424 relation == ICALGAUGECOMPARE_LESS)) {
432 this_clause = local_pass > 0 ? 1 : 0;
435 /* Now look at the logic operator for this clause to see how
436 the value should be merge with the previous clause */
438 if(w->logic == ICALGAUGELOGIC_AND){
439 last_clause = this_clause && last_clause;
440 } else if(w->logic == ICALGAUGELOGIC_OR) {
441 last_clause = this_clause || last_clause;
443 last_clause = this_clause;
448 }/**** check next one in where clause ****/
455 * Print gauge information to stdout.
458 void icalgauge_dump(icalgauge* gauge)
463 printf("--- Select ---\n");
464 for(p = pvl_head(gauge->select);p!=0;p=pvl_next(p)){
465 struct icalgauge_where *w = pvl_data(p);
467 if(w->comp != ICAL_NO_COMPONENT){
468 printf("%s ",icalenum_component_kind_to_string(w->comp));
471 if(w->prop != ICAL_NO_PROPERTY){
472 printf("%s ",icalenum_property_kind_to_string(w->prop));
475 if (w->compare != ICALGAUGECOMPARE_NONE){
476 printf("%d ",w->compare);
481 printf("%s",w->value);
488 printf("--- From ---\n");
489 for(p = pvl_head(gauge->from);p!=0;p=pvl_next(p)){
490 icalcomponent_kind k = (icalcomponent_kind)pvl_data(p);
492 printf("%s\n",icalenum_component_kind_to_string(k));
495 printf("--- Where ---\n");
496 for(p = pvl_head(gauge->where);p!=0;p=pvl_next(p)){
497 struct icalgauge_where *w = pvl_data(p);
499 if(w->logic != ICALGAUGELOGIC_NONE){
500 printf("%d ",w->logic);
503 if(w->comp != ICAL_NO_COMPONENT){
504 printf("%s ",icalenum_component_kind_to_string(w->comp));
507 if(w->prop != ICAL_NO_PROPERTY){
508 printf("%s ",icalenum_property_kind_to_string(w->prop));
511 if (w->compare != ICALGAUGECOMPARE_NONE){
512 printf("%d ",w->compare);
517 printf("%s",w->value);