From 570a8e42684f542d6deceffd59c4eca234ffabc7 Mon Sep 17 00:00:00 2001 From: Britney Fransen Date: Sat, 2 Nov 2013 17:51:08 -0500 Subject: mythtv stable-0.27 mythtv: initial commit. refs #933 changed the name of pretty to recordings --- ...tect-metadata-loads-from-multiple-threads.patch | 52 + abs/core/mythtv/stable-0.27/mythtv/PKGBUILD | 118 ++ abs/core/mythtv/stable-0.27/mythtv/__changelog | 2 + .../stable-0.27/mythtv/menu-xml/HOST_SETTINGS.xml | 98 + .../stable-0.27/mythtv/menu-xml/dvd_backup.xml | 39 + .../mythtv/stable-0.27/mythtv/menu-xml/game.xml | 12 + .../stable-0.27/mythtv/menu-xml/info_menu.xml | 76 + abs/core/mythtv/stable-0.27/mythtv/menu-xml/is.xml | 3 + .../stable-0.27/mythtv/menu-xml/library.xml.patch | 26 + .../mythtv/stable-0.27/mythtv/menu-xml/linhes.xml | 60 + .../stable-0.27/mythtv/menu-xml/mainmenu.xml.patch | 37 + .../stable-0.27/mythtv/menu-xml/mythbackup.xml | 20 + .../stable-0.27/mythtv/menu-xml/mythrestore.xml | 21 + .../mythtv/menu-xml/optical_menu.xml.patch | 23 + .../mythtv/menu-xml/original/create_patch.sh | 5 + .../stable-0.27/mythtv/menu-xml/siriusmenu.xml | 419 +++++ .../mythtv/stable-0.27/mythtv/menu-xml/update.xml | 9 + .../mythtv/stable-0.27/mythtv/menu-xml/update2.xml | 20 + .../mythtv/stable-0.27/mythtv/menu-xml/xmmenu.xml | 574 ++++++ .../mythtv/stable-0.27/mythtv/myth_settings.patch | 1980 ++++++++++++++++++++ abs/core/mythtv/stable-0.27/mythtv/mythtv.install | 24 + abs/core/mythtv/stable-0.27/mythtv/recordings | 5 + 22 files changed, 3623 insertions(+) create mode 100644 abs/core/mythtv/stable-0.27/mythtv/0001-protect-metadata-loads-from-multiple-threads.patch create mode 100644 abs/core/mythtv/stable-0.27/mythtv/PKGBUILD create mode 100644 abs/core/mythtv/stable-0.27/mythtv/__changelog create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/HOST_SETTINGS.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/dvd_backup.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/game.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/info_menu.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/is.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/library.xml.patch create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/linhes.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/mainmenu.xml.patch create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/mythbackup.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/mythrestore.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/optical_menu.xml.patch create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/original/create_patch.sh create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/siriusmenu.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/update.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/update2.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/menu-xml/xmmenu.xml create mode 100644 abs/core/mythtv/stable-0.27/mythtv/myth_settings.patch create mode 100644 abs/core/mythtv/stable-0.27/mythtv/mythtv.install create mode 100644 abs/core/mythtv/stable-0.27/mythtv/recordings 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 +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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 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 @@ + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + 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 @@ + + + ++ ++ + + 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 @@ + + + + + + + + + + + + + + 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 @@ + + ++ + + + + +- +- + + 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 @@ + + + + + + + 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 @@ + + + + + + + + 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 @@ + + + ++ ++ ++ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + 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 @@ + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 +Date: Fri Sep 28 14:25:06 2012 -0500 + + new patch + + Signed-off-by: root + +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 MythCoreContext::list_settingsgroupname() ++{ ++ return d->m_database->list_settingsgroupname(); ++} ++ ++QMap 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 vp_map, ++ QString table) ++{ ++ return d->m_database->import_settings(vp_map, table); ++} ++ ++ ++QMap > 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 list_settingsgroupname(); ++ QMap 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 vp_map, QString table); ++ ++ QMap > 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 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 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 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 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 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 > ++ MythDB::export_settings(QString src_hostname, ++ QString saved_settingsgroupname, ++ QStringList table_list, bool skip_host ) ++{ ++ QMap > 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 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 list_settingsgroupname(); ++ ++ QMap 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 vp_map, QString table); ++ ++ ++ QMap > 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 ++ ++//QT includes ++#include ++#include ++#include ++ ++// 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 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::iterator i; ++ ++ ++ for (i = resultset.begin(); i != resultset.end(); ++i) ++ { ++ cout << endl< resultset; ++ QString diff_hostname1; ++ QString diff_hostname2; ++ QStringList table_list; ++ bool format_results = FALSE; ++ QMap::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()< resultset; ++ resultset = gCoreContext->list_settingsgroupname(); ++ QMap::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 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 > 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 record_count; ++ QMap >::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 value_pair = i.value(); ++ QMap::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::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 -- cgit v0.12