Logo Search packages:      
Sourcecode: pan version File versions  Download package

rule-xml.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Pan - A Newsreader for Gtk+
 * Copyright (C) 2002  Charles Kerr <charles@rebelbase.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*********************
**********************  Includes
*********************/

#include <config.h>

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <glib.h>

#include <libxml/parser.h>
#include <libxml/xmlmemory.h>

#include <pan/base/debug.h>
#include <pan/base/log.h>
#include <pan/base/pan-i18n.h>
#include <pan/base/pan-glib-extensions.h>
#include <pan/base/util-file.h>

#include <pan/rules/rule-xml.h>

/************
*************  UTIL
************/

static void
newline_depth (GString * appendme, gint depth)
{
      gint i;
      g_string_append_c (appendme, '\n');
      for (i=0; i<depth; ++i)
            g_string_append_c (appendme, '\t');
}

static void
pan_g_string_append_escaped (GString * gstr, gchar * escapeme)
{
      gchar * pch = pan_str_escape (escapeme);
      g_string_append (gstr, pch);
      g_free (pch);
}


/*****
******  
******    WRITING
******  
*****/

static void
write_rule (GString * gstr, const Rule * r, gint depth)
{
      gint i;

      g_return_if_fail (gstr!=NULL);
      g_return_if_fail (r!=NULL);

      /* the rule itself */
      newline_depth (gstr, depth);
      g_string_append (gstr, "<rule name=\"");
      pan_g_string_append_escaped (gstr, r->name);
      g_string_append (gstr, "\" filter_name=\"");
      pan_g_string_append_escaped (gstr, r->filter_name);
      g_string_append_printf (gstr, "\" hits=\"%lu\" misses=\"%lu\"", 
            (gulong)r->hits, (gulong)(r->tries - r->hits));
      if (r->apply_to_incoming)
            g_string_append (gstr, " apply_to_incoming=\"t\"");

      switch (r->group_type)
      {
            case RULE_GROUP_WILDCARD:
                  g_string_append (gstr, " group_type=\"w\"");
                  g_string_append_printf (gstr, " group_wildcard=\"%s\"",
                        r->group_wildcard);
                  break;
            case RULE_GROUP_LIST:
                  if (r->group_list == NULL &&
                      r->group_list->len == 0)
                        break;
                  g_string_append (gstr, " group_type=\"l\"");
                  g_string_append (gstr, " group_list=\"");
                  for (i=0; i<r->group_list->len; i++)
                  {
                        if (i>0) g_string_append (gstr, ";");
                        g_string_append (gstr, (gchar *)
                              g_ptr_array_index(r->group_list, i));
                  }
                  g_string_append (gstr, "\"");
      }
      g_string_append (gstr, ">");

      /* alert */
      if ((r->action->flags & RULE_ACTION_SHOW_ALERT) != 0) {
            newline_depth (gstr, depth+1);
            g_string_append (gstr, "<alert message=\"");
            pan_g_string_append_escaped (gstr, r->action->alert_message);
            g_string_append (gstr, "\"/>");
      }

      /* decode */
      if ((r->action->flags & RULE_ACTION_DECODE) != 0) {
            newline_depth (gstr, depth+1);
            g_string_append (gstr, "<decode directory=\"");
            pan_g_string_append_escaped (gstr, r->action->decode_path);
            g_string_append (gstr, "\"/>");
      }

      /* read */
      if ((r->action->flags & RULE_ACTION_MARK_READ) != 0) {
            newline_depth (gstr, depth+1);
            g_string_append (gstr, "<read/>");
      }

      /* unread */
      if ((r->action->flags & RULE_ACTION_MARK_UNREAD) != 0) {
            newline_depth (gstr, depth+1);
            g_string_append (gstr, "<unread/>");
      }

      /* flag */
      if ((r->action->flags & RULE_ACTION_TAG_FOR_RETRIEVAL) != 0) {
            newline_depth (gstr, depth+1);
            g_string_append (gstr, "<flag/>");
      }

      /* fetch */
      if ((r->action->flags & RULE_ACTION_RETREIVE_BODY) != 0) {
            newline_depth (gstr, depth+1);
            g_string_append (gstr, "<fetch_body/>");
      }

      /* watch */
      if ((r->action->flags & RULE_ACTION_WATCH) != 0) {
            newline_depth (gstr, depth+1);
            g_string_append (gstr, "<watch/>");
      }

      /* ignore */
      if ((r->action->flags & RULE_ACTION_IGNORE) != 0) {
            newline_depth (gstr, depth+1);
            g_string_append (gstr, "<ignore/>");
      }

      /* discard */
      if ((r->action->flags & RULE_ACTION_DISCARD) != 0) {
            newline_depth (gstr, depth+1);
            g_string_append (gstr, "<discard/>");
      }

      newline_depth (gstr, depth);
      g_string_append (gstr, "</rule>");
}


