summaryrefslogtreecommitdiff
path: root/src/atom-writer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/atom-writer.c')
-rw-r--r--src/atom-writer.c307
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);
+}
+