diff options
| author | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2010-10-08 17:02:47 +0200 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2010-10-08 17:02:47 +0200 |
| commit | 10c6b1f0978710cf5a9f309b6fdcaef922f9b07f (patch) | |
| tree | 00679d479d9554f91f5d3beb4f4e709705ba55df /src/atom-writer.c | |
| parent | 5fc53d25a171fbd85ee09c9fc771580350d689c8 (diff) | |
| download | cataract-10c6b1f0978710cf5a9f309b6fdcaef922f9b07f.tar.xz | |
Add basic Atom feed writer
Diffstat (limited to 'src/atom-writer.c')
| -rw-r--r-- | src/atom-writer.c | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/src/atom-writer.c b/src/atom-writer.c new file mode 100644 index 0000000..958d700 --- /dev/null +++ b/src/atom-writer.c @@ -0,0 +1,307 @@ +/* Cataract - Static web photo gallery generator + * Copyright (C) 2010 Tomas Bzatek <tbzatek@users.sourceforge.net> + * + * 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; either version 2 + * of the License, or any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#define _XOPEN_SOURCE /* for strptime() */ +#define _BSD_SOURCE /* for struct tm.tm_gmtoff */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <time.h> + +#include <glib.h> + +#include <config.h> + +#include "setup.h" +#include "atom-writer.h" +#include "gallery-utils.h" + + + + +TAtomFeed * +atom_writer_new () +{ + return g_new0 (TAtomFeed, 1); +} + +static time_t +parse_timestamp (const gchar *timestamp) +{ + struct tm t = {0}; + long saved_tm_gmtoff; + + + if (timestamp == NULL || strlen (timestamp) == 0) { + g_print ("parse_timestamp() error: invalid timestamp NULL\n"); + return 0; + } + + strptime (timestamp, "%FT%T%z", &t); + saved_tm_gmtoff = t.tm_gmtoff; + + return mktime (&t) - saved_tm_gmtoff; +} + +static gint +feed_list_date_sort_func (TAtomFeedItem *item1, TAtomFeedItem *item2) +{ + time_t t1, t2; + + t1 = parse_timestamp (item1->date); + t2 = parse_timestamp (item2->date); + + return - (t1 - t2); +} + +static gchar * +atom_create_tag (const gchar *base_url, const gchar *date, const gchar *title, const gchar *path) +{ + gchar *s, *s2, *s3; + + /* http://feedvalidator.org/docs/error/InvalidTAG.html */ + + /* extract domain name */ + s2 = strstr (base_url, "://"); + if (s2 != NULL) { + s2 += 3; + s3 = strstr (s2, "/"); + + /* no slash found, treat it as is */ + if (s3 == NULL) + s3 = g_strdup (s2); + else + s3 = g_strndup (s2, s3 - s2); + + s = g_strdup_printf ("tag:%s,", s3); + g_free (s3); + } + else { + g_print ("atom_create_tag() error: invalid base_url '%s'\n", base_url); + s = g_strdup ("tag:unknown.cgg.gallery.com,"); + } + + /* copy the date, let's assume correct format */ + s3 = g_strndup (date, 10); + s2 = g_strdup_printf ("%s%s:x", s, s3 ? s3 : "2010-01-01"); + g_free (s3); + g_free (s); + s = s2; + + /* append hashed title and path */ + if (title) { + s2 = g_strdup_printf ("%s.%u", s, g_str_hash (title)); + g_free (s); + s = s2; + } + if (path) { + s2 = g_strdup_printf ("%s.%u", s, g_str_hash (path)); + g_free (s); + s = s2; + } + + return s; +} + +void +atom_writer_write_to_file (TAtomFeed *feed, const gchar *filename, TGallerySetup *setup) +{ + FILE* f; + GSList *list; + TAtomFeedItem *item; + gchar *s; + const gchar *last_updated; + + f = fopen (filename, "w"); + if (f == NULL) { + log_error ("Error writing atom feed: %s\n", strerror (errno)); + return; + } + + /* sort items by date */ + feed->items = g_slist_sort (feed->items, (GCompareFunc) feed_list_date_sort_func); + + /* find most recent date */ + last_updated = NULL; + for (list = feed->items; list; list = list->next) { + item = list->data; + last_updated = item->date; + if (last_updated) + break; + } + + /* write header */ + fprintf (f, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); + fprintf (f, "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n"); + fprintf (f, " <title>%s</title>\n", feed->title); + if (last_updated) + fprintf (f, " <updated>%s</updated>\n", last_updated); + + s = atom_create_tag (feed->base_url, last_updated, feed->title, NULL); + fprintf (f, " <id>%s</id>\n", s); + g_free (s); + + s = g_build_path ("/", feed->base_url, "/", NULL); + fprintf (f, " <link rel=\"alternate\" type=\"text/html\" href=\"%s\"/>\n", s); + g_free (s); + + fprintf (f, " <link rel=\"self\" type=\"application/atom+xml\" href=\"%s\"/>\n", feed->feed_url); + fprintf (f, " <generator uri=\"%s\" version=\"%s\">%s</generator>\n", APP_HOMEPAGE, VERSION, APP_NAME_FULL); + + if (setup->favicon_file) + fprintf (f, " <icon>%s</icon>\n", setup->favicon_file); + + if (setup->meta_author || setup->meta_author_email) { + fprintf (f, " <author>\n"); + if (setup->meta_author) + fprintf (f, " <name>%s</name>\n", setup->meta_author); + if (setup->meta_author_email) + fprintf (f, " <email>%s</email>\n", setup->meta_author_email); + fprintf (f, " </author>\n"); + } + fprintf (f, "\n"); + + /* write items */ + for (list = feed->items; list; list = list->next) { + item = list->data; + if (item->title == NULL || strlen (item->title) == 0 || + item->date == NULL || strlen (item->date) == 0 || + item->path == NULL || strlen (item->path) == 0) + log_error ("Error: missing required fields in feed item data (title = '%s').\n", item->title); + else { + fprintf (f, " <entry>\n"); + fprintf (f, " <title>%s</title>\n", item->title); + s = g_build_path ("/", setup->feed_base_url, item->path, "/", NULL); + fprintf (f, " <link rel=\"alternate\" type=\"text/html\" href=\"%s\"/>\n", s); + g_free (s); + + s = atom_create_tag (feed->base_url, item->date, item->title, item->path); + fprintf (f, " <id>%s</id>\n", s); + g_free (s); + + fprintf (f, " <updated>%s</updated>\n", item->date); + fprintf (f, " <summary"); + if (item->summary_type) + fprintf (f, " type=\"%s\"", item->summary_type); + fprintf (f, ">\n%s\n </summary>\n", item->summary); + fprintf (f, " </entry>\n\n"); + } + } + + fprintf (f, "</feed>\n"); + fclose (f); +} + +static void +atom_feed_item_free (TAtomFeedItem *item) +{ + g_free (item->title); + g_free (item->path); + g_free (item->date); + g_free (item->summary); + g_free (item->summary_type); +} + +void +atom_writer_free (TAtomFeed *feed) +{ + if (feed) { + g_slist_foreach (feed->items, (GFunc) atom_feed_item_free, NULL); + g_slist_free (feed->items); + g_free (feed->title); + g_free (feed->base_url); + g_free (feed->feed_url); + g_free (feed); + } +} + +void +atom_writer_set_title (TAtomFeed *feed, const gchar *title) +{ + g_free (feed->title); + feed->title = g_markup_escape_text (title, -1); +} + +void +atom_writer_set_base_url (TAtomFeed *feed, const gchar *base_url) +{ + g_free (feed->base_url); + feed->base_url = g_strdup (base_url); +} + +void +atom_writer_set_feed_url (TAtomFeed *feed, const gchar *feed_url) +{ + g_free (feed->feed_url); + feed->feed_url = g_strdup (feed_url); +} + + +G_LOCK_DEFINE (atom_writer_items); + +TAtomFeedItem * +atom_writer_add_item (TAtomFeed *feed) +{ + TAtomFeedItem *item; + + item = g_new0 (TAtomFeedItem, 1); + + G_LOCK (atom_writer_items); + feed->items = g_slist_append (feed->items, item); + G_UNLOCK (atom_writer_items); + + return item; +} + + +void +atom_feed_item_set_title (TAtomFeedItem *item, const gchar *title) +{ + g_free (item->title); + item->title = g_markup_escape_text (title, -1); +} + +void +atom_feed_item_set_path (TAtomFeedItem *item, const gchar *path) +{ + g_free (item->path); + item->path = g_strdup (path); +} + +void +atom_feed_item_set_date (TAtomFeedItem *item, const gchar *date) +{ + g_free (item->date); + item->date = g_strdup (date); +} + +void +atom_feed_item_set_summary (TAtomFeedItem *item, const gchar *summary) +{ + g_free (item->summary); + item->summary = g_markup_escape_text (summary, -1); +} + +void +atom_feed_item_set_summary_type (TAtomFeedItem *item, const gchar *summary_type) +{ + g_free (item->summary_type); + item->summary_type = g_strdup (summary_type); +} + |