char*
rule_xml_to_string  (const Rule  ** rules,
                     int            rule_qty)
{
      int i;
      GString * str;

      g_return_val_if_fail (rule_qty>=0, NULL);

      /* write the rules to a buf */
      str = g_string_sized_new (4096);
      for (i=0; i<rule_qty; ++i) {
            write_rule (str, rules[i], 1);
            if (i!=rule_qty)
                  g_string_append (str, "\n\n");
      }

      g_string_prepend (str, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
                             "<!DOCTYPE rules SYSTEM \"rules.dtd\">\n"
                             "<rules>\n");
      g_string_append (str, "\n</rules>");

      return g_string_free (str, FALSE);
}

static gboolean
rule_xml_fwrite (FILE        * fp,
                 const Rule ** rules,
                 gint          rule_qty)
{
      gchar  * pch;
      size_t   to_write, written;

      g_return_val_if_fail (fp!=NULL, 0);
      g_return_val_if_fail (rules!=NULL, 0);
      g_return_val_if_fail (rule_qty>0, 0);

      pch = rule_xml_to_string (rules, rule_qty);
      to_write = strlen (pch);
      written = fwrite (pch, sizeof(char), to_write, fp);
      g_free (pch);

      return to_write = written;
}

void
rule_xml_write (const char   * filename,
                const Rule  ** rules,
                int           rule_qty)
{
      /* sanity clause */
      g_return_if_fail (is_nonempty_string(filename));
      g_return_if_fail (rule_qty>=0);

      /* write the file */

      if (rule_qty == 0)
            unlink (filename);
      else {
            FILE * fp;
            char * filename_tmp = pan_file_make_temp (&fp);
            gboolean ok = fp ? TRUE : FALSE;

            if (ok) {
                  ok = rule_xml_fwrite (fp, rules, rule_qty);
                  fclose (fp);
            }
            
            if (ok && pan_file_swap_datafile (filename_tmp, filename))
                  log_add_va (LOG_INFO, _("Wrote rules to \"%s\""), filename);

            g_free (filename_tmp);
      }
}

/****
*****  
*****    READING
*****  
****/

