]> git.wh0rd.org Git - tt-rss.git/commitdiff
opml: remove CRs, tweak category node detection
authorAndrew Dolgov <fox@madoka.volgo-balt.ru>
Wed, 15 Aug 2012 11:58:05 +0000 (15:58 +0400)
committerAndrew Dolgov <fox@madoka.volgo-balt.ru>
Wed, 15 Aug 2012 11:58:43 +0000 (15:58 +0400)
classes/opml.php

index 011c66eb2eeca240f25f2571e913002b937307d2..af597caf446beab7c6fed284a0f53ac2ac9b3b3b 100644 (file)
-<?php\r
-class Opml extends Protected_Handler {\r
-\r
-       function csrf_ignore($method) {\r
-               $csrf_ignored = array("export", "import");\r
-\r
-               return array_search($method, $csrf_ignored) !== false;\r
-       }\r
-\r
-       function export() {\r
-               $output_name = $_REQUEST["filename"];\r
-               if (!$output_name) $output_name = "TinyTinyRSS.opml";\r
-\r
-               $show_settings = $_REQUEST["settings"];\r
-\r
-               $owner_uid = $_SESSION["uid"];\r
-               return $this->opml_export($output_name, $owner_uid, false, ($show_settings == 1));\r
-       }\r
-\r
-       function import() {\r
-               $owner_uid = $_SESSION["uid"];\r
-\r
-               header('Content-Type: text/html; charset=utf-8');\r
-\r
-               print "<html>\r
-                       <head>\r
-                               <link rel=\"stylesheet\" href=\"utility.css\" type=\"text/css\">\r
-                               <title>".__("OPML Utility")."</title>\r
-                               <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\r
-                       </head>\r
-                       <body>\r
-                       <div class=\"floatingLogo\"><img src=\"images/logo_wide.png\"></div>\r
-                       <h1>".__('OPML Utility')."</h1>";\r
-\r
-               add_feed_category($this->link, "Imported feeds");\r
-\r
-               $this->opml_notice(__("Importing OPML..."));\r
-               $this->opml_import($owner_uid);\r
-\r
-               print "<br><form method=\"GET\" action=\"prefs.php\">\r
-                       <input type=\"submit\" value=\"".__("Return to preferences")."\">\r
-                       </form>";\r
-\r
-               print "</body></html>";\r
-\r
-\r
-       }\r
-\r
-       // Export\r
-\r
-       private function opml_export_category($owner_uid, $cat_id, $hide_private_feeds=false) {\r
-\r
-               if ($cat_id) {\r
-                       $cat_qpart = "parent_cat = '$cat_id'";\r
-                       $feed_cat_qpart = "cat_id = '$cat_id'";\r
-               } else {\r
-                       $cat_qpart = "parent_cat IS NULL";\r
-                       $feed_cat_qpart = "cat_id IS NULL";\r
-               }\r
-\r
-               if ($hide_private_feeds)\r
-                       $hide_qpart = "(private IS false AND auth_login = '' AND auth_pass = '')";\r
-               else\r
-                       $hide_qpart = "true";\r
-\r
-               $out = "";\r
-\r
-               if ($cat_id) {\r
-                       $result = db_query($this->link, "SELECT title FROM ttrss_feed_categories WHERE id = '$cat_id'\r
-                               AND owner_uid = '$owner_uid'");\r
-                       $cat_title = db_fetch_result($result, 0, "title");\r
-               }\r
-\r
-               if ($cat_title) $out .= "<outline title=\"$cat_title\">\n";\r
-\r
-               $result = db_query($this->link, "SELECT id,title\r
-                       FROM ttrss_feed_categories WHERE\r
-                       $cat_qpart AND owner_uid = '$owner_uid' ORDER BY order_id, title");\r
-\r
-               while ($line = db_fetch_assoc($result)) {\r
-                       $title = htmlspecialchars($line["title"]);\r
-                       $out .= $this->opml_export_category($owner_uid, $line["id"], $hide_private_feeds);\r
-               }\r
-\r
-               $feeds_result = db_query($this->link, "select title, feed_url, site_url\r
-                               from ttrss_feeds where $feed_cat_qpart AND owner_uid = '$owner_uid' AND $hide_qpart\r
-                               order by order_id, title");\r
-\r
-               while ($fline = db_fetch_assoc($feeds_result)) {\r
-                       $title = htmlspecialchars($fline["title"]);\r
-                       $url = htmlspecialchars($fline["feed_url"]);\r
-                       $site_url = htmlspecialchars($fline["site_url"]);\r
-\r
-                       if ($site_url) {\r
-                               $html_url_qpart = "htmlUrl=\"$site_url\"";\r
-                       } else {\r
-                               $html_url_qpart = "";\r
-                       }\r
-\r
-                       $out .= "<outline text=\"$title\" xmlUrl=\"$url\" $html_url_qpart/>\n";\r
-               }\r
-\r
-               if ($cat_title) $out .= "</outline>\n";\r
-\r
-               return $out;\r
-       }\r
-\r
-       function opml_export($name, $owner_uid, $hide_private_feeds=false, $include_settings=true) {\r
-               if (!$owner_uid) return;\r
-\r
-               if (!isset($_REQUEST["debug"])) {\r
-                       header("Content-type: application/xml+opml");\r
-                       header("Content-Disposition: attachment; filename=" . $name );\r
-               } else {\r
-                       header("Content-type: text/xml");\r
-               }\r
-\r
-               $out = "<?xml version=\"1.0\" encoding=\"utf-8\"?".">";\r
-\r
-               $out .= "<opml version=\"1.0\">";\r
-               $out .= "<head>\r
-                       <dateCreated>" . date("r", time()) . "</dateCreated>\r
-                       <title>Tiny Tiny RSS Feed Export</title>\r
-               </head>";\r
-               $out .= "<body>";\r
-\r
-               $out .= $this->opml_export_category($owner_uid, false, $hide_private_feeds);\r
-\r
-               # export tt-rss settings\r
-\r
-               if ($include_settings) {\r
-                       $out .= "<outline title=\"tt-rss-prefs\" schema-version=\"".SCHEMA_VERSION."\">";\r
-\r
-                       $result = db_query($this->link, "SELECT pref_name, value FROM ttrss_user_prefs WHERE\r
-                          profile IS NULL AND owner_uid = " . $_SESSION["uid"] . " ORDER BY pref_name");\r
-\r
-                       while ($line = db_fetch_assoc($result)) {\r
-                               $name = $line["pref_name"];\r
-                               $value = htmlspecialchars($line["value"]);\r
-\r
-                               $out .= "<outline pref-name=\"$name\" value=\"$value\"/>";\r
-                       }\r
-\r
-                       $out .= "</outline>";\r
-\r
-                       $out .= "<outline title=\"tt-rss-labels\" schema-version=\"".SCHEMA_VERSION."\">";\r
-\r
-                       $result = db_query($this->link, "SELECT * FROM ttrss_labels2 WHERE\r
-                               owner_uid = " . $_SESSION['uid']);\r
-\r
-                       while ($line = db_fetch_assoc($result)) {\r
-                               $name = htmlspecialchars($line['caption']);\r
-                               $fg_color = htmlspecialchars($line['fg_color']);\r
-                               $bg_color = htmlspecialchars($line['bg_color']);\r
-\r
-                               $out .= "<outline label-name=\"$name\" label-fg-color=\"$fg_color\" label-bg-color=\"$bg_color\"/>";\r
-\r
-                       }\r
-\r
-                       $out .= "</outline>";\r
-\r
-                       $out .= "<outline title=\"tt-rss-filters\" schema-version=\"".SCHEMA_VERSION."\">";\r
-\r
-                       $result = db_query($this->link, "SELECT filter_type,\r
-                                       reg_exp,\r
-                                       action_id,\r
-                                       enabled,\r
-                                       action_param,\r
-                                       inverse,\r
-                                       filter_param,\r
-                                       cat_filter,\r
-                                       ttrss_feeds.feed_url AS feed_url,\r
-                                       ttrss_feed_categories.title AS cat_title\r
-                                       FROM ttrss_filters\r
-                                               LEFT JOIN ttrss_feeds ON (feed_id = ttrss_feeds.id)\r
-                                               LEFT JOIN ttrss_feed_categories ON (ttrss_filters.cat_id = ttrss_feed_categories.id)\r
-                                       WHERE\r
-                                               ttrss_filters.owner_uid = " . $_SESSION['uid']);\r
-\r
-                       while ($line = db_fetch_assoc($result)) {\r
-                               $name = htmlspecialchars($line['reg_exp']);\r
-\r
-                               foreach (array('enabled', 'inverse', 'cat_filter') as $b) {\r
-                                       $line[$b] = sql_bool_to_bool($line[$b]);\r
-                               }\r
-\r
-                               $filter = json_encode($line);\r
-\r
-                               $out .= "<outline filter-name=\"$name\">$filter</outline>";\r
-\r
-                       }\r
-\r
-\r
-                       $out .= "</outline>";\r
-               }\r
-\r
-               $out .= "</body></opml>";\r
-\r
-               // Format output.\r
-               $doc = new DOMDocument();\r
-               $doc->formatOutput = true;\r
-               $doc->preserveWhiteSpace = false;\r
-               $doc->loadXML($out);\r
-\r
-               $xpath = new DOMXpath($doc);\r
-               $outlines = $xpath->query("//outline[@title]");\r
-\r
-               // cleanup empty categories\r
-               foreach ($outlines as $node) {\r
-                       if ($node->getElementsByTagName('outline')->length == 0)\r
-                               $node->parentNode->removeChild($node);\r
-               }\r
-\r
-               $res = $doc->saveXML();\r
-\r
-               // saveXML uses a two-space indent.  Change to tabs.\r
-               $res = preg_replace_callback('/^(?:  )+/mu',\r
-                       create_function(\r
-                               '$matches',\r
-                               'return str_repeat("\t", intval(strlen($matches[0])/2));'),\r
-                       $res);\r
-\r
-               print $res;\r
-       }\r
-\r
-       // Import\r
-\r
-       private function opml_import_feed($doc, $node, $cat_id, $owner_uid) {\r
-               $attrs = $node->attributes;\r
-\r
-               $feed_title = db_escape_string($attrs->getNamedItem('text')->nodeValue);\r
-               if (!$feed_title) $feed_title = db_escape_string($attrs->getNamedItem('title')->nodeValue);\r
-\r
-               $feed_url = db_escape_string($attrs->getNamedItem('xmlUrl')->nodeValue);\r
-               if (!$feed_url) $feed_url = db_escape_string($attrs->getNamedItem('xmlURL')->nodeValue);\r
-\r
-               $site_url = db_escape_string($attrs->getNamedItem('htmlUrl')->nodeValue);\r
-\r
-               if ($feed_url && $feed_title) {\r
-                       $result = db_query($this->link, "SELECT id FROM ttrss_feeds WHERE\r
-                               feed_url = '$feed_url' AND owner_uid = '$owner_uid'");\r
-\r
-                       if (db_num_rows($result) == 0) {\r
-                               #$this->opml_notice("[FEED] [$feed_title/$feed_url] dst_CAT=$cat_id");\r
-                               $this->opml_notice(T_sprintf("Adding feed: %s", $feed_title));\r
-\r
-                               $query = "INSERT INTO ttrss_feeds\r
-                                       (title, feed_url, owner_uid, cat_id, site_url, order_id) VALUES\r
-                                       ('$feed_title', '$feed_url', '$owner_uid',\r
-                                       '$cat_id', '$site_url', 0)";\r
-                               db_query($this->link, $query);\r
-\r
-                       } else {\r
-                               $this->opml_notice(T_sprintf("Duplicate feed: %s", $feed_title));\r
-                       }\r
-               }\r
-       }\r
-\r
-       private function opml_import_label($doc, $node, $owner_uid) {\r
-               $attrs = $node->attributes;\r
-               $label_name = db_escape_string($attrs->getNamedItem('label-name')->nodeValue);\r
-\r
-               if ($label_name) {\r
-                       $fg_color = db_escape_string($attrs->getNamedItem('label-fg-color')->nodeValue);\r
-                       $bg_color = db_escape_string($attrs->getNamedItem('label-bg-color')->nodeValue);\r
-\r
-                       if (!label_find_id($this->link, $label_name, $_SESSION['uid'])) {\r
-                               $this->opml_notice(T_sprintf("Adding label %s", htmlspecialchars($label_name)));\r
-                               label_create($this->link, $label_name, $fg_color, $bg_color);\r
-                       } else {\r
-                               $this->opml_notice(T_sprintf("Duplicate label: %s", htmlspecialchars($label_name)));\r
-                       }\r
-               }\r
-       }\r
-\r
-       private function opml_import_preference($doc, $node, $owner_uid) {\r
-               $attrs = $node->attributes;\r
-               $pref_name = db_escape_string($attrs->getNamedItem('pref-name')->nodeValue);\r
-\r
-               if ($pref_name) {\r
-                       $pref_value = db_escape_string($attrs->getNamedItem('value')->nodeValue);\r
-\r
-                       $this->opml_notice(T_sprintf("Setting preference key %s to %s",\r
-                               $pref_name, $pref_value));\r
-\r
-                       set_pref($this->link, $pref_name, $pref_value);\r
-               }\r
-       }\r
-\r
-       private function opml_import_filter($doc, $node, $owner_uid) {\r
-               $attrs = $node->attributes;\r
-\r
-               $filter_name = db_escape_string($attrs->getNamedItem('filter-name')->nodeValue);\r
-\r
-               if ($filter_name) {\r
-\r
-               $filter = json_decode($node->nodeValue, true);\r
-\r
-                       if ($filter) {\r
-                               $reg_exp = db_escape_string($filter['reg_exp']);\r
-                               $filter_type = (int)$filter['filter_type'];\r
-                               $action_id = (int)$filter['action_id'];\r
-\r
-                               $result = db_query($this->link, "SELECT id FROM ttrss_filters WHERE\r
-                                       reg_exp = '$reg_exp' AND\r
-                                       filter_type = '$filter_type' AND\r
-                                       action_id = '$action_id' AND\r
-                                       owner_uid = " .$_SESSION['uid']);\r
-\r
-                               if (db_num_rows($result) == 0) {\r
-                                       $enabled = bool_to_sql_bool($filter['enabled']);\r
-                                       $action_param = db_escape_string($filter['action_param']);\r
-                                       $inverse = bool_to_sql_bool($filter['inverse']);\r
-                                       $filter_param = db_escape_string($filter['filter_param']);\r
-                                       $cat_filter = bool_to_sql_bool($filter['cat_filter']);\r
-\r
-                                       $feed_url = db_escape_string($filter['feed_url']);\r
-                                       $cat_title = db_escape_string($filter['cat_title']);\r
-\r
-                                       $result = db_query($this->link, "SELECT id FROM ttrss_feeds WHERE\r
-                                               feed_url = '$feed_url' AND owner_uid = $owner_uid");\r
-\r
-                                       if (db_num_rows($result) != 0) {\r
-                                               $feed_id = db_fetch_result($result, 0, "id");\r
-                                       } else {\r
-                                               $feed_id = "NULL";\r
-                                       }\r
-\r
-                                       $result = db_query($this->link, "SELECT id FROM ttrss_feed_categories WHERE\r
-                                               title = '$cat_title' AND  owner_uid = $owner_uid");\r
-\r
-                                       if (db_num_rows($result) != 0) {\r
-                                               $cat_id = db_fetch_result($result, 0, "id");\r
-                                       } else {\r
-                                               $cat_id = "NULL";\r
-                                       }\r
-\r
-                                       $this->opml_notice(T_sprintf("Adding filter %s", htmlspecialchars($reg_exp)));\r
-\r
-                                       $query = "INSERT INTO ttrss_filters (filter_type, action_id,\r
-                                                       enabled, inverse, action_param, filter_param,\r
-                                                       cat_filter, feed_id,\r
-                                                       cat_id, reg_exp,\r
-                                                       owner_uid)\r
-                                               VALUES ($filter_type, $action_id,\r
-                                                       $enabled, $inverse, '$action_param', '$filter_param',\r
-                                                       $cat_filter, $feed_id,\r
-                                                       $cat_id, '$reg_exp', ".\r
-                                                       $_SESSION['uid'].")";\r
-\r
-                                       db_query($this->link, $query);\r
-\r
-                               } else {\r
-                                       $this->opml_notice(T_sprintf("Duplicate filter %s", htmlspecialchars($reg_exp)));\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       private function opml_import_category($doc, $root_node, $owner_uid, $parent_id) {\r
-               $body = $doc->getElementsByTagName('body');\r
-\r
-               $default_cat_id = (int) get_feed_category($this->link, 'Imported feeds', false);\r
-\r
-               if ($root_node) {\r
-                       $cat_title = db_escape_string($root_node->attributes->getNamedItem('title')->nodeValue);\r
-\r
-                       if (!in_array($cat_title, array("tt-rss-filters", "tt-rss-labels", "tt-rss-prefs"))) {\r
-                               $cat_id = get_feed_category($this->link, $cat_title, $parent_id);\r
-                               db_query($this->link, "BEGIN");\r
-                               if ($cat_id === false) {\r
-                                       add_feed_category($this->link, $cat_title, $parent_id);\r
-                                       $cat_id = get_feed_category($this->link, $cat_title, $parent_id);\r
-                               }\r
-                               db_query($this->link, "COMMIT");\r
-                       } else {\r
-                               $cat_id = 0;\r
-                       }\r
-\r
-                       $outlines = $root_node->childNodes;\r
-\r
-               } else {\r
-                       $xpath = new DOMXpath($doc);\r
-                       $outlines = $xpath->query("//opml/body/outline");\r
-\r
-                       $cat_id = 0;\r
-               }\r
-\r
-               #$this->opml_notice("[CAT] $cat_title id: $cat_id P_id: $parent_id");\r
-               $this->opml_notice(T_sprintf("Processing category: %s", $cat_title ? $cat_title : __("Uncategorized")));\r
-\r
-               foreach ($outlines as $node) {\r
-                       if ($node->hasAttributes() && strtolower($node->tagName) == "outline") {\r
-                               $attrs = $node->attributes;\r
-                               $node_cat_title = db_escape_string($attrs->getNamedItem('title')->nodeValue);\r
-\r
-                               if ($node->hasChildNodes() && $node_cat_title) {\r
-                                       $this->opml_import_category($doc, $node, $owner_uid, $cat_id);\r
-                               } else {\r
-\r
-                                       if (!$cat_id) {\r
-                                               $dst_cat_id = $default_cat_id;\r
-                                       } else {\r
-                                               $dst_cat_id = $cat_id;\r
-                                       }\r
-\r
-                                       switch ($cat_title) {\r
-                                       case "tt-rss-prefs":\r
-                                               $this->opml_import_preference($doc, $node, $owner_uid);\r
-                                               break;\r
-                                       case "tt-rss-labels":\r
-                                               $this->opml_import_label($doc, $node, $owner_uid);\r
-                                               break;\r
-                                       case "tt-rss-filters":\r
-                                               $this->opml_import_filter($doc, $node, $owner_uid);\r
-                                               break;\r
-                                       default:\r
-                                               $this->opml_import_feed($doc, $node, $dst_cat_id, $owner_uid);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       function opml_import($owner_uid) {\r
-               if (!$owner_uid) return;\r
-\r
-               $debug = isset($_REQUEST["debug"]);\r
-               $doc = false;\r
-\r
-               #if ($debug) $doc = DOMDocument::load("/tmp/test.opml");\r
-\r
-               if (is_file($_FILES['opml_file']['tmp_name'])) {\r
-                       $doc = DOMDocument::load($_FILES['opml_file']['tmp_name']);\r
-               } else if (!$doc) {\r
-                       print_error(__('Error: please upload OPML file.'));\r
-                       return;\r
-               }\r
-\r
-               if ($doc) {\r
-                       $this->opml_import_category($doc, false, $owner_uid, false);\r
-               } else {\r
-                       print_error(__('Error while parsing document.'));\r
-               }\r
-       }\r
-\r
-       private function opml_notice($msg) {\r
-               print "$msg<br/>";\r
-       }\r
-\r
-}\r
-?>\r
+<?php
+class Opml extends Protected_Handler {
+
+       function csrf_ignore($method) {
+               $csrf_ignored = array("export", "import");
+
+               return array_search($method, $csrf_ignored) !== false;
+       }
+
+       function export() {
+               $output_name = $_REQUEST["filename"];
+               if (!$output_name) $output_name = "TinyTinyRSS.opml";
+
+               $show_settings = $_REQUEST["settings"];
+
+               $owner_uid = $_SESSION["uid"];
+               return $this->opml_export($output_name, $owner_uid, false, ($show_settings == 1));
+       }
+
+       function import() {
+               $owner_uid = $_SESSION["uid"];
+
+               header('Content-Type: text/html; charset=utf-8');
+
+               print "<html>
+                       <head>
+                               <link rel=\"stylesheet\" href=\"utility.css\" type=\"text/css\">
+                               <title>".__("OPML Utility")."</title>
+                               <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
+                       </head>
+                       <body>
+                       <div class=\"floatingLogo\"><img src=\"images/logo_wide.png\"></div>
+                       <h1>".__('OPML Utility')."</h1>";
+
+               add_feed_category($this->link, "Imported feeds");
+
+               $this->opml_notice(__("Importing OPML..."));
+               $this->opml_import($owner_uid);
+
+               print "<br><form method=\"GET\" action=\"prefs.php\">
+                       <input type=\"submit\" value=\"".__("Return to preferences")."\">
+                       </form>";
+
+               print "</body></html>";
+
+
+       }
+
+       // Export
+
+       private function opml_export_category($owner_uid, $cat_id, $hide_private_feeds=false) {
+
+               if ($cat_id) {
+                       $cat_qpart = "parent_cat = '$cat_id'";
+                       $feed_cat_qpart = "cat_id = '$cat_id'";
+               } else {
+                       $cat_qpart = "parent_cat IS NULL";
+                       $feed_cat_qpart = "cat_id IS NULL";
+               }
+
+               if ($hide_private_feeds)
+                       $hide_qpart = "(private IS false AND auth_login = '' AND auth_pass = '')";
+               else
+                       $hide_qpart = "true";
+
+               $out = "";
+
+               if ($cat_id) {
+                       $result = db_query($this->link, "SELECT title FROM ttrss_feed_categories WHERE id = '$cat_id'
+                               AND owner_uid = '$owner_uid'");
+                       $cat_title = db_fetch_result($result, 0, "title");
+               }
+
+               if ($cat_title) $out .= "<outline title=\"$cat_title\">\n";
+
+               $result = db_query($this->link, "SELECT id,title
+                       FROM ttrss_feed_categories WHERE
+                       $cat_qpart AND owner_uid = '$owner_uid' ORDER BY order_id, title");
+
+               while ($line = db_fetch_assoc($result)) {
+                       $title = htmlspecialchars($line["title"]);
+                       $out .= $this->opml_export_category($owner_uid, $line["id"], $hide_private_feeds);
+               }
+
+               $feeds_result = db_query($this->link, "select title, feed_url, site_url
+                               from ttrss_feeds where $feed_cat_qpart AND owner_uid = '$owner_uid' AND $hide_qpart
+                               order by order_id, title");
+
+               while ($fline = db_fetch_assoc($feeds_result)) {
+                       $title = htmlspecialchars($fline["title"]);
+                       $url = htmlspecialchars($fline["feed_url"]);
+                       $site_url = htmlspecialchars($fline["site_url"]);
+
+                       if ($site_url) {
+                               $html_url_qpart = "htmlUrl=\"$site_url\"";
+                       } else {
+                               $html_url_qpart = "";
+                       }
+
+                       $out .= "<outline text=\"$title\" xmlUrl=\"$url\" $html_url_qpart/>\n";
+               }
+
+               if ($cat_title) $out .= "</outline>\n";
+
+               return $out;
+       }
+
+       function opml_export($name, $owner_uid, $hide_private_feeds=false, $include_settings=true) {
+               if (!$owner_uid) return;
+
+               if (!isset($_REQUEST["debug"])) {
+                       header("Content-type: application/xml+opml");
+                       header("Content-Disposition: attachment; filename=" . $name );
+               } else {
+                       header("Content-type: text/xml");
+               }
+
+               $out = "<?xml version=\"1.0\" encoding=\"utf-8\"?".">";
+
+               $out .= "<opml version=\"1.0\">";
+               $out .= "<head>
+                       <dateCreated>" . date("r", time()) . "</dateCreated>
+                       <title>Tiny Tiny RSS Feed Export</title>
+               </head>";
+               $out .= "<body>";
+
+               $out .= $this->opml_export_category($owner_uid, false, $hide_private_feeds);
+
+               # export tt-rss settings
+
+               if ($include_settings) {
+                       $out .= "<outline title=\"tt-rss-prefs\" schema-version=\"".SCHEMA_VERSION."\">";
+
+                       $result = db_query($this->link, "SELECT pref_name, value FROM ttrss_user_prefs WHERE
+                          profile IS NULL AND owner_uid = " . $_SESSION["uid"] . " ORDER BY pref_name");
+
+                       while ($line = db_fetch_assoc($result)) {
+                               $name = $line["pref_name"];
+                               $value = htmlspecialchars($line["value"]);
+
+                               $out .= "<outline pref-name=\"$name\" value=\"$value\"/>";
+                       }
+
+                       $out .= "</outline>";
+
+                       $out .= "<outline title=\"tt-rss-labels\" schema-version=\"".SCHEMA_VERSION."\">";
+
+                       $result = db_query($this->link, "SELECT * FROM ttrss_labels2 WHERE
+                               owner_uid = " . $_SESSION['uid']);
+
+                       while ($line = db_fetch_assoc($result)) {
+                               $name = htmlspecialchars($line['caption']);
+                               $fg_color = htmlspecialchars($line['fg_color']);
+                               $bg_color = htmlspecialchars($line['bg_color']);
+
+                               $out .= "<outline label-name=\"$name\" label-fg-color=\"$fg_color\" label-bg-color=\"$bg_color\"/>";
+
+                       }
+
+                       $out .= "</outline>";
+
+                       $out .= "<outline title=\"tt-rss-filters\" schema-version=\"".SCHEMA_VERSION."\">";
+
+                       $result = db_query($this->link, "SELECT filter_type,
+                                       reg_exp,
+                                       action_id,
+                                       enabled,
+                                       action_param,
+                                       inverse,
+                                       filter_param,
+                                       cat_filter,
+                                       ttrss_feeds.feed_url AS feed_url,
+                                       ttrss_feed_categories.title AS cat_title
+                                       FROM ttrss_filters
+                                               LEFT JOIN ttrss_feeds ON (feed_id = ttrss_feeds.id)
+                                               LEFT JOIN ttrss_feed_categories ON (ttrss_filters.cat_id = ttrss_feed_categories.id)
+                                       WHERE
+                                               ttrss_filters.owner_uid = " . $_SESSION['uid']);
+
+                       while ($line = db_fetch_assoc($result)) {
+                               $name = htmlspecialchars($line['reg_exp']);
+
+                               foreach (array('enabled', 'inverse', 'cat_filter') as $b) {
+                                       $line[$b] = sql_bool_to_bool($line[$b]);
+                               }
+
+                               $filter = json_encode($line);
+
+                               $out .= "<outline filter-name=\"$name\">$filter</outline>";
+
+                       }
+
+
+                       $out .= "</outline>";
+               }
+
+               $out .= "</body></opml>";
+
+               // Format output.
+               $doc = new DOMDocument();
+               $doc->formatOutput = true;
+               $doc->preserveWhiteSpace = false;
+               $doc->loadXML($out);
+
+               $xpath = new DOMXpath($doc);
+               $outlines = $xpath->query("//outline[@title]");
+
+               // cleanup empty categories
+               foreach ($outlines as $node) {
+                       if ($node->getElementsByTagName('outline')->length == 0)
+                               $node->parentNode->removeChild($node);
+               }
+
+               $res = $doc->saveXML();
+
+               // saveXML uses a two-space indent.  Change to tabs.
+               $res = preg_replace_callback('/^(?:  )+/mu',
+                       create_function(
+                               '$matches',
+                               'return str_repeat("\t", intval(strlen($matches[0])/2));'),
+                       $res);
+
+               print $res;
+       }
+
+       // Import
+
+       private function opml_import_feed($doc, $node, $cat_id, $owner_uid) {
+               $attrs = $node->attributes;
+
+               $feed_title = db_escape_string($attrs->getNamedItem('text')->nodeValue);
+               if (!$feed_title) $feed_title = db_escape_string($attrs->getNamedItem('title')->nodeValue);
+
+               $feed_url = db_escape_string($attrs->getNamedItem('xmlUrl')->nodeValue);
+               if (!$feed_url) $feed_url = db_escape_string($attrs->getNamedItem('xmlURL')->nodeValue);
+
+               $site_url = db_escape_string($attrs->getNamedItem('htmlUrl')->nodeValue);
+
+               if ($feed_url && $feed_title) {
+                       $result = db_query($this->link, "SELECT id FROM ttrss_feeds WHERE
+                               feed_url = '$feed_url' AND owner_uid = '$owner_uid'");
+
+                       if (db_num_rows($result) == 0) {
+                               #$this->opml_notice("[FEED] [$feed_title/$feed_url] dst_CAT=$cat_id");
+                               $this->opml_notice(T_sprintf("Adding feed: %s", $feed_title));
+
+                               $query = "INSERT INTO ttrss_feeds
+                                       (title, feed_url, owner_uid, cat_id, site_url, order_id) VALUES
+                                       ('$feed_title', '$feed_url', '$owner_uid',
+                                       '$cat_id', '$site_url', 0)";
+                               db_query($this->link, $query);
+
+                       } else {
+                               $this->opml_notice(T_sprintf("Duplicate feed: %s", $feed_title));
+                       }
+               }
+       }
+
+       private function opml_import_label($doc, $node, $owner_uid) {
+               $attrs = $node->attributes;
+               $label_name = db_escape_string($attrs->getNamedItem('label-name')->nodeValue);
+
+               if ($label_name) {
+                       $fg_color = db_escape_string($attrs->getNamedItem('label-fg-color')->nodeValue);
+                       $bg_color = db_escape_string($attrs->getNamedItem('label-bg-color')->nodeValue);
+
+                       if (!label_find_id($this->link, $label_name, $_SESSION['uid'])) {
+                               $this->opml_notice(T_sprintf("Adding label %s", htmlspecialchars($label_name)));
+                               label_create($this->link, $label_name, $fg_color, $bg_color);
+                       } else {
+                               $this->opml_notice(T_sprintf("Duplicate label: %s", htmlspecialchars($label_name)));
+                       }
+               }
+       }
+
+       private function opml_import_preference($doc, $node, $owner_uid) {
+               $attrs = $node->attributes;
+               $pref_name = db_escape_string($attrs->getNamedItem('pref-name')->nodeValue);
+
+               if ($pref_name) {
+                       $pref_value = db_escape_string($attrs->getNamedItem('value')->nodeValue);
+
+                       $this->opml_notice(T_sprintf("Setting preference key %s to %s",
+                               $pref_name, $pref_value));
+
+                       set_pref($this->link, $pref_name, $pref_value);
+               }
+       }
+
+       private function opml_import_filter($doc, $node, $owner_uid) {
+               $attrs = $node->attributes;
+
+               $filter_name = db_escape_string($attrs->getNamedItem('filter-name')->nodeValue);
+
+               if ($filter_name) {
+
+               $filter = json_decode($node->nodeValue, true);
+
+                       if ($filter) {
+                               $reg_exp = db_escape_string($filter['reg_exp']);
+                               $filter_type = (int)$filter['filter_type'];
+                               $action_id = (int)$filter['action_id'];
+
+                               $result = db_query($this->link, "SELECT id FROM ttrss_filters WHERE
+                                       reg_exp = '$reg_exp' AND
+                                       filter_type = '$filter_type' AND
+                                       action_id = '$action_id' AND
+                                       owner_uid = " .$_SESSION['uid']);
+
+                               if (db_num_rows($result) == 0) {
+                                       $enabled = bool_to_sql_bool($filter['enabled']);
+                                       $action_param = db_escape_string($filter['action_param']);
+                                       $inverse = bool_to_sql_bool($filter['inverse']);
+                                       $filter_param = db_escape_string($filter['filter_param']);
+                                       $cat_filter = bool_to_sql_bool($filter['cat_filter']);
+
+                                       $feed_url = db_escape_string($filter['feed_url']);
+                                       $cat_title = db_escape_string($filter['cat_title']);
+
+                                       $result = db_query($this->link, "SELECT id FROM ttrss_feeds WHERE
+                                               feed_url = '$feed_url' AND owner_uid = $owner_uid");
+
+                                       if (db_num_rows($result) != 0) {
+                                               $feed_id = db_fetch_result($result, 0, "id");
+                                       } else {
+                                               $feed_id = "NULL";
+                                       }
+
+                                       $result = db_query($this->link, "SELECT id FROM ttrss_feed_categories WHERE
+                                               title = '$cat_title' AND  owner_uid = $owner_uid");
+
+                                       if (db_num_rows($result) != 0) {
+                                               $cat_id = db_fetch_result($result, 0, "id");
+                                       } else {
+                                               $cat_id = "NULL";
+                                       }
+
+                                       $this->opml_notice(T_sprintf("Adding filter %s", htmlspecialchars($reg_exp)));
+
+                                       $query = "INSERT INTO ttrss_filters (filter_type, action_id,
+                                                       enabled, inverse, action_param, filter_param,
+                                                       cat_filter, feed_id,
+                                                       cat_id, reg_exp,
+                                                       owner_uid)
+                                               VALUES ($filter_type, $action_id,
+                                                       $enabled, $inverse, '$action_param', '$filter_param',
+                                                       $cat_filter, $feed_id,
+                                                       $cat_id, '$reg_exp', ".
+                                                       $_SESSION['uid'].")";
+
+                                       db_query($this->link, $query);
+
+                               } else {
+                                       $this->opml_notice(T_sprintf("Duplicate filter %s", htmlspecialchars($reg_exp)));
+                               }
+                       }
+               }
+       }
+
+       private function opml_import_category($doc, $root_node, $owner_uid, $parent_id) {
+               $body = $doc->getElementsByTagName('body');
+
+               $default_cat_id = (int) get_feed_category($this->link, 'Imported feeds', false);
+
+               if ($root_node) {
+                       $cat_title = db_escape_string($root_node->attributes->getNamedItem('title')->nodeValue);
+
+                       if (!in_array($cat_title, array("tt-rss-filters", "tt-rss-labels", "tt-rss-prefs"))) {
+                               $cat_id = get_feed_category($this->link, $cat_title, $parent_id);
+                               db_query($this->link, "BEGIN");
+                               if ($cat_id === false) {
+                                       add_feed_category($this->link, $cat_title, $parent_id);
+                                       $cat_id = get_feed_category($this->link, $cat_title, $parent_id);
+                               }
+                               db_query($this->link, "COMMIT");
+                       } else {
+                               $cat_id = 0;
+                       }
+
+                       $outlines = $root_node->childNodes;
+
+               } else {
+                       $xpath = new DOMXpath($doc);
+                       $outlines = $xpath->query("//opml/body/outline");
+
+                       $cat_id = 0;
+               }
+
+               #$this->opml_notice("[CAT] $cat_title id: $cat_id P_id: $parent_id");
+               $this->opml_notice(T_sprintf("Processing category: %s", $cat_title ? $cat_title : __("Uncategorized")));
+
+               foreach ($outlines as $node) {
+                       if ($node->hasAttributes() && strtolower($node->tagName) == "outline") {
+                               $attrs = $node->attributes;
+                               $node_cat_title = db_escape_string($attrs->getNamedItem('title')->nodeValue);
+                               $node_feed_url = db_escape_string($attrs->getNamedItem('xmlUrl')->nodeValue);
+
+                               if ($node_cat_title && !$node_feed_url) {
+                                       $this->opml_import_category($doc, $node, $owner_uid, $cat_id);
+                               } else {
+
+                                       if (!$cat_id) {
+                                               $dst_cat_id = $default_cat_id;
+                                       } else {
+                                               $dst_cat_id = $cat_id;
+                                       }
+
+                                       switch ($cat_title) {
+                                       case "tt-rss-prefs":
+                                               $this->opml_import_preference($doc, $node, $owner_uid);
+                                               break;
+                                       case "tt-rss-labels":
+                                               $this->opml_import_label($doc, $node, $owner_uid);
+                                               break;
+                                       case "tt-rss-filters":
+                                               $this->opml_import_filter($doc, $node, $owner_uid);
+                                               break;
+                                       default:
+                                               $this->opml_import_feed($doc, $node, $dst_cat_id, $owner_uid);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       function opml_import($owner_uid) {
+               if (!$owner_uid) return;
+
+               $debug = isset($_REQUEST["debug"]);
+               $doc = false;
+
+               #if ($debug) $doc = DOMDocument::load("/tmp/test.opml");
+
+               if (is_file($_FILES['opml_file']['tmp_name'])) {
+                       $doc = DOMDocument::load($_FILES['opml_file']['tmp_name']);
+               } else if (!$doc) {
+                       print_error(__('Error: please upload OPML file.'));
+                       return;
+               }
+
+               if ($doc) {
+                       $this->opml_import_category($doc, false, $owner_uid, false);
+               } else {
+                       print_error(__('Error while parsing document.'));
+               }
+       }
+
+       private function opml_notice($msg) {
+               print "$msg<br/>";
+       }
+
+}
+?>