summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/0001-protect-metadata-loads-from-multiple-threads.patch52
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/PKGBUILD118
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/__changelog2
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/HOST_SETTINGS.xml98
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/dvd_backup.xml39
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/game.xml12
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/info_menu.xml76
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/is.xml3
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/library.xml.patch26
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/linhes.xml60
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/mainmenu.xml.patch37
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/mythbackup.xml20
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/mythrestore.xml21
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/optical_menu.xml.patch23
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/original/create_patch.sh5
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/siriusmenu.xml419
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/update.xml9
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/update2.xml20
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/menu-xml/xmmenu.xml574
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/myth_settings.patch1980
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/mythtv.install24
-rw-r--r--abs/core/mythtv/stable-0.27/mythtv/recordings5
22 files changed, 3623 insertions, 0 deletions
diff --git a/abs/core/mythtv/stable-0.27/mythtv/0001-protect-metadata-loads-from-multiple-threads.patch b/abs/core/mythtv/stable-0.27/mythtv/0001-protect-metadata-loads-from-multiple-threads.patch
new file mode 100644
index 0000000..d8f4a0c
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/0001-protect-metadata-loads-from-multiple-threads.patch
@@ -0,0 +1,52 @@
+From b20171597097f8b933065ef3291c63194d310fbf Mon Sep 17 00:00:00 2001
+From: George Nassas <george@nassas.com>
+Date: Sun, 10 Jun 2012 13:36:42 -0400
+Subject: [PATCH] protect metadata loads from multiple threads
+
+---
+ mythtv/libs/libmythmetadata/dbaccess.cpp | 9 +++++++++
+ 1 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/mythtv/libs/libmythmetadata/dbaccess.cpp b/mythtv/libs/libmythmetadata/dbaccess.cpp
+index 67cd904..46adb7a 100644
+--- a/mythtv/libs/libmythmetadata/dbaccess.cpp
++++ b/mythtv/libs/libmythmetadata/dbaccess.cpp
+@@ -47,8 +47,11 @@ class SingleValueImp
+
+ virtual ~SingleValueImp() {}
+
++ mutable QMutex mutex;
++
+ void load_data()
+ {
++ QMutexLocker locker(&mutex);
+ if (!m_ready)
+ {
+ fill_from_db();
+@@ -271,8 +274,11 @@ class MultiValueImp
+ .arg(m_value_name).arg(m_table_name).arg(m_id_name);
+ }
+
++ mutable QMutex mutex;
++
+ void load_data()
+ {
++ QMutexLocker locker(&mutex);
+ if (!m_ready)
+ {
+ fill_from_db();
+@@ -730,8 +736,11 @@ class FileAssociationsImp
+ }
+ }
+
++ mutable QMutex mutex;
++
+ void load_data()
+ {
++ QMutexLocker locker(&mutex);
+ if (!m_ready)
+ {
+ fill_from_db();
+--
+1.7.2.5
+
diff --git a/abs/core/mythtv/stable-0.27/mythtv/PKGBUILD b/abs/core/mythtv/stable-0.27/mythtv/PKGBUILD
new file mode 100644
index 0000000..a00c869
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/PKGBUILD
@@ -0,0 +1,118 @@
+pkgname=mythtv
+pkgver=0.27
+pkgrel=1
+commit_hash=`cat ../git_src/git_hash`
+pkgdesc="A Homebrew PVR project $commit_hash"
+arch=('i686' 'x86_64')
+url="http://www.mythtv.org/"
+license=('GPL')
+depends=('avahi' 'fftw' 'glew' 'lame' 'libass' 'libavc1394' 'libcdio'
+ 'libcec' 'libiec61883' 'libva' 'libvpx' 'libxinerama' 'libxml2'
+ 'lirc-utils' 'mysql-clients' 'mysql-python' 'openssl'
+ 'perl-dbd-mysql' 'perl-io-socket-inet6' 'perl-libwww'
+ 'perl-net-upnp' 'python2-lxml' 'qtwebkit' 'taglib' 'urlgrabber'
+ 'x264' 'xmltv'
+ #'qt'
+ #'ffmpeg'
+ #'fribidi'
+ #'perl-soap-lite'
+ #'perl-date-manip'
+ #'perl-xml-sax'
+ #'perl-math-round'
+ #'perl-time-hires'
+ #'wget'
+ #'libxrandr'
+ #'faad2'
+ #'libvdpau'
+ #'libcrystalhd-git'
+ #'python-pycurl'
+ #'lsdvd'
+ #'dvdbackup'
+ )
+makedepends=('mesa' 'libgl' 'yasm' 'git' 'rsync')
+replaces=()
+groups=('pvr')
+backup=()
+install='mythtv.install'
+
+patches=(#'myth_settings.patch'
+ '0001-protect-metadata-loads-from-multiple-threads.patch')
+ #http://code.mythtv.org/trac/ticket/10825 thread safety in video metadata load
+
+optdepends=()
+replaces=('mythvideo' 'myththemes')
+conflicts=('mythvideo' 'myththemes')
+source=(`echo ${patches[@]:0}` 'recordings')
+
+build() {
+ if [ -e ${srcdir}/mythtv ]
+ then
+ msg "Removing old mythtv src"
+ rm -rf ${srcdir}/mythtv
+ fi
+
+ cd ${startdir}
+ msg "Copying in mythtv git_src"
+ cp -rp ../git_src/mythtv/mythtv $srcdir
+ cd ${srcdir}/$pkgname
+ echo "#!/bin/bash" > version.sh
+
+ msg "--------------------------applying patches------------------------------"
+ for i in `echo ${patches[@]:0} `
+ do
+ echo applying $i
+ echo "-----------------------------"
+ patch -Np2 -i ${startdir}/src/$i || return 1
+ done
+ msg "--------------------------done applying patches-------------------------"
+
+ msg "Configuring mythtv"
+ ARCH=${CARCH/_/-}
+ ./configure --prefix=/usr \
+ --cpu=${ARCH} \
+ --disable-altivec \
+ --disable-audio-jack \
+ --disable-audio-pulse \
+ --disable-ccache \
+ --disable-distcc \
+ --dvb-path=/usr/include \
+ --enable-libfftw3 \
+ --enable-libmp3lame \
+ --enable-libvpx \
+ --enable-libx264 \
+ --enable-vaapi \
+ --python=python2 \
+ --with-bindings=perl,python || return 1
+ msg "Compiling mythtv"
+ make all || return 1
+}
+
+package() {
+ cd "${srcdir}/${pkgname}"
+ # basic install
+ make INSTALL_ROOT="${pkgdir}" install
+ # install contrib files
+ rsync -arp --exclude .svn --delete-excluded contrib ${pkgdir}/usr/share/mythtv/ || return 1
+ # install database structure
+ rsync -arp --exclude .svn --delete-excluded database ${pkgdir}/usr/share/mythtv/ || return 1
+ # install docs
+ rsync -arp --exclude .svn --delete-excluded docs ${pkgdir}/usr/share/mythtv/ || return 1
+
+ # patch the xml LinHES style
+ cp -r ${startdir}/menu-xml/*.xml ${pkgdir}/usr/share/mythtv/themes/defaultmenu/
+ cd ${pkgdir}/usr/share/mythtv
+ patch -p0 < ${startdir}/menu-xml/mainmenu.xml.patch || return 1
+ patch -p0 < ${startdir}/menu-xml/optical_menu.xml.patch || return 1
+ patch -p0 < ${startdir}/menu-xml/library.xml.patch || return 1
+
+ # make mythtv log dir for old scripts that use it
+ mkdir -p ${pkgdir}/var/log/mythtv
+ chown 1000.1000 ${pkgdir}/var/log/mythtv
+
+ #install recordings (was pretty)
+ mkdir -p ${pkgdir}/etc/cron.hourly/
+ install -m0755 ${srcdir}/recordings ${pkgdir}/etc/cron.hourly/
+}
+
+md5sums=('67f7316c750fba17fa578d10840b9dbd'
+ '65a08d8949431ecdeb51a686dc6f9c21')
diff --git a/abs/core/mythtv/stable-0.27/mythtv/__changelog b/abs/core/mythtv/stable-0.27/mythtv/__changelog
new file mode 100644
index 0000000..91a959c
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/__changelog
@@ -0,0 +1,2 @@
+update to 0.27-fixes
+
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/HOST_SETTINGS.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/HOST_SETTINGS.xml
new file mode 100644
index 0000000..b1fa6b5
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/HOST_SETTINGS.xml
@@ -0,0 +1,98 @@
+<mythmenu name="HOST_SETTINGS">
+ <button>
+ <type>MV_ACCESS_SETUP_MENU</type>
+ <text>Access Control</text>
+ <action>EXEC mythinstall -s accesscontrol </action>
+ </button>
+
+ <button>
+ <type>MV_SOFTWARE_MENU</type>
+ <text>Add/Remove software</text>
+ <action>EXEC mythinstall -s plugins,software </action>
+ </button>
+
+ <button>
+ <type>MV_ADVANCED_SETUP_MENU</type>
+ <text>Advanced</text>
+ <action>EXEC mythinstall -s advanced</action>
+ </button>
+
+ <button>
+ <type>MV_AUDIO_SETUP_MENU</type>
+ <text>Audio Settings</text>
+ <action>EXEC mythinstall -s sound </action>
+ </button>
+
+ <button>
+ <type>MV_ADVANCED_X_SETUP_MENU</type>
+ <text>Display</text>
+ <action>EXEC mythinstall -s advancedX</action>
+ </button>
+
+ <button>
+ <type>MV_NETWORK_SETUP_MENU</type>
+ <text>Dynamic DNS</text>
+ <action>EXEC mythinstall -s ddns </action>
+ </button>
+
+ <button>
+ <type>MV_FILESHARES_MENU</type>
+ <text>File Shares</text>
+ <action>EXEC mythinstall -s fileshare</action>
+ </button>
+
+ <button>
+ <type>MV_MISC_SETUP_MENU</type>
+ <text>Miscellanous</text>
+ <action>EXEC mythinstall -s misc </action>
+ </button>
+
+ <button>
+ <type>MV_NETWORK_SETUP_MENU</type>
+ <text>Network</text>
+ <action>EXEC mythinstall -s network </action>
+ </button>
+
+ <button>
+ <type>MV_IR_SETUP_MENU</type>
+ <text>Remotes</text>
+ <action>EXEC mythinstall -s ir </action>
+ </button>
+
+ <button>
+ <type>MV_SCREENSAVER_SETUP_MENU</type>
+ <text>Screensaver</text>
+ <action>EXEC mythinstall -s screensaver </action>
+ </button>
+
+ <button>
+ <type>MV_SHUTDOWN_SETUP_MENU</type>
+ <text>Shutdown Settings</text>
+ <action>EXEC mythinstall -s sleep </action>
+ </button>
+
+ <button>
+ <type>MV_SYSTEM_SETUP_MENU</type>
+ <text>System Type</text>
+ <action>EXEC mythinstall -s hostype </action>
+ </button>
+
+ <button>
+ <type>MV_USER_SETUP_MENU</type>
+ <text>User Accounts</text>
+ <action>EXEC mythinstall -s user </action>
+ </button>
+
+ <button>
+ <type>MV_VNC_SETUP_MENU</type>
+ <text>VNC Service</text>
+ <action>EXEC mythinstall -s vnc </action>
+ </button>
+
+ <button>
+ <type>MV_WEBACCESS_SETUP_MENU</type>
+ <text>Web Security</text>
+ <action>EXEC mythinstall -s webuser </action>
+ </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/dvd_backup.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/dvd_backup.xml
new file mode 100644
index 0000000..2647d81
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/dvd_backup.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<mythmenu name="OPTICAL_DISK">
+
+ <button>
+ <type>DVD_RIP</type>
+ <text>Mirror DVD</text>
+ <description>Creates a mirror of your DVD</description>
+ <action>EXEC /usr/LH/bin/ripD_eject.sh m &amp;</action>
+ </button>
+
+ <button>
+ <type>DVD_RIP</type>
+ <text>ISO of DVD</text>
+ <description>Creates an ISO of your DVD</description>
+ <action>EXEC /usr/LH/bin/ripD_eject.sh i &amp;</action>
+ </button>
+
+ <button>
+ <type>DVD_RIP</type>
+ <text>High Quality</text>
+ <description>Creates a high quality MPEG4 of your DVD</description>
+ <action>EXEC /usr/LH/bin/ripD_eject.sh h &amp;</action>
+ </button>
+
+ <button>
+ <type>DVD_RIP</type>
+ <text>Normal Quality</text>
+ <description>Creates a normal quality MPEG4 of your DVD</description>
+ <action>EXEC /usr/LH/bin/ripD_eject.sh n &amp;</action>
+ </button>
+
+ <button>
+ <type>DVD_RIP</type>
+ <text>Low Quality</text>
+ <description>Creates a low quality MPEG4 of your DVD</description>
+ <action>EXEC /usr/LH/bin/ripD_eject.sh l &amp;</action>
+ </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/game.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/game.xml
new file mode 100644
index 0000000..293a9e6
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/game.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<mythmenu name="GAME">
+
+ <button>
+ <type>GAME</type>
+ <text>MythGame</text>
+ <description>Play video games</description>
+ <action>PLUGIN mythgame</action>
+ <depends>mythgame</depends>
+ </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/info_menu.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/info_menu.xml
new file mode 100644
index 0000000..017f90b
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/info_menu.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<mythmenu name="INFO">
+
+ <button>
+ <type>NEWS</type>
+ <text>News Feeds</text>
+ <description>Keep up with the news</description>
+ <action>PLUGIN mythnews</action>
+ <depends>mythnews</depends>
+ </button>
+
+ <button>
+ <type>MYTHTWITTER_TIMELINE</type>
+ <text>Twitter</text>
+ <description>Send and receive tweets</description>
+ <action>JUMP MythTwitter_Timeline</action>
+ <depends>mythtwitter</depends>
+ </button>
+
+ <button>
+ <type>WEATHER</type>
+ <text>Weather</text>
+ <action>PLUGIN mythweather</action>
+ <description>Local weather forecast</description>
+ <depends>mythweather</depends>
+ </button>
+
+ <button>
+ <type>WEATHER</type>
+ <text>Weather Station</text>
+ <action>PLUGIN mythwstation</action>
+ <depends>mythwstation</depends>
+ </button>
+
+ <button>
+ <type>WEBPAGE</type>
+ <text>Web</text>
+ <description>Browse the web</description>
+ <action>PLUGIN mythbrowser</action>
+ <depends>mythbrowser</depends>
+ </button>
+
+ <button>
+ <type>RECIPE</type>
+ <text>Recipes</text>
+ <description>Start cooking!</description>
+ <action>PLUGIN mythRecipe</action>
+ <depends>mythrecipe</depends>
+ </button>
+
+ <button>
+ <type>TV_STATUS</type>
+ <text>System Status</text>
+ <description>See what your system is doing</description>
+ <action>TV_STATUS</action>
+ </button>
+
+ <button>
+ <type>ZONEMINDER</type>
+ <text>ZoneMinder</text>
+ <description>Home surveillance</description>
+ <action>PLUGIN mythzoneminder</action>
+ <depends>mythzoneminder</depends>
+ </button>
+
+<!--
+ <button>
+ <type>SMOLT</type>
+ <text>Hardware profile</text>
+ <description>Tell us what hardware you have so we can support it</description>
+ <action>PLUGIN mythsmolt</action>
+ <depends>mythsmolt</depends>
+ </button>
+ -->
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/is.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/is.xml
new file mode 100644
index 0000000..88b7e6b
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/is.xml
@@ -0,0 +1,3 @@
+<mythmenu name="Internet Steams">
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/library.xml.patch b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/library.xml.patch
new file mode 100644
index 0000000..8f80928
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/library.xml.patch
@@ -0,0 +1,26 @@
+--- themes/defaultmenu/library.xml.orig 2012-06-10 08:02:54.000000000 +0000
++++ themes/defaultmenu/library.xml 2012-06-10 08:03:38.000000000 +0000
+@@ -40,6 +40,13 @@
+ </button>
+
+ <button>
++ <type>STREAM</type>
++ <text>Online Content</text>
++ <description>Play content from online sources</description>
++ <action>MENU gen_is.xml</action>
++ </button>
++
++ <button>
+ <type>IMAGES</type>
+ <text>Image Gallery</text>
+ <description>Look at Pictures</description>
+@@ -51,8 +58,7 @@
+ <type>GAME</type>
+ <text>Play Games</text>
+ <description>Play video games</description>
+- <action>PLUGIN mythgame</action>
+- <depends>mythgame</depends>
++ <action>MENU game.xml</action>
+ </button>
+
+ </mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/linhes.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/linhes.xml
new file mode 100644
index 0000000..342766d
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/linhes.xml
@@ -0,0 +1,60 @@
+<mythmenu name="LinHES">
+
+ <button>
+ <type>SETUP_GENERAL</type>
+ <text>MythTV Configuration</text>
+ <text lang="IT">Impostazioni</text>
+ <text lang="ES">Configuración</text>
+ <text lang="DE">Zubehör / Konfiguration</text>
+ <text lang="DA">Tilbehør/Indstillinger</text>
+ <text lang="IS">Uppsetning</text>
+ <text lang="NL">Configuratie</text>
+ <text lang="PT">Utensílios</text>
+ <text lang="SV">Verktyg / Inställningar</text>
+ <text lang="JA">設å®~Z</text>
+ <text lang="FI">Oheis/Asetukset</text>
+ <text lang="ZH_TW">å·¥å~E·/設å®~Z</text>
+ <text lang="SL">Nastavitve</text>
+ <text lang="ET">Utiliidid / sätted</text>
+ <text lang="RU">УÑ~BилиÑ~BÑ~K / Ð~]аÑ~AÑ~BÑ~@ойки</text>
+ <text lang="AR">تضبÙ~Jطات</text>
+ <text lang="PL">NarzÄ~Ydzia / ustawienia</text>
+ <text lang="HE">×¢×~Vר×~Y×~] / ×~T×~R×~Sר×~Uת</text>
+ <text lang="HU">Eszközök / Beállítások</text>
+ <alttext lang="DE">Verschiedenes</alttext>
+ <alttext lang="SV">Inställningar</alttext>
+ <alttext lang="ET">Sätted</alttext>
+ <alttext lang="RU">Ð~]аÑ~AÑ~BÑ~@ойки</alttext>
+ <alttext lang="AR">تضبÙ~Jطات</alttext>
+ <description>Configure MythTV and plugins</description>
+ <description lang="DE">MythTV und Plugins konfigurieren</description>
+ <action>MENU util_menu.xml</action>
+ </button>
+
+ <button>
+ <type>LINHES_SETUP</type>
+ <text>LinHES Configuration</text>
+ <description>Configure LinHES</description>
+ <action>MENU HOST_SETTINGS.xml</action>
+ </button>
+
+ <button>
+ <type>BACKUP</type>
+ <text>Backup LinHES</text>
+ <action>MENU mythbackup.xml</action>
+ </button>
+
+ <button>
+ <type>RESTORE</type>
+ <text>Restore LinHES</text>
+ <action>MENU mythrestore.xml</action>
+ </button>
+
+<!--#Check for updates-->
+ <button>
+ <type>UPGRADE</type>
+ <text>Update LinHES</text>
+ <action>MENU update.xml</action>
+ </button>
+<!--#Check for updates-->
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/mainmenu.xml.patch b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/mainmenu.xml.patch
new file mode 100644
index 0000000..73a8940
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/mainmenu.xml.patch
@@ -0,0 +1,37 @@
+--- themes/defaultmenu/mainmenu.xml.orig 2012-07-29 21:39:46.000000000 +0000
++++ themes/defaultmenu/mainmenu.xml 2012-07-29 21:41:50.000000000 +0000
+@@ -1,5 +1,11 @@
+ <?xml version="1.0" encoding="UTF-8" ?>
+ <mythmenu name="MAIN">
++ <button>
++ <type>TV_WATCH_TV</type>
++ <text>Watch TV</text>
++ <description>Watch live television</description>
++ <action>TV_WATCH_LIVE</action>
++ </button>
+
+ <button>
+ <type>MENU_MEDIA_LIBRARY</type>
+@@ -30,18 +36,11 @@
+ </button>
+
+ <button>
+- <type>TV_WATCH_TV</type>
+- <text>Watch TV</text>
+- <description>Watch live television</description>
+- <action>TV_WATCH_LIVE</action>
+- </button>
+-
+- <button>
+ <type>MENU_UTILITIES_SETUP</type>
+- <text>Setup</text>
+- <description>Configure MythTV and plugins</description>
+- <action>MENU main_settings.xml</action>
+- <password>SetupPinCode</password>
++ <text>Service Menu</text>
++ <description>Configure your system</description>
++ <action>MENU linhes.xml</action>
++ <password>SetupPinCode</password>
+ </button>
+
+ </mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/mythbackup.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/mythbackup.xml
new file mode 100644
index 0000000..7890d88
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/mythbackup.xml
@@ -0,0 +1,20 @@
+<mythmenu name="LinHES">
+ <button>
+ <type>BACKUP</type>
+ <text>Do you wish to backup?</text>
+ <description></description>
+ <action>NONE</action>
+ </button>
+
+ <button>
+ <type>BACKUP</type>
+ <text>Yes</text>
+ <action>EXEC sudo /usr/LH/bin/lh_system_backup &amp;</action>
+ </button>
+
+ <button>
+ <type>BACKUP</type>
+ <text>No</text>
+ <action>UPMENU</action>
+ </button>
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/mythrestore.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/mythrestore.xml
new file mode 100644
index 0000000..161f13f
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/mythrestore.xml
@@ -0,0 +1,21 @@
+<mythmenu name="LinHES">
+
+ <button>
+ <type>RESTORE</type>
+ <text>Do you wish to restore?</text>
+ <description>This will restore from most recent backup.</description>
+ <action>NONE</action>
+ </button>
+
+ <button>
+ <type>RESTORE</type>
+ <text>Yes</text>
+ <action>EXEC sudo /usr/LH/bin/lh_system_restore &amp;</action>
+ </button>
+
+ <button>
+ <type>BACKUP</type>
+ <text>No</text>
+ <action>UPMENU</action>
+ </button>
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/optical_menu.xml.patch b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/optical_menu.xml.patch
new file mode 100644
index 0000000..b836e85
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/optical_menu.xml.patch
@@ -0,0 +1,23 @@
+--- themes/defaultmenu/optical_menu.xml.orig 2012-05-02 18:41:38.000000000 +0000
++++ themes/defaultmenu/optical_menu.xml 2012-07-30 05:33:03.000000000 +0000
+@@ -17,6 +17,20 @@
+ </button>
+
+ <button>
++ <type>DVD_RIP</type>
++ <text>Backup DVD</text>
++ <description>Backup your DVDs</description>
++ <action>MENU dvd_backup.xml</action>
++ </button>
++
++ <button>
++ <type>DVD_RIP</type>
++ <text>Import Files from DVD</text>
++ <description>Import all files from a data DVD</description>
++ <action>EXEC /usr/LH/bin/importfiles.sh &amp;</action>
++ </button>
++
++ <button>
+ <type>MUSIC_RIP</type>
+ <text>Import CD</text>
+ <description>Import music from an audio CD</description>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/original/create_patch.sh b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/original/create_patch.sh
new file mode 100644
index 0000000..34d8b8c
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/original/create_patch.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+for i in *.xml
+do
+ diff -u $i.orig $i > ../$i.patch
+done
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/siriusmenu.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/siriusmenu.xml
new file mode 100644
index 0000000..e317b36
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/siriusmenu.xml
@@ -0,0 +1,419 @@
+<mythmenu name="SIRIUS">
+ <button>
+ <type>MUSIC</type>
+ <text>Sirius Hits 1</text>
+ <action>EXEC /usr/bin/cliSipie siriushits1</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>StarLite</text>
+ <action>EXEC /usr/bin/cliSipie starlite</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Sirius Love</text>
+ <action>EXEC /usr/bin/cliSipie siriuslove</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Movin EZ</text>
+ <action>EXEC /usr/bin/cliSipie movineasy</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Sirius Gold</text>
+ <action>EXEC /usr/bin/cliSipie siriusgold</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>'60s Vibrations</text>
+ <action>EXEC /usr/bin/cliSipie 60svibrations</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Totally '70s</text>
+ <action>EXEC /usr/bin/cliSipie totally70s</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Big '80s</text>
+ <action>EXEC /usr/bin/cliSipie big80s</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>ThePulse</text>
+ <action>EXEC /usr/bin/cliSipie thepulse</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Bridge</text>
+ <action>EXEC /usr/bin/cliSipie thebridge</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>BBC Radio 1</text>
+ <action>EXEC /usr/bin/cliSipie bbcradio1</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Super Shuffle</text>
+ <action>EXEC /usr/bin/cliSipie supershuffle</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Elvis Radio</text>
+ <action>EXEC /usr/bin/cliSipie elvisradio</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Classic Vinyl</text>
+ <action>EXEC /usr/bin/cliSipie classicvinyl</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Classic Rewind</text>
+ <action>EXEC /usr/bin/cliSipie classicrewind</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>TheVault</text>
+ <action>EXEC /usr/bin/cliSipie thevault</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Jam_ON</text>
+ <action>EXEC /usr/bin/cliSipie jamon</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Spectrum</text>
+ <action>EXEC /usr/bin/cliSipie thespectrum</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>BuzzSaw</text>
+ <action>EXEC /usr/bin/cliSipie buzzsaw</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Octane</text>
+ <action>EXEC /usr/bin/cliSipie octane</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Alt Nation</text>
+ <action>EXEC /usr/bin/cliSipie altnation</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>1st Wave</text>
+ <action>EXEC /usr/bin/cliSipie firstwave</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Hair Nation</text>
+ <action>EXEC /usr/bin/cliSipie hairnation</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>'90s Alternative</text>
+ <action>EXEC /usr/bin/cliSipie 90salternative</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Garage</text>
+ <action>EXEC /usr/bin/cliSipie undergroundgarage</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Left of Center</text>
+ <action>EXEC /usr/bin/cliSipie leftofcenter</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Hard Attack</text>
+ <action>EXEC /usr/bin/cliSipie hardattack</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Faction</text>
+ <action>EXEC /usr/bin/cliSipie faction</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Punk</text>
+ <action>EXEC /usr/bin/cliSipie punk</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>The Coffee House</text>
+ <action>EXEC /usr/bin/cliSipie coffeehouse</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Margaritaville</text>
+ <action>EXEC /usr/bin/cliSipie radiomargaritaville</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Sirius Disorder</text>
+ <action>EXEC /usr/bin/cliSipie siriusdisorder</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Reggae</text>
+ <action>EXEC /usr/bin/cliSipie reggaerhythms</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Area 33</text>
+ <action>EXEC /usr/bin/cliSipie area33</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Boombox</text>
+ <action>EXEC /usr/bin/cliSipie boombox</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Chill</text>
+ <action>EXEC /usr/bin/cliSipie chill</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>The Beat</text>
+ <action>EXEC /usr/bin/cliSipie thebeat</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Strobe</text>
+ <action>EXEC /usr/bin/cliSipie thestrobe</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Hip-Hop Nation</text>
+ <action>EXEC /usr/bin/cliSipie hiphopnation</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>BackSpin</text>
+ <action>EXEC /usr/bin/cliSipie backspin</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Shade 45</text>
+ <action>EXEC /usr/bin/cliSipie shade45</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Hot Jamz</text>
+ <action>EXEC /usr/bin/cliSipie hotjamz</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Heart &amp; Soul</text>
+ <action>EXEC /usr/bin/cliSipie heartandsoul</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>SoulTown</text>
+ <action>EXEC /usr/bin/cliSipie soultown</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>New Country</text>
+ <action>EXEC /usr/bin/cliSipie newcountry</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Prime Country</text>
+ <action>EXEC /usr/bin/cliSipie primecountry</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Roadhouse</text>
+ <action>EXEC /usr/bin/cliSipie theroadhouse</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Outlaw Country</text>
+ <action>EXEC /usr/bin/cliSipie outlawcountry</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Bluegrass</text>
+ <action>EXEC /usr/bin/cliSipie bluegrass</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Spirit</text>
+ <action>EXEC /usr/bin/cliSipie spirit</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Praise</text>
+ <action>EXEC /usr/bin/cliSipie praise</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Planet Jazz</text>
+ <action>EXEC /usr/bin/cliSipie planetjazz</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>JazzCafe</text>
+ <action>EXEC /usr/bin/cliSipie jazzcafe</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>PureJazz</text>
+ <action>EXEC /usr/bin/cliSipie purejazz</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Spa 73</text>
+ <action>EXEC /usr/bin/cliSipie spa73</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Blues</text>
+ <action>EXEC /usr/bin/cliSipie siriusblues</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Siriusly Sinatra</text>
+ <action>EXEC /usr/bin/cliSipie siriuslysinatra</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Broadway's Best</text>
+ <action>EXEC /usr/bin/cliSipie broadwaysbest</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Symphony Hall</text>
+ <action>EXEC /usr/bin/cliSipie symphonyhall</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Met Opera Radio</text>
+ <action>EXEC /usr/bin/cliSipie metropolitanopera</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Sirius Pops</text>
+ <action>EXEC /usr/bin/cliSipie siriuspops</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Universo Latino</text>
+ <action>EXEC /usr/bin/cliSipie universolatino</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Rumbon</text>
+ <action>EXEC /usr/bin/cliSipie rumbon</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Martha Stewart</text>
+ <action>EXEC /usr/bin/cliSipie marthastewartlivingradio</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Sirius Stars</text>
+ <action>EXEC /usr/bin/cliSipie siriusstars</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>OutQ Gay Radio</text>
+ <action>EXEC /usr/bin/cliSipie siriusoutq</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Patriot</text>
+ <action>EXEC /usr/bin/cliSipie siriuspatriot</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Left</text>
+ <action>EXEC /usr/bin/cliSipie siriusleft</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>CNN</text>
+ <action>EXEC /usr/bin/cliSipie cnn</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>wrn</text>
+ <action>EXEC /usr/bin/cliSipie wrn</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Blue Collar Comedy</text>
+ <action>EXEC /usr/bin/cliSipie bluecollarcomedy</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Raw Dog Comedy</text>
+ <action>EXEC /usr/bin/cliSipie rawdog</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Laugh Break Comedy</text>
+ <action>EXEC /usr/bin/cliSipie laughbreak</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>thefoxxhole</text>
+ <action>EXEC /usr/bin/cliSipie thefoxxhole</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>lime</text>
+ <action>EXEC /usr/bin/cliSipie lime</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Kids Stuff</text>
+ <action>EXEC /usr/bin/cliSipie kidsstuff</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Catholic Channel</text>
+ <action>EXEC /usr/bin/cliSipie thecatholicchannel</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>EWTN</text>
+ <action>EXEC /usr/bin/cliSipie ewtnglobal</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>christiantalk</text>
+ <action>EXEC /usr/bin/cliSipie christiantalk</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Sirius NFL Radio</text>
+ <action>EXEC /usr/bin/cliSipie siriusnflradio</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Maxim Radio</text>
+ <action>EXEC /usr/bin/cliSipie maximradio</action>
+ </button>
+ <button>
+ <type>MUSIC</type>
+ <text>Cosmo Radio</text>
+ <action>EXEC /usr/bin/cliSipie cosmopolitanradio</action>
+ </button>
+ <button>
+ <type>TV_DELETE</type>
+ <text>Stop Listening</text>
+ <action>EXEC /usr/bin/sipie_kill</action>
+ </button>
+
+</mythmenu>
+
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/update.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/update.xml
new file mode 100644
index 0000000..d2ac3fe
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/update.xml
@@ -0,0 +1,9 @@
+<mythmenu name="LinHES">
+
+ <button>
+ <type>UPGRADE</type>
+ <text>Check for Updates</text>
+ <action>EXEC sudo /usr/LH/bin/linhes_update.sh</action>
+ </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/update2.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/update2.xml
new file mode 100644
index 0000000..64388cb
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/update2.xml
@@ -0,0 +1,20 @@
+<mythmenu name="LinHES">
+
+ <button>
+ <type>UPGRADE</type>
+ <text>Install Updates</text>
+ <action>EXEC sudo /usr/LH/bin/linhes_update2.sh install</action>
+ </button>
+
+ <button>
+ <type>UPGRADE</type>
+ <text>Cancel Updates</text>
+ <action>EXEC sudo /usr/LH/bin/linhes_update2.sh</action>
+ </button>
+
+ <button>
+ <type>UPGRADE</type>
+ <text>View Updates</text>
+ <action>MENU update3.xml</action>
+ </button>
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/menu-xml/xmmenu.xml b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/xmmenu.xml
new file mode 100644
index 0000000..6b26d11
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/menu-xml/xmmenu.xml
@@ -0,0 +1,574 @@
+<!-- Current as of April 25, 2007 -->
+<mythmenu name="XM">
+
+ <button>
+ <type>MUSIC</type>
+ <text>The '40s</text>
+ <action>EXEC /usr/bin/xamp kill 4</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The '50s</text>
+ <action>EXEC /usr/bin/xamp kill 5</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The '60s</text>
+ <action>EXEC /usr/bin/xamp kill 6</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The '70s</text>
+ <action>EXEC /usr/bin/xamp kill 7</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The '80s</text>
+ <action>EXEC /usr/bin/xamp kill 8</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The '90s</text>
+ <action>EXEC /usr/bin/xamp kill 9</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>America</text>
+ <action>EXEC /usr/bin/xamp kill 10</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>X Country</text>
+ <action>EXEC /usr/bin/xamp kill 12</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Willie's Place</text>
+ <action>EXEC /usr/bin/xamp kill 13</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Bluegrass Junction</text>
+ <action>EXEC /usr/bin/xamp kill 14</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Village</text>
+ <action>EXEC /usr/bin/xamp kill 15</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Highway 16</text>
+ <action>EXEC /usr/bin/xamp kill 16</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>US Country</text>
+ <action>EXEC /usr/bin/xamp kill 17</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>20 on 20</text>
+ <action>EXEC /usr/bin/xamp kill 20</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Heart</text>
+ <action>EXEC /usr/bin/xamp kill 23</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Blend</text>
+ <action>EXEC /usr/bin/xamp kill 25</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Flight 26</text>
+ <action>EXEC /usr/bin/xamp kill 26</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Cinemagic</text>
+ <action>EXEC /usr/bin/xamp kill 27</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>On Broadway</text>
+ <action>EXEC /usr/bin/xamp kill 28</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>U-Pop</text>
+ <action>EXEC /usr/bin/xamp kill 29</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>XM Hitlist</text>
+ <action>EXEC /usr/bin/xamp kill 30</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Torch</text>
+ <action>EXEC /usr/bin/xamp kill 31</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Message</text>
+ <action>EXEC /usr/bin/xamp kill 32</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Spirit</text>
+ <action>EXEC /usr/bin/xamp kill 33</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>enLighten</text>
+ <action>EXEC /usr/bin/xamp kill 34</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Deep Tracks</text>
+ <action>EXEC /usr/bin/xamp kill 40</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Boneyard</text>
+ <action>EXEC /usr/bin/xamp kill 41</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>XM Liquid Metal</text>
+ <action>EXEC /usr/bin/xamp kill 42</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>XMU</text>
+ <action>EXEC /usr/bin/xamp kill 43</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Fred</text>
+ <action>EXEC /usr/bin/xamp kill 44</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>XM Cafe</text>
+ <action>EXEC /usr/bin/xamp kill 45</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Top Tracks</text>
+ <action>EXEC /usr/bin/xamp kill 46</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Ethel</text>
+ <action>EXEC /usr/bin/xamp kill 47</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Squizz</text>
+ <action>EXEC /usr/bin/xamp kill 48</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Big Tracks</text>
+ <action>EXEC /usr/bin/xamp kill 49</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Loft</text>
+ <action>EXEC /usr/bin/xamp kill 50</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>XM Music Lab</text>
+ <action>EXEC /usr/bin/xamp kill 51</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Verge</text>
+ <action>EXEC /usr/bin/xamp kill 52</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Fungus</text>
+ <action>EXEC /usr/bin/xamp kill 53</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Lucy</text>
+ <action>EXEC /usr/bin/xamp kill 54</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Soul Street</text>
+ <action>EXEC /usr/bin/xamp kill 60</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Flow</text>
+ <action>EXEC /usr/bin/xamp kill 61</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Suite 62</text>
+ <action>EXEC /usr/bin/xamp kill 62</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Groove</text>
+ <action>EXEC /usr/bin/xamp kill 64</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Rhyme</text>
+ <action>EXEC /usr/bin/xamp kill 65</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>RAW</text>
+ <action>EXEC /usr/bin/xamp kill 66</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The City</text>
+ <action>EXEC /usr/bin/xamp kill 67</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Heat</text>
+ <action>EXEC /usr/bin/xamp kill 68</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Real Jazz</text>
+ <action>EXEC /usr/bin/xamp kill 70</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Watercolors</text>
+ <action>EXEC /usr/bin/xamp kill 71</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Beyond Jazz</text>
+ <action>EXEC /usr/bin/xamp kill 72</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>High Standards</text>
+ <action>EXEC /usr/bin/xamp kill 73</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Bluesville</text>
+ <action>EXEC /usr/bin/xamp kill 74</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Hear Music</text>
+ <action>EXEC /usr/bin/xamp kill 75</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Fine Tuning</text>
+ <action>EXEC /usr/bin/xamp kill 76</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Audio Visions</text>
+ <action>EXEC /usr/bin/xamp kill 77</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Escape</text>
+ <action>EXEC /usr/bin/xamp kill 78</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>On The Rocks</text>
+ <action>EXEC /usr/bin/xamp kill 79</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Move</text>
+ <action>EXEC /usr/bin/xamp kill 80</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>BPM</text>
+ <action>EXEC /usr/bin/xamp kill 81</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The System</text>
+ <action>EXEC /usr/bin/xamp kill 82</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Chrome</text>
+ <action>EXEC /usr/bin/xamp kill 83</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>XM-Chill</text>
+ <action>EXEC /usr/bin/xamp kill 84</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Fuego</text>
+ <action>EXEC /usr/bin/xamp kill 90</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Viva</text>
+ <action>EXEC /usr/bin/xamp kill 91</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Aguila</text>
+ <action>EXEC /usr/bin/xamp kill 92</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Caliente</text>
+ <action>EXEC /usr/bin/xamp kill 94</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Luna</text>
+ <action>EXEC /usr/bin/xamp kill 95</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Air Musique</text>
+ <action>EXEC /usr/bin/xamp kill 100</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Joint</text>
+ <action>EXEC /usr/bin/xamp kill 101</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Sur La Route</text>
+ <action>EXEC /usr/bin/xamp kill 102</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>World Zone</text>
+ <action>EXEC /usr/bin/xamp kill 103</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Ngoma</text>
+ <action>EXEC /usr/bin/xamp kill 104</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>XM Classics</text>
+ <action>EXEC /usr/bin/xamp kill 110</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Vox</text>
+ <action>EXEC /usr/bin/xamp kill 112</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>XM Pops</text>
+ <action>EXEC /usr/bin/xamp kill 113</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>XM Kids</text>
+ <action>EXEC /usr/bin/xamp kill 116</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Bob Edwards Show</text>
+ <action>EXEC /usr/bin/xamp kill 133</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>XM Comedy</text>
+ <action>EXEC /usr/bin/xamp kill 150</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Laugh USA</text>
+ <action>EXEC /usr/bin/xamp kill 151</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Special X</text>
+ <action>EXEC /usr/bin/xamp kill 154</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Agenda</text>
+ <action>EXEC /usr/bin/xamp kill 134</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Oprah and Friends</text>
+ <action>EXEC /usr/bin/xamp kill 156</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>The Virus</text>
+ <action>EXEC /usr/bin/xamp kill 202</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>1 Hit Wonders</text>
+ <action>EXEC /usr/bin/xamp kill 300</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Metalcore</text>
+ <action>EXEC /usr/bin/xamp kill 301</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>New Indie First</text>
+ <action>EXEC /usr/bin/xamp kill 302</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Late Night Mix</text>
+ <action>EXEC /usr/bin/xamp kill 303</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Sessions@AOL</text>
+ <action>EXEC /usr/bin/xamp kill 304</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>Shuffle</text>
+ <action>EXEC /usr/bin/xamp kill 305</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>New Rock First</text>
+ <action>EXEC /usr/bin/xamp kill 306</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>New Country First</text>
+ <action>EXEC /usr/bin/xamp kill 307</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>New Hip Hop First</text>
+ <action>EXEC /usr/bin/xamp kill 308</action>
+ </button>
+
+ <button>
+ <type>MUSIC</type>
+ <text>New Pop First</text>
+ <action>EXEC /usr/bin/xamp kill 309</action>
+ </button>
+
+ <button>
+ <type>TV_DELETE</type>
+ <text>Stop Listening</text>
+ <action>EXEC /usr/bin/xamp kill</action>
+ </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-0.27/mythtv/myth_settings.patch b/abs/core/mythtv/stable-0.27/mythtv/myth_settings.patch
new file mode 100644
index 0000000..dd1de24
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/myth_settings.patch
@@ -0,0 +1,1980 @@
+commit 9b4205fa320c06afde8c6d866b854cb12d3ec99c
+Author: root <root@localhost.localdomain>
+Date: Fri Sep 28 14:25:06 2012 -0500
+
+ new patch
+
+ Signed-off-by: root <root@localhost.localdomain>
+
+diff --git a/mythtv/libs/libmythbase/mythcorecontext.cpp b/mythtv/libs/libmythbase/mythcorecontext.cpp
+index 84cb01a..6e3c54a 100644
+--- a/mythtv/libs/libmythbase/mythcorecontext.cpp
++++ b/mythtv/libs/libmythbase/mythcorecontext.cpp
+@@ -1260,6 +1260,90 @@ void MythCoreContext::ResetLanguage(void)
+ d->language.clear();
+ }
+
++//JM ADDED
++void MythCoreContext::savesettings_togroup (QString src_hostname,
++ QString saved_settingsgroupname )
++{
++ return d->m_database->savesettings_togroup(src_hostname,
++ saved_settingsgroupname);
++}
++
++void MythCoreContext::deletesettings(QString delete_hostname,
++ QString saved_settingsgroupname)
++{
++ return d->m_database->deletesettings(delete_hostname,
++ saved_settingsgroupname);
++}
++
++QMap<QString,QStringList> MythCoreContext::list_settingsgroupname()
++{
++ return d->m_database->list_settingsgroupname();
++}
++
++QMap<QString,QStringList> MythCoreContext::diff_settingsgroupname(
++ QString diff_hostname1,
++ QString diff_hostname2,
++ QStringList table_list)
++{
++ return d->m_database->diff_settingsgroupname(diff_hostname1,
++ diff_hostname2,
++ table_list);
++}
++
++void MythCoreContext::clonesettings(QString src_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list,
++ bool is_full_clone,
++ QString dest_hostname)
++{
++ return d->m_database->clonesettings(src_hostname,
++ saved_settingsgroupname,
++ table_list,
++ is_full_clone,
++ dest_hostname);
++}
++
++void MythCoreContext::restoresettings(QString dest_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list )
++{
++ return d->m_database->restoresettings( dest_hostname,
++ saved_settingsgroupname,
++ table_list);
++}
++
++void MythCoreContext::change_hostname(QString old_hostname,
++ QString new_hostname)
++{
++ return d->m_database->change_hostname(old_hostname, new_hostname) ;
++}
++
++bool MythCoreContext::settings_check(QString src_hostname,
++ QString saved_settingsgroupname)
++{
++ return d->m_database->settings_check(src_hostname,saved_settingsgroupname);
++}
++
++void MythCoreContext::import_settings(QMap<QString,QString> vp_map,
++ QString table)
++{
++ return d->m_database->import_settings(vp_map, table);
++}
++
++
++QMap<QString, QMap<QString,QString> > MythCoreContext::export_settings(
++ QString src_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list, bool skip_host )
++{
++ return d->m_database->export_settings(src_hostname,
++ saved_settingsgroupname,
++ table_list , skip_host );
++}
++
++//END JM ADDED
++
++
+ void MythCoreContext::InitLocale(void )
+ {
+ if (!d->m_locale)
+diff --git a/mythtv/libs/libmythbase/mythcorecontext.h b/mythtv/libs/libmythbase/mythcorecontext.h
+index 0917313..3f6d5f8 100644
+--- a/mythtv/libs/libmythbase/mythcorecontext.h
++++ b/mythtv/libs/libmythbase/mythcorecontext.h
+@@ -168,6 +168,40 @@ class MBASE_PUBLIC MythCoreContext : public MythObservable, public MythSocketCBs
+ QString GetLanguageAndVariant(void);
+ void ResetLanguage(void);
+
++ //JM ADDED
++ void savesettings_togroup(QString src_hostname,
++ QString saved_settingsgroupname );
++
++ void deletesettings(QString delete_hostname,
++ QString saved_settingsgroupname);
++
++ QMap<QString,QStringList> list_settingsgroupname();
++ QMap<QString,QStringList> diff_settingsgroupname(QString diff_hostname1,
++ QString diff_hostname2,
++ QStringList table_list);
++
++ void clonesettings(QString src_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list,
++ bool is_full_clone=TRUE,
++ QString dest_hostname="");
++
++ void restoresettings (QString dest_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list);
++
++ void change_hostname (QString old_hostname, QString new_hostname);
++
++ bool settings_check (QString src_hostname ,QString saved_settingsgroupname);
++ void import_settings(QMap<QString,QString> vp_map, QString table);
++
++ QMap<QString,QMap <QString,QString> > export_settings(
++ QString src_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list,
++ bool skip_host = FALSE );
++ //END JM ADDED
++
+ private:
+ MythCoreContextPrivate *d;
+
+diff --git a/mythtv/libs/libmythbase/mythdb.cpp b/mythtv/libs/libmythbase/mythdb.cpp
+index ea30783..e4c1781 100644
+--- a/mythtv/libs/libmythbase/mythdb.cpp
++++ b/mythtv/libs/libmythbase/mythdb.cpp
+@@ -774,7 +774,7 @@ void MythDB::OverrideSettingForSession(
+ QString mk = key.toLower(), mk2 = d->m_localhostname + ' ' + mk, mv = value;
+ if ("dbschemaver" == mk)
+ {
+- LOG(VB_GENERAL, LOG_ERR,
++ LOG(VB_GENERAL, LOG_ERR,
+ QString("ERROR: Refusing to allow override for '%1'.").arg(key));
+ return;
+ }
+@@ -1055,6 +1055,1015 @@ void MythDB::WriteDelayedSettings(void)
+ }
+ }
+
++//JM ADDED
++void MythDB::savesettings_togroup(QString src_hostname,
++ QString saved_settingsgroupname )
++{
++ LOG(VB_GENERAL, LOG_ERR, QString("Using hostname of : %1")
++ .arg(src_hostname));
++ LOG(VB_GENERAL, LOG_ERR, QString("Saving to group: %1")
++ .arg(saved_settingsgroupname));
++ if ( settings_check( src_hostname , "current" ) )
++ {
++ QStringList table_list;
++ QString hostname_clause;
++ table_list.append("settings");
++ table_list.append("keybindings");
++ table_list.append("jumppoints");
++ if ( src_hostname == "GLOBAL" )
++ hostname_clause = "hostname IS NULL";
++ else
++ hostname_clause ="hostname = :HOSTNAME";
++
++ foreach (QString table, table_list)
++ {
++ QString dest_tablename = table +"_" + saved_settingsgroupname ;
++ create_new_table(dest_tablename,table);
++
++ QString query_string;
++ // Remove old saved values
++ MSqlQuery query(MSqlQuery::InitCon());
++ query_string = QString("DELETE FROM %1 WHERE %2")
++ .arg(dest_tablename)
++ .arg(hostname_clause);
++
++ //query_string = QString("DELETE FROM %1 WHERE "
++ // "hostname = :HOSTNAME").arg(dest_tablename);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME" ,src_hostname);
++ query.exec();
++
++ //insert all new settings
++ query_string = QString("REPLACE INTO %1 "
++ "SELECT * from %2 where %3")
++ .arg(dest_tablename)
++ .arg(table)
++ .arg(hostname_clause);
++// query_string = QString("REPLACE INTO %1 "
++// "SELECT * from %2 where hostname = :HOSTNAME)")
++// .arg(dest_tablename)
++// .arg(table);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME",src_hostname);
++ query.exec();
++ }
++ }
++ else
++ LOG(VB_GENERAL| VB_STDIO|VB_FLUSH, LOG_ERR,
++ QString("Couldn't find settings for: %1 \n").arg(src_hostname));
++ return;
++
++};
++
++void MythDB::deletesettings(QString delete_hostname,
++ QString saved_settingsgroupname)
++{
++ LOG(VB_GENERAL, LOG_ERR, QString("Using hostname of : %1")
++ .arg(delete_hostname));
++ LOG(VB_GENERAL, LOG_ERR, QString("Deleting: %1")
++ .arg(saved_settingsgroupname));
++ int tempItem;
++ QString src_tablename;
++ QStringList table_list;
++
++ table_list.append("settings");
++ table_list.append("keybindings");
++ table_list.append("jumppoints");
++ QString hostname_clause;
++ if ( delete_hostname == "GLOBAL" )
++ hostname_clause = "hostname IS NULL";
++ else
++ hostname_clause ="hostname = :HOSTNAME";
++
++ foreach (QString table, table_list)
++ {
++ src_tablename = find_group_table_name(table, saved_settingsgroupname);
++ MSqlQuery query(MSqlQuery::InitCon());
++ // Remove old saved values
++ if ( does_table_exist(src_tablename))
++ {
++ QString query_string = QString("DELETE from %1 "
++ "WHERE %2")
++ .arg(src_tablename)
++ .arg(hostname_clause);
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME" ,delete_hostname);
++ query.exec();
++
++ //check if ok to delete table
++ query_string = QString("SELECT count(*) from %1")
++ .arg(src_tablename);
++ query.prepare(query_string);
++ if (query.exec() && query.isActive() && query.size() > 0)
++ {
++ query.next();
++ tempItem = query.value(0).toInt();
++ if ( tempItem == 0 )
++ drop_temp_table(src_tablename);
++ }
++ }
++ else
++ LOG(VB_GENERAL, LOG_ERR,
++ QString("Couldn't find table: %1").arg(src_tablename));
++ }
++ return;
++}; // end delete settings
++
++
++QMap<QString,QStringList> MythDB::list_settingsgroupname()
++{
++ //Returns a QMAP of "settings_groups: hostname"
++ MSqlQuery query(MSqlQuery::InitCon());
++ MSqlQuery subquery(MSqlQuery::InitCon());
++ QString tempItem;
++ QString temp_hostnameItem;
++ QStringList hostname_list;
++ QMap<QString,QStringList> return_list;
++ QString full_table_name;
++ query.prepare( "show tables like \"settings%\" " );
++ if (query.exec() && query.isActive() && query.size() > 0)
++ {
++ while (query.next())
++ {
++ full_table_name = query.value(0).toString();
++ tempItem=query.value(0).toString().remove(QRegExp("settings_"));
++ if ( tempItem != "distro_default" )
++ {
++ //loop over tables looking for hostnames
++ QString query_string = QString("SELECT DISTINCT "
++ "hostname from %1")
++ .arg(full_table_name);
++ subquery.prepare(query_string);
++
++ if (subquery.exec() && subquery.isActive()
++ && subquery.size() > 0)
++ {
++ while (subquery.next())
++ {
++ temp_hostnameItem = subquery.value(0).toString();
++ hostname_list.append(temp_hostnameItem);
++ }
++ }
++ //Special case of naming for the settings table;
++ //This only affects output.
++ if ( tempItem == "settings" )
++ return_list["current"] = hostname_list;
++ else
++ return_list[tempItem] = hostname_list;
++
++ //reset hostname_list for the next group
++ hostname_list = QStringList();
++ }
++ }
++ }
++ return return_list;
++}; // end list_settingsgroupname
++
++QMap<QString,QStringList> MythDB::diff_settingsgroupname(
++ QString diff_hostname1 ,
++ QString diff_hostname2,
++ QStringList table_list )
++{
++ // Returns a QMAP of tablename : diff results
++ LOG(VB_GENERAL, LOG_ERR, QString("Comparing settings for:"));
++ LOG(VB_GENERAL, LOG_ERR, QString("host 1: %1").arg(diff_hostname1));
++ LOG(VB_GENERAL, LOG_ERR, QString("host 2: %1").arg(diff_hostname2));
++
++ QString qstr;
++ QString tempItem;
++ QString tempString;
++
++ QStringList diff_list;
++ QStringList settings_list;
++ QStringList keybinding_list;
++
++ QMap<QString,QStringList> return_list;
++ if ( table_list.isEmpty() )
++ {
++ table_list.append("settings");
++ table_list.append("keybindings");
++ }
++
++ MSqlQuery query(MSqlQuery::InitCon());
++ foreach (QString table, table_list)
++ {
++ if ( table == "settings")
++ {
++
++ qstr= "SELECT distinct settings.value, :DIFF_HOSTNAME1 AS `hostname`, settings_a.data, :DIFF_HOSTNAME2 AS `hostname`"
++ " , settings_b.data FROM settings LEFT JOIN settings AS settings_a ON settings_a.value = settings.value AND settings_a.hostname = :DIFF_HOSTNAME1"
++ " LEFT JOIN settings AS settings_b ON settings_b.value = settings.value AND settings_b.hostname = :DIFF_HOSTNAME2"
++ " WHERE settings_a.data != settings_b.data OR "
++ " (settings_a.data IS NULL AND settings_b.data IS NOT NULL) OR (settings_a.data IS NOT NULL AND settings_b.data IS NULL);";
++
++ query.prepare(qstr);
++ query.bindValue(":DIFF_HOSTNAME1" , diff_hostname1);
++ query.bindValue(":DIFF_HOSTNAME2" , diff_hostname2);
++
++ if (query.exec() && query.isActive() && query.size() > 0)
++ {
++ while (query.next())
++ {
++ tempString="";
++ //value
++ tempItem = query.value(0).toString();
++ tempString.append(tempItem);
++ tempString.append("|");
++
++ //hostname_1
++ tempItem = query.value(1).toString();
++ if (tempItem.isEmpty())
++ tempItem=diff_hostname1;
++ tempString.append(tempItem);
++ tempString.append("|");
++
++ //data
++ tempItem = query.value(2).toString();
++ if (tempItem.isEmpty())
++ tempItem="NULL";
++ tempString.append(tempItem);
++ tempString.append("|");
++
++ //hostname_2
++ tempItem = query.value(3).toString();
++ if (tempItem.isEmpty())
++ tempItem=diff_hostname2;
++ tempString.append(tempItem);
++ tempString.append("|");
++
++ //data
++ tempItem = query.value(4).toString();
++ if (tempItem.isEmpty())
++ tempItem="NULL";
++ tempString.append(tempItem);
++
++ settings_list.append(tempString);
++ }
++ return_list["Settings"] = settings_list;
++ }
++ }
++ else if ( table == "keybindings")
++ {
++
++ qstr="SELECT distinct keybindings.context, keybindings.action, :DIFF_HOSTNAME1 AS `hostname`, keybindings_a.keylist, :DIFF_HOSTNAME2 AS `hostname`, keybindings_b.keylist FROM keybindings "
++ " LEFT JOIN keybindings AS keybindings_a ON keybindings_a.context = keybindings.context AND keybindings_a.action = keybindings.action "
++ " AND keybindings_a.hostname = :DIFF_HOSTNAME1 "
++ " LEFT JOIN keybindings AS keybindings_b ON keybindings_b.context = keybindings.context "
++ " AND keybindings_b.action = keybindings.action AND keybindings_b.hostname = :DIFF_HOSTNAME2 "
++ " WHERE keybindings_a.keylist != keybindings_b.keylist OR "
++ " (keybindings_a.keylist IS NULL AND keybindings_b.keylist IS NOT NULL) OR (keybindings_a.keylist IS NOT NULL AND keybindings_b.keylist IS NULL);";
++ query.prepare(qstr);
++ query.bindValue(":DIFF_HOSTNAME1" , diff_hostname1);
++ query.bindValue(":DIFF_HOSTNAME2" , diff_hostname2);
++
++ if (query.exec() && query.isActive() && query.size() > 0)
++ {
++ while (query.next())
++ {
++ tempString="";
++ //context
++ tempItem = query.value(0).toString();
++ tempString.append(tempItem);
++ tempString.append("|");
++
++ //action
++ tempItem = query.value(1).toString();
++ tempString.append(tempItem);
++ tempString.append("|");
++
++ //hostname
++ tempItem = query.value(2).toString();
++ if (tempItem.isEmpty())
++ tempItem=diff_hostname1;
++ tempString.append(tempItem);
++ tempString.append("|");
++
++ //keylist
++ tempItem = query.value(3).toString();
++ if (tempItem.isEmpty())
++ tempItem="NULL";
++ tempString.append(tempItem);
++ tempString.append("|");
++
++ //hostname
++ tempItem = query.value(4).toString();
++ if (tempItem.isEmpty())
++ tempItem=diff_hostname2;
++ tempString.append(tempItem);
++ tempString.append("|");
++
++ //keylist
++ tempItem = query.value(5).toString();
++ if (tempItem.isEmpty())
++ tempItem="NULL";
++ tempString.append(tempItem);
++ keybinding_list.append(tempString);
++ }
++ return_list["Keybindings"] = keybinding_list;
++ }
++ }
++
++ }
++ return return_list;
++}; //end diff_settingsgroupname
++
++void MythDB::clonesettings(QString src_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list,
++ bool is_full_clone, QString dest_hostname)
++{
++ LOG(VB_GENERAL, LOG_ERR, QString("Using src hostname of : %1")
++ .arg(src_hostname));
++ LOG(VB_GENERAL, LOG_ERR, QString("Using dest hostname of : %1")
++ .arg(dest_hostname));
++ LOG(VB_GENERAL, LOG_ERR, QString("Cloning setting group: %1")
++ .arg(saved_settingsgroupname));
++ LOG(VB_GENERAL, LOG_ERR, QString("Full Copy : %1")
++ .arg(is_full_clone));
++
++ MSqlQuery query(MSqlQuery::InitCon());
++ QStringList::Iterator it;
++ QString current_table;
++ QString dest_tablename;
++ QString temptable;
++
++ if ( table_list.isEmpty() )
++ {
++ table_list.append("settings");
++ table_list.append("keybindings");
++ table_list.append("jumppoints");
++ }
++
++ for ( it = table_list.begin(); it != table_list.end(); ++it )
++ {
++ current_table = *it ;
++ dest_tablename = find_group_table_name(current_table,
++ saved_settingsgroupname);
++
++ if ( does_table_exist(dest_tablename))
++ {
++ // create temp table for merging settings
++ temptable="temp_table_" + dest_tablename;
++ create_temp_table(temptable, current_table );
++
++ // copy in stored settings
++ QString query_string = QString("REPLACE INTO %1 "
++ "(SELECT * from %2 where hostname = :HOSTNAME)")
++ .arg(temptable)
++ .arg(dest_tablename);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME",src_hostname );
++ query.exec();
++
++ // update hostname for dest_hostname
++ query_string = QString("UPDATE %1 set hostname = :HOSTNAME")
++ .arg(temptable);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME" , dest_hostname );
++ query.exec();
++
++ //if not full clone remove HOST% settings from temp table;
++ if ( current_table == "settings" && !is_full_clone)
++ {
++ query_string = QString("DELETE FROM %1 WHERE "
++ "hostname=:HOSTNAME and value like 'HOST%' " )
++ .arg(temptable);
++
++ query.prepare(query_string);
++ query.bindValue( ":HOSTNAME" , dest_hostname );
++ query.exec();
++ }
++
++ //remove current settings from dest table,
++ //if not full clone, then leave HOST%
++ //Need to remove because the old table allows for duplicates
++
++ if ( current_table == "settings" && !is_full_clone)
++ query_string = QString ("DELETE FROM %1 WHERE "
++ "hostname = :HOSTNAME "
++ "and value not like 'HOST%'")
++ .arg(dest_tablename);
++
++ else
++ query_string = QString ("DELETE FROM %1 WHERE "
++ "hostname = :HOSTNAME ")
++ .arg(dest_tablename);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME",dest_hostname);
++ query.exec();
++
++ // copy new settings from temp to current
++ query_string = QString("REPLACE INTO %1 "
++ "(SELECT * from %2)")
++ .arg(dest_tablename)
++ .arg(temptable);
++
++ query.prepare(query_string);
++ query.exec();
++
++ // drop temptable
++ drop_temp_table(temptable);
++ }
++ else
++ LOG(VB_GENERAL, LOG_NOTICE, QString("Couldn't find table: %1")
++ .arg(dest_tablename));
++ }
++}; //end clonesettings
++
++void MythDB::restoresettings (QString dest_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list )
++{
++ LOG(VB_GENERAL, LOG_NOTICE, QString("Restoring Settings:"));
++ LOG(VB_GENERAL, LOG_NOTICE, QString(" src: %1")
++ .arg(saved_settingsgroupname));
++ LOG(VB_GENERAL, LOG_NOTICE, QString(" dest:%1")
++ .arg(dest_hostname));
++
++ QString hostname_clause;
++ if ( dest_hostname == "GLOBAL" )
++ hostname_clause = "hostname IS NULL";
++ else
++ hostname_clause ="hostname = :HOSTNAME";
++
++ bool table_check;
++ if ( saved_settingsgroupname == "distro_default" )
++ table_check = settings_check ( "distro_default" , saved_settingsgroupname );
++ else
++ table_check = settings_check ( dest_hostname , saved_settingsgroupname );
++
++
++ if ( table_check == TRUE )
++ {
++ MSqlQuery query(MSqlQuery::InitCon());
++ QStringList::Iterator it;
++ QString current_table;
++ if ( table_list.isEmpty() )
++ {
++ table_list.append("settings");
++ table_list.append("keybindings");
++ table_list.append("jumppoints");
++ }
++
++ for ( it = table_list.begin(); it != table_list.end(); ++it )
++ {
++ current_table = *it ;
++ //find tablenames to use
++ QString src_tablename = find_group_table_name(current_table,
++ saved_settingsgroupname);
++
++ QString temptable="temp_table_" + src_tablename;
++ if ( ! does_table_exist(src_tablename))
++ {
++ LOG(VB_GENERAL, LOG_NOTICE, QString("table does not exist: %1")
++ .arg(src_tablename));
++ continue;
++ }
++ // create temp table for merging settings
++ create_temp_table(temptable, current_table );
++
++ //could copy in current settings here to account for new stuff
++
++
++
++ // copy in stored settings
++ QString query_string;
++ if ( saved_settingsgroupname == "distro_default" )
++ { //special case for restoring default settings
++ query_string = QString("REPLACE INTO %1 "
++ "(SELECT * from %2 WHERE %3)")
++ .arg(temptable)
++ .arg(src_tablename)
++ .arg(hostname_clause);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME", "distro_default" );
++ query.exec();
++
++ // update hostname in temp table from distro_default
++ query_string = QString("UPDATE %1 set hostname = :HOSTNAME")
++ .arg(temptable);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME" , dest_hostname );
++ query.exec();
++
++ }
++ else
++ { //normal use case
++ query_string = QString("REPLACE INTO %1 "
++ "(SELECT * from %2 WHERE %3)")
++ .arg(temptable)
++ .arg(src_tablename)
++ .arg(hostname_clause);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME",dest_hostname );
++ query.exec();
++ }
++
++ //Remove current settings.
++ //Need to remove because the old table allows for duplicates
++ query_string = QString("DELETE FROM %1 WHERE "
++ "%2")
++ .arg(current_table)
++ .arg(hostname_clause);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME",dest_hostname);
++ query.exec();
++
++ // copy new settings from temp to current
++ query_string = QString("REPLACE INTO %1 "
++ "(SELECT * from %2)")
++ .arg(current_table)
++ .arg(temptable);
++
++ query.prepare(query_string);
++ query.exec();
++ // drop temptable
++ drop_temp_table(temptable);
++ }
++ }
++}; //end restore settings
++
++void MythDB::change_hostname (QString old_hostname, QString new_hostname)
++{
++ LOG(VB_GENERAL, LOG_NOTICE, QString("Changing hostname from %1 -> %2")
++ .arg(old_hostname)
++ .arg(new_hostname));
++
++ MSqlQuery query(MSqlQuery::InitCon());
++ MSqlQuery sub_query(MSqlQuery::InitCon());
++ query.prepare( "SHOW TABLES" );
++
++ if (query.exec() && query.isActive() && query.size() > 0)
++ {
++ while (query.next())
++ {
++ QString table_name = query.value(0).toString();
++ LOG(VB_GENERAL, LOG_NOTICE, QString("Scanning %1")
++ .arg(table_name));
++
++ // LOOP OVER TABLES, CHECK IF IT HAS A HOSTNAME FIELD
++ QString query_string=QString("SHOW COLUMNS from %1 "
++ "where field='hostname'")
++ .arg(table_name);
++ sub_query.prepare(query_string);
++
++ if (sub_query.exec() && sub_query.size() > 0)
++ { //update hostname
++ LOG(VB_GENERAL, LOG_NOTICE, QString(" Updating hostname in: %1")
++ .arg(table_name));
++ query_string = QString("UPDATE %1 SET hostname = :NEW_HOSTNAME "
++ "WHERE hostname = :OLD_HOSTNAME")
++ .arg(table_name);
++ sub_query.prepare(query_string);
++ sub_query.bindValue(":NEW_HOSTNAME" , new_hostname);
++ sub_query.bindValue(":OLD_HOSTNAME" , old_hostname);
++ sub_query.exec();
++ }
++ }
++ }
++
++
++
++
++
++
++}
++
++bool MythDB::settings_check(QString src_hostname,
++ QString saved_settingsgroupname)
++{
++ int tempItem;
++ bool returncode = FALSE ;
++ QString table="settings";
++
++ QString tablename = find_group_table_name(table, saved_settingsgroupname);
++ QString hostname_clause;
++ if ( src_hostname == "GLOBAL" )
++ hostname_clause = "hostname IS NULL";
++ else
++ hostname_clause ="hostname = :HOSTNAME";
++
++ if (does_table_exist (tablename))
++ {
++ MSqlQuery query(MSqlQuery::InitCon());
++ QString query_string = QString("SELECT COUNT(data) from %1 "
++ "WHERE %2")
++ .arg(tablename)
++ .arg(hostname_clause);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME" , src_hostname );
++
++ if (query.exec() && query.isActive() && query.size() > 0 )
++ {
++ while (query.next())
++ {
++ tempItem = query.value(0).toInt();
++ if ( tempItem >= 1 )
++ returncode = TRUE;
++ else
++ {
++ LOG(VB_GENERAL, LOG_NOTICE,
++ QString("Group %1 does not contain"
++ " valid settings")
++ .arg(saved_settingsgroupname));
++ }
++ }
++ }
++ }
++ else
++ LOG(VB_GENERAL, LOG_NOTICE, QString("Couldn't find table: %1")
++ .arg(tablename));
++ return returncode;
++}; // end settings_check
++
++void MythDB::import_settings(QMap<QString,QString> vp_map,
++ QString table)
++{
++ MSqlQuery query(MSqlQuery::InitCon());
++
++ //IMPORT SETTINGS TABLE
++ if (table.startsWith("settings"))
++ {
++ if ( table != "settings" )
++ create_new_table(table,"settings");
++ QString hostname = vp_map.value("hostname");
++ QString value = vp_map.value("value");
++ QString data = vp_map.value("data");
++
++ QString hostname_clause;
++ QVariant import_hostname = QVariant(QVariant::String);
++
++ if ( hostname.isEmpty())
++ hostname_clause = "hostname IS NULL";
++ else
++ {
++ hostname_clause ="hostname = :HOSTNAME";
++ import_hostname = hostname;
++ }
++
++ QString query_string=QString("SELECT value, data, hostname "
++ "FROM %1 "
++ "WHERE %2 AND value = :VALUE "
++ "ORDER BY value")
++ .arg(table)
++ .arg(hostname_clause);
++
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME", hostname);
++ query.bindValue(":VALUE", value);
++
++ // if already exisiting records then update, otherwise insert
++ if (query.exec() && query.isActive())
++ {
++ MSqlQuery sub_query(MSqlQuery::InitCon());
++ if ( query.size() > 0 )
++ {
++ query_string = QString("UPDATE "
++ "%1 "
++ "set data = :DATA "
++ "WHERE %2 AND "
++ "value = :VALUE ")
++ .arg(table)
++ .arg(hostname_clause);
++
++ sub_query.prepare(query_string);
++ sub_query.bindValue(":HOSTNAME", import_hostname);
++ sub_query.bindValue(":VALUE", value);
++ sub_query.bindValue(":DATA", data);
++ sub_query.exec();
++ }
++ else
++ {
++ query_string = QString("INSERT INTO "
++ " %1 "
++ "(value,data,hostname) "
++ "VALUES ( :VALUE , :DATA , :HOSTNAME)").arg(table);
++
++ sub_query.prepare(query_string);
++ sub_query.bindValue(":HOSTNAME", import_hostname);
++ sub_query.bindValue(":VALUE", value);
++ sub_query.bindValue(":DATA", data);
++ sub_query.exec();
++ }
++ }
++ }
++ //KEYBINDINGS TABLE
++ else if (table.startsWith("keybindings"))
++ {
++ if ( table != "keybindings" )
++ create_new_table(table,"keybindings");
++ QString hostname = vp_map.value("hostname");
++ QString context = vp_map.value("context");
++ QString action = vp_map.value("action");
++ QString description = vp_map.value("description");
++ QString keylist = vp_map.value("keylist");
++
++ QString query_string=QString("SELECT context,action,hostname "
++ "FROM %1 "
++ "WHERE hostname = :HOSTNAME AND "
++ "context = :CONTEXT "
++ "AND action = :ACTION ").arg(table);
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME", hostname);
++ query.bindValue(":CONTEXT", context);
++ query.bindValue(":ACTION", action);
++
++ if (query.exec() && query.isActive())
++ {
++ MSqlQuery sub_query(MSqlQuery::InitCon());
++ if ( query.size() > 0 )
++ {
++ query_string = QString("UPDATE "
++ " %1 "
++ "set keylist = :KEYLIST "
++ "WHERE hostname = :HOSTNAME AND "
++ "context = :CONTEXT "
++ "AND action = :ACTION ").arg(table);
++
++ sub_query.prepare(query_string);
++ sub_query.bindValue(":HOSTNAME", hostname);
++ sub_query.bindValue(":KEYLIST", keylist);
++ sub_query.bindValue(":CONTEXT", context);
++ sub_query.bindValue(":ACTION", action);
++ sub_query.exec();
++ }
++ else
++ {
++ query_string = QString("INSERT INTO "
++ " %1 "
++ " (context , action , description , keylist , hostname) "
++ " VALUES( "
++ " :CONTEXT ,"
++ " :ACTION , "
++ " :DESCRIPTION , "
++ " :KEYLIST , "
++ " :HOSTNAME)").arg(table) ;
++
++ sub_query.prepare(query_string);
++ sub_query.bindValue(":HOSTNAME", hostname);
++ sub_query.bindValue(":KEYLIST", keylist);
++ sub_query.bindValue(":CONTEXT", context);
++ sub_query.bindValue(":ACTION", action);
++ sub_query.bindValue(":DESCRIPTION", description);
++ sub_query.exec();
++ }
++ }
++ }
++ //JUMP POINTS
++ else if (table.startsWith("jumppoints"))
++ {
++ if ( table != "jumppoints" )
++ create_new_table(table,"jumppoints");
++ QString hostname = vp_map.value("hostname");
++ QString description = vp_map.value("description");
++ QString destination = vp_map.value("destination");
++ QString keylist = vp_map.value("keylist");
++
++ QString query_string=QString("SELECT destination, keylist "
++ "FROM %1 "
++ "WHERE hostname = :HOSTNAME AND "
++ "destination = :DESTINATION "
++ "AND keylist = :KEYLIST ").arg(table);
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME", hostname);
++ query.bindValue(":DESTINATION", destination);
++ query.bindValue(":KEYLIST", keylist);
++
++ if (query.exec() && query.isActive())
++ {
++ MSqlQuery sub_query(MSqlQuery::InitCon());
++ if ( query.size() > 0 )
++ {
++ query_string = QString("UPDATE "
++ " %1 "
++ "set keylist = :KEYLIST "
++ "WHERE hostname = :HOSTNAME AND "
++ "destination = :DESTINATION ").arg(table);
++
++ sub_query.prepare(query_string);
++ sub_query.bindValue(":HOSTNAME", hostname);
++ sub_query.bindValue(":KEYLIST", keylist);
++ sub_query.bindValue(":DESTINATION", destination);
++ sub_query.exec();
++ }
++ else
++ {
++ query_string = QString("INSERT INTO "
++ " %1 "
++ " (description , destination, keylist , hostname) "
++ " VALUES( "
++ " :DESCRIPTION ,"
++ " :DESTINATION , "
++ " :KEYLIST , "
++ " :HOSTNAME)").arg(table) ;
++
++ sub_query.prepare(query_string);
++ sub_query.bindValue(":HOSTNAME", hostname);
++ sub_query.bindValue(":KEYLIST", keylist);
++ sub_query.bindValue(":DESTINATION", destination);
++ sub_query.bindValue(":DESCRIPTION", description);
++ sub_query.exec();
++ }
++ }
++ }
++}; //end import_settings
++
++QMap<QString, QMap<QString,QString> >
++ MythDB::export_settings(QString src_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list, bool skip_host )
++{
++ QMap<QString, QMap<QString,QString> > result_set;
++ QStringList::Iterator it;
++ QString current_table;
++ int record_count = 0;
++
++ if ( table_list.isEmpty() )
++ {
++ table_list.append("settings");
++ table_list.append("keybindings");
++ table_list.append("jumppoints");
++ }
++
++ MSqlQuery query(MSqlQuery::InitCon());
++ QString query_string;
++
++ //loop over tablelist
++ for ( it = table_list.begin(); it != table_list.end(); ++it )
++ {
++ current_table = *it ;
++ QString sub_sql;
++ QStringList fields;
++ QString field_query;
++
++ QString table_name = find_group_table_name(current_table,
++ saved_settingsgroupname);
++
++ QString hostname_clause;
++ if ( src_hostname == "GLOBAL" )
++ hostname_clause = "hostname IS NULL";
++ else
++ hostname_clause ="hostname = :HOSTNAME";
++
++ // find field names
++ query_string = QString("SHOW COLUMNS from %1").arg(table_name);
++ query.prepare(query_string);
++
++ //build up field name vars
++ if (query.exec() && query.isActive() && query.size() > 0)
++ {
++ while (query.next())
++ {
++ if (! field_query.isEmpty())
++ field_query +=',';
++ QString tempItem = query.value(0).toString();
++ fields.append(tempItem);
++ field_query += tempItem;
++ }
++ }
++ // when working with settings table skip HOST if skip_host is true
++ if ( current_table == "settings" && skip_host == TRUE )
++ {
++ QString skip_host_clause;
++ skip_host_clause = " VALUE not like 'HOST%' AND DATA not like 'HardwareProfile%UUID'" ;
++ query_string = QString("SELECT %1 FROM %2 WHERE %3 AND %4")
++ .arg(field_query)
++ .arg(table_name)
++ .arg(hostname_clause)
++ .arg(skip_host_clause);
++
++ }
++ else
++ {
++ query_string = QString("SELECT %1 FROM %2 WHERE %3")
++ .arg(field_query)
++ .arg(table_name)
++ .arg(hostname_clause);
++ }
++ query.prepare(query_string);
++ query.bindValue(":HOSTNAME" , src_hostname);
++
++ //looping over each record in the table query
++ if (query.exec() && query.isActive() && query.size() > 0)
++ {
++ while (query.next())
++ {
++ //construct qmap of elements
++ //add table name
++ QMap<QString,QString> value_pair;
++ value_pair["table"]=table_name;
++
++ for ( int i=0 ; i < fields.size();i++ )
++ {
++ QString tempvalue = fields[i];
++ QString tempItem = query.value(i).toString();
++ value_pair[tempvalue]=tempItem;
++ }
++ result_set[QString(record_count)] = value_pair;
++ record_count++;
++ }
++ }
++
++ } // end table loop
++ return result_set;
++}; //end export_settings
++
++
++void MythDB::create_new_table (QString create_table_name,QString like_name)
++{
++ if ( ! does_table_exist(create_table_name))
++ {
++ MSqlQuery query(MSqlQuery::InitCon());
++ QString query_string = QString("CREATE TABLE %1 like %2")
++ .arg(create_table_name)
++ .arg(like_name);
++
++ query.prepare(query_string);
++ query.exec();
++ }
++ else
++ LOG(VB_GENERAL, LOG_NOTICE, QString("Table is already present,"
++ "will not create it: %1")
++ .arg(create_table_name));
++};
++
++
++void MythDB::drop_temp_table (QString table_name)
++{
++ MSqlQuery query(MSqlQuery::InitCon());
++ if (table_name == "settings" | table_name == "keybindings" | table_name == "jumppoints")
++ return;
++ QString query_string = QString("DROP TABLE %1").arg(table_name);
++ query.prepare(query_string);
++ query.exec();
++ return;
++}
++
++void MythDB::create_temp_table (QString create_table_name,QString like_name)
++{
++ MSqlQuery query(MSqlQuery::InitCon());
++ create_new_table(create_table_name,like_name);
++ QString query_string;
++ if ( like_name == "settings")
++ {
++ query_string = QString ("ALTER TABLE %1 ADD UNIQUE( value)")
++ .arg(create_table_name);
++ query.prepare(query_string);
++ query.exec();
++ }
++
++ query_string = QString("TRUNCATE %1").arg(create_table_name);
++ query.prepare(query_string);
++ query.exec();
++ return;
++}
++
++bool MythDB::does_table_exist(QString table_name)
++{
++ bool table_exist = FALSE;
++ QString full_table_name;
++ MSqlQuery query(MSqlQuery::InitCon());
++
++ query.prepare( "SHOW TABLES" );
++ if (query.exec() && query.isActive() && query.size() > 0)
++ {
++ while (query.next())
++ {
++ full_table_name = query.value(0).toString();
++ if (table_name == full_table_name)
++ {
++ table_exist = TRUE;
++ break;
++ }
++ }
++ }
++ return table_exist;
++};
++
++
++QString MythDB::find_group_table_name(QString current_table,
++ QString saved_settingsgroupname)
++{
++ QString table_name;
++ if ( saved_settingsgroupname.toLower() == "current" )
++ table_name = current_table ;
++ else
++ table_name = current_table + "_" + saved_settingsgroupname ;
++
++ return table_name;
++};
++//END JM ADDED
++
+ /**
+ * \brief Set a flag indicating we have successfully connected to the database
+ */
+diff --git a/mythtv/libs/libmythbase/mythdb.h b/mythtv/libs/libmythbase/mythdb.h
+index 79abe56..fd6044e 100644
+--- a/mythtv/libs/libmythbase/mythdb.h
++++ b/mythtv/libs/libmythbase/mythdb.h
+@@ -75,6 +75,49 @@ class MBASE_PUBLIC MythDB
+
+ void WriteDelayedSettings(void);
+
++ //JM ADDED
++ void savesettings_togroup(QString src_hostname,
++ QString saved_settingsgroupname );
++ void deletesettings(QString delete_hostname,
++ QString saved_settingsgroupname);
++
++ QMap<QString,QStringList> list_settingsgroupname();
++
++ QMap<QString,QStringList> diff_settingsgroupname(QString diff_hostname1,
++ QString diff_hostname2,
++ QStringList table_list);
++
++ void clonesettings(QString src_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list,
++ bool is_full_clone=TRUE,
++ QString dest_hostname="");
++
++ void restoresettings (QString dest_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list);
++
++ void change_hostname (QString old_hostname, QString new_hostname);
++ bool settings_check (QString src_hostname, QString saved_settingsgroupname);
++ void import_settings(QMap<QString,QString> vp_map, QString table);
++
++
++ QMap<QString,QMap <QString,QString> > export_settings(
++ QString src_hostname,
++ QString saved_settingsgroupname,
++ QStringList table_list,
++ bool skip_host = FALSE);
++
++ void create_new_table (QString create_table_name,QString like_name);
++ void drop_temp_table (QString table_name);
++ void create_temp_table (QString create_table_name,QString like_name);
++ bool does_table_exist(QString table_name);
++ QString find_group_table_name(QString current_table,
++ QString saved_settingsgroupname);
++ //END JM ADDED
++
++
++
+ void SetHaveDBConnection(bool connected);
+ void SetHaveSchema(bool schema);
+ bool HaveSchema(void) const;
+diff --git a/mythtv/programs/mythutil/commandlineparser.cpp b/mythtv/programs/mythutil/commandlineparser.cpp
+index f4a6035..fdeeb8e 100644
+--- a/mythtv/programs/mythutil/commandlineparser.cpp
++++ b/mythtv/programs/mythutil/commandlineparser.cpp
+@@ -118,6 +118,37 @@ void MythUtilCommandLineParser::LoadArguments(void)
+ << add("--print-template", "printtemplate", false,
+ "Print the template to be sent to the frontend", "")
+ ->SetGroup("Messaging")
++
++ //settingsutil.cpp
++ << add("--save-settings", "savesettings", false,
++ "Save current settings", "")
++ ->SetGroup("Settings")
++ << add("--delete-settings", "deletesettings", false,
++ "Delete current settings", "")
++ ->SetGroup("Settings")
++ << add("--restore-settings", "restoresettings", false,
++ "Restore settings from previous backup", "")
++ ->SetGroup("Settings")
++ << add("--list-groups", "listgroups", false,
++ "List hosts and groups of settings", "")
++ ->SetGroup("Settings")
++ << add("--copy-settings", "copysettings", false,
++ "Copy or Clone settings from one host to another", "")
++ ->SetGroup("Settings")
++ << add("--diff-settings", "diffsettings", false,
++ "Show settings that are different between two hosts", "")
++ ->SetGroup("Settings")
++ << add("--change-hostname", "changehostname", false,
++ "Change the hostname", "")
++ ->SetGroup("Settings")
++ << add("--import-settings", "importsettings", false,
++ "import settings", "")
++ ->SetRequiredChild("infile")
++
++ << add("--export-settings", "exportsettings", false,
++ "export settings", "")
++ ->SetRequiredChild("outfile")
++
+ );
+
+ // mpegutils.cpp
+@@ -140,6 +171,59 @@ void MythUtilCommandLineParser::LoadArguments(void)
+ add("--bcastaddr", "bcastaddr", "127.0.0.1", "(optional) IP address to send to", "")
+ ->SetChildOf("message");
+
++ //settingsutils.cpp
++ add("--groupname", "groupname", "", "Group of settings name", "")
++ ->SetRequiredChildOf("savesettings")
++ ->SetRequiredChildOf("restoresettings")
++ ->SetRequiredChildOf("deletesettings")
++ ->SetChildOf("copysettings");
++
++ add("--hostname", "hostname", "", "System name to save/restore settings", "")
++ ->SetChildOf("savesettings")
++ ->SetChildOf("restoresettings")
++ ->SetChildOf("copysettings")
++ ->SetChildOf("deletesettings")
++ ->SetChildOf("exportsettings")
++ ->SetChildOf("importsettings");
++
++ add("--host_1", "host_1", "", "First host in compare list", "")
++ ->SetRequiredChildOf("diffsettings");
++
++ add("--host_2", "host_2", "", "Second host in compare list", "")
++ ->SetRequiredChildOf("diffsettings");
++
++
++ add("--tablelist", "table_list", "", "List of tables to operate on "
++ "[keybindings,settings]", "")
++ ->SetChildOf("diffsettings")
++ ->SetChildOf("restoresettings")
++ ->SetChildOf("copysettings")
++ ->SetChildOf("exportsettings");
++
++ add("--clone", "fullclone", false, "Enable copy of all settings, "
++ "including those that are unique to each system.", "")
++ ->SetChildOf("copysettings");
++
++
++ add("--old-host", "oldhost", "", "Hostname to change", "")
++ ->SetRequiredChildOf("changehostname");
++
++ add("--new-host", "newhost", "", "New hostname", "")
++ ->SetRequiredChildOf("changehostname")
++ ->SetRequiredChildOf("copysettings");
++
++ add("--format", "format", false, "Format output of differences", "")
++ ->SetChildOf("diffsettings");
++ add("--distro-default", "distro-default", false, "Export settings for"
++ "import into the default table", "")
++ ->SetChildOf("exportsettings");
++ add("--generic", "generic", false, "export settings without saving "
++ "the hostname", "")
++ ->SetChildOf("exportsettings");
++
++
++
++
+ // Generic Options used by more than one utility
+ addRecording();
+ addInFile(true);
+diff --git a/mythtv/programs/mythutil/main.cpp b/mythtv/programs/mythutil/main.cpp
+index 418ea01..bd4a1f4 100644
+--- a/mythtv/programs/mythutil/main.cpp
++++ b/mythtv/programs/mythutil/main.cpp
+@@ -21,6 +21,7 @@
+ #include "jobutils.h"
+ #include "markuputils.h"
+ #include "messageutils.h"
++#include "settingsutils.h"
+ #include "signalhandling.h"
+
+
+@@ -105,6 +106,7 @@
+ registerJobUtils(utilMap);
+ registerMarkupUtils(utilMap);
+ registerMessageUtils(utilMap);
++ registerSettingsUtils(utilMap);
+
+ bool cmdFound = false;
+ int cmdResult = GENERIC_EXIT_OK;
+diff --git a/mythtv/programs/mythutil/mythutil.pro b/mythtv/programs/mythutil/mythutil.pro
+index 066e618..87d7952 100644
+--- a/mythtv/programs/mythutil/mythutil.pro
++++ b/mythtv/programs/mythutil/mythutil.pro
+@@ -10,7 +10,7 @@ TARGET = mythutil
+ target.path = $${PREFIX}/bin
+ INSTALLS = target
+
+-LIBS += $$EXTRA_LIBS
++LIBS += $$EXTRA_LIBS
+ INCLUDEPATH += ../../libs/libmythbase
+
+ QMAKE_CLEAN += $(TARGET)
+@@ -19,8 +19,10 @@ QMAKE_CLEAN += $(TARGET)
+ HEADERS += mythutil.h commandlineparser.h
+ HEADERS += backendutils.h fileutils.h jobutils.h markuputils.h
+ HEADERS += messageutils.h mpegutils.h
++HEADERS += settingsutils.h
++
+ SOURCES += main.cpp mythutil.cpp commandlineparser.cpp
+ SOURCES += backendutils.cpp fileutils.cpp jobutils.cpp markuputils.cpp
+ SOURCES += messageutils.cpp mpegutils.cpp
+-
++SOURCES += settingsutils.cpp
+ mingw: LIBS += -lwinmm -lws2_32
+diff --git a/mythtv/programs/mythutil/settingsutils.cpp b/mythtv/programs/mythutil/settingsutils.cpp
+new file mode 100644
+index 0000000..8fc7b0e
+--- /dev/null
++++ b/mythtv/programs/mythutil/settingsutils.cpp
+@@ -0,0 +1,586 @@
++// C++ includes
++#include <iostream>
++
++//QT includes
++#include <qdom.h>
++#include <QFile>
++#include <QDomElement>
++
++// libmyth* includes
++#include "compat.h"
++#include "exitcodes.h"
++#include "mythlogging.h"
++#include "mythcontext.h"
++
++
++#include "settingsutils.h"
++
++
++static int SaveSettings(const MythUtilCommandLineParser &cmdline)
++{
++ QString src_hostname;
++ QString groupname;
++
++ if (cmdline.toBool("groupname"))
++ groupname = cmdline.toString("groupname");
++
++ if (cmdline.toBool("hostname"))
++ src_hostname = cmdline.toString("hostname");
++ else
++ src_hostname = gCoreContext->GetHostName();
++
++ gCoreContext->savesettings_togroup(src_hostname,groupname);
++ return GENERIC_EXIT_OK;
++}
++
++static int DeleteSettings(const MythUtilCommandLineParser &cmdline)
++{
++
++ QString delete_hostname;
++ QString groupname;
++
++ if (cmdline.toBool("groupname"))
++ groupname = cmdline.toString("groupname");
++
++ if (cmdline.toBool("hostname"))
++ delete_hostname = cmdline.toString("hostname");
++ else
++ delete_hostname = gCoreContext->GetHostName();
++
++
++ gCoreContext->deletesettings(delete_hostname,groupname);
++
++ return GENERIC_EXIT_OK;
++}
++
++
++static int RestoreSettings(const MythUtilCommandLineParser &cmdline)
++{
++ QString dest_hostname;
++ QString groupname;
++ QString tablestring;
++ QStringList table_list;
++
++ if (cmdline.toBool("groupname"))
++ groupname = cmdline.toString("groupname");
++
++
++ if (cmdline.toBool("hostname"))
++ dest_hostname = cmdline.toString("hostname");
++ else
++ dest_hostname = gCoreContext->GetHostName();
++
++ if (cmdline.toBool("table_list"))
++ {
++ tablestring = QString(cmdline.toString("table_list"));
++ table_list = tablestring.split(",", QString::SkipEmptyParts);
++ }
++
++ gCoreContext->restoresettings(dest_hostname,
++ groupname,
++ table_list);
++
++ return GENERIC_EXIT_OK;
++}
++
++
++static int CopySettings(const MythUtilCommandLineParser &cmdline)
++{
++ QString src_hostname;
++ QString groupname;
++ QString tablestring;
++ QStringList table_list;
++ bool is_full_clone;
++ QString dest_hostname;
++
++ if (cmdline.toBool("groupname"))
++ groupname = cmdline.toString("groupname");
++ else
++ groupname = "Current";
++
++ if (cmdline.toBool("hostname"))
++ src_hostname = cmdline.toString("hostname");
++ else
++ src_hostname = gCoreContext->GetHostName();
++
++ if (cmdline.toBool("newhost"))
++ dest_hostname = cmdline.toString("newhost");
++
++ if (cmdline.toBool("table_list"))
++ {
++ tablestring = QString(cmdline.toString("table_list"));
++ table_list = tablestring.split(",", QString::SkipEmptyParts);
++ }
++
++ if (cmdline.toBool("fullclone"))
++ is_full_clone = TRUE;
++ else
++ is_full_clone = FALSE;
++
++ gCoreContext->clonesettings(src_hostname,
++ groupname,
++ table_list,
++ is_full_clone,
++ dest_hostname);
++
++ return GENERIC_EXIT_OK;
++}
++
++void print_out_diff_formated(QMap<QString, QStringList> resultset)
++{
++ QString settings_header;
++ QString keybindings_header;
++ QString tempString;
++ QString tempItem;
++ QString dashline_settings;
++ QString dashline_key;
++ QStringList tempList;
++
++ QString host_1;
++ QString host_2;
++ QString data_1;
++ QString data_2;
++ QString value;
++ QString context;
++ QString action;
++
++ int value_width = 35;
++ int data_width = 40;
++
++ int context_width = 22;
++ int action_width = 22;
++ int key_width = 35;
++
++ dashline_key = (tempString.fill('-', 133));
++ dashline_settings = (tempString.fill('-', 130));
++
++ QMap<QString, QStringList>::iterator i;
++
++
++ for (i = resultset.begin(); i != resultset.end(); ++i)
++ {
++ cout << endl<<i.key().toLocal8Bit().constData() << ": \t" << endl;;
++ //construct the headers
++ if (i.key() == "Settings")
++ {
++ //settings header
++ tempList = (i.value().at(0)).split("|", QString::SkipEmptyParts);
++ host_1 = tempList.at(1);
++ host_2 = tempList.at(3);
++ tempString="|";
++ tempItem = "Value";
++ tempString.append(tempItem.leftJustified(value_width));
++ tempString.append("|");
++ tempItem = host_1; //hostname 1
++ tempString.append(tempItem.leftJustified(data_width));
++ tempString.append("|");
++ tempItem = host_2; //hostname 2
++ tempString.append(tempItem.leftJustified(data_width));
++ tempString.append("|");
++ settings_header = tempString;
++
++ cout << settings_header.toLocal8Bit().constData() << endl;;
++ cout << dashline_settings.toLocal8Bit().constData() << endl;
++ }
++
++ if (i.key() == "Keybindings")
++ {
++ //keybindings_header
++ tempList = (i.value().at(0)).split("|", QString::SkipEmptyParts);
++ host_1 = tempList.at(2);
++ host_2 = tempList.at(4);
++ tempString="|";
++ tempItem = "Context";
++ tempString.append(tempItem.leftJustified(context_width));
++ tempString.append("|");
++ tempItem = "Action";
++ tempString.append(tempItem.leftJustified(action_width));
++ tempString.append("|");
++ tempItem = host_1;
++ tempString.append(tempItem.leftJustified(key_width));
++ tempString.append("|");
++ tempItem = host_2;
++ tempString.append(tempItem.leftJustified(key_width));
++ tempString.append("|");
++ keybindings_header = tempString;
++
++ cout << keybindings_header.toLocal8Bit().constData() << endl;;
++ cout << dashline_key.toLocal8Bit().constData() << endl;
++
++ }
++ // format each line
++ for (int y = 0; y < i.value().size(); ++y)
++ {
++ if (i.key() == "Settings")
++ {
++ tempList = (i.value().at(y)).split("|",
++ QString::SkipEmptyParts);
++ data_1 = tempList.at(2);
++ data_2 = tempList.at(4);
++ value = tempList.at(0);
++ tempString="|";
++ tempItem = value;
++ tempString.append(tempItem.leftJustified(value_width));
++ tempString.append("|");
++ tempItem = data_1;
++ tempString.append(tempItem.leftJustified(data_width));
++ tempString.append("|");
++ tempItem = data_2;
++ tempString.append(tempItem.leftJustified(data_width));
++ tempString.append("|");
++ }
++ if (i.key() == "Keybindings")
++ {
++ tempList = (i.value().at(y)).split("|",
++ QString::SkipEmptyParts);
++ data_1 = tempList.at(3);
++ data_2 = tempList.at(5);
++ context = tempList.at(0);
++ action = tempList.at(1);
++
++ tempString="|";
++ tempItem = context;
++ tempString.append(tempItem.leftJustified(context_width));
++ tempString.append("|");
++ tempItem = action;
++ tempString.append(tempItem.leftJustified(action_width));
++ tempString.append("|");
++ tempItem = data_1;
++ tempString.append(tempItem.leftJustified(key_width));
++ tempString.append("|");
++ tempItem = data_2;
++ tempString.append(tempItem.leftJustified(key_width));
++ tempString.append("|");
++ }
++
++ cout << tempString.toLocal8Bit().constData()<<endl;
++ }
++ }
++};
++
++static int DiffSettings(const MythUtilCommandLineParser &cmdline)
++{
++ QMap<QString, QStringList> resultset;
++ QString diff_hostname1;
++ QString diff_hostname2;
++ QStringList table_list;
++ bool format_results = FALSE;
++ QMap<QString, QStringList>::iterator i;
++
++ if (cmdline.toBool("host_1"))
++ diff_hostname1 = cmdline.toString("host_1");
++ if (cmdline.toBool("host_2"))
++ diff_hostname2 = cmdline.toString("host_2");
++
++ if (cmdline.toBool("table_list"))
++ {
++ QString tablestring = QString(cmdline.toString("table_list"));
++ table_list = tablestring.split(",", QString::SkipEmptyParts);
++ }
++
++ if (cmdline.toBool("format"))
++ format_results = TRUE;
++
++ resultset = gCoreContext->diff_settingsgroupname(diff_hostname1,
++ diff_hostname2,
++ table_list);
++ if (resultset.isEmpty())
++ cout << "No differences found" << endl;
++ else
++ {
++ if (format_results)
++ print_out_diff_formated(resultset);
++ else
++ {
++ for (i = resultset.begin(); i != resultset.end(); ++i)
++ {
++ cout << i.key().toLocal8Bit().constData() << " : \t" << endl;;
++ for (int y = 0; y < i.value().size(); ++y)
++ cout << i.value().at(y).toLocal8Bit().constData()<<endl;
++ cout << endl;
++ }
++ }
++ }
++ return GENERIC_EXIT_OK;
++};// DiffSettings
++
++static int ListGroups(const MythUtilCommandLineParser &cmdline)
++{
++ QMap<QString, QStringList> resultset;
++ resultset = gCoreContext->list_settingsgroupname();
++ QMap<QString, QStringList>::iterator i;
++ cout << endl;
++ for (i = resultset.begin(); i != resultset.end(); ++i)
++ {
++ cout << i.key().toLocal8Bit().constData() << " : \t";
++ for (int y = 0; y < i.value().size(); ++y)
++ cout << i.value().at(y).toLocal8Bit().constData()<<" " ;
++ cout << endl;
++ }
++ return GENERIC_EXIT_OK;
++};
++
++static int ImportSettings(const MythUtilCommandLineParser &cmdline)
++{
++
++ if (cmdline.toString("infile").isEmpty())
++ {
++ LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing --infile option\n");
++ return GENERIC_EXIT_INVALID_CMDLINE;
++ }
++ QString import_hostname;
++ bool change_name = FALSE;
++ if (cmdline.toBool("hostname"))
++ {
++ change_name = TRUE;
++ import_hostname = cmdline.toString("hostname");
++ }
++ QString import_filename = cmdline.toString("infile");
++ QFile myFile(import_filename);
++
++ QDomDocument doc( "exported_xml" );
++ doc.setContent( &myFile );
++
++ QDomElement docElement = doc.documentElement();
++ QDomElement record_element;
++
++ if ( docElement.nodeName() != "exported_xml" )
++ {
++ cout << "not a valid exported xml file" << endl;
++ return 1;
++ }
++
++ QString out_string = "Importing records, please be patient";
++ cout << out_string.toLocal8Bit().constData() << endl;
++ //Gives list of records in the file + count
++ QDomNodeList nodeList = docElement.childNodes();
++ int total_records = nodeList.count();
++ out_string = QString("\nFound %1 records \n").arg(total_records);
++ cout << out_string.toLocal8Bit().constData() << endl;
++ LOG(VB_STDIO|VB_FLUSH, LOG_ERR, out_string);
++
++ for(QDomNode n = docElement.firstChild(); !n.isNull(); n = n.nextSibling())
++ {
++ QString table_name=QString();
++ QMap<QString,QString> value_pair_map ;
++
++ //find table name for this record
++ QDomNode tablenode=n.namedItem("table");
++ record_element = tablenode.toElement();
++ table_name = record_element.text();
++
++ //loop over childern of n and convert to element
++ for(QDomNode subn = n.firstChild();
++ !subn.isNull();
++ subn = subn.nextSibling())
++ {
++ record_element = subn.toElement();
++ if ( record_element.nodeName() == "table" )
++ continue;
++ if ( change_name && record_element.nodeName() == "hostname" )
++ value_pair_map[record_element.nodeName()] = import_hostname;
++ else
++ value_pair_map[record_element.nodeName()] = record_element.text();
++ }
++ if (import_filename.endsWith("syssettings.xml"))
++ {
++ if ( value_pair_map["value"] == "BackendServerIP")
++ {
++ out_string = "sysettings, ignoring backendserver ip record";
++ cout << out_string.toLocal8Bit().constData() << endl;
++ }
++ else
++ gCoreContext->import_settings(value_pair_map,table_name);
++ }
++ else
++ //perform insert
++ gCoreContext->import_settings(value_pair_map,table_name);
++ }
++ return GENERIC_EXIT_OK;
++}; //end ImportSettings
++
++
++static int ExportSettings(const MythUtilCommandLineParser &cmdline)
++{
++ QMap<QString, QMap<QString,QString> > records;
++ QString src_hostname;
++ QString groupname;
++ QStringList table_list;
++ QString tablestring;
++ bool distro_default = FALSE;
++ bool generic = FALSE;
++ bool skip_host = FALSE;
++
++
++
++ QDomDocument doc("mythutils_exported_settings");
++
++ if (cmdline.toBool("groupname"))
++ groupname = cmdline.toString("groupname");
++ else
++ groupname = "current";
++
++ if (cmdline.toBool("hostname"))
++ src_hostname = cmdline.toString("hostname");
++ else
++ src_hostname = gCoreContext->GetHostName();
++
++ if (cmdline.toBool("distro-default"))
++ {
++ distro_default = TRUE;
++ skip_host = TRUE;
++ }
++ if (cmdline.toBool("generic"))
++ {
++ generic = TRUE;
++ //skip_host = TRUE;
++ }
++ if (cmdline.toBool("table_list"))
++ {
++ tablestring = QString(cmdline.toString("table_list"));
++ table_list = tablestring.split(",", QString::SkipEmptyParts);
++ }
++ else
++ table_list << "settings" <<"keybindings" <<"jumppoints" ;
++
++ if (cmdline.toString("outfile").isEmpty())
++ {
++ LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing --outfile option\n");
++ return GENERIC_EXIT_INVALID_CMDLINE;
++ }
++
++ QString export_filename = cmdline.toString("outfile");
++
++ records = gCoreContext->export_settings(src_hostname,groupname,
++ table_list, skip_host);
++
++ QDomElement exported_xml = doc.createElement("exported_xml");
++ doc.appendChild(exported_xml);
++
++ QMap<QString,int> record_count;
++ QMap<QString,QMap<QString,QString> >::iterator i;
++ for (i = records.begin(); i != records.end(); ++i )
++ {
++ QDomElement record = doc.createElement("record");
++ exported_xml.appendChild(record);
++
++ //loop over all values in the record
++ QMap<QString,QString> value_pair = i.value();
++ QMap<QString, QString>::iterator y;
++ //because we don't know the name of the key, we loop over it
++ for (y = value_pair.begin(); y != value_pair.end(); ++y)
++ {
++ //add key/pair to xml document
++ QDomElement tag = doc.createElement(y.key());
++ record.appendChild(tag);
++ QDomText t;
++ if ( distro_default == TRUE )
++ { // If exporting distro_default then change hostname + table
++ if ( y.key() == "hostname" )
++ { //check for global values here, empty value means global
++ if ( y.value().isEmpty() )
++ t = doc.createTextNode(y.value());
++ else
++ t = doc.createTextNode("distro_default");
++ }
++ else if ( y.key() == "table")
++ t = doc.createTextNode(y.value()+"_distro_default");
++ else
++ t = doc.createTextNode(y.value());
++ }
++
++ else if ( generic == TRUE )
++ { // If exporting generic then change hostname
++ if ( y.key() == "hostname" )
++ { //check for global values here, empty value means global
++ if ( y.value().isEmpty() )
++ t = doc.createTextNode(y.value());
++ else
++ t = doc.createTextNode("REPLACE_ME");
++ }
++ else
++ t = doc.createTextNode(y.value());
++ }
++ else
++ t = doc.createTextNode(y.value());
++
++ tag.appendChild(t);
++ //create record counts
++ if ( y.key() == "table" )
++ {
++ if ( record_count.contains( y.value()) )
++ {
++ int record_num = record_count[y.value()];
++ record_count[y.value()] = ++record_num;
++ }
++ else
++ record_count[y.value()] = 1;
++ }
++ }
++ }
++ QFile file( export_filename );
++
++ if( !file.open(QIODevice::WriteOnly) )
++ return -1;
++
++ QTextStream ts( &file );
++ ts << doc.toString();
++ file.close();
++ QMap<QString, int >::iterator rc_it;
++ for ( rc_it = record_count.begin(); rc_it != record_count.end(); ++rc_it)
++ {
++ QString table = rc_it.key();
++ int rc_count = rc_it.value();
++ QString out_string = QString ("Exported table %1: %2 records")
++ .arg(table)
++ .arg(rc_count);
++ cout << out_string.toLocal8Bit().constData() << endl;
++ }
++ return GENERIC_EXIT_OK;
++}; // end export_settings
++
++
++static int ChangeHostname(const MythUtilCommandLineParser &cmdline)
++{
++
++ QString old_hostname;
++ QString new_hostname;
++
++
++ if (cmdline.toBool("oldhost"))
++ old_hostname = cmdline.toString("oldhost");
++
++ if (cmdline.toBool("newhost"))
++ new_hostname = cmdline.toString("newhost");
++
++ if (old_hostname.isEmpty())
++ {
++ LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing or empty --old-host option\n");
++ return GENERIC_EXIT_INVALID_CMDLINE;
++ }
++
++ if (new_hostname.isEmpty())
++ {
++ LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing or empty --new-host option\n");
++ return GENERIC_EXIT_INVALID_CMDLINE;
++ }
++
++ gCoreContext->change_hostname(old_hostname, new_hostname);
++
++ return GENERIC_EXIT_OK;
++}; //end ChangeHostname
++
++void registerSettingsUtils(UtilMap &utilMap)
++{
++ utilMap["savesettings"] = &SaveSettings;
++ utilMap["deletesettings"] = &DeleteSettings;
++ utilMap["restoresettings"] = &RestoreSettings;
++ utilMap["copysettings"] = &CopySettings;
++ utilMap["diffsettings"] = &DiffSettings;
++ utilMap["listgroups"] = &ListGroups;
++ utilMap["importsettings"] = &ImportSettings;
++ utilMap["exportsettings"] = &ExportSettings;
++ utilMap["changehostname"] = &ChangeHostname;
++}
++
++/* vim: set expandtab tabstop=4 shiftwidth=4: */
+\ No newline at end of file
+diff --git a/mythtv/programs/mythutil/settingsutils.h b/mythtv/programs/mythutil/settingsutils.h
+new file mode 100644
+index 0000000..413496c
+--- /dev/null
++++ b/mythtv/programs/mythutil/settingsutils.h
+@@ -0,0 +1,3 @@
++#include "mythutil.h"
++
++void registerSettingsUtils(UtilMap &utilMap);
diff --git a/abs/core/mythtv/stable-0.27/mythtv/mythtv.install b/abs/core/mythtv/stable-0.27/mythtv/mythtv.install
new file mode 100644
index 0000000..8e900ed
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/mythtv.install
@@ -0,0 +1,24 @@
+# arg 1: the new package version
+post_install() {
+ gen_is_xml.py
+ gen_lib_xml.py
+}
+
+pre_upgrade() {
+ /bin/true
+}
+
+post_upgrade() {
+ post_install
+}
+
+
+# arg 1: the old package version
+post_remove() {
+ /bin/true
+
+}
+
+op=$1
+shift
+$op $*
diff --git a/abs/core/mythtv/stable-0.27/mythtv/recordings b/abs/core/mythtv/stable-0.27/mythtv/recordings
new file mode 100644
index 0000000..7fdde51
--- /dev/null
+++ b/abs/core/mythtv/stable-0.27/mythtv/recordings
@@ -0,0 +1,5 @@
+#!/bin/bash
+if [ -f /usr/share/mythtv/contrib/user_jobs/mythlink.pl ]
+then
+ su - mythtv -c "perl /usr/share/mythtv/contrib/user_jobs/mythlink.pl --link /data/storage/disk0/media/recordings"
+fi