1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* Copyright (C) 2001-2004 Novell, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
20 /* e2k-restriction.c: message restrictions (WHERE clauses / Rule conditions) */
26 #include "e2k-restriction.h"
27 #include "e2k-properties.h"
33 static E2kRestriction *
34 conjoin (E2kRestrictionType type, int nrns, E2kRestriction **rns, gboolean unref)
36 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
40 ret->res.and.nrns = nrns;
41 ret->res.and.rns = g_new (E2kRestriction *, nrns);
42 for (i = 0; i < nrns; i++) {
43 ret->res.and.rns[i] = rns[i];
45 e2k_restriction_ref (rns[i]);
52 * e2k_restriction_and:
53 * @nrns: length of @rns
54 * @rns: an array of #E2kRestriction
55 * @unref: whether or not to unref the restrictions when it is done
57 * Creates a new restriction which is true if all of the restrictions
60 * If @unref is %TRUE, then e2k_restriction_and() is essentially
61 * stealing the caller's references on the restrictions. If it is
62 * %FALSE, then e2k_restriction_and() will acquire its own references
63 * to each of the restrictions.
65 * Return value: the new restriction
68 e2k_restriction_and (int nrns, E2kRestriction **rns, gboolean unref)
70 return conjoin (E2K_RESTRICTION_AND, nrns, rns, unref);
75 * @nrns: length of @rns
76 * @rns: an array of #E2kRestriction
77 * @unref: see e2k_restriction_and()
79 * Creates a new restriction which is true if any of the restrictions
82 * Return value: the new restriction
85 e2k_restriction_or (int nrns, E2kRestriction **rns, gboolean unref)
87 return conjoin (E2K_RESTRICTION_OR, nrns, rns, unref);
90 static E2kRestriction *
91 conjoinv (E2kRestrictionType type, E2kRestriction *rn, va_list ap)
93 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
96 rns = g_ptr_array_new ();
98 g_ptr_array_add (rns, rn);
99 rn = va_arg (ap, E2kRestriction *);
104 ret->res.and.nrns = rns->len;
105 ret->res.and.rns = (E2kRestriction **)rns->pdata;
106 g_ptr_array_free (rns, FALSE);
112 * e2k_restriction_andv:
113 * @rn: an #E2kRestriction
114 * @...: a %NULL-terminated list of additional #E2kRestrictions
116 * Creates a new restriction which is true if all of the passed-in
117 * restrictions are true. e2k_restriction_andv() steals the caller's
118 * reference on each of the passed-in restrictions.
120 * Return value: the new restriction
123 e2k_restriction_andv (E2kRestriction *rn, ...)
128 return conjoinv (E2K_RESTRICTION_AND, rn, ap);
132 * e2k_restriction_orv:
133 * @rn: an #E2kRestriction
134 * @...: a %NULL-terminated list of additional #E2kRestrictions
136 * Creates a new restriction which is true if any of the passed-in
137 * restrictions are true. e2k_restriction_orv() steals the caller's
138 * reference on each of the passed-in restrictions.
140 * Return value: the new restriction
143 e2k_restriction_orv (E2kRestriction *rn, ...)
148 return conjoinv (E2K_RESTRICTION_OR, rn, ap);
152 * e2k_restriction_not:
153 * @rn: an #E2kRestriction
154 * @unref: see e2k_restriction_and()
156 * Creates a new restriction which is true if @rn is false.
158 * Return value: the new restriction
161 e2k_restriction_not (E2kRestriction *rn, gboolean unref)
163 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
165 ret->type = E2K_RESTRICTION_NOT;
166 ret->res.not.rn = rn;
168 e2k_restriction_ref (rn);
174 * e2k_restriction_content:
175 * @propname: text property to compare against
176 * @fuzzy_level: how to compare
177 * @value: value to compare against
179 * Creates a new restriction that is true for objects where the
180 * indicated property's value matches @value according to @fuzzy_level.
182 * For a WebDAV SEARCH, @fuzzy_level should be %E2K_FL_FULLSTRING,
183 * %E2K_FL_SUBSTRING, %E2K_FL_PREFIX, or %E2K_FL_SUFFIX.
185 * For a MAPI restriction, @fuzzy_level may not be %E2K_FL_SUFFIX, but
186 * may be ORed with any of the additional values %E2K_FL_IGNORECASE,
187 * %E2K_FL_IGNORENONSPACE, or %E2K_FL_LOOSE.
189 * To compare a property's sort order to another string, use
190 * e2k_restriction_prop_string().
192 * Return value: the new restriction
195 e2k_restriction_content (const char *propname,
196 E2kRestrictionFuzzyLevel fuzzy_level,
199 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
201 ret->type = E2K_RESTRICTION_CONTENT;
202 ret->res.content.fuzzy_level = fuzzy_level;
203 e2k_rule_prop_set (&ret->res.content.pv.prop, propname);
204 ret->res.content.pv.type = E2K_PROP_TYPE_STRING;
205 ret->res.content.pv.value = g_strdup (value);
211 * e2k_restriction_prop_bool:
212 * @propname: boolean property to compare against
213 * @relop: %E2K_RELOP_EQ or %E2K_RELOP_NE
214 * @value: %TRUE or %FALSE
216 * Creates a new restriction that is true for objects where the
217 * indicated property matches @relop and @value.
219 * Return value: the new restriction
222 e2k_restriction_prop_bool (const char *propname, E2kRestrictionRelop relop,
225 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
227 ret->type = E2K_RESTRICTION_PROPERTY;
228 ret->res.property.relop = relop;
229 e2k_rule_prop_set (&ret->res.property.pv.prop, propname);
230 ret->res.property.pv.type = E2K_PROP_TYPE_BOOL;
231 ret->res.property.pv.value = GUINT_TO_POINTER (value);
237 * e2k_restriction_prop_int:
238 * @propname: integer property to compare against
239 * @relop: an #E2kRestrictionRelop
240 * @value: number to compare against
242 * Creates a new restriction that is true for objects where the
243 * indicated property matches @value according to @relop.
245 * Return value: the new restriction
248 e2k_restriction_prop_int (const char *propname, E2kRestrictionRelop relop,
251 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
253 ret->type = E2K_RESTRICTION_PROPERTY;
254 ret->res.property.relop = relop;
255 e2k_rule_prop_set (&ret->res.property.pv.prop, propname);
256 ret->res.property.pv.type = E2K_PROP_TYPE_INT;
257 ret->res.property.pv.value = GINT_TO_POINTER (value);
263 * e2k_restriction_prop_date:
264 * @propname: date/time property to compare against
265 * @relop: an #E2kRestrictionRelop
266 * @value: date/time to compare against (as returned by e2k_make_timestamp())
268 * Creates a new restriction that is true for objects where the
269 * indicated property matches @value according to @relop.
271 * Return value: the new restriction
274 e2k_restriction_prop_date (const char *propname, E2kRestrictionRelop relop,
277 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
279 ret->type = E2K_RESTRICTION_PROPERTY;
280 ret->res.property.relop = relop;
281 e2k_rule_prop_set (&ret->res.property.pv.prop, propname);
282 ret->res.property.pv.type = E2K_PROP_TYPE_DATE;
283 ret->res.property.pv.value = g_strdup (value);
289 * e2k_restriction_prop_string:
290 * @propname: text property to compare against
291 * @relop: an #E2kRestrictionRelop
292 * @value: text to compare against
294 * Creates a new restriction that is true for objects where the
295 * indicated property matches @value according to @relop.
297 * To do a substring match, use e2k_restriction_content().
299 * Return value: the new restriction
302 e2k_restriction_prop_string (const char *propname, E2kRestrictionRelop relop,
305 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
307 ret->type = E2K_RESTRICTION_PROPERTY;
308 ret->res.property.relop = relop;
309 e2k_rule_prop_set (&ret->res.property.pv.prop, propname);
310 ret->res.property.pv.type = E2K_PROP_TYPE_STRING;
311 ret->res.property.pv.value = g_strdup (value);
317 * e2k_restriction_prop_binary:
318 * @propname: binary property to compare against
319 * @relop: %E2K_RELOP_EQ or %E2K_RELOP_NE
320 * @data: data to compare against
321 * @len: length of @data
323 * Creates a new restriction that is true for objects where the
324 * indicated property matches @value according to @relop.
326 * Return value: the new restriction
329 e2k_restriction_prop_binary (const char *propname, E2kRestrictionRelop relop,
330 gconstpointer data, int len)
332 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
334 ret->type = E2K_RESTRICTION_PROPERTY;
335 ret->res.property.relop = relop;
336 e2k_rule_prop_set (&ret->res.property.pv.prop, propname);
337 ret->res.property.pv.type = E2K_PROP_TYPE_BINARY;
338 ret->res.property.pv.value = g_byte_array_new ();
339 g_byte_array_append (ret->res.property.pv.value, data, len);
345 * e2k_restriction_compare:
346 * @propname1: first property
347 * @relop: an #E2kRestrictionRelop
348 * @propname2: second property
350 * Creates a new restriction which is true for objects where
351 * @propname1 and @propname2 have the relationship described by
354 * Return value: the new restriction
357 e2k_restriction_compare (const char *propname1, E2kRestrictionRelop relop,
358 const char *propname2)
360 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
362 ret->type = E2K_RESTRICTION_COMPAREPROPS;
363 ret->res.compare.relop = relop;
364 e2k_rule_prop_set (&ret->res.compare.prop1, propname1);
365 e2k_rule_prop_set (&ret->res.compare.prop2, propname2);
371 * e2k_restriction_bitmask:
372 * @propname: integer property to compare
373 * @bitop: an #E2kRestrictionBitop
374 * @mask: mask of bits to compare against
376 * Creates a new restriction that is true for objects where the
377 * indicated bits of the value of @propname either are or aren't zero,
378 * as indicated by @bitop.
380 * This cannot be used for WebDAV SEARCH restrictions.
382 * Return value: the new restriction
385 e2k_restriction_bitmask (const char *propname, E2kRestrictionBitop bitop,
388 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
390 ret->type = E2K_RESTRICTION_BITMASK;
391 ret->res.bitmask.bitop = bitop;
392 e2k_rule_prop_set (&ret->res.bitmask.prop, propname);
393 ret->res.bitmask.mask = mask;
399 * e2k_restriction_size:
400 * @propname: property to compare
401 * @relop: an #E2kRestrictionRelop
402 * @size: the size to compare @propname to
404 * Creates a new restriction which is true for objects where the size
405 * of the value of @propname matches @size according to @relop.
407 * This cannot be used for WebDAV SEARCH restrictions.
409 * You probably do not want to use this. The standard idiom for
410 * checking the size of a message is to use e2k_restriction_prop_int()
411 * on its %PR_MESSAGE_SIZE property, not to use e2k_restriction_size()
414 * Return value: the new restriction
417 e2k_restriction_size (const char *propname, E2kRestrictionRelop relop,
420 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
422 ret->type = E2K_RESTRICTION_SIZE;
423 ret->res.size.relop = relop;
424 e2k_rule_prop_set (&ret->res.size.prop, propname);
425 ret->res.size.size = size;
431 * e2k_restriction_exist:
432 * @propname: property to check
434 * Creates a new restriction which is true for objects that have
435 * a @propname property.
437 * This cannot be used for WebDAV SEARCH restrictions.
439 * Return value: the new restriction
442 e2k_restriction_exist (const char *propname)
444 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
446 ret->type = E2K_RESTRICTION_EXIST;
447 e2k_rule_prop_set (&ret->res.exist.prop, propname);
453 * e2k_restriction_sub:
454 * @subtable: the WebDAV name of a MAPI property of type PT_OBJECT
455 * @rn: the restriction to apply against the values of @subtable
456 * @unref: see e2k_restriction_and()
458 * Creates a new restriction that is true for objects where @rn is
459 * true when applied to the value of @subtable on that object.
461 * @subtable is generally %PR_MESSAGE_RECIPIENTS (for finding messages
462 * whose recipients match a given restriction) or
463 * %PR_MESSAGE_ATTACHMENTS (for finding messages whose attachments
464 * match a given restriction).
466 * This cannot be used for WebDAV SEARCH restrictions.
468 * Return value: the new restriction
471 e2k_restriction_sub (const char *subtable, E2kRestriction *rn, gboolean unref)
473 E2kRestriction *ret = g_new0 (E2kRestriction, 1);
475 ret->type = E2K_RESTRICTION_SUBRESTRICTION;
476 e2k_rule_prop_set (&ret->res.sub.subtable, subtable);
477 ret->res.sub.rn = rn;
479 e2k_restriction_ref (rn);
485 * e2k_restriction_unref:
488 * Unrefs @rn. If there are no more references to @rn, it is freed.
491 e2k_restriction_unref (E2kRestriction *rn)
499 case E2K_RESTRICTION_AND:
500 case E2K_RESTRICTION_OR:
501 for (i = 0; i < rn->res.and.nrns; i++)
502 e2k_restriction_unref (rn->res.and.rns[i]);
503 g_free (rn->res.and.rns);
506 case E2K_RESTRICTION_NOT:
507 e2k_restriction_unref (rn->res.not.rn);
510 case E2K_RESTRICTION_CONTENT:
511 e2k_rule_free_propvalue (&rn->res.content.pv);
514 case E2K_RESTRICTION_PROPERTY:
515 e2k_rule_free_propvalue (&rn->res.property.pv);
526 * e2k_restriction_ref:
532 e2k_restriction_ref (E2kRestriction *rn)
540 static gboolean rn_to_sql (E2kRestriction *rn, GString *sql, E2kRestrictionType inside);
542 static const char *sql_relops[] = { "<", "<=", ">", ">=", "=", "!=" };
543 static const int n_sql_relops = G_N_ELEMENTS (sql_relops);
546 rns_to_sql (E2kRestrictionType type, E2kRestriction **rns, int nrns, GString *sql)
549 gboolean need_op = FALSE;
552 for (i = 0; i < nrns; i++) {
554 g_string_append (sql, type == E2K_RESTRICTION_AND ?
558 if (rn_to_sql (rns[i], sql, type)) {
567 append_sql_quoted (GString *sql, const char *string)
571 g_string_append (sql, "''");
573 g_string_append_c (sql, *string);
579 rn_to_sql (E2kRestriction *rn, GString *sql, E2kRestrictionType inside)
584 case E2K_RESTRICTION_AND:
585 case E2K_RESTRICTION_OR: {
586 GString *subsql = g_string_new ("");
588 if ((rv = rns_to_sql (rn->type, rn->res.and.rns, rn->res.and.nrns, subsql))) {
589 if (rn->type != inside)
590 g_string_append (sql, "(");
591 g_string_append (sql, subsql->str);
592 if (rn->type != inside)
593 g_string_append (sql, ")");
595 g_string_free (subsql, TRUE);
600 case E2K_RESTRICTION_NOT: {
601 GString *subsql = g_string_new ("");
603 if ((rv = rn_to_sql (rn->res.not.rn, subsql, rn->type))) {
604 g_string_append (sql, "NOT (");
605 g_string_append (sql, subsql->str);
606 g_string_append (sql, ")");
608 g_string_free (subsql, TRUE);
613 case E2K_RESTRICTION_CONTENT:
614 pv = &rn->res.content.pv;
615 g_string_append_printf (sql, "\"%s\" ", pv->prop.name);
617 switch (E2K_FL_MATCH_TYPE (rn->res.content.fuzzy_level)) {
618 case E2K_FL_SUBSTRING:
619 g_string_append (sql, "LIKE '%");
620 append_sql_quoted (sql, pv->value);
621 g_string_append (sql, "%'");
625 g_string_append (sql, "LIKE '");
626 append_sql_quoted (sql, pv->value);
627 g_string_append (sql, "%'");
631 g_string_append (sql, "LIKE '%");
632 append_sql_quoted (sql, pv->value);
633 g_string_append_c (sql, '\'');
636 case E2K_FL_FULLSTRING:
638 g_string_append (sql, "= '");
639 append_sql_quoted (sql, pv->value);
640 g_string_append_c (sql, '\'');
645 case E2K_RESTRICTION_PROPERTY:
646 if (rn->res.property.relop >= n_sql_relops)
649 pv = &rn->res.property.pv;
650 g_string_append_printf (sql, "\"%s\" %s ", pv->prop.name,
651 sql_relops[rn->res.property.relop]);
654 case E2K_PROP_TYPE_INT:
655 g_string_append_printf (sql, "%d",
656 GPOINTER_TO_UINT (pv->value));
659 case E2K_PROP_TYPE_BOOL:
660 g_string_append (sql, pv->value ? "True" : "False");
663 case E2K_PROP_TYPE_DATE:
664 g_string_append_printf (sql,
665 "cast (\"%s\" as 'dateTime.tz')",
670 g_string_append_c (sql, '\'');
671 append_sql_quoted (sql, pv->value);
672 g_string_append_c (sql, '\'');
677 case E2K_RESTRICTION_COMPAREPROPS:
678 if (rn->res.compare.relop >= n_sql_relops)
681 g_string_append_printf (sql, "\"%s\" %s \"%s\"",
682 rn->res.compare.prop1.name,
683 sql_relops[rn->res.compare.relop],
684 rn->res.compare.prop2.name);
687 case E2K_RESTRICTION_COMMENT:
690 case E2K_RESTRICTION_BITMASK:
691 case E2K_RESTRICTION_EXIST:
692 case E2K_RESTRICTION_SIZE:
693 case E2K_RESTRICTION_SUBRESTRICTION:
701 * e2k_restriction_to_sql:
704 * Converts @rn to an SQL WHERE clause to be used with the WebDAV
705 * SEARCH method. Note that certain restriction types cannot be used
706 * in SQL, as mentioned in their descriptions above.
708 * If the restriction matches all objects, the return value will
709 * be the empty string. Otherwise it will start with "WHERE ".
711 * Return value: the SQL WHERE clause, which the caller must free,
712 * or %NULL if @rn could not be converted to SQL.
715 e2k_restriction_to_sql (E2kRestriction *rn)
720 sql = g_string_new (NULL);
721 if (!rn_to_sql (rn, sql, E2K_RESTRICTION_AND)) {
722 g_string_free (sql, TRUE);
727 g_string_prepend (sql, "WHERE ");
730 g_string_free (sql, FALSE);
735 /* Binary import/export */
738 extract_restriction (guint8 **data, int *len, E2kRestriction **rn)
749 case E2K_RESTRICTION_AND:
750 case E2K_RESTRICTION_OR:
752 E2kRestriction **rns;
756 if (!e2k_rule_extract_uint16 (data, len, &nrns))
758 rns = g_new0 (E2kRestriction *, nrns);
759 for (i = 0; i < nrns; i++) {
760 if (!extract_restriction (data, len, &rns[i])) {
762 e2k_restriction_unref (rns[i]);
768 *rn = conjoin (type, nrns, rns, TRUE);
772 case E2K_RESTRICTION_NOT:
774 E2kRestriction *subrn;
776 if (!extract_restriction (data, len, &subrn))
778 *rn = e2k_restriction_not (subrn, TRUE);
782 case E2K_RESTRICTION_CONTENT:
788 if (!e2k_rule_extract_uint32 (data, len, &fuzzy_level) ||
789 !e2k_rule_extract_proptag (data, len, &prop) ||
790 !e2k_rule_extract_propvalue (data, len, &pv))
795 *rn = g_new0 (E2kRestriction, 1);
797 (*rn)->res.content.fuzzy_level = fuzzy_level;
798 (*rn)->res.content.pv = pv;
802 case E2K_RESTRICTION_PROPERTY:
808 if (!e2k_rule_extract_byte (data, len, &relop) ||
809 !e2k_rule_extract_proptag (data, len, &prop) ||
810 !e2k_rule_extract_propvalue (data, len, &pv))
815 *rn = g_new0 (E2kRestriction, 1);
817 (*rn)->res.property.relop = relop;
818 (*rn)->res.property.pv = pv;
822 case E2K_RESTRICTION_COMPAREPROPS:
828 case E2K_RESTRICTION_BITMASK:
834 if (!e2k_rule_extract_byte (data, len, &bitop) ||
835 !e2k_rule_extract_proptag (data, len, &prop) ||
836 !e2k_rule_extract_uint32 (data, len, &mask))
839 *rn = g_new0 (E2kRestriction, 1);
841 (*rn)->res.bitmask.bitop = bitop;
842 (*rn)->res.bitmask.prop = prop;
843 (*rn)->res.bitmask.mask = mask;
847 case E2K_RESTRICTION_SIZE:
853 case E2K_RESTRICTION_EXIST:
857 if (!e2k_rule_extract_proptag (data, len, &prop))
860 *rn = g_new0 (E2kRestriction, 1);
862 (*rn)->res.exist.prop = prop;
866 case E2K_RESTRICTION_SUBRESTRICTION:
868 E2kRuleProp subtable;
869 E2kRestriction *subrn;
871 if (!e2k_rule_extract_proptag (data, len, &subtable) ||
872 !extract_restriction (data, len, &subrn))
875 *rn = g_new0 (E2kRestriction, 1);
877 (*rn)->res.sub.subtable = subtable;
878 (*rn)->res.sub.rn = subrn;
882 case E2K_RESTRICTION_COMMENT:
884 guint8 nprops, dummy;
888 if (!e2k_rule_extract_byte (data, len, &nprops))
891 props = g_new0 (E2kPropValue, nprops);
892 for (i = 0; i < nprops; i++) {
893 if (!e2k_rule_extract_propvalue (data, len, &props[i])) {
895 e2k_rule_free_propvalue (&props[i]);
901 *rn = g_new0 (E2kRestriction, 1);
903 (*rn)->res.comment.nprops = nprops;
904 (*rn)->res.comment.props = props;
906 /* FIXME: There is always a "1" byte here, but I don't
909 if (!e2k_rule_extract_byte (data, len, &dummy) || dummy != 1) {
910 e2k_restriction_unref (*rn);
914 if (!extract_restriction (data, len, &(*rn)->res.comment.rn)) {
915 e2k_restriction_unref (*rn);
928 * e2k_restriction_extract:
929 * @data: pointer to data pointer
930 * @len: pointer to data length
931 * @rn: pointer to variable to store the extracted restriction in
933 * Attempts to extract a restriction from *@data, which contains
934 * a binary-encoded restriction from a server-side rule.
936 * On success, *@rn will contain the extracted restriction, *@data
937 * will be advanced past the end of the restriction data, and *@len
938 * will be decremented accordingly.
940 * Return value: success or failure
943 e2k_restriction_extract (guint8 **data, int *len, E2kRestriction **rn)
947 if (!e2k_rule_extract_uint32 (data, len, &rnlen))
952 if (rnlen == 1 && (*data)[0] == 0xFF) {
961 if ((*data)[0] != 0 || (*data)[1] != 0)
966 return extract_restriction (data, len, rn);
970 append_restriction (GByteArray *ba, E2kRestriction *rn)
974 e2k_rule_append_byte (ba, rn->type);
977 case E2K_RESTRICTION_AND:
978 case E2K_RESTRICTION_OR:
979 e2k_rule_append_uint16 (ba, rn->res.and.nrns);
980 for (i = 0; i < rn->res.and.nrns; i++)
981 append_restriction (ba, rn->res.and.rns[i]);
984 case E2K_RESTRICTION_NOT:
985 append_restriction (ba, rn->res.not.rn);
988 case E2K_RESTRICTION_CONTENT:
989 e2k_rule_append_uint32 (ba, rn->res.content.fuzzy_level);
990 e2k_rule_append_proptag (ba, &rn->res.content.pv.prop);
991 e2k_rule_append_propvalue (ba, &rn->res.content.pv);
994 case E2K_RESTRICTION_PROPERTY:
995 e2k_rule_append_byte (ba, rn->res.property.relop);
996 e2k_rule_append_proptag (ba, &rn->res.property.pv.prop);
997 e2k_rule_append_propvalue (ba, &rn->res.property.pv);
1000 case E2K_RESTRICTION_COMPAREPROPS:
1004 case E2K_RESTRICTION_BITMASK:
1005 e2k_rule_append_byte (ba, rn->res.bitmask.bitop);
1006 e2k_rule_append_proptag (ba, &rn->res.bitmask.prop);
1007 e2k_rule_append_uint32 (ba, rn->res.bitmask.mask);
1010 case E2K_RESTRICTION_SIZE:
1013 case E2K_RESTRICTION_EXIST:
1014 e2k_rule_append_proptag (ba, &rn->res.exist.prop);
1017 case E2K_RESTRICTION_SUBRESTRICTION:
1018 e2k_rule_append_proptag (ba, &rn->res.sub.subtable);
1019 append_restriction (ba, rn->res.sub.rn);
1022 case E2K_RESTRICTION_COMMENT:
1023 e2k_rule_append_byte (ba, rn->res.comment.nprops);
1025 for (i = 0; i < rn->res.comment.nprops; i++)
1026 e2k_rule_append_propvalue (ba, &rn->res.comment.props[i]);
1028 /* FIXME: There is always a "1" byte here, but I don't
1031 e2k_rule_append_byte (ba, 1);
1033 append_restriction (ba, rn->res.comment.rn);
1042 * e2k_restriction_append:
1043 * @ba: a buffer into which a server-side rule is being constructed
1044 * @rn: the restriction to append to @ba
1046 * Appends @rn to @ba as part of a server-side rule.
1049 e2k_restriction_append (GByteArray *ba, E2kRestriction *rn)
1051 int rnlen_offset, rnlen;
1054 e2k_rule_append_uint32 (ba, 1);
1055 e2k_rule_append_byte (ba, 0xFF);
1059 /* Save space for the length field */
1060 rnlen_offset = ba->len;
1061 e2k_rule_append_uint32 (ba, 0);
1064 e2k_rule_append_uint16 (ba, 0);
1066 append_restriction (ba, rn);
1068 rnlen = ba->len - rnlen_offset - 4;
1069 e2k_rule_write_uint32 (ba->data + rnlen_offset, rnlen);