diff -Naur ../raggle-0.1.2/raggle ./raggle
--- ../raggle-0.1.2/raggle	2003-06-28 22:28:34.000000000 +0300
+++ ./raggle	2003-06-30 16:12:46.000000000 +0300
@@ -255,6 +255,95 @@
   end
 end
 
+# Very simple OPML importer/exporter
+module OPML
+  # Import OPML file
+  # file_name::  OPML file
+  # refresh::    refresh rate used for all imported feeds.
+  #              If nil, then value of option +feed_default_value+
+  #              is used.
+  # lock_title:: If true, then all title's of imported feeds
+  #              will be locked
+  # save_items:: If true, then all imported feeds' items will be saved.
+  def OPML::import(file_name, refresh=nil, lock_title=false, save_items=false)
+    refresh = $config['feed_default_refresh'] unless refresh
+    feed_list = $config['feeds']
+
+    begin
+      doc = File.open(file_name) do |f|
+	doc = REXML::Document.new(f)
+	doc.root.elements.each('//outline') do |outline|
+	  title = outline.attributes['title']
+	  url = outline.attributes['xmlUrl']
+	  site = outline.attributes['htmlUrl'] || ''
+	  desc = outline.attributes['description'] || ''
+
+	  if title.nil? || url.nil?
+	    $stderr.puts "Warning: skipping incomplete OPML entry: #{outline}"
+	    next
+	  end
+
+	  feed_list.add(title, url, refresh, lock_title, save_items, site, desc)
+	end
+      end
+    rescue REXML::ParseException
+      die "Parsing #{file_name} failed: #{$!.message}"
+    rescue
+      die $!.message
+    end
+  end
+
+
+  # Export all feeds to OPMl format
+  def OPML::export(file_name)
+    begin
+      feed_list = $config['feeds']
+
+      opml = REXML::Element.new("opml")
+      opml.attributes['version'] = '1.1'
+
+      opml.add_element(opml_head)
+      
+      body = REXML::Element.new('body')
+      opml.add_element(body)
+      feed_list.each do |feed|
+	body.add_element(feed_to_outline(feed))
+      end
+
+      doc = REXML::Document.new
+      doc << REXML::Document::DECLARATION
+      doc.add(opml)
+
+      File.open(file_name, 'w') do |f|
+	doc.write(f, 0)
+      end
+    rescue
+      die $!.message
+    end
+  end
+
+  # Generate OPML header
+  def OPML::opml_head
+    head = REXML::Element.new('head')
+    title = REXML::Element.new('title')
+    title.text = 'Raggle subscriptions'
+    head.add_element(title)
+    head
+  end
+
+  # Convert feed hash to outline-element
+  def OPML::feed_to_outline(feed)
+    outline = REXML::Element.new('outline')
+    outline.attributes['title'] = feed['title'] || ''
+    outline.attributes['description'] = feed['desc'] || ''
+    outline.attributes['xmlUrl'] = feed['url'] || ''
+    outline.attributes['htmlUrl'] = feed['site'] if feed.has_key?('site')
+    outline.attributes['version'] = 'RSS'
+    outline.attributes['type'] = 'rss'
+    outline
+  end
+end
+
 class FeedList
   attr_accessor :feeds
   def initialize
@@ -1190,9 +1279,11 @@
   -c, --config                  Specify an alternate config file.
   -d, --delete, --delete-feed   Delete an existing feed.
   -e, --edit, --edit-feed       Edit an existing feed.
+  --export-opml                 Export feeds to OPML.  
   --force                       Force behavior Raggle won't normally allow.
                                 Use this option with caution.
   -h, --help, --usage           Display this usage screen.
+  --import-opml                 Import feeds from an OPML file.
   -i, --invalidate              Invalidate a feed (force an update).
   -l, --list                    List existing feeds (use '--verbose' to 
                                 show URLs as well).
@@ -1266,6 +1357,8 @@
     ['--save-items',                            GetoptLong::NO_ARGUMENT],
     ['--unsave-items',                          GetoptLong::NO_ARGUMENT],
     ['--verbose',                               GetoptLong::NO_ARGUMENT],
+    ['--import-opml',                           GetoptLong::REQUIRED_ARGUMENT],		 
+    ['--export-opml',                           GetoptLong::REQUIRED_ARGUMENT],
     ['--help', '-h', '--usage',                 GetoptLong::NO_ARGUMENT]
   )
   
