/* Cataract - Static web photo gallery generator * Copyright (C) 2010 Tomas Bzatek * * 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 _DEFAULT_SOURCE /* for struct tm.tm_gmtoff */ #include #include #include #include #include #include #include "setup.h" #include "atom-writer.h" #include "gallery-utils.h" TAtomFeed *news_feed; 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, "\n"); fprintf (f, "\n"); fprintf (f, " %s\n", feed->title); if (last_updated) fprintf (f, " %s\n", last_updated); s = atom_create_tag (feed->base_url, last_updated, feed->title, NULL); fprintf (f, " %s\n", s); g_free (s); s = g_build_path ("/", feed->base_url, "/", NULL); fprintf (f, " \n", s); g_free (s); fprintf (f, " \n", feed->feed_url); fprintf (f, " %s\n", APP_HOMEPAGE, VERSION, APP_NAME_FULL); if (setup->favicon_file) fprintf (f, " %s\n", setup->favicon_file); if (setup->meta_author || setup->meta_author_email) { fprintf (f, " \n"); if (setup->meta_author) fprintf (f, " %s\n", setup->meta_author); if (setup->meta_author_email) fprintf (f, " %s\n", setup->meta_author_email); fprintf (f, " \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, " \n"); fprintf (f, " %s\n", item->title); s = g_build_path ("/", setup->location_base_url, item->path, "/", NULL); fprintf (f, " \n", s); g_free (s); s = atom_create_tag (feed->base_url, item->date, item->title, item->path); fprintf (f, " %s\n", s); g_free (s); fprintf (f, " %s\n", item->date); fprintf (f, " summary_type) fprintf (f, " type=\"%s\"", item->summary_type); fprintf (f, ">\n%s\n \n", item->summary); fprintf (f, " \n\n"); } } fprintf (f, "\n"); if (fclose (f) != 0) log_error ("Error writing atom feed: %s\n", strerror (errno)); } 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); g_free (item); } 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); }