#!/usr/bin/perl
#######################################################################
# $Id: opml2snow 1176 2007-12-02 10:55:52Z kiza $
#
# Snownews - A lightweight console RSS newsreader
#
# Copyright 2003-2004 Oliver Feiler <kiza@kcore.de>
# http://kiza.kcore.de/software/snownews/
#
# opml2snow
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# 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
#######################################################################

use strict;
use XML::LibXML;
use Data::Dumper;
use English;

#######################################################################
# Help
if (index($ARGV[0], "-h") >= 0) {
	print "Snownews opml2snow - subsription file import/export utility\n\n".
		  "Creative usage examples:\n".
		  "Importing an OPML file:\n".
		  "       opml2snow <list.opml >urls\n".
		  "       opml2snow list.opml >urls\n".
		  "       cat list.opml | opml2snow >urls\n\n".
		  "Exporting to OPML:\n".
		  "       opml2snow --export [urls file] >MySubscriptions.opml\n".
		  "       Alternatively you may run snow2opml [urls file] >file.opml\n\n".
		  "The program will print to stdout by default. If you want to append the output\n".
		  "to your subsription list, redirect to >>~/.snownews/url instead.\n";
	exit (0);
}

#######################################################################
# Importing
if (($PROGRAM_NAME =~ "snow2opml") || ($ARGV[0] eq "--export")) {
	OPMLexport();
} else {
	my $parser = XML::LibXML->new();
	$parser->validation(0);				# Turn off validation from libxml
	$parser->recover(1);				# And ignore any errors while parsing
	
	my(@lines) = <>;
	my($input) = join ("\n", @lines);
	
	my($doc) = $parser->parse_string($input);
	my($root) = $doc->documentElement();
	
	# Parsing the document tree using xpath
	my(@items) = $root->findnodes("//outline");
	foreach (@items) {
		my(@attrs) = $_->attributes();
		foreach (@attrs) {
			# Only print attribute xmlUrl=""
			if ($_->nodeName =~ /xmlUrl/i) {
				print $_->value."\n";
			}
		}
	}
}

#######################################################################
# Exporting
sub OPMLexport {
	my($inputfile);
	if (defined($ARGV[1])) {
		$inputfile = $ARGV[1];
	} else {
		$inputfile = "$ENV{'HOME'}/.snownews/urls"
	}
	open (URLS, "$inputfile");
	my(@urls) = <URLS>;
	close (URLS);
	
	if (scalar(@urls) == 0) {
		print "Could not read anything from \"$inputfile\"!\nExiting.\n";
		exit(1);
	}
	
	# Create bare OPML doc
	my($opml) = XML::LibXML::Document->new();
	my($opml_root) = $opml->createElement('opml');
	$opml->setDocumentElement($opml_root);

	my($opml_comment) = $opml->createComment(' File generated by opml2snow ');
	$opml_root->appendChild($opml_comment);
	
	my($opml_head) = $opml->createElement('head');
	$opml_root->appendChild($opml_head);
	$opml_head->appendTextChild('title', 'MySubscriptions');
	
	my($opml_body) = $opml->createElement('body');
	$opml_root->appendChild($opml_body);

	foreach(@urls) {
		chomp;
		/^(.*)?\|(.*?)\|(.*?)\|(.*)$/;
		
		my($feed_url) = $1;
		my($feed_url_hash) = $feed_url;
		$feed_url_hash =~ tr/[\x00-\x19\x27-\x2a\x2f\x5b-\x60\x7b-\xff]/_/;  # Translated from Hashify in conversions.c
		$feed_url_hash = substr($feed_url_hash, 0, 128);

		if ($feed_url_hash =~ /^smartfeed/) {
			next;
		}
		my($feed_override_title) = $2;
		my($feed_category) = $3;
		my($feed_script) = 4;
		
		my($parser) = XML::LibXML->new();
		my($feed_doc) = $parser->parse_file("$ENV{'HOME'}/.snownews/cache/$feed_url_hash");
		my($feed_root) = $feed_doc->documentElement();
		$feed_root->setNamespace('http://purl.org/rss/1.0/', 'rss', 1);
		
		# Make outline element. Actually I have absolutely no idea how
		# this should look like. I copied the layout from an OPML file
		# produced by NetNewsWire. The OPML "spec" is supposed to be at:
		# http://www.opml.org/spec
		my($opml_outline) = $opml->createElement('outline');
		$opml_outline->setAttribute('text', $feed_root->findvalue('//rss:channel/rss:title'));
		$opml_outline->setAttribute('title', $feed_root->findvalue('//rss:channel/rss:title'));
		$opml_outline->setAttribute('description', $feed_root->findvalue('//rss:channel/rss:description'));
		$opml_outline->setAttribute('type', 'rss');
		$opml_outline->setAttribute('version', 'RSS');
		$opml_outline->setAttribute('htmlUrl', $feed_root->findvalue('/rss:channel/rss:link'));
		$opml_outline->setAttribute('xmlUrl', "$feed_url");
		$opml_body->appendChild($opml_outline);
	}

	print $opml->serialize(1);
}
