$darkmode
Libical API Documentation 4.0 STABLE VERSION Visit the v3.0 documentation
icalgauge.c
Go to the documentation of this file.
1 /*======================================================================
2  FILE: icalgauge.c
3  CREATOR: eric 23 December 1999
4 
5  SPDX-FileCopyrightText: 2000, Eric Busboom <eric@civicknowledge.com>
6  SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
7 
8  The Original Code is eric. The Initial Developer of the Original
9  Code is Eric Busboom
10 ======================================================================*/
11 
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20 
21 #include "icalgauge.h"
22 #include "icalgaugeimpl.h"
23 #include "icalerror_p.h"
24 #include "icalpvl_p.h"
25 #include "icalvalue.h"
26 
27 #include <stddef.h> /* for ptrdiff_t */
28 #include <stdlib.h>
29 
31 extern int ssparse(void);
32 extern char *input_buffer;
33 extern char *input_buffer_p;
34 
35 struct icalgauge_impl *icalss_yy_gauge;
37 
38 icalgauge *icalgauge_new_from_sql(const char *sql, int expand)
39 {
40  struct icalgauge_impl *impl;
41  int r;
42 
43  if ((impl = (struct icalgauge_impl *)malloc(sizeof(struct icalgauge_impl))) == 0) {
45  return 0;
46  }
47 
48  impl->select = icalpvl_newlist();
49  impl->from = icalpvl_newlist();
50  impl->where = icalpvl_newlist();
51  impl->expand = expand;
52 
53  icalss_yy_gauge = impl;
54  input_buffer = input_buffer_p = (char *)sql;
55 
56  r = ssparse();
57 
58  if (r == 0) {
59  return impl;
60  } else {
61  icalgauge_free(impl);
62  return NULL;
63  }
64 }
65 
66 int icalgauge_get_expand(const icalgauge *gauge)
67 {
68  icalerror_check_arg_rz((gauge != 0), "gauge");
69  return gauge->expand;
70 }
71 
72 void icalgauge_free(icalgauge *gauge)
73 {
74  struct icalgauge_where *w;
75 
76  assert(gauge->select != 0);
77  assert(gauge->where != 0);
78  assert(gauge->from != 0);
79 
80  if (gauge->select) {
81  while ((w = icalpvl_pop(gauge->select)) != 0) {
82  if (w->value != 0) {
83  free(w->value);
84  }
85  free(w);
86  }
87  icalpvl_free(gauge->select);
88  gauge->select = 0;
89  }
90 
91  if (gauge->where) {
92  while ((w = icalpvl_pop(gauge->where)) != 0) {
93  if (w->value != 0) {
94  free(w->value);
95  }
96  free(w);
97  }
98  icalpvl_free(gauge->where);
99  gauge->where = 0;
100  }
101 
102  if (gauge->from) {
103  icalpvl_free(gauge->from);
104  gauge->from = 0;
105  }
106 
107  free(gauge);
108 }
109 
111 /*non-static,recursive*/
112 int icalgauge_compare_recurse(icalcomponent *comp, icalcomponent *gauge)
113 {
114  int pass = 1, localpass = 0;
115  icalproperty *p;
116  icalcomponent *child, *subgauge;
117  icalcomponent_kind gaugekind, compkind;
118 
119  icalerror_check_arg_rz((comp != 0), "comp");
120  icalerror_check_arg_rz((gauge != 0), "gauge");
121 
122  gaugekind = icalcomponent_isa(gauge);
123  compkind = icalcomponent_isa(comp);
124 
125  if (!(gaugekind == compkind || gaugekind == ICAL_ANY_COMPONENT)) {
126  return 0;
127  }
128 
129  /* Test properties. For each property in the gauge, search through
130  the component for a similar property. If one is found, compare
131  the two properties value with the comparison specified in the
132  gauge with the X-LIC-COMPARETYPE parameter */
133 
134  for (p = icalcomponent_get_first_property(gauge, ICAL_ANY_PROPERTY);
135  p != 0;
136  p = icalcomponent_get_next_property(gauge, ICAL_ANY_PROPERTY)) {
137  icalproperty *targetprop;
138  icalparameter *compareparam;
139  icalparameter_xliccomparetype compare;
140 
141  /* Extract the comparison type from the gauge. If there is no
142  comparison type, assume that it is "EQUAL" */
143 
144  compareparam = icalproperty_get_first_parameter(p, ICAL_XLICCOMPARETYPE_PARAMETER);
145 
146  if (compareparam != 0) {
147  compare = icalparameter_get_xliccomparetype(compareparam);
148  } else {
149  compare = ICAL_XLICCOMPARETYPE_EQUAL;
150  }
151 
152  /* Find a property in the component that has the same type
153  as the gauge property. HACK -- multiples of a single
154  property type in the gauge will match only the first
155  instance in the component */
156 
157  targetprop = icalcomponent_get_first_property(comp, icalproperty_isa(p));
158 
159  if (targetprop != 0) {
160  /* Compare the values of the gauge property and the target
161  property */
162 
163  /* The relationship between the gauge and target values */
164  icalparameter_xliccomparetype rel = icalvalue_compare(icalproperty_get_value(p), icalproperty_get_value(targetprop));
165 
166  /* Now see if the comparison is equivalent to the comparison
167  specified in the gauge */
168 
169  if (rel == ICAL_XLICCOMPARETYPE_NONE || compare == ICAL_XLICCOMPARETYPE_NONE) {
170  localpass = 0;
171  } else if (rel == compare) {
172  localpass++;
173  } else if (compare == ICAL_XLICCOMPARETYPE_LESSEQUAL &&
174  (rel == ICAL_XLICCOMPARETYPE_LESS || rel == ICAL_XLICCOMPARETYPE_EQUAL)) {
175  localpass++;
176  } else if (compare == ICAL_XLICCOMPARETYPE_GREATEREQUAL &&
177  (rel == ICAL_XLICCOMPARETYPE_GREATER || rel == ICAL_XLICCOMPARETYPE_EQUAL)) {
178  localpass++;
179  } else if (compare == ICAL_XLICCOMPARETYPE_NOTEQUAL &&
180  (rel == ICAL_XLICCOMPARETYPE_GREATER || rel == ICAL_XLICCOMPARETYPE_LESS)) {
181  localpass++;
182  } else {
183  localpass = 0;
184  }
185 
186  pass = pass && (localpass > 0);
187  }
188  }
189 
190  /* Test subcomponents. Look for a child component that has a
191  counterpart in the gauge. */
192 
194  subgauge != 0;
196  gaugekind = icalcomponent_isa(subgauge);
197 
198  if (gaugekind == ICAL_ANY_COMPONENT) {
200  } else {
201  child = icalcomponent_get_first_component(comp, gaugekind);
202  }
203 
204  if (child != 0) {
205  localpass = icalgauge_compare_recurse(child, subgauge);
206  pass = pass && localpass;
207  } else {
208  pass = 0;
209  }
210  }
211 
212  return pass;
213 }
215 
216 bool icalgauge_compare(icalgauge *gauge, icalcomponent *comp)
217 {
218  icalcomponent *inner;
219  int local_pass = 0;
220  bool last_clause = true;
221  icalpvl_elem e;
222  int compare_recur = 0;
223 
224  icalerror_check_arg_rz((comp != 0), "comp");
225  icalerror_check_arg_rz((gauge != 0), "gauge");
226 
228 
229  if (inner == 0) {
230  /* Wally Yau: our component is not always wrapped with
231  * a <VCALENDAR>. It's not an error.
232  * icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
233  * return false; */
235  if (kind == ICAL_VEVENT_COMPONENT ||
236  kind == ICAL_VTODO_COMPONENT ||
237  kind == ICAL_VJOURNAL_COMPONENT ||
238  kind == ICAL_VQUERY_COMPONENT || kind == ICAL_VAGENDA_COMPONENT) {
239  inner = comp;
240  } else {
242  return false;
243  }
244  }
245 
246  /* Check that this component is one of the FROM types */
247  local_pass = 0;
248  for (e = icalpvl_head(gauge->from); e != 0; e = icalpvl_next(e)) {
249  icalcomponent_kind k = (icalcomponent_kind)(ptrdiff_t)icalpvl_data(e);
250 
251  if (k == icalcomponent_isa(inner)) {
252  local_pass = 1;
253  }
254  }
255 
256  if (local_pass == 0) {
257  return false;
258  }
259 
260  /**** Check each where clause against the component ****/
261  for (e = icalpvl_head(gauge->where); e != 0; e = icalpvl_next(e)) {
262  struct icalgauge_where *w = icalpvl_data(e);
263  icalcomponent *sub_comp;
264  icalvalue *v;
265  icalproperty *prop;
266  icalvalue_kind vk;
267 
268  if (!w || w->prop == ICAL_NO_PROPERTY || w->value == 0) {
270  return false;
271  }
272 
273  /* First, create a value from the gauge */
274  vk = icalproperty_kind_to_value_kind(w->prop);
275 
276  if (vk == ICAL_NO_VALUE) {
278  return false;
279  }
280 
281  if (w->compare == ICALGAUGECOMPARE_ISNULL || w->compare == ICALGAUGECOMPARE_ISNOTNULL) {
282  v = icalvalue_new(vk);
283  } else {
284  v = icalvalue_new_from_string(vk, w->value);
285  }
286 
287  if (v == 0) {
288  /* Keep error set by icalvalue_from-string */
289  return false;
290  }
291 
292  /* Now find the corresponding property in the component,
293  descending into a sub-component if necessary */
294 
295  if (w->comp == ICAL_NO_COMPONENT) {
296  sub_comp = inner;
297  } else {
298  sub_comp = icalcomponent_get_first_component(inner, w->comp);
299  if (sub_comp == 0) {
300  icalvalue_free(v);
301  return false;
302  }
303  }
304 
305  /* check if it is a recurring */
306  const icalproperty *rrule = icalcomponent_get_first_property(sub_comp, ICAL_RRULE_PROPERTY);
307 
308  if (gauge->expand && rrule) {
309  if (w->prop == ICAL_DTSTART_PROPERTY ||
310  w->prop == ICAL_DTEND_PROPERTY || w->prop == ICAL_DUE_PROPERTY) {
312  compare_recur = 1;
313  }
314  }
315 
316  local_pass = (w->compare == ICALGAUGECOMPARE_ISNULL) ? 1 : 0;
317 
318  for (prop = icalcomponent_get_first_property(sub_comp, w->prop);
319  prop != 0;
320  prop = icalcomponent_get_next_property(sub_comp, w->prop)) {
321  icalvalue *prop_value;
322  icalgaugecompare relation;
323 
324  if (w->compare == ICALGAUGECOMPARE_ISNULL) {
325  local_pass = 0;
326  break;
327  }
328 
329  if (w->compare == ICALGAUGECOMPARE_ISNOTNULL) {
330  local_pass = 1;
331  break;
332  }
333 
334  if (compare_recur) {
335  icalproperty *p =
336  icalcomponent_get_first_property(sub_comp, ICAL_RECURRENCEID_PROPERTY);
337  prop_value = icalproperty_get_value(p);
338  } else { /* prop value from this component */
339  prop_value = icalproperty_get_value(prop);
340  }
341 
342  relation = (icalgaugecompare)icalvalue_compare(prop_value, v);
343 
344  if (relation == w->compare) {
345  local_pass++;
346  } else if (w->compare == ICALGAUGECOMPARE_LESSEQUAL &&
347  (relation == ICALGAUGECOMPARE_LESS || relation == ICALGAUGECOMPARE_EQUAL)) {
348  local_pass++;
349  } else if (w->compare == ICALGAUGECOMPARE_GREATEREQUAL &&
350  (relation == ICALGAUGECOMPARE_GREATER ||
351  relation == ICALGAUGECOMPARE_EQUAL)) {
352  local_pass++;
353  } else if (w->compare == ICALGAUGECOMPARE_NOTEQUAL &&
354  (relation == ICALGAUGECOMPARE_GREATER ||
355  relation == ICALGAUGECOMPARE_LESS)) {
356  local_pass++;
357  } else {
358  local_pass = 0;
359  }
360  }
361 
362  bool this_clause = (local_pass > 0);
363 
364  /* Now look at the logic operator for this clause to see how
365  the value should be merge with the previous clause */
366 
367  if (w->logic == ICALGAUGELOGIC_AND) {
368  last_clause = this_clause && last_clause;
369  } else if (w->logic == ICALGAUGELOGIC_OR) {
370  last_clause = this_clause || last_clause;
371  } else {
372  last_clause = this_clause;
373  }
374 
375  icalvalue_free(v);
376 
377  } /**** check next one in where clause ****/
378 
379  return last_clause;
380 }
381 
382 void icalgauge_dump(icalgauge *gauge)
383 {
384  icalpvl_elem p;
385 
386  printf("--- Select ---\n");
387  for (p = icalpvl_head(gauge->select); p != 0; p = icalpvl_next(p)) {
388  struct icalgauge_where *w = icalpvl_data(p);
389 
390  if (!w) {
391  continue;
392  }
393 
394  if (w->comp != ICAL_NO_COMPONENT) {
395  printf("%s ", icalcomponent_kind_to_string(w->comp));
396  }
397 
398  if (w->prop != ICAL_NO_PROPERTY) {
399  printf("%s ", icalproperty_kind_to_string(w->prop));
400  }
401 
402  if (w->compare != ICALGAUGECOMPARE_NONE) {
403  printf("%d ", w->compare);
404  }
405 
406  if (w->value != 0) {
407  printf("%s", w->value);
408  }
409 
410  printf("\n");
411  }
412 
413  printf("--- From ---\n");
414  for (p = icalpvl_head(gauge->from); p != 0; p = icalpvl_next(p)) {
415  icalcomponent_kind k = (icalcomponent_kind)(ptrdiff_t)icalpvl_data(p);
416 
417  printf("%s\n", icalcomponent_kind_to_string(k));
418  }
419 
420  printf("--- Where ---\n");
421  for (p = icalpvl_head(gauge->where); p != 0; p = icalpvl_next(p)) {
422  struct icalgauge_where *w = icalpvl_data(p);
423 
424  if (!w) {
425  continue;
426  }
427 
428  if (w->logic != ICALGAUGELOGIC_NONE) {
429  printf("%d ", w->logic);
430  }
431 
432  if (w->comp != ICAL_NO_COMPONENT) {
433  printf("%s ", icalcomponent_kind_to_string(w->comp));
434  }
435 
436  if (w->prop != ICAL_NO_PROPERTY) {
437  printf("%s ", icalproperty_kind_to_string(w->prop));
438  }
439 
440  if (w->compare != ICALGAUGECOMPARE_NONE) {
441  printf("%d ", w->compare);
442  }
443 
444  if (w->value != 0) {
445  printf("%s", w->value);
446  }
447 
448  printf("\n");
449  }
450 }
icalcomponent * icalcomponent_get_first_component(icalcomponent *c, icalcomponent_kind kind)
const char * icalproperty_kind_to_string(icalproperty_kind kind)
bool icalgauge_compare(icalgauge *gauge, icalcomponent *comp)
Definition: icalgauge.c:216
icalvalue * icalproperty_get_value(const icalproperty *prop)
Definition: icalproperty.c:817
icalparameter_xliccomparetype icalvalue_compare(const icalvalue *a, const icalvalue *b)
Definition: icalvalue.c:1356
Routines implementing a filter for ical components.
icalproperty_kind icalproperty_isa(const icalproperty *p)
Definition: icalproperty.c:466
icalproperty * icalcomponent_get_next_property(icalcomponent *c, icalproperty_kind kind)
Defines the data structure representing iCalendar parameter values.
icalcomponent * icalcomponent_get_first_real_component(const icalcomponent *c)
icalgauge * icalgauge_new_from_sql(const char *sql, int expand)
Definition: icalgauge.c:38
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition: icalerror.c:90
void icalvalue_free(icalvalue *v)
Definition: icalvalue.c:796
icalvalue_kind icalproperty_kind_to_value_kind(icalproperty_kind kind)
icalcomponent * icalcomponent_get_next_component(icalcomponent *c, icalcomponent_kind kind)
void icalgauge_dump(icalgauge *gauge)
Definition: icalgauge.c:382
icalparameter * icalproperty_get_first_parameter(icalproperty *p, icalparameter_kind kind)
Definition: icalproperty.c:704
void icalgauge_free(icalgauge *gauge)
Definition: icalgauge.c:72
icalcomponent_kind
Definition: icalenums.h:28
icalcomponent_kind icalcomponent_isa(const icalcomponent *component)
icalvalue * icalvalue_new(icalvalue_kind kind)
Definition: icalvalue.c:60
int icalgauge_get_expand(const icalgauge *gauge)
Definition: icalgauge.c:66
icalvalue * icalvalue_new_from_string(icalvalue_kind kind, const char *str)
Definition: icalvalue.c:791
const char * icalcomponent_kind_to_string(icalcomponent_kind kind)
icalproperty * icalcomponent_get_first_property(icalcomponent *c, icalproperty_kind kind)