@@ -1309,7 +1402,13 @@
         when '--unsave-items'
           ret['save_items?'] = false
         when '--verbose'
-          $config['verbose'] = true
+	  $config['verbose'] = true
+        when '--import-opml'
+	  ret['mode'] = 'import_opml'
+	  ret['opml_file'] = arg
+        when '--export-opml'
+	  ret['mode'] = 'export_opml'
+	  ret['opml_file'] = arg
         when '--help'
           print_usage
       else
@@ -1587,6 +1686,13 @@
   when 'purge'
     purge_feed_cache
     exit 0
+  when 'import_opml'
+    OPML::import opts['opml_file'], opts['refresh'], opts['lock_title?'], opts['save_items']
+    save_feed_list
+    exit 0
+  when 'export_opml'
+    OPML::export opts['opml_file']
+    exit 0
   end
   
   # load feed cache
@@ -1867,6 +1973,9 @@
   # warn if feed refresh is set to less than this
   'feed_refresh_warn'     => 60,
 
+  # default refresh rate
+  'feed_default_refresh'  => 120,
+
   # open new screen window for browser?
   'use_screen'            => true,
 
diff -Naur ../raggle-0.1.2/raggle.1 ./raggle.1
--- ../raggle-0.1.2/raggle.1	2003-06-28 00:42:52.000000000 +0300
+++ ./raggle.1	2003-06-30 00:57:36.000000000 +0300
@@ -42,10 +42,12 @@
 .Op Fl e Ar feed
 .Op Fl Fl edit Ar feed
 .Op Fl Fl edit-feed Ar feed
+.Op Fl Fl export-opml Ar file
 .Op Fl Fl force
 .Op Fl Fl help
 .Op Fl Fl usage
 .Op Fl i Ar feed
+.Op Fl Fl import-opml Ar file
 .Op Fl Fl invalidate Ar feed
 .Op Fl Fl list
 .Op Fl Fl lock-title
@@ -126,6 +128,11 @@
 .It Fl Fl edit-feed Ar feed
 Edit
 .Ar feed
+.\" --export-opml
+.It Fl Fl export-opml Ar file
+Export all feeds to
+.Ar file
+in OPML format.
 .\" --force
 .It Fl Fl force
 Force an edit/addition to succeed even if it wants to do things that
@@ -136,6 +143,10 @@
 .\" --usage
 .It Fl Fl usage
 Show usage message
+.\" --import-opml
+.It Fl Fl import-opml Ar file
+Import feeds from an OPML 
+.Ar file
 .\" -i
 .It Fl i Ar feed
 Invalidate 
@@ -154,7 +165,9 @@
 Lock the title of a feed (used with
 .Fl Fl edit
 or 
-.Fl Fl add ) , 
+.Fl Fl add
+or
+.Fl Fl import-opml) , 
 prevents the feed title being updated from RSS.
 .\" --purge
 .It Fl Fl purge
@@ -164,7 +177,9 @@
 Use with
 .Fl Fl edit 
 or
-.Fl Fl add .
+.Fl Fl add 
+or
+.Fl Fl import-opml .
 Set the feed refresh time to
 .Ar refresh_time
 .\" --refresh
@@ -172,7 +187,9 @@
 Use with
 .Fl Fl edit 
 or
-.Fl Fl add .
+.Fl Fl add 
+or
+.Fl Fl import-opml .
 Set the feed refresh time to
 .Ar refresh_time
 .\" --save-items
@@ -180,7 +197,9 @@
 Use with
 .Fl Fl edit
 or 
-.Fl Fl add .
+.Fl Fl add 
+or
+.Fl Fl import-opml .
 Save old feed items
 .\" --sort
 .It Fl Fl sort
@@ -314,6 +333,13 @@
 .Pp
 Change the URL of the 3rd feed.
 .Dl $ raggle --edit 3 --url http://www.slashdot.org/slashdot.rss
+.Pp
+Export all feeds to foo.opml
+.Dl $ raggle --export-opml foo.opml
+.Pp
+Import feeds from foo.opml, so that their refresh time is set
+to 90 minutes.
+.Dl $ raggle --import-opml foo.opml --refresh 90
 .Bd -literal
 .Sh BUGS
 .\" XXX Keep in sync with raggle/BUGS (but prettify)