static Rule*
create_rule (xmlDoc * doc, xmlNode * node)
{
      Rule * r = NULL;
      xmlChar * val;
      xmlNode * child;
      const gchar * tag = (const gchar*) node->name;

      if (pan_strcmp(tag,"rule")!=0)
            return NULL;

      /* init toplevel */
      r = rule_new ();

      /* populate toplevel */
      if ((val = xmlGetProp (node, "name")) != NULL) {
            replace_gstr (&r->name, g_strdup(val));
            xmlFree (val);
      }
      if ((val = xmlGetProp (node, "filter_name")) != NULL) {
            replace_gstr (&r->filter_name, g_strdup(val));
            xmlFree (val);
      }
      if ((val = xmlGetProp (node, "hits")) != NULL) {
            r->hits = atoi (val);
            r->tries += r->hits;
            xmlFree (val);
      }

      if ((val = xmlGetProp (node, "misses")) != NULL) {
            r->tries += atoi (val);
            xmlFree (val);
      }

      val = xmlGetProp (node, "apply_to_incoming");
      r->apply_to_incoming = val!=NULL && tolower(*val)=='t';
      xmlFree (val);

      if ((val = xmlGetProp (node, "group_type")) != NULL)
      {
            if (*val == 'w')
            {
                  xmlChar * wild;
                  r->group_type = RULE_GROUP_WILDCARD;
                  if ((wild = xmlGetProp (node, "group_wildcard")) != NULL)
                  {
                        r->group_wildcard = g_strdup(wild);
                        xmlFree (wild);
                  }
            }
            else if (*val == 'l')
            {
                  xmlChar * list;
                  r->group_type = RULE_GROUP_LIST;
                  if ((list = xmlGetProp (node, "group_list")) != NULL)
                  {
                        char * str;
                        const char * walk = (const char*) list;
                        r->group_list = g_ptr_array_new();
                        while ((str = get_next_token_str (walk, ';', &walk)) != NULL)
                              g_ptr_array_add(r->group_list, str);
                        xmlFree (list);
                  }
            }

            xmlFree (val);
      }

      /* walk through children */
      for (child=node->xmlChildrenNode; child!=NULL; child=child->next)
      {
            xmlChar * val;
            const char * tag = (const gchar*) child->name;

            if (!pan_strcmp (tag, "alert"))
            {
                  r->action->flags |= RULE_ACTION_SHOW_ALERT;
                  if ((val = xmlGetProp (child, "message")) != NULL) {
                        replace_gstr (&r->action->alert_message, g_strdup(val));
                        xmlFree (val);
                  }
            }
            else if (!pan_strcmp (tag, "decode"))
            {
                  r->action->flags |= RULE_ACTION_DECODE;
                  if ((val = xmlGetProp (child, "directory")) != NULL) {
                        replace_gstr (&r->action->decode_path, g_strdup(val));
                        xmlFree (val);
                  }
            }
            else if (!pan_strcmp (tag, "read"))
            {
                  r->action->flags |= RULE_ACTION_MARK_READ;
            }
            else if (!pan_strcmp (tag, "unread"))
            {
                  r->action->flags |= RULE_ACTION_MARK_UNREAD;
            }
            else if (!pan_strcmp (tag, "flag"))
            {
                  r->action->flags |= RULE_ACTION_TAG_FOR_RETRIEVAL;
            }
            else if (!pan_strcmp (tag, "fetch_body"))
            {
                  r->action->flags |= RULE_ACTION_RETREIVE_BODY;
            }
            else if (!pan_strcmp (tag, "watch"))
            {
                  r->action->flags |= RULE_ACTION_WATCH;
            }
            else if (!pan_strcmp (tag, "ignore"))
            {
                  r->action->flags |= RULE_ACTION_IGNORE;
            }
            else if (!pan_strcmp (tag, "discard"))
            {
                  r->action->flags |= RULE_ACTION_DISCARD;
            }
      }

      return r;
}

 
void
rule_xml_read (const char * filename,
               GPtrArray  * appendme_rules)
{
      /* sanity clause */
      g_return_if_fail (is_nonempty_string(filename));
      g_return_if_fail (appendme_rules!=NULL);

      /* read the file */
      if (pan_file_exists (filename))
      {
            xmlDocPtr doc = xmlParseFile (filename);

            if (doc != NULL)
            {
                  xmlNodePtr cur = xmlDocGetRootElement(doc);
                  cur = cur->xmlChildrenNode;

                  for (; cur!=NULL; cur=cur->next)
                  {
                        Rule * r = create_rule (doc, cur);
                        if (r != NULL)
                              g_ptr_array_add (appendme_rules, r);
                  }

                  xmlFreeDoc (doc);
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index